0. setDataSource时序图

1. MediaExtractor(java)

file: frameworks/base/media/java/android/mediaf/MediaExtractor.java
目前Android 5.0仅支持本地视频

    public final void setDataSource(FileDescriptor fd) throws IOException {        setDataSource(fd, 0, 0x7ffffffffffffffL);    }

这会调用JNI setDataSource

2. android_media_MediaExtractor(native)

file: frameworks/base/media/jni/android_media_MediaExtractor.cpp
native的setDataSource是调用NuMediaExtractor的setDataSource

status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {    return mImpl->setDataSource(fd, offset, size);}

3. NuMediaExtractor

file:frameworks/av/media/libstagefright/NuMediaExtractor.cpp
NuMediaExtractor先创建FileSource
然后根据FileSource创建相应的Extractor

status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {    ...    sp<FileSource> fileSource = new FileSource(dup(fd), offset, size);    mImpl = MediaExtractor::Create(fileSource);    ...    mDataSource = fileSource;    updateDurationAndBitrate();    return OK;}

4. New FileSource

FileSource继承于DataSource。
FileSource初始化函数执行操作有:打开文件,获取文件FD,Seek文件

FileSource::FileSource(const char *filename)    : mFd(-1),      mOffset(0),      mLength(-1),      mDecryptHandle(NULL),      mDrmManagerClient(NULL),      mDrmBufOffset(0),      mDrmBufSize(0),      mDrmBuf(NULL){    mFd = open(filename, O_LARGEFILE | O_RDONLY);    if (mFd >= 0) {        mLength = lseek64(mFd, 0, SEEK_END);    } else {        ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));    }}

DataSource初始化函数执行操作有:new Sniffer

    DataSource() : mSniffer(new Sniffer()) {}

Sniffer构造过程:注册各个Extractor的Sniffer函数
registerDefaultSniffers

void Sniffer::registerDefaultSniffers() {    Mutex::Autolock autoLock(mSnifferMutex);    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(ExtendedExtractor::Sniff);    char value[PROPERTY_VALUE_MAX];    if (property_get("drm.service.enabled", value, NULL)            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {        registerSniffer_l(SniffDRM);    }}

5. MediaExtractor::Create

file:frameworks/av/media/libstagefright/MediaExtractor.cpp
MediaExtractor(C++)是MediaExtractor体系中核心,是各个extractor(eg.MPEG4Extractor)的父类,管理者.
Create它根据文件的MIME信息创建对应的Extractor,具体逻辑如下:
(1)sniff : 获取文件meta信息
(2)根据meta中的MIME创建对应的Extractor
(3)ExtendedUtils判断创建默认Extractor还是扩展Extractor

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)) {            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;        }    }    MediaExtractor *ret = NULL;    if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)            || !strcasecmp(mime, "audio/mp4")) {        ret = new MPEG4Extractor(source);    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {        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)) {        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)) {        ret = new MatroskaExtractor(source);    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {        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)) {        ret = new AACExtractor(source, meta);    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {        ret = new MPEG2PSExtractor(source);    }    if (ret != NULL) {       if (isDrm) {           ret->setDrmFlag(true);       } else {           ret->setDrmFlag(false);       }    }    return ExtendedUtils::MediaExtractor_CreateIfNeeded(ret, source, mime);}

6. ExtendedUtils::MediaExtractor_CreateIfNeeded

MediaExtractor_CreateIfNeeded的作用如其名就是判断是否需要启用ExtentedExtractor。
如果看源代码的话会发现整个过程比较繁琐,下面说下启用ExtentedExtractor的原则,(如果需要深究还是仔细阅读源代码好了),原则如下:
(1)尽量采用ExtentedExtractor
因为DefaultExtractor是google的decoder,采用的是软解;ExtentedExtractor一般是厂商的decoder,通常采用硬解。
(2)如果无法正确获取多媒体信息则采用ExtentedExtractor
(3)如果没有找到DefaultExtractor则采用ExtentedExtractor
(4)对于某些特殊格式采用ExtentedExtractor
比如MPEG4格式,这个一般厂商都支持硬解。

sp<MediaExtractor> ExtendedUtils::MediaExtractor_CreateIfNeeded(sp<MediaExtractor> defaultExt,                                                            const sp<DataSource> &source,                                                            const char *mime) {    bool bCheckExtendedExtractor = false;    bool videoTrackFound         = false;    bool audioTrackFound         = false;    bool amrwbAudio              = false;    bool hevcVideo               = false;    bool dolbyAudio              = false;    bool mpeg4Container          = false;    bool aacAudioTrack           = false;    int  numOfTrack              = 0;    mpeg4Container = !strncasecmp(mime,                                MEDIA_MIMETYPE_CONTAINER_MPEG4,                                strlen(MEDIA_MIMETYPE_CONTAINER_MPEG4));    if (defaultExt != NULL) {        for (size_t trackItt = 0; trackItt < defaultExt->countTracks(); ++trackItt) {            ++numOfTrack;            sp<MetaData> meta = defaultExt->getTrackMetaData(trackItt);            const char *_mime;            CHECK(meta->findCString(kKeyMIMEType, &_mime));            String8 mime = String8(_mime);            const char * dolbyFormats[ ] = {                MEDIA_MIMETYPE_AUDIO_AC3,                MEDIA_MIMETYPE_AUDIO_EAC3,#ifdef DOLBY_UDC                MEDIA_MIMETYPE_AUDIO_EAC3_JOC,#endif            };            if (!strncasecmp(mime.string(), "audio/", 6)) {                audioTrackFound = true;                amrwbAudio = !strncasecmp(mime.string(),                                          MEDIA_MIMETYPE_AUDIO_AMR_WB,                                          strlen(MEDIA_MIMETYPE_AUDIO_AMR_WB));                aacAudioTrack = !strncasecmp(mime.string(),                                          MEDIA_MIMETYPE_AUDIO_AAC,                                          strlen(MEDIA_MIMETYPE_AUDIO_AAC));                for (size_t i = 0; i < ARRAY_SIZE(dolbyFormats); i++) {                    if (!strncasecmp(mime.string(), dolbyFormats[i], strlen(dolbyFormats[i]))) {                        dolbyAudio = true;                    }                }                if (amrwbAudio || dolbyAudio) {                    break;                }            } else if (!strncasecmp(mime.string(), "video/", 6)) {                videoTrackFound = true;                if(!strncasecmp(mime.string(), "video/hevc", 10)) {                    hevcVideo = true;                }            }        }        if (amrwbAudio || dolbyAudio) {            bCheckExtendedExtractor = true;        } else if (numOfTrack  == 0) {            bCheckExtendedExtractor = true;        } else if (numOfTrack == 1) {            if ((videoTrackFound) ||                (!videoTrackFound && !audioTrackFound) ||                (audioTrackFound && mpeg4Container && aacAudioTrack)) {                bCheckExtendedExtractor = true;            }        } else if (numOfTrack >= 2) {            if (videoTrackFound && audioTrackFound) {                if (amrwbAudio || hevcVideo ) {                    bCheckExtendedExtractor = true;                }            } else {                bCheckExtendedExtractor = true;            }        }    } else {        bCheckExtendedExtractor = true;    }    if (!bCheckExtendedExtractor) {        ALOGD("extended extractor not needed, return default");        return defaultExt;    }    //Create Extended Extractor only if default extractor is not selected    ALOGD("Try creating ExtendedExtractor");    sp<MediaExtractor>  retExtExtractor = ExtendedExtractor::Create(source, mime);    if (retExtExtractor == NULL) {        ALOGD("Couldn't create the extended extractor, return default one");        return defaultExt;    }    if (defaultExt == NULL) {        ALOGD("default extractor is NULL, return extended extractor");        return retExtExtractor;    }    //bCheckExtendedExtractor is true which means default extractor was found    //but we want to give preference to extended extractor based on certain    //conditions.    //needed to prevent a leak in case both extractors are valid    //but we still dont want to use the extended one. we need    //to delete the new one    bool bUseDefaultExtractor = true;    const char * extFormats[ ] = {        MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,        MEDIA_MIMETYPE_VIDEO_HEVC,        MEDIA_MIMETYPE_AUDIO_AC3,        MEDIA_MIMETYPE_AUDIO_EAC3,#ifdef DOLBY_UDC        MEDIA_MIMETYPE_AUDIO_EAC3_JOC,#endif        MEDIA_MIMETYPE_AUDIO_AAC,    };    for (size_t trackItt = 0; (trackItt < retExtExtractor->countTracks()); ++trackItt) {        sp<MetaData> meta = retExtExtractor->getTrackMetaData(trackItt);        const char *mime;        bool success = meta->findCString(kKeyMIMEType, &mime);        bool isExtFormat = false;        for (size_t i = 0; i < ARRAY_SIZE(extFormats); i++) {            if (!strncasecmp(mime, extFormats[i], strlen(extFormats[i]))) {                isExtFormat = true;                break;            }        }        if ((success == true) && isExtFormat) {            ALOGD("Discarding default extractor and using the extended one");            bUseDefaultExtractor = false;            break;        }    }    if (bUseDefaultExtractor) {        ALOGD("using default extractor inspite of having a new extractor");        retExtExtractor.clear();        return defaultExt;    } else {        defaultExt.clear();        return retExtExtractor;    }}

更多相关文章

  1. 拥抱Android:编译nginx搭建移动平台
  2. Android(安卓)NDK概述
  3. Android局部布局替换实现
  4. 用gradle 来打包Android
  5. Android(安卓)引入AspectJ的记录
  6. Android编译环境
  7. 关于Android的prelink(Linux)
  8. Fedora 15下使用android ndk 编译ffmepg0.8.4
  9. android 学习笔记1

随机推荐

  1. Android(安卓)5.x特性概览三
  2. (转帖)Android系列之Wifi定位
  3. Android处理后台返回数据——Json转实体
  4. Android学习蛋疼集锦(Android启动流程)
  5. 优秀的Android文件管理器
  6. 新浪微博Android客户端学习记录一:完成Log
  7. Android知识点——更改软键盘回车键
  8. android:scaleType属性
  9. Android控件GridView的使用
  10. Android 自定义TextView 实现文本间距