From 9d4b448a541d1f4a8a2ebc2df2a9067a6a64984c Mon Sep 17 00:00:00 2001 From: Mark Kendall Date: Fri, 15 Mar 2019 09:28:54 +0000 Subject: [PATCH] MythVideoTexture: Support software NV12 textures - rendering support is already available (as needed for hardware frames) - this adds support for creating and uploading NV12 frames directly which in the short term is useful for direct rendering of VideoToolBox decoded frames (decode only) and in the longer term will be part of a suite of supported direct rendering formats. --- mythtv/libs/libmythtv/mythvideotexture.cpp | 80 +++++++++++++++++---- mythtv/libs/libmythtv/mythvideotexture.h | 10 ++- mythtv/libs/libmythui/mythrender_opengl.cpp | 1 + 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/mythtv/libs/libmythtv/mythvideotexture.cpp b/mythtv/libs/libmythtv/mythvideotexture.cpp index bf2dcea0c9a..a751ec9cbd4 100644 --- a/mythtv/libs/libmythtv/mythvideotexture.cpp +++ b/mythtv/libs/libmythtv/mythvideotexture.cpp @@ -170,6 +170,19 @@ vector MythVideoTexture::CreateSoftwareTextures(MythRenderOpe case FMT_YUYVHQ: texture = CreateTexture(Context, size, Target); break; + case FMT_NV12: + if (plane == 0) + { + texture = CreateTexture(Context, size, Target, + QOpenGLTexture::UInt8, QOpenGLTexture::Red); + } + else + { + size = QSize(size.width() >> 1, size.height() >> 1); + texture = CreateTexture(Context, size, Target, + QOpenGLTexture::UInt8, QOpenGLTexture::RG); + } + break; default: break; } if (texture) @@ -216,6 +229,8 @@ void MythVideoTexture::UpdateTextures(MythRenderOpenGL *Context, return; } + OpenGLLocker locker(Context); + for (uint i = 0; i < count; ++i) { MythVideoTexture *texture = Textures[i]; @@ -236,9 +251,18 @@ void MythVideoTexture::UpdateTextures(MythRenderOpenGL *Context, { switch (texture->m_frameFormat) { - case FMT_YV12: YV12ToYV12(Context, Frame, texture, i); break; - case FMT_YUY2: YV12ToYUYV(Context, Frame, texture); break; - case FMT_YUYVHQ: YV12ToYUYVHQ(Context, Frame, texture); break; + case FMT_YV12: YV12ToYV12(Frame, texture, i); break; + case FMT_YUY2: YV12ToYUYV(Frame, texture); break; + case FMT_YUYVHQ: YV12ToYUYVHQ(Frame, texture); break; + default: break; + } + break; + } + case FMT_NV12: + { + switch (texture->m_frameFormat) + { + case FMT_NV12: NV12ToNV12(Frame, texture, i); break; default: break; } break; @@ -306,17 +330,15 @@ MythVideoTexture* MythVideoTexture::CreateTexture(MythRenderOpenGL *Context, } /// \brief Copy YV12 frame data to 'YV12' textures. -void MythVideoTexture::YV12ToYV12(MythRenderOpenGL *Context, const VideoFrame *Frame, +void MythVideoTexture::YV12ToYV12(const VideoFrame *Frame, MythVideoTexture *Texture, int Plane) { - OpenGLLocker locker(Context); - void *buffer = nullptr; int offset = 0; int width = Texture->m_size.width(); // Direct copy - if ((Frame->codec == FMT_YV12) && (Frame->pitches[Plane] == width)) + if (Frame->pitches[Plane] == width) { buffer = Frame->buf; offset = Frame->offsets[Plane]; @@ -341,15 +363,13 @@ void MythVideoTexture::YV12ToYV12(MythRenderOpenGL *Context, const VideoFrame *F } /// \brief Copy YV12 frame data to a YUYV texture. -void MythVideoTexture::YV12ToYUYV(MythRenderOpenGL *Context, const VideoFrame *Frame, +void MythVideoTexture::YV12ToYUYV(const VideoFrame *Frame, MythVideoTexture *Texture) { - OpenGLLocker locker(Context); - void * buffer = nullptr; // Direct copy - if ((Frame->codec == FMT_YUY2) && (Frame->pitches[0] == Texture->m_size.width())) + if (Frame->pitches[0] == Texture->m_size.width()) { buffer = Frame->buf; } @@ -380,11 +400,9 @@ void MythVideoTexture::YV12ToYUYV(MythRenderOpenGL *Context, const VideoFrame *F } /// \brief Copy YV12 frame data to a YUYV texture with high quality interlaced chroma sampling. -void MythVideoTexture::YV12ToYUYVHQ(MythRenderOpenGL *Context, const VideoFrame *Frame, +void MythVideoTexture::YV12ToYUYVHQ(const VideoFrame *Frame, MythVideoTexture *Texture) { - OpenGLLocker locker(Context); - // Create a buffer if (!Texture->m_data) if (!CreateBuffer(Texture, Texture->m_bufferSize)) @@ -407,6 +425,40 @@ void MythVideoTexture::YV12ToYUYVHQ(MythRenderOpenGL *Context, const VideoFrame Texture->m_valid = true; } +/// \brief Copy NV12 video frame data to 'NV12' textures. +void MythVideoTexture::NV12ToNV12(const VideoFrame *Frame, MythVideoTexture *Texture, int Plane) +{ + void *buffer = nullptr; + int offset = 0; + int width = Texture->m_size.width(); + if (Plane) + width *= 2; + + // Direct copy + if (Frame->pitches[Plane] == width) + { + buffer = Frame->buf; + offset = Frame->offsets[Plane]; + } + else + { + // Create a buffer + if (!Texture->m_data) + if (!CreateBuffer(Texture, Texture->m_bufferSize)) + return; + buffer = Texture->m_data; + + // Refresh + copyplane(static_cast(buffer), width, Frame->buf + Frame->offsets[Plane], + Frame->pitches[Plane], width, Texture->m_size.height()); + } + + // Update + Texture->m_texture->setData(Texture->m_pixelFormat, Texture->m_pixelType, + static_cast(buffer) + offset); + Texture->m_valid = true; +} + /// \brief Create a data buffer for holding CPU side texture data. bool MythVideoTexture::CreateBuffer(MythVideoTexture *Texture, int Size) { diff --git a/mythtv/libs/libmythtv/mythvideotexture.h b/mythtv/libs/libmythtv/mythvideotexture.h index e9f9ac356ce..1b152e8491e 100644 --- a/mythtv/libs/libmythtv/mythvideotexture.h +++ b/mythtv/libs/libmythtv/mythvideotexture.h @@ -63,12 +63,10 @@ class MythVideoTexture : public MythGLTexture private: Q_DISABLE_COPY(MythVideoTexture) - static void YV12ToYV12 (MythRenderOpenGL* Context, const VideoFrame *Frame, - MythVideoTexture* Texture, int Plane); - static void YV12ToYUYV (MythRenderOpenGL* Context, const VideoFrame *Frame, - MythVideoTexture* Texture); - static void YV12ToYUYVHQ (MythRenderOpenGL* Context, const VideoFrame *Frame, - MythVideoTexture* Texture); + static void YV12ToYV12 (const VideoFrame *Frame, MythVideoTexture* Texture, int Plane); + static void YV12ToYUYV (const VideoFrame *Frame, MythVideoTexture* Texture); + static void YV12ToYUYVHQ (const VideoFrame *Frame, MythVideoTexture* Texture); + static void NV12ToNV12 (const VideoFrame *Frame, MythVideoTexture* Texture, int Plane); static bool CreateBuffer (MythVideoTexture* Texture, int Size); static void StoreBicubicWeights(float X, float *Dest); }; diff --git a/mythtv/libs/libmythui/mythrender_opengl.cpp b/mythtv/libs/libmythui/mythrender_opengl.cpp index b37ab59628a..9bbda141277 100644 --- a/mythtv/libs/libmythui/mythrender_opengl.cpp +++ b/mythtv/libs/libmythui/mythrender_opengl.cpp @@ -1334,6 +1334,7 @@ int MythRenderOpenGL::GetBufferSize(QSize Size, QOpenGLTexture::PixelFormat Form case QOpenGLTexture::RGBA: bpp = 4; break; case QOpenGLTexture::BGR: case QOpenGLTexture::RGB: bpp = 3; break; + case QOpenGLTexture::RG: bpp = 2; break; case QOpenGLTexture::Red: case QOpenGLTexture::Alpha: case QOpenGLTexture::Luminance: bpp = 1; break;