协议-ACLLite-ffmpeg
是什么?
- FFmpeg是一个开源的多媒体处理工具包,它集成了多种功能,包括音视频的录制、转换和流式传输处理。
- FFmpeg由一系列的库和工具组成,其中最核心的是libavcodec和libavformat库。
- libavcodec是一个领先的音频/视频编解码器库,支持多种音频和视频格式的编码和解码操作。
- libavformat库则用于处理各种不同的多媒体容器格式,如MP4、AVI、MKV等。它能够解析提取其中的音频和视频流,以便进行进一步的处理
为什么?
为什么有GStreamer的前提下,还要使用FFmpeg?
- 在某些情况下,GStreamer 会比 FFmpeg 更适合特定的需求
- FFmpeg 是一个功能强大的单体框架,主要专注于媒体的编解码、转码和流处理
- GStreamer适合构建复杂的媒体处理管道,如视频会议、实时流媒体处理和视频编辑
功能 | FFmpeg | GStreamer |
---|---|---|
核心架构 | Monolithic | 模块化,基于管道线 |
易用性 | 使用 CLI 更容易完成简单的媒体任务 | 需要更多设置,但管道灵活 |
编解码器支持 | 广泛的编解码器支持,几乎涵盖所有编解码器 | 功能强大,但通常需要额外的插件 |
使用案例 | 媒体转换、流媒体 | 转码、实时流媒体、媒体应用 |
模块化 | 模块化程度低,围绕特定命令构建 | 模块化程度高,可定制组件 |
插件系统 | 有限的插件系统,主要集中于编解码器 | 广泛的插件系统,用于自定义处理 |
实时处理 | 可以,但不直观 | 专为实时流媒体和处理而设计 |
跨平台 | 是(Linux、Windows、macOS 等) | 是(Linux、Windows、macOS 等) |
复杂性 | 对于简单的任务来说更简单 | 对于复杂的自定义媒体工作流程来说更好 |
许可 | LGPL 或 GPL(取决于配置) | LGPL |
开发者社区 | 庞大、活跃、被广泛采用 | 活跃,但规模小于 FFmpeg |
怎么做?
- 官网Download FFmpeg,选择安装包
Windows builds from gyan.dev
- 找到
release bulids
部分,选择 ffmpeg-release-essentials.zip - 解压文件并检查目录结构
- 配置环境变量 并检验 ffmpeg -version
核心本质
本质就四个名词
- Demuxer:拆解多媒体文件,提取音频和视频流。
- Decoder:将编码后的音频或视频数据解码为原始数据。
- Encoder:将原始音频或视频数据编码为特定格式。
- Muxer:将音频和视频流重新封装为多媒体文件。
- Demuxer:拆解多媒体文件,提取音频和视频流。
- 解码器接收音频、视频、 或字幕基本流,并将它们解码为原始帧( 视频的像素,音频的 PCM)
- 编码器接收原始音频、视频或字幕帧并进行编码 它们被编码为数据包
- Muxer:将音频和视频流重新封装为多媒体文件
大局观总览
- 库总览
真正有用三库
- libavcodec库包含多种音频、视频和字幕流的解码器和编码器,以及多种位流过滤器。
- libavformat库用于将音频、视频和字幕流多路复用和解复用
- libavfilter库用于处理音频/视频数据,例如进行视频的缩放、裁剪、旋转,音频的混音、音量调整
辅助类型库
-
libavutil包含了一些安全的、可移植的字符串函数、随机数生成器、数据结构、额外的数学函数、密码学和与多媒体相关的功能(如枚举像素和采样格式)
-
libswscale是一个用于图像缩放和颜色空间以及像素格式转换的高效库。
-
libswresample是一个高度优化的音频重采样、重矩阵和采样格式转换库。
-
libavdevice是一个通用的框架,用于抓取和渲染许多常见的多媒体输入/输出设备。
-
命令总览
- 功能总览
转换格式流程图
- 输入文件拆解多媒体文件,提取音频和视频流 ;将编码后的音频或视频数据解码为原始数据;将原始音频或视频数据编码为特定格式;将音频和视频流重新封装为多媒体文件;
ffmpeg -i INPUT.mkv -map 0:v -map 0:a -c:v libx264 -c:a copy OUTPUT.mp4
简单的 filtergraph
- 将编码后的音频或视频数据解码为原始数据;并对原始数据进行处理;将原始音频或视频数据编码为特定格式;
复杂 filtergraph 它可能有多个输入,多个输出,可能是不同类型的(音频或 video)
- 第二个输入的帧将叠加在来自第一个输入的帧上。第三个 input 被重新缩放,然后被复制到两个相同的流中。其中之一 它们叠加在组合的前两个输入上,显示为 FilterGraph 的第一个输出。另一个是 filterGraph 的第二个输出
基本命令
ffmpeg -y -c:a libfdk_aac -c:v libx264 -i input.mp4 -c:v libvpx-vp9 -c:a libvorbis output.webm
- -y:不经过确认,输出时直接覆盖同名文件
- -c:指定编码器
- -c copy:直接复制,不经过重新编码(这样比较快)
- -c:v:指定视频编码器
- -c:a:指定音频编码器
- -i:指定输入文件
- -an:去除音频流
- -vn: 去除视频流
- -preset:指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow。
- -f:fmt指定格式(音频或视频格式)
- -t:duration 记录时长为t
- -acodec: 音频选项, 一般后面加copy表示拷贝
- -vcodec:视频选项,一般后面加copy表示拷贝
- h264: 表示输出的是h264的视频裸流
- mp4: 表示输出的是mp4的视频
- mpegts: 表示ts视频流
ffmpeg -r 1 -i racing.mp4 -c:v libx264 -profile:v high -level:v 5.1 -c:a copy -r 60 racingoutput.mp4
- -r 强制输入文件的帧速率(仅对 Raw 格式有效)为 1 fps,并且 输出文件的帧速率为 24 fps
- -profile:v -level 设置H.264画质级别
ffmpeg -i input.avi output.mp4
- 通过重新编码媒体流,将输入媒体文件转换为其他格式
ffmpeg -i input.avi -b:v 64k -bufsize 64k output.mp4
- -b:v 64k 设置输出文件的视频码率为 64 kbit/s
Streamcopy 流复制 -map 的使用
ffmpeg -i INPUT.mkv -map 0:1 -c copy OUTPUT.mp4
ffmpeg -i INPUT0.mkv -i INPUT1.aac -map 0:0 -map 1:0 -c copy OUTPUT.mp4
ffmpeg -i INPUT.mkv -map 0:0 -c copy OUTPUT0.mp4 -map 0:1 -c copy OUTPUT1.mp4
推拉流RTSP命令
UDP推流
ffmpeg -re -i input.mp4 -c copy -f rtsp rtsp://127.0.0.1:8554/stream
- -re 为以流的方式读取
TCP推流
ffmpeg -re -i input.mp4 -c copy -rtsp_transport tcp -f rtsp rtsp://127.0.0.1:8554/stream
循环推流
ffmpeg -re -stream_loop -1 -i input.mp4 -c copy -f rtsp rtsp://127.0.0.1:8554/stream
- -stream_loop 为循环读取视频源的次数,-1为无限循环
拉流
ffplay rtsp://127.0.0.1:8554/stream
FFmpeg拉流保存成视频
ffmpeg -stimeout 30000000 -i rtsp://127.0.0.1:8554/stream -c copy output.mp4
- -stimeout 30000000 为等待RTSP 流连接的时间,单位为us微秒,等待 30 秒如果连接失败则退出
过滤器(fliter)命令
-
过滤器就是实现某一种视频功能的工具,FFmpeg自带开发了很多种filter用于实现不同的功能
-
源视频宽度扩大两倍
ffmpeg -i jidu.mp4 -t 10 -vf pad=2 * iw output.mp4
- 源视频水平翻转
ffmpeg -i jidu.mp4 -t 10 -vf hflip output2.mp4
- 水平翻转视频覆盖output.mp4
ffmpeg -i output.mp4 -i output2.mp4 -filter_complex overlay=w compare.mp4
核心结构体
- 围绕解协议,解封装,解码
- libavcodec 的核心是 AVCodec 和 AVCodecContext
AVIOContext,URLProtocol,URLContext,AVFormatContext
解协议(http,rtsp,rtmp,mms)
- AVIOContext,URLProtocol,URLContext
- AVIOContext是FFMPEG管理输入输出数据的结构体,内含指针指向URLContext结构体
- URLContext结构体中包含结构体URLProtocol
- URLContext存储音频/视频使用的协议的类型以及状态
- URLProtocol存储音频/视频使用的协议(rtp,rtmp,file等)操作函数接口
解封装(flv,avi,rmvb,mp4)
- AVFormatContext存储音频/视频封装包含的数据和信息
- AVInputFormat表示音频/视频输入格式
AVCodec AVCodecContext AVStream
架构类似于昇腾的device conent steam
解码(h264,mpeg2,aac,mp3)
- AVCodecContext,存储该音视频流使用解码器的相关数据(所需的上下文环境)
- AVCodec (该音视频的解码器)(h264 mpeg2 AAC mp3)
- 实际使用时有可能会有多个 AVCodecContext 关联同一个 AVCodec 的情况。尤其是我们解码音频的时候。
音频文件时 5.1声道的 AVCodec AVCodecContext AVStream关系
-
通常会对应 3 个 AVStream
- 左右声道在一个 AVStream
- 环绕声在一个 AVStream
- 最后低音在另一个AVStream
-
3 个AVStream的编码可能是相同的
-
解码这个音频文件时就应该建立 3 个 AVCodecContext ,分别对应三个 AVStream。然后只需要有 1 个 AVCodec 。每个 AVCodecContext 都利用这一个 AVCodec 来解码。
AVPacket - AVFrame
- 所谓解码就是把一个 AVPacket 中的数据解成 AVFrame
- AVPacket是 编码压缩之后的数据
- AVFrame 是原始的,没有编码、没有压缩的数据 对视频来说是YUV RGB,对音频来说是PCM
I帧 P帧 B帧 的影响
-
我们会遇到前几个 AVPacket 解不出数据。
- 到了某个 AVPacket ,可以连续解出多个 AVFrame 来的情况。
- 这时这多个 AVFrame 就包括前面积压的 AVPacket 里的数据
-
avcodec_send_packet() 调用一次将一个 packet 推给Codec,
-
avcodec_receive_frame() 调用一次或多次来获得 frame
华为昇腾ACLLite库封装ffmpeg案例
什么是华为昇腾ACLLite库?
- ACLLite库是对CANN提供的ACL接口进行的高阶封装,简化用户调用流程,为用户提供一组简易的公共接口。当前主要针对边缘场景设计
ACLLite\Media\CameraRead.cpp
void CameraRead::DecodeFrameThread(void* decoderSelf)
对照核心结构体 理解 具体解码流程
void CameraRead::DecodeFrameThread(void* decoderSelf)
{CameraRead* thisPtr = (CameraRead*)decoderSelf;int videoStreamIndex = -1;for (int i = 0; i < thisPtr->formatContext_->nb_streams; ++i) {if (thisPtr->formatContext_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {videoStreamIndex = i;break;}}if (videoStreamIndex == -1) {LOG_PRINT("[ERROR] usb camera %s index is -1", thisPtr->streamName_.c_str());thisPtr->isOpened_ = false;return;}AVCodecParameters* codecParameters = thisPtr->formatContext_->streams[videoStreamIndex]->codecpar;AVCodec* codec = avcodec_find_decoder(codecParameters->codec_id);if (codec == nullptr) {LOG_PRINT("[ERROR] Could not find ffmpeg decoder.");thisPtr->isOpened_ = false;return;}AVCodecContext* codecContext = avcodec_alloc_context3(codec);if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) {LOG_PRINT("[ERROR] Could not create decoder context.");thisPtr->isOpened_ = false;return;}if (avcodec_open2(codecContext, codec, nullptr) < 0) {LOG_PRINT("[ERROR] Could not open decoder context.");thisPtr->isOpened_ = false;return;}AVFrame* frame = av_frame_alloc();AVPacket packet;while (av_read_frame(thisPtr->formatContext_, &packet) >= 0 && !thisPtr->isStop_) {if (packet.stream_index == videoStreamIndex) {int response = avcodec_send_packet(codecContext, &packet);if (response < 0 || response == AVERROR(EAGAIN)) {continue;}while (response >= 0) {response = avcodec_receive_frame(codecContext, frame);if (response == AVERROR(EAGAIN)) {break;} else if (response < 0) {LOG_PRINT("[ERROR] Receive false frame from ffmpeg.");thisPtr->isOpened_ = false;return;}bool ret = thisPtr->SendFrame(packet.data, packet.size);if (!ret) {thisPtr->isOpened_ = false;LOG_PRINT("[ERROR] Send single frame from ffmpeg failed.");return;}}}av_packet_unref(&packet);}av_frame_free(&frame);avcodec_close(codecContext);avformat_close_input(&thisPtr->formatContext_);thisPtr->isOpened_ = false;return;
}
- avcodec_find_decoder 根据编解码参数的编解码器ID查找对应的编解码器
- avcodec_alloc_context3 分配编解码器上下文
- avcodec_open2 打开编解码器上下文
- av_frame_alloc 分配帧结构体
- av_read_frame 从输入文件中读取一个数据包(AVPacket),并将其存储到 packet 中
- avcodec_send_packet 将一个数据包发送到解码器
- avcodec_receive_frame 从解码器中接收一个解码后的帧
- SendFrame 用于将解码后的帧发送到其他地方(例如显示或进一步处理)
- av_frame_free avcodec_close avformat_close_input 最后释放资源
ACLLite\DVPPLite\src\VideoRead.cpp
void FFmpegDecoder::Decode(FrameProcessCallBack callback,void *callbackParam)
对照核心结构体 理解 具体解码流程
void FFmpegDecoder::Decode(FrameProcessCallBack callback,void *callbackParam)
{LOG_PRINT("[INFO] Start ffmpeg decode video %s ...", streamName_.c_str());avformat_network_init(); // init networkAVFormatContext* avFormatContext = avformat_alloc_context();// check open video resultif (!OpenVideo(avFormatContext)) {return;}int videoIndex = GetVideoIndex(avFormatContext);if (videoIndex == kInvalidVideoIndex) { // check video index is validLOG_PRINT("[ERROR] Rtsp %s index is -1", streamName_.c_str());return;}AVBSFContext* bsfCtx = nullptr;// check initialize video parameters resultif (!InitVideoParams(videoIndex, avFormatContext, bsfCtx)) {return;}LOG_PRINT("[INFO] Start decode frame of video %s ...", streamName_.c_str());AVPacket avPacket;int processOk = true;// loop to get every frame from video streamwhile ((av_read_frame(avFormatContext, &avPacket) == 0) && processOk && !isStop_) {if (avPacket.stream_index == videoIndex) { // check current stream is video// send video packet to ffmpegif (av_bsf_send_packet(bsfCtx, &avPacket)) {LOG_PRINT("[ERROR] Fail to call av_bsf_send_packet, channel id:%s",streamName_.c_str());}// receive single frame from ffmpegwhile ((av_bsf_receive_packet(bsfCtx, &avPacket) == 0) && !isStop_) {int ret = callback(callbackParam, avPacket.data, avPacket.size);if (ret != 0) {processOk = false;break;}}}av_packet_unref(&avPacket);}av_bsf_free(&bsfCtx); // free AVBSFContext pointeravformat_close_input(&avFormatContext); // close input videoisFinished_ = true;LOG_PRINT("[INFO] Ffmpeg decoder %s finished", streamName_.c_str());
}
- av_read_frame 从输入文件中读取一个数据包(AVPacket)
- av_bsf_send_packet 数据包发送到解码器
- av_bsf_receive_packet 从解码器中接收解码后的帧
- callback 进一步处理
- av_packet_unref av_bsf_free avformat_close_input 最后释放资源
根据对应类型初始化过滤器
void FFmpegDecoder::InitVideoStreamFilter(const AVBitStreamFilter*& videoFilter)
{if (videoType_ == AV_CODEC_ID_H264) { // check video type is h264videoFilter = av_bsf_get_by_name("h264_mp4toannexb"); // 目的是从Avcodec库中获取一个名为"h264_mp4toannexb"的视频过滤器。} else { // the video type is h265videoFilter = av_bsf_get_by_name("hevc_mp4toannexb");}
}
附录-h264基础概念
H264
为什么诞生
-
⼀段分辨率为 1920 * 1080,每个像素点为 RGB 占⽤3 个字节,帧率是 25 的视频,对于传输带宽的要求是
-
换成 bps 则意味着视频每秒带宽为 1186.523Mbps,这样的速率对于⽹络存储是不可接受的
-
H264 采⽤了 16 * 16 的分块⼤⼩对,视频帧图像进⾏相似⽐较和压缩编码
- 一帧图片经过 H.264 编码器之后,就被编码为一个或多个片(slice),而装载着这些片(slice)的载体,就是 NALU 了
H264有两种封装
-
H.264码流分Annex-B和mp4两种格式。
-
⼀种是 annexb 模式,传统模式
-
⼀种是 mp4 模式,⼀般 mp4 mkv 都是 mp4 模式
-
很多解码器只⽀持 annexb 这种模式,因此需要将 mp4 做转换:
-
在 ffmpeg 中⽤h264_mp4toannexb_filter 可以做转换
ffmpeg -i INPUT.mp4 -codec copy -bsf:v h264_mp4toannexb OUTPUT.ts
- -bsf:v h264_mp4toannexb:指定视频过滤器为h264_mp4toannexb,这个过滤器的作用是将H.264流从长度前缀模式转换为开始代码前缀模式。
H.264有四种画质级别,分别是baseline, extended, main, high:
- Baseline Profile:基本画质。支持I/P 帧,只支持无交错(Progressive)和CAVLC;
- Extended profile:进阶画质。支持I/P/B/SP/SI 帧,只支持无交错(Progressive)和CAVLC;(用的少)
- Main profile:主流画质。提供I/P/B 帧,支持无交错(Progressive)和交错(Interlaced), 也支持CAVLC 和CABAC 的支持;
- High profile:高级画质。在main Profile 的基础上增加了8x8内部预测、自定义量化、 无损视频编码和更多的YUV 格式;
ffmpeg -i input.mp4 -profile:v baseline -level 3.0 output.mp4
ffmpeg -i input.mp4 -profile:v main -level 4.2 output.mp4
ffmpeg -i input.mp4 -profile:v high -level 5.1 output.mp4
GOP - I帧 P帧 B帧
-
编码器将多张图像进行编码后生产成一段一段的 GOP ( Group of Pictures )
-
解码器在播放时则是读取一段一段的 GOP 进行解码后读取画面再渲染显示
-
GOP ( Group of Pictures) 是一组连续的画面,由一张 I 帧和数张 B / P 帧组成
-
I 帧是内部编码帧(也称为关键帧),P帧是前向预测帧(前向参考帧),B 帧是双向内插帧(双向参考帧)
简单地讲,I 帧是一个完整的画面,而 P 帧和 B 帧记录的是相对于 I 帧的变化。
- I帧表示关键帧,你可以理解为经过适度地压缩这一帧画面的完整保留
- P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别
- B帧记录的是本帧与前后帧的差别
- B帧传送的是它与前面的I帧或P帧和后面的P帧之间的预测误差及运动矢量
有了 I帧,P帧, 为什么需要B帧
- 因为B帧记录的是前后帧的差别,比P帧能节约更多的空间
IDR 图像(立即刷新图像)
- 一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像
- H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,
- 将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列
- 如果前一个序列出现重大错误,在这里可以获得重新同步的机会
- IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码
DTS PTS
为什么会有PTS和DTS的概念
-
P帧需要参考前面的I帧或P帧才可以生成一张完整的图片
-
B帧则需要参考前面I帧或P帧及其后面的一个P帧才可以生成一张完整的图片
-
这样就带来了一个问题:在视频流中,先到来的 B 帧无法立即解码,需要等待它依赖的后面的 I、P 帧先解码完成,这样一来播放时间与解码时间不一致了,顺序打乱了,那这些帧该如何播放呢?
PTS和DTS的概念
- DTS(Decoding Time Stamp):即解码时间戳
- 这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。
- PTS(Presentation Time Stamp):即显示时间戳
- 这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。
文档链接说明
-
官方文档
Documentation (ffmpeg.org) -
基本概念
I帧、P帧、B帧、GOP、IDR 和PTS, DTS之间的关系 - 夜行过客 - 博客园 -
参考文档
音视频八股文 – h264 AnnexB_音视频开发面试八股文-CSDN博客 -
参考文档
FFmpeg基础知识之-—— H264编码profile & level控制_ffmpeg level-CSDN博客 -
参考文档
基于 FFMPEG 的视频解码(libavcodec ,致敬雷霄骅)-CSDN博客 -
参考文档
ffmpeg 结构体之间的关系_packet解码frame之间的对应-CSDN博客
FFMPEG结构体分析:AVIOContext-CSDN博客 -
参考文档
ffmpeg 常用命令汇总_ffmpeg命令大全-CSDN博客
基于FFmpeg进行rtsp推流及拉流(详细教程)_ffmpeg rtsp推流-CSDN博客 -
华为昇腾ACLLite仓库
Ascend/ACLLite -
华为昇腾对照概念
AscendCL架构及基本概念-AscendCL应用开发概述-AscendCL应用开发(C&C++)-应用开发-开发指南-CANN社区版8.0.0.alpha003开发文档-昇腾社区
相关文章:

协议-ACLLite-ffmpeg
是什么? FFmpeg是一个开源的多媒体处理工具包,它集成了多种功能,包括音视频的录制、转换和流式传输处理。FFmpeg由一系列的库和工具组成,其中最核心的是libavcodec和libavformat库。 libavcodec是一个领先的音频/视频编解码器库&…...

ARM嵌入式学习--第十四天(SPI)
SPI -介绍 SPI(Serial Peripheral Interface)串行外围设备接口。是由Motorola公司开发,用来在微控制器和外围设备芯片之间提供一个低成本,易使用的接口。这样接口可以用来连接存储器、AD转换器、DA转换器、实时时钟、LCD驱动器、…...

DeepSeek-V2 论文解读:混合专家架构的新突破
论文链接:DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model 目录 一、引言二、模型架构(一)多头部潜在注意力(MLA):重塑推理效率(二)DeepSeekM…...

5分钟了解回归测试
1. 什么是回归测试(Regression Testing) 回归测试是一个系统的质量控制过程,用于验证最近对软件的更改或更新是否无意中引入了新错误或对以前的功能方面产生了负面影响(比如你在家中安装了新的空调系统,发现虽然新的空…...

路由器如何进行数据包转发?
路由器进行数据包转发的过程是网络通信的核心之一,主要涉及以下几个步骤: 接收数据包:当一个数据包到达路由器的一个接口时,它首先被暂时存储在该接口的缓冲区中。 解析目标地址:路由器会检查数据包中的目标IP地址。…...

【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(四) -> 常见组件(一)
目录 1 -> List 1.1 -> 创建List组件 1.2 -> 添加滚动条 1.3 -> 添加侧边索引栏 1.4 -> 实现列表折叠和展开 1.5 -> 场景示例 2 -> dialog 2.1 -> 创建Dialog组件 2.2 -> 设置弹窗响应 2.3 -> 场景示例 3 -> form 3.1 -> 创建…...

iOS 自动翻滚广告条(榜单条)实现方案
引言 在直播场景中,榜单信息、活动公告或者广告推广通常需要以醒目的方式展示,但由于屏幕空间有限,一次只能显示一条内容。为了让用户能够持续关注这些信息,我们可以实现一个自动翻滚的广告条(或榜单条)&a…...

TensorFlow深度学习实战(7)——分类任务详解
TensorFlow深度学习实战(7)——分类任务详解 0. 前言1. 分类任务1.1 分类任务简介1.2 分类与回归的区别 2. 逻辑回归3. 使用 TensorFlow 实现逻辑回归小结系列链接 0. 前言 分类任务 (Classification Task) 是机器学习中的一种监督学习问题,…...

动态规划问题——青蛙跳台阶案例分析
问题描述: 一只青蛙要跳上n级台阶,它每次可以跳 1级或者2级。问:青蛙有多少种不同的跳法可以跳完这些台阶? 举个例子: 假设台阶数 n 3 ,我们来看看青蛙有多少种跳法。 可能的跳法: 1. 跳1级…...
element-ui使用el-table,保留字段前的空白
项目名称项目编号1、XXXXX1111111111111111111 1.1 XXXXX11111111111111222222222 如上表格中,实现项目名称字段1.1前空白的效果。 从JAVA返回的数据带有空白,即数据库中插入的数据带有空白。 原先写法: <el-table><el-tabl…...
kamailio中路由模块汇总
功能模块描述请求路由 (request_route)主要处理进入的SIP请求,包含初步检查、NAT检测、CANCEL请求处理、重传处理等。处理通过REQINIT、NATDETECT、RELAY等子模块的调用。CANCEL处理对CANCEL请求进行处理,包括更新对话状态并检查事务。如果事务检查通过&…...
如何使用 DeepSeek 搭建本地知识库
使用 DeepSeek 搭建本地知识库可以帮助您高效管理和检索本地文档、数据或知识资源。以下是详细的步骤指南: 1. 准备工作 (1) 安装 DeepSeek 确保您的系统已安装 Python 3.8 或更高版本。使用 pip 安装 DeepSeek: bash pip install deepseek (2) 准备…...
网络HTTP详细讲解
学习目标 什么是HTTPHTTP的请求和响应常见的HTTP状态码HTTP的安全性 什么是HTTP?HTTP的请求和响应,常见的HTTP状态码,HTTP的安全性 什么是HTTP HTTP(HyperText Transfer Protocol,超文本传输协议)是一种用…...

《Origin画百图》之边际分布曲线图
《Origin画百图》第六集——边际分布曲线图 入门操作可看《30秒,带你入门Origin》 边际分布曲线图,其中包含散点图形,而在图的边际有着分布曲线图。在比较数据以查看多个变量之间是否存在关系时非常有用。 1.数据准备:为多列XY数…...
【Milvus】向量数据库pymilvus使用教程
以下是根据 Milvus 官方文档整理的详细 PyMilvus 使用教程,基于 Milvus 2.5.x 版本: PyMilvus 使用教程 目录 安装与环境准备连接 Milvus 服务数据模型基础概念创建集合(Collection)插入数据创建索引向量搜索删除操作完整示例注…...
React 生命周期函数详解
React 组件在其生命周期中有多个阶段,每个阶段都有特定的生命周期函数(Lifecycle Methods)。这些函数允许你在组件的不同阶段执行特定的操作。以下是 React 组件生命周期的主要阶段及其对应的生命周期函数,并结合了 React 16.3 的…...

第 26 场 蓝桥入门赛
2.对联【算法赛】 - 蓝桥云课 问题描述 大年三十,小蓝和爷爷一起贴对联。爷爷拿出了两副对联,每副对联都由 N 个“福”字组成,每个“福”字要么是正的(用 1 表示),要么是倒的(用 0 表示&#…...
组合(力扣77)
从这道题开始,我们正式进入回溯算法的学习。之前在二叉树中只是接触到了一丢丢,而这里我们将使用回溯算法解决很多经典问题。 那么这道题是如何使用回溯算法的呢?在讲回溯之前,先说明一下此题是如何递归的。毕竟回溯递归不分家&a…...

网络工程师 (22)网络协议
前言 网络协议是计算机网络中进行数据交换而建立的规则、标准或约定的集合,它规定了通信时信息必须采用的格式和这些格式的意义。 一、基本要素 语法:规定信息格式,包括数据及控制信息的格式、编码及信号电平等。这是协议的基础,确…...

Linux之文件IO前世今生
在 Linux之文件系统前世今生(一) VFS中,我们提到了文件的读写,并给出了简要的读写示意图,本文将分析文件I/O的细节。 一、Buffered I/O(缓存I/O)& Directed I/O(直接I/O&#…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...