当前位置: 首页 > news >正文

Vue3 中集成海康 H5 监控视频播放功能

​🌈个人主页:前端青山
🔥系列专栏:Vue篇
🔖人终将被年少不可得之物困其一生

依旧青山,本期给大家带来Vuet篇专栏内容:Vue-集成海康 H5 监控视频播放功能

目录

一、引言

二、环境搭建

三、代码解析

子组件部分

1. 导入模块和组件

2. 定义组件属性和事件

3. 初始化变量

4. 初始化视频插件

5. 控制分屏数量

6. 视频线路弹框按钮

7. 生命周期钩子

8. 初始化视频播放

9. 处理事件

10.调用插件播放

父组件调用

一、引言

随着视频监控技术的发展,许多应用场景需要集成实时视频监控功能。本文将详细介绍如何在 Vue 3 应用中集成海康 H5 监控视频播放功能,实现视频的实时播放、分屏显示以及全屏切换等功能。

二、环境搭建

为了确保代码能够正常运行,我们需要准备以下开发环境:

  • Vue 3:用于构建前端应用。

  • Element Plus:用于 UI 组件库。

  • 海康 H5 SDK:用于播放视频流。

三、代码解析

子组件部分

<template><div class="play_windows" v-loading="loading" element-loading-background="rgba(122, 122, 122, 0.8)"><div class="tree-form"><el-treeref="tree":data="dataTree":props="defaultProps":highlight-current="true"@node-click="pitchOns"><template #default="{ node, data }"><span class="custom-tree-node">{{ data.name }}</span></template></el-tree></div><div class="video"><div class="dialog-slot-video-header-right"><el-button class="myButton" :class="{ 'active': videoIndex == 4 }" @click="videoTabClick(4)">1×1</el-button><el-button class="myButton" :class="{ 'active': videoIndex == 1 }" @click="videoTabClick(1)">3×3</el-button><el-button class="myButton" :class="{ 'active': videoIndex == 2 }" @click="videoTabClick(2)">4×4</el-button><el-button class="myButton" :class="{ 'active': videoIndex == 3 }" @click="videoTabClick(3)">整体全屏</el-button></div><div id='corpvideo'></div></div></div>
</template>
  • 功能说明

    • play_windows 容器:包含两个主要部分,左侧为树形结构,右侧为视频播放区域。

    • el-tree 组件:展示监控设备树形结构,点击节点触发 pitchOns 方法。

    • 视频播放区域:通过按钮控制不同的分屏模式(1×1、3×3、4×4)及全屏模式。

    • id='corpvideo':指定视频播放容器的 ID,供 H5 SDK 使用。

1. 导入模块和组件
import { ref, onMounted, nextTick, defineProps, defineExpose, defineEmits, watch, onBeforeUnmount } from 'vue';
import { ElMessage } from 'element-plus';
import { videoallList } from '@/api/screenVideo/index';
import { getGetByCode } from '@/api/videoSurveillance/index';
  • 功能说明:导入了 Vue 的一些核心函数,如 refonMountednextTick 等,以及 Element Plus 的消息提示组件 ElMessage 和相关 API。

2. 定义组件属性和事件
const emit = defineEmits(["handleSpjkPOIClick"]);
const props = defineProps({playURL: String, // 视频 URLsplitNum: Number, // 分屏播放,默认最大分屏 4*4dataTree: Object, // 树形数据defaultProps: Object
});
  • 功能说明:定义了组件的属性 props 和自定义事件 emit,用于接收父组件传递的数据和触发事件。

3. 初始化变量
let dataTree = ref<any>(props.dataTree);
let defaultProps = ref<any>(props.defaultProps);
let loading = ref<Boolean>(false);
let myPlugin = ref<any>(null);
let index = ref<any>(1); // 多屏播放显示第几个
let mode = ref<any>(1); // 0 为低级播放,1 为高级播放
const urlList = ref<any>([]);
let playURLs = ref<any>("");
const jsPlugin = (window as any).JSPlugin;
  • 功能说明:定义了一些响应式变量,用于存储数据和状态,如 loading 用于控制加载状态,myPlugin 用于存储视频插件实例。

4. 初始化视频插件
const myPlugins = () => {myPlugin.value = new jsPlugin({szId: 'corpvideo', // 需要英文字母开头,唯一性,必填szBasePath: '/h5player', // 必填,与 h5player.min.js 的引用目录一致bSupporDoubleClickFull: true, // 是否支持双击全屏,默认 trueiMaxSplit: 4, // 分屏播放,默认最大分屏 4*4iCurrentSplit: splitNum.value,oStyle: {borderSelect: '#FFCC00',},openDebug: true,});
};
  • 功能说明:定义了一个方法 myPlugins,用于初始化视频插件实例,并配置相关参数。

5. 控制分屏数量
const tabPosition = ref<any>(1);
const playBackNum = (num: any) => {if (num == "3") {myPlugin.value.JS_FullScreenDisplay(true).then(() => { console.log(`wholeFullScreen success`) },(e: any) => { console.error(e) });return;}if (num == splitNum.value) {return;}splitNum.value = num;
};
  • 功能说明:定义了一个方法 playBackNum,用于控制分屏数量,并支持全屏显示。

6. 视频线路弹框按钮
const splitNum = ref<any>(1);
const videoIndex = ref<number>(4); // 视频信息弹框默认值 index
const videoTabClick = (type: number) => {videoIndex.value = Number(type);if (type == 1) {splitNum.value = 3;const totalWindows = splitNum.value * splitNum.value;for (let i = 0; i < totalWindows; i++) {const url = urlList.value[i] || urlList.value[0];myPlugin.value.JS_Play(url, { playURL: url, mode: mode.value }, i).then(() => console.log(`Playing in window ${i}`),(e: any) => console.error('Error playing video', e));}} else if (type == 2) {splitNum.value = 4;const totalWindows = splitNum.value * splitNum.value;for (let i = 0; i < totalWindows; i++) {const url = urlList.value[i] || urlList.value[0];myPlugin.value.JS_Play(url, { playURL: url, mode: mode.value }, i).then(() => console.log(`Playing in window ${i}`),(e: any) => console.error('Error playing video', e));}} else if (type == 3) {myPlugin.value.JS_FullScreenDisplay(true).then(() => { console.log(`wholeFullScreen success`) },(e: any) => { console.error(e) });return;} else if (type == 4) {splitNum.value = 1;}myPlugin.value.JS_ArrangeWindow(splitNum.value).then(() => { console.log(`arrangeWindow to ${splitNum.value}x${splitNum.value} success`) },(e: any) => { console.error(e) });console.log(splitNum.value, '监控视频的值');
};
  • 功能说明:定义了一个方法 videoTabClick,用于控制视频线路弹框按钮,并根据不同的类型调整分屏数量和播放视频。

7. 生命周期钩子
onMounted(() => {nextTick(() => {myPlugins();// 事件回调绑定myPlugin.value.JS_SetWindowControlCallback({windowEventSelect: function (iWndIndex: any) { // 插件选中窗口回调console.log('windowSelect callback: ', iWndIndex);},pluginErrorHandler: function (iWndIndex: any, iErrorCode: any, oError: any) { // 插件错误回调console.log('pluginError callback: ', iWndIndex, iErrorCode, oError);},windowEventOver: function (iWndIndex: any) { // 鼠标移过回调// console.log(iWndIndex);},windowEventOut: function (iWndIndex: any) { // 鼠标移出回调// console.log(iWndIndex);},windowEventUp: function (iWndIndex: any) { // 鼠标mouseup事件回调// console.log(iWndIndex);},windowFullCreenChange: function (bFull: any) { // 全屏切换回调console.log('fullScreen callback: ', bFull);},firstFrameDisplay: function (iWndIndex: any, iWidth: any, iHeight: any) { // 首帧显示回调console.log('firstFrame loaded callback: ', iWndIndex, iWidth, iHeight);},performanceLack: function () { // 性能不足回调console.log('performanceLack callback: ');}});});
});
​
onBeforeUnmount(() => {console.log('切换了');
});
  • 功能说明:在组件挂载时初始化视频插件,并绑定事件回调。在组件卸载前执行清理操作。

8. 初始化视频播放
const initialize = (playURL: any, urls?: any[]) => {urlList.value = urls;playURLs.value = playURL;loading.value = true;index.value = myPlugin.value.currentWindowIndex;myPlugin.value.JS_Play(playURL, { playURL, mode: mode.value }, index.value).then(() => { loading.value = false }, // 成功操作(e: any) => { loading.value = false;ElMessage.error('监控视频异常'); // 失败操作});
};
  • 功能说明:定义了一个方法 initialize,用于初始化视频播放,并处理加载状态和错误提示。

9. 处理事件
const pitchOns = (e: any) => {if (!e || !e.self) {if (e.equipmentCoding) {handleAddChild(e);}return;}if (e.children) {emit("handleSpjkPOIClick", e.self.indexCode, '');return;} else {handleAddChild(e);}
};const handleAddChild = (e: any) => {if (!e || !e.self) {if (e.equipmentCoding) {videoUrl(e.equipmentCoding);}return;}if (e.self.indexCode) {let params = {UnitIndexCode: e.self.indexCode,};videoallList(params).then((res: any) => {if (res.data.rows.length == 0) {emit("handleSpjkPOIClick", e.self.indexCode, '');} else {e.children = e.children || [];// 修改 res.data.rows 中所有数据对象的字段 equipmentName 变成 nameres.data.rows = res.data.rows.map((child: any) => ({...child,name: child.equipmentName, // 将 equipmentName 字段复制到 name 字段// 删除原 equipmentName 字段}));res.data.rows.forEach((child: any) => {e.children.push(child);});// 展开当前节点(e as any).expanded = true;}})}
}
10.调用插件播放
const videoUrl =(e:any)=>{let params = {equipmentCoding: e,};getGetByCode(params).then(res => {setTimeout(() => {initialize(res.data.url);}, 1);});
}// 使用 watch 监听 splitNum 的变化watch(splitNum, (newValue, oldValue) => {if (newValue !== oldValue) {myPlugins();myPlugin.value.JS_ArrangeWindow(splitNum.value).then(() => { console.log(`arrangeWindow to ${splitNum.value}x${splitNum.value} success`) },(e: any) => { console.error(e) })}
});
//最后暴露方法defineExpose({initialize,myPlugins})

父组件调用

<template><div><ScreenMonitoring ref="screenmonitoring" :dataTree="dataTree" :defaultProps="defaultProps" @handleSpjkPOIClick="handleSpjkPOIClick" /></div>
</template><script setup>
import { ref, onMounted, nextTick } from 'vue';const dataTree = ref<any>([]);
const dataTree1 = ref<any>([]);
let screenmonitoring = ref();
const defaultProps = {children: 'children',label: 'name',
};onMounted(() => {nextTick(() => {let params = {};getTreeJson(params).then((res: any) => {let list = res.rows[0].children[9].children;list.forEach((item: any) => {extractNameAndRebuildTree(item);  // 对每个根节点执行递归提取});dataTree.value = list;  // 将处理后的列表赋值给 dataTree});});
});const extractNameAndRebuildTree = (node: any) => {// 如果节点有 self,提取 name 并放在最外层if (node.self && node.self.name) {node.name = node.self.name;}// 如果节点有 children,递归处理每个子节点if (node.children && node.children.length > 0) {node.children.forEach((child: any) => {extractNameAndRebuildTree(child);});}
};
const handleSpjkPOIClick = (poiId: string, coord: string) => {let params = {UnitIndexCode: poiId,};getGetByCodes(params).then((res: any) => {setTimeout(() => {screenmonitoring.value.initialize(res.data.urls[0], res.data.urls);}, 1);});
};
</script>
  1. 初始化数据树

    • dataTreedataTree1 是两个响应式数组,用于存储处理后的数据。

    • screenmonitoring 是一个引用,用于指向 ScreenMonitoring 子组件的实例。

    • defaultProps 是传递给子组件的默认属性配置。

  2. 组件挂载时

    • nextTick():等待 DOM 更新完成后再执行后续操作。

    • getTreeJson(params):从服务器获取数据,并处理返回的数据。

    • extractNameAndRebuildTree(item):递归处理每个节点,提取 name 并放在最外层。

  3. 处理点击事件

    • handleSpjkPOIClick(poiId, coord):当点击某个 时,获取对应的视频 URL 并初始化视频播放。

    • getGetByCodes(params):从服务器获取视频 URL 数据。

    • setTimeout(() => { ... }, 1):延迟 1 毫秒后初始化视频播放。

通过这种方式,父组件能够有效地初始化数据树,并在点击 树状 时触发视频播放。

本文旨在详细介绍如何在 Vue 3 应用中集成海康 H5 监控视频播放功能,实现视频的实时播放、分屏显示以及全屏切换等功能。

相关文章:

Vue3 中集成海康 H5 监控视频播放功能

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vuet篇专栏内容:Vue-集成海康 H5 监控视频播放功能 目录 一、引言 二、环境搭建 三、代码解析 子组件部分 1.…...

Linux: eBPF: libbpf-bootstrap-master 编译

文章目录 简介编译运行展示输出展示:简介 这个是使用libbpf的一个例子; 编译 如果是一个可以联网的机器,这个libbpf-bootstrap的编译就方便了,完全是自动化的下载依赖文件;如果没有,就只能自己准备这些个软件。 需要:libbpf-static; [root@RH8-LCP c]# makeLIB …...

1.1.4 计算机网络的分类

按分布范围分类&#xff1a; 广域网&#xff08;wan&#xff09; 城域网&#xff08;man&#xff09; 局域网&#xff08;lan&#xff09; 个域网&#xff08;pan&#xff09; 注意&#xff1a;如今局域网几乎采用“以太网技术实现”&#xff0c;因此“以太网”几乎成了“局域…...

周家庄智慧旅游小程序

项目概述 周家庄智慧旅游小程序将通过数字化手段提升游客的旅游体验&#xff0c;依托周家庄的自然与文化资源&#xff0c;打造智慧旅游新模式。该小程序将结合虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;和人工智能等技术&#xff0c;提供丰富的…...

【在Linux世界中追寻伟大的One Piece】命名管道

目录 1 -> 命名管道 1.1 -> 创建一个命名管道 1.2 -> 匿名管道与命名管道的区别 1.3 -> 命名管道的打开规则 1.4 -> 例子 1 -> 命名管道 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据&…...

如意控物联网项目-ML307R模组软件及硬件调试环境搭建

软件及硬件调试环境搭建 1、 软件环境搭建及编译 a) 打开官方SDK&#xff0c;内涵APP-DEMO&#xff0c;通过vscode打开程序&#xff0c; 软件程序编写及编译参考下边说明文档链接 OneMO线上服务平台 编译需预安装python3.7以上版本&#xff0c;安装完python后&#xff0c;打开…...

大模型分布式训练并行技术(九)-总结

近年来&#xff0c;随着Transformer、MOE架构的提出&#xff0c;使得深度学习模型轻松突破上万亿规模参数&#xff0c;传统的单机单卡模式已经无法满足超大模型进行训练的要求。因此&#xff0c;我们需要基于单机多卡、甚至是多机多卡进行分布式大模型的训练。 而利用AI集群&a…...

uniapp view设置当前view之外的点击事件

推荐学习文档 golang应用级os框架&#xff0c;欢迎stargolang应用级os框架使用案例&#xff0c;欢迎star案例&#xff1a;基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识&#xff0c;这里有免费的golang学习笔…...

【Mybatis篇】动态SQL的详细带练

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【计算机网络】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 文章目录 &#x1f3af;一.动态SQL简单介绍 &#x1f6a6;动态S…...

【MyBatis-Plus】 学习记录 常用功能及代码生成器使用

文章目录 1. 环境准备2. 创建基础实体类3. 编写 Mapper 接口4. Service 层5. 控制器层6. 分页功能7. 条件构造器8. 配置乐观锁9. 常见问题10. 代码生成器1. 创建数据库表2. 引入依赖3. 配置数据库连接4. 编写代码生成器5. 运行代码生成器6. 查看生成的代码 MyBatis-Plus 是一个…...

HalconDotNet实现OCR详解

文章目录 一、基于字符分割的 OCR二、基于模板匹配的 OCR三、基于深度学习的 OCR四、基于特征提取的 OCR五、基于区域建议的 OCR 一、基于字符分割的 OCR 字符分割是 OCR 中的一个重要步骤。首先&#xff0c;对包含文本的图像进行预处理&#xff0c;如去噪、二值化等操作&#…...

手搓一个Agent#Datawhale 组队学习Task3

书接上回&#xff0c;首先回顾一下Task2的一些补充&#xff1a; Task2主要任务是从零预训练一个tiny-llama模型&#xff0c;熟悉一下Llama的模型架构和流程。然后测试一下模型的效果。总的来说&#xff0c;因为某些未知的原因&#xff0c;loss一直没有降下去&#xff0c;导致最…...

基于SpringBoot+Vue+MySQL的在线酷听音乐系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着互联网技术的飞速发展&#xff0c;网络已成为人们日常生活中不可或缺的一部分。在线音乐服务因其便捷性和丰富性&#xff0c;逐渐成为用户获取音乐内容的主要渠道。然而&#xff0c;传统的音乐播放平台往往存在歌曲资源有限…...

大数据实时数仓Hologres(一):Hologres 简单介绍

文章目录 Hologres 简单介绍 一、什么是实时数仓 Hologres 二、产品优势 1、专注实时场景 2、亚秒级交互式分析 3、统一数据服务出口 4、开放生态 5、MaxCompute查询加速 6、计算存储分离架构 三、应用场景 搭建实时数仓 四、产品架构 1、Shared Disk/Storage &am…...

【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库

【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库 一、环境说明二、分布式键值数据库介绍三、示例代码加以说明四、小结 一、环境说明 DevEco Studio 版本&#xff1a; API版本&#xff1a;以12为主 二、分布式键值数据库介绍 KVStore简介&#xff1a; 分布式键值数据库…...

基于springboot+小程序的儿童预防接种预约管理系统(疫苗1)(源码+sql脚本+视频导入教程+文档)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 本儿童预防接种预约微信小程序可以实现管理员和用户。 1、管理员功能有个人中心&#xff0c;用户管理&#xff0c;儿童信息管理&#xff0c;疫苗信息管理&#xff0c;儿童接种管理&#x…...

计算物理精解【8】-计算原理精解【5】

文章目录 logistic模型多元回归分析多元回归分析概览1. 多元回归的概念与重要性2. 多元回归在实际应用中的例子3. 多元回归在预测和解释数据中的优势和局限性4. 多元回归的优缺点及改进建议 多元线性回归分析详解一、原理二、性质三、计算四、例子与例题五、应用场景六、优缺点…...

【Linux】 tcp | 解除服务器对tcp连接的限制 | 物联网项目配置

一、修改tcp连接限制 1、编辑 vi /etc/sysctl.conf 2、内容 net.ipv4.tcp_keepalive_intvl 75 net.ipv4.tcp_keepalive_probes 9 net.ipv4.tcp_keepalive_time 7200 net.ipv4.ip_local_port_range 1024 65535 net.ipv4.ip_conntrack_max 20000 net.ipv4.tcp_max_tw_bucket…...

如何隐藏Windows10「安全删除硬件」里的USB无线网卡

本方法参照了原文《如何隐藏Windows10「安全删除硬件」里的USB无线网卡》里面的方法&#xff0c;但是文章中的描述我的实际情况不太一样&#xff0c;于是我针对自己的实际情况进行了调整&#xff0c;经过测试可以成功隐藏Windows10「安全删除硬件」里的USB无线网卡。 先说一下…...

【QT Quick】基础语法:导入外部JS文件及调试

在 QML 中&#xff0c;可以使用 JavaScript 来实现业务逻辑的灵活性和简化开发。接下来我们会学习如何导入 JavaScript 文件&#xff0c;并在 QML 中使用它&#xff0c;同时也会介绍如何调试这些 JavaScript 代码。 导入 JavaScript 文件 在 QML 中导入 JavaScript 文件的方式…...

罗技鼠标宏终极指南:5步实现绝地求生精准压枪

罗技鼠标宏终极指南&#xff1a;5步实现绝地求生精准压枪 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 你是否在绝地求生中总是压不住枪&#…...

Qwen3跨平台GUI开发:基于Qt框架打造桌面级字幕工具

Qwen3跨平台GUI开发&#xff1a;基于Qt框架打造桌面级字幕工具 最近有不少朋友在问&#xff0c;有没有那种既好用又能在自己电脑上离线运行的字幕生成工具&#xff1f;毕竟现在很多在线服务要么有隐私顾虑&#xff0c;要么网络不稳定&#xff0c;处理个长视频还得提心吊胆。正…...

深入理解Sentinel: 02 为什么需要服务降级以及常见的几种降级方式

为什么需要服务降级&#xff0c;常见的降级方式有哪些&#xff1f;上一篇跟大家分享了一个真实的服务雪崩的故事&#xff0c;也分析了造成服务雪崩的真正原因&#xff0c;那么&#xff0c;如何才能避免服务雪崩的出现呢&#xff1f;我知道你会说&#xff1a;增加硬件&#xff0…...

【协议森林】F-Stack与DPDK融合实践:用户态协议栈加速TCP通信的架构解析

1. 为什么需要用户态协议栈&#xff1f; 传统的内核协议栈在处理网络数据包时&#xff0c;就像是一个繁忙的十字路口&#xff0c;所有车辆&#xff08;数据包&#xff09;都要经过红绿灯&#xff08;中断处理&#xff09;和收费站&#xff08;内存拷贝&#xff09;。当网卡性能…...

Coze-Loop在金融风控中的应用:实时交易监测系统

Coze-Loop在金融风控中的应用&#xff1a;实时交易监测系统 1. 引言 想象一下这样的场景&#xff1a;一家大型银行的交易系统每秒处理着成千上万笔交易&#xff0c;突然出现了一笔异常大额转账&#xff0c;收款账户来自高风险地区。传统的风控系统可能需要几分钟才能识别这个…...

别再手动清理了!给RocketMQ客户端日志(rocketmq_client.log)上个“自动瘦身”套餐

RocketMQ客户端日志自动化管理&#xff1a;从配置优化到运维实践 在分布式系统架构中&#xff0c;日志管理往往被视为"二等公民"——直到某个深夜&#xff0c;磁盘告警短信把运维团队从睡梦中惊醒。RocketMQ作为消息中间件的核心组件&#xff0c;其客户端日志(rocke…...

论文合规双检新标杆:paperzz 查重系统,一站式破解本科毕业双重检测焦虑

Paperzz-AI官网免费论文查重复率AIGC检测/开题报告/文献综述/论文初稿paperzz - 论文查重https://www.paperzz.cc/check 一、毕业季的检测困局&#xff1a;为何查重 AIGC 双检成了本科生的 “通关门槛”&#xff1f; 每到毕业论文定稿阶段&#xff0c;本科生群体都会陷入一场…...

s2-pro语音合成实战:支持长文本分块合成与无缝拼接技术方案

s2-pro语音合成实战&#xff1a;支持长文本分块合成与无缝拼接技术方案 1. 专业级语音合成工具s2-pro简介 s2-pro是Fish Audio开源的专业级语音合成模型镜像&#xff0c;它能够将文本内容转换为自然流畅的语音输出。这个工具特别适合需要高质量语音合成的各种应用场景&#x…...

保姆级教程:用K210+MaixHub,5分钟搞定人脸识别门锁的模型训练与部署

K210MaixHub人脸识别门锁开发实战&#xff1a;从零训练到部署全指南 1. 边缘AI开发环境搭建 在开始人脸识别门锁项目前&#xff0c;我们需要准备合适的硬件和软件环境。K210开发板作为一款专为边缘计算设计的AIoT芯片&#xff0c;具有以下核心优势&#xff1a; 双核64位RISC-V处…...

Keil开发必备:AStyle代码格式化插件一键配置指南(附最新参数详解)

Keil开发必备&#xff1a;AStyle代码格式化插件一键配置指南&#xff08;附最新参数详解&#xff09; 在嵌入式开发领域&#xff0c;代码风格的一致性往往被忽视&#xff0c;却直接影响团队协作效率和代码可维护性。Keil作为嵌入式开发的主流IDE&#xff0c;原生并未提供强大的…...