C++调用ffmpeg解复用、解码案例

框架

        一个封装文件(mp4)如何播放?大体流程如下:

 案例

        本案例实现在windows环境下,调用ffmpeg4.4.5动态库实现上述从解封装、视频解码、音频解码的全部过程,案例测试通过。由于ffmpeg接口功能网上资料较多,这里就不在赘述,代码如下:

 1、DeCoder.h

#pragma once
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}#include <iostream>
#include <fstream>
#include <vector>#define ADTS_HERDER_LEN 7const int sampling_frequencies[] = {96000, //0x088200, //0x164000, //0x248000, //0x344100, //0x432000, //0x524000, //0x622050, //0x716000, //0x812000, //0x911025, //0xa8000   //0xb  // 0xc d e f是保留的
};int test_deMuxer();int test_deCoderH264();
int test_deCoderAac();

2、DeMuxer.cpp


#include "DeCoder.h"using namespace std;int adts_header(uint8_t* const p_adts_header, const int data_length, const int profile, const int samplerate, const int channels)
{int sampling_frequency_index = 3; //48000int adtsLen = data_length + ADTS_HERDER_LEN;   // ADTS的头部信息总是占7个字节int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]); //求内存的分配大小int i = 0;for (i = 0; i < frequencies_size; i++){if (sampling_frequencies[i] == samplerate){sampling_frequency_index = i;break;}}if (i > frequencies_size){printf("unsupport samplerate:%d \n", samplerate);return -1;}p_adts_header[0] = 0xff;        //syncword:0xfff    高8bits  1111 1111  位数不足则用0补齐p_adts_header[1] = 0xf0;        //syncword:0xfff    低4bits  前面的4bit是属于syncword,后面的才是重新赋值    1111 0000p_adts_header[1] |= (0 << 3);   //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bit  |= 按位或后赋值 1111 0000  和 0000  = 1111 0000p_adts_header[1] |= (0 << 1);                                       //Layer:0                                 2bits                       1111 0000 和 00p_adts_header[1] |= 1;                                              // protection absent:1   不校验                 1bit                      1111 00000 和 1  = 1111 0000   0000 0001=  1111 0001p_adts_header[2] = (profile << 6);                                   //profile:profile               2bits                    profile :1110 0011  左移6位 1100 0000p_adts_header[2] |= (sampling_frequency_index & 0x0f) << 2;           //sampling frequency index:sampling_frequency_index  4bitsp_adts_header[2] |= (0 << 1);                                        //private bit:0                   1bitp_adts_header[2] |= (channels & 0x04) >> 2;                          //channel configuration:channels  高1bitp_adts_header[3] = (channels & 0x03) << 6;                          //channel configuration:channels 低2bitsp_adts_header[3] |= (0 << 5);                                       //original:0                1bitp_adts_header[3] |= (0 << 4);                                       //home:0                    1bitp_adts_header[3] |= (0 << 3);                                       //copyright id bit:0        1bitp_adts_header[3] |= (0 << 2);                                       //copyright id start:0      1bitp_adts_header[3] |= ((adtsLen & 0x1800) >> 11);                      //frame length:value   高2bitsp_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);                 //frame length:value    中间8bitsp_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);                    //frame length:value    低3bitsp_adts_header[5] |= 0x1f;                                           //buffer fullness:0x7ff 高5bitsp_adts_header[6] = 0xfc;                                            //buffer fullness:0x7ff 低6bitsreturn 0;
}void save_packet_to_file(const AVPacket* pkt, FILE* file) {fwrite(pkt->data, 1, pkt->size, file);
}int test_deMuxer() {const char* input_filename = "../test_video/d2.mp4";const char* video_output_filename = "../test_video/output_video.h264"; // 或者其他格式,取决于视频编码const char* audio_output_filename = "../test_video/output_audio.aac";  // 或者其他格式,取决于音频编码AVFormatContext* fmt_ctx = nullptr;if (avformat_open_input(&fmt_ctx, input_filename, nullptr, nullptr) != 0) {std::cerr << "Could not open input file." << std::endl;return -1;}if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {std::cerr << "Could not find stream information." << std::endl;avformat_close_input(&fmt_ctx);return -1;}AVCodecParameters* video_codecpar = nullptr;AVCodecParameters* audio_codecpar = nullptr;int video_stream_index = -1;int audio_stream_index = -1;// 查找视频流和音频流for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {AVCodecParameters* codecpar = fmt_ctx->streams[i]->codecpar;AVCodec* codec = avcodec_find_decoder(codecpar->codec_id);if (codec->type == AVMEDIA_TYPE_VIDEO) {video_codecpar = codecpar;video_stream_index = i;}else if (codec->type == AVMEDIA_TYPE_AUDIO) {audio_codecpar = codecpar;audio_stream_index = i;}}// std::cout << "---" << video_stream_index << ", " << audio_stream_index << std::endl;if (video_stream_index == -1) {std::cerr << "Could not find a video stream." << std::endl;avformat_close_input(&fmt_ctx);return -1;}if (audio_stream_index == -1) {std::cerr << "Could not find an audio stream." << std::endl;// 可以选择继续处理视频流,或者退出程序// avformat_close_input(&fmt_ctx);// return -1;}// 打开输出文件FILE* video_file, *audio_file;errno_t err = fopen_s(&video_file, video_output_filename, "wb");if (err != 0) {std::cerr << "Could not open video output file." << std::endl;avformat_close_input(&fmt_ctx);return -1; }err = fopen_s(&audio_file, audio_output_filename, "wb");if (err != 0 && audio_stream_index != -1) {std::cerr << "Could not open audio output file." << std::endl;fclose(video_file);avformat_close_input(&fmt_ctx);return -1;}const AVBitStreamFilter* bsfilter = av_bsf_get_by_name("h264_mp4toannexb");if (!bsfilter){std::cerr << "av_bsf_get_by_name." << std::endl;fclose(video_file);fclose(audio_file);avformat_close_input(&fmt_ctx);return -1;}AVBSFContext* bsf_ctx = NULL;int ret = av_bsf_alloc(bsfilter, &bsf_ctx);if (ret < 0){std::cerr << "av_bsf_alloc." << std::endl;fclose(video_file);fclose(audio_file);avformat_close_input(&fmt_ctx);return -1;}ret = avcodec_parameters_copy(bsf_ctx->par_in, fmt_ctx->streams[video_stream_index]->codecpar); //拷贝属性if (ret < 0){std::cerr << "avcodec_parameters_copy." << std::endl;fclose(video_file);fclose(audio_file);avformat_close_input(&fmt_ctx);return -1;}ret = av_bsf_init(bsf_ctx);if (ret < 0){std::cerr << "av_bsf_init." << std::endl;fclose(video_file);fclose(audio_file);avformat_close_input(&fmt_ctx);return -1;}AVPacket pkt;while (av_read_frame(fmt_ctx, &pkt) >= 0) {if (pkt.stream_index == video_stream_index) {//处理视频ret = av_bsf_send_packet(bsf_ctx, &pkt);if (ret < 0){std::cerr << "av_bsf_send_packet." << std::endl;continue;}ret = av_bsf_receive_packet(bsf_ctx, &pkt);if (ret != 0) {std::cerr << "av_bsf_receive_packet." << std::endl;break;}save_packet_to_file(&pkt, video_file);}else if (pkt.stream_index == audio_stream_index) {// 注意:对于AAC音频,MP4容器中的原始数据可能不包含ADTS头。// 如果需要ADTS头,你需要在保存之前手动添加。//处理音频uint8_t adts_header_buf[7] = { 0 };//添加adts头部信息adts_header(adts_header_buf, pkt.size,fmt_ctx->streams[audio_stream_index]->codecpar->profile,fmt_ctx->streams[audio_stream_index]->codecpar->sample_rate,fmt_ctx->streams[audio_stream_index]->codecpar->channels);//写adts headerfwrite(adts_header_buf, 1, 7, audio_file);save_packet_to_file(&pkt, audio_file);}av_packet_unref(&pkt);}fclose(video_file);if (audio_file) {fclose(audio_file);}avformat_close_input(&fmt_ctx);return 0;
}

