/// <summary> /// Add new frame to the AVI file. /// </summary> /// /// <param name="frameImage">New frame image.</param> /// /// <remarks><para>The method adds new video frame to an opened video file. The width and heights /// of the frame should be the same as it was specified in <see cref="Open"/> method /// (see <see cref="Width"/> and <see cref="Height"/> properties).</para></remarks> /// /// <exception cref="System.IO.IOException">Thrown if no video file was open.</exception> /// <exception cref="ArgumentException">Bitmap size must be of the same as video size, which was specified on opening video file.</exception> /// <exception cref="VideoException">A error occurred while writing new video frame. See exception message.</exception> public void AddFrame(Bitmap frameImage) { lock (sync) { // check if AVI file was properly opened if (buffer == IntPtr.Zero) { throw new IOException("AVI file should be successfully opened before writing."); } // check image dimension if ((frameImage.Width != width) || (frameImage.Height != height)) { throw new ArgumentException("Bitmap size must be of the same as video size, which was specified on opening video file."); } // lock bitmap data BitmapData imageData = frameImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); // copy image data int srcStride = imageData.Stride; int dstStride = stride; int src = imageData.Scan0.ToInt32() + srcStride * (height - 1); int dst = buffer.ToInt32(); for (int y = 0; y < height; y++) { NativeMethods.memcpy(dst, src, dstStride); dst += dstStride; src -= srcStride; } // unlock bitmap data frameImage.UnlockBits(imageData); // write to stream if (NativeMethods.AVIStreamWrite(streamCompressed, position, 1, buffer, stride * height, 0, IntPtr.Zero, IntPtr.Zero) != 0) { throw new Exception("Failed adding frame."); } position++; } }