Qt编写RK3588视频播放器/支持RKMPP硬解/支持各种视音频文件和视频流/海康大华视频监控
一、前言
用ffmpeg做硬解码开发,参考自带的示例hw_decode.c即可,里面提供了通用的dxva2/d3d11va/vaapi这种系统层面封装的硬解码,也就是无需区分用的何种显卡,操作系统自动调度,基本上满足了各种场景的需要,这种方式很通用也便捷,但是一些特殊场景必须要用指定硬解码器名称的方式,比如指定 h264_qsv/h264_cuvid/h264_vaapi hevc_qsv/hevc_cuvid/hevc_vaapi/h264_mediacodec/h264_rkmpp,在瑞星微显卡的嵌入式开发板上面,基本上用的就是这种方式,视频源是264则指定h264_rkmpp,视频源是265则指定hevc_rkmpp来解码,当然这是有个前提的,并不是你指定这个解码器名称后初始化就能成功的,一定要当时编译ffmpeg的时候把对应功能打开,也不是你打开就能正常编译成功的,又有个前提是环境中要有对应的依赖都存在,编译器能正常找到对应的硬解的依赖。
二、效果图
三、相关地址
- 国内站点:https://gitee.com/feiyangqingyun
- 国际站点:https://github.com/feiyangqingyun
- 个人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
- 文件地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_demo。
四、功能特点
4.1 基础功能
- 支持各种音频视频文件格式,比如mp3、wav、mp4、asf、rm、rmvb、mkv等。
- 支持本地摄像头设备和本地桌面采集,支持多设备和多屏幕。
- 支持各种视频流格式,比如rtp、rtsp、rtmp、http、udp等。
- 本地音视频文件和网络音视频文件,自动识别文件长度、播放进度、音量大小、静音状态等。
- 文件可以指定播放位置、调节音量大小、设置静音状态等。
- 支持倍速播放文件,可选0.5倍、1.0倍、2.5倍、5.0倍等速度,相当于慢放和快放。
- 支持开始播放、停止播放、暂停播放、继续播放。
- 支持抓拍截图,可指定文件路径,可选抓拍完成是否自动显示预览。
- 支持录像存储,手动开始录像、停止录像,部分内核支持暂停录像后继续录像,跳过不需要录像的部分。
- 支持无感知切换循环播放、自动重连等机制。
- 提供播放成功、播放完成、收到解码图片、收到抓拍图片、视频尺寸变化、录像状态变化等信号。
- 多线程处理,一个解码一个线程,不卡主界面。
4.2 特色功能
- 同时支持多种解码内核,包括qmedia内核(Qt4/Qt5/Qt6)、ffmpeg内核(ffmpeg2/ffmpeg3/ffmpeg4/ffmpeg5/ffmpeg6)、vlc内核(vlc2/vlc3)、mpv内核(mpv1/mp2)、mdk内核、海康sdk、easyplayer内核等。
- 非常完善的多重基类设计,新增一种解码内核只需要实现极少的代码量,就可以应用整套机制,极易拓展。
- 同时支持多种画面显示策略,自动调整(原始分辨率小于显示控件尺寸则按照原始分辨率大小显示,否则等比缩放)、等比缩放(永远等比缩放)、拉伸填充(永远拉伸填充)。所有内核和所有视频显示模式下都支持三种画面显示策略。
- 同时支持多种视频显示模式,句柄模式(传入控件句柄交给对方绘制控制)、绘制模式(回调拿到数据后转成QImage用QPainter绘制)、GPU模式(回调拿到数据后转成yuv用QOpenglWidget绘制)。
- 支持多种硬件加速类型,ffmpeg可选dxva2、d3d11va等,vlc可选any、dxva2、d3d11va,mpv可选auto、dxva2、d3d11va,mdk可选dxva2、d3d11va、cuda、mft等。不同的系统环境有不同的类型选择,比如linux系统有vaapi、vdpau,macos系统有videotoolbox。
- 解码线程和显示窗体分离,可指定任意解码内核挂载到任意显示窗体,动态切换。
- 支持共享解码线程,默认开启并且自动处理,当识别到相同的视频地址,共享一个解码线程,在网络视频环境中可以大大节约网络流量以及对方设备的推流压力。国内顶尖视频厂商均采用此策略。这样只要拉一路视频流就可以共享到几十个几百个通道展示。
- 自动识别视频旋转角度并绘制,比如手机上拍摄的视频一般是旋转了90度的,播放的时候要自动旋转处理,不然默认是倒着的。
- 自动识别视频流播放过程中分辨率的变化,在视频控件上自动调整尺寸。比如摄像机可以在使用过程中动态配置分辨率,当分辨率改动后对应视频控件也要做出同步反应。
- 音视频文件无感知自动切换循环播放,不会出现切换期间黑屏等肉眼可见的切换痕迹。
- 视频控件同时支持任意解码内核、任意画面显示策略、任意视频显示模式。
- 视频控件悬浮条同时支持句柄、绘制、GPU三种模式,非绝对坐标移来移去。
- 本地摄像头设备支持指定设备名称、分辨率、帧率进行播放。
- 本地桌面采集支持设定采集区域、偏移值、指定桌面索引、帧率、多个桌面同时采集等。还支持指定窗口标题采集固定窗口。
- 录像文件同时支持打开的视频文件、本地摄像头、本地桌面、网络视频流等。
- 瞬间响应打开和关闭,无论是打开不存在的视频或者网络流,探测设备是否存在,读取中的超时等待,收到关闭指令立即中断之前的操作并响应。
- 支持打开各种图片文件,支持本地音视频文件拖曳播放。
- 视频流通信方式可选tcp/udp,有些设备可能只提供了某一种协议通信比如tcp,需要指定该种协议方式打开。
- 可设置连接超时时间(视频流探测用的超时时间)、读取超时时间(采集过程中的超时时间)。
- 支持逐帧播放,提供上一帧/下一帧函数接口,可以逐帧查阅采集到的图像。
- 音频文件自动提取专辑信息比如标题、艺术家、专辑、专辑封面,自动显示专辑封面。
- 视频响应极低延迟0.2s左右,极速响应打开视频流0.5s左右,专门做了优化处理。
- 支持H264/H265编码(现在越来越多的监控摄像头是H265视频流格式)生成视频文件,内部自动识别切换编码格式。
- 支持用户信息中包含特殊字符(比如用户信息中包含+#@等字符)的视频流播放,内置解析转义处理。
- 支持滤镜,各种水印及图形效果,支持多个水印和图像,可以将OSD标签信息和各种图形信息写入到MP4文件。
- 支持视频流中的各种音频格式,AAC、PCM、G.726、G.711A、G.711Mu、G.711ulaw、G.711alaw、MP2L2等都支持,推荐选择AAC兼容性跨平台性最好。
- 内核ffmpeg采用纯qt+ffmpeg解码,非sdl等第三方绘制播放依赖,gpu绘制采用qopenglwidget,音频播放采用qaudiooutput。
- 内核ffmpeg和内核mdk支持安卓,其中mdk支持安卓硬解码,性能非常凶残。
- 可以切换音视频轨道,也就是节目通道,可能ts文件带了多个音视频节目流,可以分别设置要播放哪一个,可以播放前设置好和播放过程中动态设置。
- 可以设置视频旋转角度,可以播放前设置好和播放过程中动态改变。
- 视频控件悬浮条自带开始和停止录像切换、声音静音切换、抓拍截图、关闭视频等功能。
- 音频组件支持声音波形值数据解析,可以根据该值绘制波形曲线和柱状声音条,默认提供了声音振幅信号。
- 标签和图形信息支持三种绘制方式,绘制到遮罩层、绘制到图片、源头绘制(对应信息可以存储到文件)。
- 通过传入一个url地址,该地址可以带上通信协议、分辨率、帧率等信息,无需其他设置。
- 保存视频到文件支持三种策略,自动处理、仅限文件、全部转码,转码策略支持自动识别、转264、转265,编码保存支持指定分辨率缩放或者等比例缩放。比如对保存文件体积有要求可以指定缩放后再存储。
- 支持加密保存文件和解密播放文件,可以指定秘钥文本。
- 提供的监控布局类支持64通道同时显示,还支持各种异型布局,比如13通道,手机上6行2列布局。各种布局可以自由定义。
- 支持电子放大,在悬浮条切换到电子放大模式,在画面上选择需要放大的区域,选取完毕后自动放大,再次切换放大模式可以复位。
- 各组件中极其详细的打印信息提示,尤其是报错信息提示,封装的统一打印格式。针对现场复杂的设备环境测试极其方便有用,相当于精确定位到具体哪个通道哪个步骤出错。
- 同时提供了简单示例、视频播放器、多画面视频监控、监控回放、逐帧播放、多屏渲染等单独窗体示例,专门演示对应功能如何使用。
- 监控回放可选不同厂家类型、回放时间段、用户信息、指定通道。支持切换回放进度。
- 可以从声卡设备下拉框选择声卡播放声音,提供对应的切换声卡函数接口。
- 支持编译到手机app使用,提供了专门的手机app布局界面,可以作为手机上的视频监控使用。
- 代码框架和结构优化到最优,性能强悍,注释详细,持续迭代更新升级。
- 源码支持windows、linux、mac、android等,支持各种国产linux系统,包括但不限于统信UOS/中标麒麟/银河麒麟等。还支持嵌入式linux。
- 源码支持Qt4、Qt5、Qt6,兼容所有版本。
4.3 视频控件
- 可动态添加任意多个osd标签信息,标签信息包括名字、是否可见、字号大小、文本文字、文本颜色、背景颜色、标签图片、标签坐标、标签格式(文本、日期、时间、日期时间、图片)、标签位置(左上角、左下角、右上角、右下角、居中、自定义坐标)。
- 可动态添加任意多个图形信息,比如人工智能算法解析后的图形区域信息直接发给视频控件即可。图形信息支持任意形状,直接绘制在原始图片上,采用绝对坐标。
- 图形信息包括名字、边框大小、边框颜色、背景颜色、矩形区域、路径集合、点坐标集合等。
- 每个图形信息都可指定三种区域中的一种或者多种,指定了的都会绘制。
- 内置悬浮条控件,悬浮条位置支持顶部、底部、左侧、右侧。
- 悬浮条控件参数包括边距、间距、背景透明度、背景颜色、文本颜色、按下颜色、位置、按钮图标代码集合、按钮名称标识集合、按钮提示信息集合。
- 悬浮条控件一排工具按钮可自定义,通过结构体参数设置,图标可选图形字体还是自定义图片。
- 悬浮条按钮内部实现了录像切换、抓拍截图、静音切换、关闭视频等功能,也可以自行在源码中增加自己对应的功能。
- 悬浮条按钮对应实现了功能的按钮,有对应图标切换处理,比如录像按钮按下后会切换到正在录像中的图标,声音按钮切换后变成静音图标,再次切换还原。
- 悬浮条按钮单击后都用名称唯一标识作为信号发出,可以自行关联响应处理。
- 悬浮条空白区域可以显示提示信息,默认显示当前视频分辨率大小,可以增加帧率、码流大小等信息。
- 视频控件参数包括边框大小、边框颜色、焦点颜色、背景颜色(默认透明)、文字颜色(默认全局文字颜色)、填充颜色(视频外的空白处填充黑色)、背景文字、背景图片(如果设置了图片优先取图片)、是否拷贝图片、缩放显示模式(自动调整、等比缩放、拉伸填充)、视频显示模式(句柄、绘制、GPU)、启用悬浮条、悬浮条尺寸(横向为高度、纵向为宽度)、悬浮条位置(顶部、底部、左侧、右侧)。
五、相关代码
QStringList VideoUtil::getHardware(const VideoCore &videoCore)
{
QStringList list;
list << "none";
//ffmpeg建议用dxva2 / vlc建议用any / mpv建议用auto
if (videoCore == VideoCore_FFmpeg) {
//list << "qsv" << "cuda";
} else if (videoCore == VideoCore_Vlc) {
list << "any";
} else if (videoCore == VideoCore_Mpv) {
list << "auto";
} else if (videoCore == VideoCore_Mdk) {
#if defined(Q_OS_WIN)
list << "qsv" << "cuda" << "mft";
#endif
} else if (videoCore == VideoCore_Qtav) {
#if defined(Q_OS_WIN)
list << "qsv" << "cuda";
#endif
}
//因特尔显卡=vaapi/英伟达显卡=vdpau
//安卓=mediacodec/树莓派=mmal/CUDA平台=nvdec/cuda/瑞星微=rkmpp
#if defined(Q_OS_WIN)
list << "dxva2" << "d3d11va";
#elif defined(Q_OS_ANDROID)
list << "mediacodec";
#elif defined(Q_OS_LINUX)
list << "vaapi" << "vdpau" << "rkmpp";
#elif defined(Q_OS_MAC)
list << "videotoolbox";
#endif
return list;
}
void FFmpegThreadHelper::initVideoCodec(AVCodecx **videoCodec, AVCodecID codecId, QString &videoCodecName, QString &hardware)
{
//获取默认的解码器
(*videoCodec) = avcodec_find_decoder(codecId);
videoCodecName = (*videoCodec)->name;
bool otherHardware = (hardware != "none" && hardware != "dxva2" && hardware != "d3d11va");
if (!otherHardware) {
return;
}
//264/265才能去启用系统层以外的硬解码
if (videoCodecName != "h264" && videoCodecName != "hevc") {
hardware = "none";
return;
}
//指定硬解码器名称 h264_qsv/h264_cuvid/h264_vaapi hevc_qsv/hevc_cuvid/hevc_vaapi/h264_mediacodec
QString name = QString("%1_%2").arg(videoCodecName).arg(hardware);
(*videoCodec) = avcodec_find_decoder_by_name(name.toUtf8().constData());
//如果硬解码器分配失败则立即切换到软解码
if (!(*videoCodec)) {
(*videoCodec) = avcodec_find_decoder(codecId);
}
}
bool FFmpegThreadHelper::initHardware(FFmpegThread *thread, AVCodecx *videoCodec, AVCodecContext *videoCodecCtx, const QString &hardware)
{
#if (FFMPEG_VERSION_MAJOR > 2)
//根据名称自动寻找硬解码
enum AVHWDeviceType type;
QByteArray hwData = hardware.toUtf8();
const char *hwName = hwData.constData();
#ifdef __arm__
//发现嵌入式上低版本的库没有av_hwdevice_find_type_by_name函数
#if (FFMPEG_VERSION_MAJOR < 4)
return false;
#else
type = av_hwdevice_find_type_by_name(hwName);
#endif
#else
type = av_hwdevice_find_type_by_name(hwName);
#endif
//找到对应的硬解码格式
thread->debug(0, "硬件加速", QString("名称: %1 数值: %2").arg(hardware).arg(type));
FFmpegThreadHelper::hw_pix_fmt = FFmpegThreadHelper::find_fmt_by_hw_type(type, videoCodec);
if (FFmpegThreadHelper::hw_pix_fmt == -1) {
thread->debug(0, "加速失败", "");
return false;
}
int result = -1;
//创建硬解码设备
AVBufferRef *hw_device_ref;
result = av_hwdevice_ctx_create(&hw_device_ref, type, NULL, NULL, 0);
if (result < 0) {
thread->debug(result, "创建硬解", "av_hwdevice_ctx_create");
return false;
}
//解码器格式赋值为硬解码
videoCodecCtx->get_format = FFmpegThreadHelper::get_hw_format;
videoCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ref);
av_buffer_unref(&hw_device_ref);
thread->debug(result, "初始硬解", QString("成功: %1").arg(hardware));
return true;
#else
return false;
#endif
}
AVPixelFormat FFmpegThreadHelper::hw_pix_fmt = AV_PIX_FMT_NONE;
AVPixelFormat FFmpegThreadHelper::get_hw_format(AVCodecContext *ctx, const AVPixelFormat *pix_fmts)
{
const enum AVPixelFormat *p;
for (p = pix_fmts; *p != -1; p++) {
if (*p == hw_pix_fmt) {
return *p;
}
}
return AV_PIX_FMT_NONE;
}
AVPixelFormat FFmpegThreadHelper::find_fmt_by_hw_type(const AVHWDeviceType &type, const AVCodec *codec)
{
enum AVPixelFormat fmt = AV_PIX_FMT_NONE;
#if (FFMPEG_VERSION_MAJOR < 4)
switch (type) {
case AV_HWDEVICE_TYPE_DXVA2:
fmt = AV_PIX_FMT_DXVA2_VLD;
break;
#if (FFMPEG_VERSION_MAJOR > 2)
case AV_HWDEVICE_TYPE_D3D11VA:
fmt = AV_PIX_FMT_D3D11;
break;
#endif
case AV_HWDEVICE_TYPE_VAAPI:
fmt = AV_PIX_FMT_VAAPI;
break;
case AV_HWDEVICE_TYPE_VDPAU:
fmt = AV_PIX_FMT_VDPAU;
break;
case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
fmt = AV_PIX_FMT_VIDEOTOOLBOX;
break;
default:
fmt = AV_PIX_FMT_NONE;
break;
}
#else
for (int i = 0;; i++) {
const AVCodecHWConfig *config = avcodec_get_hw_config(codec, i);
if (!config) {
break;
}
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == type) {
fmt = config->pix_fmt;
break;
}
}
#endif
return fmt;
}
int FFmpegThreadHelper::decode(FFmpegThread *thread, AVCodecContext *avctx, AVPacket *packet, AVFrame *frameSrc, AVFrame *frameDst)
{
int result = -1;
#ifdef videoffmpeg
QString flag = "硬解出错";
#if (FFMPEG_VERSION_MAJOR > 2)
result = avcodec_send_packet(avctx, packet);
if (result < 0) {
thread->debug(result, flag, "avcodec_send_packet");
return result;
}
while (result >= 0) {
result = avcodec_receive_frame(avctx, frameSrc);
if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
break;
} else if (result < 0) {
thread->debug(result, flag, "avcodec_receive_frame");
break;
}
//将数据从GPU拷贝到CPU(这一步也比较耗CPU/最佳做法就是直接底层绘制显卡数据/目前不会)
//result = av_hwframe_map(frameDst, frameSrc, 0);
thread->lockFrame();
result = av_hwframe_transfer_data(frameDst, frameSrc, 0);
thread->unlockFrame();
if (result < 0) {
av_frame_unref(frameDst);
av_frame_unref(frameSrc);
thread->debug(result, flag, "av_hwframe_transfer_data");
return result;
}
goto end;
}
#endif
return result;
end:
//调用线程处理解码后的数据
thread->decodeVideo2(packet);
#endif
return result;
}
int FFmpegThreadHelper::decode(FFmpegThread *thread, AVCodecContext *avctx, AVPacket *packet, AVFrame *frame, bool video)
{
int result = -1;
#ifdef videoffmpeg
QString flag = video ? "视频解码" : "音频解码";
#if (FFMPEG_VERSION_MAJOR < 3)
if (video) {
avcodec_decode_video2(avctx, frame, &result, packet);
if (result < 0) {
thread->debug(result, flag, "avcodec_decode_video2");
return result;
}
} else {
avcodec_decode_audio4(avctx, frame, &result, packet);
if (result < 0) {
thread->debug(result, flag, "avcodec_decode_audio4");
return result;
}
}
goto end;
#else
result = avcodec_send_packet(avctx, packet);
//有些国标ts文件会是其他几种结果但是能正常解码
if (result < 0 && (result != AVERROR(EAGAIN)) && (result != AVERROR_EOF)) {
//if (result < 0) {
thread->debug(result, flag, "avcodec_send_packet");
return result;
}
result = 0;
while (result >= 0) {
if (video) {
//这里为什么要加个锁/因为外面可能其他线程在调用getImage函数获取图片/数据可能有冲突
thread->lockFrame();
result = avcodec_receive_frame(avctx, frame);
thread->unlockFrame();
} else {
result = avcodec_receive_frame(avctx, frame);
}
if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
//thread->debug(result, flag, "avcodec_receive_frame");
break;
} else if (result < 0) {
thread->debug(result, flag, "avcodec_receive_frame");
break;
}
goto end;
}
#endif
return result;
end:
//调用线程处理解码后的数据
if (video) {
thread->decodeVideo2(packet);
} else {
thread->decodeAudio2(packet);
}
#endif
return result;
}
Qt编写RK3588视频播放器/支持RKMPP硬解/支持各种视音频文件和视频流/海康大华视频监控的更多相关文章
- XBMC源代码简析 5:视频播放器(dvdplayer)-解复用器(以ffmpeg为例)
XBMC分析系列文章: XBMC源代码分析 1:整体结构以及编译方法 XBMC源代码分析 2:Addons(皮肤Skin) XBMC源代码分析 3:核心部分(core)-综述 XBMC源代码分析 4: ...
- Qt编写高仿苹果MAC电脑输入法(支持触摸滑动选词)
最近有个朋友找我定制一个输入法,需要高仿一个苹果MAC电脑的输入法,MAC操作系统的审美无疑是相当棒的,于是乎直接拿以前的输入法高仿了一个,由于之前有做过输入法这块的开发,而且改进了四年,各种需求都遇 ...
- JSmpeg-用JavaScript编写的视频播放器
使用说明:https://github.com/phoboslab/jsmpeg ffmpeg -i rtmp://abc/ccc/111 -f mpegts -codec:v mpeg1video ...
- Qt编写安防视频监控系统9-自动隐藏光标
一.前言 这个效果的灵感来自于大屏电子看板系统,在很多系统中尤其是上了大屏的时候,其实在用户不在操作的时候,是很不希望看到那个鼠标箭头指针的,只有当用户操作的时候才显示出来,这个就需要开个定时器定时计 ...
- Qt编写安防视频监控系统(界面很漂亮)
一.前言 视频监控系统在整个安防领域,已经做到了烂大街的程序,全国起码几百家公司做过类似的系统,当然这一方面的需求量也是非常旺盛的,各种定制化的需求越来越多,尤其是这几年借着人脸识别的东风,发展更加迅 ...
- Qt编写安防视频监控系统14-本地回放
一.前言 在上一篇文章将视频文件存储好了,需要提供界面方便用户查询视频文件进行回放,其实这个回放就是播放历史存储的视频文件,并不是什么高大上的东西,视频回放在这个系统中分三种,第一种是本地回放,回放存 ...
- Qt编写安防视频监控系统18-云台控制
一.前言 云台控制是视频监控系统中必备的一个功能,对球机进行上下左右的移动,还有焦距的控制,其实核心就是控制XYZ三个坐标轴,为了开发这个模块,特意研究了各种云台控制的方法和开源库比如soap,有些厂 ...
- Qt编写安防视频监控系统17-在线地图
一.前言 在线地图模块在一开始设计整个系统的时候就考虑进去了,主要功能就是在摄像机管理中,提供经纬度信息,然后加载百度地图在浏览器中显示,根据摄像机信息表中的每个摄像机的经纬度信息,自动生成设备点在地 ...
- Qt编写安防视频监控系统16-设备播放
一.前言 设备播放模块是后面增加的,核心就是通过组合rtsp视频流地址来播放实时视频和历史视频,目前市面上很多厂家比如排第一的海康都是支持直接rtsp通过NVR来播放某个通道视频流和回放某个通道的视频 ...
- Qt编写安防视频监控系统13-视频存储
一.前言 一般视频监控行业都会选择把视频存储在本地NVR或者服务器上,而不是存储在客户端电脑,只有当用户经费预算有限的时候,或者用户特殊需求要求存储在本地客户端电脑的时候才会开启存储到本地,正常来说视 ...
随机推荐
- yarn serve 开启项目服务失败 assets emit different content to the same filename
error: answer: 删除public的文件,重新 yarn serve :
- Access to XMLHttpRequest at xxxx from origin xxx has been blocked by CORS policy: No 'Access-Control- Allow-Origin' header is present on the requested resource
错误:控制台报错 : network 自动发起了请求: 解决办法: 找到 \node_modules\sockjs-client\dist\sockjs.js 文件 然后 crtl + g 快捷键跳 ...
- 使用datagrip时,报错 connection refused
因为数据库没有开启 : 打开终端 输入(管理员身份): net start mysql80 (这是你的数据库的名字)
- el-tree 懒加载复选框默认展开和默认选中
.markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...
- 5.15 相约上海!2021 年度首届云原生 Meetup | KubeSphere & Friends
时至今日,Kubernetes 虽然变成了云原生这套系统化方法论和开源技术的核心一环,但已经无法独立存在,而是与云原生生态中所有的技术形态息息相关.为了将云原生生态中的各个技术形态结合起来,帮助企业最 ...
- .NET周刊【10月第3期 2024-10-20】
国内文章 我被 .NET8 JIT 的一个BUG反复折磨了半年之久(JIT tier1 finally optimizations) https://www.cnblogs.com/calvinK/p ...
- Data-Free,多目标域适应合并方案,简单又有效 | ECCV'24
来源:晓飞的算法工程笔记 公众号,转载请注明出处 论文: Training-Free Model Merging for Multi-target Domain Adaptation 论文地址:htt ...
- 2024 xp_CAPTCHA(瞎跑-白嫖版) 4.3最新版安装使用教程
前言 xp_CAPTCHA(瞎跑-白嫖版)是一个免费的burpsuite插件,具有自动化图形验证码识别的功能.在安装的过程中,我发现网上的教程基本都为其较早的版本,已经不具备参考价值.因而我写下本篇博 ...
- 11.Kubernetes控制器Controller详解
Kubernetes控制器Controller详解 Statefulset Statefulset主要是用来部署有状态应用 对于StatefulSet中的Pod,每个Pod挂载自己独立的存储,如果一个 ...
- 鸿蒙Navigation拦截器实现页面跳转登录鉴权方案
我们在进行页面跳转时,很多情况下都得考虑登录状态问题,比如进入个人信息页面,下单交易页面等等.在这些场景下,通常在页面跳转前,会先判断下用户是否已经登录,若已登录,则跳转到相应的目标页面,若没有登录, ...