#include "libavutil/common.h"
#include "libavutil/mathematics.h"
-#include "libavutil/hwcontext.h"
-#include "libavutil/hwcontext_qsv.h"
#include "libavutil/time.h"
#include "libavutil/pixdesc.h"
#include "qsvvpp.h"
#include "video.h"
+#if QSV_ONEVPL
+#include <mfxdispatcher.h>
+#else
+#define MFXUnload(a) do { } while(0)
+#endif
+
#define IS_VIDEO_MEMORY(mode) (mode & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \
MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET))
+#if QSV_HAVE_OPAQUE
#define IS_OPAQUE_MEMORY(mode) (mode & MFX_MEMTYPE_OPAQUE_FRAME)
+#endif
#define IS_SYSTEM_MEMORY(mode) (mode & MFX_MEMTYPE_SYSTEM_MEMORY)
#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
+#define QSV_HAVE_AUDIO !QSV_ONEVPL
+
static const AVRational default_tb = { 1, 90000 };
typedef struct QSVAsyncFrame {
} qsv_iopatterns[] = {
{MFX_IOPATTERN_IN_VIDEO_MEMORY, "input is video memory surface" },
{MFX_IOPATTERN_IN_SYSTEM_MEMORY, "input is system memory surface" },
+#if QSV_HAVE_OPAQUE
{MFX_IOPATTERN_IN_OPAQUE_MEMORY, "input is opaque memory surface" },
+#endif
{MFX_IOPATTERN_OUT_VIDEO_MEMORY, "output is video memory surface" },
{MFX_IOPATTERN_OUT_SYSTEM_MEMORY, "output is system memory surface" },
+#if QSV_HAVE_OPAQUE
{MFX_IOPATTERN_OUT_OPAQUE_MEMORY, "output is opaque memory surface" },
+#endif
};
int ff_qsvvpp_print_iopattern(void *log_ctx, int mfx_iopattern,
{ MFX_ERR_INVALID_VIDEO_PARAM, AVERROR(EINVAL), "invalid video parameters" },
{ MFX_ERR_UNDEFINED_BEHAVIOR, AVERROR_BUG, "undefined behavior" },
{ MFX_ERR_DEVICE_FAILED, AVERROR(EIO), "device failed" },
+#if QSV_HAVE_AUDIO
{ MFX_ERR_INCOMPATIBLE_AUDIO_PARAM, AVERROR(EINVAL), "incompatible audio parameters" },
{ MFX_ERR_INVALID_AUDIO_PARAM, AVERROR(EINVAL), "invalid audio parameters" },
+#endif
+ { MFX_ERR_GPU_HANG, AVERROR(EIO), "GPU Hang" },
+ { MFX_ERR_REALLOC_SURFACE, AVERROR_UNKNOWN, "need bigger surface for output" },
{ MFX_WRN_IN_EXECUTION, 0, "operation in execution" },
{ MFX_WRN_DEVICE_BUSY, 0, "device busy" },
{ MFX_WRN_VALUE_NOT_CHANGED, 0, "value is saturated" },
{ MFX_WRN_OUT_OF_RANGE, 0, "value out of range" },
{ MFX_WRN_FILTER_SKIPPED, 0, "filter skipped" },
+#if QSV_HAVE_AUDIO
{ MFX_WRN_INCOMPATIBLE_AUDIO_PARAM, 0, "incompatible audio parameters" },
+#endif
+
+#if QSV_VERSION_ATLEAST(1, 31)
+ { MFX_ERR_NONE_PARTIAL_OUTPUT, 0, "partial output" },
+#endif
};
static int qsv_map_error(mfxStatus mfx_err, const char **desc)
return MFX_FOURCC_YUY2;
case AV_PIX_FMT_BGRA:
return MFX_FOURCC_RGB4;
+ case AV_PIX_FMT_P010:
+ return MFX_FOURCC_P010;
+#if CONFIG_VAAPI
+ case AV_PIX_FMT_UYVY422:
+ return MFX_FOURCC_UYVY;
+#endif
}
return MFX_FOURCC_NV12;
surface->Data.R = frame->data[0] + 2;
surface->Data.A = frame->data[0] + 3;
break;
+ case AV_PIX_FMT_UYVY422:
+ surface->Data.Y = frame->data[0] + 1;
+ surface->Data.U = frame->data[0];
+ surface->Data.V = frame->data[0] + 2;
+ break;
default:
return MFX_ERR_UNSUPPORTED;
}
frameinfo->CropH = link->h;
frameinfo->FrameRateExtN = link->frame_rate.num;
frameinfo->FrameRateExtD = link->frame_rate.den;
+
+ /* Apparently VPP in the SDK requires the frame rate to be set to some value, otherwise
+ * init will fail */
+ if (frameinfo->FrameRateExtD == 0 || frameinfo->FrameRateExtN == 0) {
+ frameinfo->FrameRateExtN = 25;
+ frameinfo->FrameRateExtD = 1;
+ }
+
frameinfo->AspectRatioW = link->sample_aspect_ratio.num ? link->sample_aspect_ratio.num : 1;
frameinfo->AspectRatioH = link->sample_aspect_ratio.den ? link->sample_aspect_ratio.den : 1;
return NULL;
}
- av_frame_copy_props(qsv_frame->frame, picref);
+ if (av_frame_copy_props(qsv_frame->frame, picref) < 0) {
+ av_frame_free(&qsv_frame->frame);
+ return NULL;
+ }
} else
qsv_frame->frame = av_frame_clone(picref);
inlink->time_base, default_tb);
qsv_frame->surface.Info.PicStruct =
- !qsv_frame->frame->interlaced_frame ? MFX_PICSTRUCT_PROGRESSIVE :
- (qsv_frame->frame->top_field_first ? MFX_PICSTRUCT_FIELD_TFF :
+ !(qsv_frame->frame->flags & AV_FRAME_FLAG_INTERLACED) ? MFX_PICSTRUCT_PROGRESSIVE :
+ ((qsv_frame->frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? MFX_PICSTRUCT_FIELD_TFF :
MFX_PICSTRUCT_FIELD_BFF);
if (qsv_frame->frame->repeat_pict == 1)
qsv_frame->surface.Info.PicStruct |= MFX_PICSTRUCT_FIELD_REPEATED;
}
/* get the output surface */
-static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink)
+static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink, const AVFrame *in)
{
AVFilterContext *ctx = outlink->src;
QSVFrame *out_frame;
if (!out_frame->frame)
return NULL;
+ ret = av_frame_copy_props(out_frame->frame, in);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to copy metadata fields from src to dst.\n");
+ return NULL;
+ }
+
ret = av_hwframe_get_buffer(outlink->hw_frames_ctx, out_frame->frame, 0);
if (ret < 0) {
av_log(ctx, AV_LOG_ERROR, "Can't allocate a surface.\n");
if (!out_frame->frame)
return NULL;
- out_frame->frame->width = outlink->w;
- out_frame->frame->height = outlink->h;
+ ret = av_frame_copy_props(out_frame->frame, in);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to copy metadata fields from src to dst.\n");
+ return NULL;
+ }
ret = map_frame_to_surface(out_frame->frame,
&out_frame->surface);
return NULL;
}
+ if (outlink->frame_rate.num && outlink->frame_rate.den)
+ out_frame->frame->duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+ else
+ out_frame->frame->duration = 0;
+
+ out_frame->frame->width = outlink->w;
+ out_frame->frame->height = outlink->h;
out_frame->surface.Info = s->vpp_param.vpp.Out;
+ for (int i = 0; i < s->vpp_param.NumExtParam; i++) {
+ mfxExtBuffer *extbuf = s->vpp_param.ExtParam[i];
+
+ if (extbuf->BufferId == MFX_EXTBUFF_VPP_DEINTERLACING) {
+#if FF_API_INTERLACED_FRAME
+FF_DISABLE_DEPRECATION_WARNINGS
+ out_frame->frame->interlaced_frame = 0;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+ out_frame->frame->flags &= ~AV_FRAME_FLAG_INTERLACED;
+ break;
+ }
+ }
+
+ out_frame->surface.Info.PicStruct =
+ !(out_frame->frame->flags & AV_FRAME_FLAG_INTERLACED) ? MFX_PICSTRUCT_PROGRESSIVE :
+ ((out_frame->frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? MFX_PICSTRUCT_FIELD_TFF :
+ MFX_PICSTRUCT_FIELD_BFF);
+
return out_frame;
}
if (!out_frames_ref)
return AVERROR(ENOMEM);
+#if QSV_HAVE_OPAQUE
s->out_mem_mode = IS_OPAQUE_MEMORY(s->in_mem_mode) ?
MFX_MEMTYPE_OPAQUE_FRAME :
MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | MFX_MEMTYPE_FROM_VPPOUT;
+#else
+ s->out_mem_mode = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | MFX_MEMTYPE_FROM_VPPOUT;
+#endif
out_frames_ctx = (AVHWFramesContext *)out_frames_ref->data;
out_frames_hwctx = out_frames_ctx->hwctx;
}
/* create a "slave" session with those same properties, to be used for vpp */
- ret = MFXInit(impl, &ver, &s->session);
- if (ret < 0)
- return ff_qsvvpp_print_error(avctx, ret, "Error initializing a session");
- else if (ret > 0) {
- ff_qsvvpp_print_warning(avctx, ret, "Warning in session initialization");
+ ret = ff_qsvvpp_create_mfx_session(avctx, device_hwctx->loader, impl, &ver,
+ &s->session);
+ if (ret)
+ return ret;
+
+ ret = MFXQueryVersion(s->session, &s->ver);
+ if (ret != MFX_ERR_NONE) {
+ av_log(avctx, AV_LOG_ERROR, "Error querying the runtime version\n");
return AVERROR_UNKNOWN;
}
return AVERROR_UNKNOWN;
}
+#if QSV_HAVE_OPAQUE
if (IS_OPAQUE_MEMORY(s->in_mem_mode) || IS_OPAQUE_MEMORY(s->out_mem_mode)) {
s->opaque_alloc.In.Surfaces = s->surface_ptrs_in;
s->opaque_alloc.In.NumSurface = s->nb_surface_ptrs_in;
s->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
s->opaque_alloc.Header.BufferSz = sizeof(s->opaque_alloc);
- } else if (IS_VIDEO_MEMORY(s->in_mem_mode) || IS_VIDEO_MEMORY(s->out_mem_mode)) {
+ } else
+#endif
+ if (IS_VIDEO_MEMORY(s->in_mem_mode) || IS_VIDEO_MEMORY(s->out_mem_mode)) {
mfxFrameAllocator frame_allocator = {
.pthis = s,
.Alloc = frame_alloc,
return 0;
}
-int ff_qsvvpp_create(AVFilterContext *avctx, QSVVPPContext **vpp, QSVVPPParam *param)
+static int set_frame_ext_params_null(AVFilterContext *ctx, const AVFrame *in, AVFrame *out, QSVVPPFrameParam *fp)
+{
+ return 0;
+}
+
+int ff_qsvvpp_init(AVFilterContext *avctx, QSVVPPParam *param)
{
int i;
int ret;
- QSVVPPContext *s;
-
- s = av_mallocz(sizeof(*s));
- if (!s)
- return AVERROR(ENOMEM);
+ QSVVPPContext *s = avctx->priv;
s->filter_frame = param->filter_frame;
if (!s->filter_frame)
s->filter_frame = ff_filter_frame;
s->out_sw_format = param->out_sw_format;
+ s->set_frame_ext_params = param->set_frame_ext_params;
+ if (!s->set_frame_ext_params)
+ s->set_frame_ext_params = set_frame_ext_params_null;
+
/* create the vpp session */
ret = init_vpp_session(avctx, s);
if (ret < 0)
goto failed;
}
- if (IS_OPAQUE_MEMORY(s->in_mem_mode) || IS_OPAQUE_MEMORY(s->out_mem_mode)) {
- s->nb_ext_buffers = param->num_ext_buf + 1;
+ s->nb_seq_buffers = param->num_ext_buf;
+#if QSV_HAVE_OPAQUE
+ if (IS_OPAQUE_MEMORY(s->in_mem_mode) || IS_OPAQUE_MEMORY(s->out_mem_mode))
+ s->nb_seq_buffers++;
+#endif
+
+ if (s->nb_seq_buffers) {
+ s->seq_buffers = av_calloc(s->nb_seq_buffers, sizeof(*s->seq_buffers));
+ if (!s->seq_buffers) {
+ ret = AVERROR(ENOMEM);
+ goto failed;
+ }
+
+ for (i = 0; i < param->num_ext_buf; i++)
+ s->seq_buffers[i] = param->ext_buf[i];
+
+#if QSV_HAVE_OPAQUE
+ if (IS_OPAQUE_MEMORY(s->in_mem_mode) || IS_OPAQUE_MEMORY(s->out_mem_mode))
+ s->seq_buffers[i] = (mfxExtBuffer *)&s->opaque_alloc;
+#endif
+
+ s->nb_ext_buffers = s->nb_seq_buffers;
s->ext_buffers = av_calloc(s->nb_ext_buffers, sizeof(*s->ext_buffers));
if (!s->ext_buffers) {
ret = AVERROR(ENOMEM);
goto failed;
}
- s->ext_buffers[0] = (mfxExtBuffer *)&s->opaque_alloc;
- for (i = 1; i < param->num_ext_buf; i++)
- s->ext_buffers[i] = param->ext_buf[i - 1];
- s->vpp_param.ExtParam = s->ext_buffers;
- s->vpp_param.NumExtParam = s->nb_ext_buffers;
- } else {
- s->vpp_param.NumExtParam = param->num_ext_buf;
- s->vpp_param.ExtParam = param->ext_buf;
+ memcpy(s->ext_buffers, s->seq_buffers, s->nb_seq_buffers * sizeof(*s->seq_buffers));
}
+ s->vpp_param.ExtParam = s->ext_buffers;
+ s->vpp_param.NumExtParam = s->nb_ext_buffers;
+
s->got_frame = 0;
/** keep fifo size at least 1. Even when async_depth is 0, fifo is used. */
- s->async_fifo = av_fifo_alloc2(param->async_depth + 1, sizeof(QSVAsyncFrame), 0);
- s->async_depth = param->async_depth;
+ s->async_fifo = av_fifo_alloc2(s->async_depth + 1, sizeof(QSVAsyncFrame), 0);
if (!s->async_fifo) {
ret = AVERROR(ENOMEM);
goto failed;
}
- s->vpp_param.AsyncDepth = param->async_depth;
+ s->vpp_param.AsyncDepth = s->async_depth;
if (IS_SYSTEM_MEMORY(s->in_mem_mode))
s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_SYSTEM_MEMORY;
else if (IS_VIDEO_MEMORY(s->in_mem_mode))
s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_VIDEO_MEMORY;
+#if QSV_HAVE_OPAQUE
else if (IS_OPAQUE_MEMORY(s->in_mem_mode))
s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_OPAQUE_MEMORY;
+#endif
if (IS_SYSTEM_MEMORY(s->out_mem_mode))
s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
else if (IS_VIDEO_MEMORY(s->out_mem_mode))
s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_VIDEO_MEMORY;
+#if QSV_HAVE_OPAQUE
else if (IS_OPAQUE_MEMORY(s->out_mem_mode))
s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
+#endif
/* Print input memory mode */
ff_qsvvpp_print_iopattern(avctx, s->vpp_param.IOPattern & 0x0F, "VPP");
/* Print output memory mode */
ff_qsvvpp_print_iopattern(avctx, s->vpp_param.IOPattern & 0xF0, "VPP");
- ret = MFXVideoVPP_Init(s->session, &s->vpp_param);
+
+ /* Validate VPP params, but don't initial VPP session here */
+ ret = MFXVideoVPP_Query(s->session, &s->vpp_param, &s->vpp_param);
if (ret < 0) {
- ret = ff_qsvvpp_print_error(avctx, ret, "Failed to create a qsvvpp");
+ ret = ff_qsvvpp_print_error(avctx, ret, "Error querying VPP params");
goto failed;
} else if (ret > 0)
- ff_qsvvpp_print_warning(avctx, ret, "Warning When creating qsvvpp");
+ ff_qsvvpp_print_warning(avctx, ret, "Warning When querying VPP params");
- *vpp = s;
return 0;
failed:
- ff_qsvvpp_free(&s);
+ ff_qsvvpp_close(avctx);
return ret;
}
-int ff_qsvvpp_free(QSVVPPContext **vpp)
+static int qsvvpp_init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s, const QSVFrame *in, QSVFrame *out)
{
- QSVVPPContext *s = *vpp;
+ int ret;
+ mfxExtBuffer *ext_param[QSVVPP_MAX_FRAME_EXTBUFS];
+ QSVVPPFrameParam fp = { 0, ext_param };
- if (!s)
- return 0;
+ ret = s->set_frame_ext_params(avctx, in->frame, out->frame, &fp);
+ if (ret)
+ return ret;
+
+ if (fp.num_ext_buf) {
+ av_freep(&s->ext_buffers);
+ s->nb_ext_buffers = s->nb_seq_buffers + fp.num_ext_buf;
+
+ s->ext_buffers = av_calloc(s->nb_ext_buffers, sizeof(*s->ext_buffers));
+ if (!s->ext_buffers)
+ return AVERROR(ENOMEM);
+
+ memcpy(&s->ext_buffers[0], s->seq_buffers, s->nb_seq_buffers * sizeof(*s->seq_buffers));
+ memcpy(&s->ext_buffers[s->nb_seq_buffers], fp.ext_buf, fp.num_ext_buf * sizeof(*fp.ext_buf));
+ s->vpp_param.ExtParam = s->ext_buffers;
+ s->vpp_param.NumExtParam = s->nb_ext_buffers;
+ }
+
+ if (!s->vpp_initted) {
+ s->vpp_param.vpp.In.PicStruct = in->surface.Info.PicStruct;
+ s->vpp_param.vpp.Out.PicStruct = out->surface.Info.PicStruct;
+
+ /* Query VPP params again, including params for frame */
+ ret = MFXVideoVPP_Query(s->session, &s->vpp_param, &s->vpp_param);
+ if (ret < 0)
+ return ff_qsvvpp_print_error(avctx, ret, "Error querying VPP params");
+ else if (ret > 0)
+ ff_qsvvpp_print_warning(avctx, ret, "Warning When querying VPP params");
+
+ ret = MFXVideoVPP_Init(s->session, &s->vpp_param);
+ if (ret < 0)
+ return ff_qsvvpp_print_error(avctx, ret, "Failed to create a qsvvpp");
+ else if (ret > 0)
+ ff_qsvvpp_print_warning(avctx, ret, "Warning When creating qsvvpp");
+
+ s->vpp_initted = 1;
+ } else if (fp.num_ext_buf) {
+ ret = MFXVideoVPP_Reset(s->session, &s->vpp_param);
+ if (ret < 0) {
+ ret = ff_qsvvpp_print_error(avctx, ret, "Failed to reset session for qsvvpp");
+ return ret;
+ } else if (ret > 0)
+ ff_qsvvpp_print_warning(avctx, ret, "Warning When resetting session for qsvvpp");
+ }
+
+ return 0;
+}
+
+int ff_qsvvpp_close(AVFilterContext *avctx)
+{
+ QSVVPPContext *s = avctx->priv;
if (s->session) {
MFXVideoVPP_Close(s->session);
MFXClose(s->session);
+ s->session = NULL;
+ s->vpp_initted = 0;
}
/* release all the resources */
clear_frame_list(&s->out_frame_list);
av_freep(&s->surface_ptrs_in);
av_freep(&s->surface_ptrs_out);
+ av_freep(&s->seq_buffers);
av_freep(&s->ext_buffers);
av_freep(&s->frame_infos);
av_fifo_freep2(&s->async_fifo);
- av_freep(vpp);
return 0;
}
QSVAsyncFrame aframe;
mfxSyncPoint sync;
QSVFrame *in_frame, *out_frame;
- int ret, filter_ret;
+ int ret, ret1, filter_ret;
while (s->eof && av_fifo_read(s->async_fifo, &aframe, 1) >= 0) {
if (MFXVideoCORE_SyncOperation(s->session, aframe.sync, 1000) < 0)
}
do {
- out_frame = query_frame(s, outlink);
+ out_frame = query_frame(s, outlink, in_frame->frame);
if (!out_frame) {
av_log(ctx, AV_LOG_ERROR, "Failed to query an output frame.\n");
return AVERROR(ENOMEM);
}
+ ret = qsvvpp_init_vpp_session(ctx, s, in_frame, out_frame);
+ if (ret)
+ return ret;
+
do {
ret = MFXVideoVPP_RunFrameVPPAsync(s->session, &in_frame->surface,
&out_frame->surface, NULL, &sync);
av_fifo_read(s->async_fifo, &aframe, 1);
do {
- ret = MFXVideoCORE_SyncOperation(s->session, aframe.sync, 1000);
- } while (ret == MFX_WRN_IN_EXECUTION);
+ ret1 = MFXVideoCORE_SyncOperation(s->session, aframe.sync, 1000);
+ } while (ret1 == MFX_WRN_IN_EXECUTION);
+
+ if (ret1 < 0) {
+ ret = ret1;
+ break;
+ }
filter_ret = s->filter_frame(outlink, aframe.frame->frame);
if (filter_ret < 0) {
return 0;
}
+
+#if QSV_ONEVPL
+
+int ff_qsvvpp_create_mfx_session(void *ctx,
+ void *loader,
+ mfxIMPL implementation,
+ mfxVersion *pver,
+ mfxSession *psession)
+{
+ mfxStatus sts;
+ mfxSession session = NULL;
+ uint32_t impl_idx = 0;
+
+ av_log(ctx, AV_LOG_VERBOSE,
+ "Use Intel(R) oneVPL to create MFX session with the specified MFX loader\n");
+
+ if (!loader) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid MFX Loader handle\n");
+ return AVERROR(EINVAL);
+ }
+
+ while (1) {
+ /* Enumerate all implementations */
+ mfxImplDescription *impl_desc;
+
+ sts = MFXEnumImplementations(loader, impl_idx,
+ MFX_IMPLCAPS_IMPLDESCSTRUCTURE,
+ (mfxHDL *)&impl_desc);
+ /* Failed to find an available implementation */
+ if (sts == MFX_ERR_NOT_FOUND)
+ break;
+ else if (sts != MFX_ERR_NONE) {
+ impl_idx++;
+ continue;
+ }
+
+ sts = MFXCreateSession(loader, impl_idx, &session);
+ MFXDispReleaseImplDescription(loader, impl_desc);
+ if (sts == MFX_ERR_NONE)
+ break;
+
+ impl_idx++;
+ }
+
+ if (sts < 0)
+ return ff_qsvvpp_print_error(ctx, sts,
+ "Error creating a MFX session");
+ else if (sts > 0) {
+ ff_qsvvpp_print_warning(ctx, sts,
+ "Warning in MFX session creation");
+ return AVERROR_UNKNOWN;
+ }
+
+ *psession = session;
+
+ return 0;
+}
+
+#else
+
+int ff_qsvvpp_create_mfx_session(void *ctx,
+ void *loader,
+ mfxIMPL implementation,
+ mfxVersion *pver,
+ mfxSession *psession)
+{
+ mfxSession session = NULL;
+ mfxStatus sts;
+
+ av_log(ctx, AV_LOG_VERBOSE,
+ "Use Intel(R) Media SDK to create MFX session, API version is "
+ "%d.%d, the required implementation version is %d.%d\n",
+ MFX_VERSION_MAJOR, MFX_VERSION_MINOR, pver->Major, pver->Minor);
+
+ *psession = NULL;
+ sts = MFXInit(implementation, pver, &session);
+ if (sts < 0)
+ return ff_qsvvpp_print_error(ctx, sts,
+ "Error initializing an MFX session");
+ else if (sts > 0) {
+ ff_qsvvpp_print_warning(ctx, sts, "Warning in MFX session initialization");
+ return AVERROR_UNKNOWN;
+ }
+
+ *psession = session;
+
+ return 0;
+}
+
+#endif
+
+AVFrame *ff_qsvvpp_get_video_buffer(AVFilterLink *inlink, int w, int h)
+{
+ /* When process YUV420 frames, FFmpeg uses same alignment on Y/U/V
+ * planes. VPL and MSDK use Y plane's pitch / 2 as U/V planes's
+ * pitch, which makes U/V planes 16-bytes aligned. We need to set a
+ * separate alignment to meet runtime's behaviour.
+ */
+ return ff_default_get_video_buffer2(inlink,
+ FFALIGN(inlink->w, 32),
+ FFALIGN(inlink->h, 32),
+ 16);
+}