Книга представляется в виде расширенного описания оглавления и фрагментов текста , что поможет Вам понять ee содержание. Все права на книгу принадлежат автору. Вы не имеете права распространять книгу в целом или по частям без разрешения автора.

Условия закачки книги в формате PDF находятся здесь http://www.plati.ru/asp/pay.asp?id_d=681750. Условия закачки исходных текстов здесь http://www.plati.ru/asp/pay.asp?id_d=681755.

Глава 2 (фрагмент) Построение фильтрового графа DirectShow

Подготовка проекта, выбор шаблона проекта
Доработка шаблона проекта [переход...]

Класс фильтрового графа [переход...]
Реализация менеджера фильтрового графа [переход...]
Интерфейсы менеджера фильтрового графа

Подготовка проекта, выбор шаблона проекта

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

Обычно при выборе шаблона проекта, прежде всего, руководствуются требованиями заказчика, особенностями аппаратной и программной реализации устройства и возможностями предоставляемой средой разработки. В данном случае, проект создается для изучения DirectShow, а также для проверки и отладки решений в процессе изучения. Поэтому, он должен легко перестраиваться и позволять создавать практически автономные блоки программы, каждый из которых предназначен для решения определенных задач, связанных единым замыслом. Устройство, для которого создается программа, является аналоговым телевизионным приемником, что сразу же предполагает большое количество разнообразных настроек и регулировок телевизионного приемника, которые необходимо будет отображать, как элементы интерфейса пользователя. Очевидно, что регулировки приемника по своему назначению будут делиться на группы. Для вывода изображения необходимо окно, отдельное от окон управления функциями приемника.

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

Посмотрим, что предлагает среда разработки для минимизации трудозатрат. Автор использует две версии Microsoft Visual Studio, VC 6.0 и .NET 2003 (VC 7.0), которые не конфликтуют на одном компьютере. Однозначно, шаблоны MDI, SDI и шаблон, основанный на диалоге, не подходят для структуры нашего приложения, поскольку потребуют дополнительных усилий по созданию отдельного окна для изображения, а большего VC 6.0 не предлагает. VC 7.0 предлагает нам более широкие возможности, такие как например, multi top-level documents (Рис.2. 1). Картинка в правом верхнем углу мастера подсказывает нам, что это, возможно, то, что нужно. Во всяком случае, есть основное окно и несколько окон верхнего уровня. Если изменить начальный шаблон таким образом, чтобы отображалось одно окно верхнего уровня, а в основном окне располагались переключаемые диалоги, то такой шаблон соответствовал бы сформулированным требованиям. Существование нескольких окон отображения верхнего уровня также может оказаться полезной возможностью. Попытаемся произвести задуманные изменения типового шаблона проекта.

Дадим имя проекту TVshow, включим поддержку архитектуры Document/View и в качестве основного класса выберем CFormView для размещения элементов управления приемником. Архитектура Document/View поможет упростить сохранение и автоматическое восстановление настроек приемника и программы, что для пользователя немаловажно при эксплуатации устройства с большим количеством настроек. Также включим поддержку HTML Help, которая значительно упрощает создание справки. Проект находится в папке ProjectState1.

Нажимаем OK, затем компилируем проект, запускаем его на выполнение и смотрим, что создала среда разработки. А создала она небольшое окно, заполненное формой класса CFormView.

Если в меню File выбрать пункт New Frame, то будет создано еще одно точно такое же, свободно плавающее окно.


Рис.2. 1 Выбор типа приложения

 

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

    • При загрузке программы на выполнение должно формироваться только два окна. Одно для управления и второе для отображения.
    • Окно управления должно содержать несколько сменяемых представлений класса CFormView с органами управления. Их количество должно легко изменяться.
    • Окно отображения должно содержать представление класса CView для телевизионной картинки.

    Таким образом, необходимо несколько окон класса CFormView разместить в одном основном окне в виде переключаемых вкладок диалогов, а окно верхнего уровня должно быть только одно и класса CView, для отображения фильма.

    [в начало]

 

 

