Skip to content

Commit

Permalink
VAAPI: Add VideoOutputNullVAAPI.
Browse files Browse the repository at this point in the history
As for VideoOutputNullVDPAU, if you poke it just right it can be used to
accelerate transcoding etc.
  • Loading branch information
Mark Kendall committed Dec 29, 2011
1 parent 8811210 commit 42d9577
Show file tree
Hide file tree
Showing 4 changed files with 369 additions and 4 deletions.
12 changes: 8 additions & 4 deletions mythtv/libs/libmythtv/libmythtv.pro
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,14 @@ using_frontend {
using_opengl_video:HEADERS += openglvideo.h videoout_opengl.h
using_opengl_video:SOURCES += openglvideo.cpp videoout_opengl.cpp

using_vaapi: DEFINES += USING_VAAPI
using_vaapi: DEFINES += vaapicontext.h videoout_openglvaapi.h
using_vaapi: SOURCES += vaapicontext.cpp videoout_openglvaapi.cpp
using_vaapi: LIBS += -lva -lva-x11 -lva-glx
using_vaapi {
DEFINES += USING_VAAPI
HEADERS += vaapicontext.h videoout_nullvaapi.h
SOURCES += vaapicontext.cpp videoout_nullvaapi.cpp
LIBS += -lva -lva-x11 -lva-glx
using_opengl_video:HEADERS += videoout_openglvaapi.h
using_opengl_video:SOURCES += videoout_openglvaapi.cpp
}

# Misc. frontend
HEADERS += DetectLetterbox.h
Expand Down
288 changes: 288 additions & 0 deletions mythtv/libs/libmythtv/videoout_nullvaapi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
#include "videoout_nullvaapi.h"
#include "vaapicontext.h"

#define LOC QString("NullVAAPI: ")

void VideoOutputNullVAAPI::GetRenderOptions(render_opts &opts)
{
opts.renderers->append("nullvaapi");
(*opts.osds)["nullvaapi"].append("dummy");
QStringList dummy(QString("dummy"));
opts.deints->insert("nullvaapi", dummy);
if (opts.decoders->contains("vaapi"))
(*opts.safe_renderers)["vaapi"].append("nullvaapi");
if (opts.decoders->contains("ffmpeg"))
(*opts.safe_renderers)["ffmpeg"].append("nullvaapi");
if (opts.decoders->contains("crystalhd"))
(*opts.safe_renderers)["crystalhd"].append("nullvaapi");
(*opts.safe_renderers)["dummy"].append("nullvaapi");
(*opts.safe_renderers)["nuppel"].append("nullvaapi");

opts.priorities->insert("nullvaapi", 20);
}

VideoOutputNullVAAPI::VideoOutputNullVAAPI()
: m_ctx(NULL), m_lock(QMutex::Recursive), m_shadowBuffers(NULL)
{
}

VideoOutputNullVAAPI::~VideoOutputNullVAAPI()
{
TearDown();
}

void VideoOutputNullVAAPI::TearDown(void)
{
QMutexLocker lock(&m_lock);
DeleteBuffers();
DeleteVAAPIContext();
}

bool VideoOutputNullVAAPI::CreateVAAPIContext(QSize size)
{
QMutexLocker lock(&m_lock);
if (m_ctx)
DeleteVAAPIContext();

m_ctx = new VAAPIContext(kVADisplayX11, video_codec_id);
if (m_ctx && m_ctx->CreateDisplay(size))
return true;
return false;
}

void VideoOutputNullVAAPI::DeleteVAAPIContext(void)
{
QMutexLocker lock(&m_lock);
delete m_ctx;
m_ctx = NULL;
}

bool VideoOutputNullVAAPI::InitBuffers(void)
{
QMutexLocker lock(&m_lock);
if (!codec_is_vaapi_hw(video_codec_id) || !m_ctx ||
!m_ctx->CreateBuffers())
{
return false;
}

// create VAAPI buffers
vbuffers.Init(24, true, 2, 1, 4, 1);
int num_buffers = m_ctx->GetNumBuffers();
const QSize video_dim = window.GetActualVideoDim();
bool ok = true;
for (int i = 0; i < num_buffers; i++)
{
ok &= vbuffers.CreateBuffer(video_dim.width(),
video_dim.height(), i,
m_ctx->GetVideoSurface(i),
FMT_VAAPI);
}

// create CPU buffers
m_shadowBuffers = new VideoBuffers();
if (!m_shadowBuffers)
return false;
m_shadowBuffers->Init(24, true, 2, 1, 4, 1);
if (!m_shadowBuffers->CreateBuffers(FMT_YV12,
video_dim.width(),
video_dim.height()))
{
return false;
}

return true;
}

void VideoOutputNullVAAPI::DeleteBuffers(void)
{
QMutexLocker lock(&m_lock);
DiscardFrames(true);
vbuffers.Reset();
vbuffers.DeleteBuffers();
if (m_shadowBuffers)
{
m_shadowBuffers->Reset();
m_shadowBuffers->DeleteBuffers();
}
delete m_shadowBuffers;
m_shadowBuffers = NULL;
}

QStringList VideoOutputNullVAAPI::GetAllowedRenderers(MythCodecID myth_codec_id)
{
QStringList list;
if ((codec_is_vaapi_hw(myth_codec_id)) && !getenv("NO_VAAPI"))
list += "nullvaapi";
return list;
}

bool VideoOutputNullVAAPI::Init(int width, int height, float aspect,
WId winid, const QRect &win_rect,
MythCodecID codec_id)
{
QMutexLocker locker(&m_lock);
bool ok = VideoOutput::Init(width, height, aspect, winid, win_rect, codec_id);
if (!codec_is_vaapi_hw(video_codec_id))
return false;

if (db_vdisp_profile)
db_vdisp_profile->SetVideoRenderer("nullvaapi");
if (ok) ok = CreateVAAPIContext(window.GetActualVideoDim());
if (ok) ok = InitBuffers();
if (!ok)
return false;

LOG(VB_PLAYBACK, LOG_INFO, LOC +
"Created VAAPI context with GPU decoding");
return ok;
}

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

QMutexLocker locker(&m_lock);

bool cid_changed = (video_codec_id != av_codec_id);
bool res_changed = input_size != window.GetActualVideoDim();
if (!res_changed && !cid_changed)
{
aspect_only = true;
return true;
}

TearDown();
QRect disp = window.GetDisplayVisibleRect();
if (Init(input_size.width(), input_size.height(),
aspect, 0, disp, av_codec_id))
{
return true;
}

LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to re-initialise video output.");
errorState = kError_Unknown;
return false;
}

