海康工业相机对接优化视频流

This commit is contained in:
zc
2026-03-11 11:09:56 +08:00
parent fde2f18ff5
commit 4802e11f7c

View File

@@ -6,6 +6,9 @@ import org.springframework.stereotype.Service;
import org.springframework.web.socket.BinaryMessage; import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -24,6 +27,10 @@ public class CameraService {
private final Map<String, WebSocketSession> webSocketSessions = new ConcurrentHashMap<>(); private final Map<String, WebSocketSession> webSocketSessions = new ConcurrentHashMap<>();
// 相机是否正在运行 // 相机是否正在运行
private boolean isRunning = false; private boolean isRunning = false;
// 帧率控制相关
private long lastFrameTime = 0;
private final int targetFps = 15; // 目标帧率
private final long frameInterval = 1000 / targetFps; // 帧间隔(毫秒)
/** /**
* 初始化相机 * 初始化相机
@@ -228,13 +235,33 @@ public class CameraService {
} }
try { try {
// 帧率控制
long currentTime = System.currentTimeMillis();
if (currentTime - lastFrameTime < frameInterval) {
return; // 跳过当前帧,控制帧率
}
lastFrameTime = currentTime;
// 打印帧信息,以便调试 // 打印帧信息,以便调试
printFrameInfo(frameInfo); printFrameInfo(frameInfo);
// 对于黑白相机MV-CE050-30GM数据是单通道灰度格式 // 对于黑白相机MV-CE050-30GM数据是单通道灰度格式
// 创建包含图像尺寸信息和原始数据的消息 // 将原始灰度数据转换为BufferedImage
BufferedImage image = new BufferedImage(frameInfo.width, frameInfo.height, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, frameInfo.width, frameInfo.height, bytes);
// 压缩图像为JPEG格式
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "jpeg", baos);
byte[] compressedData = baos.toByteArray();
baos.close();
log.debug("Original size: {} bytes, Compressed size: {} bytes, Compression ratio: {:.2f}%",
bytes.length, compressedData.length, (1 - (double)compressedData.length / bytes.length) * 100);
// 创建包含图像尺寸信息和压缩数据的消息
// 消息格式: [width(4 bytes)][height(4 bytes)][image data] // 消息格式: [width(4 bytes)][height(4 bytes)][image data]
byte[] message = new byte[8 + bytes.length]; byte[] message = new byte[8 + compressedData.length];
// 写入宽度和高度(使用小端序) // 写入宽度和高度(使用小端序)
message[0] = (byte) (frameInfo.width & 0xFF); message[0] = (byte) (frameInfo.width & 0xFF);
@@ -247,8 +274,8 @@ public class CameraService {
message[6] = (byte) ((frameInfo.height >> 16) & 0xFF); message[6] = (byte) ((frameInfo.height >> 16) & 0xFF);
message[7] = (byte) ((frameInfo.height >> 24) & 0xFF); message[7] = (byte) ((frameInfo.height >> 24) & 0xFF);
// 写入原始图像数据 // 写入压缩后的图像数据
System.arraycopy(bytes, 0, message, 8, bytes.length); System.arraycopy(compressedData, 0, message, 8, compressedData.length);
// 发送图像数据到所有连接的WebSocket客户端 // 发送图像数据到所有连接的WebSocket客户端
for (WebSocketSession session : webSocketSessions.values()) { for (WebSocketSession session : webSocketSessions.values()) {