-
Notifications
You must be signed in to change notification settings - Fork 345
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
Showing
4 changed files
with
369 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.