10. Android MultiMedia框架完全解析 - MediaExtractor::Create函数的解析和FslExtractor分析

先来看看MediaExtractor所处的位置:

(一)创建流程

在GenericSource.cpp的NuPlayer::GenericSource::initFromDataSource()函数中调用了:

 

extractor = MediaExtractor::Create(mDataSource,
                mimeType.isEmpty() ? NULL : mimeType.string());

NuPlayer会为每个播放的文件,创建一个MediaExtractor,这个类的作用就是解析,概念上等同于demuxer或者Parser。MediaExtractor负责从文件中分离音视频数据,并抽象成MediaSource。MediaSource生产数据,送往MediaCodec。MediaCodec又将数据通过ACodec和OpenMAX的接口送往组件。组件解码后的数据会返回给MediaCodec,之后再由MediaCodec送往Renderer模块。

 

函数如下所示(MediaExtractor.cpp):

sp<MediaExtractor> MediaExtractor::Create(
        const sp<DataSource> &source, const char *mime) {
    sp<AMessage> meta;

    String8 tmp;
    if (mime == NULL) {
        float confidence;
        if (!source->sniff(&tmp, &confidence, &meta)) {//此时的source是FileSource
            ALOGV("FAILED to autodetect media content.");

            return NULL;
        }

        mime = tmp.string();
        ALOGV("Autodetected media content as '%s' with confidence %.2f",
             mime, confidence);
    }

    bool isDrm = false;
    // DRM MIME type syntax is "drm+type+original" where
    // type is "es_based" or "container_based" and
    // original is the content's cleartext MIME type
    if (!strncmp(mime, "drm+", 4)) {
        const char *originalMime = strchr(mime+4, '+');
        if (originalMime == NULL) {
            // second + not found
            return NULL;
        }
        ++originalMime;
        if (!strncmp(mime, "drm+es_based+", 13)) {
            // DRMExtractor sets container metadata kKeyIsDRM to 1
            return new DRMExtractor(source, originalMime);
        } else if (!strncmp(mime, "drm+container_based+", 20)) {
            mime = originalMime;
            isDrm = true;
        } else {
            return NULL;
        }
    }
    bool use_fsl = false;
    int value;
    MediaExtractor *ret = NULL;
    value = property_get_int32("media.fsl_codec.flag", 0);
    if(value & 0x01)
        use_fsl = true;

    if(isDrm)
        use_fsl = false;

    if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
            || !strcasecmp(mime, "audio/mp4")) {
        if(use_fsl)
            ret = new FslExtractor(source,mime);
        else
            ret = new MPEG4Extractor(source);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
        if(use_fsl)
            ret = new FslExtractor(source,mime);
        else
            ret = new MP3Extractor(source, meta);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
        ret = new AMRExtractor(source);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
        if(use_fsl)
            ret = new FslExtractor(source,mime);
        else
            ret = new FLACExtractor(source);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
        ret = new WAVExtractor(source);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
        ret = new OggExtractor(source);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
        if(use_fsl)
            ret = new FslExtractor(source,mime);
        else
            ret = new MatroskaExtractor(source);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
        if(use_fsl)
            ret = new FslExtractor(source,mime);
        else
            ret = new MPEG2TSExtractor(source);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
        // Return now.  WVExtractor should not have the DrmFlag set in the block below.
        return new WVMExtractor(source);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
        if(use_fsl)
            ret = new FslExtractor(source,mime);
        else
            ret = new AACExtractor(source, meta);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
        if(use_fsl)
            ret = new FslExtractor(source,mime);
        else
            ret = new MPEG2PSExtractor(source);
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) {
        ret = new MidiExtractor(source);
    } else if(!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_AVI)){
        ret = new FslExtractor(source,mime);
    } else if(!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_FLV)){
        ret = new FslExtractor(source,mime);
    } else if(!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_ASF)){
        ret = new FslExtractor(source,mime);
    } else if(!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_RMVB)){
        ret = new FslExtractor(source,mime);
    } else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_APE)) {
        ret = new FslExtractor(source,mime);
    }

    if (ret != NULL) {
       if (isDrm) {
           ret->setDrmFlag(true);
       } else {
           ret->setDrmFlag(false);
       }
    }

    return ret;
}

