Я написал прогу на пайтон для преобразования изобр...

Created on: June 28, 2026

Answered using GPT-5.5 Thinking by Chat01

Question

Я написал прогу на пайтон для преобразования изображений и аудио в видео. на моем сервере используется видеокарта от нвидиа RTX4060. также я использую ffmpeg 8.1. Посмотри мой код и предложи что можно улучшить (может кодек), основная задача увеличить скорость создания видео
ffmpeg_image = (
FFmpeg()
.option('y')
.option('loop', '1') # зацикливаем изображение
.input(img_path)
.input(aud_path)
.output(segment_path, {
'c:v': 'h264_nvenc', # используем NVIDIA encoder вместо CPU
'c:a': 'aac',
'vf': 'scale=1280:720,fps=24',
't': str(duration),
'shortest': None,
'preset': 'p1', # preset для NVENC (p1-p7, p4 - баланс качества и скорости)
'rc': 'vbr', # режим контроля битрейта
'cq': '28', # качество сжатия (аналог crf для CPU)
})
)

Thought

undefined

Thought

undefined

Thought

Evaluating encoding options for speed and file size

I'm considering if AV1 encoding could improve speed, but it may be slower than H.264, especially for static images. For speed, using h264_nvenc p1 might already be the fastest, and options like -tune ull, -zerolatency, and -bf 0 could enhance performance. For file generation, using rc constqp might be faster than variable bitrate options, though NVIDIA docs could help clarify any technical details. Also, I should avoid using -movflags +faststart if speed is crucial.

Thought for 40s

Answer

Главный вывод: для статичной картинки + аудио быстрее всего не “подкрутить NVENC”, а перестать делать 24 одинаковых кадра в секунду. Сейчас строка:

python
'vf': 'scale=1280:720,fps=24',

может быть главным тормозом: scale — CPU-фильтр, а fps=24 заставляет генерировать много одинаковых кадров.

1. Самое сильное ускорение: делай 1 fps, если видео — статичная картинка

Если тебе не принципиально, чтобы файл был именно 24 fps, ставь 1 fps. Для видео “картинка + звук” это нормально: картинка просто висит на экране, звук играет.

Пример:

python
ffmpeg_image = ( FFmpeg() .option('y') .option('hide_banner') .option('loglevel', 'error') .input(img_path, {'loop': '1', 'framerate': '1'}) .input(aud_path) .output(segment_path, { 'map': ['0:v:0', '1:a:0'], 'c:v': 'h264_nvenc', 'preset': 'p1', 'rc': 'constqp', 'qp': '30', 'r': '1', 'pix_fmt': 'yuv420p', 'c:a': 'aac', 'b:a': '128k', 't': str(duration), 'shortest': None, 'vf': 'scale=1280:720', }) )

Что изменилось:

python
.input(img_path, {'loop': '1', 'framerate': '1'})

и

python
'r': '1'

Вместо 24 кадров в секунду будет 1 кадр в секунду. Для 5-минутного ролика это примерно 300 кадров вместо 7200. Ускорение может быть очень заметным.

2. Если обязательно нужен 24 fps

Тогда хотя бы задай входной framerate для картинки как 1, а уже потом делай fps=24:

python
.input(img_path, {'loop': '1', 'framerate': '1'})

и фильтр:

python
'vf': 'scale=1280:720,fps=24'

Это лучше, чем пускать looped image с дефолтной частотой. Но всё равно медленнее, чем 1 fps, потому что NVENC будет кодировать 24 кадра в секунду.

3. Замени vbr + cq на constqp, если главная цель — скорость

Сейчас у тебя:

python
'rc': 'vbr', 'cq': '28',

Для максимальной скорости проще использовать:

python
'rc': 'constqp', 'qp': '30',

Например:

python
'rc': 'constqp', 'qp': '30',

qp можно подбирать:

text
26–28 — лучше качество, больше размер 30–32 — быстрее/меньше размер, качество чуть хуже 34+ — заметнее сжатие

Для статичной картинки qp=30 или 32 обычно вполне нормально.

4. Аудио: если можно — копируй, не перекодируй

Если входной аудиофайл уже AAC и тебе подходит контейнер MP4, лучше:

python
'c:a': 'copy'

Вместо:

python
'c:a': 'aac'

Копирование потока убирает декодирование и повторное кодирование аудио; FFmpeg прямо описывает, что при codec copy нет операций decoding-filtering-encoding, пакеты просто переносятся в выходной файл. (FFmpeg)

Вариант:

python
'c:a': 'copy',

