private void DecodeTransponderData(byte[] section, int endOfSection, ref int pointer) { if (pointer + 6 > endOfSection) { throw new Exception(string.Format("NIT: corruption detected at transponder data, pointer = {0}, end of section = {1}", pointer, endOfSection)); } bool isMpeg2Transport = ((section[pointer] & 0x80) == 0); bool isVerticalRightPolarisation = ((section[pointer] & 0x40) != 0); int transponderNumber = (section[pointer++] & 0x3f); byte cdsReference = section[pointer++]; Log.Log.Debug("NIT: transponder data, is MPEG 2 transport = {0}, is vertical/right polarisation = {1}, transponder number = {2}, CDS reference = {3}", isMpeg2Transport, isVerticalRightPolarisation, transponderNumber, cdsReference); if (isMpeg2Transport) { byte mmsReference = section[pointer++]; int vctId = (section[pointer] << 8) + section[pointer + 1]; pointer += 2; bool isRootTransponder = ((section[pointer++] & 0x80) != 0); Log.Log.Debug("NIT: MPEG 2 transponder data, MMS reference = {0}, VCT ID = 0x{1:x}, is root transponder = {2}", mmsReference, vctId, isRootTransponder); } else { bool isWideBandwidthVideo = ((section[pointer] & 0x80) != 0); WaveformStandard waveformStandard = (WaveformStandard)(section[pointer++] & 0x1f); bool isWideBandwidthAudio = ((section[pointer] & 0x80) != 0); bool isCompandedAudio = ((section[pointer] & 0x40) != 0); MatrixMode matrixMode = (MatrixMode)((section[pointer] >> 4) & 0x03); int subcarrier2Offset = 10 * (((section[pointer] & 0x0f) << 6) + (section[pointer + 1] >> 2)); // kHz pointer++; int subcarrier1Offset = 10 * (((section[pointer] & 0x03) << 8) + section[pointer + 1]); pointer += 2; Log.Log.Debug("NIT: non-MPEG 2 transponder data, is WB video = {0}, waveform standard = {1}, is WB audio = {2}, is companded audio = {3}, matrix mode = {4}, subcarrier 2 offset = {5} kHz, subcarrier 1 offset = {6} kHz", isWideBandwidthVideo, waveformStandard, isWideBandwidthAudio, isCompandedAudio, matrixMode, subcarrier2Offset, subcarrier1Offset); } }
private void DecodeVirtualChannelMap(byte[] section, int endOfSection, ref int pointer, AtscTransmissionMedium transmissionMedium, int vctId) { // Virtual channel formats depend on transmission medium. if (pointer + 7 > endOfSection) { throw new Exception(string.Format("S-VCT: corruption detected at virtual channel map, pointer = {0}, end of section = {1}", pointer, endOfSection)); } bool freqSpecIncluded = ((section[pointer] & 0x80) != 0); bool symbolRateIncluded = ((section[pointer] & 0x40) != 0); bool descriptorsIncluded = ((section[pointer++] & 0x20) != 0); bool splice = ((section[pointer++] & 0x80) != 0); uint activationTime = 0; for (byte b = 0; b < 4; b++) { activationTime = activationTime << 8; activationTime = section[pointer++]; } byte numberOfVcRecords = section[pointer++]; Log.Log.Debug("S-VCT: virtual channel map, transmission medium = {0}, freq. spec. included = {1}, symbol rate included = {2}, descriptors included = {3}, splice = {4}, activation time = {5}, number of VC records = {6}", transmissionMedium, freqSpecIncluded, symbolRateIncluded, descriptorsIncluded, splice, activationTime, numberOfVcRecords); for (byte i = 0; i < numberOfVcRecords; i++) { if (pointer + 9 > endOfSection) { throw new Exception(string.Format("S-VCT: detected number of virtual channel records {0} is invalid, pointer = {1}, end of section = {2}, loop = {3}", numberOfVcRecords, pointer, endOfSection, i)); } int virtualChannelNumber = ((section[pointer] & 0x0f) << 8) + section[pointer + 1]; pointer += 2; _channelDefinitions.Add(virtualChannelNumber); bool applicationVirtualChannel = ((section[pointer] & 0x80) != 0); int bitstreamSelect = ((section[pointer] & 0x40) >> 6); // broadcast reserved int pathSelect = ((section[pointer] & 0x20) >> 5); // satellite, SMATV, broadcast reserved TransportType transportType = (TransportType)((section[pointer] & 0x10) >> 4); ChannelType channelType = (ChannelType)(section[pointer++] & 0x0f); int sourceId = (section[pointer] << 8) + section[pointer + 1]; pointer += 2; Log.Log.Debug("S-VCT: virtual channel number = {0}, application virtual channel = {1}, bitstream select = {2}, path select = {3}, transport type = {4}, channel type = {5}, source ID = 0x{6:x}", virtualChannelNumber, applicationVirtualChannel, bitstreamSelect, pathSelect, transportType, channelType, sourceId); if (channelType == ChannelType.NvodAccess) { int nvodChannelBase = ((section[pointer] & 0x0f) << 8) + section[pointer + 1]; pointer += 2; if (transmissionMedium == AtscTransmissionMedium.Smatv) { pointer += 3; } else if (transmissionMedium != AtscTransmissionMedium.OverTheAir) { pointer += 2; } Log.Log.Debug("S-VCT: NVOD channel base = 0x{0:x}", nvodChannelBase); } else { switch (transmissionMedium) { case AtscTransmissionMedium.Satellite: if (transportType == TransportType.Mpeg2) { byte satellite = section[pointer++]; int transponder = (section[pointer++] & 0x3f); int programNumber = (section[pointer] << 8) + section[pointer + 1]; pointer += 2; Log.Log.Debug("S-VCT: satellite = {0}, transponder = {1}, program number = 0x{2:x}", satellite, transponder, programNumber); } else { byte satellite = section[pointer++]; int transponder = (section[pointer++] & 0x3f); pointer += 2; Log.Log.Debug("S-VCT: satellite = {0}, transponder = {1}", satellite, transponder); } break; case AtscTransmissionMedium.Smatv: if (transportType == TransportType.Mpeg2) { byte cdsReference = section[pointer++]; int programNumber = (section[pointer] << 8) + section[pointer + 1]; pointer += 2; byte mmsReference = section[pointer++]; pointer++; Log.Log.Debug("S-VCT: CDS reference = {0}, program number = 0x{1:x}, MMS reference = {2}", cdsReference, programNumber, mmsReference); } else { byte cdsReference = section[pointer++]; bool scrambled = ((section[pointer] & 0x80) != 0); VideoStandard videoStandard = (VideoStandard)(section[pointer++] & 0x0f); bool isWideBandwidthVideo = ((section[pointer] & 0x80) != 0); WaveformStandard waveformStandard = (WaveformStandard)(section[pointer++] & 0x1f); bool isWideBandwidthAudio = ((section[pointer] & 0x80) != 0); bool isCompandedAudio = ((section[pointer] & 0x40) != 0); MatrixMode matrixMode = (MatrixMode)((section[pointer] >> 4) & 0x03); int subcarrier2Offset = 10 * (((section[pointer] & 0x0f) << 6) + (section[pointer + 1] >> 2)); // kHz pointer++; int subcarrier1Offset = 10 * (((section[pointer] & 0x03) << 8) + section[pointer + 1]); pointer += 2; Log.Log.Debug("S-VCT: CDS reference = {0}, scrambled = {1}, video standard = {2}, is WB video = {3}, waveform standard = {4}, is WB audio = {5}, is companded audio = {6}, matrix mode = {7}, subcarrier 2 offset = {8} kHz, subcarrier 1 offset = {9} kHz", cdsReference, scrambled, videoStandard, isWideBandwidthVideo, waveformStandard, isWideBandwidthAudio, isCompandedAudio, matrixMode, subcarrier2Offset, subcarrier1Offset); } break; case AtscTransmissionMedium.OverTheAir: if (transportType == TransportType.Mpeg2) { int programNumber = (section[pointer] << 8) + section[pointer + 1]; pointer += 2; Log.Log.Debug("S-VCT: program number = 0x{0:x}", programNumber); } else { bool scrambled = ((section[pointer] & 0x80) != 0); VideoStandard videoStandard = (VideoStandard)(section[pointer++] & 0x0f); pointer++; Log.Log.Debug("S-VCT: scrambled = {0}, video standard = {1}", scrambled, videoStandard); } break; case AtscTransmissionMedium.Cable: case AtscTransmissionMedium.Mmds: if (transportType == TransportType.Mpeg2) { byte cdsReference = section[pointer++]; int programNumber = (section[pointer] << 8) + section[pointer + 1]; pointer += 2; byte mmsReference = section[pointer++]; Log.Log.Debug("S-VCT: CDS reference = {0}, program number = 0x{1:x}, MMS reference = {2}", cdsReference, programNumber, mmsReference); if (OnChannelDetail != null) { OnChannelDetail(transmissionMedium, vctId, virtualChannelNumber, applicationVirtualChannel, bitstreamSelect, pathSelect, channelType, sourceId, cdsReference, programNumber, mmsReference); } } else { byte cdsReference = section[pointer++]; bool scrambled = ((section[pointer] & 0x80) != 0); VideoStandard videoStandard = (VideoStandard)(section[pointer++] & 0x0f); pointer += 2; Log.Log.Debug("S-VCT: CDS reference = {0}, scrambled = {1}, video standard = {2}", cdsReference, scrambled, videoStandard); } break; default: throw new Exception(string.Format("S-VCT: unsupported transmission medium {0}", transmissionMedium)); } } if (freqSpecIncluded || transmissionMedium == AtscTransmissionMedium.OverTheAir) { int frequencyUnit = 10; // kHz if ((section[pointer] & 0x80) != 0) { frequencyUnit = 125; // kHz } int carrierFrequency = frequencyUnit * (((section[pointer] & 0x7f) << 8) + section[pointer + 1]); // kHz pointer += 2; Log.Log.Debug("S-VCT: frequency, unit = {0} kHz, carrier = {1} kHz", frequencyUnit, carrierFrequency); } if (symbolRateIncluded && transmissionMedium != AtscTransmissionMedium.OverTheAir) { // s/s int symbolRate = ((section[pointer] & 0x0f) << 24) + (section[pointer + 1] << 16) + (section[pointer + 2] << 8) + section[pointer + 3]; pointer += 4; Log.Log.Debug("S-VCT: symbol rate = {0} s/s", symbolRate); } if (descriptorsIncluded) { if (pointer >= endOfSection) { throw new Exception(string.Format("S-VCT: invalid section length at virtual channel map descriptor count, pointer = {0}, end of section = {1}, loop = {2}", pointer, endOfSection, i)); } byte descriptorCount = section[pointer++]; for (byte d = 0; d < descriptorCount; d++) { if (pointer + 2 > endOfSection) { throw new Exception(string.Format("S-VCT: detected virtual channel map descriptor count {0} is invalid, pointer = {1}, end of section = {2}, loop = {3}, inner loop = {4}", descriptorCount, pointer, endOfSection, i, d)); } byte tag = section[pointer++]; byte length = section[pointer++]; Log.Log.Debug("S-VCT: virtual channel map descriptor, tag = 0x{0:x}, length = {1}", tag, length); if (pointer + length > endOfSection) { throw new Exception(string.Format("S-VCT: invalid virtual channel map descriptor length {0}, pointer = {1}, end of section = {2}, loop = {3}, inner loop = {4}", length, pointer, endOfSection, i, d)); } pointer += length; } } } }