在 Android 音視頻開發學習思路 中,咱們不斷的學習和了解音視頻相關的知識,隨着知識點不斷的學習,咱們如今應該作的事情,就是將知識點不斷的串聯起來。這樣才能獲得更深層次的領悟。經過整理 Android 音視頻開發(一) : 經過三種方式繪製圖片 咱們知道可使用ImageView和SurfaceView甚至是View來展現圖片,經過整理 Android 音視頻開發(三):使用 AudioTrack 播放PCM音頻 咱們知道如何播放音頻原始數據了。那麼可不能夠定義爲,咱們找到了如何播放音視頻的最基本的方式呢?答,固然是的!在 JavaCV 學習(一):JavaCV 初體驗 裏,咱們接觸了一次JavaCV,發現裏面提供的API至關豐富,尤爲是圖形圖像處理方面,那麼下面咱們就基於JavaCV加上它提供的ffmpegAPi工具,來完成一個基本的拉流播放器的製做,鑑於起名很難,咱們先把名字起好:NBPlayer。html
咱們要作的是一個簡單的拉流播放器,須要具有如下功能:java
在定義播放器的生命週期們須要作到如下兩步:1. 先定義一下播放器的事件 2. 定義播放器展現的控件git
由於咱們要作的就是一個播放器,因此就須要定義出來相應的播放器的事件,最基本的播放器的操做就是:播放、暫停、中止。示例代碼以下:github
/** * 播放器抽象類 */ public abstract class Player { protected boolean play = false; public void play() { this.play = true; } public void pause() { this.play = false; } public void stop() { this.play = false; } }
爲何定義完播放器的操做事件以後,就去定義播放器展現的控件呢?canvas
答:主要是由於咱們作的播放器在展現控件方面的思路上和Android原生的MediaPlayer及Ijkplayer是同樣的,都是監聽Surface的狀態來控制播放器何時建立,何時暫停,何時中止並release。ide
這裏咱們使用的控件是SurfaceView,建立一個VideoSurfaceView繼承SurfaceView,並實現SurfaceHolder.Callback接口:工具
@Override public void surfaceCreated(SurfaceHolder holder) { initLayout(mPlayer.getWidth(), mPlayer.getHeight()); play(); if (onPreparedListener != null) onPreparedListener.onPrepared(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.v(TAG, "surfaceChanged..."); } @Override public void surfaceDestroyed(SurfaceHolder holder) { mPlayer.pause(); } public void releasePlayer() { mPlayer.stop(); }
上述代碼能夠看到咱們把基本的播放器的生命週期的控制部分完成了,後續的工做就是完成基本的音視頻數據的獲取和播放了。post
咱們使用的是 JavaCV + FFmpeg的API,關於JavaCV的基本的介紹在上一篇文章 JavaCV 學習(一):JavaCV 初體驗 裏面已經作了,下面一邊介紹使用到的核心類一邊說明音視頻播放的流程:學習
所在package包爲:org.bytedeco.javacv,完整類名爲:org.bytedeco.javacv.FFmpegFrameGrabberui
FFmpegFrameGrabber能夠理解爲解碼器,也能夠理解爲幀收集器,主要做用就是將視頻流以幀的形式拉去到手機設備上。
mFrameGrabber = FFmpegFrameGrabber.createDefault(path);
上面的代碼就是建立FFmpegFrameGrabber的方式,path就是要拉取流的地址。
mFrameGrabber.setPixelFormat(AV_PIX_FMT_RGBA);
設置幀收集時的像素格式,這塊設置AV_PIX_FMT_RGBA的緣由主要是,咱們展現畫面的時候是轉換爲Bitmap格式的。
mFrameGrabber.setOption("fflags", "nobuffer");
上面的代碼表示咱們能夠像ijkplayer同樣,設置一些參數,這些參數格式咱們能夠參考ijkplayer也能夠去ffmpeg命令行的一些設置參數文檔裏面去查找,這裏就很少贅述了。
mFrameGrabber.start();
上面的代碼就是讓幀收集器啓動,這樣就開始拉流了。
所在package包爲:org.bytedeco.javacv,完整類名爲:org.bytedeco.javacv.Frame
Frame 是一個用於管理音頻和視頻幀數據的類。 在CanvasFrame、FrameGrabber、FrameRecorder及他們的子類裏面都有用到。
Frame grabframe = mFrameGrabber.grab();
上面的代碼表示從幀收集器裏面抓去最新的幀:
播放音頻:grabframe.samples裏面獲取到的就是原始的pcm音頻數據,交給AudioTrack處理就ok了。
播放視頻:首先須要將Frame圖像轉換爲Bitmap,AndroidFrameConverter.convert(frame)就能夠轉換,可是在這以前須要使用OpenCVFrameConverter.ToIplImage將抓出來的Frame轉換一下。
Canvas canvas = mHolder.lockCanvas(); canvas.drawBitmap(bmp, null, new Rect(0, 0, canvas.getWidth(), frame.imageHeight * canvas.getWidth() / frame.imageWidth), null); mHolder.unlockCanvasAndPost(canvas);
上面的代碼表示將獲取到的位圖繪製到SurfaceHolder裏面去,這裏建議啓動線程去繪製,這樣效率會高不少。And 別問爲啥子能在線程裏面繪製畫面,本身學習SurfaceView去。