diff --git a/app/streaming/video/ffmpeg-renderers/eglvid.cpp b/app/streaming/video/ffmpeg-renderers/eglvid.cpp index 76c1e8d0..34df1cba 100644 --- a/app/streaming/video/ffmpeg-renderers/eglvid.cpp +++ b/app/streaming/video/ffmpeg-renderers/eglvid.cpp @@ -74,6 +74,7 @@ EGLRenderer::EGLRenderer(IFFmpegRenderer *backendRenderer) m_ColorSpace(AVCOL_SPC_NB), m_ColorFull(false), m_BlockingSwapBuffers(false), + m_LastFrame(av_frame_alloc()), m_glEGLImageTargetTexture2DOES(nullptr), m_glGenVertexArraysOES(nullptr), m_glBindVertexArrayOES(nullptr), @@ -124,6 +125,8 @@ EGLRenderer::~EGLRenderer() SDL_DestroyRenderer(m_DummyRenderer); } + av_frame_free(&m_LastFrame); + // Reset the global properties back to what they were before SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "0"); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, m_OldContextProfileMask); @@ -803,4 +806,12 @@ void EGLRenderer::renderFrame(AVFrame* frame) } m_Backend->freeEGLImages(m_EGLDisplay, imgs); + + // Free the DMA-BUF backing the last frame now that it is definitely + // no longer being used anymore. While the PRIME FD stays around until + // EGL is done with it, the memory backing it may be reused by FFmpeg + // before the GPU has read it. This is particularly noticeable on the + // RK3288-based TinkerBoard when V-Sync is disabled. + av_frame_unref(m_LastFrame); + av_frame_move_ref(m_LastFrame, frame); } diff --git a/app/streaming/video/ffmpeg-renderers/eglvid.h b/app/streaming/video/ffmpeg-renderers/eglvid.h index 70e16507..1cce8350 100644 --- a/app/streaming/video/ffmpeg-renderers/eglvid.h +++ b/app/streaming/video/ffmpeg-renderers/eglvid.h @@ -45,6 +45,7 @@ private: int m_ColorSpace; bool m_ColorFull; bool m_BlockingSwapBuffers; + AVFrame* m_LastFrame; PFNGLEGLIMAGETARGETTEXTURE2DOESPROC m_glEGLImageTargetTexture2DOES; PFNGLGENVERTEXARRAYSOESPROC m_glGenVertexArraysOES; PFNGLBINDVERTEXARRAYOESPROC m_glBindVertexArrayOES;