Comments 20
А покажите, пожалуйста, пример кодирования H.265, и с какой скоростью оно это делает. Очень интересно.
И, кстати, надеюсь, что в конце сентября покажу уже сервис по распределенному кодированию видео, о концепции которого писал год назад. Сейчас, я считаю, самое время: людям нужно кодировать и в h.265, и в vp8, и в vp9, да еще и 4K-видео вот-вот пойдет потоком, а тот же ZenCoder — один из самых популярных сервисов по кодированию видео ­— возьмет с вас более $2 (!!!) за кодирование 3-минутного видеоролика в 4K в H.265. Мой же сервис будет не только позволять устанавливать все параметры кодирования для любого видеокодека, и использовать встроенные фильтры ffmpeg, но и будет заметно дешевле. Кодирование подобного видео обойдется примерно в 30 центов.
Решил для сравнения закодировать то же видео с помощью x264 (на процессоре i7-3770K). Подобрал параметры, чтобы получилась такая же скорость кодирования и размер файла (preset=ultrafast, crf=24.5).

Получившееся видео. При сравнении на глаз и там и там артефакты, какое видео лучше — непонятно.

Но, согласитесь, довольно достойный результат для H.265 с такой скоростью. Я несколько удивлен даже.
Хм, а может это не лучшая идея просто игнорировать возвращенное значение? Ведь функция все-таки зачем-то вызывается. Мне кажется, стоило проверить, что на самом деле не так…
Кроме того, я не вижу, как функция явным образом меняет eax, да и код функции приведен не весь (куда ведет je 0x7fffe288d568?)
Код не полностью приведён, это правда, меняется ниже. Совпадение размера окна ассемлерного кода в отладчике и инструкции ret вводит в заблуждение.

Правда в том, что eax меняется вообще в другом модуле.
www.dropbox.com/s/9by7mkr9lh4ajg7/%D0%A1%D0%BA%D1%80%D0%B8%D0%BD%D1%88%D0%BE%D1%82%202015-07-15%2001.39.13.png?dl=0

То есть, когда первая загадочная функция вызывается, она что-то делает, получает через dlsym указатель на другую библиотечную функцию и прыгает по нему. Не вызывает, а просто прыгает. Возврат на пропатченную мною инструкцию происходит уже из другого модуля. Мне кажется, в коде это выглядит как хвостовая оптимизация, когда функция всегда возвращает результат другой функции. Вызов опускается, заменяется на прыжок и управление возвращается уже вызвавшему первую функцию. Мне кажется, там ничего ценного, раз она безусловно возвращается и результат не проверяется.
а наплевать на эту лицензию в России. Она нарушает российское законодательство и в этой части ничтожна
UPD: Всё указанное выше справедливо и для новых драйверов 367.35. Смещение в файле получается 0x163bd.
а есть мысли насчет реализации дров и работы с 1070?
Там после 3-го потока падает:
pthread_mutex_unlock(0x3681dc0, 2, 0x10cbbc0, 1) = 0
pthread_mutex_lock(0x3681dc0, 1, 0, 1) = 0
posix_memalign(0x7ffebf75a6f0, 32, 488, 0) = 0
memset(0x3682700, '\0', 488) = 0x3682700
free(0) = dlopen(«libcuda.so.1», 1) = 0x3682910
dlsym(0x3682910, «cuInit») = 0x7fe3dd42b500
dlsym(0x3682910, «cuDeviceGetCount») = 0x7fe3dd42b9a0
dlsym(0x3682910, «cuDeviceGet») = 0x7fe3dd42b800
dlsym(0x3682910, «cuDeviceGetName») = 0x7fe3dd42bb20
dlsym(0x3682910, «cuDeviceComputeCapability») = 0x7fe3dd42c1c0
dlsym(0x3682910, «cuCtxCreate_v2») = 0x7fe3dd42cb80
dlsym(0x3682910, «cuCtxPopCurrent_v2») = 0x7fe3dd42d030
dlsym(0x3682910, «cuCtxDestroy_v2») = 0x7fe3dd42cd30
dlopen(«libnvidia-encode.so.1», 1) = 0x3683280
dlsym(0x3683280, «NvEncodeAPIGetMaxSupportedVersio»...) = 0x7fe3dcde2cb0
dlsym(0x3683280, «NvEncodeAPICreateInstance») = 0x7fe3dcde6410
posix_memalign(0x7ffebf75a5f8, 32, 32, 1) = 0
memcmp(0x3dc3440, 0x344779c, 16, 0) = 0
free(0x3dc3440) = posix_memalign(0x7ffebf759090, 32, 24, 0x3dc4f50) = 0
memset(0x3dc3440, '\0', 24) = 0x3dc3440
realloc(0, 16) = 0x3dc3b30
posix_memalign(0x7ffebf75a5e0, 32, 0xc800, 31) = 0
memset(0x3e9d1c0, '\0', 51200) = 0x3e9d1c0
posix_memalign(0x7ffebf75a5d8, 32, 256, 0x3ea99c0) = 0
posix_memalign(0x7ffebf75a5c0, 32, 40, 0x7fe3e791f760) = 0
memset(0x3dc35e0, '\0', 40) = 0x3dc35e0
posix_memalign(0x7ffebf75a5d8, 32, 256, 0x7fe3e791f760) = 0
posix_memalign(0x7ffebf75a5c0, 32, 40, 0x7fe3e791f760) = 0
memset(0x3dc37c0, '\0', 40) = 0x3dc37c0
posix_memalign(0x7ffebf75a5d8, 32, 256, 0x7fe3e791f760) = 0
posix_memalign(0x7ffebf75a5c0, 32, 40, 0x7fe3e791f760) = 0
memset(0x3dc39a0, '\0', 40) = 0x3dc39a0
pthread_mutex_lock(0x1c94ac0, 16, 0x130298a, 0x7ffebf759ed8) = 0
__vsnprintf_chk(0x7ffebf758e94, 1004, 1, -1) = 25
__vsnprintf_chk(0x7ffebf759694, 1004, 1, -1) = 49
__snprintf_chk(0x7ffebf759a80, 1024, 1, 1024) = 74
strcmp("[h264_nvenc @ 0x340bde0] CreateB"..., "\n") = 81
__strcpy_chk(0x1c946a0, 0x7ffebf759a80, 1024, 0) = 0x1c946a0
__fprintf_chk(0x7fe3e79201c0, 1, 0x132c96d, 1[h264_nvenc @ 0x340bde0] ) = 36
__fprintf_chk(0x7fe3e79201c0, 1, 0x132c96d, 1CreateBitstreamBuffer failed: out of memory (10)
) = 60
pthread_mutex_unlock(0x1c94ac0, 0, 0x7ffebf759694, 0x7fe3e764c72d) = 0
free(0x3dc3480) = free(0x3dc35e0) = free(0x3dc3840) = free(0x3dc39a0) = free(0x3dc3660) = free(0x3dc37c0) = — SIGSEGV (Segmentation fault) — +++ killed by SIGSEGV +++
Причина оказалась в лимите числа буферов у видеокарты. Решили ограничить аппетиты ffmpeg по числу буферов вот таким патчем:
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index a3a2ef5..1691d15 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -1157,7 +1157,7 @@ static av_cold int nvenc_setup_surfaces(AVCodecContext *avctx)
     NvencContext *ctx = avctx->priv_data;
     int i, res;
     int num_mbs = ((avctx->width + 15) >> 4) * ((avctx->height + 15) >> 4);
