3

I have a bunch of .mp4 files (DRM free). Each file comprises two episodes of a kids TV show. I would like to simply split the file in two without re-encoding. What's the best way to do this? Preferably with a GUI (as I need to skip to the correct part of each file to find the divider between the two episodes).

Thanks,

5
  • 2
    Have you read the answers to this question? A few of them suggest GUI-based solutions too. Jan 30, 2016 at 21:30
  • 3
    Possible duplicate of Splitting an MP4 file Jan 30, 2016 at 21:32
  • You could simply find out the point where to split by watching it in a normal viewer (VLC, etc) and then use the terminal, as most things are command line based in ubuntu Jan 30, 2016 at 21:34
  • I have been trimming a lot of videos lately using something similar to what I posted below. The combo of opening in VLC, and then running the script is probably just as fast if not faster than a GUI application.
    – jbrock
    Jan 31, 2016 at 21:54
  • If they all split at exactly the same place, then I'd be glad to update the below script so it is a batch operation. That would save a lot of time.
    – jbrock
    Jan 31, 2016 at 21:56

2 Answers 2

7

I recommend opening the video in a media player to find the time where you want to split it. Then you can use ffmpeg with the following script. It does not re-encode the video.

#!/bin/bash

# Split Video Script
# Usage: script_name file_name split-point
# Example: split_video_script bugs_bunny.mp4 31:23
# Instructions:     
# 1. Type the name of your script (if it is already added to ~/bin and marked as executable). 
# 2. Type the file name including path to it if necessary. 
# 3. Type the time where you want to split the video. It goes in minutes:seconds

# Get length in seconds
length=$(echo "$2" | awk -F: '{print ($1 * 60) + $2}')

# Get filename without extension
fname="${1%.*}"

# First half
ffmpeg -i "${fname}.mp4" -c copy -t "$length" "${fname}1.mp4"

# Second half
ffmpeg -i "${fname}.mp4" -c copy -ss "$length" "${fname}2.mp4"

Update: I recently needed to update this script because of an issue with the second half. So, now I have to process the second half of it. You would add in the parameters that are specific to your original video. You can use mediainfo, ffprobe or ffmpeg -i to find the needed information about your original video.

#!/bin/bash

if [ -z "$1" ]; then
    echo "Usage: $0 file-name"
    exit 1
fi

read -p "Enter time to split video (hh:mm:ss.mmm) " split_time

ext="${1##*.}"
fname="${1%.*}"

# First half
ffmpeg -i "$1" -c copy -t "$split_time" -c:s copy "${fname}1.${ext}"

# Second half
ffmpeg -ss "$split_time" -i "$1" -c:v libx264 -crf 17 -preset veryfast -r 30 -s 1920x1080 -c:a aac -ac 2 -b:a 256k -ar 44100 -pix_fmt yuv420p -movflags faststart -c:s copy "${fname}2.${ext}"
3
  • The command generates two parts. The first part is fine. But the second video plays with a black screen for the first couple of seconds. Any idea how to fix that problem?
    – nbkhope
    Apr 24, 2021 at 3:59
  • Thank you for bringing this to my attention. I had updated my script recently due to the same issue. I have posted it above. Best of luck.
    – jbrock
    Apr 24, 2021 at 20:31
  • Works great for me, thank you :+1:
    – Wim
    Jul 20, 2023 at 15:32
0

I needed to use your script to split a video into thirds instead of splitting the mp4 into two. Here is my version of the script:

#!/bin/bash

NUM_OF_SPLITS=3

main() {
    # Requires: $ `brew install ffmpeg`

    # total length in seconds 
    total_length=$(ffprobe -v quiet -of csv=p=0 -show_entries format=duration "$1")

    # Get filename without extension
    fname="${1%.*}"
    split_time=$(echo "$total_length"/"$NUM_OF_SPLITS" | bc -l)

    declare -a start_times
    declare -a end_times

    for((i=0; i < $num_of_splits; i++)); do
        local output_file="${fname}_"part$i".mp4"
        if [[ "$i" -eq 0 ]]; then
            local start_time=0
            local end_time="$split_time"

            ffmpeg -i "${fname}.mp4" -c copy -t "$end_time" "$output_file"
        else
            local start_time="${end_times[$i-1]}"
            local end_time=$(echo "$start_time "*" 2" | bc -l)

            # echo "Start time: $start_time"
            # echo "End time: $end_time"

            ffmpeg -ss "$start_time" -to "$end_time"  -i "${fname}.mp4" -c copy "$output_file"
        fi

        start_times+=($start_time)
        end_times+=("$end_time")
    done

}

# Split Video Script
# Example: split_video_script bugs_bunny.mp4
# Instructions:     
# 1. Type the name of your script (if it is already added to ~/bin and marked as executable). 
# 2. Type the file name including path to it if necessary. 

main "$1"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .