协议-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 network

    AVFormatContext* avFormatContext = avformat_alloc_context();

    // check open video result
    if (!OpenVideo(avFormatContext)) {
        return;
    }

    int videoIndex = GetVideoIndex(avFormatContext);
    if (videoIndex == kInvalidVideoIndex) { // check video index is valid
        LOG_PRINT("[ERROR] Rtsp %s index is -1", streamName_.c_str());
        return;
    }

    AVBSFContext* bsfCtx = nullptr;
    // check initialize video parameters result
    if (!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 stream
    while ((av_read_frame(avFormatContext, &avPacket) == 0) && processOk && !isStop_) {
        if (avPacket.stream_index == videoIndex) { // check current stream is video
          // send video packet to ffmpeg
            if (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 ffmpeg
            while ((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 pointer
    avformat_close_input(&avFormatContext); // close input video

    isFinished_ = 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 h264
        videoFilter = av_bsf_get_by_name("h264_mp4toannexb"); // 目的是从Avcodec库中获取一个名为"h264_mp4toannexb"的视频过滤器。
    } else { // the video type is h265
        videoFilter = 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开发文档-昇腾社区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/967585.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DuckDB:pg_duckdb集成DuckDB和PostgreSQL实现高效数据分析

pg_duckdb是PostgreSQL的扩展&#xff0c;它将DuckDB的列矢量化分析引擎和特性嵌入到PostgreSQL中。本文介绍pg_duckdb插件安装、特点以及如何快速入门使用。 pg_duckdb简介 pg_duckdb扩展将完全能够查询DuckDB中存储在云中的数据&#xff0c;就像它是本地的一样。DuckDB的“双…

防火墙安全综合实验

防火墙安全综合实验 一、拓扑信息 二、需求及配置 实验步骤 需求一&#xff1a;根据下表&#xff0c;完成相关配置 设备接口VLAN接口类型SW2GE0/0/2VLAN 10AccessGE0/0/3VLAN 20AccessGE0/0/1VLAN List&#xff1a;10 20Trunk 1、创建vlan10和vlan20 2、将接口划分到对应…

Vue 响应式渲染 - 过滤应用

Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue响应式渲染综合 - 过滤应用 目录 过滤应用 引入vue Vue设置 设置页面元素 模糊查询过滤实现 函数表达式实现 总结 过滤应用 综合响应式渲染做一个输入框&#xff0c;用来实现&#xff1b;搜索输入框关键词符合列表。…

一文学会:用DeepSeek R1/V3 + AnythingLLM + Ollama 打造本地化部署的个人/企业知识库,无须担心数据上传云端的泄露问题

文章目录 前言一、AnythingLLM 简介&基础应用1.主要特性2.下载与安装3.配置 LLM 提供商4.AnythingLLM 工作区&对话 二、AnythingLLM 进阶应用&#xff1a;知识增强使用三、AnythingLLM 的 API 访问四、小结1.聊天模式2.本地存储&向量数据库 前言 如果你不知道Olla…

CNN-LSTM卷积神经网络长短期记忆神经网络多变量多步预测,光伏功率预测

CNN-LSTM卷积神经网络长短期记忆神经网络多变量多步预测&#xff0c;光伏功率预测 一、引言 1.1、研究背景和意义 光伏发电作为一种清洁能源&#xff0c;对于实现能源转型和应对气候变化具有重要意义。然而&#xff0c;光伏发电的输出功率具有很强的间歇性和波动性&#xff…

cppcheck静态扫描代码是否符合MISRA-C 2012规范

1 下载安装cppcheck 1.1 下载安装包 下载地址&#xff1a;http://cppcheck.net/ 同时把 Source code (.zip) 也下载下来&#xff0c;后面会用到。 1.2 安装及配置 双击安装文件&#xff0c;保持默认配置安装即可&#xff0c;默认安装的路径为&#xff1a;C:\Program Files\…

【Unity3D】UGUI的anchoredPosition锚点坐标

本文直接以实战去理解锚点坐标&#xff0c;围绕着将一个UI移动到另一个UI位置的需求进行说明。 &#xff08;anchoredPosition&#xff09;UI锚点坐标&#xff0c;它是UI物体的中心点坐标&#xff0c;以UI物体锚点为中心的坐标系得来&#xff0c;UI锚点坐标受锚点(Anchors Min…

【Hadoop】大数据权限管理工具Ranger2.1.0编译

目录 ​编辑一、下载 ranger源码并编译 二、报错信息 报错1 报错2 报错3 报错4 一、下载 ranger源码并编译 ranger官网 https://ranger.apache.org/download.html 由于Ranger不提供二进制安装包&#xff0c;故需要maven编译。安装其它依赖&#xff1a; yum install gcc …

C++20导出模块及使用

1.模块声明 .ixx文件为导入模块文件 math_operations.ixx export module math_operations;//模块导出 //导出命名空间 export namespace math_ {//导出命名空间中函数int add(int a, int b);int sub(int a, int b);int mul(int a, int b);int div(int a, int b); } .cppm文件…

使用 mkcert 本地部署启动了 TLS/SSL 加密通讯的 MongoDB 副本集和分片集群

MongoDB 是支持客户端与 MongoDB 服务器之间启用 TLS/SSL 进行加密通讯的, 对于 MongoDB 副本集和分片集群内部的通讯, 也可以开启 TLS/SSL 认证. 本文会使用 mkcert 创建 TLS/SSL 证书, 基于创建的证书, 介绍 MongoDB 副本集、分片集群中启动 TLS/SSL 通讯的方法. 我们将会在…

2、k8s的cni网络插件和基本操作命令

kube-prxoy属于节点组件&#xff0c;网络代理&#xff0c;实现服务的自动发现和负载均衡。 k8s的内部网络模式 1、pod内的容器于容器之间的通信。 2、一个节点上的pod之间的通信&#xff0c;docker0网桥直接通信。 3、不同节点上的pod之间的通信&#xff1a; 通过物理网卡的…

如何在RTACAR中配置IP多播(IP Multicast)

一、什么是IP多播 IP多播&#xff08;IP Multicast&#xff09;是一种允许数据包从单一源地址发送到多个目标地址的技术&#xff0c;是一种高效的数据传输方式。 多播地址是专门用于多播通信的IP地址&#xff0c;范围从 224.0.0.0到239.255.255.255 与单播IP地址不同&#x…

JavaEE架构

一.架构选型 1.VM架构 VM架构通常指的是虚拟机&#xff08;Virtual Machine&#xff09;的架构。虚拟机是一种软件实现的计算机系统&#xff0c;它模拟了物理计算机的功能&#xff0c;允许在单一物理硬件上运行多个操作系统实例。虚拟机架构主要包括以下几个关键组件&#xff…

车载测试工具 --- CANoe VH6501 进行Not Acknowledge (NAck) 测试

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

第40天:Web开发-JS应用VueJS框架Vite构建启动打包渲染XSS源码泄露代码审计

#知识点 1、安全开发-VueJS-搭建启动&打包安全 2、安全开发-VueJS-源码泄漏&代码审计 一、Vue搭建创建项目启动项目 1、Vue 框架搭建->基于nodejs搭建&#xff0c;安装nodejs即可 参考&#xff1a;https://cn.vuejs.org/ 已安装18.3或更高版本的Node.js 2、Vue 创建…

Axure原型图怎么通过链接共享

一、进入Axure 二、点击共享 三、弹出下面弹框&#xff0c;点击发布就可以了 发布成功后&#xff0c;会展示链接&#xff0c;复制即可共享给他人 四、发布失败可能的原因 Axure未更新&#xff0c;首页菜单栏点击帮助选择Axure更新&#xff0c;完成更新重复以上步骤即可

DeepSeek本地化部署

DeepSeek本地化部署 本教程为一键式部署&#xff0c;适合于mac、ubuntu、windows。【开源地址】 环境要求 nodejs > 18Python > 3.10.12 步骤一&#xff1a;安装ollama客户端 官网直接安装&#xff0c;ollama官网。安装完成后使用命令&#xff1a;ollama -h&#xf…

单片机学习笔记——入门51单片机

一、单片机基础介绍 1.何为单片机 单片机&#xff0c;英文Micro Controller Unit&#xff0c;简称MCU 。内部集成了中央处理器CPU、随机存储器ROM、只读存储器RAM、定时器/计算器、中断系统和IO口等一系列电脑的常用硬件功能 单片机的任务是信息采集&#xff08;依靠传感器&a…

DeepSeek-R1相关论文解读

另&#xff1a;数学推理论文篇&#xff1a;DeepSeekMath 一、DeepSeek-R1-Zero和DeepSeek R1区别 都使用了RL强化学习中的GROP&#xff0c;但是R1还使用了SFT&#xff0c;进行了多阶段训练。 1. 什么是SFT&#xff1f; SFT是给模型一些正确例子&#xff1a;情况1 answer&…

【AIGC】语言模型的发展历程:从统计方法到大规模预训练模型的演化

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;语言模型的发展历程&#xff1a;从统计方法到大规模预训练模型的演化1 统计语言模型&#xff08;Statistical Language Model, SLM&#xff09;&#xff1a;统…