Follow up: I appear to have solved this and have some further information which may be useful.

TL;DR: Setting AVStream's avg_frame_rate, which corresponds to mkvinfo's "Default duration" field, appears to have fixed this.

From my investigation, it appears VLC will use a few different sources of information to determine the timecode. The first and foremost is the aforementioned "default duration", corresponding to avg_frame_rate. However if it's missing, it appears to use the MKV cluster size (corresponding to the codec's gop_size). I noticed from mkvinfo that each cluster started at the times VLC's playhead would appear to jump to (0:00, 0:03, 0:07, etc.) and that changing the gop_size would shift these around.

Following from this, it was somewhat inaccurate to say all of the examples exhibit this issue. The "muxing" example, which sets the gop_size to 12, creates an MKV that plays reasonably in VLC. With far more frequent MKV clusters, VLC's timecode doesn't hang for seconds at a time. However the downside of decreasing the gop_size is that naturally it makes the file larger due to more intra frames and it presumably means VLC's playhead is still only accurate to the nearest 12th frame. When FFmpeg remuxes, it obviously doesn't change the gop_size, but it does set the "default duration"/avg_frame_rate. Output from my program, with avg_frame_rate set, works as expected without the file size increases that result from changing the gop_size, so that appears to be the solution.

As for the "remuxing" and "transcoding" examples:

 * The output from "transcoding" will always exhibit this issue since
   it doesn't set gop_size nor avg_frame_rate.
 * The "remuxing" example depends on the input. If the MKV has a low
   gop_size, it will obviously preserve that. However, it doesn't set
   nor preserve "avg_frame_rate", so the output will exhibit this issue
   with larger gop_size inputs (including non-MKV files such as MP4s).
 * Disregard my comment about "encode_video", I forgot it didn't mux
   anything.

It may be worth updating the relevant tests to fix this, but it depends on whether this is considered a priority or not.

PS Andreas: You were correct about my subtitle packet duration being set wrong, I have fixed this now.

Matt

On 8/7/2021 10:52 PM, MattKC wrote:
Andreas,

    (A quick look showed that the transcoding example does not use
    pkt_timebase for decoding, as does your code;

This is certainly the first time I've heard of using pkt_timebase. Almost all examples and tutorials I've seen use AVStream::time_base. What's the usage of this though? Documentation says "encoding unused" and it seems to be null (0/1) when I tried using it just now.

    furthermore, your code
    sets the duration of subtitle packets wrong, as the end_display_time is
    in a different timebase than the subtitle's pts.)

Is that incorrect? The AVSubtitle struct definition says start_display_time and end_display_time are in ms not in time base units. Also, the subtitles, as encoded by my program, appear to be correct when played back.

I can open an issue on trac at some point, but the issue can be fairly easily recreated just by using "remuxing <input-file> output.mkv" or "encode-video output.mkv libx264" or "transcoding <input-file> output.mkv". It would seem most if not all of the examples produce a broken file when outputting to MKV.

I've attached the output of "mkvinfo -a" on both a broken MKV exported from my program and a remuxed MKV from FFmpeg. They're largely similar; the "Default duration" section in the remux and slightly different order of packets are the only parts that stands out to me. Let me know if you can get any meaningful information out of them.

Matt

On 8/7/2021 9:58 PM, Andreas Rheinhardt wrote:
MattKC:
==Summary==

I've been implementing ffmpeg/libav into an application, and have run
into timing-related issues when playing back Matroska/MKV videos created
by my application in VLC. I tried asking about this on the libav-user
mailing list and received no response so I thought I'd try here. While
it's true that there may be issues with VLC's implementation too, I've
noticed specifically that videos generated by FFmpeg do not cause these
issues, while my application and the examples in "doc/examples" (which
my code is modeled from) do, which makes me think this code is missing
something crucial.

==Symptoms==

During playback, VLC's playback time will appear to stay frozen at 0:00
while the video and audio plays normally. It will then jump only in
increments of a few seconds (0:03, then 0:07, then 0:11, etc.) This
behavior occurs with videos produced both by my application and by the
FFmpeg examples programs "transcoding.c" and "remuxing.c".

The fact that this occurs with "remuxing.c" is particularly interesting
since that would seem to imply it's an issue with the format/container
writing specifically. If "remuxing.c" is given a correct MKV file (i.e.
one that does not exhibit this issue) produced by FFmpeg as its input,
and outputs to a second MKV file, that second MKV will demonstrate this
issue even though the first one didn't, indicating that something is
breaking during the remuxing process despite no decoding/encoding
occurring.

The worst demonstration of this issue that I've run into is if my
application writes any audio packets before writing the first video
packet (with "av_interleaved_write_frame"), the first few seconds of
video (until that first 0:03) will be considered completely blank by
VLC. The fact that it will pick up after 0:03, the same time the timer
will make its first update on other MKV files, leads me to believe it's
the exact same root cause, just a different presentation of it.

This issue only occurs on MKV files. MP4/MOV appear to have no issues
whatsoever.

==Conclusion==

Considering FFmpeg produces correct MKV files, I don't believe this to
be a bug in libav (though it could be considered a bug in the examples).
I'm assuming the examples and my program are missing something or doing
something incorrectly.

My code can be seen here, however the examples will almost certainly be
easier to read and test:
https://github.com/olive-editor/olive/blob/master/app/codec/ffmpeg/ffmpegencoder.cpp


Thanks in advance for any help, I'm a little confused about this whole
issue.

If it happens with our examples, too (as you said), then you should open
an issue on trac (for the examples). Be sure to add samples that allow
to reproduce it.
It would probably be enlightening to use mkvinfo to look at the
generated files. The files are probably badly interleaved (your
description makes me suspect that the generated files have lots of audio
packets at the beginning before the first video packet).
(A quick look showed that the transcoding example does not use
pkt_timebase for decoding, as does your code; furthermore, your code
sets the duration of subtitle packets wrong, as the end_display_time is
in a different timebase than the subtitle's pts.)

- Andreas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org  with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to