Script to calculate clip duration from start/stop times for trimming with mencoder or ffmpeg

To trim a video clip, mencoder and ffmpeg expect a start time in hh:mm:ss, but instead of end time, want duration:

$ mencoder -ss 00:02:55 -endpos 00:07:15 -oac copy -ovc copy in.avi -o out.avi
$ ffmpeg -ss 00:02:55 -t 00:07:15 -vcodec copy -acodec copy -i in.avi out.avi

Video players make it easy to identify start/stop times, but difficult to figure out duration, so I wrote a little shell script that will calculate duration from start/stop times.

Update 2011-06-02: for those lazy like me, here's a script that calculates duration and trims the video. Gosh, could I make it any easier for ya? (Hint: the answer is "no").

Update 2014-06-17: here's an improved version of this script that fixes the limitations of this script, adds some functionality, and generally easier on the eye thanks to my improved scripting skills. :-)

Usage example:

$ calc-duration 00:02:55 00:10:10
 
 Start: 00 hrs 02 min 55 sec
 Stop:  00 hrs 10 min 10 sec
 
 +----------------------+
 | duration is 00:07:15 |
 +----------------------+

Script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
#!/bin/bash
#============================================================#
# Calculates duration between start time and stop time
# USAGE: calc-duration 00:02:00 00:10:10
# Fix:
# 1. Currently expects start hour to be less than stop hour,
# so won't work for a clip that's longer than 24 hrs, not an
# issue for me as I don't have any of those... ;-)
#============================================================#
starthh=$(echo $1 | awk -F: '{print$1}')
startmm=$(echo $1 | awk -F: '{print$2}')
startss=$(echo $1 | awk -F: '{print$3}')
 
stophh=$(echo $2 | awk -F: '{print$1}')
stopmm=$(echo $2 | awk -F: '{print$2}')
stopss=$(echo $2 | awk -F: '{print$3}')
 
echo
echo " Start:" $starthh hrs $startmm min $startss sec
echo " Stop: " $stophh hrs $stopmm min $stopss sec
echo
 
if   [[ $((10#$startmm)) -gt $((10#$stopmm)) && $((10#$startss)) -gt $((10#$stopss)) ]]; then
        # echo start mm and ss are greater than stop
	# start mm is greater than stop mm, so we add 60 to stop mm and
	# substract 1 from stop hh
	newstopmm1=$((10#$stopmm+10#60))
	newstophh=$((10#$stophh-10#1))
	# start ss is greater than stop ss, so we add 60 to stop ss and
        # substract 1 from stop mm
        newstopss=$((10#$stopss+10#60))
        newstopmm=$((10#$newstopmm1-10#1))
        # calculate differences
	diffhh=$((10#$newstophh-10#$starthh))
	diffmm=$((10#$newstopmm-10#$startmm))
	diffss=$((10#$newstopss-10#$startss))
 
elif [[ $((10#$startmm)) -gt $((10#$stopmm)) ]]; then
        # echo startmm is greater than stopmm
	# start mm is greater than stop mm, so we add 60 to stop mm and
        # substract 1 from stop hh
        newstopmm=$((10#$stopmm+10#60))
        newstophh=$((10#$stophh-10#1))
	# calculate differences
        diffhh=$((10#$newstophh-10#$starthh))
        diffmm=$((10#$newstopmm-10#$startmm))
        diffss=$((10#$stopss-10#$startss))
 
elif [[ $((10#$startss)) -gt $((10#$stopss)) ]]; then
        # echo startss is greater than stopss
        # start ss is greater than stop ss, so we add 60 to stop ss and
        # substract 1 from stop mm
        newstopss=$((10#$stopss+10#60))
        newstopmm=$((10#$stopmm-10#1))
        # calculate differences
        diffhh=$((10#$stophh-10#$starthh))
        diffmm=$((10#$newstopmm-10#$startmm))
        diffss=$((10#$newstopss-10#$startss))
else
	# echo all stop values are greater than start values
        # calculate differences
        diffhh=$((10#$stophh-10#$starthh))
        diffmm=$((10#$stopmm-10#$startmm))
        diffss=$((10#$stopss-10#$startss))
fi
 
# pad single digit results with a zero (if + signs contain a single digit, add a zero, then remove + signs)
pdiffhh=$(echo +$diffhh+ | sed 's/+\([0-9]\{1\}\)+/+0\1+/g;s/+//g')
pdiffmm=$(echo +$diffmm+ | sed 's/+\([0-9]\{1\}\)+/+0\1+/g;s/+//g')
pdiffss=$(echo +$diffss+ | sed 's/+\([0-9]\{1\}\)+/+0\1+/g;s/+//g')
 
echo " +----------------------+"
echo " | duration is" $pdiffhh:$pdiffmm:$pdiffss "|"
echo " +----------------------+"
echo

4 Comments

  • 1. Alain Kelder is a Giant D&hellip replies at 18th July 2012, 11:44 am :

    [...] previously posted a script to calculate clip duration from start/stop times for trimming with mencoder or ffmpeg, but in an effort to improve customer satisfaction (e.g. recently had to trim a bunch of [...]

  • 2. Cleyton replies at 18th June 2013, 6:19 pm :

    Thanks a lot! Good work!

  • 3. Anton Gusev replies at 2nd November 2014, 12:56 am :

    Thank you for idea!
    I think I found a simpler way to calc duration (with millisecs):

    #!/bin/bash
     
    # convert time (in format "hh:mm:ss.xxx") to milliseconds.
    TimeToMs()
    {
        tm=$(echo $1  | cut -d'.' -f1)
        ms=$(echo $1  | cut -d'.' -f2)
        hh=$(echo $tm | cut -d':' -f1)
        mm=$(echo $tm | cut -d':' -f2)
        ss=$(echo $tm | cut -d':' -f3)
        echo $((10#$ss * 1000 + 10#$mm * 60000 + 10#$hh * 3600000 + 10#$ms))
    }
     
    # convert milliseconds to time (in format "hh:mm:ss.xxx").
    MsToTime()
    {
        ss=$(($1 / 1000))
        ms=$(($1 % 1000))
        mm=$((ss / 60))
        ss=$((ss % 60))
        hh=$((mm / 60))
        mm=$((mm % 60))
        printf "%02d:%02d:%02d.%03d" $hh $mm $ss $ms
    }
     
    CalcDuration()
    {
        t1=$(TimeToMs $1)
        t2=$(TimeToMs $2)
        d=$((t2 - t1))
        echo $(MsToTime $d)
    }
     
    dur1=$(CalcDuration "00:01:10.080" "01:06:07.440")
    echo "duration = $dur1"  # prints "duration = 01:04:57.360"
  • 4. Alain Kelder replies at 18th December 2014, 12:10 am :

    Thank you for sharing, Anton. Definitely an improvement. The millisecond handling is also nice.

Leave a comment

NOTE: Enclose quotes in <blockquote></blockquote>. Enclose code in <pre lang="LANG"></pre> (where LANG is one of these).