Создаем свой медиаплеер на базе библиотеки vlc lib с нуля

Приветствую вас дамы, господа, ожившие механизмы, ксеносы и другие, mynameisinfinityandilivetits и сегодня мы создадим свой медиаплеер на базе готовых боярских библиотек от плеера vlc (https://www.videolan.org/vlc/).

Создаем свой медиаплеер на базе библиотеки vlc lib с нуля Программирование, Своими руками, Длинное, Плеер, Тыжпрограммист, Туториал, Длиннопост

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

Итак ближе к делу. Я буду использовать лазарус (кроссплатформная среда разработки для фрипаскаля), так как мне лень лишний раз возится, но логику объясню вне конкретного языка, для твоей системы и языка исходники тут (https://www.videolan.org/vlc/libvlc.html). В частности для джава (https://github.com/caprica/vlcj) и сиплюсплюс (https://code.videolan.org/videolan/libvlcpp). Для паскаля сурсы будут в моем проекте, но ссылка также (https://wiki.videolan.org/Using_libvlc_with_Delphi/) тут.

Создаем новый проект десктопного приложения, и сразу добавляем формы, в моем случае я добавил сразу 5 форм (в идеале даже 6 или больше), для области рисования видео, для плейлиста, кнопок управления, меню и тд. Так как мой интерфейс будет содержать всякие финтефлюшки.

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

У всех окон я убираю стандартный бордюр (так как любой колхозный плеер имеет свои, это канон), и добавляю на форму 6 панелек и таймер, панели размещаю и привязываю так чтобы получился бордюр окна с заголовком, но только в 1 пиксель.

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

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

// вспомогательная переменная для получения координат курсора

help_last_resize_position:TPoint;

// еще одна, для получения размера окна плеера и его позиции

help_last_resize_position2:TPoint;

// а эта для таймера, чтобы определять какие манипуляции надо делать

rsz_move_type:string;

И на самом деле у меня для всех событий отпускания клавиши одна процедура\функция\события, которое я просто создал для одной панельки, и потом присвоил эту процедуру в качестве события отпускания для всех, так как она просто отключает таймер.

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

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

// процедура для обработки простого перемещения окна по экрану

// типа тык по заголовку окна

procedure TMP.BRDTRMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

Begin


// получаем во вспомогательную переменную

// координаты тыка мыши по оси Х

help_last_resize_position.X:=X;


// получаем во вспомогательную переменную

// координаты тыка мыши по оси У

help_last_resize_position.Y:=Y;


// получаем в другую вспомогательную переменную

// отступ слева (отступ окна плеера, от левого

// края экрана, в пикселях), к которому прибавляем

// ширину окна плеера

help_last_resize_position2.X:=MP.Left+MP.Width;


// получаем в другую вспомогательную переменную

// отступ сверху (отступ окна плеера, от верхнего

// края экрана, в пикселях), к которому прибавляем

// высоту окна плеера

help_last_resize_position2.Y:=MP.Top+MP.Height;


// получаем во вспомогательную переменную тип

// манипуляции с окном программы, в моем случе

// по слову top я буду определять что это простое

// перемещение окна программы

rsz_move_type:='top';


// включаем наш таймер, который был изначально выключен

Rsz.Enabled:=true;

end;

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

ШиринаОкнаПрограммы = ШиринаОкнаПрограммы + (ТекущиеКоординатыМышиПоОсиХ - (ОтступОкнаПрограммыОтЛевогоКраяЭкрана+ШиринаОкнаПрограммы ));

Или пример для изменения размера справа, где мы изменяем положение отступа окна слева и ширину

ОтступОкнаПрограммыОтЛевогоКраяЭкрана = ТекущиеКоординатыМышиПоОсиХ -КоординатыМышиВМоментНачалаИзмененияРазмера;

ШиринаОкнаПрограммы = ОтступОкнаПрограммыОтЛевогоКраяЭкрана + ШиринаОкнаПрограммы + (КоординатыМышиВМоментНачалаИзмененияРазмера -ТекущиеКоординатыМышиПоОсиХ );

Как то так. Чтобы не забивать голову вот мой код.

// волшебный код который не требует комментариев

if rsz_move_type = 'move' then

begin

MP.Left:=Mouse.CursorPos.X-help_last_resize_position.X;

MP.Top:=Mouse.CursorPos.Y-help_last_resize_position.Y;

end;

if rsz_move_type = 'right_bottom' then

begin

MP.Width:=MP.Width + (Mouse.CursorPos.X - (MP.Left+MP.Width));

MP.Height:=MP.Height + (Mouse.CursorPos.Y - (MP.Top+MP.Height));

end;

if rsz_move_type = 'right' then

begin

MP.Width:=MP.Width + (Mouse.CursorPos.X - (MP.Left+MP.Width));

end;

if rsz_move_type = 'bottom' then

begin

MP.Height:=MP.Height + (Mouse.CursorPos.Y - (MP.Top+MP.Height));

end;

if rsz_move_type = 'left' then

begin

MP.Left:=Mouse.CursorPos.X-help_last_resize_position.X;

MP.Width:=help_last_resize_position2.X+(help_last_resize_position.X-Mouse.CursorPos.X);

end;

if rsz_move_type = 'top' then

begin

MP.Top:=Mouse.CursorPos.Y-help_last_resize_position.Y;

MP.Height:=help_last_resize_position2.Y+(help_last_resize_position.Y-Mouse.CursorPos.Y);

end;


// помимо изменения размера и положения окна плеера

// перетаскиваю вслед за ним и задаю новые размеры для

// плейлистов, панели кнопок плеера и тд

TopMenu.Left:=MP.Left+1;

TopMenu.Top:=MP.Top+1;

TopMenu.Width:=MP.Width-2;

TopMenu.Visible:=true;

TopMenu.BringToFront;

PlayerControls.Left:=MP.Left+1;

PlayerControls.Top:=MP.Top+(MP.Height-51);

PlayerControls.Width:=MP.Width-2;

PlayerControls.Visible:=true;

PlayerControls.BringToFront;

if PMenu.Visible = true then

begin

PMenu.Left:=MP.Left;

PMenu.Top:=MP.Top+51;

PMenu.Height:=MP.Height-102;

PMenu.Width:=400;

end;

if Playlist.Visible = true then

begin

Playlist.Visible:=true;

Playlist.Left:=(MP.Left+MP.Width)-Playlist.Width;

Playlist.Top:=MP.Top+51;

Playlist.Height:=MP.Height-102;

end;

Теперь когда у нас есть окно плеера подтянем картинки со звуками на экран, подключением библиотеки lib_vlc.dll. Все функции из этой библиотеки интуитивно понятны и одинаковы для всех языков. Полный список функций из библиотек можно посмотреть на сайте (https://videolan.videolan.me/vlc/group__libvlc.html).

Подключаем исходники связывающие библиотеку с описанными функциями-заголовками (для паскаля это uses PasLibVlcUnit). Создаем две глобальных переменных, первая переменная типа libvlc_instance_t_ptr, вторая переменная типа libvlc_media_player_t_ptr, для экземпляра библиотеки и плеера, название может быть любым, у меня они называются из примеров p_li и p_mi (неудачные сокращения от либрарей инстанс и медиа инстанс).

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

function INITVLC:boolean;

begin


// загружаем библиотеку и линкуем заголовки

// для того чтобы эта функция работала корректно

// на компьютере должен быть vlc media player

// я же использую ее так как у меня кривая сборка

// винды, в которой не регистрируются дллешки

libvlc_dynamic_dll_init();


// загружаем библиотеку из какого нибудь места

// в качестве аргумента функции я передаю

// содержимое моей глобальной переменной app_path,

// в которую я поместил путь до моей программы,

// к которой добавляю название библиотеки с плеером

//libvlc_dynamic_dll_init_with_path(app_path+'libvlc.dll');


// создаю условие, если содержимое переменной

// libvlc_dynamic_dll_error из PasLibVlcUnit

// содержит что то большее чем ничего, вызываю

// стандартное диалоговое окно системы, и вывожу

// код ошибки из libvlc_dynamic_dll_error

if (libvlc_dynamic_dll_error <> '') then

begin


// вызываю диалог

MessageDlg(libvlc_dynamic_dll_error, mtError, [mbOK], 0);


// уничтожаю экземпляр программы

// и завершаю работу приложения

Application.Terminate();


// экстренно прирываю выполнение дальнейшего кода

exit;

end;


// с объектом библиотеки PasLibVlcUnit

// создаю новый экземпляр перменной, в

// которую помещаю дополнительные параметры

// для загрузки библиотеки

with TArgcArgs.Create([

WideString(libvlc_dynamic_dll_path),

'--intf=dummy',

'--ignore-config',

'--quiet',

'--no-video-title-show',

'--no-video-on-top'

]) do

begin


// вызываю функцию из библиотеки PasLibVlcUnit,

// которая создает новый экземпляр условного

// скрытого плеера vlc с аргументами и ассоциирую

// ее с переменной p_li

p_li := libvlc_new(ARGC, ARGS);


// уничтожаю объект TArgcArgs, так как он больше

// не нужен

Free;

end;


// создаю условие, если переменная экземпляра p_li

// содержит что то, кроме ничего продолжаю действия

if (p_li <> NIL) then

begin


// ассоциирую с переменной p_mi результат выполнения

// функции libvlc_media_player_new, в которой передаю

// в качестве аргумента переменную с загруженным

// экземпляром библиотеки lib_vlc.dll

p_mi := libvlc_media_player_new(p_li);


end;


// возвращяю результат работы функции как true

result:=true;

end;

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

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

function StopVideo:boolean;

begin


// создаю условие, если содержимое

// переменной p_mi с медиаплеером

// не равно ничему, выполняю содержимое

// условия

if (p_mi <> NIL) then

begin


// вызываю функцию из библиотеки

// PasLibVlcUnit, которая выполняет паузу,

// в качестве аргумента указываю

// переменную с которой ассоциирован

// экземпляр плеера

libvlc_media_player_pause(p_mi);


// выполняю перерисовку области экрана

// это для моих финтифлюшек, этот код не

// обязателен

MP.Monitor1.Repaint;

MP.Monitor1.ParentBackground:=false;

MP.Monitor1.ParentBackground:=true;

end;


// возвращяю результат выполнения функции как true

result:=true;

end;


function PlayVideo(filename:WideString):boolean;

var


// создаю переменную типа медиаобъект

// из библиотеки PasLibVlcUnit

p_md : libvlc_media_t_ptr;


// слздаю вспомогательную переменную

// для конвертирования имени файла

// типа строка анси

a_st : AnsiString;


// и еще одну типа символ

p_st : PAnsiChar;

begin


// конвертирую содержимое аргумента

// функции PlayVideo в фют8

a_st := UTF8Encode(fileName);


// получаю первый символ из пути,

// который конвертирую в формат анси,

// не совсем понятно для чего это

p_st := PAnsiChar(@a_st[1]);


// создаю условие, если содержимое

// переменной, с которой ассоциированна библиотека

// lib_vlc.dll больше чем ничего, продолжаю действия

if (p_li <> NIL) then

begin


// вызываю функцию из библиотеки PasLibVlcUnit

// которая получает информацию об файле, его тип,

// размер и тд, в качестве параметра передаю

// содержимое вспомогательных переменных, с которыми

// я ассоциировал конвертированный в формат ютф8

// путь к файлу с имененм, результат выполнения

// функции помещяю в другую вспомогательную перменную p_md

p_md := libvlc_media_new_path(p_li, p_st);


// создаю условие, если содержимое

// переменной p_md больше чем ничего,

// продолжаю действия

if (p_md <> NIL) then

begin


// создаю условие, если содержимое

// переменной с экземпляром медиаплеера

// больше чем ничего, продолжаю действия

if (p_mi <> NIL) then

begin


// вызываю функцию из библиотеки PasLibVlcUnit,

// которая позволяет перехватить из программы,

// в библиотеку обработку нажатия клавиш клавиатуры,

// в качестве параметров передаю переменную с медиаплеером

// и указатель 0, так как обрабатывать клавишы

// будет моя программа

libvlc_video_set_key_input(p_mi, 0);


// выполняю аналогичную операцию для мыши

libvlc_video_set_mouse_input(p_mi, 0);


// вызываю функцию из библиотеки PasLibVlcUnit,

// которая позволяет назначить какой нибудь объект,

// у которого есть в своем содержимом область для

// рисования в качестве экрана для видео, в качестве

// параметров передаю переменную с экземпляром плеера,

// и индекс объекта с областью рисования в формате

// системы, у меня это панелька с названием Monitor1

libvlc_media_player_set_display_window(p_mi, MP.Monitor1.Handle);


// вызываю функцию из библиотеки PasLibVlcUnit,

// которая позволяет ассоциировать медиаобъект с

// экземпляром плеера, в качестве параметра передаю

// экземпляр медиплеера из глобальной переменной и

// содержимое вспомогательной переменной с информацией

// о медиафайле

libvlc_media_player_set_media(p_mi, p_md);

end;


// вызываю функцию из библиотеки PasLibVlcUnit,

// которая позволяет определить и декодировать файл

libvlc_media_release(p_md);

end;

end;


// возвращяю результатом выполнения функции true

result:=true;

end;

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

procedure TPlayerControls.Image1Click(Sender: TObject);

begin


// создаю условие если результат выполнения

// функции из библиотеки PasLibVlcUnit под названием

// libvlc_media_player_get_state вернул значение,

// которое соответствует условному ключевому слову

// из библиотеки libvlc_Paused, выполняю действия условия

if libvlc_media_player_get_state(p_mi) = libvlc_Paused then

begin


// вызываю функцию воспроизведения

libvlc_media_player_play(p_mi);


// это финтефлюшки, изменяю иконку кнопки

// воспроизведение с воспроизводить на паузу

Self.Image1.Picture:=Self.src_img_pause.Picture;

// внезапно прерываю выполнение процедуры

exit;

end;

if libvlc_media_player_get_state(p_mi) = libvlc_Playing then

begin

libvlc_media_player_pause(p_mi);

Self.Image1.Picture:=Self.src_img_play.Picture;

exit;

end;

if libvlc_media_player_get_state(p_mi) = libvlc_Ended then

begin

libvlc_media_player_play(p_mi);

Self.Image1.Picture:=Self.src_img_pause.Picture;

exit;

end;

if libvlc_media_player_get_state(p_mi) = libvlc_Stopped then

begin

libvlc_media_player_play(p_mi);

Self.Image1.Picture:=Self.src_img_pause.Picture;

exit;

end;

end;

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

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

Плейлист я размещу в отдельном окне и возьму для него стандартную заготовки из системных библиотек TListBox (в с++ cli это ListBox как не парадоксально, и JList вjdk). Еще добавлю новый таймер, который будет получать текущую позицию времени воспроизводимого файла, и обновлять прогресс панельки со временем.

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

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

function ConvertMsToNormalTime(i:TCaption):TCaption;

var a:string;

b:real;

c,d:integer;

min,sec,hours:integer;

begin

a:='';

c:=0;

d:=round(StrToFloat(i));

min:=0;

sec:=0;

hours:=0;

while c < d do

begin

inc(sec);

if sec = 60 then

begin

inc(min);

sec:=0;

end;

if min = 60 then

begin

inc(hours);

min:=0;

end;

inc(c);

end;

if hours < 10 then

begin

a:=a+'0'+IntToStr(hours)+':';

end else

begin

a:=a+IntToStr(hours)+':';

end;

if min < 10 then

begin

a:=a+'0'+IntToStr(min)+':';

end else

begin

a:=a+IntToStr(min)+':';

end;

if sec < 10 then

begin

a:=a+'0'+IntToStr(sec);

end else

begin

a:=a+IntToStr(sec);

end;

result:=a;

end;

Теперь сама функция таймера-обновлятеля прогресса временной шкалы.

procedure TMP.MoveTimerTimer(Sender: TObject);

// создаю вспомогательные переменные типа

// реальное число (для быдлокодеров поясню что

// это число с плавающей запятой)

var a,s1,s2,s3:real;


// создаю вспомогательные переменные типа число

// (целое число)

var b,c:integer;

begin


// создаю условие, если с переменной

// для экземпляра ассоциированно что

// то что больше ничего, выполняю код

// условия

if (p_mi <> NIL) then

begin


// создаю условие, если функция

// libvlc_media_player_get_state для

// получения статуса плеера из

// библиотеки PasLibVlcUnit возвращяет

// значение, которое соотвествует

// описанному в библиотеке PasLibVlcUnit

// libvlc_Playing значение, выполняю код условия

if (libvlc_media_player_get_state(p_mi) = libvlc_Playing) then

begin


// ассоциирую со вспомогательной

// переменной значени 0

b:=0;


// начинаю цикл с условием

// повторять до тех пор, пока

// значение переменной b меньше 100

while b < 100 do

begin


// со вспомогательной переменной

// ассоциирую результат выполнения функции

// libvlc_media_player_get_position, которая

// позволяет получить текущую позицию в милисекундах

// воспроизводимого видео, из библиотеки PasLibVlcUnit,

// в качестве параметра передаю глобальную переменную

// с которой ассоциирован экземпляр плеера, и конвертируя

// встроенной функцией паскаля Real привожу данные к типу

// число с плавующей точкой, которое округляю до секунд

s1:=RoundTo(Real(libvlc_media_player_get_position(p_mi)),-3);


// создаю условие, если 1 деленный

// на 100 умноженный на содержимоей

// вспомогательной переменной b больше

// значения s1 выполняю условие, иначе

// выполняю альтернативное действие

// (функция libvlc_media_player_get_position

// возвращяет значение в диапозоне от 0.0 до

// 1.0)

if ((1 / 100) * Real(b) >= s1) then

begin


// переношу значение переменной b

// в другую вспомогательную переменную c

// и прекращяю цикл

c:=b;

b:=100;


end ELSE

begin

c:=100;

end;

inc(b);

end;


// для панельки прогресса задаю ширину,

// которая равна округленному процентному

// соотношению всей временной шкалы,

// которая у меня представлена в другой

// панельке

PlayerControls.Time2.Width:=Round((PlayerControls.Time1.Width / 100) * c);


// в надпись (или обхект Textlabel) помещаю результат

// выполнения вспомогательной функции для конвертирования

// секунд в привычный формат, в которую передаю (конвертируя

// в текст значение с плавующей точкой), которое получаю

// из функции библиотеки PasLibVlcUnit, которая возвращяет

// текущее время воспроизведения в милисекундах

PlayerControls.Label1.Caption:=ConvertMsToNormalTime(FloatToStr(libvlc_media_player_get_time(p_mi) / 1000));


// аналогичную операцию проделываю для другой надписи,

// в которой находится полное время видео

PlayerControls.Label2.Caption:=ConvertMsToNormalTime(FloatToStr(Real(libvlc_media_player_get_length(p_mi)) / 1000))+' ('+IntToStr(c)+'%)';

end;


// создю условие, если результат выполнения функции

// libvlc_media_player_get_state возвращяет значение соотвествующие

// libvlc_Ended из библиотеки PasLibVlcUnit, выполняю действия условия

if libvlc_media_player_get_state(p_mi) = libvlc_Ended then

begin


// задаю ширину панельки прогресса, равную ширине

// всей панельки времени

PlayerControls.Time2.Width:=PlayerControls.Time1.Width;


// ещё раз получаю текущее время воспроизведения

// видео (позицию воспроизведения)

PlayerControls.Label1.Caption:=ConvertMsToNormalTime(FloatToStr(libvlc_media_player_get_time(p_mi) / 1000));


// отключаю таймеры моих финтифлюшек

// этот код не обязателен

MP.MoveTimer.Enabled:=false;

MP.Player_Next.Enabled:=true;

end;

end;

end;

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

procedure TPlayerControls.Time1Click(Sender: TObject);

// создаем вспомогательные переменные

// типа целое число

var b,c:integer;


begin

// со вспомогательной переменной ассоциируем

// координаты курсора по оси Х, из которых

// вычитаем все отступы от левого края экрана,

// до нашей панельки с прогрессом

c:=Mouse.CursorPos.X - (1+MP.Left+Time1.left);


// начинаем цикл для получения процентного

// значения панельки воспроизведения

b:=0;

while b <= 99 do

begin


// создаем условие, если конвертированное

// в число с плавующей точкой значение

// ширины панельки текущего времени деленное

// на 100 и умноженное на значение переменной b

// больше или равно значениею переменной c

// выполняем дийствия условия

if Real(Time1.Width / 100) * b >= c then

begin


// из библиотеки PasLibVlcUnit вызываем функцию для

// изменения времени воспроизведения, в качестве параметра

// указываем переменную с которой ассоциирован экземпляр

// плеера и новое время в формате числа с плавующей точкой,

// которое получаем из умножения 1 на значение переменной b

libvlc_media_player_set_position(p_mi, StrToFloat(FloatToStr(Real(1) / Real(99) * b)));


// вызываем функцию для воспроизведения

// видео, из библиотеки PasLibVlcUnit, которая

// начинает воспроизведение видео, в качестве параметра

// указываем переменную с которой ассоциирован экземпляр

libvlc_media_player_play(p_mi);

b:=100;

end;

inc(b);

end;

end;

Вот у нас есть уже рабочий плеер, и в нем даже есть временная шкала. Давайте я еще немного расскажу про плейлист и в принципе альфа версия плеера будет готова. Так как у меня плеер планировался преимущественно как видеоплеер, как альтернатива тому же vlc media player, с функционалом больше приближенным к ютюбу и вообще интерфейсом веб плеера, у меня нет в программе получения расширенной информации о медиа.

Это получить не так сложно, тем более что vlc уже все сам сделал, просто нужно взять, написав соответствующую функцию-запрос (вики по vlc lib в помощь). У меня плейлист будет содержать информацию о размере файла, имя файла и расположение.

При этом во время загрузки первого файла, как и WMP, мой плеер ищет все другие воспроизводимые форматы в той же папке и помещает их в плейлист. Насколько мне известно vlc работает со всеми основными форматами медиа.

В моей программе планировался совмещенный режим с просмотром фотографии, поэтому у меня список немного другой.

*.mp4;*.mp3;*.mp2;*.wmv;*.wma;*.avi;*.asf;*.mov;*.mkv;*.wav;*.ogg;*.ogm;*.flac;*.flv;*.mxf;*.smf;*.mid;*.3gp;*.jpg;*.jpeg;*.png;*.gif;*.bmp;*.ico;*.tif;*.tiff;

В лазарусе для этого есть функция FindAllFiles(), у вас может быть другая (скорее всего стандартный интерфейс с результирующим листом, или функция FindFirst, FindNext). Я просто помещаю в список листа все полные пути к файлам, которые перерисовываю в событии отрисовки элементов списка TListBox.

procedure TPlaylist.ListBox1DrawItem(Control: TWinControl; Index: Integer;

ARect: TRect; State: TOwnerDrawState);


// создаю числовую переменную

var b:integer;

begin


// с объектом канвас у ListBox начинаю действия

with ListBox1.Canvas do

begin


// создаю условие, если значение

// передаваемого аргумента с текущим

// индексом в листе, которое, деленное

// имеет остаток 0, выполняю условия,

// иначе перехожу к альтернативному условию

if (Index) mod 2 = 0 then

begin


// у объхекта канвас листбокса1

// свойства цвета фона закраски задаю

// из глобальной вспомогательной переменной,

// в которой содержится код цвета

Brush.Color := style_base_color;


// аналогично для цвета отрисовки

Font.Color := style_text_color;


// заполняю фоновым цветом

// всю область отрисовки

FillRect(ARect);


// для текстовой отрисовки

// задаю размер шрифта в 10

Font.Size:=10;


// отрисовываю текст в координатах,

// которые были получены в качесте аргумента,

// отрисовываю имя файла, полученное из

// значения строки списка, которое пропускаю

// через функцию, которая отрезает из названия

// расширение и путь (то есть оставляет только имя)

TextOut(ARect.Left+4, ARect.Top, GetFileNameFromFullPath(ListBox1.Items[Index]));


// для текстовой отрисовки

// задаю размер шрифта 6

Font.Size:=6;


// отрисовываю в сдвинутых координатах, относительно

// и внутри области отрисовки, отрисовываю полный

// путь к файлу с имененм

TextOut(ARect.Left+4, ARect.Top+16, ListBox1.Items[Index]);


end else

begin

// Альтернативное условие,

// делаю все тоже саоме,

// олько инвертирую цвета отрисовки

// и заливки

Brush.Color := style_text_color;

FillRect(ARect);

Font.Color := style_base_color;

Font.Size:=10;

TextOut(ARect.Left+4, ARect.Top, GetFileNameFromFullPath(ListBox1.Items[Index]));

Font.Size:=6;

TextOut(ARect.Left+4, ARect.Top+16, ListBox1.Items[Index]);

end;

end;

end;

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

Ссылка на сурсы (https://1drv.ms/u/s!Att7piQftCNFgSAEPOUhgXc0jR5R?e=F2CALy)

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