【问题标题】:C++ and DirectShowC++ 和 DirectShow
【发布时间】:2012-05-29 10:37:00
【问题描述】:

我才刚刚开始使用 DirectShow 编程,而 DirectShow API 的“C”特性让我感到毛骨悚然。无尽的返回码而不是异常,到处都是 addref/release,函数获取指针的指针......

是否有任何用于 DirectShow 编程的“C++ 友好”包装器可以隐藏所有 COM 丑陋之处?

【问题讨论】:

    标签: c++ winapi com directshow


    【解决方案1】:

    对于 98% 的 DirectShow 代码,您应该永远看到对 AddRef 或 Release 的调用。始终使用CComPtr。此规则有一些小例外。

    此外,了解锁定也很重要,CCritSec 和 CAutoLock 也是如此;再一次,我会避免手动锁定 CCritSec 实例,因为这是使应用程序死锁的好方法。

    另外,这段代码也很方便:

    #include <dxerr9.h>
    
    ...
    
    HRESULT hr = S_OK;
    
    ... something goes wrong ...
    
    CString err(::DXGetErrorString9(hr));
    err += ::DXGetErrorDescription9(hr);
    

    最后,确保您使用的是 DShow 事件。各种有用的信息来自 DShow 图表中的事件,令人惊讶的是有多少应用程序没有实现(或实现不正确)。

    不久前,I wrote this,我把使用 DShow 的一些陷阱放在一起。可悲的是,我知道这些陷阱,因为我几乎在所有这些方面都搞砸了。

    【讨论】:

      【解决方案2】:

      CComPtr 非常方便,

      除此之外,您只需要忍受 HRESULTS 之类的东西。我更喜欢它们而不是例外……发现它们更容易使用……各有特色。

      【讨论】:

        【解决方案3】:

        值得知道的是,DirectShow 是在quartz.dll 中实现的,而 DirectShow 编辑服务是在 qedit.dll 中实现的。

        您可以将这两个与 Visual C++ 中的 Compiler COM Support 一起使用来编写 DirectShow 客户端应用程序。

        这是一个小播放 media_file 示例(使用 cl /D_UNICODE playfile.cpp 编译):

        #include <iostream> 
        
        #import <quartz.dll> rename_namespace("dshow") 
        #import <qedit.dll> rename_namespace("dshow")
        
        // Required for CLSID_FilterGraph
        #include <uuids.h> 
        #pragma comment(lib, "strmiids.lib")
        
        int wmain(int argc, wchar_t* argv[]) 
        {  
            using namespace dshow;
            using namespace std;
        
            if (argc != 2)
            {
                wcout << "Usage: play media_file" << endl;
                return 1;
            }
        
            struct ComInitializer
            {
                ComInitializer() 
                { 
                    ::CoInitialize(0);
                }
        
                ~ComInitializer()
                {
                    ::CoUninitialize();
                }
            } comInit;
        
            try 
            { 
                IGraphBuilderPtr graphBuilder; 
                graphBuilder.CreateInstance(CLSID_FilterGraph); 
        
                graphBuilder->RenderFile(argv[1], 0);
        
                IMediaControlPtr mediaControl = graphBuilder;
                mediaControl->Run();
        
                wcout << "Press Return to stop playback." << endl;
                wcin.get();
        
                mediaControl->Stop();
            } 
            catch (const _com_error& err)
            {
                wcout << L"Error code: 0x" << hex << err.Error() << endl;
            }
        } 
        

        我在构建控制台DirectShow oggenc 应用程序时使用了这种方法。

        【讨论】:

        • 有什么线索可以解释为什么 DirectShow 文档和其他在线示例中没有使用它? MSXML 文档有一个单独的部分描述如何使用这些自动生成的智能指针。
        • 可能他们不知道这件事。文档和书籍都非常面向 C 风格。这种风格看起来更像 DirectShow.NET。
        【解决方案4】:

        如果您没有找到包装器,那么您可能会从我的博客文章 "B true, or B thrown! (Using the >> throwing pattern)" 中讨论的编码模式中受益。

        该博客条目中的示例(这很容易适用于 COM,事实上我首先“发明”了它以供 COM 使用):

        std::ostream& operator<<( std::ostream& stream, wchar_t const s[] )
        {
            Size const  nBytes      = wcstombs( 0, s, 0 );
            (nBytes >= 0)
                || throwX( "wcstombs failed to deduce buffer size" );
        
            Size const              bufSize     = nBytes + 1;
            std::vector< char >     buf( bufSize );
        
            // The count of bytes written does not include terminating nullbyte.
            wcstombs( &buf[0], s, bufSize )
                >> Accept< IsNonNegative >()
                || throwX( "wcstombs failed to convert string" );
        
            return (stream << &buf[0]);
        }
        

        博客上有一些讨论,显然每个人对合适的运算符等都有自己的偏好,所以我只是在这里抛出一般原则

        哦,应该添加,而不是 AddRefRelease 调用,只需使用一些 COM 智能指针。周围有很多(例如在 ATL/MFC 中,以及 Visual C++ 的“内在”),它只是挑选你喜欢的那个。或创建自己的例如基于boost::intrusive_ptr

        干杯,

        【讨论】:

        • 每个人都有自己的想法,但我发现您在上面的构造完全深不可测。一目了然,它在做什么甚至都不是很明显,因此,IMO,它是一个糟糕的编程结构......
        • @Alf:我把最后几句话改写成“IMO,这是一个糟糕的 C++ 编程结构”。
        • @Alf:我确实阅读了您的博客文章,但它仍然让我觉得这是一个没有意义的丑陋结构。如果你必须有一个例外,那么使用苹果的 XThrowIfError(...) 函数有什么问题?除了制作不可读的代码之外,我没有得到你的系统提供的东西......
        • @Alf: Sigh 我永远不会说服你,我也不会尝试,但是滥用操作符会使代码难以阅读和维护。也有很多人同意我的观点(到目前为止,你的博客已经传给了很多人,除了负面评论之外没有人发表任何评论)。不过,我承认,这并不能证明它是轶事。不过,最后,你在乎我和其他人的想法吗?
        • 那是很多文本。无论如何,CComPtr/smart 指针确实是 DirectShow 的首选对象模型。我不建议使用其他任何东西。此外,输入 DirectShow 代码可能很危险,尤其是在过滤器中时。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多