netlib.narod.ru< Назад | Оглавление | Далее >

Присоединяемся к MP3-революции

Если последние несколько лет вы жили в пещере, то могли пропустить появление разработанного в институте Фраунгхофера формата музыкальных файлов MP3, который вызвал громадные потрясения в мире музыки. Куда ни повернешься можно увидеть портативные плееры, домашние кинотеатры, автомобильные магнитолы — и все они поддерживают воспроизведение музыки в формате MP3.

Так что же такое MP3? Это формат сжатия аудиоданных, позволяющий сделать их намного компактнее. Я мог бы долго продолжать разговор о том, что делает формат MP3 таким особенным, но в действительности он настолько вошел в нашу жизнь, что вы должны были бы жить в пещере, если не знаете что он делает для вас — воспроизводит музыку.

Возможность использовать MP3 в ваших проектах дает Microsoft DirectShow. Всего несколько коротких строк кода позволят вам воспроизводить в вашем проекте любой MP3-файл (или любой другой мультимедийный формат, DirectShow поддерживает WMA, AVI, MPG и это только несколько названий). Единственное требование, чтобы в вашей системе был установлен необходимый кодек (большинство популярных кодеков распространяются вместе с Windows 98 и XP).

ПРИМЕЧАНИЕ
Кодек (это означает кодирование/декодирование) — это процесс или программа, используемая для зашифровывания и/или расшифровывания определенного типа формата данных, например, MP3. Обычно вы получаете кодек от компании, разработавшей формат данных. В частности, кодек MP3 предоставляется институтом Фраунгхофера. К счастью Windows поставляется вместе с набором кодеков для наиболее популярных форматов — MP3, AVI, MPG и т.д., так что вам не надо беспокоиться об их поиске в Интернете.

 

ПРИМЕЧАНИЕ
Чтобы использовать DirectShow в собственных проектах необходимо добавить к проекту заголовочный файл dshow.h и библиотеку strmiids.lib.

Давайте посмотрим, как настроить DirectShow для воспроизведения звуков и музыки в вашем проекте.

Использование DirectShow

Как и везде в DirectX, для доступа к компонентам DirectShow используются COM-объекты и интерфейсы. Интерфейсы с которыми мы будем иметь дело перечислены в таблице 4.5.


Таблица 4.5. COM-интерфейсы DirectShow



Интерфейс Описание

IGraphBuilder Помогает построить граф фильтров. Граф фильтров — это набор объектов и интерфейсов, используемых для обработки медиафайлов.
IMediaControl Управляет потоком данных через граф фильтров. Этот интерфейс вы используете для контроля воспроизведения ваших звуков и музыки.
IMediaEvent Получает уведомления о событиях от графа фильтров. Это полезно, если вы хотите знать, что происходит в вашем графе фильров — воспроизводится ли еще музыка, остановлена ли она и т.д.


Хотя в таблице 4.5 перечислено лишь несколько интерфейсов, их достаточно для воспроизведения MP3-файлов в ваших проектах. Первый из этих трех объектов, IGraphBuilder, большая шишка среди объектов DirectShow — он создает набор фильтров, обрабатывающих медиаданные и делает другие полезные вещи. В нашем случае это загрузка MP3-файла, инициализация декодера и передача звука на ваши динамики.

Звучит сложно, но делается просто. Первый этап — создание объекта построителя графа с помощью функции CoCreateInstance:

STDAPI CoCreateInstance(
     REFCLSID  rclsid,       // ID класса (CLSID) желаемого объекта
     LPUNKNOWN pUnkOuter,    // NULL
     DWORD     dwClsContext, // Контекст класса (CLSCTX_INPROC_SERVER)
     REFIID    riid,         // Ссылка на идентификатор
     LPVOID    *ppv);        // Указатель на создаваемый объект

CoCreateInstance исключительно полезная функция; она позволяет вам создать любой COM-объект, задав идентификатор класса и ссылку на идентификатор объекта. В данном случае идентификатор класса будет CLSID_FilterGraph, а идентификатор объекта — IID_IGraphBuilder.

IGraphBuilder *pGraphBuilder = NULL;

