最近在研究Directshow,就用Directshow写一个播放控件吧。由于在Directshow9 SDK 中已经没有Directshow了,所以我到codeproject上去下了一个Directshow.net,它是一群牛人用C#写的,重写了所有接口,并且开源。

     进入正题吧!控件的外观就一个PicturesBox控件,然后是代码。

 

代码
1 Imports DirectShowLib ‘导入Directshow.net
2  Imports System.Runtime.InteropServices ’导入该库可获得对COM组建的操作支持
3
4
5  Public Class JRMPActiveX ’控件名
6
7 '一下是必须变量的声明
8 Private NewMediaName As String
9 Private fg As IGraphBuilder ’这就是所谓的过滤器图表,播放的核心
10 Private MyMediaControl As IMediaControl ‘用于控制媒体的播放
11 Private MyMediaEventEx As IMediaEventEx ’用于获取Directshow的事件通知
12 Private MediaAudio As IBasicAudio ‘用于控制媒体的声音
13 Private MediaVideoWindow As IVideoWindow ’用于控制视频的播放窗口
14 Private MediaVeido As IBasicVideo ‘用于控制视频
15 Private MediaPosition As IMediaPosition ’用于控制媒体的播放点
16 Private MediaSeeking As IMediaSeeking ‘用于获取媒体现在的播放位置
17 Private CurrentState As PlayState ’用于保存播放状态
18 Private CurrentPlaySpeed As Double ‘保存播放速度
19 Private CurrentVolume As Integer = 0 ’保存音量大小
20 Private CurrentBalance As Integer = 0 ’保存音量平衡值
21 Private Const WMGraphNotify As Integer = &H400 + 13 ‘定义消息常量,通知窗口是否播放完毕
22
23 Delegate Sub ML() '加载媒体事件
24 Public Event MediaLoad As ML
25
26 Delegate Sub ErrorE(ByVal ErrorCode As Integer) '加载媒体错误事件
27 Public Event ErrorEvent As ErrorE
28
29 Delegate Sub MFinished() '媒体播放完成事件
30 Public Event MediaFinished As MFinished
31
32 Delegate Sub MStop() '停止播放媒体事件
33 Public Event MediaStop As MStop
34
35 Delegate Sub MRun() '开始播放媒体事件
36 Public Event MediaRun As MRun
37
38 Delegate Sub MPause() '暂停播放媒体事件
39 Public Event MediaPause As MPause
40
41 Delegate Sub MReady() '媒体就绪事件
42 Public Event MediaReady As MReady
43
44 Delegate Sub MClean()
45 Public Event MediaClean As MClean
46
47 '定义错误代码
48 Private Enum ErrorCodes As Integer
49 LoadError
50 RunMediaError
51 PauseMediaError
52 StopMediaError
53 CleanUpMediaError
54 UnKnowError
55 SetPositionError
56 End Enum
57
58 '定义播放状态
59 Private Enum PlayState As Integer
60 Stopped
61 Paused
62 Running
63 Init
64 End Enum
65
66 '设置或获取播放音量
67 Public Property Volume() As Integer
68 Get
69 Return CurrentVolume
70 End Get
71 Set(ByVal value As Integer)
72 If MediaAudio IsNot Nothing Then
73 Dim hr As Integer = MediaAudio.get_Volume(CurrentVolume)
74 If hr >= 0 Then
75 MediaAudio.put_Volume(value)
76 End If
77 End If
78 CurrentVolume = value
79 End Set
80 End Property
81
82 '设置或获取播放音量平衡
83 Public Property Balance() As Integer
84 Get
85 Return CurrentBalance
86 End Get
87 Set(ByVal value As Integer)
88 If MediaAudio IsNot Nothing Then
89 Dim hr As Integer = MediaAudio.get_Balance(CurrentBalance)
90 If hr >= 0 Then
91 MediaAudio.put_Balance(value)
92 End If
93 End If
94 CurrentBalance = value
95 End Set
96 End Property
97
98 '获取现在的播放状态
99 Public ReadOnly Property NowPlayState() As Integer
100 Get
101 Return CurrentState
102 End Get
103 End Property
104
105 '设置或获取媒体播放速度
106 Public Property PlaySpeed() As Double
107 Get
108 Return CurrentPlaySpeed
109 End Get
110 Set(ByVal value As Double)
111 If MediaPosition IsNot Nothing Then
112 Dim hr As Integer = MediaPosition.put_Rate(value)
113 If hr >= 0 Then
114 CurrentPlaySpeed = value
115 End If
116 End If
117 End Set
118 End Property
119
120 '停止播放当前媒体
121 Public Sub CtrStop()
122 Try
123 If MyMediaControl IsNot Nothing Then
124 Dim hr As Integer = MyMediaControl.Stop()
125 If hr >= 0 Then
126 CurrentState = PlayState.Stopped
127 If MediaPosition IsNot Nothing Then
128 MediaPosition.put_CurrentPosition(0)
129 End If
130 RaiseEvent MediaStop()
131 End If
132 End If
133 Catch ex As Exception
134 RaiseEvent ErrorEvent(ErrorCodes.StopMediaError)
135 End Try
136
137 End Sub
138
139 '开始播放当前媒体
140 Public Sub CtrRun()
141 Try
142 If MyMediaControl IsNot Nothing Then
143 Dim hr As Integer = MyMediaControl.Run()
144 If hr >= 0 Then
145 CurrentState = PlayState.Running
146 RaiseEvent MediaRun()
147 End If
148 End If
149 Catch ex As Exception
150 RaiseEvent ErrorEvent(ErrorCodes.RunMediaError)
151 End Try
152
153 End Sub
154
155 '暂停播放当前媒体
156 Public Sub CtrPause()
157 Try
158 If MyMediaControl IsNot Nothing Then
159 Dim hr As Integer = MyMediaControl.Pause()
160 If hr >= 0 Then
161 CurrentState = PlayState.Paused
162 RaiseEvent MediaPause()
163 End If
164 End If
165 Catch ex As Exception
166 RaiseEvent ErrorEvent(ErrorCodes.PauseMediaError)
167 End Try
168 End Sub
169
170 '重写WndProc以获取DirectShow的通知,并激发相应事件
171 Protected Overrides Sub WndProc(ByRef m As Message)
172 If m.Msg = WMGraphNotify Then
173 Dim NowPosition As Long
174 Dim StopPosition As Long
175 MediaSeeking.GetPositions(NowPosition, StopPosition)
176
177 If NowPosition = StopPosition Then
178 RaiseEvent MediaFinished()
179 End If
180 End If
181 MyBase.WndProc(m)
182 End Sub
183
184 '获取播放进度的百分数
185 Public ReadOnly Property PlayPercent() As Double
186 Get
187 Try
188 Dim NowPosition As Long
189 Dim StopPosition As Long
190 If MediaSeeking IsNot Nothing Then
191
192 MediaSeeking.GetPositions(NowPosition, StopPosition)
193
194 Return NowPosition / StopPosition
195 End If
196 Catch ex As Exception
197 RaiseEvent ErrorEvent(ErrorCodes.UnKnowError)
198 End Try
199
200 End Get
201 End Property
202
203 '获取媒体总时间
204 Public ReadOnly Property StopTime() As Double
205 Get
206 Try
207 If MediaPosition IsNot Nothing Then
208 Dim StPo As Double
209 Dim hr As Integer = MediaPosition.get_StopTime(StPo)
210
211 If hr >= 0 Then
212 Return StPo
213 End If
214 End If
215 Catch ex As Exception
216 RaiseEvent ErrorEvent(ErrorCodes.UnKnowError)
217 End Try
218 End Get
219 End Property
220
221 '获取现在所播放的时间
222 Public ReadOnly Property CurTime() As Double
223 Get
224 Try
225 If MediaPosition IsNot Nothing Then
226 Dim StPo As Double
227 Dim hr As Integer = MediaPosition.get_CurrentPosition(StPo)
228
229 If hr >= 0 Then
230 Return StPo
231 End If
232 End If
233 Catch ex As Exception
234 RaiseEvent ErrorEvent(ErrorCodes.UnKnowError)
235 End Try
236 End Get
237 End Property
238
239 '设置或获取媒体播放点
240 Public Property SetOrGetPosition() As Double
241 Get
242 Try
243 If MediaPosition IsNot Nothing Then
244 Dim NowPosition As Double
245 MediaPosition.get_CurrentPosition(NowPosition)
246 Return NowPosition
247 End If
248 Catch ex As Exception
249 RaiseEvent ErrorEvent(ErrorCodes.SetPositionError)
250 End Try
251 End Get
252 Set(ByVal value As Double)
253 Try
254 If MediaPosition IsNot Nothing Then
255 MediaPosition.put_CurrentPosition(value)
256 End If
257 Catch ex As Exception
258 RaiseEvent ErrorEvent(ErrorCodes.SetPositionError)
259 End Try
260 End Set
261 End Property
262
263 '将秒格式化为“时:分:秒”格式
264 Public Function ShowTime(ByVal mstime As Double) As String
265
266 Dim hh As Integer = mstime \ 3600
267 Dim ss As Integer = (mstime - 3600 * hh) \ 60
268 Dim ms As Integer = CInt(mstime - 3600 * hh - ss * 60)
269 Dim strhh As String = CStr(hh)
270 Dim strss As String = CStr(ss)
271 Dim strms As String = CStr(ms)
272
273 If hh < 10 Then
274 strhh = "0" & strhh
275 End If
276
277 If ss < 10 Then
278 strss = "0" & strss
279 End If
280
281 If ms < 10 Then
282 strms = "0" & strms
283 End If
284
285 Return strhh & ":" & strss & ":" & strms
286
287 End Function
288
289 '设置视频是否全屏播放
290 Public Property IsFullScreen() As Boolean
291 Get
292 If MediaVideoWindow IsNot Nothing Then
293 Dim booIsFullScreen As Boolean
294 MediaVideoWindow.get_FullScreenMode(booIsFullScreen)
295 Return booIsFullScreen
296 Else
297 Return False
298 End If
299 End Get
300 Set(ByVal value As Boolean)
301
302 If MediaVideoWindow IsNot Nothing Then
303 MediaVideoWindow.put_FullScreenMode(value)
304 End If
305
306 End Set
307 End Property
308
309 '实现按ESC退出全屏
310 Private Sub JRMPActiveX_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress
311
312 If e.KeyChar = CChar(ChrW(27)) Then
313 IsFullScreen = False
314 End If
315
316 End Sub
317
318 '让视频窗口大小改变时,视频尺寸也跟着改变
319 Private Sub PictureBox1_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles PictureBox1.SizeChanged
320 If MediaVideoWindow IsNot Nothing AndAlso MediaVeido IsNot Nothing Then
321 MediaVideoWindow.SetWindowPosition(Me.ClientRectangle.Left, Me.ClientRectangle.Top, Me.ClientRectangle.Width, Me.ClientRectangle.Height)
322 End If
323 End Sub
324
325 '媒体载入接口
326 Public Sub OpenMedia(ByVal FileName As String)
327 RaiseEvent MediaLoad()
328 CleanUP()
329 NewMediaName = FileName
330 LoadMedia()
331 End Sub
332
333 '媒体载入及初始化函数
334 Private Sub LoadMedia()
335 Try
336 Dim hr As Integer
337
338 fg = New FilterGraph ’获取过滤器图表对象
339
340 MyMediaControl = DirectCast(fg, IMediaControl) ‘以下:从过滤器图表的对象中可获取各分对象,用DirectCast转化类型的效率要高一些。
341
342 MediaPosition = DirectCast(fg, IMediaPosition)
343
344 MediaSeeking = DirectCast(fg, IMediaSeeking)
345
346 MediaAudio = DirectCast(fg, IBasicAudio)
347
348 MediaVeido = DirectCast(fg, IBasicVideo)
349
350 MediaVideoWindow = DirectCast(fg, IVideoWindow)
351
352 MyMediaEventEx = DirectCast(fg, IMediaEvent)
353
354 '建立过滤器图表,也就是加载媒体文件
355 hr = fg.RenderFile(NewMediaName, Nothing)
356 DsError.ThrowExceptionForHR(hr)
357
358 If MediaVideoWindow IsNot Nothing AndAlso MediaVeido IsNot Nothing Then '判断加载的媒体是纯音乐还是有视频
359
360 MediaVideoWindow.put_Owner(Me.Handle) ’设置播放窗口为自身
361
362 MediaVideoWindow.put_Visible(OABool.True)
363
364 MediaVideoWindow.put_MessageDrain(Me.Handle) ‘设置此窗口为可接受事件
365
366 MediaVideoWindow.put_WindowStyle(WindowStyle.Child Or WindowStyle.ClipSiblings Or WindowStyle.ClipChildren) ’设置窗口模式,这里设置为子窗口且停靠于父容器
367
368 MediaVideoWindow.SetWindowPosition(Me.ClientRectangle.Left, Me.ClientRectangle.Top, Me.ClientRectangle.Width, Me.ClientRectangle.Height) ‘设置窗口大小
369
370 End If
371
372 MediaAudio.put_Volume(CurrentVolume) ‘设置音量和平衡
373
374 MediaAudio.put_Balance(CurrentBalance)
375
376 '设置事件处理窗口,这里设置为自身
377 MyMediaEventEx.SetNotifyWindow(Me.Handle, WMGraphNotify, IntPtr.Zero)
378
379 RaiseEvent MediaReady() ’发出事件通知,表示一切就绪
380
381 Catch ex As Exception
382 CleanUP()
383 RaiseEvent ErrorEvent(ErrorCodes.LoadError)
384 End Try
385
386 End Sub
387
388 '释放资源函数
389 Public Sub CleanUP()
390 Try
391 RaiseEvent MediaClean()
392 CloseInterface()
393 CurrentState = PlayState.Init
394 Catch ex As Exception
395 RaiseEvent ErrorEvent(ErrorCodes.CleanUpMediaError)
396 End Try
397 End Sub
398
399 '释放资源
400 Private Sub CloseInterface()
401
402 If MyMediaEventEx IsNot Nothing Then
403 MyMediaEventEx.SetNotifyWindow(IntPtr.Zero, 0, IntPtr.Zero) ’将监视窗口的句柄设为0
404 MyMediaEventEx = Nothing
405 End If
406
407 If MyMediaControl IsNot Nothing Then MyMediaControl = Nothing
408 If MediaAudio IsNot Nothing Then MediaAudio = Nothing
409 If MediaVeido IsNot Nothing Then MediaVeido = Nothing
410 If MediaVideoWindow IsNot Nothing Then MediaVideoWindow = Nothing
411 If MediaSeeking IsNot Nothing Then MediaSeeking = Nothing
412 If MediaPosition IsNot Nothing Then MediaPosition = Nothing
413
414 If fg IsNot Nothing Then Marshal.FinalReleaseComObject(fg)
415 fg = Nothing
416
417 GC.Collect() ‘强制垃圾回收器立即进行回收
418
419 End Sub
420
421 End Class
422

 

大概就这么多,还有一些功能没实现,比如显示比特率等,以后继续改进。再有就是,这个播放控件只能播放wmv和avi文件,要想播放更多格式,去下一个万能解码包安上即可。

posted on 2010-10-20 14:38  AniX  阅读(1641)  评论(0编辑  收藏  举报