早期的电视提词器,提示文稿的摄取和回放,是利用位于播音员头顶的专用摄像头拍摄播音员手中的文稿,然后通过视频电缆送入播音员前方的提词器中,提词器所用的回显系统一般使用的是CRT显示器,文稿的移动需要播音员自己控制手动移动稿纸。如图1所示。
由于提词器显示的图像需要经过镜面反射,如果直接显示出来,播音员看到的将是个镜像的图像,阅读起来非常困难。如图2所示。
为了解决图像经提词器镜面折射后,产生的图像镜像反转问题,需要提前对显示器显示的图像进行镜像处理,产生负负得正的效果,如图3所示。
由于CRT显示方式的工作特点,实现镜像显示其实很简单,只需要对显示器电路作简单的修改,将显像管的行偏转线圈两个接线头调换一下,即可实现图像的镜像显示。
近年来,随着电视文稿处理的计算机化,网络发展趋势,电视提词器也逐步由模拟信号提词器发展成计算机提词器,可实现文稿的无纸化传递,播音员也只需要通过鼠标或控制器就可以灵活控制文稿的显示。同时由于显示技术的发展和对提词器轻量化和移动性,便携性的要求,传统的CRT提词器已经逐渐被淘汰,转而大量使用液晶显示器做为显示单元。新型电脑提词器的组成如图4所示。
由于液晶显示器的显示原理,液晶显示器不再具有偏转线圈扫描单元。市售的液晶显示器也都无法通过简单地修改电路实现图像的镜像显示。目前实现液晶显示器提词的方法基本有两种:
一种方法是使用专用的硬件VGA镜像发生器,实现显示器信号的镜向输出,如图5A所示。采用这种方法的国内厂商有北京视讯。但这种方法的缺点是设备成本高,由于采用专用硬件设备,一旦损坏,将难以及时修复。
第二种方法是使用双显卡或双头显卡,利用软件实现副显卡与主显卡显示内容的镜向,如图5B所示。采用这种方法的国内厂商有青岛广研所,他们的实现方法是使用专用软件辅以一种专用的镜像显示字库并通过改变文字的显示顺序来实现文字的镜向显示。这种方法的优点在于使用通用的计算机硬件,维修更新方便,成本低。缺点在于必须使用专用软件,文稿兼容性差,不能兼容常见的WORD,WPS,PDF等文稿格式,更无法实现图文同时显示,由于使用专用字库,仅能实现中文或英文单独提词,无法实现中英文混合显示,这在我台英语新闻节目制作时带来很大不便。
为解决上述两种方案的弊病,需要设计出一种使用通用硬件,同时又能直接支持各种软件的提词器系统。方案B的硬件设计具有很强的通用性,目前主流PC均可安装双显卡或单片双头显卡,普通显卡由于是民用产品,价格便宜,来源广泛,数百元即可购得,因此这将是一种极为廉价的高可靠性电脑提词器信号输出方案,值得采用,因此提词器系统硬件部分应该选用这种方法。
关键的难点在于如何用软件实现副显示器对主显示器的镜像滚屏输出,同时又要兼容众多的文档格式。经过分析可以发现,事实上,各种文档格式都有成熟的软件可以打开,并可以在鼠标控制下实现自动滚屏和手动滚屏,例如Microsoft Word,只要打开文档后,点击鼠标滚轮键,即可控制滚屏速度和方向,同时显示字号、字体的大小均可任意调节。因此,多文档格式滚屏的实现,完全可以利用各类文稿软件自身的功能来实现。问题就简化为如何将主显示卡上显示的内容实时地水平镜像复制到副显示器上。
通过对微软开发网络MSDN(Microsoft Developer Network)相关文档的查询可以发现,实际上Microsoft Windows操作系统有相应的底层GDI API(图形驱动应用程序接口)可供调用实现提词器的核心功能——软件镜像发生器。
GDI是Windows操作系统提供的设备无关图形驱动接口,从Windows98到WindowsVista操作系统都支持。GDI接口中提供了大量的API可供各类编程语言调用。其中有一个功能函数StretchBlt,在MSDN中对StretchBlt的描述是这样的:
BOOL StretchBlt(
HDC hdcDest, // handle to destination DC(目标设备场景句柄)
int nXOriginDest, // x-coord of destination upper-left corner(目标矩形左上角X坐标)
int nYOriginDest, // y-coord of destination upper-left corner(目标矩形左上角Y坐标)
int nWidthDest, // width of destination rectangle(目标矩形宽度)
int nHeightDest, // height of destination rectangle(目标矩形高度)
HDC hdcSrc, // handle to source DC(源设备场景句柄)
int nXOriginSrc, // x-coord of source upper-left corner(源矩形左上角X坐标)
int nYOriginSrc, // y-coord of source upper-left corner(源矩形左上角Y坐标)
int nWidthSrc, // width of source rectangle(源矩形宽度)
int nHeightSrc, // height of source rectangle(源矩形高度)
DWORD dwRop // raster operation code(光栅操作码)
);
StretchBlt函数可以实现将屏幕任意位置的一个矩形位置复制到另一个位置,并且,要实现水平或垂直镜像翻转复制,只要将目标矩形宽度或长度设为源矩形宽度或长度的负数即可。
光栅操作码决定了复制时的光栅运算的方式,详细涵意也可以在MSDN中查阅,例如当光栅操作码为CC0020H时,是直接复制源图像,当光栅操作码为00330008H时,是将源图像作反色处理后再复制,利用此特性,我们可以将正常的白底黑字显示成黑底白字,适合某些场合要求。
下面给出一个在VisualBasic 6.0下开发的提词器镜像发生器的核心代码,并作逐一详细说明。
首先在VB中新建一个标准exe工程,在缺省的窗体form1上建立一个名为Timer1的Timer部件。新建模块module1,输入以下代码:
Public Const Srccopy = &HCC0020
'定义常数用作函数StretechBlt中正常色彩复制的光栅操作码
Public Const NotSrccopy = &H330008
'定义常数用作函数StretechBlt中反色复制的光栅操作码
Public Const hwnd_topmost = -1
Public Const Swp_nomove = &H2
Public Const Swp_nosize = &H1
Public Const Flags = Swp_nomove Or Swp_nosize
'定义常数用作函数SetWindowPos中使窗口位于所有窗口最上面一层,避免被其它窗口遮挡
Public Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
'函数声明,用于将窗口置于最上方
Public Declare Function GetDesktopWindow Lib "user32" () As Long
'函数声明,用于获得整个屏幕的窗口句柄,以作为绘制的源
Public Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
'函数声明,用于用于获得指定窗口一个设备环境。
Public Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long
'函数声明,用于将屏幕任意位置的一个矩形位置复制到另一个位置并实现镜像翻转
Public Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long
'函数声明,释放窗口的设备环境
在form1中输入以下代码:
Option Explicit
Dim w As Long '屏幕宽
Dim h As Long '屏幕高
Dim hWndDesk As Long'桌面窗口句柄
Dim hdcdesk As Long '桌面设备场景
Private Sub Form_Load()
SetWindowPos hwnd, hwnd_topmost, 0, 0, 0, 0, Flags '使窗口总在最上面
Form1.BorderStyle =0'设置窗口风格
Timer1.Interval = 40 '初始刷新率定为1000/40=25FPS
Form1.Width = Screen.Width '将form1大小设为屏幕大小
Form1.Height = Screen.Height
w = Screen.Width / Screen.TwipsPerPixelX '换算出屏幕的水平和垂直像素大小
h = Screen.Height / Screen.TwipsPerPixelY
Form1.Move Screen.Width + 1, 0
'将form1置于主显示器右侧,也就是副显示器上,以用作绘制主显示器的镜像
End Sub
Private Sub Timer1_Timer() '定时重绘窗口
hWndDesk = GetDesktopWindow() '获得桌面的句柄
hdcdesk = GetDC(hWndDesk) '获得桌面窗口的设备环境
StretchBlt Form1.hdc, w, 0, -1 * w, h, hdcdesk, 0, 0, w, h, Srccopy
'在form1上生成桌面镜像图像,反色显示,将Srccopy改为NotSrccopy即可
ReleaseDC hWndDesk, hdcdesk '释放桌面窗口的设备环境
ReleaseDC Form1.hwnd, Form1.hdc '释放form1窗口的设备环境
End Sub
此程序在Windows XP及Windows 2000环境下,显卡采用Ati X1650双头显卡,及Nvdia Geforce8600 GT双头显卡、Inter845GV+Matrox Mystique 100双显卡下均测试通过。单片双头显卡的安装很简单,不再赘述,只需要将计算机显示器和提词器显示分别接双头显示的两个头上。在AGP+PCI双显卡安装时,如果遇到PC无法启动,可以将显卡的PCI槽位换一下再试,一般取用最接近AGP插槽的PCI插槽安装副显卡。需要注意的是,显示模式设置时,需要将副显示器分辨率设置成和主显示器分辨率一致,才能完整显示,同时将副显示器的显示位置设置在主显示器右侧,并勾选副显示器的“将Windows桌面扩展到该监视器上”如图6所示。
以上程序虽然使用了VisualBasic高级语言进行设计,但由于程序核心均采用的是直接调用Windows底层应用程序接口Win32api,所以具有很高的运行效率。目前已在我台演播室中已经使用了四年多,效果令人非常满意,图7是实际运行效果。