Dspack - мультимедіа фреймворк для delphi - directshow по-російськи

Dspack - мультимедіа фреймворк для delphi - directshow по-російськи

Мал. 13. Структура класів пакета DSPack

Звичайно, без доброго знання DirectShow API важко оцінити якість і корисність класової обгортки. Але ми все ж спробуємо розібратися з цими класами.

TFilterGraph

Цей компонент - обгортка над менеджером графа фільтрів DirectShow і займає виняткове місце як в самому DirectShow, так і в DSPack'е. Будь-який додаток, що має справу з DirectShow, обов'язково буде мати справу і менеджером графа фільтрів. Він використовується для побудови і управління графом, а також для управління синхронізацією, повідомленнями про події та інших аспектах контролю графа.

При використанні API DirectShow для створення менеджера графа фільтрів потрібно користуватися викликом функції CoCreateInstance. а в якості CLSID передавати або CLSID_FilterGraph, або CLSID_FilterGraphNoThread. CLSID_FilterGraph відповідає за створення менеджера графа фільтрів (МГФ) на спільно використовуваному робочому потоці (мабуть, потрібно все ж дати уявлення про використання потоків в DirectShow), а CLSID_FilterGraphNoThread - за створення МГФ на потоці додатки.

Зазвичай додатки використовують CLSID_FilterGraph. Але обидва CLSID_ використовуються для створення того ж об'єкта, але з використанням різних потокових моделей:

  • CLSID_FilterGraph служить для створення МГФ на робочому потоці, який спільно використовується всіма примірниками CLSID_FilterGraph в одному процесі. Потік діспетчерезірует повідомлення, які посилають фільтри і управляє життєвим циклом будь-яких вікон, створених фільтрами.
  • CLSID_FilterGraphNoThread служить для створення МГФ на потоці додатки. Якщо ви використовуєте цей CLSID, то потік, що викликає CoCreateInstance, повинен мати цикл обробки повідомлень. В іншому випадку можуть відбуватися різного роду блокування (deadlock). Перед завершенням роботи цього потоку потрібно також звільнити (release) МГФ і всі об'єкти графа (такі, як фільтри, контакти, посилальні годинник і т.д.).

Виходячи з вищевикладеного, начебто немає особливих причин використовувати при створенні МГФ CLSID_FilterGraphNoThread.

Втім, компонент TFilterGraph не використовує CLSID_FilterGraphNoThread, тому більше не будемо про нього згадувати.

МГФ надає наступні, коротко описані, інтерфейси. Незважаючи на те, що їх досить багато, я не полінуюся їх все виписати, а вам раджу не полінуватися і прочитати цю табличку. Після цього вам стануть набагато зрозуміліше права і обов'язки менеджера графа фільтрів.

