Java使用WebSocket视频拆帧进度处理与拆帧图片推送,结合Apipost进行调试

news2025/4/16 9:17:51
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
@Configuration
public class WebSocketConfig {
    /**
     * 启动 WebSocket 服务器
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

webSocket拆帧进度推送

/**
 * 请求连接路径 ws://127.0.0.1:4000/ws/sp/677b4046371de933500ae72bc03bf70b
 *
 * @author zym
 * date:  2025-04-14 18:58
 */
@Component
@ServerEndpoint("/ws/sp/{md5}") // WebSocket 连接端点
public class WebSocketSplitFrame {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    // 存储所有用户的 WebSocket 连接
    private static final Map<String, Session> clients = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("md5") String md5) {
        clients.put(md5, session);
        logger.info("当前拆帧连接视频数量:{}", clients.size());
    }

    /**
     * 接收消息
     *
     * @param md5AndNum 9b60f7c6ef241ceb7076f8f241c62a22:1200
     */
    @OnMessage
    public int onMessage(String md5AndNum) throws InterruptedException {
        String[] split = md5AndNum.split(":", 2);
        String md5 = split[0];//拆帧视频的MD5值
        Integer num = Integer.valueOf(split[1]);//视频的总帧数
        File sfUiFile = FileUtil.getSfUiFile();
        File splitFrameFile = new File(sfUiFile.getPath() + File.separator + md5);
        int length = 0;
        while (num != length) {
            length = splitFrameFile.listFiles().length;
            Thread.sleep(400);
            sendFrameNum(md5, length);//推送当前拆帧的图片数量
        }
        logger.info("素材已拆帧数完毕 md5:{} num:{}", md5, length);
        return length;
    }


    /**
     * 发送视频帧数
     *
     * @param md5 拆帧视频的MD5值
     * @param num 拆帧数量
     */
    public void sendFrameNum(String md5, int num) {
        Session session = clients.get(md5);
        if (session != null) {
            try {
                session.getBasicRemote().sendText(num + "");
            } catch (IOException e) {
                logger.error("sendFrameNum e:{}", e.getMessage());
            }
        } else {
            logger.info("[sendFrameNum]视频拆帧已完毕:{}", md5);
        }
    }

    @OnClose
    public void onClose(@PathParam("md5") String md5) {
        Session session = clients.get(md5);
        StreamClose.close(session);
        clients.remove(md5);
        logger.info("[onClose]视频拆帧已完毕断开连接:{}", md5);
    }
    
}

在这里插入图片描述

在这里插入图片描述

WebSocket图片推送

/**
 * 请求连接路径 ws://127.0.0.1:4000/ws/fp/677b4046371de933500ae72bc03bf70b
 *
 * @author zym
 */
@Component
@ServerEndpoint("/ws/fp/{md5}") // WebSocket 连接端点
public class WebSocketFramePic {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    // 存储所有用户的 WebSocket 连接
    private final Map<String, Session> clients = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("md5") String md5) {
        clients.put(md5, session);
        logger.info("获取拆帧图连接数量:{}", clients.size());
    }

    /**
     * 接收消息,消息为MD5值
     *
     * @param md5 9b60f7c6ef241ceb7076f8f241c62a22
     */
    @OnMessage
    public int onMessage(String md5) throws InterruptedException {
        File splitFrameFile = new File(FileUtil.getSfUiFile().getPath() + File.separator + md5);
        //获取视频拆帧后的图片文件夹,根据图片名称进行排序
        LinkedList<File> mergePicFiles = Arrays.stream(splitFrameFile.listFiles())
                .sorted(Comparator.comparingInt(x -> Integer.parseInt(x.getName().substring(0, x.getName().lastIndexOf(".")))))
                .collect(Collectors.toCollection(LinkedList::new));
        List<String> pics = new ArrayList<>();
        for (File mergePicFile : mergePicFiles) {
            byte[] bytes = FileUtil.getFileBytes(mergePicFile);
            String base64str = Base64.encodeBase64String(bytes);
            String picBase64 = "data:image/jpeg;base64," + base64str;
            pics.add(picBase64);
            if (pics.size() == 30) {//单次传输图片最多30张
                Thread.sleep(1000);
                sendFramePic(md5, pics);//推送图片
                pics = new ArrayList<>();
            }
        }
        logger.info("获取素材已拆帧图片 md5:{} num:{}", md5, mergePicFiles.size());
        return mergePicFiles.size();
    }


    /**
     * 发送视频帧片
     *
     * @param md5  拆帧视频的MD5值
     * @param pics 图片
     */
    public void sendFramePic(String md5, List<String> pics) {
        Session session = clients.get(md5);
        if (session != null) {
            try {
                String text = JSONArray.toJSONString(pics);
                session.getBasicRemote().sendText(text);
            } catch (Exception e) {
                logger.error("sendFramePic e:{}", e.getMessage());
            }
        } else {
            logger.info("[sendFrameNum]视频拆帧已完毕:{}", md5);
        }
    }

    @OnClose
    public void onClose(@PathParam("md5") String md5) {
        Session session = clients.get(md5);
        StreamClose.close(session);
        clients.remove(md5);
        logger.info("[onClose]拆帧图片推送已完毕断开连接:{}", md5);
    }
    
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2335851.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算斐波那契数列

