一套rk3588 rtsp服务器推流的 github 方案及记录 -01

news2025/2/24 7:05:06

我不生产代码,我只是代码的搬运工,相信我,看完这个文章你的图片一定能变成流媒体推出去。
诉求:使用opencv拉流,转成bgr数据,需要把处理后的数据(BGR)编码成264,然后推流推出去,相当于直播(实时编码)

播放器

超低延迟的RTSP播放器
https://github.com/tsingsee/EasyPlayer-RTSP-Win

青犀的一个播放器,直接下他的EasyPlayer-RTSP-Win用来测试就行。划重点,超低延时,我整体方案的延时大概是600-700ms,使用海康相机,rtsp拉流,做了yolo处理,再推出去,有编码,有解码,vlc的延时设置低了就回卡帧,Gop已经改成5了还是卡帧,没有测试Gop改成1的情况,但是vlc的延时和流畅,整体看是不太兼容的。ffmpeg使用nobuffer也会卡帧。直观感受卡的就是Gop的P帧。

服务器

live555 方案

如果你不着急的话。。。 可以试试这个方案,这方面的参考文献给列下面了,因为确实正经研究了几天还看了不少代码,认真想了应该怎么处理,但是确实不太想写,而且对我的需求来讲live555冗余了很多功能,再加上网上确实没有写好的,我又很着急要结果,确定方案能用,所以也没有用这个方案。

官方demo

live555自己的测试文件是有推流demo的,主要是根据实时需求推264文件,以及无脑做一个推264文件的服务器,当时看代码的时候一头雾水加上着急,也没太认真看,主要在live555\testProgs下面,testOnDemandRTSPServer,testH264VideoStreamer ,第二个是无脑推,第一个是你来一个请求,我从头开始给你播放一次视频文件。
这个东西的底层是向一个fTo指针里面拷贝264码流。
如果你Cpp、coding能力强的话,应该是能看懂直接改的,也就不用往后看了。

参考demo 零声 usb相机推流

网上基本上和我需求最接近的live555方案下的代码是国内的做音视频开发教学的一个零声出的视频还有他们传的这个代码。

主要功能是 v4l2相机读取mjpeg,然后ffmpeg的avcodec相关库编码,然后送live555,然后推实时流,像是改的testOnDemandRTSPServer,结构很清晰,除了不能用我也找不到原因外都挺好的。另外他的课是5K的,有点贵。

视频的话去B站带关键词,基本都能搜到,这个代码我加了那个联系QQ要到的。但是在我本地没有推成功,我也不确定是哪里的问题,编译过了,放在这里
https://gitee.com/qingfuliao/v4l2_ipc_live555?_from=gitee_search

在我这是下面这个demo 实现了一个相似的功能,编译实测是可以读取usb相机然后推流成功的。但是代码结构没有上面那个清晰。

参考demo

https://github.com/mpromonet/v4l2rtspserver

这个功能是基于linux的v4l2,使用264的方式读取相机视频流(如果你的usb相机不支持264输出,会驱动失败),然后直接拆帧把流发出去
需要自己下一个libv4l2cpp的代码放进来就能编译了

这个现在看稍微改一改就能用了,不过当时对整体没有概念,改了一阵子不知道怎么下手把我自己的码流变成demo的输入,码流送进去了但是没有推成功,定位了一会儿很难定位问题,也就搁置了。有兴趣的可以基于这个改一改。

https://blog.csdn.net/qq_43418269/article/details/122488866

这个方案我是成功了的,不过延时不太能满足我的需求,这个复现很快。他是用一个管道文件做的,我把编码之后264文件直接写到live555的testOnDemandRTSPServer.cpp这边的读取文件里面,然后逻辑是live555这边接收到请求,创建管道,相机程序初始化后阻塞住,管道被创建后往管道里写,然后另一边就开始播。。

这个就相当于是运行在一个demo里的两个程序。流倒是推出来了,只不过,我这样实现,延时很大,他说的百毫秒量级我做不到,我是2s左右。感觉也可能是我操作不当。

https://blog.csdn.net/lifexx/article/details/52823777

live555读文件改为内存读取实现,确实C++不太行,这个文章对我理解Live555,还有改成内存中的数据方向给了很大启发,但是没有按照他的做,而且他的参考代码无法运行。对我理解另一个推相机的demo有帮助

