Skip to content

Commit

Permalink
MythVideoTexture: Optimise YV12 and NV12 texture uploads
Browse files Browse the repository at this point in the history
- use GL_UNPACK_ROW_LENGTH to handle different pitches instead of
creating a software buffer and copying.
- remove bogus attempt at optimisation for YV12 to YUYV conversion.
- make MythFrame::copyplane private again
  • Loading branch information
mark-kendall committed Mar 15, 2019
1 parent c755f0d commit 3d72cc5
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 99 deletions.
12 changes: 12 additions & 0 deletions mythtv/libs/libmythtv/mythframe.cpp
Expand Up @@ -286,6 +286,18 @@ static inline void SSE_splitplanes(uint8_t* dstu, int dstu_pitch,
}
#endif /* ARCH_X86 */

static inline void copyplane(uint8_t* dst, int dst_pitch,
const uint8_t* src, int src_pitch,
int width, int height)
{
for (int y = 0; y < height; y++)
{
memcpy(dst, src, width);
src += src_pitch;
dst += dst_pitch;
}
}

static void splitplanes(uint8_t* dstu, int dstu_pitch,
uint8_t* dstv, int dstv_pitch,
const uint8_t* src, int src_pitch,
Expand Down
12 changes: 0 additions & 12 deletions mythtv/libs/libmythtv/mythframe.h
Expand Up @@ -433,18 +433,6 @@ static inline void copybuffer(uint8_t *dstbuffer, const VideoFrame *src,
copy(&frameout, src);
}
}

static inline void copyplane(uint8_t* dst, int dst_pitch,
const uint8_t* src, int src_pitch,
int width, int height)
{
for (int y = 0; y < height; y++)
{
memcpy(dst, src, width);
src += src_pitch;
dst += dst_pitch;
}
}
#endif /* __cplusplus */