Доработка шаблона проекта

Первое действие это корректировка файла stdafx.h. Заменяем значения некоторых строк, определяющих использование дополнительных возможностей предоставляемых Windows 2000/XP. Если этого не сделать, то компилятор при использовании некоторых идентификаторов, констант и т.д. будет выдавать ошибку. Новые значения выделены в тексте жирным шрифтом.

#ifndef WINVER //allow use of features specific to Windows 95 and Windows NT 4 or later.
#define WINVER 0x0501 //Change this to the appropriate
// value to target Windows 98
//and Windows 2000 or later.
#endif
#ifndef _WIN32_WINNT //Allow use of features specific //to Windows NT 4 or later.
#define _WIN32_WINNT 0x0501 //Change this to the
//appropriate value to target
//Windows 98 and Windows 2000 or //later.
#endif 
#ifndef _WIN32_WINDOWS //Allow use of features //specific to Windows 98 or later.
#define _WIN32_WINDOWS 0x0500 //Change this to the
//appropriate value to 
//target Windows Me or later.
#endif
#ifndef _WIN32_IE //Allow use of features specific
//to IE 4.0 or later.
#define _WIN32_IE 0x0600 //Change this to the
//appropriate value to
//target IE 5.0 or later.
#endif

Второе действие корректировка файлов класса CTVshowApp. Здесь попытаемся ввести новый шаблон документа для окна вывода изображения класса CView, поскольку его нет вообще, а также введем еще одно представление на основе CFormView и осуществим переключение между основным представлением CFormView и дополнительным представлением CFormView. Отработав эти основные решения в дальнейшем, можно будет просто добавлять новые представления класса CFormView.

Итак, добавляем новый шаблон документа для окна вывода изображения класса CView. Для этого посмотрим на строки в функции InitInstance, где создается шаблон документа для главного окна. Здесь мы видим, что все окна создаются по одному шаблону.

CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTVshowDoc),
RUNTIME_CLASS(CMainFrame), //Main SDI frame window

RUNTIME_CLASS(CTVshowView));
if (!pDocTemplate)
return FALSE;
m_pDocTemplate = pDocTemplate;
AddDocTemplate(pDocTemplate);

Добавляем новый шаблон. Класс документа в новом шаблоне оставим прежний CTVshowDoc, а классы рамки и представления должны быть другие. Поэтому создадим два новых класса один наследуемый от CFrameWnd и второй, наследуемый от CView. В таблицу строк добавим новую строку с произвольным идентификатором, например, IDR_WNDSHOW и текстом \nShow\nShow. Классы назовем CShowFrame и CShowView.

Процесс добавления нового класса в VC 7.0 несколько отличается от такого же действия в VC 6.0, здесь отсутствует ClassWizard и WizardBar. Все подробности можно найти в MSDN в разделе Where Are ClassWizard and WizardBar in Visual C++ .NET?. Коротко это действие выглядит так. В окне ClassView или другом, где есть имя проекта, сделайте правый щелчок на имени проекта и в открывшемся меню выберите пункт ADD/Add Class. В открывшемся окне выбираете класс MFC и нажимаете ОК, после этого откроется окно мастера ClassWizard. Далее действуйте обычным образом.

После добавления этих классов в проекте появляются два новых файла класс CShowFrame и класс CShowView. Файлы класса CShowView пока не изменяются, а в классе CShowFrame следует перегрузить функцию Create. Это можно сделать и вручную, но с использованием оболочки IDE будет быстрее. Возможно, вы не еще использовали Visual C++ .NET и для ускорения процесса обучения поясню это, не совсем очевидное, действие.

В главном меню откройте окно свойств View/Properties Window и сделайте его скрывающимся автоматически. Для этого на заголовке окна щелкните по значку, или правым щелчком на заголовке окна откройте меню и установите режим Auto Hide. После этого окно минимизируется, и вы должны увидеть картинку, показанную на рис 2.3, 2.4.

