ffmpeg笔记
ffmpeg demuxer的调用方法
View Code
调用者可以指定文件读取protocol,通过s->pb来指定
调用者也可以指定文件解析器demuxer,通过s->iformat来指定
//参数ps包含一切媒体相关的上下文结构,有它就有了一切,本函数如果打开媒体成功,
//会返回一个AVFormatContext的实例.
//参数filename是媒体文件名或URL.
//参数fmt是要打开的媒体格式的操作结构,因为是读,所以是inputFormat.此处可以
//传入一个调用者定义的inputFormat,对应命令行中的 -f xxx段,如果指定了它,
//在打开文件中就不会探测文件的实际格式了,以它为准了.
//参数options是对某种格式的一些操作,是为了在命令行中可以对不同的格式传入
//特殊的操作参数而建的, 为了了解流程,完全可以无视它.
int avformat_open_input(AVFormatContext **ps,
const char *filename,
AVInputFormat *fmt,
AVDictionary **options)
ffmpeg及时退出方法
View Code
if (ff_check_interrupt(&ic->interrupt_callback)){ ret= AVERROR_EXIT; av_log(ic, AV_LOG_DEBUG, "interrupted\n"); break; }
计算PTS流程
View Code
在文件头中读取和设置时间戳信息:
读取scale和rate生成时间基
ast->scale = get_le32(pb);
ast->rate = get_le32(pb);
av_set_pts_info(st, 64, ast->scale, ast->rate);
先在TAG “strh”中读取nb_frames,
st->nb_frames = get_le32(pb);
之后将duration设置为视频流的帧数:
if(ast->sample_size == 0){
st->duration = st->nb_frames;
}
最后在函数av_estimate_timings_from_pts生成时长信息
每次读帧的时候来计算时间戳
Pts默认的初始化在函数av_get_packet(pb, pkt, size)中实现,最终通过调用
av_new_packet(pkt, size)------> av_init_packet(pkt)----> pkt->pts = AV_NOPTS_VALUE; pkt->dts = AV_NOPTS_VALUE;
读到帧时,音视频都通过compute_pkt_fields(s, st, st->parser, pkt);函数来计算。其中frame_offset作为后面的dts,而dts进一步作为pts,在AVI文件中pts等于dts
计算duration流程
View Code
av_find_stream_info->获取流信息
+av_estimate_timings->计算时间
+ av_estimate_timings_from_pts
+av_estimate_timings_from_bit_rate
fill_all_stream_timings
计算bitrate流程
Seek的流程
读包的流程
查找codec信息的流程
主要数据结构的使用,以及其作用
解析头后,保存文件的偏移
View Code
在avformat_open_input中解析id3v2,并保存文件偏移:
//保存数据区开始的位置
if (!(s->flags & AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
s->data_offset = avio_tell(s->pb);
Seek的流程
View Code
Seek的策略:
1. 如果文件有索引,而且索引是准确的,则直接跟据文件的索引seek到相应位置。
av_seek_frame-->iformat->read_seek
2. 如果没找到索引,但可以通过位置取到时间戳,则通过二分查找法能找到相应位置。
av_seek_frame-->av_seek_frame_binary-->av_gen_search
3. 如果前两种情况都不可行,那只能逐个读包,直到读到期望的时间戳才停止。
av_seek_frame-->av_seek_frame_generic-->av_read_frame
注意会使用二分法查找,所以索引表中会有最后一个index
.flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH,这个选项会禁止在框架层上做Bin seek,或gen seek,而直接在demuxer里完成精确的seek操作。
二分查找seek
View Code
二分查找函数ff_seek_frame_binary的流程:
1. 在当前索引中找出pos_min和pos_max
2. 调用ff_gen_search
后续再补充详细流程...