using System.IO; using System.Windows.Media.Imaging; using IvfTl.ControlHost.Debug; using Xunit; namespace IvfTl.ControlHost.Tests { public class MjpegStreamWriterTests { // 造一张 4x4 纯色 24bpp BGR 像素(每像素 3 字节)。 private static byte[] SolidBgr(int w, int h, byte b, byte g, byte r) { var buf = new byte[w * h * 3]; for (int i = 0; i < w * h; i++) { buf[i * 3] = b; buf[i * 3 + 1] = g; buf[i * 3 + 2] = r; } return buf; } [Fact] public void EncodeJpeg_ProducesDecodableJpeg_WithRightSize() { var rgb = SolidBgr(4, 4, 10, 20, 30); byte[] jpeg = MjpegStreamWriter.EncodeJpeg(rgb, 4, 4); Assert.NotNull(jpeg); Assert.True(jpeg.Length > 2); // JPEG 魔数 FF D8 开头 Assert.Equal(0xFF, jpeg[0]); Assert.Equal(0xD8, jpeg[1]); // 能被解码器读回、尺寸对 var dec = new JpegBitmapDecoder(new MemoryStream(jpeg), BitmapCreateOptions.None, BitmapCacheOption.OnLoad); Assert.Equal(4, dec.Frames[0].PixelWidth); Assert.Equal(4, dec.Frames[0].PixelHeight); } [Fact] public void FrameBytes_WrapsJpegInMultipartBoundary() { var jpeg = new byte[] { 0xFF, 0xD8, 1, 2, 0xFF, 0xD9 }; byte[] frame = MjpegStreamWriter.FrameBytes(jpeg); string head = System.Text.Encoding.ASCII.GetString(frame, 0, 60); Assert.Contains("--frame", head); Assert.Contains("Content-Type: image/jpeg", head); Assert.Contains("Content-Length: 6", head); // 帧尾部含 jpeg 原始字节 + 末尾 \r\n Assert.Equal(0xFF, frame[frame.Length - 8]); // jpeg 起点附近(粗校验帧体存在) Assert.Equal((byte)'\r', frame[frame.Length - 2]); Assert.Equal((byte)'\n', frame[frame.Length - 1]); } } }