Пример #1
0
 /// <summary>
 /// Decodes a PES packet from TS packets.
 /// </summary>
 /// <param name="packet">The TS packet to decode a PES packet from.</param>
 /// <returns>A PES packet if one is decoded, otherwise null.</returns>
 public Pes?DecodePesFromTsPacket(TsPacket packet)
 {
     // If the TS packet is the start of a PES, create a new elementary stream packet
     if (packet.PayloadUnitStartIndicator)
     {
         try
         {
             _elementaryStreamPacket = new Pes(packet);
         }
         catch
         {
             _elementaryStreamPacket = null;
         }
     }
     // If we have an elementary stream packet, add the packet and decode the PES if it is complete
     if (_elementaryStreamPacket != null)
     {
         _elementaryStreamPacket.Add(packet);
         if (_elementaryStreamPacket.HasAllBytes())
         {
             _elementaryStreamPacket.Decode();
             return(_elementaryStreamPacket);
         }
     }
     // Return null if no other response has been returned
     return(null);
 }
Пример #2
0
        public void AddPacket(TsPacket newPacket, long timestamp = -1)
        {
            try
            {
                if (newPacket.Pid != Pid)
                {
                    throw new InvalidOperationException("Cannot add TS Packet from different pid to a metric!");
                }

                if (newPacket.TransportErrorIndicator)
                {
                    TeiCount++;
                    _periodTeiCount++;
                    OnTeiDetected(newPacket);
                }
                else
                {
                    CheckCcContinuity(newPacket);
                    CheckPcr(newPacket, timestamp);
                    LastCc = newPacket.ContinuityCounter;
                }

                PacketCount++;
                _periodPacketCount++;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception generated within AddPacket method: " + ex.Message);
            }
        }
        public void AddPacket(TsPacket packet)
        {
            CheckPid(packet.Pid);

            // if this isn't a start of payload packet, just return and don't process until we have a start one
            if (!packet.PayloadUnitStartIndicator) return;

            InProgressTable = new ProgramAssociationTable { PointerField = packet.Payload[0] };

            if (InProgressTable.PointerField > packet.Payload.Length)
            {
                Debug.Assert(true, "Program Association Table has packet pointer outside the packet.");
            }

            var pos = 1 + InProgressTable.PointerField;

            InProgressTable.VersionNumber = (byte)((packet.Payload[pos + 5] & 0x3E) >> 1);
            
            //if (ProgramAssociationTable != null && ProgramAssociationTable.VersionNumber == InProgressTable.VersionNumber)
            //{
            //    InProgressTable = null;
            //    return;
            //}

            InProgressTable.TransportStreamId = (short)((packet.Payload[pos + 3] << 8) + packet.Payload[pos + 4]);

            InProgressTable.TableId = packet.Payload[pos];
            InProgressTable.SectionLength = (short)(((packet.Payload[pos + 1] & 0x3) << 8) + packet.Payload[pos + 2]);

            InProgressTable.CurrentNextIndicator = (packet.Payload[pos + 5] & 0x1) != 0;
            InProgressTable.SectionNumber = packet.Payload[pos + 6];
            InProgressTable.LastSectionNumber = packet.Payload[pos + 7];

            InProgressTable.ProgramNumbers = new short[((InProgressTable.SectionLength - 9) / 4) + 1];
            InProgressTable.Pids = new short[((InProgressTable.SectionLength - 9) / 4) + 1];

            var programStart = pos + 8;
            pos = programStart;

            for (var i = 0; i < (InProgressTable.SectionLength - 9) / 4; i++)
            {
                InProgressTable.ProgramNumbers[i] =
                    (short)
                         ((packet.Payload[programStart + (i * 4)] << 8) + packet.Payload[programStart + 1 + (i * 4)]);
                InProgressTable.Pids[i] =
                    (short)
                    (((packet.Payload[programStart + 2 + (i * 4)] & 0x1F) << 8) +
                        packet.Payload[programStart + 3 + (i * 4)]);

                pos += 4;
            }
            
//            InProgressTable.Crc = (uint)(((packet.Payload[pos]) << 24) + (packet.Payload[pos + 1] << 16) + (packet.Payload[pos + 2] << 8) + (packet.Payload[pos + 3]));
//            if (InProgressTable.Crc == ProgramAssociationTable.Crc) return;

            ProgramAssociationTable = InProgressTable;

            OnTableChangeDetected();
        }
Пример #4
0
        private void CheckCcContinuity(TsPacket newPacket)
        {
            try
            {
                if (PacketCount == 0)
                {
                    //fresh metric, first packet - so no possible error yet...
                    return;
                }

                if (newPacket.Pid == 0x1fff)
                {
                    return;
                }

                if (LastCc == newPacket.ContinuityCounter)
                {
                    //CC should only be expected to increase if data is present
                    //E.g. a pid used for PCR only may never increase CC
                    if (newPacket.ContainsPayload)
                    {
                        CcErrorCount++;
                        _periodCcErrorCount++;
                    }

                    return;
                }

                if (LastCc != 15)
                {
                    if (LastCc + 1 != newPacket.ContinuityCounter)
                    {
                        CcErrorCount++;
                        _periodCcErrorCount++;
                        OnDiscontinuityDetected(newPacket);
                        return;
                    }
                }

                if (LastCc != 15 || newPacket.ContinuityCounter == 0)
                {
                    return;
                }

                CcErrorCount++;
                _periodCcErrorCount++;
                OnDiscontinuityDetected(newPacket);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception generated within CheckCcContinuity method: " + ex.Message);
            }
        }
Пример #5
0
        private void OnDiscontinuityDetected(TsPacket tsPacket)
        {
            //reset reference PCR values used for drift check - set up reference values
            ResetReferenceTime(0);

            var handler = DiscontinuityDetected;

            if (handler == null)
            {
                return;
            }
            var args = new TransportStreamEventArgs {
                TsPid = tsPacket.Pid
            };

            handler(this, args);
        }
Пример #6
0
        private void OnTeiDetected(TsPacket tsPacket)
        {
            //reset reference PCR values used for drift check - set up reference values
            ResetReferenceTime(tsPacket.AdaptationField.Pcr);

            var handler = TeiDetected;

            if (handler == null)
            {
                return;
            }
            var args = new TransportStreamEventArgs {
                TsPid = tsPacket.Pid
            };

            handler(this, args);
        }
