diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 24ccec0a..d0a542ae 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -49,7 +49,13 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 return -1; } frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); + #if defined(__linux__) frames_ctx->format = AV_PIX_FMT_VAAPI; + #elif defined(_WIN32) + frames_ctx->format = AV_PIX_FMT_DXVA2_VLD; + #elif defined(__APPLE__) + frames_ctx->format = AV_PIX_FMT_QSV; + #endif frames_ctx->sw_format = AV_PIX_FMT_NV12; frames_ctx->width = width; frames_ctx->height = height; @@ -70,9 +76,9 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 #endif #if IS_FFMPEG_3_2 -#if defined(__linux__) +//#if defined(__linux__) #pragma message "You are compiling with experimental hardware encode" -#endif +//#endif #endif FFmpegWriter::FFmpegWriter(string path) : @@ -171,6 +177,28 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i else { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 0; + hw_en_supported = 0; + } + #elif defined(_WIN32) + if ( (strcmp(codec.c_str(),"h264_dxva2") == 0)) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + } + else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; + hw_en_supported = 0; + } + #elif defined(__APPLE__) + if ( (strcmp(codec.c_str(),"h264_qsv") == 0)) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + } + else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; hw_en_supported = 0; } #else // is FFmpeg 3 but not linux @@ -799,14 +827,14 @@ void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) AV_FREE_CONTEXT(video_codec); video_codec = NULL; #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { if (hw_device_ctx) { av_buffer_unref(&hw_device_ctx); hw_device_ctx = NULL; } } - #endif +// #endif #endif } @@ -1176,8 +1204,8 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) video_codec->thread_count = min(FF_NUM_PROCESSORS, 16); #if IS_FFMPEG_3_2 - #if defined(__linux__) if (hw_en_on && hw_en_supported) { + #if defined(__linux__) // Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set char *dev_hw = getenv( "HW_EN_DEVICE_SET" ); // Check if it is there and writable @@ -1189,8 +1217,20 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; throw InvalidCodec("Could not create hwdevice", path); } + #elif defined(_WIN32) + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, + NULL, NULL, 0) < 0) { + cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; + throw InvalidCodec("Could not create hwdevice", path); + } + #elif defined(__APPLE__) + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, + NULL, NULL, 0) < 0) { + cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; + throw InvalidCodec("Could not create hwdevice", path); + } + #endif } - #endif #endif /* find the video encoder */ codec = avcodec_find_encoder_by_name(info.vcodec.c_str()); @@ -1208,10 +1248,15 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) av_dict_set(&opts, "strict", "experimental", 0); #if IS_FFMPEG_3_2 - #if defined(__linux__) if (hw_en_on && hw_en_supported) { video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames + #if defined(__linux__) video_codec->pix_fmt = AV_PIX_FMT_VAAPI; + #elif defined(_WIN32) + video_codec->pix_fmt = AV_PIX_FMT_DXVA2_VLD + #elif defined(__APPLE__) + video_codec->pix_fmt = AV_PIX_FMT_QSV + #endif video_codec->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; av_opt_set(video_codec->priv_data,"preset","slow",0); av_opt_set(video_codec->priv_data,"tune","zerolatency",0); @@ -1222,7 +1267,6 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) fprintf(stderr, "Failed to set hwframe context.\n"); } } - #endif #endif /* open the codec */ @@ -1675,11 +1719,11 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) frame_source = allocate_avframe(PIX_FMT_RGBA, source_image_width, source_image_height, &bytes_source, (uint8_t*) pixels); #if IS_FFMPEG_3_2 AVFrame *frame_final; - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { frame_final = allocate_avframe(AV_PIX_FMT_NV12, info.width, info.height, &bytes_final, NULL); } else - #endif +// #endif { frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL); } @@ -1758,7 +1802,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Assign the initial AVFrame PTS from the frame counter frame_final->pts = write_video_count; #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { if (!(hw_frame = av_frame_alloc())) { fprintf(stderr, "Error code: av_hwframe_alloc\n"); @@ -1775,7 +1819,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra } av_frame_copy_props(hw_frame, frame_final); } - #endif +// #endif #endif /* encode the image */ int got_packet_ptr = 0; @@ -1784,13 +1828,13 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Write video packet (latest version of FFmpeg) int frameFinished = 0; int ret; - #if defined(__linux__) +// #if defined(__linux__) #if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { ret = avcodec_send_frame(video_codec, hw_frame); //hw_frame!!! } else #endif - #endif +// #endif ret = avcodec_send_frame(video_codec, frame_final); error_code = ret; if (ret < 0 ) { @@ -1877,14 +1921,14 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Deallocate packet AV_FREE_PACKET(&pkt); #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { if (hw_frame) { av_frame_free(&hw_frame); hw_frame = NULL; } } - #endif +// #endif #endif } @@ -1907,11 +1951,11 @@ void FFmpegWriter::InitScalers(int source_width, int source_height) { // Init the software scaler from FFMpeg #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_PIX_FMT_NV12, SWS_BILINEAR, NULL, NULL, NULL); } else - #endif +// #endif #endif { img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), SWS_BILINEAR, NULL, NULL, NULL);