日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

MP4音频解码信息(转帖加注释)

發布時間:2023/12/13 综合教程 26 生活家
生活随笔 收集整理的這篇文章主要介紹了 MP4音频解码信息(转帖加注释) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://blog.csdn.net/linzhiji/article/details/5840031

注釋:

1。3gp和MP4中的AAC的私有數據保存在esds的0x05標簽的數據,

結構為 05 + 長度 + 內容。

將長度賦值給 extradatasize

將內容賦值給 extradata

長度的計算函數在ffmpeg中的static int mp4_read_descr_len(ByteIOContext *pb)

2。avc/h264的extradata和extradata信息在avcc atom中,將avcc atom去掉type和長度(8個字節)后的長度賦予extradatasize,內容賦值給extradata.

MP4文件格式分為頭部和數據兩部分,頭部是由許多被稱作Atom的結構單元嵌套或排列而成,數據部分則完全為實際數據不包含元信息,因此具體解碼時音視頻幀的位置和大小都要在頭部獲取。詳細內容見以下鏈接:
http://wqyuwss.52rd.net
這里總結下音頻解碼信息獲取的一些經驗,當然詳細內容需要查看quick time file format的文檔。
MP4的音頻解碼信息保存在如下嵌套的Atom中,{moov{mdia{minf{smhd{stbl{stsd}}}}}}
stsd可能包括多個音頻信息的描述,結構如下:

typedefstructstsdtable
{
unsignedintsize;//Atom大小
charformat[4];//音頻編碼格式
intres1;
intref;
shortversion;//版本
shortpad1;
intpad2;
shortchannels;//聲道
shortbitspersample;
shortcompress_id;
shortres2;
shortsamplerate1;//采樣率
shortsamplerate2;
//{if(version==1)

intsampleperpacket;
intbytesperpacket;
intbytesperframe;
intbytespersample;
//}

}stsdtable;

其中format對應音頻編碼格式:
PCM_S32BE, in32
PCM_S32LE, in32
PCM_S24BE, in24
PCM_S24LE, in24
PCM_S16BE, twos // 16 bits //
PCM_S16LE, sowt //
PCM_S16LE, lpcm
PCM_F32BE, fl32
PCM_F64BE, fl64
PCM_S8, sowt
PCM_U8, raw // 8 bits unsigned
PCM_U8, NONE // uncompressed
PCM_MULAW, ulaw //
PCM_ALAW, alaw //
ADPCM_IMA_QT, ima4 // IMA-4 ADPCM //
MACE3, MAC3 // Macintosh Audio Compression and Expansion 3:1 ///
MACE6, MAC6 // Macintosh Audio Compression and Expansion 6:1 //
MP3, .mp3 // MPEG layer 3 */ /* sample files at http://www.3ivx.com/showcase.html use this tag //
MP3, 0x6D730055 // MPEG layer 3 //
OGG_VORBIS, OggS //// sample files at http://heroinewarrior.com/xmovie.php3 use this tag //
AAC, mp4a // MPEG-4 AAC //
AC3, ac-3 // ETSI TS 102 366 Annex F //
AMR_NB, samr // AMR-NB 3gp //
AMR_WB, sawb // AMR-WB 3gp//
GSM, agsm
ALAC, alac // Apple Lossless //
QCELP, Qclp
QCELP, sqcp // ISO Media fourcc //
QDM2, QDM2 // QDM2 //
DVAUDIO, vdva
DVAUDIO, dvca
WMAV2, WMA2
這個獲取比較簡單,下面是解碼私有數據的獲取:
這些解碼私有數據也保存在Atom中,通常在上面結構體的后面,有esds、frma、mp4a、wave。AAC的私有數據保存在esds的0x05標簽的數據,QDM2的則是"wave"Atom的數據部分(以下按順序分析):
4字節 長度
4字節 "esds" or "m4ds" 標志
4字節 版本標識

1字節 ES描述類型標簽 0x03
--3字節 擴展描述類型標簽 可能沒有
1字節 描述類型長度
2字節 ES ID
1字節 流優先級

1字節 解碼配置描述類型標簽 0x04
--3字節 擴展描述類型標簽 可能沒有
1字節 描述類型長度
1字節 描述對象ID
1字節
3字節
4字節
4字節

1字節 解碼配置描述類型標簽 0x05
--3字節 擴展描述類型標簽 可能沒有
1字節 長度