3、DeCoder_H264.cpp


#include "DeCoder.h"int test_deCoderH264() {const char* input_filename = "../test_video/output_video.h264";const char* output_yuv = "../test_video/output_video.yuv";AVFormatContext* fmt_ctx = nullptr;if (avformat_open_input(&fmt_ctx, input_filename, nullptr, nullptr) != 0) {std::cerr << "Could not open input file." << std::endl;return -1;}if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {std::cerr << "Could not find stream information." << std::endl;avformat_close_input(&fmt_ctx);return -1;}AVCodecParameters* codecpar = nullptr;AVCodec* codec = nullptr;AVPacket* pkt = av_packet_alloc();AVFrame* frameYUV = av_frame_alloc();SwsContext* sws_ctx = nullptr;int video_stream_index = -1;for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {video_stream_index = i;codecpar = fmt_ctx->streams[i]->codecpar;// 查找对应解码器codec = avcodec_find_decoder(codecpar->codec_id);break;}}std::cout << "-------" << fmt_ctx->nb_streams << std::endl;if (video_stream_index == -1) {std::cerr << "Could not find a video stream." << std::endl;av_packet_free(&pkt);av_frame_free(&frameYUV);avformat_close_input(&fmt_ctx);return -1;}// 创建解码器上下文AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {std::cerr << "Could not copy codec parameters to context." << std::endl;av_packet_free(&pkt);av_frame_free(&frameYUV);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);return -1;}std::cout << "-------" << codec_ctx->width << ", " << codec_ctx->height << std::endl;// 打开解码器if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {std::cerr << "Could not open codec." << std::endl;av_packet_free(&pkt);av_frame_free(&frameYUV);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);return -1;}// 32位字节对齐的方式计算缓冲区大小int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height, 32);uint8_t* buffer = (uint8_t*)av_malloc(num_bytes * sizeof(uint8_t));av_image_fill_arrays(frameYUV->data, frameYUV->linesize, buffer, AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height, 1);FILE* yuvFile, *yuvFileY;errno_t err = fopen_s(&yuvFile, output_yuv, "wb");if (err != 0) {std::cerr << "Could not open output_filename file." << std::endl;av_packet_free(&pkt);av_frame_free(&frameYUV);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);return -1;}while (av_read_frame(fmt_ctx, pkt) >= 0) {if (pkt->stream_index == video_stream_index) {if (avcodec_send_packet(codec_ctx, pkt) == 0) {while (avcodec_receive_frame(codec_ctx, frameYUV) == 0) {// YUV存入另一个文件fwrite(frameYUV->data[0], 1, codec_ctx->width * codec_ctx->height, yuvFile);fwrite(frameYUV->data[1], 1, codec_ctx->width * codec_ctx->height/4, yuvFile);fwrite(frameYUV->data[2], 1, codec_ctx->width * codec_ctx->height/4, yuvFile);}}}av_packet_unref(pkt);}fclose(yuvFile);av_frame_free(&frameYUV);avcodec_free_context(&codec_ctx);av_packet_free(&pkt);avformat_close_input(&fmt_ctx);av_free(buffer);return 0;
}

