MediaPlayer本地播放流程解析(1)

应用场景:

[java]  view plain  copy
  1. MediaPlayer mediaPlayer = new MediaPlayer();  
  2. mediaPlayer.setOnCompletionListener(new OnCompletionListener() {  
  3.     @Override  
  4.     public void onCompletion(MediaPlayer mp) {  
  5.         mediaPlayer.release();  
  6.         mediaPlayer = null;  
  7.     }  
  8. });  
  9. mediaPlayer.setDataSource(“abc.mp3”);  
  10. mediaPlayer.prepare();  
  11. mediaPlayer.start();  

一、setDataSource

在MediaPlayer.java 中

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void setDataSource(FileDescriptor fd, long offset, long length)  
  2.     throws IOException, IllegalArgumentException, IllegalStateException {  
  3.     disableProxyListener();  
  4.     setDataSource(fd, offset, length);  
  5. }  

setDataSource最终调用了native函数:_setDataSource(fd,offset, length);

我们直接跳到JNI层来看它的具体实现

根据JNI相关的知识,在android_media_MediaPlayer.cpp中找到了其实现代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void  
  2. android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)  
  3. {  
  4.     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);  
  5.     if (mp == NULL ) {  
  6.         jniThrowException(env, "java/lang/IllegalStateException", NULL);  
  7.         return;  
  8.     }  
  9.   
  10.     if (fileDescriptor == NULL) {  
  11.         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);  
  12.         return;  
  13.     }  
  14.     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);  
  15.     ALOGV("setDataSourceFD: fd %d", fd);  
  16.     process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException""setDataSourceFD failed." );  
  17. }  
mp为MediaPlayer类型的对象,在JNI层创建,在MediaPlayer.cpp中,一起来看setDataSource的实现。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)  
  2. {  
  3.     status_t err = UNKNOWN_ERROR;  
  4.     const sp<IMediaPlayerService>& service(getMediaPlayerService());  
  5.     if (service != 0) {  
  6.         sp<IMediaPlayer> player(service->create(this, mAudioSessionId));  
  7.         if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||  
  8.             (NO_ERROR != player->setDataSource(fd, offset, length))) {  
  9.             player.clear();  
  10.         }  
  11.         err = attachNewPlayer(player);  
  12.     }  
  13.     return err;  
  14. }  

getMediaPlayerService()为一个典型的Binder机制向ServiceManager获取服务的方法,Binder这方面的知识可以参考http://blog.csdn.net/super_dc/article/details/37738123http://blog.csdn.net/super_dc/article/details/37764947

service->create(this, mAudioSessionId),先看create方法在IMediaPlayerService.cpp中的实现:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. virtual sp<IMediaPlayer> create(  
  2.         const sp<IMediaPlayerClient>& client, int audioSessionId) {  
  3.     Parcel data, reply;  
  4.     data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());  
  5.     data.writeStrongBinder(client->asBinder());  
  6.     data.writeInt32(audioSessionId);  
  7.   
  8.     remote()->transact(CREATE, data, &reply);  
  9.     return interface_cast<IMediaPlayer>(reply.readStrongBinder());  
  10. }  
这里只是Binder客户端的实现,其最终实现会在MediaPlayerService.cpp中由服务端MediaPlayerService来实现。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,  
  2.         int audioSessionId)  
  3. {  
  4.     pid_t pid = IPCThreadState::self()->getCallingPid();  
  5.     int32_t connId = android_atomic_inc(&mNextConnId);  
  6.   
  7.     sp<Client> c = new Client(  
  8.             this, pid, connId, client, audioSessionId,  
  9.             IPCThreadState::self()->getCallingUid());  
  10.   
  11.     ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,  
  12.          IPCThreadState::self()->getCallingUid());  
  13.     /* add by Gary. start {{----------------------------------- */  
  14.     c->setScreen(mScreen);  
  15.     /* add by Gary. end   -----------------------------------}} */  
  16.     c->setSubGate(mGlobalSubGate);  // 2012-03-12, add the global interfaces to control the subtitle gate  
  17.   
  18.     wp<Client> w = c;  
  19.     {  
  20.         Mutex::Autolock lock(mLock);  
  21.         mClients.add(w);  
  22.     }  
  23.     return c;  
  24. }  

综合上面两点,sp<IMediaPlayer>player(service->create(this, mAudioSessionId));中player实际上是一个Client类型对象的proxy。其具体实现都在Client中实现。

