public void Width_ReturnsBitmapWidth()
        {
            var bitmap = new Bitmap(32, 16);
            var bitmapVideoFrame = new BitmapVideoFrame(bitmap);

            Assert.AreEqual(32, bitmapVideoFrame.Width);
        }
        public void Height_ReturnsBitmapHeight()
        {
            var bitmap = new Bitmap(32, 16);
            var bitmapVideoFrame = new BitmapVideoFrame(bitmap);

            Assert.AreEqual(16, bitmapVideoFrame.Height);
        }
        public void Bitmap_ReturnsBitmapProvidedInConstructor()
        {
            var bitmap = new Bitmap(32, 32);
            var bitmapVideoFrame = new BitmapVideoFrame(bitmap);

            Assert.AreSame(bitmap, bitmapVideoFrame.Bitmap);
        }
        public void CopyPixels_WhenPixelBufferIsNull_Throws()
        {
            var bitmap = new Bitmap(32, 32);
            var bitmapVideoFrame = new BitmapVideoFrame(bitmap);
            var rectangle = new Rectangle(0, 0, 32, 32);
            int[] pixelBuffer = null;
            int startOffset = 0;
            int stride = 32;

            Assert.Throws<ArgumentNullException>(() => bitmapVideoFrame.CopyPixels(rectangle, pixelBuffer, startOffset, stride));
        }
        public void CopyPixels_WhenRectangleAreOutOfBounds_Throws(int x, int y, int width, int height)
        {
            var bitmap = new Bitmap(32, 32);
            var bitmapVideoFrame = new BitmapVideoFrame(bitmap);
            var rectangle = new Rectangle(x, y, width, height);
            int[] pixelBuffer = new int[32 * 32];
            int startOffset = 0;
            int stride = 32;

            var ex = Assert.Throws<ArgumentOutOfRangeException>(() => bitmapVideoFrame.CopyPixels(rectangle, pixelBuffer, startOffset, stride));
            Assert.Contains(ex.Message, "Rectangle position and dimensions must be within the bounds of the frame.");
        }
        public void CreateVideo()
        {
            const int width = 640;
            const int height = 480;
            const int frames = 30;

            Stopwatch stopwatch = Stopwatch.StartNew();
            var parameters = new FlashScreenVideoParameters(width, height, 5)
            {
                BlockWidth = 256,
                BlockHeight = 256
            };
            video = new FlashScreenVideo(parameters);
            stopwatch.Stop();

            Bitmap bitmap = new Bitmap(width, height);
            BitmapVideoFrame bitmapVideoFrame = new BitmapVideoFrame(bitmap);
            for (int frame = 0; frame < frames; frame++)
            {
                BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height),
                    ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
                try
                {
                    int offset = 0;
                    for (int y = 0; y < height; y++)
                    {
                        int scanOffset = offset;

                        for (int x = 0; x < width; x++)
                        {
                            int color = (x * 255 / width) << 16 | (y * 255 / height) << 8 | frame * 255 / frames;
                            Marshal.WriteInt32(bitmapData.Scan0, scanOffset, color);

                            scanOffset += 4;
                        }

                        offset += bitmapData.Stride;
                    }
                }
                finally
                {
                    bitmap.UnlockBits(bitmapData);
                }

                stopwatch.Start();
                video.AddFrame(bitmapVideoFrame);
                stopwatch.Stop();
            }

            TestLog.WriteLine("Video encoding {2} frames at {0}x{1} took {3}s", width, height, frames, stopwatch.Elapsed.TotalSeconds);
        }
        public void CopyPixels_WhenStartOffsetIsOutOfBounds_Throws(int startOffset)
        {
            var bitmap = new Bitmap(32, 32);
            var bitmapVideoFrame = new BitmapVideoFrame(bitmap);
            var rectangle = new Rectangle(0, 0, 32, 32);
            int[] pixelBuffer = new int[32 * 32];
            int stride = 32;

            var ex = Assert.Throws<ArgumentOutOfRangeException>(() => bitmapVideoFrame.CopyPixels(rectangle, pixelBuffer, startOffset, stride));
            Assert.Contains(ex.Message, "Start offset must be within the bounds of the pixel buffer.");
        }
        public void CopyPixels_WhenArgumentsValid_ShouldCopyTheRegion(int x, int y, int width, int height, int startOffset, int stride, int pixelBufferLength)
        {
            // Create a 4x4 bitmap initialized with an array of RGB pixel colors like this:
            //   {000, 100, 200}, {001, 101, 201}, {002, 102, 202}, {003, 103, 203}
            //   {010, 110, 210}, {011, 111, 211}, {012, 112, 212}, {013, 113, 213}
            //   {020, 120, 220}, {021, 121, 221}, {022, 122, 222}, {023, 123, 223}
            //   {030, 130, 230}, {031, 131, 231}, {032, 132, 232}, {033, 133, 233}
            var bitmap = new Bitmap(4, 4);
            for (int bx = 0; bx < bitmap.Width; bx++)
            {
                for (int by = 0; by < bitmap.Height; by++)
                {
                    int component = bx + by * 10;
                    Color color = Color.FromArgb(component, component + 100, component + 200);
                    bitmap.SetPixel(bx, by, color);
                }
            }

            var bitmapVideoFrame = new BitmapVideoFrame(bitmap);
            var rectangle = new Rectangle(x, y, width, height);
            var pixelBuffer = new int[pixelBufferLength];

            bitmapVideoFrame.CopyPixels(rectangle, pixelBuffer, startOffset, stride);

            for (int i = 0; i < pixelBufferLength; i++)
            {
                int bx = (i - startOffset) % stride + x;
                int by = (i - startOffset) / stride + y;

                if (bx < x || by < y || bx - x >= width || by - y >= height)
                {
                    Assert.AreEqual(0, pixelBuffer[i], "i: {0}, bx: {1}, by: {2}", i, bx, by);
                }
                else
                {
                    Assert.AreEqual(bitmap.GetPixel(bx, by).ToArgb(), pixelBuffer[i], "i: {0}, bx: {1}, by: {2}", i, bx, by);
                }
            }
        }
        public void CopyPixels_WhenSpaceRequirementsExceedPixelBuffer_Throws(int width, int height, int startOffset, int stride,
            int exactPixelBufferLengthRequired)
        {
            var bitmap = new Bitmap(32, 32);
            var bitmapVideoFrame = new BitmapVideoFrame(bitmap);
            var rectangle = new Rectangle(0, 0, width, height);

            Assert.Multiple(() =>
            {
                Assert.DoesNotThrow(
                    () => bitmapVideoFrame.CopyPixels(rectangle, new int[exactPixelBufferLengthRequired], startOffset, stride),
                    "Should not throw when pixel buffer is exactly the right size.");

                Assert.DoesNotThrow(
                    () => bitmapVideoFrame.CopyPixels(rectangle, new int[exactPixelBufferLengthRequired + 1], startOffset, stride),
                    "Should not throw when pixel buffer is one pixel too large.");

                if (width != 0 && height != 0)
                {
                    var ex = Assert.Throws<ArgumentException>(
                        () => bitmapVideoFrame.CopyPixels(rectangle, new int[exactPixelBufferLengthRequired - 1], startOffset, stride),
                        "Should throw when pixel buffer is one pixel too small.");
                    Assert.Contains(ex.Message, "The combined rectangle dimensions, start offset and stride would cause pixels to be written out of bounds of the pixel buffer.");
                }
            });
        }
        public void CopyPixels_WhenStrideIsLessThanWidth_Throws(int stride)
        {
            var bitmap = new Bitmap(32, 32);
            var bitmapVideoFrame = new BitmapVideoFrame(bitmap);
            var rectangle = new Rectangle(0, 0, 32, 32);
            int[] pixelBuffer = new int[32 * 32];
            int startOffset = 0;

            var ex = Assert.Throws<ArgumentOutOfRangeException>(() => bitmapVideoFrame.CopyPixels(rectangle, pixelBuffer, startOffset, stride));
            Assert.Contains(ex.Message, "Stride must be at least as large as the width of the rectangle.");
        }