17 #include "libavfilter/buffersrc.h"
18 #include "libavfilter/buffersink.h"
19 #include "libavutil/hwcontext_vaapi.h"
22 #define LOC QString("VAAPIInterop: ")
46 bool egl = Context->
IsEGL();
47 bool opengles = Context->isOpenGLES();
48 bool wayland = qgetenv(
"XDG_SESSION_TYPE").contains(
"wayland");
53 #ifdef USING_DRM_VIDEO
67 if (!egl && !opengles && !wayland)
70 if (!vaapitypes.empty())
82 for (
auto type : vaapi->second)
114 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Error closing VAAPI display");
135 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to initialise VAAPI display");
142 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Created VAAPI %1.%2 display for %3 (%4)")
150 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Destroying VAAPI deinterlacer");
165 VASurfaceID result = 0;
176 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Mismatched OpenGL contexts!");
181 QSize surfacesize(
Frame->m_width,
Frame->m_height);
185 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Video texture size changed!");
190 auto id =
static_cast<VASurfaceID
>(
reinterpret_cast<uintptr_t
>(
Frame->m_buffer));
197 AVBufferRef *FramesContext,
198 int Width,
int Height,
200 AVFilterGraph *&Graph,
202 AVFilterContext *&Sink)
206 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No hardware frames context");
212 QString deinterlacer =
"bob";
214 deinterlacer =
"motion_adaptive";
216 deinterlacer =
"motion_compensated";
219 QString filters = QString(
"deinterlace_vaapi=mode=%1:rate=%2:auto=0")
220 .arg(deinterlacer, DoubleRate ?
"field" :
"frame");
221 const AVFilter *buffersrc = avfilter_get_by_name(
"buffer");
222 const AVFilter *buffersink = avfilter_get_by_name(
"buffersink");
223 AVFilterInOut *outputs = avfilter_inout_alloc();
224 AVFilterInOut *inputs = avfilter_inout_alloc();
225 AVBufferSrcParameters* params =
nullptr;
227 Graph = avfilter_graph_alloc();
228 if (!outputs || !inputs || !Graph)
230 ret = AVERROR(ENOMEM);
235 args = QString(
"video_size=%1x%2:pix_fmt=%3:time_base=1/1")
236 .arg(Width).arg(Height).arg(AV_PIX_FMT_VAAPI);
238 ret = avfilter_graph_create_filter(&
Source, buffersrc,
"in",
239 args.toLocal8Bit().constData(),
nullptr, Graph);
242 LOG(VB_GENERAL, LOG_ERR,
LOC +
"avfilter_graph_create_filter failed for buffer source");
246 params = av_buffersrc_parameters_alloc();
247 params->hw_frames_ctx = FramesContext;
248 ret = av_buffersrc_parameters_set(
Source, params);
252 LOG(VB_GENERAL, LOG_ERR,
LOC +
"av_buffersrc_parameters_set failed");
255 av_freep(
reinterpret_cast<void*
>(¶ms));
258 ret = avfilter_graph_create_filter(&Sink, buffersink,
"out",
259 nullptr,
nullptr, Graph);
262 LOG(VB_GENERAL, LOG_ERR,
LOC +
"avfilter_graph_create_filter failed for buffer sink");
277 outputs->name = av_strdup(
"in");
278 outputs->filter_ctx =
Source;
279 outputs->pad_idx = 0;
280 outputs->next =
nullptr;
288 inputs->name = av_strdup(
"out");
289 inputs->filter_ctx = Sink;
291 inputs->next =
nullptr;
293 ret = avfilter_graph_parse_ptr(Graph, filters.toLocal8Bit(),
294 &inputs, &outputs,
nullptr);
297 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"avfilter_graph_parse_ptr failed for %1")
302 ret = avfilter_graph_config(Graph,
nullptr);
305 LOG(VB_GENERAL, LOG_ERR,
LOC +
306 QString(
"VAAPI deinterlacer config failed - '%1' unsupported?").arg(deinterlacer));
310 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Created deinterlacer '%1'")
316 avfilter_graph_free(&Graph);
319 avfilter_inout_free(&inputs);
320 avfilter_inout_free(&outputs);
326 VASurfaceID result = Current;
334 bool doublerate =
true;
342 deinterlacer = doublepref;
346 deinterlacer = singlepref;
357 auto* frames =
reinterpret_cast<AVBufferRef*
>(
Frame->m_priv[1]);
361 AVBufferRef* hwdeviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI);
365 auto* hwdevicecontext =
reinterpret_cast<AVHWDeviceContext*
>(hwdeviceref->data);
366 hwdevicecontext->free = [](AVHWDeviceContext* ) {
LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"VAAPI VPP device context finished"); };
368 auto *vaapidevicectx =
reinterpret_cast<AVVAAPIDeviceContext*
>(hwdevicecontext->hwctx);
371 if (av_hwdevice_ctx_init(hwdeviceref) < 0)
373 av_buffer_unref(&hwdeviceref);
378 AVBufferRef *newframes = av_hwframe_ctx_alloc(hwdeviceref);
382 av_buffer_unref(&hwdeviceref);
386 auto* dstframes =
reinterpret_cast<AVHWFramesContext*
>(newframes->data);
387 auto* srcframes =
reinterpret_cast<AVHWFramesContext*
>(frames->data);
391 static constexpr
int kVppPoolSize = 2;
392 dstframes->sw_format = srcframes->sw_format;
395 dstframes->initial_pool_size = kVppPoolSize;
396 dstframes->format = AV_PIX_FMT_VAAPI;
397 dstframes->free = [](AVHWFramesContext* ) {
LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"VAAPI VPP frames context finished"); };
399 if (av_hwframe_ctx_init(newframes) < 0)
402 av_buffer_unref(&hwdeviceref);
403 av_buffer_unref(&newframes);
408 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"New VAAPI frame pool with %1 %2x%3 surfaces")
410 av_buffer_unref(&hwdeviceref);
416 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to create VAAPI deinterlacer %1 - disabling")
453 while ((result == Current) && retries--)
459 sinkframe->format = AV_PIX_FMT_VAAPI;
468 result =
m_lastFilteredFrame =
static_cast<VASurfaceID
>(
reinterpret_cast<uintptr_t
>(sinkframe->data[3]));
473 if (ret != AVERROR(EAGAIN))
479 sourceframe->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
480 if (
Frame->m_interlacedReverse ^
Frame->m_topFieldFirst)
482 sourceframe->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
484 sourceframe->flags |= AV_FRAME_FLAG_INTERLACED;
485 sourceframe->data[3] =
Frame->m_buffer;
486 auto* buffer =
reinterpret_cast<AVBufferRef*
>(
Frame->m_priv[0]);
487 sourceframe->buf[0] = buffer ? av_buffer_ref(buffer) :
nullptr;
490 sourceframe->format = AV_PIX_FMT_VAAPI;
496 sourceframe->data[3] =
nullptr;
497 sourceframe->buf[0] =
nullptr;
506 result =
m_lastFilteredFrame =
static_cast<VASurfaceID
>(
reinterpret_cast<uintptr_t
>(sinkframe->data[3]));