/* 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" #include "mozilla/widget/DMABufDevice.h" namespace mozilla { VALibWrapper VALibWrapper::sFuncs; static int (*vaInitialize)(void* dpy, int* major_version, int* minor_version); static int (*vaTerminate)(void* dpy); static void* (*vaGetDisplayDRM)(int fd); static VADisplayHolder* sDisplayHolder; static StaticMutex sDisplayHolderMutex; 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(); } VADisplayHolder::VADisplayHolder(UniqueVADisplay aDisplay, UniqueFileHandle aDRMFd) : mDRMFd(std::move(aDRMFd)), mDisplay(std::move(aDisplay)) {}; VADisplayHolder::~VADisplayHolder() = default; /* static */ RefPtr VADisplayHolder::GetSingleton() { StaticMutexAutoLock lock(sDisplayHolderMutex); if (sDisplayHolder) { return RefPtr{sDisplayHolder}; } UniqueFileHandle drmFd{widget::GetDMABufDevice()->OpenDRMFd()}; UniqueVADisplay display{vaGetDisplayDRM(drmFd.get())}; if (!display) { FFMPEGP_LOG(" Can't get DRM VA-API display."); return nullptr; } int major, minor; VAStatus status = vaInitialize(display.get(), &major, &minor); if (status != VA_STATUS_SUCCESS) { FFMPEGP_LOG(" vaInitialize failed."); // |display| is destroyed while sDisplayHolderMutex is still held, to // vaTerminate() before another VADisplay might be accessed. // See Bug 1850615. return nullptr; } RefPtr displayHolder = new VADisplayHolder(std::move(display), std::move(drmFd)); sDisplayHolder = displayHolder; return displayHolder; } void VADisplayHolder::MaybeDestroy() { StaticMutexAutoLock lock(sDisplayHolderMutex); MOZ_ASSERT(int32_t(mRefCnt) >= 0, "dup release"); if (mRefCnt == 0) { // No new reference added before the lock was taken. sDisplayHolder = nullptr; delete this; } } void VADisplayHolder::VADisplayDeleter::operator()(VADisplay aDisplay) { vaTerminate(aDisplay); } } // namespace mozilla