Делаем свой ютуб своими кривыми руками

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

Сегодня имеет смысл смотреть сюда: https://github.com/videojs/video.js/ - оно швабодное, афтары мамой клялись что трекинговый пиксел был в одном-единственном и то не self-hosted месте да и там включался рандомно для 1% пользователей, то есть, может быть, и правда использован только для сбора статистики, "и ваще мы его уже выпилили, а куда перепрятали - хрен вы найдете!"
При этом там есть flash: https://github.com/videojs/videojs-flash (archived в последние дни флэша, то есть скорее всего еще долго будет рабочим), там есть vtt: https://github.com/chrisboustead/videojs-vtt-thumbnails и еще штук пять разных васянских реализаций, хз какая лучше/хуже, там есть тыкоуй для дибильников: https://github.com/mister-ben/videojs-mobile-ui и много еще чего (mse, hls, прочие лайвстримы и т п), минус только что и тривиальные вещи типа выбора качества или плейлистов тоже делаются через плагины, разнообразного васянского качества, и от троянов вы тоже не гарантированы. Я привык к своему jwp, и переделывать пока ничего не планирую, тем более что whitewater весь на изуродованном 1сниками jwp и там проще чинить чем переделывать радикально.

на сегодня (18.01.2013) еще далеко не каждый браузер у нас html5, а мазилла никогда полностью им не будет (идиотизм с поддержкой mp4 через жопу/через виндовые средства и ублюдище gstreamer окончательно подтвержден тем, что автор одного такого говнопатча ничтожесумняшеся "для большей безопасности" прибил туда гвоздем пути вида c:\windows, мысль что бывают другие буквы дисков ему в голову может и приходила, но, никого не застав, ушла - этот бред похоронили, но понаделали новый, короче, идиотов в мозилле немерянно). Зато флэш все еще есть везде, кроме распоследних андроидов.

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

2015: это я оптимист был. Ситуация за последние годы стала только хуже. Либо надо перекодировать все в поддерживаемый мазилой webm параллельно с копией mp4 (ибо маки ничему другому не научились), либо забить на мобильных клиентов с неправильными (читай, не chrome, у которого с mp4 все в порядке) бразуерами. Я, видимо, выбираю второе, поэтому текст остается актуальным и сейчас, через пять лет.

flash умеет играть только два типа файлов - mp4 (Video: h264 (Main/High), yuv420p, Audio: aac s16) и flv (то же самое, или, хуже Video: flv1, yuv420p, Audio: mp3, 44100 Hz - при этом mp3 играется везде, а вот с aac иногда возникают глюки) Не стоит так же разгонять видео bitrate выше 2000Kb/s - практика показала что дальше даже на достаточно современной машине начинает глючить (не тормозить, а именно глючить). Я предпочитаю забивать на flv хуй, поскольку нам не надо портить себе совместимость с html5-capable. Правда, следует понимать, что ее можно испортить и другими способами - например, половина говна все еще непредсказуема при встрече с кодированием более мощным чем baseline profile, при том что флэш-то с ним проблем не имеет, кроме, разумеется, производительности.

На всякий случай, для flv в h264 - все еще актуальна софтина yamdi, добавляющая туда правильные мета-теги. На случай окончательной смерти SF, лежит тут где и все прочее.

git clone git://git.videolan.org/x264.git
cd x264/
git checkout 1cffe9f406cc54f4759fc9eeb85598fb8cae66c7 (иначе нужен yasm 1.2, который доступен только в новомодных дистрибутивах) - внезапно, "тут videolan взял и похерил свою репу, поэтому все айдишники поменялись, кажется, теперь нужно c6bfcec47c9d1fff0489a30215501babea29f59c " (c)https://communities.intel.com/thread/51949 - не проверял точное совпадение, но с таким - да, собирается. - уже нет, теперь 8a9608bbbdf77ceb3ee537271549111468175a2b - короче, git log | less /Bump yasm version to 1.2.0
./configure --enable-static
--bit-depth=10 эффективно предотвращает возможность потом показать это дет...виндовым клиентам - все уходит в зеленые тона, видимо, если там и есть десятибитный декодер, работает как минимум в виндовом флэше он неправильно (а нативный мозилловский проигрыватель вообще не признает в этом видеотрек). В линуксе, как ни странно, адоб играет нормально, ну а gstreamer у меня нет. В общем, остаемся на восьми битах.

