Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android MediaExtractor setDataSource

Android MediaExtractor setDataSource

編輯:關於Android編程

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::Create(
        const sp &source, const char *mime) {
    sp 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;
    }

}

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved