本课程主要从
- 音视频采集
- 音视频编码
- 音视频协议封装传输
- 音视频协议解封装
- 音视频解码
- 音视频播放
关于Jessibuca
- 官网地址:jessibuca.com
- Demo: Demo
- Doc:Doc
- Github地址:Github
关于JessibucaPro
- 地址:JessibucaPro
- Demo: Demo
- AI:AI
- 插件:插件
第四章:音视频解封装
通过网络请求,请求到了mp4/flv/hls/webm内容。
通过解封装协议可以解封装到音视频数据。
对于音频可以解封装到:aac/g711/mp3/opus 数据。
对于音频可以解封装到:h264/h265/v9 数据。
mp4
在MP4文件格式中,整个视频容器都是由多个box和子box组成,根据box类型主要分为3大类:视频类型(ftyp)、视频数据(mdat)、视频信息(moov)。
视频信息(moov)用来描述视频数据(mdat)。
在web端,可以使用mp4Box.js来封装mp4文件。
兼容性
目前web端 可以通过video标签进行 mp4文件的播放。
flv
FLV(Flash Video)是目前最流行的流媒体格式,其文件体积小、封装播放简单,非常适合在网络场景下应用。
对于FLV ,是由一个文件头(FLV header)和 很多tag组成(FLV body),tag又可以分成三类:audio,video,script,分别代表音频流,视频流,脚本流,而每个tag又由tag header和tag data组成
文件头 (flv header)
在文件头内容里面:
- 前3个bytes是文件类型,总是"FLV",也就是(0x46 0x4C 0x56)。
- 第4btye是版本号,目前一般是0x01。
- 第5byte是流的信息,倒数第一bit是1表示有视频(0x01),倒数第三bit是1表示有音频(0x4),有视频又有音频就是0x01 | 0x04(0x05),其他都应该是0。
- 最后4bytes表示FLV 头的长度,
flv header 的长度是:3+1+1+4 = 9。
在web端,利用js 来解封装flv协议。
            
            
              js
              
              
            
          
          // 解析flv header
const flvHeader = flvData.slice(0,9);
// 前3字节是 'FLV' 三个字符
const f = flvHeader[0];
const l = flvHeader[1];
const v = flvHeader[2];
// 第4btye是版本号,目前一般是0x01。
const version = flvHeader[3];
// 第5字节是Flags ,用于鉴别是否含有音频、视频数据
const hasAudio = ((flvHeader[4] & 4) >>> 2) !== 0;
const hasVideo = (flvHeader[4] & 1) !== 0;
// 最后4bytes表示FLV 头的长度。若干个tag(flv body)
对于 flv body 是由:previous tag size #0 (4 size) + tag #1 + previous tag size #1 (4 size) (tag #1的大小 11+ datasize) + tag #2 + previous tag size #1(4 size) + ... + tag #n + previous tag size #n(4 size) 组成。
tag header
在tag header 里面
- 第1个byte为记录着tag的类型,音频(0x8),视频(0x9),脚本(0x12)18;
- 第2到4bytes是数据区的长度,也就是tag data的长度(头部之后的数据体的大小);
- 再后面3个bytes是时间戳,单位是毫秒,类型为0x12则时间戳为0,时间戳控制着文件播放的速度,可以根据音视频的帧率类设置;
- 时间戳后面一个byte是扩展时间戳,时间戳不够长的时候用;
- 最后3bytes是streamID,但是总为0。
tag header 的长度是: 1+3+3+1+3=11。
在web端,利用js 来解封装flv协议。
            
            
              js
              
              
            
          
          const tagType = flvData[0] & 0x1F; // 5bit代表类型,8:audio 9:video 18:script other:其他
 //
const tmp = new ArrayBuffer(4);
const dv = new DataView(tmp);
// 2-4 消息长度
dv.setUint8(0, flvData[3]);
dv.setUint8(1, flvData[2]);
dv.setUint8(2, flvData[1]);
dv.setUint8(3, 0);
// tag data的长度(头部之后的数据体的大小);
const payloadLen = dv.getUint32(0, true);
// 5-7 时间戳
dv.setUint8(0, flvData[6]);
dv.setUint8(1, flvData[5]);
dv.setUint8(2, flvData[4]);
// 8-8 时间戳扩展
dv.setUint8(3, flvData[7]);
const dts = dv.getUint32(0, true);
// 最后3bytes是streamID,但是总为0。tag data
裸流数据
script tag
该类型Tag又通常被称为Metadata Tag,会放一些关于FLV视频和音频的元数据信息如:duration、width、height等。
通常该类型Tag会跟在File Header后面作为第一个Tag出现,而且只有一个。
主要结构: 由AMF1("onMetaData") + AMF2("width,height,...") 组成。
audio tag
通过 tag header 里面得知是audio tag,接下来就是解析tag data 数据了
在 tag header 里面 第一个字节 表示 音频头(audio tag header)
音频头(audio tag header)
在音频头里面:
            
            
              ini
              
              
            
          
          1-4bit,音频格式【SoundFormat】
	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 , reserved
	8 = G.711 mu-law logarithmic PCM , reserved
	9 = reserved
	10 = AAC (supported in Flash Player 9,0,115,0 and higher)
	11 = Speex (supported in Flash Player 10 and higher)
	14 = MP3 8 kHz , reserved
	15 = Device-specific sound , reserved
