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); }
private int GetMaxEncodedSize() { var inHeader = inBitmapInfo; var outHeader = outBitmapInfo; return(VfwApi.ICSendMessage(compressorHandle, VfwApi.ICM_COMPRESS_GET_SIZE, ref inHeader, ref outHeader)); }
private int EncodeFrame(IntPtr sourcePtr, IntPtr destinationPtr, uint destinationSize, out bool isKeyFrame) { var outInfo = outBitmapInfo; outInfo.ImageSize = destinationSize; var inInfo = inBitmapInfo; var flags = framesFromLastKey >= keyFrameRate ? VfwApi.ICCOMPRESS_KEYFRAME : 0; var result = VfwApi.ICCompress(compressorHandle, flags, ref outInfo, destinationPtr, ref inInfo, sourcePtr, out _, out var outFlags, frameIndex, 0, quality, IntPtr.Zero, IntPtr.Zero); CheckICResult(result); frameIndex++; isKeyFrame = (outFlags & VfwApi.AVIIF_KEYFRAME) == VfwApi.AVIIF_KEYFRAME; if (isKeyFrame) { framesFromLastKey = 1; } else { framesFromLastKey++; } return((int)outInfo.ImageSize); }
private void StartCompression() { var inHeader = inBitmapInfo; var outHeader = outBitmapInfo; var result = VfwApi.ICSendMessage(compressorHandle, VfwApi.ICM_COMPRESS_BEGIN, ref inHeader, ref outHeader); CheckICResult(result); needEnd = true; framesFromLastKey = keyFrameRate; }
private void CheckICResult(int result) { if (result != VfwApi.ICERR_OK) { var errorDesc = VfwApi.GetErrorDescription(result); var resultStr = errorDesc == null ? result.ToString() : string.Format("{0} ({1})", result, errorDesc); throw new InvalidOperationException(string.Format("Encoder operation returned an error: {0}.", resultStr)); } }
private void InitCompressFramesInfo(double fps, int frameCount) { var info = new VfwApi.CompressFramesInfo { StartFrame = 0, FrameCount = frameCount, Quality = quality, KeyRate = keyFrameRate, }; AviUtils.SplitFrameRate((decimal)fps, out info.FrameRateNumerator, out info.FrameRateDenominator); var result = VfwApi.ICSendMessage(compressorHandle, VfwApi.ICM_COMPRESS_FRAMES_INFO, ref info, Marshal.SizeOf(typeof(VfwApi.CompressFramesInfo))); CheckICResult(result); }
/// <summary>Encodes a frame.</summary> /// <seealso cref="IVideoEncoder.EncodeFrame"/> public int EncodeFrame(byte[] source, int srcOffset, byte[] destination, int destOffset, out bool isKeyFrame) { // TODO: Introduce Width and Height in IVideoRecorder and add Requires to EncodeFrame contract Contract.Assert(srcOffset + 4 * width * height <= source.Length); BitmapUtils.FlipVertical(source, srcOffset, sourceBuffer, 0, height, width * 4); var sourceHandle = GCHandle.Alloc(sourceBuffer, GCHandleType.Pinned); var encodedHandle = GCHandle.Alloc(destination, GCHandleType.Pinned); try { var outInfo = outBitmapInfo; outInfo.ImageSize = (uint)destination.Length; var inInfo = inBitmapInfo; int outFlags; int chunkID; var flags = framesFromLastKey >= keyFrameRate ? VfwApi.ICCOMPRESS_KEYFRAME : 0; var result = VfwApi.ICCompress(compressorHandle, flags, ref outInfo, encodedHandle.AddrOfPinnedObject(), ref inInfo, sourceHandle.AddrOfPinnedObject(), out chunkID, out outFlags, frameIndex, 0, quality, IntPtr.Zero, IntPtr.Zero); CheckICResult(result); frameIndex++; isKeyFrame = (outFlags & VfwApi.AVIIF_KEYFRAME) == VfwApi.AVIIF_KEYFRAME; if (isKeyFrame) { framesFromLastKey = 1; } else { framesFromLastKey++; } return((int)outInfo.ImageSize); } finally { sourceHandle.Free(); encodedHandle.Free(); } }
/// <summary> /// Releases all unmanaged resources used by the encoder. /// </summary> public void Dispose() { if (!isDisposed) { if (needEnd) { EndCompression(); } if (compressorHandle != IntPtr.Zero) { VfwApi.ICClose(compressorHandle); } isDisposed = true; GC.SuppressFinalize(this); } }
/// <summary> /// Gets info about the supported codecs that are installed on the system. /// </summary> public static CodecInfo[] GetAvailableCodecs() { var result = new List <CodecInfo>(); var inBitmapInfo = CreateBitmapInfo(8, 8, 32, KnownFourCCs.Codecs.Uncompressed); inBitmapInfo.ImageSize = (uint)4; foreach (var codec in DefaultCodecPreference) { var outBitmapInfo = CreateBitmapInfo(8, 8, 24, codec); VfwApi.CompressorInfo compressorInfo; var compressorHandle = GetCompressor(inBitmapInfo, outBitmapInfo, out compressorInfo); if (compressorHandle != IntPtr.Zero) { VfwApi.ICClose(compressorHandle); result.Add(new CodecInfo(codec, compressorInfo.Description)); } } return(result.ToArray()); }
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; }
private void EndCompression() { var result = VfwApi.ICSendMessage(compressorHandle, VfwApi.ICM_COMPRESS_END, IntPtr.Zero, IntPtr.Zero); CheckICResult(result); }