PeerCastStation.MKV.Element.ReadHeaderAsync C# (CSharp) Method

ReadHeaderAsync() public static method

public static ReadHeaderAsync ( Stream s, CancellationToken cancel_token ) : Task
s Stream
cancel_token System.Threading.CancellationToken
return Task
    public static async Task<Element> ReadHeaderAsync(Stream s, CancellationToken cancel_token)
    {
      var id  = await VInt.ReadUIntAsync(s, cancel_token);
      var sz  = await VInt.ReadUIntAsync(s, cancel_token);
      return new Element(id, sz);
    }

Usage Example

        public async Task ReadAsync(IContentSink sink, Stream stream, CancellationToken cancel_token)
        {
            var state          = ReaderState.EBML;
            var position       = 0L;
            var stream_index   = -1;
            var stream_origin  = DateTime.Now;
            var timecode_scale = 1000000.0;
            var ebml           = new EBML();
            var clusters       = new LinkedList <Cluster>();
            var headers        = new List <Element>();

            var eos = false;

            while (!eos)
            {
                try {
                    var elt = await Element.ReadHeaderAsync(stream, cancel_token).ConfigureAwait(false);

                    if (ebml.MaxIDLength < elt.ID.Length ||
                        ebml.MaxSizeLength < elt.Size.Length)
                    {
                        throw new BadDataException();
                    }
parse_retry:
                    switch (state)
                    {
                    case ReaderState.EBML:
                        if (elt.ID.BinaryEquals(Elements.EBML))
                        {
                            await elt.ReadBodyAsync(stream, cancel_token).ConfigureAwait(false);

                            headers.Clear();
                            headers.Add(elt);
                            ebml  = new EBML(elt);
                            state = ReaderState.Segment;
                        }
                        else
                        {
                            throw new BadDataException();
                        }
                        break;

                    case ReaderState.Segment:
                        if (elt.ID.BinaryEquals(Elements.Segment))
                        {
                            headers.Add(elt);
                            state = ReaderState.EndOfHeader;
                        }
                        else if (elt.ID.BinaryEquals(Elements.EBML))
                        {
                            state = ReaderState.EBML;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.Void) ||
                                 elt.ID.BinaryEquals(Elements.CRC32))
                        {
                            await elt.ReadBodyAsync(stream, cancel_token).ConfigureAwait(false);

                            headers.Add(elt);
                        }
                        else
                        {
                            throw new BadDataException();
                        }
                        break;

                    case ReaderState.EndOfHeader:
                        if (elt.ID.BinaryEquals(Elements.Segment))
                        {
                            state = ReaderState.Segment;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.EBML))
                        {
                            state = ReaderState.EBML;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.Cluster))
                        {
                            clusters.Clear();
                            MemoryStream header;
                            using (header = new MemoryStream()) {
                                foreach (var c in headers)
                                {
                                    c.Write(header);
                                }
                            }
                            headers.Clear();

                            stream_index  = Channel.GenerateStreamID();
                            stream_origin = DateTime.Now;
                            position      = 0;
                            sink.OnContentHeader(
                                new Content(stream_index, TimeSpan.Zero, 0, header.ToArray(), PCPChanPacketContinuation.None)
                                );
                            position += header.ToArray().LongLength;
                            var info = new AtomCollection();
                            if (ebml.DocType == "webm")
                            {
                                info.SetChanInfoType("WEBM");
                                info.SetChanInfoStreamType("video/webm");
                                info.SetChanInfoStreamExt(".webm");
                            }
                            else
                            {
                                info.SetChanInfoType("MKV");
                                info.SetChanInfoStreamType("video/x-matroska");
                                info.SetChanInfoStreamExt(".mkv");
                            }
                            sink.OnChannelInfo(new ChannelInfo(info));

                            state = ReaderState.Cluster;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.Info))
                        {
                            await elt.ReadBodyAsync(stream, cancel_token).ConfigureAwait(false);

                            var s = new MemoryStream(elt.Data);
                            while (s.Position < s.Length)
                            {
                                var child = Element.ReadHeader(s);
                                if (child.ID.BinaryEquals(Elements.TimecodeScale))
                                {
                                    timecode_scale = Element.ReadUInt(s, child.Size.Value) * 1.0;
                                }
                                else
                                {
                                    child.ReadBody(s);
                                }
                            }
                            headers.Add(elt);
                        }
                        else
                        {
                            await elt.ReadBodyAsync(stream, cancel_token).ConfigureAwait(false);

                            headers.Add(elt);
                        }
                        break;

                    case ReaderState.Cluster:
                        if (elt.ID.BinaryEquals(Elements.Segment))
                        {
                            state = ReaderState.Segment;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.EBML))
                        {
                            state = ReaderState.EBML;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.Cluster))
                        {
                            if (clusters.Count > 0)
                            {
                                var timespan = clusters.Sum(c => c.Timespan);
                                if (timespan >= 30.0)
                                {
                                    var sz   = clusters.Sum(c => c.Timespan > 0 ? c.BlockSize : 0);
                                    var kbps = (int)((sz * 8 / timespan + 900) / 1000.0);
                                    var info = new AtomCollection();
                                    info.SetChanInfoBitrate(kbps);
                                    sink.OnChannelInfo(new ChannelInfo(info));
                                    while (clusters.Count > 1)
                                    {
                                        clusters.RemoveFirst();
                                    }
                                }
                            }
                            var cluster = new Cluster(elt);
                            clusters.AddLast(cluster);
                            sink.OnContent(
                                new Content(stream_index, DateTime.Now - stream_origin, position, elt.ToArray(), PCPChanPacketContinuation.None)
                                );
                            position += elt.ByteSize;
                            state     = ReaderState.Timecode;
                        }
                        else if (elt.ID.BinaryEquals(Elements.Void) ||
                                 elt.ID.BinaryEquals(Elements.CRC32))
                        {
                            await elt.ReadBodyAsync(stream, cancel_token).ConfigureAwait(false);

                            sink.OnContent(
                                new Content(stream_index, DateTime.Now - stream_origin, position, elt.ToArray(), PCPChanPacketContinuation.None)
                                );
                            position += elt.ByteSize;
                        }
                        else
                        {
                            throw new BadDataException();
                        }
                        break;

                    case ReaderState.Timecode:
                        if (elt.ID.BinaryEquals(Elements.Segment))
                        {
                            state = ReaderState.Segment;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.EBML))
                        {
                            state = ReaderState.EBML;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.Cluster))
                        {
                            state = ReaderState.Cluster;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.SimpleBlock) ||
                                 elt.ID.BinaryEquals(Elements.BlockGroup))
                        {
                            state = ReaderState.Block;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.Timecode))
                        {
                            await elt.ReadBodyAsync(stream, cancel_token).ConfigureAwait(false);

                            if (clusters.Last != null)
                            {
                                clusters.Last.Value.Timecode =
                                    Element.ReadUInt(new MemoryStream(elt.Data), elt.Data.Length) * (timecode_scale / 1000000000.0);
                                if (clusters.Count > 1)
                                {
                                    clusters.Last.Previous.Value.Timespan = clusters.Last.Value.Timecode - clusters.Last.Previous.Value.Timecode;
                                }
                            }
                            sink.OnContent(
                                new Content(stream_index, DateTime.Now - stream_origin, position, elt.ToArray(), PCPChanPacketContinuation.None)
                                );
                            position += elt.ByteSize;
                            state     = ReaderState.Block;
                        }
                        else
                        {
                            await elt.ReadBodyAsync(stream, cancel_token).ConfigureAwait(false);

                            sink.OnContent(
                                new Content(stream_index, DateTime.Now - stream_origin, position, elt.ToArray(), PCPChanPacketContinuation.None)
                                );
                            position += elt.ByteSize;
                        }
                        break;

                    case ReaderState.Block:
                        if (elt.ID.BinaryEquals(Elements.Segment))
                        {
                            state = ReaderState.Segment;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.EBML))
                        {
                            state = ReaderState.EBML;
                            goto parse_retry;
                        }
                        else if (elt.ID.BinaryEquals(Elements.Cluster))
                        {
                            state = ReaderState.Cluster;
                            goto parse_retry;
                        }
                        else if ((elt.ID.BinaryEquals(Elements.SimpleBlock) ||
                                  elt.ID.BinaryEquals(Elements.BlockGroup)) &&
                                 (clusters.Last.Value.BlockID == null ||
                                  elt.ID.BinaryEquals(clusters.Last.Value.BlockID)))
                        {
                            await elt.ReadBodyAsync(stream, cancel_token).ConfigureAwait(false);

                            clusters.Last.Value.BlockSize += elt.Size.Value;
                            clusters.Last.Value.BlockID    = elt.ID.Binary;
                            sink.OnContent(
                                new Content(stream_index, DateTime.Now - stream_origin, position, elt.ToArray(), PCPChanPacketContinuation.None)
                                );
                            position += elt.ByteSize;
                        }
                        else if (clusters.Last.Value.BlockID == null)
                        {
                            await elt.ReadBodyAsync(stream, cancel_token).ConfigureAwait(false);

                            sink.OnContent(
                                new Content(stream_index, DateTime.Now - stream_origin, position, elt.ToArray(), PCPChanPacketContinuation.None)
                                );
                            position += elt.ByteSize;
                        }
                        else
                        {
                            state = ReaderState.Cluster;
                            goto parse_retry;
                        }
                        break;
                    }
                }
                catch (EndOfStreamException) {
                    eos = true;
                }
                catch (BadDataException) {
                }
            }
        }