public void OnModulationMode(AtscTransmissionMedium transmissionMedium, byte index, TransmissionSystem transmissionSystem, BinaryConvolutionCodeRate innerCodingMode, bool isSplitBitstreamMode, ModulationType modulationFormat, int symbolRate) { if (transmissionMedium != AtscTransmissionMedium.Cable) { return; } _modulationModes[index] = modulationFormat; }
public void OnCarrierDefinition(AtscTransmissionMedium transmissionMedium, byte index, int carrierFrequency) { if (transmissionMedium != AtscTransmissionMedium.Cable) { return; } if (carrierFrequency > 1750) { // Convert from centre frequency to the analog video carrier frequency. // This is a BDA convention. PhysicalChannel channel = new PhysicalChannel(); channel.Frequency = carrierFrequency - 1750; channel.Channel = ATSCChannel.GetPhysicalChannelFromFrequency(carrierFrequency); _carrierFrequencies[index] = channel; } }
public void OnSourceName(AtscTransmissionMedium transmissionMedium, bool applicationType, int sourceId, string name) { if (transmissionMedium != AtscTransmissionMedium.Cable || applicationType) { return; } ATSCChannel channel = null; if (_channels.TryGetValue(sourceId, out channel)) { channel.Name = name; channel.NetworkId = sourceId; _sourcesWithoutNames.Remove(sourceId); if (_sourcesWithoutNames.Count == 0) { Log.Log.Info("DRI CC: all sources now have names, assuming NTT is complete"); OnTableComplete(MgtTableType.NttSns); } } }
public void OnSvctChannelDetail(AtscTransmissionMedium transmissionMedium, int vctId, int virtualChannelNumber, bool applicationVirtualChannel, int bitstreamSelect, int pathSelect, ChannelType channelType, int sourceId, byte cdsReference, int programNumber, byte mmsReference) { if (transmissionMedium != AtscTransmissionMedium.Cable || applicationVirtualChannel || programNumber == 0 || sourceId == 0) { // Not tunable/supported. return; } ATSCChannel channel = null; if (_channels.TryGetValue(sourceId, out channel)) { Log.Log.Info("DRI CC: received repeated S-VCT channel detail for source 0x{0:x}", sourceId); return; } channel = new ATSCChannel(); _channels.Add(sourceId, channel); channel.LogicalChannelNumber = virtualChannelNumber; channel.IsTv = true; channel.IsRadio = false; channel.FreeToAir = false; channel.Frequency = _carrierFrequencies[cdsReference].Frequency; channel.MajorChannel = virtualChannelNumber; channel.MinorChannel = 0; channel.ModulationType = _modulationModes[mmsReference]; channel.NetworkId = sourceId; channel.PhysicalChannel = _carrierFrequencies[cdsReference].Channel; channel.PmtPid = 0; // TV Server will automatically lookup the correct PID from the PAT channel.Provider = "Cable"; channel.ServiceId = programNumber; channel.TransportId = 0; // We don't have these details. _sourcesWithoutNames.Add(sourceId); }
public void Decode(byte[] section) { if (OnTableComplete == null) { return; } if (section.Length < 14) { Log.Log.Error("NTT: invalid section size {0}, expected at least 14 bytes", section.Length); return; } byte tableId = section[2]; if (tableId != 0xc3) { return; } int sectionLength = ((section[3] & 0x0f) << 8) + section[4]; if (section.Length != 2 + sectionLength + 3) // 2 for section length bytes, 3 for table ID and PID { Log.Log.Error("NTT: invalid section length = {0}, byte count = {1}", sectionLength, section.Length); return; } int protocolVersion = (section[5] & 0x1f); string isoLangCode = System.Text.Encoding.ASCII.GetString(section, 6, 3); AtscTransmissionMedium transmissionMedium = (AtscTransmissionMedium)(section[9] >> 4); TableSubtype tableSubtype = (TableSubtype)(section[9] & 0x0f); Log.Log.Debug("NTT: section length = {0}, protocol version = {1}, ISO language code = {2}, transmission medium = {3}, table subtype = {4}", sectionLength, protocolVersion, isoLangCode, transmissionMedium, tableSubtype); int pointer = 10; int endOfSection = section.Length - 4; try { switch (tableSubtype) { case TableSubtype.TransponderName: DecodeTransponderName(section, endOfSection, ref pointer); break; case TableSubtype.SatelliteText: DecodeSatelliteText(section, endOfSection, ref pointer); break; case TableSubtype.RatingsText: DecodeRatingsText(section, endOfSection, ref pointer); break; case TableSubtype.RatingSystem: DecodeRatingSystem(section, endOfSection, ref pointer); break; case TableSubtype.CurrencySystem: DecodeCurrencySystem(section, endOfSection, ref pointer); break; case TableSubtype.SourceName: DecodeSourceName(section, endOfSection, ref pointer, transmissionMedium); break; case TableSubtype.MapName: DecodeMapName(section, endOfSection, ref pointer); break; default: Log.Log.Error("NTT: unsupported table subtype {0}", tableSubtype); return; } } catch (Exception ex) { Log.Log.Error(ex.Message); return; } while (pointer + 1 < endOfSection) { byte tag = section[pointer++]; byte length = section[pointer++]; Log.Log.Debug("NTT: descriptor, tag = 0x{0:x}, length = {1}", tag, length); if (pointer + length > endOfSection) { Log.Log.Error("NTT: invalid descriptor length {0}, pointer = {1}, end of section = {2}", length, pointer, endOfSection); return; } if (tag == 0x93) // revision detection descriptor { DecodeRevisionDetectionDescriptor(section, pointer, length, (int)tableSubtype); } pointer += length; } if (pointer != endOfSection) { Log.Log.Error("NTT: corruption detected at end of section, pointer = {0}, end of section = {1}", pointer, endOfSection); return; } if (tableSubtype == TableSubtype.SourceName && _currentVersions[(int)TableSubtype.SourceName] != -1 && _unseenSections[(int)TableSubtype.SourceName].Count == 0 && OnTableComplete != null) { OnTableComplete(MgtTableType.NttSns); OnTableComplete = null; OnSourceName = null; } }
private void DecodeModulationMode(byte[] section, int endOfSection, ref int pointer, ref byte firstIndex, AtscTransmissionMedium transmissionMedium) { if (pointer + 6 > endOfSection) { throw new Exception(string.Format("NIT: corruption detected at modulation mode, pointer = {0}, end of section = {1}", pointer, endOfSection)); } TransmissionSystem transmissionSystem = (TransmissionSystem)(section[pointer] >> 4); BinaryConvolutionCodeRate innerCodingMode = BinaryConvolutionCodeRate.RateNotDefined; switch (section[pointer] & 0x0f) { case 0: innerCodingMode = BinaryConvolutionCodeRate.Rate5_11; break; case 1: innerCodingMode = BinaryConvolutionCodeRate.Rate1_2; break; case 3: innerCodingMode = BinaryConvolutionCodeRate.Rate3_5; break; case 5: innerCodingMode = BinaryConvolutionCodeRate.Rate2_3; break; case 7: innerCodingMode = BinaryConvolutionCodeRate.Rate3_4; break; case 8: innerCodingMode = BinaryConvolutionCodeRate.Rate4_5; break; case 9: innerCodingMode = BinaryConvolutionCodeRate.Rate5_6; break; case 11: innerCodingMode = BinaryConvolutionCodeRate.Rate7_8; break; case 15: // concatenated coding not used innerCodingMode = BinaryConvolutionCodeRate.RateNotSet; break; } pointer++; bool isSplitBitstreamMode = ((section[pointer] & 0x80) != 0); ModulationType modulationFormat = ModulationType.ModNotSet; switch (section[pointer] & 0x1f) { case 1: modulationFormat = ModulationType.ModQpsk; break; case 2: modulationFormat = ModulationType.ModBpsk; break; case 3: modulationFormat = ModulationType.ModOqpsk; break; case 4: modulationFormat = ModulationType.Mod8Vsb; break; case 5: modulationFormat = ModulationType.Mod16Vsb; break; case 6: modulationFormat = ModulationType.Mod16Qam; break; case 7: modulationFormat = ModulationType.Mod32Qam; break; case 8: modulationFormat = ModulationType.Mod64Qam; break; case 9: modulationFormat = ModulationType.Mod80Qam; break; case 10: modulationFormat = ModulationType.Mod96Qam; break; case 11: modulationFormat = ModulationType.Mod112Qam; break; case 12: modulationFormat = ModulationType.Mod128Qam; break; case 13: modulationFormat = ModulationType.Mod160Qam; break; case 14: modulationFormat = ModulationType.Mod192Qam; break; case 15: modulationFormat = ModulationType.Mod224Qam; break; case 16: modulationFormat = ModulationType.Mod256Qam; break; case 17: modulationFormat = ModulationType.Mod320Qam; break; case 18: modulationFormat = ModulationType.Mod384Qam; break; case 19: modulationFormat = ModulationType.Mod448Qam; break; case 20: modulationFormat = ModulationType.Mod512Qam; break; case 21: modulationFormat = ModulationType.Mod640Qam; break; case 22: modulationFormat = ModulationType.Mod768Qam; break; case 23: modulationFormat = ModulationType.Mod896Qam; break; case 24: modulationFormat = ModulationType.Mod1024Qam; break; } pointer++; // s/s int symbolRate = ((section[pointer] & 0x0f) << 24) + (section[pointer + 1] << 16) + (section[pointer + 2] << 8) + section[pointer + 3]; pointer += 4; Log.Log.Debug("NIT: modulation mode, transmission system = {0}, inner coding mode = {1}, is split bitstream mode = {2}, modulation format = {3}, symbol rate = {4} s/s", transmissionSystem, innerCodingMode, isSplitBitstreamMode, modulationFormat, symbolRate); if (OnModulationMode != null) { OnModulationMode(transmissionMedium, firstIndex++, transmissionSystem, innerCodingMode, isSplitBitstreamMode, modulationFormat, symbolRate); } }
private void DecodeCarrierDefinition(byte[] section, int endOfSection, ref int pointer, ref byte firstIndex, AtscTransmissionMedium transmissionMedium) { if (pointer + 5 > endOfSection) { throw new Exception(string.Format("NIT: corruption detected at carrier definition, pointer = {0}, end of section = {1}", pointer, endOfSection)); } byte numberOfCarriers = section[pointer++]; int spacingUnit = 10; // kHz if ((section[pointer] & 0x80) != 0) { spacingUnit = 125; // kHz } int frequencySpacing = spacingUnit * (((section[pointer] & 0x3f) << 8) + section[pointer + 1]); // kHz pointer += 2; int frequencyUnit = 10; // kHz if ((section[pointer] & 0x80) != 0) { frequencyUnit = 125; // kHz } int firstCarrierFrequency = frequencyUnit * (((section[pointer] & 0x7f) << 8) + section[pointer + 1]); // kHz pointer += 2; Log.Log.Debug("NIT: carrier definition, number of carriers = {0}, spacing unit = {1} kHz, frequency spacing = {2} kHz, frequency unit = {3} kHz, first carrier frequency = {4} kHz", numberOfCarriers, spacingUnit, frequencySpacing, frequencyUnit, firstCarrierFrequency); if (OnCarrierDefinition != null) { int carrierFrequency = firstCarrierFrequency; for (byte f = 0; f < numberOfCarriers; f++) { OnCarrierDefinition(transmissionMedium, firstIndex++, carrierFrequency); carrierFrequency += frequencySpacing; } } }
public void Decode(byte[] section) { if (OnTableComplete == null) { return; } if (section.Length < 13) { Log.Log.Error("NIT: invalid section size {0}, expected at least 13 bytes", section.Length); return; } byte tableId = section[2]; if (tableId != 0xc2) { return; } int sectionLength = ((section[3] & 0xf) << 8) + section[4]; if (section.Length != 2 + sectionLength + 3) // 2 for section length bytes, 3 for table ID and PID { Log.Log.Error("NIT: invalid section length = {0}, byte count = {1}", sectionLength, section.Length); return; } int protocolVersion = (section[5] & 0x1f); byte firstIndex = section[6]; byte numberOfRecords = section[7]; AtscTransmissionMedium transmissionMedium = (AtscTransmissionMedium)(section[8] >> 4); TableSubtype tableSubtype = (TableSubtype)(section[8] & 0x0f); if ((tableSubtype != TableSubtype.CarrierDefinition || OnCarrierDefinition == null) && (tableSubtype != TableSubtype.ModulationMode || OnModulationMode == null)) { return; } int pointer = 9; int endOfSection = section.Length - 4; byte satelliteId = 0; if (tableSubtype == TableSubtype.TransponderData) { if (pointer >= endOfSection) { Log.Log.Error("NIT: invalid section length at satellite ID, pointer = {0}, end of section = {1}", pointer, endOfSection); return; } satelliteId = section[pointer++]; } Log.Log.Debug("NIT: section length = {0}, protocol version = {1}, first index = {2}, number of records = {3}, transmission medium = {4}, table subtype = {5}, satellite ID = {6}", sectionLength, protocolVersion, firstIndex, numberOfRecords, transmissionMedium, tableSubtype, satelliteId); for (byte i = 0; i < numberOfRecords; i++) { try { switch (tableSubtype) { case TableSubtype.CarrierDefinition: DecodeCarrierDefinition(section, endOfSection, ref pointer, ref firstIndex, transmissionMedium); break; case TableSubtype.ModulationMode: DecodeModulationMode(section, endOfSection, ref pointer, ref firstIndex, transmissionMedium); break; case TableSubtype.SatelliteInformation: DecodeSatelliteInformation(section, endOfSection, ref pointer); break; case TableSubtype.TransponderData: DecodeTransponderData(section, endOfSection, ref pointer); break; default: Log.Log.Error("NIT: unsupported table subtype {0}", tableSubtype); return; } } catch (Exception ex) { Log.Log.Error(ex.Message); return; } // table descriptors if (pointer >= endOfSection) { Log.Log.Error("NIT: invalid section length at table descriptor count, pointer = {0}, end of section = {1}, loop = {2}", pointer, endOfSection, i); return; } byte descriptorCount = section[pointer++]; for (byte d = 0; d < descriptorCount; d++) { if (pointer + 2 > endOfSection) { Log.Log.Error("NIT: detected table descriptor count {0} is invalid, pointer = {1}, end of section = {2}, loop = {3}, inner loop = {4}", descriptorCount, pointer, endOfSection, i, d); return; } byte tag = section[pointer++]; byte length = section[pointer++]; Log.Log.Debug("NIT: table descriptor, tag = 0x{0:x}, length = {1}", tag, length); if (pointer + length > endOfSection) { Log.Log.Error("NIT: invalid table descriptor length {0}, pointer = {1}, end of section = {2}, loop = {3}, inner loop = {4}", length, pointer, endOfSection, i, d); return; } pointer += length; } } while (pointer + 1 < endOfSection) { byte tag = section[pointer++]; byte length = section[pointer++]; Log.Log.Debug("NIT: descriptor, tag = 0x{0:x}, length = {1}", tag, length); if (pointer + length > endOfSection) { Log.Log.Error("NIT: invalid descriptor length {0}, pointer = {1}, end of section = {2}", length, pointer, endOfSection); return; } if (tag == 0x93) { DecodeRevisionDetectionDescriptor(section, pointer, length, (int)tableSubtype); } pointer += length; } if (pointer != endOfSection) { Log.Log.Error("NIT: corruption detected at end of section, pointer = {0}, end of section = {1}", pointer, endOfSection); return; } if (tableSubtype == TableSubtype.CarrierDefinition && ( _currentVersions[(int)TableSubtype.CarrierDefinition] == -1 || _unseenSections[(int)TableSubtype.CarrierDefinition].Count == 0 ) && OnCarrierDefinition != null) { OnCarrierDefinition = null; if (OnModulationMode == null && OnTableComplete != null) { OnTableComplete(MgtTableType.NitCds); OnTableComplete = null; } } else if (tableSubtype == TableSubtype.ModulationMode && ( _currentVersions[(int)TableSubtype.ModulationMode] == -1 || _unseenSections[(int)TableSubtype.ModulationMode].Count == 0 ) && OnModulationMode != null) { OnModulationMode = null; if (OnCarrierDefinition == null && OnTableComplete != null) { OnTableComplete(MgtTableType.NitMms); OnTableComplete = null; } } }
public void Decode(byte[] section) { if (OnTableComplete == null) { return; } if (section.Length < 13) { Log.Log.Error("S-VCT: invalid section size {0}, expected at least 13 bytes", section.Length); return; } byte tableId = section[2]; if (tableId != 0xc4) { return; } int sectionLength = ((section[3] & 0x0f) << 8) + section[4]; if (section.Length != 2 + sectionLength + 3) // 2 for section length bytes, 3 for table ID and PID { Log.Log.Error("S-VCT: invalid section length = {0}, byte count = {1}", sectionLength, section.Length); return; } byte protocolVersion = (byte)(section[5] & 0x1f); AtscTransmissionMedium transmissionMedium = (AtscTransmissionMedium)(section[6] >> 4); TableSubtype tableSubtype = (TableSubtype)(section[6] & 0x0f); int vctId = (section[7] << 8) + section[8]; Log.Log.Debug("S-VCT: section length = {0}, protocol version = {1}, transmission medium = {2}, table subtype = {3}, VCT ID = 0x{4:x}", sectionLength, protocolVersion, transmissionMedium, tableSubtype, vctId); int pointer = 9; int endOfSection = section.Length - 4; try { switch (tableSubtype) { case TableSubtype.DefinedChannelMap: DecodeDefinedChannelMap(section, endOfSection, ref pointer); break; case TableSubtype.VirtualChannelMap: DecodeVirtualChannelMap(section, endOfSection, ref pointer, transmissionMedium, vctId); break; case TableSubtype.InverseChannelMap: DecodeInverseChannelMap(section, endOfSection, ref pointer); break; default: Log.Log.Error("S-VCT: unsupported table subtype {0}", tableSubtype); return; } } catch (Exception ex) { Log.Log.Error(ex.Message); return; } while (pointer + 1 < endOfSection) { byte tag = section[pointer++]; byte length = section[pointer++]; Log.Log.Debug("S-VCT: descriptor, tag = 0x{0:x}, length = {1}", tag, length); if (pointer + length > endOfSection) { Log.Log.Error("S-VCT: invalid descriptor length {0}, pointer = {1}, end of section = {2}", length, pointer, endOfSection); return; } if (tag == 0x93) // revision detection descriptor { DecodeRevisionDetectionDescriptor(section, pointer, length, (int)tableSubtype); } pointer += length; } if (pointer != endOfSection) { Log.Log.Error("S-VCT: corruption detected at end of section, pointer = {0}, end of section = {1}", pointer, endOfSection); return; } // Two methods for detecting S-VCT VCM completion: // 1. Revision detection descriptors. // 2. DCM channel count equals VCM channel count. if ( ( tableSubtype == TableSubtype.VirtualChannelMap && _currentVersions[(int)TableSubtype.VirtualChannelMap] != -1 && _unseenSections[(int)TableSubtype.VirtualChannelMap].Count == 0 && OnTableComplete != null ) || ( (tableSubtype == TableSubtype.DefinedChannelMap || tableSubtype == TableSubtype.VirtualChannelMap) && _currentVersions[(int)TableSubtype.VirtualChannelMap] == -1 && _channelDefinitions.Count == _definedChannels.Count && OnTableComplete != null ) ) { OnTableComplete(MgtTableType.SvctVcm); OnTableComplete = null; OnChannelDetail = null; } }
private void DecodeSourceName(byte[] section, int endOfSection, ref int pointer, AtscTransmissionMedium transmissionMedium) { if (pointer >= endOfSection) { throw new Exception(string.Format("NTT: corruption detected at source name, pointer = {0}, end of section = {1}", pointer, endOfSection)); } byte numberOfSntRecords = section[pointer++]; for (byte i = 0; i < numberOfSntRecords; i++) { if (pointer + 5 > endOfSection) { throw new Exception(string.Format("NTT: detected source name table number of SNT records {0} is invalid, pointer = {1}, end of section = {2}, loop = {3}", numberOfSntRecords, pointer, endOfSection, i)); } bool applicationType = ((section[pointer++] & 0x80) != 0); int sourceId = (section[pointer] << 8) + section[pointer + 1]; pointer += 2; byte nameLength = section[pointer++]; if (pointer + nameLength > endOfSection) { throw new Exception(string.Format("NTT: invalid source name table string length {0}, pointer = {1}, end of section = {2}, loop = {3}", nameLength, pointer, endOfSection, i)); } string sourceName = DecodeMultilingualText(section, pointer + nameLength, ref pointer); Log.Log.Debug("NTT: source name, source ID = 0x{0:x}, name = {1}, application type = {2}", sourceId, sourceName, applicationType); if (OnSourceName != null) { OnSourceName(transmissionMedium, applicationType, sourceId, sourceName); } // table descriptors if (pointer >= endOfSection) { throw new Exception(string.Format("NTT: invalid section length at source name table 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("NTT: detected source name table 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("NTT: source name table descriptor, tag = 0x{0:x}, length = {1}", tag, length); if (pointer + length > endOfSection) { throw new Exception(string.Format("NTT: invalid source name table descriptor length {0}, pointer = {1}, end of section = {2}, loop = {3}, inner loop = {4}", length, pointer, endOfSection, i, d)); } pointer += length; } } }
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; } } } }