DSow视频开发,欢迎大家都来讨论 (140分)

这几天我在网上看了一些资料,准备直接用Dshow接口,不用DShowPack了。
 
请熟悉DShow接口的朋友帮我看看下面的代码,其问题是图像有马赛克,而且在窗口关闭时出读地址错。
unit main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DSUtil, StdCtrls, DSPack, DirectShow9, Menus, ExtCtrls, ComCtrls,
ExtDlgs, ActiveX;

type
TVideoForm = class(TForm)
MainMenu1: TMainMenu;
Devices: TMenuItem;
SavePictureDialog1: TSavePictureDialog;
Bitmap1: TMenuItem;
Setup1: TMenuItem;
Bitmap2: TMenuItem;
Callback1: TMenuItem;
VideoSize1: TMenuItem;
N320X2401: TMenuItem;
N640X4801: TMenuItem;
N720X5761: TMenuItem;
Debug1: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure N720X5761Click(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private

public
end;


var
VideoForm: TVideoForm;
//DirectShow 接口定义
GraphBuilder : IGraphBuilder;
CaptureGraphBuilder : ICaptureGraphBuilder2;

MediaControl : IMediaControl;
MediaSeeking : IMediaSeeking;
MediaPosition : IMediaPosition;
MediaEventEx : IMediaEventEx;

BasicAudio : IBasicAudio;
BasicVideo : IBasicVideo;
VideoWindow : IVideoWindow;

SampleGrabber : ISampleGrabber;
VideoFrameStep : IVideoFrameStep;

CreateDevEnum : ICreateDevEnum;
EnumMoniker : IEnumMoniker;


implementation

{$R *.dfm}

procedure TVideoForm.FormCreate(Sender: TObject);
var
HR : HResult;
DebugMsg : string;
Moniker : IMoniker;
cFetched : PLongInt;
BaseFilter : IBaseFilter;
begin

Self.Width := 640;
Self.Height := 480;
Self.Left := (Screen.Width - Self.Width) div 2;
Self.Top := (Screen.Height - Self.Height) div 2;
//初始化接口...
try
HR := CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, GraphBuilder);
if not Succeeded(HR) then
Exit;
DebugMsg := 'GraphBuilder Created!';

HR := CoCreateInstance(CLSID_CaptureGraphBuilder2, nil, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, CaptureGraphBuilder);
if not Succeeded(HR) then
Exit;
DebugMsg := 'CaptureGraphBuilder Created!';

GraphBuilder.QueryInterface(IID_IMediaControl, MediaControl);
GraphBuilder.QueryInterface(IID_IMediaEventEx, MediaEventEx);
GraphBuilder.QueryInterface(IID_IVideoWindow, VideoWindow);

MediaEventEx.SetNotifyWindow(Self.Handle, WM_GRAPHNOTIFY, 0);

CaptureGraphBuilder.SetFiltergraph(GraphBuilder);

//设备枚举
HR := CoCreateInstance (CLSID_SystemDeviceEnum, nil, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, CreateDevEnum);
if not Succeeded(HR) then
Exit;
CreateDevEnum.CreateClassEnumerator(CLSID_VideoInputDeviceCategory, EnumMoniker, 0);
if EnumMoniker = nil then
Exit;
if EnumMoniker.Next(1, Moniker, cFetched) = S_OK then

begin

Moniker.BindToObject(nil, nil, IID_IBaseFilter, BaseFilter);
Moniker := nil;
end
else
Exit;

//将设备添加到graph
HR := GraphBuilder.AddFilter(BaseFilter, 'Video Capture');
if not Succeeded(HR) then
Exit;
//连接源...
HR := CaptureGraphBuilder.RenderStream(nil, nil, BaseFilter, nil, nil);
if not Succeeded(HR) then
Exit;
//视频窗口...
HR := VideoWindow.put_Owner(Self.Handle);
if not Succeeded(HR) then
Exit;
HR := VideoWindow.put_WindowStyle(WS_CHILD and WS_CLIPCHILDREN);
if not Succeeded(HR) then
Exit;
VideoWindow.SetWindowPosition(0, 0, 640, 480);
VideoWindow.put_Visible(True);
//
MediaControl.Run;
finally
Self.Caption := DebugMsg;
end;

end;


procedure TVideoForm.FormDestroy(Sender: TObject);
begin

