video_topic
使用qt5,ffmpeg6.0,opencv,os2来实现。qt并非必要,只是用惯了。
步骤是:
1.读取rtsp码流,转换成mat图像
2.发送ros::mat图像
项目结构如下:

videoplayer.h
#ifndef VIDEOPLAYER_H
#define VIDEOPLAYER_H#include <QThread>
#include <QImage>class VlcInstance;
class VlcMedia;
class VlcMediaPlayer;class VideoPlayer : public QThread
{Q_OBJECTpublic:explicit VideoPlayer();~VideoPlayer();void startPlay();void stopPlay();signals:void sig_GetOneFrame(QImage); //每获取到一帧图像 就发送此信号void sig_GetRFrame(QImage); signals://void SigFinished(void);protected:void run();private:QString mFileName;VlcInstance *_instance;VlcMedia *_media;VlcMediaPlayer *_player;std::string rtspaddr;bool mStopFlag;//是否退出标志
public slots:void setrtsp(std::string addr);
};#endif // VIDEOPLAYER_H
videoplayer.cpp
#include "videoplayer.h"
extern "C"
{#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libavutil/pixfmt.h"#include "libswscale/swscale.h"#include "libavutil/imgutils.h"}#include <stdio.h>
#include<iostream>
using namespace std;
VideoPlayer::VideoPlayer()
{rtspaddr="rtsp://admin:123456@192.168.123.104:554/stream1";
}VideoPlayer::~VideoPlayer()
{}void VideoPlayer::setrtsp(std::string addr){rtspaddr=addr;
}void VideoPlayer::startPlay()
{///调用 QThread 的start函数 将会自动执行下面的run函数 run函数是一个新的线程this->start();
}void VideoPlayer::stopPlay(){mStopFlag= true;
}void VideoPlayer::run()
{AVFormatContext *pFormatCtx;AVCodecContext *pCodecCtx;const AVCodec *pCodec;AVFrame *pFrame, *pFrameRGB;AVPacket *packet;uint8_t *out_buffer;static struct SwsContext *img_convert_ctx;int videoStream, i, numBytes;int ret, got_picture;avformat_network_init();//Allocate an AVFormatContext.pFormatCtx = avformat_alloc_context();AVDictionary *avdic=NULL;/*char option_key[]="rtsp_transport";char option_value[]="tcp";av_dict_set(&avdic,option_key,option_value,0);char option_key2[]="max_delay";char option_value2[]="100";av_dict_set(&avdic,option_key2,option_value2,0);*/av_dict_set(&avdic, "buffer_size", "1024000", 0); //设置最大缓存,1080可调到最大av_dict_set(&avdic, "rtsp_transport", "udp", 0); //以tcp的方式传送av_dict_set(&avdic, "stimeout", "5000000", 0); //设置超时断开链接时间,单位usav_dict_set(&avdic, "max_delay", "500000", 0); //设置最大时延av_dict_set(&avdic, "framerate", "5", 0);//av_dict_set(&avdic, "video_size","640x40",0);/*AVDictionary* options = NULL;av_dict_set(&options, "buffer_size", "1024000", 0); //设置最大缓存,1080可调到最大av_dict_set(&options, "rtsp_transport", "udp", 0); //以tcp的方式传送av_dict_set(&options, "stimeout", "5000000", 0); //设置超时断开链接时间,单位usav_dict_set(&options, "max_delay", "500000", 0); //设置最大时延av_dict_set(&options, "framerate", "20", 0);*////rtsp地址,可根据实际情况修改/// rtsp://127.0.0.1:8554/stream/// rtsp://admin:123456@192.168.123.104:554/stream1//char * tmp=(char*)rtspaddr.data();//char url[50];//strcpy(url, tmp);//char url[] ="rtsp://admin:123456@192.168.123.104:554/stream1";char url[100];for(int i=0;i<rtspaddr.length();i++){url[i] = rtspaddr[i];}url[rtspaddr.length()]='\0';if (avformat_open_input(&pFormatCtx, url, NULL, &avdic) != 0) {printf("can't open the file. \n");return;}if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {printf("Could't find stream infomation.\n");return;}videoStream = -1;///循环查找视频中包含的流信息,直到找到视频类型的流///便将其记录下来 保存到videoStream变量中///这里我们现在只处理视频流 音频流先不管他for (i = 0; i < pFormatCtx->nb_streams; i++) {if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {videoStream = i;break;}}///如果videoStream为-1 说明没有找到视频流if (videoStream == -1) {printf("Didn't find a video stream.\n");return;}printf("nb_stream:%d videoStream:%d\n",pFormatCtx->nb_streams,videoStream);pCodec = avcodec_find_decoder(pFormatCtx->streams[videoStream]->codecpar->codec_id);pCodecCtx = avcodec_alloc_context3(pCodec);avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStream]->codecpar);//printf("pCodecCtx->frame_number:%d\n", pCodecCtx->frame_number);//printf("pCodecCtx->time_base.num:%d\n", pCodecCtx->time_base.num);//printf("pCodecCtx->time_base.den:%d\n", pCodecCtx->time_base.den);//printf("pCodecCtx->bit_rate:%d\n", pCodecCtx->bit_rate);//printf("pCodecCtx->framerate:%d\n", pCodecCtx->framerate);// pCodecCtx->bit_rate =0; //初始化为0// pCodecCtx->time_base.num=1; //下面两行:一秒钟25帧// pCodecCtx->time_base.den=10;// pCodecCtx->frame_number=1; //每包一个视频帧if (pCodec == NULL) {printf("Codec not found.\n");return;}///打开解码器if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {printf("Could not open codec.\n");return;}pFrame = av_frame_alloc();pFrameRGB = av_frame_alloc();///这里我们改成了 将解码后的YUV数据转换成RGB32img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL);numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGBA, pCodecCtx->width,pCodecCtx->height,1);out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));av_image_fill_arrays(pFrameRGB->data,pFrameRGB->linesize,out_buffer,AV_PIX_FMT_RGBA,pCodecCtx->width,pCodecCtx->height,1);int y_size = pCodecCtx->width * pCodecCtx->height;packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packetav_new_packet(packet, y_size); //分配packet的数据mStopFlag = false;while (!mStopFlag){if (av_read_frame(pFormatCtx, packet) < 0){continue; //这里认为视频读取完了}if (packet->stream_index == videoStream) {ret = avcodec_send_packet(pCodecCtx,packet);if( 0 != ret){continue;}while (avcodec_receive_frame(pCodecCtx,pFrame) == 0){sws_scale(img_convert_ctx,(uint8_t const * const *) pFrame->data,pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,pFrameRGB->linesize);//把这个RGB数据 用QImage加载QImage tmpImg((uchar *)out_buffer,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGBA8888);//QImage tmpImg((uchar *)out_buffer,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB888);QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示emit sig_GetOneFrame(image); //发送信号/*printf("pCodecCtx->width:%d\n", pCodecCtx->width);printf("pCodecCtx->height:%d\n", pCodecCtx->height);printf("pCodecCtx->frame_number:%d\n", pCodecCtx->frame_number);printf("pCodecCtx->time_base.num:%d\n", pCodecCtx->time_base.num);printf("pCodecCtx->time_base.den:%d\n", pCodecCtx->time_base.den);printf("pCodecCtx->bit_rate:%d\n", pCodecCtx->bit_rate);printf("pCodecCtx->framerate:%d\n", pCodecCtx->framerate);printf("pCodecCtx->frame_size:%d\n", pCodecCtx->frame_size);*/}}av_packet_unref(packet); //释放资源,否则内存会一直上升msleep(0.02); //停一停 不然放的太快了}av_free(out_buffer);av_free(pFrameRGB);avcodec_close(pCodecCtx);avformat_close_input(&pFormatCtx);//emit SigFinished();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QLineEdit>
#include <QDir>
#include <QSettings>
#include <QDebug>
#include <QPushButton>
#include <QPainter>
#include <QInputDialog>
#include <QtMath>
#include <iostream>#include "videoplayer.h"
#include <iostream>
#include <csignal>
#include <opencv4/opencv2/opencv.hpp>#include <iostream>
#include <iomanip>
#include <ctime>
#include <opencv2/opencv.hpp>#include<algorithm>
#include<vector>
#include<iostream>#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"#include <QTimer>#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/msg/image.hpp>
#include <std_msgs/msg/string.hpp>
using namespace std::chrono_literals;QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
signals:void sig_fame(QImage img);private:Ui::Widget *ui;
private:void readconfig();QString rtspaddr;void initWidget();void initconnect();
private slots:void slot_open_or_close();protected://void paintEvent(QPaintEvent *event);private:VideoPlayer *mPlayer; //播放线程QImage mImage; //记录当前的图像QString url;//QImage initimage;cv::Mat QImage2Mat(QImage image);QImage Mat2QImage(const cv::Mat &mat);//void readvideo();//std::vector<cv::Vec3b> colors(32);//cv::VideoWriter outputVideo;//int encode_type ;//= VideoWriter::fourcc('M', 'J', 'P', 'G');//std::vector<cv::Vec3b> colors;//cv::VideoWriter outputVideo;private slots:void slotGetOneFrame(QImage img);private:cv::Mat tempmat;// -------------------------------------// ros// -------------------------------------// noderclcpp::Node::SharedPtr node_;// pubrclcpp::Publisher<sensor_msgs::msg::CompressedImage>::SharedPtr publisher_;// sub//rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscriber_;// spinrclcpp::TimerBase::SharedPtr timer_;void initSpin(void);QTimer spin_timer_;void timer_callback();};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{mPlayer = new VideoPlayer;ui->setupUi(this);readconfig();initWidget();initconnect();// -------------------------------------/*// create topic pubthis->publisher_ = this->node_->create_publisher<std_msgs::msg::String>("pub_topic", 10);// create topic subthis->subscriber_ = node_->create_subscription<std_msgs::msg::String>("sub_topic", 10,[&](const std_msgs::msg::String::SharedPtr msg){// 處理訂閱到的消息QString receivedMsg = QString::fromStdString(msg->data);std::cout << msg->data << std::endl;//ui->textBrowser->append(receivedMsg);});this->initSpin();*/rclcpp::init(0, nullptr);// create nodethis->node_ = rclcpp::Node::make_shared("video");this->publisher_ = this->node_->create_publisher<sensor_msgs::msg::CompressedImage>("pubImageTopic", 10);this->timer_ = this->node_->create_wall_timer(33ms, std::bind(&Widget::timer_callback, this));this->initSpin();}Widget::~Widget()
{delete ui;// -------------------------------------// ROS 釋放// -------------------------------------this->spin_timer_.stop();rclcpp::shutdown();// -------------------------------------}void Widget::initSpin(void)
{this->spin_timer_.setInterval(1); // 1 msQObject::connect(&this->spin_timer_, &QTimer::timeout, [&](){ rclcpp::spin_some(node_); });this->spin_timer_.start();
}void Widget::timer_callback(){try{//ros_img_ = cv_bridge::CvImage(std_msgs::msg::Header(), "bgr8", tempmat).toImageMsg();//sensor_msgs::msg::Image::SharedPtr ros_img_ = cv_bridge::CvImage(std_msgs::msg::Header(), "bgr8", tempmat).toImageMsg();if(!tempmat.empty()){//rclcpp::Publisher<sensor_msgs::msg::CompressedImage>::SharedPtr video_compressed_publisher_;cv::Mat des1080;cv::resize(tempmat, des1080, cv::Size(1080, 720), 0, 0, cv::INTER_NEAREST);sensor_msgs::msg::CompressedImage::SharedPtr ros_img_compressed_ = cv_bridge::CvImage(std_msgs::msg::Header(), "bgr8", des1080).toCompressedImageMsg();//video_compressed_publisher_->publish(*ros_img_compressed_);this->publisher_ ->publish(*ros_img_compressed_);qDebug()<<"publisher";}else{qDebug()<<"empty image";}//RCLCPP_WARN(this->get_logger(), "empty image");// video_publisher_->publish(*ros_img_);}catch (cv_bridge::Exception &e){//RCLCPP_ERROR(this->get_logger(),ros_img_->encoding.c_str());qDebug()<<"Exception";}}void Widget::readconfig(){QSettings settingsread("./src/video_topic/conf/config.ini",QSettings::IniFormat);rtspaddr = settingsread.value("SetUpOption/camerartsp").toString();mPlayer->setrtsp(rtspaddr.toStdString());
}void Widget::initWidget(){qDebug()<<rtspaddr;ui->le_rtstspaddr->setText(rtspaddr);
}void Widget::slot_open_or_close(){if(ui->btn_openorclose->text()=="open"){ui->btn_openorclose->setText("close");mPlayer->startPlay();// ROS 初始化// -------------------------------------/*rclcpp::init(0, nullptr);// create nodethis->node_ = rclcpp::Node::make_shared("video");this->publisher_ = this->node_->create_publisher<sensor_msgs::msg::CompressedImage>("pubImageTopic", 10);this->timer_ = this->node_->create_wall_timer(500ms, std::bind(&Widget::timer_callback, this));//pub_img = this->create_publisher<sensor_msgs::msg::Image>("res_img", 10);rclcpp::spin(this->node_);*///readvideo();}else{ui->btn_openorclose->setText("open");mPlayer->stopPlay();}
}void Widget::initconnect(){connect(ui->btn_openorclose,&QPushButton::clicked,this,&Widget::slot_open_or_close);connect(mPlayer,SIGNAL(sig_GetOneFrame(QImage)),this,SLOT(slotGetOneFrame(QImage)));connect(this,&Widget::sig_fame,this,&Widget::slotGetOneFrame);//connect(mPlayer,&VideoPlayer::SigFinished, mPlayer,&VideoPlayer::deleteLater);//自动释放
}void Widget::slotGetOneFrame(QImage img)
{//cv::Mat tempmat = QImage2Mat(img);tempmat = QImage2Mat(img);if (tempmat.empty()) {printf("null img\n");}else {QImage outimg = Mat2QImage(tempmat);//printf("get img\n");mImage = outimg;QImage imageScale = mImage.scaled(QSize(ui->label->width(), ui->label->height()));QPixmap pixmap = QPixmap::fromImage(imageScale);ui->label->setPixmap(pixmap);}}cv::Mat Widget::QImage2Mat(QImage image)
{cv::Mat mat = cv::Mat::zeros(image.height(), image.width(),image.format()); //初始化Matswitch(image.format()) //判断image的类型{case QImage::QImage::Format_Grayscale8: //灰度图mat = cv::Mat(image.height(), image.width(),CV_8UC1,(void*)image.constBits(),image.bytesPerLine());break;case QImage::Format_RGB888: //3通道彩色mat = cv::Mat(image.height(), image.width(),CV_8UC3,(void*)image.constBits(),image.bytesPerLine());break;case QImage::Format_ARGB32: //4通道彩色mat = cv::Mat(image.height(), image.width(),CV_8UC4,(void*)image.constBits(),image.bytesPerLine());break;case QImage::Format_RGBA8888:mat = cv::Mat(image.height(), image.width(),CV_8UC4,(void*)image.constBits(),image.bytesPerLine());break;default:return mat;}cv::cvtColor(mat, mat, cv::COLOR_BGR2RGB);return mat;}QImage Widget::Mat2QImage(const cv::Mat &mat)
{if(mat.type()==CV_8UC1 || mat.type()==CV_8U){QImage image((const uchar *)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);return image;}else if(mat.type()==CV_8UC3){QImage image((const uchar *)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);return image.rgbSwapped(); //r与b调换}
}
widget.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Widget</class><widget class="QWidget" name="Widget"><property name="geometry"><rect><x>0</x><y>0</y><width>645</width><height>461</height></rect></property><property name="windowTitle"><string>Widget</string></property><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QStackedWidget" name="stackedWidget"><widget class="QWidget" name="page"><layout class="QVBoxLayout" name="verticalLayout_2"><item><widget class="QLabel" name="label"><property name="text"><string>TextLabel</string></property></widget></item><item><layout class="QHBoxLayout" name="horizontalLayout"><item><widget class="QLineEdit" name="le_rtstspaddr"><property name="readOnly"><bool>true</bool></property></widget></item><item><widget class="QPushButton" name="btn_openorclose"><property name="text"><string>open</string></property></widget></item></layout></item></layout></widget><widget class="QWidget" name="page_2"/></widget></item></layout></widget><resources/><connections/>
</ui>
main.cpp
#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();//w.showMaximized();return a.exec();
}
package.xml
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3"><name>video_topic</name><version>0.0.0</version><description>TODO: Package description</description><maintainer email="cl@todo.todo">cl</maintainer><license>TODO: License declaration</license><buildtool_depend>ament_cmake</buildtool_depend><buildtool_depend>cv_bridge</buildtool_depend><depend>rclcpp</depend><depend>std_msgs</depend><depend>cv_bridge</depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><export><build_type>ament_cmake</build_type></export>
</package>
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(video_topic)# Default to C++14
if(NOT CMAKE_CXX_STANDARD)set(CMAKE_CXX_STANDARD 14)
endif()if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic)
endif()# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
# qt
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets)
find_package(cv_bridge REQUIRED)
find_package(image_transport)
find_package(sensor_msgs REQUIRED)add_executable(videosrc/main.cppsrc/videoplayer.hsrc/videoplayer.cppsrc/widget.hsrc/widget.cppsrc/widget.ui
)#set(FFMPEG_LIBS_DIR /usr/local/ffmpeg/lib)
#set(FFMPEG_HEADERS_DIR /usr/local/ffmpeg/include)set(FFMPEG_LIBS_DIR /usr/lib/aarch64-linux-gnu)
set(FFMPEG_HEADERS_DIR /usr/include/aarch64-linux-gnu)
include_directories(${FFMPEG_HEADERS_DIR})
#link_directories(${FFMPEG_LIBS_DIR})
#set(FFMPEG_LIBS libavutil.so libavcodec.so libavdevice.so libavformat.so libavfilter.so libswresample.so libswscale.so libavutil.so)
set(FFMPEG_LIBS libavcodec.so libavformat.so libswscale.so libavutil.so)find_package(OpenCV REQUIRED)
include_directories( ${OpenCV_INCLUDE_DIRS})
target_link_libraries(video ${OpenCV_LIBS})# ros
target_link_libraries(video${rclcpp_LIBRARIES}
)
# qt
target_link_libraries(video Qt5::Core Qt5::GuiQt5::Widgets
)
#ffmpegtarget_link_libraries(video ${FFMPEG_LIBS})ament_target_dependencies(videorclcppstd_msgssensor_msgs cv_bridge OpenCV image_transport
)# ------------------------------------------
# 設置自動MOC、UIC和RCC (與QT相關)
# ------------------------------------------
set_target_properties(video PROPERTIES AUTOMOC ON)
set_target_properties(video PROPERTIES AUTOUIC ON)
set_target_properties(video PROPERTIES AUTORCC ON)
# ------------------------------------------# 安装可执行文件
install(TARGETS videoDESTINATION lib/${PROJECT_NAME}
)ament_package()
相关文章:
video_topic
使用qt5,ffmpeg6.0,opencv,os2来实现。qt并非必要,只是用惯了。 步骤是: 1.读取rtsp码流,转换成mat图像 2.发送ros::mat图像 项目结构如下: videoplayer.h #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H#include …...
uniapp获取公钥、MD5,‘keytool‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
获取MD5、SHA1、SHA256指纹信息 通过命令的形式获取 winr调出黑窗口cd到证书所在目录输入keytool -list -v -keystore test.keystore,其中 test.keystore为你的证书名称加文件后缀按照提示输入你的证书密码,就可以查看证书的信息 通过uniapp云端查看(证书是在DClou…...
Jetson Orin NX 开发指南(5): 安装 OpenCV 4.6.0 并配置 CUDA 以支持 GPU 加速
一、前言 Jetson 系列的开发板 CPU 性能不是很强,往往需要采用 GPU 加速的方式处理图像数据,因此本文主要介绍如何安装带有 GPU 加速的 OpenCV,其中 GPU 加速通过 CUDA 来实现。 参考博客 Ubuntu 20.04 配置 VINS-Fusion-gpu OpenCV 4.6.…...
Spring Security 6.x 系列【67】认证篇之安装 ApacheDS
有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列Spring Security 版本 6.1.0 源码地址:https://gitee.com/pearl-organization/study-spring-security-demo 文章目录 1. 概述2. 安装3. 连接工具1. 概述 官方文档 在前两篇文档中,我们简单了…...
理解线程池源码 【C++】面试高频考点
理解线程池 C 文章目录 理解线程池 C程序源码知识点emplace_back 和 push_back有什么区别?互斥锁 mutexcondition_variablestd::move()函数bind()函数join 函数 线程池的原理就是管理一个任务队列和一个工作线程队列。 工作线程不断的从任务队列取任务,然…...
BP神经网络应用案例
目录 背景介绍 【神经网络符号说明】 【建立网络拓扑结构】 【神经网络学习步骤】 步骤1 准备输入和输出样本 步骤2 确定网络学习参数 步骤3 初始化网络权值W和阀值B 步骤4 计算网络第一层的输入和输出 步骤5 计算中间层(隐含层输入和输出) 步骤…...
日常学习记录随笔-大数据之日志(hadoop)收集实战
数据收集(nginx)--->数据分析---> 数据清洗--->数据聚合计算---数据展示 可能涉及到zabix 做任务调度我们的项目 电商日志分析 比如说我们现在有一个系统,我们的数仓建立也要有一个主题 我这个项目是什么我要干什么定义方向 对用户进行分析,用户信息 要懂整个数据的流…...
【云计算】相关解决方案介绍
文章目录 1.1 云服务环境 Eucalyptus1.1.1 介绍1.1.2 开源协议及语言1.1.3 官方网站 1.2 开源云计算平台 abiCloud1.2.1 开源协议及语言1.2.2 官方网站 1.3 分布式文件系统 Hadoop1.3.1 开源协议及语言1.3.2 官方网站 1.4 JBoss云计算项目集 StormGrind1.4.1 开源协议及语言1.4…...
攻防世界题目练习——Crypto密码新手+引导模式(二)(持续更新)
题目目录 1. 转轮机加密2. easychallenge 上一篇:攻防世界题目练习——Crypto密码新手引导模式(一)(持续更新) 1. 转轮机加密 首先了解一下轮转机加密吧。 传统密码学(三)——转轮密码机 题目内容如下: …...
LeetCode【1】两数之和
题目: 代码: public int[] twoSum(int[] nums, int target) {int[] result new int[2];Map<Integer, Integer> map new HashMap<>();// for (int i 0; i < nums.length; i) { // 这么写不能防重复啊!注意这里不…...
【运维笔记】VMWare 另一个程序已锁定文件的一部分,进程无法访问
情景再现 这里使用的是VMware 17 解决办法 进入设置 点击选项,全选复制里面内容 进入文件夹,删除所有包含.lck后缀的文件和文件夹 再启动虚拟机即可...
[Springboot]统一响应和异常处理配置
背景 前后端分离情况下,后端接口通常只需要返回JSON数据。 但有时候因为某些原因可能会导致得不到正确的结果。 比如 因为登录密码错误,你不能直接返回错误信息和null,这样前端很难处理。 又比如 因为后端接口爆出了异常,也不能直…...
Redis第四五六章 持久化事务主从复制
Redis ⽀持 RDB 和 AOF 两种持久化机制,持久化功能有效地避免因进程退出造成数据丢失问题, 当下次重启时利⽤之前持久化的⽂件即可实现数据恢复。 目录 第四章 持久化 4.1 RDB 4.1.1 触发机制 4.1.2 流程说明 4.1.3 RDB ⽂件的处理 4.1.4 RDB 的优…...
【强烈推荐】免费的PDF工具,包括PDF拆分/分割、转WORD等功能的免费在线软件工具,救了大命,找了半天什么pdf365、福xipdf、还有哔果pdf全是打着免费名义收费,烦死了
PDF拆分 - 图文工具箱 - imgtool.net,嘎嘎好用,主要是免费 除此之外,还有其他的功能,需要的可以去看看...
SpringMVC源码分析(二)启动过程之RequestMappingHandlerMapping分析
a、http请求中的url是如何与对应Handler的即Controller对应method映射的? 在上篇中提到在SpringMVC中,初始化9大内置组件的时候其中有一个组件就是HandlerMapping,在初始化HandlerMapping的时候会加载代码中所有标注了Controller和RequestMap…...
KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(7)
接前一篇文章:KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(6) 上一回讲到了drm_internal_framebuffer_create函数中的framebuffer_check函数。讲解了该函数的参数检查部分中的第二部分,本回对于该函数余下部分进行解析。 为了便于理解,再次贴出framebuffer_ch…...
2023 年 Arm A-Profile 架构发展
随着人工智能 (AI) 的兴起和安全威胁的加剧,计算需求不断发展,作为世界设备核心的基础计算架构也必须不断发展。这就是为什么我们的工程团队向普遍存在的 Arm 架构添加新功能和技术,然后软件团队确保软件尽可能无缝地适应这些未来的功能和技术。 Arm架构是如何开发的 Arm …...
2023年09月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试
C/C++编程(1~8级)全部真题・点这里 Python编程(1~6级)全部真题・点这里 第1题:红与黑 有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。 时间限…...
CentOS系统/root根目录扩容(扩展逻辑卷)
具体操作步骤 1、查看本机磁盘环境挂载情况 2、添加磁盘分区 3、开始扩容 4、同步到文件系统 1、查看本机磁盘环境挂载情况 [rooticon ~]# df -lh 可以看到/dev/mapper/centos-root 路径下容量为50G,我们要给这个路径下的容量扩容:[rooticon ~]# lsblk…...
苍穹外卖(三) 员工分页及技术实现细节
2. 员工分页查询 2.1 需求分析和设计 2.1.1 产品原型 2.1.2 接口设计 2.2 代码开发 2.2.1 设计DTO类 根据请求参数进行封装 2.2.2 封装PageResult 后面所有的分页查询,统一都封装为PageResult对象。 员工信息分页查询后端返回的对象类型为: Result 2.…...
树莓派Web IDE:零配置云端编程环境与Python硬件模拟实践
1. 项目概述:一个“开箱即用”的编程环境革命最近,树莓派基金会悄无声息地扔下了一颗“重磅炸弹”——他们正式推出了一个网页端的代码编辑器。这个消息在创客圈和教育圈里,可能比发布一款新硬件还要让人兴奋。为什么?因为它直接戳…...
ARM Trace Buffer架构与调试优化实践
1. ARM Trace Buffer架构解析Trace Buffer是ARM处理器中用于实时捕获指令执行轨迹的专用硬件模块,它通过独立的缓冲区和控制逻辑实现低开销的程序流监控。在ARMv8/v9架构中,Trace Buffer Extension(TRBE)作为可选的硬件扩展&#…...
高速串行通信信号抖动关键技术【附模型】
✨ 长期致力于串行通信、抖动、抖动分析、时钟恢复、均衡研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)基于有界不相关抖动注入的发送端信号生成模型…...
②Allegro PCB转Altium Designer PCB转Pads Layout PCB
在工作中,难免会遇到主流画板EDA软件(Pads、Altium Designer、Cadence allegeo、嘉立创EDA等)文件格式相互间转换的问题。下面来介绍一下Allegro PCB转Pads Layout PCB的详细操作步骤,前面已经介绍过allegro不用经过Altium Designer软件直接转PADS格式pc…...
Keil MDK中EVR选项缺失的解决方案与原理
1. 问题现象解析:EVR选项缺失的典型表现 在Keil MDK开发环境中使用Event Recorder(事件记录器)时,开发者常会遇到一个令人困惑的现象:按照官方文档配置printf重定向到EVR时,STDOUT的下拉菜单中本该出现的&q…...
【开源首发】双脑 AI 工作流:强制模型隔离 + 省 60% Token,完美替代 CrewAI,支持本地 Ollama 免费跑
前言 大家好,我是一名大一的生物医药数据科学专业学生。最近半年一直在用 AI 做各种自动化工具,前前后后踩了 LangChain 和 CrewAI 的无数坑。 我发现所有主流 AI Agent 框架都有一个致命的设计盲区:它们默认相信 AI 能自己监督自己。但实际…...
Purple Pi OH开发板适配OpenHarmony 5.0全流程解析与实战
1. 项目概述:从一块开发板到OpenHarmony 5.0的完整旅程最近,我手头的这块触觉智能Purple Pi OH开发板,终于成功跑通了OpenHarmony 5.0 Release版本。这不仅仅是一次简单的系统升级适配,更像是一场从硬件引脚定义、内核驱动、系统服…...
从点击到意图:鸿蒙 App 的 AI 进化
子玥酱 (掘金 / 知乎 / CSDN / 简书 同名) 大家好,我是 子玥酱,一名长期深耕在一线的前端程序媛 👩💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚…...
Teledyne PDS后处理软件保姆级教程:从新建项目到格网导出的完整流程
Teledyne PDS后处理软件从入门到精通:多波束数据处理全流程实战指南 第一次打开Teledyne PDS后处理软件时,满屏的专业术语和复杂菜单让不少水下测量工程师感到无从下手。作为处理T50P等多波束测深数据的核心工具,PDS软件的操作流程直接关系到…...
BiliBiliToolPro:解放双手的B站自动化神器,让你的账号管理从未如此轻松
BiliBiliToolPro:解放双手的B站自动化神器,让你的账号管理从未如此轻松 【免费下载链接】BiliBiliToolPro B 站(bilibili)自动任务工具,支持docker、青龙、k8s等多种部署方式。全面拥抱AI。敏感肌也能用。 项目地址:…...