其他开源服务器框架

这个也是一个很容易就编译成功的服务器,可以使用这个做服务器,然后调用ffmpeg推流,在RK3588上也推成功了,基本没改make相关的配置,需要按照他给的快速开始流程使用git下附加库,功能很强大,但是对我的需求来讲,这个功能我进行二次开发比较慢。不排除我太菜。
https://github.com/ZLMediaKit/ZLMediaKit/tree/master

这里写这个的主要原因是他的一些文章对我的启发和快速上手有很大的参考意义,比如下面这个。

https://github.com/ZLMediaKit/ZLMediaKit/wiki/%E6%80%8E%E4%B9%88%E6%B5%8B%E8%AF%95ZLMediaKit%E7%9A%84%E5%BB%B6%E6%97%B6%EF%BC%9F

RK3399 参考

网上有瑞芯微其他方案的rtsp推流,我只能帮忙排除错误选项
https://t.rock-chips.com/forum.php?mod=viewthread&tid=749&extra=page%3D1
如果你是在看这个帖子,可以不用看了,这个猫头的代码虽然推出去了,但是他的Rtsp是调库,这个库是闭源的,3588没有,这个网站注册要两三天才能通过,不必等这个,用不了。

rtsp推流

在github上搜索rtsp,排名最高的那个结果,就是那个小乌龟,

https://github.com/PHZ76/RtspServer
这个功能比较单一,但是足够满足我的需求了,他还使用他自己的库做了一个windows下的应用,windows上编译成功了,但是不太好用,不过对我理解他的Demo运行有一定帮助。因为用的是一套库。另外他主页还有一个rtmp ,我没进去看也没试能不能用。

https://github.com/PHZ76/DesktopSharing

在这里插入图片描述

下载安装

下载下来直接在3588上面make就可以,编译的是RtspServer-master/example里面的main 文件,这里的rtsp_h264_file.cpp是可以直接推运行推264文件的,一般不需要修改就能直接用,如果不能用,有可能是554端口被占用,改一个大点的就好了

    std::string suffix = "live";
	std::string ip = "127.0.0.1";
	std::string port = "5543";// 改这里 不要改那个"0.0.0.0" 那个是对的不用改
	std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;

然后rtsp_pusher.cpp还有rtsp_server.cpp都把发送文件的部分注释掉了,需要结合h264那个文件来对比把264码流写进去。

运行测试

编译出来之后运行 ./rtsp_h264_file ./test.264 就能推出来了
工程已经被我魔改过了,重新生成一个sample 来演示下结果
这是RK3588 服务器
在这里插入图片描述

这是VLC的界面IP
在这里插入图片描述

下面的是显示的结果
在这里插入图片描述

改cmake 支持opencv 、rknn,mpp

因为我使用的RKNN之间是在Qt里面编译的,工程使用的都是Cmake的cmakelists,他的makefile也不难改,主要的问题是我自己写的解码器,在使用makefile指定mpp库之后编译出来的mpp库运行不正常,具体报错找不到了,然后我qt上用是没问题的,定位到是makefile没写好,改成cmakelist就可以正常编译了
-g是为了支持gdb调试,配合我的vscode 调试配置文件,可以单步调试,全程在板上编译,没配置交叉编译环境

cmake_minimum_required(VERSION 3.5)
project(rtspserver)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSOCKLEN_T=socklen_t -g ")

find_package(OpenCV 4.5.5 REQUIRED)
find_package(OpenSSL REQUIRED)

# MPP
set(MPP_PATH /home/orangepi/code/mpp-develop/inc)
set(MPP_LIBS /home/orangepi/code/mpp-develop/mpp/librockchip_mpp.so)
include_directories(${MPP_PATH})

# OSAL
set(OSAL_PATH /home/orangepi/code/mpp-develop/osal/inc/ /home/orangepi/code/mpp-develop/utils)
set(OSAL_LIBS /home/orangepi/code/mpp-develop/osal/libosal.a /home/orangepi/code/mpp-develop/utils/libutils.a)
include_directories(${OSAL_PATH})

# RKNN lib
set(RKNN_API_PATH ${CMAKE_SOURCE_DIR}/lib)
set(RKNN_RT_LIB ${RKNN_API_PATH}/aarch64/librknnrt.so)
include_directories(${RKNN_API_PATH}/include)
include_directories(${CMAKE_SOURCE_DIR}/3rdparty)

