Search code examples
pythonffmpegmoviepy

Python - How to trim black boarder from video (top, bottom, sides)


If I have a .mp4 video file with black boarders on the top, bottom, and/or sides, How can I trim these boarders off with python?

I do not want to replace the boarders with anything, I just want to trim the video.

For example, if I run magically_trim_black_boarders_from_vid(in_vid) on a video that looks like the frame below, the video's height would not change, but its width would be reduced.

enter image description here

Thanks!


Solution

  • We my use cropdetect filter as described in the following post.

    Within Python we may execute FFmpeg as subprocess twice - first time with cropdetect filter for finding the black borders, and second time for cropping the borders.

    The output of cropdetect filter is as a lines of text, that should be parsed:

    #[Parsed_cropdetect_0 @ 00000232c2705e00] x1:69 x2:551 y1:0 y2:309 w:480 h:304 x:72 y:4 pts:512 t:0.040000 crop=480:304:72:4
    #[Parsed_cropdetect_0 @ 00000232c2705e00] x1:69 x2:551 y1:0 y2:309 w:480 h:304 x:72 y:4 pts:1024 t:0.080000 crop=480:304:72:4
    ...
    

    Suggested stages:

    • Execute FFmpeg as subprocess with cropdetect filter, and storing the (stderr) output in cropdetect_output string:

       cropdetect_output = sp.run(['ffmpeg', '-hide_banner', '-i', in_video_file, '-vf', 'cropdetect=skip=0', '-t', '1', '-f', 'null', 'pipe:'], stderr=sp.PIPE, universal_newlines=True).stderr
      
    • Find the substring, that starts with "crop=" and ends by new line using re.search regular expression searching:

       crop_str = re.search('crop=.*', cropdetect_output).group(0)  # crop=480:304:72:4
      
    • Execute FFmpeg using crop filter with the crop= arguments found above.

       sp.run(['ffmpeg', '-hide_banner', '-i', in_video_file, '-vf', crop_str+',setsar=1', out_video_file])
      

    Code sample:

    import subprocess as sp
    import re
    
    in_video_file = 'wnkaa.mp4'
    out_video_file = 'cropped_wnkaa.mp4'
    
    # ffmpeg -hide_banner -i wnkaa.mp4 -vf cropdetect=skip=0 -t 1 -f null
    cropdetect_output = sp.run(['ffmpeg', '-hide_banner', '-i', in_video_file, '-vf', 'cropdetect=skip=0', '-t', '1', '-f', 'null', 'pipe:'], stderr=sp.PIPE, universal_newlines=True).stderr
    
    # Return: crop=480:304:72:4
    crop_str = re.search('crop=.*', cropdetect_output).group(0)  # Find the first match of "crop=", and return all characters from "crop=" up to new line.
    
    # ffmpeg -hide_banner -i wnkaa.mp4 -vf crop=480:304:72:4,setsar=1 cropped_wnkaa.mp4
    sp.run(['ffmpeg', '-hide_banner', '-i', in_video_file, '-vf', crop_str+',setsar=1', out_video_file])
    

    Note:
    The above command uses default codec arguments (it's just an example).
    We may add encoding arguments like '-vcodec', 'libx264', '-crf', '20', '-pix_fmt', 'yuv420p'...


    Sample output frame:
    enter image description here