player->setDataSource(fd, offset, length)就可以直接到MediaPlayerService.cpp中的Client类中来看其具体实现了。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)  
  2. {  
  3.     struct stat sb;  
  4.     int ret = fstat(fd, &sb);  
  5.     if (ret != 0) {  
  6.         ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));  
  7.         return UNKNOWN_ERROR;  
  8.     }  
  9.   
  10.     if (offset >= sb.st_size) {  
  11.         ALOGE("offset error");  
  12.         ::close(fd);  
  13.         return UNKNOWN_ERROR;  
  14.     }  
  15.     if (offset + length > sb.st_size) {  
  16.         length = sb.st_size - offset;  
  17.         ALOGV("calculated length = %lld", length);  
  18.     }  
  19.     // 关键点1  
  20.     player_type playerType = MediaPlayerFactory::getPlayerType(this,  
  21.                                                                fd,  
  22.                                                                offset,  
  23.                                                                length);  
  24.     // 关键点2  
  25.     sp<MediaPlayerBase> p = setDataSource_pre(playerType);  
  26.     if (p == NULL) {  
  27.         return NO_INIT;  
  28.     }  
  29.   
  30.     // now set data source  
  31.     // 关键点3  
  32.     setDataSource_post(p, p->setDataSource(fd, offset, length));  
  33.     return mStatus;  
  34. }  
这里有3个关键点,我们分别破解之,先看getPlayerType

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,  
  2.                                               int fd,  
  3.                                               int64_t offset,  
  4.                                               int64_t length) {  
  5.     GET_PLAYER_TYPE_IMPL(client, fd, offset, length);  
  6. }  
  7.   
  8. #define GET_PLAYER_TYPE_IMPL(a...)                      \  
  9.     Mutex::Autolock lock_(&sLock);                      \  
  10.                                                         \  
  11.     player_type ret = STAGEFRIGHT_PLAYER;               \  
  12.     float bestScore = 0.0;                              \  
  13.                                                         \  
  14.     for (size_t i = 0; i < sFactoryMap.size(); ++i) {   \  
  15.                                                         \  
  16.         IFactory* v = sFactoryMap.valueAt(i);           \  
  17.         float thisScore;                                \  
  18.         CHECK(v != NULL);                               \  
  19.         thisScore = v->scoreFactory(a, bestScore);      \  
  20.         if (thisScore > bestScore) {                    \  
  21.             ret = sFactoryMap.keyAt(i);                 \  
  22.             bestScore = thisScore;                      \  
  23.         }                                               \  
  24.     }                                                   \  
  25.                                                         \  
  26.     if (0.0 == bestScore) {                             \  
  27.         ret = getDefaultPlayerType();                   \  
  28.     }                                                   \  
  29.                                                         \  
  30.     return ret;  

MediaPlayerFactory作为一个工厂类,各种mediaplayer向它注册,并各自实现scoreFactory和createPlayer用来判断当前多媒体文件是否适合用此mediaplayer来播放和创建mediaplayer。在哪儿注册mediaplayer呢?在MediaPlayerService的构造函数中,也就是说当向系统注册MediaPlayerService服务时,就已经注册了一些mediaplayer了。

播放mp3文件时,会创建STAGEFRIGHT_PLAYER,这也是默认的播放器。下面就以STAGEFRIGHT_PLAYER来继续下面的流程。

到目前为止,我们知道playerType返回了STAGEFRIGHT_PLAYER,接着来看关键点2.

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(  
  2.         player_type playerType)  
  3. {  
  4.     ALOGV("player type = %d", playerType);  
  5.   
  6.     // create the right type of player  
  7.     sp<MediaPlayerBase> p = createPlayer(playerType);  
  8.     if (p == NULL) {  
  9.         return p;  
  10.     }  
  11.   
  12.     if (!p->hardwareOutput()) {  
  13.         mAudioOutput = new AudioOutput(mAudioSessionId);  
  14.         static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);  
  15.     }  
  16.   
  17.     return p;  
  18. }  

根据playerType创建播放器,实际上就是创建StagefrightPlayer

再看关键点3,p->setDataSource(fd,offset, length)实际上就是调用了StagefrightPlayer的setDataSource。看代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. StagefrightPlayer::StagefrightPlayer()  
  2.     : mPlayer(new AwesomePlayer) {  
  3.     ALOGV("StagefrightPlayer");  
  4.   
  5.     mPlayer->setListener(this);  
  6. }  
  7. status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {  
  8.     ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);  
  9.     return mPlayer->setDataSource(dup(fd), offset, length);  
  10. }  
由代码可知,StagefrightPlayer只是AwesomePlayer的代理类,具体实现还在AwesomePlayer里面。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t AwesomePlayer::setDataSource(  
  2.         int fd, int64_t offset, int64_t length) {  
  3.     Mutex::Autolock autoLock(mLock);  
  4.   
  5.     reset_l();  
  6.   
  7.     sp<DataSource> dataSource = new FileSource(fd, offset, length);  
  8.   
  9.     status_t err = dataSource->initCheck();  
  10.   
  11.     if (err != OK) {  
  12.         return err;  
  13.     }  
  14.   
  15.     mFileSource = dataSource;  
  16.   
  17.     {  
  18.         Mutex::Autolock autoLock(mStatsLock);  
  19.         mStats.mFd = fd;  
  20.         mStats.mURI = String8();  
  21.     }  
  22.   
  23.     return setDataSource_l(dataSource);  
  24. }  
FileSource类实现了数据读取,播放器调用dataSource->readAt来获取数据,另外,其基类DataSource提供了一些分离器如下。RegisterDefaultSniffers将在AwesomePlayer的构造函数中被调用。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // static  
  2. void DataSource::RegisterDefaultSniffers() {  
  3.     RegisterSniffer(SniffMPEG4);  
  4.     RegisterSniffer(SniffMatroska);  
  5.     RegisterSniffer(SniffOgg);  
  6.     RegisterSniffer(SniffWAV);  
  7.     RegisterSniffer(SniffFLAC);  
  8.     RegisterSniffer(SniffAMR);  
  9.     RegisterSniffer(SniffMPEG2TS);  
  10.     RegisterSniffer(SniffMP3);  
  11.     RegisterSniffer(SniffAAC);  
  12.     RegisterSniffer(SniffMPEG2PS);  
  13.     RegisterSniffer(SniffWVM);  
  14.   
  15.     char value[PROPERTY_VALUE_MAX];  
  16.     if (property_get("drm.service.enabled", value, NULL)  
  17.             && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {  
  18.         RegisterSniffer(SniffDRM);  
  19.     }  
  20. }  
接着往下看setDataSource_l(dataSource)

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. status_t AwesomePlayer::setDataSource_l(  
  2.         const sp<DataSource> &dataSource) {  
  3.   
  4.     // 对于不同的文件格式会创建不同的MediaExtractor,MP3文件会创建MP3Extractor  
  5.     // 文件格式靠source->sniff(&tmp, &confidence, &meta)来区分,这个函数会遍历之前通过RegisterSniffer注册的分离器,得到最合适的文件格式  
  6.     sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);  
  7.   
  8.     if (extractor == NULL) {  
  9.         return UNKNOWN_ERROR;  
  10.     }  
  11.   
  12.     if (extractor->getDrmFlag()) {  
  13.         checkDrmStatus(dataSource);  
  14.     }  
  15.   
  16.     return setDataSource_l(extractor);  
  17. }  
  18.   
  19. status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {  
  20.     // Attempt to approximate overall stream bitrate by summing all  
  21.     // tracks' individual bitrates, if not all of them advertise bitrate,  
  22.     // we have to fail.  
  23.   
  24.     int64_t totalBitRate = 0;  
  25.   
  26.     mExtractor = extractor;  
  27.     for (size_t i = 0; i < extractor->countTracks(); ++i) {  
  28.         sp<MetaData> meta = extractor->getTrackMetaData(i);  
  29.   
  30.         int32_t bitrate;  
  31.         if (!meta->findInt32(kKeyBitRate, &bitrate)) {  
  32.             const char *mime;  
  33.             CHECK(meta->findCString(kKeyMIMEType, &mime));  
  34.             ALOGV("track of type '%s' does not publish bitrate", mime);  
  35.   
  36.             totalBitRate = -1;  
  37.             break;  
  38.         }  
  39.   
  40.         totalBitRate += bitrate;  
  41.     }  
  42.   
  43.     mBitrate = totalBitRate;  
  44.   
  45.     ALOGV("mBitrate = %lld bits/sec", mBitrate);  
  46.   
  47.     {  
  48.         Mutex::Autolock autoLock(mStatsLock);  
  49.         mStats.mBitrate = mBitrate;  
  50.         mStats.mTracks.clear();  
  51.         mStats.mAudioTrackIndex = -1;  
  52.         mStats.mVideoTrackIndex = -1;  
  53.     }  
  54.   
  55.     bool haveAudio = false;  
  56.     bool haveVideo = false;  
  57.     for (size_t i = 0; i < extractor->countTracks(); ++i) {  
  58.         sp<MetaData> meta = extractor->getTrackMetaData(i);  
  59.   
  60.         const char *_mime;  
  61.         CHECK(meta->findCString(kKeyMIMEType, &_mime));  
  62.   
  63.         String8 mime = String8(_mime);  
  64.   
  65.         if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) {  
  66.             setVideoSource(extractor->getTrack(i));  
  67.             haveVideo = true;  
  68.   
  69.             // Set the presentation/display size  
  70.             int32_t displayWidth, displayHeight;  
  71.             bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);  
  72.             if (success) {  
  73.                 success = meta->findInt32(kKeyDisplayHeight, &displayHeight);  
  74.             }  
  75.             if (success) {  
  76.                 mDisplayWidth = displayWidth;  
  77.                 mDisplayHeight = displayHeight;  
  78.             }  
  79.   
  80.             {  
  81.                 Mutex::Autolock autoLock(mStatsLock);  
  82.                 mStats.mVideoTrackIndex = mStats.mTracks.size();  
  83.                 mStats.mTracks.push();  
  84.                 TrackStat *stat =  
  85.                     &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);  
  86.                 stat->mMIME = mime.string();  
  87.             }  
  88.         } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) {  
  89.             setAudioSource(extractor->getTrack(i));  
  90.             haveAudio = true;  
  91.             mActiveAudioTrackIndex = i;  
  92.   
  93.             {  
  94.                 Mutex::Autolock autoLock(mStatsLock);  
  95.                 mStats.mAudioTrackIndex = mStats.mTracks.size();  
  96.                 mStats.mTracks.push();  
  97.                 TrackStat *stat =  
  98.                     &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);  
  99.                 stat->mMIME = mime.string();  
  100.             }  
  101.   
  102.             if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) {  
  103.                 // Only do this for vorbis audio, none of the other audio  
  104.                 // formats even support this ringtone specific hack and  
  105.                 // retrieving the metadata on some extractors may turn out  
  106.                 // to be very expensive.  
  107.                 sp<MetaData> fileMeta = extractor->getMetaData();  
  108.                 int32_t loop;  
  109.                 if (fileMeta != NULL  
  110.                         && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {  
  111.                     modifyFlags(AUTO_LOOPING, SET);  
  112.                 }  
  113.             }  
  114.         } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {  
  115.             addTextSource_l(i, extractor->getTrack(i));  
  116.         }  
  117.     }  
  118.   
  119.     if (!haveAudio && !haveVideo) {  
  120.         if (mWVMExtractor != NULL) {  
  121.             return mWVMExtractor->getError();  
  122.         } else {  
  123.             return UNKNOWN_ERROR;  
  124.         }  
  125.     }  
  126.   
  127.     mExtractorFlags = extractor->flags();  
  128.   
  129.     return OK;  
  130. }  
MediaExtractor涉及到媒体文件格式的很多内容,比如track的构成,有几种track等等,后面再做讲解,这里我们播放的是MP3文件,所以countTracks的值为1,sp<MetaData> meta = extractor->getTrackMetaData(i)中meta的kKeyMIMEType值为"audio/",将会执行到setAudioSource(extractor->getTrack(i)),再看代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. sp<MediaSource> MP3Extractor::getTrack(size_t index) {  
  2.     if (mInitCheck != OK || index != 0) {  
  3.         return NULL;  
  4.     }  
  5.     // 返回的是一个MP3Source对象  
  6.     return new MP3Source(  
  7.             mMeta, mDataSource, mFirstFramePos, mFixedHeader,  
  8.             mSeeker);  
  9. }  
  10.   
  11. void AwesomePlayer::setAudioSource(sp<MediaSource> source) {  
  12.     CHECK(source != NULL);  
  13.   
  14.     mAudioTrack = source;  
  15. }  
至此,setdatasource就分析完成,下一篇将分析prepare的实现过程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值