Qt调用FFmpeg库实时播放UDP组播视频流
基于以下参考链接,通过改进实现实时播放UDP组播视频流
https://blog.csdn.net/u012532263/article/details/102736700
源码在windows(qt-opensource-windows-x86-5.12.9.exe)、ubuntu20.04.6(x64)(qt-opensource-linux-x64-5.12.12.run)、以及针对arm64的ubuntu20.04.6(x64)交叉编译环境下编译成功(QT5.12.8, 5.15.13), 可执行程序在windows,ubuntu(x64)、arm64上均可运行。
工程代码见:
https://download.csdn.net/download/daqinzl/90315016
主要代码
videoplayer.cpp
#include "videoplayer.h"
#include <QDebug>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/pixfmt.h"
#include "libswscale/swscale.h"
}
#include <stdio.h>
#include<iostream>
using namespace std;
VideoPlayer::VideoPlayer()
{
}
VideoPlayer::~VideoPlayer()
{
}
void VideoPlayer::startPlay()
{
///调用 QThread 的start函数 将会自动执行下面的run函数 run函数是一个新的线程
this->start();
}
void VideoPlayer::run()
{
/*
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame;
AVFrame *pFrameRGB;
AVPacket *packet;
uint8_t *out_buffer;
static struct SwsContext *img_convert_ctx;
int videoStream, i, numBytes;
int ret, got_picture;
avformat_network_init();
av_register_all();
//Allocate an AVFormatContext.
pFormatCtx = avformat_alloc_context();
// ffmpeg取rtsp流时av_read_frame阻塞的解决办法 设置参数优化
AVDictionary* avdic = NULL;
//rtsp
//av_dict_set(&avdic, "buffer_size", "102400", 0); //设置缓存大小,1080p可将值调大
//av_dict_set(&avdic, "rtsp_transport", "udp", 0); //以udp方式打开,如果以tcp方式打开将udp替换为tcp
//rtmp
//av_dict_set(&avdic, "buffer_size", "8192000", 0); //设置缓存大小,1080p可将值调大
//av_dict_set(&avdic, "rtsp_transport", "tcp", 0); //以udp方式打开,如果以tcp方式打开将udp替换为tcp
//udp
av_dict_set(&avdic, "buffer_size", "8192000", 0); //设置缓存大小,1080p可将值调大
av_dict_set(&avdic, "rtsp_transport", "udp", 0); //以udp方式打开,如果以tcp方式打开将udp替换为tcp
//av_dict_set(&avdic, "fflags", "nobuffer", 0); // 设置实时选项
//av_dict_set(&avdic, "flags", "low_delay", 0); // 设置低延迟选项
av_dict_set(&avdic, "max_interleave_delta", "40000", 0);
//av_dict_set(&avdic, "stimeout", "2000000", 0); //设置超时断开连接时间,单位微秒
//av_dict_set(&avdic, "max_delay", "500000", 0); //设置最大时延
///rtsp地址,可根据实际情况修改
//char url[]="rtsp://admin:admin@192.168.1.18:554/h264/ch1/main/av_stream";
//char url[]="rtsp://192.168.17.112/test2.264";
//char url[]="rtsp://admin:admin@192.168.43.1/stream/main";
//char url[]="rtmp://mobliestream.c3tv.com:554/live/goodtv.sdp";
char url[]="udp://224.1.1.1:5001";
//char url[]="rtmp://192.168.1.100:1935/live/desktop";
if (avformat_open_input(&pFormatCtx, url, NULL, &avdic) != 0) {
qDebug("can't open the file. \n");
return;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
qDebug("Could't find stream infomation.\n");
return;
}
videoStream = -1;
///循环查找视频中包含的流信息,直到找到视频类型的流
///便将其记录下来 保存到videoStream变量中
///这里我们现在只处理视频流 音频流先不管他
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
}
}
///如果videoStream为-1 说明没有找到视频流
if (videoStream == -1) {
qDebug("Didn't find a video stream.\n");
return;
}
///查找解码器
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
///2017.8.9---lizhen
//pCodecCtx->bit_rate = 0; //初始化为0
//pCodecCtx->time_base.num = 1; //下面两行:一秒钟25帧
//pCodecCtx->time_base.den = 10;
//pCodecCtx->frame_number = 1; //每包一个视频帧
if (pCodec == NULL) {
qDebug("Codec not found.\n");
return;
}
///打开解码器
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
qDebug("Could not open codec.\n");
return;
}
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
///这里我们改成了 将解码后的YUV数据转换成RGB32
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_RGB32, SWS_FAST_BILINEAR, NULL, NULL, NULL);
numBytes = avpicture_get_size(AV_PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height);
out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *) pFrameRGB, out_buffer, AV_PIX_FMT_RGB32,
pCodecCtx->width, pCodecCtx->height);
int y_size = pCodecCtx->width * pCodecCtx->height;
packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet
av_new_packet(packet, y_size); //分配packet的数据
//*/
//bool CanRun = true;
//ffmpeg 初始化
// 初始化注册ffmpeg相关的编码器
av_register_all();
avcodec_register_all();
avformat_network_init();
//qDebug()<<"1 FFmpeg version info: { av_version_info() }";
qDebug()<<"2 FFmpeg version info: { " << av_version_info() << "}";
qDebug()<<"3 FFmpeg version info:";
qDebug()<< av_version_info() ;
char url[]="udp://224.1.1.1:5001";
// ffmpeg 转码
// 分配音视频格式上下文
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary* avdic = NULL;
av_dict_set(&avdic, "buffer_size", "8192000", 0);
av_dict_set(&avdic, "max_interleave_delta", "40000", 0);
av_dict_set(&avdic, "analyzeduration", "100000000", 0);
av_dict_set(&avdic, "probesize", "100000000", 0);
int ret;
//打开流
ret = avformat_open_input(&pFormatCtx, url, NULL, &avdic);
if (ret != 0){ qDebug("can't open the url. \n"); return; }
// 读取媒体流信息
ret = avformat_find_stream_info(pFormatCtx, NULL);
if (ret != 0) { qDebug("Could't find stream infomation.\n"); return; }
// 这里只是为了打印些视频参数
AVDictionaryEntry* tag = NULL;
while ((tag = av_dict_get(pFormatCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)) != NULL)
{
char * key = tag->key;
char * value = tag->value;
qDebug()<< *key << *value << "\n";
}
// 从格式化上下文获取流索引
AVStream* pStream = NULL;
//AVStream* aStream = NULL;
int videoStream = -1;
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
pStream = pFormatCtx->streams[i];
videoStream = i;
}
//else if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
//{
// aStream = pFormatCtx->streams[i];
//}
}
if (pStream == NULL) { qDebug("Didn't find a video stream.\n"); return; }
// 获取流的编码器上下文
AVCodecContext codecContext = *pStream->codec;
qDebug() << "codec name: {" << avcodec_get_name(codecContext.codec_id) << "}\n";
// 获取图像的宽、高及像素格式
int width = codecContext.width;
int height = codecContext.height;
AVPixelFormat sourcePixFmt = codecContext.pix_fmt;
// 得到编码器ID
AVCodecID codecId = codecContext.codec_id;
// 目标像素格式
AVPixelFormat destinationPixFmt = AV_PIX_FMT_RGB32;
// 某些264格式codecContext.pix_fmt获取到的格式是AV_PIX_FMT_NONE 统一都认为是YUV420P
if (sourcePixFmt == AV_PIX_FMT_NONE && codecId == AV_CODEC_ID_MPEG2TS)
{
sourcePixFmt = AV_PIX_FMT_YUV420P;
}
static struct SwsContext *img_convert_ctx;
// 得到SwsContext对象:用于图像的缩放和转换操作
img_convert_ctx = sws_getContext(width, height, sourcePixFmt,
width, height, destinationPixFmt,
SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (img_convert_ctx == NULL) { qDebug() << "Could not initialize the conversion context.\n" ; return; }
//分配一个默认的帧对象:AVFrame
//AVFrame* pConvertedFrame = av_frame_alloc();
// 目标媒体格式需要的字节长度
//numBytes = avpicture_get_size(AV_PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height);
int numBytes = avpicture_get_size(destinationPixFmt, width, height);
// 分配目标媒体格式内存使用
//out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
uint8_t * out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
//var dstData = new byte_ptrArray4();
//var dstLinesize = new int_array4();
AVFrame *pFrameRGB = av_frame_alloc();
// 设置图像填充参数
//av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, convertedFrameBufferPtr, destinationPixFmt, width, height, 1);
avpicture_fill((AVPicture *) pFrameRGB, out_buffer, destinationPixFmt,width, height);
// ffmpeg 解码
// 根据编码器ID获取对应的解码器
AVCodec* pCodec = avcodec_find_decoder(codecId);
if (pCodec == NULL) { qDebug() << "Unsupported codec.\n"; }
AVCodecContext* pCodecCtx = &codecContext;
if ((pCodec->capabilities & AV_CODEC_CAP_TRUNCATED) == AV_CODEC_CAP_TRUNCATED)
pCodecCtx->flags |= AV_CODEC_FLAG_TRUNCATED;
// 通过解码器打开解码器上下文:AVCodecContext pCodecContext
ret = avcodec_open2(pCodecCtx, pCodec, NULL);
if (ret < 0) { qDebug() << ret << "\n"; return; }
// 分配解码帧对象:AVFrame pDecodedFrame
AVFrame* pFrame = av_frame_alloc();
// 初始化媒体数据包
AVPacket* packet = new AVPacket();
AVPacket** pPacket = &packet;
av_init_packet(packet);
while (1)
{
/*
if (av_read_frame(pFormatCtx, packet) < 0)
{
qDebug() << "av_read_frame < 0";
break; //这里认为视频读取完了
}
if (packet->stream_index == videoStream) {
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);
if (ret < 0) {
qDebug("decode error.\n");
return;
}
if (got_picture) {
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_RGB32);
QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示
emit sig_GetOneFrame(image); //发送信号
//emit sig_GetOneFrame(tmpImg);
//提取出图像中的R数据
//for(int i=0;i<pCodecCtx->width;i++)
//{
// for(int j=0;j<pCodecCtx->height;j++)
// {
// QRgb rgb=image.pixel(i,j);
// int r=qRed(rgb);
// image.setPixel(i,j,qRgb(r,0,0));
// }
//}
//emit sig_GetRFrame(image);
}else qDebug() << "got_picture < 0";
}else qDebug() << "packet->stream_index not video stream";
av_free_packet(packet); //释放资源,否则内存会一直上升
//msleep(0.02); //停一停 不然放的太快了
//*/
//*
try
{
do
{
// 读取一帧未解码数据
ret = av_read_frame(pFormatCtx, packet);
// Console.WriteLine(pPacket->dts);
if (ret == AVERROR_EOF) break;
if (ret < 0) { qDebug() << "got error "; return; }
if (packet->stream_index != videoStream) continue;
// 解码
ret = avcodec_send_packet(pCodecCtx, packet);
if (ret < 0) { qDebug() << "got error 2 "; return; }
// 解码输出解码数据
ret = avcodec_receive_frame(pCodecCtx, pFrame);
} while (ret == AVERROR(EAGAIN) && 1);
if (ret == AVERROR_EOF) break;
if (ret < 0) { qDebug() << "got error 3 "; return; }
if (packet->stream_index != videoStream) continue;
//Console.WriteLine($@"frame: {frameNumber}");
// YUV->RGB
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
//把这个RGB数据 用QImage加载
QImage tmpImg((uchar *)out_buffer,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);
QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示
emit sig_GetOneFrame(image); //发送信号
//emit sig_GetOneFrame(tmpImg);
} catch (exception e) {
}
{
av_packet_unref(packet);//释放数据包对象引用
av_frame_unref(pFrame);//释放解码帧对象引用
}
//*/
}
av_free(out_buffer);
av_free(pFrameRGB);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
}
相关文章:
Qt调用FFmpeg库实时播放UDP组播视频流
基于以下参考链接,通过改进实现实时播放UDP组播视频流 https://blog.csdn.net/u012532263/article/details/102736700 源码在windows(qt-opensource-windows-x86-5.12.9.exe)、ubuntu20.04.6(x64)(qt-opensource-linux-x64-5.12.12.run)、以…...
YOLOv10改进,YOLOv10检测头融合DynamicHead,添加小目标检测层(四头检测)+CA注意机制,全网首发
摘要 作者提出一种新的检测头,称为“动态头”,旨在将尺度感知、空间感知和任务感知统一在一起。如果我们将骨干网络的输出(即检测头的输入)视为一个三维张量,其维度为级别 空间 通道,这样的统一检测头可以看作是一个注意力学习问题,直观的解决方案是对该张量进行全自…...
【ComfyUI专栏】推荐几个常用的云端ComfyUI平台
如果我们本身的系统资源不足,但是我们依然能够使用显卡来利用ComfyUI生成我们需要的图片或者视频。当前平台中主要有两个不同的廉价平台提供了ComfyUI的功能,这里提供的资源基本上都是基于分钟进行计算。这些平台的好处就是基本上不需要你额外进行配置。…...
std::pair源码:operator=被delete了,提供的是sfinae版本
D:\DevTools\VS2017\VC\Tools\MSVC\14.16.27023\include\utility pair& operator(const volatile pair&) delete;真正版本:template<class _Other1 _Ty1,class _Other2 _Ty2,enable_if_t<conjunction_v<is_assignable<_Ty1&, const _Oth…...
数据要素白皮书(2024年)(解读+全文阅读)
数据要素白皮书(2024年)》由中国通信标准化协会大数据技术标准推进委员会发布,版权受法律保护,转载需注明来源。该白皮书深入分析了当前数据要素在全球及中国的发展态势,并提出了关键观察与展望。 全球范围内…...
C#常用257单词
1、Visual Studio 直译:可视化开发环境 说明:简称VS,我们编写程序的集成开发环境,可以写代码、编译代码、调试代码、发布程序。 2、.Net 直译:dotNet 说明:我们常说的.net读作dotnet,表示网…...
禅道2024年度回顾:品牌向善,才能向上!
很高兴禅道顺利完成了2024年的跃升计划,并交出了一份认真的答卷! 这一年,禅道的产品在变强,完成了产品的重构与全面升级; 这一年,禅道的朋友在变多,服务到更多不同行业的客户; 这…...
RK3568 adb使用
文章目录 一、adb介绍**ADB 主要功能****常用 ADB 命令****如何使用 ADB****总结** 二、Linux下载adb**方法 1:使用包管理器(适用于 Ubuntu/Debian 系统)****方法 2:通过 Snap 安装(适用于支持 Snap 的系统)…...
koodo-reader-电脑跨平台现代阅读器[支持ebook等电子书,支持多种格式]
koodo-reader-电脑跨平台现代阅读器[支持ebook等电子书,支持多种格式] 链接:https://pan.xunlei.com/s/VOH_rDBEXIU8lg4aA6IztZ4PA1?pwdg724# 特色 支持阅读格式: EPUB (.epub) PDF (.pdf) Kindle (.azw3, .mobi, .azw) 纯文本 (.txt…...
03:Heap代码的分析
Heap代码的分析 1、内存对齐2、Heap_1.c文件代码分析3、Heap_2.c文件代码分析4、Heap_4.c文件代码分析5、Heap_5.c文件代码分析 1、内存对齐 内存对齐的作用是为了CPU更快的读取数据。对齐存储与不对齐存储的情况如下: 计算机读取内存中的数据时是一组一组的读取的…...
二分查找题目:寻找两个正序数组的中位数
文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题:寻找两个正序数组的中位数 出处:4. 寻找两个正序数组的中位数 难度 8 级 题目描述 要求 给定两个大…...
Java Web-Tomcat Servlet
Web服务器-Tomcat Web服务器简介 Web 服务器是一种软件程序,它主要用于在网络上接收和处理客户端(如浏览器)发送的 HTTP 请求,并返回相应的网页内容或数据。以下是关于 Web 服务器的详细介绍: 功能 接收请求&#…...
渗透测试-WAF是什么以及原理解释 waf功能详解
目录 waf功能介绍 waf出现的地点: 什么是waf 功能: 常见的系统攻击分为两类 一是利用Web服务器的漏洞进行攻击 二是利用网页自身的安全漏洞进行攻击 WAF主要功能: waf的特点1 waf主要功能2 网马木马主动防御及查杀 流量监控 网站漏洞防御功能 危险组件…...
Vue3 provide/inject用法总结
1. 基本概念 provide/inject 是 Vue3 中实现跨层级组件通信的方案,类似于 React 的 Context。它允许父组件向其所有子孙组件注入依赖,无论层级有多深。 1.1 基本语法 // 提供方(父组件) const value ref(hello) provide(key, …...
C# 提取PDF表单数据
目录 使用工具 C# 提取多个PDF表单域的数据 C# 提取特定PDF表单域的数据 PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景。凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用。然而,当需要整合…...
【JAVA项目】基于ssm的【宠物医院信息管理系统】
【JAVA项目】基于ssm的【宠物医院信息管理系统】 技术简介:采用JSP技术、ssm框架、B/S架构、MySQL技术等实现。 系统简介:宠物医院信息管理系统,在系统首页可以查看首页、医学知识、医生信息、药品信息、新闻资讯、留言反馈、我的、跳转到后台…...
书生大模型实战营2
L0——入门岛 Python基础 Conda虚拟环境 虚拟环境是Python开发中不可或缺的一部分,它允许你在不同的项目中使用不同版本的库,避免依赖冲突。Conda是一个强大的包管理器和环境管理器。 创建新环境 首先,确保你已经安装了Anaconda或Minico…...
产业园管理系统提升企业综合管理效率与智能化水平的成功案例分析
内容概要 在当前科技迅猛发展的时代,越来越多的企业意识到数字化转型的重要性。为了提升管理效率和智能化水平,产业园管理系统应运而生,成为众多园区和商办写字楼不可或缺的一部分。无论是工业园、物流园还是公寓,这些系统都能为…...
《AI赋能光追:开启图形渲染新时代》
光线追踪技术是图形渲染领域的重大突破,能够通过模拟光的传播路径,精准渲染反射、折射、阴影和间接光照等效果,实现高度逼真的场景呈现。而人工智能的加入,更是为光线追踪技术带来了前所未有的变革,主要体现在以下几个…...
危机13小时:追踪一场GitHub投毒事件
事件概要 自北京时间 2024.12.4 晚间6点起, GitHub 上不断出现“幽灵仓库”,仓库中没有任何代码,只有诱导性的病毒文件。当天,他们成为了 GitHub 上 star 增速最快的仓库。超过 180 个虚假僵尸账户正在传播病毒,等待不…...
利用JSON数据类型优化关系型数据库设计
利用JSON数据类型优化关系型数据库设计 前言 在关系型数据库中,传统的结构化存储方式要求预先定义好所有的列及其数据类型。 然而,随着业务的发展,这种设计可能会显得不够灵活,尤其是在需要扩展单个列的描述功能时。 JSON数据…...
如何学习Java后端开发
文章目录 一、Java 语言基础二、数据库与持久层三、Web 开发基础四、主流框架与生态五、分布式与高并发六、运维与部署七、项目实战八、持续学习与提升总结路线图 学习 Java 后端开发需要系统性地掌握多个技术领域,从基础到进阶逐步深入。以下是一个详细的学习路线和…...
AI刷题-蛋糕工厂产能规划、优质章节的连续选择
挑两个简单的写写 目录 一、蛋糕工厂产能规划 问题描述 输入格式 输出格式 解题思路: 问题理解 数据结构选择 算法步骤 关键点 最终代码: 运行结果:编辑 二、优质章节的连续选择 问题描述 输入格式 输出格式 解题思路&a…...
SpringBoot统一数据返回格式 统一异常处理
统一数据返回格式 & 统一异常处理 1. 统一数据返回格式1.1 快速入门1.2 存在问题1.3 案列代码修改1.4 优点 2. 统一异常处理 1. 统一数据返回格式 强制登录案例中,我们共做了两部分⼯作 通过Session来判断⽤⼾是否登录对后端返回数据进⾏封装,告知前端处理的结果 回顾 后…...
[MySQL]事务的理论、属性与常见操作
目录 一、事物的理论 1.什么是事务 2.事务的属性(ACID) 3.再谈事务的本质 4.为什么要有事务 二、事务的操作 1.事务的支持版本 2.事务的提交模式 介绍 自动提交模式 手动提交模式 3.事务的操作 4.事务的操作演示 验证事务的回滚 事务异常…...
JWT实现单点登录
文章目录 JWT实现单点登录JWT 简介存在问题及解决方案登录流程后端程序实现前端保存Tokenstore存放信息的缺点及解决 校验流程:为gateway增加登录校验拦截器 另一种单点登录方法:Token+Redis实现单点登录 JWT实现单点登录 登录流程ÿ…...
docker 学习笔记
一、docker容器快速上手以及简单操作 docker的image和container image镜像 docker image就是一个read.only文件,可以理解成一个模版,docker image具有分层的概念 可以自己制作,也可以从registry拉去 container容器 一个运行中的docker …...
Lesson 119 A true story
Lesson 119 A true story 词汇 story n. 故事,传记,小说,楼层storey 搭配:tell a story 讲故事,说谎 true story 真实的故事 the second floor 二楼 例句:我猜他正在说谎。 I guess he…...
c语言版贪吃蛇(Pro Max版)附源代码
1 背景 贪吃蛇是一款经典的电子游戏,最早出现在20世纪70年代的街机游戏中。游戏的核心玩法是玩家控制一条蛇在有限的空间内移动,通过吃食物来增长身体长度,同时避免撞到墙壁、障碍物或自身。随着蛇的长度增加,游戏难度逐渐提升。 …...
蓝桥村打花结的花纸选择问题
在这篇文章中,我们将探讨一个有趣的算法问题,这个问题涉及到中国传统手工艺——打花结。我们需要判断给定的矩形花纸是否可以通过折叠操作使其面积变为特定的值 X,从而适合用来打花结。 问题描述 解题思路 这个问题可以通过循环方法来解决。…...
SSM开发(三) spring与mybatis整合(含完整运行demo源码)
目录 本文主要内容 一、Spring整合MyBatis的三个关键点 二、整合步骤 1、创建一个Maven项目 2、在pom.xml文件中添加jar包的依赖 3、配置MyBatis 注解实现方式 XML配置文件实现 4、配置Spring 5、测试运行 本文主要内容 1. Spring + Mybatis整合; 2. MyBatis两种SQL…...
【Matlab高端绘图SCI绘图模板】第006期 对比绘柱状图 (只需替换数据)
1. 简介 柱状图作为科研论文中常用的实验结果对比图,本文采用了3组实验对比的效果展示图,代码已调试好,只需替换数据即可生成相关柱状图,为科研加分。通过获得Nature配色的柱状图,让你的论文看起来档次更高࿰…...
Elasticsearch中的度量聚合:深度解析与实战应用
在大数据和实时分析日益重要的今天,Elasticsearch以其强大的搜索和聚合能力,成为了众多企业和开发者进行数据分析和处理的首选工具。本文将深入探讨Elasticsearch中的度量聚合(Metric Aggregations),展示其如何在数据分…...
重回C语言之老兵重装上阵(十六)C语言可变参数
C语言可变参数 在C语言中,标准库提供了一些函数允许接收可变数量的参数。最典型的例子就是 printf 和 scanf,它们能够处理不确定数量的参数。为了实现这一功能,C语言提供了可变参数函数的概念。 1. 可变参数函数的概念 可变参数函数是指函数…...
第4章 神经网络【1】——损失函数
4.1.从数据中学习 实际的神经网络中,参数的数量成千上万,因此,需要由数据自动决定权重参数的值。 4.1.1.数据驱动 数据是机器学习的核心。 我们的目标是要提取出特征量,特征量指的是从输入数据/图像中提取出的本质的数 …...
动态规划——斜率优化DP
题目清单 acwing300.任务安排1 状态表示f[i]: 集合:完成前i个任务且第i个任务为最后一个批次最后一个任务的方案。 属性:min 状态计算: f [ i ] m i n { f [ j ] s u m t [ i ] ∑ j 1 i w [ u ] s ∑ j 1 n w [ i ] } f[i]min\{f[j…...
函数栈帧的创建和销毁
1、总述: 大家在前期学习函数的时候,肯定会有诸多疑惑: 1、局部变量怎么创建的? 2、为什么有时候局部变量是随机值? 3、函数是怎么传参的?传参的顺序如何? 4、形参和实参是什么样的关系&am…...
【MQ】探索 Kafka
高性能 消息的顺序性、顺序写磁盘 零拷贝 RocketMQ内部主要是使用基于mmap实现的零拷贝,用来读写文件 减少cpu的拷贝次数和上下文切换次数,实现文件的高效读写操作 Kafka 零拷贝 Kafka 使用到了 mmap 和 sendfile 的方式来实现零拷贝。分别对应 Jav…...
c++ set/multiset 容器
1. set 基本概念 简介: 所有元素都会在插入时自动排序本质: set/multiset属于关联式容器,底层结构是用二叉树实现。set 和 multiset 区别: set容器不允许有重复的元素。 multiset允许有重复的元素。2. set 构造和赋值 构造&a…...
react-bn-面试
1.主要内容 工作台待办 实现思路: 1,待办list由后端返回,固定需要的字段有id(查详细)、type(本条待办的类型),还可能需要时间,状态等 2,一个集中处理待办中转路由页,所有待办都跳转到这个页面…...
【C++数论】880. 索引处的解码字符串|2010
本文涉及知识点 数论:质数、最大公约数、菲蜀定理 LeetCode880. 索引处的解码字符串 给定一个编码字符串 s 。请你找出 解码字符串 并将其写入磁带。解码时,从编码字符串中 每次读取一个字符 ,并采取以下步骤: 如果所读的字符是…...
shiro学习五:使用springboot整合shiro。在前面学习四的基础上,增加shiro的缓存机制,源码讲解:认证缓存、授权缓存。
文章目录 前言1. 直接上代码最后在讲解1.1 新增的pom依赖1.2 RedisCache.java1.3 RedisCacheManager.java1.4 jwt的三个类1.5 ShiroConfig.java新增Bean 2. 源码讲解。2.1 shiro 缓存的代码流程。2.2 缓存流程2.2.1 认证和授权简述2.2.2 AuthenticatingRealm.getAuthentication…...
Python案例--养兔子
兔子繁殖问题是一个经典的数学问题,最早由意大利数学家斐波那契在13世纪提出。这个问题不仅在数学领域具有重要意义,还广泛应用于计算机科学、生物学和经济学等领域。本文将通过一个具体的Python程序,深入探讨兔子繁殖问题的建模和实现&#…...
【搜索回溯算法】:BFS的魔力--如何使用广度优先搜索找到最短路径
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:搜索回溯算法篇–CSDN博客 文章目录 一.广度优先搜索(BFS)解决最短路…...
JavaSE第十一天——集合框架Collection
一、List接口 List接口是一个有序的集合,允许元素有重复,它继承了Collection接口,提供了许多额外的功能,比如基于索引的插入、删除和访问元素等。 常见的List接口的实现类有ArrayList、LinkedList和Vector。 List接口的实现类 …...
Three城市引擎地图插件Geo-3d
一、简介 基于Three开发,为Three 3D场景提供GIS能力和城市底座渲染能力。支持Web墨卡托、WGS84、GCJ02等坐标系,支持坐标转换,支持影像、地形、geojson建筑、道路,植被等渲染。支持自定义主题。 二、效果 三、代码 //插件初始化…...
深度学习|表示学习|卷积神经网络|详细推导每一层的维度变化|14
如是我闻: 一个经典的卷积神经网络(CNN)架构,呈现的是输入图像通过多个卷积层、池化层以及全连接层,最终输出分类结果的过程。整个过程的核心是理解输入特征图的尺寸如何在每一层发生变化,我们可以通过卷积…...
多级缓存(亿级并发解决方案)
多级缓存(亿级流量(并发)的缓存方案) 传统缓存的问题 传统缓存是请求到达tomcat后,先查询redis,如果未命中则查询数据库,问题如下: (1)请求要经过tomcat处…...
BOM对象location与数组操作结合——查询串提取案例
BOM对象location与数组操作结合——查询串提取案例 前置知识 1. Location 对象 Location 对象是 JavaScript 提供的内置对象之一,它表示当前窗口或框架的 URL,并允许你通过它操作或获取 URL 的信息。可以通过 window.location 访问。 主要属性&#…...
读书笔记--分布式服务架构对比及优势
本篇是在上一篇的基础上,主要对共享服务平台建设所依赖的分布式服务架构进行学习,主要记录和思考如下,供大家学习参考。随着企业各业务数字化转型工作的推进,之前在传统的单一系统(或单体应用)模式中&#…...