# RGA
set(RGA_PATH ${CMAKE_SOURCE_DIR}/3rdparty/rga/RK3588)
set(RGA_LIB ${RGA_PATH}/lib/Linux/aarch64/librga.so)
include_directories(${RGA_PATH}/include)


aux_source_directory(src/xop SOURCE1)
aux_source_directory(src/net SOURCE2)

include_directories(    
    src    
    src/xop
    src/net
    src/3rdpart
    )

# add_executable(rtsp
# example/rtsp_server.cpp
# ${SOURCE1}
# ${SOURCE2}
# src/3rdpart/md5/md5.hpp
# )
# target_link_libraries(rtsp ${MPP_LIBS} ${OSAL_LIBS}  ${OpenCV_LIBS} ${RKNN_RT_LIB} ${RGA_LIB} OpenSSL::SSL OpenSSL::Crypto )
# add_executable(rh264
# example/rtsp_h264_file.cpp
# ${SOURCE1}
# ${SOURCE2}
# src/3rdpart/md5/md5.hpp
# )
# target_link_libraries(rh264 ${MPP_LIBS} ${OSAL_LIBS}  ${OpenCV_LIBS} OpenSSL::SSL OpenSSL::Crypto )
add_executable(sample
example/sample.cpp
${SOURCE1}
${SOURCE2}
src/3rdpart/md5/md5.hpp
)
target_link_libraries(sample ${MPP_LIBS} ${OSAL_LIBS}  ${OpenCV_LIBS}  ${RKNN_RT_LIB} ${RGA_LIB} OpenSSL::SSL OpenSSL::Crypto )

代码修改

代码是基于他的rtsp_server来修改的,主要修改的内容是sendFrameThread,大概思路是这样的,还差一个问题,怎么把你的原始mat图像转成264码流

bool IsKeyFrame(const char* data, uint32_t size)
{
	if (size > 4) {
		//0x67:sps ,0x65:IDR, 0x6: SEI
		if (data[4] == 0x67 || data[4] == 0x65 || 
			data[4] == 0x6 || data[4] == 0x27) {
			return true;
		}
	}

	return false;
}

void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, int& clients)
{       
	encoder e;
    
	
   
//  encoder相关 内存拷贝
	int size = 0;
	char* buffer ;

	// 编码标志位
    int i = 0;

    // 生成图像
    int width = 1920;
    int height = 1080;
	cv::Mat colorBar= cv::Mat::zeros(height, width, CV_8UC3);
    // 设置彩条的宽度
    int barWidth = width / 8; // 8个彩条,你可以根据需要调整
    // 生成彩条
    for (int i = 0; i < 8; ++i) {
        // 计算彩条的起始和结束位置
        int startX = i * barWidth;
        int endX = (i + 1) * barWidth;
        // 设置彩条颜色(BGR格式)
        cv::Vec3b color;
        if (i % 2 == 0) {
            color = cv::Vec3b(255, 0, 155); // 蓝色
        } else {
            color = cv::Vec3b(0, 255, 0); // 绿色
        }
        // 在colorBar上画出彩条
        colorBar(cv::Rect(startX, 0, barWidth, height)) = color;
    }

	while(1)
	{
		
		if(clients > 0) /* 会话有客户端在线, 发送音视频数据 */
		{
			{     
				xop::AVFrame videoFrame = {0};
				// printf("width is %d, height is %d",colorBar.rows,colorBar.cols);
				// 编码 发包
				if(0==i){
					// 第一帧有sps信息 给他两帧拼一起
					char *buffer1;
					int size1;
					e.init(buffer1,size1);
					videoFrame.size = size1;
					e.postAframe(colorBar,buffer,size);
					videoFrame.size += size;					
					videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
					memcpy(videoFrame.buffer.get(), buffer1, size1);
					memcpy(videoFrame.buffer.get()+size1, buffer, size);
					i++;
				}		
				else{
					e.postAframe(colorBar,buffer,size);
					videoFrame.size = size;  // 视频帧大小 
					videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
					memcpy(videoFrame.buffer.get(), buffer, videoFrame.size);
				}
				

				
				videoFrame.type = IsKeyFrame(buffer, size) ? xop::VIDEO_FRAME_I : xop::VIDEO_FRAME_P;
				// videoFrame.type = 0; // 建议确定帧类型。I帧(xop::VIDEO_FRAME_I) P帧(xop::VIDEO_FRAME_P)

				videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳
							
				// writeCharPointerToFile((char *)videoFrame.buffer.get(), videoFrame.size,  "filename.txt");		
				rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); //送到服务器进行转发, 接口线程安全
				/*
				//获取一帧 H264, 打包
				xop::AVFrame videoFrame = {0};
				videoFrame.type = 0; // 建议确定帧类型。I帧(xop::VIDEO_FRAME_I) P帧(xop::VIDEO_FRAME_P)
				videoFrame.size = video frame size;  // 视频帧大小 
				videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳
				videoFrame.buffer.reset(new uint8_t[videoFrame.size]);                    
				memcpy(videoFrame.buffer.get(), video frame data, videoFrame.size);					
                   
				rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); //送到服务器进行转发, 接口线程安全
				*/
			}
                    
			{				
				/*
				//获取一帧 AAC, 打包
				xop::AVFrame audioFrame = {0};
				audioFrame.type = xop::AUDIO_FRAME;
				audioFrame.size = audio frame size;  /* 音频帧大小 
				audioFrame.timestamp = xop::AACSource::GetTimestamp(44100); // 时间戳
				audioFrame.buffer.reset(new uint8_t[audioFrame.size]);                    
				memcpy(audioFrame.buffer.get(), audio frame data, audioFrame.size);

				rtsp_server->PushFrame(session_id, xop::channel_1, audioFrame); // 送到服务器进行转发, 接口线程安全
				*/
			}		
		}
		// xop::Timer::Sleep(20);  /* 实际使用需要根据帧率计算延时!  我这里处理延时很大,就不人工延迟了*/
	}
	videocapture->release();
	e.deinit((MPP_RET)0);
	yolo5.deinit();

}

rk3588编码

这方面网上的文章不太多,但是官方给了demo,都是中文,认真看看,功能都是能用的。
主要参考他的mpp-develop/test/mpi_enc_test 以及Rk3588-linux-v002\linux\docs\Linux\Multimedia\Rockchip_Developer_Guide_MPP_CN.pdf进行配置和使用。这相关的东西我之后再另开一个文章单独说,总之参考这部分可以做一个BGR888转成264存储的demo。
这里重点说一个概念,I、P、B帧
这个东西是264流编码的一个概念,正常你每一帧的图像都很大,比如一个1920*1080,每个像素点存一个BGR888的话,就是1920*1080*3 Byte =6220800 Byte ≈ 6M ,然后一秒30帧的话,一秒就要传180M,局域网或许勉强可以,但是对带宽压力也很大。所以这里就涉及到了压缩,264、265就是压缩标准,压缩中需要做两种压缩 帧内压缩帧间压缩

  • 帧内压缩:使用一定方法使用尽量小的空间存一帧数据。

  • 帧间压缩:利用帧和前后帧的关联来进一步的压缩视频。

这里我们重点关注帧间压缩。给一个参考文献
https://zhuanlan.zhihu.com/p/409527359
说的挺透彻的,这里我粗略说一下,看下面这个图
在这里插入图片描述

I帧 ,是帧间压缩里面的一帧完整图像,P帧是前向预测帧,B帧是双向预测帧
IDR帧是特殊的I帧,在编解码时候P、B帧可以参考I帧前面的帧进行复原,但是不能参考IDR帧前面的帧进行复原

而一个上面这样的循环,被编码成一组,我们指定了h264的gop大小,就确定了多少帧中有一个I帧
而我们在做直播,就导致为了低延时,不要B帧,gop 也要尽量的不要太大,如果要解码P帧,前面就一定要缓存I帧,

监测工具

wireshark, 这个感觉还是蛮必要的,至少你能看见客户端和服务器之间说没说话。如果你有耐心开RTSP 或者网络协议握手说明的话,你甚至能看到他们之间的握手流程。

杂记

中间遇到了一个问题,因为我这个地方没有公网,所以只能自己给开一个热点给电脑,PC和RK3588之间通过路由器连接,然后使用前面的某个demo的时候遇到的,主机向服务器(RK3588)发出视频请求时,服务器并没有直接给客户端发rtcp包,而是给一个200多的地址发包,而这个包在客户端收不到,但是他能收到rtp的协议包,所以vlc这边也不提示打不开,就是没有图像显示。
后来使用的方法是,和板子通过路由器网线连接,然后电脑PC wifi 连接路由器,然后路由器没有公网,再使用一个手机usb给电脑共享网络,让我的调试环境稳定可以接受到3588的流,和路由器网线连接的时候接受不到包,感觉是因为路由器没有网,使用网线连接时候被屏蔽了服务器功能,所以交给路由器的包转发请求没有被PC识别到,但是wifi连接的话,就算他没有网,也是不能忽略的。 目前是这样理解的。

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

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

相关文章

第三方支付原理

1.什么是第三方支付 所谓第三方支付&#xff0c;就是一些和各大银行签约、并具备一定实力和信誉保障的第三方独立机构提供的交易支持平台。在通过第三方支付平台的交易中&#xff0c;买方选购商品后&#xff0c;使用第三方平台提供的账户进行货款支付&#xff0c;由第三方通知卖…

微信小程序基础

1.小程序发展史 微信小程序之前&#xff0c;是使用weixin-sdk进行开发&#xff0c;调用视频&#xff0c;摄像头等。 微信小程序weixin up端&#xff0c;所以PC端的window这些没有&#xff0c;运行环境是IOS&#xff0c;安卓等&#xff0c;有一些特殊的调用录音功能&#xff0…

百元开放式蓝牙耳机哪款好、热门高性价比开放式推荐

在众多耳机类型中&#xff0c;开放式耳机正逐渐崭露头角。它们融合了音质和佩戴舒适性&#xff0c;能给你带来全新的佩戴感受。这些耳机不仅提供高品质的音响体验&#xff0c;还让你能够在户外佩戴欣赏音乐的同时保持对周围环境的感知&#xff0c;更加安全、保障。 在本文中&a…

分布式版本管理系统---->Git(Linux---centos(保姆式)讲解1)

文章目录: 1:什么是Git以及作用 2.Git的基本操作过程(创建git仓库,配置仓库的配置) 3.git的工作区&#xff0c;暂存区&#xff0c;版本库的关系 4.将文件添加到版本库&#xff1a;git add 与git commit -m命令 5.git log查看日志的引入 6.查看.git文件中的内容 7.修改文件内容查…

从浅入深掌握进阶结构体(C语言)

前言 这一期我们将继续讲解结构体的知识&#xff0c;还没有看过上一期的小伙伴一定要赶紧去学习哦。 上一期&#xff0c;冲鸭&#xff01; 那么话不多说我们开始今天的学习吧&#xff01; 文章目录 1,结构体的自引用2,匿名结构体3,位段4,结构体的传参5,尾声 1,结构体的自引用 …

SqlServer存储过程中使用in

第一步&#xff1a;创建测试存储过程&#xff1a; CREATE PROCEDURE [dbo].[test] deptCode varchar(MAX)AS BEGINSELECT * from DEPT_INFO_A where DEPT_CODE in (deptCode)END 此存储过程只是一个简单的查询 第二步测试&#xff1a; 传入的 deptCode为&#xff1a;101200…

苍穹外卖项目笔记(7)— 微信登录、商品浏览

前言 苍穹外卖项目代码&#xff1a;https://github.com/Echo0701/take-out 1 HttpClient 1.1 介绍 HttpClient 是 Apche Jakarta Common 下的子项目&#xff0c;可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包&#xff0c;并且支持 HTTP 协议最新…

微信小程序开发:地图路线规划全流程,超详细!!!(包括遇到的问题解决)

目录 效果展示 第一章 准备阶段 1.1 使用uniapp搭建微信小程序 1.2 条件1&#xff1a;appId&#xff08;微信小程序appId&#xff09; 1.3 条件2&#xff1a;key&#xff08;腾讯位置服务申请的key&#xff09; 1.4 条件3&#xff1a;插件appId&#xff08;微信小程序插件…

GEE:使用拉普拉斯(Laplacian)算子对遥感图像进行卷积操作

作者:CSDN @ _养乐多_ 本文记录了使用拉普拉斯(Laplacian)算子对遥感图像进行卷积操作的代码。并以试验区NDVI图像为例。 研究区真彩色影像、NDVI图像以及Sobel卷积结果如下所示, 文章目录 一、拉普拉斯算子二、完整代码三、代码链接一、拉普拉斯算子 详细介绍参考《遥感…

