Direct Show.


    Опустим исторические введения и перейдем к делу. Direct Show это замечательный и простой, я не побоюсь этого слова, интерфейс для программирования потокового ( и не только )  видео для Windows. Основан он полностью на технологии COM. Тем, кто с ней знаком достаточно глубоко, будет очень просто изучить DirectShow, я бы даже сказал, что в этом случае все изучение сводится к прочтению мануала по интерфейсам. Тем, кто ничего о ней не знает, придется разбираться по ходу, что я представляю себе не самым простым занятием и рекомендую все же обратиться к соответствующей литературе, коей не мало на просторах сети и уделить немного времени на чтение, за то потом, все станет легко и понятно.

    К делу. Есть у COM один недостаток, который мне очень не нравится, это громоздкость выделения и освобождения ресурсов. Но тут на помощь приходит методика «выделение ресурса есть инициализация», которую очень хорошо описал в своей книге Бьерн Страуструп, а воплощена она будет в виде умных указателей на интерфейсы COM. А вот и их реализация, не стоит обращать внимание на объем кода, там много рутинных операций, реализация которых тривиальна, но их инкапсуляция в этом классе существенно облегчит нам жизнь.

    И так, в этой статье я приведу немного кода, а теоретический груз, поясняющий нижеследующие пертурбации перенесу в следующие статьи. Исходный код я приведу прям тут:



#ifndef IFACEPTR_H
#define IFACEPTR_H

#ifndef QT_NO_DEBIG
#include <QDebug>
#endif

/**
 * @file ifaceptr.h
 * @class CIFacePtr
 *
 * Реализует класс smart указателя на интерфейс COM.Инкапсулирует в себе
 * рутинные операции подсчета ссылок,освобождения интерфейсов и т.д.
 *
 * @param T   - интерфейс на который указывает класс
 * @param IID - указатель на идентификатор интерфейса
 */

template <class T, const IID* piid = 0> class CIFacePtr
{
public:

   /**
    * Консртуктор по умолчанию
    */

    CIFacePtr()
        :m_pointer(0)
        {
        }

   /**
    * Конструктор копирования
    * Создает объект из указателя на T
    * @param ptr - указатель на T
    */

    CIFacePtr(T* ptr)
        :m_pointer(ptr)
        {
            if (m_pointer)
                m_pointer->AddRef();
        }

   /**
    * Конструктор копирования
    * Создает объект из указателя на IUnknown
    * @param iu - указатель на IUnknown
    */

    CIFacePtr(IUnknown* iu)
        :m_pointer(iu)
        {
            if (iu) {

#ifdef  QT_NO_DEBUG
                iu->
    QueryInterface(*piid,reinterpret_cast<void**>(&m_pointer));
#else
                HRESULT hr = iu->
     QueryInterface(*piid,reinterpret_cast<void**>(&m_pointer));

                if (FAILED(hr))
                    qDebug()<<"CIFacePtr(IUnknown* iu): failed";
#endif

            }
        }

   /**
    * @return указатель пуст?
    */

    bool isNull() const
        {
            return m_pointer == 0 ? true : false;
        }

   /**
    * Освобождает интерфейс
    */

    void release()
        {
            if (m_pointer) {
                m_pointer->Release();
                m_pointer = 0;
            }
        }

   /**
    * Деструктор освобождает интерфейс
    */

    ~CIFacePtr()
        {
            release();
        }

   /**
    * Оператор взятия адреса,позволяет использовать стандартную
    * семантику.
    * @return &указатель
    */

    T** operator&()
        {
            return &m_pointer;
        }

   /**
    * Операция стрелка
    * @return T*
    */

    T* operator->()
        {
            Q_ASSERT(m_pointer != 0);
            return m_pointer;
        }

   /**
    * Оператор преобразования к bool.
    * @return true если указатель не нулевой,false иначе
    */

    operator bool() const
        {
            return (m_pointer != 0) ? true : false;
        }

   /**
    * Оператор логического не.
    * @return true если указатель нулевой, false иначе
    *
    * Позволяет использовать семантику на подобие:
    * CIFacePtr<IGraphBuilder> psGraph;
    * //......
    * if (!psGraph) //...
    */

    bool operator!()
        {
            return (m_pointer == 0) ? true : false;    
        }

   /**
    * @return идентификатор иньтерфейса
    */

    const IID& iid()
        {
            Q_ASSERT(piid != 0);
            return *piid;
        }

   /**
    * Оператор присваивания.
    * @param ptr - указатель на T.
    * 
    * Присваиваие нулевого указателя 
    * (в прочем, как и любое изменение      значения) 
    * освобождает инкапсулируемый интерфейс
    */

    T* operator=(T* ptr)
        {
            IUnknown* temp = m_pointer;
            m_pointer = ptr;

            if (m_pointer)
                m_pointer->AddRef();

            if (temp)
                temp->Release();

            return m_pointer;
        }

   /**
    * Оператор присваивания.
    * @param ptr - указатель на IUnknown
    *
    * За исключением типов аргументов аналогичен
    * оператору выше.
    */

    T* operator=(IUnknown* ptr)
        {
            IUnknown* temp = m_pointer;
            m_pointer = ptr;

            if (m_pointer) {

#ifdef QT_NO_DEBUG
            m_pointer->
            QueryInterface(*piid,reinterpret_cast<void**>(&m_pointer));
#else
HRESULT hr = QueryInterface(*piid,reinterpret_cast<void**>(&m_pointer));

            if (FAILED(hr))
                qDebug()<<"T* operator=(IUnknown* ptr)"
#endif
            }

            if (temp)
                temp->Release();

            return m_pointer;
        }

   /**
    * Оператор сравнения.
    * @param ptr - указатель на T
    * @return true если указатель на инкапсулируемый интерфейс
    * равен ptr
    */

    bool operator == (T* ptr) const
        {
            return m_pointer == ptr;
        }

   /**
    * Оператор сравнения.
    * @param other - другой экземпляр CIFacePtr
    * @return true если классы равны, false иначе
    */

    bool operator == (CIFacePtr<T>& other) const
        {
            return m_pointer == other.m_pointer;
        }

   /**
    * Проверка на нерванество.
    * @param ptr - указатель на T.
    * @return true если ptr не равен указателю
    * на инкапсулируемый интерфейс
    */

    bool operator != (T* ptr) const
        {
            return m_pointer != ptr;
        }

   /**
    * Проверка на нерванество.
    * @param other - другой экземпляр CIFacePtr
    * @return true если классы не равны, false иначе
    */

    bool operator != (CIFacePtr<T>& other) const
        {
            return m_pointer != other.m_pointer;
        }

   /**
    * @return  указатель на инкапсулируемый интерфейс
    */

    T* get()
        {
            Q_ASSERT(m_pointer != 0);
            return m_pointer;
        }

   /**
    * Обертка для глобальной CoCreateInstance призвана
    * избавить от жаншлирования аргументами
    *
    * @param clsid - идентификатор классаs
    * @param i - указатель на агрегирующий интерфейс
    * @param clsctx - контекст
    * @return признак усешности
    */

    HRESULT createInstance(const CLSID& clsid,IUnknown* i,DWORD clsctx)
        {
            release();
return 
CoCreateInstance(clsid,i,clsctx,*piid,
reinterpret_cast<void**>(&m_pointer));
        }

   /**
    * @return инкапсулируемый интерфейс в виде void**
    */

    void** toVoidVoid()
        {
            return reinterpret_cast<void**>(&m_pointer);
        }

private:

   /**
    * @var m_pointer - внутренний указатель на интерфейс
    */

    T* m_pointer;
};