void* VideoOutputNullVAAPI::GetDecoderContext(unsigned char* buf, uint8_t*& id)
{
if (m_ctx)
{
id = m_ctx->GetSurfaceIDPointer(buf);
return &m_ctx->m_ctx;
}
return NULL;
}

// Always returns the CPU version of a frame
VideoFrame* VideoOutputNullVAAPI::GetLastDecodedFrame(void)
{
VideoFrame* gpu = vbuffers.GetLastDecodedFrame();
for (uint i = 0; i < vbuffers.Size(); i++)
if (vbuffers.at(i) == gpu)
return m_shadowBuffers->at(i);
LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find frame.");
return NULL;
}

// Always returns the CPU version of a frame
VideoFrame* VideoOutputNullVAAPI::GetLastShownFrame(void)
{
VideoFrame* gpu = vbuffers.GetLastShownFrame();
for (uint i = 0; i < vbuffers.Size(); i++)
if (vbuffers.at(i) == gpu)
return m_shadowBuffers->at(i);
LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find frame.");
return NULL;
}

// Should work with either the CPU or GPU version of a frame
void VideoOutputNullVAAPI::DiscardFrame(VideoFrame *frame)
{
// is this a CPU frame
for (uint i = 0; i < m_shadowBuffers->Size(); i++)
{
if (m_shadowBuffers->at(i) == frame)
{
frame = vbuffers.at(i);
break;
}
}

// is this a GPU frame
for (uint i = 0; i < vbuffers.Size(); i++)
{
if (vbuffers.at(i) == frame)
{
m_lock.lock();
vbuffers.DiscardFrame(frame);
m_lock.unlock();
return;
}
}
}

// Should work with either the CPU or GPU version of a frame
void VideoOutputNullVAAPI::DoneDisplayingFrame(VideoFrame *frame)
{
// is this a CPU frame
for (uint i = 0; i < m_shadowBuffers->Size(); i++)
{
if (m_shadowBuffers->at(i) == frame)
{
frame = vbuffers.at(i);
break;
}
}

// is this a GPU frame
for (uint i = 0; i < vbuffers.Size(); i++)
{
if (vbuffers.at(i) == frame)
{
m_lock.lock();
VideoOutput::DiscardFrame(frame);
m_lock.unlock();
return;
}
}
}

void VideoOutputNullVAAPI::ReleaseFrame(VideoFrame *frame)
{
if (!frame)
return;

if ((frame->codec != FMT_VAAPI) || !m_ctx)
{
VideoOutput::ReleaseFrame(frame);
return;
}

QMutexLocker lock(&m_lock);
for (uint i = 0; i < vbuffers.Size() && m_ctx; i++)
{
if (vbuffers.at(i)->buf == frame->buf)
{
VideoFrame *vf = m_shadowBuffers->at(i);
vf->aspect = frame->aspect;
vf->disp_timecode = frame->disp_timecode;
vf->dummy = frame->dummy;
vf->frameNumber = frame->frameNumber;
vf->interlaced_frame = frame->interlaced_frame;
vf->timecode = frame->timecode;
vf->repeat_pict = frame->repeat_pict;
vf->top_field_first = frame->top_field_first;
m_ctx->CopySurfaceToFrame(vf, vbuffers.at(i)->buf);
}
}
VideoOutput::ReleaseFrame(frame);
}
66 changes: 66 additions & 0 deletions mythtv/libs/libmythtv/videoout_nullvaapi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#ifndef VIDEOOUT_NULLVAAPI_H
#define VIDEOOUT_NULLVAAPI_H

#include "videooutbase.h"

class VAAPIContext;

class VideoOutputNullVAAPI : public VideoOutput
{
public:
static void GetRenderOptions(render_opts &opts);
static QStringList GetAllowedRenderers(MythCodecID myth_codec_id);
VideoOutputNullVAAPI();
~VideoOutputNullVAAPI();

virtual void* GetDecoderContext(unsigned char* buf, uint8_t*& id);
virtual bool Init(int width, int height, float aspect, WId winid,
const QRect &win_rect, MythCodecID codec_id);
virtual bool InputChanged(const QSize &input_size,
float aspect,
MythCodecID av_codec_id,
void *codec_private,
bool &aspect_only);

virtual bool SetupDeinterlace(bool, const QString &ovrf = "") { return false; }
virtual bool SetDeinterlacingEnabled(bool) { return false; }
virtual bool ApproveDeintFilter(const QString& filtername) const { return false; }
virtual void ReleaseFrame(VideoFrame *frame);
virtual void ProcessFrame(VideoFrame *frame, OSD *osd,
FilterChain *filterList,
const PIPMap &pipPlayers,
FrameScanType scan) {;}
virtual void PrepareFrame(VideoFrame *buffer,
FrameScanType, OSD *osd) {;}
virtual void Show(FrameScanType ) {;}

virtual void Zoom(ZoomDirection direction) {;}
virtual void EmbedInWidget(const QRect &rect) {;}
virtual void StopEmbedding(void) {;}
virtual void DrawUnusedRects(bool sync = true) {;}
virtual void UpdatePauseFrame(int64_t &disp_timecode) {;}
virtual void MoveResizeWindow(QRect ) {;}
virtual bool CanVisualise(AudioPlayer *audio, MythRender *render)
{ return false; }
virtual bool SetupVisualisation(AudioPlayer *audio, MythRender *render)
{ return false; }
virtual MythPainter *GetOSDPainter(void) { return NULL; }
virtual VideoFrame *GetLastDecodedFrame(void);
virtual VideoFrame *GetLastShownFrame(void);
virtual void DoneDisplayingFrame(VideoFrame *frame);

private:
void TearDown(void);
bool CreateVAAPIContext(QSize size);
void DeleteVAAPIContext(void);
bool InitBuffers(void);
void DeleteBuffers(void);
void DiscardFrame(VideoFrame*);

private:
VAAPIContext *m_ctx;
QMutex m_lock;
VideoBuffers *m_shadowBuffers;
};

#endif // VIDEOOUT_NULLVAAPI_H
Loading

0 comments on commit 42d9577

Please sign in to comment.