FLV流媒体封装格式

1、FLV 简介


FLV(Flash Video) 是 Adobe 公司推出的一种流媒体格式,由于其封装后的音视频文件体积小、封装简单等特点,非常适合于互联网上使用。目前主流的视频网站基本都支持FLV。采用 FLV 格式封装的文件后缀为.flv。直播场景下拉流比较常见的是 http-flv 直播流,具有延时低,易传输等特点。

------------------------

2、FLV 格式


总体上看,FLV 由文件头(file header)和(file body)组成,其中 FLV body 由一对对的 Tag 和 Previous Tag Size(占用4个字节,记录前一个 Tag 的大小,用于逆向读取处理,FLV header 后的第一个 Previous Tag Size 为 0)组成。而 Tag 一般分为三种类型:脚本数据、视频数据、音频数据,有 Tag header 和 Tag Data 组成。FLV 数据以大端序进行存储,在解析时需要注意。一个标准 FLV 文件结构如下图:

FLV 文件的详细内容结构如下:

---------------------------

2.1 FLV header(文件头)

从上图中可以看到,FLV 头占用 9 个字节,用来标识文件类型为 FLV 类型,以及后续的音视频标识。一个 FLV 文件,每种类型的 tag 都属于一个流,也就是一个 flv 文件最多只有一个音频流,一个视频流,不存在多个独立的音视频流在一个文件的情况。FLV 头的结构如下:

上面的 UI 表示无符号整型,后面跟着的数字代表其长度是多少位;UB 表示位域,表示一个字节的多少位。可以参考C语言中的结构体位域。

------------------------------------

2.2 FLV Body(文件体)


FLV Header之后,就是 FLV File Body。FLV File Body 是由一连串的 back-pointers + tags 构成。

back-pointer
back-pointer 表示 Previous Tag Size(前一个 tag 的字节数据长度),占4个字节,
第一个 back-pointer 数据为0。Tag
音视频数据,每一个 tag 由两部分组成:tag header 和 tag data。

----------------------------------------

3、FLV Tag 详解

3.1 Tag 数据结构

flv_tag_header + flv_tag_data,其中 flv_tag_header 占 11 个字节。

3.2 FLV_tag_header

存放当前 tag 的类型、数据区长度、时间戳等信息。tag header 一般占 11 个字节的内粗空间。

3.3 FLV_Tag_Data

FLV Tag 的类型可以是视频、音频和 Script(脚本类型)

3.3.1 Script Tag Data(脚本类型、帧类型)

脚本 Tag 一般只有一个,是 flv 的第一个 Tag,跟在 flv header 后,用于存放 flv 视频和音频的元信息,比如 duration、audiodatarate、creator、width 等。一般来说,Script Tag Data结构包含两个 AMF 包(AMF(Action Message Format)是 Adobe 设计的一种通用数据封装格式,在 Adobe 的很多产品中应用,简单来说,AMF 将不同类型的数据用统一的格式来描述),结构如下:

第一个 AMF 包(封装字符串类型数据):

第 1 个字节表示 AMF 包类型,一般总是 0x02,表示字符串; 第 2-3 个字节为 UI16 类型值,表示字符串的长度,一般总是 0x000A(“onMetaData”长度); 后面字节为字符串数据,一般总为 “onMetaData”(6F,6E,4D,65,74,61,44,61,74,61)。

---------------------------------------

第二个 AMF 包(封装一个数组类型,这个数组中包含了音视频信息项的名称和值):

第 1 个字节表示 AMF 包类型,一般总是 0x08,表示数组。 第 2-5 个字节为 UI32 类型值,表示数组元素的个数。 后面即为各数组元素的封装,数组元素为元素名称和值组成的对。表示方法如下: 第 1-2 个字节表示元素名称的长度,假设为 L。后面跟着为长度为 L 的字符串。第 L+3 个字节表示元素值的类型。后面跟着为对应值,占用字节数取决于值的类型。

常见的数组元素表示如下表:

=======================

3.3.2 Video Tag Data(视频类型)


视频 Tag Data 开始的第一个字节包含视频数据的参数信息,从第二个字节开始为视频流数据。结构如下:

第一个字节包含视频信息:前4位表示帧类型;后4位表示编码类型。

第二个字节开始为视频数据

AVC VIDEO PACKET

