当前位置: 首页 > news >正文

FFmepg源码系列-avformat_open_input()

===========================================
【FFmpeg入门系列】
FFmpeg入门:最简单的视频播放器
FFmpeg入门:最简单的音频播放器
FFmpeg入门:最简单的音视频播放器
FFmpeg入门:最简单的音视频播放器(Plus优化版)
FFmepg入门:最简单的音视频转码工具
基于ImGui+FFmpeg实现播放器

很久没有和大家分享FFmpeg了,也是因为最近工作上的事情比较多,上周花了一周时间读了一下FFmpeg的源码?对内部的很多实体和源码都仔细梳理了一下;所以往后的系列就是FFmpeg源码系列哈哈。

OK,进入今天的源码分析主题:avformat_open_input()
这个方法大家应该都不陌生,我们在做之前的音视频播放器的时候,打开一个文件的开始就是使用了avformat_open_input方法,今天我们就对这个方法,以及内部的实体进行详细分析

核心功能

⏺ avformat_open_input是FFmpeg中用于打开媒体文件并读取其头部信息的核心函数。其主要功能包括:

  1. 打开指定URL的媒体文件
  2. 自动探测并识别文件格式
  3. 为各种流(视频、音频等)创建AVStream结构
  4. 读取并解析文件头信息
  5. 分配并初始化AVFormatContext结构体
  6. 不打开编解码器,仅处理容器格式层面的操作

复用(muxing)和解复用(demuxing)

Demuxing(解复用)
定义: 将一个包含多种数据流的媒体文件分离成独立的数据流的过程。
特点:

  1. 输入: 一个完整的媒体文件(如MP4、AVI等容器格式)
  2. 输出: 多个独立的数据流(如视频流、音频流、字幕流等)
  3. 方向: 从一个复合文件到多个单独流
  4. 使用场景: 播放媒体文件、提取特定流、转码处理等 在FFmpeg中的实现:
  5. 使用avformat_open_input()打开媒体文件
  6. 使用av_read_frame()读取数据包
  7. 每个数据包属于特定的流(通过AVPacket.stream_index标识)

