Pull to refresh

Comments 24

«Опасное видео» ­— просто пушка. Я даже подумать не мог, что кто-то может вызывать ffmpeg в серьезных проектах напрямую, я не использовать libavcodec, libavformat и прочие библиотеки. Мой мир серьезных программистов, которые думают о последствиях, опять перевернулся.
А что в этом плохого, зачем для такой задачи писать/отлаживать/поддерживать из библиотек свой велосипед (причем совсем не простой, когда нужно сделать конфигурируемыми пару десятков параметров), если утилита ffmpeg с этим прекрасно справляется?
Другое дело, что почему-то некоторые сервисы не задумались о запуске ffmpeg в песочнице с урезанием всего, что явно не нужно (хотя бы доступа в сеть).

И я вообще не уверен, что использование библиотек вместо утилиты ffmpeg тут бы помогло, утилита ведь точно так же использует эти самые библиотеки, в которых точно так же могут быть уязвимости. Если говорить про пример с m3u8, то делать черный список форматов, которые не конвертировать — плохая идея, можно что-то не учесть, аналогично и с белым списком — не учтешь особенностей каждого из нескольких сотен вариантов, может где-то есть неявная возможность обращения к сети например.

На мой взгляд, именно изолированние любой обработки пользовательских данных — это то решение, которое необходимо *в первую очередь*, которое, кстати, помогло бы в данном случае.
А что в этом плохого, зачем для такой задачи писать/отлаживать/поддерживать из библиотек свой велосипед (причем совсем не простой, когда нужно сделать конфигурируемыми пару десятков параметров), если утилита ffmpeg с этим прекрасно справляется?
Я не имею ничего против вызова бинарников в целом, но использовать бинарник, когда есть байндинги для библиотек, для меня выглядит примерно как вызов system('sleep 10') вместо использования средств языка — нелогично и глупо, хотя, вероятно, и приемлемо, если конкретно в этом случае никаких тонких настроек видео не требуется, что, вероятно, практически всегда правда для сервиса проигрывания видео в браузере.
никаких тонких настроек видео не требуется

как раз наоборот — требуется довольно много настроек кодека + цепочка фильтров в нужном порядке со своими настройками + другие различные опции, и все это очень легко задается опциями утилиты ffmpeg.

Пример с system('sleep 10') лучше заменить на
system('cat /proc/blabla | grep aaa | awk '{print $3" "$4}' | sort | uniq -c | sort -n | head -n3')
Конечно, и для моего примера использовать system() это не хорошо и не стоит так делать в большинстве случаев, но думаю мысль понятна.

Кстати, мне встречались биндинги для некоторых языков именно к утилите ffmpeg — т.е. идея запускать бинарник ffmpeg вместо использования библиотек именно в случае FFmpeg довольно распространена.
как раз наоборот — требуется довольно много настроек кодека + цепочка фильтров в нужном порядке со своими настройками + другие различные опции, и все это очень легко задается опциями утилиты ffmpeg.
Тогда я вообще без идей, почему вы решили использовать именно ffmpeg, а не библиотеки. Можно, конечно, и mediainfo вызывать, и ffprobe для анализа файла, но зачем, когда есть байндинги-то?

идея запускать бинарник ffmpeg вместо использования библиотек именно в случае FFmpeg довольно распространена.
Так и картинки вызовом imagemagick конвертируют, но что в этом хорошего-то?
Зачем, какие будут плюсы именно в задаче конвертирования видео?
Про некоторые минусы я уже говорил выше — время на написание/тестирование/поддержку, хотя по сути это будет копипаст бОльшей части ffmpeg.c. Затраты на fork()+exec() пренебрежимо малы со временем работы процесса конвертации.

Несколько плюсов модели «запуск отдельного процесса на каждую конвертацию»:
— конвертация не может повлиять на враппер — демон, который принимает решение о необходимости запуска процесса конвертации конкретного файла с конкретными параметрами
— возможность запуска из под отдельного пользователя, с более урезанными чем «демон-враппер» правами
— удобное управление лимитами — память, максимальное время работы (считаем, что в библиотеках могут быть баги)

