Shell script to trim a video with mencoder or ffmpeg

I'd 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 Olivia's videos and couldn't be bothered to run the calc-duration script then copy/paste and edit the mencoder command), wrote a quick script that both calculates and trims.

UPDATE 2015-02-28: there are newer versions of this script:

For example, to trim a video with the start time of 45 seconds (e.g. drop the first 45 sec) and the end time of 3 min 15 sec (e.g. drop anything past that point), do:

$ trim.vid example.avi 00:00:45 00:03:15
checking input..
all good
 
calculating duration from start/stop times..
clip duration is 00:02:30
 
constructing file name for output..
trimmed video will be saved as example.trim.000045-000315.avi
 
trimming video..
==================================================
MEncoder 1.0rc4-4.4.5 (C) 2000-2010 MPlayer Team
success: format: 0  data: 0x0 - 0x38de94a
AVI file format detected.
[aviheader] Video stream found, -vid 0
[aviheader] Audio stream found, -aid 1
VIDEO:  [XVID]  640x480  12bpp  29.970 fps  2054.6 kbps (250.8 kbyte/s)
[V] filefmt:3  fourcc:0x44495658  size:640x480  fps:29.970  ftime:=0.0334
==========================================================================
Opening audio decoder: [mp3lib] MPEG layer-2, layer-3
AUDIO: 32000 Hz, 2 ch, s16le, 192.0 kbit/18.75% (ratio: 24000->128000)
Selected audio codec: [mp3] afm: mp3lib (mp3lib MPEG layer-2, layer-3)
==========================================================================
videocodec: framecopy (640x480 12bpp fourcc=44495658)
audiocodec: framecopy (format=55 chans=2 rate=32000 bits=0 B/s=22671 sample-0)
Writing header...
ODML: Aspect information not (yet?) available or unspecified, not writing vprp header.
Setting audio delay to 0.036s.
Writing header...
ODML: Aspect information not (yet?) available or unspecified, not writing vprp header.
Setting audio delay to 0.036s.
Pos:   0.7s     22f (23%)  0.00fps Trem:   0min   0mb  A-V:0.070 [0:183]
Skipping frame!
Pos:   1.0s     32f (23%)  0.00fps Trem:   0min   1mb  A-V:0.067 [2011:183]
Skipping frame!
Writing index...98f (93%)  0.00fps Trem:   0min  42mb  A-V:0.051 [2035:181]
Writing header...
ODML: Aspect information not (yet?) available or unspecified, not writing vprp header.
Setting audio delay to 0.036s.
 
Video stream: 2035.115 kbit/s  (254389 B/s)  size: 38162649 bytes  150.017 secs  4498 frames
 
Audio stream:  181.003 kbit/s  (22625 B/s)  size: 3394080 bytes  150.012 secs
==================================================
all done, have a fantastic day!

The 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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/bin/bash
# Usage: trim.vid MyVid.avi 00:30:00 00:40:00
 
if [ "$#" -ne "3" ]; then
  echo "Error: need some args like which video file to trim and new start/stop times. Usage example:"
  echo "$(basename $0) video.avi 00:30:00 00:40:00"
  exit 1
 else
  InFile=$1
  StartTime=$2
  StopTime=$3
fi
 
CheckInput()
{
 if ! [ -r $InFile ]; then
   echo "Error: input file \"$InFile\" not readable"
   exit 1
 fi
 
 for time in StartTime StopTime; do
   if [ "$(echo $(eval echo \$$time) | grep -o ":" | wc -l)" -ne "2" ]; then
     echo "Error: check $time time format, expecting two colons colons, e.g.:"
     echo "00:20:00"
     exit 1
   fi
   if [ "$(echo $(eval echo \$$time) | sed 's/://g' | wc -c)" -ne "7" ]; then
     echo "Error: check $time time format, expecting six digits, e.g.:"
     echo "00:20:00"
     exit 1
   fi  
 done
 
 if [ "$StartTime" == "$StopTime" ]; then
   echo "Error: same start and stop times don't make sense. I quit."
   exit 1
 fi
}
 
CalcDuration()
{
 # calculates duration between start time and stop time, e.g. 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 $StartTime | cut -d':' -f1)
 startmm=$(echo $StartTime | cut -d':' -f2)
 startss=$(echo $StartTime | cut -d':' -f3)
 #---------------------------------------#
 stophh=$(echo  $StopTime  | cut -d':' -f1)
 stopmm=$(echo  $StopTime  | cut -d':' -f2)
 stopss=$(echo  $StopTime  | cut -d':' -f3)
 #---------------------------------------#
 ### DEBUG
 #echo " Start:" $starthh hrs $startmm min $startss sec
 #echo " Stop: " $stophh hrs $stopmm min $stopss sec
 #---------------------------------------#
 if [[ $((10#$startmm)) -gt $((10#$stopmm)) && $((10#$startss)) -gt $((10#$stopss)) ]]; then
         # 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
         # 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
         # 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
         # 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')
 #=======================================#
 Duration=$pdiffhh:$pdiffmm:$pdiffss
 #=======================================#
}
 
ConstructFileName()
{
 ext=$(echo "$InFile" | egrep -io "\.[a-z0-9]{2,4}$")
 main=$(echo "$InFile" | sed "s/$ext$//")
 start=$(echo $StartTime | sed 's/://g')
 stop=$(echo $StopTime | sed 's/://g')
 OutFile=$main.trim.$start-$stop$ext
}
 
TrimVid()
{
 mencoder=$(which mencoder)
 if [ -x $mencoder ]; then
   mencoder -ss $StartTime -endpos $Duration -oac copy -ovc copy $InFile -o $OutFile
   echo "=================================================="
   echo "all done, have a fantastic day!"
   exit 0
 fi
 ffmpeg=$(which ffmpeg)
 if [ -x $ffmpeg ]; then
   ffmpeg -ss $StartTime -t $Duration -vcodec copy -acodec copy -i $InFile $OutFile
   echo "=================================================="
   echo "all done, have a fantastic day!"
   exit 0
 fi
 
 echo "Error: need mencoder or ffmpeg, neither where found in your PATH.."
}
 
 
echo -e "\nchecking input.."
CheckInput
echo "all good"
 
echo -e "\ncalculating duration from start/stop times.."
CalcDuration
echo "clip duration is $Duration"
 
echo -e "\nconstructing file name for output.."
ConstructFileName
echo "trimmed video will be saved as $OutFile"
 
echo -e "\ntrimming video.."
echo "=================================================="
TrimVid

1 Comment

Leave a comment

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