Android Mediaplayer解讀

來源:互聯網
上載者:User
http://blog.csdn.net/menguio/article/details/6323965

1 Gallery應用端表現
    Gallery僅僅提供一個呈現架構,Gallery用來管理所有的視頻和圖片檔案,具有播放、查看、刪除等功能。自動搜尋本地sdcard存有的picture和video,並分類將同性質檔案picture和video集中在一起,播放時呈現。Gallery內部實現的播放主用是同MediaPlayer,主要包含了Audio和video的播放功能。
    
    Gallery中增加從指定目錄選擇播放檔案的功能:
方法:首先遍曆sdcard下的目錄,然後通過選擇某個目錄,再遍曆檔案,點擊檔案播放。
說明:
   定義了兩個List表:
   videoPathList:遍曆/sdcard下目錄,並存於此List。
   videlFileList:遍曆相應目錄下的檔案,並存於此List。
   定義了兩個Activity:
   VideoList2Play:實現/sdcard下目錄和檔案遍曆。
   VideoPlayer:利用VideoView類實現視頻播放。
   從Gallery的按鈕和功能表項目著手,將該功能植入Gallery。
   Gallery首次載入的圖框上“拍照按鈕”,能夠找到內部功能實現的類和方法,並可以將該功能加入。
   利用more菜單,增加“選擇其它視頻”功能,涉及內部類複雜,需進一步研究,暫沒有實現。
   利用視頻播放是的MovieView中增加“選擇其它視頻”按鈕,當有視頻真現正播放時,點擊按鈕選擇其它視頻,會有衝突。
需改進:研究通過彈出選擇對話方塊方式,可以自由選擇/sdcard下的目錄和檔案,並實現播放。

    Gallery中資料緩衝及處理流程
    在應用程式中有三個線程存在:主線程(隨activity的聲明周期啟動銷毀)、feed初始化線程(進入程式時只運行一次,用於載入相簿初始資訊)、feed監聽線程(監聽相簿和相片的變更)。主要流程歸納如下:
    1、首次進入程式Gallery調用onCreate,此時發送初始化訊息進入訊息佇列;然後Gallery調用onResume,向下進入GridLayer的onResume。MediaFeed對象需要進行初始化,然後才可調用MediaFeed 的onResume;
    2、處理訊息佇列中的HANDLE_INTENT訊息,Gallery處理這個訊息會初始化資料來源,從而調用GridLayer的setDataSource方法,這個方法會觸發底層MediaFeed的啟動方法start,執行完後啟動feed監聽線程繼續執行MediaFeed的run方法。
    start方法會作兩件事:調用自己底層的重新開始方法onResume,onResume中會為映像和視頻這兩個媒體源分別增加“內容變化監聽器”,並請求重新整理這兩個媒體源(加入全域的重新整理請求列表);啟動feed初始化線程mAlbumSourceThread。
    3、其中MediaFeed初始化線程的工作是:調用MediaFeed的loadMediaSets載入相簿,它又調用了下層 LocalDataSource中的refresh方法(查詢資料庫是否有相簿變化,新增或修改feed中相應的MediaSet相簿的名字)和 loadMediaSets方法(調用下層CacheService.loadMediaSets方法)載入所有相簿和相簿中的所有相片資訊。
    4、MediaFeed監聽線程MediaFeed.run()的工作是:根據“內容變化監聽器”返回的媒體變動訊息(增刪改),持續不斷的更新MediaFeed中的相簿和相片變數。具體機制如下:如果全域的重新整理請求列表中有內容,則調用LocalDataSource.refresh進行相簿資訊的更新(其中 LocalDataSource.refresh調用了CacheService的computeDirtySets),然後run遍曆每個相簿並調用dataSource.loadItemsForSet()方法為相簿載入相片記錄。

2 功能模組說明
1) 階層
    分為三層:上層Java應用程、中層Framework層、下層是底層libaries層。整個MediaPlayer在啟動並執行時候,可以大致上分成Client和Server兩個部分,它們分別在兩個進程中運行,它們之間使用Binder機制實現IPC通訊。

