public void WritePMT(int pid, ProgramMapTable pmt) { var program_info = new MemoryStream(); using (program_info) { foreach (var entry in pmt.ProgramInfo) { program_info.WriteByte(entry.Tag); program_info.WriteByte(entry.Data.Length); program_info.Write(entry.Data, 0, entry.Data.Length); } } var body = new MemoryStream(); using (body) { body.WriteUInt16BE(pmt.ProgramNumber); body.WriteByte((3 << 6) | (pmt.Version << 1) | (pmt.CurrentNextIndicator ? 1 : 0)); body.WriteByte(pmt.SectionNumber); body.WriteByte(pmt.LastSectionNumber); body.WriteUInt16BE((7 << 13) | (pmt.PCRPID & 0x1FFF)); var program_info_ary = program_info.ToArray(); body.WriteUInt16BE((15 << 12) | program_info_ary.Length); body.Write(program_info_ary, 0, program_info_ary.Length); foreach (var entry in pmt.Table) { body.WriteByte(entry.StreamType); body.WriteUInt16BE((7 << 13) | (entry.PID & 0x1FFF)); body.WriteUInt16BE((15 << 12) | (entry.ESInfo.Length & 0xFFF)); body.Write(entry.ESInfo, 0, entry.ESInfo.Length); } } WriteSection(pid, 0x02, body.ToArray()); }
private void Clear() { pps = new NALUnit[0]; sps = new NALUnit[0]; spsExt = new NALUnit[0]; pat = new ProgramAssociationTable(); pmt = new ProgramMapTable(); adtsHeader = ADTSHeader.Default; nalSizeLen = 0; ptsBase = -1; }
private void ProcessQueueWorkerThread() { var dataBuffer = new byte[12 + (188 * 7)]; while (_pendingExit != true) { try { lock (_ringBuffer) { int dataSize; ulong timestamp; if (_ringBuffer.BufferFullness < 10) { Thread.Sleep(1); continue; } var capacity = _ringBuffer.Remove(ref dataBuffer, out dataSize, out timestamp); if (capacity > 0) { dataBuffer = new byte[capacity]; continue; } if (dataBuffer == null) { continue; } var packets = Factory.GetTsPacketsFromData(dataBuffer, dataSize); //use decoder to register default program (muxing always happens on default program) if (_mainStreamDecoder.GetSelectedPmt() == null) { _mainStreamDecoder.AddPackets(packets); } else { if (_mainStreamTargetPmt == null && _subStreamSourcePmt != null) { _mainStreamTargetPmt = _mainStreamDecoder.GetSelectedPmt(); var pmtSpaceNeeded = 0; foreach (var esinfo in _subStreamSourcePmt.EsStreams) { if (_subPids.Contains(esinfo.ElementaryPid)) { pmtSpaceNeeded += esinfo.SourceData.Length; } } if ((_mainStreamTargetPmt.SectionLength + pmtSpaceNeeded) > (TsPacketSize - 12)) { throw new InvalidDataException( "Cannot add to PMT - no room (packet spanned PMT not supported)"); } } } //check for any PMT packets, and adjust them to reflect the new muxed reality... foreach (var packet in packets) { if (_mainStreamTargetPmt != null && packet.Pid == _mainStreamTargetPmt.Pid) { //this is the PMT for the target program on the target stream - patch in the substream PID entries foreach (var esinfo in _subStreamSourcePmt.EsStreams) { if (_subPids.Contains(esinfo.ElementaryPid)) { //locate current SectionLength bytes in databuffer var pos = packet.SourceBufferIndex + 4; //advance to start of PMT data structure (past TS header) var pointerField = dataBuffer[pos]; pos += pointerField; //advance by pointer field var SectionLength = (short)(((dataBuffer[pos + 2] & 0x3) << 8) + dataBuffer[pos + 3]); //get current length //increase length value by esinfo length var extendedSectionLength = (short)(SectionLength + (short)esinfo.SourceData.Length); //set back new length into databuffer var bytes = BitConverter.GetBytes(extendedSectionLength); dataBuffer[pos + 2] = (byte)((dataBuffer[pos + 2] & 0xFC) + (byte)(bytes[1] & 0x3)); dataBuffer[pos + 3] = bytes[0]; //copy esinfo source data to end of program block in pmt Buffer.BlockCopy(esinfo.SourceData, 0, dataBuffer, packet.SourceBufferIndex + 4 + pointerField + SectionLength, esinfo.SourceData.Length); //correct CRC after each extension var crcBytes = BitConverter.GetBytes(GenerateCRC(ref dataBuffer, pos + 1, extendedSectionLength - 1)); dataBuffer[packet.SourceBufferIndex + 4 + pointerField + extendedSectionLength] = crcBytes[3]; dataBuffer[ packet.SourceBufferIndex + 4 + pointerField + extendedSectionLength + 1] = crcBytes[2]; dataBuffer[ packet.SourceBufferIndex + 4 + pointerField + extendedSectionLength + 2] = crcBytes[1]; dataBuffer[ packet.SourceBufferIndex + 4 + pointerField + extendedSectionLength + 3] = crcBytes[0]; } } } } //insert any queued filtered sub PID packets if (_subPidBuffer.BufferFullness > 0) { foreach (var packet in packets) { if (packet.Pid == (short)PidType.NullPid) { //candidate for wiping with any data queued up for muxing in byte[] subPidPacketBuffer = new byte[TsPacketSize]; int subPidDataSize = 0; ulong subPidTimeStamp = 0; //see if there is any data waiting to get switched into the mux... lock (_subPidBuffer) { if (_subPidBuffer.BufferFullness < 1) { break; //double check here because prior check was not thread safe } var subPidPacketDataReturned = _subPidBuffer.Remove(ref subPidPacketBuffer, out subPidDataSize, out subPidTimeStamp); if (subPidPacketDataReturned != 0 && subPidPacketDataReturned != TsPacketSize) { PrintToConsole("Sub PID data seems to not be size of TS packet!"); return; } } if (packet.SourceBufferIndex % 188 != 0) { PrintToConsole("Misaligned packet"); return; } Buffer.BlockCopy(subPidPacketBuffer, 0, dataBuffer, packet.SourceBufferIndex, TsPacketSize); } } } var packetReadyEventArgs = new PacketReadyEventArgs(); packetReadyEventArgs.UdpPacketData = new byte[dataSize]; Buffer.BlockCopy(dataBuffer, 0, packetReadyEventArgs.UdpPacketData, 0, dataSize); OnPacketReady(packetReadyEventArgs); } } catch (Exception ex) { PrintToConsole($@"Unhandled exception within network receiver: {ex.Message}"); } } //Logger.Log(new TelemetryLogEventInfo { Level = LogLevel.Info, Message = "Stopping analysis thread due to exit request." }); }
public async Task ReadAsync(IContentSink sink, Stream stream, CancellationToken cancel_token) { int streamIndex = -1; long contentPosition = 0; DateTime streamOrigin = DateTime.Now; DateTime latestContentTime = DateTime.Now; byte[] bytes188 = new byte[188]; byte[] latestHead = new byte[0]; byte[] contentData = null; streamIndex = Channel.GenerateStreamID(); streamOrigin = DateTime.Now; sink.OnContentHeader(new Content(streamIndex, TimeSpan.Zero, contentPosition, new byte[] {}, PCPChanPacketContinuation.None)); try { while (!cancel_token.IsCancellationRequested) { bytes188 = await stream.ReadBytesAsync(188, cancel_token).ConfigureAwait(false); TSPacket packet = new TSPacket(bytes188); if (packet.sync_byte != 0x47) { throw new Exception(); } if (packet.payload_unit_start_indicator > 0) { if (packet.PID == patID) { pmtID = packet.PMTID; head = new MemoryStream(); if (!addHead(bytes188)) { throw new Exception(); } continue; } if (packet.PID == pmtID) { var pmt = new ProgramMapTable(packet, bytes188); pcrPID = pmt.PCRPID; if (!addHead(bytes188)) { throw new Exception(); } head.Close(); byte[] newHead = head.ToArray(); if (!Enumerable.SequenceEqual(newHead, latestHead)) { streamIndex = Channel.GenerateStreamID(); contentPosition = 0; sink.OnContentHeader(new Content(streamIndex, DateTime.Now - streamOrigin, contentPosition, newHead, PCPChanPacketContinuation.None)); contentPosition += newHead.Length; latestHead = newHead; } continue; } if (packet.PID == pcrPID && packet.program_clock_reference > 0.0) { if (packet.program_clock_reference < rateCounter.lastPCR) { rateCounter.lastPCR = packet.program_clock_reference; rateCounter.byteCount = 0; recvRate = 0.0; } else if (rateCounter.lastPCR + 10.0 < packet.program_clock_reference) { var bitrate = 8 * rateCounter.byteCount / (packet.program_clock_reference - rateCounter.lastPCR); UpdateRecvRate(sink, bitrate); rateCounter.lastPCR = packet.program_clock_reference; rateCounter.byteCount = 0; } } if ((DateTime.Now - latestContentTime).Milliseconds > 50) { TryParseContent(packet, out contentData); if (contentData != null) { sink.OnContent(new Content(streamIndex, DateTime.Now - streamOrigin, contentPosition, contentData, PCPChanPacketContinuation.None)); contentPosition += contentData.Length; latestContentTime = DateTime.Now; } } } if (!addCache(bytes188)) { throw new Exception(); } rateCounter.byteCount += 188; } } catch (EndOfStreamException) { } catch (Exception) { } }
private void ProcessSubQueueWorkerThread() { var dataBuffer = new byte[12 + (188 * 7)]; while (_pendingExit != true) { try { if (_subRingBuffer.BufferFullness < 1) { Thread.Sleep(1); continue; } lock (_subRingBuffer) { if (_subRingBuffer.BufferFullness < 1) { continue; } int dataSize; ulong timestamp; var capacity = _subRingBuffer.Remove(ref dataBuffer, out dataSize, out timestamp); if (capacity > 0) { dataBuffer = new byte[capacity]; continue; } if (dataBuffer == null) { continue; } //check to see if there are any specific TS packets by PIDs we want to select var packets = Factory.GetTsPacketsFromData(dataBuffer, dataSize, true, true); foreach (var packet in packets) { if (_subStreamDecoder.GetSelectedPmt() == null) { _subStreamDecoder.AddPackets(packets); } else { if (_subStreamSourcePmt == null) { _subStreamSourcePmt = _subStreamDecoder.GetSelectedPmt(); } } if (_subPids.Contains(packet.Pid)) { //this pid is selected for mapping across... add to PID buffer to merge replacing NULL pid var buffer = new byte[packet.SourceData.Length]; Buffer.BlockCopy(packet.SourceData, 0, buffer, 0, packet.SourceData.Length); _subPidBuffer.Add(ref buffer); } } //lock (_outputUdpClient) //{ // _outputUdpClient.Send(dataBuffer, dataSize); //} } } catch (Exception ex) { PrintToConsole($@"Unhandled exception within network receiver: {ex.Message}"); } } //Logger.Log(new TelemetryLogEventInfo { Level = LogLevel.Info, Message = "Stopping analysis thread due to exit request." }); }