[Matroska-devel] timecode scale handling & sample precision

Moritz Bunkus m.bunkus at linet-services.de
Sun Aug 1 13:51:17 CEST 2004


until now I really didn't care all that much, but now that I'm
implementing sample precision I have to care. So I took the time to
study the current explanation for the timecode scale handling available
at http://www.matroska.org/technical/specs/notes.html#TimecodeScale

It is wrong.

Let's take the sample rate of 44100. A timecode scale parameter of
1000000000/44100 is 22675.736961. The example uses 22676 which results
in a precision that is LESS than the sample rate. There's no way to to
regenerate 44100 different sample numbers from < 44100 different values.
It must be 22675 - always _truncate_ the timecode scale factor.

The next thing is:
To determine which sample that is,
(313450348 / 1000000000) * 44100 = ~13823.16
Check to see if the value is greater than the truncated version of
itself and if so, round up.

A value is always at least as big as its truncated value! So this will
simply result in wrong values. You're throwing away up to nearly 1
sample of time. There's NO way a program can regenerate that from the
raw timecode and the timecode scale factor.

Here's how to use it right including a small demonstration application:

(I'll use $var for a variable name because the text might be confusing

Use the following timecode scale value:

$tc_scale = (int64_t)(1000000000ll / $sample_rate)

Let's assume we have a sample number $sample, the sample rate
$sample_rate and the timecode scale factor as given above. We further
need a function that can round a value to the nearest integer (in this
case the nearest 64bit integer). We can use a simple #define for this:

#define irnd(v) ((int64_t)((v) + 0.5) > (int64_t)(v) ? \
                 (int64_t)((v) + 0.5) : (int64_t)(v))

The 'original' timecode $unscaled_timecode is the one the application
deals with. It is obviously just

$unscaled_timecode = 1000000000ll * $sample / $sample_rate 

Easy enough. Even better wound be using double precision and rounding,
but 1ns is WAY below any sensible $sample_rate so we can live with the
imprecision of just truncating this value to the lower ns.

Next: the $scaled_timecode is the one that is actually written to the
Matroska file. Other folks call this the 'raw' timecode. I'll use
'scaled' for timecodes whose unit is '1 $tc_scale' and 'unscaled' for
timecodes whose unit is '1ns'.

--> Here we HAVE to round! <--

This timecode is 

$scaled_timecode = irnd((double)$unscaled_timecode / (double)$tc_scale)

Now we have a nice scaled timecode in our file. Another application
wants to read such a file, gets $tc_scale from the header and reads a
block. Inside that file it finds $scaled_timecode for that block. From
that it can calculated the 'unscaled' timecode on the reader's part:

$rescaled_timecode = $scaled_timecode * $tc_scale

Easy. No rounding needed obviously because we multiply integers in the
first place. How does the application get the sample number from this?
Again this involves...

--> ROUNGIN! <--

$recalculated_sample = irnd((double)$rescaled_timecode * $sample_rate /

Et voila. That's it.

I've attached a small test application that demonstrates this for a
sample rate of 44100. It will output each of the four values along with
a string 'ok' or 'NOT OK!' if the $sample is equal to or different from
the $recalculated_sample. If you don't believe me just test it, redirect
the output to a file and search for 'NOT OK'. You won't find it.

I REALLY hope I'm not making a mistake here, but I'm pretty sure I
don't. So I'll overhaul the web page mentioned at the beginning with
this information and modify mkvmerge accordingly if no one objects.


LINET Services
Bunkus, Geisler und Reetz GbR

Gotenweg 15                      Tel.: 0531-280 191 71
38106 Braunschweig               Fax.: 0531-280 191 72

mailto:info at linet-services.de
-------------- next part --------------
A non-text attachment was scrubbed...
Name: tcscale-working.c
Type: text/x-csrc
Size: 1180 bytes
Desc: not available
URL: <http://lists.matroska.org/pipermail/matroska-devel/attachments/20040801/085a48f2/attachment.c>

More information about the Matroska-devel mailing list