/// <summary> /// Create new AVI file and open it for writing. /// </summary> /// /// <param name="fileName">AVI file name to create.</param> /// <param name="width">Video width.</param> /// <param name="height">Video height.</param> /// /// <remarks><para>The method opens (creates) a video files, configure video codec and prepares /// the stream for saving video frames with a help of <see cref="AddFrame"/> method.</para></remarks> /// /// <exception cref="System.IO.IOException">Failed opening the specified file.</exception> /// <exception cref="VideoException">A error occurred while creating new video file. See exception message.</exception> /// <exception cref="OutOfMemoryException">Insufficient memory for internal buffer.</exception> /// <exception cref="ArgumentException">Video file resolution must be a multiple of two.</exception> public void Open(string fileName, int width, int height, bool showOptions = false) { // close previous file Close(); // check width and height if (((width & 1) != 0) || ((height & 1) != 0)) { throw new ArgumentException("Video file resolution must be a multiple of two."); } bool success = false; try { lock (sync) { // calculate stride stride = width * 3; if ((stride % 4) != 0) { stride += (4 - stride % 4); } // create new file if (NativeMethods.AVIFileOpen(out file, fileName, OpenFileMode.Create | OpenFileMode.Write, IntPtr.Zero) != 0) { throw new IOException("Failed opening the specified file."); } this.width = width; this.height = height; // describe new stream AVISTREAMINFO info = new AVISTREAMINFO(); info.type = NativeMethods.mmioFOURCC("vids"); info.handler = NativeMethods.mmioFOURCC(codec); info.scale = 1; info.rate = rate; info.suggestedBufferSize = stride * height; // create stream if (NativeMethods.AVIFileCreateStream(file, out stream, ref info) != 0) { throw new Exception("Failed creating stream."); } // describe compression options AVICOMPRESSOPTIONS options = new AVICOMPRESSOPTIONS(); options.handler = NativeMethods.mmioFOURCC(codec); options.quality = quality; if (showOptions) { NativeMethods.AVISaveOptions(stream, ref options); } // create compressed stream if (NativeMethods.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero) != 0) { throw new Exception("Failed creating compressed stream."); } // describe frame format BITMAPINFOHEADER bitmapInfoHeader = new BITMAPINFOHEADER(); bitmapInfoHeader.size = Marshal.SizeOf(bitmapInfoHeader.GetType()); bitmapInfoHeader.width = width; bitmapInfoHeader.height = height; bitmapInfoHeader.planes = 1; bitmapInfoHeader.bitCount = 24; bitmapInfoHeader.sizeImage = 0; bitmapInfoHeader.compression = 0; // BI_RGB // set frame format if (NativeMethods.AVIStreamSetFormat(streamCompressed, 0, ref bitmapInfoHeader, Marshal.SizeOf(bitmapInfoHeader.GetType())) != 0) { throw new Exception("Failed setting format of the compressed stream."); } // alloc unmanaged memory for frame buffer = Marshal.AllocHGlobal(stride * height); if (buffer == IntPtr.Zero) { throw new OutOfMemoryException("Insufficient memory for internal buffer."); } position = 0; success = true; } } finally { if (!success) { Close(); } } }