视频播放器实现原理

最近刚刚开始接触视频,对于视频本身的基础知识非常匮乏,搜集整理一下自己的学习过程。这篇视频播放器实现的文章对于理解视频是如何传输、编码、解码、播放整个流程有不少帮助:

原文地址:http://blog.csdn.net/l_yangliu/article/details/13503823


一、知识点 

ES流(Elementary Stream): 也叫基本码流,包含视频、音频或数据的连续码流.

PES流(Packet Elementary Stream): 也叫打包的基本码流, 是将基本的码流ES流根据需要分成长
度不等的数据包, 并加上包头就形成了打包的基本码流PES流.

TS流(Transport Stream): 也叫传输流, 是由固定长度为188字节的包组成, 含有独立时基的一个或
多个program, 一个program又可以包含多个视频、音频、和文字信息的ES流; 每个ES流会有不同的
PID标示. 而又为了可以分析这些ES流, TS有一些固定的PID用来间隔发送program和ES流信息的表格: PAT和PMT表.

(在MPEG-2系统中,由视频, 音频的ES流和辅助数据复接生成的用于实际传输的标准信息流称为MPEG-2传送流)

封装 : 就是捆绑打包, 将画面视频文件和音轨文件打包在一起, 并按照一定规则建立排序和索引, 便
于播放器或播放软件来索引播放. 包括AVI \ PS(Program Stream)\ TS(Transport Stream)\ MKV(Matroska)等.


二、播放过程回放
 

Figure 1. 视频播放基本处理流程

①access 访问: 无需多说, 可理解为接收、获取、得到数据流

②demux 解复用: 把合在一起的音频和视频分离(还有可能的字幕)  

③decode 解码: 包括音频和视频的解码

④output 输出: 也分为音频和视频的输出(aout 和 vout)


这里需要着重说明的是: demux 和 decode 部分

demux部分
我们都知道, 音视频在制作的时候实际上是独立编码的, 得到的是分开的数据, 为了传输方便必须要用某种
方式合起来, 这就有了各种封装格式. 例如, rm \ avi \ mov \ mpg 等等. 同时, 在视频播放器上demux解
复用部分也就有了他存在意义 .

他首先解析TS流的信息, 之后把分解出来的音频和视频流分别送往音频解码器和视频解码器, 进行解码操作.


decode部分
影像在录制后, 原始的音视频都是占用大量空间, 而且是冗余度较高的数据. 因此, 通常会在制作的时候就会进
行某种压缩 ( 压缩技术就是将数据中的冗余信息去除数据之间的相关性 ). 这就是我们熟知的音视频编码格式,
 包括MPEG1(VCD)\ MPEG2(DVD)\ MPEG4 \ H.264 等等. 音视频解码器的作用就是把这些压缩了的数据还原
成原始的音视频数据. 当然, 编码解码过程基本上都是有损的 .


那播放器是如何实现视频一帧一帧的播放的呢?

一般在内存中将压缩的视频帧依次解码出来(当然不可能把一个视频文件的所有压缩数据一次性装到内存中去, 
而是读出一点, 然后解码出来一点), 然后一帧一帧送到显卡的显存中就能显示了. 
如果机器性能跟得上(基本上不用考虑机器性能), 解一帧的时间小于帧与帧之间的正常间隔, 就能流畅的播放.   
每帧的播放是靠PTS来控制的, 解码器解完每幅图像, 都会给出该图像的PTS, video  renderer就能按图像的PTS
来安排显示.


与此同时, 别忘了音频和视频在demux之后是独立的,这就需要有一套机制把它们同步起来. 同时我们需要有一套机
制来控制速度、暂停、停止、跳进、 获取各种媒体信息、设置属性等等 .这些也就是同步控制机制来完成的事情
(基于时间戳来搞定) .简略来说, 就是以音频时间为主 (声卡有时间同步处理机制), 声音图象交错发送 
视频解码时, 按当前播放时间找到对应的视频帧 (可以假设一个音频包有N个图象, 就在这一个音频包完成的过
程中按帧率显示图象)

 

