首页 > 编程语言 >【java 使用 ffmpeg 将rtsp转hls】

【java 使用 ffmpeg 将rtsp转hls】

时间:2024-10-09 08:50:03浏览次数:11  
标签:java String jsonBody rtsp hls new import null

java 海康接口 ffmpeg

提示

java使用 SpringBoot 框架
jdk使用 1.8版本

海康

通过访问 OpenAPI 文档中心的方式可以验证 API 网关是否安装成功,访问地址
http://IP:Port/artemis-portal/document 打开文档中心(其中 IP:Port 以及 http 头与登录门户页面信息保
持一致)。海康运管中心

相关文件

海康调试工具 下载
海康在线 文档 (需登录)

开发准备

环境
ip,prot门户登录地址,注意端口要和所选的协议匹配(http 默认端口 80,https 默认 端口 443,如有修改,以实际端口为准);
参数
appkey ,secret Appkey/Secret:合作方 Key 和 Secret(从运管中心-状态监控-API 网关-API 管理-合作方 管理,点开具体合作方获得);
参数来源

工具使用

  • 视频WEB插件
    浏览器插件播放
    根据cameraIndexCode播放

  • OpenApi 签名生成工具
    根据签名使用postman调用调试

   X-Ca-Key:appKey,即 AK。
   X-Ca-Signature:签名,以 appSecret(即 SK)为密钥,
   X-Ca-Signature-Headers:请求头,填写有值字段
   以上字段为必填值

获取签名
获取签名 使用postman调取接口
postman调用接口

  • OpenAPI 接口测试工具
    根据参数直接调取
    直接调取

引入海康依赖
pom.xml

<dependency>
    <groupId>com.hikvision.ga</groupId>
    <artifactId>artemis-http-client</artifactId>
    <version>1.1.3</version>
</dependency>

java文件

package com.landy.framework.web.controller;
// 引入类
import com.alibaba.fastjson.JSONObject;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import com.landy.framework.common.Response; //自定义 Spring Boot 相应包
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

获取监控列表

@RestController
@RequestMapping("/api/camera")
@Api(tags = "1-海康威视接口")
@ApiSupport(order = 1)
public class TWaternetCameraController {

    @ApiOperation(value = "1-查询视频列表", notes = "调用海康威视接口查询视频列表")
    @GetMapping("/cameraSearch")
    public Response cameraSearch(Integer pageNo, Integer pageSize) {
        return Response.ok(this.GetCameraPreviewURL("/api/resource/v2/encodeDevice/search", null, pageNo, pageSize));
    }

    @ApiOperation(value = "2-查询摄像头视频流", notes = "调用海康威视接口查询摄像头视频流")
    @GetMapping("/cameraPreviewUrl")
    public Response cameraPreviewUrl(String cameraCode) {
        return Response.ok(this.GetCameraPreviewURL("/api/video/v1/cameras/previewURLs", cameraCode, null, null));
    }

    public String GetCameraPreviewURL(String url, String indexCodes, Integer pageNo, Integer pageSize) {
    	/*
    		url 根据官方文档或提供接口切换
    	*/
    	
        /**
         * STEP1:设置平台参数,根据实际情况,设置host appkey appsecret 三个参数.
         * {appkey:"******",secret:"******",ip:"***",port:***
         */
        ArtemisConfig.host = "ip:port"; // artemis网关服务器ip端口
        ArtemisConfig.appKey = "******"; // 秘钥appkey
        ArtemisConfig.appSecret = "******";// 秘钥appSecret

		/**
		* 两种都可
		*
		  ArtemisConfig artemisConfig = new ArtemisConfig();
          artemisConfig.setHost("ip:port"); //平台(nginx)IP和端口
          artemisConfig.setAppKey("******"); //合作方key
          artemisConfig.setAppSecret("******");//合作方Secret
		*/
		
        /**
         * STEP2:设置OpenAPI接口的上下文
         */
        final String ARTEMIS_PATH = "/artemis";

        /**
         * STEP3:设置接口的URI地址
         */
        final String previewURLsApi = ARTEMIS_PATH + url;

        Map<String, String> path = new HashMap<String, String>(2) {
            {
                put("https://", previewURLsApi);//根据现场环境部署确认是http还是https
            }
        };

        /**
         * STEP4:设置参数提交方式
         */
        String contentType = "application/json";

        /**
         * STEP5:组装请求参数
         */
        JSONObject jsonBody = new JSONObject();

         // jsonBody.put("userId", "***");
        // jsonBody.put("cameraIndexCode", "***");
        // jsonBody.put("streamType", 0);
        // jsonBody.put("protocol", "rtsp");
        // jsonBody.put("transmode", 1);
        // jsonBody.put("expand", "streamform=ps");

        if (StringUtils.isNotBlank(indexCodes)) {
            // jsonBody.put("cameraIndexCode", new String[]{indexCodes});
            jsonBody.put("cameraIndexCode", indexCodes);
            jsonBody.put("protocol", "rtsp");
        } else {
            if (pageNo == null) {
                pageNo = 1;
            }
            if (pageSize == null) {
                pageSize = 1000;
            }
            jsonBody.put("pageNo", pageNo);
            jsonBody.put("pageSize", pageSize);
        }
        String body = jsonBody.toJSONString();

        /**
         * STEP6:调用接口
         */
        String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null,
                contentType, null);// post请求application/json类型参数
        return result;
    }
}

