Skip to content

Commit

Permalink
Refactor VideoOutputOpenGL to allow efficient subclassing and extend
Browse files Browse the repository at this point in the history
OpenGLVideo to enable direct update of the output video textures via
hardware decoders.

This will be used by VAAPI in the short term (if I ever get it working
properly) and probably VDPAU and VDA for 0.25. There are other potential
issues such as deinterlacing of RGBA frames (generally a bad idea) but
I'll deal with those as they arise.

Refs #8593. Refs #8621


git-svn-id: http://svn.mythtv.org/svn/trunk@26098 7dbf422c-18fa-0310-86e9-fd20926502f2
  • Loading branch information
Mark Kendall committed Sep 3, 2010
1 parent 885c012 commit a9c57e7
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 46 deletions.
42 changes: 36 additions & 6 deletions mythtv/libs/libmythtv/openglvideo.cpp
Expand Up @@ -84,6 +84,7 @@ OpenGLVideo::OpenGLVideo() :
textureRects(false), textureType(GL_TEXTURE_2D),
helperTexture(0), defaultUpsize(kGLFilterResize),
gl_features(0), using_ycbcrtex(false),
using_hardwaretex(false),
gl_letterbox_colour(kLetterBoxColour_Black)
{
}
Expand Down Expand Up @@ -139,6 +140,7 @@ bool OpenGLVideo::Init(MythRenderOpenGL *glcontext, bool colour_control,
QSize videoDim, QRect displayVisibleRect,
QRect displayVideoRect, QRect videoRect,
bool viewport_control, QString options,
bool hw_accel,
LetterBoxColour letterbox_colour)
{
gl_context = glcontext;
Expand Down Expand Up @@ -175,10 +177,12 @@ bool OpenGLVideo::Init(MythRenderOpenGL *glcontext, bool colour_control,

SetViewPort(display_visible_rect.size());

bool use_pbo = gl_features & kGLExtPBufObj;
using_hardwaretex = hw_accel;
bool use_pbo = !using_hardwaretex && (gl_features & kGLExtPBufObj);
bool basic_features = gl_features & kGLExtFragProg;
bool full_features = basic_features && (gl_features & kGLExtFBufObj);
using_ycbcrtex = !full_features && (gl_features & kGLMesaYCbCr);
using_ycbcrtex = !using_hardwaretex && !full_features &&
(gl_features & kGLMesaYCbCr);

if (using_ycbcrtex)
basic_features = false;
Expand All @@ -192,27 +196,33 @@ bool OpenGLVideo::Init(MythRenderOpenGL *glcontext, bool colour_control,
QString("No OpenGL feature support for Bicubic filter."));
}

if ((defaultUpsize != kGLFilterBicubic) && (gl_features & kGLExtRect))
if (!using_hardwaretex &&
(defaultUpsize != kGLFilterBicubic) && (gl_features & kGLExtRect))
textureType = gl_context->GetTextureType(textureRects);

GLuint tex = 0;
bool ok = false;

if (basic_features)
if (basic_features && !using_hardwaretex)
{
tex = CreateVideoTexture(actual_video_dim, inputTextureSize, use_pbo);
ok = tex && AddFilter(kGLFilterYUV2RGB);
}
else if (using_ycbcrtex)
else if (using_ycbcrtex || using_hardwaretex)
{
tex = CreateVideoTexture(actual_video_dim,
inputTextureSize, use_pbo);
ok = tex && AddFilter(kGLFilterResize);
if (ok)
if (ok && using_ycbcrtex)
VERBOSE(VB_PLAYBACK, LOC + QString("Using GL_MESA_ycbcr_texture for"
" colorspace conversion."));
else if (ok && using_hardwaretex)
VERBOSE(VB_PLAYBACK, LOC + QString("Using plain RGBA tex for hw accel."));
else
{
using_ycbcrtex = false;
using_hardwaretex = false;
}
}

if (ok)
Expand Down Expand Up @@ -707,6 +717,11 @@ uint OpenGLVideo::CreateVideoTexture(QSize size, QSize &tex_size,
tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType,
GL_UNSIGNED_SHORT_8_8_MESA,
GL_YCBCR_MESA, GL_YCBCR_MESA);
else if (using_hardwaretex)
tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType,
GL_UNSIGNED_BYTE, GL_RGBA,
GL_RGBA, GL_LINEAR,
GL_CLAMP_TO_EDGE);
else
tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType);
tex_size = gl_context->GetTextureSize(textureType, size);
Expand Down Expand Up @@ -737,6 +752,21 @@ QSize OpenGLVideo::GetTextureSize(const QSize &size)
return QSize(w, h);
}

uint OpenGLVideo::GetInputTexture(void)
{
return inputTextures[0];
}

uint OpenGLVideo::GetTextureType(void)
{
return textureType;
}

void OpenGLVideo::SetInputUpdated(void)
{
inputUpdated = true;
}

/**
* \fn OpenGLVideo::UpdateInputFrame(const VideoFrame *frame, bool soft_bob)
* Update the current input texture using the data from the given YV12 video
Expand Down
5 changes: 5 additions & 0 deletions mythtv/libs/libmythtv/openglvideo.h
Expand Up @@ -44,8 +44,12 @@ class OpenGLVideo
QSize videoDim, QRect displayVisibleRect,
QRect displayVideoRect, QRect videoRect,
bool viewport_control, QString options,
bool hwaccel,
LetterBoxColour letterbox_colour = kLetterBoxColour_Black);

uint GetInputTexture(void);
uint GetTextureType(void);
void SetInputUpdated(void);
void UpdateInputFrame(const VideoFrame *frame, bool soft_bob = false);

/// \brief Public interface to AddFilter(OpenGLFilterType filter)
Expand Down Expand Up @@ -124,6 +128,7 @@ class OpenGLVideo
OpenGLFilterType defaultUpsize;
uint gl_features;
bool using_ycbcrtex;
bool using_hardwaretex;
LetterBoxColour gl_letterbox_colour;
};
#endif // _OPENGL_VIDEO_H__
53 changes: 30 additions & 23 deletions mythtv/libs/libmythtv/videoout_opengl.cpp
Expand Up @@ -7,8 +7,8 @@
#include "osd.h"
#include "mythuihelper.h"

#define LOC QString("VidOutOGL: ")
#define LOC_ERR QString("VidOutOGL: ")
#define LOC QString("VidOutGL: ")
#define LOC_ERR QString("VidOutGL Error: ")

void VideoOutputOpenGL::GetRenderOptions(render_opts &opts,
QStringList &cpudeints)
Expand Down Expand Up @@ -125,12 +125,12 @@ bool VideoOutputOpenGL::Init(int width, int height, float aspect,
winid, winx, winy, winw, winh,
codec_id, embedid);

if (db_vdisp_profile)
db_vdisp_profile->SetVideoRenderer("opengl");
SetProfile();

success &= SetupContext();
InitDisplayMeasurements(width, height, false);
success &= CreateBuffers();
success &= CreatePauseFrame();
success &= SetupOpenGL();

InitOSD();
Expand All @@ -146,18 +146,23 @@ bool VideoOutputOpenGL::Init(int width, int height, float aspect,
return success;
}

void VideoOutputOpenGL::SetProfile(void)
{
if (db_vdisp_profile)
db_vdisp_profile->SetVideoRenderer("opengl");
}

bool VideoOutputOpenGL::InputChanged(const QSize &input_size,
float aspect,
MythCodecID av_codec_id,
void *codec_private,
bool &aspect_only)
{
VERBOSE(VB_PLAYBACK, LOC + QString("InputChanged(%1,%2,%3) %4")
VERBOSE(VB_PLAYBACK, LOC + QString("InputChanged(%1,%2,%3) %4->%5")
.arg(input_size.width()).arg(input_size.height()).arg(aspect)
.arg(toString(av_codec_id)));
.arg(toString(video_codec_id)).arg(toString(av_codec_id)));

QMutexLocker locker(&gl_context_lock);

if (!codec_is_std(av_codec_id))
{
VERBOSE(VB_IMPORTANT, LOC_ERR +
Expand Down Expand Up @@ -244,7 +249,8 @@ bool VideoOutputOpenGL::SetupOpenGL(void)
window.GetVideoDim(), dvr,
window.GetDisplayVideoRect(),
window.GetVideoRect(), true,
GetFilters(), db_letterbox_colour);
GetFilters(), !codec_is_std(video_codec_id),
db_letterbox_colour);
if (success)
{
bool temp_deinterlacing = m_deinterlacing;
Expand Down Expand Up @@ -278,13 +284,14 @@ void VideoOutputOpenGL::InitOSD(void)
bool VideoOutputOpenGL::CreateBuffers(void)
{
QMutexLocker locker(&gl_context_lock);

bool success = true;
vbuffers.Init(31, true, 1, 12, 4, 2, false);
success &= vbuffers.CreateBuffers(FMT_YV12,
window.GetVideoDim().width(),
window.GetVideoDim().height());
return vbuffers.CreateBuffers(FMT_YV12,
window.GetVideoDim().width(),
window.GetVideoDim().height());
}

bool VideoOutputOpenGL::CreatePauseFrame(void)
{
av_pause_frame.height = vbuffers.GetScratchFrame()->height;
av_pause_frame.width = vbuffers.GetScratchFrame()->width;
av_pause_frame.bpp = vbuffers.GetScratchFrame()->bpp;
Expand All @@ -293,11 +300,10 @@ bool VideoOutputOpenGL::CreateBuffers(void)
av_pause_frame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;

if (!av_pause_frame.buf)
success = false;
else
clear(&av_pause_frame);
return false;

return success;
clear(&av_pause_frame);
return true;
}

void VideoOutputOpenGL::ProcessFrame(VideoFrame *frame, OSD *osd,
Expand All @@ -309,6 +315,7 @@ void VideoOutputOpenGL::ProcessFrame(VideoFrame *frame, OSD *osd,
if (!gl_videochain || !gl_context)
return;

bool sw_frame = codec_is_std(video_codec_id);
bool deint_proc = m_deinterlacing && (m_deintFilter != NULL);
OpenGLLocker ctx_lock(gl_context);

Expand All @@ -320,11 +327,11 @@ void VideoOutputOpenGL::ProcessFrame(VideoFrame *frame, OSD *osd,
pauseframe = true;
}

if (filterList)
if (filterList && sw_frame)
filterList->ProcessFrame(frame);

bool safepauseframe = pauseframe && !IsBobDeint();
if (deint_proc && m_deinterlaceBeforeOSD &&
if (sw_frame && deint_proc && m_deinterlaceBeforeOSD &&
(!pauseframe || safepauseframe))
{
m_deintFilter->ProcessFrame(frame, scan);
Expand All @@ -336,15 +343,15 @@ void VideoOutputOpenGL::ProcessFrame(VideoFrame *frame, OSD *osd,
ShowPIPs(frame, pipPlayers);
}

if ((!pauseframe || safepauseframe) &&
if (sw_frame && (!pauseframe || safepauseframe) &&
deint_proc && !m_deinterlaceBeforeOSD)
{
m_deintFilter->ProcessFrame(frame, scan);
}

bool soft_bob = m_deinterlacing && (m_deintfiltername == "bobdeint");

if (gl_videochain)
if (gl_videochain && sw_frame)
gl_videochain->UpdateInputFrame(frame, soft_bob);
}

Expand Down Expand Up @@ -633,7 +640,7 @@ void VideoOutputOpenGL::ShowPIP(VideoFrame *frame,
QSize(pipVideoWidth, pipVideoHeight),
dvr, position,
QRect(0, 0, pipVideoWidth, pipVideoHeight),
false, GetFilters());
false, GetFilters(), false);
gl_pipchain->SetMasterViewport(gl_videochain->GetViewPort());
if (!success)
{
Expand All @@ -654,7 +661,7 @@ void VideoOutputOpenGL::ShowPIP(VideoFrame *frame,
QSize(pipVideoWidth, pipVideoHeight),
dvr, position,
QRect(0, 0, pipVideoWidth, pipVideoHeight),
false, GetFilters());
false, GetFilters(), false);

gl_pipchain->SetMasterViewport(gl_videochain->GetViewPort());
if (!success)
Expand Down
36 changes: 19 additions & 17 deletions mythtv/libs/libmythtv/videoout_opengl.h
Expand Up @@ -11,22 +11,23 @@ class VideoOutputOpenGL : public VideoOutput
public:
static void GetRenderOptions(render_opts &opts, QStringList &cpudeints);
VideoOutputOpenGL();
~VideoOutputOpenGL();
virtual ~VideoOutputOpenGL();

bool Init(int width, int height, float aspect, WId winid,
int winx, int winy, int winw, int winh,
MythCodecID codec_id, WId embedid = 0);
void TearDown(void);
virtual bool Init(int width, int height, float aspect, WId winid,
int winx, int winy, int winw, int winh,
MythCodecID codec_id, WId embedid = 0);
virtual void SetProfile(void);
virtual void TearDown(void);

void PrepareFrame(VideoFrame *buffer, FrameScanType, OSD *osd);
void ProcessFrame(VideoFrame *frame, OSD *osd,
FilterChain *filterList,
const PIPMap &pipPlayers,
FrameScanType scan);
void Show(FrameScanType );
bool InputChanged(const QSize &input_size, float aspect,
MythCodecID av_codec_id, void *codec_private,
bool &aspect_only);
virtual void ProcessFrame(VideoFrame *frame, OSD *osd,
FilterChain *filterList,
const PIPMap &pipPlayers,
FrameScanType scan);
virtual void Show(FrameScanType );
virtual bool InputChanged(const QSize &input_size, float aspect,
MythCodecID av_codec_id, void *codec_private,
bool &aspect_only);
void UpdatePauseFrame(void);
void DrawUnusedRects(bool) { }
void Zoom(ZoomDirection direction);
Expand All @@ -37,8 +38,8 @@ class VideoOutputOpenGL : public VideoOutput
const QSize &video_dim);
void EmbedInWidget(int x, int y, int w, int h);
void StopEmbedding(void);
bool SetDeinterlacingEnabled(bool);
bool SetupDeinterlace(bool i, const QString& ovrf="");
virtual bool SetDeinterlacingEnabled(bool);
virtual bool SetupDeinterlace(bool i, const QString& ovrf="");
void ShowPIP(VideoFrame *frame,
MythPlayer *pipplayer,
PIPLocation loc);
Expand All @@ -51,8 +52,9 @@ class VideoOutputOpenGL : public VideoOutput
virtual bool ApproveDeintFilter(const QString& filtername) const;
virtual MythPainter *GetOSDPainter(void) { return (MythPainter*)gl_painter; }

private:
bool CreateBuffers(void);
protected:
virtual bool CreateBuffers(void);
bool CreatePauseFrame(void);
bool SetupContext(void);
bool SetupOpenGL(void);
void InitOSD(void);
Expand Down

0 comments on commit a9c57e7

Please sign in to comment.