1字節 0x06
0x06不再分析
下面是一個例子:
長度標簽
00015218h:00 00 00 1073 6D 68 6400 00 00 00 00 00 00 00 ; ....smhd........
00015228h:00 00 00 2464 69 6E 6600 00 00 1C64 72 65 66 ; ...$dinf....dref
00015238h: 00 00 00 00 00 00 00 01 00 00 00 0C 75 72 6C 20 ; ............url
00015248h: 00 00 00 0100 02 C0 9773 74 62 6C00 00 00 5B; ......罈stbl...[
00015258h:73 74 73 6400 00 00 00 00 00 00 01 00 00 00 4B ; stsd...........K
00015268h:6D 70 34 6100 00 00 00 00 00 00 01 00 00 00 00 ; mp4a............
00015278h: 00 00 00 00 00 01 00 10 00 00 00 00 7D 00 00 00 ; ............}...
00015288h:00 00 00 2765 73 64 7300 00 00 00031900 00 ; ...'esds........
00015298h: 00041140 15 00 00 D2 00 00 BB 88 00 00 7D 00 ; ...@...?.粓..}.
000152a8h:050212 88060102 ; ...?..

0x12 0x88即私有數據(對應ffmpeg中AVCodecContext.extradata)
下面是mp4音頻部分分析的代碼:

//MP4Analyze.h

#defineuint8_tunsignedchar

/******atom tag*******/
uint8_tmoov[]="moov";
uint8_ttrak[]="trak";
uint8_tmdia[]="mdia";
uint8_tminf[]="minf";
uint8_tstbl[]="stbl";
uint8_tstsd[]="stsd";
uint8_tstsc[]="stsc";
uint8_tstsz[]="stsz";
uint8_tstco[]="stco";
uint8_tftyp[]="ftyp";
uint8_tmdat[]="mdat";

typedefstructAtom
{
unsignedintsize;
uint8_ttag[4];
intver_flag;
unsignedintnum_of_entries;
unsignedintpos;
uint8_t*data;
}Atom;

/****audio format****/
uint8_tkmp3[]={0x6D,0x73,0x00,0x55};
uint8_tfmp3[]=".mp3";
uint8_traw[]="raw ";

uint8_twave[]="wave";
uint8_tmp4a[]="mp4a";
uint8_tenca[]="enca";//encrypted to ISO/IEC 14496-12 or 3GPP standards

uint8_tsmar[]="smar";//encoded to 3GPP GSM 6.10 AMR narrowband standards

uint8_tsawb[]="sawb";//encoded to 3GPP GSM 6.10 AMR wideband standards

uint8_tm4ds[]="m4ds";//encoded to ISO/IEC 14496-10 AVC standards

uint8_tesds[]="esds";
uint8_tfram[]="fram";

/*** We may not need these ***/
#defineMKTAG(a,b,c,d)(a|(b<<8)|(c<<16)|(d<<24))
typedefstructAVCodecTag{
intid;
unsignedinttag;
}AVCodecTag;

typedefstructstsdtable
{
unsignedintsize;
charformat[4];
intres1;
intref;
shortversion;
shortpad1;
intpad2;
shortchannels;
shortbitspersample;
shortcompress_id;
shortres2;
shortsamplerate1;
shortsamplerate2;
//{if(version==1)

intsampleperpacket;
intbytesperpacket;
intbytesperframe;
intbytespersample;
//}

}stsdtable;

/***** result is stored here ******/
typedefstructsampletable
{
unsignedintsize;
unsignedintid_of_sd;
}sampletable;
//MP4Analyze.cpp

#include"MP4Analyze.h"
#include<vector>
#include<map>
#include<iostream>
#include<string>
#ifdefWIN32
#include<winsock2.h>
#pragmacomment(lib,"Ws2_32.lib")
#pragmawarning(disable:4786)
#endif

#ifdef__GNUG__
#include<netinet/in.h>
#endif
usingnamespacestd;

/**
*** mp4存在寬度為8字節的wide atom tag,需要注意,這里暫未考慮
**/

/*
* check if a mov/mp4/3gp type
*/
intcheck_format(uint8_t*data,intsize)
{
if(strncmp((char*)moov,(char*)(data+4),4)==0||
strncmp((char*)ftyp,(char*)(data+4),4)==0||strncmp((char*)mdat,(char*)(data+4),4)==0)
return0;
return-1;
}