4、DeCoder_AAC.cpp

#include "DeCoder.h"int test_deCoderAac(){const char* input_file = "../test_video/output_audio.aac";const char* output_file = "../test_video/output_audio.pcm";// 打开输入文件AVFormatContext* fmt_ctx = nullptr;if (avformat_open_input(&fmt_ctx, input_file, nullptr, nullptr) < 0) {std::cerr << "Could not open input file\n";return 1;}// 查找流信息if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {std::cerr << "Could not find stream information\n";return 1;}// 查找音频流int audio_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);if (audio_stream_index < 0) {std::cerr << "Could not find audio stream\n";return 1;}// 获取解码器参数AVCodecParameters* codec_params = fmt_ctx->streams[audio_stream_index]->codecpar;// 查找解码器const AVCodec* codec = avcodec_find_decoder(codec_params->codec_id);if (!codec) {std::cerr << "Unsupported codec\n";return 1;}// 创建解码器上下文AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);if (avcodec_parameters_to_context(codec_ctx, codec_params) < 0) {std::cerr << "Could not initialize codec context\n";return 1;}// 打开解码器if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {std::cerr << "Could not open codec\n";return 1;}// 准备重采样器(AAC解码后通常为FLTP格式,转换为S16格式)SwrContext* swr = swr_alloc_set_opts(nullptr,AV_CH_LAYOUT_STEREO,      // 输出声道布局AV_SAMPLE_FMT_S16,        // 输出格式codec_ctx->sample_rate,   // 输出采样率codec_ctx->channel_layout ?codec_ctx->channel_layout :av_get_default_channel_layout(codec_ctx->channels), // 输入声道布局codec_ctx->sample_fmt,    // 输入格式codec_ctx->sample_rate,   // 输入采样率0, nullptr);// 检查重采样器初始化if (!swr || swr_init(swr) < 0) {std::cerr << "Failed to initialize resampler\n";return 1;}// 准备数据包和帧AVPacket* pkt = av_packet_alloc();AVFrame* frame = av_frame_alloc();// 打开输出文件std::ofstream outfile(output_file, std::ios::binary);if (!outfile.is_open()) {std::cerr << "Could not open output file\n";return 1;}// 解码循环while (av_read_frame(fmt_ctx, pkt) >= 0) {if (pkt->stream_index == audio_stream_index) {// 发送数据包到解码器if (avcodec_send_packet(codec_ctx, pkt) < 0) {std::cerr << "Error sending packet\n";continue;}// 接收解码后的帧while (avcodec_receive_frame(codec_ctx, frame) >= 0) {// 检查帧有效性if (frame->nb_samples == 0 || !frame->data) {continue;}// 分配输出缓冲区uint8_t* output_buffer = nullptr;int out_linesize;int ret = av_samples_alloc(&output_buffer, &out_linesize,2,  // 输出声道数(立体声)frame->nb_samples,AV_SAMPLE_FMT_S16, 0);if (ret < 0) {std::cerr << "Failed to allocate samples\n";continue;}// 重采样int sample_count = swr_convert(swr,&output_buffer, frame->nb_samples,(const uint8_t**)frame->data, frame->nb_samples);// 写入PCM数据if (sample_count > 0) {int data_size = av_samples_get_buffer_size(nullptr, 2,sample_count,AV_SAMPLE_FMT_S16, 1);outfile.write(reinterpret_cast<char*>(output_buffer), data_size);}av_freep(&output_buffer);}}av_packet_unref(pkt);}// 清理资源av_packet_free(&pkt);av_frame_free(&frame);swr_free(&swr);avcodec_free_context(&codec_ctx);avformat_close_input(&fmt_ctx);outfile.close();std::cout << "Decoding completed successfully\n";return 0;
}

