A Weird Imagination

Checking for truncated videos

Posted in

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.