make all install DESTDIR=/tmp/x264
rpmbuild -bb x264.spec  --buildroot /tmp/x264 
git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg.git
../ffmpeg.git/configure --disable-ffplay --disable-avdevice --disable-runtime-cpudetect --disable-outdevs --disable-indevs --enable-libx264 --enable-gpl --enable-nonfree
и проверяем факт
 libx264 enabled           yes 
(License: nonfree and unredistributable!)

(если x264 был с --enable-static, в общем-то можно уже сносить rpm)

если нужно что-то кроме тупого копирования аудио - собирать libfdk_aac - из вики ffmpeg: Fraunhofer FDK AAC codec library. This is currently the highest-quality AAC encoder available with ffmpeg. Requires ffmpeg to be configured with --enable-libfdk_aac (and additionally --enable-nonfree if you're also using --enable-gpl). But beware, it defaults to a low-pass filter of around 14kHz. If you want to preserve higher frequencies, use -cutoff 18000. Adjust the number to the upper frequency limit you prefer.

git clone --depth 1 git://github.com/mstorsjo/fdk-aac.git
cd fdk-aac
autoreconf -fiv
./configure --disable-shared
make install DESTDIR=кудаподальше
ffmpeg собирать после этого --enable-libfdk_aac --enable-nonfree и env CFLAGS=-I... LDFLAGS=-L... в это куда. (если нет желания иметь в системе и еще один совершенно ненужный пакет)

Как кодировать, на случай если проебется http://ffmpeg.org/trac/ffmpeg/wiki/x264EncodingGuide :
obj/ffmpeg -i source.mp4 -c:v libx264 -preset slow -b:v 2000k small.mp4 или так: ffmpeg -i source.MP4 -c:v libx264 -preset slow -b:v 2000k -vf scale=1024:-1 -r 30 -ar 44100 -c:a libfdk_aac -b:a 64k -t 0:20:45 work.MP4
пресеты ниже slow вам не нужны, поверьте. До кучи: to achieve maximum backwards compatibility with early iPhones and iPods you should stick with:

    Baseline Profile
    Level 3.0
    1 reference frame

и не забываем про swapoff -a - x264 похоже "меряет" доступную память и пытается ее занять всю - в результате система уносится в трэшинг, даже если памяти дофига. похоже, уже неактуально, на современных системах своп не жрется.
swscale: -vf scale=320:-1 (обратить внимание - в wiki синтаксис неверен!)
Ну и можно вот это почитать на досуге: http://slhck.info/articles/crf

На закуску, ffmpeg запишет индексный блок в самый конец вашего двухгигового шадевра. Если вы хотите чтобы в флэше (для html5 неактуально) нормально работала перемотка - wget -N https://github.com/danielgtaylor/qtfaststart/archive/master.zip (в ffmpeg есть собственная поделка, но она адски кривая и глючная - хотя и послужила основой этого кода)
дальше по инструкции: python setup.py install --user (можно и easy_install qtfaststart, конечно. Предполагаю наличие setuptools/python-distribute.) - владельцы SuSE идут, внезапно, нахуй - точнее создавать в $HOME/.pydistutils.cfg вида:

[install]
prefix=

иначе install вы можете сделать только из под рута, а с ключом user оно падает со странными ошибками, привет кривому конфигу дистрибутива, как это запаковать в аккуратный rpm - я не ведаю. Да и не нужна она system-wide. If outfile is not present then the infile is overwritten. Гыгы. ~/.local/bin/qtfaststart -l <file> расскажет вам много нового.

x265 - инфа с редита, за что купил:
I use x265 with two tunings: 480p:

 ~/bin/HandBrakeCLI -i "$1" -o "$2" -O --no-markers -e x265 --encoder-preset=fast --vfr -q 23 -Y 480 -E fdk_aac -R auto -6 stereo -B 112 --crop 0:0:0:0 --loose-anamorphic --keep-display-aspect 
720p with better audio:
~/bin/HandBrakeCLI -i "$1" -o "$2" -e x265 -O -2 --no-markers --encoder-preset=slow --vfr -q 21 -E fdk_aac -R auto -6 dpl2 -B 192 -Y 720 --crop 0:0:0:0 --loose-anamorphic --keep-display-aspect 
if you are using 320, set q=24 x265 gives me at least 50% (average is 70%) reduction in file sizes with no discernible reduction in quality

Теперь вещи поважнее: нам понадобится плейер. На сегодня их, работающих, приемлемо глючащих и не написанных идиотами, есть примерно два: JWPlayer имени longtailvideo - написан ради денег, но раздается свободно бесплатно, в том числе и в исходниках (https://github.com/jwplayer/jwplayer , но вы ежа родите против шерсти, пытаясь собрать это у себя) Правда, хочет на память ваши адреса, каких-то сраных акаунтов и т д. Я ебал их в рот: files/jwplayer-free-6-1-2972.zip или jwplayer-free-6-0-2813.zip(устарел) - не успел я порадоваться что они не проверяют реферер, как они попрятали архивы в динамическую ссылку, открываемую только зарегистрированному юзеру (впрочем, в конечном итоге идет на https://account.jwplayer.com/static/download/, рефереры по прежнему не проверяют, главное угадать имя файла, сегодня это ..-6.12.zip). Открытых линков тут не будет, копирасты не дремлют.
Но это были - еще цветочки. Ягодки наступают для параноиков - чудо софтина очень-очень хочет следить за вашими посетителями - кто, чаво, зачем (и в платной версии тоже, пока кто-то не спалил контору и не заставил их открыть тикет, после чего эту backdoor в 2013м все же выпилили. 2015: бэкдор, похоже, запилен обратно в десятикратном размере), причем для любителей, типа меня, разрешать js'ы и cookies только там, где на самом деле они нужны, внезапно, оказывается необходимо разрешать первое для какого-то левого лонгтейловского сервака, а второе для своего хоста, который лично у меня юзерскую информацию никогда не коллекционировал. Снова спасибо им за непроверку рефереров. Распаковываем-ставим все по инструкции, затем лезем (лучше - vi, даже если вы фанат кдевого говна) в jwplayer.js , ищем там кусок вида: "https://ssl.":"http://")+"p.jwpcdn.com/"+c.version.replace(/(\d+)\.(\d+).*/,"$1 +/$2")+"/jwpsrv.js
(/jwpsrv, короче) и заменяем его линком на свой собственный сайт, куда положим мой jwpsrv.js для 6.0 (угадайте линк) - поздравляю, вы избавились от пидорского счетчика. (заметьте как мило избежали варнинга о mixed content - не сломайте, если у вас тоже есть ssl. А вот упражнения с version.replace можно выкинуть нахер, если только не собираетесь коллекционировать разные версии этого плейера. Впрочем, с 6.0 по 6.12 чудо-сайт отдает один и тот же файл, проверено) Нет, я не буду рассказывать как отломать логотип - это, как раз, на мой взгляд вполне приличествующий реверанс за бесплатность софта (а анального зонда, вроде, к нему не прилагается - хотя это и не гарантированно).
Поскольку они херачат новые версии, хочу предупредить что в более новых код другой, более сложный, качает уже не один скрипт а целую пачку, непонятно, делающих ли что-то полезное кроме анального внедрения, а в jwpsrv завелся закопанный в самое нутро вызов ping.gif с полным набором информации о тебе и твоем сайте (а о юзере оно соберет и само, после того как он этот говногиф откроет). Разумеется, никто вас не предупреждает, что оно вот так. При этом сидеть на старой версии можно в весьма ограниченных пределах, поскольку, например, кнопка "hd" (напоминаю, сделана через плейлисты) для выбора одного из нескольких качеств воспроизведения, работает в тех версиях только в доисторических браузерах или при принудительном определении primary: flash
У меня тут лежит и jwpsrv.6.1.js для более свежих (до 6.6 точно) - но там могут быть глюки или недовыпиленный трекинг - будьте осторожны. кнопку не исправляет.
Более надежный но адски геморройный способ избавления от пидорских трекеров - собрать таки версию с github самому. В ней из внешних обращений - только логотип (и его можно, в общем-то, тупо подменить своим). Однако, у меня она активно плюется в консоль ошибками, нефатальными, но отсутствующими в версии с сайта, к тому же ее флэшовый вариант адски тормозит и глючит, то ли потому, что родной собран более эффективным компилятором, то ли потому, что он вообще другой, а в фри версию подсунуто нечто нерабочее.
Новая пичалька - внезапно, сломался вычислятель урла собственно плейеров. Пришлось заменить k.base (в котором вместо нужного мне собственно base url плейера оказывается base страницы с плейером) в jwplayer/jwplayer.js на "/jwplayer/" (или где он там у вас) - некрасиво, но у меня нет времени распутывать этот говнокод. В двух местах.
Код в jwpsrv, кроме слива данных ваших юзеров хозяину сервиса, еще инициализирует собственно плейер, чтобы вы не могли по тихому совсем от него избавиться. У opensource версии инициализация вынесена в основной скрипт.

Кому не нравится, что ж, "есть еще один":
http://flowplayer.org/
http://flash.flowplayer.org/
Да, вот такая херня - флэшовая версия отдельно, html5-я отдельно (в ней есть фаллбэк на флэш, но отдельный и кривой) Ну и дефолтный скин выглядит вполне уебански. До кучи, перемотка вперед работает только с отдельно устанавливаемым-скачиваемым плагином: wget -N http://releases.flowplayer.org/flowplayer/flowplayer-3.2.15.zip
wget -N http://releases.flowplayer.org/flowplayer.pseudostreaming/flowplayer.pseudostreaming-3.2.11.zip (опять хотят от меня паролей и явок, и опять идут нахуй) [версии устарели безнадежно, новые я не пробовал и не знаю как настраиваются. Зато оно GPL, лежит на гитхабе и, возможно, его можно осилить поправить. Где брать современные версии плагина и/или его исходник - не знаю. ]

Нет, uРРод я категорически нерекомендую, извиняйте.

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

Ключевой функционал который нам нужен (который мы можем получить) - возможность "как в ютубе" промотать файл за пределы уже скачанного куска, чтобы не смотреть унылое говно. Как ни смешно, адобовский кусок дерьма до сих пор не в курсе http заголовка Range: - плейеры при такой манипуляции с интерфейсом просто говорят флэшу "а теперь спроси у сервера и покажи другой файл", "другой" отличается cgi-параметром в url, обычно ?start= (угу, теперь вы знаете почему если захочется вернуться опять к началу - оно опять качает заново. Да, у html5 такой проблемы нет. У него других прорва.)

Сперва собираем nginx с --with-http_mp4_module --with-http_flv_module (вдруг) - опять привет сузи, которая об этих модулях не позаботилась, зато вхуярила ненужные мэйлпрокси. (почему модули разные? А потому что mp4 start в секундах, а flv - в байтах, опять привет адобу - видимо, так устроен его родной сервер.)

у меня, к примеру, так: --conf-path=/usr/local/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --user=wwwrun --with-http_ssl_module --prefix=/usr/local --with-http_mp4_module --with-http_flv_module --error-log-path=/var/log/www/error_log --with-cc-opt='-pipe -O2 -fomit-frame-pointer -fstack-protector -march=native'

рисуем локэйшн вида ~ \.mp4$ { mp4; } ну или как-то так.

наконец, скрипт:

<div id="myvidos1">Loading the player ... это видят те у кого не включен скрипт</div>
        <script type="text/javascript">
                jwplayer("myvidos1").setup({
                        flashplayer: "/jwp/jwplayer.flash.swf",
// это ваш локальный линк, разумеется
                        file: "/video/somevideo.mp4",
// это собственно что будем играть
                        image: "/icons/movie.gif",
// это то что выводится в качестве заставки до нажатия кнопки play
                        height: 360,
                        width: 640,
// в этот размер втиснется плейер - независимо от размера видео и картинки
// при этом картинку распидорасит на все поле, а вот видео правильно
// отмасштабируется - с темными полосами, если необходимо для сохранения aspect.
// оно управляется параметром stretching: "uniform" является разумным дефолтом
// fill убирает черные полосы, вместе с краями картинки, ну а exactfit кому
// нужен - не знаю
// С версии 6.4 стало можно width: "90%" - угу, оно умеет масштабироваться под
// размер окна
// соответственно, теперь ему нужна:
//			aspectratio: "16:9", //ну или сколько там надо

//                        duration: 2958, это секунды, если опустить - угадает сам
// полезно если хочется урезать осетра - за пределы duration этот плейер ни 
// перематывать, ни подглядывать не даст
                        mute: true,
                        smoothing: "false",
                        provider: "http",
                        startparam: "start"
//два последних как раз и отвечают за псевдостриминг - ту самую перемотку вперед
                });

//                      bufferlength: 0, не работает для файлов, увы
        </script>
заметим, что jwplayer у меня лежит не в стандартном месте, всем пох

или так:

<div style="display:block;width:600px;height:338px;" id=player1> </div>
- обратить внимание, что это уебище именно такого размера все и отрисует
<script language="JavaScript">
    flowplayer("player1", "flowplayer/flowplayer-3.2.15.swf", {
        clip: {
                url: "http://тут у меня почему-то плохо работают relative urls.mp4",
                provider: 'lighttpd',
// из примера, название пох
                autoPlay: false,
                autoBuffer: false,
                accelerated: true,
		duration: 25,
// а вот этому плейеру duration необходим - иначе, пока он не принюхается к
// вашему кину, будет рисовать некрасивый ноль, впрочем, до нажатия 
// play он в любом случае его будет рисовать.
                scaling: 'orig' },
// а вот это ключевое слово ^^ - по умолчанию размер видео вгоняется в размер
// окна, а если нажать кнопку fullscreen - то экрана, посрать что видео
// квадратное а экран прямоугольный или наоборот
        plugins: {
// а вот где оно используется: lighttpd: { url: "flowplayer.pseudostreaming/flowplayer.pseudostreaming-3.2.11.swf" } } }); </script>

- не забываем включить (пох куда, лишь бы до обращения к нему) загрузку самого плейера, один раз на страницу, независимо от количества div'ов с видией.
<script src="flowplayer/flowplayer-3.2.11.min.js"></script> или так: <script type="text/javascript" src="/jwp/jwplayer.js" ></script> Рекомендацию делать это в секции <HEAD> сворачиваем трубочкой и засовываем сами-знаете куда. В head она работает почему-то только для предопределенных браузеров, среди которых нет андроидовских, к примеру.

Следует помнить что flow и свежие версии jwplayer требуют начинать документ с <!DOCTYPE html> This is mandatory. Otherwise HTML5 video will not work in some browsers, notably Internet Explorer 9.

описание "плейлистов" (попутно ими же, через жопу, делается переключение качества видео) ищите в родных документациях того и другого, плюс имейте в виду, что по моим ощущениям кнопка 'hd' давно и безнадежно сломана в jwplayer с современными браузерами (если не энфорсить flash).

В помощь страждущим тут есть два говноскрипта (с намервто вшитыми путями, мне большего не нужно): rss-gen.csh - для 6.12 и mrss-gen.csh - для 6.1 и рядом, который еще не умел специфического jwplayer'овского формата ("No playable source found" означает что вы их перепутали)

Ну вот, вроде ничего не забыто.

А, нет. Еще я наконец-то нашел как сделать последнюю фичу, которая "как в youtube", и которой нет ни в одном самодельном и даже в большинстве коммерческих сайтов (даже вымя обзавелось этой фишкой совсем недавно) - превьюшки в таймлайне. (при елозеньи мышью по слайдеру, показывать превьюшку примерно из этого места в ролике)
Описание для шестой версии jwp - тут - да, такое вот заебись, на родном сайте эту статью давно проебли (я нашел линк на вебархив в их саппорте, три хаха). Вкратце - это называется "video tooltips", использует формат html5 WebVTT, здорово похожий на формат сраных сабов к сраной японской порнухе, ну вы поняли, да. Работает в версии 6.12, не работает в 6.1 - где взять для теста 6что-томежду я не в курсе, звиняйте.
Моментики: Note the range needs to be in (HH:)MM:SS.MMM format. Only this exact notation will be parsed.
Note JW Player will render the thumbnails in the tooltip using their original dimensions. We think thumbnails that are around 100 to 150 pixels wide tend to work well.
Note JW Player to date only supports pixel-based fragments, not percentage-based ones.
Ну и relative линки relative'ны vtt файлу а не плейеру или странице с ним.

Tooptip Thumbnail VTT files can be embedded in a player by adding it as a track to the Playlist Object. The tooltip thumbnails track has 2 required properties:

file
URL to the WebVTT file that refers to the thumbnails (e.g. /assets/myThumbnails.vtt).
kind
The type of text track we are using. For thumbnails, specify thumbnails here. Otherwise, this will default to captions.

Note that tracks in JW Player have two additional properties, default and label. Both are only used for Closed Captions, and ignored for Tooltip Thumbnails.

Ну и пример:

var playerInstance = jwplayer("myElement");
playerInstance.setup({
    playlist: [{
        file: "/assets/myVideo.mp4",
        image: "/assets/myPoster.jpg",
        tracks: [{ 
            file: "/assets/myThumbnails.vtt", 
            kind: "thumbnails"
        }]
    }]
});
Или, для rss:
<jwplayer:track file="/assets/myThumbnails.vtt" kind="thumbnails" />

Софтина для генерации этих чудес, к счастью, уже написана: git://github.com/vlanard/videoscripts - git clone ее, есессно. Помимо очевидного питона и затребованного imagemagick, захотела от меня еще неочевидного python-dateutil. Ну и мой дифф для любознательных (еще может понадобиться в 106й строке cmd = "ffmpeg заменить полным путем, если вы, как я, любитель собирать его из исходников и никуда не устанавливать)

у flowplayer не так давно появилась аналогичная хрень, https://flowplayer.com/docs/plugins.html#thumbnails - примеры и методы изготовления превьюшек там же.

И еще одно: если вы вынуждены хостить видео, снятое ифоноухими в вертикальном формате, вместо того чтобы сразу удалить подобные поделки и забанить авторов, вам поможет эта инструкция (уже доступная только в архиве) - это что нужно патчить и где, чтобы автоматически обнаруживать подобное (конвертить может обычный ffmpeg - как-то вот так: -acodec copy -qscale 0 -map_metadata 0 -metadata:s:v rotate="0" - обратить внимание, что -vf "rotate=3.14159" не нужен, ffmpeg сам повернет ) Может оно уже и попало в libavformat, но я не проверял, за ненадобностью дерьма. У меня 0c7ceb1e0acc2d4b741bce07ad70b353869da4c3