Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1853142
  • 博文数量: 274
  • 博客积分: 2366
  • 博客等级: 大尉
  • 技术积分: 1880
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-22 09:37
文章分类

全部博文(274)

文章存档

2022年(1)

2020年(10)

2019年(7)

2018年(18)

2017年(26)

2016年(32)

2015年(43)

2014年(30)

2013年(44)

2012年(36)

2011年(17)

2010年(10)

分类: C/C++

2012-12-05 13:43:48

MOV/3GP/MP4文件解析  

2012-04-23 14:51:41|  分类: MPEG-2解码器编程 |字号 订阅

#include

typedef unsigned char  uint8_t;
typedef unsigned short  uint16_t;
typedef unsigned int  uint32_t;
typedef unsigned __int64 uint64_t;

typedef signed char   int8_t;
typedef signed short  int16_t;
typedef signed int   int32_t;
typedef signed __int64  int64_t;

#define FOURCC(a,b,c,d)   ((a << 24) | (b << 16) | (c << 8) | d)

#define LE16(a)    (((a)[0] << 8) | (a)[1])
#define LE32(a)    (((a)[0] << 24) | ((a)[1] << 16) | ((a)[2] << 8) | (a)[3])
#define LE64(a)    ((LE32((a)) << 32) | LE32(((a) + 4)) )


#define BE16(a)    (((a)[1] << 8) | (a)[0])
#define BE32(a)    (((a)[3] << 24) | ((a)[2] << 16) | ((a)[1] << 8) | (a)[0])
#define BE64(a)    ((BE32((a) + 4) << 32) | BE32(((a))) )


#define MKINT16    LE16
#define MKINT32    LE32
#define MKINT64    LE64

#define FOURCC_ftyp    FOURCC('f','t','y','p')
#define FOURCC_moov    FOURCC('m','o','o','v')
#define FOURCC_mvhd    FOURCC('m','v','h','d')
#define FOURCC_trak    FOURCC('t','r','a','k')
#define FOURCC_tkhd    FOURCC('t','k','h','d')
#define FOURCC_edts    FOURCC('e','d','t','s')
#define FOURCC_mdia    FOURCC('m','d','i','a')
#define FOURCC_mdhd    FOURCC('m','d','h','d')
#define FOURCC_hdlr    FOURCC('h','d','l','r')
#define FOURCC_minf    FOURCC('m','i','n','f')
#define FOURCC_vmhd    FOURCC('v','m','h','d')
#define FOURCC_smhd    FOURCC('s','m','h','d')
#define FOURCC_dinf    FOURCC('d','i','n','f')
#define FOURCC_dref    FOURCC('d','r','e','f')
#define FOURCC_stbl    FOURCC('s','t','b','l')
#define FOURCC_stsd    FOURCC('s','t','s','d')
#define FOURCC_stts    FOURCC('s','t','t','s')
#define FOURCC_ctts    FOURCC('c','t','t','s')
#define FOURCC_stsc    FOURCC('s','t','s','c')
#define FOURCC_stsz    FOURCC('s','t','s','z')
#define FOURCC_stco    FOURCC('s','t','c','o')
#define FOURCC_stss    FOURCC('s','t','s','s')
#define FOURCC_stsz    FOURCC('s','t','s','z')
#define FOURCC_esds    FOURCC('e','s','d','s')

#define FOURCC_mp4a    FOURCC('m','p','4','a')
#define FOURCC_mp4v    FOURCC('m','p','4','v')
#define FOURCC_avc1    FOURCC('a','v','c','1')
#define FOURCC_avcC    FOURCC('a','v','c','C')

#define FOURCC_wave    FOURCC('w','a','v','e')
#define FOURCC_frma    FOURCC('f','r','m','a')


typedef struct
{
 uint64_t creation_time;
 uint64_t modification_time;
 uint32_t timescale;
 uint64_t duration;
}mvhd_t;

typedef struct
{
  uint32_t sample_count;
  uint32_t sample_delta;
}stts_t;

typedef struct
{
 uint32_t first_chunk;
 uint32_t first_sample;
 uint32_t samples_per_chunk;
 uint32_t samples_desc_index;
}stsc_t;

typedef struct
{
 uint32_t chunk_offset;
}stco_t;

typedef struct
{
 uint32_t sample_number;
}stss_t;

typedef struct
{
  uint32_t sample_size;
}stsz_t;