ffmpeg转换视频流

视频流可获取 hls 格式不需要转换

java文件

package com.landy.framework.web.controller;
// 引入类
import com.alibaba.fastjson.JSONObject;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import com.landy.framework.common.Response; //自定义 Spring Boot 相应包
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

视频流转换

使用ffmpeg转换视频流 可自定义转换格式

@RestController
@RequestMapping("/api/camera")
@Api(tags = "2-视频流转换")
@ApiSupport(order = 1)
public class videoStreamController {

    private FileUtil fileUtil;
    @Value("${mapFile.path}")  // 存储地址
    private String filePath;
    @Value("${mapFile.address}") // 外层文件夹名
    private String address;
    @Value("${mapFile.ip}")  // 映射ip
    private String ip;

    @ApiOperation(value = "1-RTSP转HLS视频流", notes = "调用FFmpeg转视频流")
    @GetMapping("/changePreviewUrl")
    public Response changePreviewUrl(String rtspUrl, String codeName) {
        this.stopFFmpeg();
        return Response.ok(this.GetCameraPreviewURL(rtspUrl, codeName));
    }

    @ApiOperation(value = "2-停止视频流转换", notes = "停止FFmpeg转视频流")
    @GetMapping("/stopPreviewUrl")
    public Response stopPreviewUrl() {
        return Response.ok(this.stopFFmpeg());
    }

    private Process ffmpegProcess;
    private String outputName = "";

    public String GetCameraPreviewURL(String url, String codeName) {
        // 工作目录
        String currentPath = System.getProperty("user.dir");
        // 获取当前类的路径
        // String classPath = GetClassPathExample.class.getResource("/").getPath();
        // 获取类路径中的资源文件路径
        // JAR 包中,它将返回 null
        // String resourcePath = GetResourcePathExample.class.getClassLoader().getResource("example.txt").getPath();

         this.getFilePath();

        // RTSP 输入 URL 和 HLS 输出设置
        String rtspUrl = "rtsp://your_rtsp_stream_url";
        rtspUrl = url;
        /*
        	url: "rtsp://用户名:密码@ip:port/Streaming/Channels/101"; // 密码不能有@
        	url: "rtsp:ip:port/openUrl/U7p2Rgl // 获取摄像头对应的rtsp地址
        */
        // 
        if (StringUtils.isNotBlank(codeName)) {
            int nameIdx =  codeName.lastIndexOf("\\");
            outputName = codeName;
            if (nameIdx != -1) {
                outputName = codeName.substring(0, nameIdx);
            }
        }
        String outputPath = filePath.replaceAll("/", "\\\\") + outputName + ".m3u8";
        //outputPath = "D:\\apache-tomcat-8\\webapps\\output\\" + outputName + ".m3u8";

        // FFmpeg 命令
        String[] command = {
                "ffmpeg",
                "-i", rtspUrl,
                "-c:v", "libx264",
                "-preset", "fast",
                "-crf", "20",
                "-c:a", "aac",
                "-b:a", "128k",
                "-f", "hls",
                "-hls_time", "10",
                "-hls_list_size", "10",
                "-hls_flags", "delete_segments",
                outputPath
        };

        String result = "";
        try {
            // 创建 ProcessBuilder 实例
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            processBuilder.redirectErrorStream(true);

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

            /*
            // 读取并打印 FFmpeg 的输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;

            //reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));

            System.out.println(reader.readLine());

            while ((line = reader.readLine()) != null) {
                if (result == "") {
                    result = "/output/"+outputName+".m3u8";
                    System.out.println(line);
                }
            }
             */

            result = "/file/"+outputName+".m3u8";

            //new Thread(() -> {
                String line = "";
                File dir = new File(outputPath);
                int j = 0;
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(ffmpegProcess.getInputStream()))) {
					// 生成文件后返回视频路径
                    while (line != null || dir.exists()) {
                        line = reader.readLine();
                        dir = new File(outputPath);
                        System.out.println("line " + Integer.toString(j) + line);
                        System.out.println("dire " + Integer.toString(j) + " " + dir.exists());
                        if (line == null || dir.exists()) break;
                        j++;
                    }

                    if (line != null) return  result;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            //}).start();

            // 等待进程结束
            int exitCode = ffmpegProcess.waitFor();
            result = Integer.toString(exitCode);
            System.out.println("FFmpeg exited with code " + exitCode);
            ffmpegProcess = null;
            outputName = "";
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        return result;
    }

    public String stopFFmpeg() {
    	// 单进程
        String result = "false";
        if (ffmpegProcess != null) {
            ffmpegProcess.destroy(); // 终止FFmpeg进程
            System.out.println("FFmpeg process stopped.");
            ffmpegProcess = null;
            result = "true";
        }
        if (outputName != "") {
            this.delFileInPath();
            outputName = "";
        }
        return result;
    }


