static int opt_input_file(const char *opt, const char *filename)
{
AVFormatContext *ic; //对于该数据结构参考另一篇博客
AVInputFormat *file_iformat = NULL;
int err, i, ret, rfps, rfps_base;
int64_t timestamp;
uint8_t buf[128];
AVDictionary **opts;
int orig_nb_streams; // number of streams before avformat_find_stream_info
if (last_asked_format) { //从我分析的情形来看这个函数不执行
if (!(file_iformat = av_find_input_format(last_asked_format))) {
fprintf(stderr, "Unknown input format: '%s'\n", last_asked_format);
exit_program(1);
}
last_asked_format = NULL;
}
if (!strcmp(filename, "-")) //不执行
filename = "pipe:";
//下面的代码很令人费解,不知道干什么的,其表达式这样: using_stdin = using_stdin|((!strncmp(filename, "pipe:", 5) ||!strcmp(filename, "/dev/stdin"));不过根据根据具体的命令,using_stdin = 0;
using_stdin |= !strncmp(filename, "pipe:", 5) || //这个在后面就知道了,在输出文件的阶段,以这个参数来判断文件重名
!strcmp(filename, "/dev/stdin");
/* get default parameters from command line */ //从命令行获取默认的参数
ic = avformat_alloc_context(); // 初始化
if (!ic) { //一般的能成功吧
print_error(filename, AVERROR(ENOMEM));
exit_program(1);
}
if (audio_sample_rate) {
snprintf(buf, sizeof(buf), "%d", audio_sample_rate);
av_dict_set(&format_opts, "sample_rate", buf, 0);
}
if (audio_channels) {
snprintf(buf, sizeof(buf), "%d", audio_channels);
av_dict_set(&format_opts, "channels", buf, 0);
}
if (frame_rate.num) {
snprintf(buf, sizeof(buf), "%d/%d", frame_rate.num, frame_rate.den);
av_dict_set(&format_opts, "framerate", buf, 0);
}
if (frame_width && frame_height) {
snprintf(buf, sizeof(buf), "%dx%d", frame_width, frame_height);
av_dict_set(&format_opts, "video_size", buf, 0);
} // 上面都不用看
if (frame_pix_fmt != PIX_FMT_NONE)
av_dict_set(&format_opts, "pixel_format", av_get_pix_fmt_name(frame_pix_fmt), 0);
//指定音频,视频,字幕的编码id
ic->video_codec_id =
find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0);
ic->audio_codec_id =
find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0);
ic->subtitle_codec_id=
find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0); //字幕的编解码id
ic->flags |= AVFMT_FLAG_NONBLOCK;
/* open the input file with generic libav function */
err = avformat_open_input(&ic, filename, file_iformat, &format_opts); // Open an input stream and read the header. The codecs are not opened.该函数的代码阅读
if (err < 0) { //不用看
print_error(filename, err);
exit_program(1);
}
assert_avoptions(format_opts); //不用看
if(opt_programid) {//不用看 ·
int i, j;
int found=0;
for(i=0; i<ic->nb_streams; i++){
ic->streams[i]->discard= AVDISCARD_ALL;
}
for(i=0; i<ic->nb_programs; i++){
AVProgram *p= ic->programs[i];
if(p->id != opt_programid){
p->discard = AVDISCARD_ALL;
}else{
found=1;
for(j=0; j<p->nb_stream_indexes; j++){
ic->streams[p->stream_index[j]]->discard= AVDISCARD_DEFAULT;
}
}
}
if(!found){
fprintf(stderr, "Specified program id not found\n");
exit_program(1);
}
opt_programid=0;
}
if (loop_input) {
av_log(NULL, AV_LOG_WARNING, "-loop_input is deprecated, use -loop 1\n");
ic->loop_input = loop_input;
}
/* Set AVCodecContext options for avformat_find_stream_info */
opts = setup_find_stream_info_opts(ic, codec_opts);
orig_nb_streams = ic->nb_streams;
/* 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); //这个函数,注释说的很明白了 ret = 0
if (ret < 0 && verbose >= 0) {
fprintf(stderr, "%s: could not find codec parameters\n", filename);
av_close_input_file(ic);
exit_program(1);
}
timestamp = start_time;
/* add the stream start time */
if (ic->start_time != AV_NOPTS_VALUE)
timestamp += ic->start_time;
/* if seeking requested, we execute it */
if (start_time != 0) {
ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
if (ret < 0) {
fprintf(stderr, "%s: could not seek to position %0.3f\n",
filename, (double)timestamp / AV_TIME_BASE);
}
/* reset seek info */
start_time = 0;
}
/* update the current parameters so that they match the one of the input stream */
for(i=0;i<ic->nb_streams;i++) {
AVStream *st = ic->streams[i];
AVCodecContext *dec = st->codec;
InputStream *ist;
dec->thread_count = thread_count;
input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1); //这个需要仔细的看看,特别是指针的偏移这一点不懂那么这里就看不懂了
ist = &input_streams[nb_input_streams - 1];
ist->st = st;
ist->file_index = nb_input_files;
ist->discard = 1;
ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st);
if (i < nb_ts_scale)
ist->ts_scale = ts_scale[i];
switch (dec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
ist->dec = avcodec_find_decoder_by_name(audio_codec_name);
if(audio_disable)
st->discard= AVDISCARD_ALL;
break;
case AVMEDIA_TYPE_VIDEO:
ist->dec = avcodec_find_decoder_by_name(video_codec_name);
rfps = ic->streams[i]->r_frame_rate.num;
rfps_base = ic->streams[i]->r_frame_rate.den;
if (dec->lowres) {
dec->flags |= CODEC_FLAG_EMU_EDGE;
dec->height >>= dec->lowres;
dec->width >>= dec->lowres;
}
if(me_threshold)
dec->debug |= FF_DEBUG_MV;
if (dec->time_base.den != rfps*dec->ticks_per_frame || dec->time_base.num != rfps_base) {
if (verbose >= 0)
fprintf(stderr,"\nSeems stream %d codec frame rate differs from container frame rate: %2.2f (%d/%d) -> %2.2f (%d/%d)\n",
i, (float)dec->time_base.den / dec->time_base.num, dec->time_base.den, dec->time_base.num,
(float)rfps / rfps_base, rfps, rfps_base);
}
if(video_disable)
st->discard= AVDISCARD_ALL;
else if(video_discard)
st->discard= video_discard;
break;
case AVMEDIA_TYPE_DATA:
break;
case AVMEDIA_TYPE_SUBTITLE:
ist->dec = avcodec_find_decoder_by_name(subtitle_codec_name);
if(subtitle_disable)
st->discard = AVDISCARD_ALL;
break;
case AVMEDIA_TYPE_ATTACHMENT:
case AVMEDIA_TYPE_UNKNOWN:
break;
default:
abort();
}
}
/* dump the file content */
if (verbose >= 0)
av_dump_format(ic, nb_input_files, filename, 0); //输出基本的信息属于库函数的内容,不做深入的研究
input_files = grow_array(input_files, sizeof(*input_files), &nb_input_files, nb_input_files + 1);//同样使用了指针的偏移
input_files[nb_input_files - 1].ctx = ic;
input_files[nb_input_files - 1].ist_index = nb_input_streams - ic->nb_streams;
input_files[nb_input_files - 1].ts_offset = input_ts_offset - (copy_ts ? 0 : timestamp);
input_files[nb_input_files - 1].nb_streams = ic->nb_streams;
frame_rate = (AVRational){0, 0};
frame_pix_fmt = PIX_FMT_NONE;
frame_height = 0;
frame_width = 0;
audio_sample_rate = 0;
audio_channels = 0;
audio_sample_fmt = AV_SAMPLE_FMT_NONE;
av_freep(&ts_scale);
nb_ts_scale = 0;
for (i = 0; i < orig_nb_streams; i++)
av_dict_free(&opts[i]);
av_freep(&opts);
av_freep(&video_codec_name);
av_freep(&audio_codec_name);
av_freep(&subtitle_codec_name);
uninit_opts();
init_opts();
return 0;
}
看完了opt_input_file函数(注意使用的是“ffmpeg -i k.png kuan.mp4”命令),这个函数其实最终要完成的是input_files的赋值,其中使用的指针偏移的技巧很重要。
在实际上调试发现,AVFormatContext ic 被赋值,但是没有编码或者解码的信息,在成员数据段 AVStream 也没有具体的解码信息,也就是AVCoder的值为0