CaptureGraphBuilder := nil;
GraphBuilder := nil;
MediaControl := nil;
MediaEventEx := nil;
VideoWindow := nil;
CreateDevEnum := nil;
EnumMoniker := nil;
end;


end.
 
帮你顶一下
 
自己顶一下
 
{设置采集分辩率...}
function TVideoForm.SetCaptureScale(AMStreamConfig : IAMStreamConfig;
xScale, yScale : integer) : HResult;
var
iFormat, iCount, iSize : integer;
VideoStreamConfigCaps : TVideoStreamConfigCaps;
AMMediaType : TAMMediaType;
VIDEOINFOHEADER : PVIDEOINFOHEADER;
begin

if AMStreamConfig = nil then
Exit;

AMStreamConfig.GetNumberOfCapabilities(iCount, iSize);
if iSize = SizeOf(VIDEO_STREAM_CONFIG_CAPS) then

for iFormat := 0 to iCount - 1do

begin

//New(AMMediaType);
//New(VideoStreamConfigCaps);
Result := AMStreamConfig.GetStreamCaps(iFormat, @AMMediaType, VideoStreamConfigCaps);
if SUCCEEDED(Result) then

begin

if IsEqualGUID(AMMediaType.majortype , MEDIATYPE_Video) and
IsEqualGUID(AMMediaType.subtype , MEDIASUBTYPE_RGB24) and
IsEqualGUID(AMMediaType.formattype, FORMAT_VideoInfo) and
(AMMediaType.cbFormat >= SizeOf(VIDEOINFOHEADER)) and
(AMMediaType.pbFormat <> nil) then

begin

//ShowMessage('aa');
//New(VIDEOINFOHEADER);
VIDEOINFOHEADER := PVIDEOINFOHEADER(AMMediaType.pbFormat);
// 设置 VIDEOINFOHEADER 格式
VIDEOINFOHEADER.bmiHeader.biWidth := xScale;
VIDEOINFOHEADER.bmiHeader.biHeight := yScale;
Result := AMStreamConfig.SetFormat(AMMediaType);
//Dispose(VIDEOINFOHEADER);
if SUCCEEDED(Result) then

begin

DeleteMediaType(AMMediaType);
Break;
end;

end;
//if...
// 删除对象
ShowMessage('bb');
DeleteMediaType(AMMediaType);
end;
//if...
//Dispose(AMMediaType);
//Dispose(VideoStreamConfigCaps);
end;
//if...for...
end;

=========
再帮忙看看这段代码。
 
............................
 
给你2段我的代码吧,pGB,pCGB,
ConnectDevice(bool bOverlay, HWND hParent)//bOverlay是否用overlay播放
//hParent父窗口的句柄
{
// Create the Capture Graph Builder.
HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICaptureGraphBuilder2,
(void**)&amp;pCGB);
if (SUCCEEDED(hr))
{
// Create the Filter Graph Manager.
hr = CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void **)&amp;pGB);
if (SUCCEEDED(hr))
{
// Initialize the Capture Graph Builder.
pCGB->SetFiltergraph(pGB);
}
else

{
pGB ->Release();
pCGB->Release();
return hr;
}
}
else

{
return hr;
// Failed
}

IMediaControl *pControl;

hr = pGB->QueryInterface(IID_IMediaControl, (void **)&amp;pControl);
pControl->Stop();

if(!SUCCEEDED(hr))
{
return hr;
}

ICreateDevEnum *pSysDevEnum = NULL;
//System Device Enumerator
// Create the System Device Enumerator.
hr = CoCreateInstance(CLSID_SystemDeviceEnum,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum,
reinterpret_cast<void**>(&amp;pSysDevEnum));
IEnumMoniker *pMonikerEnum = NULL;
//Moniker Enumerator
if (SUCCEEDED(hr))
{
// Create an enumerator for the video capture category.
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
&amp;pMonikerEnum, 0);
}
else

{
return hr;
}
IMoniker *pMoniker = NULL;
//The Current Device
pMonikerEnum->Next(1, &amp;pMoniker, NULL);//第一个捕捉设备
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&amp;pSourceFilter);
if (SUCCEEDED(hr))
{
hr = pGB->AddFilter(pSourceFilter, L"Capture Filter");
}

//if use overlay
if (bOverlay==true)
{
IBaseFilter *pOverlay = NULL;
CoCreateInstance(CLSID_OverlayMixer,
NULL,
CLSCTX_INPROC,
IID_IBaseFilter,
(LPVOID*)&amp;pOverlay);
pGB->AddFilter(pOverlay, L"Overaly Mixer");
hr = pCGB->RenderStream(&amp;PIN_CATEGORY_PREVIEW,
&amp;MEDIATYPE_Video,
pSourceFilter,
pOverlay'
NULL);
pOverlay->Release();


}
else

