【FFmpeg】解封装 ① ( 封装与解封装流程 | 解封装函数简介 | 查找码流标号和码流参数信息 | 使用 MediaInfo 分析视频文件 )

文章目录

  • 一、解封装
    • 1、封装与解封装流程
    • 2、解封装 常用函数
  • 二、解封装函数简介
    • 1、avformat_alloc_context 函数
    • 2、avformat_free_context 函数
    • 3、avformat_open_input 函数
    • 4、avformat_close_input 函数
    • 5、avformat_find_stream_info 函数
    • 6、av_read_frame 函数
    • 7、avformat_seek_file 函数
    • 8、av_seek_frame 函数
  • 三、查找码流标号和参数信息
    • 1、码流标号
    • 2、查找码流标号 - av_find_best_stream 函数
    • 3、查找码流参数信息 - avformat_find_stream_info 函数
    • 4、查找码流参数信息延迟分析
  • 四、视频文件解封装示例
    • 1、使用 MediaInfo 分析视频文件
    • 2、使用 MediaInfo 分析视频文件的每个字节的信息


FFmpeg 4.0 版本源码地址 :

  • GitHub : https://github.com/FFmpeg/FFmpeg/tree/release/4.0
  • GitCode : https://gitcode.com/gh_mirrors/ff/FFmpeg/tree/release/4.0
  • FFmpeg/libavcodec/avpacket.c 源码 : https://gitcode.com/gh_mirrors/ff/FFmpeg/blob/release/4.0/libavcodec/avpacket.c




一、解封装




1、封装与解封装流程


" 封装 " 是 将 音频流 / 视频流 / 字幕流 等多媒体流 , 按照一定的规则 组合成 特定格式的 视频文件 ;

  • 封装 主要是由 " 复用器 " 完成的 ;
  • 封装示例 : 将 AAC 格式的 音频流 和 H.264 格式的 视频流 封装成一个 .mp4 文件 ;

在这里插入图片描述

" 解封装 " 是 将 特定格式的 视频文件 , 按照一定的规则 拆分成 音频流 / 视频流 / 字幕流 等多媒体流 ;

  • 解封装 主要是由 " 解复用器 " 完成的 ;
  • 解封装示例 : 将 .mp4 文件 拆分成 AAC 格式的 音频流 和 H.264 格式的 视频流 ;

在这里插入图片描述


2、解封装 常用函数


解封装 常用函数 简介 :

  • avformat_alloc_context 函数 : 用于 申请 AVFormatContext 结构体内存 , 并 对 结构体的字段 进行简单初始化操作 ;
  • avformat_free_context 函数 : 释放 AVFormatContext 结构体 及其 关联的资源 ;
  • avformat_open_input 函数 : 使用 解复用器 打开 视频文件 / 媒体流 ;
  • avformat_close_input 函数 : 关闭 解复用器 ;
  • avformat_find_stream_info 函数 : 获取 媒体流信息 ;
  • av_read_frame 函数 : 读取 媒体流 中的 AVPacket 数据包 ;
  • avformat_seek_file 函数 : 根据 时间戳 跨多个流 定位文件 中的位置 ;
  • av_seek_frame 函数 : 根据 时间戳 跳转到指定流的指定位置 ;




二、解封装函数简介



下面的 解封装 函数 可 参考 【FFmpeg】FFmpeg 函数简介 ② ( 封装格式相关函数解析 | 封装格式与解复用器 | avformat_alloc_context 函数 | avformat_open_input函数 ) 博客 ;

解封装流程如下 :
在这里插入图片描述


1、avformat_alloc_context 函数


avformat_alloc_context 函数原型 :

AVFormatContext *avformat_alloc_context(void);
  • 函数作用 : 该函数用于 分配并初始化一个 AVFormatContext 结构体 ;
  • 函数参数 : 函数参数为空 ;
  • 函数返回值 : 函数 返回一个 AVFormatContext 指针 , 指向分配的结构体 ; 如果分配失败 , 则返回 NULL ;

AVFormatContext 结构体 用于 存储 文件格式相关信息 , 其中包括文件中 各个媒体流 的参数信息 ;


2、avformat_free_context 函数


avformat_free_context 函数 用于 释放 AVFormatContext 结构体 以及相关的资源 , 包括 流信息 / IO 资源 / 解码器 / 格式上下文 等数据 ,


avformat_free_context 函数原型如下 :

void avformat_free_context(AVFormatContext *s);

avformat_free_context 函数avformat_alloc_context 函数 一般都要成对使用 , 防止内存泄漏 ;

如果 之前调用过 avformat_alloc_context 函数 , 则必须调用 avformat_free_context 函数 释放内存 ;