-    ctx->nb_surfaces = FFMAX((num_mbs >= 8160) ? 32 : 48,
+    ctx->nb_surfaces = FFMAX((num_mbs >= 8160) ? 8 : 12,
                              ctx->nb_surfaces);
     ctx->async_depth = FFMIN(ctx->async_depth, ctx->nb_surfaces - 1);
 
diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
index 6914046b..7f050af 100644
--- a/libavcodec/nvenc_h264.c
+++ b/libavcodec/nvenc_h264.c
@@ -80,7 +80,7 @@ static const AVOption options[] = {
     { "vbr_2pass",    "Multi-pass variable bitrate mode",   0,                    AV_OPT_TYPE_CONST, { .i64 = NV_ENC_PARAMS_RC_2_PASS_VBR },           0, 0, VE, "rc" },
     { "rc-lookahead", "Number of frames to look ahead for rate-control",
                                                             OFFSET(rc_lookahead), AV_OPT_TYPE_INT,   { .i64 = -1 }, -1, INT_MAX, VE },
-    { "surfaces",     "Number of concurrent surfaces",      OFFSET(nb_surfaces),  AV_OPT_TYPE_INT,   { .i64 = 32 },  0, INT_MAX, VE },
+    { "surfaces",     "Number of concurrent surfaces",      OFFSET(nb_surfaces),  AV_OPT_TYPE_INT,   { .i64 = 8 },  0, INT_MAX, VE },
     { "cbr",          "Use cbr encoding mode",              OFFSET(cbr),          AV_OPT_TYPE_BOOL,  { .i64 = 0 },   0, 1, VE },
     { "2pass",        "Use 2pass encoding mode",            OFFSET(twopass),      AV_OPT_TYPE_BOOL,  { .i64 = -1 }, -1, 1, VE },
     { "gpu",          "Selects which NVENC capable GPU to use. First GPU is 0, second is 1, and so on.",
Соответственно, теперь работает ограничение через параметр surfaces командной строки.
На GP107GL Quadro P400 запуск патча убрал ограничение на количество одновременно запущенных ffmpeg'ов (ловите pull request на github'e для поддержки текущей версии и CentOS).

Однако скорость работы линейно уменьшается с увеличением числа ffmpeg'ов, как будто обработку всё равно ведут только два процессора.

Так и должно быть?

Измерял так: gist.github.com/ilyaevseev/fc75df36fe27f1ab580e6afb285b9ab7#file-ffmpeg-nvenc-parbench-sh
Если декодирование ведётся средствами процессора, то скорее всего в него и упирается. В мэйлинг-листе ffmpeg один пользователь сообщает, что достиг параллелизма 60 SD-каналов. И то, упёрся только в объём памяти GPU. Судя по опциям, которые он указал, у него и декодирование аппаратное.

А пуллреквесты принимает keylase.
если декодирование ведется процессором, то легко можно и в шину упереться.

Мы кстати смогли уменьшить память относительно ффмпега — не надо разные процессы создавать.
А что в данном случае подразумевается под «процессором»?
Илья пишет что используется GP107GL Quadro P400.
Имеется ввиду её процессор или обычный процессор?
Имеется в виду ситуация, когда декодинг ведётся обычным процессором, а энкодинг на GPU.
Only those users with full accounts are able to leave comments. Log in, please.