Java 应用Nginx+ffmpeg实现海康视频web直播

环境:Linux(Centos 7.5)

实现方案
1、前期准备
按照功能要求,确定使用ffmpeg命令将rtsp转为hls(.m3u8)
ffmpeg命令实例:ffmpeg -i rtsp://用户名:密码@ip:port/Streaming/Channels/1 -c:v libx264 -preset faster -crf 20 -vprofile main -pix_fmt yuv420p -c:a aac -b:a 64k -y -hls_wrap 10 index.m3u8
—更新优化—————————————————————————————————
补充更新:降低ffmpeg命令CPU占用率 1:rtsp 地址使用子码流 2增加线程设置 (-threads 10)
3防止流转换过程中的丢包问题-rtsp_transport tcp
优化ffmpeg 命令:
ffmpeg -rtsp_transport tcp -threads 10 -re -i rtsp://用户名:密码@ip:port/h264/ch1/sub/av_stream(替换“rtsp://用户名:密码@ip:port/Streaming/Channels/1”) -c:v libx264 -preset faster -crf 20 -vprofile main -pix_fmt yuv420p -c:a aac -b:a 64k -y -hls_wrap 10 index.m3u8
——————————————————————————————————————
2、测试工具
选用VLC播放器,可以直接使用hls地址检查输出结果
3、Java部分
①创建springboot项目,并在启动类中开启异步任务

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableAsync        //开启异步任务
public class DemoApplication {

    @Bean(name="processExecutor")
    public TaskExecutor workExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setThreadNamePrefix("Async-");
        threadPoolTaskExecutor.setCorePoolSize(10);
        threadPoolTaskExecutor.setMaxPoolSize(20);
        threadPoolTaskExecutor.setQueueCapacity(600);
        threadPoolTaskExecutor.afterPropertiesSet();
        return threadPoolTaskExecutor;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

②实现类

@Service
public class AsyncTask {

    //获取摄像头地址列表,按照顺序获取摄像头信息
    @Value("#{'${video.list:}'.split(',')}")
    private List<String> videoList;

    @Async("processExecutor")
    public void start(int id) {
        //根据编号获取摄像头地址
        String rtsp = videoList.get(id-1);
        //hls输出地址
        String url = "/home/html/hls/live/"+id+"/index.m3u8";
        ProcessBuilder builder = new ProcessBuilder(); //创建系统进程
        List<String> commend = new ArrayList<>();
        //拼接ffmpeg执行命令
        //ffmpeg -i rtsp://用户名:密码@ip:port/Streaming/Channels/1 -c:v libx264 -preset faster -crf 20 -vprofile main -pix_fmt yuv420p -c:a aac -b:a 64k -y -hls_wrap 10 index.m3u8
        commend.add("ffmpeg");
        //-rtsp_transport  tcp 防止流转换过程中的丢包问题
        commend.add("-rtsp_transport");
        commend.add("tcp");
        commend.add("-re");
        commend.add("-i");
        commend.add(rtsp);
        //格式转换
        commend.add("-c:v");
        commend.add("libx264");
        commend.add("-preset");
        commend.add("faster");
        commend.add("-crf");
        commend.add("20");
        commend.add("-vprofile");
        commend.add("main");
        commend.add("-pix_fmt");
        commend.add("yuv420p");
        commend.add("-c:a");
        commend.add("aac");
        commend.add("-b:a");
        commend.add("64k");
        commend.add("-y");
        //设置切片数量 循环覆盖
        commend.add("-hls_wrap");
        commend.add("10");
        commend.add(url);
        builder.command(commend);
        builder.redirectErrorStream(true);
        try {
            Process start = builder.start();//启动进程
            InputStream inputStream = start.getInputStream();
            InputStreamReader gbk = new InputStreamReader(inputStream);
            int len = -1;
            char[] c = new char[1024];
            StringBuffer outputString = new StringBuffer();

            //读取进程输入流中的内容
            while ((len = gbk.read(c)) != -1) {
                String ss = new String(c, 0, len);
                outputString.append(ss);
                System.out.print(ss);
            }
            /*int exitVal = start.waitFor();*/
            gbk.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

③异步任务调用

@RestController
public class VideoController implements ApplicationRunner {

    @Autowired
    private AsyncTask asyncTask;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        int id =3;//直播数量
        for (int i = 1; i <= id ; i++) {
            asyncTask.start(i);
        }
    }
}

4、服务器部分
(1)ffmpeg安装
选择已经编译好的Ffmpeg,已编译好的ffmpeg包含大部分编译库、编解码库,且免安装。
下载并解压tar -xvJf ffmpeg-4.2.1-amd64-static.tar.xz
解压后将目录下的可执行文件移动到/usr/local/bin/ 里, 这样不用每次都写完整路径

把当前目录下的ffmpeg 、ffprobe、qt-faststart移动到/usr/local/bin/
mv ffmpeg /usr/local/bin/
此时执行ffmpeg可以查询ffmpeg的基本信息,也可以使用ffmpeg命令进行视频流转换。

下载地址:https://www.johnvansickle.com/ffmpeg/old-releases/

(2)nginx安装
修改配置,在nginx\conf\nginx.conf下。
①vi nginx\conf\nginx.conf增加以下配置:
新增hls流协议:
location /hls {
types{
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root html;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
}
②重启nginx
检查nginx配置是否正确
/usr/local/nginx/sbin/nginx -t
进入nginx可执行目录sbin下,输入命令./nginx -s reload
/usr/local/nginx/sbin/nginx -s reload

配置完成后前端可以通过http://172.20.1.41:57002/hls/1/index.m3u8播放视频
5、问题汇总
(1)ffmpeg版本选择:根据运行环境选择合适的版本,请优先选择已经编译好的ffmpeg,可以不用自行编译,避免缺少编译库,否则会影响ffmpeg命令的参数使用以及最终运行结果(视频无法播放)。
(2)多视频流的直播无法同时进行,请检查运行环境,选择合适的系统硬件支持。
6、扩展
(1)Ffmpeg卸载
卸载除了删除解压目录还要删除编译过后生成的,
执行whereis ffmpeg 找到生成的路径删除相关的文件
(2)Vlc播放器使用
播放器安装之后,从左上角“媒体”→“打开网络串流”→“网络”,输入
http://172.20.1.41:57002/hls/6/index.m3u8即可查看直播内容。
Java 应用Nginx+ffmpeg实现海康视频web直播_第1张图片
参考链接:
参考方案:https://blog.csdn.net/weixin_45848110/article/details/119363602?spm=1001.2014.3001.5501
海康rtsp地址格式:https://blog.csdn.net/haovin/article/details/90649038

你可能感兴趣的:(java,nginx,音视频)