typedef struct
{
 uint64_t creation_time;
 uint64_t modification_time;
 uint32_t language;
 uint32_t handler_type;
 uint32_t track_id;
 uint32_t timescale;
 uint64_t duration;

 uint32_t codec;
 uint32_t width;
 uint32_t height;
 uint32_t channels;
 uint32_t samplesize;
 uint32_t samplerate;

 uint8_t* extra_data;
 uint32_t extra_data_size;
 uint32_t nal_size;


 stts_t*  stts;
 uint32_t stts_count;

 stsc_t* stsc;
 uint32_t stsc_count;

 stco_t* stco;
 uint32_t stco_count;

 stss_t* stss;
 uint32_t stss_count;

 stsz_t* stsz;
 uint32_t stsz_count;

 uint32_t sample_idx;
}track_t;


typedef struct
{
 uint32_t qtmux;
 mvhd_t mvhd;
 FILE* fp;

 track_t tracks[16];
 uint32_t num_tracks;
 track_t* current;

 track_t* video;
 track_t* audio;

}MP4DMX;

#ifdef __cplusplus
extern "C"
{
#endif
 
 void* mp4dmxCreate(char* filename);
 int mp4dmxGetVideoPacket(void* dmx,char* buf,uint32_t* pts);
 int mp4dmxGetAudioPacket(void* dmx,char* buf,uint32_t* pts);
 int mp4dmxDestroy(void* dmx);


#ifdef __cplusplus
}
#endif

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#ifndef __MP4DMX_C__
#define __MP4DMX_C__

#include "mp4dmx.h"

typedef struct
{
 int64_t size;
 uint32_t type;
 uint8_t uid[16];
 uint32_t version;
 uint32_t flags;
}ATOM;

static int mp4dmxParseAtom(MP4DMX* dmx,ATOM* atom);


static int mp4dmxReadVersionFlags(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[4];
 fread(buf,1,4,dmx->fp);
 atom->version = buf[0];
 atom->flags = MKINT32(buf) & 0x00ffffff;
 return 0; 
}

static int mp4dmxReadAtom(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[8];
 if(8 == fread(buf,1,8,dmx->fp))
 {
  atom->size = MKINT32(buf);
  atom->type = MKINT32(buf + 4);
  if(atom->size == 0)
  {
   return -1;
  }
  else if(atom->size == 1)
  {
   if(8 == fread(buf,1,8,dmx->fp))
   {
     atom->size = MKINT64(buf) - 16;
   }
   else
   {
    return -1;
   }
  }
  else
  {
   atom->size -= 8;
  }
  if(atom->type == FOURCC('u','u','i','d'))
  {
   if(16 != fread(atom->uid,1,16,dmx->fp))
   {
    return -1;
   }
   atom->size -= 16;
  }
  return 0;
 }
 return -1;
}

static int mp4dmxParseSkip(MP4DMX* dmx,ATOM* atom)
{
 fseek(dmx->fp,atom->size,SEEK_CUR);
 return 0;
}

static int mp4dmxParseNone(MP4DMX* dmx,ATOM* atom)
{
 return 0;
}

static int mp4dmxParseFTYP(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[4];
 fread(buf,1,4,dmx->fp);
 if(MKINT32(buf) == 0x71742020)
 {
  dmx->qtmux = 1;
 }
 else
 {
  dmx->qtmux = 0;
 }
 fseek(dmx->fp,atom->size - 4,SEEK_CUR);
 return 0;
}

static int mp4dmxParseMVHD(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[28];
 mp4dmxReadVersionFlags(dmx,atom);
 if(atom->version)
 {
  fread(buf,1,28,dmx->fp);
  dmx->mvhd.creation_time = MKINT64(buf);
  dmx->mvhd.modification_time = MKINT64(buf + 8);
  dmx->mvhd.timescale = MKINT32(buf + 16);
  dmx->mvhd.duration = MKINT64(buf + 20);
 }
 else
 {
  fread(buf,1,16,dmx->fp);
  dmx->mvhd.creation_time = MKINT32(buf);
  dmx->mvhd.modification_time = MKINT32(buf + 4);
  dmx->mvhd.timescale = MKINT32(buf + 8);
  dmx->mvhd.duration = MKINT32(buf + 12);
 }
 fseek(dmx->fp,80,SEEK_CUR);
 return 0;
}

