音视频入门基础:FLV专题(8)——FFmpeg源码中,解码Tag header的实现

一、引言

在《音视频入门基础:FLV专题(7)——Tag header简介》中对Tag header进行了简介,本文讲述FFmpeg源码中是怎样解码Tag header,拿到里面的信息。

二、FFmpeg源码中,解码Tag header的实现

FFmpeg源码中使用flv_read_packet函数来读取每个Tag的信息。flv_read_packet函数的前半部分实现了解码Tag header的功能。该函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/flvdec.c中:

static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{FLVContext *flv = s->priv_data;int ret, i, size, flags;enum FlvTagType type;int stream_type=-1;int64_t next, pos, meta_pos;int64_t dts, pts = AV_NOPTS_VALUE;int av_uninit(channels);int av_uninit(sample_rate);AVStream *st    = NULL;int last = -1;int orig_size;int enhanced_flv = 0;uint32_t video_codec_id = 0;retry:/* pkt size is repeated at end. skip it */pos  = avio_tell(s->pb);type = (avio_r8(s->pb) & 0x1F);orig_size =size = avio_rb24(s->pb);flv->sum_flv_tag_size += size + 11LL;dts  = avio_rb24(s->pb);dts |= (unsigned)avio_r8(s->pb) << 24;av_log(s, AV_LOG_TRACE, "type:%d, size:%d, last:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, last, dts, avio_tell(s->pb));if (avio_feof(s->pb))return AVERROR_EOF;avio_skip(s->pb, 3); /* stream id, always 0 */flags = 0;//...if (size == 0) {ret = FFERROR_REDO;goto leave;}next = size + avio_tell(s->pb);if (type == FLV_TAG_TYPE_AUDIO) {//...} else if (type == FLV_TAG_TYPE_VIDEO) {//...}else if (type == FLV_TAG_TYPE_META) {//...}else{//...}//...return ret;
}

flv_read_packet函数中,首先获取Tag header的TagType属性,赋值给局部变量type。关于avio_r8函数的用法可以参考:《FFmpeg源码:avio_r8、avio_rl16、avio_rl24、avio_rl32、avio_rl64函数分析》。可以看到Tag header中的Filter属性并没有被保存到FFmpeg的内存中,所以FFmpeg源码内部是不会判断FLV文件是否被加密的:

    type = (avio_r8(s->pb) & 0x1F);

在FFmpeg源码中TagType属性对应的枚举成员有三个:FLV_TAG_TYPE_AUDIO、FLV_TAG_TYPE_VIDEO、FLV_TAG_TYPE_META。如果局部变量type的值为FLV_TAG_TYPE_AUDIO表示该Tag为音频Tag;如果值为FLV_TAG_TYPE_VIDEO表示是视频Tag;如果值为FLV_TAG_TYPE_META表示是脚本Tag:

enum FlvTagType {FLV_TAG_TYPE_AUDIO = 0x08,FLV_TAG_TYPE_VIDEO = 0x09,FLV_TAG_TYPE_META  = 0x12,
};

获取Tag header的DataSize属性,即该Tag以字节为单位的Tag data的长度,赋值给局部变量orig_size和size:

    orig_size =size = avio_rb24(s->pb);

从《音视频入门基础:FLV专题(7)——Tag header简介》可以知道,DataSize属性的值等于整个Tag的长度 - 11。所以让DataSize属性的值加上11就是整个Tag的长度。所以flv->sum_flv_tag_size为已被读取的各个Tag加起来的总长度,单位为字节:

    flv->sum_flv_tag_size += size + 11LL;

获取Tag header的Timestamp和TimestampExtended属性,合成1个4字节的解码时间戳,赋值给局部变量dts:

    dts  = avio_rb24(s->pb);dts |= (unsigned)avio_r8(s->pb) << 24;

如果已经读取到文件末尾,返回AVERROR_EOF。关于avio_feof函数用法可以参考:《FFmpeg源码:avio_feof函数分析》:

    if (avio_feof(s->pb))return AVERROR_EOF;

如果还没有读取到文件末尾,继续往下执行,跳过Tag header的StreamID属性。关于avio_skip函数用法可以参考:《FFmpeg源码:avio_skip函数分析》:

    avio_skip(s->pb, 3); /* stream id, always 0 */

avio_tell(s->pb)是当前读取到的位置相对于文件首的偏移,关于avio_tell函数用法可以参考:《FFmpeg源码:avio_tell函数分析》。这时候已经读取完了该Tag的Tag header了,而从前面我们可以知道,局部变量size存贮该Tag的Tag data的长度。所以size + avio_tell(s->pb)为该Tag对应的PreviousTagSize相对于文件首的偏移(单位为字节):

    next = size + avio_tell(s->pb);

根据该Tag为音频Tag,视频Tag还是脚本Tag,分别执行不同的解码操作:

    if (type == FLV_TAG_TYPE_AUDIO) {//...} else if (type == FLV_TAG_TYPE_VIDEO) {//...}else if (type == FLV_TAG_TYPE_META) {//...}else{//...}//...

三、总结

1.FFmpeg源码中通过flv_read_packet函数解码每个Tag的Tag header,根据Tag header的TagType属性来判断该Tag为音频Tag,视频Tag还是脚本Tag,分别执行不同的解码操作。

2.Tag header中的Filter属性并没有被保存到FFmpeg的内存中,FFmpeg源码内部是不会判断FLV文件是否被加密的。要想处理加密过的FLV文件,得改FFmpeg源码或者自己实现。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Node.js安装Express,Node.js支持Typescript以及Express支持Typescript的步骤

1. Node.js 安装Express 运行如下命令&#xff1a; $ mkdir express-demo $ cd express-demo$ npm install express $ npm install body-parser //(可选)中间件&#xff0c;用于处理 JSON, Raw, Text 和 URL 编码的数据 $ npm install cookie-parser //(可选)通过req.cookies…

如何使用ssm实现大学生校园招聘网的设计与实现

TOC ssm738大学生校园招聘网的设计与实现jsp 第1章 绪论 1.1 课题背景 二十一世纪互联网的出现&#xff0c;改变了几千年以来人们的生活&#xff0c;不仅仅是生活物资的丰富&#xff0c;还有精神层次的丰富。在互联网诞生之前&#xff0c;地域位置往往是人们思想上不可跨域…

网页WebRTC电话和软电话哪个好用?

关于WebRTC电话与软件电话哪个更好用&#xff0c;这实际上取决于多个因素&#xff0c;并没有一个绝对的答案。不过&#xff0c;我可以根据WebRTC技术的一些特点&#xff0c;以及与传统软件电话相比的优劣势&#xff0c;为你提供一个清晰的对比。 首先&#xff0c;让我们了解一下…

单细胞miloR分析(基于 KNN 图的细胞差异丰度分析方法)

通常情况下&#xff0c;对两组或多组样本进行了不同处理/干预之后&#xff0c;研究者首先会进行同种细胞亚群处理前后的细胞数量的比较&#xff0c;但在单细胞分辨率时代之后&#xff0c;即使是同一个亚群中的不同细胞也应当看成不同的样本。 那么问题就来了&#xff0c;既然应…

算法:按既定顺序创建目标数组

力扣1389 提示&#xff1a; 1 < nums.length, index.length < 100nums.length index.length0 < nums[i] < 1000 < index[i] < i 题解&#xff1a; class Solution {public int[] createTargetArray(int[] nums, int[] index) {int[] target new int[num…

SD2.0 Specification之CRC(Cyclic Redundancy Code)

文章目录 本文章主要讲解关于SD2.0中的CRC应用&#xff0c;其它基础概念和其它内容请参考以下文章。 SD2.0 Specification简述 CRC全称为Cyclic Redundancy Code&#xff0c;中文名称是循环冗余校验&#xff0c;该方法通过附加冗余数据来保证数据的完整性&#xff0c;即用于检…

RabbitMQ的高级特性-限流

消息分发: RabbitMQ队列拥有多个消费者时, 队列会把收到的消息分派给不同的消费者. 每条消息只会发送给订阅列表⾥的⼀个消费者. 这种⽅式⾮常适合扩展, 如果现在负载加重,那么只需要创建更多的消费者来消费处理消息即可. 默认情况下, RabbitMQ是以轮询的⽅法进⾏分发的, ⽽不管…

BetterAndBetter--Mac上强大的手势操控软件,让你的Mac更加得心应手

很多新人在开始使用Mac的时候&#xff0c;很难脱离鼠标操作&#xff0c;但是Mac的触摸板可以说是Mac的一大特色&#xff0c;能够完成非常多的操作&#xff0c;甚至在有些时候比鼠标更加的好用&#xff0c;那么新手该如何使用触摸板呢&#xff0c;BetterAndBetter可以帮助新手快…

Alternative Reconciliation Accounts 备选统驭科目

业务场景&#xff1a; #1 海外项目对于应付账款&#xff0c;超过1年期的需要转入到其他科目&#xff1b; #2. 通过备选统驭科目进行 从应付账款&#xff0c;到应付账款-长期的结转 备选统驭科目的使用与配置 备选统驭科目&#xff08;AlternativeReconciliation Accounts)就…

Dynamics 365 dependency EntityType

导解决方案时经常会碰到组件依赖导致导入报错&#xff0c;而错误提示中组件只有type, 比如下图中的type 20和60, 初看之下并不知道是什么意思&#xff0c;从parentDisplayName能看出来&#xff0c;这个parent是个实体&#xff0c;但实体中的什么呢&#xff0c;目测是看不出来的…

怎样用python+sqlalchemy获得mssql视图对应物理表关系(二)

话不多说 目标:为了实现低代码数据视图对接,有必要得到视图所对应物理表及字段名称,字段类型等 1)约束:视图中用到的物理表不能起别名,所以修改上一篇中存储过程建立语句 USE [agui_conn] GO /****** Object: StoredProcedure [dbo].[sp_GetOrdersByTimestamp] Script D…

生信机器学习入门4 - 构建决策树(Decision Tree)和随机森林(Random Forest)分类器

机器学习文章回顾 生信机器学习入门1 - 数据预处理与线性回归&#xff08;Linear regression&#xff09;预测 生信机器学习入门2 - 机器学习基本概念 生信机器学习入门3 - Scikit-Learn训练机器学习分类感知器 生信机器学习入门4 - scikit-learn训练逻辑回归&#xff08;L…

第五周做题总结_数据结构_队列与应用

id:43 A. DS队列之银行排队 题目描述 银行营业大厅共服务3种客户&#xff0c;类型为A\B\C&#xff0c;大厅分别设置了3个窗口分别服务三种客户&#xff0c;即每个窗口只服务一种客户。现有一批客户来银行办理业务&#xff0c;每个客户都有类型和办理业务时间。每个窗口按照客…

Servlet详细讲解(一篇就够)

目录 一、Servlet 1.1 Servlet介绍 1.2 HTTP 1.2.1 在http请求中有请求报文 1.2.2 在http响应中有响应报文 1.3 GET和POST 1.3.1 GET 1.3.2 POST 二、第一个Servlet程序[重点] 2.1 创建web项目 2.2 pom依赖 2.3 编写Servlet 2.4 配置Servlet 2.5 部署项目 2.6 启…

C++进阶知识2 多态

多态 1. 多态的概念2. 多态的定义及实现2.1 多态的构成条件2.1.2 虚函数2.1.3 虚函数的重写/覆盖2.1.5 虚函数重写的⼀些其他问题2.1.6 override和final关键字2.1.7 重载/重写/隐藏的对⽐ 3. 多态的原理3.2 多态的原理3.2.1 多态是如何实现的3.2.2 动态绑定与静态绑定3.2.3 虚函…

PL/SOL 连接提示 Initialization error 解决方法

问题 测试连接数据库报错&#xff0c;提示如下 解决方法 1、OCI 库输入的时候&#xff0c;路径两遍有" " 2、Instant Client 和 PL/SOL Developer 位数版本不一致 要么都是x64位&#xff0c;要么都是x86位&#xff08;32位&#xff09;&#xff0c;以下为下载链接…

算力运力解决方案:构建未来智算新生态

中国联通国际有限公司产品之算力运力解决方案&#xff1a;构建未来智算新生态 在当今这个数据爆炸、技术日新月异的时代&#xff0c;算力已成为推动社会进步和产业升级的关键力量。中国联通国际有限公司紧跟时代步伐&#xff0c;依托其强大的网络资源和深厚的技术积累&#xf…

63.5 注意力提示_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录注意力提示生物学中的注意力提示查询、键和值注意力的可视化使用 show_heatmaps 显示注意力权重代码示例 代码解析结果 小结练习 注意力提示 &#x1f3f7;sec_attention-cues 感谢读者对本书的关注&#xff0c;因为读者的注意力是一种稀缺…

此连接非私人连接

当你手机浏览器输入网站打开提示“此连接非私人连接&#xff0c;此网站可能在冒充来窃取你的个人或财务信息。你应回到之前的页面”这是因为该网站的SSL数字证书到期导致&#xff0c;需要此网站的管理员重新申请数字证书替换之前的文件才可以实现。 注意&#xff1a;如果你不是…

java 洛谷题单【数据结构1-1】线性表

P3156 【深基15.例1】询问学号 解题思路 很简单的一道题&#xff0c;但是由于n、m的数据很大&#xff0c;要用Java的I/O流读入和输出。 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.StreamTokenizer; impo…