5、main.cpp

#include "DeCoder.h"int main() {av_log_set_level(AV_LOG_DEBUG);test_deMuxer();test_deCoderH264();test_deCoderAac();return 0;
}

上述代码已验证通过,笔者用的运行环境是VS2019,所用的ffmpeg4.4.5库是自己编译的x64库。项目路径下载地址:https://download.csdn.net/download/ddazz0621/90519707;运行成功最终生成如下文件:

需要注意:想验证最后生成的pcm播放,调用ffplay执行如下命令:

ffplay -f s16le -ar 8000 -ac 2 output_audio.pcm

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux(进程)

一.冯诺依曼体系结构 输入设备&#xff1a;键盘&#xff0c;鼠标&#xff0c;话筒&#xff0c;摄像头...网卡&#xff0c;磁盘 输出设备&#xff1a;显示器&#xff0c;磁盘&#xff0c;网卡&#xff0c;打印机 外设&#xff1a;输入设备输出设备 cpu&#xff08;中央处理器&am…

[极客大挑战 2019]BabySQL—3.20BUUCTF练习day4(3)

[极客大挑战 2019]BabySQL-3.20BUUCTF练习day4(3) 做题过程 打开是以下页面&#xff08;前几天有它的第一版和第二版出现&#xff09;输入1’ 回显以下内容&#xff08;还是字符型以单引号闭合&#xff0c;因为有报错信息回显&#xff09; 输入1 order by 4%23回显成这个 被过…

[Effective C++]条款20:宁以 pass-by-reference-to-const替换 pass-by-value

. 在C中&#xff0c;函数参数与返回值的数据传递的方式&#xff0c;对程序的性能和正确性有着重要影响。C默认使用pass-by-value&#xff08;传值&#xff09;的方式传递参数。但这种方式在某些情况下会导致性能问题和对象切割问题。 C推荐使用pass-by-reference-to-const&…

文字变央视级语音转换工具

大家在制作短视频、广告宣传、有声读物、自媒体配音、学习辅助等场景的时候&#xff0c;经常会需要用到配音来增强视频的表现力和吸引力。然而&#xff0c;市面上的一些配音软件往往需要收费&#xff0c;这对于很多初学者或者预算有限的朋友来说&#xff0c;无疑增加了一定的负…

邂逅书香:在诗韵与青春中找寻心灵归处

在信息如洪流般奔涌的当下&#xff0c;我们的灵魂时常在喧嚣中漂泊&#xff0c;渴望一处宁静港湾。而书籍&#xff0c;一直以来都是人类最忠诚的精神伴侣。今天&#xff0c;要为诗歌爱好者和青春文学迷们带来两份特别的礼物——《韵之队诗集》与《青春与爱共舞》&#xff0c;它…

国科大——计网(0812)——实验作业

**前沿&#xff1a;**此博客记录了24—25年度秋季学期计算机网络&#xff08;0812&#xff09;课程的实验作业&#xff0c;所提供的材料仅供参考。 0 实验题目 本次实验总共提供了四个可选的题目&#xff0c;即BGP分析实验&#xff0c;BGP 前缀劫持攻击及检测实验&#xff0c…

新能源汽车高压液体加热器总成技术解析及未来发展趋势

