From c7ed87060ffe2ace96a9748a3bb8daf195d03ce5 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 13 Mar 2025 11:07:02 +0000 Subject: [PATCH] Bug 1850615 Share the same libva handle across all FFmpegVideoDecoders a=pascalc Rebased from https://hg.mozilla.org/mozilla-central/rev/b34601c7751d Differential Revision: https://phabricator.services.mozilla.com/D241144 --- .../platforms/ffmpeg/FFmpegLibWrapper.cpp | 70 +-------------- dom/media/platforms/ffmpeg/FFmpegLibWrapper.h | 15 +--- .../platforms/ffmpeg/FFmpegRuntimeLinker.cpp | 4 - .../platforms/ffmpeg/FFmpegVideoDecoder.cpp | 18 ++-- dom/media/platforms/ffmpeg/VALibWrapper.cpp | 90 +++++++++++++++++++ dom/media/platforms/ffmpeg/VALibWrapper.h | 54 +++++++++++ .../ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp | 4 - dom/media/platforms/ffmpeg/moz.build | 1 + 8 files changed, 158 insertions(+), 98 deletions(-) create mode 100644 dom/media/platforms/ffmpeg/VALibWrapper.cpp create mode 100644 dom/media/platforms/ffmpeg/VALibWrapper.h diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp index 8557a1eb1911..06009058579b 100644 --- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp @@ -14,6 +14,7 @@ #ifdef MOZ_WIDGET_GTK # include "mozilla/gfx/gfxVars.h" # include "mozilla/widget/DMABufLibWrapper.h" +# include "VALibWrapper.h" #endif #define AV_LOG_INFO 32 @@ -288,33 +289,6 @@ FFmpegLibWrapper::LinkResult FFmpegLibWrapper::Link() { #undef AV_FUNC #undef AV_FUNC_OPTION -#ifdef MOZ_WIDGET_GTK -# define VA_FUNC_OPTION_SILENT(func) \ - if (!((func) = (decltype(func))PR_FindSymbol(mVALib, #func))) { \ - (func) = (decltype(func))nullptr; \ - } - - // mVALib is optional and may not be present. - if (mVALib) { - VA_FUNC_OPTION_SILENT(vaExportSurfaceHandle) - VA_FUNC_OPTION_SILENT(vaSyncSurface) - VA_FUNC_OPTION_SILENT(vaInitialize) - VA_FUNC_OPTION_SILENT(vaTerminate) - } -# undef VA_FUNC_OPTION_SILENT - -# define VAD_FUNC_OPTION_SILENT(func) \ - if (!((func) = (decltype(func))PR_FindSymbol(mVALibDrm, #func))) { \ - FFMPEGP_LOG("Couldn't load function " #func); \ - } - - // mVALibDrm is optional and may not be present. - if (mVALibDrm) { - VAD_FUNC_OPTION_SILENT(vaGetDisplayDRM) - } -# undef VAD_FUNC_OPTION_SILENT -#endif - if (avcodec_register_all) { avcodec_register_all(); } @@ -350,48 +324,10 @@ void FFmpegLibWrapper::Unlink() { if (mAVCodecLib) { PR_UnloadLibrary(mAVCodecLib); } -#endif -#ifdef MOZ_WIDGET_GTK - if (mVALib) { - PR_UnloadLibrary(mVALib); - } - if (mVALibDrm) { - PR_UnloadLibrary(mVALibDrm); - } #endif PodZero(this); } -#ifdef MOZ_WIDGET_GTK -void FFmpegLibWrapper::LinkVAAPILibs() { - if (!gfx::gfxVars::CanUseHardwareVideoDecoding() || !XRE_IsRDDProcess()) { - return; - } - - PRLibSpec lspec; - lspec.type = PR_LibSpec_Pathname; - const char* libDrm = "libva-drm.so.2"; - lspec.value.pathname = libDrm; - mVALibDrm = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL); - if (!mVALibDrm) { - FFMPEGP_LOG("VA-API support: Missing or old %s library.\n", libDrm); - return; - } - - const char* lib = "libva.so.2"; - lspec.value.pathname = lib; - mVALib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL); - // Don't use libva when it's missing vaExportSurfaceHandle. - if (mVALib && !PR_FindSymbol(mVALib, "vaExportSurfaceHandle")) { - PR_UnloadLibrary(mVALib); - mVALib = nullptr; - } - if (!mVALib) { - FFMPEGP_LOG("VA-API support: Missing or old %s library.\n", lib); - } -} -#endif - #ifdef MOZ_WIDGET_GTK bool FFmpegLibWrapper::IsVAAPIAvailable() { # define VA_FUNC_LOADED(func) ((func) != nullptr) @@ -407,9 +343,7 @@ bool FFmpegLibWrapper::IsVAAPIAvailable() { VA_FUNC_LOADED(av_hwframe_ctx_alloc) && VA_FUNC_LOADED(av_dict_set) && VA_FUNC_LOADED(av_dict_free) && VA_FUNC_LOADED(avcodec_get_name) && VA_FUNC_LOADED(av_get_pix_fmt_string) && - VA_FUNC_LOADED(vaExportSurfaceHandle) && - VA_FUNC_LOADED(vaSyncSurface) && VA_FUNC_LOADED(vaInitialize) && - VA_FUNC_LOADED(vaTerminate) && VA_FUNC_LOADED(vaGetDisplayDRM); + VALibWrapper::IsVAAPIAvailable(); } #endif diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h index d3b1be90f337..4421b4221e42 100644 --- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h +++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h @@ -77,7 +77,7 @@ struct MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS FFmpegLibWrapper { return "Unknown"; } - // Examine mAVCodecLib, mAVUtilLib and mVALib, and attempt to resolve + // Examine mAVCodecLib and mAVUtilLib, and attempt to resolve // all symbols. // Upon failure, the entire object will be reset and any attached libraries // will be unlinked. @@ -87,9 +87,8 @@ struct MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS FFmpegLibWrapper { void Unlink(); #ifdef MOZ_WIDGET_GTK - // Check if mVALib are available and we can use HW decode. + // Check if libva and libva-drm are available and we can use HW decode. bool IsVAAPIAvailable(); - void LinkVAAPILibs(); #endif // indicate the version of libavcodec linked to. @@ -210,12 +209,6 @@ struct MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS FFmpegLibWrapper { AVBufferRef* (*av_hwframe_ctx_alloc)(AVBufferRef* device_ctx); const char* (*avcodec_get_name)(int id); char* (*av_get_pix_fmt_string)(char* buf, int buf_size, int pix_fmt); - - int (*vaExportSurfaceHandle)(void*, unsigned int, uint32_t, uint32_t, void*); - int (*vaSyncSurface)(void*, unsigned int); - int (*vaInitialize)(void* dpy, int* major_version, int* minor_version); - int (*vaTerminate)(void* dpy); - void* (*vaGetDisplayDRM)(int fd); #endif // Only ever used with ffvpx @@ -224,10 +217,6 @@ struct MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS FFmpegLibWrapper { PRLibrary* mAVCodecLib; PRLibrary* mAVUtilLib; -#ifdef MOZ_WIDGET_GTK - PRLibrary* mVALib; - PRLibrary* mVALibDrm; -#endif }; } // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp index 81eb2c0441ac..dfdfe32b8ba5 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp @@ -68,10 +68,6 @@ bool FFmpegRuntimeLinker::Init() { return sLinkStatus == LinkStatus_SUCCEEDED; } -#ifdef MOZ_WIDGET_GTK - sLibAV.LinkVAAPILibs(); -#endif - // While going through all possible libs, this status will be updated with a // more precise error if possible. sLinkStatus = LinkStatus_NOT_FOUND; diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp index ff0f50c9d8f4..1c7e75abc69c 100644 --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -11,6 +11,7 @@ #include "ImageContainer.h" #include "MP4Decoder.h" #include "MediaInfo.h" +#include "VALibWrapper.h" #include "VideoUtils.h" #include "VPXDecoder.h" #include "mozilla/layers/KnowsCompositor.h" @@ -213,15 +214,14 @@ class VAAPIDisplayHolder; template <> class VAAPIDisplayHolder { public: - VAAPIDisplayHolder(FFmpegLibWrapper* aLib, VADisplay aDisplay, int aDRMFd) - : mLib(aLib), mDisplay(aDisplay), mDRMFd(aDRMFd) {}; + VAAPIDisplayHolder(VADisplay aDisplay, int aDRMFd) + : mDisplay(aDisplay), mDRMFd(aDRMFd) {}; ~VAAPIDisplayHolder() { - mLib->vaTerminate(mDisplay); + VALibWrapper::sFuncs.vaTerminate(mDisplay); close(mDRMFd); } private: - FFmpegLibWrapper* mLib; VADisplay mDisplay; int mDRMFd; }; @@ -246,17 +246,17 @@ bool FFmpegVideoDecoder::CreateVAAPIDeviceContext() { AVVAAPIDeviceContext* vactx = (AVVAAPIDeviceContext*)hwctx->hwctx; int drmFd = widget::GetDMABufDevice()->OpenDRMFd(); - mDisplay = mLib->vaGetDisplayDRM(drmFd); + mDisplay = VALibWrapper::sFuncs.vaGetDisplayDRM(drmFd); if (!mDisplay) { FFMPEG_LOG(" Can't get DRM VA-API display."); return false; } - hwctx->user_opaque = new VAAPIDisplayHolder(mLib, mDisplay, drmFd); + hwctx->user_opaque = new VAAPIDisplayHolder(mDisplay, drmFd); hwctx->free = VAAPIDisplayReleaseCallback; int major, minor; - int status = mLib->vaInitialize(mDisplay, &major, &minor); + int status = VALibWrapper::sFuncs.vaInitialize(mDisplay, &major, &minor); if (status != VA_STATUS_SUCCESS) { FFMPEG_LOG(" vaInitialize failed."); return false; @@ -1516,13 +1516,13 @@ MediaResult FFmpegVideoDecoder::CreateImage( bool FFmpegVideoDecoder::GetVAAPISurfaceDescriptor( VADRMPRIMESurfaceDescriptor* aVaDesc) { VASurfaceID surface_id = (VASurfaceID)(uintptr_t)mFrame->data[3]; - VAStatus vas = mLib->vaExportSurfaceHandle( + VAStatus vas = VALibWrapper::sFuncs.vaExportSurfaceHandle( mDisplay, surface_id, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS, aVaDesc); if (vas != VA_STATUS_SUCCESS) { return false; } - vas = mLib->vaSyncSurface(mDisplay, surface_id); + vas = VALibWrapper::sFuncs.vaSyncSurface(mDisplay, surface_id); if (vas != VA_STATUS_SUCCESS) { NS_WARNING("vaSyncSurface() failed."); } diff --git a/dom/media/platforms/ffmpeg/VALibWrapper.cpp b/dom/media/platforms/ffmpeg/VALibWrapper.cpp new file mode 100644 index 000000000000..b3870f2d81a0 --- /dev/null +++ b/dom/media/platforms/ffmpeg/VALibWrapper.cpp @@ -0,0 +1,90 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "VALibWrapper.h" + +#include "FFmpegLog.h" +#include "PlatformDecoderModule.h" +#include "prlink.h" +#include "mozilla/gfx/gfxVars.h" + +namespace mozilla { + +VALibWrapper VALibWrapper::sFuncs; + +void VALibWrapper::Link() { +#define VA_FUNC_OPTION_SILENT(func) \ + if (!((func) = (decltype(func))PR_FindSymbol(mVALib, #func))) { \ + (func) = (decltype(func))nullptr; \ + } + + // mVALib is optional and may not be present. + if (mVALib) { + VA_FUNC_OPTION_SILENT(vaExportSurfaceHandle) + VA_FUNC_OPTION_SILENT(vaSyncSurface) + VA_FUNC_OPTION_SILENT(vaInitialize) + VA_FUNC_OPTION_SILENT(vaTerminate) + } +#undef VA_FUNC_OPTION_SILENT + +#define VAD_FUNC_OPTION_SILENT(func) \ + if (!((func) = (decltype(func))PR_FindSymbol(mVALibDrm, #func))) { \ + FFMPEGP_LOG("Couldn't load function " #func); \ + } + + // mVALibDrm is optional and may not be present. + if (mVALibDrm) { + VAD_FUNC_OPTION_SILENT(vaGetDisplayDRM) + } +#undef VAD_FUNC_OPTION_SILENT +} + +bool VALibWrapper::LinkVAAPILibs() { + if (!gfx::gfxVars::CanUseHardwareVideoDecoding() || !XRE_IsRDDProcess()) { + return false; + } + + PRLibSpec lspec; + lspec.type = PR_LibSpec_Pathname; + const char* libDrm = "libva-drm.so.2"; + lspec.value.pathname = libDrm; + mVALibDrm = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL); + if (!mVALibDrm) { + FFMPEGP_LOG("VA-API support: Missing or old %s library.\n", libDrm); + return false; + } + + const char* lib = "libva.so.2"; + lspec.value.pathname = lib; + mVALib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL); + // Don't use libva when it's missing vaExportSurfaceHandle. + if (mVALib && !PR_FindSymbol(mVALib, "vaExportSurfaceHandle")) { + PR_UnloadLibrary(mVALib); + mVALib = nullptr; + } + if (!mVALib) { + FFMPEGP_LOG("VA-API support: Missing or old %s library.\n", lib); + return false; + } + + Link(); + return true; +} + +bool VALibWrapper::AreVAAPIFuncsAvailable() { +#define VA_FUNC_LOADED(func) ((func) != nullptr) + return VA_FUNC_LOADED(vaExportSurfaceHandle) && + VA_FUNC_LOADED(vaSyncSurface) && VA_FUNC_LOADED(vaInitialize) && + VA_FUNC_LOADED(vaTerminate) && VA_FUNC_LOADED(vaGetDisplayDRM); +} + +/* static */ +bool VALibWrapper::IsVAAPIAvailable() { + static bool once = sFuncs.LinkVAAPILibs(); + (void)once; + + return sFuncs.AreVAAPIFuncsAvailable(); +} + +} // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/VALibWrapper.h b/dom/media/platforms/ffmpeg/VALibWrapper.h new file mode 100644 index 000000000000..20f1c9d74c4d --- /dev/null +++ b/dom/media/platforms/ffmpeg/VALibWrapper.h @@ -0,0 +1,54 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_MEDIA_PLATFORMS_FFMPEG_VALIBWRAPPER_H_ +#define DOM_MEDIA_PLATFORMS_FFMPEG_VALIBWRAPPER_H_ + +#include "mozilla/Attributes.h" +#include "mozilla/Types.h" + +struct PRLibrary; + +#ifdef MOZ_WIDGET_GTK +namespace mozilla { + +class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS VALibWrapper { + public: + // The class is used only in static storage and so is zero initialized. + VALibWrapper() = default; + // The libraries are not unloaded in the destructor, because doing so would + // require a static constructor to register the static destructor. As the + // class is in static storage, the destructor would only run on shutdown + // anyway. + ~VALibWrapper() = default; + + // Check if sVALib and sVALibDrm are available with necessary symbols and + // initialize sFuncs; + static bool IsVAAPIAvailable(); + static VALibWrapper sFuncs; + + private: + void Link(); + bool AreVAAPIFuncsAvailable(); + // Attempt to load libva-drm and libva and resolve necessary symbols. + // Upon failure, the entire object will be reset and any attached libraries + // will be unlinked. Do not invoke more than once. + bool LinkVAAPILibs(); + + public: + int (*vaExportSurfaceHandle)(void*, unsigned int, uint32_t, uint32_t, void*); + int (*vaSyncSurface)(void*, unsigned int); + int (*vaInitialize)(void* dpy, int* major_version, int* minor_version); + int (*vaTerminate)(void* dpy); + void* (*vaGetDisplayDRM)(int fd); + + private: + PRLibrary* mVALib; + PRLibrary* mVALibDrm; +}; + +} // namespace mozilla +#endif // MOZ_WIDGET_GTK + +#endif // DOM_MEDIA_PLATFORMS_FFMPEG_VALIBWRAPPER_H_ diff --git a/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp b/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp index c0a6e01f9892..ad52a37385a1 100644 --- a/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp +++ b/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp @@ -76,10 +76,6 @@ bool FFVPXRuntimeLinker::Init() { sLinkStatus = LinkStatus_FAILED; -#ifdef MOZ_WIDGET_GTK - sFFVPXLib.LinkVAAPILibs(); -#endif - #ifdef XP_WIN PathString path = GetLibraryFilePathname(LXUL_DLL, (PRFuncPtr)&FFVPXRuntimeLinker::Init); diff --git a/dom/media/platforms/ffmpeg/moz.build b/dom/media/platforms/ffmpeg/moz.build index ce7c06b9a64e..07e9dde13511 100644 --- a/dom/media/platforms/ffmpeg/moz.build +++ b/dom/media/platforms/ffmpeg/moz.build @@ -23,6 +23,7 @@ UNIFIED_SOURCES += ["FFmpegRuntimeLinker.cpp"] if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": include("/ipc/chromium/chromium-config.mozbuild") + UNIFIED_SOURCES += ["VALibWrapper.cpp"] LOCAL_INCLUDES += [ "/media/libyuv/libyuv/include",