Рекомендации по созданию видео-туториалов
1) Обязательно сделайте обширное предисловие, с экскурсом в собственную биографию, а также с подробным изложением избранных эпизодов из жизни ваших друзей, родственников, домашних животных и соседки тёти Мани. Чем более обыденными и типичными будут рассказанные истории — тем лучше.
2) Если в процессе работы подразумевается многократное повторение однотипных операций — снимайте и включайте в ролик их все.
3) Ни в коем случае никак не объясняйте, почему вы делаете именно так, а не иначе, не обращайте внимания зрителей на критичные моменты технологии, не показывайте близко сырьё, инструмент и материалы.
4) Все операции проделывайте максимально быстро, чтобы никто не успел рассмотреть ваши приёмы работы.
5) Болтайте. Болтайте как можно больше. Можете продолжать интересные рассказы из ежедневной жизни тети Мани и про то, как вы во времена вашего школьного детства ехали в поезде в гости к родственникам. Или же поведайте о том, как ваш ребёнок в два года называл вашу кошку. Или рассказывайте, как вы круты, в каких выставках и конкурсах принимали участие, кого из известных людей видели вблизи.
Но максимально избегайте говорить о работе, которую вот прямо сейчас проделываете на камеру. Если же избежать сей низменной темы никак не получается, то избавьте зрителей от
мерзкой конкретики и деталей, ограничьтесь репликами типа «вот, делаем [операция 1]… и еще делаем [операция 1]… и продолжаем делать [операция 1]…»6) Кстати о ребёнке. Если вы делитесь рецептом, а ваш ребёнок или внук ещё малыш, то у вас есть замечательная возможность воспользоваться беспроигрышным приёмом: высадите его на стол среди продуктов и посуды, желательно прямо голой попой. Если дитя ещё и станет что-то тянуть в рот — просто отлично.
Если вы не готовите, а ваш ребёнок постарше — всё равно, пускай мельтешится в кадре, а вы почаще отвлекайтесь на общение с ним. Всем очень интересно слушать эстрогенный лепет, ведь больше ни у кого детей нет и не было никогда, и ваш родительский опыт уникален.
Нет ребёнка — сойдёт и песик либо котик.
На совсем крайний случай, можете общаться с оператором — он, конечно, не котик, но лучше, чем ничего.
7) Не забывайте использовать диминутивы и слово «наш». Наши ниточки, наши ножнички, наше мяско, наша бензопилонька. А то ещё кто-нибудь подумает, что бензопилоньку и мяско вы коварно стащили у соседа.
8) Запомните, длительность вашего ролика не должна быть меньше сорока минут. Из них непосредственно показу последовательности операций и приемов работы может быть посвящено не более десяти минут. Всё прочее должно приходиться на повторение однотипных операций, общение с родственниками и домашними животными, а также обсуждение вашей приватной жизни.
9) Описания роликов лучше всего не писать вообще. И уж ни в коем случае не дублируйте туда самой важной информации из ролика
10) Желательно вставить безполезную заставку в самом начале с помпезным лого канала и вашим именем, чем длиннее будет заставка, тем лучше
11) Заставку обязательно сопровождать громкой музыкой для пущего эффекту
12) Крайне рекомендованы к использованию слова-паразиты, мычание, скрежет и скрип. Без них ни один туториал нельзя назвать законченным
13) Туториал нельзя назвать полезным, если вы не использовали крайне тихий микрофон, а если тихий звук сопровождается еще и мычанием и скрежетом, то это просто мечта
14) Обязательно сидите в бездействии по 2-3 минуты, когда ничего не происходит, не вздумайте вырезать эти фрагменты из видео, желательно сопровождайте моменты бездействия хаотичным тыканьем курсора, если вы снимаете туториал на ПК
15) Основополагающий момент: без фоновой музыки ни одна видео-инструкция не имеет права на существование
Создаем свой медиаплеер на базе библиотеки 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)
В общем на этом я думаю можно закончить, так как альфа плеера по сути описана, а что то дополнительное для слабаков. Надеюсь данная статья будет полезна, поделись своим мнением и если есть какие либо ошибки и предложения, ты всегда можешь дополнить меня в комментах, спасибо за внимание^^
Косячный Arduino CNC Shield v4. Полное восстановление работоспособности
Купил я себе Arduino CNC Shield v4. Как оказалась данный шилд косячный, и про эту проблему известно давно, а китайские производитель так и продают их с данным браком. Но я решил не выбрасывать данную плату, а реанимировать.
Первое что нужно сделать, это настроить прошивку, так как при разводке платы перепутаны местами контакты step и dir.
Второе что не работает это деление шага. Чтобы сделать максимальное деление шага можно припаять 3 перемычки. Внимание джамперы ставить в данном случае нельзя, ЗАМКНЕТ!
Если вам нужно выставлять деление шага можно перерезать дорожки и припаять 5 перемычек. Подробнее про данный способ читайте на сайте.
Что меня удивляет это факт того, что CNC Shield v4 стоит дороже чем его не бракованный брат Arduino CNC Shield v3. Почему так?
3Д Текст в After Effects [БЕЗ ПЛАГИНОВ]
В этом видео я покажу крутой способ, как сделать 3D текст в After Effects без плагинов.
Потом мы сделаем анимацию металлического текста в стиле Голливудских фильмов.
ТРУДНО БЫТЬ ГЕРОЕМ | TUTORIAL ELEMENT 3D | AFTER EFFECTS - speed art tutorial
Привет! Мое хобби - 3d моделирование. Я создаю видео-арты и показываю свой процесс работы в after effects.
Поиграем в бизнесменов?
Одна вакансия, два кандидата. Сможете выбрать лучшего? И так пять раз.
Анимированный текст интро HTML CSS
Всем привет, новое видео от меня!
Важно! Это не уроки! Если ты неделю в вебе, то скорей всего ничего не поймешь! У меня нет цели кого-то учить, так как я считаю, что уроков и курсов и так полно на просторах интернета. Я делаю разнообразные задачки для себя в не скучном формате, чтобы всегда была практика и решил поделиться с другими, чтобы была возможность получить готовый код, адаптировать готовое решение под себя или попробовать реализовать тоже самое для практики (практика главное в разработке!).
jsFiddle: https://jsfiddle.net/CrazyCoding21/cf9n357a/1/
GitHub: https://github.com/CrazyCoding21/CC-HTML-CSS-42-Intro-Text-A...