FFmpeg 源码学习(一):avformat_open_input 源码分析

一、源码方法参数分析

下面是avformat_open_input的方法及参数:

 
  
/**
* Open an input stream and read the header. The codecs are not opened.
* The stream must be closed with avformat_close_input().
*
* @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).
* May be a pointer to NULL, in which case an AVFormatContext is allocated by this
* function and written into ps.
* Note that a user-supplied AVFormatContext will be freed on failure.
* @param url URL of the stream to open.
* @param fmt If non-NULL, this parameter forces a specific input format.
* Otherwise the format is autodetected.
* @param options A dictionary filled with AVFormatContext and demuxer-private options.
* On return this parameter will be destroyed and replaced with a dict containing
* options that were not found. May be NULL.
*
* @return 0 on success, a negative AVERROR on failure.
*
* @note If you want to use custom IO, preallocate the format context and set its pb field.
*/
int avformat_open_input(AVFormatContext **ps,  const char *filename,  AVInputFormat *fmt,  AVDictionary **options)

这里我们提供的是英文的参数注释,主要是翻译不好,对此方法的理解也没有什么帮助。下面针对此方法的这几个参数进行一下说明:

  • AVFormatContext **ps : 参数ps包含一切媒体相关的上下文结构,有它就有了一切,本函数如果打开媒体成功,会返回一个AVFormatContext的实例。此参数可以为avformat_alloc_context创建的,也可以是NULL。
  • 参数filename是媒体文件名或URL.  
  • 参数fmt是要打开的媒体格式的操作结构,因为是读,所以是inputFormat.此处可以传入一个调用者定义的inputFormat,对应命令行中的 -f xxx段,如果指定了它,在打开文件中就不会探测文件的实际格式了,以它为准了. 
  • 参数options是对某种格式的一些操作,是为了在命令行中可以对不同的格式传入,特殊的操作参数而建的, 可以无视。

二、方法的作用及流程

1. 输入输出结构体AVIOContext的初始化;

2. 输入数据的协议(例如RTMP,或者File)的识别(通过一套评分机制)

  • 判断文件名的后缀

  • 读取文件头的数据进行比对;

3. 使用获得最高分的文件协议对应的URLProtocol,通过函数指针的方式,与FFMPEG连接,剩下的就是调用该URLProtocol的函数进行open,read等操作。

 

下图用来了解一下和avformat_open_input有关系的函数调用流程图:

 

可见最终都调用了URLProtocol结构体中的函数指针。

下面是URLProtocol结构,可以看出来URLProtocol是一大堆函数指针的集合(avio.h文件)

typedef struct URLProtocol {
    const char *name;
    int (*url_open)(URLContext *h, const char *url, int flags);
    int (*url_read)(URLContext *h, unsigned char *buf, int size);
    int (*url_write)(URLContext *h, const unsigned char *buf, int size);
    int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);
    int (*url_close)(URLContext *h);
    struct URLProtocol *next;
    int (*url_read_pause)(URLContext *h, int pause);
    int64_t (*url_read_seek)(URLContext *h, int stream_index,
                             int64_t timestamp, int flags);
    int (*url_get_file_handle)(URLContext *h);
    int priv_data_size;
    const AVClass *priv_data_class;
    int flags;
    int (*url_check)(URLContext *h, int mask);
} URLProtocol;

URLProtocol功能就是完成各种输入协议的读写等操作

但输入协议种类繁多,它是怎样做到“大一统”的呢?

原来,每个具体的输入协议都有自己对应的URLProtocol。

比如file协议(FFMPEG把文件也当做一种特殊的协议)(*file.c文件)

URLProtocol ff_pipe_protocol = {
    .name                = "pipe",
    .url_open            = pipe_open,
    .url_read            = file_read,
    .url_write           = file_write,
    .url_get_file_handle = file_get_handle,
    .url_check           = file_check,
};

或者rtmp协议(此处使用了librtmp)(librtmp.c文件)

URLProtocol ff_rtmp_protocol = {
    .name                = "rtmp",
    .url_open            = rtmp_open,
    .url_read            = rtmp_read,
    .url_write           = rtmp_write,
    .url_close           = rtmp_close,
    .url_read_pause      = rtmp_read_pause,
    .url_read_seek       = rtmp_read_seek,
    .url_get_file_handle = rtmp_get_file_handle,
    .priv_data_size      = sizeof(RTMP),
    .flags               = URL_PROTOCOL_FLAG_NETWORK,
};

可见它们把各自的函数指针都赋值给了URLProtocol结构体的函数指针

因此avformat_open_input只需调用url_open,url_read这些函数就可以完成各种具体输入协议的open,read等操作了

三、方法的使用技巧

合理的使用 avformat_open_input 方法能够加快视频的首屏播放。

首先我们知道avformat_open_input这个函数的作用是打开文件的链接,如果是网络连接,还会发起网络请求,并一直等待网络数据的返回,然后读取视频流的数据。

那如何加快首屏播放呢?

我们可以利用方法中的第三个参数——AVInputFormat。AVInputFormat的结构体比较复杂,主要是封装媒体数据封装类型的结构体,比如flv, mpegts, mp4等,在这里可以传入空(或者0),如果为空(或者0),那么FFmpeg就会自行去检测获取。

当然如果我们知道文件的类型,先用av_find_input_format("flv")初始化出对应的结构体,这里我们用的是flv,先初始化好这个结构体,就能够节约时间加快首屏播放了。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值