http://www.taidous.com/bbs/article-860-1.htmlphp
Unity视频播放有不少种实现方式,可根据要求来选择适当的实现,这里总结一下:
1. MovieTexture
Unity标准接口,支持的播放视频格式有.mov、.mpg、.mpeg、.mp四、.avi和.asf。仅支持PC端的本地视频播放。
1. 在游戏对象中播放,就比如在游戏世界中建立一个Plane面对象,摄像机直直的照射在这个面上
在新建的一个plane平面,将其纹理绑定为电影纹理便可
//设置当前对象的主纹理为电影纹理
renderer.material.mainTexture = movTexture;
//设置电影纹理播放模式为循环
movTexture.loop = true;
并可经过
movTexture.Play();
movTexture.Pause();
movTexture.Stop();
来进得播放控制。
此时能够经过直接缩放plane平面来达到缩放视频的目的
至于MovieTexture的赋值,在4.6x/5.0x版本上是没法经过将视频拖入Project视频来自动形成纹理的,以前的老版本是可行的。
2. 在GUI层面播放。它其实和贴图很是相像,由于播放视频用到的MovieTexture属于贴图Texture的子类。
//绘制电影纹理
GUI.DrawTexture (new Rect (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/路径下
上面的方法在移动端是边下载边播放网络视频的,属于在线播放,很差的地方就是,再次观看还须要再次加载。可能在播放的时候判断是否已下载到本地若是在本地就能够播放本地,若是没有再从网上下载到本地
html
3. MobileMovieTexture
Unity移动端第三方插件视频播放,分免费版和收费版,免费版视频加了水印,收费版无水印,但该插件自己有不少bug,其中最重要的是没有音频。它也不支持在线视频播放。
4. EasyMovieTexture
Unity移动端第三方视频播放插件,支持视频本地播放,支持RTSP。
1>. 初始化加载,该部分主要在Unity中将播放视频的地址(本地/URL)传送到Android,并完成MediaPlayer的初始化
2>. Android建立一个Surface,并将其与以前建立的MediaPlayer绑定
3>. 结合视频绘制载体计算图像拉伸比
4>. 根据视频宽高比建立VideoTexture并传到Android与
m_VideoTexture = new Texture2D(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
api
播放组件上层使用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是针对GL_TEXTURE_EXTERNAL_OES的一种扩展,完成YUV到RGB的转换,采样出来的数据须要绘制到Unity纹理上,这里面不能直接操做,须要借助FBO和EGLImage来操做。该片元着色器的写法在使用SurfaceTexture里面已经有说起。
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: 这里没有截很代码的详细逻辑,只是原理,可能有理解不到位的地方,欢迎指证。