New issue
Advanced search Search tips

Issue 793635 link

Starred by 2 users

Issue metadata

Status: WontFix
Owner: ----
Closed: Dec 2017
Components:
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: 3
Type: Bug



Sign in to add a comment

Timestamps are ignored if decoded frames are in wrong order

Reported by taemoji...@gmail.com, Dec 10 2017

Issue description

Chrome Version       : 62.0.3202.97 (64-bit)
URLs (if applicable) :
OS version               : 9901.77.0 stable (unless Platform is not OS)
Network (such as Cable/DSL/Dial up etc):
Audio/Video format (if applicable): mpeg4 / .avi
Special chrome flags (if applicable):

Behavior in Firefox (if known): The file is not supported.

Video issue, Audio issue, both, neither? Video

Occurs with HTML5 or native playback.

I am attempting to play a file from around 10 years ago on a Chromebook, since it seems difficult or impossible to use the Chromebook to play it on a certain Roku set-top device model. The problem is it 'stutters', going one or two frames forward and then going back to an older frame. This happens both with the 'video app' and with the Chrome browser.

As noted above, Firefox won't play the file at all. The Chrome browser on my (GNU/)Linux laptop will play audio from the file, but no video shows up and the controls are centered with no video size selected. So to play the video with a 'stutter' is an improvement. The video plays fine in other applications using the avformat/ffmpeg-based libraries with no problems.


The ffmpeg mpeg4 demuxer gives this warning: 

"Video uses a non-standard and wasteful way to store B-frames ('packed B-frames'). Consider using the mpeg4_unpack_bframes bitstream filter without encoding but stream copy to fix it."

I tried copying the video to an mp4 container, same result. I tried using this bitstream filter. The warning disappears, but ChromeOS still plays the file with a stutter.

I tried testing the ordered-frames.mp4 file, generated with this command:

ffmpeg -filter_complex "color=white:160x160:1,drawtext='fontcolor=black:fontsize=96:x=(W-tw)/2+4:y=(H-th)/2+4:text=%{n}:alpha=0.5',boxblur,drawtext='fontcolor=black:fontsize=96:x=(W-tw)/2:y=(H-th)/2:text=%{n}'" -preset veryslow -refs 8 -aq-strength 0.5 -threads 1 -crf 20 -frames:v 30 -movflags faststart ordered-frames.mp4

The resulting frames are out of order, as can be seen from 'ffprobe -hide_banner -show_frames ordered-frames.mp4 -select_streams v | grep coded', but Chrome OS and the Chrome browser play the file perfectly.

slow.mp4 is copy.mp4 slowed down using mencoder. The stuttering can be seen in more detail.

The reason for the stuttering seems to be that the 'Video Player' and Chrome browser in Chrome OS show frames in the order they appear in the decoded stream, without regard to the timestamps.

With ordered-frames.mp4 and typical h.264 files such as those served by YouTube, if you examine the packets with ffprobe and -show_packets or a command like ' ffprobe -hide_banner -show_entries packet=size,pts_time,flags ordered-frames.mp4 -select_streams v | less', you can see the timestamps skip around.

But if you check the decoded frames, with 'ffprobe -show_frames <file>', they are in monotonically ascending timestamp order.

With copy.mp4, it's the opposite. The packets are in order, but the decoded frames are mixed up, with the B-frames coming before the P-frames that they, presumably, depend on. I had sort of assumed that ffprobe sorted the packets itself, but either a file like this is specifying the packet order independently of the timestamps, or the demuxer is bugged and putting the outputted frames in the wrong order even if it gets the timestamps right.

The dts/decode timestamps of copy.mp4 are also changed between -show_frames and -show_packets, and I think I've seen this to be a problem before, but I don't think it's the problem in this case.

(One thing I haven't done is check other .avi files, since I guess .avi files don't track dts, and whether putting an mpeg stream into an avi file will cause it to stutter after being moved back to mp4.)
 
copy.mp4
603 KB View Download
slow.mp4
552 KB View Download
ordered-frames.mp4
14.0 KB View Download
The attached files show the same problem, in Chrome OS and the Chrome browser on (GNU/)Linux.

So it has nothing to do with the mpeg4 demuxer.

Firefox, ffplay, vlc, and totem (using many of the same libraries as ffplay) all have some slight problems at the start of the file, and then are two frames (two seconds) late for the rest of the video.

Chrome ends up skipping numbered frames 3 and 9, and maybe later frames, due to them being late or something. <del>The displayed frames are otherwise the same as the decoded frame order, which is the same as the packet order in the original mp4 file. The packet order for the .avi file is ascending timestamp order, instead of presentation order, so they were rearranged when copied into the format.</del>

It's rather confusing and I might be getting numbers mixed up. The 'avicopy.mp4' has the decoded frames in the same order as the original, but the pts/presentation timestamp values are completely different. They skip around, while the dts/decode timestamp values ascend, and are always later. Maybe other applications are following the dts time strictly, always getting late frames that are in the wrong order, and always displaying them, even if the pts is lower than the previous frame's pts.

So it's possible that Chrome is displaying the frames correctly, based on what is shown for 'ffprobe -show_frames'...

