private static IntPtr GetCompressor(VfwApi.BitmapInfoHeader inBitmapInfo, VfwApi.BitmapInfoHeader outBitmapInfo, out VfwApi.CompressorInfo compressorInfo) { // Using ICLocate is time-consuming. Besides, it does not clean up something, so the process does not terminate on exit. // Instead open a specific codec and query it for needed features. var compressorHandle = VfwApi.ICOpen((uint)KnownFourCCs.CodecTypes.Video, outBitmapInfo.Compression, VfwApi.ICMODE_COMPRESS); if (compressorHandle != IntPtr.Zero) { var inHeader = inBitmapInfo; var outHeader = outBitmapInfo; var result = VfwApi.ICSendMessage(compressorHandle, VfwApi.ICM_COMPRESS_QUERY, ref inHeader, ref outHeader); if (result == VfwApi.ICERR_OK) { var infoSize = VfwApi.ICGetInfo(compressorHandle, out compressorInfo, Marshal.SizeOf(typeof(VfwApi.CompressorInfo))); if (infoSize > 0 && compressorInfo.SupportsFastTemporalCompression) { return(compressorHandle); } } VfwApi.ICClose(compressorHandle); } compressorInfo = new VfwApi.CompressorInfo(); return(IntPtr.Zero); }
/// <summary> /// Creates a new instance of <see cref="Mpeg4VcmVideoEncoder"/>. /// </summary> /// <param name="width">Frame width.</param> /// <param name="height">Frame height.</param> /// <param name="fps">Frame rate.</param> /// <param name="frameCount"> /// Number of frames to be encoded. /// If not known, specify 0. /// </param> /// <param name="quality"> /// Compression quality in the range [1..100]. /// Less values mean less size and lower image quality. /// </param> /// <param name="codecPreference"> /// List of codecs that can be used by this encoder, in preferred order. /// </param> /// <exception cref="InvalidOperationException"> /// No compatible codec was found in the system. /// </exception> /// <exception cref="PlatformNotSupportedException"> /// Running not on Windows. /// </exception> /// <remarks> /// <para> /// It is not guaranteed that the codec will respect the specified <paramref name="quality"/> value. /// This depends on its implementation. /// </para> /// <para> /// If no preferred codecs are specified, then <see cref="DefaultCodecPreference"/> is used. /// MPEG-4 codecs that are not explicitly supported can be specified. However, in this case /// the encoder is not guaranteed to work properly. /// </para> /// </remarks> public Mpeg4VcmVideoEncoder(int width, int height, double fps, int frameCount, int quality, params FourCC[] codecPreference) { Argument.IsPositive(width, nameof(width)); Argument.IsPositive(height, nameof(height)); Argument.IsPositive(fps, nameof(fps)); Argument.IsNotNegative(frameCount, nameof(frameCount)); Argument.IsInRange(quality, 1, 100, nameof(quality)); CheckSupportedPlatform(); this.width = width; this.height = height; sourceBuffer = new byte[width * height * 4]; inBitmapInfo = CreateBitmapInfo(width, height, 32, CodecIds.Uncompressed); inBitmapInfo.ImageSize = (uint)sourceBuffer.Length; if (codecPreference == null || codecPreference.Length == 0) { codecPreference = DefaultCodecPreference.ToArray(); } foreach (var codec in codecPreference) { outBitmapInfo = CreateBitmapInfo(width, height, 24, codec); compressorHandle = GetCompressor(inBitmapInfo, outBitmapInfo, out compressorInfo); if (compressorHandle != IntPtr.Zero) { break; } } if (compressorHandle == IntPtr.Zero) { throw new InvalidOperationException("No compatible MPEG-4 encoder found."); } try { maxEncodedSize = GetMaxEncodedSize(); // quality for ICM ranges from 0 to 10000 this.quality = compressorInfo.SupportsQuality ? quality * 100 : 0; // typical key frame rate ranges from FPS to 2*FPS keyFrameRate = (int)Math.Round((2 - 0.01 * quality) * fps); if (compressorInfo.RequestsCompressFrames) { InitCompressFramesInfo(fps, frameCount); } StartCompression(); } catch { Dispose(); throw; } }
/// <summary> /// Creates a new instance of <see cref="Mpeg4VideoEncoderVcm"/>. /// </summary> /// <param name="width">Frame width.</param> /// <param name="height">Frame height.</param> /// <param name="fps">Frame rate.</param> /// <param name="frameCount"> /// Number of frames to be encoded. /// If not known, specify 0. /// </param> /// <param name="quality"> /// Compression quality in the range [1..100]. /// Less values mean less size and lower image quality. /// </param> /// <param name="codecPreference"> /// List of codecs that can be used by this encoder, in preferred order. /// </param> /// <exception cref="InvalidOperationException"> /// No compatible codec was found in the system. /// </exception> /// <remarks> /// <para> /// It is not guaranteed that the codec will respect the specified <paramref name="quality"/> value. /// This depends on its implementation. /// </para> /// <para> /// If no preferred codecs are specified, then <see cref="DefaultCodecPreference"/> is used. /// MPEG-4 codecs that are not explicitly supported can be specified. However, in this case /// the encoder is not guaranteed to work properly. /// </para> /// </remarks> public Mpeg4VideoEncoderVcm(int width, int height, double fps, int frameCount, int quality, params FourCC[] codecPreference) { Contract.Requires(width > 0); Contract.Requires(height > 0); Contract.Requires(fps > 0); Contract.Requires(frameCount >= 0); Contract.Requires(1 <= quality && quality <= 100); this.width = width; this.height = height; sourceBuffer = new byte[width * height * 4]; inBitmapInfo = CreateBitmapInfo(width, height, 32, KnownFourCCs.Codecs.Uncompressed); inBitmapInfo.ImageSize = (uint)sourceBuffer.Length; if (codecPreference == null || codecPreference.Length == 0) { codecPreference = DefaultCodecPreference.ToArray(); } foreach (var codec in codecPreference) { outBitmapInfo = CreateBitmapInfo(width, height, 24, codec); compressorHandle = GetCompressor(inBitmapInfo, outBitmapInfo, out compressorInfo); if (compressorHandle != IntPtr.Zero) { break; } } if (compressorHandle == IntPtr.Zero) { throw new InvalidOperationException("No compatible MPEG-4 encoder found."); } try { maxEncodedSize = GetMaxEncodedSize(); // quality for ICM ranges from 0 to 10000 this.quality = compressorInfo.SupportsQuality ? quality * 100 : 0; // typical key frame rate ranges from FPS to 2*FPS keyFrameRate = (int)Math.Round((2 - 0.01 * quality) * fps); if (compressorInfo.RequestsCompressFrames) { InitCompressFramesInfo(fps, frameCount); } StartCompression(); } catch { Dispose(); throw; } }
/// <summary> /// Creates a new instance of <see cref="Mpeg4VideoEncoderVcm"/>. /// </summary> /// <param name="width">Frame width.</param> /// <param name="height">Frame height.</param> /// <param name="fps">Frame rate.</param> /// <param name="frameCount"> /// Number of frames to be encoded. /// If not known, specify 0. /// </param> /// <param name="quality"> /// Compression quality in the range [1..100]. /// Less values mean less size and lower image quality. /// </param> /// <param name="codecPreference"> /// List of codecs that can be used by this encoder, in preferred order. /// </param> /// <exception cref="InvalidOperationException"> /// No compatible codec was found in the system. /// </exception> /// <remarks> /// <para> /// It is not guaranteed that the codec will respect the specified <paramref name="quality"/> value. /// This depends on its implementation. /// </para> /// <para> /// If no preferred codecs are specified, then <see cref="DefaultCodecPreference"/> is used. /// MPEG-4 codecs that are not explicitly supported can be specified. However, in this case /// the encoder is not guaranteed to work properly. /// </para> /// </remarks> public Mpeg4VideoEncoderVcm(int width, int height, double fps, int frameCount, int quality, params FourCC[] codecPreference) { Contract.Requires(width > 0); Contract.Requires(height > 0); Contract.Requires(fps > 0); Contract.Requires(frameCount >= 0); Contract.Requires(1 <= quality && quality <= 100); this.width = width; this.height = height; sourceBuffer = new byte[width * height * 4]; inBitmapInfo = CreateBitmapInfo(width, height, 32, KnownFourCCs.Codecs.Uncompressed); inBitmapInfo.ImageSize = (uint)sourceBuffer.Length; if (codecPreference == null || codecPreference.Length == 0) { codecPreference = DefaultCodecPreference.ToArray(); } foreach (var codec in codecPreference) { outBitmapInfo = CreateBitmapInfo(width, height, 24, codec); compressorHandle = GetCompressor(inBitmapInfo, outBitmapInfo, out compressorInfo); if (compressorHandle != IntPtr.Zero) break; } if (compressorHandle == IntPtr.Zero) { throw new InvalidOperationException("No compatible MPEG-4 encoder found."); } try { maxEncodedSize = GetMaxEncodedSize(); // quality for ICM ranges from 0 to 10000 this.quality = compressorInfo.SupportsQuality ? quality * 100 : 0; // typical key frame rate ranges from FPS to 2*FPS keyFrameRate = (int)Math.Round((2 - 0.01 * quality) * fps); if (compressorInfo.RequestsCompressFrames) { InitCompressFramesInfo(fps, frameCount); } StartCompression(); } catch { Dispose(); throw; } }