if(FAILED(CoCreateInstance(CLSID_FilterGraph, NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_IGraphBuilder,
                           (void**)&pGraphBuilder))) {
    // Произошла ошибка
}

 

ВНИМАНИЕ!
Обязательно убедитесь, что инициализировали COM-систему перед вызовом CoCreateInstance. Для приложений, которые не используют несколько потоков (однопоточных), добавьте следующую строку до того, как делать какие-либо вызовы DirectX:
CoInitialize(NULL);
С другой стороны, если вы используете многопоточность, воспользуйтесь следующим вызовом функции:
CoInitializeEx(NULL, COINIT_MULTITHREADED);
Убедитесь, что при завершении работы ваше приложение вызывает функцию CoUninitialize:
CoUninitialize();

После того, как вы использовали CoCreateInstance для создания вашего объекта построителя графа, вы можете запросить два медиа-объекта, перечисленных в таблице 4.5:

IMediaControl *pMediaControl = NULL;
IMediaEvent   *pMediaEvent   = NULL;

pGraphBuilder->QueryInterface(IID_IMediaControl,
                              (void**)&pMediaControl);
pGraphBuilder->QueryInterface(IID_IMediaEvent,
                              (void**)&pMediaEvent);

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

Загрузка медиа-файла

Собственно говоря, вам не надо в действительности загружать медиа-файл, вы создаете ссылку из фильтра DirectShow на файл данных. Поток данных поступает из файла по мере расшифровки, что сокращает объем памяти, необходимый для воспроизведения содержимого. Процесс создания такой ссылки из медиа-файла к фильтру называется визуализацией (rendering).

Чтобы визуализировать файл вам надо всего лишь вызвать функцию IGraphBuilder::RenderFile:

HRESULT IGraphBuilder::RenderFile(
     LPCWSTR lpwstrFile,      // Имя обрабатываемого медиа-файла
     LPCWSTR lpwstrPlayList); // Не используется - укажите NULL

По сути RenderFile требует от вас один параметр — имя загружаемого медиа-файла. (Второй параметр не используется, так что укажите в нем NULL.) Обратите внимание, что строка с именем файла имеет тип LPCWSTR, а это указатель на строку широких символов.

ПРИМЕЧАНИЕ
Чтобы преобразовать строку обычных символов в строку широких символов вы можете использовать функцию mbstowcs, как показано здесь:
char  Filename[MAX_PATH];  // Строка символов, содержащая имя файла
WCHAR wFilename[MAX_PATH]; // Строка широких символов
// Преобразуем из Filename в wFilename
mbstowcs(wFilename, Filename, MAX_PATH);
Или, если вы хотите задать имя медиа-файла, используя текст в кавычках, такой, как "filename.mp3", вам достаточно просто воспользоваться макросом L для преобразования текста в строку широких символов, как показано ниже:
WCHAR *wFilename = L"filename.mp3"; // Обратите внимание на L

Вот, например, как можно визуализировать файл с именем song.mp3:

pGraphBuilder->RenderFile(L"song.mp3", NULL);

Управление воспроизведением вашей музыки и звуков

После того, как медиа-файл визуализирован, вы можете перейти к управлению воспроизведением звука и определением состояния воспроизведения с использованием двух ранее созданных интерфейсов IMediaControl и IMediaEvent.

Первый объект, IMediaControl, вы используете для управлением воспроизведением медиа-файла. Здесь стоит уделить внимание трем функциям: IMediaControl::Run, IMediaControl::Pause и IMediaControl::Stop. У каждой из этих функций есть свое назначение и они рассматриваются в последующих подразделах.

Воспроизведение звука

Чтобы начать воспроизведение вашего медиа-файла, вызовите функцию IMediaControl::Run:

HRESULT IMediaControl::Run();

У функции нет параметров, просто вызовите ее, чтобы началось воспроизведение вашей песни:

pMediaControl->Run();

Приостановка воспроизведения

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

HRESULT IMediaControl::Pause();

Еще одна не напрягающая мозги функция — для паузы в воспроизведении песни вызовите Pause:

pMediaControl->Pause();

Чтобы закончить паузу в воспроизведении просто вызовите снова IMediaControl::Run.

