Splits a byte array into values, based on a series of bit lengths Translations are done from network byte order.
            /// <summary>
            /// Digest a packet payload into structured table. Payload should be from the pointer field onward.
            /// Does not yet handle multi-packet tables
            /// </summary>
            public PMT(byte[] RawPayload)
            {
                BitSplitter bs = new BitSplitter(RawPayload);
                Map = new Dictionary<int, int>();
                ReverseMap = new Dictionary<StreamType, int>();

                ValidateTable(bs);

                bs.SkipBits(2);
                SectionLength = (int)bs.GetInteger(12); // total length after this, in bytes; includes 4 byte CRC.
                ProgramNumber = (int)bs.GetInteger(16);
                bs.SkipBits(2);

                Version = (int)bs.GetInteger(5);
                IsCurrent = bs.GetFlag();
                SectionNumber = (int)bs.GetInteger(8);
                LastSection = (int)bs.GetInteger(8);
                bs.SkipBits(3);
                PCR_PID = (int)bs.GetInteger(13); // Either the PID of a channel timecode stream, or 0x1FFF for none.
                bs.SkipBits(4);

                ProgInfoLength = (int)bs.GetInteger(12); // number of bytes of descriptors.
                if (bs.BitOffset != 0) throw new DemuxException("Byte alignment error (internal)");
                bs.SkipBytes(ProgInfoLength); // ignore descriptors.

                int info_bytes = (SectionLength - ProgInfoLength) - 13; // bytes of descriptor.

                while (info_bytes > 0) { // descriptions can be variable length
                    int stream_type = (int)bs.GetInteger(8);
                    bs.SkipBits(3);
                    int pid = (int)bs.GetInteger(13);
                    bs.SkipBits(4);

                    if (!Map.ContainsKey(pid)) Map.Add(pid, stream_type); // more complete map of pid types
                    else throw new DemuxException("Invalid PMT: PID specified more than once");

                    StreamType st = DecodeStreamType(stream_type);
                    if (!ReverseMap.ContainsKey(st)) ReverseMap.Add(st, pid); // store first pid of each type

                    int es_info_length = (int)bs.GetInteger(12);
                    bs.SkipBytes(es_info_length);
                    info_bytes -= 5 + es_info_length;
                }
                if (bs.BitOffset != 0) throw new DemuxException("Invalid PMT: program info length didn't match data");

                // ignoring CRC.
            }
            private void ValidateTable(BitSplitter bs)
            {
                int pointer = (int)bs.GetInteger(8);
                if (pointer != 0) throw new DemuxException("Non-zero pointers are not currently supported");

                int table_id = (int)bs.GetInteger(8);
                if (table_id != 0x02) throw new DemuxException("Wrong table ID for PMT");

                SectionSyntax = bs.GetFlag();
                if (!SectionSyntax) throw new DemuxException("Invalid PMT: incorrect section syntax");
                bool zero = bs.GetFlag();
                if (zero) throw new DemuxException("Invalid PMT: zero bit wasn't zero");
            }
 /// <summary>
 /// Decode the bizzare PTS format
 /// </summary>
 private void ReadPTS(BitSplitter bs)
 {
     int marker = (int)bs.GetInteger(4);
     if (marker != 2) throw new DemuxException("Invalid PES: PTS marker incorrect");
     long part_1 = (long)bs.GetInteger(3);
     bs.SkipBits(1);
     long part_2 = (long)bs.GetInteger(15);
     bs.SkipBits(1);
     long part_3 = (long)bs.GetInteger(15);
     bs.SkipBits(1);
     PTS = part_3 + (part_2 << 15) + (part_1 << 30);
 }
 private void ReadSpecialForm(BitSplitter bs)
 {
     byte[] data = bs.RemainingBytes();
     if (data.Length < PacketLength) throw new DemuxException("Invalid PES: packet shorter than described");
     MemoryStream ms = new MemoryStream(data, 0, PacketLength);
     FrameData = ms.ToArray();
 }
 private void ReadExtendedHeader(BitSplitter bs)
 {
     throw new NotImplementedException();
 }
            /// <summary>
            /// Reads the long list of flags in the default PES header.
            /// </summary>
            private void ReadFlags(BitSplitter bs)
            {
                ScrambleControl = (int)bs.GetInteger(2);
                HighPriority = bs.GetFlag();
                HasAlignment = bs.GetFlag();
                IsCopyright = bs.GetFlag();
                IsOriginal = bs.GetFlag();
                HasPTS = bs.GetFlag();
                HasDTS = bs.GetFlag();

                if (HasDTS && !HasPTS) throw new DemuxException("Invalid PES: DTS without PTS is not allowed");

                HasESCR = bs.GetFlag();
                HasEsRate = bs.GetFlag();
                UsesTrickMode = bs.GetFlag();
                MoreCopyright = bs.GetFlag();
                HasPesCRC = bs.GetFlag();
                HasPesExtension = bs.GetFlag();
            }
            /// <summary>
            /// Digest a PES payload into structured table.
            /// Does not handle split-payloads -- agregate payloads before calling
            /// </summary>
            public PES(byte[] RawPayload)
            {
                BitSplitter bs = new BitSplitter(RawPayload);

                int start_code = (int)bs.GetInteger(24);
                if (start_code != 1) throw new DemuxException("Invalid PES: start code prefix missing");

                PTS = DTS = -1;

                StreamId = (int)bs.GetInteger(8);
                PacketLength = (int)bs.GetInteger(16);

                // Both these methods set 'FrameData'
                if (SpecialStream(StreamId)) {
                    ReadSpecialForm(bs);
                } else {
                    DecodeElementaryStream(bs);
                }
            }
            private void DecodeElementaryStream(BitSplitter bs)
            {
                int marker = (int)bs.GetInteger(2);
                if (marker != 2) throw new DemuxException("Invalid PES: first marker missing");
                ReadFlags(bs);
                if (bs.BitOffset != 0) throw new DemuxException("Alignment problem in PES (internal)");
                HeaderLength = (int)bs.GetInteger(8);

                int head_start = bs.ByteOffset;
                if (HasPTS && HasDTS) {
                    ReadDTS_PTS(bs);
                } else if (HasPTS) {
                    ReadPTS(bs);
                }

                if (HasESCR) bs.SkipBytes(6); // not currently used.
                if (HasEsRate) bs.SkipBits(24); // not currently used.
                if (UsesTrickMode) bs.SkipBytes(1); // ignored
                if (MoreCopyright) bs.SkipBytes(1); // ignored
                if (HasPesCRC) bs.SkipBytes(2); // ignored

                if (HasPesExtension) ReadExtendedHeader(bs);

                // skip anything that's left
                int head_end = bs.ByteOffset;
                int to_skip = HeaderLength - (head_end - head_start);
                if (to_skip < 0) throw new DemuxException("Invalid PES: declared header length did not match measured length");
                bs.SkipBytes(to_skip);

                // Now, the remaining bytes are data and padding
                int data_length = PacketLength - (HeaderLength + to_skip) - 3; // no idea where the '3' is coming from...
                byte[] data = bs.RemainingBytes();
                if (data.Length < data_length)
                    throw new DemuxException("Invalid PES: packet shorter than described");

                /*if (data.Length != data_length)
                    throw new DemuxException("Possible issue: expect length != real length");*/
                MemoryStream ms = new MemoryStream(data, 0, data_length);
                FrameData = ms.ToArray();
            }
 private void ReadTransportHeader(BitSplitter bs)
 {
     bs.SkipToNextByte(); // Sync byte
     Error = bs.GetFlag();
     StartIndicator = bs.GetFlag();
     HighPriority = bs.GetFlag();
     PID = (int)bs.GetInteger(13);
     ScrambleCode = (int)bs.GetInteger(2);
     HasAdaptionField = bs.GetFlag();
     HasPayload = bs.GetFlag();
     Counter = (int)bs.GetInteger(4);
 }
            /// <summary>
            /// Digest a packet payload into structured table. Payload should be from the pointer field onward.
            /// Does not yet handle multi-packet tables
            /// </summary>
            public PAT(byte[] RawPayload)
            {
                Map = new Dictionary<int, int>();
                BitSplitter bs = new BitSplitter(RawPayload);
                ValidateTable(bs);

                bs.SkipBits(2); // reserved;
                SectionLength = (int)bs.GetInteger(12);
                TransportID = (int)bs.GetInteger(16);
                bs.SkipBits(2); // reserved
                Version = (int)bs.GetInteger(5);
                IsCurrent = bs.GetFlag();
                SectionNumber = (int)bs.GetInteger(8);
                LastSection = (int)bs.GetInteger(8);

                int bits_left = (SectionLength - 5) - 4; // remaining length in bytes, excluding CRC
                int items = bits_left / 4;
                for (int i = 0; i < items; i++) {
                    int prog = (int)bs.GetInteger(16);
                    bs.SkipBits(3);
                    int pid = (int)bs.GetInteger(13);
                    if (!Map.ContainsKey(prog))
                        Map.Add(prog, pid);
                    else throw new DemuxException("Invalid PAT: program number specified more than once (" + prog + ")");
                }

                // Ignoring CRC.
            }
 private void CheckPayloadType(BitSplitter bs)
 {
     if (payload.Length > 4) {
         if (payload[0] == 0 && payload[1] == 0 && payload[2] == 0x01) {
             PayloadIs_PES = true;
         }
     }
     if (!PayloadIs_PES && HasPayload && StartIndicator) {
         if (payload[0] != 0x00) throw new DemuxException("Non-zero pointer values are not yet supported!");
         TableId = payload[1];
     }
 }
            private void CheckAdaptionField(BitSplitter bs)
            {
                if (HasAdaptionField) {
                    int adaption_end = (int)bs.GetInteger(8);
                    adaption_end += bs.ByteOffset;
                    Discont = bs.GetFlag();
                    KeyFrame = bs.GetFlag();
                    ES_Prio = bs.GetFlag();
                    HasPCR = bs.GetFlag();
                    HasOPCR = bs.GetFlag();
                    HasSplice = bs.GetFlag();
                    PrivateFlag = bs.GetFlag();
                    AdapExtFlag = bs.GetFlag();
                    if (bs.BitOffset != 0) throw new Exception("bit align problem");

                    if (HasPCR) {
                        PCR = (long)bs.GetInteger(33);
                        bs.SkipBits(15); // throw away useless sync stuff.
                    }
                    if (HasOPCR) bs.SkipBits(48); // throw away useless "old" timecode
                    if (HasSplice) bs.SkipBits(8); // throw away splice counter
                    if (PrivateFlag) {
                        int priv_len = (int)bs.GetInteger(8);
                        bs.SkipBytes(priv_len); // skip private data
                    }
                    // ignore the rest of the adaption field (it's mostly to support stuff we ignore)
                    int skip_len = adaption_end - bs.ByteOffset;
                    bs.SkipBytes(skip_len);
                }
            }
            /// <summary>Digest data into structured packet</summary>
            public Packet(byte[] RawPacket)
            {
                if (RawPacket[0] != 0x47) throw new DemuxException("Sync byte missing");

                PCR = -1; TableId = -1; PayloadIs_PES = false;

                BitSplitter bs = new BitSplitter(RawPacket);
                ReadTransportHeader(bs);

                if (PID == 0x1FFF) return; // null packet

                CheckAdaptionField(bs);

                payload = bs.RemainingBytes();

                CheckPayloadType(bs);
            }
 /// <summary>
 /// Decode the bizzare PTS format
 /// </summary>
 private void ReadPTS(BitSplitter bs)
 {
     int marker = (int)bs.GetInteger(4);
     if (marker != 2) throw new DemuxException("Invalid PES: PTS marker incorrect");
     long part_1 = (long)bs.GetInteger(3);
     bs.SkipBits(1);
     long part_2 = (long)bs.GetInteger(15);
     bs.SkipBits(1);
     long part_3 = (long)bs.GetInteger(15);
     bs.SkipBits(1);
     unchecked { // allow overflow so we can catch it later:
         PTS = (UInt32)(part_3 + (part_2 << 15) + (part_1 << 30));
     }
 }
 private void ReadExtendedHeader(BitSplitter bs)
 {
     // not yet implemented
 }