[FFmpeg-devel] [PATCH] libavcodec/libvpx: Add VPx alpha decode support
Vignesh Venkatasubramanian
vigneshv at google.com
Thu Jul 7 21:43:32 EEST 2016
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 <vigneshv at 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
More information about the ffmpeg-devel
mailing list