It doesn't help that "decode" and "display" both start with a D, and even now I accidentally wrote "display" when expanding 'dts'. The avi file has no pts for the frames, only dts.

To verify that this isn't (just) an ffmpeg bug, I am attaching the first 1 MB of the original .avi file, as truncated.avi (with 'dd if=sample-file of=small-sample-file bs=1024 count=1000').
ordered-frames.avi
20.0 KB Download
ordered-frames-avicopy.mp4
13.8 KB View Download
truncated.avi
1000 KB Download
So, the title of this bug is partially incorrect. Apparently, Chrome displays an mp4 file converted from avi 'incorrectly' only because it reads frames early, allowing it to notice presentation timestamps before other programs, even if it apparently reads less than 10 frames ahead so some frames can get missed and then dropped, if a file is 'broken' with dts being later than pts.

To reiterate, in copy.mp4, Chrome isn't displaying the decoded frames in stream order as shown in ffprobe. It is paying attention to presentation timestamps, not ignoring them. The frames are not in the wrong order, but they do appear to have the wrong presentation timestamps (pts), which is why Chrome displays them incorrectly. Other programs display them correctly because they avoid decoding frames early.

The reason for displaying an avi file incorrectly might be different. Chrome displays the avi file the same as it does the re-muxed (?) mp4 file, but avi files have no recorded pts value for Chrome to look for. It appears Chrome is showing frames based on their packet dts as shown in ffprobe, instead of the frame dts which is different.

So looking at ordered-frames.avi, using 'ffprobe -hide_banner -show_entries frame=pkt_pts_time,pkt_dts_time,pkt_size,coded_picture_number ordered-frames.avi -select_streams v | less'. The frames appear sorted, starting at pkt_dts_time=2 and increasing from there. But packet sizes go 1808, 351, 779.

If we look at the packets instead, with 'ffprobe -hide_banner -show_entries packet=dts_time,size ordered-frames.avi -select_streams v | less', the packets seem sorted here as well, going 0, 1, 2, 3...

But size goes 1808, 779, 351.

Based on ffprobe output for the original file, ordered-frames.mp4, the second frame should have size 351. (Also, coded_picture_number doesn't mean what I implied it did, and if their order was close to the 'buggy' output, probably coincidence.)

In the buggy output, the numbers displayed go 0, 2, 1. For the avi file, this matches the packet order and packet dts values, not the frame order or frame dts values that ffprobe shows. Presumably the packets contain the different dts value.

For pts values and mp4 files, it seems the packet and frame pts are the same. dts for frames is shown as always being the same as pts for the original file, ordered-frames.mp4, with no relation to the packet dts; but in ordered-frames-avicopy.mp4, the frame pts is always the same as the packet dts (and packet pts), which is two more than the packet pts for the original, while the frame dts is always two more than the frame dts for the original.

I'm not sure why the dts for a packet, and pkt_dts for a frame, are different when "pkt" seems like an abbreviation for packet.

For typical files that aren't copied from an avi, the frame dts and pts seem to always be the same. So if programs are ignoring the 'frame pts' recorded for a frame, and only using the dts value which has also been recorded for the frame separately than for the packet that contains it, they wouldn't have any bugs.

But Chrome doesn't ignore it or reads ahead when other programs don't, and also apparently handles avi files wrong in a way that coincidentally leads to the same output, so the video stutters.

I hope this problem can be fixed, so avi files and bugged mp4 files will play correctly in Chrome OS.
pts values reported as a bug for ffmpeg, but will not fix avi playback: https://trac.ffmpeg.org/ticket/6905
Using MP4Box, which is part of the 'gpac' package, I was able to get a non-bugged mp4 for the original avi I was testing with, but it didn't accept the 'avc1' (h.264) codec from ordered-frames.avi.

After copying the first few seconds of the original avi to copy.avi, I then performed

MP4Box -add copy.avi copy-MP4Box.mp4

The result is attached. It doesn't stutter in Chrome OS. When I unpacked the frames using ffmpeg's bitstream filter, the time to play that file ('time ffmpeg -i copy2-MP4Box.mp4 -f null -', with CPU frequency locked) is statistically indistinguishable from the non-unpacked version, though it could possibly affect hardware decoding.

Neither the unpacked nor the packed B-frame versions would play video in Chrome on Linux, so I am just including the original packed version.

In this file, the frame pts's are the same as the dts's when examined with ffprobe.
copy-MP4Box.mp4
602 KB View Download
Status: WontFix (was: Unconfirmed)
I appreciate your debugging, but we intentionally do not support manual reordering of decoded frames. These files are considered broken if the encoded bitstream is not correctly marked for reordering (which doesn't use timestamps).

It seems you've found a way to remux the file with correct timestamps in c#4 without re-encoding which is great!

Chrome doesn't aim to play or work with every file; for reasons of maintenance and security over the lifetime of a project the size and age of Chrome, we try to error out on unexpected conditions as soon as possible.
You may want to prevent Chrome from playing .avi files, then. As it was, I spent some time looking for a cause and solution. Many answers about stuttering video said to disable hardware acceleration, which I tried.

I do wonder why Chrome OS has libraries to demux .avi files if it does not intend to correctly order the frames in it.

Sign in to add a comment