Skip to content

Cut Video

The cut-video command creates a new video by removing the silences present in the video file.

For example:

vmh cut-video sample.mp4

This will remove the silences and generate a file called result.mp4.

You can find some examples of cuts here.

Usage examples

Simple cuts

To edit a video named sample.mp4 using the default parameters, use:

vmh cut-video sample.mp4

This will remove the silences and generate a file called result.mp4.

Cuts based on another audio file

Sometimes, we have a video file and an external audio file that is already equalized and processed.

We can cut the video based on the silences from this audio and generate a new file that removes the original audio from the video and replaces it with the new audio file:

vmh cut-video video_sample.mp4 --audio_file equalized_audio.wav

This way, the new video will have the equalized audio with the cuts already applied.

Concepts and features

Silences are defined by the audio threshold and the minimum duration of silence found in the audio. As this is common for all cutting commands, the explanation can be found here.

--help Flag Output:

$ vmh cut-video --help

 Usage: vmh cut-video [OPTIONS] VIDEO_FILE [OUTPUT_PATH] [AUDIO_FILE]                  

 Edits a video using silences as reference.                                            

╭─ Arguments ─────────────────────────────────────────────────────────────────────────╮
│ *    video_file       PATH           [default: None] [required]                     │
│      output_path      [OUTPUT_PATH]  [default: result.mp4]                          │
│      audio_file       [AUDIO_FILE]   Optional audio equilized audio file            │
╰─────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ───────────────────────────────────────────────────────────────────────────╮
│ --silence-time  -s                INTEGER                  Minimal time in ms for   │
│                                                            configure a silence      │
│                                                            [default: 400]           │
│ --threshold     -t                INTEGER                  Value in db for detect   │
│                                                            silence                  │
│                                                            [default: -65]           │
│ --distance      -d                [negative|tiny|small|me  Distance betweet         │
│                                   dium|large|huge]         silences                 │
│                                                            [default: tiny]          │
│ --codec         -c                [libx264|mpeg4|rawvideo  [default: mpeg4]         │
│                                   |png|libvorbis|libvpx]                            │
│ --preset        -p                [ultrafast|superfast|ve  [default: medium]        │
│                                   ryfast|faster|fast|medi                           │
│                                   um|slow|slower|veryslow                           │
│                                   ]                                                 │
│ --bitrate       -b                TEXT                     [default: 15M]           │
│ --force             --no-force                             Ignore cache             │
│                                                            [default: no-force]      │
│ --help                                                     Show this message and    │
│                                                            exit.                    │
╰─────────────────────────────────────────────────────────────────────────────────────╯

API for developers

Source code in videomaker_helper/video.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
def cut_video(
    input_file: str,
    output_file: str,
    silence_time: int,
    threshold: int,
    distance: Literal[
        'negative',
        'tiny',
        'small',
        'medium',
        'large',
        'huge',
    ] = 'tiny',
    bitrate: str = '15M',
    codec: Codec = Codec.mpeg4,
    audio_file: str = '',
    preset: Preset = Preset.medium,
    force: bool = True,
):
    logger.info(f'Detecting silences on {input_file}')
    if audio_file:
        silences = detect_silences(
            audio_file,
            force=force,
            threshold=threshold,
            silence_time=silence_time,
            distance=distance,
        )
        video = VideoFileClip(input_file)
        paudio = AudioFileClip(str(audio_file))
        video.audio = paudio
    else:
        silences = detect_silences(
            input_file,
            force=force,
            threshold=threshold,
            silence_time=silence_time,
            distance=distance,
        )
        video = VideoFileClip(input_file)

    logger.info(f'Creating subclips on {input_file}')
    clips = [
        video.subclipped(start, stop)
        for start, stop in islice(pairwise(silences), 1, None, 2)
    ]

    final_video = concatenate_videoclips(clips)

    logger.info(f'Writing {output_file}')
    final_video.write_videofile(
        output_file,
        codec=codec.value,
        preset=preset.value,
        bitrate=bitrate,
    )