diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/thread/MediaTransferFlvByJavacv.java b/ruoyi-video/src/main/java/com/ruoyi/video/thread/MediaTransferFlvByJavacv.java index 1215280..50c72a8 100644 --- a/ruoyi-video/src/main/java/com/ruoyi/video/thread/MediaTransferFlvByJavacv.java +++ b/ruoyi-video/src/main/java/com/ruoyi/video/thread/MediaTransferFlvByJavacv.java @@ -41,7 +41,11 @@ import java.util.Collections; import java.util.UUID; import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; import java.awt.image.BufferedImage; +import java.awt.Image; import static org.bytedeco.opencv.global.opencv_core.CV_8UC3; @@ -342,19 +346,49 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable return; } + // 优化:跳帧处理,只推送 1/3 的帧(25fps -> 8.3fps,如果还慢可改为 %3) + // 如果帧率太低,可以改为 % 2(推送 50% 帧);如果还是慢,保持 % 3(推送 33% 帧) + if (totalFrames % 3 != 0) { + droppedFrames++; + return; + } + if (totalFrames == 1) { log.info("📤 开始推流到客户端,客户端数量: {}", contexts.size()); } try { - // 转换为JPEG字节 + // 转换为JPEG字节(优化:降低质量和分辨率以提高帧率) BufferedImage bufferedImage = toImage.convert(frame); if (bufferedImage == null) { return; } + // 优化1:降低分辨率(缩小到60%,更快) + int targetWidth = (int) (bufferedImage.getWidth() * 0.6); + int targetHeight = (int) (bufferedImage.getHeight() * 0.6); + BufferedImage scaledImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB); + + // 使用快速缩放(Graphics2D) + java.awt.Graphics2D g2d = scaledImage.createGraphics(); + g2d.setRenderingHint(java.awt.RenderingHints.KEY_INTERPOLATION, + java.awt.RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); // 最快 + g2d.drawImage(bufferedImage, 0, 0, targetWidth, targetHeight, null); + g2d.dispose(); + + // 优化2:使用低质量 JPEG 编码(质量 0.5,速度快很多) ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - ImageIO.write(bufferedImage, "jpg", outputStream); + ImageWriter jpegWriter = ImageIO.getImageWritersByFormatName("jpeg").next(); + ImageWriteParam jpegParams = jpegWriter.getDefaultWriteParam(); + jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + jpegParams.setCompressionQuality(0.5f); // 质量 50%(默认 75-90%) + + ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream); + jpegWriter.setOutput(imageOutputStream); + jpegWriter.write(null, new javax.imageio.IIOImage(scaledImage, null, null), jpegParams); + jpegWriter.dispose(); + imageOutputStream.close(); + byte[] imageBytes = outputStream.toByteArray(); // 每1000帧输出一次统计