DirectShow之接口实战篇--视频抓图与播放控制

DirectShow之接口实战篇(一)


-----------------------------------------------

    现今自己编程做一个多媒体播放工具是一件很令人开心愉悦的事情,但如果使用MediaPlay控制项开发则会受到很多限制,自己的很多好的创意想法都无法或者很难实现,如果利用微软的DirectX接口开发则可以充分的将作者的独特想法付诸於实现,何乐而不为呢!!不过关於DirectShow接口的开发说明文档实在是少之又少,仅有的一些不是英文的就是一些关於理论方面的,真正关於接口实战编程而且是用Delphi开发工具实现的更是凤毛麟角,使很多人都望而却步。在这里,我把我应用Directshow开发的心得以及我搜集到一些资料重新整理编辑出来公布,希望对所有由此兴趣的同仁有所帮助,就算达到了我的目的。废话少说,进入正文。

    既然是接口实战篇,就先把一些常用的接口列出来,让大家有一些基本的认识,都是用来做什麽的,什麽时候我们会需要用到此接口。


IFilterGraph ----过滤通道接口

IFilterGraph2----增强的IFilterGraph

IGraphBuilder----最为重用的COM接口,用於手动或者自动构造过滤通道FilterGraph Manager

IMediaControl----用来控制流媒体,例如流的启动和停止暂停等,播放控制接口

IMediaEvent  ----播放事件接口 ,该接口在Filter Graph发生一些事件时用来创建事件的标志资讯并传送给应用程序

IMediaEventEx----扩展播放事件接口

IMediaPosition----播放的位置和速度控制接口(控制播放位置只能为设置时间控制方式)

IMediaSeeking-----另一个播放的位置和播放速度控制接口,在位置选择方面功能较强.

     设置播放格式,多种控制播放方式.常用的有:
    (1)TIME_FORMAT_MEDIA_TIME单位100纳秒。
    (2)TIME_FORMAT_FRAME按帧播放

IBasicAudio------声音控制接口

IBasicVideo------图像控制接口(串列传输速率,宽度,长度等资讯)

IVideoWindow------显示视窗控制接口 (有关播放视窗的一切控制,包括caption显示,视窗位置控制等)

ISampleGrabber-----捕获图像接口(可用於抓图控制)

IVideoFrameStep-----控制单帧播放的接口


好了,熟悉了应用DirectShow应用开发常用的接口後,我们就通过一个实例媒体播放器来熟悉掌握这些接口,实例的代码虽然简单,但五脏俱全,功能强大,同时也了解一下应用DirectShow开发一般常用的步骤。


--------------------------------------------------------------------------------
DirectShow之接口实战篇(二)

大体说来,一般使用DirectShow接口编程无非3个步骤,
初始化接口,
利用接口中的控制函数使用控制操作,
最後释放接口。

(当然这里假定你已经拥有了directshow.pas等必须单元,如果没有的话请在网上查找)
(注:以下变量没有定义,需自己定义使用)

(1) 首先初始化部分接口,需要定义需要使用的接口
GraphBuilder: IGraphBuilder;
MediaControl: IMediaControl;
MediaSeeking: IMediaSeeking;
MediaPosition: IMediaPosition;
MediaEventEx: IMediaEvent;
BasicAudio: IBasicAudio;
BasicVideo: IBasicVideo;
VideoWindow: IVideoWindow;
SampleGrabber: ISampleGrabber;
VideoFrameStep: IVideoFrameStep;

(2)然後需要使用CoCreateInstance函数创建一个Filter Graph Manager 实例,
CoCreateInstance(TGUID(CLSID_FilterGraph),nil, CLSCTX_INPROC_SERVER,TGUID(IID_IGraphBuilder),GraphBuilder)
  
因为需要抓图使用IsampleGrabber接口,需要创建SampleGrabber实例,
var Filter: IBaseFilter;
CoCreateInstance(CLSID_SampleGrabber, nil, CLSCTX_INPROC_SERVER,IID_IBaseFilter, Filter);