Пример #7
0
        private void OnTeiDetected(TsPacket tsPacket)
        {
            //reset reference PCR values used for drift check - set up reference values
            _referencePcr  = tsPacket.AdaptationField.Pcr;
            _referenceTime = (ulong)(DateTime.UtcNow.Ticks * 2.7);

            var handler = TeiDetected;

            if (handler == null)
            {
                return;
            }
            var args = new TransportStreamEventArgs {
                TsPid = tsPacket.Pid
            };

            handler(this, args);
        }
        protected void AddData(TsPacket packet)
        {
            CheckPid(packet.Pid);

            if (packet.PayloadUnitStartIndicator)
            {
                Data        = new byte[InProgressTable.SectionLength + 3];
                _tableBytes = 0;
            }

            if (InProgressTable.SectionLength + 3 - _tableBytes > packet.Payload.Length)
            {
                Buffer.BlockCopy(packet.Payload, 0, Data, _tableBytes, packet.Payload.Length);
                _tableBytes += (ushort)packet.Payload.Length;
            }
            else
            {
                Buffer.BlockCopy(packet.Payload, 0, Data, _tableBytes, InProgressTable.SectionLength + 3 - _tableBytes);
                _tableBytes += (ushort)(InProgressTable.SectionLength + 3 - _tableBytes);
            }
        }
        protected void AddData(TsPacket packet)
        {
            // CheckPid(packet.Pid);

            if (packet.PayloadUnitStartIndicator)
            {
                //Console.WriteLine("packet.PayloadUnitStartIndicator");

                Data        = new byte[_InProgress.SectionLength + 3];
                _tableBytes = 0;
            }

            if (Data == null)
            {
                //Console.WriteLine("packet.PayloadUnitStartIndicator");

                Data        = new byte[_InProgress.SectionLength + 3];
                _tableBytes = 0;
            }

            if ((_InProgress.SectionLength + 3 - _tableBytes) > packet.Payload.Length)
            {
                Buffer.BlockCopy(packet.Payload, 0, Data, _tableBytes, packet.Payload.Length);
                _tableBytes += (ushort)(packet.Payload.Length);
            }
            else
            {
                if ((_InProgress.SectionLength + 3 - _tableBytes) > 0)
                {
                    Buffer.BlockCopy(packet.Payload, 0, Data, _tableBytes, (_InProgress.SectionLength + 3 - _tableBytes));
                    _tableBytes += (ushort)(_InProgress.SectionLength + 3 - _tableBytes);
                }
                else
                {
                    Console.WriteLine("Error more than 0 bytes needs copying");
                }
            }
        }
Пример #10
0
        public void AddPacket(TsPacket packet)
        {
            CheckPid(packet.Pid);

            if (packet.PayloadUnitStartIndicator)
            {
                InProgressTable = new SpliceInfoTable {
                    Pid = packet.Pid, PointerField = packet.Payload[0]
                };

                if (InProgressTable.PointerField > packet.Payload.Length)
                {
                    Debug.Assert(true, "Splice Info Table has packet pointer outside the packet.");
                }

                var pos = 1 + InProgressTable.PointerField;

                // InProgressTable.VersionNumber = (byte)(packet.Payload[pos + 5] & 0x3E);

                InProgressTable.TableId = packet.Payload[pos];

                //TODO: Refactor with enum for well-known table IDs, and add option below as filter
                if (InProgressTable.TableId != 0xFC)
                {
                    InProgressTable = null;
                    return;
                }

                /* if (SpliceInfoTable?.VersionNumber != InProgressTable.VersionNumber)
                 * {
                 *   //if the version number of any section jumps, we need to refresh
                 *   _sectionsCompleted = new HashSet<int>();
                 *   NetworkInformationItems = new List<NetworkInformationItem>();
                 * }*/

                InProgressTable.SectionLength =
                    (short)(((packet.Payload[pos + 1] & 0x3) << 8) + packet.Payload[pos + 2]);
            }

            if (InProgressTable == null)
            {
                return;
            }

            /* if (_sectionsCompleted.Contains(InProgressTable.SectionNumber))
             * {
             *   InProgressTable = null;
             *   return;
             * }*/

            AddData(packet);

            if (!HasAllBytes())
            {
                return;
            }

            InProgressTable.ProtocolVersion     = packet.Payload[InProgressTable.PointerField + 4];
            InProgressTable.EncryptedPacket     = (packet.Payload[InProgressTable.PointerField + 5] & 0x80) == 0x80;
            InProgressTable.EncryptionAlgorithm = (byte)((packet.Payload[InProgressTable.PointerField + 5] >> 1) & 0x3F);
            InProgressTable.PTSAdjustment       = (ulong)(((((ulong)packet.Payload[InProgressTable.PointerField + 5] >> 7) & 0x1) << 32) + ((ulong)packet.Payload[InProgressTable.PointerField + 6] << 24) + ((ulong)packet.Payload[InProgressTable.PointerField + 7] << 16) + ((ulong)packet.Payload[InProgressTable.PointerField + 8] << 8) + ((ulong)packet.Payload[InProgressTable.PointerField + 9]));
            InProgressTable.CWIndex             = packet.Payload[InProgressTable.PointerField + 10];
            InProgressTable.Tier = (ushort)((packet.Payload[InProgressTable.PointerField + 11] << 4) + ((packet.Payload[InProgressTable.PointerField + 12] >> 4) & 0xF));
            InProgressTable.SpliceCommandLength = (ushort)(((packet.Payload[InProgressTable.PointerField + 12] & 0xF) << 8) + packet.Payload[InProgressTable.PointerField + 13]);
            InProgressTable.SpliceCommandType   = packet.Payload[InProgressTable.PointerField + 14];

            var startOfNextField = (ushort)(InProgressTable.PointerField + 15);

            if (InProgressTable.SpliceCommandType == 5)
            {
                var si = new SpliceInsert();
                si.SpliceEventId = (ulong)((packet.Payload[startOfNextField] << 24) + (packet.Payload[startOfNextField + 1] << 16) + (packet.Payload[startOfNextField + 2] << 8) + (packet.Payload[startOfNextField + 3]));
                si.SpliceEventCancelIndicator = (packet.Payload[startOfNextField + 4] & 0x80) == 0x80;

                if (!si.SpliceEventCancelIndicator)
                {
                    si.OutOfNetworkIndicator = si.SpliceEventCancelIndicator = (packet.Payload[startOfNextField + 5] & 0x80) == 0x80;
                    si.ProgramSpliceFlag     = si.SpliceEventCancelIndicator = (packet.Payload[startOfNextField + 5] & 0x40) == 0x40;
                    si.DurationFlag          = si.SpliceEventCancelIndicator = (packet.Payload[startOfNextField + 5] & 0x20) == 0x20;
                    si.SpliceImmediateFlag   = si.SpliceEventCancelIndicator = (packet.Payload[startOfNextField + 5] & 0x10) == 0x10;
                    if (si.ProgramSpliceFlag && !si.SpliceImmediateFlag)
                    {
                        var st = new SpliceTime()
                        {
                            TimeSpecifiedFlag = (packet.Payload[startOfNextField + 6] & 0x80) == 0x80
                        };
                        if (st.TimeSpecifiedFlag)
                        {
                            st.PTSTime = (ulong)((((((ulong)packet.Payload[startOfNextField + 6] >> 7) & 0x1) << 32)) + ((ulong)packet.Payload[startOfNextField + 7] << 24) + ((ulong)packet.Payload[startOfNextField + 8] << 16) + ((ulong)packet.Payload[startOfNextField + 9] << 8) + ((ulong)packet.Payload[startOfNextField + 10]));
                        }

                        si.SpliceTime = st;
                    }
                    else if (!si.ProgramSpliceFlag)
                    {
                        si.ComponentCount = packet.Payload[startOfNextField + 6];
                        startOfNextField += 7;
                        List <SpliceInsert.Component> components = new List <SpliceInsert.Component>();
                        for (int i = 0; i < si.ComponentCount; i++)
                        {
                            SpliceInsert.Component component = new SpliceInsert.Component()
                            {
                                ComponentTag = packet.Payload[startOfNextField]
                            };

                            if (!si.SpliceImmediateFlag)
                            {
                                var st = new SpliceTime()
                                {
                                    TimeSpecifiedFlag = (packet.Payload[startOfNextField + 1] & 0x80) == 0x80
                                };
                                if (st.TimeSpecifiedFlag)
                                {
                                    st.PTSTime        = (ulong)((((((ulong)packet.Payload[startOfNextField + 1] >> 7) & 0x1) << 32)) + ((ulong)packet.Payload[startOfNextField + 2] << 24) + ((ulong)packet.Payload[startOfNextField + 3] << 16) + ((ulong)packet.Payload[startOfNextField + 4] << 8) + ((ulong)packet.Payload[startOfNextField + 5]));
                                    startOfNextField += 5;
                                }
                                component.SpliceTime = st;
                                startOfNextField++;
                            }
                            components.Add(component);
                        }
                        si.Components = components;
                    }
                    if (si.DurationFlag)
                    {
                        var br = new BreakDuration()
                        {
                            AutoReturn = (packet.Payload[startOfNextField] & 0x80) == 0x80
                        };
                        br.Duration       = (ulong)((((((ulong)packet.Payload[startOfNextField] >> 7) & 0x1) << 32)) + ((ulong)packet.Payload[startOfNextField + 1] << 24) + ((ulong)packet.Payload[startOfNextField + 2] << 16) + ((ulong)packet.Payload[startOfNextField + 3] << 8) + ((ulong)packet.Payload[startOfNextField + 4]));
                        startOfNextField += 5;
                    }

                    si.UniqueProgramId = (ushort)((packet.Payload[startOfNextField] << 8) + packet.Payload[startOfNextField + 1]);
                    si.AvailNum        = packet.Payload[startOfNextField + 2];
                    si.AvailsExpected  = packet.Payload[startOfNextField + 3];
                }

                InProgressTable.Splice = si;
            }

            SpliceInfoTable = InProgressTable;

            OnTableChangeDetected();
        }