static int mp4dmxParseTKHD(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[32];
 track_t* trk = &dmx->tracks[dmx->num_tracks++];
 dmx->current = trk;
 mp4dmxReadVersionFlags(dmx,atom);
 if(atom->version)
 {
  fread(buf,1,32,dmx->fp);
  trk->creation_time = MKINT64(buf);
  trk->modification_time = MKINT64(buf + 8);
  trk->track_id = MKINT32(buf + 16);
  trk->duration = MKINT64(buf + 20);
 }
 else
 {
  fread(buf,1,20,dmx->fp);
  trk->creation_time = MKINT32(buf);
  trk->modification_time = MKINT32(buf + 4);
  trk->track_id = MKINT32(buf + 8);
  trk->duration = MKINT32(buf + 12);
 }
 fseek(dmx->fp,52,SEEK_CUR);
 fread(buf,1,8,dmx->fp);
 trk->width = LE16(buf);
 trk->height = LE16(buf + 4);
 return 0;
}

static int mp4dmxParseMDHD(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[32];
 track_t* trk = dmx->current;
 mp4dmxReadVersionFlags(dmx,atom);
 if(atom->version)
 {
  fread(buf,1,32,dmx->fp);
  trk->creation_time = MKINT64(buf);
  trk->modification_time = MKINT64(buf + 8);
  trk->timescale = MKINT32(buf + 16);
  trk->duration = MKINT64(buf + 20);
 }
 else
 {
  fread(buf,1,16,dmx->fp);
  trk->creation_time = MKINT32(buf);
  trk->modification_time = MKINT32(buf + 4);
  trk->timescale = MKINT32(buf + 8);
  trk->duration = MKINT32(buf + 12);
 }
 fread(buf,1,4,dmx->fp);
 trk->language = LE16(buf) & 0x07ff;
 return 0;
}

static int mp4dmxParseHDLR(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[24];
 uint32_t type;
 track_t* trk = dmx->current;
 mp4dmxReadVersionFlags(dmx,atom);
 fread(buf,1,20,dmx->fp);
 type = MKINT32(buf + 4);
 if((type == FOURCC('s','o','u','n')) || (type == FOURCC('v','i','d','e')) )
 {
  trk->handler_type = type;
 }
 fseek(dmx->fp,atom->size - 24,SEEK_CUR);
 return 0;
}

static int mp4dmxParseMP4A(MP4DMX* dmx,ATOM* atom)
{
 /*mp4a section formats:
 size(32) mp4a(32) reserved(32) reserved(16) dref_id(16) version(16) revision(16) vendor(32)
 channels(16) bits_per_sample(16) packet_size(16) sample_rate(32) [16 bytes reserved in version 1,36 bytes reserved in version 2,no reserved byte in version 0]
 */
 uint32_t version;
 uint8_t buf[12];
 track_t* trk = dmx->current;
 if(atom->size > 16)
 {
  fseek(dmx->fp,8,SEEK_CUR);
  fread(buf,1,2,dmx->fp);
  version = MKINT16(buf);
  fseek(dmx->fp,6,SEEK_CUR);
  fread(buf,1,12,dmx->fp);
  trk->channels = MKINT16(buf);
  trk->samplesize = MKINT16(buf + 2);
  trk->samplerate = MKINT16(buf + 8);
  if(version == 1)
  {
   fseek(dmx->fp,16,SEEK_CUR);
  }
  else if(version == 2)
  {
   fseek(dmx->fp,36,SEEK_CUR);
  }
 }
 else
 {
  fseek(dmx->fp,atom->size,SEEK_CUR);
 }
 return 0;
}

static int mp4dmxParseAVCC(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[8];
 int i;
 int size = atom->size;
 uint8_t* extra;
 uint32_t num_sps,num_pps;
 uint16_t len;
 track_t* trk = dmx->current;
 fread(buf,1,6,dmx->fp);
 trk->nal_size = (buf[4] & 0x03) + 1;
 num_sps = buf[5] & 0x1f;
 extra = trk->extra_data = (uint8_t*)malloc(64 * 1024);
 trk->extra_data_size = 0;
 size -= 6;
 for(i = 0; i < num_sps; i ++)
 {
  fread(buf,1,2,dmx->fp);
  len = LE16(buf);
  memcpy(extra,"\0\0\0\1",4);
  fread(extra + 4,1,len,dmx->fp);
  trk->extra_data_size += len + 4;
  extra += len + 4;
  size -= 2 + len;
 }
 fread(buf,1,1,dmx->fp);
 num_pps = buf[0];
 size --;
 for(i = 0; i < num_pps; i ++)
 {
  fread(buf,1,2,dmx->fp);
  len = LE16(buf);
  memcpy(extra,"\0\0\0\1",4);
  fread(extra + 4,1,len,dmx->fp);
  trk->extra_data_size += len + 4;
  extra += len + 4;
  size -= 2 + len;
 }
 fseek(dmx->fp,size,SEEK_CUR);
 return 0;
}