Цей інтерфейс надає методи, пзволяет додатком будувати граф фільтрів. Цей інтерфейс реалізує МГФ.Етот інтерфейс успадковується від IFilterGraph (який надає базові операції - такі, як додавання фільтра в граф або з'єднання двох контактів). і додає методи, що дозволяють створювати граф по частковому інформації.

Використовується МГФ для підтримки динамічного побудови графа. Цей інтерфейс дозволяє додаткам і фільтрів переконфигурировать граф, що знаходиться в занедбаному стані, без його зупинки, і без втрати даних.

Повідомляє менеджер графа фільтрів про події, що відбуваються на графі. Фільтри використовують цей інтерфейс для звіту про події. Додатки не використовують його.

Управляє потоковим станом фільтра. Всі фільтри DirectShow реалізують цей інтерфейс. Він надає методи перемикання станів (зупинка, пауза, запуск), для отримання поточного стану та для установки довідкових годин. Додатки не викликають методів IMediaFilter. МГФ також надає цей інтерфейс. Додатки можуть викликати методи цього інтерфейсу SetSyncSource і GetSyncSource для установки і отримання довідкових годин. Додатки не повинні викликати інших методів цього інтерфейсу, а замість цього використовувати методи IMediaControl.Сам IMediaFilter успадковує від IPersist, а інтерфейс IBaseFilter успадковує, в свою чергу, від IMediaFilter.

Містить методи для пошуку позиції в потоці. Інтерфейс IMediaSeeking грунтується на цьому інтерфейсі. Програми, написані на C / C ++, можуть використовувати інтеерфейс IMediaSeeking замість IMediaPosition. Але IMediaSeeking несумісний з автоматизацією, тому додатки, написані, наприклад, на Visual Basic'е, повинні використовувати IMediaPosition.Етот інтерфейс надається як МГФ, так і окремими фільтрами. Додатки повинні отримувати покажчик на інтерфейс IMediaPosition від МГФ, а не від фільтрів. МГФ розподіляє метод шляхом виклику всіх фільтрів рендеринга. Фльтри рендеринга поширюють виклик вгору по потоку до фільтрів джерел. Така послідовність подій гарантує синхронізацію всіх потоков.Еслі один з распеделенних викликів поверне помилку, МГФ поверне першу отриману ним помилку. Деякі з розподілених викликів можуть бути і успішними. Якщо, втім, хоч один з розподілу викликів повернеться не E_NOTIMPL, то і МГФ не поверне E_NOTIMPL. Тільки в тому випадку, якщо всі розподілені виклики повернуть E_NOTIMPL, МГФ поверне E_NOTIMPL.Замечаніе для розробників фільтрів. Не потрібно реалізовувати цей інтерфейс. Замість цього потрібно реалізовувати IMediaSeeking. Якщо ваш фільтр підтримує IMediaSeeking, МГФ автоматично буде управляти інтерфейсом IMediaPosition.

Ставить команду в чергу для її обробки в певний час. Додаток може використовувати його для просування вперед керуючих команд для графа (?). Методи цього інтерфейсу моделюють метод IDispatch :: InvokeAt. Додаток вказує інтерфейс, метод інтерфейсу, параметри методу і посилальне час. МГФ ставить цю інформацію в чергу і, потім, викликає цей метод в зазначений час. Необхідні інтерфейс повинен наслідувати IDispatch і повинен надаватися МГФ. Прикладами таких інтерфейсів є IMediaControl, IMediaEventEx і IMediaPosition.После постановки команди в чергу МГФ повертає покажчик на інтерфейс IDefferedCommand. Додаток може використовувати цей інтерфейс для скасування або модіфкаціі команди.

Реєструє об'єкт як сервіс.

Цей інтерфейс відповідає за дозвіл конкуренції за системні ресурси.Фільтри можуть використовувати цей інтерфейс для запиту ресурсів, які, можливо, використовують інші об'єкти. Наприклад, аудіо-рендерер (фільтри, які відтворюють аудіо) використовую цей інтерфейс для вирішення конфліктів за пристрій аудіо-вивода.Пріложенія, зазвичай, не використовують цей інтерфейс.

Цей інтерфейс в довідці по DirectShow не описаний.

Як бачите, інтерфейсів досить багато. З цієї причини більш детально ми їх розглядати будемо тільки в разі потреби.

Нам потрібні будуть ще два інтерфейси: IAMGraphBuilderCallback і IAMFilterGraphCallback. Перший з них надає механізм callback'а при побудові графа. Для його використання потрібно реалізувати його методи в додатку або клієнтському об'єкті. Запитуйте у МГФ інтерфейс IObjectWithSize і викликайте метод IObjectWithSize :: SetSize, передаючи покажчик на реалізацію цього інтерфейсу. МГФ викликає методи цього інтерфейсу при побудові графа, який (інтерфейс) дає клієнт з метою модифікації процесу побудови графа. Головне використання цього інтерфейсу - конфігурація фільтра VMR перед його з'єднанням. Його можна використовувати також для відмови використання деяких фільтрів (наприклад, декодерів). Спеціфічекіе методи цього інтерфейсу - SelectedFilter (викликається, коли МГФ знаходить фільтр-кандидат, але перед створенням фільтра) і CreatedFilter (викликається після того, як МГФ створює фільтр, але до спроби його з'єднати). Другий інтерфейс - IAMFilterGraphCallback, - теж надає callback-механізм при побудові графа. Якщо при побудові графа МГФ отримує помилку при спробі рендеринга деякого контакту, він викликає єдиний метод цього інтерфейсу UnableToRender.

Так ось, клас TFilterGraph є спадкоємцем TComponent, а також інтерфейсів IAMGraphBuilderCallback, IAMFilterGraphCallback і IServiceProvider:

TFilterGraph = class (TComponent, IAMGraphBuilderCallback, IAMFilterGraphCallback, IServiceProvider)

МГФ може працювати в трьох режимах - gmNormal, gmCapture і gmDVD. При використанні режиму gmNormal створюється COM-об'єкт IGraphBuilder (FFilterGraph), при використанні gmCapture - створюються COM-об'єкти ICaptureGraphBuilder2 (FCaptureGraph) і IGraphBuilder (FFilterGraph), при використанні gmDVD - COM-об'єкт IDvdGraphBuilder (FDvdGraph). Давайте спочатку розглянемо ці інтерфейси, а потім продовжимо дослідження класу TFilterGraph.