Пример #11
0
        public void AddPacket(TsPacket packet)
        {
            CheckPid(packet.Pid);

            if (packet.PayloadUnitStartIndicator)
            {
                InProgressTable = new ProgramMapTable {
                    Pid = packet.Pid, PointerField = packet.Payload[0]
                };

                if (InProgressTable.PointerField > packet.Payload.Length)
                {
                    Debug.Assert(true, "Program Map Table has packet pointer outside the packet.");
                }

                var pos = 1 + InProgressTable.PointerField;

                InProgressTable.VersionNumber = (byte)((packet.Payload[pos + 5] & 0x3E) >> 1);

                if (ProgramMapTable?.VersionNumber == InProgressTable.VersionNumber)
                {
                    InProgressTable = null;
                    return;
                }

                InProgressTable.TableId       = packet.Payload[pos];
                InProgressTable.SectionLength =
                    (short)(((packet.Payload[pos + 1] & 0x3) << 8) + packet.Payload[pos + 2]);
                InProgressTable.ProgramNumber        = (ushort)((packet.Payload[pos + 3] << 8) + packet.Payload[pos + 4]);
                InProgressTable.CurrentNextIndicator = (packet.Payload[pos + 5] & 0x1) != 0;
                InProgressTable.SectionNumber        = packet.Payload[pos + 6];
                InProgressTable.LastSectionNumber    = packet.Payload[pos + 7];
                InProgressTable.PcrPid            = (ushort)(((packet.Payload[pos + 8] & 0x1f) << 8) + packet.Payload[pos + 9]);
                InProgressTable.ProgramInfoLength =
                    (ushort)(((packet.Payload[pos + 10] & 0x3) << 8) + packet.Payload[pos + 11]);
            }

            if (InProgressTable == null)
            {
                return;
            }

            AddData(packet);

            if (!HasAllBytes())
            {
                return;
            }

            var startOfNextField = GetDescriptors(InProgressTable.ProgramInfoLength, InProgressTable.PointerField + 13);

            InProgressTable.EsStreams = ReadEsInfoElements(InProgressTable.SectionLength, startOfNextField);

            var crcPos = InProgressTable.PointerField + InProgressTable.SectionLength - 1; //+3 for start, -4 for len CRC = -1

            InProgressTable.Crc = (uint)((Data[crcPos] << 24) + (Data[crcPos + 1] << 16) +
                                         (Data[crcPos + 2] << 8) + Data[crcPos + 3]);

            ProgramMapTable = InProgressTable;

            OnTableChangeDetected();
        }
