1

I am using the timestamps that FFmpeg outputs to get information about the video integrity. So far I have tested this on about 50 videos and only had one "Unusual time skip" false positive.

Is this method of checking a valid way to do this, could there be legitimate reasons why the time skip would significantly increase and is there a more accurate way to determine an invalid time skip than $dif*2?

ffmpegIntegrityCheck() {
    local frame=0
    local prevFrame=0
    local duration=0
    local timestamp=0
    local seconds=0
    local prevSeconds=0
    local dif=0
    local line=""

    ffmpeg -v debug -progress - -nostats -i "$1" -f null - 2>&1 \
    | while read -r line; do
        # Get the video duration
        if [[ "$duration" = 0 && "$line" =~ "Duration: " ]]; then
            duration=${line#* }
            duration=${duration%, start*}
            duration=${duration%.*}
            echo "Duration $duration"

        # Check if the frame number stops increasing
        elif [[ "$line" =~ "frame=" ]]; then
            frame=${line#*=}

            if [ "$frame" = "$prevFrame" ]; then
                echo "No frame change at $timestamp frame $frame"
            fi
            prevFrame="$frame"

        # Check the increase in seconds between each timestamp,
        elif [[ "$line" =~ "out_time=" ]]; then
            timestamp=${line#*=}
            timestamp=${timestamp%.*}
            seconds=$(echo "$timestamp" \
                    | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')

            if [ "$dif" != 0 ] && (( $seconds-$prevSeconds > $dif*2 )); then
                echo "Unusual time skip at $timestamp"
            else
                dif=$(($seconds-$prevSeconds))
            fi
            prevSeconds="$seconds"

        # Check if the last timestamp matches the duration 
        elif [[ "$line" = "progress=end" ]]; then
            if [ "$duration" != "$timestamp" ]; then
                duration=$(echo "$duration" \
                         | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')

                if (( $seconds < $duration-1 || $seconds > $duration+1 )); then
                    echo "End time mismatch at $timestamp"
                fi
            fi
        fi
    done
}

The reason I am trying to check with more than just ffmpeg -v error is because I have found corrupted files where ffmpeg has reported no errors. I have also found files where FFmpeg reports errors but when I watch the video there are no problems so I would like to try and check whether there are any playback problems without watching it.

The logic behind looking at the timestamp jumps was that if the file all of a sudden starts processing significantly faster, I assume it is having errors and skipping some processing. This assumption does seem to match my results with files where ffmpeg -v error is reporting errors but it does produce some false positives

The log from a file producing errors in FFmpeg:

Duration 01:36:32
No frame change at 00:48:29 frame 69673
Unusual time skip at 00:49:42
No frame change at 00:49:42 frame 69673
Unusual time skip at 00:50:58
No frame change at 00:50:58 frame 69673
Unusual time skip at 00:51:44
No frame change at 00:51:44 frame 69673
Unusual time skip at 00:53:09
No frame change at 00:53:09 frame 69673
Unusual time skip at 00:54:04
No frame change at 00:54:04 frame 69673
Unusual time skip at 00:55:25
No frame change at 00:55:25 frame 69673
Unusual time skip at 00:56:32
No frame change at 00:56:32 frame 69673
Unusual time skip at 00:57:30
No frame change at 00:57:30 frame 69673
Unusual time skip at 00:58:08
No frame change at 00:58:08 frame 69673
Unusual time skip at 00:59:37
No frame change at 00:59:37 frame 69673
No frame change at 01:00:02 frame 69673
Unusual time skip at 01:01:19
No frame change at 01:01:19 frame 69673
Unusual time skip at 01:02:33
No frame change at 01:02:33 frame 69673
Unusual time skip at 01:03:39
No frame change at 01:03:39 frame 69673
No frame change at 01:03:39 frame 69673
No frame change at 01:06:02 frame 69673
No frame change at 01:06:25 frame 69673
Unusual time skip at 01:08:18
No frame change at 01:08:18 frame 69673
Unusual time skip at 01:09:19
No frame change at 01:09:19 frame 69673
Unusual time skip at 01:10:19
No frame change at 01:10:19 frame 69673
Unusual time skip at 01:11:26
No frame change at 01:11:26 frame 69673
Unusual time skip at 01:12:39
No frame change at 01:12:39 frame 69673
Unusual time skip at 01:13:53
No frame change at 01:13:53 frame 69673
Unusual time skip at 01:14:55
No frame change at 01:14:55 frame 69673
No frame change at 01:14:59 frame 69673
Unusual time skip at 01:17:04
No frame change at 01:17:04 frame 69673
No frame change at 01:17:04 frame 69673
No frame change at 01:19:01 frame 69673
No frame change at 01:19:25 frame 69673
Unusual time skip at 01:21:07
No frame change at 01:21:07 frame 69673
No frame change at 01:21:40 frame 69673
Unusual time skip at 01:23:34
No frame change at 01:23:34 frame 69673
No frame change at 01:24:18 frame 69673
No frame change at 01:25:34 frame 69673
No frame change at 01:26:41 frame 69673
No frame change at 01:27:48 frame 69673
No frame change at 01:28:06 frame 69673
Unusual time skip at 01:29:01
No frame change at 01:29:01 frame 69673
Unusual time skip at 01:30:38
No frame change at 01:30:38 frame 69673
No frame change at 01:30:38 frame 69673
No frame change at 01:33:15 frame 69673
No frame change at 01:33:51 frame 69673
Unusual time skip at 01:35:24
No frame change at 01:35:24 frame 69673
End time mismatch at 01:36:16
Gary
  • 318
  • 3
  • 14
  • What do you mean by video integrity? – Gyan Jan 01 '23 at 05:41
  • 1
    You have 2 close votes with the opinion that this is not a software development problem. While I disagree, I don't have a good answer for your issue. I do have an interest in this same problem, i.e. "grading" the quality of a video and kudos to you for raising the issue and to have a possibly working solution! If your Q is closed completely without an answer, I recommend that you repost and include a URL (yotube or ??) to small sample videos, one that illusrates the problem and another that is "clean". Also include the output from both versions (small, or edited to the relevant bits). – shellter Jan 01 '23 at 05:50
  • 1
    Also, very nice bash code. Personally, I would convert the `while read` loop to an awk script, and then you could just declare a function that creates the `seconds` value for you. I almost think that could be done in `bash` without calling awk, but allf of this is off topic and would take some experimenting. Add that sample output , at least, and others with more experience in video may be able to help. Good luck! – shellter Jan 01 '23 at 05:54
  • 1
    AND lots of references to timestamp if you run `ffmpeg -h full` . Way over my pay grade, but may give you some better terms to search the interweb for. Good luck! – shellter Jan 01 '23 at 06:11
  • @Gyan I mean whether the video has any corruption that will freeze or crash the player when trying to play it. – Gary Jan 01 '23 at 06:42
  • @shellter Thanks for the suggestions and information. I will be able to add a partial answer tomorrow but would still like some more technical insight. The method definitely is valid for checking integrity, I have already found 2 corrupt files that `ffmpeg -v error` was reporting no errors for – Gary Jan 01 '23 at 06:47
  • @shellter On the opinions of if this is a software development problem. There are several other SO questions on detecting errors with FFmpeg. This is just another one of those question, I didn't know if this would work or not and don't completely understand why it does. I don't want to have code that works but I don't understand why. – Gary Jan 01 '23 at 06:56

2 Answers2

1

Based on my results so far I can say that checking "End time mismatch" is useful but checking "Unusual time skip" so far, isn't telling me anything that ffmpeg -v error was missing, I may be able to use it to quantify error though.

I have found several files with "End time mismatch" where the file stops playing too early but ffmpeg error/debug output doesn't report any problems.

Duration 01:53:53
progress=end
End time mismatch at 00:10:29

[AVIOContext @ 0x5587868cfcc0] Statistics: 0 seeks, 21 writeouts
video:7894kB audio:108396kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Input file #0 (vid.avi):
Input stream #0:0 (video): 15082 packets read (74354639 bytes); 15082 frames decoded;
Input stream #0:1 (audio): 24088 packets read (8809327 bytes); 24088 frames decoded (27749376 samples);
Total: 39170 packets (83163966 bytes) demuxed
Output file #0 (pipe:):
Output stream #0:0 (video): 15082 frames encoded; 15082 packets muxed (8083952 bytes);
Output stream #0:1 (audio): 24088 frames encoded (27749376 samples); 24088 packets muxed (110997504 bytes);
Total: 39170 packets (119081456 bytes) muxed
39170 frames successfully decoded, 0 decoding errors
[AVIOContext @ 0x5587868d8c40] Statistics: 713804051 bytes read, 18836 seeks

ffprobe -show_streams -show_format FILE results

[STREAM]
index=0
codec_name=mpeg4
codec_long_name=MPEG-4 part 2
profile=Advanced Simple Profile
codec_type=video
codec_time_base=417083/10000000
codec_tag_string=DX50
codec_tag=0x30355844
width=608
height=320
coded_width=608
coded_height=320
has_b_frames=1
sample_aspect_ratio=1:1
display_aspect_ratio=19:10
pix_fmt=yuv420p
level=5
color_range=unknown
color_space=unknown
color_transfer=unknown
color_primaries=unknown
chroma_location=left
field_order=unknown
timecode=N/A
refs=1
quarter_sample=false
divx_packed=false
id=N/A
r_frame_rate=10000000/417083
avg_frame_rate=10000000/417083
time_base=417083/10000000
start_pts=0
start_time=0.000000
duration_ts=163848
duration=6833.821538
bit_rate=N/A
max_bit_rate=N/A
bits_per_raw_sample=N/A
nb_frames=163848
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=0
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
[/STREAM]
[STREAM]
index=1
codec_name=mp3
codec_long_name=MP3 (MPEG audio layer 3)
profile=unknown
codec_type=audio
codec_time_base=1/44100
codec_tag_string=U[0][0][0]
codec_tag=0x0055
sample_fmt=fltp
sample_rate=44100
channels=2
channel_layout=stereo
bits_per_sample=0
id=N/A
r_frame_rate=0/0
avg_frame_rate=0/0
time_base=1/14000
start_pts=0
start_time=0.000000
duration_ts=N/A
duration=N/A
bit_rate=112000
max_bit_rate=N/A
bits_per_raw_sample=N/A
nb_frames=95673053
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=0
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
[/STREAM]
[FORMAT]
filename=vid.avi
nb_streams=2
nb_programs=0
format_name=avi
format_long_name=AVI (Audio Video Interleaved)
start_time=0.000000
duration=6833.821538
size=732241860
bit_rate=857197
probe_score=100
TAG:encoder=AVI-Mux GUI 1.17.8.3, Feb 16 201019:42:50
TAG:JUNK=
[/FORMAT]
Gary
  • 318
  • 3
  • 14
0

This looks to be an instance of an XY question.

Checking timestamp intervals will not tell you whether the file is corrupt i.e.

  1. is the container metadata missing (fully or partially) or malformed ?
  2. is any of the media data missing or malformed ?

At most, it will identify if a portion of the file will lead to subjective 'freezes' due to prolonged video frames or silences due to a large inter-packet intervals in the audio.

Running ffmpeg -i INPUT and checking the exit code is sufficient to identify if the input header has any fatal errors.

To check media data, decoding the file is sufficient.

ffmpeg -v 48 -i INPUT -f null -

After completion, check the logs for Packet corrupt to identify errors at the packet encapsulation level. And at the end of the log, look for a line of this form: X frames successfully decoded, Y decoding errors for corrupt frames.

Gyan
  • 85,394
  • 9
  • 169
  • 201
  • Thanks @Gyan . Now I can write my own video file checker! Good luck to all. – shellter Jan 01 '23 at 15:42
  • Based on my results so far this doesn't seem to be correct. – Gary Jan 01 '23 at 18:45
  • What doesn't seem to be correct? – Gyan Jan 01 '23 at 18:53
  • Decoding the file is not sufficient to check media – Gary Jan 01 '23 at 18:58
  • Check media for what? – Gyan Jan 01 '23 at 19:03
  • You have already asked me that and I think I have explained what I am trying to do? – Gary Jan 01 '23 at 19:04
  • Your Q talks about video integrity and corrupt files, and that's what my answer addresses. – Gyan Jan 01 '23 at 19:10
  • Yes and I have detected corrupt files that FFmpeg has not detected itself so decoding the file was not sufficient. You are giving me the same answer I have seen everywhere but the reason I am looking for another answer is because that answer has not been sufficient. – Gary Jan 01 '23 at 19:12
  • "I have detected corrupt files that FFmpeg has not detected itself" --> how? Your current method does not identify corrupt files. – Gyan Jan 01 '23 at 19:22
  • https://stackoverflow.com/a/74976663/793088 This file plays for 10 minutes when it should play for nearly 2 hours do you not consider that a corrupt file? – Gary Jan 01 '23 at 19:29
  • Share the log of `ffprobe -show_streams -show_format FILE` for that file. – Gyan Jan 01 '23 at 19:44
  • I have added the log to my answer. – Gary Jan 01 '23 at 19:51
  • @Gary : When I clicked on your link above (stackoverflow...7497.../793...) to open in a new browser tab, it seemed to open this page again at the top. I was expecting to see some Video file. The questionID looks the same, but the 793... is different than the URL for this page. Did I miss something? – shellter Jan 01 '23 at 21:41
  • It opens up on my answer to this question for me, which it is supposed to, I'm not sure why it opens at the top for you. – Gary Jan 01 '23 at 21:45
  • 1
    @gary : ah I see. With that link, you said "this file plays for 10 minutes" so I expected to see a video available "this file" (-; But now understand you are referring to the "infile" argument to `ffmpeg`. This goes back to my advice to include testable data and outputs in the body of your question. But it seems like you have a pretty good idea as to what is happening, so best wishes, Happy New Year and good luck to all (-;! – shellter Jan 02 '23 at 03:20
  • So, this file is an AVI with DivX video containing B-frames. That container is ancient and the codec is problematic to store in AVI. There's likely to be non-fatal demuxing errors in the full log for `ffmpeg -v debug -i "$1" -f null -` – Gyan Jan 02 '23 at 05:00