Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DirectX. Продвинутая Анимация (2004) [rus].pdf
Скачиваний:
335
Добавлен:
16.08.2013
Размер:
8.39 Mб
Скачать

438

Глава 14

NAME("ANIMATEDTEXTURE"), pUnk, phr)

{

//Сохранить указатель на устройство m_pD3DDevice = pD3DDevice;

//Возвратить успешное окончание выполнения функции *phr = S_OK;

}

Чтобы зарегистрировать фильтр, необходимо вызвать конструктор CbaseVideoRenderer, как показано в вызове конструктора вашего фильтра. В качестве параметров конструктор CbaseVideoRenderer принимает UUID созданного фильтра и имя, присваиваемое фильтру (в данном случае ANIMATEDTEXTURE). Другие две переменные просто передаются из параметров конструктора фильтра.

Внутри конструктора необходимо просто сохранить указатель объект 3D указателя в переменной класса (m_pD3DDevice) и код успешного завершения в указателе на HRESULT. Вот и весь конструктор класса фильтра!

Вторая (и последняя) добавляемая к классу фильтра функция возвращает указатель на объект поверхность текстуры. Вспомните, объект текстуры был объявлен в классе как m_Texture, поэтому вернуть указатель на него можно при помощи следующего кода:

IDirect3DTexture9 *cTextureFilter::GetTexture()

{

return m_Texture;

}

После создания последней функции класс фильтра готов к использованию!

Работа со специализированным фильтром

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

На самом деле, вам необходимо использовать один из основных интерфейсов DirectShowIGraphBuilder. Интерфейс IGraphBuilder, называемый построитель графов, создает и содержит список фильтров (называемый графом фильтров), которые используются при декодировании медиа файла. Построитель графов загружает медиа файл и настраивает соответствующие фильтры, необходимые для обработки данных этого файла. Давайте рассмотрим этот очень важный объект поближе.

Использованиеанимированныхтекстур .

Использование построителя графов

Объект IGraphBuilder очень похож на все остальные интерфейсы COМ. Чтобы использовать IGraphBuilder, необходимо создать его экземпляр и вызвать CoCreateInstance для создания фактического объекта и получения его интерфейса.

IGraphBuilder *pGraph; CoCreateInstance(CLSID_FilterGraph,NULL,\

CLSCTX_INPROC_SERVER,IID_IGraphBuilder, \ (void**)&pGraph);

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

Совет. Прежде чем использовать СOМ-объекты, необходимо убедиться, что система COМ инициализирована. Вы можете инициализировать систему COМ, вставив следующую строчкукодавначаловашегоприложения (обычно, вначалофункции WinMain):

CoInitialize(NULL);

При выходе из приложения необходимо деинициализировать систему COМ, используя следующую строчку кода:

CoUninitialize();

Замечание. Функция CoCreateInstance возвращает S_OK, если она была выполнена успешно. Любое другое возвращаемое значение означает, что при создании СOМобъекта произошла ошибка. Для получения дополнительной информации о значении возвращаемых кодов обратитесь к Win32 SDK.

Вот пример кода, создающего фильтр и регистрирующего его в графопостроителе:

//pD3DDevice=указатель на предварительно инициализированный объект 3D

//устройства

//Создать экземпляр фильтра

cTextureFilter *pTextureFilter = \

new cTextureFilter(pD3DDevice, NULL, &hr);

// Добавить фильтр в построитель графов

IBaseFilter *pFilter = (IBaseFilter*)pTextureFilter; pGraph->AddFilter(pFilter, L"ANIMATEDTEXTURE");

440

Глава 14

Функция AddFilter построителя графов принимает в качестве параметров указатель на фильтр (преобразовываемый к интерфейсу класса IBbaseFilter, от которого наследуются все фильтры) и присваиваемое ему имя. В предыдущем примере построителю графов были переданы указатель на фильтр текстур (pFilter) и его имя (ANIMATEDTEXTURE). После этого имя фильтра больше не используется; оно необходимо для ваших собственных целей и для внешнего просмотрщика фильтров, проверяющего все фильтры DirectShow.

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