{
hr = pCGB->RenderStream(&amp;PIN_CATEGORY_PREVIEW,
&amp;MEDIATYPE_Video,
pSourceFilter,
NULL,
NULL);

}
//Set Output Format
IAMStreamConfig *pConfig = NULL;
pCGB->FindInterface(&amp;PIN_CATEGORY_PREVIEW, // Preview pin.
0, // Any media type.
pSourceFilter, // Pointer to the capture filter.
IID_IAMStreamConfig,
(void**)&amp;pConfig);
AM_MEDIA_TYPE *pmtConfig;
pConfig->GetFormat(&amp;pmtConfig);
if(bOverlay==true)
{
pmtConfig->subtype = MEDIASUBTYPE_YUY2;
}
else

{
pmtConfig->subtype = MEDIASUBTYPE_RGB24;
}
pConfig->SetFormat(pmtConfig);
DeleteMediaType(pmtConfig);
//Set videowindow rect
RECT rc;
GetClientRect(hParent, &amp;rc);
SetVideoWindow(0, hParent, rc);//自定义的


pControl->Run();
pMoniker->Release();
pMonikerEnum->Release();
pSysDevEnum->Release();
pControl->Release();

return hr;
}

SetVideoWindow(HWND hParent, RECT rc)
{ //Set videowindow owner
IMediaControl *pControl;
HRESULT hr = pGB->QueryInterface(IID_IMediaControl, (void **)&amp;pControl);
pControl->Stop();
IVideoWindow *pVideoWindow = NULL;
hr = pGB->QueryInterface(IID_IVideoWindow, (void **)&amp;pVideoWindow);
pVideoWindow->put_Visible(OAFALSE);
pVideoWindow->put_Owner(NULL);
pVideoWindow->put_Owner((OAHWND)hParent);
pVideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
pVideoWindow->SetWindowPosition(0, 0, rc.right, rc.bottom);
pVideoWindow->put_Visible(OATRUE);

//Set Output Format
IAMStreamConfig *pConfig = NULL;
pCGB->FindInterface(
&amp;PIN_CATEGORY_PREVIEW, // Preview pin.
0, // Any media type.
pSourceFilter, // Pointer to the capture filter.
IID_IAMStreamConfig, (void**)&amp;pConfig);
AM_MEDIA_TYPE *pmtConfig;
pConfig->GetFormat(&amp;pmtConfig);
VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
pVih->bmiHeader.biWidth = rc.right;//分辨率的宽
pVih->bmiHeader.biHeight = rc.bottom;//分辨率的高
pVih->bmiHeader.biSizeImage = DIBSIZE(pVih->bmiHeader);
pConfig->SetFormat(pmtConfig);
MyDeleteMediaType(pmtConfig);
pControl->Run();

pConfig->Release();
pControl->Release();
pVideoWindow->Release();

return hr;
}

我试过了,没问题的,将按照你设置的大小播放视频,就是那个RECT rc参数
 
谢谢大家这段时间对此问题的关注,小弟在此问题上已经取得一定进展,但还没有完全搞定。
现在,视频尺寸的问题小弟已经解决。静态图像的抓取也可以实现,在动态视频的采集上,还有一点问题。
先说说怎么解决视频尺寸和Play时图像的闪烁的问题,以让有这方面困惑的朋友作作参考。在Play以前,要设置很多东西,比如视频制式、色深、视频尺寸等,不然就有可能出现视频闪烁现像,得不到很清晰的图像。视置视频尺寸的代码在DFW上其实有,只是要注意一点,用IcaptureGraphBuilder2调用FindInterface查找IAMStreamConfig接口时,第一个参数和其后调用的RenderStream的第一个参数应该一样。设置制式和色深的方法,在SDK有。
现在小弟的问题是:在PIN_CATEGORY_PREVIEW、768 X 576下,图像很流畅很清晰,而且没马赛克。在PIN_CATEGORY_Capture下,如果只设置色深和制式,可以采集成AVI,但有马赛克,如果设置视频尺寸为768 X 576,则不能采集。请问是啥原因?
还有,请问RenderStream(@PIN_CATEGORY_CAPTURE, nil, VideoSourceFilter as IBaseFilter,nil, multiplexer as IBaseFilter)中的倒数第二个参数应该是一个压缩filter,应该怎么使用这个filter呢?比如说,如果我想使用MPG4算法,应该怎么做?
谢谢大家!国庆节快到了,先祝大家国庆快乐!
:-)
 
