/// <summary>
 /// Adds the tv capture to the graph and connects it to the crossbar.
 /// At the end of this method the graph looks like:
 /// [          ] ------------------------->[           ]------>[               ]
 /// [ tvtuner  ]                           [ crossbar  ]       [ video capture ]
 /// [          ]----[            ]-------->[           ]------>[  filter       ]
 ///                 [ tvaudio    ]
 ///                 [   tuner    ]
 /// </summary>
 /// <param name="tvAudio">The tvaudio component</param>
 /// <param name="crossbar">The crossbar componen</param>
 /// <param name="tuner">The tuner component</param>
 /// <param name="graph">The stored graph</param>
 /// <param name="graphBuilder">The graphBuilder</param>
 /// <param name="capBuilder">The Capture graph builder</param>
 /// <returns>true, if the graph building was successful</returns>
 public bool CreateFilterInstance(Graph graph, ICaptureGraphBuilder2 capBuilder, IFilterGraph2 graphBuilder,
                                  Tuner tuner, Crossbar crossbar, TvAudio tvAudio)
 {
     if (!string.IsNullOrEmpty(graph.Capture.Name))
     {
         Log.Log.WriteFile("analog: Using Capture configuration from stored graph");
         if (CreateConfigurationBasedFilterInstance(graph, capBuilder, graphBuilder, tuner, crossbar, tvAudio))
         {
             Log.Log.WriteFile("analog: Using Capture configuration from stored graph succeeded");
             return(true);
         }
     }
     Log.Log.WriteFile("analog: No stored or invalid graph for Capture component - Trying to detect");
     return(CreateAutomaticFilterInstance(graph, capBuilder, graphBuilder, tuner, crossbar, tvAudio));
 }
Exemple #2
0
 /// <summary>
 /// Creates the filter by trying to detect it
 /// </summary>
 /// <param name="crossbar">The crossbar componen</param>
 /// <param name="tuner">The tuner component</param>
 /// <param name="graph">The stored graph</param>
 /// <param name="graphBuilder">The graphBuilder</param>
 /// <returns>true, if the graph building was successful</returns>
 private bool CreateAutomaticFilterInstance(Graph graph, Tuner tuner, Crossbar crossbar, IFilterGraph2 graphBuilder)
 {
     //get all tv audio tuner devices on this system
     DsDevice[] devices = null;
     try
     {
         devices = DsDevice.GetDevicesOfCat(FilterCategory.AMKSTVAudio);
         devices = DeviceSorter.Sort(devices, tuner.TunerName, crossbar.CrossBarName);
     }
     catch (Exception)
     {
         Log.Log.WriteFile("analog: AddTvAudioFilter no tv audio devices found - Trying TvTuner filter");
     }
     if (devices != null && devices.Length > 0)
     {
         // try each tv audio tuner
         for (int i = 0; i < devices.Length; i++)
         {
             IBaseFilter tmp;
             Log.Log.WriteFile("analog: AddTvAudioFilter try:{0} {1}", devices[i].Name, i);
             //if tv audio tuner is currently in use we can skip it
             if (DevicesInUse.Instance.IsUsed(devices[i]))
             {
                 continue;
             }
             int hr;
             try
             {
                 //add tv audio tuner 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 tv audio tuner to graph, continue with the next one
                 if (tmp != null)
                 {
                     graphBuilder.RemoveFilter(tmp);
                     Release.ComObject("tvAudioFilter filter", tmp);
                 }
                 continue;
             }
             // try connecting the tv tuner-> tv audio tuner
             if (FilterGraphTools.ConnectPin(graphBuilder, tuner.AudioPin, tmp, 0))
             {
                 // Got it !
                 // Connect tv audio tuner to the crossbar
                 IPin pin = DsFindPin.ByDirection(tmp, PinDirection.Output, 0);
                 hr = graphBuilder.Connect(pin, crossbar.AudioTunerIn);
                 if (hr < 0)
                 {
                     //failed
                     graphBuilder.RemoveFilter(tmp);
                     Release.ComObject("audiotuner pinin", pin);
                     Release.ComObject("audiotuner filter", tmp);
                 }
                 else
                 {
                     //succeeded. we're done
                     Log.Log.WriteFile("analog: AddTvAudioFilter succeeded:{0}", devices[i].Name);
                     Release.ComObject("audiotuner pinin", pin);
                     _filterTvAudioTuner = tmp;
                     _audioDevice        = devices[i];
                     DevicesInUse.Instance.Add(_audioDevice);
                     _tvAudioTunerInterface = tuner.Filter as IAMTVAudio;
                     break;
                 }
             }
             else
             {
                 // cannot connect tv tuner-> tv audio tuner, try next one...
                 graphBuilder.RemoveFilter(tmp);
                 Release.ComObject("audiotuner filter", tmp);
             }
         }
     }
     if (_filterTvAudioTuner == null)
     {
         Log.Log.WriteFile("analog: AddTvAudioFilter no tv audio devices found - Trying TvTuner filter");
         int hr = graphBuilder.Connect(tuner.AudioPin, crossbar.AudioTunerIn);
         if (hr != 0)
         {
             Log.Log.Error("analog: unable to add TvAudioTuner to graph - even TvTuner as TvAudio fails");
             mode = TvAudioVariant.Unavailable;
         }
         else
         {
             Log.Log.WriteFile("analog: AddTvAudioFilter connected TvTuner with Crossbar directly succeeded!");
             mode = TvAudioVariant.TvTunerConnection;
             _tvAudioTunerInterface = tuner.Filter as IAMTVAudio;
             if (_tvAudioTunerInterface != null)
             {
                 Log.Log.WriteFile("analog: AddTvAudioFilter succeeded - TvTuner is also TvAudio");
                 _filterTvAudioTuner = tuner.Filter;
                 mode = TvAudioVariant.TvTuner;
             }
         }
         graph.TvAudio.Mode = mode;
     }
     else
     {
         mode = TvAudioVariant.Normal;
         graph.TvAudio.Name = _audioDevice.Name;
     }
     if (mode != TvAudioVariant.Unavailable && mode != TvAudioVariant.TvTunerConnection &&
         _tvAudioTunerInterface != null)
     {
         CheckCapabilities(graph);
     }
     return(true);
 }