如果 之前没有调用过 avformat_alloc_context 函数 , 则不必调用 avformat_free_context 函数 ;


3、avformat_open_input 函数


avformat_open_input 函数 使用 " 解复用器 " 打开 视频文件 , 该函数 在内部会调用 avformat_alloc_context 函数 用于为 AVFormatContext 结构体分配内存 ;


avformat_open_input 函数原型如下 :

int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);
  • 函数参数 :
    • AVFormatContext **ps : 指向 AVFormatContext 指针的指针 ;
    • const char *url : 输入流的地址或文件名 , 文件路径 或 网络流的 URL ;
    • AVInputFormat *fmt : 设置输入格式 , 一般都是 NULL , FFmpeg 自动选择输入格式 ;
    • AVDictionary **options : 附加参数 , 设置解码器 , 网络连接 等参数 ;
  • 函数返回值 : 关闭成功 返回 0 , 关闭失败 返回 负值错误码 ;

注意 : avformat_open_input 函数 要与 avformat_close_input 函数 成对使用 ;


4、avformat_close_input 函数


avformat_close_input 函数 用于 关闭 " 解复用器 " , 该函数 在内部会调用 avformat_free_context 函数 ;


avformat_close_input 函数原型如下 :

int avformat_close_input(AVFormatContext **ps);
  • 函数参数 : 其中的参数 ps 是 指向 AVFormatContext 指针的指针 ;
  • 函数返回值 : 关闭成功 返回 0 , 关闭失败 返回 负值错误码 ;

注意 : avformat_open_input 函数 要与 avformat_close_input 函数 成对使用 ;


5、avformat_find_stream_info 函数


avformat_find_stream_info 函数 用于获取 媒体流 信息 ;

一般情况下 , 调用 avformat_open_input 函数 就可以获取到 视频文件的 媒体流信息 ;

如果调用 avformat_open_input 函数 无法获取 媒体流信息 , 此时 需要 开发者 手动调用 avformat_find_stream_info 函数 用于获取媒体流信息 ;


函数原型如下 :

int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
  • 函数参数 :
    • AVFormatContext *ic : 指向 AVFormatContext 的指针 ;
    • AVDictionary **options : 可选附加参数 , 设置解码器 , 网络连接 等参数 ;
  • 函数返回值 : 关闭成功 返回 0 , 关闭失败 返回 负值错误码 ;

6、av_read_frame 函数


av_read_frame 函数 用于 读取 音视频流 中的 数据包 , 这是压缩后的数据 , 不能直接播放 , 需要经过解码后才能播放 ;

AAC 格式的 音频流 数据包 , 需要转为 PCM 格式 才能播放 ;

H.264 格式的 视频流 数据包 , 需要转为 YUV 或 RGB 格式 才能播放 ;


av_read_frame 函数 原型 :

int av_read_frame(AVFormatContext *s, AVPacket *pkt);
  • 函数参数 :
    • AVFormatContext *s : 指向 AVFormatContext 的指针 , 这是已经打开的 多媒体流 的格式上下文 ;
    • AVPacket *pkt : 指向 AVPacket 的指针 , 用于存储读取的 一帧 音视频数据 ;
  • 函数返回值 : 关闭成功 返回 0 , 关闭失败 返回 负值错误码 ;

7、avformat_seek_file 函数


avformat_seek_file 函数 参考 【FFmpeg】FFmpeg 函数简介 ② ( 封装格式相关函数解析 | 封装格式与解复用器 | avformat_alloc_context 函数 | avformat_open_input函数 ) 一、FFmpeg 音视频文件 封装格式相关函数 8、avformat_seek_file 函数 博客章节 ;


8、av_seek_frame 函数


av_seek_frame 函数 参考 【FFmpeg】FFmpeg 函数简介 ② ( 封装格式相关函数解析 | 封装格式与解复用器 | avformat_alloc_context 函数 | avformat_open_input函数 ) 一、FFmpeg 音视频文件 封装格式相关函数 9、av_seek_frame 函数 博客章节 ;


avformat_seek_file 函数 与 av_seek_frame 函数 对比 :

  • 跳转粒度 :
    • avformat_seek_file : 支持 视频文件 跨多个媒体流 定位跳转 到 指定时间戳 , 并且 可以控制最小、最大时间戳范围 ;
    • av_seek_frame : 跳转到 特定流 的 指定时间戳 ;
  • 跳转控制 :
    • avformat_seek_file : 可以 精细控制时间戳范围 , 设置最小时间戳和最大时间戳 ;
    • av_seek_frame : 跳转到关键帧 , 灵活性较低 ;
  • 常用场景 :
    • avformat_seek_file : 适用于 跨多个媒体流 的文件 的 精准跳转 ;
    • av_seek_frame : 适用于 单个媒体流操作 , 通常用于快速定位到 视频流、音频流 或 字幕流 的 关键帧 ;




