首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

ffmpeg 源代码容易分析 : av_read_frame()

2013-10-14 
ffmpeg 源代码简单分析 : av_read_frame()ffmpeg中的av_read_frame()的作用是读取码流中的音频若干帧或者

ffmpeg 源代码简单分析 : av_read_frame()

ffmpeg中的av_read_frame()的作用是读取码流中的音频若干帧或者视频一帧。例如,解码视频的时候,每解码一个视频帧,需要先调用 av_read_frame()获得一帧视频的压缩数据,然后才能对该数据进行解码(例如H.264中一帧压缩数据通常对应一个NAL)。

对该函数源代码的分析是很久之前做的了,现在翻出来,用博客记录一下。


上代码之前,先参考了其他人对av_read_frame()的解释,在此做一个参考:

通过av_read_packet(***),读取一个包,需要说明的是此函数必须是包含整数帧的,不存在半帧的情况,以ts流为例,是读取一个完整的PES包(一个完整pes包包含若干视频或音频es包),读取完毕后,通过av_parser_parse2(***)分析出视频一帧(或音频若干帧),返回,下次进入循环的时候,如果上次的数据没有完全取完,则st = s->cur_st;不会是NULL,即再此进入av_parser_parse2(***)流程,而不是下面的av_read_packet(**)流程,这样就保证了,如果读取一次包含了N帧视频数据(以视频为例),则调用av_read_frame(***)N次都不会去读数据,而是返回第一次读取的数据,直到全部解析完毕。

av_read_frame()的源代码如下:

//解析。例如解析264里的NAL等等int av_parser_parse2(AVCodecParserContext *s,                     AVCodecContext *avctx,                     uint8_t **poutbuf, int *poutbuf_size,                     const uint8_t *buf, int buf_size,                     int64_t pts, int64_t dts,                     int64_t pos){    int index, i;    uint8_t dummy_buf[FF_INPUT_BUFFER_PADDING_SIZE];    if(!(s->flags & PARSER_FLAG_FETCHED_OFFSET)) {        s->next_frame_offset =        s->cur_offset        = pos;        s->flags |= PARSER_FLAG_FETCHED_OFFSET;    }    if (buf_size == 0) {        /* padding is always necessary even if EOF, so we add it here */        memset(dummy_buf, 0, sizeof(dummy_buf));        buf = dummy_buf;    } else if (s->cur_offset + buf_size !=               s->cur_frame_end[s->cur_frame_start_index]) { /* skip remainder packets */        /* add a new packet descriptor */            i = (s->cur_frame_start_index + 1) & (AV_PARSER_PTS_NB - 1);            s->cur_frame_start_index = i;            s->cur_frame_offset[i] = s->cur_offset;            s->cur_frame_end[i] = s->cur_offset + buf_size;            s->cur_frame_pts[i] = pts;            s->cur_frame_dts[i] = dts;            s->cur_frame_pos[i] = pos;    }    if (s->fetch_timestamp){        s->fetch_timestamp=0;        s->last_pts = s->pts;        s->last_dts = s->dts;        s->last_pos = s->pos;        ff_fetch_timestamp(s, 0, 0);    }    /* WARNING: the returned index can be negative */    //H264里对应的就是parser_parse=h264_parse,    index = s->parser->parser_parse(s, avctx, (const uint8_t **)poutbuf, poutbuf_size, buf, buf_size);//av_log(NULL, AV_LOG_DEBUG, "parser: in:%"PRId64", %"PRId64", out:%"PRId64", %"PRId64", in:%d out:%d id:%d\n", pts, dts, s->last_pts, s->last_dts, buf_size, *poutbuf_size, avctx->codec_id);    /* update the file pointer */    if (*poutbuf_size) {        /* fill the data for the current frame */        s->frame_offset = s->next_frame_offset;        /* offset of the next frame */        s->next_frame_offset = s->cur_offset + index;        s->fetch_timestamp=1;    }    if (index < 0)        index = 0;    s->cur_offset += index;    return index;}

从index = s->parser->parser_parse(s, avctx, (const uint8_t **)poutbuf, poutbuf_size, buf, buf_size);这句代码可以看出,最终调用了相应解码器的parser_parse()函数。

有点累了,先不做详细分析,以后有机会再补上。






热点排行