视频的格式(CodecID)是 AVC(H.264)的话,VideoTagHeader 会多出 4 个字节的信息,AVCPacketType 和 CompositionTime,所以是 H264 编码的情况下 VideoHeader 长度是 5 个字节。 AVC VIDEO PACKET 结构如下:

AVCDecoderConfigurationRecord

包含着 H.264 解码相关比较重要的 sps 和 pps 信息,再给 AVC 解码器送数据流之前一定要把 sps 和 pps 信息送出,否则的话解码器不能正常解码。 而且在解码器 stop 之后再次 start 之前,如 seek、快进快退状态切换等,都需要重新送一遍 sps 和 pps 的信息。 AVCDecoderConfigurationRecord 在 FLV 文件中一般情况也是出现 1 次,也就是第一个 video tag。

sps pps

第一个 video tag 一般存放的是 sps 和 pps。存储的格式: 0x01 + sps[1] + sps[2] + sps[3] + 0xFF + 0xE1 + sps size + sps + 01 + pps size + pps 其中 sps size 和 pps siz e各占两个字节。 data 数据结构:

关于 CTS:需要和 pts,dts 配合一起理解。 pts:presentation time stamps 显示时间,也就是接收方在显示器显示这帧的时间。单位为1/90000 秒; dts:decoder timestamps 解码时间,也就是rtp包中传输的时间戳,表明解码的顺序。单位为1/90000 秒。——根据后面的理解,pts 就是标准中的 CompositionTime; cts偏移:cts = (pts - dts) / 90。cts 的单位是毫秒; pts 和 dts 的时间不一样,应该只出现在含有 B 帧的情况下,也就是 profile main 以上。baseline 是没有这个问题的,baseline 的 pts 和 dts 一直相同,所以 cts 一直为 0 。

=================================

3.3.3 Audio Tag Data(音频类型)

音频 Tag Data 区域开始的第一个字节包含了音频数据的参数信息,从第二个字节开始为音频流数据。结构如下:

第一个字节包含音频信息:前 4bit 表示音频格式;第 5、6bit 表示采样率;第 7bit 表示采样精度;第 8bit 表示音频声道。

第二个字节开始为音频数据

其中如果音频格式为 10,即是 AAC 格式的,AudioTagHeader 中会多出一个字节 AACPacketType,这个字段来表示 AACAUDIODATA 的类型:0 = AAC sequence header,1 = AAC raw。

AAC sequence header 也就是包含了 AudioSpecificConfig,AudioSpecificConfig 包含着一些更加详细音频的信息。

AAC raw 这种包含的就是音频 ES 流了,也就是 audio payload。

12 00 01 17 00 00 00 00 00 00 00 (tag header 11 字节)

0x12 表示这是一个 scripts tag, 00 01 17 三子节表示 tag data 长度为 279 个字节,Timestreamp、TimestampExtended、stream id 均为0。 下一个 back-pointers,表示该 scripts tag 的 size,即 279 + 11 = 290 = 0x122,即 00 00 01 22,可以看到最后4字节刚好是的。

02 00 0a 6f 6e 4d 65 74 61 44 61 74 61 表示第一个 AMF 包,02 表示类型为 string type,后面两个字节 00 0A 表示长度是 10,值 onMetaData; 03 表示 ObjectType,此处应该一般是 08 才对,表示数组类型;表示有8个键值对。 00 05 表示键长度,77 69 64 74 68 表示 width,00 表示类型为 Number,后面 8 字节表示值; 00 06 表示键长度, 68 65 69 67 68 74 表示 height,00 表示类型为 Number,后面 8 字节表示值。 以此类推解析到最后 end marker 00 00 09,表示解析完毕。

4、举例子
根据真实数据来解析 FLV 格式。

4.1 FLV header
<464c5601 05000000 09000000 00120001 17000000 00000000 02000a6f 
6e4d6574 61446174 61030005 77696474 68004084 00000000 00000006 
68656967 68740040 7e000000 00000000 0c736f75 7263655f 77696474 
6800409e 00000000 0000000d 736f7572 63655f68 65696768 74004090 
e0000000 00000009 6672616d 65726174 6500402e 00000000 0000000c 
76696465 6f636f64 65636964 00401c00 00000000 00000f61 7564696f 
73616d70 6c657261 74650040 bf400000 00000000 0f617564 696f7361 
6d706c65 73697a65 00403000 00000000 00000673 74657265 6f010000 
0c617564 696f636f 64656369 64004024 00000000 0000000c 63726561 
74696f6e 64617465 02001732 3032312d 31312d30 33203037 3a32373a 
33302055 54430006 61757468 6f720200 034c4c4c 00000900 000122>
46 4C 56 01 05 00 00 00 09:表示 FLV header(9 字节),音视频都有; 0x 00 00 00 00 表示第一个 back-pointers(前一个 tag 的 size)。因为前面没有 tag,所以为 0。