Пример #12
0
        public void AddPacket(TsPacket packet)
        {
            CheckPid(packet.Pid);

            if (packet.PayloadUnitStartIndicator)
            {
                InProgressTable = new EventInformationTable {
                    Pid = packet.Pid, PointerField = packet.Payload[0]
                };

                if (InProgressTable.PointerField > packet.Payload.Length)
                {
                    Debug.Assert(true, "Event Information Table has packet pointer outside the packet.");
                }

                var pos = 1 + InProgressTable.PointerField;

                InProgressTable.VersionNumber = (byte)(packet.Payload[pos + 5] & 0x3E);

                InProgressTable.TableId = packet.Payload[pos];

                //TODO: Refactor with enum for well-known table IDs, and add option below as filter
                if (InProgressTable.TableId != 0x4e)
                {
                    InProgressTable = null;
                    return;
                }

                if (EventInformationTable?.VersionNumber != InProgressTable.VersionNumber)
                {
                    //if the version number of any section jumps, we need to refresh
                    _sectionsCompleted    = new HashSet <int>();
                    EventInformationItems = new List <EventInformationItem>();
                }

                InProgressTable.SectionLength =
                    (short)(((packet.Payload[pos + 1] & 0x3) << 8) + packet.Payload[pos + 2]);

                InProgressTable.SericeId             = (ushort)((packet.Payload[pos + 3] << 8) + packet.Payload[pos + 4]);
                InProgressTable.CurrentNextIndicator = (packet.Payload[pos + 5] & 0x1) != 0;
                InProgressTable.SectionNumber        = packet.Payload[pos + 6];
                InProgressTable.LastSectionNumber    = packet.Payload[pos + 7];
                InProgressTable.TransportStreamId    = (ushort)((packet.Payload[pos + 8] << 8) + packet.Payload[pos + 9]);
                InProgressTable.OriginalNetworkId    = (ushort)((packet.Payload[pos + 10] << 8) + packet.Payload[pos + 11]);
            }

            if (InProgressTable == null)
            {
                return;
            }

            if (_sectionsCompleted.Contains(InProgressTable.SectionNumber))
            {
                InProgressTable = null;
                return;
            }

            AddData(packet);

            if (!HasAllBytes())
            {
                return;
            }



            InProgressTable.SegmentLastSectionNumber = (Data[InProgressTable.PointerField + 13]);
            InProgressTable.LastTableId = (Data[InProgressTable.PointerField + 14]);

            var startOfNextField = (ushort)(InProgressTable.PointerField + 15);

            var transportStreamLoopEnd = (ushort)(InProgressTable.SectionLength - 4);

            var items = new List <EventInformationItem>();

            while (startOfNextField < transportStreamLoopEnd)
            {
                var item = new EventInformationItem
                {
                    EventId               = (ushort)((Data[startOfNextField] << 8) + Data[startOfNextField + 1]),
                    StartTime             = (ulong)(((ulong)(Data[startOfNextField + 2]) << 32) + ((ulong)(Data[startOfNextField + 3]) << 24) + ((ulong)(Data[startOfNextField + 4]) << 16) + ((ulong)(Data[startOfNextField + 5]) << 8) + ((ulong)(Data[startOfNextField + 6]))),
                    Duration              = (uint)((Data[startOfNextField + 7] << 16) + (Data[startOfNextField + 8] << 8) + Data[startOfNextField + 9]),
                    RunningStatus         = (byte)((Data[startOfNextField + 10] >> 5) & 0x07),
                    FreeCAMode            = (bool)((Data[startOfNextField + 10] & 0x10) == 0x10),
                    DescriptorsLoopLength = (ushort)(((Data[startOfNextField + 10] & 0x3) << 8) + Data[startOfNextField + 11])
                };

                var descriptors = new List <Descriptor>();

                startOfNextField = (ushort)(startOfNextField + 12);
                var endOfDescriptors = (ushort)(startOfNextField + item.DescriptorsLoopLength);

                if (endOfDescriptors > Data.Length)
                {
                    throw new InvalidDataException("Descriptor data in Event Information is marked beyond available data");
                }

                while (startOfNextField < endOfDescriptors)
                {
                    var des = DescriptorFactory.DescriptorFromData(Data, startOfNextField);
                    descriptors.Add(des);
                    startOfNextField += (ushort)(des.DescriptorLength + 2);
                }
                item.Descriptors = descriptors;
                items.Add(item);
            }

            InProgressTable.Items = items;

            EventInformationItems.AddRange(items);

            if (InProgressTable.VersionNumber == EventInformationTable?.VersionNumber)
            {
                return;
            }

            EventInformationTable = InProgressTable;
            _sectionsCompleted.Add(InProgressTable.SectionNumber);

            OnTableChangeDetected();
        }
        public void AddPacket(TsPacket packet)
        {
            CheckPid(packet.Pid);

            if (packet.PayloadUnitStartIndicator)
            {
                InProgressTable = new NetworkInformationTable {
                    Pid = packet.Pid, PointerField = packet.Payload[0]
                };

                if (InProgressTable != null)
                {
                    if (InProgressTable.PointerField > packet.Payload.Length)
                    {
                        Debug.Assert(true, "Network Information Table has packet pointer outside the packet.");
                    }
                }

                var pos = 1 + InProgressTable.PointerField;

                InProgressTable.VersionNumber = (byte)(packet.Payload[pos + 5] & 0x3E);

                InProgressTable.TableId = packet.Payload[pos];

                //TODO: Refactor with enum for well-known table IDs, and add option below as filter
                if (InProgressTable.TableId != 0x40)
                {
                    InProgressTable = null;
                    return;
                }

                if ((NetworkInformationTable == null) || (NetworkInformationTable.VersionNumber != InProgressTable.VersionNumber))
                {
                    //if the version number of any section jumps, we need to refresh
                    _sectionsCompleted      = new HashSet <int>();
                    NetworkInformationItems = new List <NetworkInformationItem>();
                }

                InProgressTable.SectionLength =
                    (short)(((packet.Payload[pos + 1] & 0x3) << 8) + packet.Payload[pos + 2]);

                InProgressTable.TransportStreamId    = (ushort)((packet.Payload[pos + 3] << 8) + packet.Payload[pos + 4]);
                InProgressTable.CurrentNextIndicator = (packet.Payload[pos + 5] & 0x1) != 0;
                InProgressTable.SectionNumber        = packet.Payload[pos + 6];
                InProgressTable.LastSectionNumber    = packet.Payload[pos + 7];
            }

            if (InProgressTable == null)
            {
                return;
            }

            if (_sectionsCompleted.Contains(InProgressTable.SectionNumber))
            {
                InProgressTable = null;
                return;
            }

            AddData(packet);

            if (!HasAllBytes())
            {
                return;
            }

            InProgressTable.NetworkDescriptorsLength = (ushort)(((Data[InProgressTable.PointerField + 9] & 0x3) << 8) + Data[InProgressTable.PointerField + 10]);

            var startOfNextField = (ushort)(InProgressTable.PointerField + 11);

            List <Descriptor> descriptors = new List <Descriptor>();
            var endOfDescriptors          = InProgressTable.PointerField + 11 + InProgressTable.NetworkDescriptorsLength;

            if (endOfDescriptors > Data.Length)
            {
                throw new InvalidDataException("Descriptor data in Network Information is marked beyond available data");
            }

            while (startOfNextField < endOfDescriptors)
            {
                Descriptor des = DescriptorFactory.DescriptorFromData(Data, startOfNextField);
                descriptors.Add(des);
                startOfNextField += (byte)(des.DescriptorLength + 2);
            }
            InProgressTable.Descriptors = descriptors;

            InProgressTable.TransportStreamLoopLength = (ushort)(((Data[startOfNextField] & 0x3) << 8) + Data[startOfNextField + 1]);

            startOfNextField += 2;
            var transportStreamLoopEnd = (byte)(startOfNextField + InProgressTable.TransportStreamLoopLength);

            var items = new List <NetworkInformationItem>();

            while (startOfNextField < transportStreamLoopEnd)
            {
                var item = new NetworkInformationItem
                {
                    TransportStreamId          = (ushort)((Data[startOfNextField] << 8) + Data[startOfNextField + 1]),
                    OriginalNetworkId          = (ushort)((Data[startOfNextField + 2] << 8) + Data[startOfNextField + 3]),
                    ReservedFutureUse          = (byte)((Data[startOfNextField + 4] >> 4) & 0x0F),
                    TransportDescriptorsLength = (ushort)(((Data[startOfNextField + 4] & 0x3) << 8) + Data[startOfNextField + 5])
                };

                descriptors = new List <Descriptor>();

                startOfNextField = (byte)(startOfNextField + 6);
                endOfDescriptors = (byte)(startOfNextField + item.TransportDescriptorsLength);

                if (endOfDescriptors > Data.Length)
                {
                    throw new InvalidDataException("Descriptor data in Network Information Item is marked beyond available data");
                }

                while (startOfNextField < endOfDescriptors)
                {
                    Descriptor des = DescriptorFactory.DescriptorFromData(Data, startOfNextField);
                    descriptors.Add(des);
                    startOfNextField += (byte)(des.DescriptorLength + 2);
                }
                item.Descriptors = descriptors;
                items.Add(item);
            }

            InProgressTable.Items = items;

            NetworkInformationItems.AddRange(items);

            NetworkInformationTable = InProgressTable;
            _sectionsCompleted.Add(InProgressTable.SectionNumber);

            OnTableChangeDetected();
        }
