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

來源:互聯網
上載者:User

標籤: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的實現過程。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.