diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp index 1c7e75abc69c..72d712b22045 100644 --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -25,7 +25,6 @@ # include "H264.h" # include "mozilla/gfx/gfxVars.h" # include "mozilla/layers/DMABUFSurfaceImage.h" -# include "mozilla/widget/DMABufLibWrapper.h" # include "FFmpegVideoFramePool.h" # include "va/va.h" #endif @@ -66,13 +65,6 @@ # include "mozilla/gfx/gfxVars.h" #endif -// Forward declare from va.h -#ifdef MOZ_USE_HWDECODE -typedef int VAStatus; -# define VA_EXPORT_SURFACE_READ_ONLY 0x0001 -# define VA_EXPORT_SURFACE_SEPARATE_LAYERS 0x0004 -# define VA_STATUS_SUCCESS 0x00000000 -#endif // Use some extra HW frames for potential rendering lags. #define EXTRA_HW_FRAMES 6 @@ -205,31 +197,9 @@ AVCodec* FFmpegVideoDecoder::FindVAAPICodec() { return nullptr; } -template -class VAAPIDisplayHolder {}; - -template <> -class VAAPIDisplayHolder; - -template <> -class VAAPIDisplayHolder { - public: - VAAPIDisplayHolder(VADisplay aDisplay, int aDRMFd) - : mDisplay(aDisplay), mDRMFd(aDRMFd) {}; - ~VAAPIDisplayHolder() { - VALibWrapper::sFuncs.vaTerminate(mDisplay); - close(mDRMFd); - } - - private: - VADisplay mDisplay; - int mDRMFd; -}; - static void VAAPIDisplayReleaseCallback(struct AVHWDeviceContext* hwctx) { - auto displayHolder = - static_cast*>(hwctx->user_opaque); - delete displayHolder; + auto displayHolder = static_cast(hwctx->user_opaque); + displayHolder->Release(); } bool FFmpegVideoDecoder::CreateVAAPIDeviceContext() { @@ -245,23 +215,15 @@ bool FFmpegVideoDecoder::CreateVAAPIDeviceContext() { AVHWDeviceContext* hwctx = (AVHWDeviceContext*)mVAAPIDeviceContext->data; AVVAAPIDeviceContext* vactx = (AVVAAPIDeviceContext*)hwctx->hwctx; - int drmFd = widget::GetDMABufDevice()->OpenDRMFd(); - mDisplay = VALibWrapper::sFuncs.vaGetDisplayDRM(drmFd); - if (!mDisplay) { - FFMPEG_LOG(" Can't get DRM VA-API display."); + RefPtr displayHolder = VADisplayHolder::GetSingleton(); + if (!displayHolder) { return false; } - hwctx->user_opaque = new VAAPIDisplayHolder(mDisplay, drmFd); + mDisplay = displayHolder->mDisplay; + hwctx->user_opaque = displayHolder.forget().take(); hwctx->free = VAAPIDisplayReleaseCallback; - int major, minor; - int status = VALibWrapper::sFuncs.vaInitialize(mDisplay, &major, &minor); - if (status != VA_STATUS_SUCCESS) { - FFMPEG_LOG(" vaInitialize failed."); - return false; - } - vactx->display = mDisplay; if (mLib->av_hwdevice_ctx_init(mVAAPIDeviceContext) < 0) { FFMPEG_LOG(" av_hwdevice_ctx_init failed."); diff --git a/dom/media/platforms/ffmpeg/VALibWrapper.cpp b/dom/media/platforms/ffmpeg/VALibWrapper.cpp index b3870f2d81a0..c64f753e674b 100644 --- a/dom/media/platforms/ffmpeg/VALibWrapper.cpp +++ b/dom/media/platforms/ffmpeg/VALibWrapper.cpp @@ -8,10 +8,17 @@ #include "PlatformDecoderModule.h" #include "prlink.h" #include "mozilla/gfx/gfxVars.h" +#include "mozilla/widget/DMABufLibWrapper.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) \ @@ -87,4 +94,48 @@ bool VALibWrapper::IsVAAPIAvailable() { return sFuncs.AreVAAPIFuncsAvailable(); } +/* static */ +RefPtr VADisplayHolder::GetSingleton() { + StaticMutexAutoLock lock(sDisplayHolderMutex); + + if (sDisplayHolder) { + return RefPtr{sDisplayHolder}; + } + + int drmFd = widget::GetDMABufDevice()->OpenDRMFd(); + VADisplay display = vaGetDisplayDRM(drmFd); + if (!display) { + FFMPEGP_LOG(" Can't get DRM VA-API display."); + return nullptr; + } + + RefPtr displayHolder = new VADisplayHolder(display, drmFd); + + int major, minor; + VAStatus status = vaInitialize(display, &major, &minor); + if (status != VA_STATUS_SUCCESS) { + FFMPEGP_LOG(" vaInitialize failed."); + return nullptr; + } + + 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; + } +} + +VADisplayHolder::~VADisplayHolder() { + vaTerminate(mDisplay); + close(mDRMFd); +} + } // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/VALibWrapper.h b/dom/media/platforms/ffmpeg/VALibWrapper.h index 20f1c9d74c4d..531f35578cf0 100644 --- a/dom/media/platforms/ffmpeg/VALibWrapper.h +++ b/dom/media/platforms/ffmpeg/VALibWrapper.h @@ -7,10 +7,19 @@ #include "mozilla/Attributes.h" #include "mozilla/Types.h" +#include "nsISupportsImpl.h" struct PRLibrary; #ifdef MOZ_WIDGET_GTK + +// Forward declare from va.h +typedef void* VADisplay; +typedef int VAStatus; +# define VA_EXPORT_SURFACE_READ_ONLY 0x0001 +# define VA_EXPORT_SURFACE_SEPARATE_LAYERS 0x0004 +# define VA_STATUS_SUCCESS 0x00000000 + namespace mozilla { class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS VALibWrapper { @@ -39,15 +48,31 @@ class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS VALibWrapper { 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; }; +class VADisplayHolder { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(VADisplayHolder, + MaybeDestroy()) + + static RefPtr GetSingleton(); + + const VADisplay mDisplay; + + private: + VADisplayHolder(VADisplay aDisplay, int aDRMFd) + : mDisplay(aDisplay), mDRMFd(aDRMFd) {}; + ~VADisplayHolder(); + + void MaybeDestroy(); + + const int mDRMFd; +}; + } // namespace mozilla #endif // MOZ_WIDGET_GTK