223 lines
10 KiB
Diff
223 lines
10 KiB
Diff
From 54a756b84e0b7a1104f9b336a1253fe36c573f56 Mon Sep 17 00:00:00 2001
|
|
From: Martin Negyokru <negyokru@inf.u-szeged.hu>
|
|
Date: Fri, 17 Jan 2025 15:40:37 +0100
|
|
Subject: [fixup][ffmpeg] Fix building with system ffmpeg
|
|
|
|
Refactor workaround for codec selection issues.
|
|
Introduce FindDecoder which meant to replace avcodec_find_decoder.
|
|
Imporove codec detection in format context.
|
|
|
|
Fixes: QTBUG-132762
|
|
Task-number: QTBUG-130273
|
|
Pick-to: 126-based 122-based
|
|
Change-Id: I6d520633ebebbb9bdb7aa71b8247066c2a662be3
|
|
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/617873
|
|
Reviewed-by: Moss Heim <moss.heim@qt.io>
|
|
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
|
|
---
|
|
.../clear_key_cdm/ffmpeg_cdm_audio_decoder.cc | 5 ++++
|
|
chromium/media/ffmpeg/ffmpeg_common.cc | 23 +++++++++++++++++
|
|
chromium/media/ffmpeg/ffmpeg_common.h | 6 +++++
|
|
chromium/media/filters/audio_file_reader.cc | 5 ++++
|
|
chromium/media/filters/ffmpeg_audio_decoder.cc | 15 ++---------
|
|
chromium/media/filters/ffmpeg_glue.cc | 29 ++++++++++++++--------
|
|
chromium/media/filters/ffmpeg_video_decoder.cc | 5 ++++
|
|
chromium/media/filters/media_file_checker.cc | 5 ++++
|
|
8 files changed, 69 insertions(+), 24 deletions(-)
|
|
|
|
diff --git a/src/3rdparty/chromium/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc b/src/3rdparty/chromium/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc
|
|
index 9646e70..5b9a02e 100644
|
|
--- a/src/3rdparty/chromium/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc
|
|
+++ b/src/3rdparty/chromium/media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.cc
|
|
@@ -177,7 +177,12 @@ bool FFmpegCdmAudioDecoder::Initialize(
|
|
if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P)
|
|
codec_context_->request_sample_fmt = AV_SAMPLE_FMT_S16;
|
|
|
|
+#if BUILDFLAG(IS_QTWEBENGINE) && BUILDFLAG(USE_SYSTEM_FFMPEG)
|
|
+ const AVCodec* codec =
|
|
+ FindDecoder(codec_context_->codec_id, codec_context_->codec_whitelist);
|
|
+#else
|
|
const AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
|
|
+#endif
|
|
if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) {
|
|
DLOG(ERROR) << "Could not initialize audio decoder: "
|
|
<< codec_context_->codec_id;
|
|
diff --git a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc
|
|
index 63159ef..f872a8e 100644
|
|
--- a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc
|
|
+++ b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.cc
|
|
@@ -29,6 +29,11 @@
|
|
#endif
|
|
#endif
|
|
|
|
+#if BUILDFLAG(IS_QTWEBENGINE) && BUILDFLAG(USE_SYSTEM_FFMPEG)
|
|
+extern "C" {
|
|
+#include <libavutil/avstring.h>
|
|
+}
|
|
+#endif
|
|
namespace media {
|
|
|
|
namespace {
|
|
@@ -67,6 +72,24 @@ static_assert(
|
|
VideoFrame::kFrameAddressAlignment % kFFmpegBufferAddressAlignment == 0,
|
|
"VideoFrame frame address alignment does not fit ffmpeg requirement");
|
|
|
|
+#if BUILDFLAG(IS_QTWEBENGINE) && BUILDFLAG(USE_SYSTEM_FFMPEG)
|
|
+const AVCodec* FindDecoder(AVCodecID id, const char* whitelist) {
|
|
+ if (!whitelist) {
|
|
+ return avcodec_find_decoder(id);
|
|
+ }
|
|
+
|
|
+ void* i = 0;
|
|
+ const AVCodec* codec;
|
|
+ while (codec = av_codec_iterate(&i)) {
|
|
+ if (av_codec_is_decoder(codec) && codec->id == id &&
|
|
+ av_match_list(codec->name, whitelist, ',')) {
|
|
+ return codec;
|
|
+ }
|
|
+ }
|
|
+ return nullptr;
|
|
+}
|
|
+#endif
|
|
+
|
|
static const AVRational kMicrosBase = { 1, base::Time::kMicrosecondsPerSecond };
|
|
|
|
base::TimeDelta ConvertFromTimeBase(const AVRational& time_base,
|
|
diff --git a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.h b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.h
|
|
index 9993d34..2332722 100644
|
|
--- a/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.h
|
|
+++ b/src/3rdparty/chromium/media/ffmpeg/ffmpeg_common.h
|
|
@@ -79,6 +79,12 @@ inline void ScopedPtrAVFreeFrame::operator()(void* x) const {
|
|
av_frame_free(&frame);
|
|
}
|
|
|
|
+#if BUILDFLAG(IS_QTWEBENGINE) && BUILDFLAG(USE_SYSTEM_FFMPEG)
|
|
+// Systemlib friendly version of avcodec_find_decoder that respects the
|
|
+// whitelisted codecs.
|
|
+MEDIA_EXPORT const AVCodec* FindDecoder(AVCodecID id, const char* whitelist);
|
|
+#endif
|
|
+
|
|
// Converts an int64_t timestamp in |time_base| units to a base::TimeDelta.
|
|
// For example if |timestamp| equals 11025 and |time_base| equals {1, 44100}
|
|
// then the return value will be a base::TimeDelta for 0.25 seconds since that
|
|
diff --git a/src/3rdparty/chromium/media/filters/audio_file_reader.cc b/src/3rdparty/chromium/media/filters/audio_file_reader.cc
|
|
index dd4f3b5..172bd9a 100644
|
|
--- a/src/3rdparty/chromium/media/filters/audio_file_reader.cc
|
|
+++ b/src/3rdparty/chromium/media/filters/audio_file_reader.cc
|
|
@@ -95,7 +95,12 @@ bool AudioFileReader::OpenDemuxer() {
|
|
}
|
|
|
|
bool AudioFileReader::OpenDecoder() {
|
|
+#if BUILDFLAG(IS_QTWEBENGINE) && BUILDFLAG(USE_SYSTEM_FFMPEG)
|
|
+ const AVCodec* codec =
|
|
+ FindDecoder(codec_context_->codec_id, codec_context_->codec_whitelist);
|
|
+#else
|
|
const AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
|
|
+#endif
|
|
if (codec) {
|
|
// MP3 decodes to S16P which we don't support, tell it to use S16 instead.
|
|
if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P)
|
|
diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc b/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc
|
|
index 22fa4d4..5d94b76 100644
|
|
--- a/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc
|
|
+++ b/src/3rdparty/chromium/media/filters/ffmpeg_audio_decoder.cc
|
|
@@ -360,19 +360,8 @@ bool FFmpegAudioDecoder::ConfigureDecoder(const AudioDecoderConfig& config) {
|
|
}
|
|
|
|
#if BUILDFLAG(IS_QTWEBENGINE) && BUILDFLAG(USE_SYSTEM_FFMPEG)
|
|
- // Workaround http://crbug.com/41492567
|
|
- // Chromium only supports the 'libopus' decoder.
|
|
- // 'avcodec_find_decoder' finds the experimental 'opus' decoder first
|
|
- // because the lookup is based on codec_id and both have the same id.
|
|
- // Bundled ffmpeg only have libopus but the system usually have both.
|
|
- const AVCodec* codec = [&config, this]() {
|
|
- if (config.codec() == AudioCodec::kOpus)
|
|
- return avcodec_find_decoder_by_name("libopus");
|
|
- if (config.codec() == AudioCodec::kMP3) {
|
|
- return avcodec_find_decoder_by_name("mp3");
|
|
- }
|
|
- return avcodec_find_decoder(codec_context_->codec_id);
|
|
- }();
|
|
+ AVCodecID id = AudioCodecToCodecID(config.codec(), config.sample_format());
|
|
+ const AVCodec* codec = FindDecoder(id, codec_context_->codec_whitelist);
|
|
#else
|
|
const AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
|
|
#endif
|
|
diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_glue.cc b/src/3rdparty/chromium/media/filters/ffmpeg_glue.cc
|
|
index 6407b5b..e9bd44b 100644
|
|
--- a/src/3rdparty/chromium/media/filters/ffmpeg_glue.cc
|
|
+++ b/src/3rdparty/chromium/media/filters/ffmpeg_glue.cc
|
|
@@ -242,20 +242,27 @@ bool FFmpegGlue::OpenContext(bool is_local_file) {
|
|
LogContainer(is_local_file, container_);
|
|
|
|
#if BUILDFLAG(IS_QTWEBENGINE) && BUILDFLAG(USE_SYSTEM_FFMPEG)
|
|
- // Sometimes FFmpeg is not aware of the whitelisted codecs and
|
|
- // configures streams and demuxers with unsupported codecs/params.
|
|
- // Force the correct codecs to avoid problems later.
|
|
+ // 'avformat_find_stream_info' is not aware of the whitelisted codecs.
|
|
+ // However it respects the codecs set in the format_context.
|
|
+ // Try to force the correct codecs here at context creation.
|
|
// https://ffmpeg.org/doxygen/7.0/structAVFormatContext.html#a52f39351b15890ef57cc6ff0ec9ab42d
|
|
// https://ffmpeg.org/doxygen/7.0/structAVFormatContext.html#ae5e087f4623b907517c0f7dd8327387d
|
|
|
|
- // Note: don't forget to update FFmpeg[Audio|Video]Decoder::ConfigureDecoder
|
|
-
|
|
- if (strcmp(format_context_->iformat->name, "mp3") == 0) {
|
|
- const AVCodec* mp3_codec = avcodec_find_decoder_by_name("mp3");
|
|
- if (mp3_codec) {
|
|
- format_context_->audio_codec = mp3_codec;
|
|
- } else {
|
|
- LOG(ERROR) << "No supported codec for mp3";
|
|
+ for (int i = 0; i < format_context_->nb_streams; i++) {
|
|
+ AVCodecParameters *params = format_context_->streams[i]->codecpar;
|
|
+ if (!params)
|
|
+ continue;
|
|
+ const AVCodec* audio_codec =
|
|
+ FindDecoder(params->codec_id, GetAllowedAudioDecoders());
|
|
+ if (audio_codec) {
|
|
+ if (format_context_->audio_codec &&
|
|
+ format_context_->audio_codec != audio_codec) {
|
|
+ LOG(INFO) << "Conflicting codecs " << format_context_->audio_codec->name
|
|
+ << ", " << audio_codec->name;
|
|
+ format_context_->audio_codec = nullptr;
|
|
+ break;
|
|
+ }
|
|
+ format_context_->audio_codec = audio_codec;
|
|
}
|
|
}
|
|
#endif
|
|
diff --git a/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc b/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc
|
|
index d08ee1d..832a3fa 100644
|
|
--- a/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc
|
|
+++ b/src/3rdparty/chromium/media/filters/ffmpeg_video_decoder.cc
|
|
@@ -524,7 +524,12 @@ bool FFmpegVideoDecoder::ConfigureDecoder(const VideoDecoderConfig& config,
|
|
codec_context_->flags2 |= AV_CODEC_FLAG2_CHUNKS;
|
|
}
|
|
|
|
+#if BUILDFLAG(IS_QTWEBENGINE) && BUILDFLAG(USE_SYSTEM_FFMPEG)
|
|
+ const AVCodec* codec =
|
|
+ FindDecoder(codec_context_->codec_id, codec_context_->codec_whitelist);
|
|
+#else
|
|
const AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
|
|
+#endif
|
|
if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) {
|
|
ReleaseFFmpegResources();
|
|
return false;
|
|
diff --git a/src/3rdparty/chromium/media/filters/media_file_checker.cc b/src/3rdparty/chromium/media/filters/media_file_checker.cc
|
|
index a2d4757..afe40e4 100644
|
|
--- a/src/3rdparty/chromium/media/filters/media_file_checker.cc
|
|
+++ b/src/3rdparty/chromium/media/filters/media_file_checker.cc
|
|
@@ -68,7 +68,12 @@ bool MediaFileChecker::Start(base::TimeDelta check_time) {
|
|
auto context = AVStreamToAVCodecContext(format_context->streams[i]);
|
|
if (!context)
|
|
continue;
|
|
+#if BUILDFLAG(IS_QTWEBENGINE) && BUILDFLAG(USE_SYSTEM_FFMPEG)
|
|
+ const AVCodec* codec =
|
|
+ FindDecoder(cp->codec_id, context->codec_whitelist);
|
|
+#else
|
|
const AVCodec* codec = avcodec_find_decoder(cp->codec_id);
|
|
+#endif
|
|
if (codec && avcodec_open2(context.get(), codec, nullptr) >= 0) {
|
|
auto loop = std::make_unique<FFmpegDecodingLoop>(context.get());
|
|
stream_contexts[i] = {std::move(context), std::move(loop)};
|