Выбор исходного файла

После того как вы зарегистрировали фильтр в DirectShow (при помощи интерфейса IGraphBuilder), необходимо указать DirectShow импортируемый видео файл. Функция IGraphBuilder::AddSourceFilter предназначена для установки исходного файла и создания соответствующих фильтров для импортирования видео данных.

HRESULT IGraphBuilder::AddSourceFilter(

LPCWSTR lpwstrFileName,

LPCWSTR lpwstrFilterName,

IBaseFilter **ppFilter);

Функция AddSourceFilter имеет три параметра: имя загружаемого медиа файла, имя исходного фильтра (lpwstrFilterName, о котором вы прочитаете чуть ниже) и указатель (ppFilter) на объект фильтра IBaseFilter, который используется для получения доступа к объекту фильтра видео.

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

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

Теперь чувствуется разница, не так ли? Для создания базового фильтра и загрузки медиа файла вызовите AddSourceFilter. Базовый фильтр будет иметь имя SOURCE (преобразованной к Unicode строке с помощью макроса L"") и требует созданного экземпляра интерфейса IBaseFilter.

//Filename = имя используемого видео файла IBaseFilter *pSrcFilter;

//Преобразовать их ASCII текста в Unicode:

Использованиеанимированныхтекстур

441

Рис. 14.2. Исходный фильтр позволяет использовать один интерфейс для представления набора объектов фильтров

WCHAR wFilename[MAX_PATH]; mbstowcs(wFilename, Filename, MAX_PATH);

// Добавить исходный фильтр pGraph->AddSourceFilter(wFilename, L"SOURCE", &pSrcFilter);

После вызова AddSourceFilter вы получите указатель на исходный фильтр. Этот указатель pSrcFilter используется для соединения выходной pin источника видео и входной pin фильтра текстуры.

Замечание.ЯконвертировалмулътибайтнуютекстовуюстрокуFilenameвуникодовскую строку, потому что функция AddSourceFilter (как и большинство функций DirectShow) принимаетвкачествепараметровсимволыуникода.

Соединение разъемов

О чем это я говорю тут - что за разъемы (pins) и что они делают? Каждый фильтр имеет набор разъемов, которые в каком-то смысле являются трубами, выдающими и принимающими данные медиа в и из фильтра. Данные медиа поступают на входной разъем первого фильтра. Данные обрабатываются фильтром и передаются следующему через выходной разъем. Процесс продолжается до тех пор, пока не закончатся данные, в настоящем случае представленные используемой поверхностью текстуры. Посмотрите на рис. 14.3, чтобы лучше понять, что я имею ввиду.

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

442

Глава14

Рис. 14.3. Демонстрационный набор из четырех фильтров используется для получения данных медиафайла, ихдекодирования и визуализации

Следующим шагом к использованию видео текстуры является нахождение входного разъема (in pin) вашего фильтра (разъема, который принимает входящие данные), выходного разъема (out pin) исходного фильтра (того, из которого данные выходят) и их соединение.

Чтобы найти эти два разъема (входной разъем вашего фильтра и выходной разъем фильтра источника), необходимо использовать функцию FindPin.

HRESULT IBaseFilter::FindPin(

LPCWSTR Id, // Имя искомого разъема

IPin **ppPin); // Объект интерфейса pin

Я знаю, что говорил вам, что мы не будем иметь дела с множеством интерфейсов DirectShow, но я обещаю вам, их осталось немного. Функция FindPin имеет два параметра: имя искомого разъема (в данном случае либо In, либо Out, причем имена представлены Unicode символами) и интерфейс IPin.

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

// Найти входной и выходной разъемы и соединить их IPin *pFilterPinIn;

IPin *pSourcePinOut; pFilter->FindPin(L"In", &pFilterPinIn);

pSourceFilter->FindPin(L"Output", &pSourcePinOut);

Нe может быть ничего проще. Сделав вызов еще одной функции, вы можете соединить разъемы.

pGraph->Connect(pSourcePinOut, pFilterPinIn);

