[FFmpeg-devel] [PATCH 3/6] lavc/qsv: Enable hwaccel qsv_vidmem.
Nablet Developer
sdk at nablet.com
Thu Aug 25 10:07:16 EEST 2016
From: ChaoX A Liu <chaox.a.liu at intel.com>
Signed-off-by: ChaoX A Liu <chaox.a.liu at intel.com>
---
ffmpeg.c | 2 +-
ffmpeg.h | 2 +
ffmpeg_opt.c | 2 +-
ffmpeg_qsv.c | 636 +++++++++++++++++++++++++++++++++++++++++++++-
libavcodec/qsv.h | 3 +
libavcodec/qsv_internal.h | 2 +
libavcodec/qsvdec.c | 5 +-
libavcodec/qsvenc.c | 2 +
8 files changed, 649 insertions(+), 5 deletions(-)
diff --git a/ffmpeg.c b/ffmpeg.c
index bad311d..0bab9e9 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -3050,7 +3050,7 @@ static int transcode_init(void)
set_encoder_id(output_files[ost->file_index], ost);
#if CONFIG_LIBMFX
- if (qsv_transcode_init(ost))
+ if (qsv_transcode_init_vidmem(ost))
exit_program(1);
#endif
diff --git a/ffmpeg.h b/ffmpeg.h
index 49d65d8..2633336 100644
--- a/ffmpeg.h
+++ b/ffmpeg.h
@@ -585,6 +585,8 @@ int vda_init(AVCodecContext *s);
int videotoolbox_init(AVCodecContext *s);
int qsv_init(AVCodecContext *s);
int qsv_transcode_init(OutputStream *ost);
+int qsv_init_vidmem(AVCodecContext *s);
+int qsv_transcode_init_vidmem(OutputStream *ost);
int vaapi_decode_init(AVCodecContext *avctx);
int vaapi_device_init(const char *device);
int cuvid_init(AVCodecContext *s);
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
index 2ea09cf..b5e4483 100644
--- a/ffmpeg_opt.c
+++ b/ffmpeg_opt.c
@@ -79,7 +79,7 @@ const HWAccel hwaccels[] = {
{ "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },
#endif
#if CONFIG_LIBMFX
- { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV },
+ { "qsv", qsv_init_vidmem, HWACCEL_QSV, AV_PIX_FMT_QSV },
#endif
#if CONFIG_VAAPI
{ "vaapi", vaapi_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI },
diff --git a/ffmpeg_qsv.c b/ffmpeg_qsv.c
index acc54dd..43402d6 100644
--- a/ffmpeg_qsv.c
+++ b/ffmpeg_qsv.c
@@ -18,11 +18,15 @@
#include <mfx/mfxvideo.h>
#include <stdlib.h>
+#include <stdbool.h>
+#include <va/va.h>
#include "libavutil/dict.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
+#include "libavutil/avstring.h"
#include "libavcodec/qsv.h"
+#include "libavcodec/qsv_internal.h"
#include "ffmpeg.h"
@@ -34,6 +38,8 @@ typedef struct QSVContext {
mfxExtOpaqueSurfaceAlloc opaque_alloc;
AVBufferRef *opaque_surfaces_buf;
+ mfxFrameAllocator frame_allocator;
+
uint8_t *surface_used;
mfxFrameSurface1 **surface_ptrs;
int nb_surfaces;
@@ -60,7 +66,7 @@ static int qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
buffer_release, &qsv->surface_used[i], 0);
if (!frame->buf[0])
return AVERROR(ENOMEM);
- frame->data[3] = (uint8_t*)qsv->surface_ptrs[i];
+ frame->data[3] = frame->buf[0]->data;
qsv->surface_used[i] = 1;
return 0;
}
@@ -265,3 +271,631 @@ fail:
av_freep(&qsv);
return AVERROR_UNKNOWN;
}
+
+enum {
+ MFX_FOURCC_VP8_NV12 = MFX_MAKEFOURCC('V','P','8','N'),
+ MFX_FOURCC_VP8_MBDATA = MFX_MAKEFOURCC('V','P','8','M'),
+ MFX_FOURCC_VP8_SEGMAP = MFX_MAKEFOURCC('V','P','8','S'),
+};
+
+typedef struct vaapiMemId
+{
+ VASurfaceID* m_surface;
+ VAImage m_image;
+ unsigned int m_fourcc;
+ mfxU8* m_sys_buffer;
+ mfxU8* m_va_buffer;
+} vaapiMemId;
+
+static QSVSession g_session;
+
+/* ****************************************************************************** *\
+
+INTEL CORPORATION PROPRIETARY INFORMATION
+This software is supplied under the terms of a license agreement or nondisclosure
+agreement with Intel Corporation and may not be copied or disclosed except in
+accordance with the terms of that agreement
+Copyright(c) 2011-2014 Intel Corporation. All Rights Reserved.
+
+\* ****************************************************************************** */
+static mfxStatus va_to_mfx_status(VAStatus va_res)
+{
+ mfxStatus mfxRes = MFX_ERR_NONE;
+
+ switch (va_res) {
+ case VA_STATUS_SUCCESS:
+ mfxRes = MFX_ERR_NONE;
+ break;
+ case VA_STATUS_ERROR_ALLOCATION_FAILED:
+ mfxRes = MFX_ERR_MEMORY_ALLOC;
+ break;
+ case VA_STATUS_ERROR_ATTR_NOT_SUPPORTED:
+ case VA_STATUS_ERROR_UNSUPPORTED_PROFILE:
+ case VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT:
+ case VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT:
+ case VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE:
+ case VA_STATUS_ERROR_FLAG_NOT_SUPPORTED:
+ case VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED:
+ mfxRes = MFX_ERR_UNSUPPORTED;
+ break;
+ case VA_STATUS_ERROR_INVALID_DISPLAY:
+ case VA_STATUS_ERROR_INVALID_CONFIG:
+ case VA_STATUS_ERROR_INVALID_CONTEXT:
+ case VA_STATUS_ERROR_INVALID_SURFACE:
+ case VA_STATUS_ERROR_INVALID_BUFFER:
+ case VA_STATUS_ERROR_INVALID_IMAGE:
+ case VA_STATUS_ERROR_INVALID_SUBPICTURE:
+ mfxRes = MFX_ERR_NOT_INITIALIZED;
+ break;
+ case VA_STATUS_ERROR_INVALID_PARAMETER:
+ mfxRes = MFX_ERR_INVALID_VIDEO_PARAM;
+ default:
+ mfxRes = MFX_ERR_UNKNOWN;
+ break;
+ }
+
+ return mfxRes;
+}
+
+static unsigned int ConvertMfxFourccToVAFormat(mfxU32 fourcc)
+{
+ switch (fourcc) {
+ case MFX_FOURCC_NV12:
+ return VA_FOURCC_NV12;
+ case MFX_FOURCC_YUY2:
+ return VA_FOURCC_YUY2;
+ case MFX_FOURCC_YV12:
+ return VA_FOURCC_YV12;
+ case MFX_FOURCC_RGB4:
+ return VA_FOURCC_ARGB;
+ case MFX_FOURCC_P8:
+ return VA_FOURCC_P208;
+
+ default:
+ return 0;
+ }
+}
+
+static unsigned int ConvertVP8FourccToMfxFourcc(mfxU32 fourcc)
+{
+ switch (fourcc) {
+ case MFX_FOURCC_VP8_NV12:
+ case MFX_FOURCC_VP8_MBDATA:
+ return MFX_FOURCC_NV12;
+ case MFX_FOURCC_VP8_SEGMAP:
+ return MFX_FOURCC_P8;
+
+ default:
+ return fourcc;
+ }
+}
+
+static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *request, mfxFrameAllocResponse *response)
+{
+ int i, format;
+ VAStatus va_res = VA_STATUS_SUCCESS;
+ VASurfaceID* surfaces = NULL;
+ vaapiMemId* vaapi_mid = NULL;
+ mfxFrameSurface1 *mfxsurface = NULL;
+ VAContextID context_id;
+ VABufferType codedbuf_type;
+ mfxStatus mfx_res = MFX_ERR_NONE;
+ mfxMemId* mids = NULL;
+ VASurfaceAttrib attrib;
+ mfxU16 surface_num;
+ unsigned int va_fourcc = 0;
+ mfxU32 fourcc = request->Info.FourCC;
+ QSVContext *q = pthis;
+ AVQSVContext *qsv = q->ost->enc_ctx->hwaccel_context;
+ mfxU16 numAllocated = 0;
+ bool bCreateSrfSucceeded = false;
+ mfxU32 mfx_fourcc;
+ int codedbuf_size;
+ int width32;
+ int height32;
+ void *avctx = NULL;
+
+ av_log(avctx, AV_LOG_INFO, "=========vaapi alloc frame==============\n");
+ if (!request || !response || !request->NumFrameSuggested)
+ return MFX_ERR_MEMORY_ALLOC;
+
+ memset(response, 0, sizeof(*response));
+ surface_num = request->NumFrameSuggested;
+ if ((request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) &&
+ (request->Type & MFX_MEMTYPE_FROM_DECODE))
+ surface_num += (qsv->nb_encoder_surfaces + qsv->nb_decoder_surfaces);
+
+ av_log(avctx, AV_LOG_INFO, "VAAPI: va_dpy =%p, surface_num=%d, width=%d, height=%d\n",
+ g_session.va_display, surface_num, request->Info.Width, request->Info.Height);
+ av_log(avctx, AV_LOG_INFO, "VAAPI: request->Type=%x\n",request->Type);
+
+ surfaces = (VASurfaceID*)av_calloc(surface_num, sizeof(VASurfaceID));
+ mids = (mfxMemId*)av_calloc(surface_num, sizeof(mfxMemId));
+ if (!surfaces || !mids) {
+ av_log(avctx, AV_LOG_ERROR, "ERROR: memory allocation failed\n");
+ return MFX_ERR_MEMORY_ALLOC;
+ }
+
+ mfx_fourcc = ConvertVP8FourccToMfxFourcc(fourcc);
+ va_fourcc = ConvertMfxFourccToVAFormat(mfx_fourcc);
+ if (va_fourcc != VA_FOURCC_P208) {
+ av_log(avctx, AV_LOG_INFO, "VAAPI: va_fourcc != VA_FOURCC_P208\n");
+ attrib.type = VASurfaceAttribPixelFormat;
+ attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
+ attrib.value.type = VAGenericValueTypeInteger;
+ attrib.value.value.i = va_fourcc;
+ format = va_fourcc;
+
+ if (fourcc == MFX_FOURCC_VP8_NV12) {
+ // special configuration for NV12 surf allocation for VP8 hybrid encoder is required
+ attrib.type = (VASurfaceAttribType)VASurfaceAttribUsageHint;
+ attrib.value.value.i = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
+ } else if (fourcc == MFX_FOURCC_VP8_MBDATA) {
+ // special configuration for MB data surf allocation for VP8 hybrid encoder is required
+ attrib.value.value.i = VA_FOURCC_P208;
+ format = VA_FOURCC_P208;
+ } else if (va_fourcc == VA_FOURCC_NV12) {
+ format = VA_RT_FORMAT_YUV420;
+ }
+
+ va_res = vaCreateSurfaces(g_session.va_display,
+ format,
+ request->Info.Width, request->Info.Height,
+ surfaces,
+ surface_num,
+ &attrib, 1);
+ bCreateSrfSucceeded = (va_res==VA_STATUS_SUCCESS);
+ } else {
+ av_log(avctx, AV_LOG_INFO, "VAAPI: va_fourcc == VA_FOURCC_P208\n");
+ context_id = request->reserved[0];
+ width32 = 32 * ((request->Info.Width + 31) >> 5);
+ height32 = 32 * ((request->Info.Height + 31) >> 5);
+
+ if (fourcc == MFX_FOURCC_VP8_SEGMAP) {
+ codedbuf_size = request->Info.Width * request->Info.Height;
+ codedbuf_type = (VABufferType)VAEncMacroblockMapBufferType;
+ } else {
+ codedbuf_size = ((width32 * height32) * 400LL / (16 * 16));
+ codedbuf_type = VAEncCodedBufferType;
+ }
+
+ for (numAllocated = 0; numAllocated < surface_num; numAllocated++) {
+ VABufferID coded_buf;
+ va_res = vaCreateBuffer(g_session.va_display,
+ context_id,
+ codedbuf_type,
+ codedbuf_size,
+ 1,
+ NULL,
+ &coded_buf);
+ mfx_res = va_to_mfx_status(va_res);
+ if (MFX_ERR_NONE != mfx_res)
+ break;
+
+ surfaces[numAllocated] = coded_buf;
+ }
+ }
+
+ if (va_res == VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_INFO, "VAAPI: %d VA surfaces have been allocated\n", surface_num);
+ for (i=0; i<surface_num; i++) {
+ vaapi_mid = av_mallocz(sizeof(*vaapi_mid));
+ vaapi_mid->m_fourcc = fourcc;
+ vaapi_mid->m_surface = surfaces + i;
+ mids[i] = vaapi_mid;
+ }
+
+ if ((request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) &&
+ (request->Type & MFX_MEMTYPE_FROM_DECODE)) {
+ q->surface_ptrs = av_realloc(q->surface_ptrs,
+ sizeof(*q->surface_ptrs) * (q->nb_surfaces + surface_num));
+ q->surface_used = av_realloc(q->surface_used,
+ sizeof(*q->surface_used) * (q->nb_surfaces + surface_num));
+
+ for (i=0; i<surface_num; i++,q->nb_surfaces++) {
+ mfxsurface = av_mallocz(sizeof(*mfxsurface));
+ memcpy(&mfxsurface->Info, &request->Info, sizeof(mfxFrameInfo));
+ mfxsurface->Data.MemId = mids[i];
+ q->surface_ptrs[q->nb_surfaces] = mfxsurface;
+ q->surface_used[q->nb_surfaces] = 0;
+ }
+ }
+ response->mids = mids;
+ response->NumFrameActual = surface_num;
+ } else {
+ response->mids = NULL;
+ response->NumFrameActual = 0;
+
+ if (VA_FOURCC_P208 != va_fourcc || fourcc==MFX_FOURCC_VP8_MBDATA) {
+ if (bCreateSrfSucceeded)
+ vaDestroySurfaces(g_session.va_display, surfaces, surface_num);
+ } else {
+ for (i=0; i<numAllocated; i++)
+ vaDestroyBuffer(g_session.va_display, surfaces[i]);
+ }
+
+ for (i=0; i<surface_num; i++) {
+ vaapi_mid = mids[i];
+ av_freep(&vaapi_mid);
+ }
+ av_freep(&mids);
+ av_freep(&surfaces);
+
+ av_log(avctx, AV_LOG_INFO, "ERROR: VA Surfaces allocation failed\n");
+
+ return MFX_ERR_MEMORY_ALLOC;
+ }
+
+ return MFX_ERR_NONE;
+}
+
+static mfxStatus frame_free(mfxHDL pthis, mfxFrameAllocResponse *response)
+{
+ vaapiMemId *vaapi_mid = NULL;
+ VASurfaceID *surfaces = NULL;
+ mfxU32 i = 0;
+ bool isBitstreamMemory = false;
+ mfxU32 mfx_fourcc;
+
+ if (!response)
+ return MFX_ERR_NULL_PTR;
+
+ av_log( NULL, AV_LOG_INFO, "=========vaapi free frame: %d==============\n", response->NumFrameActual);
+ if (response->mids) {
+ surfaces = ((vaapiMemId*)response->mids[0])->m_surface;
+ mfx_fourcc = ConvertVP8FourccToMfxFourcc(((vaapiMemId*)response->mids[0])->m_fourcc);
+ isBitstreamMemory = (MFX_FOURCC_P8==mfx_fourcc)?true:false;
+
+ for (i = 0; i < response->NumFrameActual; ++i) {
+ vaapi_mid = (vaapiMemId*)response->mids[i];
+ if (MFX_FOURCC_P8 == mfx_fourcc) {
+ vaDestroyBuffer(g_session.va_display, surfaces[i]);
+ } else if (vaapi_mid->m_sys_buffer) {
+ free(vaapi_mid->m_sys_buffer);
+ }
+ av_freep(&vaapi_mid);
+ }
+
+ if (!isBitstreamMemory)
+ vaDestroySurfaces(g_session.va_display, surfaces, response->NumFrameActual);
+
+ av_freep(&response->mids);
+ av_freep(&surfaces);
+ }
+
+ response->NumFrameActual = 0;
+
+ return MFX_ERR_NONE;
+}
+
+static mfxStatus frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
+{
+ mfxStatus mfx_res = MFX_ERR_NONE;
+ VAStatus va_res = VA_STATUS_SUCCESS;
+ VACodedBufferSegment *coded_buffer_segment;
+ vaapiMemId *vaapi_mid = (vaapiMemId*)mid;
+ mfxU8 *pBuffer = 0;
+ mfxU32 mfx_fourcc;
+
+ if (!mid)
+ return MFX_ERR_INVALID_HANDLE;
+
+ mfx_fourcc = ConvertVP8FourccToMfxFourcc(vaapi_mid->m_fourcc);
+ if (MFX_FOURCC_P8 == mfx_fourcc) {
+ if (vaapi_mid->m_fourcc == MFX_FOURCC_VP8_SEGMAP) {
+ va_res = vaMapBuffer(g_session.va_display, *(vaapi_mid->m_surface), (void **)(&pBuffer));
+ } else {
+ va_res = vaMapBuffer(g_session.va_display, *(vaapi_mid->m_surface), (void **)(&coded_buffer_segment));
+ }
+ mfx_res = va_to_mfx_status(va_res);
+ if (MFX_ERR_NONE == mfx_res) {
+ if (vaapi_mid->m_fourcc == MFX_FOURCC_VP8_SEGMAP) {
+ ptr->Y = pBuffer;
+ } else {
+ ptr->Y = (mfxU8*)coded_buffer_segment->buf;
+ }
+ }
+ } else {
+ va_res = vaSyncSurface(g_session.va_display, *(vaapi_mid->m_surface));
+ mfx_res = va_to_mfx_status(va_res);
+ if (MFX_ERR_NONE == mfx_res) {
+ va_res = vaDeriveImage(g_session.va_display, *(vaapi_mid->m_surface), &(vaapi_mid->m_image));
+ mfx_res = va_to_mfx_status(va_res);
+ }
+
+ if (MFX_ERR_NONE == mfx_res) {
+ va_res = vaMapBuffer(g_session.va_display, vaapi_mid->m_image.buf, (void **) &pBuffer);
+ mfx_res = va_to_mfx_status(va_res);
+ }
+
+ if (MFX_ERR_NONE == mfx_res) {
+ switch (vaapi_mid->m_image.format.fourcc) {
+ case VA_FOURCC_NV12:
+ if (mfx_fourcc == MFX_FOURCC_NV12) {
+ ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
+ ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0];
+ ptr->U = pBuffer + vaapi_mid->m_image.offsets[1];
+ ptr->V = ptr->U + 1;
+ } else {
+ mfx_res = MFX_ERR_LOCK_MEMORY;
+ }
+ break;
+
+ case VA_FOURCC_YV12:
+ if (mfx_fourcc == MFX_FOURCC_YV12) {
+ ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
+ ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0];
+ ptr->V = pBuffer + vaapi_mid->m_image.offsets[1];
+ ptr->U = pBuffer + vaapi_mid->m_image.offsets[2];
+ } else {
+ mfx_res = MFX_ERR_LOCK_MEMORY;
+ }
+ break;
+
+ case VA_FOURCC_YUY2:
+ if (mfx_fourcc == MFX_FOURCC_YUY2) {
+ ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
+ ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0];
+ ptr->U = ptr->Y + 1;
+ ptr->V = ptr->Y + 3;
+ } else {
+ mfx_res = MFX_ERR_LOCK_MEMORY;
+ }
+ break;
+
+ case VA_FOURCC_ARGB:
+ if (mfx_fourcc == MFX_FOURCC_RGB4) {
+ ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
+ ptr->B = pBuffer + vaapi_mid->m_image.offsets[0];
+ ptr->G = ptr->B + 1;
+ ptr->R = ptr->B + 2;
+ ptr->A = ptr->B + 3;
+ } else {
+ mfx_res = MFX_ERR_LOCK_MEMORY;
+ }
+ break;
+
+ case VA_FOURCC_P208:
+ if (mfx_fourcc == MFX_FOURCC_NV12) {
+ ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0];
+ ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0];
+ } else {
+ mfx_res = MFX_ERR_LOCK_MEMORY;
+ }
+ break;
+
+ default:
+ mfx_res = MFX_ERR_LOCK_MEMORY;
+ break;
+ }
+ }
+ }
+ return mfx_res;
+}
+
+static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
+{
+ mfxU32 mfx_fourcc;
+ vaapiMemId *vaapi_mid = (vaapiMemId*)mid;
+
+ if (!vaapi_mid || !vaapi_mid->m_surface)
+ return MFX_ERR_INVALID_HANDLE;
+
+ mfx_fourcc = ConvertVP8FourccToMfxFourcc(vaapi_mid->m_fourcc);
+ if (mfx_fourcc == MFX_FOURCC_P8) {
+ vaUnmapBuffer(g_session.va_display, *(vaapi_mid->m_surface));
+ } else {
+ vaUnmapBuffer(g_session.va_display, vaapi_mid->m_image.buf);
+ vaDestroyImage(g_session.va_display, vaapi_mid->m_image.image_id);
+
+ if (ptr) {
+ ptr->Pitch = 0;
+ ptr->Y = NULL;
+ ptr->U = NULL;
+ ptr->V = NULL;
+ ptr->A = NULL;
+ }
+ }
+
+ return MFX_ERR_NONE;
+}
+
+static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *handle)
+{
+ vaapiMemId* vaapi_mid = (vaapiMemId*)mid;
+
+ if (!handle || !mid)
+ return MFX_ERR_INVALID_HANDLE;
+
+ *handle = (mfxHDL) vaapi_mid->m_surface;
+
+ return MFX_ERR_NONE;
+}
+
+static int qsv_check_filters(const OutputStream *ost)
+{
+ AVFilterGraph *graph = NULL;
+ char args[512];
+ AVDictionaryEntry *e = NULL;
+ AVFilterInOut *inputs, *outputs;
+ int ret = 0;
+ int i;
+ const char *filter_list = "buffer|buffersink|null|format|setpts";
+
+ if (!ost->avfilter)
+ return -1;
+
+ graph = avfilter_graph_alloc();
+ if (!graph)
+ return AVERROR(ENOMEM);
+
+ args[0] = 0;
+ while ((e = av_dict_get(ost->sws_dict, "", e, AV_DICT_IGNORE_SUFFIX)))
+ av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
+ if (strlen(args))
+ args[strlen(args)-1] = 0;
+ graph->scale_sws_opts = av_strdup(args);
+
+ if ((ret = avfilter_graph_parse2(graph, ost->avfilter, &inputs, &outputs)) < 0)
+ goto out;
+
+ av_log(NULL, AV_LOG_DEBUG, "total filters %d\n", graph->nb_filters);
+ for (i = 0; i < graph->nb_filters; i++) {
+ av_log(NULL, AV_LOG_DEBUG, "\tfilter name: %s \n",
+ graph->filters[i]->filter->name);
+ if (!av_match_list(graph->filters[i]->filter->name, filter_list, '|')) {
+ ret = -1;
+ goto out;
+ }
+ }
+
+out:
+ avfilter_inout_free(&inputs);
+ avfilter_inout_free(&outputs);
+ avfilter_graph_free(&graph);
+ return ret;
+}
+
+static void qsv_uninit_vidmem(AVCodecContext *s)
+{
+ int i;
+
+ InputStream *ist = s->opaque;
+ QSVContext *qsv = ist->hwaccel_ctx;
+
+ ff_qsv_close_internal_session(&g_session);
+
+ av_freep(&qsv->ost->enc_ctx->hwaccel_context);
+ av_freep(&s->hwaccel_context);
+
+ for (i = 0; i < qsv->nb_surfaces; i++)
+ av_freep(&qsv->surface_ptrs[i]);
+ av_freep(&qsv->surface_used);
+ av_freep(&qsv->surface_ptrs);
+
+ av_freep(&qsv);
+}
+
+int qsv_init_vidmem(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ QSVContext *qsv = ist->hwaccel_ctx;
+ AVQSVContext *hwctx_dec;
+
+ if (!qsv) {
+ av_log(NULL, AV_LOG_ERROR, "QSV transcoding is not initialized. "
+ "-hwaccel qsv should only be used for one-to-one QSV transcoding "
+ "with no filters.\n");
+ return AVERROR_BUG;
+ }
+
+ hwctx_dec = av_qsv_alloc_context();
+ if (!hwctx_dec)
+ return AVERROR(ENOMEM);
+
+ hwctx_dec->session = qsv->session;
+ hwctx_dec->iopattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
+ hwctx_dec->ext_buffers = NULL;
+ hwctx_dec->nb_ext_buffers = 0;
+
+ av_freep(&s->hwaccel_context);
+ s->hwaccel_context = hwctx_dec;
+
+ ist->hwaccel_get_buffer = qsv_get_buffer;
+ ist->hwaccel_uninit = qsv_uninit_vidmem;
+
+ return 0;
+}
+
+int qsv_transcode_init_vidmem(OutputStream *ost)
+{
+ InputStream *ist = NULL;
+ const enum AVPixelFormat *pix_fmt;
+
+ AVDictionaryEntry *e;
+ const AVOption *opt;
+ int flags = 0;
+
+ int err, i;
+
+ QSVContext *qsv = NULL;
+ AVQSVContext *enc_hwctx = NULL;
+
+ /* check if the encoder supports QSV */
+ if (!ost->enc->pix_fmts)
+ return 0;
+ for (pix_fmt = ost->enc->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
+ if (*pix_fmt == AV_PIX_FMT_QSV)
+ break;
+ if (*pix_fmt == AV_PIX_FMT_NONE)
+ return 0;
+
+ /*Check if the filters support QSV*/
+ if (ost->source_index < 0 || qsv_check_filters(ost) < 0)
+ return 0;
+
+ /* check if the decoder supports QSV and the output only goes to this stream */
+ ist = input_streams[ost->source_index];
+ if (ist->nb_filters || ist->hwaccel_id != HWACCEL_QSV ||
+ !ist->dec || !ist->dec->pix_fmts)
+ return 0;
+ for (pix_fmt = ist->dec->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
+ if (*pix_fmt == AV_PIX_FMT_QSV)
+ break;
+ if (*pix_fmt == AV_PIX_FMT_NONE)
+ return 0;
+
+ for (i = 0; i < nb_output_streams; i++)
+ if (output_streams[i] != ost &&
+ output_streams[i]->source_index == ost->source_index)
+ return 0;
+
+ av_log(NULL, AV_LOG_VERBOSE, "Setting up QSV transcoding\n");
+
+ qsv = av_mallocz(sizeof(*qsv));
+ enc_hwctx = av_qsv_alloc_context();
+ if (!qsv || !enc_hwctx)
+ goto fail;
+
+ err = ff_qsv_init_internal_session(NULL, &g_session);
+ if (err != MFX_ERR_NONE) {
+ av_log(NULL, AV_LOG_ERROR, "Error initializing an MFX session: %d\n", err);
+ goto fail;
+ }
+
+ qsv->ost = ost;
+ qsv->session = g_session.session;
+ qsv->frame_allocator.Alloc = frame_alloc;
+ qsv->frame_allocator.Free = frame_free;
+ qsv->frame_allocator.Lock = frame_lock;
+ qsv->frame_allocator.Unlock= frame_unlock;
+ qsv->frame_allocator.GetHDL= frame_get_hdl;
+ qsv->frame_allocator.pthis = qsv;
+
+ err = MFXVideoCORE_SetFrameAllocator(qsv->session, &qsv->frame_allocator);
+ if (MFX_ERR_NONE != err) {
+ av_log(NULL, AV_LOG_ERROR, "Error MFXVideoCORE_SetFrameAllocator: %d\n", err);
+ goto fail;
+ }
+
+ e = av_dict_get(ost->encoder_opts, "flags", NULL, 0);
+ opt = av_opt_find(ost->enc_ctx, "flags", NULL, 0, 0);
+ if (e && opt)
+ av_opt_eval_flags(ost->enc_ctx, opt, e->value, &flags);
+
+ enc_hwctx->session = qsv->session;
+ enc_hwctx->iopattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
+ ost->hwaccel_ctx = qsv;
+ ost->enc_ctx->hwaccel_context = enc_hwctx;
+
+ ist->resample_pix_fmt = AV_PIX_FMT_QSV;
+ ist->hwaccel_ctx = qsv;
+
+ return 0;
+
+fail:
+ av_freep(&enc_hwctx);
+ av_freep(&qsv);
+
+ return AVERROR_UNKNOWN;
+}
diff --git a/libavcodec/qsv.h b/libavcodec/qsv.h
index b77158e..ee968d0 100644
--- a/libavcodec/qsv.h
+++ b/libavcodec/qsv.h
@@ -95,6 +95,9 @@ typedef struct AVQSVContext {
* the opaque allocation request.
*/
int opaque_alloc_type;
+
+ int nb_decoder_surfaces;
+ int nb_encoder_surfaces;
} AVQSVContext;
/**
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index e43728b..58589df 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -21,6 +21,8 @@
#ifndef AVCODEC_QSV_INTERNAL_H
#define AVCODEC_QSV_INTERNAL_H
+#include "config.h"
+
#if CONFIG_VAAPI
#define AVCODEC_QSV_LINUX_SESSION_HANDLE
#endif //CONFIG_VAAPI
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index b9de0af..47dd818 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -72,6 +72,7 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q, AVPacket *avpkt
q->iopattern = qsv->iopattern;
q->ext_buffers = qsv->ext_buffers;
q->nb_ext_buffers = qsv->nb_ext_buffers;
+ qsv->nb_decoder_surfaces = q->async_depth;
}
if (!q->session) {
if (!q->internal_qs.session) {
@@ -88,7 +89,7 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q, AVPacket *avpkt
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Failed to load plugins %s, ret = %s\n",
q->load_plugins, av_err2str(ret));
- return ff_qsv_error(ret);
+ return ret;
}
}
@@ -149,7 +150,7 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q, AVPacket *avpkt
So weare pre-allocating fifo big enough for 17 elements:
*/
if (!q->async_fifo) {
- q->async_fifo = av_fifo_alloc((1 + 16) *
+ q->async_fifo = av_fifo_alloc((1 + 16 + q->async_depth) *
(sizeof(mfxSyncPoint) + sizeof(QSVFrame*)));
if (!q->async_fifo)
return AVERROR(ENOMEM);
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 81b8f6f..041f298 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -760,6 +760,8 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
q->param.ExtParam[q->param.NumExtParam++] = q->extparam_internal[i];
}
+
+ qsv->nb_encoder_surfaces = q->req.NumFrameSuggested + q->async_depth;
} else {
q->param.ExtParam = q->extparam_internal;
q->param.NumExtParam = q->nb_extparam_internal;
--
2.5.0
More information about the ffmpeg-devel
mailing list