static int mp4dmxParseAVC1(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[36];
 int size;
 track_t* trk = dmx->current;
 fseek(dmx->fp,24,SEEK_CUR);
 fread(buf,1,18,dmx->fp);
 trk->width = LE16(buf);
 trk->height = LE16(buf + 2);
 fread(buf,1,36,dmx->fp);
 size = atom->size - 78;
 while(size > 8)
 {
  mp4dmxReadAtom(dmx,atom);
  mp4dmxParseAtom(dmx,atom);
  size -= atom->size + 8;
 }
 fseek(dmx->fp,size,SEEK_CUR);
 return 0;
}

static int mp4dmxParseSTSC(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[12];
 stsc_t* stsc;
 int i;
 int num_chunk,first_sample = 1;
 track_t* trk = dmx->current;
 mp4dmxReadVersionFlags(dmx,atom);
 fread(buf,1,4,dmx->fp);
 trk->stsc_count = MKINT32(buf);
 stsc = trk->stsc = (stsc_t*)malloc(sizeof(stsc_t) * trk->stsc_count);
 if(trk->stsc)
 {
  for(i = 0; i < trk->stsc_count; i ++)
  {
   fread(buf,1,12,dmx->fp);
   stsc->first_sample = 1;
   stsc->first_chunk = MKINT32(buf);
   stsc->samples_per_chunk = MKINT32(buf + 4);
   stsc->samples_desc_index = MKINT32(buf + 8);
   stsc ++;
  }
  stsc = trk->stsc;
  for(i = 0; i < trk->stsc_count - 1; i ++,stsc++)
  {
   num_chunk = (stsc + 1)->first_chunk - stsc->first_chunk;
   stsc->first_sample = first_sample;
   first_sample += stsc->samples_per_chunk * num_chunk;
  }
 }
 else
 {
  fseek(dmx->fp,atom->size - 8,SEEK_CUR);
 }
 return 0;
}

static int mp4dmxParseSTCO(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[4];
 stco_t* stco;
 int i;
 track_t* trk = dmx->current;
 mp4dmxReadVersionFlags(dmx,atom);
 fread(buf,1,4,dmx->fp);
 trk->stco_count = MKINT32(buf);
 stco = trk->stco = (stco_t*)malloc(sizeof(stco_t) * trk->stco_count);
 if(trk->stco)
 {
  for(i = 0; i < trk->stco_count; i ++)
  {
   fread(buf,1,4,dmx->fp);
   stco->chunk_offset = MKINT32(buf);
   stco ++;
  }
 }
 else
 {
  fseek(dmx->fp,atom->size - 8,SEEK_CUR);
 }
 return 0;
}


static int mp4dmxParseSTSS(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[4];
 stss_t* stss;
 int i;
 track_t* trk = dmx->current;
 mp4dmxReadVersionFlags(dmx,atom);
 fread(buf,1,4,dmx->fp);
 trk->stss_count = MKINT32(buf);
 stss = trk->stss = (stss_t*)malloc(sizeof(stss_t) * trk->stss_count);
 if(trk->stss)
 {
  for(i = 0; i < trk->stss_count; i ++)
  {
   fread(buf,1,4,dmx->fp);
   stss->sample_number = MKINT32(buf);
   stss ++;
  }
 }
 else
 {
  fseek(dmx->fp,atom->size - 8,SEEK_CUR);
 }
 return 0;
}