Если согласиться с тем, что для конвертации все же лучше запускать отдельный процесс — то так ли важно, будет ли это ffmpeg или самописнная утилита на основе тех же самых библиотек?

И да, интерфейс у библиотек не сильно высокоуровневый, т.е. там нет функции convert(const char *infile, const char *outfile, struct convert_params *params), а возможности, которые они за счет этого предоставляют (помимо тех, что есть в утилите ffmpeg) в задаче конвертирования не нужны.

И по теме выступления — использование библиотек FFmpeg вместо утилиты ведь не должно спасти от такой аттаки, или есть мнение что должно?
И по теме выступления — использование библиотек FFmpeg вместо утилиты ведь не должно спасти от такой аттаки, или есть мнение что должно?
Ну, например, если вы пишите свое приложение, которое использует библиотеки, то вы можете сделать белый список демуксеров и протоколов, чтобы не вышел такой конфуз, как с файлом. Хотя, не отрицаю, этого можно добиться и с бинарным ffmpeg, указав ему все нужные настройки перед входным файлом.
С библиотеками проще обрабатывать ошибки, вам не нужно парсить вывод в stderr, вы можете это сразу попробовать починить, не запуская процесс перекодировки с самого начала. С точки зрения безопасности, одинакового уровня безопасности можно достичь и с бинарником ffmpeg, либо вручную фильтруя фильтры и протоколы, либо скомпилировав ffmpeg самостоятельно, выкинув все ненужное и потенциально опасное, но, по моему мнению, вызывать бинарники, когда есть байндинги, да еще и не в собственном маленьком проекте, которым пользуется только автор, а в такой крупной компании, где следят за качеством кода, просто как-то неправильно. ffmpeg это не gstreamer, где практически нет вменяемых сообщений об ошибках, и хрен поймешь, почему pipeline не стартует, так что запуск бинарника нельзя оправдать плохим API.
белый список демуксеров и протоколов

выкинув все ненужное и потенциально опасное

см. мой комментарий выше:
делать черный список форматов, которые не конвертировать — плохая идея, можно что-то не учесть, аналогично и с белым списком — не учтешь особенностей каждого из нескольких сотен вариантов, может где-то есть неявная возможность обращения к сети например.


проще обрабатывать ошибки

Важно просто знать, успешной была конвертация или нет + была ли она прервана по таймауту или раньше.
Как может помочь выполнить конвертацию знание, что например файл начиная с 2млн байта полностью битый — я не понял.

просто как-то неправильно

Извините, но я пока не увидел ни одного довода, который смог бы меня убедить в утверждении «запускать бинарник ffmpeg для решения конкретной данной задачи — не правильно, а вот написать свой бинарник используя те же библиотеки и запускать его — лучше».
Для меня пока это выглядит как «не использовать goto в C, потому что это не правильно — ведь все же так говорят».
Я не говорю, что это неправильно, это допустимо, и, видимо, в некоторых случаях это вполне приемлемо, но вам, вероятно, все же не приходилось сталкиваться с задачами, которые через бинарник решить можно, но через свои обращения к библиотеками решить проще и быстрее.

Скажем, загрузили на сервис перекодирования какой-нибудь vob или mpg, у которого звук начинается мегабайта с сотого, а ffmpeg не анализирует так много с начала файла по умолчанию. Вот, ffmpeg определил, что у нас в файле только видео, без звука, начинает кодировать видео, а потом выясняется, что у нас тут еще и звук есть. Все, бинарник не может ничего с ним сделать. Придется либо останавливать процесс кодирования, выбрасывая уже скодированное видео и запуская ffmpeg заново с увеличенными параметрами analyzeduration, либо дождаться кодирования видео, скодировать отдельно аудио и домуксовать в контейнер. Не знаю, насколько распространена загрузка mpg на видеосервис, наверное, вообще не распространена, но мне с таким приходилось сталкиваться не раз и не два. С использованием прямых вызовов libav проблему решить проще, можно, например, сразу закрыть тот файл, куда записывалось видео, скопировать получившийся битстрим в новый файл и продолжить с момента останова.
Или, например, загрузили файл с VFR. С «правильным» VFR, у которого каждую секунду разный фреймрейт. Как вы заранее определите, нужно ли вам копировать pts исходного файла, или нужно свои генерировать? Или вы убъете VFR и приведете файл к какому-то наиболее близкому constant framerate?
А что в этом плохого, зачем для такой задачи писать/отлаживать/поддерживать из библиотек свой велосипед (причем совсем не простой, когда нужно сделать конфигурируемыми пару десятков параметров), если утилита ffmpeg с этим прекрасно справляется?
Я не имею ничего против вызова бинарников в целом, но использовать бинарник, когда есть байндинги для библиотек, для меня выглядит примерно как вызов system('sleep 10') вместо использования средств языка — нелогично и глупо, хотя, вероятно, и приемлемо, если конкретно в этом случае никаких тонких настроек видео не требуется, что, вероятно, практически всегда правда для сервиса проигрывания видео в браузере.
libavcodec и ко — это не «ffmpeg в виде либы», это другой уровень абстракции.
Вот примеры кодирования видео с этими либами:
www.ffmpeg.org/doxygen/0.6/api-example_8c-source.html
ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html
Вы действительно считаете, что такой кусок кода в проекте будет смотреться лучше вызова ffmpeg? :)
Там нет ничего страшного, большую часть кода занимают комментарии, fopen и его проверки, malloc, сами посмотрите. Самих вызовов библиотек там буквально несколько, и все они понятны и просты.
Ок, так Вы считаете, что вот такой цикл по кадрам видео-дорожки будет в проекте смотреться лучше, чем вызов ffmpeg?
    /* encode 1 second of video */
    for (i = 0; i < 25; i++) {
        av_init_packet(&pkt);
        pkt.data = NULL;    // packet data will be allocated by the encoder
        pkt.size = 0;
Вы посмотрите ниже, для чего это. Это пример генерации своей собственной картинки для кодирования, поэтому так подробно и расписано.

Вот, посмотрите свежий пример использования Intel Quick Sync для декодирования:
ffmpeg.org/doxygen/2.8/qsvdec_8c-example.html
В нем используется функция avcodec_decode_video2, которая делает всю основную работу сама.
Что эта функция делает сама? Декодит один кадр?
Это точно будет смотреться в проекте лучше, чем вызов ffmpeg? :)
Да, я уверен, для серьезных проектов, вроде сервиса заливки видео, это точно будет смотреться лучше, чем вызов бинарника.
Тут одно кодирование — 300 строк на C.
А в цепочке конвертации могут участвовать и другие утилиты: MP4Box, m3u8-segmenter, измерение громкости (r128gain). У некоторых из них вообще нет никакого api.
И разные параметры вызовов придется время от времени подкручивать. А еще ffmpeg иногда крешится.
Вы что-то делаете утилитами, чего не может сам ffmpeg? Про mp4box не могу ничего сказать, т.к. контейнером почти не пользуюсь, вполне возможно, что в ffmpeg нет нужной функциональности, но m3u8-segmenter deprecated, как написано в его репозитории, и автор советует использовать муксер «hls» из ffmpeg:
I no longer have much time to work on this project and for the most part it is deprecated now that both ffmpeg and libav have direct support for segmenting and creating m3u files. Quite happy to point this elsewhere if someone else would like to take over the project.

r128gain не пользовался, но что-то мне подсказывает, что его можно заменить ladspa-плагинами, которые поддерживает ffmpeg, и сразу засунуть их в фильтры аудио.
Сейчас наверное ffmpeg уже все это умеет, но в 2012 когда я занимался этим — не умел.
MP4Box использовался для перекладывания индекса в начало файла.
Еще там был mediainfo, который был чем-то лучше чем ffprobe. И утилиты шифрования видео в wiidevine и f4fpackager.
pkruglov сейчас все ссылки на видео битые, есть шанс их поправить или выложить видео еще куда-то? Спасибо.
Привет! Да, они на старом ресурсе были, поищем.
Sign up to leave a comment.