Vixen
02b45cc4
csharp
public sealed class MatroskaDemuxer

Pulls tracks and blocks out of a Matroska or WebM segment.

No guide page documents this yet — the page shows what the code says about itself.

Remarks

Why the container is ours. The same argument Vixen.Audio.Codecs.OggReader makes, one layer up: a video codec takes a packet and knows nothing about where it came from, so somebody has to turn a file into packets, and a managed reader for a format this small is cheaper in every sense than a native demuxer plus a binary per RID. WebM is also the container that is unencumbered, that browsers play, and that docs/plan/08 names for the importer.

MP4 is not here. Doc 08 names it too, and it is a genuinely larger job — a box parser, sample tables, chunk offsets, and an stsd that hands out codec configuration in a different shape per codec. It is additive: the seam every layer above this one uses is IVideoStreamDecoder, and an Mp4Demuxer plugs into the same place. What is here first is the format that the free codecs actually ship in.

Unknown elements are skipped, not rejected. That is the property EBML exists for, and it is why this reader — which understands about twenty elements out of several hundred — plays files written by muxers that did not exist when it was written.

It is safe to read two tracks from two threads, and that is not incidental. A video's picture is decoded on the player's own thread and its sound is decoded on the audio pump's, because that is what both subsystems already do — so the ordinary way to use this class is from two threads at once, and a reader that was not safe for it would be one that worked in a test and tore in a game. The lock is uncontended in practice: both callers are reading a file in blocks and hold it for the length of one packet.

A caller must drain every track it reads from. Blocks arrive interleaved, so asking for a video packet decodes the audio packets that were in front of it and holds them. Reading video and never reading audio grows that queue for the length of the film. A track that is never asked for at all costs nothing — its blocks are skipped where they lie.

Two readers, one seeker. SeekTo moves the file, and the file is shared — so a seek issued for the picture moves the sound with it, and every packet buffered for either track is dropped. That is correct when one thing owns the playback and wrong the moment two do: a video looping on its own while its audio track plays through the same reader will yank the file back to the start under the audio decoder, over and over, and what comes out is neither stream.

So: share a demuxer when nothing seeks — a cutscene played once, straight through — and give each track its own demuxer when either side seeks or loops. Two demuxers over two streams on the same file cost one file handle and a few hundred kilobytes of buffering, each skips the other's blocks where they lie, and each seeks its own position. Samples/11-VideoPlayback does exactly that, and says why in its README.

Fields and properties (5)

  • public IReadOnlyList<MatroskaTrack> Tracks

    Every track the segment declares, in the order it declared them.

  • public TimeSpan Duration

    How long the segment is, or zero if it did not say.

  • public string DocType

    What the file called itself — webm or matroska.

  • public bool CanSeek

    Whether SeekTo works.

  • public bool HasCues

    Whether the segment declared a cue index, and can therefore seek without scanning.

Methods (8)

  • public MatroskaDemuxer(string path)

    Opens a file.

  • public MatroskaDemuxer(Stream stream, bool leaveOpen = false)

    Opens a stream.

  • public void Dispose()

    Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

  • public MatroskaTrack? FindTrack(MatroskaTrackKind kind)

    Finds the first track of a kind.

  • public void Follow(int trackNumber)

    Starts buffering a track's blocks, before anybody reads one.

  • public MatroskaPacket? ReadPacket(int trackNumber)

    Reads the next packet of a track.

  • public void Release(MatroskaPacket packet)

    Gives a packet back.

  • public void SeekTo(TimeSpan position, int trackNumber)

    Moves to the cluster covering a position.

Used by (8)

  • VideoGameVideoPlayback
  • MatroskaAudioStreamDecoderVixen.Video
  • MatroskaAudioTestsVixen.Video.Tests
  • MatroskaDemuxerTestsVixen.Video.Tests
  • OpusAudioTrackTestsVixen.Video.Codecs.Tests
  • VideoPlaybackVixen.Video
  • WebMVideoStreamDecoderVixen.Video
  • VideoImporterVixen.Editor.Assets