Затем выделяем класс CShowFrame и просто переводим курсор на панель Properties. Появляется окно свойств этого класса (рис 2.4). В данном окне три кнопки с символами, в соответствии с их порядком расположения, открывают окна, отображающие для данного класса события, сообщения и перегружаемые функции. После нажатия на зеленый кубик откроется окно, в котором выбираем функцию Create (рис. 2.5). 

Предлагаемая последовательность действий самый короткий и быстрый путь для установки обработчиков событий, сообщений и перегружаемых функций. Эти действия также можно выполнить, используя горячие клавиши. В созданной функции Create модернизируем вызов функции базового класса. Устанавливаем свое имя окна, удаляем меню и расширенный стиль окна, поскольку для окна отображения телевизионного изображения эти элементы не нужны.

BOOL CShowFrame::Create(LPCTSTR lpszClassName
, LPCTSTR lpszWindowName
, DWORD dwStyle, const RECT& rect
, CWnd* pParentWnd, LPCTSTR lpszMenuName
, DWORD dwExStyle , CCreateContext* pContext)

{
    return CFrameWnd::Create(
     lpszClassName, _T("TVshow"), dwStyle,rect, pParentWnd, NULL, 0, pContext); 
}

Вернемся к покинутому файлу TVshow.cpp и продолжим создание нового шаблона для окна изображения. Прежде всего, добавляем в начале файла две строки, включающие заголовочные файлы новых классов

#include ".\showView.h"
#include ".\showFrame.h".

Затем добавляем указатель на шаблон окна отображения CMultiDocTemplate* m_pDocTemplateShow, который понадобится для идентификации шаблона. Если это сделать с помощью соответствующего мастера, то указатель будет инициализирован нулем в конструкторе автоматически, что позволит избежать возможных проблем, если при добавлении вручную этого не было сделано. Далее добавляем новый шаблон документа.

m_pDocTemplateShow = new CMultiDocTemplate(

IDR_WNDSHOW,

RUNTIME_CLASS(CTVshowDoc),

RUNTIME_CLASS(CShowFrame), 

RUNTIME_CLASS(CShowView));

if (!m_pDocTemplateShow)

return FALSE;

AddDocTemplate(m_pDocTemplateShow);

Если откомпилировать проект в этом состоянии и выполнить, то мы увидим окно, маловразумительное для пользователя, не являющего программистом (рис. 2.6.).

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

Посмотрим внимательней на два основных файла, участвующих в старте программы, TVshow.cpp и MainFrm.cpp. Первый содержит две функции OnFileNewFrame и OnFileNew, второй LoadFrame, которые явно должны принимать участие в старте программы, загрузке нового окна и создании нового документа. Для определения последовательности их вызовов установим точки останова внутри функций и запустим программу в режиме отладки. После непродолжительных экспериментов обнаруживаем следующую логику работы.

  • Первой вызывается функция OnFileNew() и, запустив на выполнение программу, видим окно, такое как на рис 2.6.
  • Нажимаем ОК в этом окне и попадаем в LoadFrame. Запускаем опять программу и видим основное окно программы.
  • Открываем меню File/New Frame и попадаем в OnFileNewFrame. Запустив программу, далее видим, второе такое же окно.

Логика работы ясна, далее изменим ее таким образом, чтобы при вызове функции OnFileNew загружался шаблон главного окна, в котором будут располагаться элементы управления телеприемником, а при выборе меню File/New Frame происходила загрузка окна изображения на основе второго шаблона.

В функции OnFileNew есть фрагмент кода, в котором вызывается функция базового класса CWinApp, формирующая первое окно (рис.6).

if (pFrame == NULL || pDoc == NULL)
{
    //If it's the first document, create as normal

     CWinApp::OnFileNew();
}

Вместо этого вызова напишем свою функцию, которая в зависимости от типа шаблона будет формировать соответствующее окно. Изобретать, что-либо новое не придется, для этой цели почти без изменений подойдет содержимое функции OnFileNewFrame. Назовем нашу функцию myNewFrame.

