|
//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;
}
|