(3) 调用QueryInterface函数获取来获取指标,好以後操作控制

Filter.QueryInterface(IID_ISampleGrabber, SampleGrabber);
GraphBuilder.AddFilter(Filter, 'Grabber');

GraphBuilder.QueryInterface(IID_IMediaControl, MediaControl);
GraphBuilder.QueryInterface(IID_IMediaPosition, MediaPosition);
GraphBuilder.QueryInterface(IID_IMediaSeeking, MediaSeeking);
GraphBuilder.QueryInterface(IID_IMediaEventEx, MediaEventEx);
GraphBuilder.QueryInterface(IID_IVideoFrameStep, VideoFrameStep);
GraphBuilder.QueryInterface(IID_IBasicAudio, BasicAudio);
GraphBuilder.QueryInterface(IID_IBasicVideo, BasicVideo);
GraphBuilder.QueryInterface(IID_IVideoWindow, VideoWindow);

当然为了安全起见,可以对以上每个过程进行是否成功判断,给出资讯,否则很有可能出现问题找不到头绪。
好了,一切准备成功,就可以进入第4步,开始我们的控制操作了。

(4)通过接口提供的函数开始控制
哦,差点忘记一件重要的事情,在上面调用QueryInterface之前,还有两件重要的事情要做,

第一,要建立一个Unicode(wide character)字串,保存档案名。
var _wfile: array[0..MAX_PATH - 1] of wchar;
MultiByteToWideChar(CP_ACP, 0, pChar(播放档案名), -1, @_wfile, MAX_PATH);

然後需要成功RenderFile才可以控制操作
GraphBuilder.RenderFile(_wfile, nil);

当然在显示的时候要把显示表单和控制项关连起来,这里需要通过IvideoWindow接口方法,

VideoWindow. put_Owner(Edit1.Handle);
VideoWindow. put_WindowStyle(DSVIDEO_WINDOW_CHILD_STYLE);
VideoWindow.SetWindowPosition(0,0, Edit1.ClientWidth, Edit1.ClientHeight);

得到图像的一些必要资讯,使用IbasicVideo接口中的方法,一些变数自己定义,
BasicVideo.GetVideoSize(VideoWidth, VideoHeight);
BasicVideo.get_BitRate(VideoBitRate);
BasicVideo.get_AvgTimePerFrame(PerFrame);

得到当前档的总时间以及播放时间,需要使用ImediaSeeking接口方法,
MediaSeeking.GetDuration(Duration);//得到总时间
MediaSeeking.GetCurrentPosition(CurrentPos);//得到当前播放时间

也可以通过IMediaSeeking::SetPositions方法设置开始和结束时间。

哦,这里得到的单位好像是毫米级的,可以自己转化为秒级的.

还有,如果想以後能够单帧控制播放,在这里也需要设定播放格式为按帧播放。
MediaSeeking.SetTimeFormat(Time_Format_Frame);

播放,停止,暂停等控制,
这些需要使用ImediaControl接口的方法,控制起来很简单,分别为
MediaControl.Play;
MediaControl.Stop;
MediaControl.Pause;

--------------------------------------------------------------------------------

DirectShow之接口实战篇(三)

播放速度的设定
需要使用ImediaPosition的方法。

MediaPosition.put_Rate(1);//正常
MediaPosition.put_Rate(0.25);//慢速
MediaPosition.put_Rate(2);//快速

单帧播放控制
需要使用IvideoFrameStep的方法
VideoFrameStep.Step(1, nil);

音量控制
需要使用IbasicAudio的方法
增加音量:
BasicAudio.get_Volume (&volume);//得到音量
volume:= volume +volumestep;
BasicAudio.put_Volume (volume);//增加一定的音量的分贝
减小音量:
BasicAudio.get_Volume (&volume); //得到音量
volume:= volume -volumestep;
BasicAudio.putVolume (volume); //减小一定音量的分贝

显示放大缩小控制
只需改变Edit1的大小,然後使用IvideoWindow接口方法即可
VideoWindow.SetWindowPosition(0, 0, Edit1.Width, Edit1.Height);