2) 說明
  2.1) Gallery.java中通過Handler實現實現處理序間通訊,涉及sendInitialMessage()方法;檢查儲存的媒體檔案,涉及checkStorage()方法;並初始化Data Source,涉及initializeDatasource()方法;判定資料類型後,通過onActivityResult()執行相應的活動。涉及到圖層,GridLayer主圖層,同GridDrawManager管理媒體的呈現。
  
 2.2) MediaPlayer的JAVA本地調用部分
    MediaPlayer的JAVA本地調用部分在目錄frameworks/base/media/jni/的 android_media_MediaPlayer.cpp中的檔案中實現。android.media.MediaPlayer中有2部分,一部分供java上層如VideoView調用,一部分為native方法,調用jni。
    通過MediaPlayerService實現client端和MediaPlayer進行互動和資料通訊,其中涉及通過MediaProvider(多媒體內容提供者)調用資料來源,MediaScannerService(多媒體掃描服務)和MediaScannerReceiver檢查資料類型(這兩個類之間通過Server和BroadcasterRevceiver, 主要的方法scan()、scanFlle()),並將統一類型的檔案歸類用MediaStore(多媒體儲存)進行資料存放區;MediaPlayer.java調用jni_android_media_MediaPlayer.jni進行同MediaPalyer.cpp實現通訊。
       
    說明:
• MediaStore這個類是android系統提供的一個多媒體資料庫,android中多媒體資訊都可以從這裡提取。這個MediaStore包括了多媒體資料庫的所有資訊,包括音頻、視頻和映像。
• MediaScannerReceiver在任何的ACTION_BOOT_COMPLETED, ACTION_MEDIA_MOUNTED或 ACTION_MEDIA_SCANNER_SCAN_FILE 意圖(intent)發出的時候啟動。因為解析媒體檔案的中繼資料或許會需要很長時間,所以MediaScannerReceiver會啟動MediaScannerService。
• MediaScannerService調用一個公用類MediaScanner進行媒體掃描工作。MediaScannerReceiver維持兩種掃描目錄:一種是內部卷(internal volume)指向$(ANDROID_ROOT)/media. 另一種是外部卷(external volume)指向$(EXTERNAL_STORAGE).

3) MediaPlayer
    Android的MediaPlayer包含了Audio和video的播放功能,在Android的介面上,Music和Video兩個應用程式都是調用MediaPlayer實現的,上層還包含了進程間通訊等內容,這種進程間通訊的基礎是Android基本庫中的Binder機制。Android的媒體播放功能分成兩部分,一部分是媒體播放應用,一部分是媒體播放服務。這兩部分分別跑在不同的進程中。媒體播放應用程式套件括Java程式和部分C++代碼,媒體播放服務是C++代碼。媒體播放應用和媒體播放服務之間需要通過binder機制來進行相互調用,這些調用包括:
   (1) 媒體播放應用向媒體播放服務發控制指令;
   (2) 媒體播放服務向媒體播放應用發事件通知(notify)。
•    媒體播放服務對外提供多個介面,其中有2個重要的介面:IMediaPlayerService和IMediaPlayer;IMediaPlayerServer用於建立和管理播放執行個體,而IMediaPlayer介面則是播放介面,用於實現指定媒體檔案的播放以及播放過程的控制。
•        媒體播放應用向媒體播放服務提供的1個介面:IMediaPlayerClient,用於接收notify()。這些介面需要跨進程調用,涉及到binder機制(就是讓這兩部分之間建立聯絡)。每個介面包括兩部分實現,一部分是介面功能的真正實現(BnInterface),這部分運行在介面提供進程中;另一部分是介面的proxy(BpInterface),這部分運行在調用介面的進程中。

3 代碼架構
 
1) JAVA程式的路徑:
packages/apps/Camera/
編譯後產生Camera.apk,對應於Camera、Gallery、Camcorder三個應用。

packages/apps/Gallery/src/com/android/camera/gallery、
packages/apps/Gallery3D/src/com/cooliris/app

