class holding all information about a channel including pids
Beispiel #1
0
 /// <summary>
 /// Creates the new channel.
 /// </summary>
 /// <param name="channel">The high level tuning detail.</param>
 /// <param name="info">The subchannel detail.</param>
 /// <returns>The new channel.</returns>
 protected override IChannel CreateNewChannel(IChannel channel, ChannelInfo info)
 {
   DVBSChannel tuningChannel = (DVBSChannel)channel;
   DVBSChannel dvbsChannel = new DVBSChannel();
   dvbsChannel.Name = info.service_name;
   dvbsChannel.LogicalChannelNumber = info.LCN;
   dvbsChannel.Provider = info.service_provider_name;
   dvbsChannel.SymbolRate = tuningChannel.SymbolRate;
   dvbsChannel.Polarisation = tuningChannel.Polarisation;
   dvbsChannel.SwitchingFrequency = tuningChannel.SwitchingFrequency;
   dvbsChannel.Frequency = tuningChannel.Frequency;
   dvbsChannel.IsTv = IsTvService(info.serviceType);
   dvbsChannel.IsRadio = IsRadioService(info.serviceType);
   dvbsChannel.NetworkId = info.networkID;
   dvbsChannel.ServiceId = info.serviceID;
   dvbsChannel.TransportId = info.transportStreamID;
   dvbsChannel.PmtPid = info.network_pmt_PID;
   dvbsChannel.DisEqc = tuningChannel.DisEqc;
   dvbsChannel.BandType = tuningChannel.BandType;
   dvbsChannel.FreeToAir = !info.scrambled;
   dvbsChannel.SatelliteIndex = tuningChannel.SatelliteIndex;
   dvbsChannel.ModulationType = tuningChannel.ModulationType;
   dvbsChannel.InnerFecRate = tuningChannel.InnerFecRate;
   dvbsChannel.Pilot = tuningChannel.Pilot;
   dvbsChannel.Rolloff = tuningChannel.Rolloff;
   Log.Log.Write("Found: {0}", dvbsChannel);
   return dvbsChannel;
 }
Beispiel #2
0
 protected override bool IsValidChannel(ChannelInfo info, short hasAudio, short hasVideo)
 {
   //In DVB-IP there are several ways to describe a channel. It is possible that no service type is given. 
   //Until we can fully implement DVB-IP support we check if video or audio is available to determine the channel type.
   if (info.serviceType <= 0)
   {
     if (hasVideo != 0)
     {
       info.serviceType = (int)DvbServiceType.DigitalTelevision;
     }
     else if (hasAudio != 0)
     {
       info.serviceType = (int)DvbServiceType.DigitalRadio;
     }
   } 
   return base.IsValidChannel(info, hasAudio, hasVideo);
 }
Beispiel #3
0
 /// <summary>
 /// CreateNewChannel
 /// </summary>
 /// <param name="channel">The high level tuning detail.</param>
 /// <param name="info">The subchannel detail.</param>
 /// <returns>The new channel.</returns>
 protected override IChannel CreateNewChannel(IChannel channel, ChannelInfo info)
 {
   DVBIPChannel tuningChannel = (DVBIPChannel)channel;
   DVBIPChannel dvbipChannel = new DVBIPChannel();
   dvbipChannel.Name = info.service_name;
   dvbipChannel.LogicalChannelNumber = info.LCN;
   dvbipChannel.Provider = info.service_provider_name;
   dvbipChannel.Url = tuningChannel.Url;
   dvbipChannel.IsTv = IsTvService(info.serviceType);
   dvbipChannel.IsRadio = IsRadioService(info.serviceType);
   dvbipChannel.NetworkId = info.networkID;
   dvbipChannel.ServiceId = info.serviceID;
   dvbipChannel.TransportId = info.transportStreamID;
   dvbipChannel.PmtPid = info.network_pmt_PID;
   dvbipChannel.FreeToAir = !info.scrambled;
   Log.Log.Write("Found: {0}", dvbipChannel);
   return dvbipChannel;
 }
Beispiel #4
0
    /// <summary>
    /// Adds the sub channel.
    /// </summary>
    /// <param name="id">The id.</param>
    /// <param name="channel">The channel</param>
    public void AddSubChannel(int id, IChannel currentChannel, ChannelInfo channelInfo, bool update)
    {
      DVBBaseChannel dvbChannel = currentChannel as DVBBaseChannel;

      if (dvbChannel != null)
      {
        bool isChannelAlreadyDecoding = IsChannelAlreadyDecoding(dvbChannel.Name);

        if (!_mapSubChannels.ContainsKey(id))
        {
          _mapSubChannels[id] = dvbChannel;
        }
        
        if (!isChannelAlreadyDecoding)
        {
          SetChannel(currentChannel, channelInfo, update); 
        }        
      }
    }
 /// <summary>
 /// Creates the new channel.
 /// </summary>
 /// <param name="channel">The high level tuning detail.</param>
 /// <param name="info">The subchannel detail.</param>
 /// <returns>The new channel.</returns>
 protected override IChannel CreateNewChannel(IChannel channel, ChannelInfo info)
 {
   ATSCChannel tuningChannel = (ATSCChannel)channel;
   ATSCChannel atscChannel = new ATSCChannel();
   atscChannel.Name = info.service_name;
   atscChannel.LogicalChannelNumber = info.LCN;
   atscChannel.Provider = info.service_provider_name;
   atscChannel.ModulationType = tuningChannel.ModulationType;
   atscChannel.Frequency = tuningChannel.Frequency;
   atscChannel.PhysicalChannel = tuningChannel.PhysicalChannel;
   atscChannel.MajorChannel = info.majorChannel;
   atscChannel.MinorChannel = info.minorChannel;
   atscChannel.IsTv = IsTvService(info.serviceType);
   atscChannel.IsRadio = IsRadioService(info.serviceType);
   atscChannel.NetworkId = info.networkID;
   atscChannel.ServiceId = info.serviceID;
   atscChannel.TransportId = info.transportStreamID;
   atscChannel.PmtPid = info.network_pmt_PID;
   atscChannel.FreeToAir = !info.scrambled;
   Log.Log.Write("atsc:Found: {0}", atscChannel);
   return atscChannel;
 }
Beispiel #6
0
    /// <summary>
    /// Initializes a new instance of the <see cref="HDPVRChannel"/> class.
    /// </summary>
    public HDPVRChannel(TvCardHDPVR card, String deviceType, Int32 subchannelId, IBaseFilter filterTsWriter, IFilterGraph2 graphBuilder)
    {
      _eventPMT = new ManualResetEvent(false);
      _graphState = GraphState.Created;
      _graphBuilder = graphBuilder;
      _channelInfo = new ChannelInfo();
      _pmtPid = -1;
      _subChannelIndex = -1;

      // Keep a reference to the card for quality control.
      _card = card;
      _deviceType = deviceType;

      _tsFilterInterface = (ITsFilter)filterTsWriter;
      _tsFilterInterface.AddChannel(ref _subChannelIndex);
      _subChannelId = subchannelId;
      _timeshiftFileName = "";
      _recordingFileName = "";
      _pmtData = null;
      _pmtLength = 0;

      _grabTeletext = false;
      _mdplugs = null;
    }
 /// <summary>
 /// Should be called before tuning to a new channel
 /// resets the state
 /// </summary>
 public override void OnBeforeTune()
 {
   Log.Log.WriteFile("subch:{0} OnBeforeTune", _subChannelId);
   if (IsTimeShifting && _subChannelIndex >= 0)
   {
     _tsFilterInterface.TimeShiftPause(_subChannelIndex, 1);
   }
   _startTimeShifting = false;
   _startRecording = false;
   _channelInfo = new ChannelInfo();
   _hasTeletext = false;
   _currentAudioStream = null;
 }
 protected override void SetNameForUnknownChannel(IChannel channel, ChannelInfo info)
 {
   if (((ATSCChannel)channel).Frequency > 0)
   {
     Log.Log.Info("DVBBaseScanning: service_name is null so now = Unknown {0}-{1}",
                  ((ATSCChannel)channel).Frequency, info.serviceID);
     info.service_name = String.Format("Unknown {0}-{1:X}", ((ATSCChannel)channel).Frequency,
                                       info.serviceID);
   }
   else
   {
     Log.Log.Info("DVBBaseScanning: service_name is null so now = Unknown {0}-{1}",
                  ((ATSCChannel)channel).PhysicalChannel, info.serviceID);
     info.service_name = String.Format("Unknown {0}-{1:X}", ((ATSCChannel)channel).PhysicalChannel,
                                       info.serviceID);
   }
 }