Завершение воспроизведения

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

HRESULT IMediaControl::Stop();

И снова здесь нет никаких параметров, так что использовать ее просто:

pMediaControl->Stop();

Обнаружение событий

Теперь вы увидели, как управлять воспроизведением медиа-файла. Но что если вам необходимо узнать, что происходит с медиа-файлом во время воспроизведения? Как он может сообщить вам, что воспроизведение остановлено из-за достижения конца песни? С помощью интерфейса IMediaEvent — вот как!

IMediaEvent предоставляет три функции, которые интересны для нас:

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

HRESULT IMediaEvent::GetEvent(
     long *lEventCode, // Код события
     long *lParam1,    // Параметр события 1
     long *lParam2,    // Параметр события 2
     long msTimeout);  // Время ожидания события

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

Одно из событий, которое вы наверняка будете отслеживать, — завершение воспроизведения. О нем сигнализирует значение EC_COMPLETE. Так что, если после вызова GetEvent в IEventCode находится значение EC_COMPLETE, вы знаете, что воспроизведение завершилось.

Вот пример использования GetEvent:

long Event, Param1, Param2;

// Ждем возникновения события 1 мс.
pMediaEvent->GetEvent(&Event, &Param1, &Param2, 1);
if(Event == EC_COMPLETE) {
    // Воспроизведение завершено
}

После того, как вы получили и обработали событие из GetEvent, необходимо освободить ресурсы, выделенные DirectShow, вызвав IMediaEvent::FreeEventParams:

HRESULT IMediaEvent::FreeEventParams(
     long lEventCode, // Событие из GetEvent
     long lParam1,    // Параметр 1 из GetEvent
     long lParam2);   // Параметр 2 из GetEvent

Вы вызываете FreeEventParams используя те же переменные, которые получили при вызове GetEvent:

// Получение какого-либо события
pMediaEvent->GetEvent(&Event, &Param1, &Param2, 1);

// Обработка события

// Освобождение ресурсов события
pMediaEvent->FreeEventParams(Event, Param1, Param2);

Постоянно вызывая GetEvent и FreeEventParams в каждом кадре вы можете определить момент завершения воспроизведения вашей песни и предпринять необходимые действия. Но что, если вы просто хотите воспроизвести медиа-файл полностью, и не желаете постоянно следить за его завершением?

Вы можете использовать третью из упомянутых мной функций, которая контролирует воспроизведение медиа-файла за вас и возвращает управление, когда оно завершено. Это функция IMediaEvent::WaitForCompletion:

HRESULT IMediaEvent::WaitForCompletion(
     long msTimeout, // Установите INFINITE
     long *pEvCode); // Код события

Поскольку единственное событие, которого вы ждете, — это завершение воспроизведения, можно использовать следующий небольшой фрагмент кода для запуска воспроизведения медиа-файла и ожидания его завершения:

// Воспроизведение песни
pMediaControl->Run();

// Ждем завершения
pMediaEvent->WaitForCompletion(INFINITE, &Event);

// Выполняем действия, необходимые после
// завершения воспроизведения

Освобождение ресурсов DirectShow

После того, как вы полностью закончили работу с вашими медиа-файлами, пришло время все выключить. После остановки воспроизведения медиа-файла (через IMediaControl::Stop) вы можете освободить объекты DirectShow используя их функции Release:

pMediaEvent->Release(); pMediaEvent = NULL;
pMediaControl->Release(); pMediaControl = NULL;
pGraphBuilder->Release(); pGraphBuilder = NULL;

 

ПРИМЕЧАНИЕ
Позднее в этой книге, а именно в главе 6, вы увидите, что для безопасного освобождения COM-объектов и присваивания указателям значения NULL, я использую собственный макрос ReleaseCOM. Относящиеся к DirectX вспомогательные библиотеки Microsoft делают тоже самое с помощью макроса с именем SAFE_RELEASE (определенного в файле dxutil.h, поставляемом вместе с DirectX SDK). Вы больше узнаете о макросе ReleaseCOM, когда встретитесь с его использованием в 6 главе.

Вот и все, что относится к воспроизведению MP3-музыки в ваших проектах!


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz