00001 #include "videoout_nullvaapi.h"
00002 #include "vaapicontext.h"
00003
00004 #define LOC QString("NullVAAPI: ")
00005
00006 void VideoOutputNullVAAPI::GetRenderOptions(render_opts &opts)
00007 {
00008 opts.renderers->append("nullvaapi");
00009 (*opts.osds)["nullvaapi"].append("dummy");
00010 QStringList dummy(QString("dummy"));
00011 opts.deints->insert("nullvaapi", dummy);
00012 if (opts.decoders->contains("vaapi"))
00013 (*opts.safe_renderers)["vaapi"].append("nullvaapi");
00014 if (opts.decoders->contains("ffmpeg"))
00015 (*opts.safe_renderers)["ffmpeg"].append("nullvaapi");
00016 if (opts.decoders->contains("crystalhd"))
00017 (*opts.safe_renderers)["crystalhd"].append("nullvaapi");
00018 (*opts.safe_renderers)["dummy"].append("nullvaapi");
00019 (*opts.safe_renderers)["nuppel"].append("nullvaapi");
00020
00021 opts.priorities->insert("nullvaapi", 20);
00022 }
00023
00024 VideoOutputNullVAAPI::VideoOutputNullVAAPI()
00025 : m_ctx(NULL), m_lock(QMutex::Recursive), m_shadowBuffers(NULL)
00026 {
00027 }
00028
00029 VideoOutputNullVAAPI::~VideoOutputNullVAAPI()
00030 {
00031 TearDown();
00032 }
00033
00034 void VideoOutputNullVAAPI::TearDown(void)
00035 {
00036 QMutexLocker lock(&m_lock);
00037 DeleteBuffers();
00038 DeleteVAAPIContext();
00039 }
00040
00041 bool VideoOutputNullVAAPI::CreateVAAPIContext(QSize size)
00042 {
00043 QMutexLocker lock(&m_lock);
00044 if (m_ctx)
00045 DeleteVAAPIContext();
00046
00047 m_ctx = new VAAPIContext(kVADisplayX11, video_codec_id);
00048 if (m_ctx && m_ctx->CreateDisplay(size))
00049 return true;
00050 return false;
00051 }
00052
00053 void VideoOutputNullVAAPI::DeleteVAAPIContext(void)
00054 {
00055 QMutexLocker lock(&m_lock);
00056 delete m_ctx;
00057 m_ctx = NULL;
00058 }
00059
00060 bool VideoOutputNullVAAPI::InitBuffers(void)
00061 {
00062 QMutexLocker lock(&m_lock);
00063 if (!codec_is_vaapi_hw(video_codec_id) || !m_ctx ||
00064 !m_ctx->CreateBuffers())
00065 {
00066 return false;
00067 }
00068
00069
00070 vbuffers.Init(24, true, 2, 1, 4, 1);
00071 int num_buffers = m_ctx->GetNumBuffers();
00072 const QSize video_dim = window.GetActualVideoDim();
00073 bool ok = true;
00074 for (int i = 0; i < num_buffers; i++)
00075 {
00076 ok &= vbuffers.CreateBuffer(video_dim.width(),
00077 video_dim.height(), i,
00078 m_ctx->GetVideoSurface(i),
00079 FMT_VAAPI);
00080 }
00081
00082
00083 m_shadowBuffers = new VideoBuffers();
00084 if (!m_shadowBuffers)
00085 return false;
00086 m_shadowBuffers->Init(24, true, 2, 1, 4, 1);
00087 if (!m_shadowBuffers->CreateBuffers(FMT_YV12,
00088 video_dim.width(),
00089 video_dim.height()))
00090 {
00091 return false;
00092 }
00093
00094 return true;
00095 }
00096
00097 void VideoOutputNullVAAPI::DeleteBuffers(void)
00098 {
00099 QMutexLocker lock(&m_lock);
00100 DiscardFrames(true);
00101 vbuffers.Reset();
00102 vbuffers.DeleteBuffers();
00103 if (m_shadowBuffers)
00104 {
00105 m_shadowBuffers->Reset();
00106 m_shadowBuffers->DeleteBuffers();
00107 }
00108 delete m_shadowBuffers;
00109 m_shadowBuffers = NULL;
00110 }
00111
00112 QStringList VideoOutputNullVAAPI::GetAllowedRenderers(MythCodecID myth_codec_id)
00113 {
00114 QStringList list;
00115 if ((codec_is_vaapi_hw(myth_codec_id)) && !getenv("NO_VAAPI"))
00116 list += "nullvaapi";
00117 return list;
00118 }
00119
00120 bool VideoOutputNullVAAPI::Init(int width, int height, float aspect,
00121 WId winid, const QRect &win_rect,
00122 MythCodecID codec_id)
00123 {
00124 QMutexLocker locker(&m_lock);
00125 bool ok = VideoOutput::Init(width, height, aspect, winid, win_rect, codec_id);
00126 if (!codec_is_vaapi_hw(video_codec_id))
00127 return false;
00128
00129 if (db_vdisp_profile)
00130 db_vdisp_profile->SetVideoRenderer("nullvaapi");
00131 if (ok) ok = CreateVAAPIContext(window.GetActualVideoDim());
00132 if (ok) ok = InitBuffers();
00133 if (!ok)
00134 return false;
00135
00136 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00137 "Created VAAPI context with GPU decoding");
00138 return ok;
00139 }
00140
00141 bool VideoOutputNullVAAPI::InputChanged(const QSize &input_size,
00142 float aspect,
00143 MythCodecID av_codec_id,
00144 void *codec_private,
00145 bool &aspect_only)
00146 {
00147 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00148 QString("InputChanged(%1,%2,%3) '%4'->'%5'")
00149 .arg(input_size.width()).arg(input_size.height()).arg(aspect)
00150 .arg(toString(video_codec_id)).arg(toString(av_codec_id)));
00151
00152 QMutexLocker locker(&m_lock);
00153
00154 bool cid_changed = (video_codec_id != av_codec_id);
00155 bool res_changed = input_size != window.GetActualVideoDim();
00156 if (!res_changed && !cid_changed)
00157 {
00158 aspect_only = true;
00159 return true;
00160 }
00161
00162 TearDown();
00163 QRect disp = window.GetDisplayVisibleRect();
00164 if (Init(input_size.width(), input_size.height(),
00165 aspect, 0, disp, av_codec_id))
00166 {
00167 return true;
00168 }
00169
00170 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to re-initialise video output.");
00171 errorState = kError_Unknown;
00172 return false;
00173 }
00174
00175 void* VideoOutputNullVAAPI::GetDecoderContext(unsigned char* buf, uint8_t*& id)
00176 {
00177 if (m_ctx)
00178 {
00179 id = m_ctx->GetSurfaceIDPointer(buf);
00180 return &m_ctx->m_ctx;
00181 }
00182 return NULL;
00183 }
00184
00185
00186 VideoFrame* VideoOutputNullVAAPI::GetLastDecodedFrame(void)
00187 {
00188 VideoFrame* gpu = vbuffers.GetLastDecodedFrame();
00189 for (uint i = 0; i < vbuffers.Size(); i++)
00190 if (vbuffers.at(i) == gpu)
00191 return m_shadowBuffers->at(i);
00192 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find frame.");
00193 return NULL;
00194 }
00195
00196
00197 VideoFrame* VideoOutputNullVAAPI::GetLastShownFrame(void)
00198 {
00199 VideoFrame* gpu = vbuffers.GetLastShownFrame();
00200 for (uint i = 0; i < vbuffers.Size(); i++)
00201 if (vbuffers.at(i) == gpu)
00202 return m_shadowBuffers->at(i);
00203 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find frame.");
00204 return NULL;
00205 }
00206
00207
00208 void VideoOutputNullVAAPI::DiscardFrame(VideoFrame *frame)
00209 {
00210
00211 for (uint i = 0; i < m_shadowBuffers->Size(); i++)
00212 {
00213 if (m_shadowBuffers->at(i) == frame)
00214 {
00215 frame = vbuffers.at(i);
00216 break;
00217 }
00218 }
00219
00220
00221 for (uint i = 0; i < vbuffers.Size(); i++)
00222 {
00223 if (vbuffers.at(i) == frame)
00224 {
00225 m_lock.lock();
00226 vbuffers.DiscardFrame(frame);
00227 m_lock.unlock();
00228 return;
00229 }
00230 }
00231 }
00232
00233
00234 void VideoOutputNullVAAPI::DoneDisplayingFrame(VideoFrame *frame)
00235 {
00236
00237 for (uint i = 0; i < m_shadowBuffers->Size(); i++)
00238 {
00239 if (m_shadowBuffers->at(i) == frame)
00240 {
00241 frame = vbuffers.at(i);
00242 break;
00243 }
00244 }
00245
00246
00247 for (uint i = 0; i < vbuffers.Size(); i++)
00248 {
00249 if (vbuffers.at(i) == frame)
00250 {
00251 m_lock.lock();
00252 VideoOutput::DiscardFrame(frame);
00253 m_lock.unlock();
00254 return;
00255 }
00256 }
00257 }
00258
00259 void VideoOutputNullVAAPI::ReleaseFrame(VideoFrame *frame)
00260 {
00261 if (!frame)
00262 return;
00263
00264 if ((frame->codec != FMT_VAAPI) || !m_ctx)
00265 {
00266 VideoOutput::ReleaseFrame(frame);
00267 return;
00268 }
00269
00270 QMutexLocker lock(&m_lock);
00271 for (uint i = 0; i < vbuffers.Size() && m_ctx; i++)
00272 {
00273 if (vbuffers.at(i)->buf == frame->buf)
00274 {
00275 VideoFrame *vf = m_shadowBuffers->at(i);
00276 vf->aspect = frame->aspect;
00277 vf->disp_timecode = frame->disp_timecode;
00278 vf->dummy = frame->dummy;
00279 vf->frameNumber = frame->frameNumber;
00280 vf->interlaced_frame = frame->interlaced_frame;
00281 vf->timecode = frame->timecode;
00282 vf->repeat_pict = frame->repeat_pict;
00283 vf->top_field_first = frame->top_field_first;
00284 m_ctx->CopySurfaceToFrame(vf, vbuffers.at(i)->buf);
00285 }
00286 }
00287 VideoOutput::ReleaseFrame(frame);
00288 }