/// <summary> /// Copy field values from another <see cref="WaveFormat"/> object. /// </summary> /// <param name="other">The <see cref="WaveFormat"/> object to copy from.</param> public override void CopyFrom(WaveFormat other) { base.CopyFrom(other); WaveFormatEx otherEx = other as WaveFormatEx; if (otherEx != null) { this.ExtraInfo = (byte[])otherEx.ExtraInfo?.Clone(); } }
/// <summary> /// Reads from a stream to create a WaveFormat object. /// </summary> /// <param name="stream"> /// The stream to read the WaveFormat from (e.g. a file). The stream should already /// be positioned on the first byte of the WaveFormat header (i.e. the format tag). /// Note that the stream is not disposed after the header has been read. /// </param> /// <param name="formatLength"> /// The total number of bytes in the stream that represent the WaveFormat header. /// </param> /// <returns> /// A new WaveFormat header constructed from the stream. /// </returns> public static WaveFormat FromStream(Stream stream, int formatLength) { if (formatLength < 16) { throw new InvalidDataException("A WaveFormat must contain at least 16 bytes"); } BinaryReader reader = new BinaryReader(stream); WaveFormat waveFormat = new WaveFormat(); waveFormat.FormatTag = (WaveFormatTag)reader.ReadUInt16(); waveFormat.Channels = reader.ReadUInt16(); waveFormat.SamplesPerSec = reader.ReadUInt32(); waveFormat.AvgBytesPerSec = reader.ReadUInt32(); waveFormat.BlockAlign = reader.ReadUInt16(); waveFormat.BitsPerSample = reader.ReadUInt16(); if (formatLength > 16) { // Format may contain extra bytes waveFormat.ExtraSize = reader.ReadUInt16(); // Sanity check and size limit if (waveFormat.ExtraSize > formatLength - 18) { throw new FormatException("Format extra size too large"); } if (waveFormat.ExtraSize > 0) { // Promote to a WaveFormatEx object to hold the extra info waveFormat = new WaveFormatEx() { FormatTag = waveFormat.FormatTag, SamplesPerSec = waveFormat.SamplesPerSec, BitsPerSample = waveFormat.BitsPerSample, Channels = waveFormat.Channels, BlockAlign = waveFormat.BlockAlign, AvgBytesPerSec = waveFormat.AvgBytesPerSec, ExtraSize = waveFormat.ExtraSize, // Read in the extended format extra bytes ExtraInfo = reader.ReadBytes(waveFormat.ExtraSize) }; } } return(waveFormat); }
/// <summary> /// Gets the appropriate Media Foundation audio media subtype from the specified wave format. /// </summary> /// <param name="format"> /// Input wave format to convert. /// </param> /// <returns> /// Media Foundation audio subtype resulting from conversion. /// </returns> internal static Guid GetMediaSubtype(WaveFormat format) { switch (format.FormatTag) { case WaveFormatTag.WAVE_FORMAT_PCM: case WaveFormatTag.WAVE_FORMAT_IEEE_FLOAT: case WaveFormatTag.WAVE_FORMAT_DTS: case WaveFormatTag.WAVE_FORMAT_DOLBY_AC3_SPDIF: case WaveFormatTag.WAVE_FORMAT_DRM: case WaveFormatTag.WAVE_FORMAT_WMAUDIO2: case WaveFormatTag.WAVE_FORMAT_WMAUDIO3: case WaveFormatTag.WAVE_FORMAT_WMAUDIO_LOSSLESS: case WaveFormatTag.WAVE_FORMAT_WMASPDIF: case WaveFormatTag.WAVE_FORMAT_WMAVOICE9: case WaveFormatTag.WAVE_FORMAT_MPEGLAYER3: case WaveFormatTag.WAVE_FORMAT_MPEG: case WaveFormatTag.WAVE_FORMAT_MPEG_HEAAC: case WaveFormatTag.WAVE_FORMAT_MPEG_ADTS_AAC: { // These format tags map 1-to-1 to Media Foundation formats. // The MSDN topic http://msdn.microsoft.com/en-us/library/aa372553(VS.85).aspx indicates that // to create an audio subtype GUID one can: // 1. Start with the value MFAudioFormat_Base // 2. Replace the first DWORD of this GUID with the format tag return(new Guid((uint)format.FormatTag, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)); } case WaveFormatTag.WAVE_FORMAT_EXTENSIBLE: { WaveFormatEx formatEx = (WaveFormatEx)format; // We only support PCM and IEEE float subtypes for extensible wave formats if (formatEx.SubFormat == Guids.KSDataFormatSubTypePCM) { return(new Guid((uint)WaveFormatTag.WAVE_FORMAT_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)); } else if (formatEx.SubFormat == Guids.KSDataFormatSubTypeIeeeFloat) { return(new Guid((uint)WaveFormatTag.WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)); } break; } } return(Guid.Empty); }
/// <summary> /// Creates a copy of an existing <see cref="WaveFormat"/>. /// </summary> /// <param name="other">The <see cref="WaveFormat"/> to copy</param> /// <returns>The WaveFormat object</returns> public static WaveFormat Create(WaveFormat other) { if (other == null) { return(null); } WaveFormat waveFormat = null; if (other is WaveFormatEx) { waveFormat = new WaveFormatEx(); } else { waveFormat = new WaveFormat(); } waveFormat.CopyFrom(other); return(waveFormat); }
/// <summary> /// Indicates whether the current object is equal to another object. /// </summary> /// <param name="other"> /// An object to compare with this object. /// </param> /// <returns> /// true if the current object is equal to the other parameter; otherwise, false. /// </returns> public override bool Equals(object other) { if (base.Equals(other)) { // extra size is zero for both, so extra bytes are irrelevant if (this.ExtraSize == 0) { return(true); } // Downcast other to WaveFormatEx to compare extra bytes WaveFormatEx format = other as WaveFormatEx; // sanity checks for extra bytes if ((format == null) || (this.ExtraInfo == null) || (format.ExtraInfo == null) || (this.ExtraInfo.Length < this.ExtraSize) || (format.ExtraInfo.Length < format.ExtraSize)) { return(false); } // byte-wise comparison of extra bytes for (int i = 0; i < this.ExtraSize; ++i) { if (this.ExtraInfo[i] != format.ExtraInfo[i]) { return(false); } } // equality return(true); } return(false); }
/// <summary> /// Marshals a <see cref="WaveFormat"/> object to a native WAVEFORMATEX structure. /// </summary> /// <param name="format">The <see cref="WaveFormat"/> object to marshal.</param> /// <param name="ptr">A pointer to an unmanaged block of memory, which must be allocated before this method is called.</param> public static void MarshalToPtr(WaveFormat format, IntPtr ptr) { // If format is of a derived type, demote it to the base WaveFormat to ensure // that the base structure marshal correctly and does not overflow the allocated // memory. The extra info bytes will be marshaled separately. WaveFormat baseFormat = format; if (format.GetType() != typeof(WaveFormat)) { baseFormat = new WaveFormat(); baseFormat.CopyFrom(format); } Marshal.StructureToPtr(baseFormat, ptr, false); if (format.ExtraSize > 0) { WaveFormatEx waveFormatEx = format as WaveFormatEx; if ((waveFormatEx == null) || (waveFormatEx.ExtraInfo == null)) { throw new InvalidOperationException("WaveFormat has non-zero extra bytes but no extra bytes field was present."); } if (waveFormatEx.ExtraInfo.Length < format.ExtraSize) { throw new InvalidOperationException($"WaveFormat extra size field and extra byte count mismatch. " + "Expected {format.ExtraSize} bytes but ExtraInfo only contains {waveFormatEx.ExtraInfo.Length} bytes."); } if (waveFormatEx != null) { // Write out extra info IntPtr extraInfoPtr = new IntPtr(ptr.ToInt64() + Marshal.SizeOf <WaveFormat>()); Marshal.Copy(waveFormatEx.ExtraInfo, 0, extraInfoPtr, format.ExtraSize); } } }
/// <summary> /// Marshals a native WAVEFORMATEX structure to a <see cref="WaveFormat"/> object. /// </summary> /// <param name="ptr">Pointer to a WAVEFORMATEX structure.</param> /// <returns>A <see cref="WaveFormat"/> object representing the WAVEFORMATEX structure.</returns> public static WaveFormat MarshalFromPtr(IntPtr ptr) { WaveFormat waveFormat = null; if (ptr != IntPtr.Zero) { waveFormat = Marshal.PtrToStructure <WaveFormat>(ptr); if (waveFormat.ExtraSize > 0) { WaveFormatEx waveFormatEx = new WaveFormatEx(); waveFormatEx.CopyFrom(waveFormat); IntPtr extraInfoPtr = new IntPtr(ptr.ToInt64() + Marshal.SizeOf <WaveFormat>()); // Read extra info waveFormatEx.ExtraInfo = new byte[waveFormatEx.ExtraSize]; Marshal.Copy(extraInfoPtr, waveFormatEx.ExtraInfo, 0, waveFormatEx.ExtraSize); // Return the WaveFormatEx object waveFormat = waveFormatEx; } } return(waveFormat); }