此文章你將會(huì)學(xué)會(huì)在android的視頻播放功能
- 使用VideoView視頻播放
- 使用TextureVideoView視頻播放
Tips
此文章僅供學(xué)習(xí)使用恢恼,有些細(xì)節(jié)還沒(méi)認(rèn)真fix的盒刚,望大家不要太在意細(xì)節(jié)妨蛹,主要列表視頻播放功能已實(shí)現(xiàn),thanks程梦!
緒論(好多廢話的~選擇忽略)
公司上班沒(méi)事干好無(wú)聊墨技,自己又剛出來(lái)社會(huì)冒泡睹耐,就學(xué)習(xí)學(xué)習(xí)下技術(shù)啦钝尸。自己應(yīng)用有個(gè)功能需求,需要在一個(gè)列表里面有多個(gè)視頻播放搂根,好了珍促,第一時(shí)間百度“android 視頻播放”,得出以下搜索結(jié)果心得:
一剩愧,時(shí)間過(guò)去太久猪叙,一般寫的文章都是N年前的。
二仁卷,寫的人太少穴翩,就像android 藍(lán)牙那些,講的人少++
三锦积,網(wǎng)上的文章太過(guò)片面芒帕,比如大多數(shù)的網(wǎng)友們寫的就是簡(jiǎn)簡(jiǎn)單單一個(gè)控件播放一個(gè)視頻的例子,或者簡(jiǎn)單說(shuō)下某個(gè)技術(shù)點(diǎn)的功能丰介,而沒(méi)有市面上存在的軟件例子來(lái)做一個(gè)相對(duì)完整的Demo講解的(或許網(wǎng)上的大神們高估了像我這些菜鳥的能力吧背蟆,所以寫得那么簡(jiǎn)單)
四,找到一款繼承視頻開發(fā)的SDK(國(guó)內(nèi)的喔)哮幢。Vitamio (https://www.vitamio.org/ )是一款 Android 與 iOS 平臺(tái)上的全能多媒體開發(fā)框架带膀,全面支持硬件解碼與 GPU 渲染。(我沒(méi)試過(guò)好不好用)聽起來(lái)挺不錯(cuò)啦橙垢,有基礎(chǔ)的小伙伴可以去使用它垛叨,沒(méi)基礎(chǔ)的建議學(xué)點(diǎn)基礎(chǔ)在去使用,這樣事半功倍柜某。
五嗽元,我想學(xué)習(xí)下敛纲,裝逼下,哈哈哈哈哈哈哈哈哈
好吧还棱,既然國(guó)內(nèi)說(shuō)得那么少载慈,我只能轉(zhuǎn)戰(zhàn)國(guó)外的,像Google官網(wǎng)學(xué)習(xí)和StackOverflow等等的地方學(xué)習(xí)了珍手。
對(duì)于我們開發(fā)者挺值得慶幸的事情是办铡,Google Developers中國(guó)網(wǎng)站(https://developers.google.cn/)在近期正式發(fā)布了,從此中國(guó)小伙伴們不用翻墻也可以上谷歌官網(wǎng)學(xué)習(xí)了琳要。以下谷歌官網(wǎng)的鏈接我都使用中國(guó)谷歌官網(wǎng)的寡具,方便你們搜索。
使用VideoView播放視頻 -Added in API level 1
Google VideoView 官方鏈接
https://developer.android.google.cn/reference/android/widget/VideoView.html
VideoView 繼承 SurfaceView implement一個(gè)MediaController.MediaPlayerControl(用來(lái)顯示進(jìn)度條稚补,播放童叠,停止 等等的那個(gè)控制器)
xml布局
<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
代碼使用
@BindView(R.id.videoView) protected VideoView videoView;
Butterknife是一個(gè)插件來(lái)的,用于View的綁定课幕,相當(dāng)于 VideoView videoView = (VideoView)findViewById(R.id.videoView)
videoView.setMediaController(new MediaController(context));
用于控制條顯示厦坛,可以不寫
videoView.setVideoPath(getVideoUrl());
設(shè)置視頻的路徑。還有setViewURI(Uri uri)乍惊,setVideoURI(Uri uri)和setVideoUri(Uri uri, Map<String, String> headers)都可以設(shè)置路徑杜秸。
videoView.requestFocus();
將焦點(diǎn)放在View上面,如果寫單單一個(gè)播放的控件润绎,不寫也是可以播放的撬碟。在列表中,使用它只是為了區(qū)分它是哪個(gè)VideoView的莉撇,方便控件的狀態(tài)還原呢蛤,你可以試著在我的Demo中注釋它播放幾個(gè)VideoView和不注釋試試就知道了。
videoView.seekTo(0);
可以不寫棍郎,查看到它的源碼其障,原來(lái)是使用MediaPlayer.seetTo(x)去設(shè)置的,用來(lái)指定哪個(gè)時(shí)間位置開始播放涂佃,單位為毫秒静秆,接著看就是NDK的東西了,詳情如下:
/** * Seeks to specified time position. * *
@param msec the offset in milliseconds from the start to seek to *
@throws IllegalStateException if the internal player engine has not been * initialized */
public native void seekTo(int msec) throws IllegalStateException;
videoView.start();
這是啟動(dòng)VideoView巡李,但這不意味視頻就可以馬上可以播放的抚笔,它只不過(guò)是開始播放準(zhǔn)備狀態(tài)中,真正可以播放視頻是在回調(diào)`videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {})的時(shí)候侨拦。當(dāng)然殊橙,如果你整個(gè)視頻緩沖完點(diǎn)擊按鈕再次觸動(dòng)videoView.start()時(shí)候,就可以馬上播放的,不會(huì)調(diào)用setOnPreparedListener的膨蛮。
就這樣叠纹,簡(jiǎn)簡(jiǎn)單單一個(gè)利用VideoView播放視頻功能的小東西就完成了。
接下來(lái)敞葛,介紹下VideoView常用的一些方法誉察,你不寫也不會(huì)報(bào)錯(cuò),此只不過(guò)增強(qiáng)對(duì)VideoView的控制罷了惹谐。
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//Register a callback to be invoked when the media file* is loaded
//and ready to go.
}
}); ```
當(dāng)VideoView執(zhí)行.start()后持偏,視頻可以播放時(shí)候就會(huì)執(zhí)行onPrepared()函數(shù)里面的東西,看函數(shù)就可以知道它是利用MediaPlayer去具體實(shí)現(xiàn)這個(gè)準(zhǔn)備播放監(jiān)聽事件的氨肌。雖然VideoView每次都使用MediaPlayer去實(shí)現(xiàn)其身的某些事件鸿秆,但是在VideoView你是不可以直接控制MediaPlayer的,比如setOnPreparedListener()(監(jiān)聽可以播放時(shí)候的函數(shù)),setOnBufferingUpdateListener(用來(lái)監(jiān)聽緩沖流有多少的函數(shù))等等怎囚,但是你可以巧妙的利用以上的onPrepared(MediaPlayer mp)里面的MediaPlayer去使用設(shè)置某些函數(shù)卿叽。
```java
videoView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
// Called when the focus state of a view has changed.
}
}); ```
當(dāng)焦點(diǎn)改變的時(shí)候這個(gè)函數(shù)會(huì)被調(diào)用,如在一個(gè)列表里的多個(gè)VideoView中點(diǎn)擊不同Item的VideoView恳守,你就可以再此函數(shù)設(shè)置前一個(gè)VideoView Item的某些控件狀態(tài)的回復(fù)考婴。如:列表中,A_VideoView播放著催烘,點(diǎn)擊B_VideoView,那么B_VideoView就要進(jìn)入準(zhǔn)備播放視頻的狀態(tài)中沥阱,而A_VideoView就要還原未播放狀態(tài),將其播放狀態(tài)停止下來(lái)颗圣,和隱藏其Item對(duì)應(yīng)的VideoView喳钟,progressBar等等的吧屁使。還是不懂的你可以運(yùn)行我的Demo和看Log在岂。
```java
/**
* Interface definition of a callback to be invoked to communicate some
* info and/or warning about the media or its playback.
*/
videoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
/**
* @return True if the method handled the info, false if it didn't.
* Returning false, or not having an OnErrorListener at all, will
* cause the info to be discarded.
*/
return false;
}
});
此方法在視頻播放的時(shí)候去返回一些事件的信息或者發(fā)出一些警告信息,比如網(wǎng)絡(luò)不好導(dǎo)致視頻停止播放的時(shí)候蛮寂,你可以設(shè)置ProgressBar加載視頻按鈕的出現(xiàn)蔽午,這樣用戶體驗(yàn)就更加好。
onInfo()函數(shù)的參數(shù)
mp : 此函數(shù)信息屬于的MediaPlayer
what :信息的類型或者是警告酬蹋。例如有: MediaPlayer.MEDIA_INFO_BUFFERING_START: 暫停播放等待緩沖更多數(shù)據(jù)及老,這里你可以設(shè)置ProgressBar的顯示 。MediaPlayer.MEDIA_INFO_BUFFERING_END: 緩沖完后繼續(xù)播放范抓,這里你可以設(shè)置ProgressBar的消失等等骄恶。
extra: 指定的code. 通常依賴于實(shí)現(xiàn)
返回值: 當(dāng)返回true的時(shí)候,這個(gè)方法會(huì)處理那些發(fā)生的異池暗妫或正常的事件僧鲁,如果返回false的時(shí)候,而且沒(méi)有OnErrorListener函數(shù),那么這個(gè)事件將會(huì)被丟失寞秃。
/**
* Register a callback to be invoked when the end of a media file
* has been reached during playback.
* * @param l The callback that will be run
*/
videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
@Override
public void onCompletion(MediaPlayer mp) {
}
});
當(dāng)時(shí)視頻播放完成的時(shí)候此方法將會(huì)被調(diào)用斟叼。
/**
* Register a callback to be invoked when an error occurs
* during playback or setup. If no listener is specified,
* or if the listener returned false, VideoView will inform
* the user of any errors.
* * @param l The callback that will be run
*/
videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
return true;
}
});
在播放或則在配置的過(guò)程中出現(xiàn)錯(cuò)誤,這個(gè)函數(shù)將被調(diào)用春寿。它也是基于MediaPlayer實(shí)現(xiàn)的朗涩。
onError()函數(shù)的參數(shù),
mp:該信息對(duì)應(yīng)的MediaPlayer
what:錯(cuò)誤類型
extra:錯(cuò)誤碼 有:
MEDIA_ERROR_IO 本地文件或網(wǎng)絡(luò)相關(guān)錯(cuò)誤
MEDIA_ERROR_MALFORMED 比特流不符合相關(guān)的編碼標(biāo)準(zhǔn)和文件規(guī)范
MEDIA_ERROR_UNSUPPORTED 比特流符合相關(guān)編碼標(biāo)準(zhǔn)和文件規(guī)范绑改,但是media框架不被支持谢床。
MEDIA_ERROR_TIMED_OUT 超時(shí)錯(cuò)誤
MEDIA_ERROR_SYSTEM 應(yīng)用系統(tǒng)比較舊的錯(cuò)誤(不知道為什么官網(wǎng)找不到這個(gè),但是AS查看源碼有)
返回值:返回true绢淀,說(shuō)明此方法處理了該錯(cuò)誤萤悴。如:當(dāng)設(shè)置不存在的鏈接時(shí)候,軟件不會(huì)報(bào)錯(cuò)皆的,但是會(huì)還原該Item的狀態(tài)覆履,你可以用我Demo玩下。返回false费薄,或者完全沒(méi)用OnErrorListener的時(shí)候硝全,OnCompletionListener將會(huì)被調(diào)用,如果設(shè)置不存在鏈接的例子楞抡,就會(huì)彈出窗口直接報(bào)錯(cuò)伟众。
總結(jié):看完上面介紹的幾個(gè)方法,聰明的你應(yīng)該會(huì)察覺(jué)召廷,雖說(shuō)是使用VideoView凳厢,但大部分最終的實(shí)現(xiàn)卻是利用MediaPlayer去實(shí)現(xiàn)的。所以還想弄懂原理的話竞慢,你們自行了解MediaPlayer去吧先紫。
使用TextureVideoView播放視頻
TextureView -Added in API level 14
開始我先簡(jiǎn)單介紹Google原生的TextureView控件,因?yàn)門extureVideoView是繼承TextureView的筹煮。
Google TextureView官方鏈接
https://developer.android.google.cn/reference/android/view/TextureView.html
TextureView 直接繼承View遮精。 TextureView主要用來(lái)繪制流內(nèi)存(比如:視頻,openGL場(chǎng)景)败潦,TextureView僅僅在硬件加速窗口時(shí)候被使用本冲,當(dāng)軟件已經(jīng)渲染完成的時(shí)候,TextureView是不會(huì)繪畫任何東西的劫扒。不像SurfaceView檬洞,TextureView不會(huì)創(chuàng)建單獨(dú)的窗口,然而其表現(xiàn)出來(lái)的就像一個(gè)View沟饥。而SurfaceView和TextureView重要不同點(diǎn)是添怔,因?yàn)閂ideoView繼承SurfaceView环戈,所以可以說(shuō)VideoView和TextureView重要的不同點(diǎn)是,TextureView可以被移動(dòng)澎灸,轉(zhuǎn)換和動(dòng)畫等等院塞。例如:你可以通過(guò)textureView.setAlpha(0.5f)去設(shè)置透明,而VideoView都是不可以的性昭。
(額外簡(jiǎn)單說(shuō)下硬件加速度這東西拦止,它是API Level 11時(shí)候開始,繪制View才支持硬件加速的糜颠,而TextureView在API 14才有汹族,硬件加速利用GPU特性,使繪制更加平滑其兴,但內(nèi)存消耗會(huì)多點(diǎn)顶瞒。硬件加速可以被代碼開啟和關(guān)閉。更多的關(guān)于硬件加速可以查看此網(wǎng)友的http://www.cnblogs.com/frydsh/archive/2012/10/23/2733581.html )
為什么不直接介紹Google原生的TextureView而是介紹一個(gè)第三方的TextureVideView元旬。
一榴徐,TextureView封裝得確實(shí)很好
二,(個(gè)人)原因是網(wǎng)上說(shuō)得太少了匀归,偷懶還沒(méi)去了解
三坑资,還有就是下面的原因:
無(wú)論繼承是surfaceView的VideoView還是TextureView播放視頻,都利用了MediaPlayer去實(shí)現(xiàn)穆端。 以前用surfaceView(VideoView是繼承surfaceView的)來(lái)播放視頻的時(shí)候可以獲得surfaceHolder對(duì)象袱贮,然后通過(guò)setDisplay方法就可以為mediaplayer指定顯示的surfaceview。 但是textureview有點(diǎn)不同体啰,他返回的是SurfaceTexture攒巍,這里我們需要先將SurfaceTexture轉(zhuǎn)為Surface,然后通過(guò)setSurface方法為Mediaplayer指定顯示的TextureView
好了荒勇!開始正式介紹TextureVideoView柒莉!
TextureVideoView是國(guó)外https://sprylab.com/en/home.html 網(wǎng)站的公司做出的第三方庫(kù)。
添加依賴 :
compile 'com.sprylab.android.texturevideoview:texturevideoview:1.1.1'
TextureVideoView:
VideoVIew:
你應(yīng)該發(fā)現(xiàn)了枕屉,它們都是implements了 MediaPlayerControl常柄,是的鲤氢,它們都是通過(guò)MediaPlayer去實(shí)現(xiàn)視頻的播放搀擂。而且TextureVideoView封裝的方法名和VideoView方法名基本都一樣,而且功能也是一樣卷玉,上面VideoView已經(jīng)介紹過(guò)了常用幾個(gè)方法哨颂,所以這就不再介紹了。 也就是說(shuō)我們將下面藍(lán)色的TextureVideoView換成VideoView也是可以播放的了相种。
播放格式的支持
用以上兩種控件播放視頻威恼,以下格式親測(cè)過(guò)。
OK: mp4,3gp箫措,flv腹备,webm
NO:avi,mov斤蔓,wmv植酥,mkv,gif
源碼地址
https://git.coding.net/Riv-Android/VideoPlayer.git
轉(zhuǎn)載請(qǐng)?jiān)陂_頭注明作者詳細(xì)信息和本文出處