大家好,又见面了,我是你们的朋友全栈君。
写在前面
2019.06.18
第三章 FFmpeg转封装
第三章 FFmpeg转封装
一、MP4格式标准
MP4文件由许多个Box与FullBox组成;每个Box由Header和Data两部分组成。 FullBox是Box的扩展,其在Box结构的基础上,在Header中增加8位version标志和24为flags标志; Header包含了整个Box的长度的大小(size)和类型(type):size=0,代表这个Box是文件的最后一个Box; size=1,说明Box的长度需要更多的位来描述,在后面会定义一个64位的largesize用来描述Box的长度; type=uuid,说明这个Box中的数据是用户自定义扩展类型 Data为Box的实际数据,可以是纯数据,也可以是更多的子Box; 当一个Box中Data是一系列的子Box时。这个Box又可以成为 Container Box
MP4中Box的组成 (书 P61-63)
主要信息:
Note:尺寸、类型、版本、标志 这四个字段都有
(1)moov:一级 音视频数据的metadata信息
mdat :一级 media数据容器 moov与mdat的存放位置没有强制要求; 互联网视频点播中,moov在前时,文件可以被快速打开; moov在后时,需要将MP4文件下载完成后才可以进行播放
(2)moov容器
moov容器定义了一个MP4文件中的数据信息,类型是moov,是一个容器Atom,其至少必须包含以下三种Atom中的一种:
mvhd标签,Movie Header Atom,存放未压缩过的影片信息的头容器 cmov标签,Compressed Movie Atom,压缩过的电影信息容器(不常用) rmra标签,Reference Movie Atom, 参考电影信息容器(不常用)
还可以包含其他的标签 (书 P64) mvhd中定义了多媒体文件的time scale、duration以及display characteristics; trak 二级 流的track,定义了多媒体文件中的一个track的信息,track是多媒体文件中可以独立操作的媒体单位,例如一个音频流或一个视频流就是一个track
(3)解析mvhd子容器
参数列表 (书 P66) 解析出视频的基本信息,包括尺寸、类型、时长、速度、音量等
(4)解析trak子容器
trak容器中定义了媒体文件中的一个track的信息,每个trak容器都有与它关联的media容器描述信息。 trak容器的主要使用目的:
包含媒体数据的引用和描述(media track) 包含modifier track 信息 流媒体协议的打包信息(hint track),hint track可以引用或者复制对应的媒体采样数据
hint track和modifier track必须保证完整性,同时要与至少一个media track一起存在。 一个trak容器中要求必须要有一个Track Header Atom(tkhd)、一个Media Atom(mdia),其他Atom可选
(5)解析tkhd容器
解析出track的尺寸、类型、ID、市场、音量等。音频与视频的trak的tkhd的大小相同,里面的内容随着音视频trak类型的不同而有所不同。
(6)解析mdia容器
Media Atom的类型是mdia,其必须包含如下容器:
一个媒体头:Media Header Atom(mdhd) 一个句柄参考:Handler Reference(hdlr) 一个媒体信息:Media Information(minf)和用户数据User Data Atom(udta)
(7)解析mdhd容器
mdhd容器被包含在各个track中,描述Media的Header,包含信息表格 P71:描述尺寸、类型、版本、生成和修订事件等。
Note:音频时长可通过Duration / TimeScale的方式来计算。
(8)解析hdlr容器
hdlr容器中描述了媒体流的播放过程,包含内容有:尺寸、类型、版本、标志、Handle的类型、Handle的子类行、保留、Component name
(9)解析minf容器
minf容器中包含了很多重要的子容器,例如音视频采样等信息相关的容器 minf容器中的信息将作为音视频数据的映射存在,内容具体如下:
视频信息头:Video Media Information Header(vmhd子容器) 音频信息头:Sound Media Information Header(smhd子容器) 数据信息:Data Information(dinf子容器) 采样表: Sample Table(stbl子容器)
(10)解析vmhd容器
图形模式:传输模式,传输模式指定的布尔值 Opcolor:颜色值,RGB颜色值
(11)解析smhd容器
均衡:音频的均衡是用来控制计算机的两个扬声器的声音混合效果,一般是0
(12)解析dinf容器
dinf容器是一个用于描述数据信息的容器,其定义的是音视频数据的信息
(13)解析stbl容器
stbl容器又称为采样参数列表的容器(Sample Table Atom),该容器包含转化媒体时间到实际的sample的信息,也说明了解释sample的信息,例如,视频数据是否需要解压缩、解压缩算法是什么 等信息。
其包含的子容器具体如下:
采样的描述、时间、同步、大小,Chunk采样、偏移等
stbl包含track中media sample的所有时间和数据索引,利用sample信息,就可以定位sample的媒体时间,决定其类型、大小,以及如何在其他容器中找到紧邻的sample
(14)解析edts容器
edts容器定义了创建Movie媒体文件中一个track的一部分媒体,所有的edts数据都在一个表里,包括每一部分的时间偏移量和长度。
一个空的edts数据用来定位到track的起始时间偏移位置。
MP4分析工具:分析MP4封装格式的工具
FFmpeg、Elecard StreamEye、mp4box、mp4info等
Elecard StreamEye
视频信息查看工具,能查看帧的排列信息,将I P B帧以不同颜色的柱状展示出来,柱的长度根据帧的大小显示;还可以分析MP4的封装内容,包括流的信息、宏块的信息、文件头信息、图像信息以及文件的信息等;还可以逐帧查看每一帧的详细信息和状态
mp4box
GPAC项目中的一个组件;针对媒体文件进行合成、拆解等操作
mp4info
可视化分析工具,将MP4文件的各Box解析出来并展示数据
MP4在FFmpeg中的Demuxer
代码语言:javascript复制ffmpeg -h demuxer=mp4
默认开启:
seek_streams_individually 根据单独的流进行seek
默认不开启:
user_absolute_path 可以通过绝对路径加载外部的track,可能有安全因素影响 ignore_editlist 忽略EditList Atom信息 ignore_chapters 忽略Chapters信息 enable_drefs 外部track支持
MP4在FFmpeg中的Muxer (参数 书P80)
1.faststart参数
正常情况下ffmpeg生成moov是在mdat写完成之后再写入,可以通过faststart将moov容器移动值mdat的前面(如前文所说,moov在前面,视频可以边下边播)
代码语言:javascript复制ffmpeg -i input.flv -c copy -f mp4 -movflags faststart output.mp4
2.dash参数
代码语言:javascript复制知识点:DASH介绍
DASH是一种服务端、客户端的流媒体解决方案
服务端:
将视频内容分割为一个个分片,每个分片可以存在不同的编码形式(不同的codec、profile、分辨率、码率等);
播放器端:
就可以根据自由选择需要播放的媒体分片;可以实现adaptive bitrate streaming技术。不同画质内容无缝切换,提供更好的播放体验。
DASH简介及使用方法(FFmpeg, MP4Box)
代码语言:javascript复制ffmpeg -i input.flv -c copy -f mp4 -moveflags dash output.mp4
3.isml参数
ISMV为微软发布的一个流媒体格式,通过参数isml可以发布ISML直播流,将ISMV推流至IIS服务器
代码语言:javascript复制ffmpeg -i input.mp4 -c copy -moveflags isml frag_keyframe -f ismv Stream
二、FLV格式标准
FLV文件分两部分,一部分为FLV头文件,另一部分为FLV文件内容
1.FLV文件头格式解析(字段 书P84)
签名字段用了三个字节,组成“FLV”;然后是版本、音频标记类型、视频标记类型、数据偏移
2.FLV文件内容格式解析
内容格式为上一个Tag大小 FLAGTAG,FLAGTAG分为两部分:TAGHeader部分和TAGBody部分
3.FLVTAG格式解析
头部:保留字段、滤镜位、TAG类型、数据大小占用、时间戳及扩展时间戳、流ID; 之后是Tag的data。
存储的数据分为视频数据、音频数据及脚本数据
4.VideoTag数据解析
header中读取到的Tag类型为0x09
帧类型、编码标识(CodecID)、H264的包类型(AVCPackerType)、CTS、视频数据
代码语言:javascript复制知识点:
PTS:Presentation Time Stamp。PTS主要用于度量解码后的视频帧什么时候被显示出来
DTS:Decode Time Stamp。DTS主要是标识读入内存中的bit流在什么时候开始送入解码器中进行解码。
在没有B帧存在的情况下DTS的顺序和PTS的顺序应该是一样的。
I,P,B帧和PTS,DTS的关系
5.AudioTag数据格式解析
header中读取到的Tag类型为0x08
声音格式(AAC、MP3、Speex等)、音频采样率(Hz)、采样大小(8或16位)、音频类型(Mono/Stereo sound)、音频包类型、音频数据
6.ScriptData格式解析
header中读取到的Tag类型为0x12 ScriptData常见的展现方式是FLV的Metadata,里面存储的数据格式一般为AMF数据 类型、数据
代码语言:javascript复制知识点:
AMF是Action Message Format协议的简称,AMF协议是Adobe公司自己的协议,主要用于数据交互和远程过程调用,
在功能上相当于WebService,但是AMF与 WebService中的XML不同的是AMF是二进制数据,而XML是文本数据,
AMF的传输效率比XML高。
AMF使用HTTP方式传输,目前主要是 用于ActionScript中,即实现Flex和Server之间的通信。
FFmpeg转FLV (书 P89)
封装FLV时,内部的音频或者视频不符合标准时,无法封装进FLV,如音频格式为AC3,需要先将其转换为AAC,再封装进FLV
代码语言:javascript复制ffmpeg -i input_ac3.mp4 -vcodec copy -acodec aac -f flv output.flv
生成带索引的FLV:将FLV文件中的关键帧建议一个索引,并将索引写入Metadata头中
代码语言:javascript复制ffmpeg -i input.mp4 -c copy -f flv -flvflags add_keyframe_index output.flv
FLV文件格式分析工具
flvparse、FlvAnalyzer、ffprobe
代码语言:javascript复制ffprobe -v trace -i output.flv
三、M3U8格式标准介绍
M3U8是一种常见的流媒体格式,主要以文件列表的形式存在,既支持直播也支持点播 标签:
- EXTM3U:M3U8文件必须包含的标签,且必须在文件的第一行
- EXT-X-VERSION:M3U8文件的版本
- EXT-X-TARGETDURATION:每一个分片都会有一个分片自己的duration,这个标签是最大的那个分片的浮点数四舍五入后的整数值
- EXT-X-MEDIA-SEQUENCE:M3U8直播时的直播切片序列,当播放打开M3U8时,以这个标签的值为参考,播放对应序列号的切片
客户端播放M3U8的标准还有更多规则:
分片必须是动态改变的,序列不能相同,且序列必须是增序的 当M3U8列表中没有出现EXT-X-ENDLIST标签时,无论M3U8列表中有多少片分片,都从倒数第三片开始播放;不满三片不应该播放 前一片与后一片有不连续时播放可能会出错,需要使用EXT-X-DISCONTINUITY标签来解决 以播放当前分片的duration时间刷新M3U8列表,然后做对应的加载动作 如果播放列表在刷新之后与之前的列表相同,那么在播放当前分片duration一半的时间再刷新一次
- EXTINF:M3U8列表中每一个分片的duration,还包含其他信息,主要为标注切片信息
- EXT-X-STREAM-INF:主要出现在多级M3U8文件中,例如不同清晰度
FFmpeg转HLS参数
FFmpeg自带HLS的封装参数,使用HLS格式即可进行HLS的封装,参数表格 P96 常规的文件转HLS直播:ffmpeg -re -i input.mp4 -c copy -f hls -bsf:v h264_mp4toannexb output.m3u8 ” -bsf:v h264_mp4toannexb”将MP4中的H.264转换为H.264 AnnexB标准的编码,AnnexB标准的编码常见与实时传输流中。如果源文件为FLV、TS等可作为直播传输流的视频,则不需要这个参数
参数解析
1.start_number参数
设置M3U8列表中第一片的序列号,例如:
代码语言:javascript复制ffmpeg -re -i input.flv -c copy -f hls -start_number 300 output.m3u8
2.hls_time参数
设置M3U8列表中切片的duration;该切片规则是从关键帧开始切片,时间不均匀;如果先转码再切片,则会比较规律
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_time 10 output.m3u8
3.hls_list_size参数
设置M3U8列表中TS切片的个数
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_list_size 3 output.m3u8
4.hls_wrap参数
为M3U8列表中TS设置刷新回滚参数
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_wrap 3 output.m3u8
5.hls_base_url参数
为M3U8列表中的文件路径设置前置基本路径参数
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_base_url http://xxx.xxx.x.x/live/ output.m3u8
6.hls_segment_filename参数
设置切片文件名的规则
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_segment_filename test_output-%d.ts output.m3u8
7.hls_flags参数
该参数包含了一些子参数
- 7.1 delete_segments
删除已经不在M3U8列表中的旧文件。 注意:FFmpeg删除切片时会将hls_list_size大小的2倍作为删除的依据
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_flags delete_segments -hls_list_size 4 output.m3u8
- 7.2 round_duration
实现切片信息duration为整型
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_flags round_durations output.m3u8
- 7.3 discont_start
在生成M3U8时,在切片信息的前边插入discontinuity标签
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_flags discont_start output.m3u8
- 7.4 omit_endlist
在生成M3U8结束的时候,若不在文件末尾,则不追加endlist标签:因为在常规的生成M3U8的操作中,FFmpeg会默认写入endlist标签
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_flags omit_endlist output.m3u8
- 7.5 split_by_time
生成M3U8时根据hls_time参数设定的数值作为秒数参考对TS进行切片,并不一定要遇到关键帧
代码语言:javascript复制ffmpeg -re -i input.flv -f hls -hls_time 2 -hls_flags split_by_time output.m3u8
8.use_localtime
以本地系统时间为切片文件名
代码语言:javascript复制ffmpeg -re -i input.mp4 -c copy -f hls -use_localtime 1 -bsf:v h264_mp4toannexb output.m3u8
9.method
设置HLS将M3U8及TS文件上传至Http服务器; Http服务器要支持上传相关方法,如POST、PUT等
代码语言:javascript复制ffmpeg -i input.mp4 -c copy -f hls -hls_time 3 -hls_list_size 0 -method POST -t 6 http://www.baidu.com
上述命令中两个FFmpeg参数的含义
-bsf 比特流过滤器设置 首先使用ffmpeg -bsfs来查看所有的比特流过滤器,使用下面的命令 ffmpeg -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264 来匹配要复制的视频流,也是就是说,是有条件复制视频流,必须匹配上才复制
-c -codec的缩写 ffmpeg -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT 意思是encodes all video streams with libx264 and copies all audio streams.
视频文件切片
视频文件切片与HLS基本类似,但HLS切片在标准中只支持TS格式的切片,且是直播与点播切片。视频切片可以使用segment方式,也可以使用ss加上t参数
FFmpeg切片segment参数 (参数表格 P105)参数中一些与HLS用法相同,下面分析一些用法不同的
FFmpeg使用segment方式进行切片
1.segment_format
指定切片文件的格式。HLS切片的格式主要为MPEGTS文件格式; 在segment中,可以根据segment_format来指定切片文件的格式,既可以为MPEGTS格式,也可以为MP4切片、FLV切片等
代码语言:javascript复制ffmpeg -re -i input.mp4 -c copy -f segment -segment_format mp4 test_output%d.mp4
2.segment_list与segment_list_type指定切片索引列表
使用segment切割文件时,不仅可以切割MP4,同样可以切割TS或FLV等文件,生成的文件索引列表名称也可以指定名称
1)生成ffconcat格式索引文件
代码语言:javascript复制ffmpeg -re -i input.mp4 -c copy -f segment -segment_format mp4 -segment_list_type ffconcat -segment_list output.lst test_output-%d.mp4
该命令生成ffconcat格式的索引文件output.lst,内包含MP4切片的文件列表
2)生成FLAT格式索引文件
代码语言:javascript复制ffmpeg -re -i input.mp4 -c copy -f segment -segment_format mp4 -segment_list_type flat -segment_list flielist.txt test_output-%d.mp4
3)生成CSV格式索引文件
代码语言:javascript复制ffmpeg -re -i input.mp4 -c copy -f segment -segment_format mp4 -segment_list_type csv -segment_list flielist.csv test_output-%d.mp4
4)生成M3U8格式索引文件
代码语言:javascript复制ffmpeg -re -i input.mp4 -c copy -f segment -segment_format mp4 -segment_list_type m3u8 -segment_list flielist.m3u8 test_output-%d.mp4
3.reset_timestamps 使切片时间戳归零
代码语言:javascript复制ffmpeg -re -i input.mp4 -c copy -f segment -segment_format mp4 -reset_timestamps 1 test_output-%d.mp4
4.segment_times 按照事件点剪切
代码语言:javascript复制ffmpeg -re -i input.mp4 -c copy -f segment -segment_format mp4 -segment_times 3,9,12 test_output-%d.mp4
根据命令参数,切片的时间点分别为3,9,12秒,在这三个时间点进行切片
FFmpeg使用ss与t参数进行切片
使用ss可以进行视频文件的seek定位,ss所传递的参数为时间值,t所传递的参数也为时间值
1.使用ss指定剪切开头部分
代码语言:javascript复制例如:从视频的第10秒开始截取
ffmpeg -ss 10 -i input.mp4 -c copy output.ts
2.使用t指定视频总长度
代码语言:javascript复制例如:截取前10秒的数据
ffmpeg -i input.mp4 -c copy -t 10 -copyts output.mp4
3.使用output_ts_offset指定输出start_time 使用ss与t可以达到切割视频的某一段的效果,但不能指定输出文件的start_time
代码语言:javascript复制ffmpeg -i input.mp4 -c copy -t 10 -output_ts_offset 120 output.mp4
FFmpeg抽取音视频文件中的AAC音频流
代码语言:javascript复制ffmpeg -i input.mp4 -vn -acodec copy output.aac
(由于我的input.mp4是录屏文件,没有音轨,所以没有获取到)
FFmpeg抽取音视频文件中的H.264视频流
代码语言:javascript复制ffmpeg -i input.mp4 -an -vcodec copy output.h264
FFmpeg抽取音视频文件中的H.265视频流
代码语言:javascript复制ffmpeg -i input.mp4 -an -vcodec copy -bsf hevc_mp4toannexb -f hevc output.hevc
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/153376.html原文链接:https://javaforall.cn