Utility Scripts for ffmpeg


Published: 2020-10-11
Updated: 2020-10-11
Web: https://fritzthecat-blog.blogspot.com/2020/10/utility-scripts-for-ffmpeg.html


Part of my new ffmpeg toolbox are some utility scripts that I want to present in this article.

  1. Display Video Properties
  2. Extract Image at Time
  3. Calculate Duration of Videos in a Folder
  4. Output Key-Frame Times

All scripts would output their syntax and exit when called without command line arguments.

Display Video Properties

videoProperties.sh

 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
#######################################################
# Displays quality settings of video and audio.
#######################################################

[ -z "$1" ] && {
echo "SYNTAX: $0 [-a|videoPropertyCsv] videoFile [videoFile ...]" >&2
echo "Shows significant properties of first video and audio stream." >&2
echo "-a: show full property listing" >&2
echo "videoPropertyCsv: comma-separated list of video properties to show" >&2
exit 1
}

formatProperties() {
ffprobe -v error \
-show_entries format=$1 \
-of default=noprint_wrappers=1 $2 \
| sort \
| uniq \
| sed 's/^/format /'
}

streamProperties() {
ffprobe -v error \
-select_streams $2 -show_entries stream=$1 \
-of default=noprint_wrappers=1 $3 \
| sort \
| uniq \
| sed 's/^/'$2' /'
}

for argument in $*
do
if [ -f "$argument" ]
then
videoFile=$argument
echo "Properties for $videoFile" >&2

if [ -n "$propertyList" ]
then
streamProperties $propertyList v:0 $videoFile
elif [ "$showAll" = "true" ]
then
ffprobe -v error -show_format -show_streams $videoFile
else
formatProperties format_name,bit_rate $videoFile
streamProperties codec_name,profile,time_base,pix_fmt,r_frame_rate,width,height,bit_rate v:0 $videoFile
streamProperties codec_name,sample_rate,channels,bit_rate a:0 $videoFile
fi
elif [ "$argument" = "-a" ]
then
showAll=true
else
propertyList=$argument
fi
done

For every given video file, it would output the most important quality properties, prepending "format" for general, "v:0" for video and "a:0" for audio, so that we can see where the property belongs to. If you give one or more property names (comma-separated without spaces), it would restrict the output to video-stream properties of that name (just the first video of possibly several).

The option -a ("all") would cause a full output of all stream- and format- properties. Mind that there could be also programs and subtitles inside the video.

Examples:


videoProperties.sh testvideos/GOPR1486.MP4
format bit_rate=30137653
format format_name=mov,mp4,m4a,3gp,3g2,mj2
v:0 bit_rate=30005060
v:0 codec_name=h264
v:0 height=1080
v:0 pix_fmt=yuvj420p
v:0 profile=High
v:0 r_frame_rate=48000/1001
v:0 time_base=1/48000
v:0 width=1920
a:0 bit_rate=128013
a:0 channels=2
a:0 codec_name=aac
a:0 sample_rate=48000

videoProperties.sh start_time,duration testvideos/GOPR1486.MP4
v:0 duration=26.797604
v:0 start_time=0.000000

Extract Image at Time

extractImage.sh

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#######################################################
# Extracts an image from given video at given time.
#######################################################

IMAGEFILENAME=image.png

[ -z "$1" -o ! -f "$1" -o -z "$2" ] && {
echo "SYNTAX: $0 videoFile time [imageFilePath]" >&2
echo "Extracts an image from a video to default image file $IMAGEFILENAME" >&2
echo "Example:" >&2
echo " $0 myvideo.mp4 1:23 title-image.png" >&2
echo " would extract the key-frame image at or before minute 1 second 23" >&2
echo " from myvideo.mp4 to title-image.png." >&2
exit 1
}

video=$1
time=$2
image=${3:-$IMAGEFILENAME}

ffmpeg -y \
-ss $time -i $video -frames:v 1 \
-f image2 $image

First argument is the video file, second the time when the targeted image occurs, optional third the name of the resulting image file.

The ffmpeg command uses input-seeking (-ss before -i), thus it would find a key-frame at, or shortly before, given time. Mind that you can also specify thousands seconds by adding ".111" to seconds.

Calculate Duration of Videos in a Folder

durationOfVideos.sh

 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
#######################################################
# The rounded duration of all videos in given directory.
#######################################################

[ -z "$1" ] && {
echo "SYNTAX: $0 videoDir" >&2
exit 1
}

cd $1 || exit 2

sum=0
for video in `ls -1 *.MP4 *.mp4 2>/dev/null | sort`
do
seconds=`ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 \$video`
sum=`echo "\$sum \$seconds" | awk '{ print $1 + $2 }'`

echo "$video: $seconds seconds" >&2
done

echo "sum of seconds = $sum" >&2

rounded=`echo \$sum | awk '{ print int($1 + 0.5) }'`

hours=`expr \$rounded / 3600`
rest=`expr \$rounded % 3600`
minutes=`expr \$rest / 60`
seconds=`expr \$rest % 60`

echo "$hours:$minutes:$seconds"

This script specializes on MP4 files. If you have others, replace the ls -1 wildcard patterns in line 13.

It changes to the given video directory, loops all videos and displays their duration in seconds on stderr. Finally it displays the rounded sum in hours:minutes:seconds format on stdout.

Because bc ("binary calculator") is not installed on every UNIX system, I use awk for calculations. It processes decimal numbers precisely, while the expr ("expression") command can process only integers.

Example:


durationOfVideos.sh testvideos
20200905_133128.mp4: 44.139000 seconds
GOPR1486.MP4: 26.816000 seconds
GOPR1487.MP4: 26.901333 seconds
GOPR1488.mp4: 29.802667 seconds
TITLE.MP4: 7.007000 seconds
sum of seconds = 134.666

0:2:15

Output Key-Frame Seconds

keyFrameSeconds.sh

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
###########################################
# Outputs the seconds when key-frames occur.
###########################################

[ -f "$1" ] || {
echo "SYNTAX: $0 videoFile" >&2
echo "Outputs the times when key-frames occur in given video." >&2
exit 1
}

ffprobe -v error \
-select_streams v:0 \
-skip_frame nokey \
-show_frames -show_entries frame=pkt_pts_time \
-of default=noprint_wrappers=1:nokey=1 \
$1

This script my be useful when you want to know where the key-frames are in your video.

Example:


keyFrameSeconds.sh testvideos/GOPR1486.MP4
0.000000
0.500500
1.001000
1.501500
2.002000
2.502500
3.003000
3.503500
4.004000
4.504500
5.005000
5.505500
6.006000
6.506500
7.007000
7.507500
8.008000
8.508500
9.009000
9.509500
10.010000
10.510500
11.011000
11.511500
12.012000
12.512500
13.013000
13.513500
14.014000
14.514500
15.015000
15.515500
16.016000
16.516500
17.017000
17.517500
18.018000
18.518500
19.019000
19.519500
20.020000
20.520500
21.021000
21.521500
22.022000
22.522500
23.023000
23.523500
24.024000
24.524500
25.025000
25.525500
26.026000
26.526500

This shows that in given video there is a key-frame every half a second.





ɔ⃝ Fritz Ritzberger, 2020-10-11