static int open_input_file(OptionsContext *o, const char *filename)
{
InputFile *f;
AVFormatContext *ic;
...
/* get default parameters from command line */
ic = avformat_alloc_context();
if (!ic) {
print_error(filename, AVERROR(ENOMEM));
exit_program(1);
}
...
if (find_stream_info) {
...
/* If not enough info to get the stream parameters, we decode the
first frames to get it. (used in mpeg case for example) */
ret = avformat_find_stream_info(ic, opts);
...
}
...
// o->start_time是命令行中"-ss"的时间,单位是AV_TIME_BASE
timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;
/* add the stream start time */
if (!o->seek_timestamp && ic->start_time != AV_NOPTS_VALUE)
timestamp += ic->start_time; // 这里的ic->start_time 是什么呢?
...
/* if seeking requested, we execute it */
if (o->start_time != AV_NOPTS_VALUE) {
int64_t seek_timestamp = timestamp; // 最终要seek的时间点 单位AV_TIME_BASE
...
// seek到目标时间点
ret = avformat_seek_file(ic, -1, INT64_MIN, seek_timestamp, seek_timestamp, 0);
if (ret < 0) {
av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
filename, (double)timestamp / AV_TIME_BASE);
}
}
}
AVFormatContext中的start_time定义如下:
typedef struct AVFormatContext {
...
/**
* Position of the first frame of the component, in
* AV_TIME_BASE fractional seconds. NEVER set this value directly:
* It is deduced from the AVStream values.
*
* Demuxing only, set by libavformat.
*/
int64_t start_time;
...
}
可见这个是只在解封装的时候用到,是第一帧的时间位置。
其实是该文件所有流中,起始时间戳最小的那个。
它是如何获取的呢?
/**
* Estimate the stream timings from the one of each components.
*
* Also computes the global bitrate if possible.
*/
static void update_stream_timings(AVFormatContext *ic)
{
int64_t start_time, start_time1, start_time_text, end_time, end_time1, end_time_text;
...
start_time = INT64_MAX;
start_time_text = INT64_MAX;
...
for (i = 0; i < ic->nb_streams; i++) {
AVStream *st = ic->streams[i];
int is_text = st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ||
st->codecpar->codec_type == AVMEDIA_TYPE_DATA;
if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) {
start_time1 = av_rescale_q(st->start_time, st->time_base,
AV_TIME_BASE_Q);
if (is_text)
start_time_text = FFMIN(start_time_text, start_time1); // 取小值
else
start_time = FFMIN(start_time, start_time1); // 取小值
...
}
} // end of for
// 比较
if (start_time == INT64_MAX || (start_time > start_time_text && start_time - (uint64_t)start_time_text < AV_TIME_BASE))
start_time = start_time_text;
else if (start_time > start_time_text)
av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream starttime %f\n", start_time_text / (float)AV_TIME_BASE);
...
if (start_time != INT64_MAX) {
ic->start_time = start_time; // 真正赋值的地方
...
}
...
}