On 2021-05-19 17:14, Lynne wrote:
May 19, 2021, 17:12 by d...@lynne.ee:

May 19, 2021, 03:44 by michael.di...@xaymar.com:

From: Michael Fabian 'Xaymar' Dirks <michael.di...@xaymar.com>

Adds the "timestamp_precision" option to matroskaenc, which allows users
to increase the time stamp precision up to 1 nanosecond. This aids with
certain demuxers being unable to detect constant rate. It is a work
around fix for the problems reported in 259, 6406, 7927, 8909 and 9124.

Signed-off-by: Michael Fabian 'Xaymar' Dirks <michael.di...@xaymar.com>
---
  libavformat/matroskaenc.c | 25 ++++++++++++++++++-------
  1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index b4284a8778..8e2813c36e 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -158,6 +158,8 @@ typedef struct MatroskaMuxContext {
  int                 default_mode;
uint32_t segment_uid[4];
+
+    AVRational          time_base;
  } MatroskaMuxContext;
/** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint,
@@ -1816,6 +1818,7 @@ static int mkv_write_header(AVFormatContext *s)
  const AVDictionaryEntry *tag;
  int ret, i, version = 2;
  int64_t creation_time;
+    int64_t time_base = 1;
if (mkv->mode != MODE_WEBM ||
  av_dict_get(s->metadata, "stereo_mode", NULL, 0) ||
@@ -1852,7 +1855,10 @@ static int mkv_write_header(AVFormatContext *s)
  return ret;
  pb = mkv->info.bc;
- put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000);
+    time_base = av_rescale_q(time_base, mkv->time_base, (AVRational){1, 
1000000000});
+    av_log(s, AV_LOG_DEBUG, "TimestampScale is: %" PRId64 " ns\n", time_base);
+    put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, time_base);
+
  if ((tag = av_dict_get(s->metadata, "title", NULL, 0)))
  put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value);
  if (!(s->flags & AVFMT_FLAG_BITEXACT)) {
@@ -1885,11 +1891,11 @@ static int mkv_write_header(AVFormatContext *s)
  int64_t metadata_duration = get_metadata_duration(s);
if (s->duration > 0) {
-            int64_t scaledDuration = av_rescale(s->duration, 1000, 
AV_TIME_BASE);
+            int64_t scaledDuration = av_rescale_q(s->duration, AV_TIME_BASE_Q, 
mkv->time_base);
  put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration);
  av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 
"\n", scaledDuration);
  } else if (metadata_duration > 0) {
-            int64_t scaledDuration = av_rescale(metadata_duration, 1000, 
AV_TIME_BASE);
+            int64_t scaledDuration = av_rescale_q(metadata_duration, 
AV_TIME_BASE_Q, mkv->time_base);
  put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration);
  av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", 
scaledDuration);
  } else if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
@@ -1950,12 +1956,12 @@ static int mkv_write_header(AVFormatContext *s)
  // after 4k and on a keyframe
  if (IS_SEEKABLE(pb, mkv)) {
  if (mkv->cluster_time_limit < 0)
-            mkv->cluster_time_limit = 5000;
+            mkv->cluster_time_limit = av_rescale_q(5000, (AVRational){1, 1000}, 
mkv->time_base);
  if (mkv->cluster_size_limit < 0)
  mkv->cluster_size_limit = 5 * 1024 * 1024;
  } else {
  if (mkv->cluster_time_limit < 0)
-            mkv->cluster_time_limit = 1000;
+            mkv->cluster_time_limit = av_rescale_q(1000, (AVRational){1, 1000}, 
mkv->time_base);
  if (mkv->cluster_size_limit < 0)
  mkv->cluster_size_limit = 32 * 1024;
  }
@@ -2736,8 +2742,8 @@ static int mkv_init(struct AVFormatContext *s)
  track->uid = mkv_get_uid(mkv->tracks, i, &c);
  }
- // ms precision is the de-facto standard timescale for mkv files
-        avpriv_set_pts_info(st, 64, 1, 1000);
+        // Use user-defined timescale.
+        avpriv_set_pts_info(st, 64, mkv->time_base.num, mkv->time_base.den);
if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT) {
  if (mkv->mode == MODE_WEBM) {
@@ -2757,6 +2763,10 @@ static int mkv_init(struct AVFormatContext *s)
  track->track_num_size = ebml_num_size(track->track_num);
  }
+ // Scale the configured cluster_time_limit.
+    if (mkv->cluster_time_limit >= 0)
+        mkv->cluster_time_limit = av_rescale_q(mkv->cluster_time_limit, 
(AVRational){1, 1000}, mkv->time_base);
+
  if (mkv->is_dash && nb_tracks != 1)
  return AVERROR(EINVAL);
@@ -2824,6 +2834,7 @@ static const AVOption options[] = {
  { "infer", "For each track type, mark the first track of disposition default as default; if 
none exists, mark the first track as default.", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_INFER }, 0, 
0, FLAGS, "default_mode" },
  { "infer_no_subs", "For each track type, mark the first track of disposition default as 
default; for audio and video: if none exists, mark the first track as default.", 0, AV_OPT_TYPE_CONST, { 
.i64 = DEFAULT_MODE_INFER_NO_SUBS }, 0, 0, FLAGS, "default_mode" },
  { "passthrough", "Use the disposition flag as-is", 0, AV_OPT_TYPE_CONST, { .i64 = 
DEFAULT_MODE_PASSTHROUGH }, 0, 0, FLAGS, "default_mode" },
+    { "timestamp_precision", "Timestamp precision to use for the entire 
container", OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0.001 }, 0.000000001, 1.0, 
FLAGS},
  { NULL },
  };

Make the default 1 ns.
This is 2021. I'm not accepting any compromises. Matroska has
dragged its heels for long enough, video players have resorted to hacks
to fix time stamps, and high-framerate video is still unacceptably jittery.

We're bumping to 5.0 next release anyway, and if any users have issues,
they can manually set this to 1ms.

Or better yet, use the timebase to decide the value.
That way, remuxing Matroska won't break anything, and the overhead
will be lower.

Most likely 1 ns would already cover any possible situation that could break, 
if the remote has a proper implementation of the Matroska spec. Calculating the 
time scale based on the time base of every stream is possible, but I'm fairly 
sure it would involve semi-complex code.

--
Sincerely | Mit freundlichen Grüßen

Michael Fabian 'Xaymar' Dirks
Software Designer & Engineer


_______________________________________________
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