Beispiel #9
0
    private bool HandlePmt()
    {
      IntPtr pmtMem = Marshal.AllocCoTaskMem(4096); // max. size for pmt
      try
      {
        _pmtLength = _tsFilterInterface.PmtGetPMTData(_subChannelIndex, pmtMem);
        if (_pmtLength < 6)
        {
          return false;
        }

        // Check the program number.
        _pmtData = new byte[_pmtLength];
        Marshal.Copy(pmtMem, _pmtData, 0, _pmtLength);
        int version = ((_pmtData[5] >> 1) & 0x1F);
        int pmtProgramNumber = (_pmtData[3] << 8) + _pmtData[4];
        Log.Log.Info("HDPVR: PMT sid=0x{0:X} pid=0x{1:X} version=0x{2:X}", pmtProgramNumber, _pmtPid, version);
        if (pmtProgramNumber != SERVICE_ID)
        {
          throw new TvException("HDPVRChannel: PMT program number doesn't match expected service ID");
        }

        // Get the program PIDs.
        _pmtVersion = version;
        _channelInfo = new ChannelInfo();
        _channelInfo.DecodePmt(_pmtData);
        _channelInfo.serviceID = pmtProgramNumber;
        _channelInfo.network_pmt_PID = _pmtPid;
        SetMpegPidMapping(_channelInfo);
        return true;
      }
      finally
      {
        Marshal.FreeCoTaskMem(pmtMem);
      }
    }
    /// <summary>
    /// Sends the PMT to the CI module
    /// </summary>
    /// <param name="subChannel">The sub channel.</param>
    /// <param name="channel">channel on which we are tuned</param>
    /// <param name="PMT">byte array containing the PMT</param>
    /// <param name="pmtLength">length of the pmt array</param>
    /// <param name="audioPid">pid of the current audio stream</param>
    /// <returns></returns>
    public bool SendPMT(int subChannel, DVBBaseChannel channel, byte[] PMT, int pmtLength, int audioPid)
    {
      try
      {
        if (!_useCam)
          return true;
        if (channel.FreeToAir)
          return true; //no need to descramble this one...

        AddSubChannel(subChannel, channel);
        ConditionalAccessContext context = _mapSubChannels[subChannel];
        context.CamType = _CamType;
        context.Channel = channel;
        if (_CamType == CamType.Astoncrypt2)
        {
          int newLength;
          context.PMT = PatchPMT_AstonCrypt2(PMT, pmtLength, out newLength);
          context.PMTLength = newLength;
        }
        else
        {
          context.PMT = PMT;
          context.PMTLength = pmtLength;
        }
        context.AudioPid = audioPid;
        context.ServiceId = channel.ServiceId;

        if (_winTvCiModule != null)
        {
          int hr = _winTvCiModule.SendPMT(PMT, pmtLength);
          if (hr != 0)
          {
            Log.Log.Info("Conditional Access:  sendPMT to WinTVCI failed");
            return false;
          }
          Log.Log.Info("Conditional Access:  sendPMT to WinTVCI succeeded");
          return true;
        }
        if (_knc != null)
        {
          ChannelInfo info = new ChannelInfo();
          info.DecodePmt(PMT);
          int caPmtLen;
          byte[] caPmt = info.caPMT.CaPmtStruct(out caPmtLen);
          return _knc.SendPMT(caPmt, caPmtLen);
        }
        if (_DigitalDevices != null)
        {
          return _DigitalDevices.SendServiceIdToCam(channel.ServiceId);
        }
        if (_digitalEveryWhere != null)
        {
          return _digitalEveryWhere.SendPMTToFireDTV(_mapSubChannels);
        }
        if (_technoTrend != null)
        {
          return _technoTrend.DescrambleMultiple(_mapSubChannels);
          // return _technoTrend.SendPMT(PMT, pmtLength);
        }
        if (_twinhan != null)
        {
          ChannelInfo info = new ChannelInfo();
          info.DecodePmt(PMT);

          int caPmtLen;
          byte[] caPmt = info.caPMT.CaPmtStruct(out caPmtLen);
          return _twinhan.SendPMT(caPmt, caPmtLen);
        }
      }
      catch (Exception ex)
      {
        Log.Log.Write(ex);
      }
      return true;
    }
Beispiel #11
0
    /// <summary>
    /// Sends the current channel to the mdapifilter
    /// </summary>    
    private void SetChannel(IChannel currentChannel, ChannelInfo channelInfo, bool update)
    {
      MDPlug[] plugins = getPlugins();
      MDPlug myPlugin = null;

      if (plugins == null || plugins.Length == 0)
      {
        Log.Log.Info("mdplug: SetChannel no MD plugins has been defined for card folder {0}.", _cardFolder);
        return;
      }

      foreach (MDPlug plugin in plugins)
      {
        if (plugin.IsDecodingChannel(currentChannel))
        {
          myPlugin = plugin;
          break;
        }
      }

      if (update)
      {
        // PMT is updated, do not increase ref count
        if (myPlugin != null)
        {
          Log.Log.Info("mdplug: SetChannel update channel {0}.", currentChannel.Name);
          myPlugin.SetChannel(currentChannel, channelInfo);
          return;
        }
        else
        {
          Log.Log.Info("mdplug: SetChannel update channel, channel not found. {0}.", currentChannel.Name);
          return;
        }
      }
      else
      {
        if (myPlugin != null)
        {
          Log.Log.Info("mdplug: SetChannel already decoding channel {0}. Increment counter", currentChannel.Name);
          return;
        } // else not found allocate new slot
      }

      int idx = 1;
      foreach (MDPlug plugin in plugins)
      {
        IChannel chan = plugin.GetDecodingChannel();
        if (chan != null)
        {
          Log.Log.Info("  slot[" + idx + "] {0}", chan.Name);
        }
        idx++;
      }

      int slotNumber;
      MDPlug freePlugin = FindFreeSlot(plugins, currentChannel, out slotNumber);
      if (freePlugin == null)
      {
        Log.Log.Info("mdplug: SetChannel no free slots available for channel {0} (try increase limit).",
                     currentChannel.Name);
        return;
      }

      Log.Log.Info("mdplug: SetChannel nr of currently decoding channels {0}.", CalculateSlotsInUse(plugins));

      Log.Log.Info("mdplug: SetChannel starting decryption on channel '{0}' using plugin slot {1} of {2} avail.",
                   currentChannel.Name, slotNumber, plugins.Length);

      freePlugin.SetChannel(currentChannel, channelInfo);
    }
