2025, Oct 20 13:17
Как ускорить видео в MoviePy без AttributeError: правильное применение MultiplySpeed
Избавляемся от AttributeError в MoviePy при ускорении видео: как правильно применить эффект MultiplySpeed и корректно вызвать write_videofile на практике.
Ускорение видео в MoviePy может неожиданно оказаться сложным, если обращаться с эффектами так, будто это клипы. Частая ловушка — присвоить MultiplySpeed напрямую переменной и затем вызвать для неё write_videofile, что заканчивается AttributeError. Если вы увидели сообщение о том, что у объекта MultiplySpeed нет атрибута write_videofile, вы по адресу.
Демонстрация проблемы
Фрагмент ниже пытается ускорить видео, но терпит неудачу, потому что эффект не применяется к клипу:
from moviepy import *
import moviepy.video.fx as vfx
from moviepy.video.fx import MultiplySpeed
# загружаем, а затем по ошибке заменяем клип объектом эффекта
media_in = VideoFileClip(r"xxx.mp4")
media_in = MultiplySpeed(2)
media_in.write_videofile("fast_export.mp4", codec="libx264")
Это приводит к AttributeError, потому что в переменной, где раньше был клип, теперь находится экземпляр эффекта.
Что происходит на самом деле
MultiplySpeed — это эффект. Он сам по себе не превращается в видео; его нужно применить к существующему клипу. Когда вы перезаписываете переменную клипа значением MultiplySpeed(2), вы теряете доступ к методам клипа, таким как write_videofile. Правильная схема — держать в переменной настоящий клип и накладывать эффект либо через apply(), либо через with_effects() у самого клипа. В документации описано применение объекта эффекта методом apply(), а исходный код показывает, что доступен и with_effects() на клипе.
Рабочее решение и исправленный код
Первый вариант: применить объект эффекта к клипу.
from moviepy import *
import moviepy.video.fx as vfx
from moviepy.video.fx import MultiplySpeed
source_clip = VideoFileClip(r"xxx.mp4")
faster_clip = MultiplySpeed(2).apply(source_clip)
faster_clip.write_videofile("output_fast.mp4", codec="libx264")
Альтернативный подход: подключить эффект через with_effects() у клипа.
from moviepy import *
import moviepy.video.fx as vfx
from moviepy.video.fx import MultiplySpeed
src = VideoFileClip(r"xxx.mp4")
accelerated = src.with_effects([MultiplySpeed(2)])
accelerated.write_videofile("output_fast.mp4", codec="libx264")
Ниже практический вариант: скорость умножается на четыре, результат пишется по вложенному пути:
from moviepy import *
import moviepy.video.fx as vfx
from moviepy.video.fx import MultiplySpeed
video_pathname = r"xxxxxx.mp4"
base = VideoFileClip(video_pathname)
boosted = base.with_effects([MultiplySpeed(4)])
boosted.write_videofile("Random/output_fast.mp4", codec="libx264")
Почему это важно
Понимание границы между «клипом» и «эффектом» экономит время и избавляет от путаных ошибок. API клипа остаётся доступным только если в переменной хранится корректный VideoFileClip (или производный клип), а эффекты применяются к нему, а не наоборот. Что вам ближе — явный apply() у эффекта или лаконичный with_effects() у клипа — оба пути делают конвейер предсказуемым, а код — понятным.
Вывод
Когда нужно ускорить видео в MoviePy, не переопределяйте переменную клипа объектом эффекта. Сначала загрузите клип, затем примените MultiplySpeed через apply() или with_effects(), и только после этого рендерьте через write_videofile. Эта небольшая деталь устраняет AttributeError и поддерживает пайплайн чистым и удобным в сопровождении.
Статья основана на вопросе на StackOverflow от Sharks Charlatans и ответе пользователя furas.