解析音频标签
入口函数CreateTag
流程如下:
1、解析标签头部
2、判断标签头部的类型
3、根据标签头部的类型,解析不同的标签
4、如果是视频类型的标签,那么就创建并解析视频标签
CFlvParser::Tag *CFlvParser::CreateTag(unsigned char *pBuf, int nLeftLen)
{
// 开始解析标签头部
TagHeader header;
header.nType = ShowU8(pBuf+0); // 类型
header.nDataSize = ShowU24(pBuf + 1); // 标签body的长度
header.nTimeStamp = ShowU24(pBuf + 4); // 时间戳
header.nTSEx = ShowU8(pBuf + 7); // 时间戳的扩展字段
header.nStreamID = ShowU24(pBuf + 8); // 流的id
header.nTotalTS = (unsigned int)((header.nTSEx << 24)) + header.nTimeStamp;
// 标签头部解析结束
cout << "total TS : " << header.nTotalTS << endl;
//cout << "nLeftLen : " << nLeftLen << " , nDataSize : " << pTag->header.nDataSize << endl;
if ((header.nDataSize + 11) > nLeftLen)
{
return NULL;
}
Tag *pTag;
switch (header.nType) {
case 0x09: // 视频类型的Tag
pTag = new CVideoTag(&header, pBuf, nLeftLen, this);
break;
case 0x08: // 音频类型的Tag
pTag = new CAudioTag(&header, pBuf, nLeftLen, this);
break;
default: // script类型的Tag
pTag = new Tag();
pTag->Init(&header, pBuf, nLeftLen);
}
return pTag;
}
创建音频标签
流程如下:
1、初始化
2、解析音频编码类型
3、解析采样率
4、解析精度和类型
5、解析音频标签
CFlvParser::CAudioTag::CAudioTag(TagHeader *pHeader, unsigned char *pBuf, int nLeftLen, CFlvParser *pParser)
{
// 初始化
Init(pHeader, pBuf, nLeftLen);
unsigned char *pd = _pTagData;
_nSoundFormat = (pd[0] & 0xf0) >> 4; // 音频编码类型
_nSoundRate = (pd[0] & 0x0c) >> 2; //采样率
_nSoundSize = (pd[0] & 0x02) >> 1; // 精度
_nSoundType = (pd[0] & 0x01); // 类型
// 解析音频标签
if (_nSoundFormat == 10) // AAC
{
ParseAACTag(pParser);
}
}
解析音频标签
流程如下:
1、获取数据包的类型
2、判断数据包的类型
3、如果数据包是音频配置信息,那么解析有音频配置信息
4、如果是原始音频数据,那么对原始音频数据进行处理
int CFlvParser::CAudioTag::ParseAACTag(CFlvParser *pParser)
{
unsigned char *pd = _pTagData;
// 数据包的类型:音频配置信息,音频数据
int nAACPacketType = pd[1];
// 如果是音频配置信息
if (nAACPacketType == 0)
{
// 解析配置信息
ParseAudioSpecificConfig(pParser, pd);
}
// 如果是音频数据
else if (nAACPacketType == 1)
{
// 解析音频数据
ParseRawAAC(pParser, pd);
}
else
{
}
return 1;
}
处理原始音频数据
流程如下:
1、解析AAC的采样率
2、解析采样率索引
3、解析声道
int CFlvParser::CAudioTag::ParseAudioSpecificConfig(CFlvParser *pParser, unsigned char *pTagData)
{
unsigned char *pd = _pTagData;
// AAC的profile
_aacProfile = ((pd[2]&0xf8)>>3) - 1;
// 采样率索引
_sampleRateIndex = ((pd[2]&0x07)<<1) | (pd[3]>>7);
// 声道
_channelConfig = (pd[3]>>3) & 0x0f;
_pMedia = NULL;
_nMediaLen = 0;
return 1;
}
处理原始音频数据
主要的功能是为原始的音频数据添加元数据,可以根据自己的需要进行改写
int CFlvParser::CAudioTag::ParseRawAAC(CFlvParser *pParser, unsigned char *pTagData)
{
uint64_t bits = 0;
// 数据长度
int dataSize = _header.nDataSize - 2;
// 制作元数据
WriteU64(bits, 12, 0xFFF);
WriteU64(bits, 1, 0);
WriteU64(bits, 2, 0);
WriteU64(bits, 1, 1);
WriteU64(bits, 2, _aacProfile);
WriteU64(bits, 4, _sampleRateIndex);
WriteU64(bits, 1, 0);
WriteU64(bits, 3, _channelConfig);
WriteU64(bits, 1, 0);
WriteU64(bits, 1, 0);
WriteU64(bits, 1, 0);
WriteU64(bits, 1, 0);
WriteU64(bits, 13, 7 + dataSize);
WriteU64(bits, 11, 0x7FF);
WriteU64(bits, 2, 0);
_nMediaLen = 7 + dataSize;
_pMedia = new unsigned char[_nMediaLen];
// 把元数据放进临时数组中
unsigned char p64[8];
p64[0] = (unsigned char)(bits >> 56);
p64[1] = (unsigned char)(bits >> 48);
p64[2] = (unsigned char)(bits >> 40);
p64[3] = (unsigned char)(bits >> 32);
p64[4] = (unsigned char)(bits >> 24);
p64[5] = (unsigned char)(bits >> 16);
p64[6] = (unsigned char)(bits >> 8);
p64[7] = (unsigned char)(bits);
// 把临时数组的数据复制给元数据
memcpy(_pMedia, p64+1, 7);
// 把读取到的数据复制到后面
memcpy(_pMedia + 7, pTagData + 2, dataSize);
return 1;
}