三、查找码流标号和参数信息




1、码流标号


在 FFmpeg 中 , 每个 多媒体文件 可能 包含 多个多媒体流 , 如 : 视频流、音频流、字幕流 等 ;

这些 媒体流都 会 被分配 一个 唯一的索引号 来标识 , 称为 " Stream index " , 用于区分文件中的不同流 ;

上述 流索引号 可以称为 " 码流标号 " , 从 0 开始进行递增编号 , 其中 标号为 0 的码流 可能是 视频流 / 音频流 / 字幕流 ;


2、查找码流标号 - av_find_best_stream 函数


av_find_best_stream 函数 用于查找 媒体文件 中的 最佳流 ;

int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, int wanted_stream, int related_stream, AVCodec **decoder_ret, int flags);
  • 函数参数 :
    • AVFormatContext *ic : 指向已打开媒体文件的 AVFormatContext 结构体的指针 , 其中封装了 媒体信息 包括 流的数量 以及 每个流的详细信息 ;
    • enum AVMediaType type : 要查找的 媒体流的类型 , 可选的媒体流类型如下 :
      • AVMEDIA_TYPE_VIDEO : 视频流类型 ;
      • AVMEDIA_TYPE_AUDIO : 音频流类型 ;
      • AVMEDIA_TYPE_DATA : 数据流类型 ;
      • AVMEDIA_TYPE_SUBTITLE : 字幕流类型 ;
      • AVMEDIA_TYPE_UNKNOWN : 未知类型 ;
      • AVMEDIA_TYPE_ATTACHMENT : 附件类型 ;
    • int wanted_stream : 用户期望的流索引 , 默认设置 -1 ;
    • int related_stream : 与之相关的最佳流的索引 , 默认设置 -1 ;
    • AVCodec **decoder_ret : 指向找到的流的对应解码器 , 默认设置 NULL ;
    • int flags : 指定额外的查找选项 , 默认设置 0 ;
  • 函数返回值 : 查找成功返回流索引 , 查找失败返回 AVERROR_STREAM_NOT_FOUND 或 错误码 ;

查找视频流示例 :

int video_index = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0)

查找音频流示例 :

int audio_index = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0)

3、查找码流参数信息 - avformat_find_stream_info 函数


视频文件 在 播放前 , 必须要进行解码 , 解码的前提就是要知道 文件中的如下信息 :

  • 媒体流数量
  • 媒体流类型 : 视频流、音频流、字幕流 等 ;
  • 每个流的详细信息 : 编码格式、比特率、分辨率 等 ;

获取到这些信息后 , 都设置到 AVFormatContext 结构体中 ;


avformat_open_input 函数 在 打开 输入媒体文件 后 , 会读取 文件的头部信息 , 函数执行过程中会 初始化 AVFormatContext 结构体 , 并将读取到的文件流信息填充到该结构体中 ;


有些类型的文件 , 如 : FLV 文件 / H.264 文件 / 网络直播流 , 文件的 头部信息 中并没有完整的流信息 , 甚至就没有头部信息 ;

此时就需要 调用 avformat_find_stream_info 函数 , 获取每个媒体流的完整流信息 , 包括流的 编码参数、比特率、分辨率 等信息 ;

avformat_find_stream_info 函数 可以 在 信息缺失的情况下 , 通过分析 数据包 格式 , 探测并分析 流 的 缺失参数信息 ;


4、查找码流参数信息延迟分析


avformat_find_stream_info 函数会尝试读取足够的数据 , 来确定每个流的参数 , 如 : 编解码器、比特率、采样率 等 ;

读取数据 , 分析数据 , 然后获取流的参数信息 , 这个过程 需要花费一定的时间 , 这就会造成延迟 , 设置的 读取数据越多 , 造成的延迟越大 ;

开发者 通过 AVFormatContext 相关结构设置的一些参数 , 设置 avformat_find_stream_info 函数 读取数据的多少 ;





四、视频文件解封装示例



视频文件 封装在 文件容器中 , 将容器中的数据提取出来 , 就是解封装过程 ;

在本章节中 使用 MediaInfo 分析视频文件 提取视频文件的信息 , 之后在下一篇博客中自己编写代码提取视频文件中的数据 , 并在 输出日志 中展示出来 ;


1、使用 MediaInfo 分析视频文件


MediaInfo 软件 可 用于 提取 视频文件 的 技术信息和元数据 , 支持多种格式和编码 , 可以快速显示文件的详细信息 ;

下面我们使用 MediaInfo 软件 分析 mp4 格式的 视频文件 ;

MediaInfo 软件 默认显示的 文件内容细节是 Details - 0 级别 , 在 " 菜单栏 / 调试 " 选项中可以查看当前的 调试级别 ;

在这里插入图片描述

在 Details - 0 调试级别下 , 只能看到 文件的 容器格式 一般信息 , 有几个文件流 , 每个文件流都是什么格式的 , 具体的文件流的内容是无法看到的 ;

下图就是 mp4 文件的 Details - 0 调试级别 显示的文件的容器信息 , 很简略 ;

在这里插入图片描述


2、使用 MediaInfo 分析视频文件的每个字节的信息


在 " 菜单栏 / 调试 " 选项中 , 设置 调试级别为 Details - 10 级别 , 这样就可以分析文件中每个字节的信息 ;

在这里插入图片描述

此时再打开上个章节中的 mp4 文件 , 就会显示如下信息 , MediaInfo 会将文件的每个字节的数据都解析出来 , 同时将每个字节的含义也展出出来 ;

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/939635.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Nginx(Linux之Ubuntu)

1.1.什么是Nginx Nginx(发音为"engine x")是由俄罗斯开发者Igor Sysoev创建的一款轻量级、高性能的Web服务器。它首次发布于2004年,如今已成为全球最受欢迎的Web服务器之一。Nginx以其卓越的性能和灵活性而闻名,适用于…

使用Docker启用MySQL8.0.11

目录 一、Docker减小镜像大小的方式 1、基础镜像选择 2、减少镜像层数 3、清理无用文件和缓存 4、优化文件复制(COPY和ADD指令) 二、Docker镜像多阶段构建 1、什么是dockers镜像多阶段构建 1.1 概念介绍 1.2 构建过程和优势 2、怎样在Dockerfil…

【微信小程序开发 - 3】:项目组成介绍

文章目录 项目组成介绍项目的基本组成结构小程序页面的组成部分JSON配置文件的作用app.json文件project.config.json文件sitemap.json文件页面的 .json 配置文件新建小程序页面修改项目首页 XWML模板XWML 和 HTML 的区别 WXSS样式WXSS 和 CSS 的区别 .js文件 项目组成介绍 项目…

springboot的项目创建和常用注解

创建springboot项目&#xff1a; 首先更改一下url&#xff0c;点击小齿轮改成https://start.aliyun.com/ 首先在选模块的时候选上SpringWeb&#xff0c;然后jdk1.8对应的springboot版本是2.6.13或者2.7.6 pom.xml: 用1.8的jdk&#xff0c;mybatis的包版本不能太高 <!-- …

flask_socketio 以继承 Namespace方式实现一个网页聊天应用

点击进入上一篇&#xff0c;可作为参考 实验环境 python 用的是3.11.11 其他环境可以通过这种方式一键安装&#xff1a; pip install flask3.1.0 Flask-SocketIO5.4.1 gevent-websocket0.10.1 -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple pip list 详情如下&am…

笔记本重装系统教程【详细教程】

一、装机前说明 各位有装机需求的伙伴&#xff0c;请根据自己的电脑配置选择合适操作系统&#xff0c;可以实现自己装机的伙伴&#xff0c;相信大家这点可以确认好。 ———————————————————————— 我的配置&#xff1a; 我的电脑是联想拯救者lenovoY7000…

uniapp入门 01创建项目模版