static int mp4dmxParseESDS(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[4];
 int size = atom->size;
 int pos = ftell(dmx->fp);
 track_t* trk = dmx->current;
 mp4dmxReadVersionFlags(dmx,atom);
 while(size > 2)
 {
  fread(buf,1,1,dmx->fp);
  switch(buf[0])
  {
  case 0x03:/*ESDescriptor_tag(8) + len(8) + esid(16) + priorty(8)*/
   fseek(dmx->fp,4,SEEK_CUR);
   size -= 5;
   break;
  case 0x04:/*DecoderConfigDescrTag(8) + len(8) + ObjectType(8) + streamType(8) + buffersize(24) + maxbitrate(32) + avgbitrage(32)*/
   fseek(dmx->fp,14,SEEK_CUR);
   size -= 15;
   break;
  case 0x05:/*DecodeSpecificInfoTag(8) + len(8) + infos(len * 8)*/
   fread(buf,1,1,dmx->fp);
   trk->extra_data = (uint8_t*)malloc(buf[0]);
   trk->extra_data_size = buf[0];
   fread(trk->extra_data,1,trk->extra_data_size,dmx->fp);
   size -= 2 + buf[0];
   break;
  case 0x06:/*SLConfigDescriptorTag(8) + len(8) + infos(len * 8)*/
  default:
   size = 0;
   break;
  }
 }
 fseek(dmx->fp,pos,SEEK_SET);
 fseek(dmx->fp,atom->size,SEEK_CUR);
 return 0;
}


static int mp4dmxParseSTSZ(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[8];
 stsz_t* stsz;
 int i;
 uint32_t sample_size,sample_count;
 track_t* trk = dmx->current;
 mp4dmxReadVersionFlags(dmx,atom);
 fread(buf,1,8,dmx->fp);
 sample_size = MKINT32(buf);
 sample_count = MKINT32(buf + 4);
 
 trk->stsz_count = sample_count;
 stsz = trk->stsz = (stsz_t*)malloc(sizeof(stsz_t) * trk->stsz_count);
 if(trk->stsz)
 {
  if(!sample_size)
  {
   for(i = 0; i < trk->stsz_count; i ++)
   {
    fread(buf,1,4,dmx->fp);
    stsz->sample_size = MKINT32(buf);
    stsz ++;
   }
  }
  else
  {
   for(i = 0; i < trk->stsz_count; i ++)
   {
    stsz->sample_size = sample_size;
    stsz ++;
   }
  }
 }
 else
 {
  fseek(dmx->fp,atom->size - 12,SEEK_CUR);
 }
 return 0;
}


static int mp4dmxParseSTTS(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[8];
 stts_t* stts;
 int i;
 track_t* trk = dmx->current;
 mp4dmxReadVersionFlags(dmx,atom);
 fread(buf,1,4,dmx->fp);
 trk->stts_count = MKINT32(buf);
 stts = trk->stts = (stts_t*)malloc(sizeof(stts_t) * trk->stts_count);
 if(trk->stts)
 {
  for(i = 0; i < trk->stts_count; i ++)
  {
   fread(buf,1,8,dmx->fp);
   stts->sample_count = MKINT32(buf);
   stts->sample_delta = MKINT32(buf + 4);
   stts ++;
  }
 }
 else
 {
  fseek(dmx->fp,atom->size - 8,SEEK_CUR);
 }
 return 0;
}

static int mp4dmxParseSTSD(MP4DMX* dmx,ATOM* atom)
{
 uint8_t buf[24];
 int i;
 track_t* trk = dmx->current;
 ATOM fmt;
 mp4dmxReadVersionFlags(dmx,atom);
 fread(buf,1,4,dmx->fp);
 i = LE32(buf);
 while(i--)
 {
  switch(trk->handler_type)
  {
  case FOURCC('s','o','u','n'):
   if(!dmx->audio)
   {
    dmx->audio = trk;
   }
   mp4dmxReadAtom(dmx,&fmt);
   trk->codec = fmt.type;/*codec type should detects by esds,if it exists,other wise it is the default!*/
   return mp4dmxParseAtom(dmx,&fmt);
   break;
  case FOURCC('v','i','d','e'):
   if(!dmx->video)
   {
    dmx->video = trk;
   }
   mp4dmxReadAtom(dmx,&fmt);
   trk->codec = fmt.type;/*codec type should detects by esds,if it exists,other wise it is the default!*/
   return mp4dmxParseAtom(dmx,&fmt);
  default:
   fseek(dmx->fp,atom->size - 8,SEEK_CUR);
   return 0;
  }
 }
 fseek(dmx->fp,atom->size,SEEK_CUR);
 return 0;
}

 


