Разное - [решено] *DirectShow* | не работает пример из SDK

Ответить
Аватара пользователя
pva

Разное - [решено] *DirectShow* | не работает пример из SDK

Сообщение pva »

Здравствуйте мною глубокоуважаемые обитатели форума, да восхвалится имя ваше (во веки веков). У меня почему-то пример из MSDN перечисления устройств DirectShow захвата видео работает не так, как там описано:



Код:

Код: Выделить всё

// есть шаблон com_object, который выполняет IUnknown::Release(),
// функции stop_error и log_error, которые сообщают результат HRESULT,
// stop* выдаёт исключение в случае ошибки, log* возвращает булевскую удачу-неудачу.
    IEnumMoniker *dev_enum_val = 0;
    // получаем перечислитель устройств
    // com_object::com_object(Interface** intf, HRESULT hr) проверяет stop_error(hr) и инициализирует
    // указатель на интерфейс значением *intf
    com_object dev_enum(&dev_enum_val,
            // com_object::com_object(const GUID&) использует CoCreateInstance для создания объекта
            com_object(CLSID_SystemDeviceEnum)->CreateClassEnumerator(
                        CLSID_VideoInputDeviceCategory, &dev_enum_val, 0));
    // перебираем устройства внутри категории
    IMoniker* dev_item_val=0;
    while(!log_error(dev_enum->Next(1, &dev_item_val, 0))
    {
         com_object dev_item(&dev_item_val, 0);
         // я проверял, dev_item->GetDisplayName(0, 0, &name) даёт правильный результат,
         // но дальше всё не по сценарию:
         // получаем набор свойств устройства
         IPropertyBag* prop_bag = 0;
         if(log_error(dev_item->BindToStorage(0, 0, IID_IPropertyBag, (void **)&prop_bag_val)))
         {
            com_object prop_bag(&prop_bag_val, 0);
           // меня устраивает любое из свойств 
           variant friendly_name;
            if (
                log_error(prop_bag->Read(L"Description", friendly_name.arg(), 0)) ||           // ошибка: неверный доступ к памяти
                log_error(prop_bag->Read(L"FriendlyName", friendly_name.arg(), 0)) ||       // ошибка: неверный доступ к памяти
                log_error(prop_bag->Read(L"Name", friendly_name.arg(), 0)))                     // ошибка: неверный доступ к памяти
            {
                // здесь, судя по примеру из MSDN, должно отображаться человеческое имя устройства
                // но до сюда не доходит :(
                MessageBoxW(Handle, friendly_name.value().c_str(), L"Enum", MB_OK);
            }
        }
    }

вспомогательный код (если понадобится):



Код:

Код: Выделить всё

// шаблон com_object
void stop_error(HRESULT hr);
bool log_error(HRESULT hr);
template
class com_object
{
public:
	static const GUID& id();
	~com_object() {_ptr->Release();}
	com_object(const GUID& type_id, IUnknown* parent=0);
	com_object(Interface** outer_interface, HRESULT hr);
	com_object(com_object const& other) throw() : _ptr(other._ptr) {_ptr->AddRef();}
	template com_object(com_object const&);
	Interface* operator->() throw() {return _ptr;}
	Interface* get() const throw() {return _ptr;}
private:
	Interface* _ptr;
};
template
com_object::com_object(const GUID& type_id, IUnknown* parent) : _ptr()
{
    stop_error(CoCreateInstance(type_id, parent, CLSCTX_INPROC_SERVER, id(), reinterpret_cast(&_ptr)));
}
template com_object::com_object(Interface** outer_interface, HRESULT hr) : _ptr(*outer_interface)
{
    stop_error(hr);
    if (!*outer_interface) throw runtime_error("got null interface");
}
template template
com_object::com_object(com_object const& other) : _ptr()
{
    stop_error(other.get()->QueryInterface(id(), reinterpret_cast(_ptr)));
}
// шаблон variant
template
class variant
{
public:
    static const VARTYPE type_id();
    ~variant()              {VariantClear(&_arg);}
    variant()               {VariantInit(&_arg);}
    variant(const variant& v2) {VariantCopy(&_arg, &v2._arg);}
    template
    variant(const variant& v2) {VariantChangeType(&_arg, &v2._arg, 0, type_id());}
    void reset()            {VariantClear(&_arg);}
    bool is_clear() const     {return _arg.vt == VT_EMPTY;}
    bool is_null() const      {return _arg.vt == VT_NULL;}
    bool is_error() const     {return _arg.vt == VT_ERROR;}
    DataT value() const;
    // для вызовов API
    VARIANT* arg() {return &_arg;}
private:
    VARIANT _arg;
    const VARIANT& _assert_value() const {
        // проверка что именно нужного типа (а не VT_EMPTY например)
        if (_arg.vt!=type_id()) throw logic_error("variant::_assert_value of different type");
        return _arg;
    }
};
template const VARTYPE variant::type_id(){return VT_UI4;}
template unsigned variant::value() const {return _assert_value().lVal;}
template const VARTYPE variant::type_id()     {return VT_I4;}
template int variant::value() const           {return _assert_value().ulVal;}
template const VARTYPE variant::type_id()   {return VT_R4;}
template float variant::value() const       {return _assert_value().fltVal;}
template const VARTYPE variant::type_id()  {return VT_R8;}
template double variant::value() const     {return _assert_value().dblVal;}
template const VARTYPE variant::type_id() {return VT_BSTR;}
template wstring variant::value() const   {return wstring(_assert_value().bstrVal);}

Теперь отдельный вопрос про получение текстового описания сообщения об ошибке: У меня возничает ситуация, когда система не может выдать текстовое сообщение (FormatMessage выдаёт пустую строку). Как с этим бороться? Мне же надо знать, чем он недоволен



Код:

Код: Выделить всё

bool log_error(HRESULT hr)
{
    if (hr)
    {
        hr &= 0xffff;
        char *ddstr;
        if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
                0, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*) &ddstr, 0, 0))
        {
            MessageBoxA(0, ddstr, 0, MB_OK|MB_ICONERROR);
            LocalFree(ddstr);
        }
        else
        {
            ostringstream ss;
            ss 

Специализация шаблона com_object для идентификации интрефейсов (простое правило):



Код:

Код: Выделить всё

#include 
#include 
#include 
template GUID const&    com_object::id()        {return IID_ICreateDevEnum;}
template GUID const&    com_object::id()          {return IID_IPropertyBag;}
template GUID const&    com_object::id()           {return IID_IBaseFilter;}
template GUID const&    com_object::id()        {return IID_ICaptureGraphBuilder2;}
template GUID const&    com_object::id()           {return IID_IGraphBuilder;}
template GUID const&    com_object::id()           {return IID_IVideoWindow;}
template GUID const&    com_object::id()           {return IID_IMediaControl;}
Аватара пользователя
Delirium

Re: Разное - [решено] *DirectShow* | не работает пример из SDK

Сообщение Delirium »

Цитата pva:



У меня почему-то пример из MSDN
Разное - [решено] *DirectShow* | не работает пример из SDK




А какая версия MSDN? Их документация часто страдает опечатками и неточностями.
Аватара пользователя
pva

Re: Разное - [решено] *DirectShow* | не работает пример из SDK

Сообщение pva »

Цитата Delirium:



А какая версия MSDN?
Разное - [решено] *DirectShow* | не работает пример из SDK




Которая у них на сайте в онлайне



Проблема решена очень просто: ти ли я недоглядел, то ли они лоханулись, если сделать всё по аналогии с описанием группы интерфейсов IEnumXXXX, то получается так:



Код:

Код: Выделить всё

// дописал wostream& operator<<(wostream&, const GUID&);
// дописал log_message(const wstring&); которая добавляет строчку в ListView
    unsigned long cnt_fetched = 0;
    IMoniker* dev_item_val[1]; // здесь изменение
    // беру только по одному объекту за раз (хотя можно и по 100 взять),
    // только чтобы соблюсти правила безопасных исключений C++
    while (log_error(filter_mons->Next(1, dev_item_val, &cnt_fetched)) && cnt_fetched)
    {
        com_object<IMoniker> dev_item(&dev_item_val[0], 0);
        {
            GUID dev_guid;
            wchar_t* str_name;
            stop_error(dev_item->GetClassID(&dev_guid));
            stop_error(dev_item->GetDisplayName(0, 0, &str_name));
            wostringstream ss;
            ss << dev_guid << str_name;
            __alloc->Free(str_name);
            log_message(ss.str());
        }
        IPropertyBag* prop_bag_val;
        com_object<IPropertyBag> prop_bag(&prop_bag_val,
            dev_item->BindToStorage(0, 0, IID_IPropertyBag, (void**)&prop_bag_val));
        variant<wstring> var_str;
        if (log_error(prop_bag->Read(L"FriendlyName", var_str.arg(), 0)))
        {
            log_message(var_str.value());
        }
    }

И ещё использовал IFilterMapper2 чтобы получить список моникеров устройств. По крайней мере так сработало правильно.

Появились новые вопросы, некоторые помещу в другое темы; Тов. модератор, если сочтёшь нужным, собери обратно в одну тему



Вопрос: имя фильтра DirectShow содержит 2 классида: категория и устройство. Как их можно попрость COM узнать, что соответствует этим классидам? Через IPropertyBag? как узнать, какие вообще свойства есть в IPropertyBag (у меня не получилось создать IPropertyBag2, который это умеет)?
Аватара пользователя
pva

Re: Разное - [решено] *DirectShow* | не работает пример из SDK

Сообщение pva »

пример заработал, был косяк в месте IEnumMoniker, нашёл способ получить описание фильтров:
Разное - [решено] *COM* | Как узнать имя класса по GUID


чтобы получить список категорий:
http://msdn.microsoft.com/en-us/libr...55(VS.85).aspx




вот что меня удивляет - это как с этим косяком у других работает, кто исходники в инете выкладывает.. у меня ни один не заработал
Ответить

Вернуться в «Программирование и базы данных»