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." }); }
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." }); }