前端模拟新闻列表ajax请求 mocky

效果图&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title> </head><style>ul {display: flex;flex-wrap: wrap;justify-content: space-between;}ul::after{content: ;width: 30%;}a…

python自动化操作:批量处理照片尺寸并输出到word文档中【第14篇—python-照片尺寸批量处理输出】

文章目录 一.背景二.需求三.实现源码3.1 项目结构3.2 源码3.3 核心调节照片大小 四.代码解释五.实现效果六.心得总结 一.背景 在当今数字化时代&#xff0c;照片处理和文档编辑是许多领域中不可或缺的任务。从个人创作到企业文档&#xff0c;人们经常需要快速而有效地处理大量…

C++检测字符串中有效的括号个数

匹配一个字符串buf中&#xff0c;连续包换运算符reg的次数&#xff1a; #include <iostream>//return 返回匹配的字符个数 //buf, 要检测的字符串 //reg, 包含的连续运算符 int GetMatchCount(std::string& buf, std::string& reg) {int nMatchCount 0;if (reg.…

android项目实战之使用框架 集成多图片、视频的上传

效果图 实现方式&#xff0c;本功能使用PictureSelector 第三方库 。作者项目地址&#xff1a;https://github.com/LuckSiege/PictureSelector 1. builder.gradle 增加 implementation io.github.lucksiege:pictureselector:v3.11.1implementation com.tbruyelle.rxpermissio…

DELL服务器ESXi 6.7平台配置网卡直通报错

报错信息&#xff1a; 内存设置无效: 内存预留 (sched.mem.min) 应该等于内存大小 尝试勾选内存配置&#xff1a;预留所有客户机内存 报错信息&#xff1a; 模块“DevicePowerOn”打开电源失败。 配置文件中缺少 pciPassthru1.id 条目。 无法启动虚拟机。 尝试&#xff1a…

基于Web和深度学习的辣椒检测产量预测系统

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 辣椒是一种重要的经济作物&#xff0c;被广泛种植和消费。然而&#xff0c;辣椒的产量预测一直是农业生产中的重要问题。准确地预测辣椒的产量可以帮助农民合理安…

『时间之外』这个不得不思考的问题,还是要说一下

还记得当初自己为什么选择计算机&#xff1f; 当初你问我为什么选择计算机&#xff0c;我笑着回答&#xff1a;“因为我梦想成为神奇的码农&#xff01;我想像编织魔法一样编写程序&#xff0c;创造出炫酷的虚拟世界&#xff01;”谁知道&#xff0c;我刚入门的那天&#xff0…

鸿蒙开发—学习声明式UI

基本UI描述 ArkTS通过装饰器Component和Entry装饰struct关键字声明的数据结构&#xff0c;构成一个自定义组件。自定义组件中提供了一个build函数&#xff0c;开发者需在该函数内以链式调用的方式进行基本的UI描述&#xff0c;UI描述的方法请参考UI描述规范。 基本概念 stru…

(11_29)畅捷通的 Serverless 探索实践之路

作者&#xff1a;计缘 畅捷通介绍 畅捷通是中国领先的小微企业财税及业务云服务提供商&#xff0c;成立于2010年。畅捷通在2021年中国小微企业云财税市场份额排名第一&#xff0c;在产品前瞻性及行业全覆盖方面领跑市场&#xff0c;位居中国小微企业云财税厂商矩阵领军象限前…

医院运维 告警闪现后的故障排查

长期以来&#xff0c;医院信息化运维中存在着科室复杂、应用场景多、终端运维工作量大、软件系统兼容需求强等诸多痛点&#xff0c;且对技术设备的稳定性、连续性要求极高&#xff0c;在日常运维中&#xff0c;需要应对和解决这些问题来保障业务稳定、健康运行。 1、数据孤岛 …

mapbox实现框选要素

成果图 参考博客 https://blog.csdn.net/ScapeD/article/details/89158755 原理与源码 利用mapbox的queryRenderedFeatures方法可以获取范围内的要素&#xff0c;但是这个只能是点和矩形和范围内的全屏要素&#xff0c;并不支持多边形&#xff0c;所以实现这个的思路就是画完框…