PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/VmcController/MCEState/DirectShow/DvrmsMetadata.cs

#
C# | 265 lines | 147 code | 29 blank | 89 comment | 15 complexity | 2bbfe26fafaac1d3ad5bfb64cdf4ad20 MD5 | raw file
  1. // Stephen Toub
  2. // stoub@microsoft.com
  3. using System;
  4. using System.IO;
  5. using System.Text;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Runtime.InteropServices;
  9. using Microsoft.DirectShow;
  10. namespace Microsoft.DirectShow.Metadata
  11. {
  12. /// <summary>
  13. /// Metadata editor for DVR-MS files.
  14. /// </summary>
  15. public sealed class DvrmsMetadata: IDisposable
  16. {
  17. IStreamBufferRecordingAttribute _editor;
  18. /// <summary>Initializes the editor.</summary>
  19. /// <param name="filepath">The path to the file.</param>
  20. public DvrmsMetadata(string filepath)
  21. {
  22. IFileSourceFilter sourceFilter = (IFileSourceFilter)ClassId.CoCreateInstance(ClassId.RecordingAttributes);
  23. sourceFilter.Load(filepath, null);
  24. _editor = (IStreamBufferRecordingAttribute)sourceFilter;
  25. }
  26. /// <summary>Gets all of the attributes on a file.</summary>
  27. /// <returns>A collection of the attributes from the file.</returns>
  28. public Dictionary<string, MetadataItem> GetAttributes()
  29. {
  30. if (_editor == null) throw new ObjectDisposedException(GetType().Name);
  31. Dictionary<string, MetadataItem> propsRetrieved = new Dictionary<string, MetadataItem>();
  32. object obj = _editor.EnumAttributes();
  33. // Get the number of attributes
  34. ushort attributeCount = _editor.GetAttributeCount(0);
  35. // Get each attribute by index
  36. for(ushort i = 0; i < attributeCount; i++)
  37. {
  38. MetadataItemType attributeType;
  39. StringBuilder attributeName = null;
  40. byte[] attributeValue = null;
  41. ushort attributeNameLength = 0;
  42. ushort attributeValueLength = 0;
  43. // Get the lengths of the name and the value, then use them to create buffers to receive them
  44. uint reserved = 0;
  45. _editor.GetAttributeByIndex(i, ref reserved, attributeName, ref attributeNameLength,
  46. out attributeType, attributeValue, ref attributeValueLength);
  47. attributeName = new StringBuilder(attributeNameLength);
  48. attributeValue = new byte[attributeValueLength];
  49. // Get the name and value
  50. _editor.GetAttributeByIndex(i, ref reserved, attributeName, ref attributeNameLength,
  51. out attributeType, attributeValue, ref attributeValueLength);
  52. // If we got a name, parse the value and add the metadata item
  53. if (attributeName != null && attributeName.Length > 0)
  54. {
  55. object val = ParseAttributeValue(attributeType, attributeValue);
  56. string key = attributeName.ToString().TrimEnd('\0');
  57. propsRetrieved[key] = new MetadataItem(key, val, attributeType);
  58. }
  59. }
  60. // Return the parsed items
  61. return propsRetrieved;
  62. }
  63. /// <summary>Gets the value of the specified attribute.</summary>
  64. /// <param name="itemType">The type of the attribute.</param>
  65. /// <param name="valueData">The byte array to be parsed.</param>
  66. private static object ParseAttributeValue(MetadataItemType itemType, byte[] valueData)
  67. {
  68. if (!Enum.IsDefined(typeof(MetadataItemType), itemType))
  69. throw new ArgumentOutOfRangeException("itemType");
  70. if (valueData == null) throw new ArgumentNullException("valueData");
  71. // Convert the attribute value to a byte array based on the item type.
  72. switch (itemType)
  73. {
  74. case MetadataItemType.String:
  75. StringBuilder sb = new StringBuilder(valueData.Length);
  76. for (int i = 0; i < valueData.Length - 2; i += 2)
  77. {
  78. sb.Append(Convert.ToString(BitConverter.ToChar(valueData, i)));
  79. }
  80. string result = sb.ToString();
  81. if (result.EndsWith("\\0")) result = result.Substring(0, result.Length - 2);
  82. return result;
  83. case MetadataItemType.Boolean: return BitConverter.ToBoolean(valueData, 0);
  84. case MetadataItemType.Dword: return BitConverter.ToInt32(valueData, 0);
  85. case MetadataItemType.Qword: return BitConverter.ToInt64(valueData, 0);
  86. case MetadataItemType.Word: return BitConverter.ToInt16(valueData, 0);
  87. case MetadataItemType.Guid: return new Guid(valueData);
  88. case MetadataItemType.Binary: return valueData;
  89. default: throw new ArgumentOutOfRangeException("itemType");
  90. }
  91. }
  92. /// <summary>
  93. /// Releases unmanaged and - optionally - managed resources
  94. /// </summary>
  95. public void Dispose()
  96. {
  97. Dispose(true);
  98. GC.SuppressFinalize(this);
  99. }
  100. /// <summary>
  101. /// Releases unmanaged and - optionally - managed resources
  102. /// </summary>
  103. /// <param name="disposeManagedObjs"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  104. void Dispose(bool disposeManagedObjs)
  105. {
  106. if (disposeManagedObjs && _editor != null)
  107. {
  108. while(Marshal.ReleaseComObject(_editor) > 0);
  109. _editor = null;
  110. }
  111. }
  112. /// <summary>
  113. /// Releases unmanaged resources and performs other cleanup operations before the
  114. /// <see cref="DvrmsMetadata"/> is reclaimed by garbage collection.
  115. /// </summary>
  116. ~DvrmsMetadata()
  117. {
  118. Dispose(false);
  119. }
  120. [ComImport]
  121. [Guid("16CA4E03-FE69-4705-BD41-5B7DFC0C95F3")]
  122. [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  123. private interface IStreamBufferRecordingAttribute
  124. {
  125. /// <summary>Sets an attribute on a recording object. If an attribute of the same name already exists, overwrites the old.</summary>
  126. /// <param name="ulReserved">Reserved. Set this parameter to zero.</param>
  127. /// <param name="pszAttributeName">Wide-character string that contains the name of the attribute.</param>
  128. /// <param name="StreamBufferAttributeType">Defines the data type of the attribute data.</param>
  129. /// <param name="pbAttribute">Pointer to a buffer that contains the attribute data.</param>
  130. /// <param name="cbAttributeLength">The size of the buffer specified in pbAttribute.</param>
  131. void SetAttribute(
  132. [In] uint ulReserved,
  133. [In, MarshalAs(UnmanagedType.LPWStr)] string pszAttributeName,
  134. [In] MetadataItemType StreamBufferAttributeType,
  135. [In, MarshalAs(UnmanagedType.LPArray)] byte [] pbAttribute,
  136. [In] ushort cbAttributeLength);
  137. /// <summary>Returns the number of attributes that are currently defined for this stream buffer file.</summary>
  138. /// <param name="ulReserved">Reserved. Set this parameter to zero.</param>
  139. /// <returns>Number of attributes that are currently defined for this stream buffer file.</returns>
  140. ushort GetAttributeCount([In] uint ulReserved);
  141. /// <summary>Given a name, returns the attribute data.</summary>
  142. /// <param name="pszAttributeName">Wide-character string that contains the name of the attribute.</param>
  143. /// <param name="pulReserved">Reserved. Set this parameter to zero.</param>
  144. /// <param name="pStreamBufferAttributeType">
  145. /// Pointer to a variable that receives a member of the STREAMBUFFER_ATTR_DATATYPE enumeration.
  146. /// This value indicates the data type that you should use to interpret the attribute, which is
  147. /// returned in the pbAttribute parameter.
  148. /// </param>
  149. /// <param name="pbAttribute">
  150. /// Pointer to a buffer that receives the attribute, as an array of bytes. Specify the size of the buffer in the
  151. /// pcbLength parameter. To find out the required size for the array, set pbAttribute to NULL and check the
  152. /// value that is returned in pcbLength.
  153. /// </param>
  154. /// <param name="pcbLength">
  155. /// On input, specifies the size of the buffer given in pbAttribute, in bytes. On output,
  156. /// contains the number of bytes that were copied to the buffer.
  157. /// </param>
  158. void GetAttributeByName(
  159. [In, MarshalAs(UnmanagedType.LPWStr)] string pszAttributeName,
  160. [In] ref uint pulReserved,
  161. [Out] out MetadataItemType pStreamBufferAttributeType,
  162. [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbAttribute,
  163. [In, Out] ref ushort pcbLength);
  164. /// <summary>The GetAttributeByIndex method retrieves an attribute, specified by index number.</summary>
  165. /// <param name="wIndex">Zero-based index of the attribute to retrieve.</param>
  166. /// <param name="pulReserved">Reserved. Set this parameter to zero.</param>
  167. /// <param name="pszAttributeName">Pointer to a buffer that receives the name of the attribute, as a null-terminated wide-character string.</param>
  168. /// <param name="pcchNameLength">On input, specifies the size of the buffer given in pszAttributeName, in wide characters.</param>
  169. /// <param name="pStreamBufferAttributeType">Pointer to a variable that receives a member of the STREAMBUFFER_ATTR_DATATYPE enumeration.</param>
  170. /// <param name="pbAttribute">Pointer to a buffer that receives the attribute, as an array of bytes.</param>
  171. /// <param name="pcbLength">On input, specifies the size of the buffer given in pbAttribute, in bytes.</param>
  172. void GetAttributeByIndex (
  173. [In] ushort wIndex,
  174. [In, Out] ref uint pulReserved,
  175. [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszAttributeName,
  176. [In, Out] ref ushort pcchNameLength,
  177. [Out] out MetadataItemType pStreamBufferAttributeType,
  178. [Out, MarshalAs(UnmanagedType.LPArray)] byte [] pbAttribute,
  179. [In, Out] ref ushort pcbLength);
  180. /// <summary>The EnumAttributes method enumerates the existing attributes of the stream buffer file.</summary>
  181. /// <returns>Address of a variable that receives an IEnumStreamBufferRecordingAttrib interface pointer.</returns>
  182. [return: MarshalAs(UnmanagedType.Interface)]
  183. object EnumAttributes();
  184. }
  185. }
  186. /// <summary>The type of a metadata attribute value.</summary>
  187. public enum MetadataItemType
  188. {
  189. /// <summary>DWORD</summary>
  190. Dword = 0,
  191. /// <summary>String</summary>
  192. String = 1,
  193. /// <summary>Binary</summary>
  194. Binary = 2,
  195. /// <summary>Boolean</summary>
  196. Boolean = 3,
  197. /// <summary>QWORD</summary>
  198. Qword = 4,
  199. /// <summary>WORD</summary>
  200. Word = 5,
  201. /// <summary>Guid</summary>
  202. Guid = 6,
  203. }
  204. /// <summary>Represents a metadata attribute.</summary>
  205. public class MetadataItem : ICloneable
  206. {
  207. /// <summary>The name of the attribute.</summary>
  208. private string _name;
  209. /// <summary>The value of the attribute.</summary>
  210. private object _value;
  211. /// <summary>The type of the attribute value.</summary>
  212. private MetadataItemType _type;
  213. /// <summary>Initializes the metadata item.</summary>
  214. /// <param name="name">The name of the attribute.</param>
  215. /// <param name="value">The value of the attribute.</param>
  216. /// <param name="type">The type of the attribute value.</param>
  217. internal MetadataItem(string name, object value, MetadataItemType type)
  218. {
  219. Name = name;
  220. Value = value;
  221. Type = type;
  222. }
  223. /// <summary>Gets or sets the name of the attribute.</summary>
  224. public string Name { get { return _name; } set { _name = value; } }
  225. /// <summary>Gets or sets the value of the attribute.</summary>
  226. public object Value { get { return _value; } set { _value = value; } }
  227. /// <summary>Gets or sets the type of the attribute value.</summary>
  228. public MetadataItemType Type { get { return _type; } set { _type = value; } }
  229. /// <summary>Clones the attribute item.</summary>
  230. /// <returns>A shallow copy of the attribute.</returns>
  231. public MetadataItem Clone() { return (MetadataItem)MemberwiseClone(); }
  232. /// <summary>Clones the attribute item.</summary>
  233. /// <returns>A shallow copy of the attribute.</returns>
  234. object ICloneable.Clone() { return Clone(); }
  235. }
  236. }