ffmpeg源码分析之三avformat_open_input()上

FFMpeg 源码分析 (3)avformat_open_input() 这个函数主要用来打开媒体资源。完成媒体格式的探测和获取相关的媒体信息的工作。函数完成定义如下:int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options) { AVFormatContext 阅读详情
URLProtocol ff_file_protocol = {
    .name                = "file",
    .url_open            = file_open,
    .url_read            = file_read,
    .url_write           = file_write,
    .url_seek            = file_seek,
    .url_close           = file_close,
    .url_get_file_handle = file_get_handle,
    .url_check           = file_check,
};


    经过第一讲之后 大家应该知道ffmpeg将所有编解码用到的东西都做成了一个个的链表 通过一个个全局的链表头指针来访问该链表 以供在涉及到具体的编解码器时用。

这一章就分析ffmpeg如何打开的视频文件。

  首先 提出来三个具体的结构,ffmpeg通过封装他们用于打开文件的相关操作 ,分别是URLProtocol URLContext与AVIOContext.

 1.URLProtocol该结构定义在libavformat/url.h文件中 结构如下:

typedef struct URLProtocol {
    const char *name;
    int     (*url_open)( URLContext *h, const char *url, int flags);
    /**
     * This callback is to be used by protocols which open further nested
     * protocols. options are then to be passed to ffurl_open()/ffurl_connect()
     * for those nested protocols.
     */
    int     (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);
    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中 无非就是定义一些函数指针 呵呵 联想到第二讲中的使用C模拟C++的多态性质 不难想到 该结构肯定会用各个类型的具体函数来填充  后面会分析
2.URLContext结构定义在libavformat/url.h中 结构如下

typedef struct URLContext {
    const AVClass *av_class;    /**< information for av_log(). Set by url_open(). */
    struct URLProtocol *prot;
    void *priv_data;
    char *filename;             /**< specified URL */
    int flags;
    int max_packet_size;        /**< if non zero, the stream is packetized with this max packet size */
    int is_streamed;            /**< true if streamed (no seek possible), default = false */
    int is_connected;
    AVIOInterruptCB interrupt_callback;
} URLContext;

3.AVIOContext定义在libavformat/avio.h中 代码如下

typedef struct {
#if !FF_API_OLD_AVIO
    AVClass *av_class;
#endif
    unsigned char *buffer;  /**< Start of the buffer. */
    int buffer_size;        /**< Maximum buffer size */
    unsigned char *buf_ptr; /**< Current position in the buffer */
    unsigned char *buf_end; /**< End of the data, may be less than
                                 buffer+buffer_size if the read function returned
                                 less data than requested, e.g. for streams where
                                 no more data has been received yet. */
    void *opaque;           /**< A private pointer, passed to the read/write/seek/...
                                 functions. */
    int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
    int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
    int64_t (*seek)(void *opaque, int64_t offset, int whence);
    int64_t pos;            /**< position in the file of the current buffer */
    int must_flush;         /**< true if the next seek should flush */
    int eof_reached;        /**< true if eof reached */
    int write_flag;         /**< true if open for writing */
#if FF_API_OLD_AVIO
    attribute_deprecated int is_streamed;
#endif
    int max_packet_size;
    unsigned long checksum;
    unsigned char *checksum_ptr;
    unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
    int error;              /**< contains the error code or 0 if no error happened */
    int (*read_pause)(void *opaque, int pause);
    int64_t (*read_seek)(void *opaque, int stream_index,
                         int64_t timestamp, int flags);
    int seekable;

     int64_t maxsize;
} AVIOContext;

好了 这三个重要的结构代码我已经贴出来了  下面进入正题 分析avformat_open_input的流程

1.该函数定义在libavformat/utils.c中,代码如下:

//继av_register_all()后 第二步就是调用该函数 主要就是打开一个多媒体文件 获取到AVFormatContext的对象
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
{
    AVFormatContext *s = *ps;
    int ret = 0;
    AVFormatParameters ap = { { 0 } };
    AVDictionary *tmp = NULL;
	//avformat_alloc_context()位于libavformat/options.c中 主要是为AVFormatContext分配空间
    if (!s && !(s = avformat_alloc_context()))
        return AVERROR(ENOMEM);
    if (fmt)
        s->iformat = fmt;

    if (options)
        av_dict_copy(&tmp, *options, 0);

    if ((ret = av_opt_set_dict(s, &tmp)) < 0)
        goto fail;

    if ((ret = init_input(s, filename, &tmp)) < 0)
        goto fail;
//........下次分析下

其中关键在init_input()

static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options)
{
    int ret;
    AVProbeData pd = {filename, NULL, 0};

    if (s->pb) {
        s->flags |= AVFMT_FLAG_CUSTOM_IO;
        if (!s->iformat)
            return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0);
        else if (s->iformat->flags & AVFMT_NOFILE)
            av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
                                      "will be ignored with AVFMT_NOFILE format.\n");
        return 0;
    }

    if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
        (!s->iformat && (s->iformat = av_probe_input_format(&pd, 0))))
        return 0;

	//avio_open2定义在libavformat/aviobuf.c中 但是在avio.h中声明
	//Create and initialize a AVIOContext for accessing the resource indicated by url
    if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ,
                          &s->interrupt_callback, options)) < 0)
        return ret;
    if (s->iformat)
        return 0;
    return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0);
}

