【发布时间】:2012-05-29 10:37:00
【问题描述】:
我才刚刚开始使用 DirectShow 编程,而 DirectShow API 的“C”特性让我感到毛骨悚然。无尽的返回码而不是异常,到处都是 addref/release,函数获取指针的指针......
是否有任何用于 DirectShow 编程的“C++ 友好”包装器可以隐藏所有 COM 丑陋之处?
【问题讨论】:
标签: c++ winapi com directshow
我才刚刚开始使用 DirectShow 编程,而 DirectShow API 的“C”特性让我感到毛骨悚然。无尽的返回码而不是异常,到处都是 addref/release,函数获取指针的指针......
是否有任何用于 DirectShow 编程的“C++ 友好”包装器可以隐藏所有 COM 丑陋之处?
【问题讨论】:
标签: c++ winapi com directshow
对于 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 的一些陷阱放在一起。可悲的是,我知道这些陷阱,因为我几乎在所有这些方面都搞砸了。
【讨论】:
CComPtr 非常方便,
除此之外,您只需要忍受 HRESULTS 之类的东西。我更喜欢它们而不是例外……发现它们更容易使用……各有特色。
【讨论】:
值得知道的是,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 应用程序时使用了这种方法。
【讨论】:
如果您没有找到包装器,那么您可能会从我的博客文章 "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]);
}
博客上有一些讨论,显然每个人对合适的运算符等都有自己的偏好,所以我只是在这里抛出一般原则。
哦,应该添加,而不是 AddRef 和 Release 调用,只需使用一些 COM 智能指针。周围有很多(例如在 ATL/MFC 中,以及 Visual C++ 的“内在”),它只是挑选你喜欢的那个。或创建自己的例如基于boost::intrusive_ptr。
干杯,
【讨论】: