import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;

public class VideoRecorder {

    private static final String SAVE_PATH = "record.mp4";

    public static void main(String[] args) {
        // ===================== 参数逻辑:时长可空 =====================
        if (args.length < 1) {
            System.err.println("用法:java VideoRecorder <RTSP_URL> [录制时长(秒)]");
            System.err.println("示例1(实时流):java VideoRecorder rtsp://xxx 10");
            System.err.println("示例2(回放流):java VideoRecorder rtsp://xxx");
            return;
        }

        String rtspUrl = args[0];
        Long maxRecordSeconds = null;

        // 如果传了第二个参数,就用;没传就不限制时间(播完即停)
        if (args.length >= 2) {
            try {
                maxRecordSeconds = Long.parseLong(args[1]);
            } catch (NumberFormatException e) {
                System.err.println("时长必须是数字!");
                return;
            }
        }
        // =============================================================

        avutil.av_log_set_level(avutil.AV_LOG_QUIET);

        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;

        try {
            grabber = new FFmpegFrameGrabber(rtspUrl);
            grabber.setOption("rtsp_transport", "tcp");
            grabber.setOption("stimeout", "5000000");
            grabber.start();
            System.out.println("RTSP 拉流成功");

            int audioChannels = grabber.getAudioChannels();
            System.out.println("音频通道:" + audioChannels);

            recorder = new FFmpegFrameRecorder(
                    SAVE_PATH,
                    grabber.getImageWidth(),
                    grabber.getImageHeight(),
                    audioChannels
            );

            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
            recorder.setFormat("mp4");
            recorder.setFrameRate(grabber.getFrameRate());
            recorder.setVideoBitrate(4000000);
            recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);

            if (audioChannels > 0) {
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
                recorder.setSampleRate(8000);
                recorder.setAudioBitrate(64000);
            }

            recorder.start();

            if (maxRecordSeconds != null) {
                System.out.println("开始录制,最长录制 " + maxRecordSeconds + " 秒");
            } else {
                System.out.println("开始录制,流播放完毕自动停止");
            }

            Frame frame;
            int frameCount = 0;
            long startTime = System.currentTimeMillis();

            // ===================== 核心逻辑 =====================
            while ((frame = grabber.grabFrame()) != null) {
                // 如果设置了时长,才判断超时
                if (maxRecordSeconds != null) {
                    long now = System.currentTimeMillis();
                    if (now - startTime > maxRecordSeconds * 1000) {
                        System.out.println("已达到最大录制时长,自动停止");
                        break;
                    }
                }
                recorder.record(frame);
                frameCount++;
            }
            // =====================================================

            if (maxRecordSeconds == null) {
                System.out.println("流已播放完毕,自动停止");
            }

            System.out.println("录制完成!总帧数:" + frameCount);

        } catch (Exception e) {
            System.err.println("录制异常:");
            e.printStackTrace();
        } finally {
            try {
                if (recorder != null) {
                    recorder.stop();
                    recorder.release();
                }
                if (grabber != null) {
                    grabber.stop();
                    grabber.release();
                }
                System.out.println("文件已保存:" + SAVE_PATH);
            } catch (Exception ignored) {}
        }
    }
}

pom依赖

全平台全功能大包

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.5.9</version>
</dependency>

只做 RTSP 转 MP4,只需要引入核心最小依赖

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv</artifactId>
    <version>1.5.8</version>
</dependency>

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv</artifactId>
    <version>1.5.8</version>
</dependency>

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg</artifactId>
    <version>5.1.2-1.5.8</version>
</dependency>

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg</artifactId>
    <version>5.1.2-1.5.8</version>
    <classifier>windows-x86_64</classifier>
</dependency>

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg</artifactId>
    <version>5.1.2-1.5.8</version>
    <classifier>linux-x86_64</classifier>
</dependency>

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg</artifactId>
    <version>5.1.2-1.5.8</version>
    <classifier>linux-arm64</classifier>
</dependency>

打包配置

<build>
    <finalName>rtsp-recorder</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>8</source>
                <target>8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>

        <!-- 关键:打包所有依赖到一个jar -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.4.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>VideoRecorder</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