这里调用了avio_open2()定义在libavformat/aviobuf.c中

int avio_open2(AVIOContext **s, const char *filename, int flags,
               const AVIOInterruptCB *int_cb, AVDictionary **options)
{
    URLContext *h;
    int err;
	//定义在libavformat/avio.c
    err = ffurl_open(&h, filename, flags, int_cb, options);
    if (err < 0)
        return err;
    err = ffio_fdopen(s, h);
    if (err < 0) {
        ffurl_close(h);
        return err;
    }
    return 0;
}

ffurl_open()定义在libavformat/avio.c中

int ffurl_open(URLContext **puc, const char *filename, int flags,
               const AVIOInterruptCB *int_cb, AVDictionary **options)
{
    int ret = ffurl_alloc(puc, filename, flags, int_cb);
    if (ret)
        return ret;
    if (options && (*puc)->prot->priv_data_class &&
        (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
        goto fail;
    ret = ffurl_connect(*puc, options);
    if (!ret)
        return 0;
fail:
    ffurl_close(*puc);
    *puc = NULL;
    return ret;
}

这里面调用了两个重要的函数 一个是ffurl_alloc 请看

int ffurl_alloc(URLContext **puc, const char *filename, int flags,
                const AVIOInterruptCB *int_cb)
{
    URLProtocol *up = NULL;
    char proto_str[128], proto_nested[128], *ptr;
    size_t proto_len = strspn(filename, URL_SCHEME_CHARS);

    if (!first_protocol) {
        av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. "
                                     "Missing call to av_register_all()?\n");
    }

    if (filename[proto_len] != ':' &&  filename[proto_len] != ',' || is_dos_path(filename))
        strcpy(proto_str, "file");
    else
        av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str)));

    if ((ptr = strchr(proto_str, ',')))
        *ptr = '\0';
    av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
    if ((ptr = strchr(proto_nested, '+')))
        *ptr = '\0';

    while (up = ffurl_protocol_next(up)) {
        if (!strcmp(proto_str, up->name))
            return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
        if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
            !strcmp(proto_nested, up->name))
            return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
    }
    *puc = NULL;
    return AVERROR(ENOENT);
}

哈哈 在ffurl_alloc中就要寻找之前在av_register_all()中串起来的链表的一个节点了 这里的依据是根据传入的filename的类型来判断是本地文件还是来自于网络流 我用的是本地文件 故其找到的是定义在libavformat/file.c中的一个urlprotocol结构


URLProtocol ff_file_protocol = {
    .name                = "file",
    .url_open            = file_open,
    .url_read            = file_read,
    .url_write           = file_write,
    .url_seek            = file_seek,
    .url_close           = file_close,
    .url_get_file_handle = file_get_handle,
    .url_check           = file_check,
};

再看ffurl_connect

