C#中基于byte[]生成MJPEG流的HTTP服务器实现咨询
MJPEG流实现方案推荐
核心实现逻辑
MJPEG的本质是HTTP长连接+多部分消息(multipart/x-mixed-replace),核心逻辑很直接:
- 客户端发起HTTP请求后,服务器不立即关闭连接,持续返回带固定分界符的JPEG数据块
- 每个JPEG块前必须附带
Content-Type: image/jpeg和Content-Length: [字节数]字段,用分界符区分不同帧
推荐的HTTP服务器库及核心实现
1. Python:Flask + 生成器
Flask的路由支持返回生成器,天然适配流式响应,核心代码示例:
from flask import Flask, Response app = Flask(__name__) # 替换为你的摄像头帧接收逻辑 def get_camera_frames(): while True: frame_bytes = get_new_frame_from_camera() # 你的byte[]帧获取函数 # 按MJPEG格式封装帧数据 yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n') @app.route('/video_feed') def video_feed(): return Response(get_camera_frames(), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
2. Java:Spring Boot + StreamingResponseBody
Spring Boot的StreamingResponseBody专门用于流式输出,适合Java项目:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; @RestController public class MJpegController { @GetMapping("/video_feed") public StreamingResponseBody streamVideo(HttpServletResponse response) { response.setContentType("multipart/x-mixed-replace; boundary=frame"); return outputStream -> { while (!Thread.currentThread().isInterrupted()) { byte[] frameBytes = getNewFrameFromCamera(); // 你的帧获取逻辑 writeFrame(outputStream, frameBytes); outputStream.flush(); Thread.sleep(33); // 控制帧率,30帧/秒示例 } }; } private void writeFrame(OutputStream os, byte[] frameBytes) throws IOException { os.write("--frame\r\n".getBytes()); os.write(("Content-Length: " + frameBytes.length + "\r\n").getBytes()); os.write("Content-Type: image/jpeg\r\n\r\n".getBytes()); os.write(frameBytes); os.write("\r\n".getBytes()); } }
3. C#:ASP.NET Core + IAsyncEnumerable
ASP.NET Core通过IAsyncEnumerable实现流式响应,代码简洁:
using Microsoft.AspNetCore.Mvc; using System.Text; using System.Threading.Tasks; [ApiController] [Route("[controller]")] public class VideoController : ControllerBase { [HttpGet("feed")] public async IAsyncEnumerable<byte[]> GetVideoFeed() { Response.ContentType = "multipart/x-mixed-replace; boundary=frame"; while (true) { byte[] frameBytes = GetNewFrameFromCamera(); // 你的帧获取逻辑 // 封装分界符和帧头 var boundaryBytes = Encoding.UTF8.GetBytes("--frame\r\nContent-Type: image/jpeg\r\nContent-Length: " + frameBytes.Length + "\r\n\r\n"); yield return boundaryBytes; yield return frameBytes; yield return Encoding.UTF8.GetBytes("\r\n"); await Task.Delay(33); // 控制帧率 } } }
关键注意事项
- 必须基于HTTP 1.1协议,依赖默认的
Connection: keep-alive维持长连接 - 分界符要全局固定,客户端依靠它识别新帧的开始
- 不要省略
Content-Length字段,部分浏览器/客户端需要它才能正确解析帧 - 按需控制帧率,避免服务器和客户端因数据量过大过载
内容的提问来源于stack exchange,提问作者Steve Bates
相关产品推荐
相关产品推荐

