Esempio n. 1
0
    /// <summary>
    /// Creates the encoder component
    /// </summary>
    /// <param name="_graphBuilder">The graph builder</param>
    /// <param name="_tuner">The tuner component</param>
    /// <param name="_tvAudio">The tvaudio component</param>
    /// <param name="_crossbar">The crossbar component</param>
    /// <param name="_capture">The capture component</param>
    /// <returns>true, if the building was successful; false otherwise</returns>
    public bool CreateFilterInstance(IFilterGraph2 _graphBuilder, Tuner _tuner, TvAudio _tvAudio, Crossbar _crossbar,
                                     Capture _capture)
    {
      _layer = new TvBusinessLayer();
      // now things get difficult.
      // Here we can have the following situations:
      // 1. we're done, the video capture filter has a mpeg-2 audio output pin
      // 2. we need to add 1 encoder filter which converts both the audio/video output pins
      //    of the video capture filter to mpeg-2
      // 3. we need to potentially mux the mpeg-2 video with audio. i.e. Nvidia NVTV Dual Tuner capture cards.
      // 4. we need to add 2 mpeg-2 encoder filters for software cards. One for audio and one for video 
      //    after the 2 encoder filters, a multiplexer will be added which takes the output of both
      //    encoders and generates mpeg-2


      //situation 1. we look if the video capture device has an mpeg-2 output pin (media type:stream)
      FindCapturePin(MediaType.Stream, MediaSubType.Null, _capture.VideoFilter);
      //specific workaround for the Plextor COnvertX devices
      if (_tuner.IsPlextorCard())
      {
        Log.Log.Info("analog: Plextor ConvertX TV402U detected");
        _isPlextorConvertX = true;
        //fake the capture pin to the Plextor media type & subtype
        FindCapturePin(MediaType.Video, MediaSubtype_Plextor, _capture.VideoFilter);
        //Find the audio pin
        FindAudioVideoPins(_capture);
        //Add the audio encoder
        AddAudioCompressor(_graphBuilder);
        //Add the Plextor specific InterVideo mux & gets the new capture pin.
        AddInterVideoMuxer(_graphBuilder, _capture);
      }
      if (_pinCapture == null)
      {
        // no it does not. So we have situation 2, 3 or 4 and first need to add 1 or more encoder filters
        // First we try only to add encoders where the encoder pin names are the same as the
        // output pins of the capture filters and we search only for filter which have an mpeg2-program stream output pin
        if (!AddTvEncoderFilter(true, true, _graphBuilder, _tuner, _tvAudio, _crossbar, _capture))
        {
          //if that fails, we try any encoder filter with an mpeg2-program stream output pin
          if (!AddTvEncoderFilter(false, true, _graphBuilder, _tuner, _tvAudio, _crossbar, _capture))
          {
            // If that fails, we try to add encoder where the encoder pin names are the same as the
            // output pins of the capture filters, and now except encoders except with mpeg2-ts output pin
            if (!AddTvEncoderFilter(true, false, _graphBuilder, _tuner, _tvAudio, _crossbar, _capture))
            {
              // If that fails, we try every encoder except encoders except with mpeg2-ts output pin
              AddTvEncoderFilter(false, false, _graphBuilder, _tuner, _tvAudio, _crossbar, _capture);
            }
          }
        }
        // 1 or 2 encoder filters have been added. 
        // check if the encoder filters supply a mpeg-2 output pin
        FindCapturePin(MediaType.Stream, MediaSubType.Null, _filterVideoEncoder);
        // not as a stream, but perhaps its supplied with another media type
        if (_pinCapture == null)
          FindCapturePin(MediaType.Video, MediaSubType.Mpeg2Program, _filterVideoEncoder);
        if (_pinCapture == null)
        {
          //still no mpeg output found, we move on to situation 3. We need to add a multiplexer
          // First we try only to add multiplexers where the multiplexer pin names are the same as the
          // output pins of the encoder filters
          //for the NVTV filter the pin names dont match .. so check first in bool eval and thus skips 
          // trying AddTvMultiPlexer with matching pinnames when using NVTV
          if (_tuner.IsNvidiaCard() || !AddTvMultiPlexer(true, _graphBuilder, _tuner, _tvAudio, _crossbar, _capture))
          {
            //if that fails, we try any multiplexer filter
            AddTvMultiPlexer(false, _graphBuilder, _tuner, _tvAudio, _crossbar, _capture);
          }
        }
      }
      // multiplexer filter now has been added.
      // check if the encoder multiplexer supply a mpeg-2 output pin
      if (_pinCapture == null)
      {
        FindCapturePin(MediaType.Stream, MediaSubType.Null, _filterMultiplexer);
        if (_pinCapture == null)
          FindCapturePin(MediaType.Video, MediaSubType.Mpeg2Program, _filterMultiplexer);
      }
      if (_pinCapture == null)
      {
        // Still no mpeg-2 output pin found
        // looks like this is a s/w encoding card
        if (!FindAudioVideoPins(_capture))
        {
          Log.Log.WriteFile("analog:   failed to find audio/video pins");
          throw new Exception("No analog audio/video pins found");
        }
        if (!AddAudioCompressor(_graphBuilder))
        {
          Log.Log.WriteFile("analog:   failed to add audio compressor. You must install a supported audio encoder!");
          throw new TvExceptionSWEncoderMissing(
            "No audio compressor filter found. You must install a supported audio encoder!");
        }
        if (!AddVideoCompressor(_graphBuilder))
        {
          Log.Log.WriteFile("analog:   failed to add video compressor. You must install a supported video encoder!");
          throw new TvExceptionSWEncoderMissing(
            "No video compressor filter found. You must install a supported video encoder!");
        }
        if (FilterGraphTools.GetFilterName(_filterAudioCompressor).Contains("InterVideo Audio Encoder"))
        {
          if (!AddInterVideoMuxer(_graphBuilder, _capture))
          {
            Log.Log.WriteFile("analog:   failed to add intervideo muxer");
            throw new Exception("No intervideo muxer filter found");
          }
        }
        else
        {
          if (!AddAnalogMuxer(_graphBuilder))
          {
            Log.Log.WriteFile("analog:   failed to add analog muxer");
            throw new Exception("No analog muxer filter found");
          }
        }
      }
      //Certain ATI cards have pin names which don't match etc.
      if (_capture.VideoCaptureName.Contains("ATI AVStream Analog Capture") ||
          _capture.AudioCaptureName.Contains("ATI AVStream Analog Capture"))
      {
        Log.Log.WriteFile("analog: ATI AVStream Analog Capture card detected adding mux");
        AddTvMultiPlexer(false, _graphBuilder, _tuner, _tvAudio, _crossbar, _capture);
        FindCapturePin(MediaType.Stream, MediaSubType.Mpeg2Program, _filterMultiplexer);
      }
      //add the mpeg-2 demultiplexer filter
      AddMpeg2Demultiplexer(_graphBuilder);
      if (!AddMpegMuxer(_graphBuilder, _capture))
      {
        throw new TvException("Analog: unable to add mpeg muxer");
      }
      return true;
    }