4.2 脚本 Tag
12 00 01 17 00 00 00 00 00 00 00 (tag header 11 字节) 0x12 表示这是一个 scripts tag, 00 01 17 三子节表示 tag data 长度为 279 个字节,Timestreamp、TimestampExtended、stream id 均为0。 下一个 back-pointers,表示该 scripts tag 的 size,即 279 + 11 = 290 = 0x122,即 00 00 01 22,可以看到最后4字节刚好是的。 02 00 0a 6f 6e 4d 65 74 61 44 61 74 61 表示第一个 AMF 包,02 表示类型为 string type,后面两个字节 00 0A 表示长度是 10,值 onMetaData; 03 表示 ObjectType,此处应该一般是 08 才对,表示数组类型;表示有8个键值对。 00 05 表示键长度,77 69 64 74 68 表示 width,00 表示类型为 Number,后面 8 字节表示值; 00 06 表示键长度, 68 65 69 67 68 74 表示 height,00 表示类型为 Number,后面 8 字节表示值。 以此类推解析到最后 end marker 00 00 09,表示解析完毕。

4.3 第一个 video tag
一般包含 sps、pps

<09000022 00000000 00000017 00000000 014d401e ffe1000e 674d401e 
a680a03d a6e02020 20400100 0468ee3c 80000000 2d>
09 00 00 22 00 00 00 00 00(tag header 11 字节) 09 表示视频 tag; 00 00 22 表示长度为 0x22 = 34,加上头部长度 11 字节,为 45。下一个 back-pointers 是 00 00 00 2D(上面数据的最后的四字节), Timestreamp、TimestampExtended、stream id 均为 0; 下面就是 tag data 数据: 0x17 即 0001 0111,前 4 位表示帧类型,1 为关键帧;后 4 位表示编码 ID,7 表示 AVC。 视频格式是AVC(H.264)类型的话,后面 1 个字节表示 AVCPacketType,再后三个字节表示 CompositionTime: 00 AVCPacketType 为 0,表示是 AVCDecoderConfigurationRecord。就表示包含着 sps 和 pps 了。这个东西要第一个发给解码器,要不然不能正常解码。 00 00 00 CompositionTime 为 0。接下来就是 sps 和 pps 的信息了。 按照 0x01 + sps[1] + sps[2] + sps[3] + 0xFF + 0xE1 + sps size + sps + 01 + pps size + pps 的格式,参照二进制数据: sps[1] = 4d;sps[2] = 40;sps[3] = 1e;sps size = 000e,表示 sps 的长度为 14,14 字节的数据读取完,读到 01;pps size = 0004,表示 pps 的长度为 4,读取完后该 tag 结束。下一个back-pointers。

4.4 第二个 video tag 以及后续的 video tag

<09002374 00000000 00000017 01000000 0000236b 65b82129 7f7ae073 
74574ffe 0fd1ebcc 6851014a d25aa986 6daee3a1 6f0d7b77 734e17a9 
0fe00e56 a92b864b 3d423839 c229a2ab 23208467 ... ...00 00237f>
下一个 video 长度为 9076 的视频数据,0x17 后一位 AVCPacketType 01,表示 NALU 数据,三个 CompositionTime 字节过后,就是 NALU 数据了。

4.5 第一个 audio tag 以及后续的 audio tag

<08000004 00005d00 000000ae 00158800 00000f>

08 00 00 04         00 00 5d 00       00 00 00ae

0x08 表示音频;

00 00 04 表示长度为 4,时间戳为 93;