Очень удобно в именах функций собственной разработки устанавливать префикс my, или любой другой. В этом случае в окне IntelliSense с длинным списком всех функций легко отыскать собственные функции, набрав только префикс (рис 2.7).

Ниже приводится текст измененного метода CTVshowApp::myNewFrame. Единственное существенное дополнение в этом методе это запоминание в классе CTVshowApp указателя на окно изображения для управления окном. Указатель объявлен защищенным и для его вызова объявлена функция
myGetPtrWndShow.

 

 

 

Рис.2.7 Отображение собственных методов в окне IntelliSense

CFrameWnd* myGetPtrWndShow(void)
{ return m_pFrameShow; };

void CTVshowApp::myNewFrame(
CMultiDocTemplate* pDocTemplate)
{

ASSERT(pDocTemplate != NULL);
CDocument* pDoc = NULL;
CFrameWnd* pFrame = NULL;

//Создаем новый документ для шаблона
pDoc = pDocTemplate->CreateNewDocument();
if (pDoc != NULL)
{

//if creation worked, use create a new frame for that document.
pFrame = pDocTemplate->CreateNewFrame(pDoc, NULL);
if (pFrame != NULL)
{

//Set the title, and initialize the document.
//If document initialization fails, clean-up the
//frame window and document.
pDocTemplate->SetDefaultTitle(pDoc);
if (!pDoc->OnNewDocument())
{

pFrame->DestroyWindow();
pFrame = NULL;

}
else
{

//Otherwise, update the frame
//если это шаблон окна отображения сохраняем
//его указатель для контроля и управления
if(pDocTemplate == m_pDocTemplateShow)
m_pFrameShow = pFrame;

pDocTemplate->InitialUpdateFrame(pFrame,pDoc, TRUE);

}

}

}

//If we failed, clean up the document and show a
//message to the user.
if (pFrame == NULL || pDoc == NULL)
{

delete pDoc;
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);

}

}

Текст OnFileNew после модернизации будет выглядеть следующим образом.

void CTVshowApp::OnFileNew()
{

CDocument* pDoc = NULL;
CFrameWnd* pFrame;
pFrame =
DYNAMIC_DOWNCAST(CFrameWnd,CWnd::GetActiveWindow()); 

if (pFrame != NULL)
pDoc = pFrame->GetActiveDocument();

if (pFrame == NULL || pDoc == NULL)
{

//Создаем главное окно с первым шаблоном при
//первом запуске программы
myNewFrame(m_pDocTemplate);

//Не вызываем CWinApp::OnFileNew(); и тем самым
//не отображаем окно выбора шаблона документа

}

//Далее удаляем все, чтобы не создавать новый
//документ, который нам не нужен

}

 

Теперь при запуске программы будет формироваться главное окно со своим документом. Формирование нового документа при выборе меню File/New не нужно, документ будет единственный, поэтому удаляем этот пункт меню и соответствующую иконку из Toolbar. Осталось откорректировать функцию OnFileNewFrame, таким образом, чтобы при вызове меню File/New Frame формировалось только окно изображения. Для этого просто удаляем все тело функции и делаем вызов myNewFrame с указателем на второй шаблон.

if(!m_pFrameShow)
myNewFrame(m_pDocTemplateShow);

Не забываем в конструкторе, инициализировать m_pFrameShow нулем, если указатель добавлялся вручную. Одной проверки указателя на нуль недостаточно. Пользователь может закрыть окно, и затем опять его открыть. Следует предусмотреть обнуление указателя при закрытии окна изображения, иначе окно не будет формироваться. Для этого, добавим в классе CShowFrame обработчик сообщения WM_CLOSE, и в нем очистим указатель.

(static_cast<CTVshowApp*>(AfxGetApp()))-> myClearPtrWndShow();