static int mp4dmxParseAtom(MP4DMX* dmx,ATOM* atom)
{
 typedef int (*ATOMPARSER)(MP4DMX* dmx,ATOM* atom);
 typedef struct
 {
  uint32_t type;
  ATOMPARSER parse;
 }ATOMCALLBACK;
 ATOMCALLBACK callbacks[] = 
 {
  {FOURCC_ftyp,mp4dmxParseFTYP},
  {FOURCC_moov,mp4dmxParseNone},
  {FOURCC_mvhd,mp4dmxParseMVHD},
  {FOURCC_trak,mp4dmxParseNone},
  {FOURCC_tkhd,mp4dmxParseTKHD},
  {FOURCC_edts,mp4dmxParseNone},
  {FOURCC_mdia,mp4dmxParseNone},
  {FOURCC_mdhd,mp4dmxParseMDHD},
  {FOURCC_hdlr,mp4dmxParseHDLR},
  {FOURCC_minf,mp4dmxParseNone},
  {FOURCC_dinf,mp4dmxParseNone},
  {FOURCC_stbl,mp4dmxParseNone},
  {FOURCC_stsd,mp4dmxParseSTSD},
  {FOURCC_mp4a,mp4dmxParseMP4A},
  {FOURCC_avc1,mp4dmxParseAVC1},
  {FOURCC_avcC,mp4dmxParseAVCC},
  {FOURCC_stts,mp4dmxParseSTTS},
  {FOURCC_stsc,mp4dmxParseSTSC},
  {FOURCC_stco,mp4dmxParseSTCO},
  {FOURCC_stss,mp4dmxParseSTSS},
  {FOURCC_stsz,mp4dmxParseSTSZ},
  {FOURCC_wave,mp4dmxParseNone},
  {FOURCC_frma,mp4dmxParseSkip},
  {FOURCC_esds,mp4dmxParseESDS},
  {FOURCC_mp4v,mp4dmxParseAVC1},
 };
 int i;
 printf("ATOM:type = %c%c%c%c,size = %I64d\n",atom->type >> 24,atom->type >> 16,atom->type >> 8,atom->type & 0xff,atom->size);
 for(i = 0; i < sizeof(callbacks) / sizeof(ATOMCALLBACK); i ++)
 {
  if(atom->type == callbacks[i].type)
  {
   return callbacks[i].parse(dmx,atom);
  }
 }
 return mp4dmxParseSkip(dmx,atom);
}


static int mp4dmxParseHeader(MP4DMX* dmx)
{
 ATOM atom;
 while(0 == mp4dmxReadAtom(dmx,&atom))
 {
  mp4dmxParseAtom(dmx,&atom);
 }
 return 0;
}


void* mp4dmxCreate(char* filename)
{
 int i;
 MP4DMX* dmx = (MP4DMX*)malloc(sizeof(MP4DMX));
 if(dmx)
 {
  memset(dmx,0,sizeof(MP4DMX));
  dmx->fp = fopen(filename,"rb");
  if(!dmx->fp)
  {
   free(dmx);
   return NULL;
  }
  mp4dmxParseHeader(dmx);
 }
 return dmx;
}

static int mp4dmxQueryNextSampleInfo(track_t* trk,uint32_t* offset,uint32_t* size,uint32_t* pts)
{
 stsc_t* stsc;
 stts_t* stts;
 uint32_t chunk;
 uint32_t num_chunk;
 uint32_t sample_last;
 int i,j;
 if(trk->sample_idx > trk->stsz_count)
 {
  return -1;
 }
 if(trk->stsc_count < 2)
 {
  uint32_t first_sample = 1;
  int idx = trk->stsc->samples_desc_index;
  trk->stsc_count = trk->stsz_count;
  trk->stsc = (stsc_t*)realloc(trk->stsc,sizeof(stsc_t) * trk->stsz_count);
  stsc = trk->stsc;
  for(i = 0; i < trk->stsc_count - 1; i ++,stsc++)
  {
   stsc->first_sample = first_sample;
   stsc->first_chunk = i + 1;
   stsc->samples_per_chunk = 1;
   stsc->samples_desc_index = idx;
   first_sample += stsc->samples_per_chunk;
  }
 }

 *size = trk->stsz[trk->sample_idx - 1].sample_size;

 *pts = 0;
 sample_last = 1;
 for(stts = trk->stts,i = 0; i < trk->stts_count; i ++,stts++)
 {
  for(j = 0; j < stts->sample_count; j ++,sample_last++)
  {
   if(sample_last == trk->sample_idx)
   {
    i = trk->stts_count;
    break;
   }
   (*pts) += stts->sample_delta;
  }
 }

 (*pts) = (*pts) / (double)trk->timescale * 1000.0f;

 *offset = 0;
 for(stsc = trk->stsc,i = 0; i < trk->stsc_count; i ++,stsc++)
 {
  if(i < trk->stsc_count - 1)
  {
   num_chunk = (stsc + 1)->first_chunk - stsc->first_chunk;
  }
  else
  {
   num_chunk = 1;
  }
  sample_last = stsc->first_sample + num_chunk * stsc->samples_per_chunk;
  if(trk->sample_idx >= stsc->first_sample && trk->sample_idx < sample_last)
  {
   chunk = stsc->first_chunk + (trk->sample_idx - stsc->first_sample) / stsc->samples_per_chunk;
   for(i = stsc->first_sample + (chunk - stsc->first_chunk) * stsc->samples_per_chunk; i < trk->sample_idx; i ++)
   {
    (*offset) += trk->stsz[i - 1].sample_size;
   }
   (*offset) += trk->stco[chunk - 1].chunk_offset;
   return 0;
  }
 }
 return -1;
}

