0

I was trying to control ffmpeg file segment function through a bash script to cut a large movie file into smaller pieces.

I took a look at the documentation here but this doesn't really cover what I would like to do.

I'd like to mix the segment function with some of my own stuff from bash. Here is an example part of the script.

#!/bin/bash
DIR="/../../*"
OUT_DIR="/../../"
file_extension=""
filename=""
input_file=""
input_file_dir=""
output_file=""
working_directory=""
output_file_dir=""
part_count=0
for f in $DIR
do
    filename=$(basename "$f")
    input_file="$filename"
    filename=${filename::-4}
    file_extension=${f: -3}
    input_file_dir=$(dirname "$f")"/"
    part_count="$(printf "%03d" "$counter")"
    output_file="$filename"_"$part_count"."$file_extension
    //my file name generation takes place here
    output_file_dir="$OUT_DIR$filename"_"$part_count".mkv"
    let part_count=$part_count+1

    ffmpeg -i "$f" -c:v libx264 -crf 22 -map 0 -strict -2 -segment_time 600 -g 9 -sc_threshold 0 -force_key_frames "expr:gte(t,n_forced*9)" -f segment "$OUT_DIR"
done

The line above "$OUT_DIR" doesn't work and throws a cryptic error. If I remove "$OUT_DIR" and put anything, example "test.mkv" then the files get written out correctly but in the wrong location.

Can I do this with ffmpeg segment command and bash?

  • Where are your input and output directories? Because /../../ means "the root (top) directory, and then up two more". – JigglyNaga Jun 5 '16 at 10:39
  • @JigglyNaga I left those out, it's for the users to fill in. – user1610950 Jun 6 '16 at 7:28
  • When you say "the line above "$OUT_DIR" doesn't work and throws a cryptic error", could you give more detail? What is "doesn't work", and what is the exact error? Could you edit the question to use valid directories, so the problem is easier to reproduce? – JigglyNaga Jun 6 '16 at 7:40
  • See unix.stackexchange.com/questions/155551/… for ways to see where your script is going wrong. For a start, $counter is undefined and ffmpeg's output is a directory. – JigglyNaga Jun 6 '16 at 9:25
0

Okay so I figured it out and I rewrote the script from scratch.

#!/bin/bash
DIR="/../../../*" #directory where the movie files are located
OUT_DIR="/../../../../" #directory where the processed movie files will be exported
OUTPUT_FILE=""

file_duration_flat=0
file_duration_int=0
working_file_duration=0
default_chunk_size=600 #video length in seconds (10 minutes)
chunk_size=600 #video length in seconds (10 minutes)
video_pieces=0
video_pieces_hum_re=0
video_pieces_hum_re_cnt=0
counter=0
chunk_start_time=0
chunk_end_time=0
tt=10
end=10
iteration=0

#extract simple metadata from files
for f in $DIR
do
    echo $f
    file_duration_float=$(ffprobe -i "$f" -show_format -v quiet | sed -n 's/duration=//p')
    file_duration_int=$( echo "($file_duration_float+0.5)/1" | bc )
    working_file_duration_int=$file_duration_int
    working_file_duration=$(expr $file_duration_int - $chunk_size )
    echo $file_duration_int

    #---------------------------------------------
    # get the count of pieces to cut the file into
    #---------------------------------------------
    # echo $working_file_duration_int
    while [ "$working_file_duration_int" -ge "$chunk_size" ]
    do
        working_file_duration_int=$(($working_file_duration_int - chunk_size))
        video_pieces=$((video_pieces + 1 ))
        video_pieces_hum_re=$((video_pieces + 1 ))
        video_pieces_hum_re_cnt=$video_pieces_hum_re

        # echo "cut video into $video_pieces pieces"
        # echo "cut video into human readable $video_pieces_hum_re pieces"
        # echo "cut video human readable c $video_pieces_hum_re_cnt pieces"
    done
    #---------------------------------------------

    #---------------------------------------------
    # determine the start and end time of each clip
    #---------------------------------------------
    while [ $working_file_duration_int -gt -1 ]
    do
        filename=$(basename "$f")
        input_file="$filename"
        filename=${filename::-4}" "
        file_extension=${f: -3}
        input_file_dir=$(dirname "$f")"/"


        if [ $iteration -eq 0 ]
        then
            working_file_duration_int=$((file_duration_int - chunk_size))
            chunk_start_time=0
            chunk_end_time=$(($default_chunk_size))

            echo "iteration $iteration start: $chunk_start_time end: $chunk_end_time duration: $default_chunk_size video length left $working_file_duration_int"

            OUTPUT_FILE="$OUT_DIR$filename$iteration.mkv"
            $(ffmpeg -hide_banner -loglevel panic -i "$f" -ss $chunk_start_time -t $chunk_end_time [youre desired encoding] "$OUTPUT_FILE")
            iteration=$((iteration+1))
        fi
        if [ $working_file_duration_int -le $chunk_size ]
        then
            # echo "break early because time is $working_file_duration_int"
            chunk_size=$working_file_duration_int
            working_file_duration_int=$((working_file_duration_int - chunk_size))
            chunk_start_time=$(($chunk_start_time+$chunk_end_time))
            chunk_end_time=$(($chunk_size))

            # echo "early chunk size: $chunk_size iteration $iteration video length left $working_file_duration_int start: $chunk_start_time end: $chunk_end_time"
            echo "early chunk size: $chunk_size iteration $iteration start: $chunk_start_time end: $((chunk_start_time+chunk_end_time)) duration: $chunk_end_time video length left $working_file_duration_int "

            OUTPUT_FILE="$OUT_DIR$filename$iteration.mkv"
            $(ffmpeg -hide_banner -loglevel panic -i "$f" -ss $chunk_start_time -t $chunk_end_time [youre desired encoding] "$OUTPUT_FILE")
            iteration=0
            chunk_size=$default_chunk_size
            break
        else
            chunk_start_time=$(($chunk_start_time+$chunk_end_time))
            chunk_end_time=$(($chunk_size))
            working_file_duration_int=$((working_file_duration_int - chunk_size))
            echo "iteration $iteration start: $chunk_start_time end: $((chunk_start_time+chunk_end_time)) duration: $chunk_end_time video length left $working_file_duration_int "

            OUTPUT_FILE="$OUT_DIR$filename$iteration.mkv"
            $(ffmpeg -hide_banner -loglevel panic -i "$f" -ss $chunk_start_time -t $chunk_end_time [youre desired encoding] "$OUTPUT_FILE")
            iteration=$((iteration+1))
        fi
    done
done

This achieved what I needed it to do.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.