    /**
     * 判断创建文件
     * */
    public void getFilePath() {
        // 创建目录
        File dir = new File(filePath);
        boolean start = dir.exists();
        if (!dir.exists()) {
            dir.mkdirs();
            start = dir.exists();
        }
        System.out.println(start);
    }
    /**
     * 删除文件夹下的文件
     * */
    public void delFileInPath() {
        File directory = new File(filePath);

        // 检查目录是否存在并且是一个目录
        if (directory.exists() && directory.isDirectory()) {
            // 获取目录中的所有文件和子目录
            File[] files = directory.listFiles();

            if (files != null) {
                for (File file : files) {
                    if (file.isFile()) {
                        if (outputName != "") {
                            if (file.getName().indexOf(outputName) != -1) {
                                file.delete();
                            }
                        } else {
                            System.out.println("文件: " + file.getName());
                        }
                    } else if (file.isDirectory()) {
                        System.out.println("目录: " + file.getName());
                    }
                }
            } else {
                System.out.println("无法列出目录中的文件");
            }
        } else {
            System.out.println("指定的路径不是一个有效的目录");
        }
    }
}

导入

标签:java,String,jsonBody,rtsp,hls,new,import,null
From: https://blog.csdn.net/qq_46551351/article/details/142763680

相关文章

  • javascript学习——CSS 操作总结
    CSS操作CSS与JavaScript是两个有着明确分工的领域,前者负责页面的视觉效果,后者负责与用户的行为互动。但是,它们毕竟同属网页开发的前端,因此不可避免有着交叉和互相配合。本章介绍如何通过JavaScript操作CSS。HTML元素的style属性操作CSS样式最简单的方法,就是......
  • javascript学习——DOM 概述
    DOM概述DOMDOM是JavaScript操作网页的接口,全称为“文档对象模型”(DocumentObjectModel)。它的作用是将网页转为一个JavaScript对象,从而可以用脚本进行各种操作(比如增删内容)。浏览器会根据DOM模型,将结构化文档(比如HTML和XML)解析成一系列的节点,再由这些节点组......
  • Java开发之JDK下载
    JDK是什么?JDK(JavaDevelopmentKit)是Java开发工具包,包含了编译、运行Java程序所需的工具和环境。如何下载JDK?访问Oracle官网:打开Oracle的Java官网:JavaDownloads|Oracle选择适合的版本:根据你的操作系统(Windows、macOS、Linux)和项目需求选择合适的JDK版本。一般来说,选......
  • 基于数据可视化+Javaweb实现的物流管理系统设计与实现(源码+数据库+论文+部署+文档+讲
    文章目录前言系统演示录像论文参考代码运行展示图技术框架SpringBoot技术介绍系统测试系统测试的目的系统功能测试推荐选题:代码参考实现案例找我做程序,有什么保障?联系我们前言......
  • 基于数据可视化+Java+SpringBoot+Vue实现的高校食堂移动预约点餐系统设计与实现
    文章目录前言系统演示录像论文参考代码运行展示图技术框架SpringBoot技术介绍系统测试系统测试的目的系统功能测试推荐选题:代码参考实现案例找我做程序,有什么保障?联系我们前言......
  • java学习笔记3-高级循环-练习题
    黑马java有关数组的几道感觉比较难的题目,记录一下。第一题现有一个整数数组,数组中的每个元素都是[0-9]之间的数字,从数组的最大索引位置开始到最小索引位置,依次表示整数的个位、十位、百位。。。依次类推。请编写程序计算,这个数组所表示的整数值。例如:数组:{2,1,3,5,4}......
  • JAVA面试八股文(上)
    Object有哪些方法?hashcode,equals,wait(), tostringhashcode和equals有什么关系?Java中规定,hashcode相同equals不一定相同,equals相同那么hashcode一定相同,如果违反这种规则hashMap和hashSet不能正常使用wait和sleep有什么区别?sleep()方法线程不会释放对象锁,wait()方法线......
  • java JNDI 注入学习
    javaJNDI注入学习JavaNamingDirectoryInterface,Java命名和目录接口,是SUN公司提供的一种标准的Java命名系统接口。通过调用JNDI的API应用程序可以定位资源和其他程序对象。JNDI可访问的现有目录及服务包括:JDBC(Java数据库连接)、LDAP(轻型目录访问协议)、RMI(远程方法调用)、DNS(域......
  • Java多线程编程基础与高级特性
    在现代软件开发中,多线程编程是一个重要的概念,它能够充分利用多核处理器的能力,提高程序的执行效率。Java语言内置了对多线程的支持,使得开发者可以方便地创建和管理线程。创建线程1.继承Thread类这是最直接的方式,通过创建一个继承自Thread类的子类,并重写run()方法来定义线程......
  • 2024年Java最新面试题总结(五年经验)
    第一章、基础技术栈1.1)集合,string等基础问题1、arraylist,linkedlist的区别,为啥集合有的快有的慢①ArrayList它的底层是数组,有下标的概念,可以通过index下标直接定位元素,所以查询快;在增删时,会进行扩容判断和拷贝,所以增删慢。②LinkedList的底层是双向链表。每次查询都要循环......