Иногда мы хотим поделиться с друзьями частью какого то видео на YouTube — время концентрации внимания в современной реальности снижено до предела, и если скидывать ссылку на ролик(даже с таймкодом начала) с комментарием «смотреть с 21:51 по 24:55» — велика вероятность, что видео просмотрено не будет.
Кроме того — куски видео могут потребоваться для монтажа своих роликов — и довольно неудобно скачивать ради нескольких секунд весь ролик и искать/вырезать нужную часть в программе для монтажа.
Как загружать часть видео YouTube при помощи ffmpeg — под катом
Получаем прямую ссылку
Часть реализации моего Telegram бота на Python:
Нам потребуется библиотека pytube.
Создаем объект класса YouTube, которому передаем нашу ссылку, передаем номер нужного потока и получаем прямую ссылку на видео/аудио
from pytube import YouTube
link = "ссылка на видео"
itag = номер_потока
url = YouTube(link).streams.get_by_itag(itag).url
Обратите внимание, что потоки 1080p и 480p не имеют аудиодорожки.
Далее — подаем ссылку на вход (-i) ffmpeg вместе с таймкодами начала (-ss) и конца (-to) в формате «hh:mm:ss.xx». Задаем аудио кодек, битрейт и "-avoid_negative_ts make_zero" для того чтобы избежать подвисания картинки в начале видео из за потери ключевых кадров.
ffmpeg загрузит видео с нужного момента — нам не нужно качать видео на компьютер и обрезать — мы сразу выкачиваем нужный кусок.
process_call_str = 'ffmpeg -ss {1} -to {2} -i "{0}"' '-acodec aac -b:a 192k -avoid_negative_ts make_zero "{3}"'
.format(str(url), str(ss), str(t), download_file_path)
status = subprocess.check_call(process_call_str, shell=True)
Потоки без аудио
А что же делать с потоками без аудио? FFMPEG выручит нас и здесь — он может принимать на вход несколько потоков и объединять их.
Получаем прямую ссылку на видеопоток (например 137 — 1080p) и на поток с аудио/видео — например 18 — 360p
url = YouTube(link).streams.get_by_itag(itag).url
aurl = YouTube(link).streams.get_by_itag(18).url
Далее начинается магия — подаем на вход оба потока и при помощи "-map" берем видео дорожку из первого потока и аудио дорожку из второго потока и объединяем- теперь загрузка и объединение потоков происходит с нужного места из двух источников.
process_call_str = 'ffmpeg -ss {2} -to {3} -i "{0}" -ss {2} -to {3} -i "{1}"' ' -acodec aac -b:a 192k -avoid_negative_ts ' 'make_zero -map 0:v:0 -map 1:a:0 "{4}"' .format(str(url), str(aurl), str(ss), str(t), download_file_path)
status = subprocess.check_call(process_call_str, shell=True)
Заключение
Вообще ffmpeg довольно мощная штука, возможности которой несколько шире переконвертации видео/аудио из одного формата в другой и позволяет соптимизировать нагрузку на входящий канал, диск, процессорное время и оперативку.
При помощи ffmpeg в боте реализовано ускорение/замедление звука с тонокомпенсацией, сжатие в формат opus. Теперь вот и загрузка видео/аудио с нужного момента по таймкодам — достаточно прикрепить к ссылке таймкоды и бот оперативно пришлет нужный кусок аудио/видео в нужном формате и качестве:
http://www.youtube.com/watch?v=Qgm36HHDEk0(30:29.5-30:38.5)
Комментарии (14)
AllexIn
17.03.2018 22:04+1Вообще ffmpeg довольно мощная штука
Хочется добавить, что если вдруг нужно провести любые манипуляции в автоматическом режиме(скриптом, например) с видео и/или аудио файлом стоит посмотреть что там умеет ffmpeg.
Ускорение/замедление/оверлей/объединение/разъединение/переконвертация, список возможностей очень обширный.SlavikMIPT Автор
17.03.2018 22:11ага — я прямо прифигел что он умеет делать) до этого приходилось качать файл и на сервере уже с ними работать, а оказывается можно все делать одним инструментом, одной командой, при этом алгоритмы оптимизированные. Единственная сложность — скомпилировать ffmpeg может быть)
Nicodinus
18.03.2018 17:20И даже для компиляции есть простой скрипт который умеет инклудить много проприетарных либ внутрь себя (раньше было особенно актуально для nvenc, ибо его не было ещё в коде родного ffmpeg'а). Разве что кофе на варит) Разработан кажется хабравчанином, только ник запамятовал. Вот ссылка (https://github.com/rdp/ffmpeg-windows-build-helpers), надеюсь не сочтут за рекламу.
valera5505
18.03.2018 00:40Это (и многое другое) умеет youtube-dl. Но самому написать, конечно, интереснее :)
Taciturn
18.03.2018 00:50Это просто прекрасно! Не могли бы вы зайти в ишью #622 (открыт с 2013 года) и рассказать там всем как именно youtube-dl всё сам умет, а то там всё тоже сводится к ffmpeg.
Zverik
18.03.2018 14:03Обрезать видеофайл в произвольном формате — не задача youtube-dl. В этом же тикете приведён пример:
ffmpeg -ss 3:59:10 -i $(youtube-dl -f 22 -g 'https://www.youtube.com/watch?v=mMZriSvaVP8') -t 3:06:40 -c copy react-spot.mp4
То же самое делает автор статьи, только вместо youtube-dl пользуется какой-то питоновской библиотекой. Библиотека оказалась не очень очевидна из консоли, в отличие от youtube-dl, поэтому появилась целая статья на хабре с предложением читать xml и вызывать ffmpeg изнутри питоновского скрипта.Taciturn
18.03.2018 14:13Статья называется «FFMPEG. Загружаем часть видео с YouTube». Она, в первую очередь, про ffmpeg, а не про как именно получить прямую ссылку на видео/аудио. Соответственно писать «Это (и многое другое) умеет youtube-dl.» не уточняя о чём речь — крайне некорректно.
Да, про то что по ссылке всё сводится к ffmpeg я сразу написал, зачем было это повторять?Zverik
18.03.2018 16:51Если бы в подводке к кату было написано не «как загружать часть видео YouTube при помощи ffmpeg», а «как загружать видео с ютуба и как обрезать его при помощи ffmpeg», вопросов бы не было. Я прочитал статью только потому что подумал: «ого, ffmpeg уже и этому научился?»
SlavikMIPT Автор
18.03.2018 15:22ну не претендую на «целую статью на хабре»(который скатился и вынуждает уже не тратить время на «целые статьи»), но совет как я считаю довольно полезный будет тем, кто занимается проектами с видео/аудио.
Youtube-dl штука полезная, но очень медленная в большинстве случаев и недостаточно гибкая — использовать в реальном проекте можно разве что для получения метаданных. Я в своем изначально пользовался pytube — она умеет и качать видео и on_progress callback есть и age_restricted обходит, ну и много чего для работы с youtube из кода — лично мне использовать вызовы консольных приложений без обертки не очень удобноZverik
18.03.2018 16:48Не-не-не, статья хорошая и полезная. Я, вот, узнал про библиотеку для питона. Она для немного другого — как вы пишете, всякие колбэки и метаданные, но почему бы и нет.
Sad_Bro
18.03.2018 12:33А возможно с помощью этого инструмента извлечь аудиопоток из стрима? Сейчас довольно много годных трансляций музыкальных идет на ютубе не прерывных.
SlavikMIPT Автор
18.03.2018 14:02да — можно, более того — можно задерживать аудио относительно видео, прокидывать из потока в поток и тд
Sad_Bro
18.03.2018 14:31Пока к сожалению, не получается создать экземпляр с подобным стримом
>>> yt = YouTube('https://www.youtube.com/watch?v=pJvDIO5P4p0') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Python27\lib\site-packages\pytube\__main__.py", line 84, in __init__ self.prefetch_init() File "C:\Python27\lib\site-packages\pytube\__main__.py", line 93, in prefetch_ init self.init() File "C:\Python27\lib\site-packages\pytube\__main__.py", line 128, in init mixins.apply_signature(self.player_config_args, fmt, self.js) File "C:\Python27\lib\site-packages\pytube\mixins.py", line 31, in apply_signa ture url = stream['url']
vladfaust
Спасибо, пригодится для одного из моих проектов!