unsignedintget_size(constuint8_t*data,intsize)
{
unsignedinttmp=0;
for(inti=0;i<size;++i)
{
tmp<<=8;
tmp+=*data++;
}
returntmp;
}
/* if found,return the offset from the data[0]*/
intseek_tag(uint8_ttag[],uint8_t*data,unsignedintsize1,uint8_t**pos,unsignedint*size2)
{
if(data==NULL||size1==0)
return-1;
unsignedinttag_size=get_size(data,4);
if(tag_size>size1+8)
return-1;
unsignedinttmp=0;
while(strncmp((char*)data+4,(char*)tag,4)!=0)
{
//printf("%s/n",data+4);

if(tag_size==0)
return-1;
if(tag_size<size1+8)
{
data+=tag_size;
tmp+=tag_size;
}
else
return-1;
tag_size=get_size(data,4);
}
printf("find :%c%c%c%c/n",tag[0],tag[1],tag[2],tag[3]);
if(tmp+tag_size>size1)
printf("warning: the atom may be not complete!/n");
*pos=data+8;
*size2=tag_size-8;
returntmp;
}
/*** elementary stream descriptor analyse ***/
/*
unsigned int codec_get_tag(const AVCodecTag *tags, int id)
{
while (tags->id != CODEC_ID_NONE) {
if (tags->id == id)
return tags->tag;
tags++;
}
return 0;
}
/* may not need analyse
int esds_analyze(uint8_t *data, unsigned int size)
{
return 0;
}
*/

/*version == 2 ??? reffer to ffmpeg source mov.c line 943
if (format == MKTAG('l','p','c','m'))
st->codec->codec_id = mov_get_lpcm_codec_id(st->codec->bits_per_coded_sample, flags);
*/
vector<stsdtable>&get_audio_info(uint8_t*data,unsignedintsize,vector<stsdtable>&stable)//stsd

{
uint8_t*datapos=data;
Atom*stsd_audio=(Atom*)data;
inttmp_size=16;

printf("size : %u/n",ntohl(stsd_audio->size));
printf("num_entr: %u/n",ntohl(stsd_audio->num_of_entries));

for(inti=0;i<ntohl(stsd_audio->num_of_entries);++i)
{
if(tmp_size>size)//注意

returnstable;
datapos+=tmp_size;
stsdtable*audio_entry=(stsdtable*)(datapos);
stable.push_back(*audio_entry);//這里存入的是網絡序的數據,使用時需進行轉換

tmp_size+=ntohl(audio_entry->size);

/***************/
printf("--tablesize: %d/n",ntohl(audio_entry->size));
printf("--format : %s/n",audio_entry->format);
printf("--version : %d/n",ntohs(audio_entry->version));
printf("--channels: %d/n",ntohs(audio_entry->channels));
printf("--bitpersam: %d/n",ntohs(audio_entry->bitspersample));
printf("--IDcompress: %d/n",ntohs(audio_entry->compress_id));
printf("--samplerate: %d.%d/n",ntohs(audio_entry->samplerate1),ntohs(audio_entry->samplerate2));
/**************/

tmp_size=sizeof(stsdtable);
if(ntohs(audio_entry->version)==0)
{
tmp_size-=16;
}
datapos+=tmp_size;
//if(ntohs(audio_entry->compress_id)==-2)//此處尚需考證

if(ntohl(audio_entry->size)>sizeof(stsdtable))
{
printf("----atom size:%d/n",get_size(datapos,4));
printf("----atom name:%c%c%c%c/n",datapos[4],datapos[5],datapos[6],datapos[7]);
if(strncmp((char*)datapos,(char*)esds,4)==0)
{
//handle esds

}
}
}
returnstable;
}
map<unsignedint,sampletable>&get_packet_offset(uint8_t*STBL[],map<unsignedint,sampletable>&table)
{
//table.insert(pair<long,sampletable>(1,sample));

unsignedintnum_sam_to_chunk=get_size(STBL[0]-4,4);//stsc

unsignedintnum_sample=get_size(STBL[1]-4,4);//stsz

unsignedintnum_chunk=get_size(STBL[2]-4,4);//stco

unsignedintchunk_index=0;
unsignedintnext_chunk_index=0;
uint8_t*cur_sam_to_chunk=STBL[0];
uint8_t*cur_sam_size=STBL[1];
uint8_t*cur_chunk_offset=STBL[2];
sampletable sample;
printf("number of stsc entries:%d /nnumber of sample size:%d /nnumber of chunk offset:%d/n",num_sam_to_chunk,num_sample,num_chunk);
for(unsignedinti=0;i<num_sam_to_chunk;++i)//對所有的entries

{
chunk_index=get_size(cur_sam_to_chunk,4);
next_chunk_index=get_size(cur_sam_to_chunk+12,4);
sample.id_of_sd=get_size(cur_sam_to_chunk+8,4);
if(i==num_sam_to_chunk-1)//最后一個

{
next_chunk_index=num_chunk+1;
}
printf("chunk_index:(%d---%d)/n",chunk_index,next_chunk_index);
for(unsignedintk=chunk_index;k<next_chunk_index;++k)//當前chunk序號到下一個chunk序號之間的chunk

{//處理所有重復的chunk

printf("chunk_index:%d sample num:%d/n",chunk_index,get_size(cur_sam_to_chunk+4,4));
unsignedintoffset=get_size(cur_chunk_offset+(chunk_index-1)*4,4);
for(unsignedintj=0;j<get_size(cur_sam_to_chunk+4,4);++j)//chunk內地sample數目

{//處理該chunk中的sample

sample.size=get_size(cur_sam_size,4);
printf("--sample offset:%d %x size:%d/n",offset,offset,sample.size);
table.insert(pair<unsignedint,sampletable>(offset,sample));
offset=offset+sample.size;
cur_sam_size+=4;
}
system("pause");
chunk_index++;
}
cur_sam_to_chunk+=12;
}
returntable;
}

