MjpegFrameParserTests.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. using System.Collections.Generic;
  2. using System.Text;
  3. using ivf_tl_Operate.Debug;
  4. using Xunit;
  5. namespace IvfTl.ControlHost.Tests
  6. {
  7. public class MjpegFrameParserTests
  8. {
  9. // 造一个 multipart 帧字节(与 control MjpegStreamWriter.FrameBytes 同格式)。
  10. private static byte[] MakeFrame(byte[] jpeg)
  11. {
  12. string head = $"--frame\r\nContent-Type: image/jpeg\r\nContent-Length: {jpeg.Length}\r\n\r\n";
  13. var ms = new List<byte>();
  14. ms.AddRange(Encoding.ASCII.GetBytes(head));
  15. ms.AddRange(jpeg);
  16. ms.AddRange(Encoding.ASCII.GetBytes("\r\n"));
  17. return ms.ToArray();
  18. }
  19. private static List<byte[]> FeedAll(MjpegFrameParser p, byte[] data)
  20. {
  21. var all = new List<byte[]>();
  22. all.AddRange(p.Feed(data, data.Length));
  23. return all;
  24. }
  25. [Fact]
  26. public void SingleWholeFrame_YieldsOneJpeg()
  27. {
  28. var jpeg = new byte[] { 0xFF, 0xD8, 1, 2, 3, 0xFF, 0xD9 };
  29. var p = new MjpegFrameParser();
  30. var frames = FeedAll(p, MakeFrame(jpeg));
  31. Assert.Single(frames);
  32. Assert.Equal(jpeg, frames[0]);
  33. }
  34. [Fact]
  35. public void TwoFramesInOneChunk_YieldsTwo()
  36. {
  37. var j1 = new byte[] { 0xFF, 0xD8, 1, 0xFF, 0xD9 };
  38. var j2 = new byte[] { 0xFF, 0xD8, 9, 8, 0xFF, 0xD9 };
  39. var combined = new List<byte>();
  40. combined.AddRange(MakeFrame(j1));
  41. combined.AddRange(MakeFrame(j2));
  42. var p = new MjpegFrameParser();
  43. var frames = FeedAll(p, combined.ToArray());
  44. Assert.Equal(2, frames.Count);
  45. Assert.Equal(j1, frames[0]);
  46. Assert.Equal(j2, frames[1]);
  47. }
  48. [Fact]
  49. public void FrameSplitAcrossChunks_Reassembles()
  50. {
  51. var jpeg = new byte[] { 0xFF, 0xD8, 5, 6, 7, 8, 0xFF, 0xD9 };
  52. byte[] full = MakeFrame(jpeg);
  53. var p = new MjpegFrameParser();
  54. // 在帧中间切两半喂
  55. int mid = full.Length / 2;
  56. var first = new byte[mid];
  57. var second = new byte[full.Length - mid];
  58. System.Array.Copy(full, 0, first, 0, mid);
  59. System.Array.Copy(full, mid, second, 0, second.Length);
  60. var frames = new List<byte[]>();
  61. frames.AddRange(p.Feed(first, first.Length));
  62. Assert.Empty(frames); // 半帧,还吐不出
  63. frames.AddRange(p.Feed(second, second.Length));
  64. Assert.Single(frames);
  65. Assert.Equal(jpeg, frames[0]);
  66. }
  67. [Fact]
  68. public void BadHeaderWithoutContentLength_SkippedThenRecovers()
  69. {
  70. var jpeg = new byte[] { 0xFF, 0xD8, 7, 0xFF, 0xD9 };
  71. var bad = Encoding.ASCII.GetBytes("--frame\r\nContent-Type: image/jpeg\r\n\r\n"); // 无 Content-Length
  72. var data = new List<byte>();
  73. data.AddRange(bad);
  74. data.AddRange(MakeFrame(jpeg));
  75. var p = new MjpegFrameParser();
  76. var frames = new List<byte[]>(p.Feed(data.ToArray(), data.Count));
  77. Assert.Single(frames);
  78. Assert.Equal(jpeg, frames[0]);
  79. }
  80. [Fact]
  81. public void EmptyInput_ReturnsEmpty_NoThrow()
  82. {
  83. var p = new MjpegFrameParser();
  84. var frames = new List<byte[]>(p.Feed(new byte[0], 0));
  85. Assert.Empty(frames);
  86. }
  87. }
  88. }