一、 前言
流媒体的定义很广泛,大多数时候指的是把连续的影像和声音信息经过压缩处理后放上网站服务器,让用户一边下载一边观看、收听,而不需要等整个压缩文件下载到自己机器就可以观看的视频/音频传输、压缩技术。流媒体也指代由这种技术支持的某种特定文件格式:压缩流式文件,它通过网络传输,并通过个人电脑软件进行解码。面对流媒体技术的迅猛发展,作为软件技术开发人员,关心的是将如何应对的问题。流媒体的处理,以其复杂性和技术性,一向受到工业界和技术界的关注。特别是随着互联网的普及,流媒体通过网络广泛应用在工业控制、现场监控、视频会议、大众娱乐等方面,选择一种合适的应用方案,可以达到事半功倍的目的。
MCI是微软为Windows最初提出的多媒体编程接口,它管理媒体控制接口(MCI)设备上的多媒体文件的记录与回放。它被用来向诸如声卡、MIDI 序列发生器、CD-ROM 驱动器、视频CD播放器和视频磁带记录器及播放器等设备发出MCI命令,还支持 Windows (*.avi) 视频文件的回放。MCI编程实现起来并不困难,但是对于用户要求获取的某些有关压缩数据流的信息和希望实现的某些功能,比如图线尺寸、Copmression Rate、图形的缩放显示等,上叙控件所提供的为方便程序开发人员使用的高层接口已不适用,要想在此基础上实现对底层的一些操作,难度可想而知;另外随着多媒体技术的迅速发展,各种压缩算法在该领域的的应用,MCI技术越来越显的力不从心,最明显的是它不支持可变比特率的压缩算法,对于处理DVD等近年出现的多种新的媒体格式也已经显的无能为力,怎么办呢?为此我们介绍一种建立在DirectX技术上的方法来实现操作多媒体数据流。作为MCI的"接班人",微软适时推出了建立在DirectX(包含DirectDraw、DirectSound、Direct3D)之上的DirectShow技术,它是在DirectX之上的媒体层,支持来自本地或网络的各种视频、音频压缩格式的媒体文件的解码和回放,可以从设备上捕捉多媒体流,可以回放各种压缩算法处理的流媒体。这些格式包括:MPEG的音频和视频标准、音频和视频交互标准(AVI)、WAVE、MIDI和高级流格式ASF。
DirectShow对媒体数据处理采用流媒体(Multimedia Stream)的方式,在应用中使用该方式可以大大的减少编程的复杂程度,同时又可以自动协商从数据源到应用的转换,流接口提供了统一的、可以预测的数据存取的控制方法,这样应用程序在播放媒体数据时不需要考虑它最初的来源和格式。
上面说了那么多,还没有进入正题,其实在Windows/System下有一个Windows中自带的用于控制运动图像播放的动态链接库Quatrz.dll,它实现了对DirectShow的简单封装,或者说它是当今流行的DirectShow技术的前身,在该库中定义了IBasicAudio,IbasicVideo、IBasicVideo2,IMediaEvent 、IMediaEventEx、ImediaPosition、ImediaControl和IVideoWindow等类,程序开发人员可以利用它们方便地控制和操作各种格式的流媒体。例如,直接调用ImediaControl类的无参函数Run、Pause、Stop等就可以控制流媒体的播放进程;利用IMediaPosition类对具体播放细节进行定位操作等。对于流媒体的数据输出显示并不需要特别的控件,在VisualBasic编程中可以简单的选择一个窗体作为容器或一个PictureBox控件作为容器。为了使用该动态连接库,你需要作的仅仅是在生成一个项目后,点击VB开发环境的工程/引用菜单,在弹出的对话框中选择ActiveMovie Control type library就可以了。
二、VB开发流媒体的播放技术
为了是说明如何在VB中利用ActiveMovie Control type library实现流媒体的播放,下面给出了一个名为VBDemo的项目实现代码,该程序可以以不同的速率来播放wav、avi、mepg等多种格式的多媒体文件,同时显示多媒体文件的长度、播放速率等信息。 在这个项目的窗体上定义一个FILE(名字为mnu_File)的主菜单,它包含OPEN(名字为mnu_FileOpen)和EXIT(名字为mnu_FileExit)子菜单,分别用于打开流媒体文件和退出应用程序;工具条tbControlBar上定义三个按钮,分别为实现流媒体的"播放"、"暂停"、"停止"功能的按钮;名为picVideoWindow的PictureBox控件用来作为播放流媒体视频数据的容器;slBanlance和slVolume两个Slider控件分别用来控制媒体流的声音大小和平衡度,它们的最大最小值分别为(-10000,0)和(-5000,5000);在界面的信息栏中,txtDuration和txtBox这两个TextBox控件分别用来显示正在播放的流媒体的时间长度和播放速率;关于播放速率,用户可以通过optplaybackR单选框来选择正常播放、两倍速率播放还是半速播放。程序编译后的界面如下(抱歉,使用考屏的方法无法将播放的图像一同考贝下来):
程序的主要实现思路是在调用了Windows/System下动态链接库Quatrz.dll的基础上,定义一个全局的Object对象m_objMediaControl,令m_objMediaControl指向FilgraphManager的一个新实例,调用它的RenderFile函数装载需要播放的流媒体文件,然后使用Run等函数就可以实现各种播放功能了;为了将流媒体的语音效果准确的显示出来,需要再定义一个IbasicAudio音频对象m_objBasicAudio,用来提取流媒体的音频数据并控制语音的大小,IMediaPosition 对象m_objMediaPosition是用来为多媒体文件定位的。最后显示流媒体时需要打开一个播放Video的窗口,可以将picVideoWindow的句柄hWnd赋给的m_objVideoWindow的Owner属性 ,这样picVideoWindow就可以显示接收的多媒体数据流了。具体实现代码如下:
******************************************************************
为了处理多媒体流,定义以下全局变量.
*******************************************************************
Option Explicit
Private m_dblRate As Double '多媒体流播放的幀速率,也既是每秒播放的幀数;
Private m_bstrFileName As String '需要播放的流媒体文件名;
Private m_dblRunLength As Double '播放的流媒体的持续时间,单位为秒;
Private m_dblStartPosition As Double '待播放的流媒体文件的初始位置,以秒为单位;
Private m_boolVideoRunning As Boolean '多媒体流正在播放的标志;
Private m_objBasicAudio As IBasicAudio 'Basic 的音频对象,用来处理媒体流中的语音数据;
Private m_objVideoWindow As IVideoWindow '视频窗口对象;
Private m_objFilgraphManager As FilgraphManager '媒体控制对象;
Private m_objMediaPosition As IMediaPosition '媒体位置对象;
********************************************************************************
* 窗体加载时作一些初始化工作
********************************************************************************
Private Sub Form_Load()
On Local Error GoTo ErrLine
optPlaybackRate(1).Value = True '回放速率设置为正常;
frmMain.ScaleMode = 3 '窗体的坐标单位设置为像素;
'将工具栏上的所有按钮设置为"无效"
tbControlBar.Buttons("play").Enabled = False
tbControlBar.Buttons("stop").Enabled = False
tbControlBar.Buttons("pause").Enabled = False
Exit Sub
ErrLine:
Err.Clear
Exit Sub
End Sub
***********************************************************************
窗体卸载时清除与多媒体流相关的全局对象;
***********************************************************************
Private Sub Form_Unload(Cancel As Integer)
On Local Error GoTo ErrLine
'停止播放;
m_boolVideoRunning = False
DoEvents
If m_objFilgraphManager <>NULL Then
m_objFilgraphManager.Stop
End If
'清除视频窗口;
If m_objVideoWindow <> NULL Then
m_objVideoWindow.Owner = 0 '设置m_objVideoWindow对象的拥有者为空;
End If
'清除与多媒体流相关的全局对象;
If m_objBasicAudio <> Null Then Set m_objBasicAudio = Nothing
If m_objBasicVideo <> NULL Then Set m_objBasicVideo = Nothing
If m_objFilgraphManager <> NULL Then Set m_objFilgraphManager = Nothing
If m_objVideoWindow <> NULL Then Set m_objVideoWindow = Nothing
If m_objMediaPosition <> NULL Then Set m_objMediaPosition = Nothing
Exit Sub
ErrLine:
Err.Clear
Exit Sub
End Sub
************************************************************************
"退出"菜单响应函数;
**************************************************************************
Private Sub mnu_FileExit_Click()
Dim frm As Form
On Local Error GoTo ErrLine
For Each frm In Forms
frm.Move Screen.Width * 8,Screen.Height * 8
frm.Visible = False: Unload frm
Next
Exit Sub
ErrLine:
Err.Clear
Exit Sub
End Sub
******************************************************************
"文件打开"菜单响应函数;
******************************************************************
Private Sub mnu_FileOpen_Click()
Dim nCount As Long
On Local Error GoTo ErrLine
'清理内存,防止在此之前已经打开过一个文件;
Call Form_Unload(True)
'选择打开的文件类型默认为:mov、avi、mp3、mp2、wav;
ctrlCommonDialog.Filter="MediaFiles (*.mpg;*.avi;*.mov;*.wav;*.mp2;*.mp3) *.mpg;*.avi;*.mov;*.wav;*.mp2;*.mp3"
ctrlCommonDialog.ShowOpen
m_bstrFileName = ctrlCommonDialog.FileName
'初始化一个滤波器图表
Set m_objFilgraphManager = New FilgraphManager
Call m_objFilgraphManager.RenderFile(m_bstrFileName) '装载流媒体文件;
'设置Basic的音频对象,如语音的大小、平衡度等;
Set m_objBasicAudio = m_objFilgraphManager
m_objBasicAudio.Volume = slVolume.Value
m_objBasicAudio.Balance = slBalance.Value
'设置视频窗口对象,初始化位置后将其父窗口设置为窗口上的PictureBox对象;
Set m_objVideoWindow = m_objFilgraphManager
m_objVideoWindow.WindowStyle = CLng(amp;H6000000)
m_objVideoWindow.Top = 0
m_objVideoWindow.Left = 0
m_objVideoWindow.Width = picVideoWindow.Width
m_objVideoWindow.Height = picVideoWindow.Height
m_objVideoWindow.Owner = picVideoWindow.hWnd
'设置多媒体位置对象;
Set m_objMediaPosition = m_objFilgraphManager
'根据用户的选择来设置多媒体流的播放速率;
For nCount = optPlaybackRate.LBound To optPlaybackRate.UBound
If optPlaybackRate(nCount).Value = True Then
Select Case nCount
Case 0
If m_objMediaPosition <>NULL Then _
m_objMediaPosition.Rate = 0.5
Case 1
If m_objMediaPosition <>NULL Then _
m_objMediaPosition.Rate = 1
Case 2
If m_objMediaPosition <> NULL Then _
m_objMediaPosition.Rate = 2
End Select
Exit For
End If
Next
m_dblRunLength = Round(m_objMediaPosition.Duration,2)
txtDuration.Text = CStr(m_dblRunLength)
' 设置当前位置为起始位置;
m_dblStartPosition = 0
' 显示用户选择的多媒体流的播放速率;
m_dblRate = m_objMediaPosition.Rate
txtRate.Text = CStr(m_dblRate)
'设置按钮的默认状态;
tbControlBar.Buttons("play").Enabled = True
tbControlBar.Buttons("stop").Enabled = False
tbControlBar.Buttons("pause").Enabled = False
Call tbControlBar_ButtonClick(tbControlBar.Buttons(1))
ErrLine:
Err.Clear
Resume Next
Exit Sub
End Sub
************************************************************************
用户点击播放速率单选按钮时的响应处理函数;
************************************************************************
Private Sub optPlaybackRate_Click(Index As Integer)
On Local Error GoTo ErrLine
Select Case Index
Case 0
If m_objMediaPosition<> NULL Then _
txtRate.Text = 0.5
Case 1
If m_objMediaPosition<> NULL Then _
txtRate.Text = 1
Case 2
If m_objMediaPosition<> NULL Then _
txtRate.Text = 2
End Select
'重新设置媒体回放的播放速率;
If m_objMediaPosition Then
Select Case Index
Case 0
If m_objMediaPosition <>NULL Then _
m_objMediaPosition.Rate = 0.5
Case 1
If m_objMediaPosition <> NULL Then _
m_objMediaPosition.Rate = 1
Case 2
If m_objMediaPosition <> NULL Then _
m_objMediaPosition.Rate = 2
End Select
End If
Exit Sub
ErrLine:
Err.Clear
Exit Sub
End Sub
**************************************************************************
音频平衡滑动条改变时的响应处理函数;
**************************************************************************
Private Sub slBalance_Change()
On Local Error GoTo ErrLine
'用户使用滑动条来设置语音平衡的值;
If m_objFilgraphManager <> NULL Then _
m_objBasicAudio.Balance = slBalance.Value
Exit Sub
ErrLine:
Err.Clear
Exit Sub
End Sub
***********************************************************************
设置音量大小的滑动条改变时的响应处理函数
***********************************************************************
Private Sub slVolume_Change()
On Local Error GoTo ErrLine
'用户使用滑动条来设置语音的大小;
If m_objFilgraphManager <>NULL Then _
m_objBasicAudio.Volume = slVolume.Value
Exit Sub
ErrLine:
Err.Clear
Exit Sub
End Sub
***************************************************************************
界面上关于多媒体流的"播放"、"暂停"、"停止"等按钮的点击响应函数;
***************************************************************************
Private Sub tbControlBar_ButtonClick(ByVal Button As Button)
On Local Error GoTo ErrLine
If ObjPtr(m_objMediaControl) > 0 Then
If Button.Key = "play" Then '如果用户点击了"播放"按钮;
'如果多媒体的当前位置不处在文件尾部,则对多媒体流的位置重新置位;
If CLng(m_objMediaPosition.CurrentPosition) < CLng(m_dblStartPosition) Then
m_objMediaPosition.CurrentPosition = m_dblStartPosition
ElseIf CLng(m_objMediaPosition.CurrentPosition) = CLng(m_dblRunLength) Then
m_objMediaPosition.CurrentPosition = m_dblStartPosition
End If
Call m_objFilgraphManager.Run
m_boolVideoRunning = True
tbControlBar.Buttons("play").Enabled = False
tbControlBar.Buttons("stop").Enabled = True
tbControlBar.Buttons("pause").Enabled = True
picVideoWindow.Refresh
ElseIf Button.Key = "pause" Then '用户点击了"暂停"按钮;
Call m_objFilgraphManager.Pause
m_boolVideoRunning = False
tbControlBar.Buttons("play").Enabled = True
tbControlBar.Buttons("stop").Enabled = True
tbControlBar.Buttons("pause").Enabled = False
ElseIf Button.Key = "stop" Then '用户点击了"停止"按钮;
Call m_objFilgraphManager.Stop
m_boolVideoRunning = False
' 重新设置视频流的当前播放位置为起始位置;
m_objMediaPosition.CurrentPosition = 0
txtElapsed.Text = "0.0"
tbControlBar.Buttons("play").Enabled = True
tbControlBar.Buttons("stop").Enabled = False
tbControlBar.Buttons("pause").Enabled = False
End If
End If
Exit Sub
ErrLine:
Err.Clear
Exit Sub
End Sub
以上内容希望对在多媒体领域有兴趣的读者朋友有所帮助,起到抛砖引玉的作用,将上面的代码稍加修改后添加到自己正在开发的应用程序中,实现流媒体的播放,达到丰富软件的功能的目的。