static int mp4dmxBuildADTSHeader(unsigned char* buf,int samplerate,int num_channels,int size)
{
 int idx;
 size += 7;
 if(samplerate <= 8000)
 {
  idx = 0x0b;
 }
 else if(samplerate <= 11025)
 {
  idx = 0x0a;
 }
 else if(samplerate <= 12000)
 {
  idx = 0x09;
 }
 else if(samplerate <= 16000)
 {
  idx = 0x08;
 }
 else if(samplerate <= 22050)
 {
  idx = 0x07;
 }
 else if(samplerate <= 24000)
 {
  idx = 0x06;
 }
 else if(samplerate <= 32000)
 {
  idx = 0x05;
 }
 else if(samplerate <= 44100)
 {
  idx = 0x04;
 }
 else if(samplerate <= 48000)
 {
  idx = 0x03;
 }
 else if(samplerate <= 64000)
 {
  idx = 0x02;
 }
 else if(samplerate <= 88200)
 {
  idx = 0x01;
 }
 else
 {
  idx = 0x00;
 }

 buf[0] = 0xff;
 buf[1] = 0xf9;/*MPEG2-AAC*/
 buf[2] = (0x01 << 6) | (idx << 2) | (num_channels >> 2); /*D7 - D6:profile 01,D5 - D2:idx,D1:1,D0:channels >> 2*/
 buf[3] = ((num_channels & 0x03) << 6) | ((size >> 11) & 0x03);/*D7 - D6:channels & 0x03,D5 - D4:0 0 ,D3 - D2: 0 0,D1 - D0:size >> 11*/
 buf[4] = ((size >> 3) & 0xff);/*(size >> 3) & 0xff*/
 buf[5] = ((size & 0x07) << 5) | 0x0f;/*D7 - D5:size & 0x07,D4 - D0:bufsize >> 6*/
 buf[6] = (0x3f << 2);/*D7 - D2:buszie & 0x3f, D1 - D0:00*/
 return 7;
}

static int mp4dmxQueryNextSample(MP4DMX* dmx,track_t* trk,uint8_t* buf,uint32_t offset,int32_t size)
{
 uint8_t sbuf[4];
 int len;
 int result = size;
 fseek(dmx->fp,offset,SEEK_SET);
 switch(trk->codec)
 {
 case FOURCC_avc1:
  while(size > 0)
  {
   fread(sbuf,1,trk->nal_size,dmx->fp);
   switch(trk->nal_size)
   {
   case 1:
    len = sbuf[0];
    break;
   case 2:
    len = LE16(sbuf);
    break;
   default:
    len = LE32(sbuf);
    break;
   }
   memcpy(buf,"\0\0\0\1",4);
   fread(buf + 4,1,len,dmx->fp);
   buf += 4 + len;
   size -= len + trk->nal_size;
  }
  break;
 case FOURCC_mp4a:
  mp4dmxBuildADTSHeader(buf,trk->samplerate,trk->channels,size);
  buf += 7;
  result += 7;
 default:
  fread(buf,1,size,dmx->fp);
  break;
 }
 return result;
}

