Android 媒體文件管理

轉自: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系統的本地服務部分。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章