public Pes(TsPacket packet) { PacketStartCodePrefix = (uint)((packet.PesHeader.Payload[0] << 16) + (packet.PesHeader.Payload[1] << 8) + packet.PesHeader.Payload[2]); StreamId = packet.PesHeader.Payload[3]; PesPacketLength = (ushort)((packet.PesHeader.Payload[4] << 8) + packet.PesHeader.Payload[5]); _data = new byte[PesPacketLength + 6]; Buffer.BlockCopy(packet.PesHeader.Payload, 0, _data, _pesBytes, packet.PesHeader.Payload.Length); _pesBytes += (ushort)(packet.PesHeader.Payload.Length); Buffer.BlockCopy(packet.Payload, 0, _data, _pesBytes, packet.Payload.Length); _pesBytes += (ushort)(packet.Payload.Length); }
private void CheckPmt(TsPacket tsPacket) { if (ProgramAssociationTable == null) { return; } if (tsPacket.Pid == (short)PidType.NitPid) { _nitFactory.AddPacket(tsPacket); return; } // CheckPcr(tsPacket); var contains = false; foreach (var pid in ProgramAssociationTable.Pids) { if (pid != tsPacket.Pid) { continue; } contains = true; break; } if (!contains) { return; } ProgramMapTableFactory selectedPmt = null; foreach (var t in _pmtFactories) { if (t.TablePid != tsPacket.Pid) { continue; } selectedPmt = t; break; } if (selectedPmt == null) { selectedPmt = new ProgramMapTableFactory(); selectedPmt.TableChangeDetected += _pmtFactory_TableChangeDetected; _pmtFactories?.Add(selectedPmt); } selectedPmt.AddPacket(tsPacket); }
protected virtual void OnTsPacketReadyDetected(TsPacket tsPacket) { var handler = TsPacketReady; if (handler == null) { return; } var args = new TsPacketReadyEventArgs { TsPacket = tsPacket }; handler(this, args); }
public bool Add(TsPacket packet) { if (packet.PayloadUnitStartIndicator) { return(false); } if ((PesPacketLength + 6 - _pesBytes) > packet.Payload.Length) { Buffer.BlockCopy(packet.Payload, 0, _data, _pesBytes, packet.Payload.Length); _pesBytes += (ushort)(packet.Payload.Length); } else { Buffer.BlockCopy(packet.Payload, 0, _data, _pesBytes, (PesPacketLength + 6 - _pesBytes)); _pesBytes += (ushort)(PesPacketLength + 6 - _pesBytes); } return(true); }
public void AddPacket(TsPacket newPacket) { try { if (newPacket.TransportErrorIndicator) { return; } switch (newPacket.Pid) { case (short)PidType.PatPid: _patFactory.AddPacket(newPacket); break; case (short)PidType.SdtPid: _sdtFactory.AddPacket(newPacket); break; case (short)PidType.EitPid: _eitFactory.AddPacket(newPacket); break; case 2048: _sitFactory.AddPacket(newPacket); break; default: CheckPmt(newPacket); break; } } catch (Exception ex) { Debug.WriteLine("Exception generated within AddPacket method: " + ex.Message); } }
/// <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> /// <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 TsPacket[] GetTsPacketsFromData(byte[] data, int dataSize = 0, bool retainPayload = true, bool preserveSourceData = false) { try { if (dataSize == 0) { dataSize = data.Length; } if (_residualData != null) { var 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; } var maxPackets = (dataSize) / TsPacketFixedSize; var tsPackets = new TsPacket[maxPackets]; var packetCounter = 0; var start = FindSync(data, 0, TsPacketFixedSize); while (start >= 0 && ((dataSize - start) >= TsPacketFixedSize)) { var 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) { #if DEBUG Debug.WriteLine("TS packet data adaptationFieldSize >= payloadSize"); #endif return(null); } 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; var 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) { #if DEBUG // Debug.WriteLine("PES syntax error: no PES startcode found, or payload offset exceeds boundary of data"); #endif } 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; var 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)) { var ptsDtsFlag = data[payloadOffs + 7] >> 6; tsPacket.PesHeader.HeaderLength = (byte)(9 + data[payloadOffs + 8]); switch (ptsDtsFlag) { case 2: tsPacket.PesHeader.Pts = Get_TimeStamp(2, data, payloadOffs + 9); break; case 3: tsPacket.PesHeader.Pts = Get_TimeStamp(3, data, payloadOffs + 9); tsPacket.PesHeader.Dts = Get_TimeStamp(1, data, payloadOffs + 14); break; case 1: throw new Exception("PES Syntax error: pts_dts_flag = 1"); } } 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 (Exception ex) { Debug.WriteLine("Exception within GetTsPacketsFromData method: " + ex.Message); } return(null); }
public void AddPacket(TsPacket newPacket) { try { //if (newPacket.Pid == 16) //{ // Console.WriteLine("NIT"); //} //if (newPacket.Pid == 17) //{ // Console.WriteLine("SDT"); //} if (newPacket.TransportErrorIndicator) { return; } switch (newPacket.Pid) { case (short)PidType.PatPid: _patFactory.AddPacket(newPacket); break; case (short)PidType.SdtPid: _sdtFactory.AddPacket(newPacket); break; //case (short)PidType.EitPid: // _eitFactory.AddPacket(newPacket); // break; case 2048: _sitFactory.AddPacket(newPacket); break; case (short)PidType.TdtPid: _tdtFactory.AddPacket(newPacket); break; default: CheckPmt(newPacket); break; } if (newPacket.Pid == 0x1929) { if (!_dsmccDictionary.ContainsKey(newPacket.Pid)) { _dsmccDictionary[newPacket.Pid] = new DsmccFactory(); } Console.WriteLine("Arqiva test carousel PayloadUnitStartIndicator = " + newPacket.PayloadUnitStartIndicator.ToString() + ", ContainsPayload = " + newPacket.ContainsPayload.ToString()); _dsmccDictionary[newPacket.Pid].AddPacket(newPacket); } } catch (Exception ex) { Console.WriteLine(ex.StackTrace); Debug.WriteLine("Exception generated within AddPacket method: " + ex.Message); } }
/// <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> /// <param name="data">Aligned or unaligned data buffer containing TS packets. Aligned is more efficient if possible.</param> /// <returns>Complete TS packets from this data and any prior partial data rolled over.</returns> public TsPacket[] GetTsPacketsFromData(byte[] data) { try { if (_residualData != null) { var tempArray = new byte[data.Length]; Buffer.BlockCopy(data, 0, tempArray, 0, data.Length); data = new byte[_residualData.Length + tempArray.Length]; Buffer.BlockCopy(_residualData, 0, data, 0, _residualData.Length); Buffer.BlockCopy(tempArray, 0, data, _residualData.Length, tempArray.Length); } var maxPackets = data.Length / TsPacketSize; var tsPackets = new TsPacket[maxPackets]; var packetCounter = 0; var start = FindSync(data, 0); while (start >= 0 && data.Length - start >= TsPacketSize) { var 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) }; //skip packets with error indicators or on the null PID if (!tsPacket.TransportErrorIndicator && tsPacket.Pid != (short)PidType.NullPid) { var payloadOffs = start + 4; var payloadSize = TsPacketSize - 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) { #if DEBUG Debug.WriteLine("TS packet data adaptationFieldSize >= payloadSize"); #endif return(null); } 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; var 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 > data.Length - 2 || data[payloadOffs] != 0 || data[payloadOffs + 1] != 0 || data[payloadOffs + 2] != 1) { #if DEBUG // Debug.WriteLine("PES syntax error: no PES startcode found, or payload offset exceeds boundary of data"); #endif } else { tsPacket.PesHeader = new PesHdr { StartCode = 0x100 + data[payloadOffs + 3], Pts = -1, Dts = -1 }; var ptsDtsFlag = data[payloadOffs + 7] >> 6; switch (ptsDtsFlag) { case 2: tsPacket.PesHeader.Pts = Get_TimeStamp(2, data, payloadOffs + 9); break; case 3: tsPacket.PesHeader.Pts = Get_TimeStamp(3, data, payloadOffs + 9); tsPacket.PesHeader.Dts = Get_TimeStamp(1, data, payloadOffs + 14); break; case 1: throw new Exception("PES Syntax error: pts_dts_flag = 1"); } //if (tsPacket.AdaptationField.PcrFlag && ptsDtsFlag > 1) //{ // var ts = new TimeSpan((long)(((long)tsPacket.AdaptationField.Pcr - tsPacket.PesHeader.Pts * 300)/2.7)); // Debug.WriteLine($"PCR: {tsPacket.AdaptationField.Pcr}, PTS: {tsPacket.PesHeader.Pts}, Delta = {ts}"); //} var pesLength = 9 + data[payloadOffs + 8]; tsPacket.PesHeader.Payload = new byte[pesLength]; Buffer.BlockCopy(data, payloadOffs, tsPacket.PesHeader.Payload, 0, pesLength); payloadOffs += pesLength; payloadSize -= pesLength; } } if (payloadSize > 1) { tsPacket.Payload = new byte[payloadSize]; Buffer.BlockCopy(data, payloadOffs, tsPacket.Payload, 0, payloadSize); } } tsPackets[packetCounter++] = tsPacket; start += TsPacketSize; if (start >= data.Length) { break; } if (data[start] != SyncByte) { break; // but this is strange! } } if (start + TsPacketSize != data.Length) { //we have 'residual' data to carry over to next call _residualData = new byte[data.Length - start]; Buffer.BlockCopy(data, start, _residualData, 0, data.Length - start); } return(tsPackets); } catch (Exception ex) { Debug.WriteLine("Exception within GetTsPacketsFromData method: " + ex.Message); } return(null); }