Android 原生播放器MediaPlayer

記得剛學Android開發(fā)的時候在2011年,那個時候除了hello world,第一個接觸的組件就是這個,這也是目前Android手機運用到最多的組件,有人說沒怎么使用過,目前的各類播放器,短視頻,都屬于多媒體播放,作為Android的多媒體開始鼻祖當屬MediaPlayer了。

回顧下官方的API接口

以官方貼圖為切入點,API地址


從上圖開始我們每一次播放的時候都要按照這樣的狀態(tài)去執(zhí)行,這就是一個典型的狀態(tài)機。
reset->Idle這個狀態(tài)就是起始狀態(tài),可以繼續(xù)執(zhí)行也可以隨時終止->release->End,也可以繼續(xù)執(zhí)行,我們俗稱Idle為起始態(tài)也可以稱之為空閑態(tài),它是伴隨播放器創(chuàng)建后首先走到的地方。若是需要播放,就要先執(zhí)行將播放需要的路徑傳進來setDataSorece,目前這個setDataSorece的重載擴展了很多。這里繼續(xù)溫故下重載(overload),重載的基本原則:

  • 被重載的方法必須改變參數(shù)列表;
  • 被重載的方法可以改變返回類型;
  • 被重載的方法可以改變訪問修飾符;
  • 被重載的方法可以聲明新的或更廣的檢查異常;
  • 方法能夠在同一個類中或者在一個子類中被重載
    那么如果返回類型不一樣算是重載嗎?答案是:不是的

setDataSorece

下面常用方法中,列出不同重載后的方法。這時播放器接收到媒體資源后準備進入初始狀態(tài)。這里需要注意的是,這個順序不能改變,setDataSourece一定是播放器處于空閑態(tài)的時候調(diào)用的,否則就會出錯。具體我們用代碼來分析:

 public void setDataSource(FileDescriptor fd, long offset, long length)
            throws IOException, IllegalArgumentException, IllegalStateException {
        try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
            if (modernFd == null) {
                _setDataSource(fd, offset, length);
            } else {
                _setDataSource(modernFd.getFileDescriptor(), offset, length);
            }
        } catch (IOException e) {
            Log.w(TAG, "Ignoring IO error while setting data source", e);
        }
    }

非Idle調(diào)用會拋出IllegalStateException異常,剩下兩個是在重載的時候拋出的。至于上面的異常,官方給出注釋了

Sets the data source (MediaDataSource) to use.
Params:
dataSource – the MediaDataSource for the media you want to play
Throws:
IllegalStateException – if it is called in an invalid state
IllegalArgumentException – if dataSource is not a valid MediaDataSource

看下底層的代碼是如何實現(xiàn)的,路徑:framework/av/media/mediaplayer.cpp
看起重載后的其中一個方法:

status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
    ALOGV("setDataSource(IDataSource)");
    status_t err = UNKNOWN_ERROR;
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(source))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

這里關注幾個點就可以
需要獲取mediaplayer的服務也就是getMediaPlayerService,這里就要來到經(jīng)常提起的binder機制了,其實就是一個典型的CS模型

  • Server端
    BnMediaPlayerService 為MediaPlayerService在server端的具體實現(xiàn);
  • Client端
    BpMediaPlayerService為MediaPlayerService在client端的具體代理;
    通過BpMediaPlayerService,可以享用MediaPlayerService所提供的服務
    通過BpMediaPlayerService可以獲取到IMediaRecorder、IMediaMetadataRetriever、IMediaPlayer、IOMX在client端的代理類BpXXX(IMediaRecorder、IMediaMetadataRetriever、IMediaPlayer、IOMX,這些皆是Bp和Bn的共同接口,和MediaPlayerService一樣,都有Bp和Bn構成)
    引用鏈接
status_t MediaPlayer::setDataSource(
        const sp<IMediaHTTPService> &httpService,
        const char *url, const KeyedVector<String8, String8> *headers)
{
    ALOGV("setDataSource(%s)", url);
    status_t err = BAD_VALUE;
    if (url != NULL) {
        const sp<IMediaPlayerService> service(getMediaPlayerService());
        if (service != 0) {
            sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
            if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                (NO_ERROR != player->setDataSource(httpService, url, headers))) {
                player.clear();
            }
            err = attachNewPlayer(player);
        }
    }
    return err;
}

status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
    status_t err = UNKNOWN_ERROR;
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(fd, offset, length))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
    ALOGV("setDataSource(IDataSource)");
    status_t err = UNKNOWN_ERROR;
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(source))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

prepareAsync

status_t MediaPlayer::prepareAsync()
{
    ALOGV("prepareAsync");
    //防止重復調(diào)用,它的作用域到函數(shù)結束
    Mutex::Autolock _l(mLock);
    return prepareAsync_l();
}
// must call with lock held
status_t MediaPlayer::prepareAsync_l()
{
    if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
        if (mAudioAttributesParcel != NULL) {
            mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
        } else {
            mPlayer->setAudioStreamType(mStreamType);
        }
        mCurrentState = MEDIA_PLAYER_PREPARING;
        return mPlayer->prepareAsync();
    }
    ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
    return INVALID_OPERATION;
}
  • prepare
  • start
  • pause
  • stop
  • reset
  • seekTo
  • release
  • setDisplay
  • setSurface
  • setVolume
  • getTrackInfo
  • selectTrack
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容