@ -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,10 +37,13 @@
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 )
const struct vpx_codec_iface * iface ,
int is_alpha_decoder )
{
VP8Context * ctx = avctx - > priv_data ;
struct vpx_codec_dec_cfg deccfg = {
@ -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 ) ;
@ -61,7 +67,8 @@ static av_cold int vpx_init(AVCodecContext *avctx,
}
// 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 +89,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 +176,75 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img)
}
}
static int decode_frame ( 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 = decode_frame ( 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 ) {
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 ) ) ) {
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 +264,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,13 +286,15 @@ 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 ;
}
# if CONFIG_LIBVPX_VP8_DECODER
static av_cold int vp8_init ( AVCodecContext * avctx )
{
return vpx_init ( avctx , & vpx_codec_vp8_dx_algo ) ;
return vpx_init ( avctx , & vpx_codec_vp8_dx_algo , 0 ) ;
}
AVCodec ff_libvpx_vp8_decoder = {
@ -246,7 +313,7 @@ AVCodec ff_libvpx_vp8_decoder = {
# if CONFIG_LIBVPX_VP9_DECODER
static av_cold int vp9_init ( AVCodecContext * avctx )
{
return vpx_init ( avctx , & vpx_codec_vp9_dx_algo ) ;
return vpx_init ( avctx , & vpx_codec_vp9_dx_algo , 0 ) ;
}
AVCodec ff_libvpx_vp9_decoder = {