1.对于斐波那契数列的理解&#xff1a; (1)常规 该数列由兔子繁衍的想法产生&#xff0c;故又“兔子数列” 其数值为&#xff1a;1、1、2、3、5、8、13、21、34 从数学定义上走&#xff1a;F(0)1&#xff0c;F(1)1, F(n)F(n - 1)F(n - 2)&#xff08;n ≥ 2&#xff0c;n ∈…

JAVA如何操作文件?(超级详细)

目录 一、认识文件和相关知识 1.认识文件 2.⽬录 3.⽂件路径&#xff08;Path&#xff09; 4.文本文件和二进制文件的区分 二、File类操作文件 1.构造方法 2.方法 2.1 方法表 2.2 get相关的方法和构造方法 2.2.1 “.” 和 “..” 2.3 is相关的方法 2.4 删除相关…

(2)VTK C++开发示例 --- 绘制多面锥体

文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;VTK开发 &#x1f448; 1. 概述 VTK C开发示例程序&#xff1b; 使用C 和VTK绘制一个多面锥体。 环境说明系统ubuntu22.04、windows11cmake3.22、3.2…

(2025-04-12)向老主机箱中安装新买的显卡及固态硬盘

目录 1 引言2 显卡及其驱动的安装3 固态硬盘的安装及C盘扩容3.1 固态硬盘正确连接到主板上后&#xff0c;操作系统上面仍然不显示对应盘符怎么办&#xff1f;3.2 如何对C盘扩容&#xff1f;3.3 新问题&#xff1a;原有D盘程序不能运行 4 总结 1 引言 今天安装昨天买的新固态硬…

rk3588 驱动开发(一)字符设备开发

3.字符设备驱动开发 3.1 什么是字符设备驱动 字符设备&#xff1a;就是一个个字节&#xff0c;按照字节流进行读写操作的设备&#xff0c;读写是按照先后顺序的。 举例子&#xff1a;IIC 按键 LED SPI LCD 等 Linux 应用程序调用驱动程序流程&#xff1a; Linux中驱动加载成功…

AbMole| 体内相互作用筛选揭示肝脏对癌症转移的限制

癌症转移&#xff0c;作为导致患者死亡的主要原因之一&#xff0c;其复杂机制一直是医学界研究的热点。肝脏&#xff0c;作为癌症转移的常见靶器官&#xff0c;其微环境对癌症细胞的生长和转移具有重要影响。然而&#xff0c;肝脏如何限制癌症转移的具体机制尚不完全清楚。 来…

STM32移植文件系统FATFS——片外SPI FLASH

一、电路连接 主控芯片选型为&#xff1a;STM32F407ZGT6&#xff0c;SPI FLASH选型为&#xff1a;W25Q256JV。 采用了两片32MB的片外SPI FLASH&#xff0c;电路如图所示。 SPI FLASH与主控芯片的连接方式如表所示。 STM32F407GT6W25Q256JVPB3SPI1_SCKPB4SPI1_MISOPB5SPI1_MOSI…

2025年第十六届蓝桥杯省赛JavaB组真题回顾

第16届蓝桥杯省赛已经结束了&#xff0c;第一次参加也是坐牢了4个小时&#xff0c;现在还是来总结一下吧&#xff08;先声明以下的解法&#xff0c;大家可以当作一种思路来看&#xff0c;解法不一定是正解&#xff0c;只是给大家提供一种能够正常想到的思路吧&#xff09; 试题…

Android 接口定义语言 (AIDL)

目录 1. 本地进程调用(同一进程内)2. 远程进程调用(跨进程)3 `oneway` 关键字用于修改远程调用的行为Android 接口定义语言 (AIDL) 与其他 IDL 类似: 你可以利用它定义客户端与服务均认可的编程接口,以便二者使用进程间通信 (IPC) 进行相互通信。 在 Android 上,一个进…

