pythonpython-3.xffmpegvideo-processingvideo-editing

Issue using moviepy package (Python)


I'm using ffmpeg_extract_subclip function from moviepy to process video files. However, the video cut I get is not the same length between start time and end time I set. For example, writing:

from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip

clip=clip_filename
cutclip="cutvideo.avi"
ffmpeg_extract_subclip(clip_filename, 0, 10, targetname=cutclip)

I get a video of length 10,03 or something like that (in terms of frame count, I get 602 frames instead of exactly 600). Is there a way to get a more accurate output?


Solution

  • Hmm...I'd merge this answer and the actual implementation of ffmpeg_extract_subclip(https://zulko.github.io/moviepy/_modules/moviepy/video/io/ffmpeg_tools.html#ffmpeg_extract_subclip):

    def ffmpeg_extract_subclip(filename, t1, t2, targetname=None):
            """ Makes a new video file playing video file ``filename`` between
            the times ``t1`` and ``t2``. """
        name, ext = os.path.splitext(filename)
        if not targetname:
            T1, T2 = [int(1000*t) for t in [t1, t2]]
            targetname = "%sSUB%d_%d.%s" % (name, T1, T2, ext)
        
        cmd = [get_setting("FFMPEG_BINARY"),"-y",
               "-ss", "%0.2f"%t1,
               "-i", filename,
               "-t", "%0.2f"%(t2-t1),
               "-map", "0", "-vcodec", "copy", "-acodec", "copy", targetname]
        
        subprocess_call(cmd)
    

    So, as you can see, the library is pretty stateless, thus can be easily extended:

    def ffmpeg_extract_subclip_precisely(filename, t1, t2, targetname=None):
        """ Makes a new video file playing video file ``filename`` between
            the times ``t1`` and ``t2``. """
        name, ext = os.path.splitext(filename)
        if not targetname:
            T1, T2 = [int(1000*t) for t in [t1, t2]]
            targetname = "%sSUB%d_%d.%s" % (name, T1, T2, ext)
    
        cmd = [get_setting("FFMPEG_BINARY"), "-i", filename,
               "-force_key_frames", "{}:{}".format(t1,t2), "temp_out.mp4"]
    
        subprocess_call(cmd)
        
        cmd = [get_setting("FFMPEG_BINARY"),"-y",
               "-ss", "%0.2f"%t1,
               "-i", "temp_out.mp4",
               "-t", "%0.2f"%(t2-t1),
               "-map", "0", "-vcodec", "copy", "-acodec", "copy", targetname]
        
        subprocess_call(cmd)
        
    

    I believe you should be specifying times with milliseconds accuracy whenever possible, by the way.

    Please note that the code above is untested.