首先,这里的source是FileSource,FileSource的父类是DataSource,在setDataSource的过程中,NuPlayer::setDataSourceAsync函数会创建一个GenericSource,如下所示:

NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) {

    sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
    sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);

    sp<GenericSource> source =
            new GenericSource(notify, mUIDValid, mUID);

    status_t err = source->setDataSource(fd, offset, length);

    if (err != OK) {
        ALOGE("Failed to set data source!");
        source = NULL;
    }

而在这个类的构造函数中,有一个很重要的点:DataSource::RegisterDefaultSniffers();(GenericSource.cpp)

void DataSource::RegisterDefaultSniffers() {
    Mutex::Autolock autoLock(gSnifferMutex);
    if (gSniffersRegistered) {
        return;
    }

    RegisterSniffer_l(SniffMPEG4);
    RegisterSniffer_l(SniffMatroska);
    RegisterSniffer_l(SniffOgg);
    RegisterSniffer_l(SniffWAV);
    RegisterSniffer_l(SniffFLAC);
    RegisterSniffer_l(SniffAMR);
    RegisterSniffer_l(SniffMPEG2TS);
    RegisterSniffer_l(SniffMP3);
    RegisterSniffer_l(SniffAAC);
    RegisterSniffer_l(SniffMPEG2PS);
    RegisterSniffer_l(SniffWVM);
    RegisterSniffer_l(SniffMidi);
    RegisterSniffer_l(SniffFSL);

    char value[PROPERTY_VALUE_MAX];
    if (property_get("drm.service.enabled", value, NULL)
            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
        RegisterSniffer_l(SniffDRM);
    }
    gSniffersRegistered = true;
}

通过这个函数,注册了很多探测器函数,这些函数用来探测文件的类型 (探测器函数究竟是如何探测出文件类型的,一般有三种方法:1) 读取文件名的后缀;2) 解析文件头;3) 读取一小段数据,解析这段数据)。

 

继续回到MediaExtractor::Create函数中,它调用了source->sniff函数,这个函数如下所示:

bool DataSource::sniff(
        String8 *mimeType, float *confidence, sp<AMessage> *meta) {
    *mimeType = "";
    *confidence = 0.0f;
    meta->clear();

    {
        Mutex::Autolock autoLock(gSnifferMutex);
        if (!gSniffersRegistered) {
            return false;
        }
    }

	ALOGV("******* In DataSource::sniff function. ************");
    for (List<SnifferFunc>::iterator it = gSniffers.begin();
         it != gSniffers.end(); ++it) {
        String8 newMimeType;
        float newConfidence;
        sp<AMessage> newMeta;
        if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {
            if (newConfidence > *confidence) {
                *mimeType = newMimeType;
                *confidence = newConfidence;
                *meta = newMeta;
            }
        }
    }

	ALOGV("******* At end of DataSource::sniff function.  ***********");
    return *confidence > 0.0;
}

从DataSource::RegisterDefaultSniffers()中注册过的sniff中,遍历执行,理论上来说,在执行到SniffMPEG4函数时,应该能够检测出来文件类型,因为这个文件就是mp4格式的。(具体内部是如何检测的,以后添加进去,同时还可以把那个检测错误的例子添加进去。)

继续回到MediaExtractor::Create函数中,从sniff函数中出来,意味着检测出媒体类型的,然后打印出:

MediaExtractor: Autodetected media content as 'video/mp4' with confidence 0.40

 

然后,会根据媒体类型来选取对应的Extractor:

if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
            || !strcasecmp(mime, "audio/mp4")) {
        if(use_fsl)
            ret = new FslExtractor(source,mime);
        else
            ret = new MPEG4Extractor(source);
    }

对于普通的平台,mp4格式的文件,就会使用MPEG4Extractor,而对于FSL平台,会提供有FSLExtractor来使用,这些Extractor以lib库的形式存在于Android系统中,这些lib库对于解析数据有硬件加速作用,但是源码是不公开的。

 

所以对于普通的文件,都会有加速的lib库来使用,那么就创建了FslExtractor来使用,进入FslExtractor的构造函数中(FslExtractor.cpp):

FslExtractor::FslExtractor(const sp<DataSource> &source,const char *mime)
    : mDataSource(source),
    mReader(new FslDataSourceReader(mDataSource)),
    mMime(strdup(mime)),
    bInit(false),
    mFileMetaData(new MetaData)
{
    memset(&mLibName,0,255);
    mLibHandle = NULL;
    IParser = NULL;
    parserHandle = NULL;
    mFileMetaData->setCString(kKeyMIMEType, mime);
    currentVideoTs = 0;
    currentAudioTs = 0;
    mVideoActived = false;

    ALOGV("FslExtractor::FslExtractor mime=%s",mMime);
    ALOGD("FslExtractor::FslExtractor mime=%s",mMime);
}

 

创建了一个FslDataSourceReader来读取文件。

至此,MediaExtractor::Create函数分析完毕。

 

(二)FslExtractor类的解读:

class FslExtractor : public MediaExtractor
class MediaExtractor : public RefBase
class MediaExtractor : public RefBase {
public:
    static sp<MediaExtractor> Create(
            const sp<DataSource> &source, const char *mime = NULL);

    virtual size_t countTracks() = 0;
    virtual sp<MediaSource> getTrack(size_t index) = 0;

    enum GetTrackMetaDataFlags {
        kIncludeExtensiveMetaData = 1
    };
    virtual sp<MetaData> getTrackMetaData(
            size_t index, uint32_t flags = 0) = 0;

    // Return container specific meta-data. The default implementation
    // returns an empty metadata object.
    virtual sp<MetaData> getMetaData();

    enum Flags {
        CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
        CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
        CAN_PAUSE          = 4,
        CAN_SEEK           = 8,  // the "seek bar"
    };

    // If subclasses do _not_ override this, the default is
    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
    virtual uint32_t flags() const;

    // for DRM
    void setDrmFlag(bool flag) {
        mIsDrm = flag;
    };
    bool getDrmFlag() {
        return mIsDrm;
    }
    virtual char* getDrmTrackInfo(size_t trackID, int *len) {
        return NULL;
    }
    virtual void setUID(uid_t uid) {
    }

protected:
    MediaExtractor() : mIsDrm(false) {}
    virtual ~MediaExtractor() {}

private:
    bool mIsDrm;

    MediaExtractor(const MediaExtractor &);
    MediaExtractor &operator=(const MediaExtractor &);
};

这个类是个基类,定义了一些简单的函数。

 

下面是FslExtractor类的实现:

class FslExtractor : public MediaExtractor {
public:
    // Extractor assumes ownership of "source".
    FslExtractor(const sp<DataSource> &source,const char *mime);//构造函数

    virtual size_t countTracks();  //统计媒体文件中的Track数目
    virtual sp<MediaSource> getTrack(size_t index);  //获取Track
    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);//获取track元数据

    virtual sp<MetaData> getMetaData();
    virtual uint32_t flags() const;
    status_t Init();  //初始化函数
    status_t ActiveTrack(uint32 index);
    status_t DisableTrack(uint32 index);
    status_t HandleSeekOperation(uint32_t index,int64_t * ts, uint32_t flag);
    status_t GetNextSample(uint32_t index,bool is_sync);
    status_t CheckInterleaveEos(uint32_t index);
    status_t ClearTrackSource(uint32_t index);


protected:
    virtual ~FslExtractor();

