open_input_file()函数介绍
来源:互联网 发布:如何获取股票交易数据 编辑:程序博客网 时间:2024/05/16 04:57
open_input_file()
本问介绍ffmpeg_opt.c中的open_input_file()函数,此函数主要就是将命令行参数中的输入文件的对应参数进行设置,并打开所有输入文件
- open_input_file
- open_files函数
- 输入文件涉及到的几个结构体
- open_input_file函数
open_files()函数
在介绍open_input_file()函数之前先介绍一下open_files()函数
在ffmpeg_parse_options()函数中是这样调用open_files()函数的
/* open input files */ ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file); if (ret < 0) { av_log(NULL, AV_LOG_FATAL, "Error opening input files: "); goto fail; }
octx.groups[GROUP_INFILE]中存放着一组输入文件和相关的参数。
static int open_files(OptionGroupList *l, const char *inout, int (*open_file)(OptionsContext*, const char*)){ int i, ret; /*经过对命令行的分析将输入文件链表放到了l中,在此逐一对输入文件进行处理*/ for (i = 0; i < l->nb_groups; i++) { OptionGroup *g = &l->groups[i]; OptionsContext o; /*对OptionsContext 中的变量做默认设置,这个结构体很重要,它和ffmpeg_opt.c中定义的const OptionDef options[]相对应。其中设置的偏移量就是针对这个结构体*/ init_options(&o); o.g = g; /*将g中存的,从命令行中获取的针对这个输入文件的参数放到o中*/ ret = parse_optgroup(&o, g); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Error parsing options for %s file " "%s.\n", inout, g->arg); return ret; } /*g->arg中存放的是-i filename中的filename*/ ret = open_file(&o, g->arg); uninit_options(&o); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Error opening %s file %s.\n", inout, g->arg); return ret; } av_log(NULL, AV_LOG_DEBUG, "Successfully opened the file.\n"); } return 0;}
输入文件涉及到的几个结构体
在介绍open_input_file()函数之前需要介绍几个结构体
在ffmpeg.c中定义了如下变量
InputStream **input_streams = NULL;int nb_input_streams = 0;InputFile **input_files = NULL;int nb_input_files = 0;
这些是针对输入文件和输入流的链表,定义如下:
typedef struct InputStream { int file_index;//在input_files中对应的下标值 AVStream *st; int discard; /* true if stream data should be discarded */ int user_set_discard; int decoding_needed; /* non zero if the packets must be decoded in 'raw_fifo', see DECODING_FOR_* */#define DECODING_FOR_OST 1#define DECODING_FOR_FILTER 2 AVCodecContext *dec_ctx; AVCodec *dec; AVFrame *decoded_frame; AVFrame *filter_frame; /* a ref of decoded_frame, to be sent to filters */ int64_t start; /* time when read started */ /* predicted dts of the next packet read for this stream or (when there are * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */ int64_t next_dts; int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units) int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units) int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units) int wrap_correction_done; int64_t filter_in_rescale_delta_last; int64_t min_pts; /* pts with the smallest value in a current stream */ int64_t max_pts; /* pts with the higher value in a current stream */ int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */ double ts_scale; int saw_first_ts; int showed_multi_packet_warning; AVDictionary *decoder_opts; AVRational framerate; /* framerate forced with -r */ int top_field_first; int guess_layout_max; int autorotate; int resample_height; int resample_width; int resample_pix_fmt; int resample_sample_fmt; int resample_sample_rate; int resample_channels; uint64_t resample_channel_layout; int fix_sub_duration; struct { /* previous decoded subtitle and related variables */ int got_output; int ret; AVSubtitle subtitle; } prev_sub; struct sub2video { int64_t last_pts; int64_t end_pts; AVFrame *frame; int w, h; } sub2video; int dr1; /* decoded data from this stream goes into all those filters * currently video and audio only */ InputFilter **filters; int nb_filters; int reinit_filters; /* hwaccel options */ enum HWAccelID hwaccel_id; char *hwaccel_device; enum AVPixelFormat hwaccel_output_format; /* hwaccel context */ enum HWAccelID active_hwaccel_id; void *hwaccel_ctx; void (*hwaccel_uninit)(AVCodecContext *s); int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags); int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame); enum AVPixelFormat hwaccel_pix_fmt; enum AVPixelFormat hwaccel_retrieved_pix_fmt; AVBufferRef *hw_frames_ctx; /* stats */ // combined size of all the packets read uint64_t data_size; /* number of packets successfully read for this stream */ uint64_t nb_packets; // number of frames/samples retrieved from the decoder uint64_t frames_decoded; uint64_t samples_decoded;} InputStream;
typedef struct InputFile { AVFormatContext *ctx; int eof_reached; /* true if eof reached */ int eagain; /* true if last read attempt returned EAGAIN */ int ist_index; /* index of first stream in input_streams */ int loop; /* set number of times input stream should be looped */ int64_t duration; /* actual duration of the longest stream in a file at the moment when looping happens */ AVRational time_base; /* time base of the duration */ int64_t input_ts_offset; int64_t ts_offset; int64_t last_ts; int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */ int seek_timestamp; int64_t recording_time; int nb_streams; /* number of stream that ffmpeg is aware of; may be different from ctx.nb_streams if new streams appear during av_read_frame() */ int nb_streams_warn; /* number of streams that the user was warned of */ int rate_emu; int accurate_seek;#if HAVE_PTHREADS AVThreadMessageQueue *in_thread_queue; pthread_t thread; /* thread reading from this file */ int non_blocking; /* reading packets from the thread should not block */ int joined; /* the thread has been joined */ int thread_queue_size; /* maximum number of queued packets */#endif} InputFile;
open_input_file()函数
//输入参数o里面存放着文件的对应参数,filename表示文件名static int open_input_file(OptionsContext *o, const char *filename){ InputFile *f;//存放此文件的所有信息,之后会放到input_files中 AVFormatContext *ic;//每个文件对应一个这样的结构体 AVInputFormat *file_iformat = NULL; int err, i, ret; int64_t timestamp; AVDictionary **opts; AVDictionary *unused_opts = NULL; AVDictionaryEntry *e = NULL; int orig_nb_streams; // number of streams before avformat_find_stream_info char * video_codec_name = NULL; char * audio_codec_name = NULL; char *subtitle_codec_name = NULL; char * data_codec_name = NULL; int scan_all_pmts_set = 0; /*在options[]中对应“f”,指定输入文件的格式“-f”*/ if (o->format) { if (!(file_iformat = av_find_input_format(o->format))) { av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format); exit_program(1); } } //如果是管道输入文件名为“-” if (!strcmp(filename, "-")) filename = "pipe:"; /*stdin_interaction针对参数-stdin*/ stdin_interaction &= 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); } /*对应参数“-ar”设置音频采样率*/ if (o->nb_audio_sample_rate) { av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i, 0); } /*对应参数"-ac"*/ if (o->nb_audio_channels) { /* because we set audio_channels based on both the "ac" and * "channel_layout" options, we need to check that the specified * demuxer actually has the "channels" option before setting it */ if (file_iformat && file_iformat->priv_class && av_opt_find(&file_iformat->priv_class, "channels", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)) { av_dict_set_int(&o->g->format_opts, "channels", o->audio_channels[o->nb_audio_channels - 1].u.i, 0); } } /*对应参数"r"*/ if (o->nb_frame_rates) { /* set the format-level framerate option; * this is important for video grabbers, e.g. x11 */ if (file_iformat && file_iformat->priv_class && av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)) { av_dict_set(&o->g->format_opts, "framerate", o->frame_rates[o->nb_frame_rates - 1].u.str, 0); } } //对应参数"s" if (o->nb_frame_sizes) { av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0); } //对应参数"pix_fmt" if (o->nb_frame_pix_fmts) av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0); //对应参数"c"和"codec" 或"c:[v/a/s/d]"和"codec:[v/a/s/d]" MATCH_PER_TYPE_OPT(codec_names, str, video_codec_name, ic, "v"); MATCH_PER_TYPE_OPT(codec_names, str, audio_codec_name, ic, "a"); MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, "s"); MATCH_PER_TYPE_OPT(codec_names, str, data_codec_name, ic, "d"); //根据命令行参数设置对应的编码格式 ic->video_codec_id = video_codec_name ? find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)->id : AV_CODEC_ID_NONE; ic->audio_codec_id = audio_codec_name ? find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : AV_CODEC_ID_NONE; ic->subtitle_codec_id= subtitle_codec_name ? find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE; ic->data_codec_id = data_codec_name ? find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)->id : AV_CODEC_ID_NONE; /*对ic中的下列项进行设置 AVCodec *video_codec; AVCodec *audio_codec; AVCodec *subtitle_codec; AVCodec *data_codec;*/ if (video_codec_name) av_format_set_video_codec (ic, find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)); if (audio_codec_name) av_format_set_audio_codec (ic, find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)); if (subtitle_codec_name) av_format_set_subtitle_codec(ic, find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)); if (data_codec_name) av_format_set_data_codec(ic, find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)); ic->flags |= AVFMT_FLAG_NONBLOCK; ic->interrupt_callback = int_cb; //设置"scan_all_pmts",应该只是针对avformat_open_input()函数用的。之后就又设为NULL了 if (!av_dict_get(o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { av_dict_set(&o->g->format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE); scan_all_pmts_set = 1; } /* open the input file with generic avformat function */ err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts); if (err < 0) { print_error(filename, err); exit_program(1); } if (scan_all_pmts_set) av_dict_set(&o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE); //删除o->g->format_opts中和o->g->codec_opts中相同的参数项 remove_avoptions(&o->g->format_opts, o->g->codec_opts); assert_avoptions(o->g->format_opts); /* apply forced codec ids 找到解码器,如果命令行里有指定强制解码类型就用之,否则根据流中的st->codec->codec_id找*/ for (i = 0; i < ic->nb_streams; i++) choose_decoder(o, ic, ic->streams[i]); /* Set AVCodecContext options for avformat_find_stream_info 返回的opts为一个链表,它的成员个数和本输入文件的流个数相同,opts[0]表示stream[0]对应的参数,来源是o->g->codec_opts 也就是将一个文件中的视频流参数、音频流参数、字幕流参数和数据流参数分开,之后提供给avformat_find_stream_info()函数用*/ opts = setup_find_stream_info_opts(ic, o->g->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); if (ret < 0) { av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename); if (ic->nb_streams == 0) { avformat_close_input(&ic); exit_program(1); } } //对应参数"sseof",设置相对于结束的开始时间 if (o->start_time_eof != AV_NOPTS_VALUE) { if (ic->duration>0) { o->start_time = o->start_time_eof + ic->duration; } else av_log(NULL, AV_LOG_WARNING, "Cannot use -sseof, duration of %s not known\n", filename); } 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; /* if seeking requested, we execute it 如果开始时间指定的话需要做seek*/ if (o->start_time != AV_NOPTS_VALUE) { int64_t seek_timestamp = timestamp; if (!(ic->iformat->flags & AVFMT_SEEK_TO_PTS)) { int dts_heuristic = 0; for (i=0; i<ic->nb_streams; i++) { AVCodecContext *avctx = ic->streams[i]->codec; if (avctx->has_b_frames) dts_heuristic = 1; } if (dts_heuristic) { seek_timestamp -= 3*AV_TIME_BASE / 23; } } 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); } } /* update the current parameters so that they match the one of the input stream */ /* Add all the streams from the given input file to the global * list of input streams. * 将本文件的各个流放入input_streams链表中,并对解码器进行设置 * InputStream中的项在此函数中填值 */ add_input_streams(o, ic); /* dump the file content */ av_dump_format(ic, nb_input_files, filename, 0); /*将这个文件放到input_files链表中,并对其中的变量做设置,如下*/ GROW_ARRAY(input_files, nb_input_files); f = av_mallocz(sizeof(*f)); if (!f) exit_program(1); input_files[nb_input_files - 1] = f; f->ctx = ic; f->ist_index = nb_input_streams - ic->nb_streams;/* index of first stream in input_streams */ f->start_time = o->start_time; f->recording_time = o->recording_time; f->input_ts_offset = o->input_ts_offset; f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp); f->nb_streams = ic->nb_streams; f->rate_emu = o->rate_emu; f->accurate_seek = o->accurate_seek; f->loop = o->loop; f->duration = 0; f->time_base = (AVRational){ 1, 1 };#if HAVE_PTHREADS f->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8;#endif /* check if all codec options have been used */ unused_opts = strip_specifiers(o->g->codec_opts); for (i = f->ist_index; i < nb_input_streams; i++) { e = NULL; while ((e = av_dict_get(input_streams[i]->decoder_opts, "", e, AV_DICT_IGNORE_SUFFIX))) av_dict_set(&unused_opts, e->key, NULL, 0); } e = NULL; while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) { const AVClass *class = avcodec_get_class(); const AVOption *option = av_opt_find(&class, e->key, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); const AVClass *fclass = avformat_get_class(); const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); if (!option || foption) continue; if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) { av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for " "input file #%d (%s) is not a decoding option.\n", e->key, option->help ? option->help : "", nb_input_files - 1, filename); exit_program(1); } av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for " "input file #%d (%s) has not been used for any stream. The most " "likely reason is either wrong type (e.g. a video option with " "no video streams) or that it is a private option of some decoder " "which was not actually used for any stream.\n", e->key, option->help ? option->help : "", nb_input_files - 1, filename); } av_dict_free(&unused_opts); //对应参数"dump_attachment" for (i = 0; i < o->nb_dump_attachment; i++) { int j; for (j = 0; j < ic->nb_streams; j++) { AVStream *st = ic->streams[j]; if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1) dump_attachment(st, o->dump_attachment[i].u.str);//把st->codec->extradata输出到文件 } } for (i = 0; i < orig_nb_streams; i++) av_dict_free(&opts[i]); av_freep(&opts); input_stream_potentially_available = 1; return 0;}
0 0
- open_input_file()函数介绍
- open_input_file函数调用结构图
- 【算法函数介绍】Hash函数介绍
- wave函数介绍
- waveOutWrite函数介绍
- waveOutOpen函数介绍
- oracle 日期函数介绍
- GetLastError()函数的介绍
- bioskey函数介绍
- oracle 日期函数介绍
- oracle 日期函数介绍
- Linux C 函数介绍
- CreateMutex函数介绍
- FindWindow函数介绍
- PostMessage函数参数介绍
- API函数介绍
- MFC常用函数介绍
- ASP常用函数介绍
- 解密 加密
- P1019 单词接龙
- C编程之预处理标识符——__LINE__,__FILE__,__DATE__,__TIME__,__STDC__,#,##
- 学生信息管理系统 SSH 框架使用及范型使用
- robotium整理(二)
- open_input_file()函数介绍
- kill adb.exe
- Pseudo code for In-class QuestionExample 3: Write pseudo code that performs the following: Ask a use
- 【杂谈】蓝屏修复杂谈
- Shell脚本快速入门
- ld: warning: directory not found for option 去掉警告的方法
- Redis(一 安装使用)
- 在windows中创建ftp服务器
- 广播、组播、点播的区别