1

我有一个带有 SDK for Visual C++ 的视频采集卡。在 SDK 的回调中,我可以以 30 fps 的速度使用彩色帧 (640 x 480)。目前,我正在将整个图像序列作为单独的 bmp 文件一次写入一个单独的线程中——即一小时内 108,000 个文件,或每小时约 100 GB,这是无法管理的。我想将这些传入的帧推送到一个 AVI 文件,而不是可选压缩。我什至从哪里开始?到目前为止,翻阅 MSDN DirectShow 文档让我感到困惑。那里有更好的例子吗?OpenCV 是答案吗?我看过一些例子,但我不确定 OpenCV 是否会将卡识别为捕获设备,我也不明白它是如何识别捕获设备的。另外,我已经把框架放进去,我只需要将它们放在一些不支持我的生产者线程的消费者线程中的 AVI 中。谢谢你的帮助。

4

3 回答 3

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 包含正确格式的数据等。但是一旦我把这些东西都整理好,它就很好用了。

于 2009-07-22T18:01:39.183 回答
0

您可以使用 Video for Windows 或 DirectShow。每个都有自己的编解码器集。(并且可以扩展)

尽管微软认为 VfW 已被弃用,但它仍然完全可用,并且比 DirectShow 更容易设置。

于 2009-07-22T17:58:19.330 回答
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;
}

祝你好运!:)

于 2009-07-24T08:32:40.810 回答