-
什么是多媒体
多媒体是计算机和视频技术的结合,实际上它是两个媒体:声音和图像
-
常用的视频格式
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
就是“表面”的意思。在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
就是一个有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
线程和渲染线程,两个线程通过“双缓冲”机制来达到高效的界面适时更新。
显示一个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
继承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
消失后才能处理手势。
- 邮箱 :charon.chui@gmail.com
- Good Luck!