The problem#
I've somehow multiple times ended up with corrupted video files such that they're cut off at some point, apparently due to a copy being interrupted or similar. As a result, I'm a bit paranoid about my video files not being what I expect, so I wanted a way to quickly check the length and view the start and end of many videos.
The solution#
The following script check_video_length.sh
, takes any number of video
files as arguments, and one-by-one, prints out the length in minutes,
and player the first and last 10 seconds of the video (or less if you
press q to quit MPlayer sooner):
#!/usr/bin/sh
for video in "$@"
do
seconds=$(mediainfo "$video" --Output=JSON
| jq '.media.track[0].Duration' | tr -d '"')
minutes="$(echo "scale=2; $seconds" / 60 | bc)"
echo "$video is $minutes minutes long."
echo "Playing $video from start first 10 seconds..."
mplayer -osdlevel 3 -endpos 10 "$video" >/dev/null 2>&1
echo "Playing $video from 10 seconds before end..."
mplayer -osdlevel 3 -ss "$(echo "$seconds" - 10\
| bc)" "$video" >/dev/null 2>&1
echo
done
The details#
Video length in seconds#
The script needs the video length for two purposes: displaying the total
video length and computing how far into the video 10 seconds before the
end is. MediaInfo has a few options to give the length in a
human-readable formats, but for the computation, we really just want a
number of seconds. This post uses jq
to extract
that information from MediaInfo's JSON output of everything it knows
about a video:
mediainfo "$video" --Output=JSON \
| jq '.media.track[0].Duration' | tr -d '"'
Video length in minutes#
We could use one of MediaInfo's output options to display the length in a human-readable format:
$ mediainfo --Output="General;%Duration/String3%" $video
01:12:42.430
But instead I figured we already had the length and dividing it by 60 to
get minutes instead of seconds was good enough. One catch is that
bash
's arithmetic only handles integers; the workaround is
to use bc
instead:
$ seconds=1492
$ echo "scale=2; $seconds" / 60 | bc
24.86
Playing only part of video#
In order to play only the first and last 10 seconds of video, I needed a way to point a video player at a video and tell it to only play a segment of the video. I had done something somewhat similar in my video clipping script, but there I created new files with the clips.
It turns out, MPlayer has options for where to start
and stop playback, -ss
and -endpos
, as described in the man
page:
mplayer -osdlevel 3 -endpos 10 "$video" >/dev/null 2>&1
mplayer -osdlevel 3 -ss "$(echo "$seconds" - 10\
| bc)" "$video" >/dev/null 2>&1
Note I also use the -osdlevel 3
option to have it display where in
the video it is currently playing.
Why 10 seconds?#
My actual intention is to see that there's actual video (not just a black screen) near the start and end of the video. I set it at 10 seconds because I had some videos with 5 seconds of black at the start or end.
But it seems like black frames should be easy for the computer to
distinguish. I considered whether it would be possible do some some sort
of analysis using ffmpeg
to extract the first and last
few keyframes to find the first non-black one and use that to determine
what section of the video to play (or something along those lines). But
just selecting a fixed number of seconds and pressing q a lot
because I didn't need to see that whole 10 seconds seemed sufficient
and required a lot less effort. Although I might go back and do the
black frame detection just for the experience of doing it even though it
doesn't seem worth the time.
Comments
Have something to add? Post a comment by sending an email to comments@aweirdimagination.net. You may use Markdown for formatting.
There are no comments yet.