[FFmpeg-devel] [PATCH 4/6] lavf/vpp: enable video memory accel for transcoding with vpp. lavc/qsv: export symbols "ff_qsv_*" which will be used by vpp. ffmpeg_qsv: set default hwaccel to qsv.

Jean-Baptiste Kempf jb at videolan.org
Thu Aug 25 10:27:44 EEST 2016


Idem. Patch does too many things and changes unrelated code.

On 25 Aug, Nablet Developer wrote :
> From: ChaoX A Liu <chaox.a.liu at intel.com>
> 
> Signed-off-by: ChaoX A Liu <chaox.a.liu at intel.com>
> ---
>  ffmpeg_qsv.c            |  46 ++++++++++++---
>  libavcodec/libavcodec.v |   1 +
>  libavcodec/qsv.h        |   2 +
>  libavfilter/vf_qsvvpp.c | 153 ++++++++++++++++++++++++++++++++++++++++--------
>  4 files changed, 172 insertions(+), 30 deletions(-)
> 
> diff --git a/ffmpeg_qsv.c b/ffmpeg_qsv.c
> index 43402d6..aed9240 100644
> --- a/ffmpeg_qsv.c
> +++ b/ffmpeg_qsv.c
> @@ -386,7 +386,7 @@ static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *request, mfxFra
>      unsigned int va_fourcc = 0;
>      mfxU32 fourcc = request->Info.FourCC;
>      QSVContext *q = pthis;
> -    AVQSVContext *qsv = q->ost->enc_ctx->hwaccel_context;
> +    AVQSVContext *qsv = NULL;
>      mfxU16 numAllocated = 0;
>      bool bCreateSrfSucceeded = false;
>      mfxU32 mfx_fourcc;
> @@ -394,17 +394,40 @@ static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *request, mfxFra
>      int width32;
>      int height32;
>      void *avctx = NULL;
> +    FilterGraph *fg = q->ost->filter->graph;
>  
> -    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);
> +    if (request->Type & MFX_MEMTYPE_FROM_DECODE) {
> +        avctx = input_streams[q->ost->source_index]->dec_ctx;
> +        if (request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
> +            AVFilterContext *qsvvpp = avfilter_graph_get_filter(fg->graph, "Parsed_qsvvpp_0");
> +            qsv = input_streams[q->ost->source_index]->dec_ctx->hwaccel_context;
> +            surface_num += qsv->nb_decoder_surfaces;
> +            if (qsvvpp) {
> +                qsv = qsvvpp->hw_device_ctx->data;
> +                surface_num += qsv->nb_vpp_surfaces;
> +            } else {
> +                qsv = q->ost->enc_ctx->hwaccel_context;
> +                surface_num += qsv->nb_encoder_surfaces;
> +            }
> +        }
> +    } else if (request->Type & MFX_MEMTYPE_FROM_VPPOUT) {
> +        AVFilterContext *qsvvpp = avfilter_graph_get_filter(fg->graph, "Parsed_qsvvpp_0");
> +        avctx = qsvvpp;
> +        if (request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
> +            qsv = q->ost->enc_ctx->hwaccel_context;
> +            surface_num += qsv->nb_encoder_surfaces;
> +        }
> +    } else if (request->Type & MFX_MEMTYPE_FROM_ENCODE) {
> +        avctx = q->ost->enc_ctx;
> +    } else
> +        av_log(avctx, AV_LOG_WARNING, "FrameAlloc: may get a bug.\n");
>  
> +    av_log(avctx, AV_LOG_INFO, "=========vaapi alloc frame==============\n");
>      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);
> @@ -720,7 +743,7 @@ static int qsv_check_filters(const OutputStream *ost)
>      AVFilterInOut *inputs, *outputs;
>      int ret = 0;
>      int i;
> -    const char *filter_list = "buffer|buffersink|null|format|setpts";
> +    const char *filter_list = "buffer|buffersink|null|format|setpts|qsvvpp";
>  
>      if (!ost->avfilter)
>          return -1;
> @@ -820,6 +843,7 @@ int qsv_transcode_init_vidmem(OutputStream *ost)
>  
>      QSVContext *qsv = NULL;
>      AVQSVContext *enc_hwctx = NULL;
> +    AVQSVContext *vpp_hwctx = NULL;
>  
>      /* check if the encoder supports QSV */
>      if (!ost->enc->pix_fmts)
> @@ -836,6 +860,8 @@ int qsv_transcode_init_vidmem(OutputStream *ost)
>  
>      /* check if the decoder supports QSV and the output only goes to this stream */
>      ist = input_streams[ost->source_index];
> +    if (ist->hwaccel_id == HWACCEL_NONE || ist->hwaccel_id == HWACCEL_AUTO)
> +        ist->hwaccel_id = HWACCEL_QSV;
>      if (ist->nb_filters || ist->hwaccel_id != HWACCEL_QSV ||
>          !ist->dec || !ist->dec->pix_fmts)
>          return 0;
> @@ -854,7 +880,8 @@ int qsv_transcode_init_vidmem(OutputStream *ost)
>  
>      qsv   = av_mallocz(sizeof(*qsv));
>      enc_hwctx = av_qsv_alloc_context();
> -    if (!qsv || !enc_hwctx)
> +    vpp_hwctx = av_qsv_alloc_context();
> +    if (!qsv || !enc_hwctx || !vpp_hwctx)
>          goto fail;
>  
>      err = ff_qsv_init_internal_session(NULL, &g_session);
> @@ -891,6 +918,11 @@ int qsv_transcode_init_vidmem(OutputStream *ost)
>      ist->resample_pix_fmt            = AV_PIX_FMT_QSV;
>      ist->hwaccel_ctx                 = qsv;
>  
> +    vpp_hwctx->session               = qsv->session;
> +    vpp_hwctx->iopattern             = MFX_IOPATTERN_IN_VIDEO_MEMORY;
> +    vpp_hwctx->pFrameAllocator       = &qsv->frame_allocator;
> +    hw_device_ctx = av_buffer_create(vpp_hwctx, sizeof(*vpp_hwctx), av_buffer_default_free, NULL, 0);
> +
>      return 0;
>  
>  fail:
> diff --git a/libavcodec/libavcodec.v b/libavcodec/libavcodec.v
> index 304c2ef..1a4cac8 100644
> --- a/libavcodec/libavcodec.v
> +++ b/libavcodec/libavcodec.v
> @@ -4,6 +4,7 @@ LIBAVCODEC_MAJOR {
>          #deprecated, remove after next bump
>          audio_resample;
>          audio_resample_close;
> +        ff_qsv_*;
>      local:
>          *;
>  };
> diff --git a/libavcodec/qsv.h b/libavcodec/qsv.h
> index ee968d0..3f7b3c8 100644
> --- a/libavcodec/qsv.h
> +++ b/libavcodec/qsv.h
> @@ -96,7 +96,9 @@ typedef struct AVQSVContext {
>       */
>      int opaque_alloc_type;
>  
> +    mfxFrameAllocator *pFrameAllocator;
>      int nb_decoder_surfaces;
> +    int nb_vpp_surfaces;
>      int nb_encoder_surfaces;
>  } AVQSVContext;
>  
> diff --git a/libavfilter/vf_qsvvpp.c b/libavfilter/vf_qsvvpp.c
> index 3a5d4d3..b1245d2 100644
> --- a/libavfilter/vf_qsvvpp.c
> +++ b/libavfilter/vf_qsvvpp.c
> @@ -21,10 +21,80 @@
>   */
>  
>  #include "internal.h"
> +#include <mfx/mfxvideo.h>
> +#include <mfx/mfxplugin.h>
>  #include <float.h>
>  #include "libavutil/parseutils.h"
>  #include "libavutil/timestamp.h"
> +#include "libavutil/avassert.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/time.h"
> +#include "libavutil/avstring.h"
> +#include "libavutil/error.h"
>  #include "libavcodec/qsv.h"
> +#include "libavcodec/qsv_internal.h"
> +
> +// number of video enhancement filters (denoise, procamp, detail, video_analysis, image stab)
> +#define ENH_FILTERS_COUNT           5
> +
> +typedef struct {
> +    const AVClass *class;
> +
> +    AVFilterContext *ctx;
> +
> +    mfxSession session;
> +    QSVSession internal_qs;
> +    int iopattern;
> +
> +    AVRational framerate;                           // target framerate
> +
> +    QSVFrame *in_work_frames;                       // used for video memory
> +    QSVFrame *out_work_frames;                      // used for video memory
> +
> +    mfxFrameSurface1 *in_surface;
> +    mfxFrameSurface1 *out_surface;
> +
> +    mfxFrameAllocRequest req[2];                    // [0] - in, [1] - out
> +    mfxFrameAllocator *pFrameAllocator;
> +    mfxFrameAllocResponse *in_response;
> +    mfxFrameAllocResponse *out_response;
> +
> +    int num_surfaces_in;                            // input surfaces
> +    int num_surfaces_out;                           // output surfaces
> +    int sysmem_cur_out_idx;
> +    int frame_number;
> +    int vpp_ready;
> +    mfxVideoParam *pVppParam;
> +
> +    AVBufferRef *hw_device_ctx;
> +
> +    /* VPP extension */
> +    mfxExtBuffer*       pExtBuf[1+ENH_FILTERS_COUNT];
> +    mfxExtVppAuxData    extVPPAuxData;
> +
> +    /* Video Enhancement Algorithms */
> +    mfxExtVPPDeinterlacing  deinterlace_conf;
> +    mfxExtVPPFrameRateConversion frc_conf;
> +    mfxExtVPPDenoise denoise_conf;
> +    mfxExtVPPDetail detail_conf;
> +    mfxExtVPPComposite composite_conf;
> +
> +    int out_width;
> +    int out_height;
> +    int dpic;                   // destination picture structure
> +                                // -1 = unknown
> +                                // 0 = interlaced top field first
> +                                // 1 = progressive
> +                                // 2 = interlaced bottom field first
> +
> +    int deinterlace;            // deinterlace mode : 0=off, 1=bob, 2=advanced
> +    int denoise;                // Enable Denoise algorithm. Level is the optional value from the interval [0; 100]
> +    int detail;                 // Enable Detail Enhancement algorithm.
> +                                // Level is the optional value from the interval [0; 100]
> +    int async_depth;            // async dept used by encoder
> +    int max_b_frames;           // maxiumum number of b frames used by encoder
> +    int use_frc;                // use framerate conversion
> +} VPPContext;
>  
>  /**
>   * ToDo :
> @@ -120,6 +190,7 @@ static int avpix_fmt_to_mfx_fourcc(int format)
>  static void vidmem_init_surface(VPPContext *vpp)
>  {
>      int i;
> +    AVQSVContext *qsv = (AVQSVContext*)vpp->hw_device_ctx->data;
>  
>      av_log(vpp->ctx, AV_LOG_INFO, "qsvvpp: vidmem_init_surface: ");
>  
> @@ -134,20 +205,17 @@ static void vidmem_init_surface(VPPContext *vpp)
>      /*
>       * We should care about next stage vpp or encoder's input surfaces.
>       */
> -    av_log(vpp->ctx, AV_LOG_INFO, "in.num = %d, out.num = %d, ",
> +    vpp->req[0].NumFrameSuggested = FFMAX(vpp->req[0].NumFrameSuggested, 1);
> +    vpp->req[1].NumFrameSuggested = FFMAX(vpp->req[1].NumFrameSuggested, 1);
> +    av_log(vpp->ctx, AV_LOG_INFO, "in.num = %d, out.num = %d\n",
>              vpp->req[0].NumFrameSuggested, vpp->req[1].NumFrameSuggested);
> -    if (vpp->enc_ctx) {
> -        vpp->req[1].NumFrameSuggested += vpp->enc_ctx->req.NumFrameSuggested;
> -        av_log(vpp->ctx, AV_LOG_INFO, "enc_ctx.num=%d\n", vpp->enc_ctx->req.NumFrameSuggested);
> -    } else {
> -        av_log(vpp->ctx, AV_LOG_INFO, "enc_ctx.num=%d\n", 0);
> -    }
> -
> -    vpp->req[0].NumFrameSuggested  = FFMAX(vpp->req[0].NumFrameSuggested, 1);
> +    qsv->nb_vpp_surfaces = vpp->req[0].NumFrameSuggested;
>  
> -    vpp->num_surfaces_out = FFMAX(vpp->req[1].NumFrameSuggested, 1);
>      vpp->out_response     = av_mallocz(sizeof(*vpp->out_response));
>      VPP_CHECK_POINTER(vpp->out_response);
> +    vpp->pFrameAllocator->Alloc(vpp->pFrameAllocator->pthis, &vpp->req[1], vpp->out_response);
> +
> +    vpp->num_surfaces_out = vpp->out_response->NumFrameActual;
>      vpp->out_surface      = av_mallocz(sizeof(*vpp->out_surface) * vpp->num_surfaces_out);
>      VPP_CHECK_POINTER(vpp->out_surface);
>  
> @@ -333,6 +401,7 @@ static int sysmem_input_get_surface( AVFilterLink *inlink, AVFrame* picref, mfxF
>  
>  static int vidmem_input_get_surface( AVFilterLink *inlink, AVFrame* picref, mfxFrameSurface1 **surface )
>  {
> +    if (picref->format == AV_PIX_FMT_QSV && picref->data[3]) {
>      if (picref->data[3]) {
>          *surface = (mfxFrameSurface1*)picref->data[3];
>      } else {
> @@ -533,11 +602,19 @@ static int initial_vpp( VPPContext *vpp )
>  static int config_vpp(AVFilterLink *inlink, AVFrame * pic)
>  {
>      AVFilterContext *ctx = inlink->dst;
> -    VPPContext *vpp= ctx->priv;
> -    mfxVideoParam mfxParamsVideo;
> -    int           ret;
> +    VPPContext      *vpp = ctx->priv;
> +    mfxVideoParam    mfxParamsVideo;
> +    int              ret;
>  
>      av_log(vpp->ctx, AV_LOG_INFO, "QSVVPP: vpp configuration and call mfxVideoVPP_Init\n");
> +    if (ctx->hw_device_ctx) {
> +        AVQSVContext *qsv    = (AVQSVContext*)ctx->hw_device_ctx->data;
> +        vpp->hw_device_ctx   = av_buffer_ref(ctx->hw_device_ctx);
> +        vpp->pFrameAllocator = qsv->pFrameAllocator;
> +        vpp->iopattern       = qsv->iopattern;
> +        vpp->session         = qsv->session;
> +    }
> +
>      if (!vpp->session) {
>          ret = ff_qsv_init_internal_session(ctx, &vpp->internal_qs);
>          if (ret < 0)
> @@ -573,6 +650,32 @@ static void deconf_vpp(AVFilterContext *ctx)
>      vpp->vpp_ready = 0;
>  }
>  
> +static void vidmem_buffer_free(void *opaque, uint8_t *data)
> +{
> +    //do nothing
> +}
> +
> +static AVFrame *vidmem_buffer_alloc(AVFilterContext *ctx, mfxFrameSurface1 *pSurface)
> +{
> +    AVFrame *frame = av_frame_alloc();
> +    if (!frame)
> +        return NULL;
> +
> +    frame->buf[0] = av_buffer_create((uint8_t*)pSurface, sizeof(pSurface),
> +                        vidmem_buffer_free, NULL, 0);
> +    if (!frame->buf[0]) {
> +        av_frame_free(&frame);
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    frame->data[3] = frame->buf[0]->data;
> +    frame->width   = ctx->outputs[0]->w;
> +    frame->height  = ctx->outputs[0]->h;
> +    frame->format  = ctx->outputs[0]->format;
> +
> +    return frame;
> +}
> +
>  /*
>   * Real filter func.
>   * Push frame into mSDK and pop out filtered frames.
> @@ -619,11 +722,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
>              break;
>          }
>  
> -        /*
> -         * get an AVFrame for output.
> -         * @NOTE: frame buffer is aligned with 128x64 to compat with GPU-copy.
> -         */
> -        out = ff_get_video_buffer(outlink, FFALIGN(vpp->out_width, 128), FFALIGN(vpp->out_height, 64));
> +        if (!vpp->pFrameAllocator) {
> +            /*
> +            * get an AVFrame for output.
> +            * @NOTE: frame buffer is aligned with 128x64 to compat with GPU-copy.
> +            */
> +            out = ff_get_video_buffer(outlink, FFALIGN(vpp->out_width, 128), FFALIGN(vpp->out_height, 64));
> +        } else {
> +            out = vidmem_buffer_alloc(ctx, pOutSurface);
> +        }
>          if (!out) {
>              ret = MFX_ERR_MEMORY_ALLOC;
>              break;
> @@ -670,10 +777,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
>              out->pts = av_rescale_q(pOutSurface->Data.TimeStamp, (AVRational){1,90000}, outlink->time_base);
>          }
>  
> -        /*For video mem, we use AVFrame->data[3] to transfer surface*/
> -        if (vpp->pFrameAllocator)
> -            out->data[3] = (void*) pOutSurface;
> -
>          filter_frame_ret = ff_filter_frame(inlink->dst->outputs[0], out);
>          if (filter_frame_ret < 0)
>              break;
> @@ -722,7 +825,6 @@ static int config_output(AVFilterLink *outlink)
>      outlink->h             = vpp->out_height;
>      outlink->frame_rate    = vpp->framerate;
>      outlink->time_base     = av_inv_q(vpp->framerate);
> -    outlink->format        = AV_PIX_FMT_NV12;
>  
>      return 0;
>  }
> @@ -763,13 +865,18 @@ static av_cold int qsvvpp_init(AVFilterContext *ctx)
>      vpp->vpp_ready       = 0;
>      vpp->ctx             = ctx;
>      vpp->sysmem_cur_out_idx = 0;
> +    vpp->hw_device_ctx   = NULL;
>  
>      return 0;
>  }
>  
>  static av_cold void qsvvpp_uninit(AVFilterContext *ctx)
>  {
> +    VPPContext *vpp = ctx->priv;
> +
>      deconf_vpp(ctx);
> +    if (vpp->hw_device_ctx)
> +        av_buffer_unref(&vpp->hw_device_ctx);
>  }
>  
>  static int qsvvpp_cmd_size(AVFilterContext *ctx, const char *arg)
> -- 
> 2.5.0
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

-- 
With my kindest regards,

-- 
Jean-Baptiste Kempf
http://www.jbkempf.com/ - +33 672 704 734
Sent from my Electronic Device


More information about the ffmpeg-devel mailing list