Возможно, пользователю не следует предоставлять возможность закрытия и открытия окна изображения, но на данном этапе разработки это еще неясно. Если в дальнейшем появятся предпосылки для такого решения, то можно будет заблокировать открытие и закрытие окна пользователем и открывать и закрывать его вместе с главным окном.

После компиляции программы ее поведение уже соответствует нашим основным требованиям. Теперь необходимо реализовать в основном окне смену представлений, которые будут содержать органы управления телеприемником.

[в начало]

Класс фильтрового графа

На первом этапе построения фильтрового графа следует решить следующие задачи:

Реализовать класс, который будет определять все функции устройства в фильтровом графе. Поскольку программа пишется для телевизионного устройства, центральным компонентом которого является фильтр сбора данных (Capture), то и класс можно создать под именем CCapture.

  • Создать менеджер фильтрового графа.
  • Найти в системе фильтр сбора и установить его в граф.

После первичной реализации класса CCapture с помощью мастера или вручную следует решить важнейшую задачу, в каком классе проекта создавать объект CCapture. Класс CCapture должен играть роль сервера, то есть обслуживать запросы пользователя по управлению фильтровым графом. Интерфейс пользователя будет располагаться на нескольких вкладках. От того, каким образом классы вкладок будут передавать запросы классу CCapture и связываться между собой, зависит эффективность и сложность реализации проекта в целом. В классе приложения CTVshowApp сохраняются все указатели на классы представлений (вкладок), поэтому если объект класса CCapture создать в классе приложения, то и реализация взаимной связи вкладок и класса CCapture будет максимально простой. Объект любой вкладки сможет получить указатель на класс CCapture через класс приложения. Другим важным условием упрощения взаимосвязи классов будет условие, при котором класс CCapture не должен по своей инициативе посылать запросы любому другому классу. В результате все запросы от классов вкладок будут односторонние. В исключительных случаях, когда классу CCapture потребуется активизировать объект вкладки, его окну можно послать пользовательское сообщение. Класс CCapture должен будет сохранять свое текущее состояние, тогда не потребуется взаимных пересекающихся запросов между классами вкладок для определения состояния элементов управления. Любой объект вкладки, при необходимости, может запросить текущее состояние параметра телеприемника у класса CCapture. На рисунке 2.16 показана структура связей класса CCapture. Пунктиром показаны сообщения классам вкладок

Создаем объект CCapture в методе CTVshowApp::InitInstance() после инициализации библиотеки COM на куче и сразу позаботимся об его удалении при завершении программы.

……………………………………………………………………….
CoInitialize(NULL);
//Создание объекта DirectShow
m_pCap = new CCapture;

……………………………………………………………………….
Для удаления объекта напишем метод myDestroyCapture.

 

 

 

Рис.2.16 Связи класса CCapture


void CTVshowApp::myDestroyCapture(void)
{

if(m_pCap)
{ delete m_pCap; m_pCap = 0; }

}


Удаление объекта производим в обработчике CMainFrame::OnClose().
void CMainFrame::OnClose()
{

CTVshowApp* pApp = static_cast<CTVshowApp*>(AfxGetApp());
//Удаление объекта сбора
pApp->myDestroyCapture();
//Удаление библиотеки COM
CoUninitialize();
CFrameWnd::OnClose();

}

Теперь проект подготовлен для разработки программы управления телевизионным приемником.

[в начало]

Реализация менеджера фильтрового графа

Построение фильтрового графа и управление им осуществляет менеджер графа (Filter Graph Manager). Объект менеджера графа является центральным компонентом в DirectShow. Приложение использует интерфейсы менеджера графа для построения и управления фильтровым графом. Менеджер графа также выполняет синхронизацию потоков данных и обработку сообщений. Построение фильтрового графа всегда начинается с создания объекта менеджера графа. После построения объекта менеджера графа можно строить сам граф с использованием различных фильтров DirectShow.

Интерфейсы менеджера фильтрового графа

