TS Packet Checker (1 Viewer)

alexi

Portal Member
January 21, 2010
35
0
Home Country
Germany Germany
sagmal schreibst lieber in visual basic kann das sein ?

grr nein. Pascal / Lazarus, das erleichtert die Migration von Windows auf Linux und irgendwann mal Raspi.

Ich habe einfach den Text aus dem ISO-Standard rauskopiert.
 
Last edited:

KayDiefenthal

MP Donator
  • Premium Supporter
  • July 18, 2006
    1,176
    92
    46
    Germany - Bonn
    Home Country
    Germany Germany
    ok sah halt ein wenig aus wie visual basic

    Code:
    private void RtpListenerThread()
            {
                try
                {
                    try
                    {                   
                       
                        while (!_rtpListenerThreadStopEvent.WaitOne(1))
                        {
                            byte[] receivedbytes = _udpClient.Receive(ref _serverEndPoint);
                            //Decode the RTPPacket
                            RtpPacket packet = RtpPacket.Decode(receivedbytes);
                            // Check  if RTPPacket has Payload and the PayloadType is M2TS
                            if((packet.HasPayload)&&(packet.PayloadType==33))
                            {
                                //Callculate how many TsPackets are in the RTPPacket Payload
                                double numberOfTsPackets = (packet.Payload.Length / 188.0) - 1.0;
                                for (double j = 0.0; j <= numberOfTsPackets; j++)
                                {
                                    // Create an Byte[] where we can store the TransportStream Packet Bytes
                                    byte[] tspacketBuffer = (byte[])Array.CreateInstance(typeof(byte), 188);
                                    Array.Copy(packet.Payload, (int)Math.Round((double)((j * 188))), tspacketBuffer, 0, 188);
                                    // Read the TSPacket Header
                                    var header = TsHeader.Decode(tspacketBuffer);
                                    // Check that the Header is not Null and that tere is no Transport Error
                                    if((header != null) && (!header.TransportErrorIndicator))
                                    {
                                        _filestream.Write(tspacketBuffer, 0, tspacketBuffer.Length);
                                        _filestream.Flush();
                                    }
                                }                           
                            }                       
                        }
                    }
                    finally
                    {
                        switch (_transmissionMode)
                        {
                            case TransmissionMode.Multicast:
                                _udpClient.DropMulticastGroup(_multicastEndPoint.Address);
                                _udpClient.Close();
                                break;
                            case TransmissionMode.Unicast:
                                _udpClient.Close();
                                break;
                        }                   
                    }
                }
                catch (ThreadAbortException)
                {
                }
                catch (Exception ex)
                {
                    Logger.Error(string.Format("SAT>IP : RTP listener thread exception"), ex);
                    return;
                }
                Logger.Warn("SAT>IP : RTP listener thread stopping");
            }

    denke damit sollten so manche TsPackete ausgefiltert werden bevor sie im file landen
     

    KayDiefenthal

    MP Donator
  • Premium Supporter
  • July 18, 2006
    1,176
    92
    46
    Germany - Bonn
    Home Country
    Germany Germany
    Ergebnis DemuxToy 1.2.4:
    in diesem 58 s langen TS-File sind fast 3000 Continuity_count_error(s). Das ist sehr viel.

    View attachment 202182
    nur NIT und TDT/TOT ist ohne Fehler, ist aber nur selten im TS.

    View attachment 202183

    TSPacketChecker zeigt mehr als 19000 cc errors an:
    dropped packets=1 cc errors=19225 pcr holes=0 pts holes=93 total payloadstart errors=0

    View attachment 202184

    SDT (32 services) könnte auch ein Bug sein. Ich zähle nur 19, dabei #770 doppelt und mit unterscheidlichem name. Könnte aber auch an den vielen Fehlern im File liegen.

    Was für ein Gerät (Receiver / TV / PC) / Software hat Du zur Aufnahme von diesem ts verwendet?
    Du solltest TS-Files mit wenigen, am besten 0 Countinity errors verwenden.
    Das sieht bei TSPacketChecker so aus:
    dropped packets=0 cc errors=0 pcr holes=0 pts holes=0 total payloadstart errors=0
    Kann sein dass TSPacketChecker Probleme hat, wenn Errors im File sind.

    und noch ein eventueller bug:
    TSPacketChecker zeigt bei anderen .ts-Files cc errors > 0 an wo DemuxToy 1.2.4 keine Continuity_count_error(s) findet.
    ISO/IEC 13818-1:
    "The continuity_counter shall not be incremented when the adaptation_field_control of the packet equals '00' or '10'."
    scheint in TSPacketChecker nicht implementiert zu sein.
    ich habe in PacketChecks.cs gefunden:

    Code:
        private bool CheckContinuityCounter(byte cc, ref PidInfo pi)
        {
          bool isOk = true;
          if (pi.continuityCounter != 0xFF)
          {
            byte expected = (byte)(pi.continuityCounter + 1);
            if (expected == 16) expected = 0;
            if (cc != expected)
            {
              totalCCErrors++;
              isOk = false;
            }
          }
          pi.continuityCounter = cc;
          return isOk;
        }

    ich vermisse:

    Code:
    if ( not adaptation_field_control of the packet equals '00' or '10')
          {
            byte expected = (byte)(pi.continuityCounter + 1);
          }

    adaptation_field_control of the packet ist vielleicht in AdaptionControl in TsHeader.cs enthalten.

    hmm werden hier nicht nur pmts auf continuityCounter gecheckt ?
     

    alexi

    Portal Member
    January 21, 2010
    35
    0
    Home Country
    Germany Germany
    hmm werden hier nicht nur pmts auf continuityCounter gecheckt ?

    mein Programm checkt alle PIDs im TS. Ergebnis (alles dezimal) ähnlich wie bei DemuxToy:

    Code:
    PID:    0  Continuity Errors         4
    PID:    1  Continuity Errors         4
    PID:   17  Continuity Errors        11
    PID:   18  Continuity Errors       146
    PID:  110  Continuity Errors         3
    PID:  111  Continuity Errors       375
    PID:  112  Continuity Errors        69
    PID:  113  Continuity Errors        54
    PID:  114  Continuity Errors        77
    PID:  120  Continuity Errors         5
    PID:  130  Continuity Errors         5
    PID:  140  Continuity Errors         4
    PID:  141  Continuity Errors       358
    PID:  142  Continuity Errors        81
    PID:  143  Continuity Errors        55
    PID:  144  Continuity Errors        67
    PID:  150  Continuity Errors         5
    PID:  151  Continuity Errors       375
    PID:  152  Continuity Errors        52
    PID:  153  Continuity Errors        55
    PID:  154  Continuity Errors        67
    PID:  155  Continuity Errors        56
    PID:  160  Continuity Errors         4
    PID:  161  Continuity Errors       369
    PID:  162  Continuity Errors        71
    PID:  163  Continuity Errors        49
    PID:  164  Continuity Errors        75
    PID:  180  Continuity Errors         3
    PID:  270  Continuity Errors         5
    PID:  276  Continuity Errors         3
    PID:  470  Continuity Errors         9
    PID: 1170  Continuity Errors         7
    PID: 1176  Continuity Errors         4
    PID: 1276  Continuity Errors         4
    PID: 1470  Continuity Errors         5
    PID: 2075  Continuity Errors         4
    PID: 2076  Continuity Errors         6
    PID: 2077  Continuity Errors         8
    PID: 2078  Continuity Errors         5
    PID: 2079  Continuity Errors         5
    PID: 2080  Continuity Errors         6
    PID: 2081  Continuity Errors         5
    PID: 2082  Continuity Errors         8
    PID: 2083  Continuity Errors         5
    PID: 2171  Continuity Errors        66
    PID: 2178  Continuity Errors         7
    PID: 2270  Continuity Errors         5
    PID: 2370  Continuity Errors         4
    PID: 2376  Continuity Errors         3
    PID: 2970  Continuity Errors         5
    PID: 3070  Continuity Errors         6
    PID: 3085  Continuity Errors       125
    PID: 3086  Continuity Errors        27
    PID: 3087  Continuity Errors        26
    PID: 3088  Continuity Errors         4
    PID: 3089  Continuity Errors         4
    PID: 3090  Continuity Errors         5
    PID: 3091  Continuity Errors         4
    PID: 3092  Continuity Errors         2
    PID: 3093  Continuity Errors         5
    PID: 3094  Continuity Errors         4
    PID: 3095  Continuity Errors         3
    PID: 3096  Continuity Errors         2
    PID: 3097  Continuity Errors         2
    PID: 3098  Continuity Errors         3
    PID: 3100  Continuity Errors         4
    PID: 3101  Continuity Errors         5
    PID: 3102  Continuity Errors         4
    PID: 3103  Continuity Errors         2
    PID: 5171  Continuity Errors        78
    PID: 5670  Continuity Errors         6
     

    KayDiefenthal

    MP Donator
  • Premium Supporter
  • July 18, 2006
    1,176
    92
    46
    Germany - Bonn
    Home Country
    Germany Germany
    ok cc werden doch für alle Pids gesetzt hab die stelle gefunden

    zu meinem splittet sections habe ich jetzt auch einen weg ;-)
    der vollständigkeits halber werde ich es auch hier mal posten aber für den TsPacketchecker ist es glaube ich nichts solange der nur file basierend ist
    im live input aber schon
    benötigt wird in den PrivateFields
    Code:
    private HashSet<int> _sectionsCompleted = new HashSet<int>();

    dann zur Methode OnNewSection(TsSection section)

    wenn man da relativ am anfang sowas wie

    Code:
    if (_sectionsCompleted.Count == section.last_section_number+1)
    {
                    IsReady = true;
                    Console.Write("Got have all Sections" );
                    return;
    }
    
    if (_sectionsCompleted.Contains(section.section_number))
    {
                    Console.Write("Hashset Contains an SectionNumber with Number :" + section.section_number.ToString());              
                    return;
    }
    einbaut wird gecheckt a ob der Count == LastSectionNumber ist oder ob die Section schon bekannt ist
    beides melden return denn warum soll man alles doppelt lesen owohl es schon vorhanden ist
    wenn es natürlich nicht vorhanden war sollte es gelesen werden und nach dem lesen
    es in _sectionsCompleted hinzufügen
    Code:
    _sectionsCompleted.Add(section.section_number);
    Console.Write("Add SectionNumber :" + section.section_number.ToString()+" to Hashset");
    dann brauchte ich noch eine Methode Reset()
    Code:
    internal void Reset()
    {
                if (_servicesReceived != null)
                    _servicesReceived.Clear();
    }
    dann man sonst gefahr läuft das keine neuen einträge hinzugefügt werden sollte aber im file modus nicht relevant sein
    so das klappt sehr gut mit der SDT Problematik und sollte auch auf alle anderen umsetzbar sein
     
    Last edited:

    alexi

    Portal Member
    January 21, 2010
    35
    0
    Home Country
    Germany Germany
    in c# sehe das in etwa so aus

    Code:
    if ((!adaptation_field_control.Equals(00) || (!adaptation_field_control.Equals(10))
                {
                    byte expected = (byte)(pi.continuityCounter + 1);
                }

    so ähnlich (PacketChecks.cs):
    Code:
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace TsPacketChecker
    {
      class PacketChecker
      {
        private long droppedPackets;
        private long totalCCErrors;
        private long totalPcrErrors;
        private long totalPtsErrors;
        private long totalPayloadStartErrors;
        private double diffAllowed;
        private SortedDictionary<ushort, PidInfo> pids = new SortedDictionary<ushort, PidInfo>();
    
        #region Existence checks
        private bool PacketContainsPcr(TsHeader header, byte[] tsPacket)
        {
          return (header.HasAdaptionField && (tsPacket[5] & 0x10) == 0x10);
        }
        private ulong PacketContainsPtsDts(TsHeader header, byte[] tsPacket, ref PidInfo pi)
        {
          if (!header.PayloadUnitStart)
            return 0;
          if (header.PayLoadStart > 185 && header.HasPayload)
          {
            totalPayloadStartErrors++;
            pi.payloadStartErrorTexts.Add(" payloadStart=" + header.PayLoadStart.ToString() + " HasAdaption=" + header.HasAdaptionField.ToString() + " HasPayload=" + header.HasPayload.ToString() + " AdaptionFieldSize=" + tsPacket[4].ToString());
            return 0;
          }
          if (!header.HasPayload)
            return 0;
          return header.PayLoadStart;
        }
        #endregion
    
        #region Continuity checks
        private bool CheckContinuityCounter(byte tsPacket3, ref PidInfo pi)
        {
          bool isOk = true;
          byte cc = (byte)(tsPacket3 & 0xF);
          if (pi.continuityCounter != 0xFF)
          {
            byte afc = (byte)((tsPacket3 >> 4) & 0x3);
            byte expected;
    // ISO/IEC 13818-1: "The continuity_counter shall not be incremented when the adaptation_field_control of the packet equals '00' or '10'." (binary)
            if ((afc.Equals(0)) || (afc.Equals(2))) expected = (byte)(pi.continuityCounter);
            else expected = (byte)(pi.continuityCounter + 1);
            if (expected == 16) expected = 0;
            if (cc != expected)
            {
              totalCCErrors++;
              isOk = false;
            }
          }
          pi.continuityCounter = cc;
          return isOk;
        }
        private void CheckPcr(TsHeader header, byte[] tsPacket, ref PidInfo pi)
        {
          if (!pi.shouldCheck) return;
          if (!PacketContainsPcr(header, tsPacket)) return;
          Pcr pcr = new Pcr(tsPacket);
          if (pi.lastPcr.isValid)
          {
            TimeSpan diff = pcr.ToDateTime() - pi.lastPcr.ToDateTime();
            if (diff.TotalSeconds > diffAllowed)
            {
              pi.pcrErrorTexts.Add("last pcr: " + pi.lastPcr.ToDateTime().ToString("HH:MM:ss") + " current pcr: " + pcr.ToDateTime().ToString("HH:MM:ss"));
              totalPcrErrors++;
            }
          }
          pi.lastPcr = pcr;
        }
        private void CheckPtsDts(TsHeader header, byte[] tsPacket, ref PidInfo pi)
        {
          if (!pi.shouldCheck) return;
          ulong offset = PacketContainsPtsDts(header, tsPacket, ref pi);
          if (offset == 0) return;
          Pcr pts; Pcr dts;
          PcrUtils.DecodePtsDts(tsPacket, offset, out pts, out dts);
          if (pi.lastPts.isValid)
          {
            TimeSpan diff = pts.ToDateTime() - pi.lastPts.ToDateTime();
            if (diff.TotalSeconds > diffAllowed)
            {
              pi.ptsErrorTexts.Add("last pts: " + pi.lastPts.ToDateTime().ToString("HH:MM:ss") + " current pts: " + pts.ToDateTime().ToString("HH:MM:ss"));
              totalPtsErrors++;
            }
          }
          pi.lastPts = pts;
        }
        #endregion
    
        #region Constructor
        public PacketChecker(double maxAllowedPcrDiff)
        {
          droppedPackets = 0;
          totalCCErrors = 0;
          totalPcrErrors = 0;
          totalPtsErrors = 0;
          totalPayloadStartErrors = 0;
          diffAllowed = maxAllowedPcrDiff;
          pids = new SortedDictionary<ushort, PidInfo>();
        }
        #endregion
    
        #region Public methods
        public void AddPidsToCheck(List<ushort> streamPids)
        {
          foreach (ushort pid in streamPids)
          {
            if (pids.ContainsKey(pid))
              pids[pid].shouldCheck = true;
          }
        }
        public void ProcessPacket(byte[] tsPacket,TsHeader header)
        {
          if (header.TransportError)
          {
            droppedPackets++;
            return;
          }
          if (!pids.ContainsKey(header.Pid))
            pids.Add(header.Pid, new PidInfo());
    
          PidInfo pi = pids[header.Pid];
          CheckContinuityCounter((byte)(tsPacket[3]), ref pi);
          if (header.Pid > 0x1f) // don't check pids which contain SI information
          {
            CheckPcr(header, tsPacket, ref pi);
            CheckPtsDts(header, tsPacket, ref pi);
          }
          pids[header.Pid] = pi;
        }
    
        public string GetStatistics()
        {
          return "dropped packets=" + droppedPackets.ToString()+" cc errors="+totalCCErrors.ToString()+" pcr holes="+totalPcrErrors.ToString()+" pts holes="+totalPtsErrors.ToString()+" total payloadstart errors="+totalPayloadStartErrors.ToString();
        }
        public string GetErrorDetails()
        {
          string log = "";
          foreach (ushort pid in pids.Keys)
          {
            if (pids[pid].HasErrors())
            {
              PidInfo pi = pids[pid];
              log+="Pid 0x" + pid.ToString("x")+Environment.NewLine;
              if (pi.pcrErrorTexts.Count > 0)
              {
                log+="  - pcr errors=" + pi.pcrErrorTexts.Count.ToString()+Environment.NewLine;
                foreach (string s in pi.pcrErrorTexts)
                  log="        ->" + s+Environment.NewLine;
              }
              if (pi.ptsErrorTexts.Count > 0)
              {
                log+="  - pts errors=" + pi.ptsErrorTexts.Count.ToString()+Environment.NewLine;
                foreach (string s in pi.ptsErrorTexts)
                  log+="        ->" + s+Environment.NewLine;
              }
              if (pi.payloadStartErrorTexts.Count > 0)
              {
                log+="  - payloadStart errors=" + pi.payloadStartErrorTexts.Count.ToString()+Environment.NewLine;
                foreach (string s in pi.payloadStartErrorTexts)
                  log+="        ->" + s+Environment.NewLine;
              }
            }
          }
          return log;
        }
        #endregion
      }
    }

    DVB-T2 Stream, DemuxToy findet keine Fehler:

    t2-demuxtoy.PNG


    TSPacketChecker Originalversion zeigt "cc errors=102743" an, mit meinem PacketChecks.cs "cc errors=48636":

    t2-mpts.PNG


    ich versuche cc errors auf 0 zu bekommen, wird aber nicht einfach.

    und: "SDT (7 services)" aber tatsächlich nur 5. Scheint auch ein bug zu sein.
     

    KayDiefenthal

    MP Donator
  • Premium Supporter
  • July 18, 2006
    1,176
    92
    46
    Germany - Bonn
    Home Country
    Germany Germany
    das mit dem sdt counter hatten wir ja schon 33 obwohl es nur 22 hätten sein dürfen da kann also etwas nicht stimmen

    edit mit dem section count änderungen könnte man auch jetzt schon einfließen lassen wenn man in den Constructoren ein bool Islivesource mit einbaut

    wenn ja ist es udp tcp als input
    wenn nein dann file

    denn die problematik besteht darin das wir nur im live modus darauf reagieren können mehr anzufordern bzw darauf zu warten
    bei file ist es fest entweder sind alle subtabels da oder es fehlt halt was

    edit 2 ps bastle grade am NITParser rum damit man auch mal den T2DeliverySystemDescriptor und C2 DeliverySystemDescriptor bekommen kann
    für den S2 muss ich mal schauen

    aber erstmal T2 und C2 da die beiden Extended Discriptoren sind

    Code:
    case 0x7f: // extended descriptor (see note 5)
    var extended_descriptor_tag = section.Data[pointer + 2];                           
    switch (extended_descriptor_tag)
    {
        case 0x04: // T2_delivery_system_descriptor
                DVB_GetT2DeliverySys(section.Data, pointer, descriptor_length);
                break;
        case 0x0d: // C2_delivery_system_descriptor
                DVB_GetC2DeliverySys(section.Data, pointer, descriptor_length);
                break;
    }
    break;
     
    Last edited:

    alexi

    Portal Member
    January 21, 2010
    35
    0
    Home Country
    Germany Germany
    denn die problematik besteht darin das wir nur im live modus darauf reagieren können mehr anzufordern bzw darauf zu warten
    bei file ist es fest entweder sind alle subtabels da oder es fehlt halt was

    Ich verstehe nicht wie Du "mehr anzufordern" möchtest. "warten" geht und ist auch gut, bei manchen Sendern dauert es sehr lange bis alle subtables da sind. Bei file muss man halt lange genug aufzeichnen. File hat den Vorteil, dass man mit einem unveränderten File die eigenen Änderungen am Sourcecode gut und reproduzierbar testen kann. In einen file kann man auch selbst Fehler einbauen, z.B. falsches Sync-Byte (0x48 sattt 0x47) um damit den TSPacketChecker zu testen. Das werde ich noch tun.
     

    alexi

    Portal Member
    January 21, 2010
    35
    0
    Home Country
    Germany Germany
    noch was:
    in NITParser.cs wird der code nach dem ersten return nie ausgeführt.

    Code:
        #region Descriptor decoders
        private void DVB_GetLogicalChannelNumber(int original_network_id, int transport_stream_id, byte[] buf, int start)
        {
          netInfo.service_id = (0x100 * buf[start]) + buf[start + 1];
          netInfo.LCN = (0x100 * (buf[start + 2] & 0x3)) + buf[start + 3];
          return;
    // hier !!!
          // 32 bits per record
          int n = buf[start + 1] / 4;
          if (n < 1)
            return;
    
          // desc id, desc len, (service id, service number)
          int pointer = start + 2;
          int ServiceID, LCN;
          for (int i = 0; i < n; i++)
          {
            //service id:16
            //visible_service_flag:1
            //reserved:5
            //logical channel number:10
            ServiceID = 0;
            LCN = 0;
            ServiceID = (buf[pointer + 0] << 8) + (buf[pointer + 1] & 0xff);
            LCN = ((buf[pointer + 2] & 0x03) << 8) + (buf[pointer + 3] & 0xff);
     

    KayDiefenthal

    MP Donator
  • Premium Supporter
  • July 18, 2006
    1,176
    92
    46
    Germany - Bonn
    Home Country
    Germany Germany
    satip = pid gefilterter Ts anfordern play Request mit addpids=16 wenn man mehr nit haben möchte und wenn die dann komplett sind play request mit delpids=16

    zum return ja ist hier schon abgeändert ;-)
    werde den fertigen code wenn er für DVBS /DVBS2 DVBT2 stabil ist dir an den original TsPacktetChecker anpassen
     

    Users who are viewing this thread

    Top Bottom