Як вже було сказано (див. Таблицю інтерфейсів, що надаються МГФ), IGraphBuilder успадковується від IFilterGraph (який надає базові операції - такі, як додавання фільтра в граф або з'єднання двох контактів). і додає методи, що дозволяють створювати граф по частковому інформації (єдиний метод - Render - дозволяє автоматично добудувати граф для зазначеного вихідного контакту).

COM-об'єкт "Будівник графа захоплення" (Capture Graph Builder) реалізує єдиний інтерфейс - ICaptureGraphBuilder2 (для мене так і залишилося нез'ясованим походження цієї назви - можливо, він замінив і розширив використовуваний раніше для тих же цілей інтерфейс ICaptureGraphBuilder), який надає методи для побудови графа захоплення і інших призначених для користувача графів фільтрів. Загалом, використання цього допоміжного об'єкту має свої особливості, але я не вважаю, що на них потрібно зупинятися (непогано б розібратися в тому, як це helper-object працює і чи можна обійтися і без нього).

Нарешті, IDvdGraphBuilder використовується для роботи з, очевидно, dvd, але це тема окремої розмови, і я постараюся надалі про dvd не згадувати взагалі.

Переважна більшість інших методів і властивостей класу TFilterGraph мають відношення до обробки повідомлень, одержуваних графом фільтрів. Розглянемо докладніше, як це відбувається (хоча б для того, щоб вміти самим це робити у випадку використання не DSPack, а безпосередньо DirectShow API). Отже, в private-секції класу TFilterGraph можна знайти інтерфейс IMediaEventEx (член FMediaEventEx). При активізації менеджера графа фільтрів (в реалізації методу TFilterGraph.SetActive) відбувається виклик методу QueryInterface для отримання інтерфейсу IMediaEventEx. Зараз саме місце більш детально торкнутися цього інтерфейсу, але почнемо, мабуть, з інтерфейсу IMediaEvent (IMediaEventEx успадковує і розширює його функціональність). Отже, інтерфейс IMediaEvent містить методи для повернення повідомлень про події і для перевизначення оброблювачів цих повідомлень, що надаються за замовчуванням МГФ. Як вже було сказано, цей інтерфейс надається МГФ. Додаток може використовувати його для реакції на події, що відбуваються в графі фільтрів, такі, як кінець потоку або помилка при відображенні (рендеринге). Фільтри посилають події в граф фільтрів, використовуючи інтерфейс IMediaEventSink. Більш докладно про події, що виникають в графі фільтрів, варто подивитися у відповідних розділах довідки.

Інтерфейс IMediaEvent надає наступні методи:

Повертає повідомлення про наступне подію з черги повідомлень.

Повертає обробник для події зі скиданням вручну (manual-reset event) (якщо ви забули або взагалі не знаєте, що це таке, почитайте в MSDN або у Ріхер), який залишається зайнятим (signaled), поки чергу містить повідомлення про події. МГФ утримує подія про скиданням вручну, яке відображає стан черги повідомлень. Якщо чергу містить повідомлення про події, подія зі скиданням вручну перебуває в зайнятому стані. Якщо чергу порожня, метод IMediaEvent :: GetEvent скидає собитіе.Пріложеніе може використати цю подію для визначення стану черги. Спочатку викликається метод GetEventHandle для отримання Хендлі події. Потім потрібно дочекатися, коли подія перейде в сигнальний стан, за допомогою функції на кшталт WaitForSingleObject. Потім потрібно отримати седующее повідомлення про подію з черги за допомогою виклику методу IMediaEvent :: GetEvent. МГФ утримує подія в сигнальному стані, поки черга порожня; потім подія скидається. Не слід закривати хендл події, що повертається цим методом, тому що він використовується всередині графа фільтрів. Не потрібно також використовувати хендл після після звільнення МГФ, оскільки в цьому випадку цей хендл НЕ буде коректним. (Щоб уникнути цієї помилки, можна дублювати хендл викликом DuplicateHandle і використовувати цей дублікат замість вихідного хендлом. Після закінчення роботи з дублікатом його потрібно закрити.) Інший спосіб моніторингу додатком черги повідомлень - виклик методу IMediaEventEx :: SetNotifyWindow (він буде розглянутий нижче).

Чекає, коли граф фільтрів обробить всі доступні дані.

Для моніторингу повідомлень нас, втім, більше буде цікавити інтерфейс IMediaEventEx, який успадковує інтерфейс IMediaEvent і, крім того, має методи для для повернення повідомлень про події і для перевизначення оброблювачів повідомлень, що надаються МГФ за замовчуванням. IMediaEventEx розширює інтерфейс IMediaEvent методами, що дозволяють вікна додатка отримають повідомлення про події, що відбуваються в МГФ. Повний список визначених системою повідомлень можна подивитися тут. Ми ж звернемося до нових методів IMediaEventEx. Їх всього три:

Повертає контакт із зазначеним ідентифікатором

Повідомляє фільтр, що він пов'язаний або left (?) Графом фільтров.Когда МГФ додає фільтр в граф фільтрів, він викликає цей метод з покажчиком на себе. Ім'я примірника фільтра зв'язується за допомогою другого параметра. Коли МГФ видаляє фільтр з графа, він викликає цей метод, передаючи в якості покажчика на граф значення nil. Додатків цей метод викликати не слід. Для додавання фільтра в граф потрібно викликати метод AddFilter інтерфейсу IFilterGraph, отриманого у МГФ

Повертає інформацію про фільтр

Повертає рядок, що містить інформацію про виробника

Це, загалом, і все, що я хотів сказати про інтерфейс IBaseFilter і, відповідно, класі TFilter, оскільки останній реалізує простий і очевидний речі, необхідні для того, щоб називатися врапперов цього інтерфейсу. Якщо вас зацікавлять подробиці згаданих вище інтерфейсів або їх методів, дивіться їх в MSDN.

TVideoWindow

IVideoWindow

Крім методів, успадкованих від IDispatch, інтерфейс IVideoWindow надає методи, описані в далееідущей табличці:

Як бачимо, інтерфейс IVideoWindow має досить багато методів (про їх подробицях можна дізнатися з того ж MSDN'а), більшість з яких має абсолютно прозорий сенс, і тільки для деяких (як, наприклад, put_FullScreenMode) характерні важливі нюанси.

VMR Windowless Mode

Тут - VMR Windowless Mode

IVMR WindowlessControl9

IVMRWindowlessControl9 крім методів, успадкованих від IUnknown, надає також і наступні:

Інформує VMR про те, що додаток отримало повідомлення WM_DISPLAYCHANGE.Пріложеніе повинно викликати цей метод завжди, коли воно отримує віконне повідомлення WM_DISPLAYCHANGE, але тільки якщо VMR знаходиться в безвіконні (windowless) режимі

Повертає поточний aspect ratio режиму відображення

Повертає поточний колір рамки, використовуваний VMR'ом

Повертає копію поточного зображення, що відображається VMR'ом. Зображення повертається в форматі пакувати Windows DIB. Цей метод може бути викликаний в будь-який час, незалежно від того, в якому стані знаходиться фільтр. Зухвалий відповідальний за звільнення повертається пам'яті за допомогою виклику coTaskMemFree. Використання цієї функції уповільнює відтворення

Встановлює поточний aspect ratio режиму відображення

Video Renderer Filter

У наступній таблиці описуються властивості фільтра Video Renderer:

Інші подробиці, пов'язані з особливостями функціонування фільтра і підтримки налагодження додатків quartz.dll, слід дивитися в MSDN.

Video Mixing Renderer Filter 9

Властивості, методи та інтерфейси для TVideoWindow

Клас TCustomContol є спадкоємцем TWinControl, тому зрозуміло, що TVideoWindow дає можливість, серед іншого, працювати з ним як з вікном. Будемо вважати, що з цим предком все ясно, і зосередимося на інтерфейсах IFilter і IEvent. Вони оголошені як

Розглянемо також деякі додаткові інтерфейси, важливі для розуміння процесу відображення. Серед них - IVMRSurfaceAllocator, IVMRSurfaceAllocatorNotify, IVMRImagePresenter.

IVMRSurfaceAllocator

Інтерфейс IVMRSurfaceAllocator реалізується аллокатором-презентери (allocator-presenter), заданих за замовчуванням для фільтра VMR-7. Він повинен реалізовуватися будь-яким plug-in allocator-presenter, який додаток фільтра VMR-7. VMR-7 використовує методи на цьому інтерфейсі для виділення, підготовку і звільнення поверхонь DirectDraw. Додатки не використовують цей інтерфейс. Для VMR-9 використовується IVMRSurfaceAllocator9. До того ж до методів IUnknown, інтерфейс IVMRSurfaceAllocator надає такі методи: