Android视频播放 (一)——TextureView和SurfaceView区别 + 视频播放
来源:互联网 发布:i started a joke 知乎 编辑:程序博客网 时间:2024/05/18 19:19
转载注明出处:
文章出自 我不只是看客/NotLooker
好久不更新博客了,视频播放相关技术继续积累。最近整理了下前端时间实现的瀑布流播放等,现在放出博客,接下来几篇 会陆续讲解 瀑布流跳转详情页的缓冲播放,以及多段视频资源的无缝切换;
短视频的资本浪潮导致很多公司都要分一杯羹,然后就苦了我们这群写代码的,要支持各种播放需求。。。
下面正文开始:
android开发中播放视频大概有3中模式,videoview+mediaplayer是最灵活强大的定制化解决办法,videoview继承于SurfaceView;简单介绍下SurfaceView:
SurfaceView从Android 1.0(API level 1)时就有 。它继承自类View,因此它本质上是一个View。但与普通View不同的是,它有自己的Surface。我们知道,一般的Activity包含的多个View会组成View hierachy的树形结构,只有最顶层的DecorView,也就是根结点视图,才是对WMS可见的。这个DecorView在WMS中有一个对应的WindowState。相应地,在SF中对应的Layer。而SurfaceView自带一个Surface,这个Surface在WMS中有自己对应的WindowState,在SF中也会有自己的Layer。如下图所示:
也就是说,虽然在App端它仍在View hierachy中,但在Server端(WMS和SF)中,它与宿主窗口是分离的。这样的好处是对这个Surface的渲染可以放到单独线程去做,渲染时可以有自己的GL context。这对于一些游戏、视频等性能相关的应用非常有益,因为它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用。
既然SurfaceView并不是一个真正的view,既它无法平移,那么自然不能把它放到listview中,查看API发现在 3.0后引入了个SurfaceTexture的东西
SurfaceTexture从Android 3.0(API level 11)加入。和SurfaceView不同的是,它对图像流的处理并不直接显示,而是转为GL外部纹理,因此可用于图像流数据的二次处理(如Camera滤镜,桌面特效等)。比如Camera的预览数据,变成纹理后可以交给GLSurfaceView直接显示,也可以通过SurfaceTexture交给TextureView作为View heirachy中的一个硬件加速层来显示。首先,SurfaceTexture从图像流(来自Camera预览,视频解码,GL绘制场景等)中获得帧数据,当调用updateTexImage()时,根据内容流中最近的图像更新SurfaceTexture对应的GL纹理对象,接下来,就可以像操作普通GL纹理一样操作它了。从下面的类图中可以看出,它核心管理着一个BufferQueue的Consumer和Producer两端。Producer端用于内容流的源输出数据,Consumer端用于拿GraphicBuffer并生成纹理。SurfaceTexture.OnFrameAvailableListener用于让SurfaceTexture的使用者知道有新数据到来。JNISurfaceTextureContext是OnFrameAvailableListener从Native到Java的JNI跳板。其中SurfaceTexture中的attachToGLContext()和detachToGLContext()可以让多个GL context共享同一个内容源。
于是继续搜索SurfaceTexture,发现在(API level 14)中 google进入了一个新的组件TextureView。
它可以将内容流直接投影到View中,可以用于实现Live preview等功能。和SurfaceView不同,它不会在WMS中单独创建窗口,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。值得注意的是TextureView必须在硬件加速的窗口中。它显示的内容流数据可以来自App进程或是远端进程。TextureView继承自View,它与其它的View一样在View hierachy中管理与绘制。TextureView重载了draw()方法,其中主要把SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。
SurfaceTexture就是mediaplayer输出视频流的窗口 Bingo!新的View找到了;
接下来就是使用TextureView+Meidaplayer播放视频了;
节约篇幅,省略无关代码:
textureView = (TextureView) findViewById(R.id.textureview1); final MediaPlayer mediaPlayer = new MediaPlayer(); textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { mediaPlayer.setSurface(new Surface(surface)); try { mediaPlayer.setDataSource(url); } catch (IOException e) { e.printStackTrace(); } mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mediaPlayer.start(); } }); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } } });
部分解释:
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener());
想要获取到TextureView的SurfaceTexture就需要确保TextureView正确的初始化, 而TextureView正好提供了一个监听TextureView.SurfaceTextureListener 它可以监听SurfaceTexture的生成、变化、销毁和更新,如果你确定TextureView已经生成完成的话 也可以直接用getSurfaceTexture来获取;
在onSurfaceTextureAvailable回调中,添加MediaPlayer的初始化操作。
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { mediaPlayer.setSurface(new Surface(surface)); try { mediaPlayer.setDataSource(url); } catch (IOException e) { e.printStackTrace(); } mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mediaPlayer.start(); } });}
获取了surfaceTexture后塞给mediaPlayer;然后设置url,并且将mediaplayer设置准备状态;设置准备播放监听,在onPrepared回调中 开始播放;
如果MediaPlayer报错极有可能是状态变更出现问题,相关文章给出:Android开发之MdiaPlayer详解
PS:本次测试的URL是http地址,mediaplayer可以识别并播放,读者需替换掉自己的可播放地址;MediaPlayer的setDataSource支持http/rtps地址,支持本地文件目录以及FileDescriptor的播放,但是android5.0及以上对读取本地文件做了权限增加,相关文献不做展开 ,这里只提供部分解决方案:在AndroidManifest.xml
中增加读取权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
然后在android6.0以上在app设置中开启应用文件读取权限,就可以播放了
- Android视频播放 (一)——TextureView和SurfaceView区别 + 视频播放
- TextureView SurfaceView和MediaPlayer的视频播放
- Android使用SurfaceView和TextureView来播放视频
- android 视频播放器 TextureView , MediaPlayer , SurfaceView 的坑
- 自封装MeidaPlayer+SurfaceView 和 TextureView视频播放控件
- android Multimedia实战(一)详解SurfaceView,TextureView之播放视频的四种方式
- android Multimedia实战(一)详解SurfaceView,TextureView之播放视频的四种方式
- android Multimedia实战(一)详解SurfaceView,TextureView之播放视频的四种方式
- Android使用TextureView播放视频
- Android视频播放02—SurfaceView实现
- android surfaceview 播放视频
- Android SurfaceView 播放视频
- Android--SurfaceView播放视频
- TextureView实现视频播放
- Android 播放视频(一)SurfaceView + MediaPlayer
- Android:使用MediaPlayer和SurfaceView播放视频
- Android播放视频之MediaPlayer和SurfaceView
- android SurfaceView 视频播放器
- IntelliJ IDEA 2017年注册码
- 程序员转行为什么这么难
- git diff 命令深入理解
- Ubuntu16.04 LTS--常用设置(长期更新)
- docker系列二 创建自己的docker及Dockerfile语法
- Android视频播放 (一)——TextureView和SurfaceView区别 + 视频播放
- 坐标系旋转矩阵推导过程
- J2EE、J2SE、J2ME的区别
- C语言static关键字的用法
- Javascript 变量对象学习笔记
- VS2015桌面老出现三个文件夹
- 对象的容纳——数组
- 第二天总结
- CSS常见兼容性问题总结