/// <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> /// 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; }
/// <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; }