@ -24,6 +24,7 @@
# include "config.h"
# include "libavutil/avassert.h"
# include "libavutil/avstring.h"
# include "libavutil/common.h"
# include "libavutil/frame.h"
# include "libavutil/hwcontext.h"
@ -31,6 +32,7 @@
# include "avcodec.h"
# include "bytestream.h"
# include "decode.h"
# include "internal.h"
# include "thread.h"
@ -152,109 +154,188 @@ static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame)
return 0 ;
}
static int do_decode ( AVCodecContext * avctx , AVPacket * pkt )
int ff_decode_get_packet ( AVCodecContext * avctx , AVPacket * pkt )
{
int got_frame ;
AVCodecInternal * avci = avctx - > internal ;
int ret ;
av_assert0 ( ! avctx - > internal - > buffer_frame - > buf [ 0 ] ) ;
if ( avci - > draining )
return AVERROR_EOF ;
if ( ! avci - > buffer_pkt - > data & & ! avci - > buffer_pkt - > side_data_elems )
return AVERROR ( EAGAIN ) ;
av_packet_move_ref ( pkt , avci - > buffer_pkt ) ;
ret = extract_packet_props ( avctx - > internal , pkt ) ;
if ( ret < 0 )
goto finish ;
ret = apply_param_change ( avctx , pkt ) ;
if ( ret < 0 )
goto finish ;
if ( avctx - > codec - > receive_frame )
avci - > compat_decode_consumed + = pkt - > size ;
if ( ! pkt )
pkt = avctx - > internal - > buffer_pkt ;
return 0 ;
finish :
av_packet_unref ( pkt ) ;
return ret ;
}
/*
* The core of the receive_frame_wrapper for the decoders implementing
* the simple API . Certain decoders might consume partial packets without
* returning any output , so this function needs to be called in a loop until it
* returns EAGAIN .
* */
static int decode_simple_internal ( AVCodecContext * avctx , AVFrame * frame )
{
AVCodecInternal * avci = avctx - > internal ;
DecodeSimpleContext * ds = & avci - > ds ;
AVPacket * pkt = ds - > in_pkt ;
int got_frame ;
int ret ;
// This is the lesser evil. The field is for compatibility with legacy users
// of the legacy API, and users using the new API should not be forced to
// even know about this field.
avctx - > refcounted_frames = 1 ;
if ( ! pkt - > data & & ! avci - > draining ) {
av_packet_unref ( pkt ) ;
ret = ff_decode_get_packet ( avctx , pkt ) ;
if ( ret < 0 & & ret ! = AVERROR_EOF )
return ret ;
}
// Some codecs (at least wma lossless) will crash when feeding drain packets
// after EOF was signaled.
if ( avctx - > internal - > draining_done )
if ( avci - > draining_done )
return AVERROR_EOF ;
if ( ! pkt - > data & &
! ( avctx - > codec - > capabilities & AV_CODEC_CAP_DELAY | |
avctx - > active_thread_type & FF_THREAD_FRAME ) )
return AVERROR_EOF ;
if ( avctx - > codec_type = = AVMEDIA_TYPE_VIDEO ) {
ret = avcodec_decode_video2 ( avctx , avctx - > internal - > buffer_frame ,
& got_frame , pkt ) ;
if ( ret > = 0 )
ret = pkt - > size ;
} else if ( avctx - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
ret = avcodec_decode_audio4 ( avctx , avctx - > internal - > buffer_frame ,
& got_frame , pkt ) ;
got_frame = 0 ;
if ( HAVE_THREADS & & avctx - > active_thread_type & FF_THREAD_FRAME ) {
ret = ff_thread_decode_frame ( avctx , frame , & got_frame , pkt ) ;
} else {
ret = AVERROR ( EINVAL ) ;
ret = avctx - > codec - > decode ( avctx , frame , & got_frame , pkt ) ;
if ( ! ( avctx - > codec - > caps_internal & FF_CODEC_CAP_SETS_PKT_DTS ) )
frame - > pkt_dts = pkt - > dts ;
/* get_buffer is supposed to set frame parameters */
if ( ! ( avctx - > codec - > capabilities & AV_CODEC_CAP_DR1 ) ) {
frame - > sample_aspect_ratio = avctx - > sample_aspect_ratio ;
frame - > width = avctx - > width ;
frame - > height = avctx - > height ;
frame - > format = avctx - > codec - > type = = AVMEDIA_TYPE_VIDEO ?
avctx - > pix_fmt : avctx - > sample_fmt ;
}
}
if ( ret < 0 )
return ret ;
emms_c ( ) ;
if ( ! got_frame )
av_frame_unref ( frame ) ;
if ( ret > = 0 & & avctx - > codec - > type = = AVMEDIA_TYPE_VIDEO )
ret = pkt - > size ;
# if FF_API_AVCTX_TIMEBASE
if ( avctx - > framerate . num > 0 & & avctx - > framerate . den > 0 )
avctx - > time_base = av_inv_q ( avctx - > framerate ) ;
# endif
if ( avctx - > internal - > draining & & ! got_frame )
avctx - > internal - > draining_done = 1 ;
avci - > draining_done = 1 ;
avci - > compat_decode_consumed + = ret ;
if ( ret > = pkt - > size ) {
av_packet_unref ( avctx - > internal - > buffer_pkt ) ;
if ( ret > = pkt - > size | | ret < 0 ) {
av_packet_unref ( pkt ) ;
} else {
int consumed = ret ;
if ( pkt ! = avctx - > internal - > buffer_pkt ) {
av_packet_unref ( avctx - > internal - > buffer_pkt ) ;
if ( ( ret = av_packet_ref ( avctx - > internal - > buffer_pkt , pkt ) ) < 0 )
return ret ;
}
avctx - > internal - > buffer_pkt - > data + = consumed ;
avctx - > internal - > buffer_pkt - > size - = consumed ;
avctx - > internal - > buffer_pkt - > pts = AV_NOPTS_VALUE ;
avctx - > internal - > buffer_pkt - > dts = AV_NOPTS_VALUE ;
pkt - > data + = consumed ;
pkt - > size - = consumed ;
pkt - > pts = AV_NOPTS_VALUE ;
pkt - > dts = AV_NOPTS_VALUE ;
avci - > last_pkt_props - > pts = AV_NOPTS_VALUE ;
avci - > last_pkt_props - > dts = AV_NOPTS_VALUE ;
}
if ( got_frame )
av_assert0 ( avctx - > internal - > buffer_frame - > buf [ 0 ] ) ;
av_assert0 ( frame - > buf [ 0 ] ) ;
return ret < 0 ? ret : 0 ;
}
static int decode_simple_receive_frame ( AVCodecContext * avctx , AVFrame * frame )
{
int ret ;
while ( ! frame - > buf [ 0 ] ) {
ret = decode_simple_internal ( avctx , frame ) ;
if ( ret < 0 )
return ret ;
}
return 0 ;
}
int attribute_align_arg avcodec_send_packet ( AVCodecContext * avctx , const AVPacket * avpkt )
static int decode_receive_frame_internal ( AVCodecContext * avctx , AVFrame * frame )
{
AVCodecInternal * avci = avctx - > internal ;
int ret ;
av_assert0 ( ! frame - > buf [ 0 ] ) ;
if ( avctx - > codec - > receive_frame )
ret = avctx - > codec - > receive_frame ( avctx , frame ) ;
else
ret = decode_simple_receive_frame ( avctx , frame ) ;
if ( ret = = AVERROR_EOF )
avci - > draining_done = 1 ;
return ret ;
}
int attribute_align_arg avcodec_send_packet ( AVCodecContext * avctx , const AVPacket * avpkt )
{
AVCodecInternal * avci = avctx - > internal ;
int ret = 0 ;
if ( ! avcodec_is_open ( avctx ) | | ! av_codec_is_decoder ( avctx - > codec ) )
return AVERROR ( EINVAL ) ;
if ( avctx - > internal - > draining )
return AVERROR_EOF ;
if ( avci - > buffer_pkt - > data | | avci - > buffer_pkt - > side_data_elems )
return AVERROR ( EAGAIN ) ;
if ( ! avpkt | | ! avpkt - > size ) {
avctx - > internal - > draining = 1 ;
avpkt = NULL ;
if ( ! ( avctx - > codec - > capabilities & AV_CODEC_CAP_DELAY ) )
return 0 ;
} else {
ret = av_packet_ref ( avci - > buffer_pkt , avpkt ) ;
if ( ret < 0 )
return ret ;
}
if ( avctx - > codec - > send_packet ) {
if ( avpkt ) {
ret = apply_param_change ( avctx , ( AVPacket * ) avpkt ) ;
if ( ret < 0 )
return ret ;
}
return avctx - > codec - > send_packet ( avctx , avpkt ) ;
if ( ! avci - > buffer_frame - > buf [ 0 ] ) {
ret = decode_receive_frame_internal ( avctx , avci - > buffer_frame ) ;
if ( ret < 0 & & ret ! = AVERROR ( EAGAIN ) & & ret ! = AVERROR_EOF )
return ret ;
}
// Emulation via old API. Assume avpkt is likely not refcounted, while
// decoder output is always refcounted, and avoid copying.
if ( avctx - > internal - > buffer_pkt - > size | | avctx - > internal - > buffer_frame - > buf [ 0 ] )
return AVERROR ( EAGAIN ) ;
// The goal is decoding the first frame of the packet without using memcpy,
// because the common case is having only 1 frame per packet (especially
// with video, but audio too). In other cases, it can't be avoided, unless
// the user is feeding refcounted packets.
return do_decode ( avctx , ( AVPacket * ) avpkt ) ;
return 0 ;
}
int attribute_align_arg avcodec_receive_frame ( AVCodecContext * avctx , AVFrame * frame )
{
AVCodecInternal * avci = avctx - > internal ;
int ret ;
av_frame_unref ( frame ) ;
@ -262,157 +343,104 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr
if ( ! avcodec_is_open ( avctx ) | | ! av_codec_is_decoder ( avctx - > codec ) )
return AVERROR ( EINVAL ) ;
if ( avctx - > codec - > receive_frame ) {
if ( avctx - > internal - > draining & & ! ( avctx - > codec - > capabilities & AV_CODEC_CAP_DELAY ) )
return AVERROR_EOF ;
return avctx - > codec - > receive_frame ( avctx , frame ) ;
}
// Emulation via old API.
if ( ! avctx - > internal - > buffer_frame - > buf [ 0 ] ) {
if ( ! avctx - > internal - > buffer_pkt - > size & & ! avctx - > internal - > draining )
return AVERROR ( EAGAIN ) ;
while ( 1 ) {
if ( ( ret = do_decode ( avctx , avctx - > internal - > buffer_pkt ) ) < 0 ) {
av_packet_unref ( avctx - > internal - > buffer_pkt ) ;
return ret ;
}
// Some audio decoders may consume partial data without returning
// a frame (fate-wmapro-2ch). There is no way to make the caller
// call avcodec_receive_frame() again without returning a frame,
// so try to decode more in these cases.
if ( avctx - > internal - > buffer_frame - > buf [ 0 ] | |
! avctx - > internal - > buffer_pkt - > size )
break ;
}
if ( avci - > buffer_frame - > buf [ 0 ] ) {
av_frame_move_ref ( frame , avci - > buffer_frame ) ;
} else {
ret = decode_receive_frame_internal ( avctx , frame ) ;
if ( ret < 0 )
return ret ;
}
if ( ! avctx - > internal - > buffer_frame - > buf [ 0 ] )
return avctx - > internal - > draining ? AVERROR_EOF : AVERROR ( EAGAIN ) ;
avctx - > frame_number + + ;
av_frame_move_ref ( frame , avctx - > internal - > buffer_frame ) ;
return 0 ;
}
int attribute_align_arg avcodec_decode_video2 ( AVCodecContext * avctx , AVFrame * picture ,
int * got_picture_ptr ,
AVPacket * avpkt )
static int compat_decode ( AVCodecContext * avctx , AVFrame * frame ,
int * got_frame , AVPacket * pkt )
{
AVCodecInternal * avci = avctx - > internal ;
int ret ;
* got_picture_ptr = 0 ;
if ( ( avctx - > coded_width | | avctx - > coded_height ) & & av_image_check_size ( avctx - > coded_width , avctx - > coded_height , 0 , avctx ) )
return - 1 ;
av_assert0 ( avci - > compat_decode_consumed = = 0 ) ;
if ( ! avctx - > codec - > decode ) {
av_log ( avctx , AV_LOG_ERROR , " This decoder requires using the avcodec_send_packet() API. \n " ) ;
return AVERROR ( ENOSYS ) ;
}
* got_frame = 0 ;
avci - > compat_decode = 1 ;
ret = extract_packet_props ( avci , avpkt ) ;
if ( ret < 0 )
return ret ;
if ( avci - > compat_decode_partial_size > 0 & &
avci - > compat_decode_partial_size ! = pkt - > size ) {
av_log ( avctx , AV_LOG_ERROR ,
" Got unexpected packet size after a partial decode \n " ) ;
ret = AVERROR ( EINVAL ) ;
goto finish ;
}
ret = apply_param_change ( avctx , avpkt ) ;
if ( ret < 0 )
return ret ;
if ( ! avci - > compat_decode_partial_size ) {
ret = avcodec_send_packet ( avctx , pkt ) ;
if ( ret = = AVERROR_EOF )
ret = 0 ;
else if ( ret = = AVERROR ( EAGAIN ) ) {
/* we fully drain all the output in each decode call, so this should not
* ever happen */
ret = AVERROR_BUG ;
goto finish ;
} else if ( ret < 0 )
goto finish ;
}
av_frame_unref ( picture ) ;
if ( ( avctx - > codec - > capabilities & AV_CODEC_CAP_DELAY ) | | avpkt - > size | |
( avctx - > active_thread_type & FF_THREAD_FRAME ) ) {
if ( HAVE_THREADS & & avctx - > active_thread_type & FF_THREAD_FRAME )
ret = ff_thread_decode_frame ( avctx , picture , got_picture_ptr ,
avpkt ) ;
else {
ret = avctx - > codec - > decode ( avctx , picture , got_picture_ptr ,
avpkt ) ;
if ( ! ( avctx - > codec - > caps_internal & FF_CODEC_CAP_SETS_PKT_DTS ) )
picture - > pkt_dts = avpkt - > dts ;
/* get_buffer is supposed to set frame parameters */
if ( ! ( avctx - > codec - > capabilities & AV_CODEC_CAP_DR1 ) ) {
picture - > sample_aspect_ratio = avctx - > sample_aspect_ratio ;
picture - > width = avctx - > width ;
picture - > height = avctx - > height ;
picture - > format = avctx - > pix_fmt ;
}
while ( ret > = 0 ) {
ret = avcodec_receive_frame ( avctx , frame ) ;
if ( ret < 0 ) {
if ( ret = = AVERROR ( EAGAIN ) | | ret = = AVERROR_EOF )
ret = 0 ;
goto finish ;
}
emms_c ( ) ; //needed to avoid an emms_c() call before every return;
if ( * got_picture_ptr ) {
if ( frame ! = avci - > compat_decode_frame ) {
if ( ! avctx - > refcounted_frames ) {
int er r = unrefcount_frame ( avci , pictur e) ;
if ( er r < 0 )
return err ;
ret = unrefcount_frame ( avci , frame ) ;
if ( ret < 0 )
goto finish ;
}
avctx - > frame_number + + ;
} else
av_frame_unref ( picture ) ;
} else
ret = 0 ;
* got_frame = 1 ;
frame = avci - > compat_decode_frame ;
} else {
if ( ! avci - > compat_decode_warned ) {
av_log ( avctx , AV_LOG_WARNING , " The deprecated avcodec_decode_* "
" API cannot return all the frames for this decoder. "
" Some frames will be dropped. Update your code to the "
" new decoding API to fix this. \n " ) ;
avci - > compat_decode_warned = 1 ;
}
}
# if FF_API_AVCTX_TIMEBASE
if ( avctx - > framerate . num > 0 & & avctx - > framerate . den > 0 )
avctx - > time_base = av_inv_q ( avctx - > framerate ) ;
# endif
if ( avci - > draining | | avci - > compat_decode_consumed < pkt - > size )
break ;
}
finish :
if ( ret = = 0 )
ret = FFMIN ( avci - > compat_decode_consumed , pkt - > size ) ;
avci - > compat_decode_consumed = 0 ;
avci - > compat_decode_partial_size = ( ret > = 0 ) ? pkt - > size - ret : 0 ;
return ret ;
}
int attribute_align_arg avcodec_decode_video2 ( AVCodecContext * avctx , AVFrame * picture ,
int * got_picture_ptr ,
AVPacket * avpkt )
{
return compat_decode ( avctx , picture , got_picture_ptr , avpkt ) ;
}
int attribute_align_arg avcodec_decode_audio4 ( AVCodecContext * avctx ,
AVFrame * frame ,
int * got_frame_ptr ,
AVPacket * avpkt )
{
AVCodecInternal * avci = avctx - > internal ;
int ret = 0 ;
* got_frame_ptr = 0 ;
if ( ! avctx - > codec - > decode ) {
av_log ( avctx , AV_LOG_ERROR , " This decoder requires using the avcodec_send_packet() API. \n " ) ;
return AVERROR ( ENOSYS ) ;
}
ret = extract_packet_props ( avci , avpkt ) ;
if ( ret < 0 )
return ret ;
if ( ! avpkt - > data & & avpkt - > size ) {
av_log ( avctx , AV_LOG_ERROR , " invalid packet: NULL data, size != 0 \n " ) ;
return AVERROR ( EINVAL ) ;
}
ret = apply_param_change ( avctx , avpkt ) ;
if ( ret < 0 )
return ret ;
av_frame_unref ( frame ) ;
if ( ( avctx - > codec - > capabilities & AV_CODEC_CAP_DELAY ) | | avpkt - > size ) {
ret = avctx - > codec - > decode ( avctx , frame , got_frame_ptr , avpkt ) ;
if ( ret > = 0 & & * got_frame_ptr ) {
avctx - > frame_number + + ;
frame - > pkt_dts = avpkt - > dts ;
if ( frame - > format = = AV_SAMPLE_FMT_NONE )
frame - > format = avctx - > sample_fmt ;
if ( ! avctx - > refcounted_frames ) {
int err = unrefcount_frame ( avci , frame ) ;
if ( err < 0 )
return err ;
}
} else
av_frame_unref ( frame ) ;
}
return ret ;
return compat_decode ( avctx , frame , got_frame_ptr , avpkt ) ;
}
int avcodec_decode_subtitle2 ( AVCodecContext * avctx , AVSubtitle * sub ,
@ -919,9 +947,12 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
avctx - > internal - > draining = 0 ;
avctx - > internal - > draining_done = 0 ;
av_frame_unref ( avctx - > internal - > buffer_frame ) ;
av_frame_unref ( avctx - > internal - > compat_decode_frame ) ;
av_packet_unref ( avctx - > internal - > buffer_pkt ) ;
avctx - > internal - > buffer_pkt_valid = 0 ;
av_packet_unref ( avctx - > internal - > ds . in_pkt ) ;
if ( HAVE_THREADS & & avctx - > active_thread_type & FF_THREAD_FRAME )
ff_thread_flush ( avctx ) ;
else if ( avctx - > codec - > flush )