引言 新能源汽车的快速发展对热管理系统提出了更高要求&#xff0c;高压液体加热器作为核心组件&#xff0c;直接影响车辆低温性能、电池寿命及用户体验。本文以实际产品为例&#xff0c;结合行业数据与技术趋势&#xff0c;深度解析高压液体加热器的技术原理、市场现状及未来…

蓝桥杯 数字接龙

问题描述 小蓝最近迷上了一款名为《数字接龙》的迷宫游戏。 游戏在一个大小为 N N 的格子棋盘上展开&#xff0c;其中每一个格子处都有一个 0 到 K-1 之间的整数。 游戏规则如下&#xff1a; 从左上角 (0, 0) 出发&#xff0c;目标是到达右下角 (N-1, N-1)。 每一步可以选…

SysVinit和Systemd的系统运行级别

Linux运行级别 SysVinit系统(init守护进程)Linux系统运行级别SysVinit系统(init守护进程)查看Linux运行级别SysVinit系统(init守护进程)修改运行级别&#xff1a; Systemd守护进程Linux系统运行级别systemd查看运行级别Systemd查看系统当前运行级别 systemd修改运行级别multi-u…

SAP SD学习笔记33 - 预詑品(寄售物料),预詑品引渡(KB),预詑品出库(KE)

上一章讲了Service品目。 SAP SD学习笔记32 - Service品目(服务产品&#xff09;-CSDN博客 本章继续讲SAP SD的知识 - 预詑品(寄售物料)。 目录 1&#xff0c;预詑品概要 1-1&#xff0c;预詑品(寄售物料)的概念 1-2&#xff0c;预詑品的4种业务 1-3&#xff0c;受托品与…

DeiT:数据高效的图像Transformer及其工作原理详解

DeiT&#xff1a;数据高效的图像Transformer及其工作原理详解 随着Transformer架构在自然语言处理&#xff08;NLP&#xff09;领域的巨大成功&#xff0c;研究者们开始探索其在计算机视觉领域的应用。Vision Transformer&#xff08;ViT&#xff09;是最早将Transformer直接应…

【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的异常处理:全局异常与自定义异常

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、开篇整…

【Mybatis-plus】在mybatis-plus中 if test标签如何判断 list不为空

博主介绍&#xff1a;✌全网粉丝22W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…

Lineageos 22.1(Android 15)制定应用强制横屏

一、前言 有时候需要系统的某个应用强制衡平显示&#xff0c;不管他是如何配置的。我们只需要简单的拿到top的Task下面的ActivityRecord&#xff0c;并判断包名来强制实现。 二、调整wms com.android.server.wm.DisplayRotation /*** Given an orientation constant, return…

HTML网页代码预览器

HTML网页代码预览器 可以用于学习和实验HTML和CSS&#xff0c;比较方便。源码参考自网络。 功能 实时预览&#xff1a;当你在左侧的“代码编辑器”中输入代码时&#xff0c;右侧的“预览窗口”会实时显示你的网页效果&#xff08;注意&#xff0c;不能体现嵌入的JavaScript运…

Arm Linux ceres库编译

由于工作需要&#xff0c;需在国产化系统上编译ceres库&#xff0c;手上有一块树莓派&#xff0c;就在树莓派上面进行测试编译ceres库&#xff0c;总体来说比较顺利。只出现了一点小问题 参考链接&#xff1a; Ceres中文教程-安装 按照上面Linux编译过程 目录 1、在线安装依赖…

【算法学习计划】动态规划 -- 背包问题(01背包和完全背包)

目录 DP41 【模板】01背包 leetcode 416.分割等和子集 leetcode 494.目标和 leetcode 1049.最后一块石头的重量Ⅱ DP42 【模板】完全背包 leetcode 322.零钱兑换 leetcode 518.零钱兑换Ⅱ leetcode 279.完全平方数 今天&#xff0c;我们将通过 8 道题目&#xff0c;来带…

138. 随机链表的复制

题目&#xff1a; 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都设为其对应的原节…

网络HTTPS协议

Https HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;是 HTTP 协议的加密版本&#xff0c;它使用 SSL/TLS 协议来加密客户端和服务器之间的通信。具体来说&#xff1a; • 加密通信&#xff1a;在用户请求访问一个 HTTPS 网站时&#xff0c;客户端&#x…

19921 多重背包

19921 多重背包 ⭐️难度&#xff1a;中等 &#x1f31f;考点&#xff1a;动态规划、背包问题 &#x1f4d6; &#x1f4da; import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; import java.util.Scanner;public class Main {static int N …