From cdce02607abf1b43cdf93c6f367825158f23a467 Mon Sep 17 00:00:00 2001 From: kongfl888 K <6991229+kongfl888@users.noreply.github.com> Date: Sat, 12 Oct 2024 19:38:58 +0800 Subject: [PATCH] FFmpeg: adapt to ffmpeg7 for dumping. (#248) * FFmpeg: update layout api for ffmpeg 6.x and ffmpeg 7. After ffmpeg 5.1, it is deprecated, and has been completely removed in ffmpeg 7. Our current project is using 6.0 headers, modifying it will not have any side effects. Since lavu 57.24.100(ffmpeg 5.1) * FFmpeg: dynamic_library and dumping adapt to ffmpeg7.1. But keeping support for older versions. * externals/library-headers: update ffmpeg to 7.1 --- externals/library-headers | 2 +- src/citra_qt/dumping/option_set_dialog.cpp | 4 +- src/common/dynamic_library/ffmpeg.cpp | 6 +++ src/common/dynamic_library/ffmpeg.h | 7 +++ src/core/dumping/ffmpeg_backend.cpp | 60 +++++++++++++++++----- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/externals/library-headers b/externals/library-headers index 3b3e28dbe..9fb99108e 160000 --- a/externals/library-headers +++ b/externals/library-headers @@ -1 +1 @@ -Subproject commit 3b3e28dbe6d033395ce2967fa8030825e7b89de7 +Subproject commit 9fb99108ee5c630ca365c8fa4a11087b84e1f58b diff --git a/src/citra_qt/dumping/option_set_dialog.cpp b/src/citra_qt/dumping/option_set_dialog.cpp index f6d6e4af7..f166973cf 100644 --- a/src/citra_qt/dumping/option_set_dialog.cpp +++ b/src/citra_qt/dumping/option_set_dialog.cpp @@ -27,7 +27,7 @@ static const std::unordered_map TypeNameMap{{ {AV_OPT_TYPE_STRING, QT_TR_NOOP("string")}, {AV_OPT_TYPE_DICT, QT_TR_NOOP("dictionary")}, {AV_OPT_TYPE_VIDEO_RATE, QT_TR_NOOP("video rate")}, - {AV_OPT_TYPE_CHANNEL_LAYOUT, QT_TR_NOOP("channel layout")}, + {AV_OPT_TYPE_CHLAYOUT, QT_TR_NOOP("channel layout")}, }}; static const std::unordered_map TypeDescriptionMap{{ @@ -39,7 +39,7 @@ static const std::unordered_map TypeDescriptionMap{{ {AV_OPT_TYPE_DICT, QT_TR_NOOP("Comma-splitted list of <key>=<value>. Do not put spaces.")}, {AV_OPT_TYPE_VIDEO_RATE, QT_TR_NOOP("<num>/<den>, or preset values like 'pal'.")}, - {AV_OPT_TYPE_CHANNEL_LAYOUT, QT_TR_NOOP("Hexadecimal channel layout mask starting with '0x'.")}, + {AV_OPT_TYPE_CHLAYOUT, QT_TR_NOOP("Hexadecimal channel layout mask starting with '0x'.")}, }}; /// Get the preset values of an option. returns {display value, real value} diff --git a/src/common/dynamic_library/ffmpeg.cpp b/src/common/dynamic_library/ffmpeg.cpp index 709f887a5..fd00db337 100644 --- a/src/common/dynamic_library/ffmpeg.cpp +++ b/src/common/dynamic_library/ffmpeg.cpp @@ -65,6 +65,9 @@ avcodec_find_encoder_by_name_func avcodec_find_encoder_by_name; avcodec_free_context_func avcodec_free_context; avcodec_get_class_func avcodec_get_class; avcodec_get_hw_config_func avcodec_get_hw_config; +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // lavc 61.13.100 +avcodec_get_supported_config_func avcodec_get_supported_config; +#endif avcodec_open2_func avcodec_open2; avcodec_parameters_from_context_func avcodec_parameters_from_context; avcodec_receive_frame_func avcodec_receive_frame; @@ -232,6 +235,9 @@ static bool LoadAVCodec() { LOAD_SYMBOL(avcodec, avcodec_free_context); LOAD_SYMBOL(avcodec, avcodec_get_class); LOAD_SYMBOL(avcodec, avcodec_get_hw_config); +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // lavc 61.13.100 + LOAD_SYMBOL(avcodec, avcodec_get_supported_config); +#endif LOAD_SYMBOL(avcodec, avcodec_open2); LOAD_SYMBOL(avcodec, avcodec_parameters_from_context); LOAD_SYMBOL(avcodec, avcodec_receive_frame); diff --git a/src/common/dynamic_library/ffmpeg.h b/src/common/dynamic_library/ffmpeg.h index f79fef8da..69df01ede 100644 --- a/src/common/dynamic_library/ffmpeg.h +++ b/src/common/dynamic_library/ffmpeg.h @@ -114,6 +114,10 @@ typedef const AVCodec* (*avcodec_find_encoder_by_name_func)(const char*); typedef void (*avcodec_free_context_func)(AVCodecContext**); typedef const AVClass* (*avcodec_get_class_func)(); typedef const AVCodecHWConfig* (*avcodec_get_hw_config_func)(const AVCodec*, int); +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // lavc 61.13.100 +typedef int (*avcodec_get_supported_config_func)(const AVCodecContext*, const AVCodec*, + enum AVCodecConfig, unsigned, const void**, int*); +#endif typedef int (*avcodec_open2_func)(AVCodecContext*, const AVCodec*, AVDictionary**); typedef int (*avcodec_parameters_from_context_func)(AVCodecParameters* par, const AVCodecContext*); typedef int (*avcodec_receive_frame_func)(AVCodecContext*, AVFrame*); @@ -138,6 +142,9 @@ extern avcodec_find_encoder_by_name_func avcodec_find_encoder_by_name; extern avcodec_free_context_func avcodec_free_context; extern avcodec_get_class_func avcodec_get_class; extern avcodec_get_hw_config_func avcodec_get_hw_config; +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // lavc 61.13.100 +extern avcodec_get_supported_config_func avcodec_get_supported_config; +#endif extern avcodec_open2_func avcodec_open2; extern avcodec_parameters_from_context_func avcodec_parameters_from_context; extern avcodec_receive_frame_func avcodec_receive_frame; diff --git a/src/core/dumping/ffmpeg_backend.cpp b/src/core/dumping/ffmpeg_backend.cpp index b38116ed3..6fcbe7708 100644 --- a/src/core/dumping/ffmpeg_backend.cpp +++ b/src/core/dumping/ffmpeg_backend.cpp @@ -171,12 +171,21 @@ bool FFmpegVideoStream::Init(FFmpegMuxer& muxer, const Layout::FramebufferLayout codec_context->gop_size = 12; // Get pixel format for codec +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // lavc 61.13.100 + const enum AVPixelFormat* pix_fmts = NULL; + int ret = FFmpeg::avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_PIX_FORMAT, 0, + (const void**)&pix_fmts, NULL); +#else + const enum AVPixelFormat* pix_fmts = codec->pix_fmts; + int ret = 0; +#endif + auto options = ToAVDictionary(Settings::values.video_encoder_options); auto pixel_format_opt = FFmpeg::av_dict_get(options, "pixel_format", nullptr, 0); if (pixel_format_opt) { sw_pixel_format = FFmpeg::av_get_pix_fmt(pixel_format_opt->value); - } else if (codec->pix_fmts) { - sw_pixel_format = GetPixelFormat(codec_context.get(), codec->pix_fmts); + } else if (ret >= 0 && pix_fmts) { + sw_pixel_format = GetPixelFormat(codec_context.get(), pix_fmts); } else { sw_pixel_format = AV_PIX_FMT_YUV420P; } @@ -285,11 +294,20 @@ void FFmpegVideoStream::ProcessFrame(VideoFrame& frame) { } bool FFmpegVideoStream::InitHWContext(const AVCodec* codec) { - for (std::size_t i = 0; codec->pix_fmts[i] != AV_PIX_FMT_NONE; ++i) { +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // lavc 61.13.100 + const enum AVPixelFormat* pix_fmts = NULL; + int ret = FFmpeg::avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_PIX_FORMAT, 0, + (const void**)&pix_fmts, NULL); +#else + const enum AVPixelFormat* pix_fmts = codec->pix_fmts; + int ret = 0; +#endif + + for (std::size_t i = 0; (ret >= 0 && pix_fmts) && (pix_fmts[i] != AV_PIX_FMT_NONE); ++i) { const AVCodecHWConfig* config; for (int j = 0;; ++j) { config = FFmpeg::avcodec_get_hw_config(codec, j); - if (!config || config->pix_fmt == codec->pix_fmts[i]) { + if (!config || config->pix_fmt == pix_fmts[i]) { break; } } @@ -303,7 +321,7 @@ bool FFmpegVideoStream::InitHWContext(const AVCodec* codec) { continue; } - codec_context->pix_fmt = codec->pix_fmts[i]; + codec_context->pix_fmt = pix_fmts[i]; // Create HW device context AVBufferRef* hw_device_context; @@ -351,7 +369,7 @@ bool FFmpegVideoStream::InitHWContext(const AVCodec* codec) { AVHWFramesContext* hw_frames_context = reinterpret_cast(hw_frames_context_ref->data); - hw_frames_context->format = codec->pix_fmts[i]; + hw_frames_context->format = pix_fmts[i]; hw_frames_context->sw_format = sw_pixel_format; hw_frames_context->width = codec_context->width; hw_frames_context->height = codec_context->height; @@ -455,6 +473,7 @@ bool FFmpegAudioStream::Init(FFmpegMuxer& muxer) { } frame_count = 0; + int ret; // Initialize audio codec const AVCodec* codec = @@ -468,16 +487,33 @@ bool FFmpegAudioStream::Init(FFmpegMuxer& muxer) { // Configure audio codec context codec_context->codec_type = AVMEDIA_TYPE_AUDIO; codec_context->bit_rate = Settings::values.audio_bitrate; - if (codec->sample_fmts) { - codec_context->sample_fmt = codec->sample_fmts[0]; + +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // lavc 61.13.100 + const enum AVSampleFormat* sample_fmts = NULL; + ret = FFmpeg::avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, + (const void**)&sample_fmts, NULL); +#else + const enum AVSampleFormat* sample_fmts = codec->sample_fmts; + ret = 0; +#endif + if (ret >= 0 && sample_fmts) { + codec_context->sample_fmt = sample_fmts[0]; } else { codec_context->sample_fmt = AV_SAMPLE_FMT_S16P; } - if (codec->supported_samplerates) { - codec_context->sample_rate = codec->supported_samplerates[0]; +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100) // lavc 61.13.100 + const int* supported_samplerates = NULL; + ret = FFmpeg::avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_SAMPLE_RATE, 0, + (const void**)&supported_samplerates, NULL); +#else + const int* supported_samplerates = codec->supported_samplerates; + ret = 0; +#endif + if (ret >= 0 && supported_samplerates) { + codec_context->sample_rate = supported_samplerates[0]; // Prefer native sample rate if supported - const int* ptr = codec->supported_samplerates; + const int* ptr = supported_samplerates; while ((*ptr)) { if ((*ptr) == AudioCore::native_sample_rate) { codec_context->sample_rate = AudioCore::native_sample_rate; @@ -956,7 +992,7 @@ std::string FormatDefaultValue(const AVOption* option, case AV_OPT_TYPE_VIDEO_RATE: { return ToStdString(option->default_val.str); } - case AV_OPT_TYPE_CHANNEL_LAYOUT: { + case AV_OPT_TYPE_CHLAYOUT: { return fmt::format("{:#x}", option->default_val.i64); } default: