static int vpx_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { VPxContext *ctx = avctx->priv_data; AVFrame *picture = data; const void *iter = NULL; const void *iter_alpha = NULL; struct vpx_image *img, *img_alpha; int ret; uint8_t *side_data = NULL; int side_data_size = 0; ret = decode_frame(avctx, &ctx->decoder, avpkt->data, avpkt->size); if (ret) return ret; side_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, &side_data_size); if (side_data_size > 1) { const 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_init(avctx, #if CONFIG_LIBVPX_VP8_DECODER && CONFIG_LIBVPX_VP9_DECODER (avctx->codec_id == AV_CODEC_ID_VP8) ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo, #elif CONFIG_LIBVPX_VP8_DECODER &vpx_codec_vp8_dx_algo, #else &vpx_codec_vp9_dx_algo, #endif 1); if (ret) return ret; } ret = decode_frame(avctx, &ctx->decoder_alpha, side_data, side_data_size); if (ret) return ret; } } 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 (img->d_w > img->w || img->d_h > img->h) { av_log(avctx, AV_LOG_ERROR, "Display dimensions %dx%d exceed storage %dx%d\n", img->d_w, img->d_h, img->w, img->h); return AVERROR_EXTERNAL; } 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); #else av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n", img->fmt, 8); #endif return ret; } if ((int) img->d_w != avctx->width || (int) img->d_h != avctx->height) { av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n", avctx->width, avctx->height, img->d_w, img->d_h); ret = ff_set_dimensions(avctx, img->d_w, img->d_h); 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]; 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; }