packages/providers/MediaProvider/
含有類MediaProvider.java、MediaScannerService.java、MediaScannerReceiver.java,
編譯後產生MediaProvider.apk。會在開機時掃描本機和sdcard上的媒體檔案(圖片、視頻、音頻),並在/data/data/com.android.providers.media/databases 目錄下產生internal.db(/system/meida)和external-?.db(/sdcard)兩個資料庫檔案。此後所有的多媒體資訊都從這兩個資料庫中擷取。

2) JAVA Framework的路徑:
frameworks/base/core/java/android/provider/MediaStore.java
提供的多媒體資料庫,所有多媒體資料資訊都可以從這裡提取。資料庫的操作通過利用ContentResolver調用相關的介面實現。

frameworks/base/media/java/android/media/
提供了android上 多媒體應用程式層的操作介面。主要說明:
• MediaPlayer.java:提供了視頻、音頻、資料流的播放控制等操作的介面。
• MediaScanner*.java:提供了媒體掃描介面的支援,媒體掃描後加入資料庫中,涉及MediaScannerConnection.java和MediaScannerConnectionClient.java。

3) JAVA本地調用部分(JNI):
frameworks/base/media/jni
JAVA本地調用部分。編譯後產生的目標是libmedia_jni.so。
•    android_media_MediaPlayer.cpp:JAVA本地調用部分,它定義了一個JNINativeMethod(JAVA本地調用方法)類型的資料gMethods用來描述介面的關聯資訊;定義了JNIMediaPlayerListener:MediaPlayerListener的notify()方法(該方法是調用c++層次的mediaplayer中,實現播放管制)。
•    android_media_MediaScanner.cpp: 媒體掃描相關的本地調用實現。處理路徑、檔案和Ablum相簿內容釋放。
•    soundpool/android_media_SoundPool.cpp:定義了音頻系統的本地調用實現、MediaPlayer回調方法android_media_callback()。

4) 多媒體底層庫:
frameworks/base/include/media/、frameworks/base/media/libmedia/
    這裡為多媒體的的底層庫,編譯產生libmedia.so。這個庫處於android多媒體架構的核心位置,它對上層提供的介面主要有MediaPlayer、MediaScanner等類。
    android.meida.* 就是通過libmedia_jni.so調用libmedia.so實現的介面實現的。    
    A) MediaPlayerInterface.h標頭檔定義了MediaPlayer的底層介面,定義了以下類:
•    MediaPlayerBase:MediaPlayerInterface的抽象基礎類,裡麵包含了音訊輸出、視頻輸出、播放控制等的基本介面。
•        MediaPlayerInterface、MediaPlayerHWInterface 繼承自MediaPlayerBase針對不同輸出作出的擴充。
•        MediaPlayerInterface得到具有相同的播放介面,可以通過繼承MediaPlayerInterface的方法,實現增加新的播放器實現。
    B) IMediaPlayer.h定義了BnMediaPlayer本地播放類;IMediaPlayer.cpp定義了BpMediaPlayer代理類(其中通過remote()->transact()方法發送訊息)和實現了BnMediaPlayer:onTransact()的具體方法。
    C) IMediaPlayerClient.h定義了BnMediaPlayerClient本地用戶端類;IMediaPlayerClient.cpp定義了BpMediaPlayerClient代理類(其中通過notify()中的remote()->transact()方法發送訊息)和實現了BnMediaPlayerClient:onTransact()方法。
    D) IMediaPlayerService.h定義了BnMediaPlayerService本地服務端類;IMediaPlayerService.cpp定義了BpMediaPlayerService代理類(其中通過remote()->transact()方法發送訊息)和實現了BnMediaPlayerService:onTransact()方法。
    E) mediaplayer.h定義了MediaPlayerListener類的notify()方法和類MediaPlayer:BnMediaPlayerClient;mediaplayer.cpp主要實現了MediaPlayer的資料設定播放和實現了MediaPlayerListener類的notify()具體方法。

5) 多媒體服務部分:
frameworks/base/media/libmediaplayerservice/
檔案為mediaplayerservice.h和mediaplayerservice.cpp
    這是多媒體的服務部分(提供Media Player執行的Proxy,同Client端建立串連、設定資料來源、根據不同類型建立播放),編譯產生libmediaplayerservice.so。     
• MediaPlayerService.cpp 通過instantiate()方法實現了一個名字為media.player的服務,MediaPlayer通過IPC同其實現通訊;
• 根據playerType的類型來決定建立不同的播放器;
• 實現了notify()通知Client端、callbackThread()回調機制、decode解碼。

frameworks/base/media/mediaserver/
檔案為main_mediaserver.cpp是Mediaplayer Server啟動的主程式,涉及AudioFlinger()、AudioPolicyService()、MediaPlayerService()的載入。

6) MediaPlayer生命週期:
 

4 Audio概念
Audio系統在Android中負責音頻方面輸入/輸出和管理層次,一般負責播放PCM聲音輸出和從外部擷取PCM聲音,以及管理聲音裝置和設定。主要涉及到AudioManager、AudioTrack、AudioServiece、AudioRecord。主要分成如下幾個層次:
 (1) media庫提供的Audio系統本地部分介面;
 (2) AudioFlinger作為Audio系統的中介層;
 (3) Audio的硬體抽象層提供底層支援;
 (4) Audio介面通過JNI和Java架構提供給上層。
    Audio管理環節    Audio輸出    Audio輸入
Java層    android.media.
AudioSystem    android.media
AudioTrack    android.media.
AudioRecorder
本地架構層    AudioSystem    AudioTrack    AudioRecorder
AudioFlinger    IAudioFlinger    IAudioTrack    IAudioRecorder
硬體抽象層    AudioHardwareInterface    AudioStreamOut    AudioStreamIn
AudioTrack.java:SoundPool.java 播放android application的生音資源。
AudioRecord.java: 為android applicatio 提供錄音設定(sample、chanel等)的介面;
AudioManager.java: 提供了音頻音量,以及播放模式(靜音、震動等)的控制。
說明:
1) Audio驅動程式(Linux系統,因不同平台而已)
2) Audio硬體抽象層:hardware/libhardware_legacy/include/hardware/
    AudioHardwareInterface.h(定義Audio硬體抽象層的介面),其中三個主要類AuidoStreamOut/AudioStreamIn/AuidoHardwareInterface實現Audio的輸出/輸入/管理。
    2.1) AudioStreamOut關鍵介面write(const void* buffer, size_t bytes)/AudioStreamIn關鍵介面read(void* buffer, size_t bytes),通過定義記憶體的指標和長度音頻資料的輸出和輸入。
    2.2) AudioHardwareInterface使用openOutputStream()和openInputStream()函數來擷取AudioStreamOut和AudioStreamIn。
    2.3) AudioHardwareInterface中所涉及的參數是在AudioSystem.h中定義,通過setParameters和getParameters介面設定和擷取參數,通過setMode()設定系統模式。
    2.4) Audio中引進了策略管理AudioPolicyInterface,目的是將Audio核心部分和輔助性功能分離。
3) AudioFlinger的實現方式
    3.1) 通用方式AndroidHardwareGeneric實現基於特定驅動的通用Audio硬體抽象層。
    3.2) 樁實現方式AndroidHardwareStub,實現Audio硬體抽象層的一個樁,是個空操作,保證沒有Audio裝置時系統正常工作。
    3.3) AudioDumpInterface實現以檔案為輸入輸出的Audio硬體抽象層,以檔案類比Audio硬體流的輸入輸出環節。

Audio代碼分布:
(1) Java部分:frameworks/base/media/java/android/media
與audio相關的java package是android.media,主要包含audio manager和audio系統的幾個類,這部分主要給上層的AP部分提供audio相關的介面。
(2) JNI部分: frameworks/base/core/jni
Android系統會產生一個libandroid_runtime.so,audio的JNI是其中的一個部分。
(3) audio frameworks
標頭檔路徑:frameworks/base/include/media/
代碼路徑:frameworks/base/media/libmedia/
Audio本地架構是media庫的一部分,本部分的內容被編譯成庫libmedia.so,提供audio部分的介面(其中包括基於binder的IPC機制)。
(4) Audio Flinger:frameworks/base/libs/audioflinger
這部分內容被編譯成庫libaudioflinger.so,它是audio系統的本地服務部分。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.