为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

视频播放器研究

2012-11-14 43页 doc 1MB 102阅读

用户头像

is_419187

暂无简介

举报
视频播放器研究一:播放器简介 1.1简介 媒体播放工具,这里主要指视频播放,因为要面临庞大的兼容性和纷繁复杂的算法,从架构上看,能脱颖而出的体系屈指可数。大体来说业界主要有3大架构:MPC、MPlayer和VLC。这3大架构及其衍生品占领了90%的市场,凡是用户能看到的免费媒体播放软件,无一不是源自这3大架构。 MPC/HC架构 MPC(Media Player Classic)和它的后续者MPC-HC应该并列而说。MPC基于DirectShow(DirectShow是微软公司提供的一套在Windows平台上进行流媒体处理的开发包,9....
视频播放器研究
一:播放器简介 1.1简介 媒体播放工具,这里主要指视频播放,因为要面临庞大的兼容性和纷繁复杂的算法,从架构上看,能脱颖而出的体系屈指可数。大体来说业界主要有3大架构:MPC、MPlayer和VLC。这3大架构及其衍生品占领了90%的市场,凡是用户能看到的免费媒体播放软件,无一不是源自这3大架构。 MPC/HC架构 MPC(Media Player Classic)和它的后续者MPC-HC应该并列而说。MPC基于DirectShow(DirectShow是微软公司提供的一套在Windows平台上进行流媒体处理的开发包,9.0之前与DirectX开发包一起发布,之后包含在windows SDK中。运用DirectShow,我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中。它广泛地支持各种媒体格式)架构,是Windows系统下元祖级别的播放器。包括KMP之流最早也就是抄来MPC的代码再换个界面。MPCHC则在MPC的原作者Gabest渐渐退出开发后的继承者,MPCHC有很多创新特性,包括开始融入ffmpeg(FFmpeg是一个开源免费跨平台的视频和音频流,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多codec都是从头开发的。)和支持更多DirectX特性和DXVA等等。 优点:更直接的支持DXVA,对一些稀奇古怪的Windows平台上的格式可以通过调用第三方的Filter组件等,拥有更好的兼容性 缺点:有人说DirectShow是Windows中最难掌握的SDK,开发复杂;DirectShow允许第三方封装的特点也让兼容性和稳定性问复杂化;第三方Filter出现异常时非常难以分析处理,更难以复用; 射手播放器的架构主要来自MPC-HC,但更多的融合了FFmpeg的优势,对DirectShow Filter进行了多处改写,大大加强了对ffmpeg的利用,提高了解码稳定性,同时扩展了解码能力和兼容性。 1.2常见多媒体播放器特点比较 目前桌面市场上存在多种媒体播放器,它们各有各的技术特点,采用的体系结构也各不相同。下面将对几种常见的媒体播放器的特点进行分析和比较,从而借鉴它们的优点。 1.2.1) Windows Media Player Windows Media Player(以下简称 WMP)是微软公司推出的基于 Windows 的媒体播放器,它可以播放和组织计算机及Internet上的数字媒体文件。它支持目前流行的大多数多媒体格式,如 asf、wmv、wma、mpeg-1、mpeg-2、wav、avi、midi、vod、au、mp3等。目前它的最新版本是 WMP10,包括 Windows Media Audio 10、 Windows Media Video 10和MP3编解码器, 并采用了Windows DRM (Digital Rights Management,数字版权管理)技术。 1992年微软在Windows 3.1当中捆绑了WMP1.0,使Windows 3.1成为第一代支持多媒体的Windows系统. 用户可以自定媒体数据库收藏媒体文件。支持播放列表,支持从CD读取音轨到硬盘。支持刻录CD,V9以后的版本甚至支持与便携式音乐设备同步音乐。整合了的收费以及免费服务,V10更整合了纯商业的在线商店商业服务。支持换肤。支持MMS与RTSP的流媒体。如果用户播放的音频文件与网站上面的数据校对一致的话,用户可以看到相关的专辑讯息。 WMP采用的是封闭式结构,但是各个组件都已经模块化,并且具有单一窗口的多合一界面,可以使用标签来打开各项功能。从整体上说,它外观华丽,功能强大。但是它是一个基于 DirectShow 体系结构的媒体播放器,没有开放源码,用户要想扩展其功能必须使用 Microsoft ActiveX 控件技术和组件对象模型 (COM) 技术利用微软给出的专用SDK来开发,这就决定了它只能适用于 Windows 系列操作系统,无法让其在 Linux 上运行,不具备可移植性。此外,由于微软公司在这款软件中集成了大量的附加功能,如广播电台、播放复制 CD、寻找 internet 视频等,因此它还存在系统资源占用大、响应速度不快的缺点。最后它是被捆绑在windows操作系统上的。 2) RealPlayer RealPlayer 是 RealNetwork 公司推出的一款媒体播放器,其最新版本是RealPlayer10。RealPlayer 能够播放最新的 RealVideo 和 RealAudio,通过其内置的浏览器还可以显示网络上使用html 和 macromedia flash 动画文件的内容。RealPlayer 支持大多数多媒体文件格式,如 rm、rmvb、avi、mpeg等,而且它还支持jpeg、gif以及 png 等图像格式,不过不支持 quicktime的文件格式。 主要功能包括:支持播放在各种在线媒体视频,包括Flash, FLV格式或者MOV格式等等,并且在播放过程中能够录制视频。同时还加入了在线视频的一键下载功能到浏览器中,支持IE和Firefox,这样便能够下载YouTube, MSN,Google Video等等在线视频到本地硬盘来离线观看。而且还加入了DVD/VCD视频刻录的功能。RealPlayer是网上收听收看实时音频、视频和Flash的最佳工具,让你享受更丰富的多媒体体验,即使你的带宽很窄。RealPlayer是一个在Internet上通过流技术实现音频和视频的实时传输的在线收听工具软件,使用它不必下载音频/视频内容,只要线路允许,就能完全实现网络在线播放,极为方便地在网上查找和收听、收看自己感兴趣的广播、电视节目。 RealPlayer,这个工具原先是播放小巧玲珑的RM音乐文件的,到现在,已经发展成为最重要的网上音乐和影像的播放工具。而RealPlayer在不断地优化发展,目前已作为网络广播的工具,播放网络广播网站的实时音乐节目,也可以播放网络电视节目和电影,因此,RealPlayer已经发展成为一个多元化的因特网节目播放工具。 和WMP不同, RealPlayer是跨平台的, 目前它可以运行在Windows、 UNIX/Linux、Mac(Macintosh,苹果电脑)系统上。这主要归功于它使用了RealMedia 结构 (RMA)来实现了一个可扩展的插件接口。RealMedia 结构 (RMA)基于微软组件对象模型(COM),但它没有采用COM 的全部,而只实现 COM 的一个子集提供跨平台操作,可使用任何编程语言开发符合 RMA 的插件。 在 Windows 平台上, RMA 插件是 32 位动态链接库; 在 UNIX 与 Macintosh 平台上是共享库。RMA 提供几个跨平台的服务,所以开发的插件代码不特定针对某一个操作系统。不过,RealPlayer 并不是开放源码的,要想对它进行二次开发必须向RealNetwork公司购买许可证并且使用专用的 RealSystem SDK。同时,由于 RealPlayer 的大量功能都是基于网络流媒体的,如CPU占用率调整、缓冲设置、网络环境设置等,作为一款本地播放器就少了些常规功能,比如声道平衡、声音控制等。 3) QuickTime Player QuickTime Player 是苹果公司在 Mac OS 和 Windows 平台推出的多媒体播放软件,最新版本是 QuickTime Player7。该软件允许你全屏播放视频,通过 Internet观看现场直播事件,用 30 多种格式打开视频、静态图片及音频文件, 支持MPEG-4视频和 AAC音频,并且是播放MOV格式文件的官方软件。 苹果电脑公司所设计的 QuickTime 架构是强大的、可扩展的、灵活的数字媒体制作平台,作为上市的最新版本,它可以与老版本相兼容。因此,即使是十年前以 QuickTime 1 制作的文件在 QuickTime 7 中也可以顺畅的播放。 现在,基于 QuickTime 的应用程序可以通过 Mac OS X Tiger 中新的 Core Media Services 充分利用硬件加速的视频处理性能。此外,QuickTime 7 为 Macintosh 的软件开发人员提供了现代化的程序设计界面 QTKit。它会让程序师们能够在基于 Cocoa 的 Mac OS X 应用程序里轻松使用 QuickTime。 可靠的文件格式:.mov 文件格式让 QuickTime 有别于其他媒体平台。其架构好像一个“容器”,能够容纳不同类型的媒体,如音频、视频、Macromedia Flash、文本、图像和子图。每一种类型的媒体都被保存为一个独立的“轨道”,既易于处理,又能够与以前的版本相兼容。开发人员通过创建 QuickTime 组件,能够轻易的利用新的媒体类型或“轨道”扩展 .mov 文件格式。 Apple QuickTime 视频文件播放程序,除了播放MP3外,QuickTime还支持MIDI播放。并且可以收听/收看网络播放,支持HTTP、RTP和RTSP标准。该软件还支持主要的图像格式,比如:JPEG、BMP、PICT、PNG和GIF。该软件的其他特性还有:支持数字视频文件,包括:MiniDV、DVCPro、 DVCam、AVI、AVR、MPEG-1、OpenDML以及Macromedia Flash等。 4) MPlayer MPlayer 是Linux 上的媒体播放器(也能运行在 Windows 和许多其它Unices上,甚至非 x86CPU上),最新版本是 MPlayer1.0pre7。它能使用众多本地的、RealPlayer和 Win32DLL编解码器来播放大多数 MPEG、 AVI、 ASF/WMV、 QT/MOV、 yuv4mpeg文件。它还能支持 VideoCD,SVCD,DVD,3ivx 和 DivX 格式的电影。Mplayer 的另一个大的特色是广泛的输出设备支持。它可以在 X11,Xv,DGA, OpenGL,SVGAlib,fbdev,AAlib,DirectFB下工作,而且也能使用GGI 和 SDL 和一些低级的硬件相关的驱动模式。MPlayer 还支持通过硬件 MPEG 解码卡显示和 on screen display(OSD)。 MPlayer 采用的是完全模块化的结构,具有一个统一的解码器插件接口,开放源码,而且它并不基于DirectShow结构,完全采用C/C++ 语言编写,所有解码器全部编译到播放器里面。这样就使它具有了很好的可移植性以及较高的执行效率和较快的响应速度。不过它的缺点也很明显,那就是界面不够友好,完全基于命令行、基本操作依赖快捷键的模式使得用户很不容易接受,达不到易用的要求。为什么MPlayer功能这么强大,结构还这么小巧,却没有在中国流行起来,这大概是因为MPlayer源自于Linux,是一个开源的播放器,国外开发网站只给出了源代码、解码包、皮肤等组件,用户想要安装使用这个播放器必须要经过繁琐的编译过程才能使用,而国内用户绝大部分均被编译这个门槛限制入内。另外,它在播放时完全是单线程,易因其他进程抢占 CPU而导致响应迟滞。 MPlayer WW 编译版是通过国外开发网站提供的源代码等数据编译而来,功能强大、界面简洁、并进行美化处理,省去令人烦恼的编译过程,用户可以直接解压使用,能自定义多种皮肤与关联图标 5)VLC media player 最初为VideoLAN Client,是VideoLAN的开放源代码多媒体播放器。支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影音光盘及各类流协定。它也能作为单播 或 多播的流服务器在IPv4 或 IPv6的高速网络连接下使用。调用FFmpeg计划的解码器与libdvdcss HYPERLINK "http://zh.wikipedia.org/wiki/%E7%A8%8B%E5%BC%8F%E5%BA%AB" \o "程序库" 程序库使其有播放多媒体文件及加密DVD影碟的功能。 VideoLAN计划是一个开发多媒体播放程序的计划。原本针对流影音有两个程序—VideoLAN Client (VLC) 及 VideoLAN Server (VLS) — 然而大部分的VLS功能都集成进VLC,所以就将程序名称改为VLC media player。 这个计划原本是巴黎中央理工学院学生的专题计划。在2001年 HYPERLINK "http://zh.wikipedia.org/wiki/2%E6%9C%881%E6%97%A5" \o "2月1日" 2月1日以GPL发布后,现在贡献者已经遍及世界。 这个播放软件的三角锥图标是源自于交通三角锥。目前的图标是2006年高分辨率的CGI(英语:电脑成像),用以取代先前手绘的低分辨率图标。 VLC media player具有跨平台的特性,可用于Linux、Microsoft Windows、Mac OS X、BeOS、BSD、Pocket PC及Solaris。 VLC 在 Windows 和 Linux 上的操作接口基于 Qt4 。 在Windows,Linux以及某些平台,VLC提供了一个Mozilla扩展,使得某些网站上附带的QuickTime及Windows Media多媒体文件,可以在非微软或苹果电脑的操作系统中,正常显示于Mozilla的浏览器下。 从版本0.8.2开始,VLC亦提供了一个ActiveX的扩展,使用户可以在Internet Explorer下,正常显示某些网站上附带的QuickTime及Windows Media多媒体文件。 VLC支持播放某些没有下载完成的视频文件部份内容。 彩蛋 VLC在12月24日会自动把软件ICON设置为一个戴圣诞帽的三角锥。 由此可知现在主流的媒体播放器按其特点大致可以分为两类:一类界面美观、使用方便,具有专用的插件接口,不开放源码,基于某一特定的体系架构,可以运行在特定的平台上,可移植性不强,扩展性一般,如 Windows Media Player、RealPlayer、QuickTime Player 等;另一类界面易用性差,具有开放式插件接口,开放源码,不基于某一特定的体系架构,可以运行在多种平台上,可移植性、扩展性强,如 Mplayer。 最后提一下一些比较常见的播放器,比如腾讯视频播放器,风暴播放器,还有白噪声播放器,是一种播放随机性[[声音]]的装置 ...滴声、风声、海浪声,或者和白噪声掺杂在一起。白噪声播放器也用来缓解耳鸣。圣经播放器,有很多牧师讲道、赞美诗等等。 二:媒体播放器架构设计 一设计需求 1) 支持符合 MPEG-1、MPEG-2、MPEG-4标准的多媒体文件,支持扩展名为avi、mp3、wav、mpg、mpeg的文件。 2) 具有多媒体文件的打开、删除、显示文件头、显示文件长度、显示播放时间等功能。 3) 提供全中文界面,并支持多种字体,并可以进行中英文界面切换。 4) 可以选择打开任意位置下的多媒体文件,包括U盘和 SD卡。 5) 可以查看和编辑MP3 文件的 ID3 标签信息。 6) 运行时占用内存较小,响应速度快,可以自动进行音视频同步。 理想的音视频同步方法及实现中的困难 由于音视频同步问题是普遍存在的, MPEG-2标准中给出了一种理想条件下的音视频同步方法。下面先简单介绍一下 MPEG-2 的语法结构及相关术语再分析它提供的音视频同步方法。 MPEG-2 的语法是一种分层结构,主要分三层:传输(Transport stream)层、PES(Packetiz Elementary Stream)层和ES(Elementary Stream)层[32]。视频、音频数据经过编码、压缩后成为 ES流。然后 ES流被进行一种逻辑意义上的打包,打成 PES流。PES 进一步打成传输包,形成传输流。MPEG-2 算法的特点是在空域和时域上都进行压缩编码, 在三层码流结构中都带有表示时间的信息。 其中比较重要的是 PES中的显示时间标签(Presentation Time Stamp,PTS)和解码时间标签(Decoding Time Stamp,DTS),以及传输层中的节目参考时钟(Program Clock Reference,PCR)。 在 MPEG-2 中,解码恢复出来的图像(Picture)被称为 PPU(Picture Presentation Unit),解码恢复出来的语音被称为 APU(Audio Presentation Unit);它们在码流中的相应部分叫PAU(Picture Access Unit)和AAU(Audio Access Unit)。一般 PPU和 APU是不同的,或说不相关的帧周期。例如,假设一个 AUDIO 序列每帧有 1152 个采样,若采样率为44.1kHz, 则帧周期为 26.1ms; 而一个 VIDEO序列, 如果帧频为29.97Hz,则帧周期为33.76ms。可见 PPU和 APU 的时间边界并不一样,采取一定的措施来进行音视频同步是必要的。 在编码器中,有一个共同的系统时钟,MPEG-2的系统流(以传输流为例)中,节目参考时钟 PCR 是这个系统时钟的采样。在系统流中,有 Video 显示时间标签和Audio 显示时间标签,表示 Picture 显示的时间和相应 Audio 回放的时间。显示时间标签也以这个系统时钟为参考, 它是工作于 90kHz 的计数器的采样值, 用 33bit 表示,可以下 24h 内的任何时钟周期。节目参考时钟和显示时间标签都被编码到码流中。相邻的节目参考时钟和显示时间标签间隔一般小于 700ms。解码端可以按照节目参考时钟,通过一个锁相环恢复与编码端一致的本地系统时钟。显示时间标签在 MPEG-2 中是以一个理想的解码器(Decoder)——系统目标解码器(STD)为基础定出的。STD 是一个真实解码器的数学模型,它假设了通道 Buffer 永不上溢、下溢(对下溢有些特例);对码流的处理是瞬时的、理想的。因此,如果节目参考时钟和显示时间标签在编码端被正确编码,被无错地存储和传送,在解码端被进行正确的解码,而解码端又以节目参考时钟为基础恢复出与编码端一致的系统时钟,并且在正确的显示时间标签时间显示图像、回放声音,则视频和音频达到同步。可以看出,调整解码器本地系统时钟是实现媒体同步的基础,若没有调整好则影响多媒体数据的同步播放。 但是一个实际解码器要比理想的解码器复杂得多,所以在具体实现中音视频同步会遇到以下困难: 1) 被解码的码流不能瞬时地从通道 Buffer 中读出来;解码过程要花时间;显示和回放要花时间。 2) 根据解码硬件系统的不同,必须采用不同的同步措施。 3) 显示时间标签和相应的 PU在码流中分别处于不同的层中,而系统头信息和基本流的处理在不同的过程中, 这在实现中存在着如何找到相配对的显示时间标签和 PU的问题。 4) 当解码工作于从模式时,视频同步信号或音频采样频率由外部供给,这时PU的输出实际上并不由解码器主动控制。 5) 码流可能出错。节目参考时钟和显示时间标签在传送中都可能误码、出错。 通常实现音视频同步的方式有两种: 一种是以视频为基准,通过重复或跳音频帧的方法来调整音视频同步;另一种则反之,以音频为基准,通过对视频帧跳帧与重复显示来完成[42]。考虑到嵌入式系统的资源非常宝贵,对视频进行跳帧往往不能很快完成,而一般处理音频帧比处理视频帧速度快,因此这里采用第一种方式。 数据流首先通过分离器分解为视频数据流和音频数据流,然后经过对应的解码器,同时由本地系统时钟来进行时间戳控制;获得准确显示或回放时间以后进行时间戳比较;若同步则直接输出,不同步则进行音频跳帧或等待,直到同步后输出。 该方法的同步精度与音频帧的时间长度关系最大,如果不考虑视频序列的播放情况以及其他因素,那么由于音频帧的长度一般不超过 100ms,一般情况下同步精度可以达到 100ms 左右。 系统数据流程: 首先输入模块从数据源(多媒体文件)读入数据,此时它将读入文件头,做一些基本的处理,如读出文件长度,获取此文件的编码类型、比特率,判断能否播放等;然后插件接口模块会调用分离器插件将多媒体数据切分为视频数据流和音频数据流;再经过视频 FIFO 和音频 FIFO,排序处理;最后送入视、音频解码器调用相应的解码器进行解码,对于音频数据就会进行重采样,对于视频数据就会读取相应的帧,逐帧解码;之后经过采样的音频数据和经过渲染覆盖的视频数据先进行音视频同步,再分别通过视、音频输出模块输出。这其中,数据的读入、分离、解码、输出都是通过 Qt 提供的类库以多线程同时进行的,在解码得同时程序也在不断将数据读入缓冲区并排序等待处理,以提高效率。 二功能模块的实现 根据上一节的设计方案,整个系统分为五个模块:输入模块、输出模块、插件接口模块、解码库模块、用户界面模块。下面依次介绍各个模块的具体实现。 2.21 输入模块 输入模块的主要功能是将用户指定的多媒体文件读入。由于不同格式的多媒体文件需要调用不同的解码器才能正常打开,因此考虑到程序的模块化将实际的文件打开工作交给插件接口模块调用相应的解码器进行,输入模块只对文件进行一些基本的处理并对文件内容进行缓存,然后为插件接口模块输送原始数据流。 输入模块的数据处理流程如图 输入模块数据处理流程 用户首先通过图形用户界面选定待播放文件发出打开指令,这将会使输入模块接收到一个信号并通过用户界面传回的信息获得待播放文件的文件路径和文件名。接下来输入模块会检查文件路径是否合法、文件是否为空,之后会向插件接口模块发出信号,通知插件接口模块查找可用的解码器,为文件解码做好准备。下一步就是进行调用播放初始化函数 init(),其具体过程下面会详细介绍,最后就是将工作移交给插件接口模块,让它调用对应文件格式的解码器的open()函数。 播放初始化函数主要是为播放做一些必要的准备工作,其执行流程可以参见图 1) 判断当前是否有文件在播放,如果有则立即调用stop()函数。stop()函数会停止当前文件的播放并关闭已打开的解码器, 同时把控制音频缓冲区的互斥信号量 audioMutex 加锁,清空音频缓冲区、关闭对音频设备的引用,再把控制音频缓冲区的互斥信号量解锁。 之所以要使用互斥信号量是因为输入输出都是多线程同时进行,通过对互斥信号量加锁可以避免发生资源冲突。 2) 把控制音频缓冲区的互斥信号量 audioMutex 加锁,读入文件名,把当前帧计数 current_frame置为0。 3) 判断是否存在可用的解码器,若不存在则把音频互斥信号量 audioMutex 解锁,返回布尔值 FALSE,结束播放初始化。 4) 测试是否可以用相应解码器的 open()函数打开文件,若不能则把音频互斥信号量 audioMutex解锁后返回FALSE。 5) 获取多媒体文件的音频通道数和视频通道数。 若有音频通道则通过解码器读取音频数据流的采样率、 频率并根据这些信息分配音频输出管道和音频输出缓冲区;若有视频通道则通过解码器获取视频数据流的总帧数、帧率、文件长度。 6) 通过执行解码器的音频采样设置函数 audioSetSample()和视频帧设置函数videoSetFrame()来判断待播放文件是否可以从任意位置开始播放,将结果保存到布尔量 isSeekable中。 7) 把音频互斥信号量 audioMutex解锁,返回真,结束播放初始化工作。 2.22输出模块 输出模块的主要功能是将通过解码器解码之后的音频、视频数据送到输出设备(如 LCD 显示屏、扬声器)输出。根据输出内容的不同可以将输出模块划分为音频输出和视频输出两个子部分。这两个部分基本上是相互独立输出的,通过插件接口模块的同步控制让它们在输出时保持同步。 1) 音频输出 音频输出的主要步骤如下: A. 调用deviceReady()函数判断音频输出设备是否已经就绪。 B. 调用音频输出设备打开函数open()。此函数的定义如下: Boolopen(unsigned int f, unsigned int chs, unsigned int bps); 其中f表示频率,chs 表示通道数,bps 表示每个采样需要写入的比特数,如果打开成功返回真,否则返回假。 C. 等待插件接口模块发出completedIO()信号, 接收到此信号表示解码过的音频数据已经到达音频缓冲区。 D. 调用写入函数write()把缓冲区内已经按照频率、通道数、每采样比特数格式化好的数据发送到音频输出设备输出。 写入函数write()的定义如下: void write(char *buffer, unsigned int length); 其中 buffer 表示缓冲区数据指针,length表示数据长度。 E. 所有数据输出完毕之后关闭音频输出设备,清空音频缓冲区。 整个音频数据输出流程见图: 2) 视频输出 视频输出和音频输出稍有不同,帧缓冲区是显卡上的内存,使用帧缓冲区可以提高绘图的速度和整体性能,与帧缓冲区有关的设备是 /dev/fb0(主设备号 29,次设备号0)。 视频输出的整个流程见图: 视频输出的主要步骤如下: A. 根据屏幕的尺寸构造两个足够大的 QImage(用于提供一个与硬件无关的可直接访问像素数据的像素映射的 QT类)对象,一个用于存放当前帧,一个用于旋转帧,并把背景画面填充为黑色,为后续处理做准备。 B. 等待解码器把解码后的数据准备好以后发出的paintEvent 信号。 C. 调用 isVisible()函数判断当前帧是否可见, 若不可见则直接等待输出下一帧,节省系统资源。 D. 获取视频画面的长和宽,据此设置输出画面的长宽比,若视频画面的尺寸比屏幕尺寸大则按比例进行缩小,反之不变,除非用户选择了全屏模式。 E. 检查是否设置了帧旋转标志, 若是就把长宽数据进行相应的变换后再进行后续处理。 F. 把待输出的区域上的内容清空, 调用 create()函数在 FrameBuffer 中分配两块区域,用于容纳最开始创建的当前帧和旋转帧QImage 对象。 G. 将待输出视频帧发送到 FrameBuffer中已分配的区域中。 调用 drawImage()函数将 FrameBuffer 中的数据输出到显示设备上。 2.23插件接口模块 插件接口模块是整个播放器的核心部分,它封装了对具体解码器的操作,从而在输入和输出模块之间搭起一座桥梁,确保数据的正常流动。插件接口模块主要提供了以下方法来控制解码器: 1) 文件支持性函数 isFileSupported() 定义:bool isFileSupported(const QString& filename); 描述:通过检查文件的扩展名来确定待播放的文件是否被播放器支持,若是返回真,否则返回假。目前可以识别的扩展名有 asf、avi、dat、mp2、mp3、mpeg、mpg、ogg、wav 等。如果添加了新的解码器插件以后可以识别新的文件格式,只需要将其扩展名添加到此函数的支持列表中即可。 2) 插件初始化函数 pluginInit() 定义:void pluginInit(); 描述:调用解码器的注册函数对所有的解码器插件进行初始化和注册。 3) 文件初始化函数 fileInit() 定义:void fileInit(); 描述:把所有和文件有关的信息和标志位都置为初值,如帧率、长度、音视频通道数、 时间戳等,同时还会检查插件初始化是否已进行,若没有会先调用 pluginInit()进行插件初始化。 4) 文件打开函数 open() 定义:bool open(const QString& filename); 描述:接管输入模块读入的数据,进行实际的处理,如果打开成功返回真,否则返回假。其流程是:首先调用函数fileInit()进行文件初始化,获得文件长度;调用解码器的一般输入函数来尝试打开文件;成功以后通过读取文件第一帧的信息得到文件的流信息;查找相应的解码器来进行音频流和视频流的解码;如果有音频流对其进行重采样初始化;获得总的播放时间,计算文件的比特率、帧率。 5) 获取文件信息函数 fileInfo() 定义:const QString &fileInfo(); 描述:用于获得文件的各种信息并将结果保存在一个常量字符串中,便于其他函数调用。这些信息包括:播放时间、音频格式、音频比特率、音频通道、音频频率、视频格式、视频比特率、视频高度、视频宽度等。 6) 关闭函数 close() 定义:bool close(); 描述:用于在停止播放时进行相应的清理工作,成功完成则返回真,否则返回假。它首先检查文件打开标志 openFlag 是否为真,若是则执行清空音频数据函数flushAudioPackets()及清空视频数据函数 flushVideoPackets(),若为假说明文件未打开,直接返回;然后将插件互斥信号量加锁,关闭音频重采样、关闭音视频解码器、关闭音视频输入,把各种文件信息置为初值,最后把文件打开标志 openFlag 置为假后返回。 7) 读取音频采样函数 audioReadSamples() 定义:bool audioReadSamples(short *output, int channels, long samples, long& samplesRead, int); 描述:调用解码器对音频采样数据进行读取,是音频数据处理的核心部分。参数 output 表示待输出文件指针,channels 表示通道数,samples 表示采样数,samplesRead表示待读取采样数,返回值用来判断执行是否成功。此函数的执行过程分为如下几步: A. 对音频缓冲互斥信号量加锁,防止资源冲突。 B. 判断是否有可用的音频解码器来读取音频数据流。 C. 根据音频帧的大小分配实际帧采样存储空间(有上限)samples_fact 并计算缓存一定量的音频帧需要的空间 tmpBufCount。 D. 判断当前视频时间戳 currentVideoTimeStamp 和当前音频时间戳currentAudioTimeStamp 是否都存在,若有一个不存在就适当扩大实际帧采样的存储空间 samples_fact 以保证音视频可以进行同步。 E. 判断临时缓存音频帧空间 tmpBufCount 是否小于实际帧采样存储空间samples_fact,若是则表明音频帧缓存空间不够,则进行如下处理:调用获取下一数据包函数getAnotherPacket()获得新的数据包,若到达文件结尾,直接返回;调用音频解码器解码数据包;若解码失败则释放数据包后返回;把解码出的音频采样数据大小加上原来的 tmpBufCount 作为新的临时缓存音频帧空间 tmpBufCount。 F. 对音频数据进行重采样,并把结果放入缓冲区。 G. 把缓冲区内的数据拷贝到音频输出模块输出。 整个处理流程见图: 8) 读取视频帧函数 videoReadScaledFrame() 定义:bool videoReadScaledFrame(unsigned char **output_rows, int, int, int in_w, int in_h, int out_w, int out_h, ColorFormat fmt, int); 描述:调用解码器对视频帧进行读取,是视频数据处理的核心部分。参数output_rows 表示输出列地址的指针,in_w、in_h、out_w、out_h 分别表示输入和输出帧数据的宽度和高度,fmt 表示采用的色彩模式,返回值用来判断执行是否成功。 此函数的处理过程见图 A. 对视频缓冲区互斥信号量加锁。 B. 获取当前的色彩模式 colorMode 并判断当前的色彩模式和视频缩放渲染深度是否相同,若不同(说明视频帧采用的是YUV色彩模式)则将以当前的色彩模式作为视频缩放渲染深度,同时进行 YUV 到 RGB 色彩模式转换的初始化。 C. 判断是否有可用的视频解码器。 D. 检查跳帧标志是否设置,若是直接返回,不读取此帧。 E. 调用获取下一数据包函数 getAnotherPacket()获得新的数据包, 若到达文件结尾,直接返回。 F. 调用视频解码器解码数据包;若解码失败则释放数据包后返回。 G. 读取每帧的毫秒数并获得当前的帧数,修正当前视频时间戳,使时间戳的精度提高。 H. 检查色彩空间转换变量是否被改变,若是则重新初始化色彩空间转换变量表。进行 YUV到RGB色彩模式转换。 9) 音视频同步函数 sync() 定义:int Sync(File* fp, int auIndex, struct timeval *vtime); 描述:fp为打开的多媒体文件指针,vtime为当前正在播放的视频文件的帧头中提取的时间,或可认为是希望当前播放的音频文件移动到的时间位置。auIndex指出当前的音频帧计数, 即当前播放到了第几帧。 通过这些参数就可以计算出希望跳到的帧数和当前帧数的差值,然后根据这个差值将音频流向前(滞后)或向后(超前)跳即可。同时 Sync 函数还会将此差值 int 反馈给音频解码器,让音频解码器修正数据流的时间戳,如此循环,从而达到较好的音视频同步效果。此函数的总体思想是在播放视频数据流的同时启动另一线程,打开对应的音频数据流播放,然后在视频线程中来同步音频数据。 具体过程为:在播放视频帧时,获得根据本地系统时钟参考确定的该帧起始时间,然后获得当前正播放的音频帧的起始时间,接着求取这两个时间的时间差。再把该差值转换为毫秒单位。用该差值除以一个音频帧的时间长度,就可以得出当前音频帧应该向前或向后移动多少帧了。如果音频起始时间 time1 小于视频起始时间time2, 说明音频流滞后, 应该对音频流进行向前跳帧; 反之, 如果音频起始时间time1大于视频起始时间 time2,说明音频流超前,应该对音频流进行向后跳帧。同步执行完毕以后还要把时间差反馈到上层的待处理数据流,对它们进行时间戳修正,以便获得更好的音视频同步效果。 为整个播放过程中的音视频同步流程。 10) 查找函数 seek() 定义:bool seek(long pos); 描述:此函数的作用是在用户对播放器进行快进或者快退操作时快速定位新的播放起始位置,参数 pos 表示用户指定的新的播放起始位置的时间值,如果操作成功返回真,否则返回假。其处理过程如下: A. 检查当前是否有打开的文件。 B. 为音频互斥信号量、视频互斥信号量加锁。 C. 清空音频、视频数据包,为读取新数据腾出空间。 D. 为插件互斥信号量加锁并清空音频缓存、视频缓存。 E. 根据用户指定的播放位置确定新的数据流打开位置。 F. 将当前音视频时间戳重置并检查视频流是否为空,若视频流为空则直接返 回,因为不用等待缓冲视频帧。 G. 调用获取下一数据包函数 getAnotherPacket()获得新的数据包,若到达文件 结尾,直接返回。 H. 调用视频解码器解码数据包,若解码失败则释放数据包后返回。 I. 读取每帧的毫秒数,修正当前视频时间戳。一直读取直到找到关键帧(keyframe)或读满 25 帧,以确保缓存中有足够的数据用来恢复播放(一般视频数据的帧率为24 帧/秒) 。 J. 等待视频帧恢复播放,在此以前所有接受到的音频数据直接丢弃,以确保响应速度。 k) 清空视频数据函数 flushVideoPackets()和清空音频数据函数flushAudioPackets() 主要是进行一些清理工作:清空音视频缓存,释放音视频数据包。 L) 获取下一数据包函数 getAnotherPacket() 定义:MediaPacket *getAnotherPacket(int stream); 描述:用于在解码开始以后继续读取文件流中的数据包,参数 stream 用来指定要读取音频流还是视频流, 返回值为MediaPacket 类的指针, 该类包含的信息有长度、文件位置指针、数据包的帧数以及在解码库中定义的AVPacket 结构。此函数的处理过程如下:首先给插件互斥信号量加锁;通过 stream 的值判断要读取的是音频流还是视频流;如果是音频流,等数据读入缓存以后,用数据包的时间戳来校正当前音频时间戳(可以精确到毫秒) ;如果是视频流,等数据读入缓存以后,用数据包的时间戳来校正当前视频时间戳;继续调用解码器读入更多的数据包;通过数据包的时间戳进一步校正当前音频时间戳和当前视频时间戳;等待数据包读取完毕。 2.24解码库模块 解码库模块的主要作用是为插件接口模块提供解码器,由于 ffmpeg的功能很多,而本系统只需要用它来解码,所以只需要从ffmpeg 中提取出需要的解码核心组件就可以了。Ffmpeg 的解码核心是 libavcodec 库和libavformat 库。将它们提取出来以后,根据系统的具体环境和播放器的源代码一起进行配置和编译就可以得到适合于嵌入式系统的静态链接库,从而成为媒体播放器的一部分。 具体的说,解码库又包含解码器和分离器。解码器就是对音视频数据流进行解码的组件,分离器就是把文件流中的数据分离为音频数据流和视频数据流的组件,音频数据和视频数据是分开解码的,所以二者缺一不可。Ffmpeg 中的 libavcodec 库主要提供各种格式的解码器,libavformat库主要提供对各种格式的解析。 另外,解码库还定义了几个比较重要的数据结构供插件接口模块使用: 1) struct AVPacket 描述:音视频流数据包结构,包含流数据包中的当前时间戳、流索引、持续时间等。 2) struct AVPicture 描述:视频图象数据结构,一共包含 4 个通道的数据,有一个是 alpha 通道。 3) struct AVCodec 描述:编解码器链表结构,包含编解码器的基本信息。 4) struct AVFormatContext 描述:定义文件格式的相关信息,如输入格式和输出格式结构、数据流结构、文件名、文件标题、注释、当前时间戳的比特数等。 5) AVCodecContext 描述:定义文件编码相关信息,如比特率、帧率、视频尺寸、像素格式、采样率、通道数、帧大小、帧数、关键帧标志、延迟标记、解码器名称、解码器类型、缓存大小等。 2.25用户界面模块 图形用户界面是直接和用户打交道的,其主窗口布局和 Windows Media Player类似,从上到下分为三个部分,包括菜单栏、播放窗口和播放信息栏。这些界面的实现主要体现简洁,友好,并方便用户使用的特点。 菜单栏包括如下几部分: 1) 文件菜单。文件菜单主要包括打开、关闭、退出、文件属性命令。通过执行打开命令可以调出打开文件对话框,让用户选择任意位置的文件打开,更简便的方法是直接执行多媒体文件,系统会自动调用播放器来播放,前提是设置了文件关联;关闭命令可以关闭当前打开的文件而不关闭播放器;退出命令可以关闭播放器; 执行文件属性命令会弹出文件属性窗口来显示当前文件的各种信息。 2) 播放列表菜单。播放列表菜单包括创建、删除、保存、修改、读取播放列表命令。创建命令可以新建一个播放列表;删除命令可以删除已经存在的播放列表;保存命令可以保存当前的播放列表;执行修改命令将进入播放列表编辑窗口,可以对当前播放列表的内容进行编辑,如排序、添加、删除曲目;读取播放列表命令可以载入用户指定的播放列表。 3) 播放控制菜单。它包括增大、减小音量,全屏/窗口模式切换,暂停/继续播放命令。 4) 语言选择菜单。它可以让用户选择使用中文或者英文界面。 是图形用户界面实现方案。 播放窗口分为音频模式和视频模式。在音频模式下,由于没有需要显示的画面,播放窗口显示的是一些用于播放控制的快捷按钮,如播放/暂停、上一首、下一首、增大音量、减小音量。在视频模式下,全部用来显示视频画面。如果用户选择了全 屏模式,那么播放窗口会扩大到整个屏幕。 播放信息栏主要包括一个播放进度条、几个播放控制按钮、时间显示框。用户通过拖动播放进度条上的游标可以对当前播放的文件进行任意的前进和后退。播放控制按钮主要包括播放/暂停、停止。时间显示框会把总的播放时间和当前播放时间显示出来。 三VLC架构剖析 3.1. VideoLan简介 3.1.1 videolan组成 Videolan有以下两部分组成: VLC:一个最主要的部分,它可以播放各种类型的媒体文件和流媒体文件,并且可以创造媒体流并保存成各种格式的媒体文件,这些文件的质量要比没保存前的件好。videolan作为客户端可以播放本地文件。 VLS:是一种流服务器,专门用来解决流的各种问题,它也具有一些VLC的特征。videolan作为服务器可以输出httP,rtP,rtsp的流。 3.1.2 VLC优点 VLC是一种跨平台的媒体播放器和流媒体服务器,最初为videolan的客户端,它是一种非常简便的多媒体播放器,它可以用来播放各种各样的音视频的格式文件(MPEG-1、MPEG- 2、MPEG- 4、DivX、WMV、mp3、OGG、Vorbis、AC3、AAC等等)流媒体协议,最具特色的功能是可以边下载边观看Divx媒体文件,并可以播放不完全的AVI文件。并且支持界面的更改。VLC支持多种的操作系统,linux(rh9,Debian,Mandrake,Gentoo),BSD,windows,Mac OS X,Be OS,Solaris等等。支持带菜单的VCD,SVCD,和DVD,数字卫星频道、数字地球电视频道(digital terrestrial television channels),在这些操作系统下通过宽带IPv4、IPv6网络播放线上影片。此软件开发项目是由法国学生所发起的,参与者来自于世界各地,设计了多平台的支持,可以用于播放网络流媒体及本机多媒体文件,特别是它能直接播放未下载完整的多媒体文件。 下图表示出了VideoLan的解决方案: VideoLan Client是VideoLan项目(一个完整的MPEG-2客户/服务器解决方案)的一个组成部分。不过VideoLan Client也可以作为一个独立的程序来播放来自硬盘或者DVDROM的MPEG数据流。它目前支持GTK+、GNOME、KDE和QT,并且可以使用X11、Xvideo、SDL或者DirectX作为视频输出。对于声音,VideoLan Client支持OSS、ALSA和ESD。要访问DVD,VideoLan Client使用的是Libdvdcss库。它是一个简单的专为DVD访问设计的库。它可以像访问块设备一样访问DVD,而不用考虑解密问题。 3.2. VLC整体架构分析 3.2.1 LibVLC LibVLC是VLC的核心部分。它是一个提供接口的库,比如给VLC提供些功能接口:流的接入,音频和视频输出,插件管理,线程系统。所有的LibVLC源码位于src\及其子目录: Interface/:包含与用户交互的代码如按键和设备弹出。 Playlist/:管理播放列表的交互,如停止,播放,下一个,或者随机播放。 Input/:打开一个输入组件,读包,解析它们并且将被还原的基本流传递给解器。 Video_output/:初始化video显示器,从解码器得到所有的图片和子图片(如subtitles)。随意将它们转换为其它格式(如:YUV到RGB)并且播放。 Audio_output/:初始化音频mixer(混合器)。如:发现正确的播放频率,然后重新制作从解码器接收过来的音频帧。 Stream_output/:类似Audio_output。 Misc/:被libvlc其它部分使用的杂项,如线程系统,消息队列,CPU探测,对象查询系统,或者特定平台代码。 3.2.2 VLC VLC是一个纯粹围绕着LibVLC写成的程序。它是非常小的,但是功能很齐全的媒体播放器,归功于LibVLC的动态组件支持。 3.2.3 组件 组件位于modules\子目录,在运行时被加载。每一个组件提供不同的特征适应特定的文件的环境。另外,大量的不断编写的可移植功能位于audio_output\,vidco_output\和interface\组件,以支持新的平台(如:BeoS Mae OS X)。 组件中的插件被位于src\misc\modules.c和include\modules*.h中的函数动态加载和卸载。写组件的API描述如下,共3种: (l)组件描述宏:声明组件具有哪种优先级的能力(接口,demux2等等),还有GUI组件的实现参数,特定组件的配置变量,快捷方式,子组件等等; (2)Open(vlc_objeet_t*p_object):被VLC调用初始化这个组件,它被组件描述宏赋值给了结构体module_t中的pf_activate函数指针,被Module_Need调用; (3)Close(vlc_objeet_t*p_object):被VLC调用负初始化这个组件,保证消耗Open分配的所有资源。它被组件描述宏赋值给了结构体module_t中的pf_deactivate函数指针,被Module_Unneed调用。 用LibVLC写的组件能够直接被编译进VLC,因为有的OS不支持动态加载代码。被静态编译进VLC的组件叫做内置组件。 3.2.4 线程分析 (l)线程管理: VLC是一个密集的多线程应用。由于解码器必须预先清空和播放工序必须预先做好流程(比如说解码器和输出必须被分开使用,否则无法保证在要求的时间里播放文件),因此VLC不采用单线程方法。目前不支持单线程的客户端,多线程的解码器通常就意味着更多的开销(各线程共享内存的问题等),进程间的通信也会比较复杂。 VLC的线程结构基于pthreads线程模型。为了可移植的目的,没有直接使用pthreads函数,而是做了一系列类似的包裹函数:vlc_thread_create,vlc_thread_exit,vlc_thread_join,vlc_mutex_init,vlc_mutex_lock,vlc_mutex_unlock,vlc_mutex_destroy,vlc_cond_init,vlc_cond_signal,vlc_cond_broadcast,vlc_cond_wait,vlc_cond_destroy和类似结构:vlc_thread_t,vlc_mutex_t,and vlc_cond_t。 (2)线程同步: VLC的另一个关键特征就是解码和播放是异步的:解码由一个解码器线程工作,播放由音频输出线程或者视频输出线程工作。这个设计的主要目的是不会阻塞任何解码器线程,能够及时播放正确的音频帧或者视频帧。这样实现也导致产生了在接口,输入,解码器和输出之间的一个复杂
/
本文档为【视频播放器研究】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索