0安装 hbuilder x 标准版 1.创建模版工程 2.创建官方 案例工程 index.uvuewen 文件解析 <!-- 模版 标签 --> <template><view></view></template><!-- 脚本 --> <script>export default {data() {return {}},onLoad() {},methods:…

ARCGIS国土超级工具集1.2更新说明

ARCGIS国土超级工具集V1.2版本&#xff0c;功能已增加至47 个。在V1.1的基础上修复了若干使用时发现的BUG&#xff0c;新增了"矢量分割工具"菜单&#xff0c;同时增加及更新了了若干功能&#xff0c;新工具使用说明如下&#xff1a; 一、勘测定界工具栏更新界址点成果…

Vue3源码笔记阅读1——Ref响应式原理

本专栏主要用于记录自己的阅读源码的过程,希望能够加深自己学习印象,也欢迎读者可以帮忙完善。接下来每一篇都会从定义、运用两个层面来进行解析 定义 运用 例子:模板中访问ref(1) <template><div>{{str}}</div> </template> <script> impo…

[react] 优雅解决typescript动态获取redux仓库的类型问题

store.getState()是可以获取总仓库的 先拿到函数的类型 再用ReturnType<T> 它是 TypeScript 中的一个内置条件类型&#xff0c;用于获取某个函数类型 T 的返回值类型 代码 // 先拿总仓库的函数类型type StatefuncType typeof store.getState;//再拿函数类型T的返回值类…

【Qt】QWidget中的常见属性及其功能(一)

目录 一、 enabled 例子&#xff1a; 二、geometry 例子&#xff1a; window fram 例子 &#xff1a; 四、windowTiltle 五、windowIcon 例子&#xff1a; qrc机制 创建qrc文件 例子&#xff1a; qt中的很多内置类都是继承自QWidget的&#xff0c;因此熟悉QWidget的…

R语言的字符串操作

【图书推荐】《R语言医学数据分析实践》-CSDN博客 《R语言医学数据分析实践 李丹 宋立桓 蔡伟祺 清华大学出版社9787302673484》【摘要 书评 试读】- 京东图书 (jd.com) R语言医学数据分析实践-R语言的数据结构-CSDN博客 在R语言中&#xff0c;字符串是一种表示文本数据的数…

webGL硬核知识:图形渲染管渲染流程,各个阶段对应的API调用方式

一、图形渲染管线基础流程概述 WebGL 的图形渲染管线大致可分为以下几个主要阶段&#xff0c;每个阶段都有其特定的任务&#xff0c;协同工作将 3D 场景中的物体最终转换为屏幕上呈现的 2D 图像&#xff1a; 顶点处理&#xff08;Vertex Processing&#xff09;阶段&#xff1…

《深入浅出Apache Spark》系列⑤:Spark SQL的表达式优化

导读&#xff1a;随着数据量的快速增长&#xff0c;传统的数据处理方法难以满足对计算速度、资源利用率以及查询响应时间的要求。为了应对这些挑战&#xff0c;Spark SQL 引入了多种优化技术&#xff0c;以提高查询效率&#xff0c;降低计算开销。本文从表达式层面探讨了 Spark…

创建项目以及本地仓库和远程仓库并上传项目

创建项目以及本地仓库和远程仓库并上传项目 其详细流程如下&#xff1a; 1、本地创建项目 2、创建本地仓库&#xff08;若使用idea在创建项目时选择了创建.git本地仓库&#xff0c;则此步骤省略&#xff09; 进入到你需要上传的项目的目录下&#xff0c;右键找到Git Bah He…

快速解决oracle 11g中exp无法导出空表的问题

在一些生产系统中&#xff0c;有些时候我们为了进行oracle数据库部分数据的备份和迁移&#xff0c;会使用exp进行数据的导出。但在实际导出的时候&#xff0c;我们发现导出的时候&#xff0c;发现很多空表未进行导出。今天我们给出一个快速解决该问题的办法。 一、问题复现 我…

MySQL八股-MVCC入门

文章目录 当前读&#xff08;加锁&#xff09;快照读&#xff08;不加锁&#xff09;MVCC隐藏字段undo-log版本链A. 第一步B.第二步C. 第三步 readview MVCC原理分析RCA. 先来看第一次快照读具体的读取过程&#xff1a;B. 再来看第二次快照读具体的读取过程: RR隔离级别 当前读…

【已解决】启动此实时调试器时未使用必需的安全权限。要调试该进程,必须以管理员身份运行此实时调试器。是否调试该进程?

【已解决】启动此实时调试器时未使用必需的安全权限。要调试该进程&#xff0c;必须以管理员身份运行此实时调试器。是否调试该进程? 目录一、前言二、具体原因三、解决方法 目录 报错截图 一、前言 进行应用程序开发时&#xff0c;需要对w3wp进行附加调试等场景&#xff…

基于Qt的登陆界面设计

目标 自由发挥登录界面的应用场景&#xff0c;实现一个登录窗口的界面。 要求&#xff1a;每行代码都要有注释 代码 // 设置窗口大小为600x400像素 this->resize(600,400); // 设置窗口标题为"TheWitcher 巫师3&#xff1a;狂猎" this->setWindowTitle(&qu…

Elasticsearch 8.x 集成与 Java API 使用指南

目录 背景 版本区别 安装elaticsearch8.x服务 启动es服务 安装es管理平台 项目集成 pom.xml文件引入依赖 application.yml配置 ES初始化配置类实现 ES8.x常用API实现 1.判断es索引是否存在 2.删除索引 3.创建索引 4.新增文档 5.更新文档 6.根据id查询文档 7.根…