[FFmpeg-devel] [PATCH] vp9: add hwaccel hooks
wm4
nfxjfg at googlemail.com
Thu Dec 3 10:58:36 CET 2015
On Thu, 3 Dec 2015 10:55:12 +0100
Hendrik Leppkes <h.leppkes at gmail.com> wrote:
> ---
> libavcodec/vp9.c | 137 ++++++++++++++++++++++++++++++++++++++++---------------
> libavcodec/vp9.h | 3 ++
> 2 files changed, 103 insertions(+), 37 deletions(-)
>
> diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
> index d8888c0..134ee55 100644
> --- a/libavcodec/vp9.c
> +++ b/libavcodec/vp9.c
> @@ -168,6 +168,15 @@ static const uint8_t bwh_tab[2][N_BS_SIZES][2] = {
> }
> };
>
> +static void vp9_unref_frame(AVCodecContext *ctx, VP9Frame *f)
> +{
> + ff_thread_release_buffer(ctx, &f->tf);
> + av_buffer_unref(&f->extradata);
> + av_buffer_unref(&f->hwaccel_priv_buf);
> + f->segmentation_map = NULL;
> + f->hwaccel_picture_private = NULL;
> +}
> +
> static int vp9_alloc_frame(AVCodecContext *ctx, VP9Frame *f)
> {
> VP9Context *s = ctx->priv_data;
> @@ -177,21 +186,28 @@ static int vp9_alloc_frame(AVCodecContext *ctx, VP9Frame *f)
> return ret;
> sz = 64 * s->sb_cols * s->sb_rows;
> if (!(f->extradata = av_buffer_allocz(sz * (1 + sizeof(struct VP9mvrefPair))))) {
> - ff_thread_release_buffer(ctx, &f->tf);
> - return AVERROR(ENOMEM);
> + goto fail;
> }
>
> f->segmentation_map = f->extradata->data;
> f->mv = (struct VP9mvrefPair *) (f->extradata->data + sz);
>
> + if (ctx->hwaccel) {
> + const AVHWAccel *hwaccel = ctx->hwaccel;
> + av_assert0(!f->hwaccel_picture_private);
> + if (hwaccel->frame_priv_data_size) {
> + f->hwaccel_priv_buf = av_buffer_allocz(hwaccel->frame_priv_data_size);
> + if (!f->hwaccel_priv_buf)
> + goto fail;
> + f->hwaccel_picture_private = f->hwaccel_priv_buf->data;
> + }
> + }
> +
> return 0;
> -}
>
> -static void vp9_unref_frame(AVCodecContext *ctx, VP9Frame *f)
> -{
> - ff_thread_release_buffer(ctx, &f->tf);
> - av_buffer_unref(&f->extradata);
> - f->segmentation_map = NULL;
> +fail:
> + vp9_unref_frame(ctx, f);
> + return AVERROR(ENOMEM);
> }
>
> static int vp9_ref_frame(AVCodecContext *ctx, VP9Frame *dst, VP9Frame *src)
> @@ -201,19 +217,31 @@ static int vp9_ref_frame(AVCodecContext *ctx, VP9Frame *dst, VP9Frame *src)
> if ((res = ff_thread_ref_frame(&dst->tf, &src->tf)) < 0) {
> return res;
> } else if (!(dst->extradata = av_buffer_ref(src->extradata))) {
> - vp9_unref_frame(ctx, dst);
> - return AVERROR(ENOMEM);
> + goto fail;
> }
>
> dst->segmentation_map = src->segmentation_map;
> dst->mv = src->mv;
> dst->uses_2pass = src->uses_2pass;
>
> + if (src->hwaccel_picture_private) {
> + dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf);
> + if (!dst->hwaccel_priv_buf)
> + goto fail;
> + dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data;
> + }
> +
> return 0;
> +
> +fail:
> + vp9_unref_frame(ctx, dst);
> + return AVERROR(ENOMEM);
> }
>
> static int update_size(AVCodecContext *ctx, int w, int h)
> {
> +#define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + CONFIG_VP9_D3D11VA_HWACCEL)
> + enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts;
> VP9Context *s = ctx->priv_data;
> uint8_t *p;
> int bytesperpixel = s->bytesperpixel, res;
> @@ -225,7 +253,25 @@ static int update_size(AVCodecContext *ctx, int w, int h)
>
> if ((res = ff_set_dimensions(ctx, w, h)) < 0)
> return res;
> - s->last_fmt = ctx->pix_fmt = s->pix_fmt;
> + s->last_fmt = s->pix_fmt;
> +
> + if (s->pix_fmt == AV_PIX_FMT_YUV420P) {
> +#if CONFIG_VP9_DXVA2_HWACCEL
> + *fmtp++ = AV_PIX_FMT_DXVA2_VLD;
> +#endif
> +#if CONFIG_VP9_D3D11VA_HWACCEL
> + *fmtp++ = AV_PIX_FMT_D3D11VA_VLD;
> +#endif
> + }
> +
> + *fmtp++ = s->pix_fmt;
> + *fmtp = AV_PIX_FMT_NONE;
I wonder if there should be a nicer way to do that, instead of
duplicating it over all new codecs. (Just thinking loudly.)
> +
> + res = ff_thread_get_format(ctx, pix_fmts);
> + if (res < 0)
> + return res;
> +
> + ctx->pix_fmt = res;
> s->sb_cols = (w + 63) >> 6;
> s->sb_rows = (h + 63) >> 6;
> s->cols = (w + 7) >> 3;
> @@ -573,32 +619,6 @@ static int decode_frame_header(AVCodecContext *ctx,
> s->s.h.varcompref[1] = 2;
> }
> }
> -
> - for (i = 0; i < 3; i++) {
> - AVFrame *ref = s->s.refs[s->s.h.refidx[i]].f;
> - int refw = ref->width, refh = ref->height;
> -
> - if (ref->format != s->pix_fmt) {
> - av_log(ctx, AV_LOG_ERROR,
> - "Ref pixfmt (%s) did not match current frame (%s)",
> - av_get_pix_fmt_name(ref->format),
> - av_get_pix_fmt_name(s->pix_fmt));
> - return AVERROR_INVALIDDATA;
> - } else if (refw == w && refh == h) {
> - s->mvscale[i][0] = s->mvscale[i][1] = 0;
> - } else {
> - if (w * 2 < refw || h * 2 < refh || w > 16 * refw || h > 16 * refh) {
> - av_log(ctx, AV_LOG_ERROR,
> - "Invalid ref frame dimensions %dx%d for frame size %dx%d\n",
> - refw, refh, w, h);
> - return AVERROR_INVALIDDATA;
> - }
> - s->mvscale[i][0] = (refw << 14) / w;
> - s->mvscale[i][1] = (refh << 14) / h;
> - s->mvstep[i][0] = 16 * s->mvscale[i][0] >> 14;
> - s->mvstep[i][1] = 16 * s->mvscale[i][1] >> 14;
> - }
> - }
> }
> }
> s->s.h.refreshctx = s->s.h.errorres ? 0 : get_bits1(&s->gb);
> @@ -748,6 +768,35 @@ static int decode_frame_header(AVCodecContext *ctx,
> return AVERROR(ENOMEM);
> }
> }
> +
> + /* check reference frames */
> + if (!s->s.h.keyframe && !s->s.h.intraonly) {
> + for (i = 0; i < 3; i++) {
> + AVFrame *ref = s->s.refs[s->s.h.refidx[i]].f;
> + int refw = ref->width, refh = ref->height;
> +
> + if (ref->format != ctx->pix_fmt) {
> + av_log(ctx, AV_LOG_ERROR,
> + "Ref pixfmt (%s) did not match current frame (%s)",
> + av_get_pix_fmt_name(ref->format),
> + av_get_pix_fmt_name(ctx->pix_fmt));
> + return AVERROR_INVALIDDATA;
> + } else if (refw == w && refh == h) {
> + s->mvscale[i][0] = s->mvscale[i][1] = 0;
> + } else {
> + if (w * 2 < refw || h * 2 < refh || w > 16 * refw || h > 16 * refh) {
> + av_log(ctx, AV_LOG_ERROR,
> + "Invalid ref frame dimensions %dx%d for frame size %dx%d\n",
> + refw, refh, w, h);
> + return AVERROR_INVALIDDATA;
> + }
> + s->mvscale[i][0] = (refw << 14) / w;
> + s->mvscale[i][1] = (refh << 14) / h;
> + s->mvstep[i][0] = 16 * s->mvscale[i][0] >> 14;
> + s->mvstep[i][1] = 16 * s->mvscale[i][1] >> 14;
> + }
> + }
> + }
>
> if (s->s.h.keyframe || s->s.h.errorres || (s->s.h.intraonly && s->s.h.resetctx == 3)) {
> s->prob_ctx[0].p = s->prob_ctx[1].p = s->prob_ctx[2].p =
> @@ -3979,6 +4028,19 @@ static int vp9_decode_frame(AVCodecContext *ctx, void *frame,
> return res;
> }
>
> + if (ctx->hwaccel) {
> + res = ctx->hwaccel->start_frame(ctx, NULL, 0);
> + if (res < 0)
> + return res;
> + res = ctx->hwaccel->decode_slice(ctx, pkt->data, pkt->size);
> + if (res < 0)
> + return res;
> + res = ctx->hwaccel->end_frame(ctx);
> + if (res < 0)
> + return res;
> + goto finish;
> + }
> +
> // main tile decode loop
> bytesperpixel = s->bytesperpixel;
> memset(s->above_partition_ctx, 0, s->cols);
> @@ -4148,6 +4210,7 @@ static int vp9_decode_frame(AVCodecContext *ctx, void *frame,
> } while (s->pass++ == 1);
> ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0);
>
> +finish:
> // ref frame setup
> for (i = 0; i < 8; i++) {
> if (s->s.refs[i].f->buf[0])
> diff --git a/libavcodec/vp9.h b/libavcodec/vp9.h
> index 27cdfc6..df5bd4d 100644
> --- a/libavcodec/vp9.h
> +++ b/libavcodec/vp9.h
> @@ -129,6 +129,9 @@ typedef struct VP9Frame {
> uint8_t *segmentation_map;
> struct VP9mvrefPair *mv;
> int uses_2pass;
> +
> + AVBufferRef *hwaccel_priv_buf;
> + void *hwaccel_picture_private;
> } VP9Frame;
>
> typedef struct VP9BitstreamHeader {
More information about the ffmpeg-devel
mailing list