javacv + ffmpeg + nginx将原始rtsp流推送到流媒体服务器,提供hls或flv流供人查看
2024年4月5日
Maven依赖
xml
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.9</version>
</dependency>
外部依赖
需要下载ffmpeg并配置环境变量,不然程序运行报错
下载nginx搭建rtmp服务器,这里是我用的版本
自己去下也行,要下载带有rtmp模块的nginx(Gryphon)这里
nginx配置
修改上面的nginx下载好解压后的配置文件,即conf/nginx-win.conf文件
无需删减,加两段配置就行。后面有完整版配置
ini
rtmp {
server {
listen 1935;
# 查看flv流时打开rtmp://localhost:1935/flv-live/test就可以了
application flv-live {
live on;
record off;
allow play all;
}
application hls {
live on;
hls on;
# 改成自己准备存放m3u8文件的目录
hls_path C:/Users/hachimi/Videos/test/hls;
hls_fragment 5s;
hls_playlist_length 30s;
}
}
}
server块里加一个location
bash
# 第二处修改,之后用vlc打开网络串流输入http://localhost/hls/test.m3u8就可以了
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
# 修改成自己的存放m3u8文件的目录
alias C:/Users/hachimi/Videos/test/hls;
add_header Cache-Control no-cache;
}
完整版修改后的配置文件
ini
#user nobody;
# multiple workers works !
worker_processes 2;
events {
worker_connections 8192;
}
# 第一处修改
rtmp {
server {
listen 1935;
# 查看flv流时打开rtmp://localhost:1935/flv-live/test就可以了
application flv-live {
live on;
record off;
allow play all;
}
application hls {
live on;
hls on;
# 改成自己准备存放m3u8文件的目录
hls_path C:/Users/hachimi/Videos/test/hls;
hls_fragment 5s;
hls_playlist_length 30s;
}
}
}
http {
include mime.types;
default_type application/octet-stream;
sendfile off;
server_names_hash_bucket_size 128;
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 30;
send_timeout 10;
keepalive_requests 10;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
# 第二处修改,之后用vlc打开网络串流输入http://localhost/hls/test.m3u8就可以了
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
# 修改成自己的存放m3u8文件的目录
alias C:/Users/hachimi/Videos/test/hls;
add_header Cache-Control no-cache;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
代码
java
package rtsp;
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;
import java.util.concurrent.TimeUnit;
public class RtspToStreamTest {
static {
// 设置FFmpeg日志级别
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
}
private static final String RTSP_URL = "rtsp://admin:123456@10.65.66.205:554/video1";
private static final String HLS_URL = "C:/Users/hachimi/Videos/test/hls/test.m3u8";
private static final String FLV_URL = "rtmp://localhost:1935/flv-live/test";
private static final String FLV_OUTPUT_PATH = "C:/Users/hachimi/Videos/test/output.flv";
private static long startTime = System.currentTimeMillis(); // 定义startTime变量
public static void main(String[] args) throws Exception {
System.out.println("hello world");
pushRtspToHLS();
//pushRtspToFLV();
// saveRtspToFlfFile();
System.out.println("good bye");
}
public static void pushRtspToHLS() throws Exception {
processAndPushStream(RTSP_URL, HLS_URL, "hls");
}
public static void pushRtspToFLV() throws Exception {
processAndPushStream(RTSP_URL, FLV_URL, "flv");
}
public static void saveRtspToFlfFile() throws Exception {
recordRtspToFile(RTSP_URL, FLV_OUTPUT_PATH, "flv");
}
private static void processAndPushStream(String inputUrl, String outputUrl, String format) throws Exception {
FFmpegFrameGrabber grabber = createGrabber(inputUrl);
FFmpegFrameRecorder recorder = createRecorder(outputUrl, grabber, format);
startRecording(grabber, recorder);
}
private static void recordRtspToFile(String inputUrl, String outputPath, String format) throws Exception {
FFmpegFrameGrabber grabber = createGrabber(inputUrl);
FFmpegFrameRecorder recorder = createRecorder(outputPath, grabber, format);
startRecording(grabber, recorder, 10, TimeUnit.SECONDS);
}
private static FFmpegFrameGrabber createGrabber(String inputUrl) throws Exception {
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputUrl);
grabber.start();
return grabber;
}
private static FFmpegFrameRecorder createRecorder(String outputUrl, FFmpegFrameGrabber grabber, String format) throws Exception {
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputUrl, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels());
recorder.setFormat(format);
configureRecorder(recorder, grabber);
return recorder;
}
private static void configureRecorder(FFmpegFrameRecorder recorder, FFmpegFrameGrabber grabber) throws Exception {
recorder.setVideoBitrate(grabber.getVideoBitrate());
recorder.setFrameRate(grabber.getFrameRate());
recorder.setGopSize((int) grabber.getVideoFrameRate());
if ("hls".equals(recorder.getFormat())) {
configureHlsRecorder(recorder);
}
recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
if (grabber.getAudioChannels() > 0) {
recorder.setAudioChannels(grabber.getAudioChannels());
recorder.setAudioBitrate(grabber.getAudioBitrate());
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
}
}
private static void configureHlsRecorder(FFmpegFrameRecorder recorder) {
recorder.setOption("hls_time", "15");
recorder.setOption("hls_list_size", "20");
recorder.setOption("hls_wrap", "20");
recorder.setOption("hls_flags", "delete_segments");
}
private static void startRecording(FFmpegFrameGrabber grabber, FFmpegFrameRecorder recorder) throws Exception {
startRecording(grabber, recorder, Long.MAX_VALUE, null);
}
private static void startRecording(FFmpegFrameGrabber grabber, FFmpegFrameRecorder recorder, long timeout, TimeUnit unit) throws Exception {
Frame frame;
recorder.start();
while ((frame = grabber.grab()) != null && (!shouldStop(timeout, unit))) {
recorder.record(frame);
}
recorder.close();
grabber.close();
}
private static boolean shouldStop(long timeout, TimeUnit unit) {
if (unit == null || timeout == Long.MAX_VALUE) {
return false;
}
return System.currentTimeMillis() - startTime >= unit.toMillis(timeout);
}
}
其他
其实推流不用Java代码就行,用安装好的ffmpeg命令就可以
rtsp推流成hls
bash
ffmpeg -i rtsp://admin:123456@10.64.45.202:554/video1 -c:v copy -c:a aac -hls_time 10 -hls_list_size 6 C:/Users/hachimi/Videos/test/hls/test.m3u8
rtsp推流成flv(这里有问题,用代码推出来的可以直接看,用下面的命令行就不行,想用flv的话就用上面的代码或者自己研究一下其他的命令)
bash
ffmpeg -rtsp_transport tcp -i rtsp://admin:123456@10.64.45.202:554/video1 -c:v copy -c:a aac -strict experimental -f flv rtmp://localhost:1935/flv-live/test
ffmpeg -i rtsp://admin:123456@10.64.45.202:554/video1 -c:v copy -f flv rtmp://localhost:1935/flv-live/test
运行
运行代码后就可以在vlc中查看了
hls用http://localhost/hls/test.m3u8
flv用rtmp://localhost:1935/flv-live/test