Exemple #3
0
        /// <summary>
        /// Adds the tv audio tuner to the graph and connects it to the crossbar.
        /// At the end of this method the graph looks like:
        /// [          ] ------------------------->[           ]
        /// [ tvtuner  ]                           [ crossbar  ]
        /// [          ]----[            ]-------->[           ]
        ///                 [ tvaudio    ]
        ///                 [   tuner    ]
        /// </summary>
        /// <param name="crossbar">The crossbar componen</param>
        /// <param name="tuner">The tuner component</param>
        /// <param name="graph">The stored graph</param>
        /// <param name="graphBuilder">The graphBuilder</param>
        /// <returns>true, if the graph building was successful</returns>
        public bool CreateFilterInstance(Graph graph, IFilterGraph2 graphBuilder, Tuner tuner, Crossbar crossbar)
        {
            streams = new List <IAudioStream>();
            if (!string.IsNullOrEmpty(graph.TvAudio.Name) && graph.TvAudio.Mode != TvAudioVariant.Unavailable)
            {
                Log.Log.WriteFile("analog: Using TvAudio configuration from stored graph");

                if (CreateConfigurationBasedFilterInstance(graph, tuner, crossbar, graphBuilder))
                {
                    Log.Log.WriteFile("analog: Using TvAudio configuration from stored graph succeeded");
                    return(true);
                }
            }
            if (tuner.AudioPin == null)
            {
                Log.Log.WriteFile("analog: AddTvAudioFilter no tv audio device needed!");
                mode = TvAudioVariant.Unavailable;
                return(true);
            }
            Log.Log.WriteFile("analog: No stored graph for TvAudio component - Trying to detect");
            return(CreateAutomaticFilterInstance(graph, tuner, crossbar, graphBuilder));
        }
        /// <summary>
        /// Creates the filter by trying to detect it
        /// </summary>
        /// <param name="tvAudio">The tvaudio component</param>
        /// <param name="crossbar">The crossbar componen</param>
        /// <param name="tuner">The tuner component</param>
        /// <param name="graph">The stored graph</param>
        /// <param name="graphBuilder">The graphBuilder</param>
        /// <param name="capBuilder">The Capture graph builder</param>
        /// <returns>true, if the graph building was successful</returns>
        private bool CreateAutomaticFilterInstance(Graph graph, ICaptureGraphBuilder2 capBuilder, IFilterGraph2 graphBuilder,
                                                   Tuner tuner, Crossbar crossbar, TvAudio tvAudio)
        {
            DsDevice[] devices;
            bool       videoConnected = false;
            bool       audioConnected = false;

            //get a list of all video capture devices
            try
            {
                if (tuner.TunerName == "Adaptec USB TvTuner")
                {
                    Log.Log.WriteFile("analog: Adaptec USB device detected!");
                    devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
                }
                else
                {
                    devices = DsDevice.GetDevicesOfCat(FilterCategory.AMKSCapture);
                    devices = DeviceSorter.Sort(devices, tuner.TunerName, tvAudio.TvAudioName, crossbar.CrossBarName);
                }
            }
            catch (Exception)
            {
                Log.Log.WriteFile("analog: AddTvCaptureFiler error in allocating devices collection");
                return(false);
            }
            if (devices.Length == 0)
            {
                Log.Log.WriteFile("analog: AddTvCaptureFilter no tvcapture devices found");
                return(false);
            }
            //try each video capture filter
            for (int i = 0; i < devices.Length; i++)
            {
                bool        filterUsed = false;
                IBaseFilter tmp;
                if (_badCaptureDevices.Contains(devices[i].Name))
                {
                    Log.Log.WriteFile("analog: AddTvCaptureFilter bypassing: {0}", devices[i].Name);
                    continue;
                }
                Log.Log.WriteFile("analog: AddTvCaptureFilter try:{0} {1}", devices[i].Name, i);
                // if video capture filter is in use, then we can skip it
                if (DevicesInUse.Instance.IsUsed(devices[i]))
                {
                    continue;
                }
                int hr;
                try
                {
                    // add video capture filter 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)
                {
                    //cannot add video capture filter to graph, try next one
                    if (tmp != null)
                    {
                        graphBuilder.RemoveFilter(tmp);
                        Release.ComObject("TvCaptureFilter", tmp);
                    }
                    continue;
                }

                int destinationIndex;
                // connect crossbar->video capture filter
                if (!videoConnected &&
                    FilterGraphTools.ConnectFilter(graphBuilder, crossbar.VideoOut, tmp, out destinationIndex))
                {
                    _filterVideoCapture = tmp;
                    _videoCaptureDevice = devices[i];
                    if (_audioCaptureDevice != _videoCaptureDevice)
                    {
                        DevicesInUse.Instance.Add(_videoCaptureDevice);
                    }
                    Log.Log.WriteFile("analog: AddTvCaptureFilter connected video to crossbar successfully");
                    graph.Capture.Name    = _videoCaptureDevice.Name;
                    graph.Capture.VideoIn = destinationIndex;
                    videoConnected        = true;
                    filterUsed            = true;
                }
                // crossbar->audio capture filter
                // Many video capture are also the audio capture filter, so we can always try it again
                if (videoConnected && FilterGraphTools.ConnectFilter(graphBuilder, crossbar.AudioOut, tmp, out destinationIndex))
                {
                    _filterAudioCapture = tmp;
                    _audioCaptureDevice = devices[i];
                    if (_audioCaptureDevice != _videoCaptureDevice)
                    {
                        DevicesInUse.Instance.Add(_audioCaptureDevice);
                    }
                    Log.Log.WriteFile("analog: AddTvCaptureFilter connected audio to crossbar successfully");
                    graph.Capture.AudioCaptureName = devices[i].Name;
                    graph.Capture.AudioIn          = destinationIndex;
                    audioConnected = true;
                    filterUsed     = true;
                }
                // _audioCaptureDevice should never be null - avoids null exception crashes with Encoder.cs
                else
                {
                    _audioCaptureDevice = devices[i];
                }

                if (!filterUsed)
                {
                    // cannot connect crossbar->video capture filter, remove filter from graph
                    // cand continue with the next vieo capture filter
                    Log.Log.WriteFile("analog: AddTvCaptureFilter failed to connect to crossbar");
                    graphBuilder.RemoveFilter(tmp);
                    Release.ComObject("capture filter", tmp);
                }
                else
                {
                    i = -1; // Go through the devices again from the start...
                }
                if (videoConnected && audioConnected)
                {
                    break;
                }
            }
            if (_filterVideoCapture != null)
            {
                FindVBIPin(graph);
                CheckCapabilities(graph, capBuilder);
            }
            return(_filterVideoCapture != null);
        }
        /// <summary>
        /// Creates the filter based on the configuration file
        /// </summary>
        /// <param name="tvAudio">The tvaudio component</param>
        /// <param name="crossbar">The crossbar componen</param>
        /// <param name="tuner">The tuner component</param>
        /// <param name="graph">The stored graph</param>
        /// <param name="graphBuilder">The graphBuilder</param>
        /// <param name="capBuilder">The Capture graph builder</param>
        /// <returns>true, if the graph building was successful</returns>
        private bool CreateConfigurationBasedFilterInstance(Graph graph, ICaptureGraphBuilder2 capBuilder,
                                                            IFilterGraph2 graphBuilder, Tuner tuner, Crossbar crossbar,
                                                            TvAudio tvAudio)
        {
            string audioDeviceName = graph.Capture.AudioCaptureName;
            string videoDeviceName = graph.Capture.Name;

            DsDevice[] devices;
            bool       videoConnected = false;
            bool       audioConnected = false;

            //get a list of all video capture devices
            try
            {
                if (tuner.TunerName == "Adaptec USB TvTuner")
                {
                    Log.Log.WriteFile("analog: Adaptec USB device detected!");
                    devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
                }
                else
                {
                    devices = DsDevice.GetDevicesOfCat(FilterCategory.AMKSCapture); //shouldn't be VideoInputDevice
                    devices = DeviceSorter.Sort(devices, tuner.TunerName, tvAudio.TvAudioName, crossbar.CrossBarName);
                }
            }
            catch (Exception)
            {
                Log.Log.WriteFile("analog: AddTvCaptureFiler error in allocating devices collection");
                return(false);
            }
            if (devices.Length == 0)
            {
                Log.Log.WriteFile("analog: AddTvCaptureFilter no tvcapture devices found");
                return(false);
            }
            //try each video capture filter
            for (int i = 0; i < devices.Length; i++)
            {
                bool        filterUsed = false;
                IBaseFilter tmp;
                if (_badCaptureDevices.Contains(devices[i].Name))
                {
                    Log.Log.WriteFile("analog: AddTvCaptureFilter bypassing: {0}", devices[i].Name);
                    continue;
                }
                Log.Log.WriteFile("analog: AddTvCaptureFilter try:{0} {1}", devices[i].Name, i);
                // if video capture filter is in use, then we can skip it
                if (DevicesInUse.Instance.IsUsed(devices[i]))
                {
                    Log.Log.WriteFile("analog: Device: {0} in use?", devices[i].Name);
                    continue;
                }
                if (!videoDeviceName.Equals(devices[i].Name) &&
                    (audioDeviceName == null || !audioDeviceName.Equals(devices[i].Name)))
                {
                    continue;
                }
                int hr;
                try
                {
                    // add video capture filter 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)
                {
                    //cannot add video capture filter to graph, try next one
                    if (tmp != null)
                    {
                        Log.Log.WriteFile("analog: cannot add filter: {0} to graph", devices[i].Name);
                        graphBuilder.RemoveFilter(tmp);
                        Release.ComObject("TvCaptureFilter", tmp);
                    }
                    continue;
                }
                // connect crossbar->video capture filter
                if (videoDeviceName.Equals(devices[i].Name) &&
                    FilterGraphTools.ConnectPin(graphBuilder, crossbar.VideoOut, tmp, graph.Capture.VideoIn))
                {
                    _filterVideoCapture = tmp;
                    _videoCaptureDevice = devices[i];
                    if (_audioCaptureDevice != _videoCaptureDevice)
                    {
                        DevicesInUse.Instance.Add(_videoCaptureDevice);
                    }
                    Log.Log.WriteFile("analog: AddTvCaptureFilter connected video to crossbar successfully");
                    videoConnected = true;
                    filterUsed     = true;
                }
                // crossbar->audio capture filter
                // Many video capture are also the audio capture filter, so we can always try it again
                if (audioDeviceName.Equals(devices[i].Name) &&
                    FilterGraphTools.ConnectPin(graphBuilder, crossbar.AudioOut, tmp, graph.Capture.AudioIn))
                {
                    _filterAudioCapture = tmp;
                    _audioCaptureDevice = devices[i];
                    if (_audioCaptureDevice != _videoCaptureDevice)
                    {
                        DevicesInUse.Instance.Add(_audioCaptureDevice);
                    }
                    Log.Log.WriteFile("analog: AddTvCaptureFilter connected audio to crossbar successfully");
                    audioConnected = true;
                    filterUsed     = true;
                }
                // _audioCaptureDevice should never be null - avoids null exception crashes with Encoder.cs
                else
                {
                    _audioCaptureDevice = devices[i];
                }

                if (!filterUsed)
                {
                    // cannot connect crossbar->video capture filter, remove filter from graph
                    // cand continue with the next vieo capture filter
                    Log.Log.WriteFile("analog: AddTvCaptureFilter failed to connect to crossbar");
                    graphBuilder.RemoveFilter(tmp);
                    Release.ComObject("capture filter", tmp);
                }
                else
                {
                    i = -1; // Go through the devices again from the start...
                }
                if (videoConnected && audioConnected)
                {
                    break;
                }
            }
            if (_filterVideoCapture != null)
            {
                if (graph.Capture.TeletextPin != -1)
                {
                    _pinVBI = DsFindPin.ByDirection(_filterVideoCapture, PinDirection.Output,
                                                    graph.Capture.TeletextPin);
                }
                _videoProcAmp              = _filterVideoCapture as IAMVideoProcAmp;
                _analogVideoDecoder        = _filterVideoCapture as IAMAnalogVideoDecoder;
                _streamConfig              = _filterVideoCapture as IAMStreamConfig;
                _videoFormats              = graph.Capture.AvailableVideoStandard;
                _defaultVideoProcAmpValues = graph.Capture.VideoProcAmpValues;
                _frameRate   = graph.Capture.FrameRate;
                _imageWidth  = graph.Capture.ImageWidth;
                _imageHeight = graph.Capture.ImageHeight;
                CheckCapabilitiesStreamConfig(graph, capBuilder);
                SetCaptureConfiguration(graph);
            }
            return(_filterVideoCapture != null);
        }
    /// <summary>
    /// Adds one or 2 encoder filters to the graph
    ///  several posibilities
    ///  1. no encoder filter needed
    ///  2. single encoder filter with seperate audio/video inputs and 1 (mpeg-2) output
    ///  3. single encoder filter with a mpeg2 program stream input (I2S)
    ///  4. two encoder filters. one for audio and one for video
    ///
    ///  At the end of this method the graph looks like:
    ///
    ///  option 2: one encoder filter, with 2 inputs
    ///    [                ]----->[                ]
    ///    [ capture filter ]      [ encoder filter ]
    ///    [                ]----->[                ]
    ///
    ///
    ///  option 3: one encoder filter, with 1 input
    ///    [                ]      [                ]
    ///    [ capture filter ]----->[ encoder filter ]
    ///    [                ]      [                ]
    ///
    ///
    ///  option 4: 2 encoder filters one for audio and one for video
    ///    [                ]----->[   video        ]
    ///    [ capture filter ]      [ encoder filter ]
    ///    [                ]      [                ]
    ///    [                ]   
    ///    [                ]----->[   audio        ]
    ///                            [ encoder filter ]
    ///                            [                ]
    ///
    /// </summary>
    /// <param name="matchPinNames">if set to <c>true</c> the pin names of the encoder filter should match the pin names of the capture filter.</param>
    /// <param name="mpeg2ProgramFilter">if set to <c>true</c> than only encoders with an mpeg2 program output pins are accepted</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 AddTvEncoderFilter(bool matchPinNames, bool mpeg2ProgramFilter, IFilterGraph2 _graphBuilder,
                                    Tuner _tuner, TvAudio _tvAudio, Crossbar _crossbar, Capture _capture)
    {
      Log.Log.WriteFile("analog: AddTvEncoderFilter - MatchPinNames: {0} - MPEG2ProgramFilter: {1}", matchPinNames,
                        mpeg2ProgramFilter);
      bool finished = false;
      DsDevice[] devices;
      // first get all encoder filters available on this system
      try
      {
        devices = DsDevice.GetDevicesOfCat(FilterCategory.WDMStreamingEncoderDevices);
        devices = DeviceSorter.Sort(devices, _tuner.TunerName, _tvAudio.TvAudioName, _crossbar.CrossBarName,
                                    _capture.VideoCaptureName, _capture.AudioCaptureName, _videoEncoderDevice,
                                    _audioEncoderDevice, _multiplexerDevice);
      }
      catch (Exception)
      {
        Log.Log.WriteFile("analog: AddTvEncoderFilter no encoder devices found (Exception)");
        return false;
      }
      if (devices == null)
      {
        Log.Log.WriteFile("analog: AddTvEncoderFilter no encoder devices found (devices == null)");
        return false;
      }
      if (devices.Length == 0)
      {
        Log.Log.WriteFile("analog: AddTvEncoderFilter no encoder devices found");
        return false;
      }
      //for each encoder
      Log.Log.WriteFile("analog: AddTvEncoderFilter found:{0} encoders", devices.Length);
      for (int i = 0; i < devices.Length; i++)
      {
        IBaseFilter tmp;
        //if encoder is in use, we can skip it
        if (DevicesInUse.Instance.IsUsed(devices[i]))
        {
          Log.Log.WriteFile("analog:  skip :{0} (inuse)", devices[i].Name);
          continue;
        }
        Log.Log.WriteFile("analog:  try encoder:{0} {1}", devices[i].Name, i);
        int hr;
        try
        {
          //add encoder filter to graph
          hr = _graphBuilder.AddSourceFilterForMoniker(devices[i].Mon, null, devices[i].Name, out tmp);
        }
        catch (Exception)
        {
          Log.Log.WriteFile("analog: cannot add filter {0} to graph", devices[i].Name);
          continue;
        }
        if (hr != 0)
        {
          //failed to add filter to graph, continue with the next one
          if (tmp != null)
          {
            _graphBuilder.RemoveFilter(tmp);
            Release.ComObject("TvEncoderFilter", tmp);
          }
          continue;
        }
        if (tmp == null)
          continue;
        // Encoder has been added to the graph
        // Now some cards have 2 encoder types, one for mpeg-2 transport stream and one for
        // mpeg-2 program stream. We dont want the mpeg-2 transport stream !
        // So first we check the output pins...
        // and dont accept filters which have a mpeg-ts output pin..
        // get the output pin
        bool isTsFilter = mpeg2ProgramFilter;
        IPin pinOut = DsFindPin.ByDirection(tmp, PinDirection.Output, 0);
        if (pinOut != null)
        {
          //check which media types it support
          IEnumMediaTypes enumMediaTypes;
          pinOut.EnumMediaTypes(out enumMediaTypes);
          if (enumMediaTypes != null)
          {
            int fetched;
            AMMediaType[] mediaTypes = new AMMediaType[20];
            enumMediaTypes.Next(20, mediaTypes, out fetched);
            if (fetched > 0)
            {
              for (int media = 0; media < fetched; ++media)
              {
                //check if media is mpeg-2 transport
                if (mediaTypes[media].majorType == MediaType.Stream &&
                    mediaTypes[media].subType == MediaSubType.Mpeg2Transport)
                {
                  isTsFilter = true;
                }
                //check if media is mpeg-2 program
                if (mediaTypes[media].majorType == MediaType.Stream &&
                    mediaTypes[media].subType == MediaSubType.Mpeg2Program)
                {
                  isTsFilter = false;
                  break;
                }

                // NVTV dual tuner needs this one to make it work so dont skip it
                if (mediaTypes[media].majorType == MediaType.Video &&
                    mediaTypes[media].subType == new Guid("be626472-fe7c-4a21-9f0b-d8f18b5ab441")) /*MediaSubType.?? */
                {
                  isTsFilter = false;
                  break;
                }
              }
            }
          }
          Release.ComObject("pinout", pinOut);
        }
        //if encoder has mpeg-2 ts output pin, then we skip it and continue with the next one
        if (isTsFilter)
        {
          Log.Log.WriteFile("analog:  filter {0} does not have mpeg-2 ps output or is a mpeg-2 ts filters",
                            devices[i].Name);
          _graphBuilder.RemoveFilter(tmp);
          Release.ComObject("TvEncoderFilter", tmp);
          continue;
        }
        // get the input pins of the encoder (can be 1 or 2 inputs)
        IPin pin1 = DsFindPin.ByDirection(tmp, PinDirection.Input, 0);
        IPin pin2 = DsFindPin.ByDirection(tmp, PinDirection.Input, 1);
        if (pin1 != null)
          Log.Log.WriteFile("analog: encoder in-pin1:{0}", FilterGraphTools.LogPinInfo(pin1));
        if (pin2 != null)
          Log.Log.WriteFile("analog: encoder in-pin2:{0}", FilterGraphTools.LogPinInfo(pin2));
        // if the encoder has 2 input pins then this means it has seperate inputs for audio and video
        if (pin1 != null && pin2 != null)
        {
          // try to connect the capture device -> encoder filters..
          if (ConnectEncoderFilter(tmp, true, true, matchPinNames, _graphBuilder, _capture))
          {
            //succeeded, encoder has been added and we are done
            _filterVideoEncoder = tmp;
            _videoEncoderDevice = devices[i];
            DevicesInUse.Instance.Add(_videoEncoderDevice);
            Log.Log.WriteFile("analog: AddTvEncoderFilter succeeded (encoder with 2 inputs)");
            //            success = true;
            finished = true;
            tmp = null;
          }
        }
        else if (pin1 != null)
        {
          //encoder filter only has 1 input pin.
          //First we get the media type of this pin to determine if its audio of video
          IEnumMediaTypes enumMedia;
          AMMediaType[] media = new AMMediaType[20];
          int fetched;
          pin1.EnumMediaTypes(out enumMedia);
          enumMedia.Next(1, media, out fetched);
          if (fetched == 1)
          {
            //media type found
            Log.Log.WriteFile("analog: AddTvEncoderFilter encoder output major:{0} sub:{1}", media[0].majorType,
                              media[0].subType);
            //is it audio?
            if (media[0].majorType == MediaType.Audio)
            {
              //yes, pin is audio
              //then connect the encoder to the audio output pin of the capture filter
              if (ConnectEncoderFilter(tmp, false, true, matchPinNames, _graphBuilder, _capture))
              {
                //this worked. but we're not done yet. We probably need to add a video encoder also
                _filterAudioEncoder = tmp;
                _audioEncoderDevice = devices[i];
                DevicesInUse.Instance.Add(_audioEncoderDevice);
                //                success = true;
                Log.Log.WriteFile("analog: AddTvEncoderFilter succeeded (audio encoder)");
                // if video encoder was already added, then we're done.
                if (_filterVideoEncoder != null)
                  finished = true;
                tmp = null;
              }
            }
            else
            {
              //pin is video
              //then connect the encoder to the video output pin of the capture filter
              if (ConnectEncoderFilter(tmp, true, false, matchPinNames, _graphBuilder, _capture))
              {
                //this worked. but we're not done yet. We probably need to add a audio encoder also
                _filterVideoEncoder = tmp;
                _videoEncoderDevice = devices[i];
                DevicesInUse.Instance.Add(_videoEncoderDevice);
                //                success = true;
                Log.Log.WriteFile("analog: AddTvEncoderFilter succeeded (video encoder)");
                // if audio encoder was already added, then we're done.
                if (_filterAudioEncoder != null)
                  finished = true;
                tmp = null;
              }
            }
            DsUtils.FreeAMMediaType(media[0]);
          }
          else
          {
            // filter does not report any media type (which is strange)
            // we must do something, so we treat it as a video input pin
            Log.Log.WriteFile("analog: AddTvEncoderFilter no media types for pin1"); //??
            if (ConnectEncoderFilter(tmp, true, false, matchPinNames, _graphBuilder, _capture))
            {
              _filterVideoEncoder = tmp;
              _videoEncoderDevice = devices[i];
              DevicesInUse.Instance.Add(_videoEncoderDevice);
              //              success = true;
              Log.Log.WriteFile("analog: AddTvEncoderFilter succeeded");
              finished = true;
              tmp = null;
            }
          }
        }
        else
        {
          Log.Log.WriteFile("analog: AddTvEncoderFilter no pin1");
        }
        if (pin1 != null)
          Release.ComObject("encoder pin0", pin1);
        if (pin2 != null)
          Release.ComObject("encoder pin1", pin2);
        if (tmp != null)
        {
          _graphBuilder.RemoveFilter(tmp);
          Release.ComObject("encoder filter", tmp);
        }
        if (finished)
        {
          Log.Log.WriteFile("analog: AddTvEncoderFilter succeeded 3");
          return true;
        }
      } //for (int i = 0; i < devices.Length; i++)
      Log.Log.WriteFile("analog: AddTvEncoderFilter no encoder found");
      return false;
    }
    /// <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;
    }
    /// <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;
    }
Exemple #9
0
        /// <summary>
        /// Builds the directshow graph for this analog tvcard
        /// </summary>
        public override void BuildGraph()
        {
            if (_cardId == 0)
            {
                GetPreloadBitAndCardId();
                _configuration = Configuration.readConfiguration(_cardId, _name, _devicePath);
                Configuration.writeConfiguration(_configuration);
            }
            _lastSignalUpdate = DateTime.MinValue;
            _tunerLocked      = false;
            Log.Log.WriteFile("analog: build graph");
            try
            {
                if (_graphState != GraphState.Idle)
                {
                    Log.Log.WriteFile("analog: Graph already build");
                    throw new TvException("Graph already build");
                }
                //create a new filter graph
                _graphBuilder = (IFilterGraph2) new FilterGraph();
                _rotEntry     = new DsROTEntry(_graphBuilder);
                _capBuilder   = (ICaptureGraphBuilder2) new CaptureGraphBuilder2();
                _capBuilder.SetFiltergraph(_graphBuilder);
                Graph graph = _configuration.Graph;
                _tuner = new Tuner(_device);
                if (!_tuner.CreateFilterInstance(graph, _graphBuilder))
                {
                    Log.Log.Error("analog: unable to add tv tuner filter");
                    throw new TvException("Analog: unable to add tv tuner filter");
                }
                _minChannel = _tuner.MinChannel;
                _maxChannel = _tuner.MaxChannel;
                //add the wdm crossbar device and connect tvtuner->crossbar
                _crossbar = new Crossbar();
                if (!_crossbar.CreateFilterInstance(graph, _graphBuilder, _tuner))
                {
                    Log.Log.Error("analog: unable to add tv crossbar filter");
                    throw new TvException("Analog: unable to add tv crossbar filter");
                }
                //add the tv audio tuner device and connect it to the crossbar
                _tvAudio = new TvAudio();
                if (!_tvAudio.CreateFilterInstance(graph, _graphBuilder, _tuner, _crossbar))
                {
                    Log.Log.Error("analog: unable to add tv audio tuner filter");
                    throw new TvException("Analog: unable to add tv audio tuner filter");
                }
                //add the tv capture device and connect it to the crossbar
                _capture = new Capture();
                if (!_capture.CreateFilterInstance(graph, _capBuilder, _graphBuilder, _tuner, _crossbar, _tvAudio))
                {
                    Log.Log.Error("analog: unable to add capture filter");
                    throw new TvException("Analog: unable to add capture filter");
                }
                Configuration.writeConfiguration(_configuration);
                _teletext = new TeletextComponent();
                if (_capture.SupportsTeletext)
                {
                    if (!_teletext.CreateFilterInstance(graph, _graphBuilder, _capture))
                    {
                        Log.Log.Error("analog: unable to setup teletext filters");
                        throw new TvException("Analog: unable to setup teletext filters");
                    }
                }
                Configuration.writeConfiguration(_configuration);
                _encoder = new Encoder();
                if (!_encoder.CreateFilterInstance(_graphBuilder, _tuner, _tvAudio, _crossbar, _capture))
                {
                    Log.Log.Error("analog: unable to add encoding filter");
                    throw new TvException("Analog: unable to add capture filter");
                }
                Log.Log.WriteFile("analog: Check quality control");
                _qualityControl = QualityControlFactory.createQualityControl(_configuration, _encoder.VideoEncoderFilter,
                                                                             _capture.VideoFilter, _encoder.MultiplexerFilter,
                                                                             _encoder.VideoCompressorFilter);
                if (_qualityControl == null)
                {
                    Log.Log.WriteFile("analog: No quality control support found");
                    //If a hauppauge analog card, set bitrate to default
                    //As the graph is stopped, we don't need to pass in the deviceID
                    //However, if we wish to change quality for a live graph, the deviceID must be passed in
                    if (_tunerDevice != null && _capture.VideoFilter != null)
                    {
                        if (_capture.VideoCaptureName.Contains("Hauppauge"))
                        {
                            Hauppauge _hauppauge = new Hauppauge(_capture.VideoFilter, string.Empty);
                            _hauppauge.SetStream(103);
                            _hauppauge.SetAudioBitRate(384);
                            _hauppauge.SetVideoBitRate(6000, 8000, true);
                            int  min, max;
                            bool vbr;
                            _hauppauge.GetVideoBitRate(out min, out max, out vbr);
                            Log.Log.Write("Hauppauge set video parameters - Max kbps: {0}, Min kbps: {1}, VBR {2}", max, min, vbr);
                            _hauppauge.Dispose();
                            _hauppauge = null;
                        }
                    }
                }

                if (!AddTsFileSink())
                {
                    throw new TvException("Analog: unable to add mpfilewriter");
                }
                Log.Log.WriteFile("analog: Graph is built");
                FilterGraphTools.SaveGraphFile(_graphBuilder, "analog.grf");
                ReloadCardConfiguration();
                _graphState = GraphState.Created;
            }
            catch (TvExceptionSWEncoderMissing ex)
            {
                Log.Log.Write(ex);
                Dispose();
                _graphState = GraphState.Idle;
                throw;
            }
            catch (Exception ex)
            {
                Log.Log.Write(ex);
                Dispose();
                _graphState = GraphState.Idle;
                throw new TvExceptionGraphBuildingFailed("Graph building failed", ex);
            }
        }
Exemple #10
0
        /// <summary>
        /// Disposes this instance.
        /// </summary>
        public virtual void Dispose()
        {
            if (_graphBuilder == null)
            {
                return;
            }
            Log.Log.WriteFile("analog:Dispose()");
            if (!CheckThreadId())
            {
                return;
            }

            if (_graphState == GraphState.TimeShifting || _graphState == GraphState.Recording)
            {
                // Stop the graph first. To ensure that the timeshift files are no longer blocked
                StopGraph();
            }
            FreeAllSubChannels();
            IMediaControl mediaCtl = (_graphBuilder as IMediaControl);

            if (mediaCtl == null)
            {
                throw new TvException("Can not convert graphBuilder to IMediaControl");
            }
            // Decompose the graph
            mediaCtl.Stop();
            FilterGraphTools.RemoveAllFilters(_graphBuilder);
            Log.Log.WriteFile("analog:All filters removed");
            if (_tuner != null)
            {
                _tuner.Dispose();
                _tuner       = null;
                _tunerDevice = null;
            }
            if (_crossbar != null)
            {
                _crossbar.Dispose();
                _crossbar = null;
            }
            if (_tvAudio != null)
            {
                _tvAudio.Dispose();
                _tvAudio = null;
            }
            if (_capture != null)
            {
                _capture.Dispose();
                _capture = null;
            }
            if (_encoder != null)
            {
                _encoder.Dispose();
                _encoder = null;
            }
            if (_teletext != null)
            {
                _teletext.Dispose();
                _teletext = null;
            }
            if (_tsFileSink != null)
            {
                Release.ComObject("tsFileSink filter", _tsFileSink);
                _tsFileSink = null;
            }
            _rotEntry.Dispose();
            _rotEntry = null;
            Release.ComObject("Graphbuilder", _graphBuilder);
            _graphBuilder = null;
            _graphState   = GraphState.Idle;
            Log.Log.WriteFile("analog: dispose completed");
        }
    /// <summary>
    /// Builds the directshow graph for this analog tvcard
    /// </summary>
    public override void BuildGraph()
    {
      if (_cardId == 0)
      {
        GetPreloadBitAndCardId();
        _configuration = Configuration.readConfiguration(_cardId, _name, _devicePath);
        Configuration.writeConfiguration(_configuration);
      }
      _lastSignalUpdate = DateTime.MinValue;
      _tunerLocked = false;
      Log.Log.WriteFile("analog: build graph");
      try
      {
        if (_graphState != GraphState.Idle)
        {
          Log.Log.WriteFile("analog: Graph already build");
          throw new TvException("Graph already build");
        }
        //create a new filter graph
        _graphBuilder = (IFilterGraph2)new FilterGraph();
        _rotEntry = new DsROTEntry(_graphBuilder);
        _capBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
        _capBuilder.SetFiltergraph(_graphBuilder);
        Graph graph = _configuration.Graph;
        _tuner = new Tuner(_device);
        if (!_tuner.CreateFilterInstance(graph, _graphBuilder))
        {
          Log.Log.Error("analog: unable to add tv tuner filter");
          throw new TvException("Analog: unable to add tv tuner filter");
        }
        _minChannel = _tuner.MinChannel;
        _maxChannel = _tuner.MaxChannel;
        //add the wdm crossbar device and connect tvtuner->crossbar
        _crossbar = new Crossbar();
        if (!_crossbar.CreateFilterInstance(graph, _graphBuilder, _tuner))
        {
          Log.Log.Error("analog: unable to add tv crossbar filter");
          throw new TvException("Analog: unable to add tv crossbar filter");
        }
        //add the tv audio tuner device and connect it to the crossbar
        _tvAudio = new TvAudio();
        if (!_tvAudio.CreateFilterInstance(graph, _graphBuilder, _tuner, _crossbar))
        {
          Log.Log.Error("analog: unable to add tv audio tuner filter");
          throw new TvException("Analog: unable to add tv audio tuner filter");
        }
        //add the tv capture device and connect it to the crossbar
        _capture = new Capture();
        if (!_capture.CreateFilterInstance(graph, _capBuilder, _graphBuilder, _tuner, _crossbar, _tvAudio))
        {
          Log.Log.Error("analog: unable to add capture filter");
          throw new TvException("Analog: unable to add capture filter");
        }
        Configuration.writeConfiguration(_configuration);
        _teletext = new TeletextComponent();
        if (_capture.SupportsTeletext)
        {
          if (!_teletext.CreateFilterInstance(graph, _graphBuilder, _capture))
          {
            Log.Log.Error("analog: unable to setup teletext filters");
            throw new TvException("Analog: unable to setup teletext filters");
          }
        }
        Configuration.writeConfiguration(_configuration);
        _encoder = new Encoder();
        if (!_encoder.CreateFilterInstance(_graphBuilder, _tuner, _tvAudio, _crossbar, _capture))
        {
          Log.Log.Error("analog: unable to add encoding filter");
          throw new TvException("Analog: unable to add capture filter");
        }
        Log.Log.WriteFile("analog: Check quality control");
        _qualityControl = QualityControlFactory.createQualityControl(_configuration, _encoder.VideoEncoderFilter,
                                                                     _capture.VideoFilter, _encoder.MultiplexerFilter,
                                                                     _encoder.VideoCompressorFilter);
        if (_qualityControl == null)
        {
          Log.Log.WriteFile("analog: No quality control support found");
          //If a hauppauge analog card, set bitrate to default
          //As the graph is stopped, we don't need to pass in the deviceID
          //However, if we wish to change quality for a live graph, the deviceID must be passed in
          if (_tunerDevice != null && _capture.VideoFilter != null)
          {
            if (_capture.VideoCaptureName.Contains("Hauppauge"))
            {
              Hauppauge _hauppauge = new Hauppauge(_capture.VideoFilter, string.Empty);
              _hauppauge.SetStream(103);
              _hauppauge.SetAudioBitRate(384);
              _hauppauge.SetVideoBitRate(6000, 8000, true);
              int min, max;
              bool vbr;
              _hauppauge.GetVideoBitRate(out min, out max, out vbr);
              Log.Log.Write("Hauppauge set video parameters - Max kbps: {0}, Min kbps: {1}, VBR {2}", max, min, vbr);
              _hauppauge.Dispose();
              _hauppauge = null;
            }
          }
        }

        if (!AddTsFileSink())
        {
          throw new TvException("Analog: unable to add mpfilewriter");
        }
        Log.Log.WriteFile("analog: Graph is built");
        FilterGraphTools.SaveGraphFile(_graphBuilder, "analog.grf");
        ReloadCardConfiguration();
        _graphState = GraphState.Created;
      }
      catch (TvExceptionSWEncoderMissing ex)
      {
        Log.Log.Write(ex);
        Dispose();
        _graphState = GraphState.Idle;
        throw;
      }
      catch (Exception ex)
      {
        Log.Log.Write(ex);
        Dispose();
        _graphState = GraphState.Idle;
        throw new TvExceptionGraphBuildingFailed("Graph building failed", ex);
      }
    }
    /// <summary>
    /// Disposes this instance.
    /// </summary>
    public virtual void Dispose()
    {
      if (_graphBuilder == null)
        return;
      Log.Log.WriteFile("analog:Dispose()");
      if (!CheckThreadId())
        return;

      if (_graphState == GraphState.TimeShifting || _graphState == GraphState.Recording)
      {
        // Stop the graph first. To ensure that the timeshift files are no longer blocked
        StopGraph();
      }
      FreeAllSubChannels();
      IMediaControl mediaCtl = (_graphBuilder as IMediaControl);
      if (mediaCtl == null)
      {
        throw new TvException("Can not convert graphBuilder to IMediaControl");
      }
      // Decompose the graph
      mediaCtl.Stop();
      FilterGraphTools.RemoveAllFilters(_graphBuilder);
      Log.Log.WriteFile("analog:All filters removed");
      if (_tuner != null)
      {
        _tuner.Dispose();
        _tuner = null;
        _tunerDevice = null;
      }
      if (_crossbar != null)
      {
        _crossbar.Dispose();
        _crossbar = null;
      }
      if (_tvAudio != null)
      {
        _tvAudio.Dispose();
        _tvAudio = null;
      }
      if (_capture != null)
      {
        _capture.Dispose();
        _capture = null;
      }
      if (_encoder != null)
      {
        _encoder.Dispose();
        _encoder = null;
      }
      if (_teletext != null)
      {
        _teletext.Dispose();
        _teletext = null;
      }
      if (_tsFileSink != null)
      {
        Release.ComObject("tsFileSink filter", _tsFileSink);
        _tsFileSink = null;
      }
      _rotEntry.Dispose();
      _rotEntry = null;
      Release.ComObject("Graphbuilder", _graphBuilder);
      _graphBuilder = null;
      _graphState = GraphState.Idle;
      Log.Log.WriteFile("analog: dispose completed");
    }