Android StagefrightPlayer调用流程

从Android 2.3开始,Android MediaPlayer采用Stagefright框架。Based on Android 4.0.1.

StagefrightPlayer创建函数如下:(MediaPlayerService.cpp,详细过程见文章:Android Audio 数据流详解

[html]  view plain copy
  1. static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,  
  2.         notify_callback_f notifyFunc)  
  3. {  
  4.     sp<MediaPlayerBase> p;  
  5.     switch (playerType) {  
  6.         case SONIVOX_PLAYER:  
  7.             LOGV(" create MidiFile");  
  8.             p = new MidiFile();  
  9.             break;  
  10.         case STAGEFRIGHT_PLAYER:  
  11.             LOGV(" create StagefrightPlayer");  
  12.             p = new StagefrightPlayer;  
  13.             break;  
  14.         case NU_PLAYER:  
  15.             LOGV(" create NuPlayer");  
  16.             p = new NuPlayerDriver;  
  17.             break;  
  18.         case TEST_PLAYER:  
  19.             LOGV("Create Test Player stub");  
  20.             p = new TestPlayerStub();  
  21.             break;  
  22.         default:  
  23.             LOGE("Unknown player type: %d", playerType);  
  24.             return NULL;  
  25.     }  
  26.     if (p != NULL) {  
  27.         if (p->initCheck() == NO_ERROR) {  
  28.             p->setNotifyCallback(cookie, notifyFunc);  
  29.         } else {  
  30.             p.clear();  
  31.         }  
  32.     }  
  33.     if (p == NULL) {  
  34.         LOGE("Failed to create player object");  
  35.     }  
  36.     return p;  
  37. }  
[html]  view plain copy
  1. static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,  
  2.         notify_callback_f notifyFunc)  
  3. {  
  4.     sp<MediaPlayerBase> p;  
  5.     switch (playerType) {  
  6.         case SONIVOX_PLAYER:  
  7.             LOGV(" create MidiFile");  
  8.             p = new MidiFile();  
  9.             break;  
  10.         case STAGEFRIGHT_PLAYER:  
  11.             LOGV(" create StagefrightPlayer");  
  12.             p = new StagefrightPlayer;  
  13.             break;  
  14.         case NU_PLAYER:  
  15.             LOGV(" create NuPlayer");  
  16.             p = new NuPlayerDriver;  
  17.             break;  
  18.         case TEST_PLAYER:  
  19.             LOGV("Create Test Player stub");  
  20.             p = new TestPlayerStub();  
  21.             break;  
  22.         default:  
  23.             LOGE("Unknown player type: %d", playerType);  
  24.             return NULL;  
  25.     }  
  26.     if (p != NULL) {  
  27.         if (p->initCheck() == NO_ERROR) {  
  28.             p->setNotifyCallback(cookie, notifyFunc);  
  29.         } else {  
  30.             p.clear();  
  31.         }  
  32.     }  
  33.     if (p == NULL) {  
  34.         LOGE("Failed to create player object");  
  35.     }  
  36.     return p;  
  37. }  

首先了解下系统本身的调用流程,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:

[html]  view plain copy
  1. Vector<String8> matchingCodecs;  
  2. findMatchingCodecs(  
  3.         mime, createEncoder, matchComponentName, flags, &matchingCodecs);  
  4.   
  5. if (matchingCodecs.isEmpty()) {  
  6.     return NULL;  
  7. }  
[html]  view plain copy
  1. Vector<String8> matchingCodecs;  
  2. findMatchingCodecs(  
  3.         mime, createEncoder, matchComponentName, flags, &matchingCodecs);  
  4.   
  5. if (matchingCodecs.isEmpty()) {  
  6.     return NULL;  
  7. }  

创建codec:

[html]  view plain copy
  1. status_t err = omx->allocateNode(componentName, observer, &node);  
  2. if (err == OK) {  
  3.     LOGV("Successfully allocated OMX node '%s'", componentName);  
  4.   
  5.     sp<OMXCodec> codec = new OMXCodec(  
  6.             omx, node, quirks, flags,  
  7.             createEncoder, mime, componentName,  
  8.             source, nativeWindow);  
  9.   
  10.     observer->setCodec(codec);  
  11.   
  12.     err = codec->configureCodec(meta);  
  13.   
  14.     if (err == OK) {  
  15.         if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {  
  16.             codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;  
  17.         }  
  18.   
  19.         return codec;  
  20.     }  
  21.   
  22.     LOGV("Failed to configure codec '%s'", componentName);  
  23. }  