加上头部长度 11,为 15,下一个 back-pointers 是 0x 00 00 00 0F(最后四子节);接下来就是 tag data: AE: 即 0b10101110,前 4 位为 10,表示音频格式是 AAC;10 会多一个字节 AACPacketType,表示该 AACAUDIODATA 的类型;第 5、6 位为 11,十进制 3,表示采样率为 44kHz;第 7 位为1,表示 16 位采样精度;第 8 位为 0,表示 sndMono 单声道。 00: 表示 AACPacketType,为 0 表示该 Tag 是 AAC sequence header。接下来两个字节表示 AudioSpecificConfig,包含更加详细音频的信息。读取完后该 tag 结束。下一个 back-pointers。

4.6 第二个 audio tag 以及后续的 audio tag

<080002fb 00005d00 000000ae 01010e34 14564a2d 92154484 d0602e72 
f7cab6d6 af82156c cae24cba a6f8d2b9 d2d512d3 db8b5632 ef76c8a9 
95225c3b 69e84d7d 03a6fa66 7b475759 0ead71f5 37c73379 fd124cd5 
1ba64d95 48d7aa3b c558863e 090fc9ae ... ...0000 0306>
下一个长度为 752 的音频数据,时间戳为 93,0xae 后一位为 01,表示 ACC raw,即音频 NALU

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

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

相关文章

计算机网络:现代通信的基石

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

小白了解Pinia第2集 · 三大核心状态Getters、Actions以及Plugins 插件

三大核心状态 state 第1集有详细讲解&#xff1a;https://blog.csdn.net/qq_51463650/article/details/137137080?spm1001.2014.3001.5501 getters Getter 完全等同于 Store 状态的 计算值。 它们可以用 defineStore() 中的 getters 属性定义。 他们接收“状态”作为第一个…

Elastic 8.13:Elastic AI 助手中 Amazon Bedrock 的正式发布 (GA) 用于可观测性

作者&#xff1a;来自 Elastic Brian Bergholm 今天&#xff0c;我们很高兴地宣布 Elastic 8.13 的正式发布。 有什么新特性&#xff1f; 8.13 版本的三个最重要的组件包括 Elastic AI 助手中 Amazon Bedrock 支持的正式发布 (general availability - GA)&#xff0c;新的向量…

汽车电子行业知识:什么是智能驾驶辅助系统(ADAS)

文章目录 1. 什么是智能驾驶辅助系统&#xff08;ADAS&#xff09;1.1 ADAS的功能1.2 ADAS的优势1.3 未来发展趋势 2. ADAS等级2.1. 0级驾驶辅助2.2. 1级驾驶辅助2.3. 2级驾驶辅助2.4. 3级驾驶辅助2.5. 4级和5级驾驶辅助 3. 智能车4. ADAS供应商 1. 什么是智能驾驶辅助系统&…

文章分享:协和文章《病原宏基因组高通量测序性能确认方案》

摘要&#xff1a;宏基因组学利用新一代高通量测序技术&#xff0c;以特定环境下病原体基因组为研究对象&#xff0c;在分析病原体多样性、种群结构、进化关系的基础上&#xff0c;进一步探究病原体的群体功能活性、相互作用及其与环境之间的关系&#xff0c;发掘潜在的生物学意…

STM32之HAL开发——串口配置(CubeMX)

串口引脚初始化&#xff08;CubeMX&#xff09; 选择RCC时钟来源 选择时钟频率&#xff0c;配置为最高频率72MHZ 将单片机调试模式打开 SW模式 选择窗口一配置为异步通信模式 点击IO口设置页面&#xff0c;可以看到当前使用的串口一的引脚。如果想使用复用功能&#xff0c;只需…

每天五分钟深度学习:使用神经网络完成人脸的特征点检测

本文重点 我们上一节课程中学习了如何利用神经网络对图片中的对象进行定位,也就是通过输出四个参数值bx、by、bℎ和bw给出图片中对象的边界框。 本节课程我们学习特征点的检测,神经网络可以通过输出图片中对象的特征点的(x,y)坐标来实现对目标特征的识别,我们看几个例子。…

前端发版上线出现白屏问题

目录 路由配置问题资源缓存问题首屏加载过慢 &#xff1a;喂&#xff0c;你的页面白啦&#xff01; 出现上线白屏的问题有很多&#xff0c;如&#xff1a;配置错误、缓存问题、浏览器兼容问题&#xff0c;根据不同情况去解决。 路由配置问题 问题描述&#xff1a; 在vue开发…

C语言中的联合体和枚举

