Fix handling of preferred/compatible pixel formats with EGLRenderer and VAAPI/DRM backends

This commit is contained in:
Cameron Gutman 2021-02-04 19:39:18 -06:00
parent 76e81fa651
commit c3895f06c0
7 changed files with 47 additions and 42 deletions

View File

@ -386,6 +386,10 @@ bool DrmRenderer::canExportEGL() {
return true; return true;
} }
AVPixelFormat DrmRenderer::getEGLImagePixelFormat() {
return AV_PIX_FMT_NV12;
}
bool DrmRenderer::initializeEGL(EGLDisplay, bool DrmRenderer::initializeEGL(EGLDisplay,
const EGLExtensions &ext) { const EGLExtensions &ext) {
if (!ext.isSupported("EGL_EXT_image_dma_buf_import")) { if (!ext.isSupported("EGL_EXT_image_dma_buf_import")) {

View File

@ -18,6 +18,7 @@ public:
virtual bool isDirectRenderingSupported() override; virtual bool isDirectRenderingSupported() override;
#ifdef HAVE_EGL #ifdef HAVE_EGL
virtual bool canExportEGL() override; virtual bool canExportEGL() override;
virtual AVPixelFormat getEGLImagePixelFormat() override;
virtual bool initializeEGL(EGLDisplay dpy, const EGLExtensions &ext) override; virtual bool initializeEGL(EGLDisplay dpy, const EGLExtensions &ext) override;
virtual ssize_t exportEGLImages(AVFrame *frame, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) override; virtual ssize_t exportEGLImages(AVFrame *frame, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) override;
virtual void freeEGLImages(EGLDisplay dpy, EGLImage[EGL_MAX_PLANES]) override; virtual void freeEGLImages(EGLDisplay dpy, EGLImage[EGL_MAX_PLANES]) override;

View File

@ -59,7 +59,7 @@ SDL_Window* EGLRenderer::s_LastFailedWindow = nullptr;
EGLRenderer::EGLRenderer(IFFmpegRenderer *backendRenderer) EGLRenderer::EGLRenderer(IFFmpegRenderer *backendRenderer)
: :
m_SwPixelFormat(AV_PIX_FMT_NONE), m_EGLImagePixelFormat(AV_PIX_FMT_NONE),
m_EGLDisplay(EGL_NO_DISPLAY), m_EGLDisplay(EGL_NO_DISPLAY),
m_Textures{0}, m_Textures{0},
m_OverlayTextures{0}, m_OverlayTextures{0},
@ -153,16 +153,16 @@ void EGLRenderer::notifyOverlayUpdated(Overlay::OverlayType type)
} }
} }
bool EGLRenderer::isPixelFormatSupported(int, AVPixelFormat pixelFormat) bool EGLRenderer::isPixelFormatSupported(int videoFormat, AVPixelFormat pixelFormat)
{ {
// Remember to keep this in sync with EGLRenderer::renderFrame()! // Pixel format support should be determined by the backend renderer
switch (pixelFormat) return m_Backend->isPixelFormatSupported(videoFormat, pixelFormat);
{ }
case AV_PIX_FMT_NV12:
return true; AVPixelFormat EGLRenderer::getPreferredPixelFormat(int videoFormat)
default: {
return false; // Pixel format preference should be determined by the backend renderer
} return m_Backend->getPreferredPixelFormat(videoFormat);
} }
void EGLRenderer::renderOverlay(Overlay::OverlayType type) void EGLRenderer::renderOverlay(Overlay::OverlayType type)
@ -367,10 +367,10 @@ bool EGLRenderer::compileShaders() {
SDL_assert(!m_ShaderProgram); SDL_assert(!m_ShaderProgram);
SDL_assert(!m_OverlayShaderProgram); SDL_assert(!m_OverlayShaderProgram);
SDL_assert(m_SwPixelFormat != AV_PIX_FMT_NONE); SDL_assert(m_EGLImagePixelFormat != AV_PIX_FMT_NONE);
// XXX: TODO: other formats // XXX: TODO: other formats
SDL_assert(m_SwPixelFormat == AV_PIX_FMT_NV12); SDL_assert(m_EGLImagePixelFormat == AV_PIX_FMT_NV12);
m_ShaderProgram = compileShader("egl.vert", "egl.frag"); m_ShaderProgram = compileShader("egl.vert", "egl.frag");
if (!m_ShaderProgram) { if (!m_ShaderProgram) {
@ -721,23 +721,18 @@ void EGLRenderer::renderFrame(AVFrame* frame)
return; return;
} }
if (frame->hw_frames_ctx != nullptr) { // Find the native read-back format and load the shaders
// Find the native read-back format and load the shader if (m_EGLImagePixelFormat == AV_PIX_FMT_NONE) {
if (m_SwPixelFormat == AV_PIX_FMT_NONE) { m_EGLImagePixelFormat = m_Backend->getEGLImagePixelFormat();
auto hwFrameCtx = (AVHWFramesContext*)frame->hw_frames_ctx->data; EGL_LOG(Info, "EGLImage pixel format: %d", m_EGLImagePixelFormat);
m_SwPixelFormat = hwFrameCtx->sw_format; SDL_assert(m_EGLImagePixelFormat != AV_PIX_FMT_NONE);
SDL_assert(m_SwPixelFormat != AV_PIX_FMT_NONE);
EGL_LOG(Info, "Selected read-back format: %d", m_SwPixelFormat);
// XXX: TODO: Handle other pixel formats
SDL_assert(m_SwPixelFormat == AV_PIX_FMT_NV12);
m_ColorSpace = frame->colorspace; m_ColorSpace = frame->colorspace;
m_ColorFull = frame->color_range == AVCOL_RANGE_JPEG; m_ColorFull = frame->color_range == AVCOL_RANGE_JPEG;
if (!specialize()) { if (!specialize()) {
m_SwPixelFormat = AV_PIX_FMT_NONE; m_EGLImagePixelFormat = AV_PIX_FMT_NONE;
return; return;
} }
} }
@ -750,11 +745,6 @@ void EGLRenderer::renderFrame(AVFrame* frame)
glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_Textures[i]); glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_Textures[i]);
m_glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, imgs[i]); m_glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, imgs[i]);
} }
} else {
// TODO: load texture for SW decoding ?
EGL_LOG(Error, "EGL rendering only supports hw frames");
return;
}
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(m_ShaderProgram); glUseProgram(m_ShaderProgram);

