Приветствую вас дамы, господа, ожившие механизмы, ксеносы и другие, mynameisinfinityandilivetits и сегодня мы создадим свой медиаплеер на базе готовых боярских библиотек от плеера vlc (https://www.videolan.org/vlc/).
Для этого нам понадобится какой нибудь компилятор (библиотека портированна на все нормальные языки программирования), и немного упорства, чтобы прочитать эту статью. Ну или чтобы скопипастить (ссылку на все исходники с готовым проектом я добавлю в конце).
Итак ближе к делу. Я буду использовать лазарус (кроссплатформная среда разработки для фрипаскаля), так как мне лень лишний раз возится, но логику объясню вне конкретного языка, для твоей системы и языка исходники тут (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
- b:=100;
- end;
- // b = b + 1;
- 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;
- //a:TLCLTextMetric;
- //var f:file;
- begin
- //AssignFile(f, ListBox1.Items[Index]);
- //Draw(0,0,Playlist.img_icon_music.Picture.Graphic);
- // с объектом канвас у 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)
В общем на этом я думаю можно закончить, так как альфа плеера по сути описана, а что то дополнительное для слабаков. Надеюсь данная статья будет полезна, поделись своим мнением и если есть какие либо ошибки и предложения, ты всегда можешь дополнить меня в комментах, спасибо за внимание^^