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
This commit is contained in:
Karl Tomlinson 2025-03-13 11:07:02 +00:00
parent 24846b1e35
commit c7ed87060f
8 changed files with 158 additions and 98 deletions

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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<LIBAV_VER>;
template <>
class VAAPIDisplayHolder<LIBAV_VER> {
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<LIBAV_VER>::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<LIBAV_VER>(mLib, mDisplay, drmFd);
hwctx->user_opaque = new VAAPIDisplayHolder<LIBAV_VER>(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<LIBAV_VER>::CreateImage(
bool FFmpegVideoDecoder<LIBAV_VER>::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.");
}

View file

@ -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

View file

@ -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_

View file

@ -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);

View file

@ -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",