private:
    sp<DataSource> mDataSource;
    FslDataSourceReader *mReader;
    char *mMime;
    bool bInit;
    char mLibName[255];
    void *mLibHandle;
    FslParserInterface * IParser;  //FslParserInterface类中包含了一个lib库向外提供的函数接口
    FslFileStream fileOps;//对于文件的操作函数集合
    ParserMemoryOps memOps;//对于内存的操作函数集合
    ParserOutputBufferOps outputBufferOps;//对于outputbuffer的操作函数集合

    uint32_t mReadMode;
    uint32_t mNumTracks;
    bool bSeekable;
    uint64_t mMovieDuration;
    struct TrackInfo {
        uint32_t mTrackNum;
        sp<FslMediaSource> mSource;
        sp<MetaData> mMeta;
        const FslExtractor *mExtractor;
        bool bCodecInfoSent;

        bool bPartial;
        sp<ABuffer> buffer;

        int64_t outTs = 0;
        int32_t syncFrame = 0;
        uint32_t max_input_size;
        uint32_t type;
        bool bIsNeedConvert;
    };
    Vector<TrackInfo> mTracks;

    sp<MetaData> mFileMetaData;

    FslParserHandle  parserHandle;

    Mutex mLock;
    int64_t currentVideoTs;
    int64_t currentAudioTs;
    bool mVideoActived;
    bool isLiveStreaming() const;
    status_t GetLibraryName();
    status_t CreateParserInterface();
    status_t ParseFromParser();
    status_t ParseMetaData();
    status_t ParseMediaFormat();
    status_t ParseVideo(uint32 index, uint32 type,uint32 subtype);
    status_t ParseAudio(uint32 index, uint32 type,uint32 subtype);
    status_t ParseText(uint32 index, uint32 type,uint32 subtype);
    int bytesForSize(size_t size);
    void storeSize(uint8_t *data, size_t &idx, size_t size);
    void addESDSFromCodecPrivate(
            const sp<MetaData> &meta,
            bool isAudio, const void *priv, size_t privSize);
    status_t addVorbisCodecInfo(
            const sp<MetaData> &meta,
            const void *_codecPrivate, size_t codecPrivateSize);

    bool isTrackModeParser();
    status_t convertPCMData(sp<ABuffer> inBuffer, sp<ABuffer> outBuffer, int32_t bitPerSample);
    FslExtractor(const FslExtractor &);
    FslExtractor &operator=(const FslExtractor &);
};

 

(三)解析文件流程

在NuPlayer::GenericSource::initFromDataSource()函数中,创建好Extractor后,随后就调用mFileMeta = extractor->getMetaData();来解析文件,来看看其内部实现(FslExtractor.cpp):

sp<MetaData> FslExtractor::getMetaData()
{
    if(!bInit){
        status_t ret = OK;
        ret = Init();

        if(ret != OK)
            return NULL;
    }
    return mFileMetaData;
}

 

跳转到Init函数中去执行了:

status_t FslExtractor::Init()
{
    status_t ret = OK;

    if(mReader == NULL)
        return UNKNOWN_ERROR;
    ALOGD("FslExtractor::Init BEGIN");
    memset (&fileOps, 0, sizeof(FslFileStream));
    fileOps.Open = appFileOpen;
    fileOps.Read= appReadFile;
    fileOps.Seek = appSeekFile;
    fileOps.Tell = appGetCurrentFilePos;
    fileOps.Size= appFileSize;
    fileOps.Close = appFileClose;
    fileOps.CheckAvailableBytes = appCheckAvailableBytes;
    fileOps.GetFlag = appGetFlag;

    memset (&memOps, 0, sizeof(ParserMemoryOps));
    memOps.Calloc = appCalloc;
    memOps.Malloc = appMalloc;
    memOps.Free= appFree;
    memOps.ReAlloc= appReAlloc;

    outputBufferOps.RequestBuffer = appRequestBuffer;
    outputBufferOps.ReleaseBuffer = appReleaseBuffer;
    ret = CreateParserInterface();
    if(ret != OK){
        ALOGE("FslExtractor create parser failed");
        return ret;
    }

    ret = ParseFromParser();

    ALOGD("FslExtractor::Init ret=%d",ret);

    if(ret == OK)
        bInit = true;
    return ret;
}

这个Init函数中,初始化了fileOps,memOps和outputBufferOps,分别为它们初始化了对应的函数指针,然后就进入CreateParserInterface函数了,这个函数如下所示:

status_t FslExtractor::CreateParserInterface()
{
    status_t ret = OK;
    int32 err = PARSER_SUCCESS;
    tFslParserQueryInterface  myQueryInterface;

    ret = GetLibraryName();
    if(ret != OK)
        return ret;

    do{
        mLibHandle = dlopen(mLibName, RTLD_NOW);
        if (mLibHandle == NULL){
            ret = UNKNOWN_ERROR;
            break;
        }
        ALOGD("load parser name %s",mLibName);
        myQueryInterface = (tFslParserQueryInterface)dlsym(mLibHandle, "FslParserQueryInterface");
        if(myQueryInterface == NULL){
            ret = UNKNOWN_ERROR;
            break;
        }

        IParser = new FslParserInterface;
        if(IParser == NULL){
            ret = UNKNOWN_ERROR;
            break;
        }

        err = myQueryInterface(PARSER_API_GET_VERSION_INFO, (void **)&IParser->getVersionInfo);
        if(err)
            break;

        if(!IParser->getVersionInfo){
            err = PARSER_ERR_INVALID_API;
            break;
        }

        // create & delete
        err = myQueryInterface(PARSER_API_CREATE_PARSER, (void **)&IParser->createParser);
        if(err)
            break;

        if(!IParser->createParser){
            err = PARSER_ERR_INVALID_API;
            break;
        }

}

这个函数中重要的部分我都用红色标出了,首先通过GetLibraryName函数获取到所需的lib库的名字,对于MP4格式的文件,所需的lib库的名字就为lib_mp4_parser_arm11_elinux.3.0.so,

status_t FslExtractor::GetLibraryName()
{
    const char * name = NULL;
    for (size_t i = 0; i < sizeof(mime_table) / sizeof(mime_table[0]); i++) {
        if (!strcmp((const char *)mMime, mime_table[i].mime)) {
            name = mime_table[i].name;
            break;
        }
    }
    if(name == NULL)
        return NAME_NOT_FOUND;

    strcpy(mLibName, "lib_");
    strcat(mLibName,name);
    strcat(mLibName,"_parser_arm11_elinux.3.0.so");

    ALOGD("GetLibraryName %s",mLibName);
    return OK;
}

然后使用dlopen函数来打开动态库,把Handler保存在mLibHandle中,这个mLibHandle就交给dlsym系统调用来使用了。有关dlopen和dlsym调用的知识,可以查看:《ShareLibarayMgr.cpp的解析》

 

然后tFslParserQueryInterface是一个函数指针:

typedef int32 (*tFslParserQueryInterface)(uint32 id, void ** func);

首先声明一个tFslParserQueryInterface类型的变量myQueryInterface,这样的话,myQueryInterface也就是一个函数指针了,然后通过强制类型转换,把dlsym(mLibHandle, "FslParserQueryInterface")也转换成一个tFslParserQueryInterface类型的函数指针,最终通过myQueryInterface(PARSER_API_GET_VERSION_INFO, (void **)&IParser->getVersionInfo);就把一个enum值与lib提供出来的接口函数统一起来。从而每个lib提供出来的函数接口就保存在FslParserInterface * IParser中了,以后如果想要使用lib库提供的函数,就只需要使用IParser中的函数接口就行,如IParser->getVersionInfo(), IParser->createParser2()等等。

 

下面继续回到FslExtractor::Init()函数中去,下一个调用的函数就是ParseFromParser();

status_t FslExtractor::ParseFromParser()
{
    int32 err = (int32)PARSER_SUCCESS;
    uint32 flag = FLAG_H264_NO_CONVERT | FLAG_OUTPUT_PTS | FLAG_ID3_FORMAT_NON_UTF8;

    uint32 trackCnt = 0;
    bool bLive = mReader->isLiveStreaming();
    ALOGI("Core parser %s \n", IParser->getVersionInfo());

    if(IParser->createParser2){
        if(bLive){
            flag |= FILE_FLAG_NON_SEEKABLE;
            flag |= FILE_FLAG_READ_IN_SEQUENCE;
        }
        err = IParser->createParser2(flag,
                &fileOps,
                &memOps,
                &outputBufferOps,
                (void *)mReader,
                &parserHandle);
        ALOGD("createParser2 flag=%x,err=%d\n",flag,err);
    }else{
        err = IParser->createParser(bLive,
                &fileOps,
                &memOps,
                &outputBufferOps,
                (void *)mReader,
                &parserHandle);
        ALOGD("createParser flag=%x,err=%d\n",flag,err);
    }

    if(PARSER_SUCCESS !=  err)
    {
        ALOGE("fail to create the parser: %d\n", err);
        return UNKNOWN_ERROR;
    }
    if(mReader->isStreaming() || !strcasecmp(mMime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)
        || !strcasecmp(mMime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS))
        mReadMode = PARSER_READ_MODE_FILE_BASED;
    else
        mReadMode = PARSER_READ_MODE_TRACK_BASED;

    err = IParser->setReadMode(parserHandle, mReadMode);
    if(PARSER_SUCCESS != err)
    {
        ALOGW("fail to set read mode to track mode\n");
        mReadMode = PARSER_READ_MODE_FILE_BASED;
        err = IParser->setReadMode(parserHandle, mReadMode);
        if(PARSER_SUCCESS != err)
        {
            ALOGE("fail to set read mode to file mode\n");
            return UNKNOWN_ERROR;
        }
    }

    if ((NULL == IParser->getNextSample && PARSER_READ_MODE_TRACK_BASED == mReadMode)
            || (NULL == IParser->getFileNextSample && PARSER_READ_MODE_FILE_BASED == mReadMode)){
        ALOGE("get next sample did not exist");
        return UNKNOWN_ERROR;
    }

    err = IParser->getNumTracks(parserHandle, &trackCnt);
    if(err)
        return UNKNOWN_ERROR;

    mNumTracks = trackCnt;
    if(IParser->initializeIndex){
        err = IParser->initializeIndex(parserHandle);
    }

    ALOGI("mReadMode=%d,mNumTracks=%u",mReadMode,mNumTracks);
    err = IParser->isSeekable(parserHandle,(bool *)&bSeekable);
    if(err)
        return UNKNOWN_ERROR;

    ALOGI("bSeekable %d", bSeekable);

    err = IParser->getMovieDuration(parserHandle, (uint64 *)&mMovieDuration);
    if(err)
        return UNKNOWN_ERROR;

    err = ParseMetaData();
    if(err)
        return UNKNOWN_ERROR;

    err = ParseMediaFormat();
    if(err)
        return UNKNOWN_ERROR;
    return OK;
}

 

首先通过IParser->getVersionInfo()获取当前使用的lib库的版本号并打印出来,然后通过IParser->createParser2来创建Parser,然后设置ReadMode,对于实时直播视频等等,它的ReadMode是PARSER_READ_MODE_FILE_BASED,对于普通文件,ReadMode是PARSER_READ_MODE_TRACK_BASED,然后把ReadMode通过IParser->setReadMode函数设置到lib库里面,这些都是lib库需要的一些参数,具体的实现在其内部。

 

之后判断IParser->getNextSample是否存在,IParser->getNextSample对应PARSER_READ_MODE_TRACK_BASED, 而IParser->getFileNextSample 对应PARSER_READ_MODE_FILE_BASED。这两个函数都是必须提供好的,如果没有这两个函数的话,就无法继续运行了。

然后就是通过IParser->getNumTracks来获取这个媒体文件的track数目,并通过IParser->isSeekable来查询文件是否可以执行seek操作。

 

然后通过ParseMetaData函数,来获取一些medatada数据,metadata数据包括title,artist,album等等,在系统中显示的这些信息就是从这里获取到的。

 

之后就是ParseMediaFormat函数了,在这个函数内部会去使用IParser->getNumPrograms, IParser->getProgramTracks,IParser->getTrackType等等操作,获取文件中的track内容和信息。然后根据解析出来的TrackTypes执行ParseVideo,ParseAudio和ParseText函数。

 

在FslExtractor::ParseVideo函数内部,分别依次调用IParser->getTrackDuration,IParser->getDecoderSpecificInfo,IParser->getBitRate,IParser->getVideoFrameWidth,IParser->getVideoFrameHeight,IParser->getVideoFrameRate等等lib库里面的函数来获取这些信息,然后打印出:

FslExtractor: ParseVideo width=1024,height=768,fps=20,rotate=0

同时呢,解析出来这些数据后,当然是把他们放在metadata数据里面比较合适啊,于是通过meta->setData把这些数据都放到metadata中。

同时,在FslExtractor中有个Vector<TrackInfo> mTracks,这里面保存着这些Track的信息,先声明一个TrackInfo结构体,然后将里面的成员变量一一赋值,最后添加到Vector中,最后打印出这句话:

FslExtractor: add video track index=0,source index=0,mime=video/avc

 

至此,ParseFromParser()函数算是分析完了,我们继续回到FslExtractor::Init()函数中,打印出这句话:FslExtractor: FslExtractor::Init ret=0

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值