Менеджер графа предоставляет несколько интерфейсов для управления фильтровым графом и для его построения. Часть интерфейсов предоставляется соответствующими фильтрами, но не прямо, а через менеджер графа. Ниже приводится краткое описание интерфейсов. После создания объекта менеджера графа метод CoCreateInstance возвращает указатель на интерфейс IGraphBuilder. Интерфейсы, выделенные жирным шрифтом, являются интерфейсами, обеспечивающими построение и перестройку фильтрового графа.

 

Интерфейс

Описание

 IFilterGraph

Обеспечивает методы для построения фильтрового графа. Является базовым для интерфейса IGraphBuilder.

 IGraphBuilder

Обеспечивает методы для построения фильтрового графа. Является производным от  интерфейса IFilterGraph. Приложение должно использовать этот интерфейс раньше, чем IFilterGraph.

IFilterGraph2

Расширяет интерфейсы IFilterGraph и IGraphBuilder. Добавляет три метода ля построения фильтрового графа.

IAMGraphStreams

Обеспечивает управление графом при обработке данных от источников реального времени ("живые" источники). Управляет синхронизацией и временем обработки выборки для "живого" источника.

IAMStats

Позволяет возвратить статистику производительности из менеджера графа.

IBasicAudio

Осуществляет управление громкостью и балансом на звуковом фильтре (канале).

IBasicVideo

Осуществляет управление параметрами изображения на отображающем фильтре.

IBasicVideo2

Интерфейс производный от IBasicVideo.  Добавляет один метод.

IFilterChain

Предоставляет интерфейсы для управления цепочкой фильтров (участком фильтрового графа).

IFilterMapper2

Управляет регистрацией и поиском фильтров в регистре.

IGraphConfig

Поддерживает динамическую реконфигурацию фильтров в графе без остановки графа.

IGraphVersion

Возвращает номер текущей версии графа.

IMediaControl

Управляет состоянием графа, пуск, стоп и пауза.

IMediaEvent

Управляет событиями, происходящими в графе.

IMediaEventEx

Интерфейс производный от IMediaEvent, дополняет и расширяет его.

IMediaEventSink

Уведомляет менеджер графа о событиях, происходящих в графе. Не применяется приложением.

IMediaFilter

Управляет состоянием фильтра (потока). Не применяется приложением, кроме двух методов, управляющих ссылочным временем.

IMediaPosition

Управляет передвижением по потоку. Интерфейс предназначен для применения с Visual Basic.

IMediaSeeking

Управляет передвижением по потоку. Интерфейс предназначен для применения с С/С++.

IQueueCommand

Интерфейс предназначен для создания очереди команд (методов), выполняющихся менеджером графа в указанное время.

IRegisterServiceProvider

Интерфейс регистрирует объект как сервис. Сервис это интерфейс, который клиент получает через СОМ. Можно зарегистрировать менеджер графа и затем получить его из другого объекта.

IResourceManager

Обеспечивает управление общими системными ресурсами, например звуковой картой. Приложения обычно не используют этот интерфейс.

IServiceProvider

Обеспечивает запрос сервиса СОМ. Относится к общим интерфейсам СОМ.

IVideoFrameStep

Обеспечивает покадровый просмотр видео потока. Просмотр в обратном направлении не поддерживается.  Интерфейс работает с аппаратным декодером, который должен поддерживать покадровый просмотр.

IVideoWindow

Устанавливает свойства для окна просмотра видео, позицию размеры и т.п.

Таблица 1 Интерфейсы менеджера графа

Кроме перечисленных интерфейсов для построения графа сбора данных важную роль играет интерфейс ICaptureGraphBuilder2, который реализуется на вспомогательном объекте построителя графа сбора. Создается объект с помощью вызова метода CoCreateInstance с идентификатором CLSID_CaptureGraphBuilder2.

При построении фильтрового графа DirectShow, в дополнение к перечисленным интерфейсам, используются и некоторые другие интерфейсы.

Интерфейс

Описание

ICreateDevEnum

