Android(安卓)MediaExtractor setDataSource
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; }}
更多相关文章
- 拥抱Android:编译nginx搭建移动平台
- Android(安卓)NDK概述
- Android局部布局替换实现
- 用gradle 来打包Android
- Android(安卓)引入AspectJ的记录
- Android编译环境
- 关于Android的prelink(Linux)
- Fedora 15下使用android ndk 编译ffmepg0.8.4
- android 学习笔记1