c# 数据结构 链表篇 有关双向链表的一切

本人能力有限,如有不足还请斧正 目录 0.双向链表的好处 1.双向链表的分类 2.不带头节点的标准双向链表 节点类:有头有尾 链表类:也可以有头有尾 也可以只有头 增 头插 尾插 删 查 改 遍历 全部代码 3.循环双向链表 节点类 链表类 增 头插 尾插 删 查 遍历…

660 中值定理

文章目录 前言168169170总结 前言 background music: 《代替》 张叶蕾 660 上面没有专门的中值定理章节&#xff0c;我蒙了。不过应该可以找一下。就是证明题&#xff0c;标志性应该还行。找一下。然后做一下。660 的题质量应该还是非常高的。但是积分中值定理&#xff0c;还有…

Elasticsearch:AI 助理 - 从通才到专才

作者&#xff1a;来自 Elastic Thorben Jndling 在 AI 世界中&#xff0c;关于构建针对特定领域定制的大型语言模型&#xff08;large language models - LLM&#xff09;的话题备受关注 —— 不论是为了更好的安全性、上下文理解、专业能力&#xff0c;还是更高的准确率。这个…

数据结构——布隆过滤器

目录 一、什么是布隆过滤器&#xff1f; 二、布隆过滤器的原理 三、布隆过滤器的特点 一、什么是布隆过滤器&#xff1f; 布隆过滤器是一种空间效率高、适合快速检索的数据结构&#xff0c;用于判断一个元素是否可能存在于一个集合中。它通过使用多个哈希函数和一个位数组来…

机器学习常用算法总结

1. 概述 机器学习的定义是对于某类任务T和性能度量P&#xff0c;如果一个计算机程序在T上其性能P随着经验E而自我完善&#xff0c;那么我们就称这个系统从经验E中学习&#xff0c;机器学习是人工智能的一种方法&#xff0c;它通过在大量数据中学习隐藏的规则&#xff0c;模式和…

关于香橙派OrangePi 5 Ultra 这个开源板子,开发Android

我下载了它资料中的开源Android13 系统SDK&#xff0c; 这个SDK连个git 都没有&#xff0c;把这种代码释放能称为开源吗&#xff1f;&#xff1f; 并且也就是说你买了这个板子&#xff0c;里面是没有任何关于RK3588的开发文档&#xff0c;如果你没玩过其他RK平台&#xff0c;估…

ubuntu启动 Google Chrome 时默认使用中文界面,设置一个永久的启动方式

方法 &#xff1a;通过桌面快捷方式设置 编辑 Chrome 的桌面快捷方式&#xff1a; 找到您的 Google Chrome 快捷方式文件。如果是通过菜单启动&#xff0c;通常会在以下路径找到与 Chrome 相关的 .desktop 文件&#xff1a; sudo vim /usr/share/applications/google-chrome.d…

字节跳动开源 Godel-Rescheduler:适用于云原生系统的全局最优重调度框架

背景 在云原生调度中&#xff0c;一次调度往往无法解决所有问题&#xff0c;需要配合重调度来优化资源分配和任务摆放。传统的重调度框架主要集中在识别异常节点或任务&#xff0c;并通过迁移或删除来解决。然而&#xff0c;这些框架往往只能解决局部问题&#xff0c;无法提供…

【大模型实战篇】--阿里云百炼搭建MCP Agent

MCP协议&#xff08;Model Communication Protocol&#xff0c;模型通信协议&#xff09;是大语言模型&#xff08;LLM&#xff09;与外部系统或其他模型交互时的一种标准化通信框架&#xff0c;旨在提升交互效率、安全性和可扩展性。 目录 1.阿里云百炼--MCP 1.1.MCP 服务接…

基于PySide6与pycatia的CATIA智能倒角工具开发全解析

引言&#xff1a;工业设计中的倒角革命 在机械设计领域&#xff0c;倒角操作是零件加工前的必要工序。传统手动操作效率低下且易出错本文基于PySide6pycatia技术栈&#xff0c;提出一种支持批量智能倒角、参数动态校验、跨层级操作的自动化方案&#xff0c;其核心突破体现在&a…

css 二维码始终显示在按钮的正下方,并且根据不同的屏幕分辨率自动调整位置

一、需求 “求职入口” 下面的浮窗位置在其正下方&#xff0c;并且浏览器分辨的改变&#xff08;拖动浏览器&#xff09;&#xff0c;位置依旧在最下方 二、实现 <div class"btn_box"><div class"btn_link id"js-apply">求职入口<di…