標籤:android mediaplayer 多媒體架構 setdatasource audio
應用情境:
MediaPlayer mediaPlayer = new MediaPlayer();mediaPlayer.setOnCompletionListener(new OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {mediaPlayer.release();mediaPlayer = null;}});mediaPlayer.setDataSource(“abc.mp3”);mediaPlayer.prepare();mediaPlayer.start();
一、setDataSource
在MediaPlayer.java 中
public void setDataSource(FileDescriptor fd, long offset, long length) throws IOException, IllegalArgumentException, IllegalStateException { disableProxyListener(); setDataSource(fd, offset, length);}
setDataSource最終調用了native函數:_setDataSource(fd,offset, length);
我們直接跳到JNI層來看它的具體實現
根據JNI相關的知識,在android_media_MediaPlayer.cpp中找到了其實現代碼:
static voidandroid_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length){ sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } if (fileDescriptor == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); ALOGV("setDataSourceFD: fd %d", fd); process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );}mp為MediaPlayer類型的對象,在JNI層建立,在MediaPlayer.cpp中,一起來看setDataSource的實現。
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length){ status_t err = UNKNOWN_ERROR; const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(fd, offset, length))) { player.clear(); } err = attachNewPlayer(player); } return err;}
getMediaPlayerService()為一個典型的Binder機制向ServiceManager擷取服務的方法,Binder這方面的知識可以參考http://blog.csdn.net/super_dc/article/details/37738123和http://blog.csdn.net/super_dc/article/details/37764947
service->create(this, mAudioSessionId),先看create方法在IMediaPlayerService.cpp中的實現:
virtual sp<IMediaPlayer> create( const sp<IMediaPlayerClient>& client, int audioSessionId) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeStrongBinder(client->asBinder()); data.writeInt32(audioSessionId); remote()->transact(CREATE, data, &reply); return interface_cast<IMediaPlayer>(reply.readStrongBinder());}這裡只是Binder用戶端的實現,其最終實現會在MediaPlayerService.cpp中由服務端MediaPlayerService來實現。
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client, int audioSessionId){ pid_t pid = IPCThreadState::self()->getCallingPid(); int32_t connId = android_atomic_inc(&mNextConnId); sp<Client> c = new Client( this, pid, connId, client, audioSessionId, IPCThreadState::self()->getCallingUid()); ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid, IPCThreadState::self()->getCallingUid()); /* add by Gary. start {{----------------------------------- */ c->setScreen(mScreen); /* add by Gary. end -----------------------------------}} */ c->setSubGate(mGlobalSubGate); // 2012-03-12, add the global interfaces to control the subtitle gate wp<Client> w = c; { Mutex::Autolock lock(mLock); mClients.add(w); } return c;}
綜合上面兩點,sp<IMediaPlayer>player(service->create(this, mAudioSessionId));中player實際上是一個Client類型對象的proxy。其具體實現都在Client中實現。
player->setDataSource(fd, offset, length)就可以直接到MediaPlayerService.cpp中的Client類中來看其具體實現了。
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length){ struct stat sb; int ret = fstat(fd, &sb); if (ret != 0) { ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno)); return UNKNOWN_ERROR; } if (offset >= sb.st_size) { ALOGE("offset error"); ::close(fd); return UNKNOWN_ERROR; } if (offset + length > sb.st_size) { length = sb.st_size - offset; ALOGV("calculated length = %lld", length); } // 關鍵點1 player_type playerType = MediaPlayerFactory::getPlayerType(this, fd, offset, length); // 關鍵點2 sp<MediaPlayerBase> p = setDataSource_pre(playerType); if (p == NULL) { return NO_INIT; } // now set data source // 關鍵點3 setDataSource_post(p, p->setDataSource(fd, offset, length)); return mStatus;}這裡有3個關鍵點,我們分別破解之,先看getPlayerType
player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client, int fd, int64_t offset, int64_t length) { GET_PLAYER_TYPE_IMPL(client, fd, offset, length);}#define GET_PLAYER_TYPE_IMPL(a...) Mutex::Autolock lock_(&sLock); player_type ret = STAGEFRIGHT_PLAYER; float bestScore = 0.0; for (size_t i = 0; i < sFactoryMap.size(); ++i) { IFactory* v = sFactoryMap.valueAt(i); float thisScore; CHECK(v != NULL); thisScore = v->scoreFactory(a, bestScore); if (thisScore > bestScore) { ret = sFactoryMap.keyAt(i); bestScore = thisScore; } } if (0.0 == bestScore) { ret = getDefaultPlayerType(); } return ret;
MediaPlayerFactory作為一個工廠類,各種mediaplayer向它註冊,並各自實現scoreFactory和createPlayer用來判斷當前多媒體檔案是否適合用此mediaplayer來播放和建立mediaplayer。在哪兒註冊mediaplayer呢?在MediaPlayerService的建構函式中,也就是說當向系統註冊MediaPlayerService服務時,就已經註冊了一些mediaplayer了。
播放mp3檔案時,會建立STAGEFRIGHT_PLAYER,這也是預設的播放器。下面就以STAGEFRIGHT_PLAYER來繼續下面的流程。
到目前為止,我們知道playerType返回了STAGEFRIGHT_PLAYER,接著來看關鍵點2.
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre( player_type playerType){ ALOGV("player type = %d", playerType); // create the right type of player sp<MediaPlayerBase> p = createPlayer(playerType); if (p == NULL) { return p; } if (!p->hardwareOutput()) { mAudioOutput = new AudioOutput(mAudioSessionId); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); } return p;}
根據playerType建立播放器,實際上就是建立StagefrightPlayer
再看關鍵點3,p->setDataSource(fd,offset, length)實際上就是調用了StagefrightPlayer的setDataSource。看代碼:
StagefrightPlayer::StagefrightPlayer() : mPlayer(new AwesomePlayer) { ALOGV("StagefrightPlayer"); mPlayer->setListener(this);}status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) { ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); return mPlayer->setDataSource(dup(fd), offset, length);}由代碼可知,StagefrightPlayer只是AwesomePlayer的代理類,具體實現還在AwesomePlayer裡面。
status_t AwesomePlayer::setDataSource( int fd, int64_t offset, int64_t length) { Mutex::Autolock autoLock(mLock); reset_l(); sp<DataSource> dataSource = new FileSource(fd, offset, length); status_t err = dataSource->initCheck(); if (err != OK) { return err; } mFileSource = dataSource; { Mutex::Autolock autoLock(mStatsLock); mStats.mFd = fd; mStats.mURI = String8(); } return setDataSource_l(dataSource);}FileSource類實現了資料讀取,播放器調用dataSource->readAt來擷取資料,另外,其基類DataSource提供了一些分離器如下。RegisterDefaultSniffers將在AwesomePlayer的建構函式中被調用。
// staticvoid DataSource::RegisterDefaultSniffers() { RegisterSniffer(SniffMPEG4); RegisterSniffer(SniffMatroska); RegisterSniffer(SniffOgg); RegisterSniffer(SniffWAV); RegisterSniffer(SniffFLAC); RegisterSniffer(SniffAMR); RegisterSniffer(SniffMPEG2TS); RegisterSniffer(SniffMP3); RegisterSniffer(SniffAAC); RegisterSniffer(SniffMPEG2PS); RegisterSniffer(SniffWVM); char value[PROPERTY_VALUE_MAX]; if (property_get("drm.service.enabled", value, NULL) && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { RegisterSniffer(SniffDRM); }}接著往下看setDataSource_l(dataSource)
status_t AwesomePlayer::setDataSource_l( const sp<DataSource> &dataSource) { // 對於不同的檔案格式會建立不同的MediaExtractor,MP3檔案會建立MP3Extractor // 檔案格式靠source->sniff(&tmp, &confidence, &meta)來區分,這個函數會遍曆之前通過RegisterSniffer註冊的分離器,得到最合適的檔案格式 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); if (extractor == NULL) { return UNKNOWN_ERROR; } if (extractor->getDrmFlag()) { checkDrmStatus(dataSource); } return setDataSource_l(extractor);}status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { // Attempt to approximate overall stream bitrate by summing all // tracks' individual bitrates, if not all of them advertise bitrate, // we have to fail. int64_t totalBitRate = 0; mExtractor = extractor; for (size_t i = 0; i < extractor->countTracks(); ++i) { sp<MetaData> meta = extractor->getTrackMetaData(i); int32_t bitrate; if (!meta->findInt32(kKeyBitRate, &bitrate)) { const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); ALOGV("track of type '%s' does not publish bitrate", mime); totalBitRate = -1; break; } totalBitRate += bitrate; } mBitrate = totalBitRate; ALOGV("mBitrate = %lld bits/sec", mBitrate); { Mutex::Autolock autoLock(mStatsLock); mStats.mBitrate = mBitrate; mStats.mTracks.clear(); mStats.mAudioTrackIndex = -1; mStats.mVideoTrackIndex = -1; } bool haveAudio = false; bool haveVideo = false; for (size_t i = 0; i < extractor->countTracks(); ++i) { sp<MetaData> meta = extractor->getTrackMetaData(i); const char *_mime; CHECK(meta->findCString(kKeyMIMEType, &_mime)); String8 mime = String8(_mime); if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) { setVideoSource(extractor->getTrack(i)); haveVideo = true; // Set the presentation/display size int32_t displayWidth, displayHeight; bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth); if (success) { success = meta->findInt32(kKeyDisplayHeight, &displayHeight); } if (success) { mDisplayWidth = displayWidth; mDisplayHeight = displayHeight; } { Mutex::Autolock autoLock(mStatsLock); mStats.mVideoTrackIndex = mStats.mTracks.size(); mStats.mTracks.push(); TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); stat->mMIME = mime.string(); } } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) { setAudioSource(extractor->getTrack(i)); haveAudio = true; mActiveAudioTrackIndex = i; { Mutex::Autolock autoLock(mStatsLock); mStats.mAudioTrackIndex = mStats.mTracks.size(); mStats.mTracks.push(); TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); stat->mMIME = mime.string(); } if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) { // Only do this for vorbis audio, none of the other audio // formats even support this ringtone specific hack and // retrieving the metadata on some extractors may turn out // to be very expensive. sp<MetaData> fileMeta = extractor->getMetaData(); int32_t loop; if (fileMeta != NULL && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { modifyFlags(AUTO_LOOPING, SET); } } } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) { addTextSource_l(i, extractor->getTrack(i)); } } if (!haveAudio && !haveVideo) { if (mWVMExtractor != NULL) { return mWVMExtractor->getError(); } else { return UNKNOWN_ERROR; } } mExtractorFlags = extractor->flags(); return OK;}MediaExtractor涉及到媒體檔案格式的很多內容,比如track的構成,有幾種track等等,後面再做講解,這裡我們播放的是MP3檔案,所以countTracks的值為1,sp<MetaData> meta = extractor->getTrackMetaData(i)中meta的kKeyMIMEType值為"audio/",將會執行到setAudioSource(extractor->getTrack(i)),再看代碼:
sp<MediaSource> MP3Extractor::getTrack(size_t index) { if (mInitCheck != OK || index != 0) { return NULL; }// 返回的是一個MP3Source對象 return new MP3Source( mMeta, mDataSource, mFirstFramePos, mFixedHeader, mSeeker);}void AwesomePlayer::setAudioSource(sp<MediaSource> source) { CHECK(source != NULL); mAudioTrack = source;}至此,setdatasource就分析完成,下一篇將分析prepare的實現過程。