Пример #14
0
        private void CheckPcr(TsPacket tsPacket, long timestamp)
        {
            if (!tsPacket.AdaptationFieldExists)
            {
                return;
            }
            if (!tsPacket.AdaptationField.PcrFlag)
            {
                return;
            }
            if (tsPacket.AdaptationField.FieldSize < 1)
            {
                return;
            }

            if (tsPacket.AdaptationField.DiscontinuityIndicator)
            {
                Debug.WriteLine("Adaptation field discont indicator");
                return;
            }

            if (_lastPcr != 0)
            {
                var latestDelta = tsPacket.AdaptationField.Pcr - _lastPcr;
                if (latestDelta > _periodLargestPcrDelta)
                {
                    _periodLargestPcrDelta = latestDelta;
                }

                var elapsedPcr = (long)(tsPacket.AdaptationField.Pcr - _referencePcr);

                //var elapsedClock = (long)((DateTime.UtcNow.Ticks * 2.7) - _referenceTime);
                //var elapsedClock = (timestamp * 27000) - _referenceTime;
                var elapsedClock = timestamp * _conversionFactor27Mhz - _referenceTime;

                var drift = (float)(elapsedClock - elapsedPcr) / 27000;

                if (drift > _periodLargestPcrDrift)
                {
                    _periodLargestPcrDrift = drift;
                }

                if (drift > PcrDriftLimit)
                {
                    _largePcrDriftCount++;
                }

                drift = (float)(elapsedPcr - elapsedClock) / 27000;
                if (drift > _periodLowestPcrDrift)
                {
                    _periodLowestPcrDrift = drift;
                }

                if (drift > PcrDriftLimit)
                {
                    _largePcrDriftCount++;
                }
            }
            else
            {
                //first PCR value - set up reference values

                //wait 10 seconds before sampling datum PCR time - otherwise everything drifts immediately as analyzer finishes launching tasks
                if (DateTime.UtcNow.Subtract(_startTime) < TimeSpan.FromSeconds(10))
                {
                    return;
                }
                ResetReferenceTime(tsPacket.AdaptationField.Pcr);
            }

            if (_largePcrDriftCount > 5)
            {
                //exceeded PCR drift ceiling - reset clocks
                ResetReferenceTime(tsPacket.AdaptationField.Pcr);
            }

            _lastPcr = tsPacket.AdaptationField.Pcr;
        }
        public void AddPacket(TsPacket packet)
        {
            //CheckPid(packet.Pid);

            Console.WriteLine("DsmccFactory packet");

            if (packet.PayloadUnitStartIndicator)
            {
                Console.WriteLine("####DsmccFactory PayloadUnitStartIndicator");

                _InProgress = new Dsmcc {
                    Pid = packet.Pid, PointerField = packet.Payload[0]
                };

                if (_InProgress.PointerField > packet.Payload.Length)
                {
                    Debug.Assert(true, "Splice Info Table has packet pointer outside the packet.");
                }

                var pos = 1 + _InProgress.PointerField;

                // InProgressTable.VersionNumber = (byte)(packet.Payload[pos + 5] & 0x3E);

                //_InProgress.TableId = packet.Payload[pos];


                //if (_InProgress.TableId != 0x70)
                //{
                //    _InProgress = null;
                //    return;
                //}

                /* if (SpliceInfoTable?.VersionNumber != InProgressTable.VersionNumber)
                 * {
                 *   //if the version number of any section jumps, we need to refresh
                 *   _sectionsCompleted = new HashSet<int>();
                 *   NetworkInformationItems = new List<NetworkInformationItem>();
                 * }*/

                //_InProgress.SectionLength =
                //    (short)(((packet.Payload[pos + 1] & 0x3) << 8) + packet.Payload[pos + 2]);
            }


            if (_InProgress == null)
            {
                return;
            }

            /* if (_sectionsCompleted.Contains(InProgressTable.SectionNumber))
             * {
             *   InProgressTable = null;
             *   return;
             * }*/

            AddData(packet);

            if (!HasAllBytes())
            {
                return;
            }


            //// DATE is 16 bits MJD (modified Julian Date)
            //ushort mjd = (ushort)((packet.Payload[4] << 8) + (packet.Payload[5]));
            //DateTime dtMjd = MjdToDateTime(mjd);

            //// TIME is 24 bits as 6 digits BCD
            //int Hour = ((byte)(packet.Payload[6] >> 4) * 10) + (byte)(packet.Payload[6] & 0x7);
            //int Min = ((byte)(packet.Payload[7] >> 4) * 10) + (byte)(packet.Payload[7] & 0x7);
            //int Sec = ((byte)(packet.Payload[8] >> 4) * 10) + (byte)(packet.Payload[8] & 0x7);

            //_InProgress.UtcTime = dtMjd.Add(new TimeSpan(Hour, Min, Sec));

            Active = _InProgress;

            //Console.WriteLine("TDT = " + Active.UtcTime.ToString());

            OnDsmccChanged();
        }
        public void AddPacket(TsPacket packet)
        {
            CheckPid(packet.Pid);

            if (packet.PayloadUnitStartIndicator)
            {
                InProgressTable = new ServiceDescriptionTable {
                    Pid = packet.Pid, PointerField = packet.Payload[0]
                };

                if (InProgressTable.PointerField > packet.Payload.Length)
                {
                    Debug.Assert(true, "Service Description Table has packet pointer outside the packet.");
                }

                var pos = 1 + InProgressTable.PointerField;

                InProgressTable.VersionNumber = (byte)(packet.Payload[pos + 5] & 0x3E);

                InProgressTable.TableId = packet.Payload[pos];

                //TODO: Refactor with enum for well-known table IDs, and add option below as filter
                //if (InProgressTable.TableId != 0x42)
                //{
                //    InProgressTable = null;
                //    return;
                //}

                if ((ServiceDescriptionTable == null) || (ServiceDescriptionTable.VersionNumber != InProgressTable.VersionNumber))
                {
                    //if the version number of any section jumps, we need to refresh
                    _sectionsCompleted      = new HashSet <int>();
                    ServiceDescriptionItems = new List <ServiceDescriptionItem>();
                }

                InProgressTable.SectionLength =
                    (short)(((packet.Payload[pos + 1] & 0x3) << 8) + packet.Payload[pos + 2]);

                InProgressTable.TransportStreamId    = (ushort)((packet.Payload[pos + 3] << 8) + packet.Payload[pos + 4]);
                InProgressTable.CurrentNextIndicator = (packet.Payload[pos + 5] & 0x1) != 0;
                InProgressTable.SectionNumber        = packet.Payload[pos + 6];
                InProgressTable.LastSectionNumber    = packet.Payload[pos + 7];
                InProgressTable.OriginalNetworkId    = (ushort)((packet.Payload[pos + 8] << 8) + packet.Payload[pos + 9]);
            }

            if (InProgressTable == null)
            {
                return;
            }

            if (_sectionsCompleted.Contains(InProgressTable.SectionNumber))
            {
                InProgressTable = null;
                return;
            }

            AddData(packet);

            if (!HasAllBytes())
            {
                return;
            }

            var startOfNextField = (ushort)(InProgressTable.PointerField + 12);

            var transportStreamLoopEnd = (ushort)(InProgressTable.SectionLength - 4);

            var items = new List <ServiceDescriptionItem>();

            while (startOfNextField < transportStreamLoopEnd)
            {
                var item = new ServiceDescriptionItem
                {
                    ServiceId               = (ushort)((Data[startOfNextField] << 8) + Data[startOfNextField + 1]),
                    EitScheduleFlag         = ((Data[startOfNextField + 2]) & 0x02) == 0x02,
                    EitPresentFollowingFlag = ((Data[startOfNextField + 2]) & 0x01) == 0x01,
                    RunningStatus           = (byte)((Data[startOfNextField + 3] >> 5) & 0x07),
                    FreeCaMode              = (Data[startOfNextField + 3] & 0x10) == 0x10,
                    DescriptorsLoopLength   =
                        (ushort)(((Data[startOfNextField + 3] & 0xf) << 8) + Data[startOfNextField + 4])
                };

                var descriptors = new List <Descriptor>();

                startOfNextField = (ushort)(startOfNextField + 5);
                var endOfDescriptors = (ushort)(startOfNextField + item.DescriptorsLoopLength);

                if (endOfDescriptors > Data.Length)
                {
                    throw new InvalidDataException("Descriptor data in Service Description is marked beyond available data");
                }

                while (startOfNextField < endOfDescriptors)
                {
                    var des = DescriptorFactory.DescriptorFromData(Data, startOfNextField);
                    descriptors.Add(des);
                    startOfNextField += (ushort)(des.DescriptorLength + 2);
                }
                item.Descriptors = descriptors;
                items.Add(item);
            }

            ServiceDescriptionItems.AddRange(items);

            ServiceDescriptionTable       = InProgressTable;
            ServiceDescriptionTable.Items = ServiceDescriptionItems;

            _sectionsCompleted.Add(InProgressTable.SectionNumber);

            InProgressTable.ItemsIncomplete = false;

            for (var i = 0; i <= InProgressTable.LastSectionNumber; i++)
            {
                if (!_sectionsCompleted.Contains(i))
                {
                    InProgressTable.ItemsIncomplete = true;
                }
            }

            OnTableChangeDetected();
        }
        public void AddPacket(TsPacket packet)
        {
            CheckPid(packet.Pid);

            if (packet.PayloadUnitStartIndicator)
            {
                InProgressTable = new TdtTable {
                    Pid = packet.Pid, PointerField = packet.Payload[0]
                };

                if (InProgressTable.PointerField > packet.Payload.Length)
                {
                    Debug.Assert(true, "Splice Info Table has packet pointer outside the packet.");
                }

                var pos = 1 + InProgressTable.PointerField;

                // InProgressTable.VersionNumber = (byte)(packet.Payload[pos + 5] & 0x3E);

                InProgressTable.TableId = packet.Payload[pos];


                if (InProgressTable.TableId != 0x70)
                {
                    InProgressTable = null;
                    return;
                }

                /* if (SpliceInfoTable?.VersionNumber != InProgressTable.VersionNumber)
                 * {
                 *   //if the version number of any section jumps, we need to refresh
                 *   _sectionsCompleted = new HashSet<int>();
                 *   NetworkInformationItems = new List<NetworkInformationItem>();
                 * }*/

                InProgressTable.SectionLength =
                    (short)(((packet.Payload[pos + 1] & 0x3) << 8) + packet.Payload[pos + 2]);
            }

            if (InProgressTable == null)
            {
                return;
            }

            /* if (_sectionsCompleted.Contains(InProgressTable.SectionNumber))
             * {
             *   InProgressTable = null;
             *   return;
             * }*/

            AddData(packet);

            if (!HasAllBytes())
            {
                return;
            }

            /*
             *          https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.03.01_60/en_300468v010301p.pdf
             *
             *          time_date_section(){
             *              table_id 8 uimsbf
             *              section_syntax_indicator 1 bslbf
             *              reserved_future_use 1 bslbf
             *              reserved 2 bslbf
             *              section_length 12 uimsbf
             *              UTC_time 40 bslbf
             *          }
             *
             *          table_id: See table 2.
             *          section_syntax_indicator: This is a one-bit indicator which shall be set to "0".
             *          section_length: This is a 12-bit field, the first two bits of which shall be "00". It specifies the number of bytes of the
             *              section, starting immediately following the section_length field and up to the end of the section.
             *          UTC_time: This 40-bit field contains the current time and date in UTC and MJD (see annex C). This field is coded as
             *              16 bits giving the 16 LSBs of MJD followed by 24 bits coded as 6 digits in 4-bit BCD.
             *              EXAMPLE: 93/10/13 12:45:00 is coded as "0xC079124500".]
             *
             *          40 bits == 5 bytes
             *
             *
             *          Console.WriteLine("TDT InProgressTable.TableId = " + InProgressTable.TableId.ToString("X"));
             *          Console.WriteLine("TDT InProgressTable.SectionLength = " + InProgressTable.SectionLength.ToString());
             */

            // DATE is 16 bits MJD (modified Julian Date)
            ushort   mjd   = (ushort)((packet.Payload[4] << 8) + (packet.Payload[5]));
            DateTime dtMjd = MjdToDateTime(mjd);

            // TIME is 24 bits as 6 digits BCD
            int Hour = ((byte)(packet.Payload[6] >> 4) * 10) + (byte)(packet.Payload[6] & 0x7);
            int Min  = ((byte)(packet.Payload[7] >> 4) * 10) + (byte)(packet.Payload[7] & 0x7);
            int Sec  = ((byte)(packet.Payload[8] >> 4) * 10) + (byte)(packet.Payload[8] & 0x7);

            InProgressTable.UtcTime = dtMjd.Add(new TimeSpan(Hour, Min, Sec));

            TdtTable = InProgressTable;

            Console.WriteLine("TDT = " + TdtTable.UtcTime.ToString());

            OnTableChangeDetected();
        }
Пример #18
0
        private void MuxPesPacketToTs(PesPacket pp, bool priority)
        {
            byte[] data = new byte[Constants.TS_SIZE];
            int    j    = 0;
            int    i    = 0;

            byte[] pes = pp.GetData();

            // take care of the first packet
            data[0] = Constants.SYNC_BYTE;
            data[1] = 0x40; // payload start
            data[2] = 0;
            if (pes.Length < Constants.TS_PAYLOAD_SIZE)
            {
                data[3] = 0x30; // adaptation and payload
                int stufLength = Constants.TS_PAYLOAD_SIZE - pes.Length - 1;
                data[4] = (byte)stufLength;
                i       = 5;
                if (stufLength > 0)
                {
                    data[i] = 0;
                    i++;
                    stufLength--;
                }
                for (; i < (6 + stufLength); i++)
                {
                    data[i] = 0xff;
                }
                for (; i < Constants.TS_SIZE; i++)
                {
                    data[i] = pes[j];
                    j++;
                }
            }
            else
            {
                data[3] = 0x10; // no adaptation, payload only
                for (i = 4; i < data.Length; i++)
                {
                    data[i] = pes[j];
                    j++;
                }
            }
            TsPacket ts = new TsPacket();

            ts.SetData(data, 0);
            ushort pid = pidMappings[pp.PID];

            ts.PID               = pid;
            ts.Priority          = priority;
            ts.ContinuityCounter = Continuities[pid];
            ts.IncrementContinuityCounter();
            Continuities[pid] = ts.ContinuityCounter;
            buffer.Add(ts);
            while (j < ((pes.Length / Constants.TS_PAYLOAD_SIZE) * Constants.TS_PAYLOAD_SIZE))
            {
                // take care of the other packets
                data[0] = Constants.SYNC_BYTE;
                data[1] = 0x00; // no payload start
                data[2] = 0;
                data[3] = 0x10; // no adaptation, payload only
                for (i = 4; i < data.Length; i++)
                {
                    data[i] = pes[j];
                    j++;
                }
                ts = new TsPacket();
                ts.SetData(data, 0);
                ts.PID               = pid;
                ts.Priority          = priority;
                ts.ContinuityCounter = Continuities[pid];
                ts.IncrementContinuityCounter();
                Continuities[pid] = ts.ContinuityCounter;
                buffer.Add(ts);
            }
            // take care of the last packet
            if (j < pes.Length)
            {
                data[0] = Constants.SYNC_BYTE;
                data[1] = 0x00; // no payload start
                data[2] = 0;
                data[3] = 0x30; // adaptation and payload
                int stufLength = Constants.TS_PAYLOAD_SIZE - (pes.Length - j) - 1;
                data[4] = (byte)stufLength;
                i       = 5;
                if (stufLength > 0)
                {
                    data[i] = 0;
                    i++;
                    stufLength--;
                    for (; i < (6 + stufLength); i++)
                    {
                        data[i] = 0xff;
                    }
                }
                for (; i < Constants.TS_SIZE; i++)
                {
                    data[i] = pes[j];
                    j++;
                }
                ts = new TsPacket();
                ts.SetData(data, 0);
                ts.PID               = pid;
                ts.Priority          = priority;
                ts.ContinuityCounter = Continuities[pid];
                ts.IncrementContinuityCounter();
                Continuities[pid] = ts.ContinuityCounter;
                buffer.Add(ts);
            }
        }