int mp4dmxGetVideoPacket(void* hdl,char* buf,uint32_t* pts)
{
 uint32_t offset,size;
 MP4DMX* dmx = (MP4DMX*)hdl;
 if(dmx->video)
 {
  if(dmx->video->extra_data)
  {
   if(dmx->video->sample_idx == 0)
   {
    *pts = 0;
    ++dmx->video->sample_idx;
    memcpy(buf,dmx->video->extra_data,dmx->video->extra_data_size);
    return dmx->video->extra_data_size;
   }
  }
  else 
  {
   if(dmx->video->sample_idx == 0)
   {
    ++dmx->video->sample_idx;
   }
  }
  if(0 == mp4dmxQueryNextSampleInfo(dmx->video,&offset,&size,pts))
  {
   ++dmx->video->sample_idx;
   return mp4dmxQueryNextSample(dmx,dmx->video,buf,offset,size);
  }
 }
 return -1;
}

int mp4dmxGetAudioPacket(void* hdl,char* buf,uint32_t* pts)
{
 uint32_t offset,size;
 MP4DMX* dmx = (MP4DMX*)hdl;
 if(dmx->audio)
 {
  *pts = 0;
  if(dmx->audio->extra_data)
  {
   if(dmx->audio->sample_idx == 0)
   {
    ++dmx->audio->sample_idx;
    memcpy(buf,dmx->audio->extra_data,dmx->audio->extra_data_size);
    return dmx->audio->extra_data_size;
   }
  }
  else
  {
   if(dmx->audio->sample_idx == 0)
   {
    ++dmx->audio->sample_idx;
   }
  }
  if(0 == mp4dmxQueryNextSampleInfo(dmx->audio,&offset,&size,pts))
  {
   ++dmx->audio->sample_idx;
   return mp4dmxQueryNextSample(dmx,dmx->audio,buf,offset,size);
  }
 }
 return -1;
}

int mp4dmxDestroy(void* hdl)
{
 int i;
 MP4DMX* dmx = (MP4DMX*)hdl;
 for(i = 0; i < sizeof(dmx->tracks) / sizeof(track_t); i ++)
 {
  if(dmx->tracks[i].extra_data)
  {
   free(dmx->tracks[i].extra_data);
  }
  if(dmx->tracks[i].stts)
  {
   free(dmx->tracks[i].stts);
  }
  if(dmx->tracks[i].stsc)
  {
   free(dmx->tracks[i].stsc);
  }
  if(dmx->tracks[i].stco)
  {
   free(dmx->tracks[i].stco);
  }
  if(dmx->tracks[i].stss)
  {
   free(dmx->tracks[i].stss);
  }
  if(dmx->tracks[i].stsz)
  {
   free(dmx->tracks[i].stsz);
  }

 }
 fclose(dmx->fp);
 free(dmx);
 return 0;
}

 

 

static char buf[1024 * 1024 * 2];

int main()
{
 int i;
 int size;
 uint32_t pts;
 int noVideo = 0,noAudio = 0;
 int first_video_pts = -1,last_video_pts;
 int first_audio_pts = -1,last_audio_pts;
 int video_frames_count = 0;
 int audio_frames_count = 0;
 FILE* vo = fopen("c:\\test.video","wb");
 FILE* ao = fopen("c:\\test.audio","wb");
 MP4DMX* dmx = mp4dmxCreate("c:\\panda.mov");
 printf("Extract Video & Audio Streams now,please wait...\n");
 while(dmx && (!noAudio || !noVideo))
 {
  size = mp4dmxGetVideoPacket(dmx,buf,&last_video_pts);
  if(size > 0)
  {
   if(first_video_pts == -1)
   {
    first_video_pts = last_video_pts;
   }
   noVideo = 0;
   fwrite(buf,1,size,vo);
   video_frames_count ++;
  }
  else
  {
   noVideo = 1;
  }
  size = mp4dmxGetAudioPacket(dmx,buf,&last_audio_pts);
  if(size > 0)
  {
   if(first_audio_pts == -1)
   {
    first_audio_pts = last_audio_pts;
   }
   noAudio = 0;
   fwrite(buf,1,size,ao);
   audio_frames_count ++;
  }
  else
  {
   noAudio = 1;
  }
  }
 fclose(vo);
 fclose(ao);
 mp4dmxDestroy(dmx);
 printf("Video %d frames extracted,duration = %8.2f seconds!\r\nAudio %d frames extracted,duration = %8.2f seconds!\n",video_frames_count,(last_video_pts - first_video_pts ) / 1000.0f,audio_frames_count,(last_audio_pts - first_audio_pts ) / 1000.0f);
 return 0;
}

 


#endif
阅读(2034) | 评论(0) | 转发(0) |
0

上一篇:转 rtsp

下一篇:转 共享内存

给主人留下些什么吧!~~