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
原创粉丝点击