Java 读取RTSP、RTMP等网络流、图像、视频指南,易于理解,方便使用

环境准备

Maven 依赖

xml 复制代码
<!-- JavaCV - 包含 OpenCV 和 FFmpeg -->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.5.10</version>
</dependency>

为什么选择 JavaCV?

  • ✅ 跨平台:自动包含 Windows/Linux/macOS 的 FFmpeg 和 OpenCV 二进制文件
  • ✅ 无需手动配置:无需单独安装 FFmpeg 或 OpenCV
  • ✅ 功能完整:支持所有主流视频格式和协议(RTSP、RTMP、HTTP)

核心依赖库介绍

JavaCV vs OpenCV 选择策略

场景 推荐库 原因
网络流 (RTSP/RTMP/HTTP) JavaCV FFmpegFrameGrabber FFmpeg 对网络流支持更好,参数可配置性强
视频文件 JavaCV FFmpegFrameGrabber 支持更多编解码器和格式
摄像头 ByteDeco OpenCV VideoCapture 更稳定,延迟更低
单张图片 ByteDeco OpenCV imread 简单直接

ByteDeco OpenCV

  • 包名 : org.bytedeco.opencv
  • 核心类 : VideoCapture, Mat, imread, imwrite
  • 适用场景: 摄像头、单张图片

JavaCV FFmpeg

  • 包名 : org.bytedeco.javacv
  • 核心类 : FFmpegFrameGrabber, Frame, OpenCVFrameConverter
  • 适用场景: 网络流、视频文件

读取单张图片

基本示例

java 复制代码
import org.bytedeco.opencv.opencv_core.Mat;
import static org.bytedeco.opencv.global.opencv_imgcodecs.*;

public class ReadImageExample {
    public static void main(String[] args) {
        // 读取图片
        Mat image = imread("input.jpg");

        // 检查是否成功读取
        if (image.empty()) {
            System.err.println("无法读取图片!");
            return;
        }

        // 打印图片信息
        System.out.println("图片尺寸: " + image.cols() + " x " + image.rows());
        System.out.println("通道数: " + image.channels());

        // ==================== 在这里处理图片 ====================
        // 可以进行:
        // - 目标检测(YOLOv8/v11)
        // - 图像分割
        // - 特征提取
        // - 图像增强
        // - 滤波处理
        // etc.

        // 保存处理后的图片
        imwrite("output.jpg", image);
        System.out.println("图片已保存到 output.jpg");

        // 释放资源
        image.release();
    }
}

批量读取图片

java 复制代码
import org.bytedeco.opencv.opencv_core.Mat;
import static org.bytedeco.opencv.global.opencv_imgcodecs.*;
import java.io.File;

public class BatchReadImageExample {
    public static void main(String[] args) {
        // 图片目录
        String imageFolder = "images/";

        // 获取所有图片文件
        File folder = new File(imageFolder);
        File[] files = folder.listFiles((dir, name) ->
            name.toLowerCase().matches(".*\\.(jpg|jpeg|png|bmp)$")
        );

        if (files == null || files.length == 0) {
            System.err.println("目录为空或不存在");
            return;
        }

        System.out.println("找到 " + files.length + " 张图片");

        // 循环处理每张图片
        int processedCount = 0;
        for (File file : files) {
            Mat image = imread(file.getAbsolutePath());

            if (image.empty()) {
                System.err.println("无法读取: " + file.getName());
                continue;
            }

            System.out.println("处理: " + file.getName() +
                             " (" + image.cols() + "x" + image.rows() + ")");

            // ==================== 在这里处理每张图片 ====================

            // 保存处理结果(可选)
            String outputPath = "output/" + file.getName();
            imwrite(outputPath, image);

            // 释放资源
            image.release();
            processedCount++;
        }

        System.out.println("批量处理完成,共处理 " + processedCount + " 张图片");
    }
}

读取视频文件

方式一:使用 OpenCV VideoCapture

java 复制代码
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_videoio.VideoCapture;
import static org.bytedeco.opencv.global.opencv_videoio.*;

public class ReadVideoFileExample {
    public static void main(String[] args) {
        String videoPath = "video.mp4";

        // 创建 VideoCapture 对象
        VideoCapture capture = new VideoCapture();

        // 打开视频文件
        if (!capture.open(videoPath)) {
            System.err.println("无法打开视频文件: " + videoPath);
            return;
        }

        // 获取视频信息
        int frameWidth = (int) capture.get(CAP_PROP_FRAME_WIDTH);
        int frameHeight = (int) capture.get(CAP_PROP_FRAME_HEIGHT);
        double fps = capture.get(CAP_PROP_FPS);
        long totalFrames = (long) capture.get(CAP_PROP_FRAME_COUNT);

        System.out.println("========== 视频信息 ==========");
        System.out.println("分辨率: " + frameWidth + " x " + frameHeight);
        System.out.println("帧率: " + fps + " FPS");
        System.out.println("总帧数: " + totalFrames);
        System.out.println("时长: " + (totalFrames / fps) + " 秒");
        System.out.println("==============================\n");

        // 创建 Mat 对象存储帧
        Mat frame = new Mat();
        int frameCount = 0;

        // 循环读取每一帧
        while (capture.read(frame) && !frame.empty()) {
            frameCount++;

            // 打印进度
            if (frameCount % 100 == 0) {
                double progress = (frameCount * 100.0) / totalFrames;
                System.out.printf("处理进度: %.1f%% (第 %d 帧)\n", progress, frameCount);
            }

            // ==================== 在这里处理每一帧 ====================

            // 示例:每 30 帧保存一张图片
            if (frameCount % 30 == 0) {
                String outputPath = "frames/frame_" + frameCount + ".jpg";
                imwrite(outputPath, frame);
            }
        }

        System.out.println("\n视频处理完成,共处理 " + frameCount + " 帧");

        // 释放资源
        frame.release();
        capture.release();
    }
}

方式二:使用 JavaCV FFmpegFrameGrabber(推荐)

优势:支持更多格式、更稳定、参数可配置

java 复制代码
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.opencv_core.Mat;
import static org.bytedeco.opencv.global.opencv_imgcodecs.*;

public class ReadVideoFileJavaCVExample {
    public static void main(String[] args) {
        String videoPath = "video.mp4";

        // 初始化 FFmpegFrameGrabber
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoPath);

