1、 Gallery應(yīng)用端表現(xiàn)
Gallery僅僅提供一個呈現(xiàn)框架,Gallery用來管理所有的視頻和圖片文件,具有播放、查看、刪除等功能。自動搜索本地sdcard存有的
picture和video,并分類將同性質(zhì)文件picture和video集中在一起,播放時呈現(xiàn)。Gallery內(nèi)部實現(xiàn)的播放主用是同
MediaPlayer,主要包含了Audio和video的播放功能。
方法:首先遍歷sdcard下的目錄,然后通過選擇某個目錄,再遍歷文件,點擊文件播放。
說明:
定義了兩個List表:
videoPathList:遍歷/sdcard下目錄,并存于此List。
videlFileList:遍歷相應(yīng)目錄下的文件,并存于此List。
定義了兩個Activity:
VideoList2Play:實現(xiàn)/sdcard下目錄和文件遍歷。
VideoPlayer:利用VideoView類實現(xiàn)視頻播放。
從Gallery的按鈕和菜單項著手,將該功能植入Gallery。
Gallery首次加載的圖框上“拍照按鈕”,能夠找到內(nèi)部功能實現(xiàn)的類和方法,并可以將該功能加入。
利用more菜單,增加“選擇其它視頻”功能,涉及內(nèi)部類復(fù)雜,需進一步研究,暫沒有實現(xiàn)。
利用視頻播放是的MovieView中增加“選擇其它視頻”按鈕,當有視頻真正在播放時,點擊按鈕選擇其它視頻,會有沖突。
需改進:研究通過彈出選擇對話框方式,可以自由選擇/sdcard下的目錄和文件,并實現(xiàn)播放。
Gallery中數(shù)據(jù)緩存及處理流程
在應(yīng)用程序中有三個線程存在:主線程(隨activity的聲明周期啟動銷毀)、feed初始化線程(進入程序時只運行一次,用于加載相冊初始信息)、feed監(jiān)聽線程(監(jiān)聽相冊和相片的變更)。主要流程歸納如下:
1、首次進入程序Gallery調(diào)用onCreate,此時發(fā)送初始化消息進入消息隊列;然后Gallery調(diào)用onResume,向下進入
GridLayer的onResume。MediaFeed對象需要進行初始化,然后才可調(diào)用MediaFeed 的onResume;
2、處理消息隊列中的HANDLE_INTENT消息,Gallery處理這個消息會初始化數(shù)據(jù)源,從而調(diào)用GridLayer的
setDataSource方法,這個方法會觸發(fā)底層MediaFeed的啟動方法start,執(zhí)行完后啟動feed監(jiān)聽線程繼續(xù)執(zhí)行MediaFeed
的run方法。
start方法會作兩件事:調(diào)用自己底層的重新開始方法onResume,onResume中會為圖像和視頻這兩個媒體源分別增加“內(nèi)容變化監(jiān)聽器”,并
請求刷新這兩個媒體源(加入全局的刷新請求列表);啟動feed初始化線程mAlbumSourceThread。
3、其中MediaFeed初始化線程的工作是:調(diào)用MediaFeed的loadMediaSets加載相冊,它又調(diào)用了下層
LocalDataSource中的refresh方法(查詢數(shù)據(jù)庫是否有相冊變化,新增或修改feed中相應(yīng)的MediaSet相冊的名字)和
loadMediaSets方法(調(diào)用下層CacheService.loadMediaSets方法)加載所有相冊和相冊中的所有相片信息。
4、MediaFeed監(jiān)聽線程MediaFeed.run()的工作是:根據(jù)“內(nèi)容變化監(jiān)聽器”返回的媒體變動消息(增刪改),持續(xù)不斷的更新
MediaFeed中的相冊和相片變量。具體機制如下:如果全局的刷新請求列表中有內(nèi)容,則調(diào)用LocalDataSource.refresh進行相冊
信息的更新(其中
LocalDataSource.refresh調(diào)用了CacheService的computeDirtySets),然后run遍歷每個相冊并調(diào)用
dataSource.loadItemsForSet()方法為相冊加載相片記錄。
2、 功能模塊說明
1》 層次結(jié)構(gòu)
分為三層:上層Java應(yīng)用程、中層Framework層、下層是底層libaries層。整個MediaPlayer在運行的時候,可以大致上分成Client和Server兩個部分,它們分別在兩個進程中運行,它們之間使用Binder機制實現(xiàn)IPC通訊。
2.1》Gallery.java中通過Handler實現(xiàn)實現(xiàn)進程間通信,涉及sendInitialMessage()方法;檢查存儲的媒體文件,涉
及checkStorage()方法;并初始化Data
Source,涉及initializeDatasource()方法;判定數(shù)據(jù)類型后,通過onActivityResult()執(zhí)行相應(yīng)的活動。涉及
到圖層,GridLayer主圖層,同GridDrawManager管理媒體的呈現(xiàn)。
2.2》MediaPlayer的JAVA本地調(diào)用部分
MediaPlayer的JAVA本地調(diào)用部分在目錄frameworks/base/media/jni/的 Android_media_MediaPlayer.cpp中的文件中實現(xiàn)。android.media.MediaPlayer中有2部分,一部分供java上層如VideoView調(diào)用,一部分為native方法,調(diào)用jni。
通過MediaPlayerService實現(xiàn)client端和MediaPlayer進行交互和數(shù)據(jù)通信,其中涉及通過MediaProvider(多
媒體內(nèi)容提供者)調(diào)用數(shù)據(jù)源,MediaScannerService(多媒體掃描服務(wù))和MediaScannerReceiver檢查數(shù)據(jù)類型(這兩
個類之間通過Server和BroadcasterRevceiver,主要的方法scan()、scanFlle()),并將統(tǒng)一類型的文件歸類用
MediaStore(多媒體存儲)進行數(shù)據(jù)存儲;MediaPlayer.java調(diào)用jni_Android_media_MediaPlayer.jni進行同MediaPalyer.cpp實現(xiàn)通信。
說明:
MediaStore這個類是Android系統(tǒng)提供的一個多媒體數(shù)據(jù)庫,android中多媒體信息都可以從這里提取。這個MediaStore包括了多媒體數(shù)據(jù)庫的所有信息,包括音頻、視頻和圖像。
MediaScannerReceiver在任何的ACTION_BOOT_COMPLETED, ACTION_MEDIA_MOUNTED或
ACTION_MEDIA_SCANNER_SCAN_FILE
意圖(intent)發(fā)出的時候啟動。因為解析媒體文件的元數(shù)據(jù)或許會需要很長時間,所以MediaScannerReceiver會啟動
MediaScannerService。
MediaScannerService調(diào)用一個公用類MediaScanner進行媒體掃描工作。MediaScannerReceiver維持兩種掃描目錄:一種是內(nèi)部卷(internal volume)指向$(Android_ROOT)/media. 另一種是外部卷(external volume)指向$(EXTERNAL_STORAGE).
3》MediaPlayer
Android的
MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video兩個應(yīng)用程序都是調(diào)用
MediaPlayer實現(xiàn)的,上層還包含了進程間通訊等內(nèi)容,這種進程間通訊的基礎(chǔ)是Android基本庫中的Binder機制。Android的媒體
播放功能分成兩部分,一部分是媒體播放應(yīng)用,一部分是媒體播放服務(wù)。這兩部分分別跑在不同的進程中。媒體播放應(yīng)用包括Java程序和部分C++代碼,媒體
播放服務(wù)是C++代碼。媒體播放應(yīng)用和媒體播放服務(wù)之間需要通過binder機制來進行相互調(diào)用,這些調(diào)用包括:
(1)媒體播放應(yīng)用向媒體播放服務(wù)發(fā)控制指令;
(2)媒體播放服務(wù)向媒體播放應(yīng)用發(fā)事件通知(notify)。
媒體播放服務(wù)對外提供多個接口,其中有2個重要的接口:IMediaPlayerService和
IMediaPlayer;IMediaPlayerServer用于創(chuàng)建和管理播放實例,而IMediaPlayer接口則是播放接口,用于實現(xiàn)指定媒
體文件的播放以及播放過程的控制。
媒體播放應(yīng)用向媒體播放服務(wù)提供的1個接口:IMediaPlayerClient,用于接收notify()。這些接口需要跨進程調(diào)用,涉及到
binder機制(就是讓這兩部分之間建立聯(lián)系)。每個接口包括兩部分實現(xiàn),一部分是接口功能的真正實現(xiàn)(BnInterface),這部分運行在接口提
供進程中;另一部分是接口的proxy(BpInterface),這部分運行在調(diào)用接口的進程中。
3、 代碼框架
1》JAVA程序的路徑:
packages/apps/Camera/
編譯后生成Camera.apk,對應(yīng)于Camera、Gallery、Camcorder三個應(yīng)用。
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)兩個數(shù)據(jù)庫文件。此后所有的多媒體信息都從這兩個數(shù)據(jù)庫中獲取。
2》JAVA Framework的路徑:
frameworks/base/core/java/Android/provider/MediaStore.java
提供的多媒體數(shù)據(jù)庫,所有多媒體數(shù)據(jù)信息都可以從這里提取。數(shù)據(jù)庫的操作通過利用ContentResolver調(diào)用相關(guān)的接口實現(xiàn)。
frameworks/base/media/java/Android/media/
提供了Android上 多媒體應(yīng)用層的操作接口。主要說明:
MediaPlayer.java:提供了視頻、音頻、數(shù)據(jù)流的播放控制等操作的接口。
MediaScanner*.java:提供了媒體掃描接口的支持,媒體掃描后加入數(shù)據(jù)庫中,涉及MediaScannerConnection.java和MediaScannerConnectionClient.java。
3》JAVA本地調(diào)用部分(JNI):
frameworks/base/media/jni
JAVA本地調(diào)用部分。編譯后生成的目標是libmedia_jni.so。
Android_media_MediaPlayer.cpp:JAVA
本地調(diào)用部分,它定義了一個JNINativeMethod(JAVA本地調(diào)用方法)類型的數(shù)據(jù)gMethods用來描述接口的關(guān)聯(lián)信息;定義了
JNIMediaPlayerListener:MediaPlayerListener的notify()方法(該方法是調(diào)用c++層次的
mediaplayer中,實現(xiàn)播放管制)。
Android_media_MediaScanner.cpp: 媒體掃描相關(guān)的本地調(diào)用實現(xiàn)。處理路徑、文件和Ablum相冊內(nèi)容釋放。
soundpool/Android_media_SoundPool.cpp:定義了音頻系統(tǒng)的本地調(diào)用實現(xiàn)、MediaPlayer回調(diào)方法android_media_callback()。
4》多媒體底層庫:
frameworks/base/include/media/、frameworks/base/media/libmedia/
這里為多媒體的的底層庫,編譯生成libmedia.so。這個庫處于Android多媒體架構(gòu)的核心位置,它對上層提供的接口主要有MediaPlayer、MediaScanner等類。
Android.meida.* 就是通過libmedia_jni.so調(diào)用libmedia.so實現(xiàn)的接口實現(xiàn)的。 A》MediaPlayerInterface.h頭文件定義了MediaPlayer的底層接口,定義了以下類:
MediaPlayerBase:MediaPlayerInterface的抽象基礎(chǔ)類,里面包含了音頻輸出、視頻輸出、播放控制等的基本接口。
MediaPlayerInterface、MediaPlayerHWInterface 繼承自MediaPlayerBase針對不同輸出作出的擴展。
MediaPlayerInterface得到具有相同的播放接口,可以通過繼承MediaPlayerInterface的方法,實現(xiàn)增加新的播放器實現(xiàn)。
B》IMediaPlayer.h定義了BnMediaPlayer本地播放類;IMediaPlayer.cpp定義了BpMediaPlayer代理
類(其中通過remote()->transact()方法發(fā)送消息)和實現(xiàn)了BnMediaPlayer:onTransact()的具體方法。
C》IMediaPlayerClient.h定義了BnMediaPlayerClient本地客戶端
類;IMediaPlayerClient.cpp定義了BpMediaPlayerClient代理類(其中通過notify()中的
remote()->transact()方法發(fā)送消息)和實現(xiàn)了BnMediaPlayerClient:onTransact()方法。
D》IMediaPlayerService.h定義了BnMediaPlayerService本地服務(wù)端
類;IMediaPlayerService.cpp定義了BpMediaPlayerService代理類(其中通過
remote()->transact()方法發(fā)送消息)和實現(xiàn)了BnMediaPlayerService:onTransact()方法。
E》mediaplayer.h定義了MediaPlayerListener類的notify()方法和類
MediaPlayer:BnMediaPlayerClient;mediaplayer.cpp主要實現(xiàn)了MediaPlayer的數(shù)據(jù)設(shè)置播放和實
現(xiàn)了MediaPlayerListener類的notify()具體方法。
5》多媒體服務(wù)部分:
frameworks/base/media/libmediaplayerservice/
文件為mediaplayerservice.h和mediaplayerservice.cpp
這是多媒體的服務(wù)部分(提供Media Player執(zhí)行的Proxy,同Client端建立連接、設(shè)置數(shù)據(jù)源、根據(jù)不同類型創(chuàng)建播放),編譯生成libmediaplayerservice.so。
MediaPlayerService.cpp 通過instantiate()方法實現(xiàn)了一個名字為media.player的服務(wù),MediaPlayer通過IPC同其實現(xiàn)通訊;
根據(jù)playerType的類型來決定創(chuàng)建不同的播放器;
實現(xiàn)了notify()通知Client端、callbackThread()回調(diào)機制、decode解碼。
frameworks/base/media/mediaserver/
文件為main_mediaserver.cpp是Mediaplayer Server啟動的主程序,涉及AudioFlinger()、AudioPolicyService()、MediaPlayerService()的加載。
6》MediaPlayer生命周期:
4、 Audio概念
Audio系統(tǒng)在Android中負責音頻方面輸入/輸出和管理層次,一般負責播放PCM聲音輸出和從外部獲取PCM聲音,以及管理聲音設(shè)備和設(shè)置。主要涉及到AudioManager、AudioTrack、AudioServiece、AudioRecord。主要分成如下幾個層次:
(1)media庫提供的Audio系統(tǒng)本地部分接口;
(3)Audio的硬件抽象層提供底層支持;
(4)Audio接口通過JNI和Java框架提供給上層。
Audio管理環(huán)節(jié) 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 提供錄音設(shè)置(sample、chanel等)的接口;
AudioManager.java: 提供了音頻音量,以及播放模式(靜音、震動等)的控制。
說明:
1》Audio驅(qū)動程序(Linux系統(tǒng),因不同平臺而已)
2》Audio硬件抽象層:hardware/libhardware_legacy/include/hardware/
AudioHardwareInterface.h(定義Audio硬件抽象層的接口),其中三個主要類AuidoStreamOut/AudioStreamIn/AuidoHardwareInterface實現(xiàn)Audio的輸出/輸入/管理。
2.1》AudioStreamOut關(guān)鍵接口write(const void* buffer, size_t bytes)/AudioStreamIn關(guān)鍵接口read(void* buffer, size_t bytes),通過定義內(nèi)存的指針和長度音頻數(shù)據(jù)的輸出和輸入。
2.2》AudioHardwareInterface使用openOutputStream()和openInputStream()函數(shù)來獲取AudioStreamOut和AudioStreamIn。
2.3》AudioHardwareInterface中所涉及的參數(shù)是在AudioSystem.h中定義,通過setParameters和getParameters接口設(shè)置和獲取參數(shù),通過setMode()設(shè)置系統(tǒng)模式。
2.4》Audio中引進了策略管理AudioPolicyInterface,目的是將Audio核心部分和輔助性功能分離。
3》AudioFlinger的實現(xiàn)方式
3.1》通用方式AndroidHardwareGeneric實現(xiàn)基于特定驅(qū)動的通用Audio硬件抽象層。
3.2》樁實現(xiàn)方式AndroidHardwareStub,實現(xiàn)Audio硬件抽象層的一個樁,是個空操作,保證沒有Audio設(shè)備時系統(tǒng)正常工作。
3.3》AudioDumpInterface實現(xiàn)以文件為輸入輸出的Audio硬件抽象層,以文件模擬Audio硬件流的輸入輸出環(huán)節(jié)。
Audio代碼分布:
(1) Java部分:frameworks/base/media/java/Android/media
與audio相關(guān)的java package是Android.media,主要包含audio manager和audio系統(tǒng)的幾個類,這部分主要給上層的AP部分提供audio相關(guān)的接口。
(2) JNI部分: frameworks/base/core/jni
Android系統(tǒng)會生成一個libandroid_runtime.so,audio的JNI是其中的一個部分。
(3) audio frameworks
頭文件路徑:frameworks/base/include/media/
代碼路徑:frameworks/base/media/libmedia/
Audio本地框架是media庫的一部分,本部分的內(nèi)容被編譯成庫libmedia.so,提供audio部分的接口(其中包括基于binder的IPC機制)。
(4) Audio Flinger:frameworks/base/libs/audioflinger
這部分內(nèi)容被編譯成庫libaudioflinger.so,它是audio系統(tǒng)的本地服務(wù)部分。