从Android 2.3开始,Android MediaPlayer采用Stagefright框架。Based on Android 4.0.1.
StagefrightPlayer创建函数如下:(MediaPlayerService.cpp,详细过程见文章:Android Audio 数据流详解)
- static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
- notify_callback_f notifyFunc)
- {
- sp<MediaPlayerBase> p;
- switch (playerType) {
- case SONIVOX_PLAYER:
- LOGV(" create MidiFile");
- p = new MidiFile();
- break;
- case STAGEFRIGHT_PLAYER:
- LOGV(" create StagefrightPlayer");
- p = new StagefrightPlayer;
- break;
- case NU_PLAYER:
- LOGV(" create NuPlayer");
- p = new NuPlayerDriver;
- break;
- case TEST_PLAYER:
- LOGV("Create Test Player stub");
- p = new TestPlayerStub();
- break;
- default:
- LOGE("Unknown player type: %d", playerType);
- return NULL;
- }
- if (p != NULL) {
- if (p->initCheck() == NO_ERROR) {
- p->setNotifyCallback(cookie, notifyFunc);
- } else {
- p.clear();
- }
- }
- if (p == NULL) {
- LOGE("Failed to create player object");
- }
- return p;
- }
- static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
- notify_callback_f notifyFunc)
- {
- sp<MediaPlayerBase> p;
- switch (playerType) {
- case SONIVOX_PLAYER:
- LOGV(" create MidiFile");
- p = new MidiFile();
- break;
- case STAGEFRIGHT_PLAYER:
- LOGV(" create StagefrightPlayer");
- p = new StagefrightPlayer;
- break;
- case NU_PLAYER:
- LOGV(" create NuPlayer");
- p = new NuPlayerDriver;
- break;
- case TEST_PLAYER:
- LOGV("Create Test Player stub");
- p = new TestPlayerStub();
- break;
- default:
- LOGE("Unknown player type: %d", playerType);
- return NULL;
- }
- if (p != NULL) {
- if (p->initCheck() == NO_ERROR) {
- p->setNotifyCallback(cookie, notifyFunc);
- } else {
- p.clear();
- }
- }
- if (p == NULL) {
- LOGE("Failed to create player object");
- }
- return p;
- }
首先了解下系统本身的调用流程,StagefrightPlayer使用的AwesomePlayer来实现的,首先是Demuxer的实现,对于系统本身不支持的格式是没有分离器的,具体查看代码(本文以本地文件播放为例).
1. Demuxer的实现
Awesomeplayer.cpp的setDataSource_l(
const sp<DataSource> &dataSource) {
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
这个就是创建Demux的地方,查看代码MediaExtractor.cpp的create函数,datasource的sniff函数就是自动检测媒体格式容器的类型的,如果需要新增原系统无法识别的媒体格式,必然无法得到有效的分离器,所以这里需要自己创建自己Demuxer,每一种格式的XXXXExtractor.cpp函数中有个SniffXXXX函数,在Awesomeplayer的构造函数中的这一句DataSource::RegisterDefaultSniffers()就是注册好所有的sniff函数,写一个自己的XXXExtractor类,照样写个XXXXsinff函数,在RegisterDefaultSniffers中加入自己的函数。然后自已实现一个需要的Demuxer.通过Demuxer分离出音视频流后,就是进入解码阶段了。
2. AV Decoder
status_t AwesomePlayer::initVideoDecoder() {
mVideoSource = OMXCodec::Create(
mClient.interface(), mVideoTrack->getFormat(),
false,
mVideoTrack);
这个就是创建的解码器了,create的最后一个参数就是分离出来的独立的视频流,具备的接口最重要的就是read接口,是分离器中实现的,这个track是XXXXExtractor中的getTrack获取的。
解码器的逻辑主要集中在OMXCodec.cpp中,在OMXCodec::Create中主要负责寻找匹配的codec并创建codec.
寻找匹配的codec:
- Vector<String8> matchingCodecs;
- findMatchingCodecs(
- mime, createEncoder, matchComponentName, flags, &matchingCodecs);
- if (matchingCodecs.isEmpty()) {
- return NULL;
- }
- Vector<String8> matchingCodecs;
- findMatchingCodecs(
- mime, createEncoder, matchComponentName, flags, &matchingCodecs);
- if (matchingCodecs.isEmpty()) {
- return NULL;
- }
创建codec:
- status_t err = omx->allocateNode(componentName, observer, &node);
- if (err == OK) {
- LOGV("Successfully allocated OMX node '%s'", componentName);
- sp<OMXCodec> codec = new OMXCodec(
- omx, node, quirks, flags,
- createEncoder, mime, componentName,
- source, nativeWindow);
- observer->setCodec(codec);
- err = codec->configureCodec(meta);
- if (err == OK) {
- if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {
- codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;
- }
- return codec;
- }
- LOGV("Failed to configure codec '%s'", componentName);
- }
- status_t err = omx->allocateNode(componentName, observer, &node);
- if (err == OK) {
- LOGV("Successfully allocated OMX node '%s'", componentName);
- sp<OMXCodec> codec = new OMXCodec(
- omx, node, quirks, flags,
- createEncoder, mime, componentName,
- source, nativeWindow);
- observer->setCodec(codec);
- err = codec->configureCodec(meta);
- if (err == OK) {
- if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {
- codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;
- }
- return codec;
- }
- LOGV("Failed to configure codec '%s'", componentName);
- }
findMatchingCodecs这个函数就是查找解码器的,它在kDecoderInfo数组中寻找需要的解码器。
- void OMXCodec::findMatchingCodecs(
- const char *mime,
- bool createEncoder, const char *matchComponentName,
- uint32_t flags,
- Vector<String8> *matchingCodecs) {
- matchingCodecs->clear();
- for (int index = 0;; ++index) {
- const char *componentName;
- if (createEncoder) {
- componentName = GetCodec(
- kEncoderInfo,
- sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
- mime, index);
- } else {
- componentName = GetCodec(
- kDecoderInfo,
- sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
- mime, index);
- }
- if (!componentName) {
- break;
- }
- // If a specific codec is requested, skip the non-matching ones.
- if (matchComponentName && strcmp(componentName, matchComponentName)) {
- continue;
- }
- // When requesting software-only codecs, only push software codecs
- // When requesting hardware-only codecs, only push hardware codecs
- // When there is request neither for software-only nor for
- // hardware-only codecs, push all codecs
- if (((flags & kSoftwareCodecsOnly) && IsSoftwareCodec(componentName)) ||
- ((flags & kHardwareCodecsOnly) && !IsSoftwareCodec(componentName)) ||
- (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {
- matchingCodecs->push(String8(componentName));
- }
- }
- if (flags & kPreferSoftwareCodecs) {
- matchingCodecs->sort(CompareSoftwareCodecsFirst);
- }
- }
- void OMXCodec::findMatchingCodecs(
- const char *mime,
- bool createEncoder, const char *matchComponentName,
- uint32_t flags,
- Vector<String8> *matchingCodecs) {
- matchingCodecs->clear();
- for (int index = 0;; ++index) {
- const char *componentName;
- if (createEncoder) {
- componentName = GetCodec(
- kEncoderInfo,
- sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
- mime, index);
- } else {
- componentName = GetCodec(
- kDecoderInfo,
- sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
- mime, index);
- }
- if (!componentName) {
- break;
- }
- // If a specific codec is requested, skip the non-matching ones.
- if (matchComponentName && strcmp(componentName, matchComponentName)) {
- continue;
- }
- // When requesting software-only codecs, only push software codecs
- // When requesting hardware-only codecs, only push hardware codecs
- // When there is request neither for software-only nor for
- // hardware-only codecs, push all codecs
- if (((flags & kSoftwareCodecsOnly) && IsSoftwareCodec(componentName)) ||
- ((flags & kHardwareCodecsOnly) && !IsSoftwareCodec(componentName)) ||
- (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {
- matchingCodecs->push(String8(componentName));
- }
- }
- if (flags & kPreferSoftwareCodecs) {
- matchingCodecs->sort(CompareSoftwareCodecsFirst);
- }
- }
差不多流程是这样把,关于显示部分就不用管了,解码器对接render部分,应该自己会弄好,解码器最重要的对外接口也就是read接口的,返回的一帧帧的解码后的数据。