最初,我开始寻找一个示例,说明由于性能不佳,我如何在c ++ Builder中使用FFMPEG创建一个应用程序以从USB捕获设备进行录制并播放视频
我尝试了使用DirectShow的Mitov组件,Datastead,FFMPEGVCL和Winsoft相机,但是它们的捕获性能似乎很差。
我需要以60fps的速度捕获1920x1080的压缩格式,然后以正常速度和慢速播放。
我发现DirectShow本身有很多限制,可以通过添加FFMPEG之类的东西来改善这些限制,但是最终添加PC硬件,尤其是HDD和处理器限制捕获功能。
1920x1080 60fps基本上是DirectShow的高端产品,因此您需要具有最佳性能的硬件才能实现这种性能。@ Spektre好心地给我提供了使用API Direct的DirectShow示例,这些示例可以与购买的组件进行比较。
使用此方法并将其与组件进行比较,我发现MITOV在较大的视频尺寸和帧频方面存在一个主要问题。使用此1920x108,可以预览30fps和60fps,但它们在视频源和预览之间会有很大的延迟(5或6秒)。其他组件的执行类似于API直接方法,只是性能略有不同。没有任何一种压缩过滤器可以捕获和记录1920x108 60fps,而没有大的帧丢失和非常生硬的预览。
答案 0 :(得分:1)
我认为您的问题不是视频捕获组件本身还是FFMPEG。主要问题是从摄像机获取图像的 Directshow 和 VFW API 相对较慢。可以通过设置适当的图像格式来提高速度,例如:
没有 JPEG 输出格式,即使在小分辨率下,我也无法通过 15 fps 。我的经验还表明, DirectShow 比 VFW 慢一点(至少对于我的相机而言)。但是,并非所有相机都提供 VFW 驱动程序:(不再。
还请确保使用正确版本的 USB端口来确保 USB带宽,并且不要减少与同一HUB上其他设备的带宽!
这就是我在Borland / Embarcadero BDS 2006 C ++中用于摄像机捕获(几年前编码的 VFW )的作用:
VideoCaptureVFW.h:
//---------------------------------------------------------------------------
//--- VFW Video Capture ver: 2.0 --------------------------------------------
//---------------------------------------------------------------------------
#ifndef _VideoCaptureVFW_h
#define _VideoCaptureVFW_h
//---------------------------------------------------------------------------
#include <vfw.h>
#include <jpeg.hpp>
#include <Clipbrd.hpp>
//---------------------------------------------------------------------------
const int _vfw_callbach_onframe=1; // bit mask for each callback
//---------------------------------------------------------------------------
#ifndef _TDirectMemoryStream
#define _TDirectMemoryStream
class TDirectMemoryStream:TMemoryStream // just for accessing protected SetPointer
{
public:
void SetMemory(BYTE *ptr,DWORD siz) { SetPointer(ptr,siz); Position=0; };
};
#endif
//---------------------------------------------------------------------------
#ifndef _avgfps
#define _avgfps
class avgfps
{
public:
int N,N2;
int frame,frame0;
double fps,t0,t1,dt,Ts;
avgfps()
{
N=40; N2=N<<1;
fps=0.0; t0=0.0; frame=0; frame0=0;
LARGE_INTEGER i;
QueryPerformanceFrequency(&i); Ts=1.0/double(i.QuadPart);
}
~avgfps() {}
void update()
{
double t;
LARGE_INTEGER i;
QueryPerformanceCounter(&i); t=double(i.QuadPart)*Ts; dt=t-t0;
if (frame<=0)
{
t0=t; t1=t;
dt=0.0;
frame=0;
frame0=0;
}
if (dt>1e-6) fps=double(frame0)/dt; else fps=0.0;
frame++; frame0++;
if (frame0==N ) t1=t;
if (frame0==N2) { t0=t1; t1=t; frame0=N; }
}
};
#endif
//---------------------------------------------------------------------------
class VideoCaptureVFW
{
private:
HWND hcap,hown; // video capture window
public:
int ins_ix,ins_use; // instance index and usage for callbacks class reference
CAPDRIVERCAPS driver_cp; // driver capabilities
CAPTUREPARMS capture; // capture setup
CAPSTATUS state;
BITMAPINFO format;
// on frame callback
avgfps fps; // average fps
TMemoryStream *mem; // just for loading jpg from memory without copy
Graphics::TBitmap *bmp; // grabbed frame
VideoCaptureVFW();
~VideoCaptureVFW();
void ins_rst();
void ins_inc();
void ins_dec();
void set_owner(HWND _hown);
AnsiString get_video_drivers();
void set_video_driver(int ix);
void dlg_source() { if(driver_cp.fHasDlgVideoSource) capDlgVideoSource(hcap); }
void dlg_format() { if(driver_cp.fHasDlgVideoFormat) capDlgVideoFormat(hcap); get_state(); get_format(); }
void dlg_display(){ if(driver_cp.fHasDlgVideoDisplay)capDlgVideoDisplay(hcap);}
void dlg_compress() { capDlgVideoCompression(hcap); }
void get_capabil(){ capDriverGetCaps (hcap,&driver_cp,sizeof(CAPDRIVERCAPS)); }
void get_setup() { capCaptureGetSetup(hcap,&capture,sizeof(CAPTUREPARMS)); }
void set_setup() { capCaptureSetSetup(hcap,&capture,sizeof(CAPTUREPARMS)); }
void get_state() { capGetStatus (hcap,&state,sizeof(CAPSTATUS)); }
void get_format() { capGetVideoFormat (hcap,&format,sizeof(BITMAPINFO)); }
void preview_start(){ capPreview(hcap,TRUE ); }
void preview_stop() { capPreview(hcap,FALSE); }
void grab_start() { set_callback_on_frame(); capGrabFrameNoStop(hcap); }
void grab_stop() { res_callback_on_frame(); }
void copy_to_clipboard() { capEditCopy(hcap); }
void set_callback_on_frame();
void res_callback_on_frame();
LRESULT _on_frame(HWND hwnd,LPVIDEOHDR hdr);
void (*on_frame)(VideoCaptureVFW &cap);
};
//---------------------------------------------------------------------------
// on frame
const int _VideoCaptureVFW_ins=32;
void* VideoCaptureVFW_ins[_VideoCaptureVFW_ins]=
{
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
};
int VideoCaptureVFW_ins_get()
{
for (int i=0;i<_VideoCaptureVFW_ins;i++)
if (VideoCaptureVFW_ins[i]==NULL) return i;
return -1;
}
LRESULT PASCAL VideoCaptureVFW00_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 0]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW01_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 1]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW02_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 2]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW03_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 3]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW04_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 4]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW05_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 5]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW06_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 6]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW07_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 7]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW08_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 8]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW09_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 9]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW10_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[10]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW11_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[11]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW12_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[12]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW13_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[13]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW14_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[14]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW15_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[15]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW16_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[16]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW17_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[17]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW18_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[18]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW19_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[19]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW20_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[20]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW21_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[21]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW22_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[22]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW23_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[23]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW24_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[24]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW25_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[25]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW26_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[26]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW27_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[27]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW28_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[28]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW29_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[29]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW30_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[30]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW31_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[31]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL(*VideoCaptureVFW_on_frame[_VideoCaptureVFW_ins])(HWND hwnd,LPVIDEOHDR hdr)=
{
VideoCaptureVFW00_on_frame,
VideoCaptureVFW01_on_frame,
VideoCaptureVFW02_on_frame,
VideoCaptureVFW03_on_frame,
VideoCaptureVFW04_on_frame,
VideoCaptureVFW05_on_frame,
VideoCaptureVFW06_on_frame,
VideoCaptureVFW07_on_frame,
VideoCaptureVFW08_on_frame,
VideoCaptureVFW09_on_frame,
VideoCaptureVFW10_on_frame,
VideoCaptureVFW11_on_frame,
VideoCaptureVFW12_on_frame,
VideoCaptureVFW13_on_frame,
VideoCaptureVFW14_on_frame,
VideoCaptureVFW15_on_frame,
VideoCaptureVFW16_on_frame,
VideoCaptureVFW17_on_frame,
VideoCaptureVFW18_on_frame,
VideoCaptureVFW19_on_frame,
VideoCaptureVFW20_on_frame,
VideoCaptureVFW21_on_frame,
VideoCaptureVFW22_on_frame,
VideoCaptureVFW23_on_frame,
VideoCaptureVFW24_on_frame,
VideoCaptureVFW25_on_frame,
VideoCaptureVFW26_on_frame,
VideoCaptureVFW27_on_frame,
VideoCaptureVFW28_on_frame,
VideoCaptureVFW29_on_frame,
VideoCaptureVFW30_on_frame,
VideoCaptureVFW31_on_frame,
};
//---------------------------------------------------------------------------
VideoCaptureVFW::VideoCaptureVFW()
{
hcap=NULL;
hown=NULL;
ins_ix=-1; ins_use=0;
on_frame=NULL;
mem=new TMemoryStream();
bmp=new Graphics::TBitmap;
}
//---------------------------------------------------------------------------
VideoCaptureVFW::~VideoCaptureVFW()
{
capDriverDisconnect(hcap);
res_callback_on_frame();
if (mem) delete mem;
if (bmp) delete bmp;
}
//---------------------------------------------------------------------------
void VideoCaptureVFW::set_owner(HWND _hown)
{
hown=_hown;
hcap=capCreateCaptureWindow("",WS_CHILD|WS_VISIBLE,0,0,1,1,hown,1);
}
//---------------------------------------------------------------------------
AnsiString VideoCaptureVFW::get_video_drivers()
{
const int _size=256;
char drv_name[_size];
char drv_ver[_size];
char dev_name[_size];
AnsiString s0,s1,list;
int i;
list="";
for (i=0;;i++)
{
if (!capGetDriverDescription(i,drv_name,_size,drv_ver,_size)) break;
s0=drv_name;
s1=drv_ver;
list+=s0+" "+s1+"\n";
}
return list;
}
//---------------------------------------------------------------------------
void VideoCaptureVFW::set_video_driver(int ix)
{
if (hcap==NULL) return;
capDriverConnect(hcap,ix);
capDriverGetCaps(hcap,&driver_cp,sizeof(CAPDRIVERCAPS));
capCaptureGetSetup(hcap,&capture,sizeof(CAPTUREPARMS));
// capture.dwRequestMicroSecPerFrame=10; // 1/fps [us]
capCaptureSetSetup(hcap,&capture,sizeof(CAPTUREPARMS));
capPreviewRate(hcap,1); // set preview [ms]
capPreviewScale(hcap,FALSE); // stretching off
//preview_start();
}
//---------------------------------------------------------------------------
void VideoCaptureVFW::set_callback_on_frame()
{
if (ins_ix<0) ins_ix=VideoCaptureVFW_ins_get();
if (ins_ix<0) return;
VideoCaptureVFW_ins[ins_ix]=this;
ins_use|=_vfw_callbach_onframe;
capSetCallbackOnFrame(hcap,(void*)(VideoCaptureVFW_on_frame[ins_ix]));
}
//---------------------------------------------------------------------------
void VideoCaptureVFW::res_callback_on_frame()
{
if (ins_ix<0) return;
if (int(ins_use&_vfw_callbach_onframe))
{
ins_use^=_vfw_callbach_onframe;
capSetCallbackOnFrame(hcap,NULL);
}
if (ins_use) return;
VideoCaptureVFW_ins[ins_ix]=NULL;
ins_ix=-1;
}
//---------------------------------------------------------------------------
LRESULT VideoCaptureVFW::_on_frame(HWND hwnd,LPVIDEOHDR hdr)
{
fps.update();
int e=0;
if (hdr->dwBytesUsed<16) return 0; // ignore too small images
((TDirectMemoryStream*)(mem))->SetMemory(hdr->lpData,hdr->dwBytesUsed);
if ((hdr->lpData[6]=='J') // JPEG signature
&&(hdr->lpData[7]=='F')
&&(hdr->lpData[8]=='I')
&&(hdr->lpData[9]=='F'))
{
e=1;
TJPEGImage *jpg=new TJPEGImage;
jpg->LoadFromStream(mem);
bmp->Assign(jpg);
delete jpg;
} else
if ((hdr->lpData[0]=='B') // BMP signature
&&(hdr->lpData[1]=='M'))
{
e=1;
bmp->LoadFromStream(mem);
}
else{ // others
e=1;
copy_to_clipboard();
try {
bmp->LoadFromClipboardFormat(CF_BITMAP,Clipboard()->GetAsHandle(CF_BITMAP),NULL);
}
catch(char *str)
{
e=0;
int hnd=FileCreate("unsuproted_format.dat");
FileWrite(hnd,hdr->lpData,hdr->dwBytesUsed);
FileClose(hnd);
}
}
if (e)
{
if (on_frame) on_frame(*this);
}
return 0;
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
我有一个带有此源代码的小型测试应用程序:
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
// select API:
#define _capture_VFW
// #define _capture_DirectShow
//---------------------------------------------------------------------------
#ifdef _capture_VFW
#include "VideoCaptureVFW.h"
#endif
#ifdef _capture_DirectShow
#include "DirectX92\\VideoCaptureDirectShow.cpp"
#endif
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
Graphics::TBitmap *bmp=new Graphics::TBitmap;
int _callback=0;
int _frame=0;
int _update=false;
//---------------------------------------------------------------------------
#ifdef _capture_VFW
VideoCaptureVFW vfw;
void on_frame_VFW(VideoCaptureVFW &cap)
{
if (_callback) Form1->Canvas->Draw(0,26,cap.bmp);
else if (!_frame) { bmp->Assign(cap.bmp); _frame=1; }
}
#endif
//---------------------------------------------------------------------------
#ifdef _capture_DirectShow
VideoCaptureDirectShow dsh;
void on_frame_DirectShow(VideoCaptureDirectShow &cap)
{
if (_callback) Form1->Canvas->Draw(0,26,cap.bmp);
else if (!_frame) { bmp->Assign(cap.bmp); _frame=1; }
}
#endif
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
#ifdef _capture_VFW
pan_VFW->Visible=true;
vfw.set_owner(this->Handle);
cb_driver->Items->Clear();
cb_driver->Items->Text=vfw.get_video_drivers();
cb_driver->ItemIndex=0;
vfw.on_frame=on_frame_VFW;
vfw.set_video_driver(cb_driver->ItemIndex);
vfw.grab_start();
#endif
#ifdef _capture_DirectShow
pan_DirectShow->Visible=true;
cb_device->Items->Clear();
cb_device->Items->Text=dsh.get_devices();
dsh.on_frame=on_frame_DirectShow;
_update=1;
cb_device->ItemIndex=0;
_update=0;
cb_device->OnChange(this);
/*
dsh.Select(0);
dsh.Start();
dsh.Stop();
*/
#endif
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
#ifdef _capture_VFW
vfw.grab_stop();
#endif
#ifdef _capture_DirectShow
dsh.Stop();
#endif
delete bmp;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
if ((!_callback)&&(_frame)) { Canvas->Draw(0,26,bmp); _frame=0; }
#ifdef _capture_VFW
Caption=AnsiString().sprintf("frame: %2i fps: %2.1lf",vfw.fps.frame,vfw.fps.fps);
#endif
#ifdef _capture_DirectShow
Caption=AnsiString().sprintf("frame: %2i fps: %2.1lf",dsh.fps.frame,dsh.fps.fps);
#endif
}
//---------------------------------------------------------------------------
//--- VFW -------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::bt_dialog_sourceClick(TObject *Sender)
{
#ifdef _capture_VFW
vfw.dlg_source();
#endif
}
void __fastcall TForm1::bt_dialog_formatClick(TObject *Sender)
{
#ifdef _capture_VFW
vfw.dlg_format();
#endif
}
void __fastcall TForm1::bt_dialog_displayClick(TObject *Sender)
{
#ifdef _capture_VFW
vfw.dlg_display();
#endif
}
void __fastcall TForm1::cb_driverChange(TObject *Sender)
{
#ifdef _capture_VFW
vfw.set_video_driver(cb_driver->ItemIndex);
vfw.grab_start();
#endif
}
//---------------------------------------------------------------------------
//--- DirectShow ------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::cb_deviceChange(TObject *Sender)
{
#ifdef _capture_DirectShow
if (_update) return;
_update=1;
dsh.Select(cb_device->ItemIndex);
cb_format->Items->Clear();
cb_format->Items->Text=dsh.get_formats();
if (cb_format->Items->Count)
cb_format->ItemIndex=0;
_update=0;
cb_format->OnChange(this);
#endif
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cb_formatChange(TObject *Sender)
{
#ifdef _capture_DirectShow
if (_update) return;
_update=1;
dsh.set_format(cb_format->Text);
_update=0;
#endif
}
//---------------------------------------------------------------------------
它的单一表单应用程序,几乎没有按钮以及对话框和配置的组合框列表(您可以模仿或忽略它们)。不能共享DirectShow,因为它太大了,不能超过30K,但速度较慢(但是ist只是一个头文件+ lib文件,没有第3方组件)。我在表单上有这些VCL组件:
TTimer *Timer1; // 10ms info text update
TPanel *pan_VFW; // just to hold the components for VFW
TSpeedButton *bt_dialog_source; // these 3 buttons configure VFW ...
TSpeedButton *bt_dialog_format;
TSpeedButton *bt_dialog_display;
TComboBox *cb_driver; // this selects VFW device
TPanel *pan_DirectShow; // just to hold DirectShow components
TComboBox *cb_device; // this selects DirectShow device
TComboBox *cb_format; // this selects DirectShow format
我将 VFW 和 DirectShow 内容封装到配置#define
中,因此您可以完全忽略 DirectShow 内容。
现在,使用此功能时,您可以使用分辨率和格式进行播放,以将fps与您的 DirectShow 组件抓取器进行比较。
如您所见,我不需要使用任何第三方组件从相机抓取图像数据,VideoCaptureVFW.h
是您唯一需要的东西。
[Edit1]
此处是指向Demo的链接,其中包含Embarcadero BDS2006 C ++中的VFW
和DirectShow
示例(源代码和Win32二进制文件)。
[Edit2]您不受支持的格式
文件大小恰好为1920*1080*3
字节,表明原始的24bpp RGB提要。当我尝试对其进行可视化处理时(是的,Y翻转了),请参见该代码(这次表单上没有任何组件):
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
Graphics::TBitmap *bmp=NULL;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
int xs=1920,ys=1080,x,y,a,hnd,siz;
BYTE *p,*dat=NULL;
// load frame
hnd=FileOpen("maybe_RGB24.dat",fmOpenRead);
siz=FileSeek(hnd,0,2); dat=new BYTE[siz];
FileSeek(hnd,0,0);
FileRead(hnd,dat,siz);
FileClose(hnd);
// convert RGB24 to 32bpp bitmap
bmp=new Graphics::TBitmap;
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
bmp->SetSize(xs,ys);
for (a=0,y=ys-1;y>=0;y--) // flip y
{
p=(BYTE*)bmp->ScanLine[y];
for (x=0;x<xs;x++)
{
p[0]=dat[a]; a++;
p[1]=dat[a]; a++;
p[2]=dat[a]; a++;
p[3]=0;
p+=4;
}
}
delete dat;
// resize form
ClientWidth=xs;
ClientHeight=ys;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
if (bmp) delete bmp; bmp=NULL;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
Canvas->Draw(0,0,bmp);
}
//---------------------------------------------------------------------------
以及出现的屏幕:
请注意,我将文件名重命名为maybe_RGB24.dat
。您可以仅通过帧大小来解码此文件格式,但其信息应类似于
AM_MEDIA_TYPE* mt;
结构,但不要问我,我很早以前在哪里编写代码,因为我很久以前就编写了此代码,因此不使用 DirectX ,因为(因为我过去的所有尝试都显示出其与众不同的劣势api的声音或gfx或抓取都没有关系...)