热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java实现rstp格式转换使用ffmpeg实现linux命令第一步安装node.js和ffmpeg第二步搭建node.js启动websocket接收服务

java实现rstp格式转换使用ffmpeg实现linux命令第一步安装node.js和ffmpeg第二步搭建node.js启动websocket接收服务第三步java实现


java实现rstp格式转换使用ffmpeg实现linux命令

    • 第一步安装node.js和ffmpeg
    • 第二步搭建node.js启动websocket接收服务
    • 第三步java实现(启动并挂起转换rtsp流)


第一步安装node.js和ffmpeg

安装可以参考网上的这里不一一介绍了

第二步搭建node.js启动websocket接收服务

部分代码:(要完整代码请关注我并私信给我)

var fs = require('fs');
var http = require('http');
var WebSocket &#61; require(&#39;ws&#39;);if (process.argv.length < 3) {console.log(&#39;输入正确参数&#39;);process.exit();
}var stream_secret &#61; process.argv[2];//密码
var stream_port &#61; process.argv[3] || 8081;//ffpeng推送端口
var websocket_port &#61; process.argv[4] || 8082;//前端websocket端口 &#xff0c;比如&#xff1a;8082
var record_stream &#61; false;
var totalSize &#61; 0;

第三步java实现&#xff08;启动并挂起转换rtsp流&#xff09;

首先我们新建一个java项目&#xff0c;可以是普通的java&#xff0c;我这里新建的是springboot看起来比较高大上。


  1. 新建springboot项目
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述next下一步到这里项目新建好了&#xff1b;
  2. 上代码

public class FfmpegTest {//自带map缓存&#xff0c;防止同一个设备机器多次转换导致视频丢帧public static Map<String , Integer> map &#61; new HashMap<>();//线程池&#xff0c;因为开启转换是持续的多线程开启保证主线程不被阻塞ExecutorService es3 &#61; Executors.newCachedThreadPool();&#64;RequestMapping(value &#61; "/hello/{code}",method &#61; RequestMethod.GET)public String test(&#64;PathVariable String code, HttpServletRequest request){//获取IP地址String ipAddress &#61; IpUtil.getIpAddr(request);System.out.println("客户端ip:"&#43;ipAddress);//转换rtsp流String ffmpeg &#61; ffmpeg(code);//获取pidString pid &#61; getPid(code);System.out.println(ffmpeg&#43;"进程号是:"&#43;pid);return ffmpeg&#43;"进程号是:"&#43;pid;}&#64;RequestMapping(value &#61; "/kill/{code}",method &#61; RequestMethod.GET)public String kill(&#64;PathVariable String code){String pid &#61; getPid(code);System.out.println(code&#43;"视频设备进程号是:"&#43;pid);String s &#61; killPid(pid , code);return code&#43;"视频设备进程号是:"&#43;pid&#43;" "&#43;s;}public String ffmpeg(String code) {String returnstr&#61;"";String s&#61;"";List<String> commend &#61; new ArrayList<String>();commend.add("ffmpeg");commend.add("-i");commend.add("rtsp://用户:摄像头密码&#64;192.168.1."&#43;code&#43;":554/h264/ch1/sub/av_stream");commend.add("-q");commend.add("0");commend.add("-f mpegts -codec:v mpeg1video -s 800x600");commend.add("http://192.168.1.142:8081/supersecret/live"&#43;code&#43;"");StringBuffer test&#61;new StringBuffer();for(int i&#61;0;i<commend.size();i&#43;&#43;)test.append(commend.get(i)&#43;" ");System.out.println(test);try {if (map.get(code)!&#61;null && map.get(code)>&#61;1){map.put(code,map.get(code)&#43;1);returnstr&#43;&#61;code&#43;"设备视频已经在转换列表里了";System.out.println("视频已经在转换列表里了");}else{//采用多线程处理防止主线程阻塞&#xff0c;一直等待startStream(test.toString(),code);map.put(code,1);System.out.println("视频转换成功:");returnstr&#43;&#61;code&#43;"设备视频转换成功";}} catch (Exception e) {e.printStackTrace();}return returnstr;}/*** 使用多线程执行linux的ffmpeg命令防止主线程阻塞* &#64;param test 命令* &#64;param code 对应的摄像投设备标志*/private void startStream(String test,String code) {//处理buffer的线程es3.submit(new Runnable() {&#64;Overridepublic void run() {String line &#61; null;try {Runtime rt &#61; Runtime.getRuntime();//执行linux命令Process proc &#61; rt.exec(test.toString());//添加缓存防止多次转换map.put(code,1);//启用多线程消费正常日志防止内存小导致线程阻塞clearStream(proc.getInputStream());//启用多线程消费错误日志防止内存小导致线程阻塞clearStream(proc.getErrorStream());} catch (IOException e) {e.printStackTrace();}}});}/*** 开启多线程消费日志&#xff0c;防止转换缓冲区内存溢出* &#64;param stream 输出流*/private void clearStream (InputStream stream) {//处理buffer的线程es3.submit(new Runnable() {&#64;Overridepublic void run() {String line &#61; null;try (BufferedReader in &#61; new BufferedReader(new InputStreamReader(stream));) {while ((line &#61; in.readLine()) !&#61; null) {System.out.println(line);}} catch (IOException e) {e.printStackTrace();}}});}/*** 根据pid关闭进程* &#64;param pid* &#64;param code* &#64;return*/public static String killPid(String pid , String code) {BufferedReader reader &#61; null;String pidStr&#61;"";try {// 显示所有进程Process process &#61; Runtime.getRuntime().exec("kill -9 " &#43; pid);pidStr&#43;&#61;"成功关闭进程&#xff1a;"&#43;pid;map.put(code,0);} catch (Exception e) {e.printStackTrace();} finally {if (reader !&#61; null) {try {reader.close();} catch (IOException e) {}}}return pidStr;}/***根据名称获取linux启动的进程pid* &#64;param pid 摄像头唯一标志开启进程时包含的标志* &#64;return*/public static String getPid(String pid) {BufferedReader reader &#61; null;try {// 显示所有进程Process process &#61; Runtime.getRuntime().exec("ps -ef");reader &#61; new BufferedReader(new InputStreamReader(process.getInputStream()));String line &#61; null;while ((line &#61; reader.readLine()) !&#61; null) {//根据设备标志获取需要的线程pidif (line.contains("rtsp://用户名:摄像头密码&#64;192.168.1."&#43;pid&#43;":554/h264/ch1/sub")) {//拿到第一个pidString[] strs &#61; line.split("\\s&#43;");return strs[1];}}} catch (Exception e) {e.printStackTrace();} finally {if (reader !&#61; null) {try {reader.close();} catch (IOException e) {}}}return null;}public static void main(String[] args) {}
}

  1. 启动项目&#xff1b;
    启动springboot项目&#xff0c;然后浏览器访问项目我这里路径是&#xff1a; http://localhost:8097/hello/27此时已经把服务开启并且把流推送到websocket项目
    浏览器访问在这里插入图片描述
    文件代码如下

