ffmpeg源码分析之open_input_file

本文深入分析ffmpeg中的open_input_file函数,该函数在open_files调用后,接收OptionsContext o和filename作为参数。首先,通过av_find_input_format查找输入格式,接着avformat_alloc_context分配上下文,并配置相关参数。然后,调用avformat_open_input打开输入,最后进行avformat_find_stream_info以获取流信息。整个过程涉及ffmpeg的内部机制和关键步骤。

open_input_file函数是被open_files函数调用,在调用之前open_files函数将解析得到的输入相关参数存入到   OptionsContext o中,以ffmpeg -f v4l2 -i /dev/video0 test.mp4为例,其实就是-f v4l2 -i /dev/video0,

其中 -f v4l2通过parse_optgroup函数来解析,这里主要还是跟options中对f参数的定义相关的,会去根据这些定义来进行相关的操作(write_option函数),write_option部分代码,这里我们其实就是获取了一个v4l2转存了一下,需要注意的就是-f 定义中的 { .off       = OFFSET(format) },其实就是格式了,这个会在后面的时候会用到

    if (po->flags & OPT_STRING) {  //
        char *str;
        str = av_strdup(arg);    
        av_freep(dst);
        if (!str)
            return AVERROR(ENOMEM);
        *(char **)dst = str;  
    } else if (po->flags & OPT_BOOL || po->flags & OPT_INT) {
        *(int *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);
    } else if (po->flags & OPT_INT64) {
        *(int64_t *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT64_MIN, INT64_MAX);
    } else if (po->flags & OPT_TIME) {
        *(int64_t *)dst = parse_time_or_die(opt, arg, 1);
    } else if (po->flags & OPT_FLOAT) {
        *(float *)dst = parse_number_or_die(opt, arg, OPT_FLOAT, -INFINITY, INFINITY);
    } else if (po->flags & OPT_DOUBLE) {
        *(double *)dst = parse_number_or_die(opt, arg, OPT_DOUBLE, -INFINITY, INFINITY);
    } else if (po->u.func_arg) {
        int ret = po->u.func_arg(optctx, opt, arg);
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR,
                   "Failed to set value '%s' for option '%s': %s\n",
                   arg, opt, av_err2str(ret));
            return ret;
        }
    }
    if (po->flags & OPT_EXIT)
        exit_program(0);

 然后调用了真正的open_input_file函数 传入两个参数一个是上面的 o就是转存的数据,另一个就是g->arg 就是filename 这里就是/dev/video0,open_input_file函数相对复杂,定义在ffmpeg_opt.c中。open_input_file函数中有很多if判断,看起来就很迷糊,都是针对一些具体的参数用的,这里我是参考了别人的文章简单看了一下

//输入参数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
在使用FFmpeg的avformat_open_input函数打开一个媒体文件之后,为了正常关闭,需要按照以下步骤: 1. 调用avformat_find_stream_info函数获取媒体文件的流信息。 2. 调用av_read_frame函数读取媒体文件中的数据帧。 3. 当需要停止读取数据帧时,调用avformat_close_input函数关闭输入流。 4. 释放所有相关的资源,包括AVFormatContext、AVIOContext、AVCodecContext等。 示例代码: ``` AVFormatContext *pFormatCtx = NULL; int videoStream = -1; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec = NULL; AVPacket packet; av_register_all(); if(avformat_open_input(&pFormatCtx, filename, NULL, NULL)!=0){ printf("Could not open file\n"); return -1; } if(avformat_find_stream_info(pFormatCtx, NULL)<0){ printf("Could not find stream information\n"); return -1; } videoStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); if(videoStream == -1){ printf("Could not find video stream\n"); return -1; } pCodecCtx = pFormatCtx->streams[videoStream]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if(pCodec == NULL){ printf("Codec not found\n"); return -1; } if(avcodec_open2(pCodecCtx, pCodec, NULL)<0){ printf("Could not open codec\n"); return -1; } av_init_packet(&packet); while(av_read_frame(pFormatCtx, &packet)>=0){ // 处理读取到的数据帧 av_packet_unref(&packet); } avformat_close_input(&pFormatCtx); avcodec_free_context(&pCodecCtx); ``` 以上代码演示了如何打开一个媒体文件,读取其中的数据帧,并在完成后正常关闭。在关闭输入流之前,需要确保所有的数据帧都已经被处理完毕,并且相关的资源已经被释放。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值