Но если аудио бывает MP3/WAV/OGG/Opus и тебе нужен стабильный MP4, оставляй:

python
'c:a': 'aac', 'b:a': '128k',

5. GPU scaling: можно, но не всегда даст выигрыш для одной картинки

NVIDIA рекомендует для GPU-пайплайна держать кадры в GPU-памяти и использовать scale_cuda или scale_npp; в их примерах для FFmpeg используются -hwaccel cuda -hwaccel_output_format cuda, а для масштабирования — scale_cuda или scale_npp. (NVIDIA Docs)

Но у тебя вход — одна картинка, а не видео. Поэтому часто быстрее будет:

  1. заранее один раз ресайзнуть картинку;
  2. потом кодировать уже готовую 1280x720 картинку без scale.

Самый практичный вариант: кэшировать подготовленные изображения.

Например:

text
original.jpg -> prepared_1280x720.jpg

И потом в FFmpeg уже не делать:

python
'vf': 'scale=1280:720'

Это может дать больше пользы, чем перенос scale на GPU.

6. Если хочешь попробовать GPU-фильтр

Проверь, есть ли у тебя scale_cuda или scale_npp:

bash
ffmpeg -filters | grep scale_cuda ffmpeg -filters | grep scale_npp

Если есть scale_cuda, можно попробовать:

python
'vf': 'format=nv12,hwupload_cuda,scale_cuda=1280:720'

Если есть scale_npp:

python
'vf': 'format=nv12,hwupload_cuda,scale_npp=1280:720'

Но для твоего кейса я бы сначала тестировал 1 fps и предварительный resize картинок.

7. Кодек: H.264 NVENC — нормальный выбор для скорости

Для скорости и совместимости оставляй:

python
'c:v': 'h264_nvenc'

RTX 4060 относится к RTX 40 Series/Ada, а у Ada есть NVENC с AV1-кодированием; NVIDIA пишет, что карты Ada имеют NVENC с AV1 и что AV1 эффективнее H.264 по сжатию. (NVIDIA) Но для твоей задачи av1_nvenc я бы не ставил первым вариантом: он может дать меньший размер файла, но совместимость хуже, а скорость создания не обязательно будет выше.

То есть:

text
нужна максимальная совместимость и скорость → h264_nvenc нужен меньший размер и современная платформа → av1_nvenc можно тестировать

8. Оптимизированный вариант под скорость

Я бы начал вот с такого варианта:

python
ffmpeg_image = ( FFmpeg() .option('y') .option('hide_banner') .option('loglevel', 'error') .input(img_path, { 'loop': '1', 'framerate': '1', }) .input(aud_path) .output(segment_path, { 'map': ['0:v:0', '1:a:0'], 'c:v': 'h264_nvenc', 'preset': 'p1', 'rc': 'constqp', 'qp': '30', 'r': '1', 'pix_fmt': 'yuv420p', 'c:a': 'aac', 'b:a': '128k', 'vf': 'scale=1280:720', 't': str(duration), 'shortest': None, }) )

Если аудио уже AAC:

python
'c:a': 'copy'

9. Ещё быстрее: заранее готовь картинки

Самая быстрая схема:

text
1. Один раз подготовить картинку 1280x720 2. Сохранить в кэш 3. Для видео использовать уже готовую картинку 4. Не использовать scale в основном ffmpeg-вызове

Тогда основной код:

python
ffmpeg_image = ( FFmpeg() .option('y') .option('hide_banner') .option('loglevel', 'error') .input(prepared_img_path, { 'loop': '1', 'framerate': '1', }) .input(aud_path) .output(segment_path, { 'map': ['0:v:0', '1:a:0'], 'c:v': 'h264_nvenc', 'preset': 'p1', 'rc': 'constqp', 'qp': '30', 'r': '1', 'pix_fmt': 'yuv420p', 'c:a': 'aac', 'b:a': '128k', 't': str(duration), 'shortest': None, }) )

Вот это, скорее всего, будет быстрее твоего текущего варианта.

10. Как проверить, где реальный тормоз

Запусти FFmpeg с benchmark:

bash
ffmpeg -benchmark ...

Сравни 3 варианта:

text
A. текущий: scale=1280:720,fps=24 B. framerate=1 + r=1 C. заранее resized image + r=1

Я бы ожидал такой порядок скорости:

text
самый быстрый: prepared image + 1 fps средний: framerate=1 + scale + 1 fps медленный: scale + fps=24

Главное: preset: p1 у тебя уже правильный для скорости. Больше всего ускорит не другой preset, а отказ от 24 fps и повторного масштабирования одинаковых кадров.

Share this Q&A