tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 654d670b05e501f7772fea1a4ac7732445406a66
parent 51ea564fcaeffdbd16ba1952fa6a415bfbe9d785
Author: Andrew Osmond <aosmond@gmail.com>
Date:   Tue, 23 Dec 2025 23:03:05 +0000

Bug 2005011 - Part 7. Update ffmpeg configuration to be more accurate on Android. r=media-playback-reviewers,padenot

This will now incorporate the updated gfxVars which now include the HW
codec status. It will also ensure that we don't disable HEVC/H264
support if we only support software codecs, even if ffmpeg regards them
as hardware codecs. It will also ensure that we don't switch away from
MediaCodec decoders when we actually need them, e.g. for encrypted
media.

Differential Revision: https://phabricator.services.mozilla.com/D275725

Diffstat:
Mdom/media/platforms/ffmpeg/FFmpegDataEncoder.cpp | 4++++
Mdom/media/platforms/ffmpeg/FFmpegDecoderModule.h | 28++++++++++++++++++++++++++--
Mdom/media/platforms/ffmpeg/FFmpegEncoderModule.cpp | 55+++++++++++++++++++++++++++++++++++++++++--------------
Mdom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp | 46+++++++++++++++++++++++++++++++++++-----------
Mdom/media/platforms/ffmpeg/FFmpegVideoEncoder.cpp | 13++++++++++++-
Mdom/media/platforms/ffmpeg/FFmpegVideoEncoder.h | 1+
Mtesting/web-platform/meta/webcodecs/video-encoder-h26x-annexb.https.any.js.ini | 8++++++--
7 files changed, 125 insertions(+), 30 deletions(-)

diff --git a/dom/media/platforms/ffmpeg/FFmpegDataEncoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataEncoder.cpp @@ -34,6 +34,10 @@ AVCodecID GetFFmpegEncoderCodecId<LIBAV_VER>(CodecType aCodec) { return AV_CODEC_ID_H264; } + if (aCodec == CodecType::H265) { + return AV_CODEC_ID_HEVC; + } + if (aCodec == CodecType::AV1) { return AV_CODEC_ID_AV1; } diff --git a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h @@ -89,16 +89,19 @@ class FFmpegDecoderModule : public PlatformDecoderModule { {AV_CODEC_ID_VP8, gfx::gfxVars::UseVP8HwDecode()}, # endif +# if defined(MOZ_WIDGET_GTK) && !defined(FFVPX_VERSION) // These proprietary video codecs can only be decoded via hardware by using // the system ffmpeg, not supported by ffvpx. -# if (defined(MOZ_WIDGET_GTK) && !defined(FFVPX_VERSION)) || \ - defined(MOZ_WIDGET_ANDROID) # if LIBAVCODEC_VERSION_MAJOR >= 55 {AV_CODEC_ID_HEVC, gfx::gfxVars::UseHEVCHwDecode()}, # endif {AV_CODEC_ID_H264, gfx::gfxVars::UseH264HwDecode()}, # endif # ifdef MOZ_WIDGET_ANDROID + // These proprietary codecs can only be decoded via MediaCodec decoders, + // but the underlying implementation may be software or hardware. + {AV_CODEC_ID_HEVC, true}, + {AV_CODEC_ID_H264, true}, {AV_CODEC_ID_AAC, true}, # endif }; @@ -261,7 +264,28 @@ class FFmpegDecoderModule : public PlatformDecoderModule { supports += media::DecodeSupport::SoftwareDecode; } if (IsHWDecodingSupported(codecId)) { +#ifdef MOZ_WIDGET_ANDROID + // Because we don't provide software implementations of H264 or HEVC on + // Android, we must use the platform software decoders even if true + // hardware decoding support is missing. + switch (codecId) { + case AV_CODEC_ID_H264: + supports += gfx::gfxVars::UseH264HwDecode() + ? media::DecodeSupport::HardwareDecode + : media::DecodeSupport::SoftwareDecode; + break; + case AV_CODEC_ID_HEVC: + supports += gfx::gfxVars::UseHEVCHwDecode() + ? media::DecodeSupport::HardwareDecode + : media::DecodeSupport::SoftwareDecode; + break; + default: + supports += media::DecodeSupport::HardwareDecode; + break; + } +#else supports += media::DecodeSupport::HardwareDecode; +#endif } #ifdef XP_WIN diff --git a/dom/media/platforms/ffmpeg/FFmpegEncoderModule.cpp b/dom/media/platforms/ffmpeg/FFmpegEncoderModule.cpp @@ -30,9 +30,10 @@ namespace mozilla { template <int V> /* static */ void FFmpegEncoderModule<V>::Init(FFmpegLibWrapper* aLib) { -#if (defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || \ - defined(MOZ_WIDGET_ANDROID)) && \ - defined(MOZ_USE_HWDECODE) && !defined(MOZ_FFVPX_AUDIOONLY) +#if (defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || \ + defined(MOZ_WIDGET_ANDROID)) && \ + defined(MOZ_USE_HWDECODE) && !defined(MOZ_FFVPX_AUDIOONLY) && \ + LIBAVCODEC_VERSION_MAJOR >= 58 # ifdef XP_WIN if (!XRE_IsGPUProcess()) # else @@ -61,23 +62,23 @@ template <int V> # if LIBAVCODEC_VERSION_MAJOR >= 59 {AV_CODEC_ID_AV1, gfx::gfxVars::UseAV1HwEncode()}, # endif -# if LIBAVCODEC_VERSION_MAJOR >= 55 {AV_CODEC_ID_VP9, gfx::gfxVars::UseVP9HwEncode()}, -# endif -# if (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_ANDROID)) && \ - LIBAVCODEC_VERSION_MAJOR >= 54 +# if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_ANDROID) {AV_CODEC_ID_VP8, gfx::gfxVars::UseVP8HwEncode()}, # endif - // These proprietary video codecs can only be encoded via hardware by using - // the system ffmpeg, not supported by ffvpx. -# if (defined(MOZ_WIDGET_GTK) && !defined(FFVPX_VERSION)) || \ - defined(MOZ_WIDGET_ANDROID) -# if LIBAVCODEC_VERSION_MAJOR >= 55 +# if defined(MOZ_WIDGET_GTK) && !defined(FFVPX_VERSION) + // These proprietary video codecs can only be encoded via hardware by + // using the system ffmpeg, not supported by ffvpx. {AV_CODEC_ID_HEVC, gfx::gfxVars::UseHEVCHwEncode()}, -# endif {AV_CODEC_ID_H264, gfx::gfxVars::UseH264HwEncode()}, # endif +# if defined(MOZ_WIDGET_ANDROID) + // These proprietary codecs can only be encoded via MediaCodec encoders, + // but the underlying implementation may be software or hardware. + {AV_CODEC_ID_HEVC, true}, + {AV_CODEC_ID_H264, true}, +# endif }; // Reset the list of supported hardware codecs and reevaluate them. @@ -104,7 +105,7 @@ template <int V> ("Support %s for hw encoding", AVCodecToString(entry.mId))); } #endif // (XP_WIN || MOZ_WIDGET_GTK || MOZ_WIDGET_ANDROID) && MOZ_USE_HWDECODE - // && !MOZ_FFVPX_AUDIOONLY + // && !MOZ_FFVPX_AUDIOONLY && LIBAVCODEC_VERSION_MAJOR >= 58 } // namespace mozilla template <int V> @@ -144,6 +145,11 @@ EncodeSupportSet FFmpegEncoderModule<V>::SupportsCodec(CodecType aCodec) const { if (id == AV_CODEC_ID_NONE) { return EncodeSupportSet{}; } +#if LIBAVCODEC_VERSION_MAJOR >= 58 + if (id == AV_CODEC_ID_HEVC && !StaticPrefs::media_hevc_enabled()) { + return EncodeSupportSet{}; + } +#endif EncodeSupportSet supports; #ifdef MOZ_USE_HWDECODE if (StaticPrefs::media_ffvpx_hw_enabled()) { @@ -151,7 +157,28 @@ EncodeSupportSet FFmpegEncoderModule<V>::SupportsCodec(CodecType aCodec) const { // populated sSupportedHWCodecs. auto hwCodecs = sSupportedHWCodecs.Lock(); if (hwCodecs->Contains(static_cast<uint32_t>(id))) { +# ifdef MOZ_WIDGET_ANDROID + // Because we don't provide software implementations of H264 or HEVC on + // Android, we must use the platform software encoders even if true + // hardware encoding support is missing. + switch (id) { + case AV_CODEC_ID_H264: + supports += gfx::gfxVars::UseH264HwEncode() + ? EncodeSupport::HardwareEncode + : EncodeSupport::SoftwareEncode; + break; + case AV_CODEC_ID_HEVC: + supports += gfx::gfxVars::UseHEVCHwEncode() + ? EncodeSupport::HardwareEncode + : EncodeSupport::SoftwareEncode; + break; + default: + supports += EncodeSupport::HardwareEncode; + break; + } +# else supports += EncodeSupport::HardwareEncode; +# endif } } #endif diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -519,7 +519,34 @@ void FFmpegVideoDecoder<LIBAV_VER>::PtsCorrectionContext::Reset() { #if defined(MOZ_USE_HWDECODE) bool FFmpegVideoDecoder<LIBAV_VER>::ShouldDisableHWDecoding( bool aDisableHardwareDecoding) const { -# ifdef MOZ_WIDGET_GTK +# ifdef MOZ_WIDGET_ANDROID +# ifdef FFVPX_VERSION + // We only support decrypt and decode with MediaCodec. + if (mCDM) { + FFMPEG_LOG("CDM requires platform decoder"); + return false; + } +# endif + switch (mCodecID) { + case AV_CODEC_ID_H264: + case AV_CODEC_ID_HEVC: + // We only support decoding H264/HEVC with MediaCodec. + FFMPEG_LOG("Codec %s requires platform decoder", + AVCodecToString(mCodecID)); + return false; + case AV_CODEC_ID_AV1: + // We only support main profile AV1 with MediaCodec. See bug 1967752. + if (!AOMDecoder::IsMainProfile(mInfo.mExtraData)) { + FFMPEG_LOG("Cannot use platfrom decoder AV1 without main profile"); + return true; + } + break; + default: + break; + } +# endif + +# if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_ANDROID) bool supported = false; switch (mCodecID) { case AV_CODEC_ID_H264: @@ -541,10 +568,16 @@ bool FFmpegVideoDecoder<LIBAV_VER>::ShouldDisableHWDecoding( break; } if (!supported) { - FFMPEG_LOG("Codec %s is not accelerated", mLib->avcodec_get_name(mCodecID)); + FFMPEG_LOG("Codec %s is not accelerated", AVCodecToString(mCodecID)); return true; } + if (!XRE_IsRDDProcess()) { + FFMPEG_LOG("Platform decoder works in RDD process only"); + return true; + } +# endif +# ifdef MOZ_WIDGET_GTK bool isHardwareWebRenderUsed = mImageAllocator && (mImageAllocator->GetCompositorBackendType() == layers::LayersBackend::LAYERS_WR) && @@ -553,15 +586,6 @@ bool FFmpegVideoDecoder<LIBAV_VER>::ShouldDisableHWDecoding( FFMPEG_LOG("Hardware WebRender is off, VAAPI is disabled"); return true; } - if (!XRE_IsRDDProcess()) { - FFMPEG_LOG("VA-API works in RDD process only"); - return true; - } -# elif defined(MOZ_WIDGET_ANDROID) - // We only support decoding these with hardware on Android. - if (mCodecID == AV_CODEC_ID_H264 || mCodecID == AV_CODEC_ID_HEVC) { - return false; - } # endif return aDisableHardwareDecoding; } diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoEncoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoEncoder.cpp @@ -317,9 +317,20 @@ bool FFmpegVideoEncoder<LIBAV_VER>::SvcEnabled() const { return mConfig.mScalabilityMode != ScalabilityMode::None; } +bool FFmpegVideoEncoder<LIBAV_VER>::ShouldTryHardware() const { +#ifdef MOZ_WIDGET_ANDROID + // On Android, the MediaCodec encoders are the only ones available to us, + // which may be implemented in hardware or software. + if (mCodecID == AV_CODEC_ID_H264 || mCodecID == AV_CODEC_ID_HEVC) { + return true; + } +#endif + return mConfig.mHardwarePreference != HardwarePreference::RequireSoftware; +} + MediaResult FFmpegVideoEncoder<LIBAV_VER>::InitEncoder() { MediaResult result(NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR); - if (mConfig.mHardwarePreference != HardwarePreference::RequireSoftware) { + if (ShouldTryHardware()) { result = InitEncoderInternal(/* aHardware */ true); } // TODO(aosmond): We should be checking here for RequireHardware, but we fail diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoEncoder.h b/dom/media/platforms/ffmpeg/FFmpegVideoEncoder.h @@ -39,6 +39,7 @@ class FFmpegVideoEncoder<LIBAV_VER> : public FFmpegDataEncoder<LIBAV_VER> { virtual ~FFmpegVideoEncoder() = default; // Methods only called on mTaskQueue. virtual MediaResult InitEncoder() override; + bool ShouldTryHardware() const; MediaResult InitEncoderInternal(bool aHardware); #if LIBAVCODEC_VERSION_MAJOR >= 58 Result<EncodedData, MediaResult> EncodeInputWithModernAPIs( diff --git a/testing/web-platform/meta/webcodecs/video-encoder-h26x-annexb.https.any.js.ini b/testing/web-platform/meta/webcodecs/video-encoder-h26x-annexb.https.any.js.ini @@ -16,7 +16,9 @@ disabled: if (os == "android") or (version == "Ubuntu 18.04"): not implemented [Verify stream compliance h26x annexb] - expected: PRECONDITION_FAILED + expected: + if os == "linux": PASS + PRECONDITION_FAILED [video-encoder-h26x-annexb.https.any.html?h265_annexb_hardware] @@ -28,7 +30,9 @@ [video-encoder-h26x-annexb.https.any.worker.html?h265_annexb_software] [Verify stream compliance h26x annexb] - expected: PRECONDITION_FAILED + expected: + if os == "linux": PASS + PRECONDITION_FAILED [video-encoder-h26x-annexb.https.any.worker.html?h265_annexb_hardware]