netlib.narod.ru | < Назад | Оглавление | Далее > |
Если последние несколько лет вы жили в пещере, то могли пропустить появление разработанного в институте Фраунгхофера формата музыкальных файлов MP3, который вызвал громадные потрясения в мире музыки. Куда ни повернешься можно увидеть портативные плееры, домашние кинотеатры, автомобильные магнитолы — и все они поддерживают воспроизведение музыки в формате MP3.
Так что же такое MP3? Это формат сжатия аудиоданных, позволяющий сделать их намного компактнее. Я мог бы долго продолжать разговор о том, что делает формат MP3 таким особенным, но в действительности он настолько вошел в нашу жизнь, что вы должны были бы жить в пещере, если не знаете что он делает для вас — воспроизводит музыку.
Возможность использовать MP3 в ваших проектах дает Microsoft DirectShow. Всего несколько коротких строк кода позволят вам воспроизводить в вашем проекте любой MP3-файл (или любой другой мультимедийный формат, DirectShow поддерживает WMA, AVI, MPG и это только несколько названий). Единственное требование, чтобы в вашей системе был установлен необходимый кодек (большинство популярных кодеков распространяются вместе с Windows 98 и XP).
Давайте посмотрим, как настроить 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))) { // Произошла ошибка }
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, а это указатель на строку широких символов.
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
FreeEventParams
WaitForCompletion
Чаще всего вы будете иметь дело с первой функцией, 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); // Выполняем действия, необходимые после // завершения воспроизведения
После того, как вы полностью закончили работу с вашими медиа-файлами, пришло время все выключить. После остановки воспроизведения медиа-файла (через IMediaControl::Stop) вы можете освободить объекты DirectShow используя их функции Release:
pMediaEvent->Release(); pMediaEvent = NULL; pMediaControl->Release(); pMediaControl = NULL; pGraphBuilder->Release(); pGraphBuilder = NULL;
Вот и все, что относится к воспроизведению MP3-музыки в ваших проектах!
netlib.narod.ru | < Назад | Оглавление | Далее > |