Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Proposal to add some rational number in timestamps #425

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions ebml_matroska.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,16 @@ The format depends on the ChapProcessCodecID used; see (#chapprocesscodecid-elem
<documentation lang="en" purpose="definition">Timestamp scale in nanoseconds (1.000.000 means all timestamps in the Segment are expressed in milliseconds).</documentation>
<extension type="libmatroska" cppname="TimecodeScale"/>
</element>
<element name="TimestampNumerator" path="\Segment\Tracks\TrackEntry\TimestampNumerator" id="0x2AF6A9" type="uinteger" range="not 0" maxOccurs="1" minver="5">
<documentation lang="en" purpose="definition">Timestamp numerator to apply instead of the TimestampScale, when the TimestampDenominator is present as well.</documentation>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If TrackTimestampScale is revived it should be mentioned its value MUST be the rounded value in nanoseconds of this fraction.

<extension webm="0"/>
</element>
<element name="TimestampDenominator" path="\Segment\Tracks\TrackEntry\TimestampDenominator" id="0x2AF6AA" type="uinteger" range="not 0" maxOccurs="1" minver="5">
<documentation lang="en" purpose="definition">Timestamp denominator to apply instead of the TimestampScale, when the TimestampNumerator is present as well.</documentation>
<extension webm="0"/>
</element>
<element name="Duration" path="\Segment\Info\Duration" id="0x4489" type="float" range="&gt; 0x0p+0" maxOccurs="1">
<documentation lang="en" purpose="definition">Duration of the Segment in nanoseconds based on TimestampScale.</documentation>
<documentation lang="en" purpose="definition">Duration of the Segment in nanoseconds based on TimestampScale and TimestampNumerator/TimestampDenominator in v5.</documentation>
</element>
<element name="DateUTC" path="\Segment\Info\DateUTC" id="0x4461" type="date" maxOccurs="1">
<documentation lang="en" purpose="definition">The date and time that the Segment was created by the muxing application or library.</documentation>
Expand All @@ -110,7 +118,7 @@ The format depends on the ChapProcessCodecID used; see (#chapprocesscodecid-elem
<documentation lang="en" purpose="definition">The Top-Level Element containing the (monolithic) Block structure.</documentation>
</element>
<element name="Timestamp" path="\Segment\Cluster\Timestamp" id="0xE7" type="uinteger" minOccurs="1" maxOccurs="1">
<documentation lang="en" purpose="definition">Absolute timestamp of the cluster (based on TimestampScale).</documentation>
<documentation lang="en" purpose="definition">Absolute timestamp of the cluster (based on TimestampScale and TimestampNumerator/TimestampDenominator in v5).</documentation>
<extension type="libmatroska" cppname="ClusterTimecode"/>
</element>
<element name="SilentTracks" path="\Segment\Cluster\SilentTracks" id="0x5854" type="master" maxOccurs="1">
Expand Down Expand Up @@ -172,7 +180,7 @@ If BlockAddIDType of the corresponding block is 0, this value is also the value
<extension type="webmproject.org" webm="1"/>
</element>
<element name="BlockDuration" path="\Segment\Cluster\BlockGroup\BlockDuration" id="0x9B" type="uinteger" maxOccurs="1">
<documentation lang="en" purpose="definition">The duration of the Block (based on TimestampScale).
<documentation lang="en" purpose="definition">The duration of the Block (based on TimestampScale and TimestampNumerator/TimestampDenominator in v5).
The BlockDuration Element can be useful at the end of a Track to define the duration of the last frame (as there is no subsequent Block available),
or when there is a break in a track like for subtitle tracks.</documentation>
<implementation_note note_attribute="minOccurs">BlockDuration **MUST** be set (minOccurs=1) if the associated TrackEntry stores a DefaultDuration value.</implementation_note>
Expand Down
26 changes: 26 additions & 0 deletions notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,32 @@ Some general notes for a program:
that it started with. Using a slightly lower timestamp scale factor can help here in
that it removes the need for proper rounding in the conversion from sample number to `Raw Timestamp`.

## Rational Number and Nanoseconds

Historically timestamps in Matroska were stored in nanoseconds precision.
The `TimestampScale` would reduce the size of each value stored in the file by dividing each real timestamps by a certain value.
For many sampling frequencies, that means rounding the values and losing precision.
There are `TimestampNumerator` and `TimestampDenominator` to fix this precision loss.
They override the value of `TimestampScale` in all places it is used.

This formula remains but there is no rounding involved anymore:

(a + b) * c

a = `Block`'s Timestamp
b = `Cluster`'s Timestamp
c = `TimestampScale`

For compatibility with older readers that don't understand these elements, the `TimestampScale` value *MUST*
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More info about the TrackTimestampScale should be added.

be the rounded values of `TimestampNumerator` divided by `TimestampDenominator` in nanoseconds.

This fraction may not be usable in most cases. It works well with files having a single Track.
It only works when Tracks have a sampling frequency which is highly divisible.
For example even a video track of 1/25000 (PAL) with audio of 1/48000 (DAT) doesn't work well. The reduced fraction gives 25/48.
A `TimestampNumerator` of 1 and `TimestampDenominator` of 25\*48000 would give ticks that hit on each clock.
But the amount of samples possible in a Block/SimpleBlock is stored on 16 bits or 65536 values. So the duration possible in a Cluster would be 65536 / (25\*48000) or 54.6 ms. Which is not enough to be efficient storage.
It would only work if audio samples were packed with a multiple of 25 samples, which is usually not the case.

## TrackTimestampScale

The `TrackTimestampScale Element` is used align tracks that would otherwise be played at
Expand Down