aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec
diff options
context:
space:
mode:
authorMarton Balint <cus@passwd.hu>2019-10-27 18:10:35 +0100
committerJames Zern <jzern@google.com>2019-11-05 23:14:24 -0800
commit5478e2cc57d1fb73ab49f39c84b23f180bfa39e5 (patch)
tree03c7a7ed988d18a13f5c9745e5ae70286882de25 /libavcodec
parent98aa1eb1cb1b354908a064c5265244e789fb8129 (diff)
downloadffmpeg-5478e2cc57d1fb73ab49f39c84b23f180bfa39e5.tar.gz
avcodec/libvpxdec: decode to custom framebuffers for vp9
This avoids copying the full frame after decoding. Signed-off-by: Marton Balint <cus@passwd.hu> Signed-off-by: James Zern <jzern@google.com>
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/libvpxdec.c73
1 files changed, 68 insertions, 5 deletions
diff --git a/libavcodec/libvpxdec.c b/libavcodec/libvpxdec.c
index 5c72be5439..fdd5d458d3 100644
--- a/libavcodec/libvpxdec.c
+++ b/libavcodec/libvpxdec.c
@@ -25,6 +25,7 @@
#define VPX_CODEC_DISABLE_COMPAT 1
#include <vpx/vpx_decoder.h>
+#include <vpx/vpx_frame_buffer.h>
#include <vpx/vp8dx.h>
#include "libavutil/common.h"
@@ -38,9 +39,46 @@
typedef struct VPxDecoderContext {
struct vpx_codec_ctx decoder;
struct vpx_codec_ctx decoder_alpha;
+ AVBufferPool *pool;
+ size_t pool_size;
int has_alpha_channel;
} VPxContext;
+
+static int get_frame_buffer(void *priv, size_t min_size, vpx_codec_frame_buffer_t *fb)
+{
+ VPxContext *ctx = priv;
+ AVBufferRef *buf;
+
+ if (min_size > ctx->pool_size) {
+ av_buffer_pool_uninit(&ctx->pool);
+ /* According to the libvpx docs the buffer must be zeroed out. */
+ ctx->pool = av_buffer_pool_init(min_size, av_buffer_allocz);
+ if (!ctx->pool) {
+ ctx->pool_size = 0;
+ return AVERROR(ENOMEM);
+ }
+ ctx->pool_size = min_size;
+ }
+
+ buf = av_buffer_pool_get(ctx->pool);
+ if (!buf)
+ return AVERROR(ENOMEM);
+
+ fb->priv = buf;
+ fb->size = ctx->pool_size;
+ fb->data = buf->data;
+
+ return 0;
+}
+
+static int release_frame_buffer(void *priv, vpx_codec_frame_buffer_t *fb)
+{
+ AVBufferRef *buf = fb->priv;
+ av_buffer_unref(&buf);
+ return 0;
+}
+
static av_cold int vpx_init(AVCodecContext *avctx,
struct vpx_codec_ctx* decoder,
const struct vpx_codec_iface *iface)
@@ -59,6 +97,9 @@ static av_cold int vpx_init(AVCodecContext *avctx,
return AVERROR(EINVAL);
}
+ if (avctx->codec_id == AV_CODEC_ID_VP9)
+ vpx_codec_set_frame_buffer_functions(decoder, get_frame_buffer, release_frame_buffer, avctx->priv_data);
+
return 0;
}
@@ -241,8 +282,6 @@ static int vpx_decode(AVCodecContext *avctx,
if (ret < 0)
return ret;
}
- if ((ret = ff_get_buffer(avctx, picture, 0)) < 0)
- return ret;
planes[0] = img->planes[VPX_PLANE_Y];
planes[1] = img->planes[VPX_PLANE_U];
@@ -254,8 +293,31 @@ static int vpx_decode(AVCodecContext *avctx,
linesizes[2] = img->stride[VPX_PLANE_V];
linesizes[3] =
ctx->has_alpha_channel ? img_alpha->stride[VPX_PLANE_Y] : 0;
- av_image_copy(picture->data, picture->linesize, (const uint8_t**)planes,
- linesizes, avctx->pix_fmt, img->d_w, img->d_h);
+
+ if (img->fb_priv && (!ctx->has_alpha_channel || img_alpha->fb_priv)) {
+ ret = ff_decode_frame_props(avctx, picture);
+ if (ret < 0)
+ return ret;
+ picture->buf[0] = av_buffer_ref(img->fb_priv);
+ if (!picture->buf[0])
+ return AVERROR(ENOMEM);
+ if (ctx->has_alpha_channel) {
+ picture->buf[1] = av_buffer_ref(img_alpha->fb_priv);
+ if (!picture->buf[1]) {
+ av_frame_unref(picture);
+ return AVERROR(ENOMEM);
+ }
+ }
+ for (int i = 0; i < 4; i++) {
+ picture->data[i] = planes[i];
+ picture->linesize[i] = linesizes[i];
+ }
+ } else {
+ if ((ret = ff_get_buffer(avctx, picture, 0)) < 0)
+ return ret;
+ av_image_copy(picture->data, picture->linesize, (const uint8_t**)planes,
+ linesizes, avctx->pix_fmt, img->d_w, img->d_h);
+ }
*got_frame = 1;
}
return avpkt->size;
@@ -267,6 +329,7 @@ static av_cold int vpx_free(AVCodecContext *avctx)
vpx_codec_destroy(&ctx->decoder);
if (ctx->has_alpha_channel)
vpx_codec_destroy(&ctx->decoder_alpha);
+ av_buffer_pool_uninit(&ctx->pool);
return 0;
}
@@ -307,7 +370,7 @@ AVCodec ff_libvpx_vp9_decoder = {
.init = vp9_init,
.close = vpx_free,
.decode = vpx_decode,
- .capabilities = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1,
+ .capabilities = AV_CODEC_CAP_AUTO_THREADS,
.init_static_data = ff_vp9_init_static,
.profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles),
.wrapper_name = "libvpx",