Тыжпрограммист и Оно
Меня часто просят прийти и "посмотреть компьютер, там фигня, тебе на пять минут работы". И если вы думаете, что я буду разводить стандартные сопли, что на самом деле там секаса на пять часов, то вы ошибаетесь. Я сейчас совсем про другое вам расскажу. Эта история, достойная экранизации лучшими мастерами триллеров, произошла, когда коллега обратился к мне с вышеупомянутой просьбой.
Ладно, прихожу в гости, смотрю - в компе стандартный набор мусора, тормозит, windows под админской учёткой, короче пару ебля-часов нужно потратить. Ладно, усаживаюсь за комп, принимаю из рук хозяйки бокал брендяка и сыр, потягиваю бухлишко, жую. Вокруг меня вертится мелкий пиздюк 7 годиков от роду. Назову его условно Олегом. Между делом познакомились, разговорились. Вполне нормальный пацан, общительный, умный и любознательный.
Постепенно разговор подзатих, я уткнулся в монитор, а Олежка начал чего-то там шуршать своими игрушками, Работа уже подходила к концу, как я, жуя очередной кусочек, ВНЕЗАПНО ощутил вонь свежей сранины! Судорожно проглотив сыр, я медленно поворачиваюсь и вижу картину нихуя не маслом - в центре комнаты горшок с огромной кучей свежевысранного говна, а пиздюк стоит наклонившись раком, раздвинув руками полужопия, целится в меня измазанным шоколадным глазом и противным голоском зовёт маму.
Пришла хозяйка, невозмутимо вытерла сраку ребёнка влажными салфетками, и унесла горшок, торжественно обдав меня волной кратно усиленного вонизма. Но самое страшное, это было её выражение лица! Оно излучало уверенность, что ничего такого не произошло, что это, блять, нормально! Подумаешь, дитё высралось перед седым дядькой, КОГДА ТОТ ЕЛ, сука!
7 лет, блять!!! В 7, сука, лет пацан не ходит срать в туалет и не вытирает себе жопу!!!
Чуть не блеванув, выбежав во двор покурить и прихватив с собой коллегу, я начал участливо спрашивать, что у них случилось с унитазом, или с ребёнком, может сантехника какого посоветовать, или доктора, но тот сделал круглые глаза и сказал, что с туалетом и дитём всё в полном порядке, просто "он всегда какает в той комнате в свой горшок". И, как и у мамы, в его глазах отчётливо читалась спокойная уверенность, что всё в порядке.
НИХУЯ у вас не в порядке! Ни с головами, ни с пиздюком!
Аж трисёт до сих пор...
Создаем свой медиаплеер на базе библиотеки vlc lib с нуля
Приветствую вас дамы, господа, ожившие механизмы, ксеносы и другие, 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;
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)
В общем на этом я думаю можно закончить, так как альфа плеера по сути описана, а что то дополнительное для слабаков. Надеюсь данная статья будет полезна, поделись своим мнением и если есть какие либо ошибки и предложения, ты всегда можешь дополнить меня в комментах, спасибо за внимание^^
Это лечится?
Пару лет назад заболел я mini-itx сборками. Сначала это была сборка на атоме (д520 и 330). Ну как сборка, корпус In-WIn мать и пру хардов. Делал из них сервер (Nextcloud, Syncthing, FTP, DLNA и прочая дичь). А потом понеслась...
Дома:
Сборка на райзене на 588 рыксой (что успел, то успел). корпус BitFenix Prodigy Midnight Black и cougar qbx лежит новенький
Сервер раз: на один диск 2 тб, на базе HP ProDesk 600 G3 (сменил проц на i3, меньше греется) 24/7/365 (не совсем mini-itx, но он маленький!!!!
Сервер два: j3455 мать и raid 5 с корпусом Cooler Master Elite 120 24/7/365
На работе сборка райзена с встройкой вега 11 в корпусе cooler master h100 (не берите, такое себе). Работа своя. родная))
Комп для печати на старых принтерах. нечто на 330 атоме.
Комп для музыки нон-стоп.
И всё это на mini-itx.
Как мне вылечится? Комплектуха дороже. Охлад продумывать надо.
И это еще фигня, похоже. У меня есть пара 3d принтеров и я подумываю распечатать корпус!!
Хелп!
Подскажите с апгрейдом
есть ноутбук Sony sve171g12v, вполне хороший, но хочется побыстрее. у него пентиум 2020m 4gb 1600 ОЗУ и ссд120. подскажите можно ли поставить 8гб и ссд 240? потянет ли? и станет ли быстрее?
Анекдот № 162. Про жену, воду в карбюраторе и машину в озере
Собственно анекдот:
- Дорогой, у меня машина не заводится, вода в карбюратор попала.
- Ого! А где сама машина? Я сейчас подъеду.
- В озере.
Ладно, это всё присказка. Сейчас реальную историю расскажу.
У меня зазвонил телефон.
- Кто говорит?
- Слон. (серьёзно, погоняло у мужика такое.) Помоги, мне нужно на материнке конденсаторы перепаять. Я корпус открыл, посмотрел, а там они полопанные.
- Ну тащи, чего уж там, делов-то. Только бухла прихвати.
- Уже лечу.
Привозит он, значицца, жутко воняющий системник с выгоревшей в полное говно начинкой!!!
Ну серьёзно, там из живого только сам корпус и остался. Внутри блока питания была просто каша. Вышеупомянутые конденсаторы на плате не просто полопались, а залепили потрохами всё. Дорожки на платах погорели и порвались, а часть просто испарилась, дематерилизовалась к хуям.
Я несколько раз перевёл красноречивый взгляд с трупа на Слона и обратно...
- Что, совсем всё плохо? - разочарованно протянул он.
- Да полный пиздец! А что, сразу нельзя было сказать, что твой компьютер дрался с Зевсом, Перуном и лордом Рейденом до кучи!?
- Я не знал. Мне его сосед-погорелец за поллитру отдал, вот я и подумал...
- Не думай больше. Не твоё это.
Что у людей в головах может твориться - ХЗ. ))
Поиск по всем php файлам в проекте
Всем привет.
Подскажите программу для редактирования php, которая умеет искать по всем файлам php всего проекта. Нужно найти код в тексте, а в каком конкретно php файле он записан не могу найти...
Пользовался такой лет 5 назад такой прогой, она открывала папку с файлами как единый проект и можно было переключаться между модулями, но никак название вспомнить не могу, а гугл выдает какую то кашу типа организация поиска по файлам в php
заранее спасибо