Android MediaExtractor setDataSource

0. setDataSource时序图

Android MediaExtractor setDataSource_第1张图片

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 = 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 ExtendedUtils::MediaExtractor_CreateIfNeeded(sp defaultExt,
                                                            const sp &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 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  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 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;
    }

}

你可能感兴趣的:(Android,Android,FFmpeg多媒体)