При склеивании видео через Moviepy: AttributeError: 'str' object has no attribute 'duration'

Я пытаюсь нарезать видео на фрагменты, потом склеить эти фрагменты в новое видео. Нарезка на фрагменты проходит успешно, а вот при склеивании выдает исключение:

Traceback (most recent call last):
  File "D:\dev\video_cut\main.py", line 53, in <module>
    main()
  File "D:\dev\video_cut\main.py", line 49, in main
    video.video_cut_and_merge('final')
  File "D:\dev\video_cut\main.py", line 38, in video_cut_and_merge
    merge_final = concatenate_videoclips(clip_merge)
  File "D:\dev\video_cut\venv\lib\site-packages\moviepy\video\compositing\concatenate.py", line 71, in concatenate_videoclips
    tt = np.cumsum([0] + [c.duration for c in clips])
  File "D:\dev\video_cut\venv\lib\site-packages\moviepy\video\compositing\concatenate.py", line 71, in <listcomp>
    tt = np.cumsum([0] + [c.duration for c in clips])
AttributeError: 'str' object has no attribute 'duration'

Сам код:

from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import concatenate_videoclips
from colorama import Fore
from colorama import init

import os
import sys
from dataclasses import dataclass


init()
working_dir = os.path.sep.join(sys.argv[0].split(os.path.sep)[:-1])


@dataclass
class VideoEditor:
    """Basic VideoEditor Class."""
    path_file: str

    def video_cut_and_merge(self, name_file):
        time_range = [(20, 30), (45, 55), (70, 90), (110, 120), (155, 170)]

        print(Fore.CYAN + 'Начинаю вырезку фрагмента видео')
        clip_merge = []
        for i, (start_time, end_time) in enumerate(time_range):
            output_path = f'{working_dir}\\sample\\clip_{i}.mp4'
            ffmpeg_extract_subclip(self.path_file, start_time, end_time, targetname=output_path)
            print(Fore.YELLOW + f'Длительность фрагмента: {end_time - start_time} секунд')
            print(Fore.CYAN + 'Начинаю вырезку фрагмента видео')
            clip_merge.append(output_path)

        print(Fore.GREEN + f'\n[+] Видео сохранено в папку: {working_dir}\\sample')

        if len(clip_merge) <= 1:
            print(Fore.RED + '[-] В указанной директории нечего объединять')
        else:
            print(Fore.YELLOW + f'[+] Найдено фалов: {len(clip_merge)}')
            merge_final = concatenate_videoclips(clip_merge)
            merge_final.write_videofile(os.path.join(os.getcwd(), f'{name_file}.mp4'))
            print(Fore.GREEN + '\n[+] Объединение файлов завершено')

    def add_audio(self):
        pass


def main() -> None:
    """Main Function."""
    video = VideoEditor('D:\\dev\\video_cut\\Logic - Lightsabers (Official Music Video).mp4')
    video.video_cut_and_merge('final')


if __name__ == "__main__":
    main()


Ответы (1 шт):

Автор решения: CrazyElf

Пример использования функции concatenate_videoclips:

from moviepy.editor import VideoFileClip, concatenate_videoclips

clip1 = VideoFileClip("myvideo.mp4")
clip2 = VideoFileClip("myvideo2.mp4").subclip(50,60)
clip3 = VideoFileClip("myvideo3.mp4")
final_clip = concatenate_videoclips([clip1,clip2,clip3])
final_clip.write_videofile("my_concatenation.mp4")

Как видно из примера, в функцию concatenate_videoclips нужно передавать объекты типа VideoFileClip, а не пути к файлам, как у вас:

clip_merge = []
...
output_path = f'{working_dir}\\sample\\clip_{i}.mp4'
clip_merge.append(output_path)
...
merge_final = concatenate_videoclips(clip_merge)

Наверное, достаточно будет поменять одну строку:

clip_merge.append(VideoFileClip(output_path))
                  ^^^^^^^^^^^^^^           ^
→ Ссылка