關于opencore下多媒體播放,在mediaserver進程里面僅僅有一行代碼: MediaPlayerService::instantiate(); 這行代碼的作用是初始化一個MediaPlayerService類的實例,并接把他增加到系統的serveceManager中。 MediaPlayerService的詳細實如今目錄frameworks/base/media/libmediaplayerservice中。 在涉及到要播放一個詳細的媒體文件時,調用的函數是:
sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url){ int32_t connId = android_atomic_inc(&mNextConnId); sp<Client> c = new Client(this, pid, connId, client); LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId); if (NO_ERROR != c->setDataSource(url)) { c.clear(); return c; } wp<Client> w = c; Mutex::Autolock lock(mLock); mClients.add(w); return c;}
這個new 了一個Client 而且函數將它返回為sp<IMediaPlayer>。
Client對象什么在文件MediaPlayerService.h中,而且是private類,說明它僅僅被MediaPlayerService對象使用。Client對象繼承自BnMediaPlayer,而BnMediaPlaye又繼承自BnInterface<IMediaPlayer>,看來是用來響應binder的IPC的函數。 而IMediaPlayer又是何許東東。 IMediaPlayer.cpp在目錄frameworks/base/media/中,而IMediaPlayer.h 在目錄frameworks/base/include/media中。IMediaPlayer.h中聲明了一個IMediaPlayer的類,而它的函數又都是virtual,一看就是用來申明接口的。
MediaPlayerService::create函數調用以后,立即調用Client:setDataSource,事實上如今MediaPlayerService.cpp中,
status_t MediaPlayerService::Client::setDataSource(const char *url){ 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) { LOGE("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 = getPlayerType(url); //通過url來取得playertype,比如對于midi,就用SONIVOX_PLAYER,mp3,mp4等就用PVPLAYER LOGV("player type = %d", playerType); // create the right type of player sp<MediaPlayerBase> p = createPlayer(playerType); //依據不同的playertype來創建不同的player實例 if (p == NULL) return NO_INIT; if (!p->hardwareOutput()) { mAudioOutput = new AudioOutput(); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); } // now set data source LOGV(" setDataSource"); mStatus = p->setDataSource(url); if (mStatus == NO_ERROR) { mPlayer = p; } else { LOGE(" error: %d", mStatus); } return mStatus; }}
注意這行代碼:sp<MediaPlayerBase> p = createPlayer(playerType); 他的作用是依據不同的playerType來創建player實例,我們這里主要關注PVPlayer。說了這么多,最終到達opencore那一層了。有時候會認為android這種設計實在太復雜了,調用起來太麻煩,直接實現一個IMediaPlayer的類不就完了嗎??墒羌氈乱粯?androide的這種設計方式事實上有它在擴展性和可維護性上才這樣做的。說究竟就是一句話,減少模塊間的耦合性。 涉及到詳細的操作,都是通過實現一個接口類來實現,這樣詳細的實例在創建的時候就能夠通過工廠模式來簡單的進行擴展。比如上面所提到的createPlayer(playerType)這個函數,當你須要加入自己的特殊格式的播放器的時候,就不用來改它本來的代碼,而僅僅用在createPlayer(playerType)的實現以下幾行代碼:
case XXX_PLAYER: LOGV(" create XXXFile"); p = new XXXPlayer(); break;
很方便,而這樣的擴展性和是由接口和實現的分離帶來的,createPlayer 返回的是sp<MediaPlayerBase>類,而去看這個類的代碼,發現這個類都是由virtual函數組成的,當你要實現詳細實現時候,你能夠繼承它,然后寫好這些virtual函數的實現。 扯遠了。設計模式的厲害,可能須要我花整個的職業生涯來體會。 廢話不多說,讓我們來看PVPlayer的實現,我剛才說過,PVPlayer才是opencore真正的內容。 PVPlayer的申明在frameworks/base/include/media/PVPlayer.h中,而實如今external/opencore/android/playerdriver.cpp。 為什么要這樣做?我不懂,我推測還是為了實現和接口的分離,僅僅只是這次的分離就僅僅能簡單的通過把頭文件和實現文件放到不同目錄下來實現。 OK,那么讓我們來看看PVPlayer是干嘛的。 PVPlayer繼承自MediaPlayerInterface,而MediaPlayerInterface是Opencore對媒體播放的抽象接口的聲明類。 那么我們去看看PVPlayer的各個接口的實現吧。PVPlayer的非常多借口都是通過向它的成員mPlayerDriver發送命令來實現,而mPlayerDriver通過調用mPVPlayer的sendEvent函數來告訴PVPlayer,命令是否運行成功了。PlayerDriver是PVPlayer的一個內部成員,它是PVPlayer的命令運行者。 sendEvent的實現例如以下:
void sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
MediaPlayerBase::sendEvent的實現例如以下:
virtual void sendEvent(int msg, int ext1=0, int ext2=0) { if (mNotify) mNotify(mCookie, msg, ext1, ext2); }
mNotify是MediaPlayerBase的一個成員變量,它是一個函數指針,原型例如以下:
typedef void (*notify_callback_f)(void* cookie, int msg, int ext1, int ext2);
這個成員變量在調用createPlayer的時候就調用setNotifyCallback來賦值的。 所以,能夠看到,底層的事件會一層一層的往上調用,直至返回給用戶層。 這里涉及到2個設計模式: 命令模式和觀察者模式。 這兩個模式都是設計模式中的基本模式之中的一個,功能強大,邏輯清晰。詳細的內容不是本文的重點,在此略過。
155305.html
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
vivo手機電池容量怎么找?這個可以到VIVO官網自助查詢,具體方法::一、簡單的方法建議使用百度找不到VIVO手機官網,然后然后點擊。二、進入到VIVO手機官網以后,找到要網站查詢的手機型號,這里以X23手機為例,進入頁面。三、直接進入以后中,選擇“參數規格”選項。四、進入到以后就這個可以查詢到手機電池的容量了。vivo手機在哪里可以查電池多少毫安?vivo手機又不能在手機上查找到手機的電池容量...
temp文件夾在哪 怎樣打開手機?temp文件?temp文件怎么開? 01安卓手機打不開.tmp如果您想查看文件內容,可以將文件發送到計算機,并用記事本打開。右鍵選擇tmp打開文件的方式是記事本,可以在記事本中看到tmp文件內容,但有些tmp文件看到內容亂碼。 tmp是temporary縮寫,即臨時。操作系統在運行過程中使用大量文件,有些文件不能直接修改,或者內存中有臨時文件。此時,...
idx文件是什么?IDX是所有的字幕文件。如果您將它們解壓縮到與電影相同的目錄中,則可以使用某些播放器(如storm video)自動讀取字幕。具體來說,流行的字幕格式分為圖形格式和文本格式。圖形字幕由IDX和子文件組成。IDX是索引文件,包括字幕出現的時間和字幕顯示的屬性。子文件是字幕文件。文本格式字幕的擴展是SRT、SMI、SSA或sub,其中SRT字幕最為流行,制作方法是一次編碼加一個字幕。...