<!DOCTYPE html>
<html>
<head><title>JSMpeg Stream Client</title><style type&#61;"text/css">html, body {text-align: center;}</style></head>
<body><canvas id&#61;"video-canvas1"></canvas><canvas id&#61;"video-canvas2"></canvas><canvas id&#61;"video-canvas3"></canvas><canvas id&#61;"video-canvas4"></canvas><canvas id&#61;"video-canvas5"></canvas><canvas id&#61;"video-canvas6"></canvas><canvas id&#61;"video-canvas7"></canvas><canvas id&#61;"video-canvas8"></canvas><canvas id&#61;"video-canvas9"></canvas><canvas id&#61;"canvas"></canvas><span id&#61;"jietu">截图</span><script type&#61;"text/Javascript" src&#61;"jsmpeg.min.js"></script><script type&#61;"text/Javascript" src&#61;"html2canvas.js"></script><script type&#61;"text/Javascript" src&#61;"canvas2Image.js"></script><script type&#61;"text/Javascript">let canvas1 &#61; document.getElementById(&#39;video-canvas1&#39;);let url1 &#61; &#39;ws://192.168.1.142:8082/live26&#39;;let player1 &#61; new JSMpeg.Player(url1, {canvas: canvas1});let canvas2 &#61; document.getElementById(&#39;video-canvas2&#39;);let url2 &#61; &#39;ws://192.168.1.142:8082/live24&#39;;let player2 &#61; new JSMpeg.Player(url2, {canvas: canvas2});let canvas3 &#61; document.getElementById(&#39;video-canvas3&#39;);let url3 &#61; &#39;ws://192.168.1.142:8082/live27&#39;;let player3 &#61; new JSMpeg.Player(url3, {canvas: canvas3});let canvas4 &#61; document.getElementById(&#39;video-canvas4&#39;);let url4 &#61; &#39;ws://192.168.1.142:8082/live33&#39;;let player4 &#61; new JSMpeg.Player(url4, {canvas: canvas4});let canvas5 &#61; document.getElementById(&#39;video-canvas5&#39;);let url5 &#61; &#39;ws://192.168.1.142:8082/live23&#39;;let player5 &#61; new JSMpeg.Player(url5, {canvas: canvas5});let canvas6 &#61; document.getElementById(&#39;video-canvas6&#39;);let url6 &#61; &#39;ws://192.168.1.142:8082/live30&#39;;let player6 &#61; new JSMpeg.Player(url6, {canvas: canvas6});let jietu &#61; document.getElementById("jietu");jietu.addEventListener("click", function(){/*var cntElem &#61; document.getElementById("video-canvas1");var shareContent &#61; cntElem;//需要截图的包裹的&#xff08;原生的&#xff09;DOM 对象var width &#61; shareContent.offsetWidth; //获取dom 宽度var height &#61; shareContent.offsetHeight; //获取dom 高度var canvas &#61; document.getElementById("canvas"); //创建一个canvas节点var scale &#61; 2; //定义任意放大倍数 支持小数canvas.width &#61; width * scale; //定义canvas 宽度 * 缩放canvas.height &#61; height * scale; //定义canvas高度 *缩放canvas.getContext("2d").scale(scale, scale); //获取context,设置scalevar opts &#61; {scale: scale, // 添加的scale 参数canvas: canvas, //自定义 canvas// logging: true, //日志开关&#xff0c;便于查看html2canvas的内部执行流程width: width, //dom 原始宽度height: height,useCORS: true // 【重要】开启跨域配置};html2canvas(shareContent, opts).then(function (canvas) {var context &#61; canvas.getContext(&#39;2d&#39;);// 【重要】关闭抗锯齿context.mozImageSmoothingEnabled &#61; false;context.webkitImageSmoothingEnabled &#61; false;context.msImageSmoothingEnabled &#61; false;context.imageSmoothingEnabled &#61; false;// 【重要】默认转化的格式为png,也可设置为其他格式var img &#61; Canvas2Image.saveAsPNG(canvas, canvas.width, canvas.height);document.body.appendChild(img);img.css &#61; {"width": canvas.width / 2 &#43; "px","height": canvas.height / 2 &#43; "px","position":"fixed","top":"0","left":"0","opacity":"1","z-index":222}});*/downloadFile(&#39;download&#39;, document.getElementById("video-canvas1").toDataURL());});function downloadFile(fileName, content) {let aLink &#61; document.createElement(&#39;a&#39;);let blob &#61; this.base64ToBlob(content); //new Blob([content]);let evt &#61; document.createEvent("HTMLEvents");evt.initEvent("click", true, true);//initEvent 不加后两个参数在FF下会报错 事件类型&#xff0c;是否冒泡&#xff0c;是否阻止浏览器的默认行为aLink.download &#61; fileName;aLink.href &#61; URL.createObjectURL(blob);// aLink.dispatchEvent(evt);aLink.click()}function base64ToBlob(code) {let parts &#61; code.split(&#39;;base64,&#39;);let contentType &#61; parts[0].split(&#39;:&#39;)[1];let raw &#61; window.atob(parts[1]);let rawLength &#61; raw.length;let uInt8Array &#61; new Uint8Array(rawLength);for (let i &#61; 0; i < rawLength; &#43;&#43;i) {uInt8Array[i] &#61; raw.charCodeAt(i);}return new Blob([uInt8Array], { type: contentType });}/*for (let i &#61; 1; i <&#61; 9; i&#43;&#43;){let canvas &#61; document.getElementById(&#39;video-canvas&#39; &#43; i);let url &#61; &#39;ws://127.0.0.1:8082/live&#39; &#43; i;let player &#61; new JSMpeg.Player(url, {canvas: canvas});}*/</script>
</body>
</html>

  1. 浏览器就可以实时看到监控了&#xff1b;
  2. 注意事项和细节代码注释。觉得还行关注和打赏一下。有需要可以添加我的qq&#xff1a;794129243
    本文是原创未经允许不得用于商业用途涉及法律效应&#xff0c;一概不负责。转载请标明出处。

推荐阅读
  • 本文详细介绍了如何在 Node.js 环境中利用 Nodemailer 库实现邮件发送功能,包括环境配置、代码实现及常见问题解决方法。 ... [详细]
  • 在Java开发中,保护代码安全是一个重要的课题。由于Java字节码容易被反编译,因此使用代码混淆工具如ProGuard变得尤为重要。本文将详细介绍如何使用ProGuard进行代码混淆,以及其基本原理和常见问题。 ... [详细]
  • 本打算教一步步实现koa-router,因为要解释的太多了,所以先简化成mini版本,从实现部分功能到阅读源码,希望能让你好理解一些。希望你之前有读过koa源码,没有的话,给你链接 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • 在处理木偶评估函数时,我发现可以顺利传递本机对象(如字符串、列表和数字),但每当尝试将JSHandle或ElementHandle作为参数传递时,函数会拒绝接受这些对象。这可能是由于这些句柄对象的特殊性质导致的,建议在使用时进行适当的转换或封装,以确保函数能够正确处理。 ... [详细]
  • 本文介绍了一个使用Spring框架和Quartz调度器实现每周定时调用Web服务获取数据的小项目。通过详细配置Spring XML文件,展示了如何设置定时任务以及解决可能遇到的自动注入问题。 ... [详细]
  • 在 Ubuntu 22.04 LTS 上部署 Jira 敏捷项目管理工具
    Jira 敏捷项目管理工具专为软件开发团队设计,旨在以高效、有序的方式管理项目、问题和任务。该工具提供了灵活且可定制的工作流程,能够根据项目需求进行调整。本文将详细介绍如何在 Ubuntu 22.04 LTS 上安装和配置 Jira。 ... [详细]
  • C#中调用OpenCTM打开.obj三维模型文件
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 尽管Medium是一个优秀的发布平台,但在其之外拥有自己的博客仍然非常重要。这不仅提供了另一个与读者互动的渠道,还能确保您的内容安全。本文将介绍如何使用Bash脚本将Medium文章迁移到个人博客。 ... [详细]
  • PHP-Casbin v3.20.0 已经发布,这是一个使用 PHP 语言开发的轻量级开源访问控制框架,支持多种访问控制模型,包括 ACL、RBAC 和 ABAC。新版本在性能上有了显著的提升。 ... [详细]
  • 本文介绍了如何使用 Node.js 和 Express(4.x 及以上版本)构建高效的文件上传功能。通过引入 `multer` 中间件,可以轻松实现文件上传。首先,需要通过 `npm install multer` 安装该中间件。接着,在 Express 应用中配置 `multer`,以处理多部分表单数据。本文详细讲解了 `multer` 的基本用法和高级配置,帮助开发者快速搭建稳定可靠的文件上传服务。 ... [详细]
  • 利用 JavaScript 和 Node.js 验证时间的有效性
    本文探讨了如何使用 JavaScript 和 Node.js 验证时间的有效性。通过编写一个 `isTime` 函数,我们可以确保输入的时间格式正确且有效。该函数利用正则表达式匹配时间字符串,检查其是否符合常见的日期时间格式,如 `YYYY-MM-DD` 或 `HH:MM:SS`。此外,我们还介绍了如何处理不同时间格式的转换和验证,以提高代码的健壮性和可靠性。 ... [详细]
  • Hyperledger Fabric 1.4 节点 SDK 快速入门指南
    本文将详细介绍如何利用 Hyperledger Fabric 1.4 的 Node.js SDK 开发应用程序。通过最新版本的 Fabric Node.js SDK,开发者可以更高效地构建和部署基于区块链的应用,实现数据的安全共享和交易处理。文章将涵盖环境配置、SDK 安装、示例代码以及常见问题的解决方法,帮助读者快速上手并掌握核心功能。 ... [详细]
  • V8不仅是一款著名的八缸发动机,广泛应用于道奇Charger、宾利Continental GT和BossHoss摩托车中。自2008年以来,作为Chromium项目的一部分,V8 JavaScript引擎在性能优化和技术创新方面取得了显著进展。该引擎通过先进的编译技术和高效的垃圾回收机制,显著提升了JavaScript的执行效率,为现代Web应用提供了强大的支持。持续的优化和创新使得V8在处理复杂计算和大规模数据时表现更加出色,成为众多开发者和企业的首选。 ... [详细]
  • WebStorm 是一款强大的集成开发环境,支持多种现代 Web 开发技术,包括 Node.js、CoffeeScript、TypeScript、Dart、Jade、Sass、LESS 和 Stylus。它为开发者提供了丰富的功能和工具,帮助高效构建和调试复杂的 Node.js 应用程序。 ... [详细]
author-avatar
ruiqiazhang_236
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有