Esempio n. 1
0
    public void OnLvctChannelDetail(MgtTableType tableType, string shortName, int majorChannelNumber, int minorChannelNumber,
      ModulationMode modulationMode, uint carrierFrequency, int channelTsid, int programNumber, EtmLocation etmLocation,
      bool accessControlled, bool hidden, int pathSelect, bool outOfBand, bool hideGuide, AtscServiceType serviceType, int sourceId)
    {
      if (programNumber == 0 || outOfBand || modulationMode == ModulationMode.Analog || modulationMode == ModulationMode.PrivateDescriptor ||
        (serviceType != AtscServiceType.Audio && serviceType != AtscServiceType.DigitalTelevision) || sourceId == 0)
      {
        // Not tunable/supported.
        return;
      }

      ATSCChannel channel = null;
      if (_channels.TryGetValue(sourceId, out channel))
      {
        Log.Log.Info("DRI CC: received repeated L-VCT channel detail for source 0x{0:x}", sourceId);
        return;
      }

      channel = new ATSCChannel();
      _channels.Add(sourceId, channel);

      carrierFrequency /= 1000; // Hz => kHz
      if (carrierFrequency > 1750)
      {
        // Convert from centre frequency to the analog video carrier
        // frequency. This is a BDA convention.
        channel.Frequency = carrierFrequency - 1750;
      }
      channel.PhysicalChannel = ATSCChannel.GetPhysicalChannelFromFrequency((int)carrierFrequency);

      switch (modulationMode)
      {
        case ModulationMode.Atsc8Vsb:
          channel.ModulationType = ModulationType.Mod8Vsb;
          break;
        case ModulationMode.Atsc16Vsb:
          channel.ModulationType = ModulationType.Mod16Vsb;
          break;
        case ModulationMode.ScteMode1:
          channel.ModulationType = ModulationType.Mod64Qam;
          break;
        default:
          channel.ModulationType = ModulationType.Mod256Qam;
          break;
      }
      channel.FreeToAir = !accessControlled;
      channel.IsTv = (serviceType == AtscServiceType.DigitalTelevision);
      channel.IsRadio = (serviceType == AtscServiceType.Audio);
      if (minorChannelNumber == 0)
      {
        channel.LogicalChannelNumber = majorChannelNumber;
      }
      else
      {
        channel.LogicalChannelNumber = (majorChannelNumber * 1000) + minorChannelNumber;
      }
      channel.Name = shortName;
      if (tableType == MgtTableType.TvctCurrentNext1 || tableType == MgtTableType.TvctCurrentNext0)
      {
        channel.Provider = "Terrestrial";
      }
      else
      {
        channel.Provider = "Cable";
      }
      channel.NetworkId = sourceId;
      channel.PmtPid = 0;   // TV Server will automatically lookup the correct PID from the PAT
      channel.ServiceId = programNumber;
      channel.TransportId = channelTsid;
    }
Esempio n. 2
0
        public void OnLvctChannelDetail(MgtTableType tableType, string shortName, int majorChannelNumber, int minorChannelNumber,
                                        ModulationMode modulationMode, uint carrierFrequency, int channelTsid, int programNumber, EtmLocation etmLocation,
                                        bool accessControlled, bool hidden, int pathSelect, bool outOfBand, bool hideGuide, AtscServiceType serviceType, int sourceId)
        {
            if (programNumber == 0 || outOfBand || modulationMode == ModulationMode.Analog || modulationMode == ModulationMode.PrivateDescriptor ||
                (serviceType != AtscServiceType.Audio && serviceType != AtscServiceType.DigitalTelevision) || sourceId == 0)
            {
                // Not tunable/supported.
                return;
            }

            ATSCChannel channel = null;

            if (_channels.TryGetValue(sourceId, out channel))
            {
                Log.Log.Info("DRI CC: received repeated L-VCT channel detail for source 0x{0:x}", sourceId);
                return;
            }

            channel = new ATSCChannel();
            _channels.Add(sourceId, channel);

            carrierFrequency /= 1000; // Hz => kHz
            if (carrierFrequency > 1750)
            {
                // Convert from centre frequency to the analog video carrier
                // frequency. This is a BDA convention.
                channel.Frequency = carrierFrequency - 1750;
            }
            channel.PhysicalChannel = ATSCChannel.GetPhysicalChannelFromFrequency((int)carrierFrequency);

            switch (modulationMode)
            {
            case ModulationMode.Atsc8Vsb:
                channel.ModulationType = ModulationType.Mod8Vsb;
                break;

            case ModulationMode.Atsc16Vsb:
                channel.ModulationType = ModulationType.Mod16Vsb;
                break;

            case ModulationMode.ScteMode1:
                channel.ModulationType = ModulationType.Mod64Qam;
                break;

            default:
                channel.ModulationType = ModulationType.Mod256Qam;
                break;
            }
            channel.FreeToAir = !accessControlled;
            channel.IsTv      = (serviceType == AtscServiceType.DigitalTelevision);
            channel.IsRadio   = (serviceType == AtscServiceType.Audio);
            if (minorChannelNumber == 0)
            {
                channel.LogicalChannelNumber = majorChannelNumber;
            }
            else
            {
                channel.LogicalChannelNumber = (majorChannelNumber * 1000) + minorChannelNumber;
            }
            channel.Name = shortName;
            if (tableType == MgtTableType.TvctCurrentNext1 || tableType == MgtTableType.TvctCurrentNext0)
            {
                channel.Provider = "Terrestrial";
            }
            else
            {
                channel.Provider = "Cable";
            }
            channel.NetworkId   = sourceId;
            channel.PmtPid      = 0; // TV Server will automatically lookup the correct PID from the PAT
            channel.ServiceId   = programNumber;
            channel.TransportId = channelTsid;
        }
        public void Decode(byte[] section)
        {
            if (OnTableComplete == null)
            {
                return;
            }
            if (section.Length < 18)
            {
                Log.Log.Error("L-VCT: invalid section size {0}, expected at least 18 bytes", section.Length);
                return;
            }

            byte tableId = section[2];

            // 0xc8 = ATSC terrestrial, A-65
            // 0xc9 = SCTE cable, SCTE-65
            // The cable and terrestrial L-VCT formats are almost identical. The few
            // differences are noted below.
            if (tableId != 0xc8 && tableId != 0xc9)
            {
                return;
            }
            MgtTableType tableType = MgtTableType.CvctCurrentNext1;

            if (tableId == 0xc8)
            {
                tableType = MgtTableType.TvctCurrentNext1;
            }
            bool sectionSyntaxIndicator = ((section[3] & 0x80) != 0);
            bool privateIndicator       = ((section[3] & 0x40) != 0);
            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("L-VCT: invalid section length = {0}, byte count = {1}", sectionLength, section.Length);
                return;
            }
            int  transportStreamId    = (section[5] << 8) + section[6];
            int  versionNumber        = ((section[7] >> 1) & 0x1f);
            bool currentNextIndicator = ((section[7] & 0x80) != 0);

            if (!currentNextIndicator)
            {
                // Not applicable yet.
                return;
            }
            byte sectionNumber     = section[8];
            byte lastSectionNumber = section[9];
            int  sectionKey        = (tableId << 8) + sectionNumber;

            if (versionNumber > _currentVersion || (_currentVersion == 31 && versionNumber < _currentVersion))
            {
                _currentVersion = versionNumber;
                _unseenSections.Clear();
                for (int s = 0; s <= lastSectionNumber; s++)
                {
                    _unseenSections.Add((tableId << 8) + s);
                }
            }
            else if (!_unseenSections.Contains(sectionKey))
            {
                // Already seen this section.
                return;
            }

            byte protocolVersion      = section[10];
            int  numChannelsInSection = section[11];

            Log.Log.Debug("L-VCT: section length = {0}, transport stream ID = 0x{1:x}, version number = {2}, section number = {3}, last section number {4}, protocol version = {5}, number of channels in section = 0x{6:x}",
                          sectionLength, transportStreamId, versionNumber, sectionNumber, lastSectionNumber, protocolVersion, numChannelsInSection);

            int pointer      = 12;
            int endOfSection = section.Length - 4;

            for (int i = 0; i < numChannelsInSection; i++)
            {
                if (pointer + 32 + 2 > endOfSection) // + 2 for the fixed bytes after the loop
                {
                    Log.Log.Error("L-VCT: detected number of channels in section {0} is invalid, pointer = {1}, end of section = {2}, loop = {3}", numChannelsInSection, pointer, endOfSection, i);
                    return;
                }

                string shortName = System.Text.Encoding.Unicode.GetString(section, pointer, 14);
                pointer += 14;

                // SCTE cable supports both one-part and two-part channel numbers where
                // the major and minor channel number range is 0..999.
                // ATSC supports only two-part channel numbers where the major range is
                // 1..99 and the minor range is 0..999.
                // When the minor channel number is 0 it indicates an analog channel.
                int majorChannelNumber = ((section[pointer] & 0x0f) << 6) + (section[pointer + 1] >> 2);
                pointer++;
                int minorChannelNumber = ((section[pointer] & 0x03) << 8) + section[pointer + 1];
                pointer += 2;
                if ((majorChannelNumber & 0x03f0) == 0x03f0)
                {
                    majorChannelNumber = ((majorChannelNumber & 0x0f) << 10) + minorChannelNumber;
                    minorChannelNumber = 0;
                }

                ModulationMode modulationMode   = (ModulationMode)section[pointer++];
                uint           carrierFrequency = 0; // Hz
                for (byte b = 0; b < 4; b++)
                {
                    carrierFrequency = carrierFrequency << 8;
                    carrierFrequency = section[pointer++];
                }
                int channelTsid = (section[pointer] << 8) + section[pointer + 1];
                pointer += 2;
                int programNumber = (section[pointer] << 8) + section[pointer + 1];
                pointer += 2;
                EtmLocation     etmLocation      = (EtmLocation)(section[pointer] >> 6); // ATSC only, SCTE reserved
                bool            accessControlled = ((section[pointer] & 0x20) != 0);
                bool            hidden           = ((section[pointer] & 0x10) != 0);
                int             pathSelect       = ((section[pointer] & 0x08) >> 3); // SCTE only, ATSC reserved
                bool            outOfBand        = ((section[pointer] & 0x04) != 0); // SCTE only, ATSC reserved
                bool            hideGuide        = ((section[pointer++] & 0x02) != 0);
                AtscServiceType serviceType      = (AtscServiceType)(section[pointer++] & 0x3f);
                int             sourceId         = (section[pointer] << 8) + section[pointer + 1];
                pointer += 2;
                Log.Log.Debug("L-VCT: channel, short name = {0}, major channel number = {1}, minor channel number = {2}, modulation mode = {3}, carrier frequency = {4} Hz, TSID = 0x{5:x}, program number = 0x{6:x}, ETM location = {7}, access controlled = {8}, hidden = {9}, path select = {10}, out of band = {11}, hide guide = {12}, service type = {13}, source ID = 0x{14:x}",
                              shortName, majorChannelNumber, minorChannelNumber, modulationMode, carrierFrequency, channelTsid, programNumber,
                              etmLocation, accessControlled, hidden, pathSelect, outOfBand, hideGuide, serviceType, sourceId);

                if (OnChannelDetail != null)
                {
                    OnChannelDetail(tableType, shortName, majorChannelNumber, minorChannelNumber, modulationMode, carrierFrequency, channelTsid,
                                    programNumber, etmLocation, accessControlled, hidden, pathSelect, outOfBand, hideGuide, serviceType, sourceId);
                }

                int descriptorsLength = ((section[pointer] & 0x03) << 8) + section[pointer + 1];
                pointer += 2;
                int endOfDescriptors = pointer + descriptorsLength;
                if (endOfDescriptors > endOfSection)
                {
                    Log.Log.Error("L-VCT: invalid descriptors length {0}, pointer = {1}, end of section = {2}, loop = {3}", descriptorsLength, pointer, endOfSection, i);
                    return;
                }
                while (pointer + 1 < endOfDescriptors)
                {
                    byte tag    = section[pointer++];
                    byte length = section[pointer++];
                    Log.Log.Debug("L-VCT: descriptor, tag = 0x{0:x}, length = {1}", tag, length);
                    if (pointer + length > endOfDescriptors)
                    {
                        Log.Log.Error("L-VCT: invalid descriptor length {0}, pointer = {1}, end of descriptors = {2}, loop = {3}", length, pointer, endOfDescriptors, i);
                        return;
                    }
                    pointer += length;
                }
                if (pointer != endOfDescriptors)
                {
                    Log.Log.Error("L-VCT: corruption detected at end of descriptors, pointer = {0}, end of section = {1}, end of descriptors = {2}, loop = {3}", pointer, endOfSection, endOfDescriptors, i);
                    return;
                }
            }

            int additionalDescriptorsLength = ((section[pointer] & 0x03) << 8) + section[pointer + 1];

            pointer += 2;
            if (pointer + additionalDescriptorsLength != endOfSection)
            {
                Log.Log.Error("L-VCT: invalid additional descriptors length {0}, pointer = {1}, end of section = {2}", additionalDescriptorsLength, pointer, endOfSection);
                return;
            }
            while (pointer + 1 < endOfSection)
            {
                byte tag    = section[pointer++];
                byte length = section[pointer++];
                Log.Log.Debug("L-VCT: additional descriptor, tag = 0x{0:x}, length = {1}", tag, length);
                if (pointer + length > endOfSection)
                {
                    Log.Log.Error("L-VCT: invalid additional descriptor length {0}, pointer = {1}, end of section = {2}", length, pointer, endOfSection);
                    return;
                }
                pointer += length;
            }

            if (pointer != endOfSection)
            {
                Log.Log.Error("L-VCT: corruption detected at end of section, pointer = {0}, end of section = {1}", pointer, endOfSection);
                return;
            }

            _unseenSections.Remove(sectionKey);
            if (_unseenSections.Count == 0 && OnTableComplete != null)
            {
                OnTableComplete(tableType);
                OnTableComplete = null;
                OnChannelDetail = null;
            }
        }