Muxing(复用)
定义: 将多个独立的数据流合并成一个包含多种数据流的媒体文件的过程。
特点:

  1. 输入: 多个独立的数据流(如视频流、音频流等
  2. 输出: 一个完整的媒体文件(指定格式的容器
  3. 方向:从多个单独流到一个复合文件
  4. 使用场景: 创建媒体文件、合并音视频流、格式转换等 在FFmpeg中的实现:
  5. 使用avformat_alloc_context()创建复用上下文
  6. 使用avformat_write_header()写入文件头
  7. 使用av_write_frame()或av_interleaved_write_frame()写入数据包
  8. 使用av_write_trailer()写入文件尾

核心区别总结

特性Demuxing(解复用)Muxing(复用)
操作方向分解:1个文件 → 多个流合并:多个流 → 1个文件
主要用途播放、分析、提取媒体内容创建、封装媒体文件
API函数avformat_open_input(), av_read_frame()avformat_write_header(), av_write_frame()
数据流向文件 → 内存中的独立流内存中的独立流 → 文件
时间处理读取已存在的时间戳读取已存在的时间戳 需要正确设置时间戳

AVFormatContext实体

这个实体是封装和解封装(复用和解复用)这一层最最关键的实体,它包含了输入/输出格式的相关信息,如文件的URL、流信息、编解码器参数等。

详细参数说明:

  基础信息字段1. const AVClass *av_class; // 日志和选项类,由avformat_alloc_context()设置2. const struct AVInputFormat *iformat; // 输入容器格式,仅解复用时使用3. const struct AVOutputFormat *oformat; // 输出容器格式,仅复用时使用4. void *priv_data; // 格式私有数据,由iformat/oformat.priv_class决定是否启用AVOptions5. AVIOContext *pb; // I/O上下文,处理输入/输出操作流信息字段8. AVStream **streams; // 文件中所有流的列表9. unsigned int nb_stream_groups; // AVFormatContext.stream_groups中的元素数量10. AVStreamGroup **stream_groups; // 文件中所有流组的列表11. unsigned int nb_chapters; // AVChapter数组中的章节数量12. AVChapter **chapters; // 章节指针数组13. char *url; // 输入或输出URL时间和持续时间字段14. int64_t start_time; // 第一帧位置,以AV_TIME_BASE为单位15. int64_t duration; // 流持续时间,以AV_TIME_BASE为单位16. int64_t bit_rate; // 总比特率,bit/s17. unsigned int packet_size; // 包大小控制标志和选项字段19. int flags; // 修改(解)复用器行为的标志,如AVFMT_FLAG_GENPTS等20. int64_t probesize; // 用于确定流属性的最大读取字节数21. int64_t max_analyze_duration; // avformat_find_stream_info()中读取数据的最大持续时间22. const uint8_t *key; // 密钥23. int keylen; // 密钥长度24. unsigned int nb_programs; // 程序数量25. AVProgram **programs; // 程序指针数组26. enum AVCodecID video_codec_id; // 强制视频编解码器ID27. enum AVCodecID audio_codec_id; // 强制音频编解码器ID28. enum AVCodecID subtitle_codec_id; // 强制字幕编解码器ID29. enum AVCodecID data_codec_id; // 强制数据编解码器ID63. const struct AVCodec *video_codec; // 强制视频编解码器64. const struct AVCodec *audio_codec; // 强制音频编解码器65. const struct AVCodec *subtitle_codec; // 强制字幕编解码器66. const struct AVCodec *data_codec; // 强制数据编解码器待逐个分析30. AVDictionary *metadata; // 应用于整个文件的元数据31. int64_t start_time_realtime; // 流开始时间,以微秒为单位32. int fps_probe_size; // 用于确定帧率的帧数33. int error_recognition; // 错误识别级别34. AVIOInterruptCB interrupt_callback; // I/O层的自定义中断回调35. int debug; // 调试标志36. int max_streams; // 最大流数37. unsigned int max_index_size; // 每个流索引的最大内存大小38. unsigned int max_picture_buffer; // 从实时捕获设备缓冲帧的最大内存39. int64_t max_interleave_delta; // 交错的最大缓冲持续时间40. int max_ts_probe; // 等待第一个时间戳时读取的最大包数41. int max_chunk_duration; // 最大块时间42. int max_chunk_size; // 最大块大小43. int max_probe_packets; // 可探测的最大包数44. int strict_std_compliance; // 允许非标准和实验性扩展45. int event_flags; // 指示文件上发生的事件的标志46. int avoid_negative_ts; // 避免复用期间出现负时间戳47. int audio_preload; // 音频预加载时间48. int use_wallclock_as_timestamps; // 强制使用wallclock时间戳49. int skip_estimate_duration_from_pts; // 跳过estimate_timings_from_pts中的持续时间计算50. int avio_flags; // avio标志,用于强制AVIO_FLAG_DIRECT51. enum AVDurationEstimationMethod duration_estimation_method; // 持续时间估算方法52. int64_t skip_initial_bytes; // 跳过初始字节53. unsigned int correct_ts_overflow; // 纠正单个时间戳溢出54. int seek2any; // 强制寻找到任何帧55. int flush_packets; // 每个包后刷新I/O上下文56. int probe_score; // 格式探测分数57. int format_probesize; // 识别输入格式的最大读取字节数58. char *codec_whitelist; // 允许的解码器列表59. char *format_whitelist; // 允许的解复用器列表60. char *protocol_whitelist; // 允许的协议列表61. char *protocol_blacklist; // 禁止的协议列表62. int io_repositioned; // I/O重新定位标志67. int metadata_header_padding; // 元数据头部填充字节数68. void *opaque; // 用户私有数据69. av_format_control_message control_message_cb; // 设备与应用程序通信的回调70. int64_t output_ts_offset; // 输出时间戳偏移71. uint8_t *dump_separator; // 转储格式分隔符72. int (*io_open)(); // 打开新IO流的回调73. int (*io_close2)(); // 关闭IO流的回调74. int64_t duration_probesize; // 确定流持续时间时读取的最大字节数

使用场景:

解复用:

  • 通过avformat_open_input()创建和初始化
  • 包含从文件中解析出的所有流信息
  • 用于读取媒体文件的数据包

复用:

  • 通过avformat_alloc_context()或avformat_alloc_output_context2()创建
  • 需要手动设置输出格式和流信息
  • 用于将数据包写入媒体文件

关键流程图

在这里插入图片描述
说一下关键的流程

AVIOContext open流程

  1. 申请内存初始化AVFormatContext
  2. 打开AVIOContext
  3. 根据输入url匹配对应的protocol
  4. 调用对应protocol的url_open方法,打开文件IO

AVInputFormat open流程

  1. 迭代支持的FFInputFormat,probe找到对应的FFInputFormat
  2. FFInputFormat->read_header读取文件头
  3. 申请AVStream,并分配的AVFormatContext上下文

举例:file协议的URLProtocol

const 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,.url_delete          = file_delete,.url_move            = file_move,.priv_data_size      = sizeof(FileContext),.priv_data_class     = &file_class,.url_open_dir        = file_open_dir,.url_read_dir        = file_read_dir,.url_close_dir       = file_close_dir,.default_whitelist   = "file,crypto,data"
};

举例 aac文件的FFInputFormat

const FFInputFormat ff_aac_demuxer = {.p.name       = "aac",.p.long_name  = NULL_IF_CONFIG_SMALL("raw ADTS AAC (Advanced Audio Coding)"),.p.flags      = AVFMT_GENERIC_INDEX,.p.extensions = "aac",.p.mime_type  = "audio/aac,audio/aacp,audio/x-aac",.read_probe   = adts_aac_probe,.read_header  = adts_aac_read_header,.read_packet  = adts_aac_read_packet,.raw_codec_id = AV_CODEC_ID_AAC,
};

aac的probe探测

在这里插入图片描述

http://www.dtcms.com/a/326483.html

相关文章:

  • python之uv使用
  • [动态规划]最长公共子序列(LCS)
  • Nacos添加权限
  • uart通信中出现乱码,可能的原因是什么 ?
  • Linux软件编程:标准IO(ASCII文件)
  • Discuz论坛和java应用的架构部署
  • 视频剪辑的工作流程
  • 笔试——Day35
  • 用 Flink SQL 和 Paimon 打造实时数仓:深度解析与实践指南
  • GitHub的简单使用方法----(1)
  • 论文阅读 arxiv 2024 MemGPT: Towards LLMs as Operating Systems
  • 平衡二叉树(AVL)解析与实现
  • python每日一题 1的数量 非常简单
  • 松灵机器人 scout ros2 galactic 驱动 安装,并且跑巡线算法
  • 深入剖析 C++ STL 中的 std::list 容器
  • 一篇文章解决Unity没有添加模块选项的问题
  • Linux系统编程 | 线程池
  • Redis7 GEO功能介绍与电商场景案例解析
  • Static CXL Switch:静态CXL交换机相关内容
  • leecode875 爱吃香蕉的珂珂
  • 【Unity】打包学习笔记
  • pip 和 conda,到底用哪个安装?
  • 【已解决】【obsidian插件开发】svg图标路径不正确
  • 第16届蓝桥杯Python青少组中/高级组选拔赛(STEMA)2025年1月12日真题
  • 机器翻译:一文掌握序列到序列(Seq2Seq)模型(包括手写Seq2Seq模型)
  • 豆包 + 蘑兔 AI:音乐创作的梦幻组合
  • UE5太空射击游戏入门(二):场景搭建与自动飞行
  • JS-第二十三天-正则
  • Vue2篇——第二章 Vue从指令修饰符到侦听器的全面解析(重点)
  • 反射之Reflect