        try {
            // 配置参数
            grabber.setPixelFormat(org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_BGR24);

            // 启动
            System.out.println("正在打开视频文件: " + videoPath);
            grabber.start();
            System.out.println("打开成功!\n");

            // 获取视频信息
            int width = grabber.getImageWidth();
            int height = grabber.getImageHeight();
            double fps = grabber.getFrameRate();
            long totalFrames = grabber.getLengthInFrames();

            System.out.println("========== 视频信息 ==========");
            System.out.println("分辨率: " + width + " x " + height);
            System.out.println("帧率: " + fps + " FPS");
            System.out.println("总帧数: " + totalFrames);
            System.out.println("时长: " + (totalFrames / fps) + " 秒");
            System.out.println("==============================\n");

            // 创建 Frame 转 Mat 的转换器
            OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();

            // 循环读取每一帧
            Frame frame;
            int frameCount = 0;

            while ((frame = grabber.grabImage()) != null) {
                frameCount++;

                // 转换为 OpenCV Mat
                Mat mat = converter.convert(frame);

                if (mat != null && !mat.empty()) {
                    // 打印进度
                    if (frameCount % 100 == 0) {
                        double progress = (frameCount * 100.0) / totalFrames;
                        System.out.printf("处理进度: %.1f%% (第 %d 帧)\n", progress, frameCount);
                    }

                    // ==================== 在这里处理每一帧 ====================

                    // 示例:保存关键帧
                    if (frameCount % 50 == 0) {
                        String outputPath = "keyframes/frame_" + frameCount + ".jpg";
                        imwrite(outputPath, mat);
                    }

                    // 释放 Mat
                    mat.release();
                }
            }

            System.out.println("\n视频处理完成,共处理 " + frameCount + " 帧");

            // 释放资源
            grabber.stop();
            grabber.release();

        } catch (Exception e) {
            System.err.println("处理视频时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

读取摄像头

基本示例

java 复制代码
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_videoio.VideoCapture;
import static org.bytedeco.opencv.global.opencv_videoio.*;

public class ReadCameraExample {
    public static void main(String[] args) {
        int cameraId = 0; // 0 表示默认摄像头,1 表示第二个摄像头

        // 创建 VideoCapture 对象
        VideoCapture capture = new VideoCapture();

        // 打开摄像头
        if (!capture.open(cameraId)) {
            System.err.println("无法打开摄像头: " + cameraId);
            return;
        }

        // 获取摄像头信息
        int width = (int) capture.get(CAP_PROP_FRAME_WIDTH);
        int height = (int) capture.get(CAP_PROP_FRAME_HEIGHT);
        double fps = capture.get(CAP_PROP_FPS);

        System.out.println("========== 摄像头信息 ==========");
        System.out.println("分辨率: " + width + " x " + height);
        System.out.println("帧率: " + fps + " FPS");
        System.out.println("================================\n");
        System.out.println("开始从摄像头读取帧,按 Ctrl+C 停止...\n");

        // 创建 Mat 对象存储帧
        Mat frame = new Mat();
        int frameCount = 0;
        long startTime = System.currentTimeMillis();

        // 循环读取帧
        while (capture.read(frame) && !frame.empty()) {
            frameCount++;
            // ==================== 在这里处理每一帧 ====================
        }

        // 释放资源
        frame.release();
        capture.release();
    }
}

自定义摄像头分辨率

java 复制代码
public class CustomCameraResolutionExample {
    public static void main(String[] args) {
        VideoCapture capture = new VideoCapture();
        capture.open(0);

        // 设置分辨率(在读取帧之前设置)
        capture.set(CAP_PROP_FRAME_WIDTH, 1920);
        capture.set(CAP_PROP_FRAME_HEIGHT, 1080);

        // 设置帧率
        capture.set(CAP_PROP_FPS, 30);

        // 验证设置是否生效
        int actualWidth = (int) capture.get(CAP_PROP_FRAME_WIDTH);
        int actualHeight = (int) capture.get(CAP_PROP_FRAME_HEIGHT);
        double actualFps = capture.get(CAP_PROP_FPS);

        System.out.println("实际分辨率: " + actualWidth + " x " + actualHeight);
        System.out.println("实际帧率: " + actualFps + " FPS");

        // 读取帧
        Mat frame = new Mat();
        while (capture.read(frame) && !frame.empty()) {
            // ==================== 处理帧 ====================
        }

        frame.release();
        capture.release();
    }
}

读取网络流(RTSP/RTMP/HTTP)

RTSP 流示例(监控摄像头)

RTSP(Real Time Streaming Protocol)常用于 IP 摄像头、监控系统。

java 复制代码
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.opencv_core.Mat;
import static org.bytedeco.opencv.global.opencv_imgcodecs.*;

public class ReadRTSPStreamExample {
    public static void main(String[] args) {
        // RTSP 流地址(示例格式)
        String rtspUrl = "rtsp://username:password@192.168.1.100:554/stream1";
        // 或者无需认证的:rtsp://192.168.1.100:554/stream1

        // 创建 FFmpegFrameGrabber
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtspUrl);

        try {
            // ===== 配置 RTSP 参数(重要!)=====
            grabber.setOption("rtsp_transport", "tcp");     // 使用 TCP 传输(更稳定)
            grabber.setOption("buffer_size", "1024000");    // 增加缓冲区 1MB
            grabber.setOption("max_delay", "500000");       // 最大延迟 500ms
            grabber.setOption("stimeout", "10000000");      // 超时 10 秒

            // 设置像素格式为 BGR24
            grabber.setPixelFormat(org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_BGR24);

            // 抑制 FFmpeg 警告日志
            org.bytedeco.ffmpeg.global.avutil.av_log_set_level(
                org.bytedeco.ffmpeg.global.avutil.AV_LOG_ERROR
            );

            // 启动
            grabber.start();

            // 获取流信息
            int width = grabber.getImageWidth();
            int height = grabber.getImageHeight();
            double fps = grabber.getFrameRate();

            System.out.println("========== RTSP 流信息 ==========");
            System.out.println("分辨率: " + width + " x " + height);
            System.out.println("帧率: " + fps + " FPS");
            System.out.println("==================================\n");

            // 创建转换器
            OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();

            // 循环读取帧
            Frame frame;
            int frameCount = 0;
            long startTime = System.currentTimeMillis();

            while ((frame = grabber.grabImage()) != null) {
                frameCount++;

                // 转换为 Mat
                Mat mat = converter.convert(frame);

                if (mat != null && !mat.empty()) {
                    // ==================== 在这里处理每一帧 ====================

                    // 释放 Mat
                    mat.release();
                }
            }

            // 释放资源
            grabber.stop();
            grabber.release();

        } catch (Exception e) {
            System.err.println("读取 RTSP 流时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

RTMP 流示例(直播流)

RTMP(Real-Time Messaging Protocol)常用于直播推流、流媒体服务。

java 复制代码
public class ReadRTMPStreamExample {
    public static void main(String[] args) {
        String rtmpUrl = "rtmp://live.example.com/live/stream";

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(rtmpUrl);

        try {
            // RTMP 特定配置
            grabber.setOption("flv_metadata", "1");
            grabber.setOption("buffer_size", "1024000");
            grabber.setPixelFormat(org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_BGR24);

            // 抑制日志
            org.bytedeco.ffmpeg.global.avutil.av_log_set_level(
                org.bytedeco.ffmpeg.global.avutil.AV_LOG_ERROR
            );

            grabber.start();

            OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();

            Frame frame;
            int frameCount = 0;

            while ((frame = grabber.grabImage()) != null) {
                frameCount++;

                Mat mat = converter.convert(frame);

                if (mat != null && !mat.empty()) {
                    // ==================== 在这里处理每一帧 ====================
                    mat.release();
                }
            }

            grabber.stop();
            grabber.release();

        } catch (Exception e) {
            System.err.println("读取 RTMP 流时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

HTTP 视频流示例

java 复制代码
public class ReadHTTPStreamExample {
    public static void main(String[] args) {
        String httpUrl = "http://example.com/stream.mjpg";

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(httpUrl);

        try {
            grabber.setPixelFormat(org.bytedeco.ffmpeg.global.avutil.AV_PIX_FMT_BGR24);

            System.out.println("正在连接 HTTP 流: " + httpUrl);
            grabber.start();
            System.out.println("连接成功!\n");

            OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();

            Frame frame;
            int frameCount = 0;

            while ((frame = grabber.grabImage()) != null) {
                frameCount++;

                Mat mat = converter.convert(frame);

                if (mat != null && !mat.empty()) {
                    // ==================== 在这里处理每一帧 ====================
                    mat.release();
                }
            }

            grabber.stop();
            grabber.release();

        } catch (Exception e) {
            System.err.println("读取 HTTP 流时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

视频推流(RTSP/RTMP/文件录制)

本节介绍如何将处理后的视频帧推送到网络流服务器(RTSP/RTMP)或录制为视频文件。这在以下场景非常有用:

  • 📹 将处理后的视频(带检测框、标注)推流到监控平台
  • 💾 录制告警视频片段保存到本地或云存储
  • 🔄 视频转码和格式转换
  • 📡 实时视频分析结果的二次分发

核心工具:FFmpegFrameRecorder

JavaCV 提供了 FFmpegFrameRecorder 类,用于将帧写入视频文件或推送到流媒体服务器。


录制视频到文件

基本示例
java 复制代码
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;

public class RecordVideoToFileExample {
    public static void main(String[] args) {
        String inputVideo = "input.mp4";
        String outputFile = "output.mp4";

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputVideo);
        FFmpegFrameRecorder recorder = null;

        try {
            // 1. 启动输入
            grabber.start();
            System.out.println("成功打开输入视频");

            // 2. 获取视频参数
            int width = grabber.getImageWidth();
            int height = grabber.getImageHeight();
            double frameRate = grabber.getFrameRate();
            int audioChannels = grabber.getAudioChannels();

            System.out.println("========== 视频信息 ==========");
            System.out.println("分辨率: " + width + " x " + height);
            System.out.println("帧率: " + frameRate + " FPS");
            System.out.println("==============================\n");

            // 3. 创建录制器
            recorder = new FFmpegFrameRecorder(outputFile, width, height, audioChannels);
            recorder.setVideoCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264);
            recorder.setFormat("mp4");
            recorder.setFrameRate(frameRate);
            recorder.setVideoBitrate(2000000); // 2 Mbps

            // 音频设置(如果有音频)
            if (audioChannels > 0) {
                recorder.setAudioCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_AAC);
                recorder.setSampleRate(grabber.getSampleRate());
            }

            // 启动录制器
            recorder.start();
            System.out.println("开始录制到文件: " + outputFile + "\n");

            // 4. 读取并写入帧
            Frame frame;
            int frameCount = 0;

            while ((frame = grabber.grab()) != null) {
                frameCount++;

                // ==================== 在这里可以处理帧 ====================

                // 录制帧
                recorder.record(frame);

                if (frameCount % 100 == 0) {
                    System.out.println("已录制 " + frameCount + " 帧");
                }
            }

            System.out.println("\n录制完成!共录制 " + frameCount + " 帧");
            System.out.println("输出文件: " + outputFile);

            // 5. 释放资源
            recorder.stop();
            recorder.release();
            grabber.stop();
            grabber.release();

        } catch (Exception e) {
            System.err.println("录制视频时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

推流到 RTSP 服务器

RTSP 推流适用于监控系统、视频管理平台(如海康、大华等)。

java 复制代码
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;

public class PushToRTSPExample {
    public static void main(String[] args) {
        String inputSource = "rtsp://192.168.1.100:554/stream1"; // 输入流
        String rtspOutput = "rtsp://localhost:8554/live";        // 输出 RTSP 地址

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputSource);
        FFmpegFrameRecorder recorder = null;

        try {
            // 配置并启动输入
            grabber.setOption("rtsp_transport", "tcp");
            grabber.start();
            System.out.println("成功连接输入流");

            // 获取视频参数
            int width = grabber.getImageWidth();
            int height = grabber.getImageHeight();
            double frameRate = grabber.getFrameRate();

            System.out.println("分辨率: " + width + " x " + height);
            System.out.println("帧率: " + frameRate + " FPS\n");

            // 创建 RTSP 推流器
            recorder = new FFmpegFrameRecorder(rtspOutput, width, height);
            recorder.setVideoCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264);
            recorder.setFormat("rtsp");
            recorder.setFrameRate(frameRate);
            recorder.setVideoBitrate(2000000);
            recorder.setGopSize((int) frameRate * 2); // 2 秒一个关键帧

            // RTSP 推流特定参数
            recorder.setOption("rtsp_transport", "tcp");
            recorder.setOption("muxdelay", "0.1");

            // 启动推流
            recorder.start();
            System.out.println("开始推流到: " + rtspOutput + "\n");

            // 读取并推流
            Frame frame;
            int frameCount = 0;
            long startTime = System.currentTimeMillis();

            while ((frame = grabber.grabImage()) != null) {
                frameCount++;

                // ==================== 在这里处理帧 ====================
                // 可以添加检测结果、标注、告警信息等

                // 推送帧
                recorder.record(frame);

                if (frameCount % 100 == 0) {
                    long elapsed = System.currentTimeMillis() - startTime;
                    double actualFps = frameCount * 1000.0 / elapsed;
                }

                // 可选:设置停止条件
                if (frameCount >= 3000) {
                    System.out.println("\n达到帧数限制,停止推流");
                    break;
                }
            }

            // 释放资源
            recorder.stop();
            recorder.release();
            grabber.stop();
            grabber.release();

        } catch (Exception e) {
            System.err.println("RTSP 推流出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

常见推流参数配置

编码器参数对照表
参数 说明 推荐值 备注
setVideoCodec 视频编码器 AV_CODEC_ID_H264 H.264 兼容性最好
setFormat 封装格式 "mp4" / "flv" / "rtsp" RTMP 用 flv,RTSP 用 rtsp
setFrameRate 帧率 25.0 / 30.0 根据输入流设置
setVideoBitrate 视频码率 2000000 (2 Mbps) 高清推荐 3-5 Mbps
setGopSize GOP 大小 frameRate * 2 2 秒一个关键帧
setPixelFormat 像素格式 AV_PIX_FMT_YUV420P 兼容性最好
H.264 编码优化选项
java 复制代码
// 编码速度优先(低延迟)
recorder.setVideoOption("preset", "ultrafast");  // 最快编码
recorder.setVideoOption("tune", "zerolatency");  // 零延迟调优

// 质量优先(录制存档)
recorder.setVideoOption("preset", "slow");       // 慢速编码
recorder.setVideoOption("crf", "18");            // 高质量(18-23)

// 平衡模式(推荐)
recorder.setVideoOption("preset", "veryfast");   // 很快编码
recorder.setVideoOption("tune", "zerolatency");  // 零延迟
recorder.setVideoOption("crf", "23");            // 中等质量
音频编码参数
java 复制代码
if (audioChannels > 0) {
    recorder.setAudioCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_AAC);
    recorder.setSampleRate(44100);      // 采样率 44.1kHz
    recorder.setAudioBitrate(128000);   // 音频码率 128kbps
    recorder.setAudioChannels(2);       // 立体声
}

推流应用场景

场景 输入源 输出目标 典型应用
监控告警录制 RTSP 摄像头 本地 MP4 文件 检测到异常时录制视频片段
实时检测展示 摄像头 RTSP 服务器 将检测结果推送到监控平台
直播审核 RTMP 直播流 RTMP 服务器 实时审核后转推到 CDN
视频转码 视频文件 不同格式文件 格式转换和压缩
多路分发 单个输入 多个 RTSP/RTMP 一个源推送到多个目标

总结

本节介绍了使用 JavaCV 进行视频推流的完整方案:

  • 录制视频文件:将处理后的帧保存为 MP4 等格式
  • RTSP 推流:推送到监控平台和视频管理系统
  • RTMP 推流:推送到直播平台
  • 实时处理推流:边处理边推流的完整流程
  • 参数优化:编码器、码率、帧率等配置指南
  • 故障排查:常见问题和解决方案

关键要点

  • 使用 FFmpegFrameRecorder 进行推流和录制
  • 根据场景选择合适的编码参数(速度 vs 质量)
  • 使用 ultrafast + zerolatency 实现低延迟推流
  • 合理设置 GOP 大小和码率

实用工具函数

自动重连函数

java 复制代码
public static VideoCapture openVideoWithRetry(String path, int maxRetries) {
    VideoCapture capture = new VideoCapture();
    int retryCount = 0;

    while (retryCount < maxRetries) {
        if (capture.open(path)) {
            System.out.println("成功打开视频源: " + path);
            return capture;
        }

        retryCount++;
        System.err.println("打开失败,重试 " + retryCount + "/" + maxRetries);

        try {
            Thread.sleep(2000); // 等待 2 秒
        } catch (InterruptedException e) {
            break;
        }
    }

    System.err.println("多次重试失败");
    return null;
}

// 使用
VideoCapture capture = openVideoWithRetry("rtsp://192.168.1.100:554/stream1", 3);
if (capture != null) {
    // 处理视频
}

获取视频信息

java 复制代码
public static void printVideoInfo(VideoCapture capture) {
    if (capture == null || !capture.isOpened()) {
        System.err.println("视频源未打开");
        return;
    }

    int width = (int) capture.get(CAP_PROP_FRAME_WIDTH);
    int height = (int) capture.get(CAP_PROP_FRAME_HEIGHT);
    double fps = capture.get(CAP_PROP_FPS);
    long totalFrames = (long) capture.get(CAP_PROP_FRAME_COUNT);

    System.out.println("========== 视频信息 ==========");
    System.out.println("分辨率: " + width + " x " + height);
    System.out.println("帧率: " + fps + " FPS");

    if (totalFrames > 0) {
        System.out.println("总帧数: " + totalFrames);
        System.out.println("时长: " + (totalFrames / fps) + " 秒");
    } else {
        System.out.println("总帧数: 未知(实时流)");
    }

    System.out.println("==============================");
}

总结

本文介绍了使用 Java 读取各种视频源的完整方案,采用面向过程编程风格:

数据源类型 推荐工具 代码复杂度 适用场景
单张图片 OpenCV imread 批量图像处理、离线分析
视频文件 JavaCV FFmpegFrameGrabber ⭐⭐ 视频分析、离线检测
摄像头 OpenCV VideoCapture ⭐⭐ 实时监控、人机交互
网络流 JavaCV FFmpegFrameGrabber ⭐⭐⭐ 网络监控、直播分析

因为是javacv-platform 此依赖包含了ffmpeg的相关封装,不需要本地安装ffmpeg,和引入opencv的相关的opencv_videoio_ffmpeg470_64.dll等额外依赖,既能实现跨平台又无需安装ffmpeg,以及依赖版本的问题。

关键要点

  • ✅ 代码简洁直观,易于理解和复制
  • ✅ 根据场景选择 OpenCV 或 JavaCV
  • ✅ 及时释放 Mat 对象避免内存泄漏
  • ✅ 配置合理的网络参数提高稳定性
  • ✅ 使用多线程和跳帧策略优化性能

在循环处理每一帧时,可以进行

  • 🔍 目标检测(YOLOv8/v11)
  • 🎨 图像分割
  • 👤 人脸识别
  • 🚗 车牌识别
  • 📊 视频分析
  • 🖼️ 图像增强
  • 📹 视频录制
  • 🚨 异常检测与告警

参考资料

相关推荐
JavaGuide1 小时前
Spring Boot 4.0 正式发布,真学不动了!
java·spring boot
90后小陈老师1 小时前
用户管理系统 03 搭建基本结构 | Java新手实战 | 最小架构用户管理系统(SpringBoot+Vue3)
java·spring boot·架构
n***84071 小时前
Spring Boot(快速上手)
java·spring boot·后端
组合缺一1 小时前
Solon AI 开发学习3 - chat - 模型配置与请求选项
java·学习·ai·chatgpt·langchain·solon
小兔崽子去哪了2 小时前
Docker部署ZLMediaKit流媒体服务器并自定义配置指南
java·后端·容器
程序猿小蒜2 小时前
基于springboot的人口老龄化社区服务与管理平台
java·前端·spring boot·后端·spring
Caarlossss2 小时前
jdbc学习
java·开发语言·学习·http·tomcat·maven
Coder-coco2 小时前
个人健康系统|健康管理|基于java+Android+微信小程序的个人健康系统设计与实现(源码+数据库+文档)
android·java·vue.js·spring boot·微信小程序·论文·个人健康系统
断剑zou天涯2 小时前
【算法笔记】从暴力递归到动态规划(二)
java·算法·动态规划