http://www.weixinnu.com/tag_article/2878539837
api
Unity視頻播放有不少種實現方式,可根據要求來選擇適當的實現,這裏總結一下:數組
1. MovieTexture緩存
Unity標準接口,支持的播放視頻格式有.mov、.mpg、.mpeg、.mp四、.avi和.asf。僅支持PC端的本地視頻播放。網絡
1. 在遊戲對象中播放,就比如在遊戲世界中建立一個Plane面對象,攝像機直直的照射在這個面上ide
在新建的一個plane平面,將其紋理綁定爲電影紋理便可oop
//設置當前對象的主紋理爲電影紋理測試
renderer.material.mainTexture=movTexture;ui
//設置電影紋理播放模式爲循環url
movTexture.loop=true;spa
並可經過
movTexture.Play();
movTexture.Pause();
movTexture.Stop();
來進得播放控制。
此時能夠經過直接縮放plane平面來達到縮放視頻的目的
至於MovieTexture的賦值,在4.6x/5.0x版本上是沒法經過將視頻拖入Project視頻來自動形成紋理的,以前的老版本是可行的。
2. 在GUI層面播放。它其實和貼圖很是相像,由於播放視頻用到的MovieTexture屬於貼圖Texture的子類。
//繪製電影紋理
GUI.DrawTexture(newRect(0,0,Screen.width,Screen.height),movTexture,ScaleMode.StretchToFill);
播放視頻的大小是屏幕的寬高,若是想動態的修改視頻的寬或高直接修改new Rect() 視頻顯示區域便可
2. Handheld.PlayFullScreenMovie
Unity標準的視頻播放接口,支持的播放視頻格式有.mov、.mpg、.mpeg、.mp四、.avi和.asf。支持PC/移動端播放,支持本地在線播放
url_movie ="http://dl.nbrom.cn/17051/c3e408229342723fbdf62d0bcf1d549c.mp4?fsname=Criminal_Minds_S01E01.mp4";
Handheld.PlayFullScreenMovie(url_movie,Color.black,FullScreenMovieControlMode.Full);
Handheld.PlayFullScreenMovie("test.mp4",Color.black,FullScreenMovieControlMode.CancelOnInput);
將視頻文件放置在Assets/StreamingAssets/路徑下
上面的方法在移動端是邊下載邊播放網絡視頻的,屬於在線播放,很差的地方就是,再次觀看還須要再次加載。可能在播放的時候判斷是否已下載到本地若是在本地就能夠播放本地,若是沒有再從網上下載到本地
3.MobileMovieTexture
Unity移動端第三方插件視頻播放,分免費版和收費版,免費版視頻加了水印,收費版無水印,但該插件自己有不少bug,其中最重要的是沒有音頻。它也不支持在線視頻播放。
4.EasyMovieTexture
Unity移動端第三方視頻播放插件,支持視頻本地播放,支持RTSP。
1>. 初始化加載,該部分主要在Unity中將播放視頻的地址(本地/URL)傳送到Android,並完成MediaPlayer的初始化
2>. Android建立一個Surface,並將其與以前建立的MediaPlayer綁定
3>. 結合視頻繪製載體計算圖像拉伸比
4>. 根據視頻寬高比建立VideoTexture並傳到Android與
m_VideoTexture =newTexture2D(Call_GetVideoWidth(), Call_GetVideoHeight(),TextureFormat.RGB565,false);
Call_SetUnityTexture(m_VideoTexture.GetNativeTextureID());
5>. 設置視頻窗口,完成TextureId與surface的綁定
SetWindowSize(GetVideoWidth(),GetVideoHeight(),m_iUnityTextureID ,m_bRockchip);
6>. 更新紋理
Call_UpdateVideoTexture();
m_SurfaceTexture.updateTexImage();
7>. 播放視頻
使用MediaPlayer播放視頻
5. MediaPlayer + SurfaceTexture
播放組件上層使用MediaPlayer來處理,在成功建立並設置好setDataSource後,須要建立GL_TEXTURE_EXTERNAL_OES格式的紋理ID來與MediaPlayer生成聯繫。
在這裏咱們須要使用SurfaceTexture的理由是,它能代替SurfaceHolder,使得當咱們指定圖像流的輸出目標爲照相機預覽或視頻解碼時,咱們在每一幀中獲得的全部數據不須要直接用於顯示在設備上,而是能夠選擇先輸出到SurfaceTexture上,在上屏以前可能作一些自定義擴展。當調用updateTexImage()時,用來建立SurfaceTexture的紋理對象內容被更新爲包含圖像流中最近的圖片。
SurfaceTexture對象能夠在任何線程裏建立。但updateTexImage()只能在包含紋理對象的OpenGL ES上下文所在的線程裏建立。能夠獲得幀信息的回調能夠在任何線程被調用。這一點要注意,上下文若是不一致,視頻沒法上屏。
這裏還有個要求就是在建立紋理的時候,須要使用使用GL_TEXTURE_EXTERNAL_OES做爲紋理目標,其是OpenGL ES擴展GL_OES_EGL_image_external定義的。這種紋理目標會對紋理的使用方式形成一些限制。每次紋理綁定的時候,都要綁定到GL_TEXTURE_EXTERNAL_OES,而不是GL_TEXTURE_2D。並且,任何須要從紋理中採樣的OpenGL ES 2.0 shader都須要聲明其對此擴展的使用,例如,使用指令」#extension GL_OES_EGL_image_external:require」。這些shader也必須使用samplerExternalOES採樣方式來訪問紋理。這部分在後面採樣器中有說明。
幾個重要的技術點以下:
Shader採樣 YUV->RGB
這裏片元着色器的使用以下:
該Shader是針對GL_TEXTURE_EXTERNAL_OES的一種擴展,完成YUV到RGB的轉換,採樣出來的數據須要繪製到Unity紋理上,這裏面不能直接操做,須要藉助FBO和EGLImage來操做。該片元着色器的寫法在使用SurfaceTexture裏面已經有說起。
EGLImage
EGLImage表明一種由EGL客戶API(如OpenGL,OpenVG)建立的共享資源類型。它的本意是共享2D圖像數據,而在這裏使用它的目的在於通過EGLImage建立的2D紋理,可以bind到任意的載體GameObject上面。
如何建立EGLImage,建立的標準接口以下
EGLImageKHR eglCreateImageKHR(
EGLDisplay dpy,
EGLContext ctx,
EGLenum target,
EGLClientBuffer buffer,
const EGLint *attrib_list);
target決定了建立EGLImage的方式,例如在Android系統中專門定義了一個稱爲EGL_NATIVE_BUFFER_ANDROID的Target,支持經過ANativeWindowBuffer建立EGLImage對象,而Buffer則對應建立EGLImage對象時的使用數據來源。
1) 首先須要一個ANativeWindowBuffer。
該buffer能夠經過ANativeWindow的接口dequeueBuffer來獲取。
這個對象的api接口較多,它對buffer的管理相似於以下
這部分操做能夠參考下面這篇文章
http://tangzm.com/blog/?p=167
在獲取buffer以前要建立一個ANativeWindow對象。
2) 經過該ANativeWindowBuffer來建立EGLImage
3) 成功建立了EGLImage後,可能經過它來建立一個2D紋理
這個2D紋理在後面建立FBO的時候會用到。
FBO - Frame Buffer Object
FBO即幀緩存對象,它是OpenGL管線的最終渲染目的地。在OpenGL渲染管線中,幾何數據和紋理在FBO內部通過屢次轉化和屢次測試,最後以二維像素的形式顯示在屏幕上。它是一些二維數組和OpenG所使用的存儲區的集合:顏色緩存、深度緩存、模板緩存和累計緩存。默認狀況下,OpenGL將幀緩衝區做爲渲染最終目的地。此幀緩衝區徹底由window系統生成和管理。這個默認的幀緩存被稱做「window系統生成」(window-system-provided)的幀緩衝區。
有兩種類型的「幀緩存關聯圖像」:紋理圖像(texture images)和渲染緩存圖像(renderbuffer images)。若是紋理對象的圖像數據關聯到幀緩存,OpenGL執行的是「渲染到紋理」(render to texture)操做。若是渲染緩存的圖像數據關聯到幀緩存,OpenGL執行的是離線渲染(offscreen rendering)。
具體的操做以下:
在這裏使用了經過上一步EGLImage生成的2D紋理mTex,這樣的話後續就能夠經過操做FBO對象來獲取MediaPlayer中SurfaceTexture中的每一幀數據。
關於FBO的詳細接口說明,可見下面連接
http://blog.csdn.net/dreamcs/article/details/7691690
SurfaceTexture.updateTexImage
當MediaPlayer中當新的幀流可用時,調用updateTexImage從圖像流中提取最近一幀到紋理圖像中,此時因爲同處一個上下文中,首先須要執行一次FBO綁定操做,這是因爲GL_TEXTURE_EXTERNAL_OES的特性決定的,實際上這個操做是爲了下幀準備的。
而後將shader採樣出來的數據幀跟Unity紋理ID綁定後就可上屏。
PS: 這裏沒有截很代碼的詳細邏輯,只是原理,可能有理解不到位的地方,歡迎指證。