【案例】Java使用ffmpeg实现rtsp视频流转hls、rtmp流

发布于:2025-03-02 ⋅ 阅读:(89) ⋅ 点赞:(0)

1. 安装ffmpeg

        linux系统直接运行命令

        ubuntu:

sudo apt install ffmpeg

         centos:

sudo yum install ffmpeg

         windows系统下载包+配置环境变量

https://github.com/BtbN/FFmpeg-Builds/releaseshttps://github.com/BtbN/FFmpeg-Builds/releases

        环境变量配置就在path中加一个你下载下来的包解压后的一直到bin目录的路径地址

2. 配置Nginx

1.1 配置 rtmp

        需要与http同级

rtmp {
    server {
        listen 1935;
        chunk_size 4096; 

        application live {
            live on;  
            record off;  
        }
    }
}
  • listen:指定 rtmp 服务监听端口 
  • chunk_size:设置 rtmp 流的分块大小
  • application live:定义一个 rtmp应用程序
  • live on:启用实时流媒体功能
  • record off:禁用录制功能(如需录制可以设为 record all)
  • 这样就可以让 ffmpeg 将 rtsp 转为 rtmp 到 rtmp://your_server_ip/live/stream_key 地址上

1.2 配置hls

        添加在http内部

    server {
        listen       1234;
        server_name  localhost;

        location /hls/ {
            alias /home/xxx/hls/;  
            add_header Cache-Control no-cache;  

            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';

            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
                add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept';
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
            }
        }

    }
  • 使用 ffmpeg 将 rtsp 转为 hls 时需要一个文件夹来存储,这里的 /home/xxx/hls/ 就是你选择用来存储的文件夹
  • 下面的 add_header 等,是为了解决前端请求流地址跨域问题的
  • 这样前端就可以通过 http://your_server_ip:1234/hls/stream_key.m3u8 来访问流

3. 编写Java代码

import java.io.File;
import java.io.IOException;

public class RTSPConverter {
    private Process ffmpegProcess;
    private Thread processMonitorThread;
    private String ffmpegPath = "ffmpeg";
    private String outputDir = "/home/xxx/hls";

    public int startRTMPStreaming(String rtspUrl, String rtmpUrl) {

        // FFmpeg 命令
        String[] command = {
            ffmpegPath,
            "-i", rtspUrl,
            "-c:v", "copy",
            "-c:a", "aac",
            "-f", "flv",
            rtmpUrl
        };

        return startStreaming(command);
    }

    public int startHLSStreaming(String rtspUrl) {
        // 确保输出目录存在
        File outputDirFile = new File(outputDir);
        if (!outputDirFile.exists()) {
            outputDirFile.mkdirs();
        }
        // FFmpeg 命令
        String[] command = {
            ffmpegPath,
            "-i", rtspUrl,          // 输入 RTSP 流
            "-c:v", "copy",         // 视频流直接复制
            "-c:a", "aac",          // 音频流重新编码为 AAC
            "-f", "hls",            // 输出格式为 HLS
            "-hls_time", "10",      // 每个 TS 文件的时长(秒)
            "-hls_list_size", "6",  // HLS 播放列表中保留的 TS 文件数量
            "-hls_flags", "delete_segments", // 自动删除旧的 TS 文件
            outputDir + "/" + "hlsStream" + ".m3u8"
        };
        return startStreaming(command);
    }

    private int startStreaming(String[] command) {
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            processBuilder.inheritIO();

            // 启动FFmpeg进程
            ffmpegProcess = processBuilder.start();

            // 创建监控线程处理进程结束
            processMonitorThread = new Thread(() -> {
                try {
                    ffmpegProcess.waitFor();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });

            processMonitorThread.start();
            return 1;
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        }
    }

    public int stopStreaming() {
        if (ffmpegProcess != null && ffmpegProcess.isAlive()) {
            // 销毁FFmpeg进程
            ffmpegProcess.destroy();
            try {
                // 等待监控线程结束
                if (processMonitorThread != null) {
                    processMonitorThread.join(5000); // 最多等待5秒
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return 0;
            }
        }
        return 1;
    }
}
  • startRTMPStreaming:拼装 ffmpeg 将 rtsp 转 rtmp 的命令
  • startHLSStreaming:拼装 ffmpeg 将 rtsp 转 rtmp 的命令
  • startStreaming:开始运行 ffmpeg 执行命令
  • stopStreaming:停止运行 ffmpeg
  • 其中 "-c:v", "copy", 如果你要编码为 h.264 则需要将 copy 改为 libx264(下面音频相同)