视频文件是指将一系列连续静态图片数据及音频数据的一个集合。视频文件包含了视频数据、音频数据、字幕数据,而且视频文件存放视频、音频编码信息等,如我们常见H264、MPEG、yuv、acc、FLV、MP4等。
概念
视频是由一组图像组成,为了将视频数据在网络中传输只能被压缩变小,最终在显示设备上显示。
图像是由像素组成,像素由RGB组成,目前显示屏幕是以红、绿、蓝三原色来调配所有颜色。
分辨率是记录横向和纵向的像素点个数。
位深是指每一个像素占用的位数(最常见24位,RGB888,每一个颜色都是8位。32位,RGBA,其中A表示alpha表示透明色)
帧率是指每秒钟播放的图像个数
屏幕指标数分为三类:PPI(屏幕的质量,一寸长的空间放多少像素)、DPI(每英寸的点数,基本上DPI等于PPI)、PPI(PPI>300就属于视网膜级别,人眼区分不出来,认为是一体的)
I帧(Intra coded frames):
I帧不需要参考其他画面而生成,解码时仅靠自己就重构完整图像;
I帧图像采用帧内编码方式;
I帧所占数据的信息量比较大;
I帧图像是周期性出现在图像序列中的,出现频率可由编码器选择;
I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量);
IDR帧是帧组GOP的基础帧(第一个(I)帧),在一组GOP中只有一个IDR帧;
I帧不需要考虑运动矢量;
P帧(Predicted frames)根据本帧与相邻的前一帧(I帧或P帧)的不同点来压缩本帧数据,同时利用了空间和时间上的相关性。
P帧属于前向预测的帧间编码。它需要参考前面最靠近它的I帧或P帧来解码。
B帧(Bi-directional predicted frames)采用双向时间预测,可以大大提高压缩倍数。
分辨率
1.分辨率:x像素个数 * y像素个数
2.常见的宽高比16:9和4:3。现在基本都是16:9,对于非标准的分辨率需要转换为16:9或4:3,否则在渲染时容易出错
3.360P(640360)/720P(1280720)/1K/2K.这些分辨率都是16:9的.4:3常见的是640*480
帧率
每秒钟播放图像的个数,常见帧率:15,30,60帧/s。
实时通信一般是15帧/s(帧率越大,占用的传输带宽就越大)
录课一般30帧/s能够满足需求;电影一般在60帧/s;
要求的平滑度越高,帧率就越大。要求的清晰度越高,分辨率就要越高。
码流计算方式
RGB码流=分辨率3Byte帧率
假设当前的分辨率 宽为1920 高为1080 像素深度为RGB三原色3Byte 帧率为1秒25帧 那么该每秒产生的RGB码流计算公式为:
RGB码流=分辨率宽高*像素深度*每秒帧率
例如:192010803*25=155520000约155M。
YUV压缩
主要用于视频信号的压缩、传输和存储,和向后相容老式黑白电视。
其中Y表示明亮度(Luminance或Luma),也称灰阶值。
U和V表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。
对于packed的YUV格式,每个像素点的Y,U,V是连续存储的。
libyuv,Google开源的实现各种YUV与RGB间相互转换、旋转、缩放的高效库。
YUV4:4:4采样,每一个Y对应一组UV分量。
YUV4:2:2采样,每两个Y共用一组UV分量。
YUV4:2:0采样,每四个Y共用一组UV分量。
H264(新一代视频压缩编码标准)
图⽚帧的像素块之间存在相似性,因此视频帧图像可以进⾏图像压缩;H264采⽤了16*16的分块⼤⼩对视频帧图像进⾏相似⽐较和压缩编码。
H264使⽤帧内压缩和帧间压缩的⽅式提⾼编码压缩率。H264采⽤了独特的I帧、P帧和B帧策略来实现连续帧之间的压缩。
I帧经过适度地压缩,做为随机访问的参考点,可以当成图象。I帧可以看成是⼀个图像经过压缩后的产物。⾃身可以通过视频解压算法解压成⼀张单独的完整的图⽚。
P帧通过充分将低于图像序列中前⾯已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧。需要参考其前⾯的⼀个I帧或者P帧来⽣成⼀张完整的图⽚。
B帧既考虑与源图像序列前⾯已编码帧,也顾及源图像序列后⾯已编码帧之间的时间冗余信息来压缩传输数据量的编码图像, 也叫双向预测帧。则要参考其前⼀个I或者P帧及其后⾯的⼀个P帧来⽣成⼀张完整的图⽚。
H264除了实现了对视频的压缩处理之外,为了⽅便⽹络传输,提供了对应的视频编码和分⽚ 策略;类似于⽹络数据封装成IP帧,在H264中将其称为组(GOP, group of pictures)、⽚ (slice)、宏块(Macroblock) 这些⼀起组成了H264的码流分层结构;H264将其组织成为序列(GOP)、图⽚(pictrue)、⽚(Slice)、宏块(Macroblock)、⼦块(subblock) 五个层次。
H264将视频分为连续的帧进⾏传输,在连续的帧之间使⽤I帧、P帧和B帧。同时对于帧内⽽⾔,将图像分为⽚、宏块和子块进⾏传输;通过这个过程实现对视频⽂件的压缩包装。
⼀个序列的第⼀个图像叫做IDR图像(⽴即刷新图像),IDR图像都是I帧图像。I帧和IDR帧都使⽤帧内预测。I帧不⽤参考任何帧,但是之后的P帧和B帧是有可能参考这个I帧之前的帧的。IDR就不允许这样,其核⼼作⽤是为了解码的重同步,当解码器解码到IDR图像时,⽴即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始⼀个新的序列。这样,如果前⼀个序列出现重⼤错误,在这⾥可以获得重新同步的机会。IDR图像之后的图像永远不会使⽤IDR之前的图像的数据来解码。
SPS:序列参数集。SPS中保存了⼀组编码视频序列(Coded video sequence) 的全局参数。
PPS:图像参数集。对应的是⼀个序列中某⼀幅图像或者某⼏幅图像的参数。
H264原始码流(裸流)是由⼀个接⼀个NALU组成,它的功能分为两层,VCL(视频编码层)和 NAL(⽹络提取层)
VCL层,视频数据编码层(Video Coding Layer),包括核⼼压缩引擎和块,宏块和⽚的语法级别定义,设计⽬标是尽可能地独⽴于⽹络进⾏⾼效的编码。
NAL层,视频数据网络抽象层(Network Abstraction Layer),负责将VCL产⽣的⽐特字符串适配到各种各样的⽹络和多元环境中,覆盖了所有⽚级以上的语法级别。
⼀个原始的H264 NALU单元通常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成,其中Start Code⽤于标示这是⼀个NALU单元的开始,必须是 "00 00 00 01"或"00 00 01" ,除此之外基本相当于⼀个 NAL header + RBSP 。3字节的0x000001只有⼀种场合下使⽤,就是⼀个完整的帧被编为多个slice(⽚)的时候,包含这些slice的NALU使⽤3字节起始码。其余场合都是4字节0x00000001的。
H264有两种封装
⼀种是annexb模式,传统模式,有startcode,SPS和PPS是在ES中。
⼀种是mp4模式,⼀般mp4、mkv都是mp4模式,没有startcode,SPS和PPS以及其它信息被封装在container中,每⼀个frame前⾯4个字节是这个frame的⻓度。很多解码器只⽀持annexb这种模式,因此需要将mp4做转换。在ffmpeg中⽤h264_mp4toannexb_filter可以做转换。
通过提⾼GOP值来提⾼图像质量是有限度的,在遇到场景切换的情况时,H264编码器会⾃动强制插⼊⼀个I帧,此时实际的GOP值被缩短了。另⼀⽅⾯,在⼀个GOP中,P、B帧是由I帧预测得到的,当I帧的图像质量⽐较差时,会影响到⼀个GOP中后续P、B帧的图像质量,直到下⼀个GOP开始才有可能得以恢复,所以GOP值也不宜设置过⼤。
由于P、B帧的复杂度⼤于I帧,所以过多的P、B帧会影响编码效率,使编码效率降低。另外,过⻓的GOP还会影响seek操作的响应速度,由于P、B帧是由前⾯的I或P帧预测得到的,所以seek操作需要直接定位,解码某⼀个P或B帧时,需要先解码得到本GOP内的I帧及之前的N个预测帧才可以。GOP值越⻓,需要解码的预测帧就越多,seek响应的时间也越⻓。
P帧特点:
P帧是I帧后⾯相隔1~2帧的编码帧;
P帧采⽤运动补偿的⽅法传送它与前⾯的I或P帧的差值及运动⽮量(预测误差);
解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像;
P帧属于前向预测的帧间编码。它只参考前⾯最靠近它的I帧或P帧;
P帧可以是其后⾯P帧的参考帧,也可以是其前后的B帧的参考帧;
由于P帧是参考帧,它可能造成解码错误的扩散;
由于是差值传送,P帧的压缩⽐较⾼。
B帧特点:
B帧是由前⾯的I或P帧和后⾯的P帧来进⾏预测的;
B帧传送的是它与前⾯的I或P帧和后⾯的P帧之间的预测误差及运动⽮量;
B帧是双向预测编码帧;
B帧压缩⽐最⾼,因为它只反映两参考帧间运动主体的变化情况,预测⽐较准确;
B帧不是参考帧,不会造成解码错误的扩散。
FLV(Flash Video)
FLV(Flash Video) 是Adobe公司推出的⼀种流媒体格式,由于其封装后的⾳视频⽂件体积⼩、封装简单等特点,⾮常适合于互联⽹上使⽤。⽬前主流的视频⽹站基本都⽀持FLV。
FLV封装格式是由⼀个⽂件头和⽂件体组成。其中,FLV body由⼀对对的 (Previous Tag Size字段 + tag) 组成。Previous Tag Size 字段排列在Tag之前,占⽤4个字节。Previous Tag Size 记录了前⾯⼀个Tag的⼤⼩,⽤于逆向读取处理。FLV header后的第⼀个Pervious Tag Size 的值为0。
FLV header由如下字段组成,其中前三个字节内容固定是FLV,最后4个字节内容固定是9(对FLV版本1来说):
字段 | 字段类型 | 字段含义 |
---|---|---|
Signature | UI8 | 签名,固定为'F' (0x46) |
Signature | UI8 | 签名,固定为'L' (0x4c) |
Signature | UI8 | 签名,固定为'V' (0x56) |
Version | UI8 | 版本,比如 0x01 表示 FLV 版本 1 |
TypeFlagsReserved | UB[5] | 全为0 |
TypeFlagsAudio | UB[1] | 1表示有audio tag,0表示没有 |
TypeFlagsReserved | UB[1] | 全为0 |
TypeFlagsVideo | UB[1] | 1表示有video tag,0表示没有 |
DataOffset | UI32 | FLV header的大小,单位是字节 |
FLV file body很有规律,由一系列的TagSize和Tag组成,其中PreviousTagSize0总是为0;tag由tag header、tag body组成;对FLV版本1,tag header固定为11个字节。因此,PreviousTagSize(除第1个)的值为 11 + 前一个tag的tag body的大小:
字段 | 字段类型 | 字段含义 |
---|---|---|
PreviousTagSize0 | UI32 | 总是0 |
Tag1 | FLVTAG | 第1个tag |
PreviousTagSize1 | UI32 | 前一个tag的大小,包括tag header |
Tag2 | FLVTAG | 第2个tag |
... | ... | ... |
PreviousTagSizeN-1 | UI32 | 第N-1个tag的大小 |
TagN | FLVTAG | 第N个tag |
PreviousTagSizeN | UI32 | 第N个tag的大小,包含tag header |
FLV tag由tag header+tag body组成。tag header如下,总共占据11个字节:
字段 | 字段类型 | 字段含义 |
---|---|---|
TagType | UI8 | tag类型: 8:audio 9:video 18:script data 其他:保留 |
DataSize | UI24 | tag body的大小 |
Timestamp | UI24 | 相对于第一个tag的时间戳(单位是毫秒)第一个tag的Timestamp为0 |
TimestampExtended | UI8 | 时间戳的扩展字段,当 Timestamp 3个字节不够时,会启用这个字段,代表高8位 |
StreamID | UI24 | 总是0 |
Data | 取决于根据TagType | TagType=8,则为AUDIODATA TagType=9,则为VIDEODATA TagType=18,则为SCRIPTDATAOBJECT |
Tag⼀般可以分为3种类型:脚本(帧)数据类型、⾳频数据类型、视频数据。FLV数据以⼤端序进⾏存储,在解析时需要注意。
⼀个FLV⽂件,每种类型的tag都属于⼀个流,也就是⼀个flv⽂件最多只有⼀个⾳频流,⼀个视频流,不存在多个独⽴的⾳视频流在⼀个⽂件的情况。
FLV⽂件中Timestamp和TimestampExtended拼出来的是dts。也就是解码时间。Timestamp和TimestampExtended拼出来dts单位为ms。(如果不存在B帧,当然dts等于pts)。
Script data脚本数据就是描述视频或⾳频的信息的数据,如宽度、⾼度、时间等等,⼀个⽂件中通常只有⼀个元数据,⾳频tag和视频tag就是⾳视频信息了,采样、声道、频率,编码等信息。
Script Tag Data结构(脚本类型、帧类型)
该类型Tag⼜被称为MetaData Tag,存放⼀些关于FLV视频和⾳频的元信息,⽐如:duration、width、height 等。通常该类型Tag会作为FLV⽂件的第⼀个tag,并且只有⼀个,跟在File Header后。
AMF包中第一个字节为类型标识:
类型 | 值 |
---|---|
Number | 0x00 |
Boolean | 0x01 |
String | 0x02 |
Object | 0x03 |
MovieClip | 0x04 |
Null | 0x05 |
Undefined | 0x06 |
Reference | 0x07 |
ECMAArray | 0x08 |
ObjectEnd | 0x09 |
StrictArray | 0x0a |
Date | 0x0b |
LongString | 0x0c |
Unsupported | 0x0d |
Recordset | 0x0e |
XMLObject | 0x0f |
TypedObject(Class) | 0×10 |
Audio Tag Data结构(⾳频类型)
Audio tags定义如下所示:
字段 | 字段类型 | 字段含义 |
---|---|---|
SoundFormat | UB[4] | 音频格式,重点关注 10 = AAC 0 = Linear PCM, platform endian 1 = ADPCM 2 = MP3 3 = Linear PCM, little endian 4 = Nellymoser 16-kHz mono 5 = Nellymoser 8-kHz mono 6 = Nellymoser 7 = G.711 A-law logarithmic PCM 8 = G.711 mu-law logarithmic PCM 9 = reserved 10 = AAC 11 = Speex 14 = MP3 8-Khz 15 = Device-specific sound |
SoundRate | UB[2] | 采样率,对AAC来说,永远等于3 0 = 5.5-kHz 1 = 11-kHz 2 = 22-kHz 3 = 44-kHz |
SoundSize | UB[1] | 采样精度,对于压缩过的音频,永远是16位 0 = snd8Bit 1 = snd16Bit |
SoundType | UB[1] | 声道类型,对Nellymoser来说,永远是单声道;对AAC来说,永远是双声道; 0 = sndMono 单声道 1 = sndStereo 双声道 |
SoundData | UI8[size of sound data] | 如果是AAC,则为AACAUDIODATA;其他请参考规范。 |
AACAUDIODATA
当SoundFormat为10时,表示音频采AAC进行编码,此时,SoundData的定义如下:
字段 | 字段类型 | 字段含义 |
---|---|---|
AACPacketType | UI8 | 0: AAC sequence header 1: AAC raw |
Data | UI8[n] | 如果AACPacketType为0,则为AudioSpecificConfig;如果AACPacketType为1,则为AAC帧数据。 |
AudioSpecificConfig
字段 | 字段类型 | 字段含义 |
---|---|---|
AudioObjectType | UB[5] | 编码器类型,比如2表示AAC-LC。 |
SamplingFrequencyIndex | UB[4] | 采样率索引值,比如4表示44100。 |
ChannelConfiguration | UB[4] | 声道配置,比如2代表双声道,front-left,front-right。 |
AOT Specific Config | UB[n] |
⾳频Tag Data区域开始的第⼀个字节包含了⾳频数据的参数信息,第⼆个字节开始为⾳频流数据。(这两个字节属于tag的data部分,不是header部分)。第⼆个字节开始为⾳频数据(需要判断该数据是真正的⾳频数据,还是⾳频config信息)。
Video Tag Data结构(视频类型)
Video tags定义如下:
字段 | 字段类型 | 字段含义 |
---|---|---|
FrameType | UB[4] | 重点关注1、2: 1: keyframe (for AVC, a seekable frame) —— 即H.264的IDR帧; 2: inter frame (for AVC, a non- seekable frame) —— H.264的普通I帧; 3: disposable inter frame (H.263 only) 4: generated keyframe (reserved for server use only) 5: video info/command frame |
CodecID | UB[4] | 编解码器,主要关注 7(AVC) 1: JPEG (currently unused) 2: Sorenson H.263 3: Screen video 4: On2 VP6 5: On2 VP6 with alpha channel 6: Screen video version 2 7: AVC |
VideoData | 取决于CodecID | 实际的媒体类型,主要关注 7:AVCVIDEOPACKE 2: H263VIDEOPACKET 3: SCREENVIDEOPACKET 4: VP6FLVVIDEOPACKET 5: VP6FLVALPHAVIDEOPACKET 6: SCREENV2VIDEOPACKET 7: AVCVIDEOPACKE |
AVCVIDEOPACKE当CodecID为7时,VideoData为 AVCVIDEOPACKE,也即H264媒体数据。AVCVIDEOPACKE的定义如下:
字段 | 字段类型 | 字段含义 |
---|---|---|
AVCPacketType | UI8 | 0: AVC sequence header 1: AVC NALU 2: AVC end of sequence |
CompositionTime | SI24 | 如果AVCPacketType=1,则为时间cts偏移量;否则,为0。当B帧的存在时,视频解码呈现过程中,dts、pts可能不同,cts的计算公式为(pts-dts)/90,单位为毫秒;如果B帧不存在,则cts固定为0。 |
Data | UI8[n] | 1、如果如果AVCPacketType=0,则为AVCDecoderConfigurationRecord,H.264 视频解码所需要的参数集(SPS、PPS) 2、如果AVCPacketType=1,则为NALU(一个或多个) 3、如果AVCPacketType=2,则为空 |
视频Tag Data开始的第⼀个字节包含视频数据的参数信息,第⼆个字节开始为视频流数据。
CompositionTime 表示PTS相对于DTS的偏移值, 在每个视频tag的第14-16字节。 显示时间(pts) = 解码时间(tag的第5-8字节) + CompositionTime ,CompositionTime的单位也是ms。
MP4
MP4主要BOX
采样频率:每秒钟采样的点的个数。常用的采样频率有:
采样率 | 常见用途 |
---|---|
22000(22kHz) | 无线广播 |
44100(44.1kHz) | CD音质 |
48000(48kHz) | 数字电视,DVD |
96000(96kHz) | 蓝光,高清DVD |
192000(192kHz) | 蓝光,高清DVD |
采样精度(采样深度):每个“样本点”的大小,常用的大小为8bit, 16bit,24bit。
通道数:单声道,双声道,四声道,5.1声道。
比特率:每秒传输的bit数,单位为:bps(Bit Per Second)。间接衡量声音质量的一个标准。没有压缩的音频数据的比特率 = 采样频率 * 采样精度 * 通道数。
码率:压缩后的音频数据的比特率。常见的码率:
码率 | 常见用途 |
---|---|
96kbps | FM质量 |
128-160kbps | 一般质量音频 |
192kbps | CD质量 |
256-320Kbps | 高质量音频 |
码率越大,压缩效率越低,音质越好,压缩后数据越大。
码率 = 音频文件大小 / 时长。
帧:每次编码的采样单元数,比如MP3通常是1152个采样点作为一个编码单元,AAC通常是1024个采样点作为一个编码单元。
帧长:可以指每帧播放持续的时间。每帧持续时间(秒)= 每帧采样点数 / 采样频率(HZ)。比如:MP3 48k,1152个采样点,每帧则为24毫秒,1152/48000 = 0.024秒 = 24毫秒;也可以指压缩后每帧的数据长度。
交错模式:数字音频信号存储的方式。数据以连续帧的方式存放,即首先记录帧1的左声道样本和右声道样本,再开始帧2的记录...
非交错模式:首先记录的是一个周期内所有帧的左声道样本,再记录所有右声道样本。
数字音频压缩编码在保证信号在听觉方面不产生失真的前提下,对音频数据信号进行尽可能大的压缩,降低数据量。数字音频压缩编码采取去除声音信号中冗余成分的方法来实现。所谓冗余成分指的是音频中不能被人耳感知到的信号,它们对确定声音的音色,音调等信息没有任何的帮助。
音视频同步
DTS(Decoding Time Stamp):即解码时间戳,这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。
PTS(Presentation Time Stamp):即显示时间戳,这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。
音视频同步方式:
名称 | 实现 |
---|---|
Audio Master | 同步视频到音频 |
Video Master | 同步音频到视频 |
External Clock Master | 同步音频和视频到外部时钟 |
一般情况下选择:Audio Master > External Clock Master > Video Master
AAC(高级音频编码)
ADIF,音频数据交换格式(Audio Data Interchange Format)。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。
ADTS,音频数据传输流(Audio Data Transport Stream)。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。
每⼀帧的ADTS的头⽂件都包含了⾳频的采样率,声道,帧⻓度等信息,这样解码器才能解析读取。⼀般情况下ADTS的头信息都是7个字节,分为2部分:
adts_fixed_header();
adts_variable_header();
其⼀为固定头信息,紧接着是可变头信息。固定头信息中的数据每⼀帧都相同,⽽可变头信息则在帧与帧之间可变。
syncword:同步头,总是0xFFF,all bits must be 1,代表着⼀个ADTS帧的开始。
ID:MPEG标识符,0标识MPEG-4,1标识MPEG-2。
Layer:always: '00'。
protection_absent:表示是否误码校验。Warning, set to 1 if there is no CRC and 0 if there is CRC。
profile:表示使⽤哪个级别的AAC,如01 Low Complexity(LC)--- AAC LC。有些芯⽚只⽀持AAC LC。profile的值等于Audio Object Type的值减1。profile = MPEG-4 Audio Object Type - 1。
sampling_frequency_index:表示使⽤的采样率下标,通过这个下标在Sampling Frequencies[ ]数组中查找得知采样率的值。
channel_configuration:表示声道数,⽐如2表示⽴体声双声道。
frame_length:⼀个ADTS帧的⻓度包括ADTS头和AAC原始流:
frame length, this value must include 7 or 9 bytes of header length;
aac_frame_length = (protection_absent == 1 ? 7 : 9) + size(AACFrame);
protection_absent=0时,header length=9bytes;
protection_absent=1时,header length=7bytes;
adts_buffer_fullness:0x7FF说明是码率可变的码流。
number_of_raw_data_blocks_in_frame:表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧。所以说number_of_raw_data_blocks_in_frame == 0表示说ADTS帧中只有⼀个AAC数据块。
ADTS可以在任意帧解码,也就是说它每⼀帧都有头信息。ADIF只有⼀个统⼀的头,所以必须得到所有的数据后解码。
封装格式(也叫容器)就是将已经编码压缩好的视频流、音频流及字幕按照一定的方案放到一个文件中,便于播放软件播放。
一般来说,视频文件的后缀名就是它的封装格式。
封装的格式不一样,后缀名也就不一样。