5-6bit,采样率【SoundRate】
	0 = 5.5kHz
	1 = 11kHz
	2 = 22kHz
	3 = 44kHz
7-7bit,位宽,0 = 8bit samples, 1= 16bit samples【SoundSize】
8-8bit,通道,0 = Mono, 1 = Stereo【SoundType】如果 音频格式是aac 的话,第二个字节表示aac音频类型
            
            
              ini
              
              
            
          
          0 = AAC sequence header
1 = AAC raw剩下的字节数据就是纯音频数据了
小结:
如果是aac tagheader(1) + 音频类型(1) + (n-2)
如果是g711a/u tagheader(1) + (n-1)
在web端,利用js 来解封装flv协议。
            
            
              js
              
              
            
          
           // 音频格式【SoundFormat】
 let soundId = (flvData[0] >> 4) & 0x0F;
 let soundrate = (flvData[0]>>2)&0x02;
 let soundsize = (flvData[0]>>1)&0x01;
 let soundtype = (flvData[0])&0x0F;
 if(soundId === '10'){
 // aac about sequence header and raw
 // [2-2]:AAC音频类型,注,只有在SoundFormat=AAC 时,才有此数据
 //  0 = AAC sequence header
 //  1 = AAC raw
 const packetType = flvData[1];
 if (packetType === 0) {
	 const config = flvData.slice(0, this.needLen);
	 const aacSequenceHeader = flvData.slice(2, this.needLen);
	 console.log('AAC sequence header');
 } else {
 // AAC raw
 const aacRaw = flvData.slice(2, this.needLen);
 console.log('AAC raw')
 }
 else{
 	// g711 音频数据
   const g711Raw = flvData.slice(1, this.needLen);
 }video tag
在 tag header 里面 第一个字节 表示 视频头(video tag header)
            
            
              ini
              
              
            
          
           1-4bit,帧类型【FrameType】
	 1 = key frame (for AVC, a seekable frame)
	 2 = inter frame (for AVC, a non-seekable frame)
	 3 = disposable inter frame (H.263 only)
	 4 = generated key frame (reserved for server use only)
	 5 = video info/command frame
 5-8bit,编码类型【CodecID】
	 2 = Sorenson H.263
	 3 = Screen video
	 4 = On2 VP6
	 5 = On2 VP6 with alpha channel
	 6 = Screen video version 2
	 7 = AVC(H.264)第 2-5 个字节是 CompositionTime
小结
video tag header(1) + compsitionTime(4) + 视频数据(n-5)
在web端,利用js 来解封装flv协议。
            
            
              js
              
              
            
          
           // 1-4bit,帧类型【FrameType】
 let frameType = (flvData[0] >> 4) & 0x0F;
 //  5-8bit,编码类型【CodecID】
 let codecId = (flvData[0]) & 0x0F;
// h264 or h265
const packetType = flvData[1];
// compositionTime
dv.setUint8(0, flvData[4]);
dv.setUint8(1, flvData[3]);
dv.setUint8(2, flvData[2]);
dv.setUint8(3, 0);
let compositionTime = dv.getUint32(0, true);
this.pts = this.dts + compositionTime;
// 完整的demo:flv-demux
兼容性
目前web端 video标签是不支持flv 文件进行播放的。需要借助浏览器提供的mediaSource 或者webcodec 或者wasm 来解封装 flv 文件。
hls
HLS 由 TS 和 M3U8 两部分组成:
- m3u8 文件:以 UTF-8 编码的 m3u 文件。
- ts 视频文件:一个 m3u8 文件对应着若干个 ts文件。
m3u8 文件
m3u8 只存放了一些 ts 文件的配置信息和相关路径。
ts 视频文件
ts 文件存放了视频的数据。
兼容性
webm
WebM 由 Google 提出,是一种专为 Web 设计的开放,免版税的媒体文件格式。WebM 文件包含使用 VP8 或 VP9 视频编解码器压缩的视频流和使用 Vorbis 或 Opus 音频编解码器压缩的音频流。
webm 格式的视频,直接可以通过video标签进行播放。