編輯:關於Android編程
本文用一個UML類圖,講解mp3文件播放的框架流程。內容以下幾個方面:
1.UML類圖
2.stagefrightPlayer是如何創建的;
3.mp3文件的解析和解碼的簡單介紹4.播放mp3文件過程中,生產者和消費者的關系;
5.openmax和stagefright框架的消息機制

對照著UML圖,看下StagefrightPlayer創建的過程。
故事的開始是Java層的MediaPlayer調用了setDataSource這個函數(參數為一個path),導致native對應的MediaPlayer 通過Binder通信機制在MediaPlayerService中開辟了一個“戶口”,即創建Client對象,這個對象是個匿名的Binder。這個“戶口”在native MediaPlayer中表現為一個IMediaPlayer的接口。
上述過程代碼如下:
路徑:frameworks/av/media/libmedia/MediaPlayer.cpp:setDataSource
sp player(service->create(this, mAudioSessionId));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(url, headers))) {
player.clear();
}
err = attachNewPlayer(player); 代碼路徑:frameworks/av/media/libmediaplayerservice/MediaPlayerService
status_t MediaPlayerService::Client::setDataSource(
const char *url, const KeyedVector *headers)
{
ALOGV("setDataSource(%s)", url);
if (url == NULL)
return UNKNOWN_ERROR;
if ((strncmp(url, "http://", 7) == 0) ||
(strncmp(url, "https://", 8) == 0) ||
(strncmp(url, "rtsp://", 7) == 0)) {
if (!checkPermission("android.permission.INTERNET")) {
return PERMISSION_DENIED;
}
}
if (strncmp(url, "content://", 10) == 0) {
// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method
String16 url16(url);
int fd = android::openContentProviderFile(url16);
if (fd < 0)
{
ALOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
return mStatus;
} else {
player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
sp p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}
setDataSource_post(p, p->setDataSource(url, headers));
return mStatus;
}
} 上面大段的代碼和分析流程沒有關系,skim it。要創建一個合適的播放器,就要分析文件的格式,根據文件的格式來匹配一個合適的播放器。這個工作交給了MediaPlayerFactory。在其中注冊了許多的工廠用於生產一個合適的播放器。基本原理就是讀取歌曲文件的開頭一段字節,根據相關的container來解析歌曲的格式,做的粗糙一點的話就直接根據後綴名來判斷了。這其中的實現取決於廠商或者組件提供商了。
不管怎麼樣,我們現在假設MediaPlayerFactory根據路徑得到了一個合適的播放器,它的基類是MediaPlayerBase。android中默認的是StagefrightPlayer,繼承了MediaPlayerBase。於是StagefrightPlayer在工廠中被生產出來了。然後調用其setDataSource。
其實StagefrightPlayer只是一個空殼,真正的工作是AwesomePlayer去做,這個對象在StagefrightPlayer構造函數中產生。看到這裡的時候一定要記得看看UML類圖。看看他們兩個之間的關系。於是這個path最終就保存到了AwesomePlayer內部。
Java層的MediaPlayer設置完路徑之後,還要調用prepare。調用流程和上面設置路徑一樣:MediaPlayer->Client->StagefrightPlayer->AwesomePlayer,略過不表。AwesomePlayer的prepare做了兩件事情。給AwesomePlayer的事件隊列發送一條Event,然後等待這個事件的處理完成。
事件的處理在onPrepareAsyncEvent()函數中完成。做了以下工作:
1.創建一個原始Audio Track流。從這個流中讀取壓縮數據;對應於圖中的mAudioTrack。
2.創建一個讀取pcm數據的流。對應於圖中的mAudioSource。
mAudioTrack實際指向一個Mp3Source,而mAudioSource指向一個OMXCodec。Mp3Source提供Mp3原始數據供OMXCodec解碼,然後把解碼完成之後的數據傳遞給AudioPlayer。OMXCodec的解碼工作實際上是由具體的解碼組件完成。一個OMXCodec對應一個Omx中的node instance,node instance操作解碼組件。而node instance提供calback接受組件的消息。
圖中藍色部分表示讀取原始mp3文件流程;綠色表示組件的callback 傳遞流程;
播放過程中存在兩組生產者和消費者。
第一組:原始數據的生產者,Mp3Source;原始數據消費者OMXCodec;
第二組:pcm數據的提供者OMXCodec和pcm數據的消費者AudioPlayer。
其中AudioPlayer其實是一個中間橋梁,真正的pcm數據的消費者是AudioTrack。它不斷的通過callback機制來從AudioPlayer中讀取pcm數據。
這一部分有兩條主線:
1.OMXCodec如何操作組件;
2.組件的消息如何傳遞到StagefrightPlayer。
首先說第一條:OMXCodec的構造函數會調用omx的接口創建一個OMXNodeInstance實例,通過OMXNodeInstance實例來操作組件;在創建OMXNodeInstance的同時會傳遞給OMXNodeInstance一個觀察者OMXCodecObserver。一旦OMXNodeInstance接收到來自組件的消息,就會通過這個觀察者把消息傳遞給OMXCodec。
在解碼過程中如果OMXCodec發生了錯誤,AudioPlayer會檢測到read錯誤,會把相關的信息通過AwesomePlayer傳遞到StagefrightPlayer中去。進而通知到native的MediaPlayer。最後透過jni會post給java的MediaPlayer。
Android教你如何一步步打造通用適配器
前言在Android開發中ListView是最為常用的控件之一,基本每個應用都會涉及到它,要使用ListView列表展示,就不可避免地涉及到另外一個東西—&m
Android 四大組件學習之Activity六
本節學習Activity的狀態保存與恢復。先用例子開始:布局文件主要是實現如下,大家自行編寫Activity邏輯代碼: public class FiveAct
Android Launcher 設置壁紙
版本:1.0 日期:2014.11.25 2014.11.26版權:©kince特別推薦:泡在網上的日子一、概述 一般Launcher都帶有壁紙設置的功能,A
Android 下拉刷新上拉加載效果功能
應用場景: 在App開發中,對於信息的獲取與演示,不可能全部將其獲取與演示,為了在用戶使用中,給予用戶以友好、方便的用戶體驗,以滑動、下拉的效果動態加載數據的要求就會出現