stagefright之MPEG4Extractor(一)

先来看一张mp4的文件结构图:

stagefright之MPEG4Extractor(一)_第1张图片
mp4文件都是由各个box组成,box里也可以包含box,那么这种box就叫containerbox.每个box前四个字节为box的size,第二个四字节为box的type,box type有ftyp,moov,trak 等等好多种,moov是containerbox,包含mvhd、trak等box,如上图.
关于各种box的详细描述,请查看Apple官方文档:quicktime file format specification: 最权威的格式文档 点击下载
在MPEG4Extractor::parseChunk(off64_t *offset, int depth)里解析各个box,并把box里的重要媒体信息 通过track->meta->setXXX来保存。parseChunk遍历box的原理是:以当前box的偏移位置offset,加上该box的size, 就可以跳跃到下一个box。 调用一次parseChunk只解析一个box,遇到container box的话,一直递归下,直到把所有的子box 解析完。比如遇到ftype box,解析完就return了,但是遇到moov, parseChunk就递归调用自己解析所有moov包含的子box
里面的Track主要是建立video track和audio track的一个链表:mFirstTrack--->track--->mLastTrack这样的链表,一般来说,只有音视频两个track。
Track是这样一个结构体:
struct Track {
        Track *next;
        sp<MetaData> meta;
        uint32_t timescale;
        sp<SampleTable> sampleTable;
        bool includes_expensive_metadata;
        bool skipTrack;
    };


包含很重要的两个东西 meta和sampleTable,
meta主要是保存一些track的codec、language宽高、创建时间等媒体信息,通过track->meta->setXXX来保存,比如:
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(original_fourcc));
mLastTrack->meta->setCString(kKeyMediaLanguage, lang_code);
mLastTrack->meta->setInt32(kKeyWidth, width);
mLastTrack->meta->setInt32(kKeyHeight, height);
mLastTrack->meta->setInt32(kKeyDisplayWidth, width >> 16);
mLastTrack->meta->setInt32(kKeyDisplayHeight, height >> 16);
mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);

那请问我们怎么知道当前的track是video track还是audio track?
开始我以我是通过trak下面的hdlr这个子box,因为他里面有个字段用vide来标识video trak,用soun来标识audio track
后面发现我错了,实际上,去解析一个track (trak box)的时候,只要发现该track下有以下子box,就认定该track为video track,
有实际代码为证:
       
       case FOURCC('m', 'p', '4', 'v'):
        case FOURCC('e', 'n', 'c', 'v'):
        case FOURCC('s', '2', '6', '3'):
        case FOURCC('H', '2', '6', '3'):
        case FOURCC('h', '2', '6', '3'):
        case FOURCC('a', 'v', 'c', '1'):
        {
            mHasVideo = true;
           ............................
           mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
同理,audio track也一样,只要发现有如下box,就认为为audio track,       
        case FOURCC('m', 'p', '4', 'a'):
        case FOURCC('e', 'n', 'c', 'a'):
        case FOURCC('s', 'a', 'm', 'r'):
        case FOURCC('s', 'a', 'w', 'b'):
        {
        .............................
       mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));

 
 
然后在AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor)里
通过meta->findCString(kKeyMIMEType, &_mime)获取track的kKeyMIMEType来判断是video track还是audio track
我们再看上面代码片段屡次提到的FourCC2MIME,
static const char *FourCC2MIME(uint32_t fourcc) {
    switch (fourcc) {
        case FOURCC('m', 'p', '4', 'a'):
            return MEDIA_MIMETYPE_AUDIO_AAC;//audio/mp4a-latm

        case FOURCC('s', 'a', 'm', 'r'):
            return MEDIA_MIMETYPE_AUDIO_AMR_NB;//audio/3gpp

        case FOURCC('s', 'a', 'w', 'b'):
            return MEDIA_MIMETYPE_AUDIO_AMR_WB;//audio/amr-wb

        case FOURCC('m', 'p', '4', 'v'):
            return MEDIA_MIMETYPE_VIDEO_MPEG4;//video/mp4v-es

        case FOURCC('s', '2', '6', '3'):
        case FOURCC('h', '2', '6', '3'):
        case FOURCC('H', '2', '6', '3'):
            return MEDIA_MIMETYPE_VIDEO_H263;

        case FOURCC('a', 'v', 'c', '1'):
            return MEDIA_MIMETYPE_VIDEO_AVC;//video/avc

        default:
            CHECK(!"should not be here.");
            return NULL;
    }
}



你可能感兴趣的:(android,mp4,stagefright,MPEG4Extractor)