intseek_audio_atom(uint8_t*data1,unsignedintsize1)
{
uint8_ttag[]="mdiaminfsmhd";
uint8_t*datapos;
unsignedinttag_size;
uint8_t*data;
unsignedintsize;
intoffset_of_atom=0;
if((offset_of_atom=seek_tag(moov,data1,size1,&data,&size))==-1)
return-1;
if(offset_of_atom+size>size1)
{//some handles

printf("moov atom is not complete,need more data");
}
data1=data;
size1=size;
uint8_t*nexttrak=data;
unsignedinttraksize=size;
inti=0;
while(1)
{
printf("-----/n");
if(seek_tag(trak,nexttrak,traksize,&datapos,&tag_size)!=-1)
{
nexttrak=datapos+tag_size;
if(size1<(nexttrak-data1))
return-1;
traksize=size1-(nexttrak-data1);
data=datapos;
size=tag_size;
}
else
{
return-1;
}
i=0;
while(i<3)
{
if(seek_tag(tag+i*4,data,size,&datapos,&tag_size)!=-1)
{
if(i==2)
break;
data=datapos;
size=tag_size;
++i;
}
else
{
break;
}
}
if(strncmp("smhd",(char*)(datapos-4),4)==0)
{
if(seek_tag(stbl,data,size,&datapos,&tag_size)!=-1)
{
printf("—find audio stbl—!/n");
data=datapos;
size=tag_size;

if(seek_tag(stsd,data,size,&datapos,&tag_size)!=-1)
{
vector<stsdtable>stable;//音頻信息

get_audio_info(datapos-8,tag_size,stable);
}

uint8_t*STBL[3]={NULL,NULL,NULL};//

uint8_t*datapos1;
unsignedinttag_size1;//

if(seek_tag(stsc,data,size,&datapos1,&tag_size1)!=-1)
{
STBL[0]=datapos1+8;
}
uint8_t*datapos2;
unsignedinttag_size2;
if(seek_tag(stsz,data,size,&datapos2,&tag_size2)!=-1)
{
STBL[1]=datapos2+12;
}
uint8_t*datapos3;
unsignedinttag_size3;
if(seek_tag(stco,data,size,&datapos3,&tag_size3)!=-1)
{
STBL[2]=datapos3+8;
}
if(STBL[0]&&STBL[1]&&STBL[2])
{
map<unsignedint,sampletable>postable;//音頻幀信息

get_packet_offset(STBL,postable);
}
}
return0;
}
}
return-1;
}
intmain(chararg,char*argv[])
{
FILE*mp4;
cout<<"please input the file name :"<<endl;
stringfilename;
cin>>filename;
mp4=fopen(filename.c_str(),"rb");
uint8_tbuffer[300000];
fread(buffer,1,300000,mp4);

seek_audio_atom((uint8_t*)buffer,300000);

fclose(mp4);
return0;
}

總結

以上是生活随笔為你收集整理的MP4音频解码信息(转帖加注释)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。