Beispiel #12
0
 protected override void SetNameForUnknownChannel(IChannel channel, ChannelInfo info)
 {
   if (info.minorChannel > 0)
   {
     // Standard ATSC two part channel number available.
     info.service_name = String.Format("Unknown {0}-{1}", info.majorChannel, info.minorChannel);
   }
   else
   {
     // QAM channel number. Informal standard used by TVs and other clear QAM equipment when PSIP is not available.
     info.service_name = String.Format("Unknown {0}-{1}", ((ATSCChannel)channel).PhysicalChannel, info.serviceID);
   }
   Log.Log.Info("ATSC: service name is not available, so set to {0}", info.service_name);
 }
Beispiel #13
0
 /// <summary>
 /// Creates the new channel.
 /// </summary>
 /// <param name="channel">The high level tuning detail.</param>
 /// <param name="info">The subchannel detail.</param>
 /// <returns>The new channel.</returns>
 protected override IChannel CreateNewChannel(IChannel channel, ChannelInfo info)
 {
   ATSCChannel tuningChannel = (ATSCChannel)channel;
   ATSCChannel atscChannel = new ATSCChannel();
   // When scanning with a CableCARD tuner and/or NIT or VCT frequency info
   // has been received and it looks plausible...
   if (tuningChannel.PhysicalChannel == 0 ||
     (info.freq > 1750 && tuningChannel.Frequency > 0 && info.freq != tuningChannel.Frequency))
   {
     atscChannel.PhysicalChannel = ATSCChannel.GetPhysicalChannelFromFrequency(info.freq);
     // Convert from centre frequency to the analog video carrier
     // frequency. This is a BDA convention.
     atscChannel.Frequency = info.freq - 1750;
   }
   else
   {
     atscChannel.PhysicalChannel = tuningChannel.PhysicalChannel;
     atscChannel.Frequency = tuningChannel.Frequency;
   }
   if (info.minorChannel == 0)
   {
     atscChannel.LogicalChannelNumber = info.majorChannel;
   }
   else
   {
     atscChannel.LogicalChannelNumber = (info.majorChannel * 1000) + info.minorChannel;
   }
   atscChannel.Name = info.service_name;
   atscChannel.Provider = info.service_provider_name;
   atscChannel.ModulationType = tuningChannel.ModulationType;
   atscChannel.MajorChannel = info.majorChannel;
   atscChannel.MinorChannel = info.minorChannel;
   atscChannel.IsTv = IsTvService(info.serviceType);
   atscChannel.IsRadio = IsRadioService(info.serviceType);
   atscChannel.NetworkId = info.networkID;
   atscChannel.ServiceId = info.serviceID;
   atscChannel.TransportId = info.transportStreamID;
   atscChannel.PmtPid = info.network_pmt_PID;
   atscChannel.FreeToAir = !info.scrambled;
   Log.Log.Write("atsc:Found: {0}", atscChannel);
   return atscChannel;
 }
    protected virtual bool IsValidChannel(ChannelInfo info, short hasAudio, short hasVideo)
    {
      // DVB/ATSC compliant services will be picked up here.
      if (IsKnownServiceType(info.serviceType))
      {
        return true;
      }

      // The SDT service type is unfortunately not sufficient for service type
      // identification. DVB-IP and some ATSC broadcasters in particular
      // do not comply with specifications. Well, either that, or we do not
      // fully/properly implement the specifications! In any case we need
      // to err on the side of caution and pick up any channels that TsWriter
      // says have video and/or audio streams until we can find a better
      // way to properly identify TV and radio services.
      if (hasVideo != 0)
      {
        info.serviceType = (int)DvbServiceType.DigitalTelevision;
      }
      else if (hasAudio != 0)
      {
        info.serviceType = (int)DvbServiceType.DigitalRadio;
      }
      return IsKnownServiceType(info.serviceType);
    }
