Проигрывание
аудио- и видеофайлов стандартными средствами Windows в Delphi – с помощью видеоплейера и модуля MMSystem, обычно затруднений не вызывает. Однако, если речь идет об использовании видео в свободном формате OGG – theora+vorbis, дело обстоит несколько сложнее.
Особенно, когда имеется ввиду воспроизведение в
приложении, которое может устанавливаться на машину, на которой соответствующие
кодеки отсутствуют.
Проще всего дело обстоит с воспроизведением звука. Популярные библиотеки fmod и bass имеют поддержку OGG, интегрируются с программами Delphi, и бесплатны для некоммерческого
применения. Есть возможность использовать и OpenAL,
что, правда, несколько сложнее. Хорошая подборка статей на эту тему (переводов
с сайта www.noeska.com) есть тут.
Хуже дело обстоит с видео в формате OGG-theora. Мне не удалось найти материалов про использование этого кодека в
программах на Delphi. Однако
в этих поисках я натолкнулся на свободно распространяемый вместе с исходными
кодами плейер VideoLAN
- VLC media player,
который содержит библиотеку, позволяющую воспроизводить аудио- и видеоматериалы
в формате OGG – theora+vorbis без
использования дополнительных кодеков. И что особенно ценно – эта библиотека (libvlc.dll) очень легко подключается к программам Delphi.
Я написал небольшой файл-интерфейс к этой библиотеке, который дает доступ к
большинству ее функций (кроме потоковых). Ниже я
изложу основные сведения, необходимые для использования libvlc.dll и основные
«подводные камни», которые я обнаружил.
За и против использования библиотеки от VideoLAN в
своих проектах.
За – бесплатность библиотеки и открытый код. Простота и многофункциональность.
Проигрывание множества форматов, в том числе OGG – theora+vorbis, без необходимости отдельной установки
кодеков в систему.
Против – необходимость
установки самого плейера VideoLAN (около 9 Мб для
полной инсталляции). В конце статьи я укажу способ, который позволяет этого
избежать.
Создадим новый проект, содержащий, как минимум, один стандартный компонент типа
TPanel. Этот компонент будет использоваться как экран для вывода видео. В секцию uses включим модуль libvlc.
В событие OnCreate формы включим следующий код:
var
err :integer;
args:array[0..1] of pchar;
val :TValue;
...
err := VLD_LoadLibrary; // загрузка библиотеки
// проверка кода ошибки
if err<>VLD_SUCCESS then
begin
case err of
VLD_NOLIB : ShowMessage('OOPS! libvlc.dll 0.8.6 not found!'); // библиотека не найдена
VLD_NOTFOUND: ShowMessage('libvlc.dll invalide ?!'); // библиотека не может загрузится
end;
Application.Terminate;
exit;
end;
// если всё в порядке, идем дальше
vlc:= VLC_Create; // создаем ссылку к библиотеке и получаем код экземпляра
args[0]:=pchar(VLD_LibPath); // передаем ссылку на путь, к файлу библиотеки. Почему он нужен – а чёрт
его знает, но иначе не работает...
args[1]:=nil;
VLC_Init(vlc,1,@args[0]);
val.AsInteger:=Panel1.Handle; // передаем ссылку на Handle компонента, который служит нашим экраном.
err := VLC_VariableSet(vlc,'drawable',val);
На этом
инициализация библиотеки закончена. Для проигрывания видеофайла, его необходимо
включить в список проигрывания, например, так:
if not OpenDialog1.Execute then exit; // Отмечаем файлы для проигрывания.
if VLC_IsPlaying(vlc) then VLC_Stop(vlc); // останавливаем проигрывание, если оно сейчас идет
VLC_PlaylistClear(vlc); // очищаем список проигрывания
for i := 0 to OpenDialog1.Files.Count - 1 do
begin
s:=UTF8Encode(OpenDialog1.Files[i]);
VLC_AddTarget(vlc,PChar(s),nil,0,PLAYLIST_APPEND,PLAYLIST_END); // добавляем пути к файлам в формате UTF8
// по очереди, в конец списка проигрывания
end;
Теперь список
можно проиграть командой:
VLC_Play(vlc);
Пример
простейшего плейера находится в файле delphi_vl.zip. Пример видеофайла, сделанного автором статьи -
flag10s.zip
прилагается. Свобода распространения гарантируется.
Внимание! Для работы этого примера у вас должен
быть установлен плейер VideoLAN - VLC media
player. Ссылка для скачивания инсталляции - http://www.videolan.org/mirror.php?file=vlc/0.8.6d/win32/vlc-0.8.6d-win32.exe
Для быстрой
конвертации видеофайлов других форматов в формат OGG удобна маленькая утилита командной строки ffmpeg2theora.
В данном примере
использован так называемый «старый интерфейс», который функционально ограничен.
В библиотеке есть набор функций «нового интерфейса», который обеспечивает
расширенную функциональность.
Предупреждение! Смешивать оба интерфейса нельзя! Надо с
самого начала инициализировать библиотеку или командой VLC_Create старого интерфейса, или командой libvlc_new интерфейса
нового – возвращаемые ими значения разные!
Объяснения команд
можно посмотреть в сишных заголовочных файлах libvlc.h и vlc.h исходников или
на сайте, на страницах http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc.html
и http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__old.html
Теперь интересный вопрос – как распространять библиотеку совместно со
своими программами.
Просто приложить
файл libvlc.dll к сожалению недостаточно – требуется
регистрация пути к нему в реестре Windows. Но и этого
мало – библиотека использует многочисленные
дополнения-plugin’ы, которые находятся в
отдельных файлах. Расположены эти plugin’ы должны быть в подкаталоге с именем plugins в том каталоге, который зарегистрирован в
реестре как корневой для библиотеки. Всего в поставку входит этих plugin’ов целых 210 штук и они составляют основной объем
инсталляции. Разумеется, для простого проигрывания нужны они не все, но выяснить,
какие именно необходимы – задача не тривиальная.
Автором экспериментально J был установлен минимальный набор plugin’ов достаточных для воспроизведения OGG – theora+vorbis аудио-видео через Direct3D. Это
libaccess_file_plugin.dll
libdirect3d_plugin.dll
libogg_plugin.dll
libtheora_plugin.dll
libtrivial_channel_mixer_plugin.dll
libtrivial_mixer_plugin.dll
libtrivial_resampler_plugin.dll
libvorbis_plugin.dll
libwaveout_plugin.dll
libwingdi_plugin.dll
Всего около 1,5 Мб. Этот набор содержится в файле vlc.zip. Для использования libvlc.dll на машине, на которой VideoLAN не установлен, надо содержимое этого файла
распаковать куда-нибудь, и в программе запустить запись в реестр пути к файлу
libvlc.dll командой: VLD_Registry(apath), где apath – текстовая переменная (string), содержащая этот путь. Делать это,
разумеется, надо только в том случае, если функция VLD_LoadLibrary выдала код ошибки VLD_NOLIB.
Дополнение – список некоторых основных функций libvlc и их параметров
«Старый
интерфейс»:
VLC_Version
:function :pchar – версия библиотеки
VLC_Error :function (id :integer) :pchar – возвращает текстовое сообщение об ошибке с
кодом id
VLC_Create :function :integer; - инициализирует библиотеку и возвращает либо индекс
экземпляра библиотеки (положительное значение), либо код ошибки (отрицательное
значение)
VLC_Init :function (id,argc :integer; args:ppchar) :integer; - инициализирует служебную структуру библиотеки. id – индекс экземпляра библиотеки (возвращаемый функцией VLC_Create, argc – число передаваемых аргументов, args – список аргументов.
Возвращает код ошибки.
VLC_AddIntf :function (id:integer; module:pchar; block,play:longbool) :integer; - вызов стандартного интерфейса проигрывателя VLC media player. id – индекс экземпляра библиотеки, module – имя модуля интерфейса (модуль по умолчанию – nil), block – блокировать(True)/разблокировать(False) интерфейс, play – немедленно начать проигрывание списка, после старта. Возвращает
код ошибки.
VLC_Die :function (id :integer) :integer; - подготавливает деинициализацию, но больше
ничего не делает. Для того, чтобы деинициализировать
библиотеку реально, необходимо вызвать функции VLC_CleanUp и VLC_Destroy. id – индекс экземпляра библиотеки. Возвращает код
ошибки.
VLC_CleanUp :function (id :integer) :integer; - очищает все списки, освобождает устройства ввода и вывода. id – индекс экземпляра библиотеки. Возвращает код
ошибки.
VLC_Destroy :function (id :integer) :integer; - деинициализирует библиотеку. id – индекс экземпляра библиотеки. Возвращает код ошибки.
VLC_VariableSet :function (id :integer; Name :pchar; value :TValue) :integer; - устанавливает значение внутренней переменной (аналогично параметрам
командной строки VLC media player). id – индекс экземпляра библиотеки. Name – название переменной, value – ёё значение. Возвращает код ошибки.
VLC_VariableGet :function (id :integer; Name :pchar; var value:TValue):integer; - позволяет прочитать значение
внутренней переменной. id – индекс экземпляра библиотеки. Name – название переменной, value – ёё значение. Возвращает код ошибки.
VLC_VariableType :function (id :integer; Name: pchar; var typeid:integer):integer; - возвращает тип внутренней
переменной.
(список параметров командной
строки можно прочитать в документации, на сайте http://wiki.videolan.org/Documentation:Play_HowTo/Advanced_Use_of_VLC#Use_the_command_line)
VLC_AddTarget :function (id :integer; target :pchar; szoptions :ppchar; options,mode,pos:integer):integer; - добавляет ссылку на медиафайл в список проигрывания. id – индекс экземпляра библиотеки. target – путь к файлу, szoptions – список опций проигрывания, таких, как :input-repeat и т.п. options – число элементов списка, mode – способ вставки (например, PLAYLIST_APPEND), pos – позиция вставки (например, PLAYLIST_END). Возвращает
код ошибки.
VLC_Play :function (id :integer) :integer; - проигрывает список. id – индекс экземпляра библиотеки. Возвращает код
ошибки.
VLC_Pause :function (id :integer) :integer; - приостонавливает проигрывание текущей записи.
id – индекс экземпляра библиотеки. Возвращает код ошибки.
VLC_Stop :function (id :integer) :integer; - прекращает проигрывание. id – индекс экземпляра библиотеки. Возвращает код
ошибки.
VLC_IsPlaying :function (id:integer):longbool; - возвращает True, если идет
проигрывание. id – индекс экземпляра библиотеки.
VLC_PlaylistIndex :function (id:integer):integer; - возвращает номер текущей
записи в списке проигрывания. id – индекс экземпляра библиотеки.
VLC_PlaylistNumberOfItems :function (id:integer):integer; - возвращает число записей в
списке проигрывания. id – индекс экземпляра библиотеки.
VLC_PlaylistNext :function (id:integer):integer; - переходит к следующей записи
в списке и начинает проигрывание. id – индекс экземпляра библиотеки. Возвращает код
ошибки.
VLC_PlaylistPrev :function (id:integer):integer; - переходит к предыдущей записи
в списке и начинает проигрывание. id – индекс экземпляра библиотеки. Возвращает код
ошибки.
VLC_PlaylistClear :function (id:integer):integer; - очищает список проигрывания. id – индекс экземпляра библиотеки. Возвращает код ошибки.
VLC_VolumeGet :function (id:integer):integer; - возвращает уровень громкости
звука (в %) – число в интервале 0..200. id – индекс экземпляра
библиотеки.
VLC_VolumeMute :function (id:integer):integer; - работает как триггер,
включая/отключая звук. id – индекс экземпляра библиотеки.
VLC_VolumeSet :function (id,volume:integer):integer; - изменяет уровень громкости звука (в %). id – индекс экземпляра библиотеки. volume – число в интервале 0..200.
VLC_FullScreen :function (id:integer):integer; - работает как триггер,
включая/отключая полноэкранный режим. id – индекс экземпляра библиотеки.
«Новый интерфейс»:
libvlc_new
:function (argc:integer; args:ppchar; var exception:libvlc_exception):libvlc_instance; - инициализирует библиотеку. Переменные argc и args имеют тот же смысл, что и для функции VLC_Init. exception – запись об ошибке. Возвращает ссылку на новый
экземпляр библиотеки, который будет использоваться во всех остальных функциях.
libvlc_destroy :procedure (vlc:libvlc_instance); - уничтожает экземпляр библиотеки. vlc – ссылка на эту библиотеку.
libvlc_exception_clear
:procedure (var exception:libvlc_exception); - очищает запись об ошибке. exception – запись об ошибке.
libvlc_playlist_play :procedure (vlc:libvlc_instance; index,optCount:integer; opts:ppchar; var exception:libvlc_exception); - аналог VLC_Play. vlc – ссылка на библиотеку. exception – запись об ошибке.
libvlc_playlist_pause
:procedure (vlc:libvlc_instance; var exception:libvlc_exception); - аналог VLC_Pause.
libvlc_playlist_isplaying
:function (vlc:libvlc_instance; var exception:libvlc_exception):longbool; - аналог VLC_IsPlaying
libvlc_playlist_items_count
:function (vlc:libvlc_instance; var exception:libvlc_exception):integer; - аналог VLC_PlaylistNumberOfItems.
libvlc_playlist_stop
:procedure (vlc:libvlc_instance; var exception:libvlc_exception);- аналог VLC_Stop.
libvlc_playlist_next
:procedure (vlc:libvlc_instance; var exception:libvlc_exception); - аналог VLC_PlaylistNext.
libvlc_playlist_prev
:procedure (vlc:libvlc_instance; var exception:libvlc_exception); - аналог VLC_PlaylistPrev.
libvlc_playlist_clear
:procedure (vlc:libvlc_instance; var exception:libvlc_exception); - аналог VLC_PlaylistClear.
libvlc_playlist_add
:function (vlc:libvlc_instance; fileName,name:pchar; var exception:libvlc_exception):integer; - аналог VLC_AddTarget, упрощенный.
libvlc_playlist_add_extended
:function (vlc:libvlc_instance; fileName,name:pchar; optCount:integer; opts:ppchar; var exception:libvlc_exception):integer; - аналог VLC_AddTarget.
libvlc_playlist_delete_item
:function (vlc:libvlc_instance; i_id:integer; var exception:libvlc_exception):libvlc_input; - удаляет запись с номером i_id из списка.
libvlc_playlist_get_input
:function (vlc:libvlc_instance; var exception:libvlc_exception):libvlc_input; - проверяет существует ли устройство для вывода видео и возвращает ссылку на него.
libvlc_video_set_parent :procedure (input:libvlc_instance; handle:HWND; var exception:libvlc_exception); - назначает для видеоустройства визуальный элемент (форму, панель и
т.п.) с дескриптором handle. Здесь и
далее input – ссылка на устройство вывода видео, которую
возвращает функция libvlc_playlist_get_input.
libvlc_video_set_size
:procedure (input:libvlc_instance; width,height :integer; var exception:libvlc_exception); - изменяет размеры выводимого изображения. Действует не всегда, а только для тех устройств, размеры которых могут
свободно изменяться. width,height – ширина и высота изображения, соответственно.
libvlc_toggle_fullscreen
:procedure (input:libvlc_input; var exception:libvlc_exception); - управление полноэкранным режимом.
libvlc_set_fullscreen
:procedure (input:libvlc_input; var exception:libvlc_exception); - устанавливает полноэкранный режим.
libvlc_get_fullscreen
:function (input:libvlc_input; var exception:libvlc_exception):longbool; - проверяет текущий режим.
libvlc_video_get_width :function (input:libvlc_input; var exception:libvlc_exception):integer; - возвращает текущую ширину
изображения.
libvlc_video_get_height
:function (input:libvlc_input; var exception:libvlc_exception):integer; - возвращает текущую высоту изображения.
libvlc_video_get_aspect_ratio
:function (input:libvlc_input; var exception:libvlc_exception):pchar; - возвращает текущее соотношение высоты к ширине изображения.
libvlc_video_set_aspect_ratio
:procedure (input:libvlc_input; aspect :pchar; var exception:libvlc_exception); - изменяет текущее соотношение высоты к ширине изображения.
libvlc_video_take_snapshot
:procedure (input:libvlc_input; filepath :pchar; var exception:libvlc_exception); - выполняет снимок экрана. Изображение записывается в файл с
путем filepath, с именем и расширением по умолчанию.
libvlc_audio_toggle_mute
:procedure (vlc:libvlc_instance; var exception:libvlc_exception); - аналог VLC_VolumeMute.
libvlc_audio_get_mute
:function (vlc:libvlc_instance; var exception:libvlc_exception):longbool; - проверяет, отключен ли звук.
libvlc_audio_set_mute
:procedure (vlc:libvlc_instance; mute:longbool; var exception:libvlc_exception); - выключает звук.
libvlc_audio_get_volume
:function (vlc:libvlc_instance; var exception:libvlc_exception):integer; - аналог VLC_VolumeGet.
libvlc_audio_set_volume
:procedure (vlc:libvlc_instance; volume:integer; var exception:libvlc_exception); - аналог VLC_VolumeSet.
Снег Север.
Декабрь 2007 г.
Вернуться к списку статей | Вернуться на главную страницу |