当前位置: 首页 > news >正文

协议-ACLLite-ffmpeg

是什么?

  • FFmpeg是一个开源的多媒体处理工具包,它集成了多种功能,包括音视频的录制、转换和流式传输处理。
  • FFmpeg由一系列的库和工具组成,其中最核心的是libavcodec和libavformat库。
    • libavcodec是一个领先的音频/视频编解码器库,支持多种音频和视频格式的编码和解码操作。
    • libavformat库则用于处理各种不同的多媒体容器格式,如MP4、AVI、MKV等。它能够解析提取其中的音频和视频流,以便进行进一步的处理

为什么?

为什么有GStreamer的前提下,还要使用FFmpeg?

  • 在某些情况下,GStreamer 会比 FFmpeg 更适合特定的需求
    • FFmpeg 是一个功能强大的单体框架,主要专注于媒体的编解码、转码和流处理
    • GStreamer适合构建复杂的媒体处理管道,如视频会议、实时流媒体处理和视频编辑
功能FFmpegGStreamer
核心架构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:将音频和视频流重新封装为多媒体文件。

![[Pasted image 20240704090349.png]]

  • Demuxer:拆解多媒体文件,提取音频和视频流。

![[Pasted image 20250206212037.png]]

  • 解码器接收音频、视频、 或字幕基本流,并将它们解码为原始帧( 视频的像素,音频的 PCM)

![[Pasted image 20250206212045.png]]

  • 编码器接收原始音频、视频或字幕帧并进行编码 它们被编码为数据包

![[Pasted image 20250206212106.png]]

  • Muxer:将音频和视频流重新封装为多媒体文件

![[Pasted image 20250206212115.png]]


大局观总览

  • 库总览

![[Pasted image 20240704161618.png]]

真正有用三库

  • libavcodec库包含多种音频、视频和字幕流的解码器和编码器,以及多种位流过滤器。
  • libavformat库用于将音频、视频和字幕流多路复用和解复用
  • libavfilter库用于处理音频/视频数据,例如进行视频的缩放、裁剪、旋转,音频的混音、音量调整

辅助类型库

  • libavutil包含了一些安全的、可移植的字符串函数、随机数生成器、数据结构、额外的数学函数、密码学和与多媒体相关的功能(如枚举像素和采样格式)

  • libswscale是一个用于图像缩放和颜色空间以及像素格式转换的高效库。

  • libswresample是一个高度优化的音频重采样、重矩阵和采样格式转换库。

  • libavdevice是一个通用的框架,用于抓取和渲染许多常见的多媒体输入/输出设备。

  • 命令总览

![[Pasted image 20240704161704.png]]

  • 功能总览

![[Pasted image 20240704161807.png]]

转换格式流程图

  • 输入文件拆解多媒体文件,提取音频和视频流 ;将编码后的音频或视频数据解码为原始数据;将原始音频或视频数据编码为特定格式;将音频和视频流重新封装为多媒体文件;

![[Pasted image 20250206170140.png]]

ffmpeg -i INPUT.mkv -map 0:v -map 0:a -c:v libx264 -c:a copy OUTPUT.mp4

简单的 filtergraph

  • 将编码后的音频或视频数据解码为原始数据;并对原始数据进行处理;将原始音频或视频数据编码为特定格式;

![[Pasted image 20250206170159.png]]

复杂 filtergraph 它可能有多个输入,多个输出,可能是不同类型的(音频或 video)

  • 第二个输入的帧将叠加在来自第一个输入的帧上。第三个 input 被重新缩放,然后被复制到两个相同的流中。其中之一 它们叠加在组合的前两个输入上,显示为 FilterGraph 的第一个输出。另一个是 filterGraph 的第二个输出

![[Pasted image 20250206172117.png]]


基本命令

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 的使用

![[Pasted image 20250207162306.png]]

ffmpeg -i INPUT.mkv -map 0:1 -c copy OUTPUT.mp4

![[Pasted image 20250207162209.png]]

ffmpeg -i INPUT0.mkv -i INPUT1.aac -map 0:0 -map 1:0 -c copy OUTPUT.mp4

![[Pasted image 20250207162215.png]]

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表示音频/视频输入格式

![[Pasted image 20250207121801.png]]

AVCodec AVCodecContext AVStream

架构类似于昇腾的device conent steam

![[Pasted image 20250207000401.png]]

解码(h264,mpeg2,aac,mp3)

  • AVCodecContext,存储该音视频流使用解码器的相关数据(所需的上下文环境)
  • AVCodec (该音视频的解码器)(h264 mpeg2 AAC mp3)

![[Pasted image 20250207091506.png]]

  • 实际使用时有可能会有多个 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

![[Pasted image 20250207114701.png]]

I帧 P帧 B帧 的影响

  • 我们会遇到前几个 AVPacket 解不出数据。

    • 到了某个 AVPacket ,可以连续解出多个 AVFrame 来的情况。
    • 这时这多个 AVFrame 就包括前面积压的 AVPacket 里的数据
  • avcodec_send_packet() 调用一次将一个 packet 推给Codec,

  • avcodec_receive_frame() 调用一次或多次来获得 frame


华为昇腾ACLLite库封装ffmpeg案例

什么是华为昇腾ACLLite库?

  • ACLLite库是对CANN提供的ACL接口进行的高阶封装,简化用户调用流程,为用户提供一组简易的公共接口。当前主要针对边缘场景设计

![[Pasted image 20250207153015.png]]

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

![[Pasted image 20250206183105.png]]

为什么诞生

  • ⼀段分辨率为 1920 * 1080,每个像素点为 RGB 占⽤3 个字节,帧率是 25 的视频,对于传输带宽的要求是

  • 换成 bps 则意味着视频每秒带宽为 1186.523Mbps,这样的速率对于⽹络存储是不可接受的

  • H264 采⽤了 16 * 16 的分块⼤⼩对,视频帧图像进⾏相似⽐较和压缩编码

![[Pasted image 20250206184128.png]]

  • 一帧图片经过 H.264 编码器之后,就被编码为一个或多个片(slice),而装载着这些片(slice)的载体,就是 NALU 了

![[Pasted image 20250206184103.png]]

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 帧的变化。

![[Pasted image 20250206174901.png]]

  • I帧表示关键帧,你可以理解为经过适度地压缩这一帧画面的完整保留
  • P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别

![[Pasted image 20250206173959.png]]

  • B帧记录的是本帧与前后帧的差别
  • B帧传送的是它与前面的I帧或P帧和后面的P帧之间的预测误差及运动矢量

![[Pasted image 20250206174047.png]]

有了 I帧,P帧, 为什么需要B帧

  • 因为B帧记录的是前后帧的差别,比P帧能节约更多的空间

IDR 图像(立即刷新图像

  • 一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像
  • H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,
    • 将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列
  • 如果前一个序列出现重大错误,在这里可以获得重新同步的机会
    • IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码

![[Pasted image 20250206180211.png]]

DTS PTS

为什么会有PTS和DTS的概念

  • P帧需要参考前面的I帧或P帧才可以生成一张完整的图片

  • B帧则需要参考前面I帧或P帧及其后面的一个P帧才可以生成一张完整的图片

  • 这样就带来了一个问题:在视频流中,先到来的 B 帧无法立即解码,需要等待它依赖的后面的 I、P 帧先解码完成,这样一来播放时间与解码时间不一致了,顺序打乱了,那这些帧该如何播放呢?

PTS和DTS的概念

  • DTS(Decoding Time Stamp):即解码时间戳
    • 这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。
  • PTS(Presentation Time Stamp):即显示时间戳
    • 这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。

[Pasted image 20250206175718.png]]![在这里插入图片描述

文档链接说明

  • 官方文档
    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

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

ARM嵌入式学习--第十四天(SPI)

SPI -介绍 SPI&#xff08;Serial Peripheral Interface&#xff09;串行外围设备接口。是由Motorola公司开发&#xff0c;用来在微控制器和外围设备芯片之间提供一个低成本&#xff0c;易使用的接口。这样接口可以用来连接存储器、AD转换器、DA转换器、实时时钟、LCD驱动器、…...

DeepSeek-V2 论文解读:混合专家架构的新突破

论文链接&#xff1a;DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model 目录 一、引言二、模型架构&#xff08;一&#xff09;多头部潜在注意力&#xff08;MLA&#xff09;&#xff1a;重塑推理效率&#xff08;二&#xff09;DeepSeekM…...

5分钟了解回归测试

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

路由器如何进行数据包转发?

路由器进行数据包转发的过程是网络通信的核心之一&#xff0c;主要涉及以下几个步骤&#xff1a; 接收数据包&#xff1a;当一个数据包到达路由器的一个接口时&#xff0c;它首先被暂时存储在该接口的缓冲区中。 解析目标地址&#xff1a;路由器会检查数据包中的目标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 自动翻滚广告条(榜单条)实现方案

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

TensorFlow深度学习实战(7)——分类任务详解

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

动态规划问题——青蛙跳台阶案例分析

问题描述&#xff1a; 一只青蛙要跳上n级台阶&#xff0c;它每次可以跳 1级或者2级。问&#xff1a;青蛙有多少种不同的跳法可以跳完这些台阶&#xff1f; 举个例子&#xff1a; 假设台阶数 n 3 &#xff0c;我们来看看青蛙有多少种跳法。 可能的跳法&#xff1a; 1. 跳1级…...

element-ui使用el-table,保留字段前的空白

项目名称项目编号1、XXXXX1111111111111111111 1.1 XXXXX11111111111111222222222 如上表格中&#xff0c;实现项目名称字段1.1前空白的效果。 从JAVA返回的数据带有空白&#xff0c;即数据库中插入的数据带有空白。 原先写法&#xff1a; <el-table><el-tabl…...

kamailio中路由模块汇总

功能模块描述请求路由 (request_route)主要处理进入的SIP请求&#xff0c;包含初步检查、NAT检测、CANCEL请求处理、重传处理等。处理通过REQINIT、NATDETECT、RELAY等子模块的调用。CANCEL处理对CANCEL请求进行处理&#xff0c;包括更新对话状态并检查事务。如果事务检查通过&…...

如何使用 DeepSeek 搭建本地知识库

使用 DeepSeek 搭建本地知识库可以帮助您高效管理和检索本地文档、数据或知识资源。以下是详细的步骤指南&#xff1a; 1. 准备工作 (1) 安装 DeepSeek 确保您的系统已安装 Python 3.8 或更高版本。使用 pip 安装 DeepSeek&#xff1a; bash pip install deepseek (2) 准备…...

网络HTTP详细讲解

学习目标 什么是HTTPHTTP的请求和响应常见的HTTP状态码HTTP的安全性 什么是HTTP&#xff1f;HTTP的请求和响应&#xff0c;常见的HTTP状态码&#xff0c;HTTP的安全性 什么是HTTP HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一种用…...

《Origin画百图》之边际分布曲线图

《Origin画百图》第六集——边际分布曲线图 入门操作可看《30秒&#xff0c;带你入门Origin》 边际分布曲线图&#xff0c;其中包含散点图形&#xff0c;而在图的边际有着分布曲线图。在比较数据以查看多个变量之间是否存在关系时非常有用。 1.数据准备&#xff1a;为多列XY数…...

【Milvus】向量数据库pymilvus使用教程

以下是根据 Milvus 官方文档整理的详细 PyMilvus 使用教程&#xff0c;基于 Milvus 2.5.x 版本&#xff1a; PyMilvus 使用教程 目录 安装与环境准备连接 Milvus 服务数据模型基础概念创建集合&#xff08;Collection&#xff09;插入数据创建索引向量搜索删除操作完整示例注…...

React 生命周期函数详解

React 组件在其生命周期中有多个阶段&#xff0c;每个阶段都有特定的生命周期函数&#xff08;Lifecycle Methods&#xff09;。这些函数允许你在组件的不同阶段执行特定的操作。以下是 React 组件生命周期的主要阶段及其对应的生命周期函数&#xff0c;并结合了 React 16.3 的…...

第 26 场 蓝桥入门赛

2.对联【算法赛】 - 蓝桥云课 问题描述 大年三十&#xff0c;小蓝和爷爷一起贴对联。爷爷拿出了两副对联&#xff0c;每副对联都由 N 个“福”字组成&#xff0c;每个“福”字要么是正的&#xff08;用 1 表示&#xff09;&#xff0c;要么是倒的&#xff08;用 0 表示&#…...

组合(力扣77)

从这道题开始&#xff0c;我们正式进入回溯算法的学习。之前在二叉树中只是接触到了一丢丢&#xff0c;而这里我们将使用回溯算法解决很多经典问题。 那么这道题是如何使用回溯算法的呢&#xff1f;在讲回溯之前&#xff0c;先说明一下此题是如何递归的。毕竟回溯递归不分家&a…...

网络工程师 (22)网络协议

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

Linux之文件IO前世今生

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

如何在Windows中配置MySQL?

MySQL是一个广泛使用的开源关系型数据库管理系统&#xff0c;它支持多种操作系统平台&#xff0c;其中包括Windows。无论是开发者进行本地开发&#xff0c;还是管理员为应用程序配置数据库&#xff0c;MySQL都是一个非常流行的选择。本篇文章将详细介绍如何在Windows操作系统中…...

Kafka 入门与实战

一、Kafka 基础 1.1 创建topic kafka-topics.bat --bootstrap-server localhost:9092 --topic test --create 1.2 查看消费者偏移量位置 kafka-consumer-groups.bat --bootstrap-server localhost:9092 --describe --group test 1.3 消息的生产与发送 #生产者 kafka-cons…...

数学知识学习1

1、数论 1质数判定 i<n/i优化O(sqrt(n)) bool is_prime(int n){if(n<2)return false;for(int i2;i<n/i;i){if(n%i0)return false;} true; } 分解质因数 i<n/i优化O(sqrt(n)) // 定义一个函数 divide&#xff0c;接收一个整数 n 作为参数&#xff0c;用于分解质…...

【AI日记】25.02.08

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】【读书与思考】【AI应用】 探索 AI 应用探索周二有个面试&#xff0c;明后天打算好好准备一下&#xff0c;我打算主要研究下 AI 如何在该行业赋能和应用&#xff0c;以及该行业未来的发展前景和公司痛点&#…...

Lecture8 | LPV VXGI SSAO SSDO

Review: Lecture 7 | Lecture 8 LPV (Light Propagation Volumes) Light Propagation Volumes(LPV)-孤岛惊魂CryEngine引进的技术 LPV做GI快|好 大体步骤&#xff1a; Step1.Generation of Radiance Point Set Scene Representation 生成辐射点集的场景表示&#xff1a;辐射…...

Java中实现定时锁屏的功能(可以指定时间执行)

Java中实现定时锁屏的功能&#xff08;可以指定时间执行&#xff09; 要在Java中实现定时锁屏的功能&#xff0c;可以使用java.util.Timer或java.util.concurrent.ScheduledExecutorService来调度任务&#xff0c;并通过调用操作系统的命令来执行锁屏。下面我将给出一个基本的…...

Java集合List详解(带脑图)

允许重复元素&#xff0c;有序。常见的实现类有 ArrayList、LinkedList、Vector。 ArrayList ArrayList 是在 Java 编程中常用的集合类之一&#xff0c;它提供了便捷的数组操作&#xff0c;并在动态性、灵活性和性能方面取得了平衡。如果需要频繁在中间插入和删除元素&#xf…...

[实验日志] VS Code 连接服务器上的 Python 解释器进行远程调试

目录 0. 前言 1. 环境 2. 准备工作 2.1 安装VS Code 2.2 安装插件 2.3 配置远程服务器 2.4 修改设置 2.5 打开远程调试窗口 3. 调试代码 3.1 输密码 3.2 打开服务器文件夹 3.3 配置Python环境 3.4 调试Python代码 补充&#xff1a;使用调试控制台&#xff0c;查看…...

(14)gdb 笔记(7):以日志记录的方式来调试多进程多线程程序,linux 命令 tail -f 实时跟踪日志

&#xff08;44&#xff09;以日志记录的方式来调试多进程多线程程序 &#xff1a; 这是老师的日志文件&#xff0c;可以用来模仿的模板&#xff1a; &#xff08;45&#xff09;实时追踪日志的 tail -f 命令&#xff1a; &#xff08;46&#xff09; 多种调试方法结合起来用 …...

Sentinel的安装和做限流的使用

一、安装 Release v1.8.3 alibaba/Sentinel GitHubA powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件) - Release v1.8.3 alibaba/Sentinelhttps://github.com/alibaba/Senti…...