2008年8月18日 星期一

盡量不要用 MediaPlayer.create() 來播放影音檔

Using MediaPlayer.create() to play your media files will have some performance issues. This problem has been fixed in v0.9 beta. The current implementation is mentioned at the last of this post.

這裡提到的問題,已經在 v0.9 beta 版本中解決了。文章最後,有提到新版 SDK 的解法。

在 Android 中,要播放影音檔,新版的 SDK 會建議你用 MediaPlayer 這個類別。裡頭提到,有兩個方法。一個是播放存放在 res/raw 中的影音檔,用下面這種方式。

另一個是直接播放在某個目錄中的檔案,用下面這種方式。

最近剛完成一個程式,就是用第一種 MediaPlayer.create() 的方式,在播放一個有幾百 K 大小的影音檔。結果我發現,怎麼這初始化的時間要這麼久?翻了一下原始碼,果然找到這元兇。讓我們先看一下這 MediaPlayer.create() 的片段原始碼。

你也看到問題點了嗎?這 16 ~ 24 行到底在做什麼啊!竟然要先複製一份要播放的影音檔,到某個暫存檔,才開始用 setDataSource() 播放這複製的影音檔。

這看起來,就像是一個偷懶的程式設計師在做的事,不能直接播放這 resources 內的影音檔嗎?就算要複製檔案,直接從 InputStream 中讀取,及使用這麼小的 buffer size (128),又是一個敗筆。我建議用 BufferedInputStream,速度就會快上 4 倍以上。希望下個版本,能改進這個問題。

如果你也像我這樣,要播放個不算小的影音檔。記得,千萬不要用 MediaPlayer.create()。

PS: 在 8/18 釋出的 v0.9 beta 版本中,已經解決這個問題。這個版本中的 MediaPlayer.create() 實現代碼如下:

嗯,已經改成直接播放 resources 內的影音檔。喔,這 AssetFileDescriptor openRawResourceFd(int id) 函式是 v.09 才新增的。之前,都找不到這樣的函式,讀原始程式,還真的讓人獲益不少。

2 則留言:

ellyer 提到...

你好~我最近也在寫類似的功能,create的那段程式碼我是複製你的~結果中間應該是設定或include的問題,我出現以下這個error:'MediaPlayer' was not declared in this scope
因為他的folder實在是太多了,我在想或許是include問題,結果試著include一些檔案還是出現錯誤,想請問你在include的部份有沒有需要注意的地方呢?謝謝你喔。

ellyer 提到...

不好意思,我說錯了,我是複製以下這一段到我的main裡面~
/*----------------------
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE);
mp.prepare();
mp.start();
*/

張貼留言