视频编解码器 : http://zh.wikipedia.org/zh-cn/%E8%A7%86%E9%A2%91%E7%BC%96%E8%A7%A3%E7%A0%81%E5%99%A8
视频文件格式 : http://zh.wikipedia.org/zh-cn/%E8%A7%86%E9%A2%91%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F
参考 : http://bbs.chinavideo.org/viewthread.php?tid=1183&extra=page%3D1

A Simple Media Player based on the FFmpeg libraries — ffplay

ffplay.c – File Reference : http://cekirdek.pardus.org.tr/~ismail/ffmpeg-docs/ffplay_8c.html

ffplay.c : http://cekirdek.pardus.org.tr/~ismail/ffmpeg-dssocs/ffplay_8c-source.html


播放器解决了视频播放的问题。通常来说,解决问题最好的办好就是大而化小,小而化无。因为整个播放过程是一个复杂的过程,所以播放器

也采用分而治之的办法。

简单来说,这个大问题可以分解为四个小问题。

1,数据接收;2,数据解析;3,数据解码;4,数据输出。

我会对mplayer和vlc这两个开源播放器的代码结构来说明这四个问题。

一,数据接收(access)

自然,我们不能无中生有,要处理数据,总要有数据来源才行。但是数据来源的渠道有很多种。

可能是硬盘文件,可能是dvd光盘,也可能是http/httplive数据包,也可能是rtp数据包(vod),或者ftp,广播电视的ts流等等。

所以第一步我们要处理的问题就是如何把不同的数据来源统一一个接口。这需要不同数据包解析器,也就是实现不同的协议来满足这个需求。

对于mplayer,相关的代码在strearm,

对于vlc,相关的代码在/modules/access

查看代码目录,里面文件名可以和我们前面说的一些数据来源一一对应。所以如果我们需要实现某种协议,大抵是可以从这里获取一些实现思路的。


二,数据解析(demux)

有了数据了,我们还要解析这些数据。

为了方便媒体文件的传输,我们要把音频,图像,同步信息等等一堆信息放到一起(就是上一篇说的容器),这个过程就是mux(multiplex)。

但是为了方便媒体文件的处理,我们又需要解复用demux(Demultiplexer)

container是为了解决的传输而诞生的,demux就是为了解析而诞生的。

不同的容器需要不同的解析器,就是不同的demux接口,为了方便编程,我们同样需要统一接口。我们来看看mplayer和vlc是如何做的。

mplayer把相关代码放在了libmpdemux里面。

vlc把相关代码放在/modules/demux里面。

这两个代码统一各种容器的解析方式(就是我们常见的avi,ts,mkv的解析)。

不过需要注意的是,这些代码很大一部分都是warp的ffmpeg/libavformat里面的代码。


三,解码(decode)

上面那个过程把音视频数据分离,我们得到的数据可能是mpeg-2/h.264压缩的视频,也可能是mp3/aac/ac-3等音频数据。

但是这些数据都是压缩过的,我们知道,屏幕是由一个一个的点结成的,这一个一个点又是由rgb来描述的,声卡是处理一个一个音频帧的。

这个过程我们要解决的问题就是把压缩过的数据还原出来。如何还原?没错,靠我们的解码器。

上一篇说了不同的解码标准,现实中的情况是,我们有了一个标准,但是我们可能根据这个标准来实现不同的解码器。就像我们有一张桌子的

草图,但是我们做的桌子却有不同的颜色一个。标准有了,实现可以不同。

mplayer把这块代码放到libmpcodecs里

vlc把这块代码放到/modules/codec里。

不过要指出的是,这两块代码同样大部分是在warp ffmpeg/libavcodec。

ffmpeg真是做为神一样库而存在啊。


四,数据输出(render)

准备好了解码后的数据,就差最好一步输出了。

视频通常会解码为yuv数据,音频通常会解码为pcm数据。然后我们把这些数据分别放到屏幕和声卡里,播放过程就算完成了。

同样,数据输出也有很多渠道,也需要统一。

图像可能会输出到sdl,x11或者framebuffer,或者directfb,也可能是wingdi。

音频可能会出到oss,alsa,等等。

为了统一这些,vlc和mplayer同样warp了一些库,

mplayer放到libvo与libao

vlc放到/modules/audio_out与/modules/video_out。

你可能感兴趣的:(音视频)