windows下使用FFmpeg开源库进行视频编解码完整步聚

news2024/11/15 8:33:19

最终解码效果:

1.UI设计

 2.在控件属性窗口中输入默认值

3.复制已编译FFmpeg库到工程同级目录下

 4.在工程引用FFmpeg库及头文件

 

5.链接指定FFmpeg库

 

6.使用FFmpeg库

引用头文件 

extern "C"
{
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/bsf.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libavutil/imgutils.h"
#include "libavutil/log.h"
#include "libavutil/imgutils.h"
#include "libavutil/time.h"
#include <libswresample/swresample.h>

}

创建视频编解码管理类 

实现视频编解码管理类

#include "ffmpegmananger.h"
#include <QThread>
ffmpegMananger::ffmpegMananger(QObject *parent ):
    QObject(parent)
{
    m_pInFmtCtx = nullptr;
    m_pTsFmtCtx  = nullptr;
    m_qstrRtspURL = "";
    m_qstrOutPutFile = "";
}
ffmpegMananger::~ffmpegMananger()
{
    avformat_free_context(m_pInFmtCtx);
    avformat_free_context(m_pTsFmtCtx);
}

void ffmpegMananger::getRtspURL(QString strRtspURL)
{
    this->m_qstrRtspURL = strRtspURL;
}
void ffmpegMananger::getOutURL(QString strRute)
{
    this->m_qstrOutPutFile = strRute;
    printf("===========%s\n",m_qstrOutPutFile.toStdString().c_str());
}
void ffmpegMananger::setOutputCtx(AVCodecContext *encCtx, AVFormatContext **pTsFmtCtx,int &nVideoIdx_out)
{
    avformat_alloc_output_context2(pTsFmtCtx , nullptr, nullptr, m_qstrOutPutFile.toStdString().c_str());
    if (!pTsFmtCtx ) {
        printf("Could not create output context\n");
        return;
    }
    if (avio_open(&((*pTsFmtCtx)->pb), m_qstrOutPutFile.toStdString().c_str(), AVIO_FLAG_READ_WRITE) < 0)
    {
       avformat_free_context(*pTsFmtCtx);
       printf("avio_open fail.");
       return;
    }
    AVStream *out_stream = avformat_new_stream(*pTsFmtCtx, encCtx->codec);
    nVideoIdx_out = out_stream->index;
    //nVideoIdx_out = out_stream->index;
    avcodec_parameters_from_context(out_stream->codecpar, encCtx);
    printf("==========Output Information==========\n");
    av_dump_format(*pTsFmtCtx, 0, m_qstrOutPutFile.toStdString().c_str(), 1);
    printf("======================================\n");
}
int ffmpegMananger::ffmepgInput()
{
    int nRet = 0;
    AVCodecContext *encCtx = nullptr;//编码器
    //const char *pUrl = "D:/videos/264.dat";
    std::string temp = m_qstrRtspURL.toStdString();
    const char *pUrl = temp.c_str();
    printf("===========%s\n",pUrl);
    AVDictionary *options = nullptr;
    av_dict_set(&options,"rtsp_transport", "tcp", 0);
    av_dict_set(&options,"stimeout","10000000",0);
    // 设置“buffer_size”缓存容量
    av_dict_set(&options, "buffer_size", "1024000", 0);
    nRet = avformat_open_input(&m_pInFmtCtx,pUrl,nullptr,&options);
    if( nRet < 0)
    {
        printf("Could not open input file,===========keep trying \n");
        return nRet;
    }
    avformat_find_stream_info(m_pInFmtCtx, nullptr);
    printf("===========Input Information==========\n");
    av_dump_format(m_pInFmtCtx, 0, pUrl, 0);
    printf("======================================\n");
    //1.获取视频流编号
    int nVideo_indx = av_find_best_stream(m_pInFmtCtx,AVMEDIA_TYPE_VIDEO,-1,-1,nullptr,0);
    if(nVideo_indx < 0)
    {
        avformat_free_context(m_pInFmtCtx);
        printf("查找解码器失败\n");
        return -1;
    }
    //2.查找解码器
    AVCodec *pInCodec = avcodec_find_decoder(m_pInFmtCtx->streams[nVideo_indx]->codecpar->codec_id);
    if(nullptr == pInCodec)
    {
        printf("avcodec_find_decoder fail.");
        return -1;
    }
    //获取解码器上下文
    AVCodecContext* pInCodecCtx = avcodec_alloc_context3(pInCodec);
    //复制解码器参数
    nRet = avcodec_parameters_to_context(pInCodecCtx, m_pInFmtCtx->streams[nVideo_indx]->codecpar);
    if(nRet < 0)
    {

        avcodec_free_context(&pInCodecCtx);
        printf("avcodec_parameters_to_context fail.");
        return -1;
    }
    //打开解码器
    if(avcodec_open2(pInCodecCtx, pInCodec, nullptr) < 0)
    {
        avcodec_free_context(&pInCodecCtx);
        printf("Error: Can't open codec!\n");
        return -1;
    }
    printf("width = %d\n", pInCodecCtx->width);
    printf("height = %d\n", pInCodecCtx->height);
    int frame_index = 0;
    int got_picture = 0;
    AVStream *in_stream =nullptr;
    AVStream *out_stream =nullptr;
    AVFrame *pFrame= av_frame_alloc();
    AVPacket *newpkt = av_packet_alloc();
    AVPacket *packet = av_packet_alloc();
    av_init_packet(newpkt);
    av_init_packet(packet);
    // alloc AVFrame
    AVFrame*pFrameRGB = av_frame_alloc();
    // 图像色彩空间转换、分辨率缩放、前后图像滤波处理
    SwsContext *m_SwsContext = sws_getContext(pInCodecCtx->width, pInCodecCtx->height,
            pInCodecCtx->pix_fmt, pInCodecCtx->width, pInCodecCtx->height,
            AV_PIX_FMT_RGB32, SWS_BICUBIC, nullptr, nullptr, nullptr);

    int bytes = av_image_get_buffer_size(AV_PIX_FMT_RGB32, pInCodecCtx->width, pInCodecCtx->height,4);
    uint8_t *m_OutBuffer = (uint8_t *)av_malloc(bytes * sizeof(uint8_t));

    // 将分配的内存空间给pFrameRGB使用
    avpicture_fill((AVPicture *)pFrameRGB, m_OutBuffer, AV_PIX_FMT_RGB32, pInCodecCtx->width, pInCodecCtx->height);
    if(encCtx == nullptr)
    {
        //打开编码器
        openEncoder(pInCodecCtx->width, pInCodecCtx->height,&encCtx);
    }
    int videoindex_out = 0;
    //设置输出文件上下文
    setOutputCtx(encCtx,&m_pTsFmtCtx,videoindex_out);
    //Write file header
    if (avformat_write_header(m_pTsFmtCtx, nullptr) < 0)
    {
        avformat_free_context(m_pTsFmtCtx);
        printf("Error occurred when opening output file\n");
        return -1;
    }
    printf("==============writer trail===================.\n");
    int count = 0;
    nRet = 0;
    while(av_read_frame(m_pInFmtCtx, packet) >= 0)//从pInFmtCtx读H264数据到packet;
    {
        if(packet->stream_index != nVideo_indx)//仅保留图像
        {
            continue;
        }
        if(avcodec_send_packet(pInCodecCtx, packet)<0)//送packet中H264数据给解码器码器进行解码,解码好的YUV数据放在pInCodecCtx,
        {
           break;
        }
        av_packet_unref(packet);
        got_picture = avcodec_receive_frame(pInCodecCtx, pFrame);//把解码好的YUV数据放到pFrame中
        if(0 == got_picture)//解码好一帧数据
        {
            //发送显示图像的信号
            // 对解码视频帧进行缩放、格式转换等操作
            sws_scale(m_SwsContext, (uint8_t const * const *)pFrame->data,
                     pFrame->linesize, 0, pInCodecCtx->height,
                     pFrameRGB->data, pFrameRGB->linesize);

            // 转换到QImage
            QImage tmmImage((uchar *)m_OutBuffer, pInCodecCtx->width, pInCodecCtx->height, QImage::Format_RGB32);
            QImage image = tmmImage.copy();

            // 发送QImage
            emit Sig_GetOneFrame(image);

            setDecoderPts(newpkt->stream_index,count, pFrame);
            count++;
            //送原始数据给编码器进行编码
            nRet = avcodec_send_frame(encCtx,pFrame);
            if(nRet < 0)
            {
                continue;
            }
            //从编码器获取编号的数据
            while(nRet >= 0)
            {
                nRet = avcodec_receive_packet(encCtx,newpkt);
                if(nRet < 0)
                {
                    break;
                }
                setEncoderPts(nVideo_indx,frame_index,videoindex_out,newpkt);
                int _count = 1;
                printf("Write %d Packet. size:%5d\tpts:%lld\n", _count,newpkt->size, newpkt->pts);

                if (av_interleaved_write_frame(m_pTsFmtCtx, newpkt) < 0)
                {
                    printf("Error muxing packet\n");
                    goto end;
                }
                _count++;
                av_packet_unref(newpkt);
            }
        }
    }
    while(1)//从pInFmtCtx读H264数据到packet;
    {
        if(packet->stream_index != nVideo_indx)//仅保留图像
        {
            continue;
        }
        if(avcodec_send_packet(pInCodecCtx, packet)<0)//送packet中H264数据给解码器码器进行解码,解码好的YUV数据放在pInCodecCtx,
        {
            continue;
        }
        av_packet_unref(packet);
        got_picture = avcodec_receive_frame(pInCodecCtx, pFrame);//把解码好的YUV数据放到pFrame中
        if(!got_picture)//解码好一帧数据
        {
            AVRational in_time_base1 = in_stream->time_base;
            in_stream = m_pInFmtCtx->streams[newpkt->stream_index];

            //Duration between 2 frames (us)
            int64_t in_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
            pFrame->pts = (double)(count*in_duration) / (double)(av_q2d(in_time_base1)*AV_TIME_BASE);
            count++;
            //送原始数据给编码器进行编码
            nRet = avcodec_send_frame(encCtx,pFrame);
            if(nRet < 0)
            {
                break;
            }
            //从编码器获取编号的数据
            while(nRet >= 0)
            {
                nRet = avcodec_receive_packet(encCtx,newpkt);
                if(nRet < 0)
                {
                    continue;
                }
                in_stream = m_pInFmtCtx->streams[newpkt->stream_index];
                out_stream = m_pTsFmtCtx->streams[videoindex_out];
                if (newpkt->stream_index == nVideo_indx)
                {
                    //FIX:No PTS (Example: Raw H.264)
                    //Simple Write PTS
                    if (newpkt->pts == AV_NOPTS_VALUE)
                    {
                        //Write PTS
                        AVRational time_base1 = in_stream->time_base;
                        //Duration between 2 frames (us)
                        int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
                        //Parameters
                        newpkt->pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE);
                        newpkt->dts = newpkt->pts;
                        newpkt->duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE);
                        frame_index++;
                    }
                 }
                //Convert PTS/DTS
                newpkt->pts = av_rescale_q_rnd(newpkt->pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
                newpkt->dts = av_rescale_q_rnd(newpkt->dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
                newpkt->duration = av_rescale_q(newpkt->duration, in_stream->time_base, out_stream->time_base);
                newpkt->pos = -1;
                newpkt->stream_index = videoindex_out;
                int count = 1;
                printf("Write %d Packet. size:%5d\tpts:%lld\n", count,newpkt->size, newpkt->pts);

                if (av_interleaved_write_frame(m_pTsFmtCtx, newpkt) < 0)
                {
                    printf("Error muxing packet\n");
                    goto end;
                }
                count++;
                av_packet_unref(newpkt);
            }
        }
    }
    //Write file trailer
    av_write_trailer(m_pTsFmtCtx);
end:
    av_frame_free(&pFrame);
    av_frame_free(&pFrameRGB);
    av_packet_unref(newpkt);
    av_packet_unref(packet);
    std::cout<<"rtsp's h264 to ts end";  
    return  0;
}
void ffmpegMananger::setDecoderPts(int idx,int count,AVFrame *pFrame)
{
    AVStream* in_stream = m_pInFmtCtx->streams[idx];
    AVRational in_time_base1 = in_stream->time_base;
    //Duration between 2 frames (us)
    int64_t in_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
    pFrame->pts = (double)(count*in_duration) / (double)(av_q2d(in_time_base1)*AV_TIME_BASE);
}
void ffmpegMananger::setEncoderPts(int nVideo_indx,int frame_index,int videoindex_out,AVPacket *newpkt)
{
    AVStream*in_stream = m_pInFmtCtx->streams[newpkt->stream_index];
    AVStream*out_stream = m_pTsFmtCtx->streams[videoindex_out];
    if (newpkt->stream_index == nVideo_indx)
    {
        //FIX:No PTS (Example: Raw H.264)
        //Simple Write PTS
        if (newpkt->pts == AV_NOPTS_VALUE)
        {
            //Write PTS
            AVRational time_base1 = in_stream->time_base;
            //Duration between 2 frames (us)
            int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
            //Parameters
            newpkt->pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE);
            newpkt->dts = newpkt->pts;
            newpkt->duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE);
            frame_index++;
        }
     }
    //Convert PTS/DTS
    newpkt->pts = av_rescale_q_rnd(newpkt->pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    newpkt->dts = av_rescale_q_rnd(newpkt->dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    newpkt->duration = av_rescale_q(newpkt->duration, in_stream->time_base, out_stream->time_base);
    newpkt->pos = -1;
    newpkt->stream_index = videoindex_out;
}
void ffmpegMananger::writeTail()
{
    //Write file trailer
    av_write_trailer(m_pTsFmtCtx);
}
void ffmpegMananger::openEncoder(int width, int height, AVCodecContext** enc_ctx)
{
    //使用libx264编码器
    AVCodec * pCodec = avcodec_find_encoder_by_name("libx264");
    if(nullptr == pCodec)
    {
        printf("avcodec_find_encoder_by_name fail.\n");
        return;
    }
    //获取编码器上下文
    *enc_ctx = avcodec_alloc_context3(pCodec);
    if(nullptr == enc_ctx)
    {
        printf("avcodec_alloc_context3(pCodec) fail.\n");
        return;
    }
    //sps/pps
    (*enc_ctx)->profile = FF_PROFILE_H264_MAIN;
    (*enc_ctx)->level = 30;//表示level是5.0
    //分辨率
    (*enc_ctx)->width = width;
    (*enc_ctx)->height = height;
    //gop
    (*enc_ctx)->gop_size = 25;//i帧间隔
    (*enc_ctx)->keyint_min = 20;//设置最小自动插入i帧的间隔.OPTION
    //B帧
    (*enc_ctx)->max_b_frames = 0;//不要B帧
    (*enc_ctx)->has_b_frames = 0;//
    //参考帧
    (*enc_ctx)->refs = 3;//OPTION
    //设置输入的yuv格式
    (*enc_ctx)->pix_fmt = AV_PIX_FMT_YUV420P;
    //设置码率
    (*enc_ctx)->bit_rate = 3000000;
    //设置帧率
    //(*enc_ctx)->time_base = (AVRational){1,25};//帧与帧之间的间隔
    (*enc_ctx)->time_base.num = 1;
    (*enc_ctx)->time_base.den = 25;
    //(*enc_ctx)->framerate = (AVRational){25,1};//帧率 25帧每秒
    (*enc_ctx)->framerate.num = 25;
    (*enc_ctx)->framerate.den = 1;
    if(avcodec_open2((*enc_ctx),pCodec,nullptr) < 0)
    {
        printf("avcodec_open2 fail.\n");
    }
    return;
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring关于注解的使用

目录 一、使用注解开发的前提 1.1 配置注解扫描路径 二、使用注解创建对象 2.1 Controller&#xff08;控制器储存&#xff09; 2.2 Service&#xff08;服务储存&#xff09; 2.3 Repository&#xff08;仓库储存&#xff09; 2.4 Component&#xff08;组件储存&#xff09; …

自研框架跻身全球 JS 框架榜单,排名紧随 React、Angular 之后!

前言 终于实现了一个重要目标&#xff01;我独立研发的 JavaScript 框架 Strve&#xff0c;最近发布了重大版本 6.0.2。距离上次大版本发布已经接近两个月&#xff0c;期间进行了大量的优化&#xff0c;使得框架性能和稳定性都得到了大幅度的提升。在上次的大版本更新中&#…

DevOps持续集成-Jenkins(2)

文章目录 DevOpsDevOps概述Integrate工具&#xff08;centos7-jenkins主机&#xff09;Integrate概述Jenkins介绍CI/CD介绍Linux下安装最新版本的Jenkins⭐Jenkins入门配置安装必备插件⭐安装插件&#xff08;方式一&#xff1a;可能有时会下载失败&#xff09;安装插件&#x…

负载均衡--Haproxy

haproxy 他也是常用的负载均衡软件 nginx 支持四层转发&#xff0c;七层转发 haproxy也可以四层和七层转发 haproxy&#xff1a;法国人开发的威利塔罗在2000年基于C语言开发的一个开源软件 可以支持一万以上的并发请求 高性能的tcp和http负载均衡2.4 1.5.9 haproxy&#…

微服务-Eureka

文章目录 提供者与消费者Eureka注册中心搭建EurekaServer服务注册服务发现项目结构 提供者与消费者 Eureka注册中心 服务消费者该如何获取服务提供者的地址信息&#xff1f; 服务提供者启动时向eureka注册自己的信息 eureka保存这些信息 消费者根据服务名称向eureka拉取提供者信…

10.Z-Stack协议栈移植

一、下载Z-Stack协议栈源文件 安装过程全部默认下一步即可&#xff0c;安装完成后会在C盘根目录下生成一个【Texas Instruments】文件夹 二、删除一些不必要的文件 将【ZStack-CC2530-2.3.0-1.4.0】文件夹&#xff0c;复制到自己放置ZigBee工程的文件夹下进入到【ZStack-CC253…

vue + html + Lodop打印功能

1.官网下载 http://www.lodop.net/download.html 2.解压安装运行 点击CLodop_Setup_for_Win32NT.exe进行安装 3.vue代码实现&#xff08;具体操作见官网&#xff1a;http://www.lodop.net/faq/pp35.html&#xff09; 3.1把官方提供的LodopFuncs.js文件保存到项目某个目录下 …

C# 使用base64编码用于加密和解密

base64编码原理&#xff1a;Base64编码是一种将二进制数据转换为ASCII字符的编码方式。它使用64个字符来表示二进制数据&#xff0c;包括大小写字母、数字和两个符号。将3个字节的二进制数据转换为4个字符的文本数据&#xff0c;如果不足3个字节&#xff0c;则在末尾补0&#x…

el-tree横向纵向滚动条

el-tree未展开时样式 el-tree展开时样式 给容器一个高度&#xff0c;然后样式加上overflow: scroll&#xff0c;这样纵向滚动条就出来了。 <el-card style"height: 528px;overflow: scroll"><el-inputplaceholder"输入关键字进行过滤"v-model&…

是顺流还是逆流?未来物流作业是否将被机器人全面取代?

原创 | 文 BFT机器人 随着人工智能的加速发展&#xff0c;各行业为适应数字时代的潮流&#xff0c;纷纷引入智能制造&#xff0c;帮助企业实现产业升级。而物流行业也不例外&#xff0c;现今人们的生活速度加快&#xff0c;为了快捷便利&#xff0c;很多的人喜欢通过网购、快递…

【Linux】Ubuntu升级nodejs版本

在下载nvm对nodejs版本进行管理时&#xff0c;由于网络因素一直下载失败&#xff0c;于是采用了新的方法对nodejs版本进行升级。 首先我们先查询一下现存的nodejs版本号&#xff0c;发现是12 我们下载一个名为n的软件包&#xff0c;n 是一个非常方便的 Node.js 版本管理工具&am…

【C++】Map和Set -- 详解

一、关联式容器 在初阶阶段&#xff0c;我们已经接触过 STL 中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forward_list&#xff08;C11&#xff09;等&#xff0c;这些容器统称为 序列式容器 &#xff0c;因为其底层为线性序列的数据结构&#xff0c;里面存…

CCF中国开源大会,中电金信与行业共探AI技术在金融行业的应用和前景

10月21日&#xff0c;以“开源联合&#xff0c;聚力共赢”为主题的2023 CCF中国开源大会在长沙开幕。中电金信副总经理、研究院院长况文川参加峰会&#xff0c;在“算力与大模型”主题论坛上发表演讲&#xff0c;与行业共同交流AI、大模型等技术在金融行业的应用与前景。 况文川…

bp前端验证码绕过及token绕过

前端验证码绕过及token绕过 原文参考&#xff1a;xiu 文章目录 前端验证码绕过及token绕过原文参考&#xff1a;[xiu](http://www.xiusafe.com/2023/10/25/%E9%AA%8C%E8%AF%81%E7%A0%81%E7%BB%95%E8%BF%87/)1 验证码爆破1. 登录Pikachu&#xff0c;先获取登录的api接口2 验证码…

基于Java的药品商城管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

jenkins配置gitlab凭据

下载Credentials Binding插件&#xff08;默认是已经安装了&#xff09; 在凭据配置里添加凭据类型 点击保存 Username with password&#xff1a; 用户名和密码 SSH Username with private 在凭据管理里面添加gitlab账号和密码 点击全局 点击添加凭据&#xff08;版本不同…

指针相关面试题目

数组名的意义&#xff1a; 1. sizeof( 数组名 ) &#xff0c;这里的数组名表示整个数组&#xff0c;计算的是整个数组的大小。 2. & 数组名&#xff0c;这里的数组名表示整个数组&#xff0c;取出的是整个数组的地址。 3. 除此之外所有的数组名都表示首元素的地址。 下…

【wespeaker】模型ECAPA_TDNN介绍

本次主要介绍开源项目wespeaker模型介绍 1. 模型超参数 model_args: feat_dim: 80 embed_dim: 192 pooling_func: “ASTP” projection_args: project_type: “softmax” # add_margin, arc_margin, sphere, softmax scale: 32.0 easy_margin: False 2. 模型结构 2.1 Layer…

python打包和运行技巧

一、打包的几种方法 Python 有多种打包方式可用于将脚本打包成可执行文件&#xff0c;以便在没有 Python 解释器的环境中运行。以下是一些常见的 Python 打包方式&#xff1a; 使用 pyinstaller&#xff1a;pyinstaller 是一个常用的第三方工具&#xff0c;可以将 Python 脚本…

中间件安全-CVE 复现K8sDockerJettyWebsphere漏洞复现

目录 服务攻防-中间件安全&CVE 复现&K8s&Docker&Jetty&Websphere中间件-K8s中间件-Jetty漏洞复现CVE-2021-28164-路径信息泄露漏洞CVE-2021-28169双重解码信息泄露漏洞CVE-2021-34429路径信息泄露漏洞 中间件-Docker漏洞复现守护程序 API 未经授权访问漏洞…