Esempio n. 2
0
    /// <summary>
    /// This method tries to connect a multiplexer filter to the encoder filters (or capture filter)
    /// See the remarks in AddTvMultiPlexer() for the possible options
    /// </summary>
    /// <param name="filterMultiPlexer">The multiplexer.</param>
    /// <param name="matchPinNames">if set to <c>true</c> the pin names of the multiplexer filter should match the pin names of the encoder filter.</param>
    /// <param name="_graphBuilder">GraphBuilder</param>
    /// <param name="_tuner">Tuner</param>
    /// <param name="_capture">Capture</param>
    /// <returns>true if multiplexer is connected correctly, otherwise false</returns>
    private bool ConnectMultiplexer(IBaseFilter filterMultiPlexer, bool matchPinNames, IFilterGraph2 _graphBuilder,
                                    Tuner _tuner, Capture _capture)
    {
      //Log.Log.WriteFile("analog: ConnectMultiplexer()");
      // get the input pins of the multiplexer filter (can be 1 or 2 input pins)
      IPin pinInput1 = DsFindPin.ByDirection(filterMultiPlexer, PinDirection.Input, 0);
      IPin pinInput2 = DsFindPin.ByDirection(filterMultiPlexer, PinDirection.Input, 1);
      //log the info for each input pin
      if (pinInput1 != null)
        Log.Log.WriteFile("analog:  found pin#0 {0}", FilterGraphTools.LogPinInfo(pinInput1));
      if (pinInput2 != null)
        Log.Log.WriteFile("analog:  found pin#1 {0}", FilterGraphTools.LogPinInfo(pinInput2));
      string pinName1 = FilterGraphTools.GetPinName(pinInput1);
      string pinName2 = FilterGraphTools.GetPinName(pinInput2);
      try
      {
        if (_filterAudioEncoder != null)
          Log.Log.WriteFile("analog: AudioEncoder available");
        if (_filterVideoEncoder != null)
          Log.Log.WriteFile("analog: VideoEncoder available");
        int pinsConnectedOnMultiplexer = 0;
        // if we have no encoder filters, the multiplexer should be connected directly to the capture filter
        if (_filterAudioEncoder == null || _filterVideoEncoder == null)
        {
          Log.Log.WriteFile("analog: ConnectMultiplexer to capture filter");
          //option 1, connect the multiplexer to the capture filter
          int pinsConnected = 0;
          int pinsAvailable = 0;
          IPin[] pins = new IPin[20];
          IEnumPins enumPins = null;
          try
          {
            // for each output pin of the capture filter
            _capture.VideoFilter.EnumPins(out enumPins);
            enumPins.Next(20, pins, out pinsAvailable);
            Log.Log.WriteFile("analog:  capture pins available:{0}", pinsAvailable);
            for (int i = 0; i < pinsAvailable; ++i)
            {
              int hr;
              // check if this is an outpin pin on the capture filter
              PinDirection pinDir;
              pins[i].QueryDirection(out pinDir);
              if (pinDir == PinDirection.Input)
                continue;
              //log the pin info
              Log.Log.WriteFile("analog:  capture pin:{0} {1} {2}", i, pinDir, FilterGraphTools.LogPinInfo(pins[i]));
              string pinName = FilterGraphTools.GetPinName(pins[i]);
              // try to connect this output pin of the capture filter to the 1st input pin
              // of the multiplexer
              // only try to connect when pin name matching is turned off
              // or when the pin names are the same
              if (matchPinNames == false || (String.Compare(pinName, pinName1, true) == 0))
              {
                //try to connect the output pin of the capture filter to the 1st input pin of the multiplexer
                hr = _graphBuilder.Connect(pins[i], pinInput1);
                if (hr == 0)
                {
                  //succeeded
                  Log.Log.WriteFile("analog:  connected pin:{0} {1} to pin1:{2}", i,
                                    FilterGraphTools.LogPinInfo(pins[i]), FilterGraphTools.LogPinInfo(pinInput1));
                  pinsConnected++;
                }
              }
              // next try to connect this output pin of the capture filter to the 2nd input pin
              // of the multiplexer
              // only try to connect when pin name matching is turned off
              // or when the pin names are the same
              if (matchPinNames == false || (String.Compare(pinName, pinName2, true) == 0))
              {
                // check if multiplexer has 2 input pins
                if (pinInput2 != null)
                {
                  //try to connect the output pin of the capture filter to the 2nd input pin of the multiplexer
                  hr = _graphBuilder.Connect(pins[i], pinInput2);
                  if (hr == 0)
                  {
                    //succeeded
                    Log.Log.WriteFile("analog:  connected pin:{0} {1} to pin2:{2}", i,
                                      FilterGraphTools.LogPinInfo(pins[i]), FilterGraphTools.LogPinInfo(pinInput2));
                    pinsConnected++;
                  }
                }
              }
              if (_tuner.IsNvidiaCard() && (pinsConnected == 1) && (_filterVideoEncoder != null))
              {
                Log.Log.WriteFile(
                  "analog: ConnectMultiplexer step 1 software audio encoder connected and no need for a software video encoder");
                break;
              }
              if (pinsConnected == 2)
              {
                //if both pins are connected, we're done..
                Log.Log.WriteFile("analog: ConnectMultiplexer succeeded at step 1");
                return true;
              }
              else
              {
                Log.Log.WriteFile("analog: ConnectMultiplexer no succes yet at step 1 only connected:" + pinsConnected +
                                  " pins");
              }
            }
            pinsConnectedOnMultiplexer += pinsConnected;
          }
          finally
          {
            if (enumPins != null)
              Release.ComObject("ienumpins", enumPins);
            for (int i = 0; i < pinsAvailable; ++i)
            {
              if (pins[i] != null)
                Release.ComObject("capture pin" + i, pins[i]);
            }
          }
        }
        //if we only have a single video encoder
        if (_filterAudioEncoder == null && _filterVideoEncoder != null)
        {
          //option 1, connect the multiplexer to a single encoder filter
          Log.Log.WriteFile("analog: ConnectMultiplexer to video encoder filter");
          int pinsConnected = 0;
          int pinsAvailable = 0;
          IPin[] pins = new IPin[20];
          IEnumPins enumPins = null;
          try
          {
            // for each output pin of the video encoder filter
            _filterVideoEncoder.EnumPins(out enumPins);
            enumPins.Next(20, pins, out pinsAvailable);
            Log.Log.WriteFile("analog:  video encoder pins available:{0}", pinsAvailable);
            for (int i = 0; i < pinsAvailable; ++i)
            {
              int hr;
              // check if this is an outpin pin on the video encoder filter
              PinDirection pinDir;
              pins[i].QueryDirection(out pinDir);
              if (pinDir == PinDirection.Input)
                continue;
              //log the pin info
              Log.Log.WriteFile("analog:  videoencoder pin:{0} {1}", i, FilterGraphTools.LogPinInfo(pins[i]));
              string pinName = FilterGraphTools.GetPinName(pins[i]);
              // try to connect this output pin of the video encoder filter to the 1st input pin
              // of the multiplexer
              // only try to connect when pin name matching is turned off
              // or when the pin names are the same
              if (matchPinNames == false || (String.Compare(pinName, pinName1, true) == 0))
              {
                //try to connect the output pin of the video encoder filter to the 1st input pin of the multiplexer filter
                hr = _graphBuilder.Connect(pins[i], pinInput1);
                if (hr == 0)
                {
                  //succeeded
                  Log.Log.WriteFile("analog:  connected pin:{0} {1} to {2}", i, FilterGraphTools.LogPinInfo(pins[i]),
                                    FilterGraphTools.LogPinInfo(pinInput1));
                  pinsConnected++;
                }
              }
              //if the multiplexer has 2 input pins
              if (pinInput2 != null)
              {
                // next try to connect this output pin of the video encoder to the 2nd input pin
                // of the multiplexer
                // only try to connect when pin name matching is turned off
                // or when the pin names are the same
                if (matchPinNames == false || (String.Compare(pinName, pinName2, true) == 0))
                {
                  //try to connect the output pin of the video encoder filter to the 1st input pin of the multiplexer filter
                  hr = _graphBuilder.Connect(pins[i], pinInput2);
                  if (hr == 0)
                  {
                    //succeeded
                    Log.Log.WriteFile("analog:  connected pin:{0} {1} to {2}", i, FilterGraphTools.LogPinInfo(pins[i]),
                                      FilterGraphTools.LogPinInfo(pinInput2));
                    pinsConnected++;
                  }
                }
              }
              if (pinsConnected == 1)
              {
                // add the already connected pin from the previous step (ConnectMultiplexer to capture filter)
                pinsConnected += pinsConnectedOnMultiplexer;
              }
              if (pinsConnected == 2)
              {
                //succeeded and done...
                Log.Log.WriteFile("analog: ConnectMultiplexer succeeded at step 2");
                return true;
              }
              else
              {
                Log.Log.WriteFile("analog: ConnectMultiplexer no succes yet at step 2 only connected:" + pinsConnected +
                                  " pins");
              }
            }
          }
          finally
          {
            if (enumPins != null)
              Release.ComObject("ienumpins", enumPins);
            for (int i = 0; i < pinsAvailable; ++i)
            {
              if (pins[i] != null)
                Release.ComObject("encoder pin" + i, pins[i]);
            }
          }
        }
        //if we have a video encoder and an audio encoder filter
        if (_filterAudioEncoder != null || _filterVideoEncoder != null)
        {
          Log.Log.WriteFile("analog: ConnectMultiplexer to audio/video encoder filters");
          //option 3, connect the multiplexer to the audio/video encoder filters
          int pinsConnected = 0;
          int pinsAvailable = 0;
          IPin[] pins = new IPin[20];
          IEnumPins enumPins = null;
          try
          {
            // for each output pin of the video encoder filter
            if (_filterVideoEncoder != null)
              _filterVideoEncoder.EnumPins(out enumPins);
            if (enumPins != null)
              enumPins.Next(20, pins, out pinsAvailable);
            Log.Log.WriteFile("analog:  videoencoder pins available:{0}", pinsAvailable);
            for (int i = 0; i < pinsAvailable; ++i)
            {
              int hr;
              // check if this is an outpin pin on the video encoder filter
              PinDirection pinDir;
              pins[i].QueryDirection(out pinDir);
              if (pinDir == PinDirection.Input)
                continue;
              //log the pin info
              Log.Log.WriteFile("analog:   videoencoder pin:{0} {1} {2}", i, pinDir,
                                FilterGraphTools.LogPinInfo(pins[i]));
              string pinName = FilterGraphTools.GetPinName(pins[i]);
              // try to connect this output pin of the video encoder filter to the 1st input pin
              // of the multiplexer
              // only try to connect when pin name matching is turned off
              // or when the pin names are the same
              if (matchPinNames == false || (String.Compare(pinName, pinName1, true) == 0))
              {
                //try to connect the output pin of the video encoder filter to the 1st input pin of the multiplexer filter
                hr = _graphBuilder.Connect(pins[i], pinInput1);
                if (hr == 0)
                {
                  //succeeded
                  Log.Log.WriteFile("analog:  connected pin:{0} {1} to {2}", i, FilterGraphTools.LogPinInfo(pins[i]),
                                    FilterGraphTools.LogPinInfo(pinInput1));
                  pinsConnected++;
                }
                else
                {
                  Log.Log.WriteFile("Cant connect 0x{0:x}", hr);
                  Log.Log.WriteFile("pin:{0} {1} to {2}", i, FilterGraphTools.LogPinInfo(pins[i]),
                                    FilterGraphTools.LogPinInfo(pinInput1));
                }
              }
              //if multiplexer has 2 inputs..
              if (pinInput2 != null)
              {
                // next try to connect this output pin of the video encoder to the 2nd input pin
                // of the multiplexer
                // only try to connect when pin name matching is turned off
                // or when the pin names are the same
                if (matchPinNames == false || (String.Compare(pinName, pinName2, true) == 0))
                {
                  //try to connect the output pin of the video encoder filter to the 2nd input pin of the multiplexer filter
                  hr = _graphBuilder.Connect(pins[i], pinInput2);
                  if (hr == 0)
                  {
                    //succeeded
                    Log.Log.WriteFile("analog:  connected pin:{0} {1} to {2}", i, FilterGraphTools.LogPinInfo(pins[i]),
                                      FilterGraphTools.LogPinInfo(pinInput2));
                    pinsConnected++;
                  }
                  else
                  {
                    Log.Log.WriteFile("Cant connect 0x{0:x}", hr);
                    Log.Log.WriteFile("pin:{0} {1} to {2}", i, FilterGraphTools.LogPinInfo(pins[i]),
                                      FilterGraphTools.LogPinInfo(pinInput2));
                  }
                }
              }
              if (pinsConnected == 1)
              {
                //we are done with the video encoder when there is 1 connection between video encoder filter and multiplexer
                //next, continue with the audio encoder...
                Log.Log.WriteFile("analog: ConnectMultiplexer part 1 succeeded");
                break;
              }
            }
            if (pinsConnected == 0) // video encoder is not connected, so we fail
            {
              Log.Log.WriteFile("analog: Video not connected to multiplexer (pinsConnected == 0) FAILURE");
              return false;
            }
            Log.Log.WriteFile("analog: (pinsConnected: {0})", pinsConnected);

            if (_filterAudioEncoder != null)
            {
              // for each output pin of the audio encoder filter
              _filterAudioEncoder.EnumPins(out enumPins);
              enumPins.Next(20, pins, out pinsAvailable);
              Log.Log.WriteFile("analog:  audioencoder pins available:{0}", pinsAvailable);
              for (int i = 0; i < pinsAvailable; ++i)
              {
                int hr;
                // check if this is an outpin pin on the audio encoder filter
                PinDirection pinDir;
                pins[i].QueryDirection(out pinDir);
                if (pinDir == PinDirection.Input)
                  continue;
                Log.Log.WriteFile("analog: audioencoder  pin:{0} {1} {2}", i, pinDir,
                                  FilterGraphTools.LogPinInfo(pins[i]));
                string pinName = FilterGraphTools.GetPinName(pins[i]);
                // try to connect this output pin of the audio encoder filter to the 1st input pin
                // of the multiplexer
                // only try to connect when pin name matching is turned off
                // or when the pin names are the same
                if (matchPinNames == false || (String.Compare(pinName, pinName1, true) == 0))
                {
                  //try to connect the output pin of the audio encoder filter to the 1st input pin of the multiplexer filter
                  hr = _graphBuilder.Connect(pins[i], pinInput1);
                  if (hr == 0)
                  {
                    //succeeded
                    Log.Log.WriteFile("analog:  connected pin:{0}", i);
                    pinsConnected++;
                  }
                }
                //if multiplexer has 2 input pins
                if (pinInput2 != null)
                {
                  // next try to connect this output pin of the audio encoder to the 2nd input pin
                  // of the multiplexer
                  // only try to connect when pin name matching is turned off
                  // or when the pin names are the same
                  if (matchPinNames == false || (String.Compare(pinName, pinName2, true) == 0))
                  {
                    //try to connect the output pin of the audio encoder filter to the 2nd input pin of the multiplexer filter
                    hr = _graphBuilder.Connect(pins[i], pinInput2);
                    if (hr == 0)
                    {
                      //succeeded
                      Log.Log.WriteFile("analog:  connected pin:{0}", i);
                      pinsConnected++;
                    }
                  }
                }
                //when both pins on the multiplexer are connected, we're done
                if (pinsConnected == 2)
                {
                  Log.Log.WriteFile("analog:  part 2 succeeded");
                  return true;
                }
              }
            }
          }
          finally
          {
            if (enumPins != null)
              Release.ComObject("ienumpins", enumPins);
            for (int i = 0; i < pinsAvailable; ++i)
            {
              if (pins[i] != null)
                Release.ComObject("audio encoder pin" + i, pins[i]);
            }
          }
        }
      }
      finally
      {
        if (pinInput1 != null)
          Release.ComObject("multiplexer pin0", pinInput1);
        if (pinInput2 != null)
          Release.ComObject("multiplexer pin1", pinInput2);
      }
      Log.Log.Error("analog: ConnectMultiplexer failed");
      return false;
    }
Esempio n. 3
0
    /// <summary>
    /// Adds the multiplexer filter to the graph.
    /// several posibilities
    ///  1. no tv multiplexer needed
    ///  2. tv multiplexer filter which is connected to a single encoder filter
    ///  3. tv multiplexer filter which is connected to two encoder filter (audio/video)
    ///  4. tv multiplexer filter which is connected to the capture filter
    /// at the end this method the graph looks like this:
    /// 
    ///  option 2: single encoder filter
    ///    [                ]----->[                ]      [             ]
    ///    [ capture filter ]      [ encoder filter ]----->[ multiplexer ]
    ///    [                ]----->[                ]      [             ]
    ///
    ///
    ///  option 3: dual encoder filters
    ///    [                ]----->[   video        ]    
    ///    [ capture filter ]      [ encoder filter ]------>[             ]
    ///    [                ]      [                ]       [             ]
    ///    [                ]                               [ multiplexer ]
    ///    [                ]----->[   audio        ]------>[             ]
    ///                            [ encoder filter ]      
    ///                            [                ]
    ///
    ///  option 4: no encoder filter
    ///    [                ]----->[             ]
    ///    [ capture filter ]      [ multiplexer ]
    ///    [                ]----->[             ]
    /// </summary>
    /// <param name="matchPinNames">if set to <c>true</c> the pin names of the multiplexer filter should match the pin names of the encoder filter.</param>
    /// <param name="_graphBuilder">GraphBuilder</param>
    /// <param name="_tuner">Tuner</param>
    /// <param name="_tvAudio">TvAudio</param>
    /// <param name="_crossbar">Crossbar</param>
    /// <param name="_capture">Capture</param>
    /// <returns>true if encoder filters are added, otherwise false</returns>
    private bool AddTvMultiPlexer(bool matchPinNames, IFilterGraph2 _graphBuilder, Tuner _tuner, TvAudio _tvAudio,
                                  Crossbar _crossbar, Capture _capture)
    {
      //Log.Log.WriteFile("analog: AddTvMultiPlexer");
      DsDevice[] devicesHW;
      DsDevice[] devicesSW;
      DsDevice[] devices;
      //get a list of all multiplexers available on this system
      try
      {
        devicesHW = DsDevice.GetDevicesOfCat(FilterCategory.WDMStreamingMultiplexerDevices);
        devicesHW = DeviceSorter.Sort(devicesHW, _tuner.TunerName, _tvAudio.TvAudioName, _crossbar.CrossBarName,
                                      _capture.VideoCaptureName, _capture.AudioCaptureName, _videoEncoderDevice,
                                      _audioEncoderDevice, _multiplexerDevice);
        // also add the SoftWare Multiplexers in case no compatible HardWare multiplexer is found (NVTV cards)
        devicesSW = _tuner.IsNvidiaCard()
                      ? DsDevice.GetDevicesOfCat(FilterCategory.MediaMultiplexerCategory)
                      : new DsDevice[0];

        devices = new DsDevice[devicesHW.Length + devicesSW.Length];
        int nr = 0;
        for (int i = 0; i < devicesHW.Length; ++i)
          devices[nr++] = devicesHW[i];
        for (int i = 0; i < devicesSW.Length; ++i)
          devices[nr++] = devicesSW[i];
      }
      catch (Exception ex)
      {
        Log.Log.WriteFile("analog: AddTvMultiPlexer no multiplexer devices found (Exception) " + ex.Message);
        return false;
      }
      if (devices.Length == 0)
      {
        Log.Log.WriteFile("analog: AddTvMultiPlexer no multiplexer devices found");
        return false;
      }
      //for each multiplexer
      for (int i = 0; i < devices.Length; i++)
      {
        IBaseFilter tmp;
        Log.Log.WriteFile("analog: AddTvMultiPlexer try:{0} {1}", devices[i].Name, i);
        // if multiplexer is in use, we can skip it
        if (DevicesInUse.Instance.IsUsed(devices[i]))
          continue;
        int hr;
        try
        {
          //add multiplexer to graph
          hr = _graphBuilder.AddSourceFilterForMoniker(devices[i].Mon, null, devices[i].Name, out tmp);
        }
        catch (Exception)
        {
          Log.Log.WriteFile("analog: cannot add filter to graph");
          continue;
        }
        if (hr != 0)
        {
          //failed to add it to graph, continue with the next multiplexer
          if (tmp != null)
          {
            _graphBuilder.RemoveFilter(tmp);
            Release.ComObject("multiplexer filter", tmp);
          }
          continue;
        }
        // try to connect the multiplexer to encoders/capture devices
        if (ConnectMultiplexer(tmp, matchPinNames, _graphBuilder, _tuner, _capture))
        {
          // succeeded, we're done
          _filterMultiplexer = tmp;
          _multiplexerDevice = devices[i];
          DevicesInUse.Instance.Add(_multiplexerDevice);
          Log.Log.WriteFile("analog: AddTvMultiPlexer succeeded");
          break;
        }
        // unable to connect it, remove the filter and continue with the next one
        _graphBuilder.RemoveFilter(tmp);
        Release.ComObject("multiplexer filter", tmp);
      }
      if (_filterMultiplexer == null)
      {
        Log.Log.WriteFile("analog: no TvMultiPlexer found");
        return false;
      }
      return true;
    }