VPx (VP8/VP9) alpha encoding has been part of FFmpeg. Now, add the ability to decode such files with alpha channel.
Signed-off-by: Vignesh Venkatasubramanian <vigne...@google.com> --- libavcodec/libvpxdec.c | 111 ++++++++++++++++++++++++++++------- tests/fate/vpx.mak | 3 + tests/ref/fate/vp8-alpha-decode | 125 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+), 20 deletions(-) create mode 100644 tests/ref/fate/vp8-alpha-decode diff --git a/libavcodec/libvpxdec.c b/libavcodec/libvpxdec.c index adbc6d0..34378d8 100644 --- a/libavcodec/libvpxdec.c +++ b/libavcodec/libvpxdec.c @@ -29,6 +29,7 @@ #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" #include "avcodec.h" #include "internal.h" #include "libvpx.h" @@ -36,12 +37,15 @@ typedef struct VP8DecoderContext { struct vpx_codec_ctx decoder; + struct vpx_codec_ctx decoder_alpha; + int has_alpha_channel; } VP8Context; -static av_cold int vpx_init(AVCodecContext *avctx, - const struct vpx_codec_iface *iface) +static int vpx_codec_dec_init_wrapper(AVCodecContext *avctx, + VP8Context *ctx, + const struct vpx_codec_iface *iface, + int is_alpha_decoder) { - VP8Context *ctx = avctx->priv_data; struct vpx_codec_dec_cfg deccfg = { /* token partitions+1 would be a decent choice */ .threads = FFMIN(avctx->thread_count, 16) @@ -50,7 +54,9 @@ static av_cold int vpx_init(AVCodecContext *avctx, av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str()); av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config()); - if (vpx_codec_dec_init(&ctx->decoder, iface, &deccfg, 0) != VPX_CODEC_OK) { + if (vpx_codec_dec_init( + is_alpha_decoder ? &ctx->decoder_alpha : &ctx->decoder, + iface, &deccfg, 0) != VPX_CODEC_OK) { const char *error = vpx_codec_error(&ctx->decoder); av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n", error); @@ -60,8 +66,16 @@ static av_cold int vpx_init(AVCodecContext *avctx, return 0; } +static av_cold int vpx_init(AVCodecContext *avctx, + const struct vpx_codec_iface *iface) +{ + VP8Context *ctx = avctx->priv_data; + return vpx_codec_dec_init_wrapper(avctx, ctx, iface, 0); +} + // returns 0 on success, AVERROR_INVALIDDATA otherwise -static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img) +static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, + int has_alpha_channel) { #if VPX_IMAGE_ABI_VERSION >= 3 static const enum AVColorSpace colorspaces[8] = { @@ -82,7 +96,8 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img) case VPX_IMG_FMT_I420: if (avctx->codec_id == AV_CODEC_ID_VP9) avctx->profile = FF_PROFILE_VP9_0; - avctx->pix_fmt = AV_PIX_FMT_YUV420P; + avctx->pix_fmt = + has_alpha_channel ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; return 0; #if CONFIG_LIBVPX_VP9_DECODER case VPX_IMG_FMT_I422: @@ -168,29 +183,72 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img) } } +static int vpx_codec_decode_wrapper(AVCodecContext *avctx, + vpx_codec_ctx_t *decoder, uint8_t *data, + uint32_t data_sz) +{ + if (vpx_codec_decode(decoder, data, data_sz, NULL, 0) != VPX_CODEC_OK) { + const char *error = vpx_codec_error(decoder); + const char *detail = vpx_codec_error_detail(decoder); + + av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error); + if (detail) { + av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", + detail); + } + return AVERROR_INVALIDDATA; + } + return 0; +} + static int vp8_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { VP8Context *ctx = avctx->priv_data; AVFrame *picture = data; const void *iter = NULL; - struct vpx_image *img; + const void *iter_alpha = NULL; + struct vpx_image *img, *img_alpha; int ret; + uint8_t *side_data = NULL; + int side_data_size = 0; - if (vpx_codec_decode(&ctx->decoder, avpkt->data, avpkt->size, NULL, 0) != - VPX_CODEC_OK) { - const char *error = vpx_codec_error(&ctx->decoder); - const char *detail = vpx_codec_error_detail(&ctx->decoder); + ret = vpx_codec_decode_wrapper(avctx, &ctx->decoder, avpkt->data, + avpkt->size); + if (ret) + return ret; - av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error); - if (detail) - av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", - detail); - return AVERROR_INVALIDDATA; + side_data = av_packet_get_side_data(avpkt, + AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, + &side_data_size); + if (side_data_size > 1) { + uint64_t additional_id = AV_RB64(side_data); + side_data += 8; + side_data_size -= 8; + if (additional_id == 1) { // 1 stands for alpha channel data. + if (!ctx->has_alpha_channel) { + ctx->has_alpha_channel = 1; + ret = vpx_codec_dec_init_wrapper( + avctx, ctx, + (avctx->codec_id == AV_CODEC_ID_VP8) ? + &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo, + 1); + if (ret) + return ret; + } + ret = vpx_codec_decode_wrapper(avctx, &ctx->decoder_alpha, + side_data, side_data_size); + if (ret) + return ret; + } } - if ((img = vpx_codec_get_frame(&ctx->decoder, &iter))) { - if ((ret = set_pix_fmt(avctx, img)) < 0) { + if ((img = vpx_codec_get_frame(&ctx->decoder, &iter)) && + (!ctx->has_alpha_channel || + (img_alpha = vpx_codec_get_frame(&ctx->decoder_alpha, &iter_alpha)))) { + uint8_t *planes[4]; + int linesizes[4]; + if ((ret = set_pix_fmt(avctx, img, ctx->has_alpha_channel)) < 0) { #ifdef VPX_IMG_FMT_HIGHBITDEPTH av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n", img->fmt, img->bit_depth); @@ -210,8 +268,19 @@ static int vp8_decode(AVCodecContext *avctx, } if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) return ret; - av_image_copy(picture->data, picture->linesize, (const uint8_t **)img->planes, - img->stride, avctx->pix_fmt, img->d_w, img->d_h); + + planes[0] = img->planes[VPX_PLANE_Y]; + planes[1] = img->planes[VPX_PLANE_U]; + planes[2] = img->planes[VPX_PLANE_V]; + planes[3] = + ctx->has_alpha_channel ? img_alpha->planes[VPX_PLANE_Y] : NULL; + linesizes[0] = img->stride[VPX_PLANE_Y]; + linesizes[1] = img->stride[VPX_PLANE_U]; + 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); *got_frame = 1; } return avpkt->size; @@ -221,6 +290,8 @@ static av_cold int vp8_free(AVCodecContext *avctx) { VP8Context *ctx = avctx->priv_data; vpx_codec_destroy(&ctx->decoder); + if (ctx->has_alpha_channel) + vpx_codec_destroy(&ctx->decoder_alpha); return 0; } diff --git a/tests/fate/vpx.mak b/tests/fate/vpx.mak index f0bcfac..b29a71a 100644 --- a/tests/fate/vpx.mak +++ b/tests/fate/vpx.mak @@ -31,6 +31,9 @@ fate-vp6f: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/flash-vp6/clip10 FATE_VP8-$(call DEMDEC, FLV, VP8) += fate-vp8-alpha fate-vp8-alpha: CMD = framecrc -i $(TARGET_SAMPLES)/vp8_alpha/vp8_video_with_alpha.webm -vcodec copy +FATE_VP8-$(call DEMDEC, FLV, VP8) += fate-vp8-alpha-decode +fate-vp8-alpha-decode: CMD = framecrc -vcodec libvpx -i $(TARGET_SAMPLES)/vp8_alpha/vp8_video_with_alpha.webm -vcodec rawvideo -pix_fmt yuva420p -f rawvideo + FATE_VP8-$(call DEMDEC, WEBM_DASH_MANIFEST, VP8) += fate-webm-dash-manifest fate-webm-dash-manifest: CMD = run $(FFMPEG) -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video1.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video2.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_audio1.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_audio2.webm -c copy -map 0 -map 1 -map 2 -map 3 -f webm_dash_manifest -adaptation_sets "id=0,streams=0,1 id=1,streams=2,3" - diff --git a/tests/ref/fate/vp8-alpha-decode b/tests/ref/fate/vp8-alpha-decode new file mode 100644 index 0000000..40b28d2 --- /dev/null +++ b/tests/ref/fate/vp8-alpha-decode @@ -0,0 +1,125 @@ +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x213 +#sar 0: 1/1 +0, 0, 0, 1, 170560, 0x2a1293ad +0, 1, 1, 1, 170560, 0x6c88cb4b +0, 2, 2, 1, 170560, 0x27585dc5 +0, 3, 3, 1, 170560, 0x73cbe037 +0, 4, 4, 1, 170560, 0x4eca3cd5 +0, 5, 5, 1, 170560, 0xdfecde95 +0, 6, 6, 1, 170560, 0x38dfe631 +0, 7, 7, 1, 170560, 0xbbe546a1 +0, 8, 8, 1, 170560, 0xa78ffec3 +0, 9, 9, 1, 170560, 0x917923f7 +0, 10, 10, 1, 170560, 0x82927437 +0, 11, 11, 1, 170560, 0xe1bfa664 +0, 12, 12, 1, 170560, 0x1091e069 +0, 13, 13, 1, 170560, 0x96551722 +0, 14, 14, 1, 170560, 0x9a952c31 +0, 15, 15, 1, 170560, 0xb2e34dff +0, 16, 16, 1, 170560, 0x09f77a76 +0, 17, 17, 1, 170560, 0xf6f5a3de +0, 18, 18, 1, 170560, 0x6453bd09 +0, 19, 19, 1, 170560, 0x7d64c755 +0, 20, 20, 1, 170560, 0x1e11c29d +0, 21, 21, 1, 170560, 0x57dca8ba +0, 22, 22, 1, 170560, 0x594d982a +0, 23, 23, 1, 170560, 0xd2017b7d +0, 24, 24, 1, 170560, 0x46af60e2 +0, 25, 25, 1, 170560, 0x186b60bd +0, 26, 26, 1, 170560, 0x9bd96210 +0, 27, 27, 1, 170560, 0x6efb7e78 +0, 28, 28, 1, 170560, 0xd0219673 +0, 29, 29, 1, 170560, 0x81bfc1c7 +0, 30, 30, 1, 170560, 0x61a30393 +0, 31, 31, 1, 170560, 0x6cfc30e0 +0, 32, 32, 1, 170560, 0x820557d8 +0, 33, 33, 1, 170560, 0xa4f88301 +0, 34, 34, 1, 170560, 0x072fb542 +0, 35, 35, 1, 170560, 0x8d3cd908 +0, 36, 36, 1, 170560, 0x776be292 +0, 37, 37, 1, 170560, 0x2074ca19 +0, 38, 38, 1, 170560, 0x3f5d8ab8 +0, 39, 39, 1, 170560, 0x393425b3 +0, 40, 40, 1, 170560, 0x8332948c +0, 41, 41, 1, 170560, 0x151df7b7 +0, 42, 42, 1, 170560, 0xd8e64eb2 +0, 43, 43, 1, 170560, 0xa3512c1c +0, 44, 44, 1, 170560, 0x27a15536 +0, 45, 45, 1, 170560, 0x2579d29a +0, 46, 46, 1, 170560, 0x75524551 +0, 47, 47, 1, 170560, 0xc7236dbd +0, 48, 48, 1, 170560, 0xbf2f7f6f +0, 49, 49, 1, 170560, 0xaad98788 +0, 50, 50, 1, 170560, 0xf5ab997a +0, 51, 51, 1, 170560, 0x153e84ef +0, 52, 52, 1, 170560, 0x79ed8200 +0, 53, 53, 1, 170560, 0x524474a3 +0, 54, 54, 1, 170560, 0x3602695d +0, 55, 55, 1, 170560, 0x13cd63cd +0, 56, 56, 1, 170560, 0xdfba6dac +0, 57, 57, 1, 170560, 0x8b319424 +0, 58, 58, 1, 170560, 0x43b49c67 +0, 59, 59, 1, 170560, 0x2107c194 +0, 60, 60, 1, 170560, 0x5ecb22f3 +0, 61, 61, 1, 170560, 0x1ddb4a99 +0, 62, 62, 1, 170560, 0xc5ac63ed +0, 63, 63, 1, 170560, 0x3db28c93 +0, 64, 64, 1, 170560, 0x6b98a419 +0, 65, 65, 1, 170560, 0x17deae77 +0, 66, 66, 1, 170560, 0x3bcfb34e +0, 67, 67, 1, 170560, 0x6f6cb81b +0, 68, 68, 1, 170560, 0x0655e03b +0, 69, 69, 1, 170560, 0xde7d06a1 +0, 70, 70, 1, 170560, 0x8e51535c +0, 71, 71, 1, 170560, 0xea256867 +0, 72, 72, 1, 170560, 0xc08c4fdd +0, 73, 73, 1, 170560, 0xe30b4791 +0, 74, 74, 1, 170560, 0x981b9218 +0, 75, 75, 1, 170560, 0x29d34848 +0, 76, 76, 1, 170560, 0xafc0000c +0, 77, 77, 1, 170560, 0x18b477fb +0, 78, 78, 1, 170560, 0x7f4ac3e3 +0, 79, 79, 1, 170560, 0xc653fcb9 +0, 80, 80, 1, 170560, 0x1bef5046 +0, 81, 81, 1, 170560, 0x34b28216 +0, 82, 82, 1, 170560, 0x2b75c377 +0, 83, 83, 1, 170560, 0x014b226b +0, 84, 84, 1, 170560, 0x8a964e61 +0, 85, 85, 1, 170560, 0xe49880a4 +0, 86, 86, 1, 170560, 0x4472cbd1 +0, 87, 87, 1, 170560, 0xe56a20f8 +0, 88, 88, 1, 170560, 0x0ab3653f +0, 89, 89, 1, 170560, 0xadc89f74 +0, 90, 90, 1, 170560, 0xe36dfdaf +0, 91, 91, 1, 170560, 0xe2514944 +0, 92, 92, 1, 170560, 0xc4eb9ac9 +0, 93, 93, 1, 170560, 0xfde3ec34 +0, 94, 94, 1, 170560, 0x4a1c4a02 +0, 95, 95, 1, 170560, 0xd803acee +0, 96, 96, 1, 170560, 0x4f8809cc +0, 97, 97, 1, 170560, 0x566b6b45 +0, 98, 98, 1, 170560, 0x8bd2bc6a +0, 99, 99, 1, 170560, 0xa509ec67 +0, 100, 100, 1, 170560, 0xeed1fe6d +0, 101, 101, 1, 170560, 0xa8fe0bef +0, 102, 102, 1, 170560, 0x909c0af9 +0, 103, 103, 1, 170560, 0xc8f5f598 +0, 104, 104, 1, 170560, 0x3e93c2e3 +0, 105, 105, 1, 170560, 0xa0c275b6 +0, 106, 106, 1, 170560, 0x93085bc0 +0, 107, 107, 1, 170560, 0x7fd646b1 +0, 108, 108, 1, 170560, 0x67a24d63 +0, 109, 109, 1, 170560, 0x184b79f1 +0, 110, 110, 1, 170560, 0x979cc32f +0, 111, 111, 1, 170560, 0xdc0a064f +0, 112, 112, 1, 170560, 0xabf94c6f +0, 113, 113, 1, 170560, 0x614d6043 +0, 114, 114, 1, 170560, 0x4a963b04 +0, 115, 115, 1, 170560, 0x06290370 +0, 116, 116, 1, 170560, 0xb68ccf53 +0, 117, 117, 1, 170560, 0x9e379142 +0, 118, 118, 1, 170560, 0x09a561af +0, 119, 119, 1, 170560, 0xf0fb1e9a -- 2.8.0.rc3.226.g39d4020 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel