Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android4.2.2多媒體架構MediaPlay的創建過程分析(一)

Android4.2.2多媒體架構MediaPlay的創建過程分析(一)

編輯:關於Android編程

 

Android源碼版本Version:4.2.2; 硬件平台 全志A31

 

前沿:
回首往事,記得2012年的時候,那時還年少不知,就研究過android的多媒體框架,那時還是2.3的源碼,看過stagefright的源碼,記得當時是特別的痛苦。而今,再次看起這個多媒體模塊的代碼,突然間覺得豁然開朗,模塊間的層次清晰,有據可依,遇到的疑問往往都能迎刃而解。我想,也許這就是2年多來的進步與經驗吧。感謝時間,讓我學會了成才。
鄧凡平老師告訴我:無論何時進入互聯網都不算遲,的確站在巨人的肩膀上再次重新梳理舊的東西,還是能學習的更多更深。

接下去的一段時間,打算主攻android多媒體框架、camera架構、surfaceflinger等FrameWork層,HAL層的模塊以及相關的Android系統定制與類平板的開發,更底層是linux內核中的視頻采集與顯示驅動等來作為接下去尋找工作的重中之重。自我感覺在移動互聯以及嵌入式的世界裡,這幾個方面現在應該還都是不可欠缺的。

Android的多媒體框架熟悉的人很熟悉,像我等菜鳥,就只能慢慢的啃了。這裡以4.2.2的源碼為背景,記錄下我所熟悉的多媒體框架的核心模塊,以便以後使用。

 

多媒體框架在android中的功能主要體現雜音視頻的播放以及錄制等,前者對應著解碼,後者對應著編碼。Android中以一個MediaPlay類作為音視頻播放的基礎類,圍繞著他開展了一系列的處理。學習一個新的模塊,最簡單的步驟就是找到一個典型的應用程序,通過它的實現,來分析整個模塊的數據流和控制流。如SurfaceFlinger的研究可以以Bootanmation的啟動來學習。典型的MediaPlay在Java處的接口包括視頻播放類VideoView以及音頻專用MediaPlay類。

1.APP閃的VideoView類,其實質是用MediaPlay類來實現的,只是由於其是視頻播放,不得不和surfaceview掛上夠,才將其獨立出來。使得其有如下的結構:

public class VideoView extends SurfaceView implements MediaPlayerControl {
    private String TAG = VideoView;
    // settable by the client
    private Uri         mUri;
    private Map mHeaders;

在APP中,VideoView的典型簡單使用如下:

                video = (VideoView) findViewById(R.id.videoView1);	
		mediacontroller =new MediaController(this);
		video.setVideoPath(Video_fd);
		mediacontroller.setAnchorView(video);        //控件和視頻綁定
		video.setMediaController(mediacontroller);  //設置視頻播放的控制器
		video.start();

通過setVideoPath的API處理,依次進行如下的調用:

  public void setVideoPath(String path) {
        setVideoURI(Uri.parse(path));
    }

    public void setVideoURI(Uri uri) {
        setVideoURI(uri, null);
    }

    /**
     * @hide
     */
    public void setVideoURI(Uri uri, Map headers) {
        mUri = uri;
        mHeaders = headers;
        mSeekWhenPrepared = 0;
        openVideo();
        requestLayout();
        invalidate();
    }

openVideo的處理,讓最終的處理權交給了MediaPlayer。

    private void openVideo() {
        if (mUri == null || mSurfaceHolder == null) {
            // not ready for playback just yet, will try again later
            return;
        }
        // Tell the music playback service to pause
        // TODO: these constants need to be published somewhere in the framework.
        Intent i = new Intent(com.android.music.musicservicecommand);
        i.putExtra(command, pause);
        mContext.sendBroadcast(i);

        // we shouldn't clear the target state, because somebody might have
        // called start() previously
        release(false);
        try {
            mMediaPlayer = new MediaPlayer();
......
			*/
            mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
.........
}

上述的兩個架構,在音頻播放的APP調用更加緊密,如下所示:

		mediaplayer = new MediaPlayer();
		mediaplayer.setDataSource(Music_fd);  //設置要播放的音頻文件
		mediaplayer.prepare(); 
		mediaplayer.seekTo(0);

到這裡基本的音視頻框架在APP中的調用就基本完成了。

 

2.進入MediaPlay的世界

2.1 首先關注MediaPlay的對象創建過程,這也是分析android源碼的一個基本要求。依次通過java,JNI(libmedia_jni.so)進入Framework(libmedia.so)的處理流程。

new VideoView——> new MediaPlay ——>native_setup:典型的一個對象的建立,並傳統到JNI。native_setup主要用於本地C++層的對象的建立

進入JNI做android_media_MediaPlayer_native_setup處理,使得最終進入C++的世界。

android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    ALOGV(native_setup);
    sp mp = new MediaPlayer();
    if (mp == NULL) {
        jniThrowException(env, java/lang/RuntimeException, Out of memory);
        return;
    }

    // create new listener and give it to MediaPlayer
    sp listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener);

    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
    setMediaPlayer(env, thiz, mp);
}

好了,到此為止,真正的建立了一個所謂native處的MediaPlayer對象。當然java處也有這個對象類。

 

2.2 setDataSource

MediaPlay的C++代碼位於/home/A31_Android4.2.2/android/frameworks/av/media/libmedia下形成一個libmedia.so。

下面來看這個API的處理,接下去都只分析FW層的C++的處理流,java的流和上面的分析類似。

status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV(setDataSource(%d, %lld, %lld), fd, offset, length);
    status_t err = UNKNOWN_ERROR;
    const sp& service(getMediaPlayerService());
    if (service != 0) {
        sp player(service->create(getpid(), this, mAudioSessionId));//返回一個Bpmediaplayer
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(fd, offset, length))) {//設置視頻源
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

典型的Binder C/S架構,獲取MediaPlayerService(MPS)的proxy,提交給MPS處理。

 

3. MediaPlayerService的工作。

MPS和千萬萬的Service一樣,以一個服務者的身份存在,他是作為分析Binder驅動架構和原理的一個典型代表。在mediaserver中啟動,和其他CameraService和AudioFlinger做為多媒體服務。

int main(int argc, char** argv)
{
    signal(SIGPIPE, SIG_IGN);
    sp proc(ProcessState::self());
    sp sm = defaultServiceManager();
    ALOGI(ServiceManager: %p, sm.get());
    AudioFlinger::instantiate();//多媒體服務的啟動包括音頻,攝像頭等
    MediaPlayerService::instantiate();
    CameraService::instantiate();
    AudioPolicyService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

 

3.1 處理create請求:

sp MediaPlayerService::create(pid_t pid, const sp& client,
        int audioSessionId)//創建一個mediaplayer,范范一個Client
{
    ALOGV(MediaPlayerService::create);
    int32_t connId = android_atomic_inc(&mNextConnId);

    sp c = new Client(
            this, pid, connId, client, audioSessionId,
            IPCThreadState::self()->getCallingUid());//內部類創建,實現BnMediaPlayer
.....
   }

創建一個MPS的內部客戶端類Client(繼承於Binder本地接口類BnMediaPlay),這個看上去和CameraService很相似。有了這個本地客戶端類,那麼應用端的MediaPlay後續只需要和Client交互即可,而這其中是匿名的Binder在起作用。

 

3.2 player->setDataSource()

player是調用MPS後返回的一個BpBinder派生類,最終調用MPS的內部類Client的setDataSource()來實現。

status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
  .........
    player_type playerType = MediaPlayerFactory::getPlayerType(this,
                                                     fd,
                                            offset,
                                                               length,
        true );//根據視頻源獲取要使用的播放器的類型
 ........
        sp p = setDataSource_pre(playerType);    // now set data source
    setDataSource_post(p, p->setDataSource(fd, offset, length));
    return mStatus;
}

這裡面出現了一個MediaPlayerFactory,姑且理解為播放器廠商類吧。通過它來獲取當前傳入的視頻源的視頻源後綴格式等:如mp4,avi,3gp等。最終假設當前返回的playerType為STAGEFRIGHT_PLAYER。接著分析setDataSource_pre函數:

sp MediaPlayerService::Client::setDataSource_pre(
        player_type playerType)
{
    // create the right type of player
    sp p = createPlayer(playerType);//創建一個播放器
    if (p == NULL) {
        return p;
    }

    if (!p->hardwareOutput()) {
        mAudioOutput = new AudioOutput(mAudioSessionId);
        static_cast(p.get())->setAudioSink(mAudioOutput);//強制轉化為MediaPlayerInterface
    }

    return p;
}


3.3 真正的創建一個適合於當前視頻文件播放需要的Player:createPlayer。

sp MediaPlayerService::Client::createPlayer(player_type playerType)
{
    // determine if we have the right player type
    sp p = mPlayer;
    if ((p != NULL) && (p->playerType() != playerType)) {
        ALOGV(delete player);
        p.clear();
    }
    if (p == NULL) {
        p = MediaPlayerFactory::createPlayer(playerType, this, notify);//新建一個player
    }

    if (p != NULL) {
        p->setUID(mUID);
    }

    return p;
}

第一次處理時,mPlayer肯定為空,故可以看到最終還是回到了這個廠商播放器類來實現,因為這個類維護著當前平台支持的播放器類型(說到低就是解碼器的種類).

sp MediaPlayerFactory::createPlayer(
        player_type playerType,
        void* cookie,
        notify_callback_f notifyFunc) {
    sp p;
    IFactory* factory;
    status_t init_result;
    Mutex::Autolock lock_(&sLock);

    if (sFactoryMap.indexOfKey(playerType) < 0) {
        ALOGE(Failed to create player object of type %d, no registered
               factory, playerType);
        return p;
    }

    factory = sFactoryMap.valueFor(playerType);//根據type類型獲取一個StagefrightPlayerFactory
    CHECK(NULL != factory);
    p = factory->createPlayer();//調用創建一個真正的palyer StagefrightPlayerPlay

    if (p == NULL) {
        ALOGE(Failed to create player object of type %d, create failed,
               playerType);
        return p;
    }

    init_result = p->initCheck();
    if (init_result == NO_ERROR) {
        p->setNotifyCallback(cookie, notifyFunc);
    } else {
        ALOGE(Failed to create player object of type %d, initCheck failed
               (res = %d), playerType, init_result);
        p.clear();
    }

    return p;
}

這裡出現了一個全局變量SFactoryMap變量:

MediaPlayerFactory::tFactoryMap sFactoryMap;//實際的類型是typedef KeyedVector tFactoryMap;KeyedVector是一個向量類,類似於數組,通過一個index進行索引查找。他代表著當前支持的播放器列表。那麼這個表的是在何處被初始化呢,我們需要回到MediaPlyerService的構造函數之中。

 

3.4 系統支持的播放器類型相關信息的注冊:

MediaPlayerService::MediaPlayerService()
{
    ALOGV(MediaPlayerService created);
    mNextConnId = 1;

    mBatteryAudio.refCount = 0;
    for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
        mBatteryAudio.deviceOn[i] = 0;
        mBatteryAudio.lastTime[i] = 0;
        mBatteryAudio.totalTime[i] = 0;
    }
    // speaker is on by default
    mBatteryAudio.deviceOn[SPEAKER] = 1;

    MediaPlayerFactory::registerBuiltinFactories();//注冊建立廠商的play
void MediaPlayerFactory::registerBuiltinFactories() {
    Mutex::Autolock lock_(&sLock);

    if (sInitComplete)
        return;

    registerFactory_l(new CedarXPlayerFactory(), CEDARX_PLAYER);
    registerFactory_l(new CedarAPlayerFactory(), CEDARA_PLAYER);
    registerFactory_l(new TPlayerFactory(), THUMBNAIL_PLAYER);
    registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
    registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
    registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
    registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);//不同的播放器注冊

    sInitComplete = true;
}

這裡以我們要舉例的STAGEFRIGHT_PLAYER為例,進行分析:

a.new StagefrightPlayerFactory()新建一個播放器類,該類的結構如下:

class StagefrightPlayerFactory :
    public MediaPlayerFactory::IFactory {
  public:
    virtual float scoreFactory(const sp& client,
                               int fd,
                               int64_t offset,
                               int64_t length,
                               float curScore) {
        char buf[20];
        lseek(fd, offset, SEEK_SET);
        read(fd, buf, sizeof(buf));
        lseek(fd, offset, SEEK_SET);
        long ident = *((long*)buf);
        // Ogg vorbis?
        if (ident == 0x5367674f) // 'OggS'
            return 1.0;
        return 0.0;
    }
    virtual sp createPlayer() {
        ALOGV( create StagefrightPlayer);
        return new StagefrightPlayer();//新建一個StagefrightPlayer
    }
};

很明顯,該類的特點是繼承並實現了IFactory這個接口類的相關功能。

b. 將新建的這個播放器對象進行注冊,依次添加索引值:播放器類型type,並將其對應的factory保存到sFactorymap這種向量表中。

status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
                                               player_type type) {
    if (NULL == factory) {
        ALOGE(Failed to register MediaPlayerFactory of type %d, factory is
               NULL., type);
        return BAD_VALUE;
    }

    if (sFactoryMap.indexOfKey(type) >= 0) {
        ALOGE(Failed to register MediaPlayerFactory of type %d, type is
               already registered., type);
        return ALREADY_EXISTS;
    }

    if (sFactoryMap.add(type, factory) < 0) {
        ALOGE(Failed to register MediaPlayerFactory of type %d, failed to add
               to map., type);
        return UNKNOWN_ERROR;
    }

    return OK;
}

 

我們回到3.3的程序中區,通過factory = sFactoryMap.valueFor(playerType);//根據type類型獲取一個StagefrightPlayerFactory,即之前注冊的factory對象。實際是調用他的虛函數create_player()來實現:

    virtual sp createPlayer() {
        ALOGV( create StagefrightPlayer);
        return new StagefrightPlayer();//新建一個StagefrightPlayer
    }

接下去我們看到的將是真正進入StageFright的實現流程:

StagefrightPlayer::StagefrightPlayer()
    : mPlayer(new AwesomePlayer) {//新建一個AwesomePlayer類,該結構體類屬於Stagefright
    ALOGV(StagefrightPlayer);

    mPlayer->setListener(this);//注冊StagefrightPlayer到AwesomePlayer類
}

 

3.4 AwesimePlayer打入stagefright內部

////////////////////////////////////////////////////////////////////////////////
AwesomePlayer::AwesomePlayer()
    : mQueueStarted(false),
      mUIDValid(false),
      mTimeSource(NULL),
      mVideoRenderingStarted(false),
      mVideoRendererIsPreview(false),
      mAudioPlayer(NULL),
      mDisplayWidth(0),
      mDisplayHeight(0),
      mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
      mFlags(0),
      mExtractorFlags(0),
      mVideoBuffer(NULL),
      mDecryptHandle(NULL),
      mLastVideoTimeUs(-1),
      mTextDriver(NULL) {
    CHECK_EQ(mClient.connect(), (status_t)OK);//OMXClient,connect後維護一個mOMX:BpOMX

    DataSource::RegisterDefaultSniffers();

    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);//注冊onVideoEvent事件
    mVideoEventPending = false;
    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);//注冊onStreamDone事件
    mStreamDoneEventPending = false;
    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);//注冊onBufferingUpdate
    mBufferingEventPending = false;
    mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
    mVideoEventPending = false;

    mCheckAudioStatusEvent = new AwesomeEvent(
            this, &AwesomePlayer::onCheckAudioStatus);

    mAudioStatusEventPending = false;

    reset();
}

Awesomeplay的構造函數,主要過程是建立了幾個事件處理的注冊,具體的event處理機制在下一文中分享

 

 

 

 

 

 

 

 

 

 

 


 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved