SourceCollection.cs
Upload User: wuming6209
Upload Date: 2013-06-06
Package Size: 161k
Code Size: 9k
Category:

Video Capture

Development Platform:

Visual C++

  1. // ------------------------------------------------------------------
  2. // DirectX.Capture
  3. //
  4. // History:
  5. // 2003-Jan-24 BL - created
  6. //
  7. // Copyright (c) 2003 Brian Low
  8. // ------------------------------------------------------------------
  9. using System;
  10. using System.Diagnostics; 
  11. using System.Collections;
  12. using System.Runtime.InteropServices;
  13. using DShowNET;
  14. namespace DirectX.Capture
  15. {
  16. /// <summary>
  17. ///  A collection of sources (or physical connectors) on an 
  18. ///  audio or video device. This is used by the <see cref="Capture"/>
  19. ///  class to provide a list of available sources on the currently
  20. ///  selected audio and video devices. This class cannot be created
  21. ///  directly.  This class assumes there is only 1 video and 1 audio
  22. ///  crossbar and all input pins route to a single output pin on each 
  23. ///  crossbar.
  24. /// </summary>
  25. public class SourceCollection : CollectionBase, IDisposable
  26. {
  27. // ------------------ Constructors/Destructors -----------------------
  28. /// <summary> Initialize collection with no sources. </summary>
  29. internal SourceCollection()
  30. {
  31. InnerList.Capacity = 1;
  32. }
  33. /// <summary> Initialize collection with sources from graph. </summary>
  34. internal SourceCollection(ICaptureGraphBuilder2 graphBuilder, IBaseFilter deviceFilter, bool isVideoDevice)
  35. {
  36. addFromGraph( graphBuilder, deviceFilter, isVideoDevice );
  37. }
  38. /// <summary> Destructor. Release unmanaged resources. </summary>
  39. ~SourceCollection()
  40. {
  41. Dispose();
  42. }
  43. // -------------------- Public Properties -----------------------
  44. /// <summary> Get the source at the specified index. </summary>
  45. public Source this[int index]
  46. {
  47. get { return( (Source) InnerList[index] ); }
  48. }
  49. /// <summary>
  50. ///  Gets or sets the source/physical connector currently in use.
  51. ///  This is marked internal so that the Capture class can control
  52. ///  how and when the source is changed.
  53. /// </summary>
  54. internal Source CurrentSource
  55. {
  56. get 
  57. {
  58. // Loop through each source and find the first
  59. // enabled source.
  60. foreach ( Source s in InnerList )
  61. {
  62. if ( s.Enabled )
  63. return( s );
  64. }
  65. return ( null );
  66. }
  67. set
  68. {
  69. if ( value == null )
  70. {
  71. // Disable all sources
  72. foreach ( Source s in InnerList )
  73. s.Enabled = false;
  74. }
  75. else if ( value is CrossbarSource )
  76. {
  77. // Enable this source
  78. // (this will automatically disable all other sources)
  79. value.Enabled = true;
  80. }
  81. else
  82. {
  83. // Disable all sources
  84. // Enable selected source
  85. foreach ( Source s in InnerList )
  86. s.Enabled = false;
  87. value.Enabled = true;
  88. }
  89. }
  90. }
  91. // -------------------- Public methods -----------------------
  92. /// <summary> Empty the collection. </summary>
  93. public new void Clear()
  94. {
  95. for ( int c = 0; c < InnerList.Count; c++ )
  96. this[c].Dispose();
  97. InnerList.Clear();
  98. }
  99. /// <summary> Release unmanaged resources. </summary>
  100. public void Dispose()
  101. {
  102. Clear();
  103. InnerList.Capacity = 1;
  104. }
  105. // -------------------- Protected Methods -----------------------
  106. /// <summary> Populate the collection from a filter graph. </summary>
  107. protected void addFromGraph ( ICaptureGraphBuilder2 graphBuilder, IBaseFilter deviceFilter, bool isVideoDevice )
  108. {
  109. Trace.Assert( graphBuilder != null );
  110. ArrayList crossbars = findCrossbars( graphBuilder, deviceFilter );
  111. foreach ( IAMCrossbar crossbar in crossbars )
  112. {
  113. ArrayList sources = findCrossbarSources( graphBuilder, crossbar, isVideoDevice );
  114. InnerList.AddRange( sources );
  115. }
  116. if ( !isVideoDevice )
  117. {
  118. if ( InnerList.Count == 0 )
  119. {
  120. ArrayList sources = findAudioSources( graphBuilder, deviceFilter );
  121. InnerList.AddRange( sources );
  122. }
  123. }
  124. }
  125. /// <summary>
  126. ///  Retrieve a list of crossbar filters in the graph.
  127. ///  Most hardware devices should have a maximum of 2 crossbars, 
  128. ///  one for video and another for audio.
  129. /// </summary>
  130. protected ArrayList findCrossbars(ICaptureGraphBuilder2 graphBuilder, IBaseFilter deviceFilter)
  131. {
  132. ArrayList crossbars = new ArrayList();
  133. Guid category = FindDirection.UpstreamOnly;
  134. Guid type = new Guid();
  135. Guid riid = typeof(IAMCrossbar).GUID;
  136. int hr;
  137. object comObj = null;
  138. object comObjNext = null;
  139. // Find the first interface, look upstream from the selected device
  140. hr = graphBuilder.FindInterface( ref category, ref type, deviceFilter, ref riid, out comObj );
  141. while ( (hr == 0) && (comObj != null) )
  142. {
  143. // If found, add to the list
  144. if ( comObj is IAMCrossbar )
  145. {
  146. crossbars.Add( comObj as IAMCrossbar );
  147. // Find the second interface, look upstream from the next found crossbar
  148. hr = graphBuilder.FindInterface( ref category, ref type, comObj as IBaseFilter, ref riid, out comObjNext );
  149. comObj = comObjNext;
  150. }
  151. else
  152. comObj = null;
  153. }
  154. return( crossbars );
  155. }
  156. /// <summary>
  157. ///  Populate the internal InnerList with sources/physical connectors
  158. ///  found on the crossbars. Each instance of this class is limited
  159. ///  to video only or audio only sources ( specified by the isVideoDevice
  160. ///  parameter on the constructor) so we check each source before adding
  161. ///  it to the list.
  162. /// </summary>
  163. protected ArrayList findCrossbarSources(ICaptureGraphBuilder2 graphBuilder, IAMCrossbar crossbar, bool isVideoDevice)
  164. {
  165. ArrayList sources = new ArrayList();
  166. int hr;
  167. int numOutPins;
  168. int numInPins;
  169. hr = crossbar.get_PinCounts( out numOutPins, out numInPins );
  170. if ( hr < 0 )
  171. Marshal.ThrowExceptionForHR( hr );
  172. // We loop through every combination of output and input pin
  173. // to see which combinations match.
  174. // Loop through output pins
  175. for ( int cOut = 0; cOut < numOutPins; cOut++ )
  176. {
  177. // Loop through input pins
  178. for ( int cIn = 0; cIn < numInPins; cIn++ )
  179. {
  180. // Can this combination be routed?
  181. hr = crossbar.CanRoute( cOut, cIn );
  182. if ( hr == 0 )
  183. {
  184. // Yes, this can be routed
  185. int relatedPin;
  186. PhysicalConnectorType connectorType;
  187. hr = crossbar.get_CrossbarPinInfo( true, cIn, out relatedPin, out connectorType );
  188. if ( hr < 0 )
  189. Marshal.ThrowExceptionForHR( hr );
  190. // Is this the correct type?, If so add to the InnerList
  191. CrossbarSource source = new CrossbarSource( crossbar, cOut, cIn, connectorType );
  192. if ( connectorType < PhysicalConnectorType.Audio_Tuner )
  193. if ( isVideoDevice )
  194. sources.Add( source );
  195. else
  196. if ( !isVideoDevice )
  197. sources.Add( source );
  198. }
  199. }
  200. }
  201. // Some silly drivers (*cough* Nvidia *cough*) add crossbars
  202. // with no real choices. Every input can only be routed to
  203. // one output. Loop through every Source and see if there
  204. // at least one other Source with the same output pin.
  205. int refIndex = 0;
  206. while ( refIndex < sources.Count )
  207. {
  208. bool found = false;
  209. CrossbarSource refSource = (CrossbarSource) sources[refIndex];
  210. for ( int c = 0; c < sources.Count; c++ )
  211. {
  212. CrossbarSource s = (CrossbarSource) sources[c];
  213. if ( ( refSource.OutputPin == s.OutputPin ) && ( refIndex != c ) )
  214. {
  215. found = true;
  216. break;
  217. }
  218. }
  219. if ( found )
  220. refIndex++;
  221. else
  222. sources.RemoveAt( refIndex );
  223. }
  224. return( sources );
  225. }
  226. protected ArrayList findAudioSources(ICaptureGraphBuilder2 graphBuilder, IBaseFilter deviceFilter)
  227. {
  228. ArrayList sources = new ArrayList();
  229. IAMAudioInputMixer audioInputMixer = deviceFilter as IAMAudioInputMixer;
  230. if ( audioInputMixer != null )
  231. {
  232. // Get a pin enumerator off the filter
  233. IEnumPins pinEnum;
  234. int hr = deviceFilter.EnumPins( out pinEnum );
  235. pinEnum.Reset();
  236. if( (hr == 0) && (pinEnum != null) )
  237. {
  238. // Loop through each pin
  239. IPin[] pins = new IPin[1];
  240. int f;
  241. do
  242. {
  243. // Get the next pin
  244. hr = pinEnum.Next( 1, pins, out f );
  245. if( (hr == 0) && (pins[0] != null) )
  246. {
  247. // Is this an input pin?
  248. PinDirection dir = PinDirection.Output;
  249. hr = pins[0].QueryDirection( out dir );
  250. if( (hr == 0) && (dir == (PinDirection.Input)) )
  251. {
  252. // Add the input pin to the sources list
  253. AudioSource source = new AudioSource( pins[0] ); 
  254. sources.Add( source );
  255. }
  256. pins[0] = null;
  257. }
  258. }
  259. while( hr == 0 );
  260. Marshal.ReleaseComObject( pinEnum ); pinEnum = null;
  261. }
  262. }
  263. // If there is only one source, don't return it
  264. // because there is nothing for the user to choose.
  265. // (Hopefully that single source is already enabled).
  266. if ( sources.Count == 1 )
  267. sources.Clear();
  268. return( sources );
  269. }
  270. }
  271. }