View File

@ -14,6 +14,7 @@ public:
virtual void renderFrame(AVFrame* frame) override; virtual void renderFrame(AVFrame* frame) override;
virtual void notifyOverlayUpdated(Overlay::OverlayType) override; virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
virtual bool isPixelFormatSupported(int videoFormat, enum AVPixelFormat pixelFormat) override; virtual bool isPixelFormatSupported(int videoFormat, enum AVPixelFormat pixelFormat) override;
virtual AVPixelFormat getPreferredPixelFormat(int videoFormat) override;
private: private:
@ -29,7 +30,7 @@ private:
int m_ViewportWidth; int m_ViewportWidth;
int m_ViewportHeight; int m_ViewportHeight;
int m_SwPixelFormat; AVPixelFormat m_EGLImagePixelFormat;
void *m_EGLDisplay; void *m_EGLDisplay;
unsigned m_Textures[EGL_MAX_PLANES]; unsigned m_Textures[EGL_MAX_PLANES];
unsigned m_OverlayTextures[Overlay::OverlayMax]; unsigned m_OverlayTextures[Overlay::OverlayMax];

View File

@ -101,7 +101,7 @@ public:
return true; return true;
} }
virtual enum AVPixelFormat getPreferredPixelFormat(int videoFormat) { virtual AVPixelFormat getPreferredPixelFormat(int videoFormat) {
if (videoFormat == VIDEO_FORMAT_H265_MAIN10) { if (videoFormat == VIDEO_FORMAT_H265_MAIN10) {
// 10-bit YUV 4:2:0 // 10-bit YUV 4:2:0
return AV_PIX_FMT_P010; return AV_PIX_FMT_P010;
@ -112,7 +112,7 @@ public:
} }
} }
virtual bool isPixelFormatSupported(int videoFormat, enum AVPixelFormat pixelFormat) { virtual bool isPixelFormatSupported(int videoFormat, AVPixelFormat pixelFormat) {
// By default, we only support the preferred pixel format // By default, we only support the preferred pixel format
return getPreferredPixelFormat(videoFormat) == pixelFormat; return getPreferredPixelFormat(videoFormat) == pixelFormat;
} }
@ -128,6 +128,10 @@ public:
return false; return false;
} }
virtual AVPixelFormat getEGLImagePixelFormat() {
return AV_PIX_FMT_NONE;
}
virtual bool initializeEGL(EGLDisplay, virtual bool initializeEGL(EGLDisplay,
const EGLExtensions &) { const EGLExtensions &) {
return false; return false;

View File

@ -483,6 +483,10 @@ VAAPIRenderer::canExportEGL() {
return true; return true;
} }
AVPixelFormat VAAPIRenderer::getEGLImagePixelFormat() {
return AV_PIX_FMT_NV12;
}
bool bool
VAAPIRenderer::initializeEGL(EGLDisplay, VAAPIRenderer::initializeEGL(EGLDisplay,
const EGLExtensions &ext) { const EGLExtensions &ext) {

View File

@ -44,6 +44,7 @@ public:
virtual int getDecoderColorspace() override; virtual int getDecoderColorspace() override;
#ifdef HAVE_EGL #ifdef HAVE_EGL
virtual bool canExportEGL() override; virtual bool canExportEGL() override;
virtual AVPixelFormat getEGLImagePixelFormat() override;
virtual bool initializeEGL(EGLDisplay dpy, const EGLExtensions &ext) override; virtual bool initializeEGL(EGLDisplay dpy, const EGLExtensions &ext) override;
virtual ssize_t exportEGLImages(AVFrame *frame, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) override; virtual ssize_t exportEGLImages(AVFrame *frame, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) override;
virtual void freeEGLImages(EGLDisplay dpy, EGLImage[EGL_MAX_PLANES]) override; virtual void freeEGLImages(EGLDisplay dpy, EGLImage[EGL_MAX_PLANES]) override;