Пример #19
0
        /// <summary>
        /// Returns TsPackets for any input data. If data ends with incomplete packet, this is stored and prepended to next call.
        /// If data stream is restarted, prior buffer will be skipped as sync will not be acknowledged - but any restarts should being with first byte as sync to avoid possible merging with prior data if lengths coincide.
        /// </summary>
        /// <remarks>
        /// This has been copied from the parent TsPacketFactory class, but modified to return packets with error indicators
        /// if the adaptation field size exceeds the payload and to ignore timestamps (and their errors).
        /// </remarks>
        /// <param name="data">Aligned or unaligned data buffer containing TS packets. Aligned is more efficient if possible.</param>
        /// <param name="dataSize">Optional length parameter to limit amount of data read from referenced array.</param>
        /// <param name="retainPayload">Optional parameter to trigger any resulting TS payload to be copied into the returned structure</param>
        /// <param name="preserveSourceData">Optional parameter to trigger complete copy of source data for TS packet to be held in array for quick access</param>
        /// <returns>Complete TS packets from this data and any prior partial data rolled over.</returns>
        public new TsPacket[]? GetTsPacketsFromData(byte[] data, int dataSize = 0, bool retainPayload = true, bool preserveSourceData = false)
        {
            try
            {
                if (dataSize == 0)
                {
                    dataSize = data.Length;
                }

                if (_residualData != null)
                {
                    byte[] tempArray = new byte[dataSize];
                    Buffer.BlockCopy(data, 0, tempArray, 0, dataSize);
                    data = new byte[_residualData.Length + tempArray.Length];
                    Buffer.BlockCopy(_residualData, 0, data, 0, _residualData.Length);
                    Buffer.BlockCopy(tempArray, 0, data, _residualData.Length, tempArray.Length);
                    dataSize = data.Length;
                }

                int        maxPackets = (dataSize) / TsPacketFixedSize;
                TsPacket[] tsPackets  = new TsPacket[maxPackets];

                int packetCounter = 0;

                int start = FindSync(data, 0, TsPacketFixedSize);

                while (start >= 0 && ((dataSize - start) >= TsPacketFixedSize))
                {
                    TsPacket tsPacket = new TsPacket
                    {
                        SyncByte = data[start],
                        Pid      = (short)(((data[start + 1] & 0x1F) << 8) + (data[start + 2])),
                        TransportErrorIndicator   = (data[start + 1] & 0x80) != 0,
                        PayloadUnitStartIndicator = (data[start + 1] & 0x40) != 0,
                        TransportPriority         = (data[start + 1] & 0x20) != 0,
                        ScramblingControl         = (short)(data[start + 3] >> 6),
                        AdaptationFieldExists     = (data[start + 3] & 0x20) != 0,
                        ContainsPayload           = (data[start + 3] & 0x10) != 0,
                        ContinuityCounter         = (short)(data[start + 3] & 0xF),
                        SourceBufferIndex         = start
                    };

                    if (preserveSourceData)
                    {
                        tsPacket.SourceData = new byte[TsPacketFixedSize];
                        Buffer.BlockCopy(data, start, tsPacket.SourceData, 0, TsPacketFixedSize);
                    }

                    // Skip packets with error indicators or on the null PID
                    if (!tsPacket.TransportErrorIndicator && (tsPacket.Pid != (short)PidType.NullPid))
                    {
                        var payloadOffs = start + 4;
                        var payloadSize = TsPacketFixedSize - 4;

                        if (tsPacket.AdaptationFieldExists)
                        {
                            tsPacket.AdaptationField = new AdaptationField()
                            {
                                FieldSize = data[start + 4],
                                DiscontinuityIndicator            = (data[start + 5] & 0x80) != 0,
                                RandomAccessIndicator             = (data[start + 5] & 0x40) != 0,
                                ElementaryStreamPriorityIndicator = (data[start + 5] & 0x20) != 0,
                                PcrFlag                      = (data[start + 5] & 0x10) != 0,
                                OpcrFlag                     = (data[start + 5] & 0x8) != 0,
                                SplicingPointFlag            = (data[start + 5] & 0x4) != 0,
                                TransportPrivateDataFlag     = (data[start + 5] & 0x2) != 0,
                                AdaptationFieldExtensionFlag = (data[start + 5] & 0x1) != 0
                            };

                            if (tsPacket.AdaptationField.FieldSize >= payloadSize)
                            {
                                tsPacket.TransportErrorIndicator = true;
                                tsPackets[packetCounter++]       = tsPacket;
                                start += TsPacketFixedSize;
                                continue;
                            }

                            if (tsPacket.AdaptationField.PcrFlag && tsPacket.AdaptationField.FieldSize > 0)
                            {
                                //Packet has PCR
                                tsPacket.AdaptationField.Pcr = (((uint)(data[start + 6]) << 24) +
                                                                ((uint)(data[start + 7] << 16)) +
                                                                ((uint)(data[start + 8] << 8)) + (data[start + 9]));

                                tsPacket.AdaptationField.Pcr <<= 1;

                                if ((data[start + 10] & 0x80) == 1)
                                {
                                    tsPacket.AdaptationField.Pcr |= 1;
                                }

                                tsPacket.AdaptationField.Pcr *= 300;
                                uint iLow = (uint)((data[start + 10] & 1) << 8) + data[start + 11];
                                tsPacket.AdaptationField.Pcr += iLow;

                                if (_lastPcr == 0)
                                {
                                    _lastPcr = tsPacket.AdaptationField.Pcr;
                                }
                            }

                            payloadSize -= tsPacket.AdaptationField.FieldSize;
                            payloadOffs += tsPacket.AdaptationField.FieldSize;
                        }

                        if (tsPacket.ContainsPayload && tsPacket.PayloadUnitStartIndicator)
                        {
                            if (payloadOffs > (dataSize - 2) || data[payloadOffs] != 0 || data[payloadOffs + 1] != 0 || data[payloadOffs + 2] != 1)
                            {
                                // Do nothing
                            }
                            else
                            {
                                tsPacket.PesHeader = new PesHdr
                                {
                                    StartCode    = (uint)((data[payloadOffs] << 16) + (data[payloadOffs + 1] << 8) + data[payloadOffs + 2]),
                                    StreamId     = data[payloadOffs + 3],
                                    PacketLength = (ushort)((data[payloadOffs + 4] << 8) + data[payloadOffs + 5]),
                                    Pts          = -1,
                                    Dts          = -1
                                };

                                tsPacket.PesHeader.HeaderLength = (byte)tsPacket.PesHeader.PacketLength;

                                byte stmrId = tsPacket.PesHeader.StreamId; //just copying to small name to make code less huge and slightly faster...

                                if ((stmrId != (uint)PesStreamTypes.ProgramStreamMap) &&
                                    (stmrId != (uint)PesStreamTypes.PaddingStream) &&
                                    (stmrId != (uint)PesStreamTypes.PrivateStream2) &&
                                    (stmrId != (uint)PesStreamTypes.ECMStream) &&
                                    (stmrId != (uint)PesStreamTypes.EMMStream) &&
                                    (stmrId != (uint)PesStreamTypes.ProgramStreamDirectory) &&
                                    (stmrId != (uint)PesStreamTypes.DSMCCStream) &&
                                    (stmrId != (uint)PesStreamTypes.H2221TypeEStream))
                                {
                                    tsPacket.PesHeader.HeaderLength = (byte)(9 + data[payloadOffs + 8]);
                                }

                                tsPacket.PesHeader.Payload = new byte[tsPacket.PesHeader.HeaderLength];
                                Buffer.BlockCopy(data, payloadOffs, tsPacket.PesHeader.Payload, 0, tsPacket.PesHeader.HeaderLength);

                                payloadOffs += tsPacket.PesHeader.HeaderLength;
                                payloadSize -= tsPacket.PesHeader.HeaderLength;
                            }
                        }

                        if (payloadSize > 1 && retainPayload)
                        {
                            tsPacket.Payload = new byte[payloadSize];
                            Buffer.BlockCopy(data, payloadOffs, tsPacket.Payload, 0, payloadSize);
                        }
                    }

                    tsPackets[packetCounter++] = tsPacket;

                    start += TsPacketFixedSize;

                    if (start >= dataSize)
                    {
                        break;
                    }
                    if (data[start] != SyncByte)
                    {
                        break;  // but this is strange!
                    }
                }

                if ((start + TsPacketFixedSize) != dataSize)
                {
                    //we have 'residual' data to carry over to next call
                    _residualData = new byte[dataSize - start];
                    Buffer.BlockCopy(data, start, _residualData, 0, dataSize - start);
                }

                return(tsPackets);
            }
            catch
            {
                return(null);
            }
        }