//解码函数
int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
const AVPacket *avpkt)
{
AVCodecInternal *avci = avctx->internal;
int ret;
// copy to ensure we do not change avpkt
AVPacket tmp = *avpkt;
if (avctx->codec->type != AVMEDIA_TYPE_VIDEO) {
//如果不是视频类型,则退出
av_log(avctx, AV_LOG_ERROR, "Invalid media type for video\n");
return AVERROR(EINVAL);
}
*got_picture_ptr = 0; /
if ((avctx->coded_width || avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx))
return AVERROR(EINVAL);
avcodec_get_frame_defaults(picture);
if (!avctx->refcounted_frames)
av_frame_unref(&avci->to_free);
//如果是帧并行解码的话
//需要在codec初始化的时候设置codec->capabilities |= CODEC_CAP_DELAY,查看注释,设置avctx->active_thread_type |= FF_THREAD_FRAME
if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
int did_split = av_packet_split_side_data(&tmp);
apply_param_change(avctx, &tmp);
avctx->pkt = &tmp;
//需要配置configure --enable-pthreads(我现在最新的默认生成的config.h就是#define HAVE_THREADS 1) ,设置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,&tmp);/
/进入帧级并行解码
else {//进入单线程解码
ret = avctx->codec->decode(avctx, picture, got_picture_ptr, &tmp);
picture->pkt_dts = avpkt->dts;
if(!avctx->has_b_frames){
av_frame_set_pkt_pos(picture, avpkt->pos);
}
//FIXME these should be under if(!avctx->has_b_frames)
/* get_buffer is supposed to set frame parameters */
if (!(avctx->codec->capabilities & CODEC_CAP_DR1)) {
if (!picture->sample_aspect_ratio.num) picture->sample_aspect_ratio = avctx->sample_aspect_ratio;
if (!picture->width) picture->width = avctx->width;
if (!picture->height) picture->height = avctx->height;
if (picture->format == AV_PIX_FMT_NONE) picture->format = avctx->pix_fmt;
}
}
add_metadata_from_side_data(avctx, picture);
emms_c(); //needed to avoid an emms_c() call before every return;
avctx->pkt = NULL;
if (did_split) {
ff_packet_free_side_data(&tmp);
if(ret == tmp.size)
ret = avpkt->size;
}
if (ret < 0 && picture->data[0])
av_frame_unref(picture);
if (*got_picture_ptr) {
if (!avctx->refcounted_frames) {
avci->to_free = *picture;
avci->to_free.extended_data = avci->to_free.data;
}
avctx->frame_number++;
av_frame_set_best_effort_timestamp(picture,
guess_correct_pts(avctx,
picture->pkt_pts,
picture->pkt_dts));
}
} else
ret = 0;
/* many decoders assign whole AVFrames, thus overwriting extended_data;
* make sure it's set correctly */
//许多解码器分配整个的AVFrames ,从而覆盖extended_data相关
picture->extended_data = picture->data;
return ret;
}
注释:
/**
* Encoder or decoder requires flushing with NULL input at the end in order to
* give the complete and correct output.
*
* NOTE: If this flag is not set, the codec is guaranteed to never be fed with
* with NULL data. The user can still send NULL data to the public encode
* or decode function, but libavcodec will not pass it along to the codec
* unless this flag is set.
*
* Decoders:
* The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL,
* avpkt->size=0 at the end to get the delayed data until the decoder no longer
* returns frames.
*
* Encoders:
* The encoder needs to be fed with NULL data at the end of encoding until the
* encoder no longer returns data.
*
* NOTE: For encoders implementing the AVCodec.encode2() function, setting this
* flag also means that the encoder must set the pts and duration for
* each output packet. If this flag is not set, the pts and duration will
* be determined by libavcodec from the input frame.
*/
#define CODEC_CAP_DELAY 0x0020