Visual C ++ AVI编写器功能将位图(640x480)推送到AVI文件?

时间:2009-07-22 17:53:22

标签: visual-c++ opencv directshow avi

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

3 个答案:

答案 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;
}
祝你好运! :)