Add support for rendering NV12 hwframes with SDL

This commit is contained in:
Cameron Gutman 2019-04-19 22:16:06 -07:00
parent d65e29111f
commit 5c8a1e632b
2 changed files with 90 additions and 22 deletions

View File

@ -7,9 +7,15 @@
#include <Limelight.h> #include <Limelight.h>
const std::vector<int> SdlRenderer::k_SwFormats({
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NV12
});
SdlRenderer::SdlRenderer() SdlRenderer::SdlRenderer()
: m_Renderer(nullptr), : m_Renderer(nullptr),
m_Texture(nullptr), m_Texture(nullptr),
m_SwPixelFormat(AV_PIX_FMT_YUV420P),
m_FontData(Path::readDataFile("ModeSeven.ttf")) m_FontData(Path::readDataFile("ModeSeven.ttf"))
{ {
SDL_assert(TTF_WasInit() == 0); SDL_assert(TTF_WasInit() == 0);
@ -171,18 +177,6 @@ bool SdlRenderer::initialize(PDECODER_PARAMETERS params)
SDL_RenderClear(m_Renderer); SDL_RenderClear(m_Renderer);
SDL_RenderPresent(m_Renderer); SDL_RenderPresent(m_Renderer);
m_Texture = SDL_CreateTexture(m_Renderer,
SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STREAMING,
params->width,
params->height);
if (!m_Texture) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_CreateRenderer() failed: %s",
SDL_GetError());
return false;
}
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
// For some reason, using Direct3D9Ex breaks this with multi-monitor setups. // For some reason, using Direct3D9Ex breaks this with multi-monitor setups.
// When focus is lost, the window is minimized then immediately restored without // When focus is lost, the window is minimized then immediately restored without
@ -251,24 +245,94 @@ void SdlRenderer::renderFrame(AVFrame* frame)
swFrame->width = frame->width; swFrame->width = frame->width;
swFrame->height = frame->height; swFrame->height = frame->height;
swFrame->format = AV_PIX_FMT_YUV420P; swFrame->format = m_SwPixelFormat;
err = av_hwframe_transfer_data(swFrame, frame, 0); err = av_hwframe_transfer_data(swFrame, frame, 0);
if (err != 0) { if (err != 0) {
av_frame_free(&swFrame); // Try to find a supported format
return; for (int i = 0; i < k_SwFormats.size(); i++) {
swFrame->format = k_SwFormats.at(i);
err = av_hwframe_transfer_data(swFrame, frame, 0);
if (err == 0) {
// The format was supported. Use that automatically in the future.
m_SwPixelFormat = swFrame->format;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Selected read-back format: %d",
m_SwPixelFormat);
break;
}
}
}
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"av_hwframe_transfer_data() failed: %d",
err);
goto Exit;
} }
frame = swFrame; frame = swFrame;
} }
SDL_UpdateYUVTexture(m_Texture, nullptr, if (m_Texture == nullptr) {
frame->data[0], Uint32 sdlFormat;
frame->linesize[0],
frame->data[1], switch (frame->format)
frame->linesize[1], {
frame->data[2], case AV_PIX_FMT_YUV420P:
frame->linesize[2]); sdlFormat = SDL_PIXELFORMAT_YV12;
break;
case AV_PIX_FMT_NV12:
sdlFormat = SDL_PIXELFORMAT_NV12;
break;
default:
SDL_assert(false);
goto Exit;
}
m_Texture = SDL_CreateTexture(m_Renderer,
sdlFormat,
SDL_TEXTUREACCESS_STREAMING,
frame->width,
frame->height);
if (!m_Texture) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_CreateTexture() failed: %s",
SDL_GetError());
goto Exit;
}
}
if (frame->format == AV_PIX_FMT_YUV420P) {
SDL_UpdateYUVTexture(m_Texture, nullptr,
frame->data[0],
frame->linesize[0],
frame->data[1],
frame->linesize[1],
frame->data[2],
frame->linesize[2]);
}
else {
char* pixels;
int pitch;
err = SDL_LockTexture(m_Texture, nullptr, (void**)&pixels, &pitch);
if (err < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_LockTexture() failed: %s",
SDL_GetError());
goto Exit;
}
memcpy(pixels,
frame->data[0],
frame->linesize[0] * frame->height);
memcpy(pixels + (frame->linesize[0] * frame->height),
frame->data[1],
frame->linesize[1] * frame->height / 2);
SDL_UnlockTexture(m_Texture);
}
SDL_RenderClear(m_Renderer); SDL_RenderClear(m_Renderer);
@ -282,6 +346,7 @@ void SdlRenderer::renderFrame(AVFrame* frame)
SDL_RenderPresent(m_Renderer); SDL_RenderPresent(m_Renderer);
Exit:
if (swFrame != nullptr) { if (swFrame != nullptr) {
av_frame_free(&swFrame); av_frame_free(&swFrame);
} }

View File

@ -20,10 +20,13 @@ private:
SDL_Renderer* m_Renderer; SDL_Renderer* m_Renderer;
SDL_Texture* m_Texture; SDL_Texture* m_Texture;
int m_SwPixelFormat;
QByteArray m_FontData; QByteArray m_FontData;
TTF_Font* m_OverlayFonts[Overlay::OverlayMax]; TTF_Font* m_OverlayFonts[Overlay::OverlayMax];
SDL_Surface* m_OverlaySurfaces[Overlay::OverlayMax]; SDL_Surface* m_OverlaySurfaces[Overlay::OverlayMax];
SDL_Texture* m_OverlayTextures[Overlay::OverlayMax]; SDL_Texture* m_OverlayTextures[Overlay::OverlayMax];
SDL_Rect m_OverlayRects[Overlay::OverlayMax]; SDL_Rect m_OverlayRects[Overlay::OverlayMax];
static const std::vector<int> k_SwFormats;
}; };