联合体 联合体的创建 联合体的关键字是union union S {char a;int i; };除了关键字和结构体不一样之外&#xff0c;联合体的创建语法形式和结构体的很相似&#xff0c;如果不熟悉结构体的创建&#xff0c;可以看一下我上一篇的博客关于结构体知识的详解。 联合体的特点 联合…

HarmonyOS 应用开发之进程模型

系统的进程模型如下图所示。 应用中&#xff08;同一Bundle名称&#xff09;的所有UIAbility、ServiceExtensionAbility和DataShareExtensionAbility均是运行在同一个独立进程&#xff08;主进程&#xff09;中&#xff0c;如下图中绿色部分的“Main Process”。应用中&#x…

matlab及其在数字信号处理中的应用001:软件下载及安装

目录 一&#xff0c;matlab的概述 matlab是什么 matlab适用于的问题 matlab的易扩展性 二&#xff0c;matlab的安装 1&#xff0c;解压所有压缩文件 2&#xff0c;解压镜像压缩文件 3&#xff0c;运行setup.exe 4&#xff0c;开始安装 5&#xff0c;不要运行软件…

Python环境下基于深度学习的旋转机械故障诊断及其权重可视化

随着神经网络所要完成的任务越来越智能化&#xff0c;其内部的结构也变得越来越复杂&#xff0c;神经网络学到的解题方法也越来越难以被人类所理解。神经网络的内部单元就好比一个“黑箱”&#xff0c;虽然这种处理方法能够在某种程度上达到非常不错的效果&#xff0c;但其原因…

同城外卖多商户点餐系统平台开发JAVA版源码跑腿小程序APP

项目背景 在快节奏的现代生活中&#xff0c;人们对于时间的需求愈发敏感。如何在忙碌中兼顾生活与工作&#xff0c;如何在繁杂琐事中找到一丝便利&#xff0c;这已然成为众多都市人共同关心的议题。在这样的背景下&#xff0c;同城外卖跑腿系统软件应运而生&#xff0c;以其高…

Modbus转Profinet网关快速解决PLC插槽数量不够用的烦恼

通过Modbus转Profinet&#xff08;XD-MDPN100&#xff09;网关的应用&#xff0c;不仅可以实现Modbus设备与Profinet网络的平滑对接&#xff0c;还能有效解决PLC插槽限制和Modbus指令轮询等问题&#xff0c;Modbus转Profinet网关&#xff08;XD-MDPN100&#xff09;在解决PLC插…

Etcd 基本入门

1&#xff1a;什么是 Etcd ? Etcd 是 CoreOS 团队于2013年6月发起的开源项目&#xff0c;它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法&#xff0c;Etcd基于 Go 语言实现。 名字由来&#xff0c;它源于两个方面&#xff0c;…

java将文件转成流文件返回给前端

环境&#xff1a;jdk1.8&#xff0c;springboot2.5.3,项目端口号&#xff1a;9100 1.待转换的文件 一、路径 二、文件内容 2.controller中代码 package com.example.pdf.controller;import com.example.pdf.service.GetFileStreamService; import org.springframework.web.b…

嵌入式linux学习之交叉编译器安装

交叉编译器介绍 ARM 裸机、Uboot 移植、Linux 移植这些都需要在 Ubuntu 下进行编译&#xff0c;编译就需要编译器&#xff0c;在 Liux 进行 C 语言开发里面使用 GCC 编译器进行代码编译&#xff0c;但是 Ubuntu 自带的 gcc 编译器是针对 X86 架构的&#xff01;而我们现在要编…

封装性练习

练习 1 &#xff1a; 创建程序&#xff1a;在其中定义两个类&#xff1a; Person 和 PersonTest 类。定义如下&#xff1a; 用 setAge() 设置人的合法年龄 (0~130) &#xff0c;用 getAge() 返回人的年龄。在 PersonTest 类中实例化 Person 类的对象 b &#xff0c;调用 set…

需要本地后端的真机调试-微信

打开和修改IP改为电脑与手机同一局域网的 不知道这个要不要

利用计算机视觉技术打造直播美颜工具:详解美颜SDK开发

本篇文章&#xff0c;小编将详解如何利用计算机视觉技术打造直播美颜工具&#xff0c;并深入探讨美颜SDK的开发过程。 一、美颜技术概述 在直播美颜工具中&#xff0c;美颜技术起到了至关重要的作用。美颜技术通过对图像进行实时处理&#xff0c;改善主播或用户的外观&#x…