int ffurl_connect(URLContext* uc, AVDictionary **options)
{
    int err =
#if !FF_API_OLD_AVIO
        uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) :
#endif
        uc->prot->url_open(uc, uc->filename, uc->flags);
    if (err)
        return err;
    uc->is_connected = 1;
    //We must be careful here as ffurl_seek() could be slow, for example for http
    if(   (uc->flags & AVIO_FLAG_WRITE)
       || !strcmp(uc->prot->name, "file"))
        if(!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
            uc->is_streamed= 1;
    return 0;
}

在这里调用了URLProtocol中的url_open 而url_open指针指向了file.c中的file_open()函数  成功的指向了本地文件的操作 。ee

爱

简要总结一下 URLContext像一个容器 封装了打开文件或者网络流的一些公共属性 URLProtocol是一个多态的基类 封装了一些操作 AVIOContext更像是一些私有的数据

这些会在下文中继续分析

   另外,FFMPEG中有很多这样的三元组 掌握他们会对你理解ffmpeg有很大的帮助 同时也能对你在面向过程的设计当中增加一个设计多态的一个工具

 

 

累了   明天继续。。。。。。

 


 

 

 


 

 


 

 

 

 


 

 

 

 

 

 

 

 

 

 

FFmpeg源码分析:avformat_open_input()打开媒体流 avformat_open_input()用于打开输入媒体流与读取头部信息,包括本地文件、网络流、自定义缓冲区。关键流程:打开avio、探测输入流的封装格式。对应的释放方法为avformat_close_input()。 阅读详情

相关推荐

ffmpeg源码分析之四-----avformat_open_input()下

