diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h @@ -10,17 +10,26 @@ #include "FFmpegLibWrapper.h" #include "FFmpegDataDecoder.h" #include "SimpleMap.h" +#ifdef MOZ_WAYLAND_USE_VAAPI +# include "mozilla/widget/WaylandDMABufSurface.h" +# include +#endif namespace mozilla { #ifdef MOZ_WAYLAND_USE_VAAPI + class VAAPIFrameHolder { public: - VAAPIFrameHolder(FFmpegLibWrapper* aLib, AVBufferRef* aVAAPIDeviceContext, + VAAPIFrameHolder(RefPtr aSurface, + FFmpegLibWrapper* aLib, AVBufferRef* aVAAPIDeviceContext, AVBufferRef* aAVHWFramesContext, AVBufferRef* aHWFrame); ~VAAPIFrameHolder(); + bool IsUsed() { return mSurface->IsGlobalRefSet(); } + private: + RefPtr mSurface; FFmpegLibWrapper* mLib; AVBufferRef* mVAAPIDeviceContext; AVBufferRef* mAVHWFramesContext; @@ -97,6 +106,7 @@ MediaResult CreateImageVAAPI(int64_t aOffset, int64_t aPts, int64_t aDuration, MediaDataDecoder::DecodedData& aResults); + void ReleaseUnusedVAAPIFrames(); #endif /** @@ -112,6 +122,7 @@ AVBufferRef* mVAAPIDeviceContext; const bool mDisableHardwareDecoding; VADisplay mDisplay; + std::list> mFrameHolders; #endif RefPtr mImageAllocator; RefPtr mImageContainer; diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -122,19 +122,30 @@ return AV_PIX_FMT_NONE; } -VAAPIFrameHolder::VAAPIFrameHolder(FFmpegLibWrapper* aLib, +VAAPIFrameHolder::VAAPIFrameHolder(RefPtr aSurface, + FFmpegLibWrapper* aLib, AVBufferRef* aVAAPIDeviceContext, AVBufferRef* aAVHWFramesContext, AVBufferRef* aHWFrame) - : mLib(aLib), + : mSurface(aSurface), + mLib(aLib), mVAAPIDeviceContext(mLib->av_buffer_ref(aVAAPIDeviceContext)), mAVHWFramesContext(mLib->av_buffer_ref(aAVHWFramesContext)), - mHWFrame(mLib->av_buffer_ref(aHWFrame)){}; + mHWFrame(mLib->av_buffer_ref(aHWFrame)) { + FFMPEG_LOG("VAAPIFrameHolder is adding dmabuf surface UID = %d\n", + mSurface->GetUID()); + // Create global refcount object to track mSurface usage over + // processes. + mSurface->GlobalRefCountCreate(); +} VAAPIFrameHolder::~VAAPIFrameHolder() { + FFMPEG_LOG("VAAPIFrameHolder is releasing dmabuf surface UID = %d\n", + mSurface->GetUID()); mLib->av_buffer_unref(&mHWFrame); mLib->av_buffer_unref(&mAVHWFramesContext); mLib->av_buffer_unref(&mVAAPIDeviceContext); + mSurface = nullptr; } AVCodec* FFmpegVideoDecoder::FindVAAPICodec() { @@ -418,6 +428,13 @@ NS_WARNING("FFmpeg h264 decoder failed to allocate frame."); return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__); } + +# ifdef MOZ_WAYLAND_USE_VAAPI + if (mVAAPIDeviceContext) { + ReleaseUnusedVAAPIFrames(); + } +# endif + res = mLib->avcodec_receive_frame(mCodecContext, mFrame); if (res == int(AVERROR_EOF)) { return NS_ERROR_DOM_MEDIA_END_OF_STREAM; @@ -624,9 +641,16 @@ } #ifdef MOZ_WAYLAND_USE_VAAPI -static void VAAPIFrameReleaseCallback(VAAPIFrameHolder* aVAAPIFrameHolder) { - auto frameHolder = static_cast(aVAAPIFrameHolder); - delete frameHolder; +void FFmpegVideoDecoder::ReleaseUnusedVAAPIFrames() { + std::list>::iterator holder = + mFrameHolders.begin(); + while (holder != mFrameHolders.end()) { + if (!(*holder)->IsUsed()) { + holder = mFrameHolders.erase(holder); + } else { + holder++; + } + } } MediaResult FFmpegVideoDecoder::CreateImageVAAPI( @@ -663,20 +687,28 @@ RESULT_DETAIL("Unable to allocate WaylandDMABufSurfaceNV12.")); } +# ifdef MOZ_LOGGING + static int uid = 0; + surface->SetUID(++uid); + FFMPEG_LOG("Created dmabuf UID = %d HW surface %x\n", uid, surface_id); +# endif + surface->SetYUVColorSpace(GetFrameColorSpace()); // mFrame->buf[0] is a reference to H264 VASurface for this mFrame. - // We need create WaylandDMABUFSurfaceImage on top of it, + // We need create WaylandDMABUFSurface on top of it, // create EGLImage/Texture on top of it and render it by GL. // FFmpeg tends to reuse the particual VASurface for another frame // even when the mFrame is not released. To keep VASurface as is - // we explicitly reference it and keep until WaylandDMABUFSurfaceImage - // is live. - RefPtr im = new layers::WaylandDMABUFSurfaceImage( - surface, VAAPIFrameReleaseCallback, - new VAAPIFrameHolder(mLib, mVAAPIDeviceContext, - mCodecContext->hw_frames_ctx, mFrame->buf[0])); + // we explicitly reference it and keep until there's any reference to + // attached WaylandDMABUFSurface. + auto holder = MakeUnique(surface, mLib, mVAAPIDeviceContext, + mCodecContext->hw_frames_ctx, + mFrame->buf[0]); + mFrameHolders.push_back(std::move(holder)); + + RefPtr im = new layers::WaylandDMABUFSurfaceImage(surface); RefPtr vp = VideoData::CreateFromImage( mInfo.mDisplay, aOffset, TimeUnit::FromMicroseconds(aPts),