#endif
113 changes: 28 additions & 85 deletions mythtv/libs/libmythtv/mythvideotexture.cpp
Expand Up @@ -249,7 +249,7 @@ void MythVideoTexture::UpdateTextures(MythRenderOpenGL *Context,
{
switch (texture->m_frameFormat)
{
case FMT_YV12: YV12ToYV12(Frame, texture, i); break;
case FMT_YV12: YV12ToYV12(Context, Frame, texture, i); break;
case FMT_YUY2: YV12ToYUYV(Frame, texture); break;
case FMT_YUYVHQ: YV12ToYUYVHQ(Frame, texture); break;
default: break;
Expand All @@ -260,7 +260,7 @@ void MythVideoTexture::UpdateTextures(MythRenderOpenGL *Context,
{
switch (texture->m_frameFormat)
{
case FMT_NV12: NV12ToNV12(Frame, texture, i); break;
case FMT_NV12: NV12ToNV12(Context, Frame, texture, i); break;
default: break;
}
break;
Expand Down Expand Up @@ -328,78 +328,44 @@ MythVideoTexture* MythVideoTexture::CreateTexture(MythRenderOpenGL *Context,
}

/// \brief Copy YV12 frame data to 'YV12' textures.
void MythVideoTexture::YV12ToYV12(const VideoFrame *Frame,
MythVideoTexture *Texture, int Plane)
inline void MythVideoTexture::YV12ToYV12(MythRenderOpenGL *Context, const VideoFrame *Frame,
MythVideoTexture *Texture, int Plane)
{
void *buffer = nullptr;
int offset = 0;
int width = Texture->m_size.width();

// 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<uint8_t*>(buffer), width, Frame->buf + Frame->offsets[Plane],
Frame->pitches[Plane], width, Texture->m_size.height());
}

// Update
Context->glPixelStorei(GL_UNPACK_ROW_LENGTH, Frame->pitches[Plane]);
Texture->m_texture->setData(Texture->m_pixelFormat, Texture->m_pixelType,
static_cast<uint8_t*>(buffer) + offset);
static_cast<uint8_t*>(Frame->buf) + Frame->offsets[Plane]);
Texture->m_valid = true;
Context->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}

/// \brief Copy YV12 frame data to a YUYV texture.
void MythVideoTexture::YV12ToYUYV(const VideoFrame *Frame,
MythVideoTexture *Texture)
inline void MythVideoTexture::YV12ToYUYV(const VideoFrame *Frame, MythVideoTexture *Texture)
{
void * buffer = nullptr;
// Create a buffer
if (!Texture->m_data)
if (!CreateBuffer(Texture, Texture->m_bufferSize))
return;
void* buffer = Texture->m_data;

// Direct copy
if (Frame->pitches[0] == Texture->m_size.width())
{
buffer = Frame->buf;
}
else
// Create a copy context
if (!Texture->m_copyContext)
{
// Create a buffer
if (!Texture->m_data)
if (!CreateBuffer(Texture, Texture->m_bufferSize))
return;
buffer = Texture->m_data;

// Create a copy context
Texture->m_copyContext = new MythAVCopy();
if (!Texture->m_copyContext)
{
Texture->m_copyContext = new MythAVCopy();
if (!Texture->m_copyContext)
return;
}

// Convert
AVFrame out;
Texture->m_copyContext->Copy(&out, Frame, static_cast<unsigned char*>(buffer), AV_PIX_FMT_UYVY422);
return;
}

// Convert
AVFrame out;
Texture->m_copyContext->Copy(&out, Frame, static_cast<unsigned char*>(buffer), AV_PIX_FMT_UYVY422);

// Update
Texture->m_texture->setData(Texture->m_pixelFormat, Texture->m_pixelType, buffer);
Texture->m_valid = true;
}

/// \brief Copy YV12 frame data to a YUYV texture with high quality interlaced chroma sampling.
void MythVideoTexture::YV12ToYUYVHQ(const VideoFrame *Frame,
MythVideoTexture *Texture)
inline void MythVideoTexture::YV12ToYUYVHQ(const VideoFrame *Frame, MythVideoTexture *Texture)
{
// Create a buffer
if (!Texture->m_data)
Expand All @@ -424,41 +390,18 @@ void MythVideoTexture::YV12ToYUYVHQ(const VideoFrame *Frame,
}

/// \brief Copy NV12 video frame data to 'NV12' textures.
void MythVideoTexture::NV12ToNV12(const VideoFrame *Frame, MythVideoTexture *Texture, int Plane)
inline void MythVideoTexture::NV12ToNV12(MythRenderOpenGL *Context, 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<uint8_t*>(buffer), width, Frame->buf + Frame->offsets[Plane],
Frame->pitches[Plane], width, Texture->m_size.height());
}

// Update
Context->glPixelStorei(GL_UNPACK_ROW_LENGTH, Plane ? Frame->pitches[Plane] >> 1 : Frame->pitches[Plane]);
Texture->m_texture->setData(Texture->m_pixelFormat, Texture->m_pixelType,
static_cast<uint8_t*>(buffer) + offset);
static_cast<uint8_t*>(Frame->buf) + Frame->offsets[Plane]);
Texture->m_valid = true;
Context->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}

/// \brief Create a data buffer for holding CPU side texture data.
bool MythVideoTexture::CreateBuffer(MythVideoTexture *Texture, int Size)
inline bool MythVideoTexture::CreateBuffer(MythVideoTexture *Texture, int Size)
{
if (!Texture || Size < 1)
return false;
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/mythvideotexture.h
Expand Up @@ -63,10 +63,10 @@ class MythVideoTexture : public MythGLTexture

private:
Q_DISABLE_COPY(MythVideoTexture)
static void YV12ToYV12 (const VideoFrame *Frame, MythVideoTexture* Texture, int Plane);
static void YV12ToYV12 (MythRenderOpenGL *Context, 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 void NV12ToNV12 (MythRenderOpenGL *Context, const VideoFrame *Frame, MythVideoTexture* Texture, int Plane);
static bool CreateBuffer (MythVideoTexture* Texture, int Size);
static void StoreBicubicWeights(float X, float *Dest);
};
Expand Down

0 comments on commit 3d72cc5

Please sign in to comment.