上篇分析到在Init_input中打开一个媒体文件 本篇将分析剩下的流程。看代码 static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options) { int ret; AVProbeData pd = {filename, NULL, 0}; if

CodeFoxTiger的专栏 2736

ffmpeg 报错 avformat_open_input 返回-1330794744

ffmpeg avformat_open_input 报错

m0_47135641的博客 3030

FFmpeg源码分析:avformat_open_input

avformat_open_input(),该函数用于打开多媒体数据并且获取一些信息,它的声明位于libavformat/avformat.h: /** * Open an input stream and read the header. The codecs are not opened. * 打开输入流,并且读取header。codecs不会被打开。 * The stream must...

小薇子的博客 1万+

FFMPEG Vcl Player 7.0 For Delphi Crack

FFMPEG Vcl Player For Delphi 7.0 是一个基于 directshow 和 ffmpeg 的 vcl 播放器,用于解码和播放视频/音频。

控件与插件之大全 1271

ffmpeg学习五:avformat_open_input函数源码分析(以mp4文件为例)

上一节我们写了一个简单的程序,它可以把一个视频文件解码成多张图片。我们只是简单的使用的ffmepg提供的api来实现这一过程的,但对api具体的实现过程却一无所知,因此,从这篇博客看是,就逐步分析这些api的内部实现原理。这一节,主要分析avformat_open_input函数的具体实现。avformat_open_input函数如下:/** * Open an input stream and

阳光玻璃杯 1万+

Avformat_open_input函数的分析 结合HTTP协议

前段时间在做直播的优化,主要是优化首屏时间,因为直播播放器大部分都会采用ffmpeg来处理,所以就会用到avformat_open_input这个函数,这也是首屏耗时比较多的一个地方,这里我主要跟踪一下http的请求以及rtmp的请求,源码都是开源的,这里主要是记录下来以备自己查询,本篇文章主要是是以ijkplayer源码为基础分析的。 avformat_open_input这个函数的作用是打开...

郭风朴(guofengpu)的Android影音专栏 1868

ffmpeg源码分析:avformat_open_input()

目录 一、avformat_alloc_context() 二、init_input() 2.1 av_probe_input_format2() 2.2 av_probe_input_buffer2() 2.3 io_open 三、read_header() 本文简单分析FFmpeg中一个常用的函数:avformat_open_input()。该函数用于打开多媒体数据并且获得一些相关的信息。它的声明位于libavformat\avformat.h,如下所示。 /** * O...

yangguoyu8023的博客 1257

【FFmpeg】ffmpeg中函数返回的错误码:AVERROR及AVERROR_*

1、AVERROR FFmpeg的错误码大部分使用的PIOSIX标准中错误码的负值。 AVERROR定义在文件 FFmpeg-n4.2.1/libavutil/error.h 中 #define AVERROR(e) (-(e)) // Returns a negative error code from a POSIX error code, to return from library functions. //FFmpeg库的错误码是POSIX错误码的负值。 2、av_strerror 将错误

郭老二 7626

FFMPEG4.1源码分析之 媒体打开函数avformat_open_input()

目录 0avformat_open_input() 功能详细描述 1 avformat_open_input()源码分析 1.1init_input() 1.1.1av_probe_input_buffer2() //1.1.1.2ffio_rewind_with_probe_data() 1.1.2av_probe_input_format2() ...

ice_ly000的博客 3430

基于ffmpeg实现的rtmp推流模块

需要先创建推流的流媒体地址,然后再创建一个对象启动推流,创建过程如下。 RtmpPublishManager* rpm = new RtmpPublishManager("rtmp://192.168.16.88:1935/hls/test0", read_fd[0]); rpm->ffmpeg_init(NULL); rpm->start();

ffmpeg.rar_ffmpeg_ffplay

FFMPEG/FFPLAY源 码 剖 析

06 FFmpeg4.4源码分析--avformat_open_input()

一、简单介绍 avformat_open_input()的主要作用是:打开一个媒体文件或RTSP链接并进行解析。 函数原型为: int avformat_open_input(AVFormatContext **ps, const char *filename, ff_const59 AVInputFormat *fmt, AVDictionary **options); 各参数含义如下: ps: 媒体相关的上下文结构信息,需要注意的是:若该函数

王木木 1164

Dify安装使用说明

dify可以说是一个功能不错的LLMOps,可以通过dify集中管理模型,可以通过界面创建AI应用,可以上传文档形成知识库,可以创建自定义工具(API),并可以对外提供API。相关功能类似Openai的GPTs或智谱的智能体,其他大厂的大模型也有类似功能,不过貌似只有dify是开源的。这就为个人本地部署AI应用提供了便利。

龙井茶的Sky 1万+

FFMpeg 源代码分析

FFMpeg 源代码分析引言最近在公司带领团队在做一个视频播放器的项目。由于整个团队之前并没有相关的技术积累,同时公司也没有相关的产品积累。为了能让项目快速的上线,决定使用FFMpeg作为底层的多媒体引擎。一方面大大节省项目时间,另一方面也可以大大降低整个项目的技术门槛。 联想起之前的一些过往经验,学过的技术很久不用还是很容易忘记的。还是记下来做个备忘比较靠谱。所以决定写这样一个技术博客来

雷霆小屁熊的专栏 3033

从零搭建UVM验证环境:新手入门实践指南

在数字芯片验证领域,SystemVerilog和UVM(Universal Verification Methodology)是构建高效验证环境的核心技术。其原理基于面向对象编程和事务级建模,通过组件化架构实现验证的复用性和自动化。这一方法学的技术价值在于显著提升验证效率与质量,广泛应用于处理器、通信芯片等复杂设计的验证场景。本文聚焦于UVM验证环境的搭建实践,通过一个加法器实例,详细解析了uvm_driver、uvm_monitor、uvm_sequence等关键组件的协同工作机制,并提供了基于Quest

weixin_30015371的博客 445

5G协议栈逆向工程:基于开源模拟器的核心网信令分析实战

本文详细介绍了基于开源模拟器Free5GC和UERANSIM的5G协议栈逆向工程实战,涵盖核心网信令分析、环境搭建、认证协议解析及安全漏洞验证。通过NGAP/NAS信令交互解密和异常流量注入测试,帮助研究人员深入理解5G网络安全机制,并提供实用的安全加固建议。

weixin_29250573的博客 674

FFmepg源码系列-avformat_open_input()

本文介绍了FFmpeg中avformat_open_input()函数的核心功能,包括打开媒体文件、识别格式、创建流结构等。深入分析了复用(demuxing)和解复用(muxing)的概念、区别及实现方式。重点讲解了AVFormatContext实体,详细说明其关键字段如流信息、时间参数、控制标志等。文章还预告了后续将转向FFmpeg源码分析系列,为开发者提供更深入的技术参考。

m0_51433562的博客 945

Rider高效调试UE引擎:无需编译源码的符号配置指南

本文提供了一份详尽的Rider高效调试UE引擎指南,核心在于无需编译源码即可配置调试符号。通过Epic启动器下载官方PDB文件,并在Rider中正确配置外部符号服务器路径,开发者能在10分钟内实现对引擎内部代码(如AActor::Tick)的源码级断点调试、变量查看和调用堆栈分析,极大提升问题排查效率。

weixin_29011239的博客 340

FFMPEG源码分析:avformat_open_input()(媒体打开函数)

本文分析了FFMPEG中的媒体打开函数avformat_open_input() //参数ps包含一切媒体相关的上下文结构,有它就有了一切,本函数如果打开媒体成功, //会返回一个AVFormatContext的实例. //参数filename是媒体文件名或URL. //参数fmt是要打开的媒体格式的操作结构,因为是读,所以是inputFormat.此处可以 //传入一个调用者定义...

sunshineywz的博客 897

高性能算力中心 — RDMA — Overview

目录 文章目录目录RDMA基于以太网的 RoCE/RDMA 计算优化NVMeNVMe Over Fabrics基于以太网的 NVMe 存储优化 RDMA RDMA(Remote DMA,远程直接内存访问)是一种新的内存访问技术,RDMA 让计算机可以直接存取其他计算机的内存,而不需要经过 CPU 耗时的处理。RDMA 将数据从一个系统快速移动到远程系统存储器中,而不对操作系统造成任何影响。RDMA 技术的原理及其与 TCP/IP 架构的对比如下图所示。 InfiniBand(IB):从一开始就支持 R

烟云的计算 2365

R语言机器学习算法实战系列(十一)MLP算法分类器 (Multi-Layer Perceptrons)

本文介绍了多层感知器(MLP)分类算法的原理和计算步骤,并通过R语言实现MLP模型。MLP是一种前馈神经网络,包含输入层、隐藏层和输出层,通过激活函数引入非线性,利用前向传播和反向传播进行训练。文章详细描述了数据预处理、数据切割、模型构建、预测和评估等步骤,并提供了乳腺癌数据集(BreastCancer_clean.csv)的下载链接。通过R包如neuralnet和caret,读者可以逐步实现MLP模型,并评估其分类性能。

专注生信领域 933

FFmpeg源码剖析: avformat_open_input()函数

上面代码主要检测ID3v2标签(通常用于MP3文件元数据).如果缓冲区大小大于10,并且缓冲区的开头与ID3v2的魔数匹配,则检测是否存在ID3标签. 根据ID3标签的大小调用。上面代码就是做一些简单的设置工作,没什么好解释的.下面讲解后面的for循环读取数据然后探测格式。回调函数探测格式设置分数,这个是每个格式都有自己的格式解析函数. 然后设置最高分数.标识输入格式的一些信息,如何解析某种格式的文件,提供了相关的回调函数。前面我们分析的是这个函数,那么计算完分数后,该执行下面的。

2401_89221445的博客 1044

航空电子系统标准全景图:ARP4754A、ARP4761、DO-178C、DO-254 的协同作用

通过 ARP4754A、ARP4761、DO-178C 和 DO-254 的相互配合,确保航空电子系统的安全性和功能性在开发过程中得到充分保障。每一个文件在不同层面发挥作用,共同构成了一个完整的、系统的开发和验证框架,确保航空电子设备达到适航要求。这些标准不仅帮助开发人员有条理地开发复杂的航空系统,还确保所有系统组件(软件和硬件)在整个生命周期内都能满足最严格的安全和可靠性要求。

qq_41854911的博客 1812
上一篇: ffmpeg代码分析之2——模拟C++多态之C实现篇章
下一篇: ffmpeg源码分析之四-----avformat_open_input()下
CodeFoxTiger
博客等级 码龄14年 9粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值