在PIN_CATEGORY_Capture下的马赛克问题已搞定,解决方法是用TVideoWindowEx,而不是用TVideoWindow。

现在,小弟只差Decoder与保存回放了,请大家继续发言。。。。。
 
怎么没人说话?

就只差一点了,视频压缩。。。。
 
中间的哪个参数其实也是一个filter,你可以看看你的机子上装了那些编码的filter然后在把他们加到Graph里面,在render里面连上就可以了
 
TO jemyzhang:小弟也知道那是一个filter。昨天我看了DX SDK,上面说在Encoder的时候,先枚举系统中的编码器,再选择一个加到Graph中。这样,就需要用户去选择压缩编码器。但有些最终用户根本不懂这些,不知道怎么选择。所以,我想固定使用一种编码器。现在有两个选择:H.263与MPG4。但不我知道用哪一个更合适,也不知道怎么安装这两编码器,怎么使用它。
jemyzhang兄,可否给点思路?希望大家多给意见。。
 
这两个编码器用哪个只能你自己选择,在枚举的时候通过他的名字来确定你要用的那个就可以了,至于怎么用你可以看看dx sdk的GraphEdit来看这个链怎么连接的,你就那样连。其他的事就交给Graph做吧
 
To jemyzhang:谢谢,我先试试。
大家可否告诉一下H.263与MPG4各自的优缺点?也好让小弟作一个正确的选择。小弟现在PIN_CATEGORY_PREVIEW下分辩率是768 X 576,在Capture下,显示还是768 X 576,输出到文件是320 X 240吧。我想在压缩以后存到数据库中,并可以以768 X 576回放,回放时要求图像很清晰。
在这样的要求下,应该选用哪一种压缩算法好呢?还有,请问H.263和MPEG4的Encoder哪里有下载,谢谢了。。。
 
怎么没有反应了?哪位大哥帮帮忙,分不够可以再加的。
小弟看了DX SDK,它上面是这样说的:
Encoding the Video Stream
================
You can encode the video stream by inserting an encoder filter between the capture filter and the AVI Mux filter. Use the System Device Enumerator or the Filter Mapper to select an encoder filter. (For more information, see Enumerating Devices and Filters.)

Specify the encoder filter as the fourth parameter to RenderStream, shown in bold in the following example:

IBaseFilter *pEncoder;
/* Create the encoder filter (not shown). */
// Add it to the filter graph.
pGraph->AddFilter(pEncoder, L"Encoder);

/* Call SetOutputFileName as shown previously. */

// Render the stream.
hr = pBuild->RenderStream(&amp;PIN_CATEGORY_CAPTURE, &amp;MEDIATYPE_Video,
pCap, pEncoder, pMux);
pEncoder->Release();

The encoder filter might support IAMVideoCompression or other interfaces for setting the encoding parameters. For a list of possible interfaces, see File Encoding and Decoding Interfaces.
小弟照着这样做,但不成功。不知道是什么原因。小弟现在用的Encoder是Microsoft H.263 Video Codec。
 
AVI Mux filter你加没有,
不成功哪有什么反应。
 
现在MPG4可以了,但H.263不行。
 
用 avphone 的话一切都很简单:

http://www.banasoft.net/AVPhone.htm

其中包含 avicq Delphi 源码示例。
 
avphone能实现768 X 576下很流畅很清析的视频采集吗?
 
本来以为搞定了,原来还是没有搞定!哪位老兄帮我再看看,300大洋送上。
我想请问:设置分辩率、色深等都要用到IAMStreamConfig接口,查询这个IAMStreamConfig方法如下:
FindInterface(@PIN_CATEGORY_PREVIEW, @MEDIATYPE_Video, Filter as IBaseFilter, IID_IAMStreamConfig, AMStreamConfig);
现在,如果在PREVIEW和Capture同时进行时,FindInterface的第一个参数应该用@PIN_CATEGORY_PREVIEW,还是该用@PIN_CATEGORY_CAPTURE?或是对两者都生成一个IAMStreamConfig接口,两个IAMStreamConfig接口都设置分辩率、色深等?
 

Similar threads

D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
顶部