本文包含原理图、PCB、源代码、封装库、中英文PDF等资源
您需要 登录 才可以下载或查看,没有账号?注册会员
×
摘 要: 根据多视点自由立体视频的压缩编码特征与数据存储结构,提出一种基于光栅显示技术的软件解决方案,采用底层Windows API 编写实现播放器的全部功能。设计实现了针对YUV视频格式的播放器,并以此为基础加入H.264解码功能模块,最终实现多线程工作模式的视频播放器,支持YUV与H.264两种视频格式,具备平面/立体播放模式自由切换功能。播放立体视频时图像清晰、流畅、立体感明显。
关键词:自由立体;高清;播放器;YUV;H.264
自由立体显示技术是指不需佩戴诸如立体眼镜等附属设备的三维立体显示技术[1],又称“裸眼式3D技术”,观察者无需借助立体眼镜即可裸眼体验立体感觉。自由立体视频技术的诸多优点决定其必然成为今后立体显示的发展趋势。目前国内外尚无商用、成熟、专用于自由立体显示技术的播放器软件,所以开发专用于自由立体视频播放显示的技术方案显得尤为重要。根据多视点自由立体显示技术的特点,本文提出了一种基于光栅显示技术的自由立体视频播放方案。
该方案基于MFC框架,播放器功能完全采用底层的WIN32API实现,具有结构清晰、设计简洁、可扩展性强的特点。与普通视频相比,立体视频具有多个视频通道,数据量较大。本文所涉及的自由立体视频源,其每一帧的立体图像都由8幅存在一定视差的平面图像合成而来。需要播放立体视频时,通过与狭缝光栅相匹配的立体合成算法[2],将8幅分辨率为720×360的图像合成分辨率为1 920×1 080的立体图像进行显示。所以,播放器除了具有普通视频播放器的基本功能之外,还具备视频格式自动匹配、帧率控制及平面/立体模式自由切换等功能。同时,为了达到明显的立体效果,帧率至少要达到20 f/s以上。
1 自由立体视频播放器实现原理
播放器基于MFC框架,按钮控件实现对播放器各项功能的控制,进度条控件显示视频解码线程的进度,滚动条控件显示视频播放的进度,并具备拖动滚动条以控制视频进度的功能。静态文本控件内显示视频帧数,累计时长、平均帧率等实时信息。播放器原理如图1所示。
立体播放器处理视频文件的流程是,从数据文件读取YUV420数据,根据图像的大小,以帧为单位转换为内存无关位图DIB(即RGB格式)[3],并利用与狭缝光栅相匹配的合成算法将RGB像素数据重新组合排列,最终将内存中已经排列好的RGB数据显示在播放器的视频区域。
视频播放器的显示原理与动画片的原理类似,利用人眼的视觉暂留特性,快速地把一张张图像贴到播放器的视频区域。人眼无法分辨这些静止图像,感觉如同播放动画一样。
通过贴有特定光栅的显示器来显示、播放立体图像,由于观察者双眼相对于光栅屏幕的空间位置不同,会产生双眼视差[4],从而令观察者无需借助立体眼镜即可裸眼体验立体感觉。
2 播放器性能
为了精确测量播放程序中各个功能模块的耗时情况,程序中加入了测量时间的功能。
实现方式:在程序运行时,首先调用QueryPerformanceFrequency()函数,得到CPU的时钟频率m_freq。在需要测量时间的操作 之前和之后调用QueryPerformanceCounter()函数,分别得到2个时钟计数值 m_count
_start和m_count_stop,则利用公式:
dT=1 000(m_count_stop-m_count_star)/m_freq
即可得到执行操作所消耗的时间。
利用此种方法,测得播放器播放视频过程中各个环节的耗时情况,如图2所示。
初步实现播放功能时,播放视频的帧率很低,只有9 f/s~11 f/s,所以需要针对视频播放过程中各个环节的原理和特点采取不同的方式提高播放器的运行效率。
3 关键技术研究与性能改进方法
3.1 内存中图像数据的显示
将内存中的RGB数据显示到视频区域,需要在具备图像显示功能的函数体中,提供表示图像颜色位数、尺寸等格式信息的结构体BITMAPINFO,以及图像数据起始地址的指针BMPbuffer[5]。对具备显示图像功能的函数进行测试,结果如下:
(1) StretchDIBits。可以用拉伸模式完成全屏显示功能,但是在拉伸模式下,图像会出现明显的色彩错误。
(2) SetDIBitsToDevice。只能原比例显示图像,如果显示器的分辨率设置小于1 920×1 080,则图像无法完整显示。
(3) DrawDib函数组。DrawDib是不依赖于图形设备接口(GDI)而直接操作显存的函数组。能够实现图像的显示功能,并且能以任意宽高比进行拉伸显示,拉伸后的图像无色彩错误。所以,此处采用DrawDib函数组来实现内存位图的显示功能。
显示功能的核心伪代码为:
DrawDibOpen();
DrawDibBegin();
DrawDibDraw(m_hDIB,hdc,rect.left,rect.top,rect.right,rect.bottom,&m_lpBmpInfo_->bmiHeader,BMPbuffer_,0,0,Width_,Height_,DDF_SAME_DRAW);
DrawDibEnd();
DrawDibClose()。
核心函数是DrawDibDraw(),参数中需要提供视频显示控件上表示绘图区域的参数rect、LPBITMAPINFO类型的结构体指针m_lpBmpInfo及DIB数据的起始地址BMPbuffer。
经测试,DrawDib函数组能够很好地完成DIB图像的显示,贴图速度快,没有明显的延迟现象,并且在全屏模式播放时没有出现类似使用StretchDIBits()函数时出现的色彩失真,达到了良好的显示效果。
3.2 内存映射文件处理大文件操作
分辨率为1 920×1 080的600帧的视频,采用YUV420存储格式时,体积高达1.78 GB。目前,对于这种大文件的操作通常是以内存映射文件的方式来加以处理的[6]。
根据播放器功能模块的耗时统计结果,未使用内存映射文件方式,而直接从硬盘读取分辨率为720×360×8的YUV420数据,平均每帧耗时35 ms,是整个播放流程中耗时最大的环节。所以,采用内存映射文件的方式改进文件读取模块可以提高播放器的效率。内存文件映射是Windows的一种内存管理方法,通过文件映射使磁盘文件的全部或部分内容与进程虚拟地址空间的某个区域建立映射关联,可以直接对被映射的文件进行访问,不必执行文件I/O操作也无需对文件内容进行缓冲处理,这种特性在进行大文件的磁盘事务操作时将获得很高的效益。内存映射文件的一般编程流程如图3所示。
经过实际对比测试,直接从硬盘读取分辨率为720×360×8的YUV420数据平均毎帧耗时35 ms。而通过内存映射文件的方式读取每帧数据的耗时可减少到15 ms左右。可见内存映射文件在处理大数据量文件时表现出了良好的性能,比通常使用的CFile类和 ReadFile()等函数的文件处理方式更加快速有效。
3.3 缓冲解码
播放器已经实现了YUV视频格式的播放功能,在此基础上加入H.264解码模块以实现播放器对H.264格式的支持。 |