Интерфейс перечислителя устройств и фильтров. Возвращается при создании объекта системного перечислителя.

IDvdGraphBuilder

Построитель фильтрового графа для DVD.

IEnumFilters

Перечисление фильтров в графе. Интерфейс предоставляется при вызове  метода менеджера графа IFilterGraph::EnumFilters.

IAMGraphBuilderCallback

Реализует механизм повторного вызова (callback) при построении графа.

IAMFilterGraphCallback

Принимает сообщения (callback) при построении графа, если контакт не может быть подключен.

 

Таблица 2 Дополнительные интерфейсы для построения графа.

Три интерфейса менеджера графа IFilterGraph, IGraphBuilder, IFilterGraph2 и интерфейс построителя графа сбора ICaptureGraphBuilder2 предоставляют методы, позволяющие построить граф тремя способами:

  • Приложение может указать графическому менеджеру, строить граф полностью автоматически. Используется при решении типовых задач, например, воспроизведение файла.
  • Использование смешанного режима построения графа. Часть графа строится автоматически, а другая часть строиться приложением в ручном режиме.
  • Приложение будет полностью строить граф, выбирая и соединяя каждый фильтр индивидуально.

Первый способ построения графа чаще всего используется при решении стандартных задач, таких как, например, воспроизведение файла AVI, MPEG, WAV, MP3 и некоторых других типов файлов. В этом случае вызывается метод IGraphBuilder::RenderFile, который требует в качестве параметра только имя файла. Файл может быть удаленным или локальным. При автоматическом построении графа менеджер осуществляет поиск фильтров в регистре, используя карту фильтров. Соединение фильтров производится в соответствии с медиа типом потока на контактах фильтра. Поиск фильтра начинается с определения медиа типа данных в файле по его расширению. Менеджер осуществляет поиск соответствия в регистре для зарегистрированных расширений файлов. Для поиска менеджер создает экземпляр карты фильтров и вызывает метод IFilterMapper2::EnumMatchingFilters. Применение этого метода показано в примере, приведенном для системного перечислителя. Если такое соответствие не установлено, тогда менеджер читает файл для поиска проверочных байтов (check bytes), по которым определяется тип медиа данных. После установки соответствия ищется фильтр источник способный читать данный медиа тип. Процесс поиска носит итеративный характер и использует следующие критерии для отбора фильтров.

  • Фильтр выбирается по категории фильтра, которая определяет его область использования.
  • Определяются медиа типы данных для входных и выходных контактов фильтра.
  • Окончательно фильтр выбирается по параметру предпочтения (merit) фильтра. В граф устанавливается фильтр, имеющий наивысший параметр предпочтения. Фильтры, имеющие более низкие параметры предпочтения при совпадении всех остальных данных, устанавливаются в граф только приложением, поскольку они проектируются для специальных целей.

Если фильтр источник найден, тогда менеджер создает экземпляр фильтра и устанавливает его в граф , вызывая метод IGraphBuilder::AddSourceFilter. После добавления фильтра менеджер проверяет контакты на соответствие медиа типу. После отбора первого фильтра, ищется второй фильтр для подключения к первому. Менеджер проверяет совпадение медиа типов выходного контакта первого фильтра и входного контакта второго фильтра и вызывает метод IGraphBuilder::Connect. Если попытка соединения фильтров оказалась неудачной, поиск повторяется до тех пор, пока поток не будет обработан. После построения графа, приложение нуждается только в интерфейсе IMediaControl для управления процессом воспроизведения файла.

Второй способ предполагает участие в построении графа приложения. Чаще всего сначала граф строится в автоматическом режиме, а затем производятся определенные коррективы, некоторые фильтры удаляются, другие устанавливаются и подключаются. Например, перекодировку файлов из одного формата в другой можно сделать из графа воспроизведения файла созданной в автоматическом режиме. Для этого удаляются фильтры воспроизведения, и устанавливается фильтр кодера и фильтр записи файлов.

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

[в начало]

Hosted by uCoz