Beispiel #15
0
    /// <summary>
    /// Sends the current channel to the mdapi filter
    /// </summary>
    public void SetChannel(IChannel currentChannel, ChannelInfo channelInfo)
    {
      int Index;
      int end_Index;
      byte[] ANSIName;
      //is mdapi installed?
      if (mdapiFilter == null)
        return; //nop, then return

      //did we already receive the pmt?
      if (channelInfo == null)
        return; //nop, then return
      if (channelInfo.caPMT == null)
        return;
      DVBBaseChannel dvbChannel = currentChannel as DVBBaseChannel;
      if (dvbChannel == null) //not a DVB channel??
        return;

      //set channel name
      if (dvbChannel.Name != null)
      {
        end_Index = _mDPlugTProg82.Name.GetLength(0) - 1;
        ANSIName = System.Text.Encoding.Default.GetBytes(dvbChannel.Name);

        if (ANSIName.GetUpperBound(0) + 1 < end_Index)
        {
          end_Index = ANSIName.GetUpperBound(0) + 1;
        }
        for (Index = 0; Index < end_Index; ++Index)
        {
          _mDPlugTProg82.Name[Index] = ANSIName[Index]; // (byte)dvbChannel.Name[Index];
        }
      }
      else
        end_Index = 0;
      _mDPlugTProg82.Name[end_Index] = 0;

      //set provide name
      if (dvbChannel.Provider != null)
      {
        end_Index = _mDPlugTProg82.Provider.GetLength(0) - 1;
        ANSIName = System.Text.Encoding.Default.GetBytes(dvbChannel.Provider);
        if (ANSIName.GetUpperBound(0) + 1 < end_Index)
          end_Index = ANSIName.GetUpperBound(0) + 1;
        for (Index = 0; Index < end_Index; ++Index)
        {
          _mDPlugTProg82.Provider[Index] = ANSIName[Index];
        }
      }
      else
        end_Index = 0;
      _mDPlugTProg82.Provider[end_Index] = 0;

      //public byte[] Country;
      _mDPlugTProg82.Freq = (uint)dvbChannel.Frequency;
      //public byte PType = (byte);
      _mDPlugTProg82.Afc = 68;
      //_mDPlugTProg82.DiSEqC = (byte)dvbChannel.DisEqc;
      //_mDPlugTProg82.Symbolrate = (uint)dvbChannel.SymbolRate;
      //public byte Qam;

      _mDPlugTProg82.Fec = 0;
      //public byte Norm;
      _mDPlugTProg82.Tp_id = (ushort)dvbChannel.TransportId;
      _mDPlugTProg82.SID_pid = (ushort)dvbChannel.ServiceId;
      _mDPlugTProg82.PMT_pid = (ushort)dvbChannel.PmtPid;
      _mDPlugTProg82.PCR_pid = (ushort)channelInfo.pcrPid;
      _mDPlugTProg82.Video_pid = 0;
      _mDPlugTProg82.Audio_pid = 0;
      _mDPlugTProg82.TeleText_pid = 0;
      _mDPlugTProg82.AC3_pid = 0;
      _mPids2Dec.nbPids = 0;
      foreach (PidInfo pid in channelInfo.pids)
      {
        if (pid.isVideo)
          if (_mDPlugTProg82.Video_pid == 0) //keep the first one
            _mDPlugTProg82.Video_pid = (ushort)pid.pid;

        if (pid.isAudio)
          if (_mDPlugTProg82.Audio_pid == 0) //keep the first one
            _mDPlugTProg82.Audio_pid = (ushort)pid.pid;

        if (pid.isTeletext)
          if (_mDPlugTProg82.TeleText_pid == 0) //keep the first one
            _mDPlugTProg82.TeleText_pid = (ushort)pid.pid;

        if (pid.isAC3Audio)
          if (_mDPlugTProg82.AC3_pid == 0) //keep the first one
            _mDPlugTProg82.AC3_pid = (ushort)pid.pid;

        _mPids2Dec.Pids[_mPids2Dec.nbPids++] = (ushort)pid.pid;
      }
      _mDPlugTProg82.ServiceTyp = currentChannel.IsTv ? (byte)1 : (byte)2;
      //public byte TVType;           //  == 00 PAL ; 11 == NTSC    
      //public ushort Temp_Audio;
      _mDPlugTProg82.FilterNr = 0; //to test
      //public byte[] Filters;  // to simulate struct PIDFilters Filters[MAX_PID_IDS];
      //public byte[] CA_Country;
      //public byte Marker;
      //public ushort Link_TP;
      //public ushort Link_SID;
      _mDPlugTProg82.PDynamic = 0; //to test
      //public byte[] Extern_Buffer;
      if (channelInfo.caPMT != null)
      {
        //get all EMM's (from CAT (pid 0x1))
        List<ECMEMM> emmList = channelInfo.caPMT.GetEMM();
        //13.05.08 GEMX: pmt is not parsed correctly
        //               This is just a quick fix. The pmt parsing has to be reworked
        //               according to the changes made for TsWriter (PmtParser.cpp - bool CPmtParser::DecodePmt(...)
        //if (emmList.Count <= 0) return;
        for (int i = 0; i < emmList.Count; ++i)
        {
          Log.Log.Info("EMM #{0} CA:0x{1:X} EMM:0x{2:X} ID:0x{3:X}",
                       i, emmList[i].CaId, emmList[i].Pid, emmList[i].ProviderId);
        }

        //get all ECM's for this service
        List<ECMEMM> ecmList = channelInfo.caPMT.GetECM();
        for (int i = 0; i < ecmList.Count; ++i)
        {
          Log.Log.Info("ECM #{0} CA:0x{1:X} ECM:0x{2:X} ID:0x{3:X}",
                       i, ecmList[i].CaId, ecmList[i].Pid, ecmList[i].ProviderId);
        }


        //Clearing OLD Values...
        for (int y = 0; y < _mDPlugTProg82.CA_System82.Length; y++)
        {
          _mDPlugTProg82.CA_System82[y].CA_Typ = 0;
          _mDPlugTProg82.CA_System82[y].ECM = 0;
          _mDPlugTProg82.CA_System82[y].EMM = 0;
          _mDPlugTProg82.CA_System82[y].Provider_Id = 0;
        }


        _mDPlugTProg82.CA_Nr = (ushort)ecmList.Count;
        int count = 0;
        for (int x = 0; x < ecmList.Count; ++x)
        {
          _mDPlugTProg82.CA_System82[x].CA_Typ = (ushort)ecmList[x].CaId;
          _mDPlugTProg82.CA_System82[x].ECM = (ushort)ecmList[x].Pid;
          _mDPlugTProg82.CA_System82[x].EMM = 0;
          _mDPlugTProg82.CA_System82[x].Provider_Id = (uint)ecmList[x].ProviderId;
          count++;
        }


        for (int i = 0; i < emmList.Count; ++i)
        {
          bool found = false;
          for (int j = 0; j < count; ++j)
          {
            if ((emmList[i].CaId == _mDPlugTProg82.CA_System82[j].CA_Typ) &&
                (emmList[i].ProviderId == _mDPlugTProg82.CA_System82[j].Provider_Id))
            {
              found = true;
              _mDPlugTProg82.CA_System82[j].EMM = (ushort)emmList[i].Pid;
              break;
            }
          }
          if (!found)
          {
            _mDPlugTProg82.CA_System82[count].CA_Typ = (ushort)emmList[i].CaId;
            _mDPlugTProg82.CA_System82[count].ECM = 0;
            _mDPlugTProg82.CA_System82[count].EMM = (ushort)emmList[i].Pid;
            _mDPlugTProg82.CA_System82[count].Provider_Id = (uint)emmList[i].ProviderId;
            count++;
          }
        }


        _mDPlugTProg82.CA_ID = 0;
        _mDPlugTProg82.CA_Nr = (ushort)count;
        if (count == 0)
        {
          _mDPlugTProg82.ECM_PID = 0;
        }
        else
        {
          _mDPlugTProg82.ECM_PID = _mDPlugTProg82.CA_System82[0].ECM;
        }
        //find preferred ECM from preferred MDAPIProvID.xml file and pointing CA_ID on the right CA_System82 row
        //first search in channel list for individual match, else search for provider ID match else search for CA_Typ match
        string xmlFile = AppDomain.CurrentDomain.BaseDirectory + "MDPLUGINS\\MDAPIProvID.xml";
        if (File.Exists(xmlFile))
        {
          try
          {
            bool providfound = false;
            bool channelfound = false;
            bool catypfound = false;
            int i;
            XmlDocument doc = new XmlDocument();
            doc.Load(xmlFile);

            XmlNode mainNode = doc.SelectSingleNode("/mdapi");
            bool filloutXMLFile;
            if (!((XmlElement)mainNode).HasAttribute("fillout"))
            {
              XmlAttribute fillout = doc.CreateAttribute("fillout");
              fillout.Value = "" + false;
              mainNode.Attributes.Append(fillout);
              doc.Save(xmlFile);
            }

            Boolean.TryParse(mainNode.Attributes["fillout"].Value, out filloutXMLFile);

            Log.Log.Info("mdplug: MDAPIProvID.xml Filling out MDAPIProvID {0} ", filloutXMLFile);

            XmlNodeList channelList = doc.SelectNodes("/mdapi/channels/channel");
            string Tp_id = String.Format("{0:D}", _mDPlugTProg82.Tp_id);
            string SID_pid = String.Format("{0:D}", _mDPlugTProg82.SID_pid);
            string PMT_pid = String.Format("{0:D}", _mDPlugTProg82.PMT_pid);

            if (channelList != null)
              foreach (XmlNode nodechannel in channelList)
              {
                if (nodechannel.Attributes["tp_id"].Value == Tp_id
                    && nodechannel.Attributes["sid"].Value == SID_pid
                    && nodechannel.Attributes["pmt_pid"].Value == PMT_pid)
                {
                  for (i = 0; i < count; ++i)
                  {
                    string ECM_pid = String.Format("{0:D}", _mDPlugTProg82.CA_System82[i].ECM);
                    if (nodechannel.Attributes["ecm_pid"].Value == ECM_pid)
                    {
                      _mDPlugTProg82.CA_ID = (byte)i;
                      _mDPlugTProg82.ECM_PID = _mDPlugTProg82.CA_System82[i].ECM;

                      if (((XmlElement)nodechannel).HasAttribute("emm_pid"))
                      {
                        _mDPlugTProg82.CA_System82[i].EMM =
                          UInt16.Parse(((XmlElement)nodechannel).GetAttribute("emm_pid"));
                      }

                      channelfound = true;
                      break;
                    }
                  }
                  if (channelfound)
                    break;
                }
              }
            if (!channelfound)
            {
              XmlNodeList providList = doc.SelectNodes("/mdapi/providers/provider");
              if (providList != null)
                foreach (XmlNode nodeprovid in providList)
                {
                  for (i = 0; i < count; ++i)
                  {
                    string Provider_Id = String.Format("{0:D}", _mDPlugTProg82.CA_System82[i].Provider_Id);
                    if (nodeprovid.Attributes["ID"].Value == Provider_Id)
                    {
                      _mDPlugTProg82.CA_ID = (byte)i;
                      _mDPlugTProg82.ECM_PID = _mDPlugTProg82.CA_System82[i].ECM;
                      providfound = true;
                      break;
                    }
                  }
                  if (providfound)
                    break;
                }
            }

            if (!channelfound && !providfound)
            {
              XmlNodeList catypList = doc.SelectNodes("/mdapi/CA_Types/CA_Type");
              if (catypList != null)
                foreach (XmlNode nodecatyp in catypList)
                {
                  for (i = 0; i < count; ++i)
                  {
                    string CAtyp_Id = String.Format("{0:D}", _mDPlugTProg82.CA_System82[i].CA_Typ);
                    if (nodecatyp.Attributes["ID"].Value == CAtyp_Id)
                    {
                      _mDPlugTProg82.CA_ID = (byte)i;
                      _mDPlugTProg82.ECM_PID = _mDPlugTProg82.CA_System82[i].ECM;
                      catypfound = true;
                      break;
                    }
                  }
                  if (catypfound)
                    break;
                }
            }
            Log.Log.Info("mdplug: MDAPIProvID.xml mode used = Channel:{0} Provider:{1} Ca_typ:{2}",
                         channelfound,
                         providfound,
                         catypfound);


            if (!channelfound)
            {
              try
              {
                Log.Log.Info("mdapi: Attempting to add entry to MDAPIProvID.xml");

                XmlNode node;
                if (filloutXMLFile && ecmList.Count > 0)
                {
                  node = doc.SelectSingleNode("/mdapi/channels");

                  String comment = "";

                  XmlNode cnode = doc.CreateElement("channel");

                  comment += "Channel Name : " + dvbChannel.Name + " ";

                  XmlAttribute tpid = doc.CreateAttribute("tp_id");
                  tpid.Value = "" + dvbChannel.TransportId;
                  cnode.Attributes.Append(tpid);
                  XmlAttribute sid = doc.CreateAttribute("sid");
                  sid.Value = "" + dvbChannel.ServiceId;
                  cnode.Attributes.Append(sid);
                  XmlAttribute pmt_pid = doc.CreateAttribute("pmt_pid");
                  pmt_pid.Value = "" + dvbChannel.PmtPid;
                  cnode.Attributes.Append(pmt_pid);
                  //CA_ID
                  //_mDPlugTProg82.CA_System82[0].ECM;
                  XmlAttribute ecm_pid = doc.CreateAttribute("ecm_pid");
                  ecm_pid.Value = "" + _mDPlugTProg82.ECM_PID;
                  cnode.Attributes.Append(ecm_pid);

                  String possibleValues = "";
                  for (int x = 0; x < ecmList.Count; ++x)
                  {
                    if (x != 0)
                      possibleValues += ", ";
                    possibleValues += "" + ecmList[x].Pid;
                    //possibleValues += "(" + ecmList[x].CaId + ")";
                    // ecmList[x].CaId;
                    // ecmList[x].Pid;
                    // ecmList[x].ProviderId;
                  }

                  comment += "Possible ECM values ( " + possibleValues + " )";


                  node.AppendChild(doc.CreateComment(comment));
                  node.AppendChild(cnode);

                  node = doc.SelectSingleNode("/mdapi/providers");

                  if (node != null)
                  {
                    for (int x = 0; x < ecmList.Count; ++x)
                    {
                      bool found = false;
                      XmlNodeList providList = doc.SelectNodes("/mdapi/providers/provider");
                      if (providList != null)
                        foreach (XmlNode nodeprovid in providList)
                        {
                          String value = nodeprovid.Attributes["ID"].Value;
                          if (Int32.Parse(value).CompareTo(ecmList[x].ProviderId) == 0)
                          {
                            found = true;
                            break;
                          }
                        }

                      if (!found && ecmList[x].ProviderId != 0)
                      {
                        XmlNode d = doc.CreateElement("provider");
                        XmlAttribute r = doc.CreateAttribute("ID");
                        r.Value = "" + ecmList[x].ProviderId;
                        d.Attributes.Append(r);
                        node.AppendChild(d);
                      }
                    }
                  }


                  node = doc.SelectSingleNode("/mdapi/CA_Types");
                  if (node != null)
                  {
                    for (int x = 0; x < ecmList.Count; ++x)
                    {
                      bool found = false;
                      XmlNodeList providList = doc.SelectNodes("/mdapi/CA_Types/CA_Type");
                      if (providList != null)
                        foreach (XmlNode nodeprovid in providList)
                        {
                          String value = nodeprovid.Attributes["ID"].Value;
                          if (Int32.Parse(value).CompareTo(ecmList[x].CaId) == 0)
                          {
                            found = true;
                            break;
                          }
                        }
                      if (!found)
                      {
                        XmlNode d = doc.CreateElement("CA_Type");
                        XmlAttribute r = doc.CreateAttribute("ID");
                        r.Value = "" + ecmList[x].CaId;
                        d.Attributes.Append(r);
                        node.AppendChild(d);
                      }
                    }
                  }

                  doc.Save(xmlFile);
                }
              }
              catch (Exception g)
              {
                Log.Log.Write(g);
              }
            }
          }
          catch (Exception e)
          {
            Log.Log.Write(e);
          }
        }

        Log.Log.Info("mdplug: tp_id:{0}(0x{1:X}) sid:{2}(0x{3:X}) pmt_id:{4}(0x{5:X})",
                     _mDPlugTProg82.Tp_id,
                     _mDPlugTProg82.Tp_id,
                     _mDPlugTProg82.SID_pid,
                     _mDPlugTProg82.SID_pid,
                     _mDPlugTProg82.PMT_pid,
                     _mDPlugTProg82.PMT_pid);

        for (int i = 0; i < count; ++i)
        {
          Log.Log.Info("mdplug: #{0} CA_typ:{1}(0x{2:X}) ECM:{3}(0x{4:X}) EMM:0x{5:X} provider:{6}(0x{7:X})",
                       i,
                       _mDPlugTProg82.CA_System82[i].CA_Typ,
                       _mDPlugTProg82.CA_System82[i].CA_Typ,
                       _mDPlugTProg82.CA_System82[i].ECM,
                       _mDPlugTProg82.CA_System82[i].ECM,
                       _mDPlugTProg82.CA_System82[i].EMM,
                       _mDPlugTProg82.CA_System82[i].Provider_Id,
                       _mDPlugTProg82.CA_System82[i].Provider_Id);
        }
      }
      //ca types:
      //0xb00 : conax
      //0x100 : seca
      //0x500 : Viaccess
      //0x622 : irdeto
      //0x1801: Nagravision
      IntPtr lparam = Marshal.AllocHGlobal(Marshal.SizeOf(_mDPlugTProg82));
      Marshal.StructureToPtr(_mDPlugTProg82, lparam, true);
      IntPtr lparam2 = Marshal.AllocHGlobal(Marshal.SizeOf(_mPids2Dec));
      Marshal.StructureToPtr(_mPids2Dec, lparam2, true);
      try
      {
        if (_changeChannel_Ex != null)
          _changeChannel_Ex.ChangeChannelTP82_Ex(lparam, lparam2);
        else
          _changeChannel.ChangeChannelTP82(lparam);

        _decodingChannel = currentChannel;        

        Log.Log.Info("mdplug: Send channel change to MDAPI filter Ca_Id:{0} CA_Nr:{1} ECM_PID:{2}(0x{3:X})",
                     _mDPlugTProg82.CA_ID,
                     _mDPlugTProg82.CA_Nr,
                     _mDPlugTProg82.ECM_PID,
                     _mDPlugTProg82.ECM_PID);
      }
      catch (Exception ex)
      {
        Log.Log.Write(ex);
      }
      Marshal.FreeHGlobal(lparam);
      Marshal.FreeHGlobal(lparam2);
    }
 /// <summary>
 /// Creates the new channel.
 /// </summary>
 /// <param name="channel">The high level tuning detail.</param>
 /// <param name="info">The subchannel detail.</param>
 /// <returns>The new channel.</returns>
 protected abstract IChannel CreateNewChannel(IChannel channel, ChannelInfo info);
    /// <summary>
    /// Initializes a new instance of the <see cref="TvDvbChannel"/> class.
    /// </summary>
    /// <param name="graphBuilder">The graph builder.</param>
    /// <param name="ca">The ca.</param>
    /// <param name="mdplugs">The mdplugs class.</param>
    /// <param name="tif">The tif filter.</param>
    /// <param name="tsWriter">The ts writer filter.</param>
    /// <param name="subChannelId">The subchannel id</param>
    /// <param name="channel">The corresponding channel</param>
    public TvDvbChannel(IFilterGraph2 graphBuilder, ConditionalAccess ca, MDPlugs mdplugs, IBaseFilter tif,
                        IBaseFilter tsWriter, int subChannelId, IChannel channel)
    {
      _cancelled = false;
      _listenCA = false;
      _eventPMT = new ManualResetEvent(false);
      _eventCA = new ManualResetEvent(false);
      _graphState = GraphState.Created;
      _graphBuilder = graphBuilder;
      _conditionalAccess = ca;
      _mdplugs = mdplugs;
      _filterTIF = tif;
      _teletextDecoder = new DVBTeletext();
      _packetHeader = new TSHelperTools.TSHeader();
      _tsHelper = new TSHelperTools();
      _channelInfo = new ChannelInfo();
      _pmtPid = -1;
      _subChannelIndex = -1;
      _tsFilterInterface = (ITsFilter)tsWriter;
      _tsFilterInterface.AddChannel(ref _subChannelIndex);

      Log.Log.WriteFile("TvDvbChannel ctor new subchIndex:{0}", _subChannelIndex);

      _subChannelId = subChannelId;
      _conditionalAccess.AddSubChannel(_subChannelId, channel);
      _timeshiftFileName = "";
      _recordingFileName = "";
      _pmtData = null;
      _pmtLength = 0;
    }
 /// <summary>
 /// Initializes a new instance of the <see cref="TvDvbChannel"/> class.
 /// </summary>
 public TvDvbChannel()
 {
   _cancelled = false;
   _listenCA = false;
   _eventPMT = new ManualResetEvent(false);
   _eventCA = new ManualResetEvent(false);
   _graphState = GraphState.Created;
   _teletextDecoder = new DVBTeletext();
   _packetHeader = new TSHelperTools.TSHeader();
   _tsHelper = new TSHelperTools();
   _channelInfo = new ChannelInfo();
   _pmtPid = -1;
   _subChannelId = 0;
   _timeshiftFileName = "";
   _recordingFileName = "";
   _pmtData = null;
   _pmtLength = 0;
 }
    /// <summary>
    /// Decodes the PMT and sends the PMT to cam.
    /// </summary>
    protected virtual bool SendPmtToCam(out bool updatePids, out int waitInterval)
    {
      ThrowExceptionIfTuneCancelled();
      lock (this)
      {
        DVBBaseChannel channel = _currentChannel as DVBBaseChannel;
        updatePids = false;
        waitInterval = 100;
        bool foundCA = false;
        if (_mdplugs != null)
        {
          if (channel != null)
          {
            //HACK: Currently Premiere Direkt Feeds (nid=133) have the free_ca flag in SDT set to true (means not scrambled), so we have to override this
            if ((!channel.FreeToAir) || (channel.NetworkId == 133 && !channel.Provider.Equals("BetaDigital")))
            {
              DateTime dtNow = DateTime.Now;
              foundCA = false;
              //Log.Log.Info("subch:{0} listen for CA", _listenCA);
              if (!_eventCA.WaitOne(10000, true)) //wait 10 sec for CA to arrive.
              {
                TimeSpan ts = DateTime.Now - dtNow;
                Log.Log.Info("subch:{0} SendPmt:no CA found after {1} seconds", _subChannelId, ts.TotalSeconds);
                return false;
              }
              else
              {
                ThrowExceptionIfTuneCancelled();
                foundCA = true;
                TimeSpan ts = DateTime.Now - dtNow;
                Log.Log.Info("subch:{0} SendPmt:CA found after {1} seconds", _subChannelId, ts.TotalSeconds);
              }              
            }
          }
        }

        if (channel == null)
        {
          Log.Log.Info("subch:{0} SendPmt:no channel set", _subChannelId);
          return true;
        }
        IntPtr pmtMem = Marshal.AllocCoTaskMem(4096); // max. size for pmt
        IntPtr catMem = Marshal.AllocCoTaskMem(4096); // max. size for cat
        try
        {
          _pmtLength = _tsFilterInterface.PmtGetPMTData(_subChannelIndex, pmtMem);
          if (_pmtLength > 6)
          {
            _pmtData = new byte[_pmtLength];
            Marshal.Copy(pmtMem, _pmtData, 0, _pmtLength);
            int version = ((_pmtData[5] >> 1) & 0x1F);
            int pmtProgramNumber = (_pmtData[3] << 8) + _pmtData[4];
            Log.Log.Info("subch:{0} SendPmt:{1:X} {2:X} {3:X} {4:X}", _subChannelId, pmtProgramNumber, channel.ServiceId,
                         _pmtVersion, version);
            if (pmtProgramNumber == channel.ServiceId)
            {
              if (_pmtVersion == version) //already received this pmt
                return true;

              _pmtVersion = version;

              _channelInfo = new ChannelInfo();
              _channelInfo.DecodePmt(_pmtData);
              _channelInfo.network_pmt_PID = channel.PmtPid;
              _channelInfo.serviceID = channel.ServiceId;

              // update any service scrambled / unscambled changes
              if (_channelInfo.scrambled == channel.FreeToAir)
              {
                channel.FreeToAir = !_channelInfo.scrambled;
                Log.Log.Info("subch:{0} SendPMT: Channel FTA information changed to {1} according to CAIDs in PMT.",
                             _subChannelId, channel.FreeToAir);
              }
              if ((_mdplugs != null) && (foundCA))
              {
                try
                {
                  int catLength = _tsFilterInterface.CaGetCaData(_subChannelIndex, catMem);
                  if (catLength > 0)
                  {
                    byte[] cat = new byte[catLength];
                    Marshal.Copy(catMem, cat, 0, catLength);
                    _channelInfo.DecodeCat(cat, catLength);
                  }
                }
                catch (Exception ex)
                {
                  Log.Log.Write(ex);
                }
              }

              updatePids = true;

              if (_conditionalAccess == null)
              {
                Log.Log.Info("subch:{0} SendPMT: No cam in use, nothing to do.", _subChannelId);
                return true;
              }
              if (channel.FreeToAir)
              {
                Log.Log.Info("subch:{0} SendPMT: Channel is FTA, nothing to do.", _subChannelId);
                return true;
              }
              Log.Log.WriteFile("subch:{0} SendPMT version:{1} len:{2} {3}", _subChannelId, version, _pmtLength,
                                _channelInfo.caPMT.ProgramNumber);

              int audioPid = -1;
              if (_currentAudioStream != null)
              {
                audioPid = _currentAudioStream.Pid;
              }

              if (_conditionalAccess.SendPMT(_subChannelId, channel, _pmtData, _pmtLength,
                                             audioPid))
              {
                Log.Log.WriteFile("subch:{0} cam flags:{1}", _subChannelId, _conditionalAccess.IsCamReady());
                return true;
              }
              else
              {
                //cam is not ready yet
                Log.Log.WriteFile("subch:{0} SendPmt failed cam flags:{1}", _subChannelId,
                                  _conditionalAccess.IsCamReady());
                _pmtVersion = -1;
                waitInterval = 3000;
                return false;
              }
            }
          }
        }
        catch (Exception ex)
        {
          Log.Log.Write(ex);
        }
        finally
        {
          Marshal.FreeCoTaskMem(pmtMem);
          Marshal.FreeCoTaskMem(catMem);
        }
      }
      return false;
    }
 /// <summary>
 /// Creates the new channel.
 /// </summary>
 /// <param name="channel">The high level tuning detail.</param>
 /// <param name="info">The subchannel detail.</param>
 /// <returns>The new channel.</returns>
 protected override IChannel CreateNewChannel(IChannel channel, ChannelInfo info)
 {
   ATSCChannel tuningChannel = (ATSCChannel)channel;
   ATSCChannel atscChannel = new ATSCChannel();
   if (tuningChannel.PhysicalChannel == 0) // ie. digital cable CableCARD tuner scan
   {
     atscChannel.PhysicalChannel = ATSCChannel.GetPhysicalChannelFromFrequency(info.freq);
     atscChannel.Frequency = info.freq;
   }
   else
   {
     atscChannel.PhysicalChannel = tuningChannel.PhysicalChannel;
     atscChannel.Frequency = tuningChannel.Frequency;
   }
   if (info.minorChannel == 0)
   {
     atscChannel.LogicalChannelNumber = info.majorChannel;
   }
   else
   {
     atscChannel.LogicalChannelNumber = (info.majorChannel * 1000) + info.minorChannel;
   }
   atscChannel.Name = info.service_name;
   atscChannel.Provider = info.service_provider_name;
   atscChannel.ModulationType = tuningChannel.ModulationType;
   atscChannel.MajorChannel = info.majorChannel;
   atscChannel.MinorChannel = info.minorChannel;
   atscChannel.IsTv = IsTvService(info.serviceType);
   atscChannel.IsRadio = IsRadioService(info.serviceType);
   atscChannel.NetworkId = info.networkID;
   atscChannel.ServiceId = info.serviceID;
   atscChannel.TransportId = info.transportStreamID;
   atscChannel.PmtPid = info.network_pmt_PID;
   atscChannel.FreeToAir = !info.scrambled;
   Log.Log.Write("atsc:Found: {0}", atscChannel);
   return atscChannel;
 }
    /// <summary>
    /// Scans the specified transponder.
    /// </summary>
    /// <param name="channel">The channel.</param>
    /// <param name="settings">The settings.</param>
    /// <returns></returns>
    public virtual List<IChannel> Scan(IChannel channel, ScanParameters settings)
    {
      try
      {
        bool isDigitalCableScan = false;
        if (_card is TunerPbdaCableCard)
        {
          isDigitalCableScan = true;
        }
        _card.IsScanning = true;
        _card.Scan(0, channel);
        _analyzer = GetAnalyzer();
        if (_analyzer == null)
        {
          Log.Log.WriteFile("Scan: no analyzer interface available");
          return new List<IChannel>();
        }
        ResetSignalUpdate();

        // Note we don't check lock for PBDA CableCARD tuners because
        // they scan using the out of band tuner. OOB lock has already
        // been checked.
        if (_card.IsTunerLocked == false && !isDigitalCableScan)
        {
          Thread.Sleep(settings.TimeOutTune * 1000);
          ResetSignalUpdate();
        }
        Log.Log.WriteFile("Scan: tuner locked:{0} signal:{1} quality:{2}", _card.IsTunerLocked, _card.SignalLevel,
                          _card.SignalQuality);
        if (_card.IsTunerLocked || _card.SignalLevel > 0 || _card.SignalQuality > 0 || isDigitalCableScan)
        {
          try
          {
            _event = new ManualResetEvent(false);
            _analyzer.SetCallBack(this);
            _analyzer.Start(_transportStreamStandard);
            _event.WaitOne(settings.TimeOutSDT * 1000, true);

            int found = 0;
            short channelCount;
            _analyzer.GetCount(out channelCount);
            List<IChannel> channelsFound = new List<IChannel>();

            for (int i = 0; i < channelCount; ++i)
            {
              int networkId;
              int transportId;
              int serviceId;
              int majorChannel;
              int minorChannel;
              int frequency;
              short freeCAMode;
              short serviceType;
              short modulation;
              IntPtr providerName;
              IntPtr serviceName;
              int pmtPid;
              short hasVideo;
              short hasAudio;
              short hasCaDescriptor;
              int lcn;
              _analyzer.GetChannel((short)i,
                                   out networkId, out transportId, out serviceId, out majorChannel, out minorChannel,
                                   out frequency, out lcn, out freeCAMode, out serviceType, out modulation,
                                   out providerName, out serviceName,
                                   out pmtPid, out hasVideo, out hasAudio, out hasCaDescriptor);

              string name = DvbTextConverter.Convert(serviceName, "");
              Log.Log.Write("{0}) 0x{1:X} 0x{2:X} 0x{3:X} 0x{4:X} {5} type:{6:X}", i, networkId, transportId, serviceId,
                            pmtPid, name, serviceType);

              found++;
              ChannelInfo info = new ChannelInfo();
              info.networkID = networkId;
              info.transportStreamID = transportId;
              info.serviceID = serviceId;
              info.majorChannel = majorChannel;
              info.minorChannel = minorChannel;
              info.freq = frequency;
              info.LCN = lcn;
              info.serviceType = serviceType;
              info.modulation = modulation;
              info.service_provider_name = DvbTextConverter.Convert(providerName, "");
              info.service_name = DvbTextConverter.Convert(serviceName, "");
              info.scrambled = (freeCAMode != 0 || hasCaDescriptor != 0);
              info.network_pmt_PID = pmtPid;

              if (IsValidChannel(info, hasAudio, hasVideo))
              {
                if (info.service_name.Length == 0)
                {
                  SetNameForUnknownChannel(channel, info);
                }
                IChannel result = CreateNewChannel(channel, info);
                if (result != null)
                {
                  channelsFound.Add(result);
                }
              }
              else
              {
                Log.Log.Write(
                  "Found Unknown: {0} {1} type:{2} onid:{3:X} tsid:{4:X} sid:{5:X} pmt:{6:X} hasVideo:{7} hasAudio:{8}",
                  info.service_provider_name, info.service_name, info.serviceType, info.networkID,
                  info.transportStreamID, info.serviceID, info.network_pmt_PID, hasVideo, hasAudio);
              }
            }

            Log.Log.Write("Scan Got {0} from {1} channels", found, channelCount);
            return channelsFound;
          }
          finally
          {
            if (_analyzer != null)
            {
              _analyzer.SetCallBack(null);
              _analyzer.Stop();
            }
            _event.Close();
          }
        }
        else
        {
          Log.Log.WriteFile("Scan: no signal detected");
          return new List<IChannel>();
        }
      }
      finally
      {
        _card.IsScanning = false;
      }
    }
    /// <summary>
    /// Should be called when graph is about to stop.
    /// stops any timeshifting/recording on this channel
    /// </summary>
    public override void OnGraphStop()
    {
      Log.Log.WriteFile("subch:{0} OnGraphStop", _subChannelId);
      _pmtPid = -1;
      _dateTimeShiftStarted = DateTime.MinValue;
      _dateRecordingStarted = DateTime.MinValue;
      _startTimeShifting = false;
      _startRecording = false;
      _pmtVersion = -1;
      _timeshiftFileName = "";
      _recordingFileName = "";
      _channelInfo = new ChannelInfo();
      _currentChannel = null;

      if (_tsFilterInterface != null)
      {
        _tsFilterInterface.RecordStopRecord(_subChannelIndex);
        _tsFilterInterface.TimeShiftStop(_subChannelIndex);
        _graphState = GraphState.Created;
      }
      if (_teletextDecoder != null)
      {
        _teletextDecoder.ClearBuffer();
      }
    }
 protected virtual void SetNameForUnknownChannel(IChannel channel, ChannelInfo info)
 {
   info.service_name = String.Format("Unknown {0:X}", info.serviceID);
 }
    /// <summary>
    /// maps the correct pids to the TsFileSink filter and teletext pins
    /// </summary>
    /// <param name="info"></param>
    protected void SetMpegPidMapping(ChannelInfo info)
    {
      if (info == null)
        return;
      try
      {
        Log.Log.WriteFile("subch:{0} SetMpegPidMapping", _subChannelId);

        List<ushort> hwPids = new List<ushort>();
        hwPids.Add(0x0); //PAT
        hwPids.Add(0x1); //CAT
        hwPids.Add(0x10); //NIT
        hwPids.Add(0x11); //SDT
        hwPids.Add(0x12); //EPG

        Log.Log.WriteFile("subch:{0}  pid:{1:X} pcr", _subChannelId, info.pcrPid);
        Log.Log.WriteFile("subch:{0}  pid:{1:X} pmt", _subChannelId, info.network_pmt_PID);

        if (info.network_pmt_PID >= 0 && info.serviceID >= 0)
        {
          hwPids.Add((ushort)info.network_pmt_PID);
        }

        if (info.pids != null)
        {
          foreach (PidInfo pidInfo in info.pids)
          {
            Log.Log.WriteFile("subch:{0}  {1}", _subChannelId, pidInfo.ToString());
            if (pidInfo.pid == 0 || pidInfo.pid > 0x1fff)
              continue;
            if (pidInfo.isTeletext)
            {
              Log.Log.WriteFile("subch:{0}    map {1}", _subChannelId, pidInfo);
              if (GrabTeletext)
              {
                _tsFilterInterface.TTxSetTeletextPid(_subChannelIndex, pidInfo.pid);
              }
              hwPids.Add((ushort)pidInfo.pid);
              _hasTeletext = true;
            }
            if (pidInfo.isAC3Audio || pidInfo.isEAC3Audio || pidInfo.isAudio)
            {
              if (_currentAudioStream == null || pidInfo.isAC3Audio || pidInfo.isEAC3Audio)
              {
                _currentAudioStream = new DVBAudioStream();
                _currentAudioStream.Pid = pidInfo.pid;
                _currentAudioStream.Language = pidInfo.language;
                if (pidInfo.IsMpeg1Audio)
                  _currentAudioStream.StreamType = AudioStreamType.Mpeg1;
                else if (pidInfo.IsMpeg2Audio)
                  _currentAudioStream.StreamType = AudioStreamType.Mpeg2;
                if (pidInfo.isAC3Audio)
                  _currentAudioStream.StreamType = AudioStreamType.AC3;
                if (pidInfo.isEAC3Audio)
                  _currentAudioStream.StreamType = AudioStreamType.EAC3;
                if (pidInfo.IsAACAudio)
                  _currentAudioStream.StreamType = AudioStreamType.AAC;
                if (pidInfo.IsLATMAACAudio)
                  _currentAudioStream.StreamType = AudioStreamType.LATMAAC;
              }

              if (_currentAudioStream.Pid == pidInfo.pid)
              {
                Log.Log.WriteFile("subch:{0}    map {1}", _subChannelId, pidInfo);
                _tsFilterInterface.AnalyzerSetAudioPid(_subChannelIndex, pidInfo.pid);
              }
              hwPids.Add((ushort)pidInfo.pid);
            }

            if (pidInfo.isVideo)
            {
              Log.Log.WriteFile("subch:{0}    map {1}", _subChannelId, pidInfo);
              hwPids.Add((ushort)pidInfo.pid);
              _tsFilterInterface.AnalyzerSetVideoPid(_subChannelIndex, pidInfo.pid);
              if (info.pcrPid > 0 && info.pcrPid != pidInfo.pid)
              {
                hwPids.Add((ushort)info.pcrPid);
              }
            }

            if (pidInfo.isDVBSubtitle)
            {
              Log.Log.WriteFile("subch:{0}    map {1}", _subChannelId, pidInfo);
              hwPids.Add((ushort)pidInfo.pid);
            }
          }
        }

        if (_mdplugs != null)
        {
          // MDPlugins Active.. 
          // It's important that the ECM pids are not blocked by the HWPID Filter in the Tuner.
          // therefore they need to be explicitly added to HWPID list.

          // HWPIDS supports max number of 16 filtered pids - Total max of 16.
          // ECM Pids
          foreach (ECMEMM ecmValue in _channelInfo.caPMT.GetECM())
          {
            if (ecmValue.Pid != 0 && !hwPids.Contains((ushort)ecmValue.Pid))
            {
              hwPids.Add((ushort)ecmValue.Pid);
            }
          }
          //EMM Pids
          foreach (ECMEMM emmValue in _channelInfo.caPMT.GetEMM())
          {
            if (emmValue.Pid != 0 && !hwPids.Contains((ushort)emmValue.Pid))
            {
              hwPids.Add((ushort)emmValue.Pid);
            }
          }
          Log.Log.WriteFile("Number of HWPIDS that needs to be sent to tuner :{0} ", hwPids.Count);
        }

        if (_conditionalAccess != null && info.network_pmt_PID >= 0 && info.serviceID >= 0)
        {
          _conditionalAccess.SendPids(_subChannelId, (DVBBaseChannel)_currentChannel, hwPids);
        }

        if (_startTimeShifting)
        {
          _startTimeShifting = false;
          _tsFilterInterface.TimeShiftReset(_subChannelIndex);
          SetTimeShiftPids();

          Log.Log.WriteFile("Set video / audio observer");
          _tsFilterInterface.SetVideoAudioObserver(_subChannelIndex, this);

          _tsFilterInterface.TimeShiftStart(_subChannelIndex);

          _graphState = GraphState.TimeShifting;
        }
        if (_startRecording)
        {
          _startRecording = false;
          SetRecorderPids();

          Log.Log.WriteFile("Set video / audio observer");
          _tsFilterInterface.RecorderSetVideoAudioObserver(_subChannelIndex, this);

          int hr = _tsFilterInterface.RecordStartRecord(_subChannelIndex);
          if (hr != 0)
          {
            Log.Log.Error("subch:[0} StartRecord failed:{1:X}", _subChannelId, hr);
          }

          _graphState = GraphState.Recording;
        }
        else
        {
          if (IsTimeShifting)
          {
            SetTimeShiftPids();
          }
          if (IsRecording)
          {
            SetRecorderPids();
          }
        }
      }
      catch (Exception ex)
      {
        Log.Log.Write(ex);
      }
    }