#endif /* !IFACEPTR_H */

    Копируем код прямо отсюда, и вставляем в файл ifaceptr.h. Думаю по комментариям можно разобраться, что к чему. 
    Макрос QT_NO_DEBUG используется что бы контролировать отладку при помощи конфигураций сборки в IDE или в pro файле.
    Что касается GCC, он не поддерживает программирование Direct Show ( по этой же причине в нем не компилится phonon на windows).  Эту реализацию нельзя использовать для IUnknown, но когда это понадобится, мы решим проблему при помощи специализации.
    Протестируем наш код не отходя от кассы, подробности и описания интерфейсов я приведу в следующей статье, а сейчас я приведу ( тривиальный ) код воспроизведения AVI файла.


#include <QtGui/QApplication>
#include "ds.h"
#include <QDebug>
#include <DShow.h>
#include "ifaceptr.h"
#include <cstdlib>

#pragma comment( lib, "strmiids" )

using std::exit;

void die(const char* message = 0)
{
    if (message)
        qDebug()<<message;

    ::CoUninitialize();
    exit(1);
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ds w;
    HRESULT hr = ::CoInitializeEx(0,COINIT_APARTMENTTHREADED);
    w.show();   

    if (SUCCEEDED(hr)) {
        CIFacePtr<IGraphBuilder,&IID_IGraphBuilder> psGraph;
        CIFacePtr<IMediaControl,&IID_IMediaControl> psControl;
        CIFacePtr<IMediaEvent,&IID_IMediaEvent> psEvent;

        if  (FAILED(
 psGraph.createInstance
 (CLSID_FilterGraph,0,CLSCTX_INPROC_SERVER)))
             die("Can't create graph builder");

        if (FAILED(
psGraph->
QueryInterface(IID_IMediaControl,psControl.toVoidVoid())))
            die("Can't create media control");

        if (FAILED
        (psGraph->QueryInterface(IID_IMediaEvent,psEvent.toVoidVoid())))
            die("Can't create media event");

        if (FAILED
           (psGraph->RenderFile
        //Это путь к файлу, разумеется при компиляции вам нужно указать
        //сдесь свой путь
           (L"E:/кино/Rekviem po Mechte. Rus. Dvd-Rip. Xvid. by. Friends-   Forum.com.avi",0)))
            die("Render file failed");

        if (SUCCEEDED(psControl->Run())) {
            long evCode;
            psEvent->WaitForCompletion(INFINITE,&evCode);
        }

        psControl->Stop();
     }

    ::CoUninitialize();
    return a.exec();
}

    Хочу лишь добавить, что стиль изложения не всегда будет таким и что следующая пара тройка статей, наверняка такого же объема будут содержать всего несколько строк кода, все остальное теория. Я надеюсь, что народ успеет разобраться с указателями, мы будем широко их применять при программировании DirectShow.




Добавлена: 25-03-2009 | Пользователем: gnudimarik | Просмотров: 1991


Оставить комментарий



Капча *

Captcha

Комментарий будет опубликован после проверки модератором

Для подсветки синтаксиса исходный код следует обрамлять следующими тэгами
<pre><code class="синтаксис" >код</code></pre>
Подерживаются следующие: cpp php javascript sql html-xml css ini