单帧捕获,抓图
其实很多接口都提供了此功能,但是我更倾向於使用IsampleGrabber接口来实现,相对来说,效率高些。
这个控制起来做的工作稍微多些,首先,在打开文件的时候
var MediaType: TAM_MEDIA_TYPE;
ZeroMemory(@MediaType, SizeOf(TAM_MEDIA_TYPE));
MediaType.majortype := MEDIATYPE_Video;//视频流
MediaType.subtype := MEDIASUBTYPE_RGB24;//24位图像
MediaType.formattype := FORMAT_VideoInfo;
SampleGrabber.SetMediaType(MediaType);//关联接口
SampleGrabber.SetBufferSamples(True);
然後在抓图按钮事件中如下操作
var
MediaType: TAM_MEDIA_TYPE;
VideoInfoHeader: TVideoInfoHeader;
BitmapInfo: TBitmapInfo;
Bitmap: HBitmap;
Buffer: Pointer;
BufferSize: Integer;
begin
SampleGrabber.GetConnectedMediaType(MediaType);

ZeroMemory(@VideoInfoHeader, SizeOf(TVideoInfoHeader));
CopyMemory(@VideoInfoHeader, MediaType.pbFormat, SizeOf(VideoInfoHeader));

ZeroMemory(@BitmapInfo, SizeOf(TBitmapInfo));
CopyMemory(@BitmapInfo, @VideoInfoHeader.bmiHeader, SizeOf(VideoInfoHeader.bmiHeader));

Bitmap:=CreateDIBSection(0, BitmapInfo, DIB_RGB_COLORS, Buffer, 0, 0);
SampleGrabber.GetCurrentBuffer(BufferSize, Buffer);

Image1.Picture.Bitmap.Handle:=Bitmap
end;
即可。

在这里,先总结这麽多,希望对大家有所帮助,这些只是DirectX的一个皮毛,它可以实现的功能十分强大,我也只是把我在实际中的遇到的问题总结出来供大家参考,後面的工作还很多,我想我会逐步的更深入的总结这方面的经验发表出来与大家分享,好了,DirectShow接口施展篇到这里该完结了,如果大家有补充或者想法,请发表出来以便我总结整理,谢谢大家。


 
--------------------------------------------------
 
 DirectShow之接口实战篇(四)
 
通过DirectShow驱动摄像头,首先要创建一个ICaptureGraphBuilder2的COM对象,它的作用是设备(摄像头)与输出画面打交道的一个接口.
//创建一个ICaptureGraphBuilder2对象
var
  m_cBuilder2: ICaptureGraphBuilder2;
  hr: HResult;
........................
begin
  hr := CoCreateInstance(CLSID_CaptureGraphBuilder2, nil, CLSCTX_INPROC, ICaptureGraphBuilder2, m_cBuilder2);
  if FAILED(hr) then Exit;//失败就返回
.........................
好有了接口就要准备输出的画面了,其实就是一个IGraphBuilder的COM对象!
在var下面添加 
m_gBuilder: IGraphBuilder;
//创建一个画面
hr := CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC, IGraphBuilder, m_gBuilder);
if FAILED(hr) then Exit;

//OK!把它们关联起来
m_cBuilder2.SetFiltergraph(m_gBuilder);

现在有了输出画面但还没有设备,别慌!下面就讲怎么得到设备!
要想得到设备就要请ICreateDevEnum接口和IEnumMoniker接口帮忙了!


首先创建ICreateDevEnum接口对象,在var下面添加 
de: ICreateDevEnum;
//创建ICreateDevEnum对象
hr := CoCreateInstance(CLSID_SystemDeviceEnum, nil, CLSCTX_INPROC, IID_ICreateDevEnum, de);
  if FAILED(hr) then Exit;
有了ICreateDevEnum我们就可以枚举设备了,在var下面添加

em: IEnumMoniker;
//创建一个枚举
de.CreateClassEnumerator(CLSID_VideoInputDeviceCategory, em, 0);
  if em = nil then Exit;
//枚举设备(摄像头)
在var下面添加
pM: IMoniker;//找到的接口
pBf: IBaseFilter;//设备的过滤器
dID: DWORD;

if em.Next(1, pM, @dID) = S_OK then

//得到设备的过滤器
  hr := pM.BindToObject(nil, nil, IID_IBaseFilter, pBf);
    if FAILED(hr) then Exit;
好了我们有了设备了!那就是pBf(过滤器)
现在我们要把它加入到输出画面去
//加入过滤器
hr := m_gBuilder.AddFilter(pBf, 'Video Capture');
    if FAILED(hr) then Exit;
当有输出画面了有了过滤器还不行!要用ICaptureGraphBuilder2把他们关联起来
hr := m_cBuilder2.RenderStream(@PIN_CATEGORY_PREVIEW, @MEDIATYPE_Video, pBf, nil, nil);
    if FAILED(hr) then Exit;
//现在基本完成了,下面就是要它们动起来!!
在var下面添加
m_mControl: IMediaControl;
  hr := m_gBuilder.QueryInterface(IID_IMediaControl, m_mControl);
  if FAILED(hr) then Exit;
这段代码是得到输出画面的控制接口,下面就要动了!!
//简单的一句
m_mControl.Run;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: DirectShow 是一种用于多媒体应用程序开发的Microsoft技术,可以实现视频的实时显示并抓图,并且还可以设置视频参数。在DirectShow中,可以通过构建图形和过滤器图来实现这些功能。 首先,要实现视频的实时显示,我们需要创建一个视频捕捉过滤器,并连接到显示过滤器。通过DirectShow提供的接口,可以选择摄像头设备作为视频源,然后创建一个Sample Grabber过滤器用于捕获视频图像。Sample Grabber过滤器可以设置回调函数,在视频数据接收时即时处理图像数据。然后将捕捉到的视频数据通过DirectShow的某个视频渲染器过滤器进行显示,如VideoRenderer。 其次,要实现视频抓图,可以使用Sample Grabber过滤器,捕获图像后保存为位图格式或其他图像格式。我们可以在回调函数中获取图像数据,并将其保存为图像文件。这样,我们就能够实现对视频流的实时截图。 最后,DirectShow还可以设置视频参数,如帧率、分辨率、亮度、对比度等。通过获取视频源过滤器的接口,可以设置这些参数,以调整视频显示效果。 综上所述,直接展示和抓取图像的方法包括创建视频捕捉过滤器、Sample Grabber过滤器和视频渲染器过滤器,并利用回调函数处理图像数据实现实时显示和抓图。此外,还可以通过DirectShow接口设置视频参数,以改变视频的显示效果。 ### 回答2: DirectShow是一套功能强大的多媒体框架,可以用于实现视频的实时显示并抓图,并且还可以设置视频的参数。 要实现视频的实时显示,首先需要使用DirectShow创建一个图形化用户界面窗口,并将视频源与该窗口进行关联。可以使用DirectShow提供的基本组件来实现这一功能,比如视频捕捉组件,将摄像头或者其他视频源的输入传递给视频渲染组件,然后通过渲染组件将视频显示在窗口中。 在实时显示视频的过程中,我们可以设置视频的参数。DirectShow提供了丰富的接口和功能,可以通过控制接口视频进行参数设置。例如可以调整视频的亮度、对比度、色彩饱和度等等。还可以调整视频的分辨率、帧率、编解码格式等参数,以满足具体应用场景的需求。 另外,DirectShow还可以实现视频抓图功能。通过调用DirectShow提供的接口,我们可以将当前视频帧保存为图像文件,以便于后续的处理和使用。可以设置抓图的分辨率和格式,以满足不同场景下的需求。 总结起来,DirectShow可以实现视频的实时显示并抓图,还可以设置视频的参数。它是一个功能强大、灵活性高的多媒体框架,为开发者提供了丰富的接口和工具,以便于实现多样化的视频处理需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值