我有一个带有Visual C ++ SDK的视频采集卡。在SDK的回调中,我可以以30 fps的速度使用彩色帧(640 x 480)。目前,我正在将整个图像序列作为单独的bmp文件一次写出一个单独的线程 - 一小时内是108,000个文件,或者每小时大约100 GB,这是不可管理的。我想将这些传入的帧推送到一个AVI文件,而不是可选的压缩。我从哪里开始?到目前为止,浏览MSDN DirectShow文档让我很困惑。那里有更好的例子吗? OpenCV是答案吗?我看了一些例子,但我不确定OpenCV是否会将该卡识别为捕获设备,我也不了解它是如何识别捕获设备的。另外,我已经在中获取了框架,我只需要将它们 out 放到一些不支持我的生产者线程的消费者线程中的AVI中。谢谢你的帮助。
答案 0 :(得分:1)
我之前使用过CAviFile。它工作得很好,我不得不稍微调整它以允许用户选择编解码器。我从CAviGenerator获取了该代码。 CAviFile的界面非常简单,下面是一些示例代码:
CAviFile *Avi = new CAviFile(fileName.c_str(), 0, 10);
HRESULT res = Avi->AppendNewFrame(Width, Height, ImageBuffer, BitsPerPixel);
if (FAILED(res))
{
std::cout << "Error recording AVI: " << Avi->GetLastErrorMessage() << std::endl;
}
delete Avi;
显然你必须确保你的ImageBuffer包含正确格式的数据等。但是一旦我得到了那些东西,所有整理好了。
答案 1 :(得分:0)
您可以使用Video for Windows或DirectShow。每个都有自己的编解码器。 (并且可以延长)
虽然微软认为VfW已被弃用,但它仍然完全可用,并且比DirectShow更容易设置。
答案 2 :(得分:0)
您需要将AVI Mux(CLSID_AviDest)连接到您的捕获卡。然后,您需要附加一个文件编写器(CLSID_FileWriter),它会为您写出一切。
不可否认设置捕获图并不一定容易,因为DirectShow会让你跳过一百万个箍。
使用ICaptureGraphBuilder2界面更容易。值得庆幸的是,微软已经给出了如何做到这一点的非常好的概述......
http://msdn.microsoft.com/en-us/library/dd318627.aspx
添加编码器并不容易,并且方便地在该链接中进行掩饰。
这是一个如何枚举我为我的MFC应用程序编写的系统中所有视频压缩器的示例。
BOOL LiveInputDlg::EnumerateVideoCompression()
{
CComboBox* pVideoCompression = (CComboBox*)GetDlgItem( IDC_COMBO_VIDEOCOMPRESSION );
pVideoCompression->SetExtendedUI( TRUE );
pVideoCompression->SetCurSel( pVideoCompression->AddString( _T( "<None>" ) ) );
ICreateDevEnum* pDevEnum = NULL;
IEnumMoniker* pEnum = NULL;
HRESULT hr = S_OK;
hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pDevEnum );
if ( FAILED( hr ) )
{
return FALSE;
}
hr = pDevEnum->CreateClassEnumerator( CLSID_VideoCompressorCategory, &pEnum, 0 );
pDevEnum->Release();
if ( FAILED( hr ) )
{
return FALSE;
}
if ( pEnum )
{
IMoniker* pMoniker = NULL;
hr = pEnum->Next( 1, &pMoniker, NULL );
while( hr == S_OK )
{
IPropertyBag* pPropertyBag = NULL;
hr = pMoniker->BindToStorage( NULL, NULL, IID_IPropertyBag, (void**)&pPropertyBag );
if ( FAILED( hr ) )
{
pMoniker->Release();
pEnum->Release();
return FALSE;
}
VARIANT varName;
VariantInit( &varName );
hr = pPropertyBag->Read( L"Description", &varName, NULL );
if ( FAILED( hr ) )
{
hr = pPropertyBag->Read( L"FriendlyName", &varName, NULL );
if ( FAILED( hr ) )
{
pPropertyBag->Release();
pMoniker->Release();
pEnum->Release();
return FALSE;
}
}
IBaseFilter* pBaseFilter = NULL;
pMoniker->BindToObject( NULL, NULL, IID_IBaseFilter, (void**)&pBaseFilter );
{
USES_CONVERSION;
TCHAR* pName = OLE2T( varName.bstrVal );
int index = pVideoCompression->AddString( pName );
pVideoCompression->SetItemDataPtr( index, pMoniker );
VariantClear( &varName );
pPropertyBag->Release();
}
hr = pEnum->Next( 1, &pMoniker, NULL );
}
pEnum->Release();
}
return TRUE;
}
祝你好运! :)