На данный момент вы загрузили медиа файл и соединили фильтры, подготовив их к работе! Осталось только начать проигрывание видео потока. Проблемой является то, что построитель графов не содержит функций управления проигрыванием. Что за бездельник! Однако не расстраивайтесь, потому что с помощью построителя графов вы можете получить интерфейсы, управляющие проигрыванием видео потоков.

Использованиеанимированныхтекстур

Получение интерфейсов

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

Для определения завершения проигрывания видео необходимо получить из графопостроителя интерфейс медиа событий - ImediaEvent. Наконец, для определения текущего положения или даже времени воспроизведения видео необходимо получить еще один дополнительный интерфейс.

Используйте следующий код для получения необходимых интерфейсов:

//Создать экземпляры объектов медиа IMediaControl *pMediaControl; IMediaPosition *pMediaPosition; IMediaEvent *pMediaEvent;

//Получить интерфейсы

pGraph->QueryInterface(IID_IMediaControl, \ (void **)&pMediaControl); pGraph->QueryInterface(IID_IMediaPosition, \ (void **)&pMediaPosition);

pGraph->QueryInterface(IID_IMediaEvent, \ (void **)&pMediaEvent);

Нe сдавайтесь - мы уже почти закончили! Осталось только начать воспроизведение видео, определять текущее положение видео по мере его воспроизведения и наблюдать за различными возникающими событиями медиа.

Управление проигрыванием и обработкасобытий

Последним шагом к получению анимированной текстуры является начало воспроизведение видео источника при помощи только что созданного объекта IMediaControl. Интерфейс IMediaControl содержит две интересующие нас функции: IMediaControl::Run и IMediaControl::Stop.

Функция IMediaControl::Run начинает воспроизведение видео с текущего положения, что в свою очередь инициирует передачу данных вашему фильтру и, в конце концов, поверхности текстуры. Функция Run не имеет никаких параметров и может быть использована так:

pMediaControl->Run();

444

Глава 14

Во время воспроизведения видео вы можете остановить его, вызвав функцию IMediaControl::Stop, которая также не имеет параметров. Следующий код останавливает воспроизведение видео:

pMediaControl->Stop();

Замечательным является то, что вы можете использовать функции Run и Stop для приостановки и продолжения видео воспроизведения. Вызов функции Stop приостанавливает воспроизведение, в то время как последующий вызов Run продолжает его.

Чтобы переместиться в заданное положение в видео (например, в начальное положение, когда вы хотите "перемотать" его) используется интерфейс IMediaPosition. Чтобы переместиться на заданное время в видео файле, вызовите функцию IMediaPosition::put_CurrentPosition.

HRESULT IMediaPosition::put_CurrentPosition(

REFTIME llTime);

При ближайшем рассмотрении параметр REFTIME функции putCurrentPosition оказывается вещественным значением; время llTime устанавливается в любое значение для перемещения видео потока. (Например, 2.0 означает переместиться на 2.0 секунды в потоке.) Функция put_CurrentPosition в основном используется для перемотки видео и воспроизведения его сначала, как я сделал тут:

// Переместиться в начало потока видео (0 секунд) pMediaPosition->put_CurrentPosition(0.0f);

Последним, в трио используемых медиа объектов, идет IMediaEvent, который получает все возникающие события. Нас интересует только событие, означающее окончание воспроизведения видео, чтобы его можно было начать заново, process some function to stream in another video или сделать еще что-нибудь.

Чтобы получить событие с помощью интерфейса IMediaEvent, необходимо использовать функцию IMediaEvent: :GetEvent.

HRESULT

IMediaEvent::GetEvent(

 

long *lEventCode, // Код события

 

long

*lParam1,

// Первый параметр

события

long

*lParam2,

// Второй

параметр

события

long msTimeout); // Время

ожидания

события

Функция GetEvent имеет четыре параметра, первые три из которых являются указателями на переменные типа long, а последний сам является переменной типа long. После вызова GetEvent первые три переменные (lEventCode, lParam1 и lРаrаm2) будут содержать информацию о текущем событии, такую как код события и два его

Соседние файлы в предмете Программирование на C++