视频播放相关内容总结
多媒体常识:
什么是多媒体
多媒体是计算机和视频技术的结合,实际上它是两个媒体:声音和图像
常用的视频格式
Android
系统默认:mp4
、3gp
常用格式:ts、3gpp、3g2、3gpp2、avi、mkv、flv、divx、f4v、rm、rmvb、rv、wmv、asf、mov、mpg、v8、ram、mpeg、 swf、m2v、asx、ra、ram、ndivx、xvid
等常用音频格式:
Android
系统:mp3、ogg
常用格式:wma、mid、m4a、xmf、aac、mpa、midi、ar
等常用图片格式:
PNG、GIF、BMP、jpg
国内各个视频网站采用的解码框架:
- 优酷、搜狐、奇艺、
pps
、暴风影音土豆、56网都是用的ffmpeg
. pptv
已经使用p2p
技术
点对点技术(peer-to-peer
, 简称P2P
)又称对等互联网络技术,是一种网络新技术,依赖网络中参与者的计算能力和带宽, 而不是把依赖都聚集在较少的几台服务器上。P2P
网络通常用于通过Ad Hoc
连接来连接节点。这类网络可以用于多种用途, 各种档案分享软件已经得到了广泛的使用。P2P
技术也被使用在类似VoIP
等实时媒体业务的数据通信中。
- 优酷、搜狐、奇艺、
目前常用的开发框架:
VLC
框架:
VLC
是一个开源项目,基于ffmpeg
框架的自定义播放器。其中LibVLC
是VLC
的核心部分,就相当于MediaPlayer
类
VLC
一个最主要的部分,它可以播放各种类型的媒体文件和流媒体文件,并且可以创造媒体流并保存成各种格式的媒体文件
VLC
是一种跨平台的媒体播放器和流媒体服务器,最初为videolan
的客户端,它是一种非常简便的多媒体播放器, 它可以用来播放各种各样的音视频的格式文件(MPEG-1、MPEG-2、MPEG- 4、DivX、WMV、mp3、OGG、Vorbis、AC3、AAC
等等)流媒体协议 最具特色的功能是可以边下载边观看Divx
媒体文件,并可以播放不完全的AVI
文件。并且支持界面的更改。
缺点:有C/C++
代码,还有Java
代码,代码太庞大ffmpeg
框架:
优点:轻量级框架,易于维护
FFmpeg
是一个集录制、转换、音/视频编码解码功能为一体的完整的开源解决方案
FFmpeg
几乎为你把所有的繁重工作都做了,比如解码、编码、复用和解复用。
这使得多媒体应用程序变得容易编写。它是一个简单的,用C
编写的,快速的并且能够解码几乎所有你能用到的格式,当然也包括编码多种格式。
FFmpeg
支持MPEG、DivX、MPEG4、AC3、DV、FLV
等40多种编码,支持AVI、MPEG、OGG、Matroska、AS
F等90多种解码
FFmpeg
主目录下主要有libavcodec、libavformat
和libavutil
等子目录。其中libavcodec
用于存放各个encode/decode
模块libavformat
用于存放muxer/demuxer
模块,libavutil
用于存放内存操作等辅助性模块vitamio
框架:
vitamio
也是基于ffmpeg
开源框架
VPlayer
是vitamio
的一个产品,vitamio
和VPlayer
是同一个团队开发的,VPlayer
能播放的vitamio
也能播放
Surface
简介
Surface
就是“表面”的意思。在SDK
的文档中,对Surface
的描述是这样的:“Handle onto a raw buffer that is being managed by the screen compositor
”, 翻译成中文就是“由屏幕显示内容合成器(screen compositor)
所管理的原生缓冲器的句柄”, 这句话包括下面两个意思:- 通过
Surface
(因为Surface
是句柄)就可以获得原生缓冲器以及其中的内容。就像在C
语言中,可以通过一个文件的句柄,就可以获得文件的内容一样; - 原生缓冲器(
rawbuffer
)是用于保存当前窗口的像素数据的。
- 通过
简单的说
Surface
对应了一块屏幕缓冲区,每个Window
对应一个Surface
,任何View
都是画在Surface
上的,传统的view
共享一块屏幕缓冲区,所有的绘制必须在UI
线程中进行- 我们不能直接操作
Surface
实例,要通过SurfaceHolder
,在SurfaceView
中可以通过getHolder()
方法获取到SurfaceHolder
实例。 Surface
是一个用来画图形的地方,但是我们知道画图都是在一个Canvas
对象上面进行的,Surface
中的Canvas
成员,是专门用于提供画图的地方,就像黑板一样,其中的原始缓冲区是用来保存数据的地方,Surface
本身的作用类似一个句柄,得到了这个句柄就可以得到其中的Canvas
、原始缓冲区以及其他方面的内容,所以简单的说Surface
是用来管理数据的(句柄)。
SurfaceView
简介
简单的说
SurfaceView
就是一个有Surface
的View
里面内嵌了一个专门用于绘制的Surface
,SurfaceView
控制这个Surface
的格式和尺寸以及绘制位置.SurfaceView
是一个View
也许不够严谨, 然而从定义中public class SurfaceView extends View
显示SurfaceView
确实是派生自View
,但是SurfaceView
却有着自己的Surface
,源码:if (mWindow == null) { ß mWindow = new MyWindow(this); mLayout.type = mWindowType; mLayout.gravity = Gravity.LEFT|Gravity.TOP; mSession.addWithoutInputChannel(mWindow, mWindow.mSeq, mLayout, mVisible ? VISIBLE : GONE, mContentInsets); }
很明显,每个
SurfaceView
创建的时候都会创建一个MyWindow
,new MyWindow(this)
中的this
正是SurfaceView
自身,因此将SurfaceView
和window
绑定在一起,而前面提到过每个window
对应一个Surface
, 所以SurfaceView
也就内嵌了一个自己的Surface
,可以认为SurfaceView
是来控制Surface
的位置和尺寸。传统View
及其派生类的更新只能在UI
线程,然而UI
线程还同时处理其他交互逻辑, 这就无法保证view
更新的速度和帧率了,而SurfaceView
可以用独立的线程来进行绘制,因此可以提供更高的帧率,例如游戏,摄像头取景等场景就比较适合用SurfaceView
来实现。Surface
是纵深排序(Z-ordered)
的,这表明它总在自己所在窗口的后面。Surfaceview
提供了一个可见区域,只有在这个可见区域内的Surface
部分内容才可见,可见区域外的部分不可见,所以可以认为SurfaceView
就是展示Surface
中数据的地方,Surface
就是管理数据的地方,SurfaceView
就是展示数据的地方,只有通过SurfaceView
才能展现Surface
中的数据。
Surface
的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者Surface
的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)
(例如,文本和按钮等控件)。 注意,如果Surface
上面有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。surfaceview
变得可见时,surface
被创建;surfaceview
隐藏前,surface
被销毁。 这样能节省资源。如果你要查看surface
被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)
和surfaceDestroyed(SurfaceHolder)
。SurfaceView
的核心在于提供了两个线程:UI
线程和渲染线程,两个线程通过“双缓冲”机制来达到高效的界面适时更新。
SurfaceHolder
简介
显示一个Surface
的抽象接口,使你可以控制Surface
的大小和格式以及在Surface
上编辑像素,和监视Surface
的改变。这个接口通常通过SurfaceView
类实现。
简单的说就是我们无法直接操作Surface
只能通过SurfaceHolder
这个接口来获取和操作Surface
。
SurfaceHolder
中提供了一些lockCanvas()
:获取一个Canvas
对象,并锁定之。所得到的Canvas
对象,其实就是Surface
中一个成员。加锁的目的其实就是为了在绘制的过程中,
Surface
中的数据不会被改变。lockCanvas
是为了防止同一时刻多个线程对同一canvas
写入。
从设计模式的角度来看,Surface、SurfaceView、SurfaceHolder
实质上就是MVC(Model-View-Controller)
,Model
就是模型或者说是数据模型,更简单的可以理解成数据,在这里也就是Surface
,
View
就是视图,代表用户交互界面,这里就是SurfaceView
,SurfaceHolder
就是Controller.
MediaController
MediaController
继承FrameLayout
,通过MediaPlayerControl
接口与VideoView
进行结合控制,内部是通过PopupWindow
将整个控制栏界面显示到界面上, 而该PopupWindow
所显示在的位置就是通过setAnchorView()
设置进来的Anchor
一般可以使当前的VideoView
或者是整个Activity
的根布局。这里要分为小屏和全屏两种情况来进行设置。 如果当前的MediaController
只是播放前下面的控制栏部分(进度条、快进、快退、暂停等)这样我们可以通过对VideoView设置点击事件,控制它的显示和隐藏。 如果MediaController
为整个屏幕包括了控制栏部分、上端的信息显示部分、以及左右栏的功能部分、这时候就可以通过对MediaController
本身设置点击事件来控制显示和隐藏。
Controller
可以用PopupWindow
来实现,具体有两种方式:
整个控制栏(上面的信息部分、下面的控制部分以及左右边)都在
Controller
中,setAnchorView()
的时候就会让Controller
中的PopupWindow
显示出来(一直显示,但是这个PopupWindow
是透明的), 真正的显示与隐藏是控制在PopupWindow
中的View
部分的显示与隐藏来实现。开始的时候我是想用这种方式,当时我想的是播放就播放、控制就控制,分离开来多好,但是没想到, 一旦有PopupWindow
显示出来后,Activity是接收不到任何Touch
事件的,所有的重试界面等都要放到Controller
中实现(手势处理等)。但是也有好处,就是不管显示还是隐藏都可以去处理手势.PopupWindow
不是全屏的,只包含下面真正的控制部分(快进、快退、暂停等,不包含上面的信息部分和左右边),而且也不是开始就显示,显示隐藏是通过控制PopupWindow
的显示与隐藏来进行的。 而对于信息部分、以及左右边都是在Activity
的布局当中,我们通过接口回调得到PopupWindow
的显示与隐藏来控制这些布局的显示与隐藏即可。 这样的话我们就需要将手势等全部放到Activity
中去处理,但是也有一个问题,就是如果Controller
正在显示的话Activity
是接收不到Touch
事件的,就无法处理手势,只能是让Controller
消失后才能处理手势。
- 邮箱 :[email protected]
- Good Luck!