[html]  view plain copy
  1. status_t err = omx->allocateNode(componentName, observer, &node);  
  2. if (err == OK) {  
  3.     LOGV("Successfully allocated OMX node '%s'", componentName);  
  4.   
  5.     sp<OMXCodec> codec = new OMXCodec(  
  6.             omx, node, quirks, flags,  
  7.             createEncoder, mime, componentName,  
  8.             source, nativeWindow);  
  9.   
  10.     observer->setCodec(codec);  
  11.   
  12.     err = codec->configureCodec(meta);  
  13.   
  14.     if (err == OK) {  
  15.         if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {  
  16.             codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;  
  17.         }  
  18.   
  19.         return codec;  
  20.     }  
  21.   
  22.     LOGV("Failed to configure codec '%s'", componentName);  
  23. }  


findMatchingCodecs这个函数就是查找解码器的,它在kDecoderInfo数组中寻找需要的解码器。

 

[html]  view plain copy
  1. void OMXCodec::findMatchingCodecs(  
  2.         const char *mime,  
  3.         bool createEncoder, const char *matchComponentName,  
  4.         uint32_t flags,  
  5.         Vector<String8> *matchingCodecs) {  
  6.     matchingCodecs->clear();  
  7.   
  8.     for (int index = 0;; ++index) {  
  9.         const char *componentName;  
  10.   
  11.         if (createEncoder) {  
  12.             componentName = GetCodec(  
  13.                     kEncoderInfo,  
  14.                     sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),  
  15.                     mime, index);  
  16.         } else {  
  17.             componentName = GetCodec(  
  18.                     kDecoderInfo,  
  19.                     sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),  
  20.                     mime, index);  
  21.         }  
  22.   
  23.         if (!componentName) {  
  24.             break;  
  25.         }  
  26.   
  27.         // If a specific codec is requested, skip the non-matching ones.  
  28.         if (matchComponentName && strcmp(componentName, matchComponentName)) {  
  29.             continue;  
  30.         }  
  31.   
  32.         // When requesting software-only codecs, only push software codecs  
  33.         // When requesting hardware-only codecs, only push hardware codecs  
  34.         // When there is request neither for software-only nor for  
  35.         // hardware-only codecs, push all codecs  
  36.         if (((flags & kSoftwareCodecsOnly) &&   IsSoftwareCodec(componentName)) ||  
  37.             ((flags & kHardwareCodecsOnly) &&  !IsSoftwareCodec(componentName)) ||  
  38.             (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {  
  39.   
  40.             matchingCodecs->push(String8(componentName));  
  41.         }  
  42.     }  
  43.   
  44.     if (flags & kPreferSoftwareCodecs) {  
  45.         matchingCodecs->sort(CompareSoftwareCodecsFirst);  
  46.     }  
  47. }  
[html]  view plain copy
  1. void OMXCodec::findMatchingCodecs(  
  2.         const char *mime,  
  3.         bool createEncoder, const char *matchComponentName,  
  4.         uint32_t flags,  
  5.         Vector<String8> *matchingCodecs) {  
  6.     matchingCodecs->clear();  
  7.   
  8.     for (int index = 0;; ++index) {  
  9.         const char *componentName;  
  10.   
  11.         if (createEncoder) {  
  12.             componentName = GetCodec(  
  13.                     kEncoderInfo,  
  14.                     sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),  
  15.                     mime, index);  
  16.         } else {  
  17.             componentName = GetCodec(  
  18.                     kDecoderInfo,  
  19.                     sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),  
  20.                     mime, index);  
  21.         }  
  22.   
  23.         if (!componentName) {  
  24.             break;  
  25.         }  
  26.   
  27.         // If a specific codec is requested, skip the non-matching ones.  
  28.         if (matchComponentName && strcmp(componentName, matchComponentName)) {  
  29.             continue;  
  30.         }  
  31.   
  32.         // When requesting software-only codecs, only push software codecs  
  33.         // When requesting hardware-only codecs, only push hardware codecs  
  34.         // When there is request neither for software-only nor for  
  35.         // hardware-only codecs, push all codecs  
  36.         if (((flags & kSoftwareCodecsOnly) &&   IsSoftwareCodec(componentName)) ||  
  37.             ((flags & kHardwareCodecsOnly) &&  !IsSoftwareCodec(componentName)) ||  
  38.             (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {  
  39.   
  40.             matchingCodecs->push(String8(componentName));  
  41.         }  
  42.     }  
  43.   
  44.     if (flags & kPreferSoftwareCodecs) {  
  45.         matchingCodecs->sort(CompareSoftwareCodecsFirst);  
  46.     }  
  47. }  


差不多流程是这样把,关于显示部分就不用管了,解码器对接render部分,应该自己会弄好,解码器最重要的对外接口也就是read接口的,返回的一帧帧的解码后的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值