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

音视频开发—FFmpeg 打开摄像头进行RTMP推流

实验平台:Ubuntu20.04

摄像头:普通USB摄像头,输出格式为YUV422

1.配置RTMP服务器推流平台

使用Nginx 配置1935端口即可,贴上教程地址

ubuntu20.04搭建Nginx+rtmp服务器)

2.配置FFmpeg开发环境

过程较为简单,这里不再赘述,可以看博主的往期博客,贴上教程地址:配置FFmpeg开发环境 (Vscode+CMake

3.推流具体实现流程

总体流程图

在这里插入图片描述

3.1 设备初始化

有些摄像头可能支持输出多种参数,因此一定要检查摄像头支持的格式

v4l2-ctl: 一个命令行工具,用于控制和调试V4L2设备。可以查询设备信息、设置参数、捕获视频帧等。

v4l2-ctl --list-formats-ext  # 列出设备支持的所有格式
v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=H264  # 设置视频格式
v4l2-ctl --stream-mmap --stream-count=100 --stream-to=output.raw  # 捕获视频流

查看本次实验的摄像头的相关参数

marxist@ubuntu:~/Desktop/audio_test/build$ v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMTType: Video Capture[0]: 'MJPG' (Motion-JPEG, compressed)Size: Discrete 1920x1080Interval: Discrete 0.033s (30.000 fps)Size: Discrete 640x480Interval: Discrete 0.008s (120.101 fps)Interval: Discrete 0.011s (90.000 fps)Interval: Discrete 0.017s (60.500 fps)Interval: Discrete 0.033s (30.200 fps)Size: Discrete 1280x720Interval: Discrete 0.017s (60.000 fps)Interval: Discrete 0.033s (30.500 fps)Size: Discrete 1024x768Interval: Discrete 0.033s (30.000 fps)Size: Discrete 800x600Interval: Discrete 0.017s (60.000 fps)Size: Discrete 1280x1024Interval: Discrete 0.033s (30.000 fps)Size: Discrete 320x240Interval: Discrete 0.008s (120.101 fps)[1]: 'YUYV' (YUYV 4:2:2)Size: Discrete 1920x1080Interval: Discrete 0.167s (6.000 fps)Size: Discrete 640x480Interval: Discrete 0.033s (30.000 fps)Size: Discrete 1280x720Interval: Discrete 0.111s (9.000 fps)Size: Discrete 1024x768Interval: Discrete 0.167s (6.000 fps)Size: Discrete 800x600Interval: Discrete 0.050s (20.000 fps)Size: Discrete 1280x1024Interval: Discrete 0.167s (6.000 fps)Size: Discrete 320x240Interval: Discrete 0.033s (30.000 fps)

由上述可知,摄像头一共支持两种格式,一是MJPG格式,已经由硬件压缩好的一种格式,一种就是常见的YUV422格式,YUV同样支持多种分辨率格式。

设置输入格式上下文,Linux系统对应的是V4L2,查找视频流信息

AVInputFormat *input_format = av_find_input_format("v4l2");if ((ret = avformat_open_input(&input_ctx, "/dev/video0", input_format, &options)) < 0){fprintf(stderr, "Could not open input\n");return ret;}// 查找流信息ret = avformat_find_stream_info(input_ctx, NULL);if (ret < 0){std::cerr << "could not find stream info" << std::endl;return -1;}// 查找视频流for (size_t i = 0; i < input_ctx->nb_streams; i++){if (input_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){video_stream_index = i;break;}}if (video_stream_index == -1){std::cerr << "no video stream found" << std::endl;return -1;}

3.2 初始化编码器

本次推流实验使用的是H264编码器,CPU软编码,没有使用到硬件编码,用到的库是X264。

主要流程为 查找编码器——分配编码器上下文——设置编码器参数——打开编码器

    // 查找编码器AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);if (!codec){fprintf(stderr, "Could not find AV_CODEC_ID_H264\n");return -1;}// 分配编码器上下文AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);if (!codec_ctx){std::cerr << "Could not allocate video codec context" << std::endl;return -1;}// 设置编码器参数codec_ctx->codec_id = codec->id;codec_ctx->bit_rate = 400000;codec_ctx->width = 1280;codec_ctx->height = 720;codec_ctx->time_base = (AVRational){1, 9};codec_ctx->framerate = (AVRational){9, 1};codec_ctx->gop_size = 10;codec_ctx->max_b_frames = 0;             // 不需要B帧codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; // 传入的420P 格式,而cam 默认输出422 则一会 需要作转换// 打开编码器if (avcodec_open2(codec_ctx, codec, NULL) < 0){fprintf(stderr, "Could not open codec\n");return -1;}

这里将B帧参数设置为了0,因为加入B帧之后,虽然提高了压缩效率,但是也显著增加了编码的复杂性。编码B帧需要更多的计算资源,因为它不仅需要前向预测,还需要后向预测。对于资源受限的设备(如移动设备、嵌入式系统等),不使用B帧可以减少编码器的负担。

3.3 设置输出流

这里的输出流地址则特指的RTMP服务器地址,也就是说FFmpeg将编码好的数据传输到RTMP服务器。如果需要写入到文件,输出流地址也可以是文件路径。

相关代码操作

 // 创建输出流AVStream *out_stream = avformat_new_stream(output_ctx, codec);if (!out_stream){fprintf(stderr, "Could not avformat_new_stream\n");return -1;}// 从输入流复制参数到输出流avcodec_parameters_from_context(out_stream->codecpar, codec_ctx);out_stream->time_base = codec_ctx->time_base;// 打开输出URLif (!(output_ctx->oformat->flags & AVFMT_NOFILE)){if (avio_open(&output_ctx->pb, output_url, AVIO_FLAG_WRITE) < 0){std::cerr << "Could not open output URL" << std::endl;return -1;}}// 写输出文件头if (avformat_write_header(output_ctx, NULL) < 0){fprintf(stderr, "Could not write header\n");return -1;}

3.4 读取摄像头数据

av_read_frame(input_ctx, &pkt)

代码作用是从输入设备读取数据帧,封装到packet中。

根据上文已经获取到了视频流索引,在此判断一下是不是视频流,因为有些摄像头支持语音输入,packet中存放的也可能是音频流

pkt.stream_index == video_stream_index

3.5 颜色空间转换

在上述过程中, 已经指定输出YUV422的数据了因此需要转换为YUV420数据

大体流程为:原始帧—转换上下文—YUV420帧

首先初始化转换上下文

 // 准备颜色空间色彩转换SwsContext *sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUYV422,codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P,SWS_BILINEAR, NULL, NULL, NULL);if (!sws_ctx){std::cerr << "Could not initialize the conversion context" << std::endl;return -1;}

分辨率与编码器参数保持一致

准备原始数据帧,从摄像头读取的数据包中得到

AVFrame *temp_frame = av_frame_alloc();if (!temp_frame){std::cerr << "Could not allocate temporary frame" << std::endl;av_packet_unref(&pkt);continue;}// 分配临时帧的内存空间if (av_image_alloc(temp_frame->data, temp_frame->linesize, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUYV422, 1) < 0){std::cerr << "Could not allocate temporary frame buffer" << std::endl;av_frame_free(&temp_frame);av_packet_unref(&pkt);continue;}// 将pkt.data中的数据填充到temp_frameret = av_image_fill_arrays(temp_frame->data, temp_frame->linesize, pkt.data, AV_PIX_FMT_YUYV422, codec_ctx->width, codec_ctx->height, 1);if (ret < 0){std::cerr << "Error filling arrays" << std::endl;av_freep(&temp_frame->data[0]);av_frame_free(&temp_frame);av_packet_unref(&pkt);continue;}

初始化YUV420的帧

    // 分配AVFrame并设置参数AVFrame *frame = av_frame_alloc();if (!frame){std::cerr << "Could not allocate video frame" << std::endl;return -1;}frame->format = codec_ctx->pix_fmt;frame->width = codec_ctx->width;frame->height = codec_ctx->height;av_frame_get_buffer(frame, 32);

最后执行转换即可

sws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, codec_ctx->height, frame->data, frame->linesize);

3.6 编码并输出到RTMP服务器

得到YUV420的数据,就可以进行最后的操作了

 // 编码视频数据ret = avcodec_send_frame(codec_ctx, frame);if (ret < 0){std::cerr << "Error sending frame to encoder" << std::endl;break;}while (ret >= 0){ret = avcodec_receive_packet(codec_ctx, &pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){break;}else if (ret < 0){std::cerr << "Error encoding frame" << std::endl;break;}// 将编码后的视频数据推送到RTMP服务器pkt.stream_index = out_stream->index;av_packet_rescale_ts(&pkt, codec_ctx->time_base, out_stream->time_base);pkt.pos = -1;ret = av_interleaved_write_frame(output_ctx, &pkt);if (ret < 0){std::cerr << "Error writing frame" << std::endl;break;}av_packet_unref(&pkt);}

4.完整代码

extern "C"
{
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include "libavutil/imgutils.h"
}
#include <iostream>
#include <cstdlib>
using namespace std;int main(int argc, char *argv[])
{const char *output_url = "rtmp://192.168.1.79:1935/orin/live"; // 替换为你的RTMP推流地址AVFormatContext *input_ctx = NULL;AVPacket pkt;int ret;int video_stream_index = -1;AVDictionary *options = nullptr; // 摄像头相关参数int64_t pts = 0;                 // 初始化 PTS// 初始化libavformat和注册所有muxers, demuxers和协议avdevice_register_all();avformat_network_init();// 打开摄像头开始//   // 摄像头支持多种参数,因此使用option 指定参数 最大支持到9帧av_dict_set(&options, "video_size", "1280*720", 0);av_dict_set(&options, "framerate", "9", 0);av_dict_set(&options, "input_format", "yuyv422", 0);AVInputFormat *input_format = av_find_input_format("v4l2");if ((ret = avformat_open_input(&input_ctx, "/dev/video0", input_format, &options)) < 0){fprintf(stderr, "Could not open input\n");return ret;}// 查找流信息ret = avformat_find_stream_info(input_ctx, NULL);if (ret < 0){std::cerr << "could not find stream info" << std::endl;return -1;}// 查找视频流for (size_t i = 0; i < input_ctx->nb_streams; i++){if (input_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){video_stream_index = i;break;}}if (video_stream_index == -1){std::cerr << "no video stream found" << std::endl;return -1;}// 查找编码器AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);if (!codec){fprintf(stderr, "Could not find AV_CODEC_ID_H264\n");return -1;}// 分配编码器上下文AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);if (!codec_ctx){std::cerr << "Could not allocate video codec context" << std::endl;return -1;}// 设置编码器参数codec_ctx->codec_id = codec->id;codec_ctx->bit_rate = 400000;codec_ctx->width = 1280;codec_ctx->height = 720;codec_ctx->time_base = (AVRational){1, 9};codec_ctx->framerate = (AVRational){9, 1};codec_ctx->gop_size = 10;codec_ctx->max_b_frames = 0;             // 不需要B帧codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; // 传入的420P 格式,而cam 默认输出422 则一会 需要作转换// 打开编码器if (avcodec_open2(codec_ctx, codec, NULL) < 0){fprintf(stderr, "Could not open codec\n");return -1;}// 分配输出上下文AVFormatContext *output_ctx = nullptr;ret = avformat_alloc_output_context2(&output_ctx, NULL, "flv", output_url);if (!output_ctx){fprintf(stderr, "Could not create output context\n");return ret;}// 创建输出流AVStream *out_stream = avformat_new_stream(output_ctx, codec);if (!out_stream){fprintf(stderr, "Could not avformat_new_stream\n");return -1;}// 从输入流复制参数到输出流avcodec_parameters_from_context(out_stream->codecpar, codec_ctx);out_stream->time_base = codec_ctx->time_base;// 打开输出URLif (!(output_ctx->oformat->flags & AVFMT_NOFILE)){if (avio_open(&output_ctx->pb, output_url, AVIO_FLAG_WRITE) < 0){std::cerr << "Could not open output URL" << std::endl;return -1;}}// 写输出文件头if (avformat_write_header(output_ctx, NULL) < 0){fprintf(stderr, "Could not write header\n");return -1;}// 分配AVFrame并设置参数AVFrame *frame = av_frame_alloc();if (!frame){std::cerr << "Could not allocate video frame" << std::endl;return -1;}frame->format = codec_ctx->pix_fmt;frame->width = codec_ctx->width;frame->height = codec_ctx->height;av_frame_get_buffer(frame, 32);// 准备颜色空间色彩转换SwsContext *sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUYV422,codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P,SWS_BILINEAR, NULL, NULL, NULL);if (!sws_ctx){std::cerr << "Could not initialize the conversion context" << std::endl;return -1;}while (true){if (av_read_frame(input_ctx, &pkt) >= 0){if (pkt.stream_index == video_stream_index){// 从相机出来的原始帧 为YUV 422 需要转换为420P// 数据是YUYV422格式,需要转换为YUV420PAVFrame *temp_frame = av_frame_alloc();if (!temp_frame){std::cerr << "Could not allocate temporary frame" << std::endl;av_packet_unref(&pkt);continue;}// 分配临时帧的内存空间if (av_image_alloc(temp_frame->data, temp_frame->linesize, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUYV422, 1) < 0){std::cerr << "Could not allocate temporary frame buffer" << std::endl;av_frame_free(&temp_frame);av_packet_unref(&pkt);continue;}// 将pkt.data中的数据填充到temp_frameret = av_image_fill_arrays(temp_frame->data, temp_frame->linesize, pkt.data, AV_PIX_FMT_YUYV422, codec_ctx->width, codec_ctx->height, 1);if (ret < 0){std::cerr << "Error filling arrays" << std::endl;av_freep(&temp_frame->data[0]);av_frame_free(&temp_frame);av_packet_unref(&pkt);continue;}// 转换颜色空间到YUV420Psws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, codec_ctx->height, frame->data, frame->linesize);// 设置帧的 PTSframe->pts = pts++;// 编码视频数据ret = avcodec_send_frame(codec_ctx, frame);if (ret < 0){std::cerr << "Error sending frame to encoder" << std::endl;break;}while (ret >= 0){ret = avcodec_receive_packet(codec_ctx, &pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){break;}else if (ret < 0){std::cerr << "Error encoding frame" << std::endl;break;}// 将编码后的视频数据推送到RTMP服务器pkt.stream_index = out_stream->index;av_packet_rescale_ts(&pkt, codec_ctx->time_base, out_stream->time_base);pkt.pos = -1;ret = av_interleaved_write_frame(output_ctx, &pkt);if (ret < 0){std::cerr << "Error writing frame" << std::endl;break;}av_packet_unref(&pkt);}av_frame_free(&temp_frame);}}}av_write_trailer(output_ctx);// 释放资源av_frame_free(&frame);avcodec_free_context(&codec_ctx);avformat_close_input(&input_ctx);if (output_ctx && !(output_ctx->oformat->flags & AVFMT_NOFILE)){avio_closep(&output_ctx->pb);}avformat_free_context(output_ctx);sws_freeContext(sws_ctx);return 0;
}

5.获取推流数据

常用的工具为VLC播放器,选择打开网络串流地址

在这里插入图片描述

就能播放推流画面了

在这里插入图片描述

相关文章:

音视频开发—FFmpeg 打开摄像头进行RTMP推流

实验平台&#xff1a;Ubuntu20.04 摄像头&#xff1a;普通USB摄像头&#xff0c;输出格式为YUV422 1.配置RTMP服务器推流平台 使用Nginx 配置1935端口即可&#xff0c;贴上教程地址 ubuntu20.04搭建Nginxrtmp服务器) 2.配置FFmpeg开发环境 过程较为简单&#xff0c;这里不…...

D触发器(D Flip-Flop)与D锁存器(D Latch)

1 基础概念 我们先来简单回顾一下D触发器&#xff08;D flip-flop&#xff09;和D锁存器&#xff08;D latch&#xff09;的概念&#xff0c;以及它们在数字电路中的作用。 1.1 D触发器&#xff08;D Flip-Flop&#xff09; D触发器是一种数字存储器件&#xff0c;它在时钟信号…...

JDK19特性

JDK19特性 一、JAVA19概述 JDK 19 2022 年 9 月 20 日正式发布以供生产使用,非长期支持版本。不过,JDK 19 中有一些比较重要的新特性值得关注。 JDK 19 只有 7 个新特性: JEP 405: Record Patterns(记录模式)[1] (预览)JEP 422: Linux/RISC-V Port[2]JEP 424: Foreign …...

sql语句中常用的函数有那些

1、字符串函数 CONCAT(string1, string2, ...): 连接两个或多个字符串。 UPPER(string): 将字符串转换为大写。 LOWER(string): 将字符串转换为小写。 TRIM(string): 去除字符串两端的空格。 LENGTH(string): 返回字符串的长度。 SUBSTRING(string, start, length): 从字符串中…...

odoo17 小变更3 Warning、 “attrs “和 “states “不再用

odoo17 小变更 1、Warning from odoo.exceptions import ValidationError,Warning ImportError: cannot import name Warning from odoo.exceptions (D:\od172406\odoo\exceptions.py) 2、自 17.0 版起&#xff0c;不再使用 "attrs "和 "states "属性。 …...

Unity3d 游戏暂停(timeScale=0)引起的deltaTime关联的系列问题解决

问题描述 游戏暂停的功能是通过设置timeScale0实现的&#xff0c;不过在暂停游戏的时候&#xff0c;需要对角色进行预览和设置&#xff0c;为了实现这个功能&#xff0c;是通过鼠标控制相机的操作&#xff0c;为了使相机的操作丝滑&#xff0c;获取鼠标操作系数乘以Time.delta…...

服务端代码编写中MySql大小写在Java中报错问题解决

报错信息&#xff1a; 原因&#xff1a;MySql和Java变量大小写产生的冲突。 经过查阅各个博客等&#xff0c;得出浅显结论&#xff08;不一定对&#xff09;&#xff1a;MySql大小写不敏感&#xff0c;Java大小写敏感&#xff0c;当Javabean转为MySql数据库表时&#xff0c;Ja…...

CRMEB 多店商品详情页装修说明

一、功能介绍 商家可调整商品详情各板块样式&#xff0c;可根据不同的需求开启或关闭单独的板块 二、操作流程 装修 > 商品详情 三、功能说明 1、商品信息 可控制商品详情页面商品信息的显示与隐藏 2、会员信息&#xff0c;排行榜 控制商品详情页面会员信息及排行榜的…...

Redis-使用 jedis 操作数据

文章目录 1、Jedis简介2、环境准备3、创建maven普通项目,导入如下依赖4、测试JAVA程序和Redis之间的通信 1、Jedis简介 "Jedis" 通常是作为 "Java Redis" 的缩写或简称来理解的。Java Embedded Data Structures Interface 表示 Java嵌入式数据结构接口 2、…...

简说PIP换源

概述 PIP&#xff08;Python Package Installer&#xff09;是 Python 的包管理工具&#xff0c;用于安装和管理 Python 包。默认情况下&#xff0c;PIP 从 Python 官方的包仓库&#xff08;即 PyPI&#xff09;下载和安装包。然而&#xff0c;由于网络原因&#xff0c;访问官…...

django学习入门系列之第三点《CSS基础样式介绍2》

文章目录 文字对齐方式外边距内边距往期回顾 文字对齐方式 水平对齐方式 text-align: center;垂直对齐方式 /* 注意&#xff0c;这个只能是一行来居中 */ line-height:/*长度*/ ;样例 <!DOCTYPE html> <html lang"en"> <head><meta charset…...

分布式光纤测温DTS在工程现场中稳定性与可靠性如何?

20年前&#xff0c;分布式光纤测温(Distributed Temperature Sensing&#xff0c;DTS)技术的发展尚不成熟&#xff0c;设备成本高昂&#xff0c;其稳定性与可靠性也存在一定问题。然而&#xff0c;经过二十多年的不断发展与创新&#xff0c;DTS技术在工程现场应用中取得了显著进…...

PHP多线程模块parallel的编译安装和多线程编程演示

从PHP7开始&#xff0c;多线程编原有的pthreads已经不在维护&#xff0c;而是使用parallel替代。 由于是新的模块&#xff0c;样例代码很少&#xff0c;这里总结一个简单的代码和详细的备注供大家参考。 编译和安装 parallel需要启用ZTS&#xff08;Zend Thread Safety&…...

记录grid布局属性

grid布局 分为容器和项目元素 容器属性 #container{display:grid;grid-template-columns:100px 100px 100px;/* 1fr 表示比例为占1份 */grid-template-columns:1fr 100px 1fr;/*100px为1列,自动填充,容器宽度不足则换行*/grid-template-columns:repeat(auto-fill,100px);/* …...

12.爬虫---PyMysql安装与使用

12.PyMysql安装与使用 1.安装 PyMySQL2.使用PyMySQL2.1创建数据表2.2连接数据库2.3增加数据2.4修改数据2.5查询数据2.6删除数据2.7关闭连接 3.总结 MySQL 安装可以看这篇文章MySql 安装与使用&#xff08;非常详细&#xff09; 1.安装 PyMySQL PyMySQL是Python中用于连接MySQL…...

VS2022遇到的两个问题

问题一&#xff1a;找不到定义的头文件 别的博主说是&#xff1a;在属性页里面进行改写&#xff0c;改成是&#xff0c;我试过之后并不行&#xff1b; 解决思路&#xff1a;但其实在右边视图里面找到你自己定义的头文件加到你运行文件中就行&#xff1b;因为程序就只有一个入口…...

【Android14 ShellTransitions】(六)SyncGroup完成

这一节的内容在WMCore中&#xff0c;回想我们的场景&#xff0c;是在Launcher启动某一个App&#xff0c;那么参与动画的就是该App对应Task&#xff08;OPEN&#xff09;&#xff0c;以及Launcher App对应的Task&#xff08;TO_BACK&#xff09;。在确定了动画的参与者后&#x…...

技术管理转型之战:决策之道-管理中的智慧与策略

文章目录 引言一、决策的重要性二、常见的决策方式1. 理性决策&#xff08;Rational Decision Making&#xff09;2. 有限理性&#xff08;Bounded Rationality&#xff09;3. 直觉决策&#xff08;Intuitive Decision Making&#xff09;4. 循证管理&#xff08;Evidence-Base…...

Shell脚本:条件语句(if、case)

目录 硬编码 硬编码的缺点 条件判断 $? 命令行语句 判断指定目录是否存在 判断指定文件是否存在 判断指定对象是否存在 表达式形式语句 判断对象是否存在 判断对象是否有权限 与、或、非 运算 与运算 或运算 非运算 比较大小 判断磁盘利用率实验步骤 字符串…...

在Linux上为Windows目标配置Qt交叉编译

问题描述 我想使用Linux x86_64主机为Windows x86_64目标交叉编译Qt库&#xff08;最终也包括我的应用程序&#xff09;。我觉得自己已经接近成功了&#xff0c;但可能对整个过程有一些基本的误解。 我从在我的Fedora机器上安装所有mingw包开始&#xff0c;并修改了win32-g的…...

Introduction to linear optimization 第 2 章课后题答案 11-15

线性规划导论 Introduction to linear optimization (Dimitris Bertsimas and John N. Tsitsiklis, Athena Scientific, 1997)&#xff0c; 这本书的课后题答案我整理成了一个 Jupyter book&#xff0c;发布在网址&#xff1a; https://robinchen121.github.io/manual-introdu…...

Java——包

一、包 1、简要介绍 在Java编程语言中&#xff0c;包&#xff08;Package&#xff09; 是一种用来组织和管理类&#xff08;Class&#xff09;和接口&#xff08;Interface&#xff09;的机制。包为开发者提供了一种逻辑分组的方式&#xff0c;使代码更加模块化、结构化和易于…...

Pipeline知识小记

在scikit-learn&#xff08;通常缩写为sklearn&#xff09;中&#xff0c;Pipeline是一个非常重要的工具&#xff0c;它允许你将多个数据转换步骤&#xff08;如特征选择、缩放等&#xff09;和估计器&#xff08;如分类器、回归器等&#xff09;组合成一个单一的估计器对象。这…...

postman国内外竞争者及使用详解分析

一、postman简介 Postman 是一款广泛使用的 API 开发和测试工具&#xff0c;适用于开发人员和测试人员。它提供了一个直观的界面&#xff0c;用于发送 HTTP 请求、查看响应、创建和管理 API 测试用例&#xff0c;以及自动化 API 测试工作流程。以下是 Postman 的主要功能和特点…...

人工智能对决:ChatGLM与ChatGPT,探索发展历程

图: a robot is writing code on a horse, By 禅与计算机程序设计艺术 目录 ChatGLM:...

探索Python元类的奥秘及其应用场景

探索Python元类的奥秘及其应用场景 一、引言 在Python中&#xff0c;元类&#xff08;Metaclasses&#xff09;是一个相对高级且容易被忽视的主题。然而&#xff0c;对于深入理解Python的面向对象编程模型以及进行高级框架和库的设计来说&#xff0c;元类是一个不可或缺的工具…...

C语言基础关键字的含义和使用方法

​关键字在C语言中扮演着非常重要的角色&#xff0c;它们定义了语言的基本构造和语法规则&#xff0c;通过使用关键字&#xff0c;开发者可以创建变量、定义数据类型、控制程序流程&#xff08;如循环和条件判断&#xff09;、声明函数等。由于这些字是保留的&#xff0c;所以编…...

【Golang - 90天从新手到大师】Day09 - string

系列文章合集 Golang - 90天从新手到大师 String 一个字符串是一个不可改变的字节序列。字符串可以包含任意的数据&#xff0c;但是通常是用来包含人类可读的文本。 len()返回字符串字节数目&#xff08;不是rune数&#xff09;。 通过索引可以访问某个字节值&#xff0c;0…...

网络安全与区块链技术:信任与安全的融合

# 网络安全与区块链技术&#xff1a;信任与安全的融合 在网络空间&#xff0c;信任是一种宝贵而稀缺的资源。区块链技术以其独特的分布式账本、加密算法和共识机制&#xff0c;为构建网络安全提供了新的解决方案。本文将探讨网络安全与区块链技术如何融合&#xff0c;以增强信…...

MySQL之复制(九)

复制 复制管理和维护 确定主备是否一致 在理想情况下&#xff0c;备库和主库的数据应该是完全一样的。但事实上备库可能发生错误并导致数据不一致。即使没有明显的错误&#xff0c;备库同样可能因为MySQL自身的特性导致数据不一致&#xff0c;例如MySQL的Bug、网络中断、服务…...

【面试干货】 Java 中的 HashSet 底层实现

【面试干货】 Java 中的 HashSet 底层实现 1、HashSet 的底层实现2、 HashSet 的特点3、 总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; HashSet 是 Java 集合框架中的一个重要成员&#xff0c;它提供了不存储重复元素的集合。但是&am…...

爬虫经典案例之爬取豆瓣电影Top250(方法二)

在上一篇文章的基础上&#xff0c;改进了代码质量&#xff0c;增加了多个正则表达式匹配&#xff0c;但同事也增加了程序执行的耗时。 from bs4 import BeautifulSoup import requests import time import re from random import randint import pandas as pdurl_list [https…...

如何优化React应用的性能?

优化React应用的性能是一个多方面的过程&#xff0c;涉及到代码的编写、组件的设计、资源的管理等多个层面。以下是一些常见的性能优化策略&#xff1a; 避免不必要的渲染: 使用React.memo、useMemo和useCallback来避免组件或其子组件不必要的重新渲染。 代码分割: 使用React.…...

css文字镂空加描边

css文字镂空加描边 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>文字镂空</title><style>/* 公用样式 */html,body{width: 100%;height: 100%;position: relative;}/* html{overflow-y: scroll;} */*{margi…...

python数据分析与可视化

Python 在数据分析和可视化方面有着广泛的应用,并且拥有众多强大的库和工具来支持这些任务。以下是一些常用的 Python 库和它们的主要用途: 数据分析 Pandas: Pandas 是 Python 中用于数据处理和分析的主要库。 它提供了数据框(DataFrame)和序列(Series)两种数据结构…...

webkit 的介绍

WebKit 是一个开源的网页浏览器引擎&#xff0c;它是 Safari 浏览器和许多其他应用程序的基础。WebKit 最初由苹果公司开发&#xff0c;并在2005年作为开源项目发布。WebKit 的核心组件包括 WebCore 和 JavaScriptCore。以下是 WebKit 的详细介绍&#xff1a; ### WebKit 的主…...

make与makefile

目录 一、make的默认目标文件与自动推导 二、不能连续make的原因 执行原理 touch .PHONY伪目标 make指令不回显 makefile多文件管理 简写依赖方法 三、回车与换行 四、缓冲区 一、make的默认目标文件与自动推导 假设这是一个makefile文件&#xff0c;make的时候默认生…...

深度神经网络一

文章目录 深度神经网络 (DNN)1. 概述2. 基本概念3. 网络结构 深度神经网络的层次结构详细讲解1. 输入层&#xff08;Input Layer&#xff09;2. 隐藏层&#xff08;Hidden Layers&#xff09;3. 输出层&#xff08;Output Layer&#xff09;整体流程深度神经网络的优点深度神经…...

Pnpm:包管理的新星,如何颠覆 Npm 和 Yarn

在探索现代 JavaScript 生态系统时&#xff0c;我们常常会遇到新兴技术的快速迭代和改进。其中&#xff0c;包管理工具的发展尤为重要&#xff0c;因为它们直接影响开发效率和项目性能。最近&#xff0c;pnpm 作为一种新的包管理工具引起了广泛关注。它不仅挑战了传统工具如 np…...

汽车IVI中控开发入门及进阶(三十二):i.MX linux开发之Yocto

前言: 对于NXP的i.mx,如果基于linux开发,需要熟悉以下文档: IMX_YOCTO_PROJECT_USERS_GUIDE.pdf IMX_LINUX_USERS_GUIDE.pdf IMX_GRAPHICS_USERS_GUIDE.pdf 如果基于android开发,需要熟悉一下文档: Android_Auto_Quick_Start_Guide.pdf ANDROID_USERS_GUIDE.pdf …...

tessy 编译报错:单元测试时,普通桩函数内容相关异常场景

目录 1&#xff0c;失败现象 2&#xff0c;原因分析 1&#xff0c;失败现象 1&#xff0c;在 step 桩函数正常的情况下报错。 2&#xff0c;测试代码执行的数据流 和 step 桩函数内容不一致。 2&#xff0c;原因分析 桩函数分为 test object, test case, test step 三种类别。…...

计算机专业是否仍是“万金油”

作为一名即将参加高考的学生&#xff0c;我站在人生的分岔路口上&#xff0c;面临着选择大学专业的重大抉择。在这个关键节点&#xff0c;计算机相关专业是否仍是炙手可热的选择&#xff1f;  首先&#xff0c;从行业的角度来看&#xff0c;计算机相关专业确实在近年来持续火…...

雷池社区版自动SSL

正常安装雷池&#xff0c;并配置站点&#xff0c;暂时不配置ssl 不使用雷池自带的证书申请。 安装&#xff08;acme.sh&#xff09;&#xff0c;使用域名验证方式生成证书 先安装git yum install git 或者 apt-get install git 安装完成后使用 git clone https://gitee.com/n…...

怎样减少徐州服务器租用的成本?

服务器租用的出现&#xff0c;十分便于网络行业的发展&#xff0c;但是随着服务器租用的广泛应用&#xff0c;整体还是有着一定的成本的吗&#xff0c;不同的服务器类型在价格方面也是不同的&#xff0c;那么企业在选择服务器租用后&#xff0c;怎样才能减少服务器租用的成本呢…...

【性能优化】表分桶实践最佳案例

分桶背景 随着企业的数据不断增长&#xff0c;数据的分布和访问模式变得越来越复杂。我们前面介绍了如何通过对表进行分区来提高查询效率&#xff0c;但对于某些特定的查询模式&#xff0c;特别是需要频繁地进行数据联接查或取样的场景&#xff0c;仍然可能面临性能瓶颈。此外…...

数据仓库的挑战

建设数据仓库是一个复杂且资源密集的过程&#xff0c;需要考虑多个方面。以下是建设数据仓库时常见的挑战及其详细解释&#xff1a; 1. 数据集成 挑战&#xff1a; 数据来源多样&#xff1a;数据来自不同的系统、数据库、文件格式&#xff08;如CSV、JSON、XML&#xff09;、…...

基于ResNet-18的简单分类(新手,而且网络效果不咋滴,就是学个流程)

引言 先看问题&#xff1a; 我手边有一数据集&#xff0c;然后我想分分类&#xff01;~~ 咳咳&#xff0c;最近刚做了一个&#xff1a;训练集有1143张&#xff0c;分为5类&#xff0c;里面图片是打乱的。测试集有248张&#xff0c;想把它分分类看看咋样。 再看一下效果: …...

自动化测试:Autorunner的使用

自动化测试&#xff1a;Autorunner的使用 一、实验目的 1、掌握自动化测试脚本的概念。 2、初步掌握Autorunner的使用 二、Autorunner的简单使用 autoRunner使用方法 新建项目 a) 在项目管理器空白区域,右键鼠标,选择新建项目 b) 输入项目名后,点击[确定]. 在初次打开aut…...

时序预测 | Matlab基于CNN-BiLSTM-Attention多变量时间序列多步预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于CNN-BiLSTM-Attention多变量时间序列多步预测&#xff1b; 2.多变量时间序列数据集&#xff08;负荷数据集&#xff09;&#xff0c;采用前96个时刻预测的特征和负荷数据预测未来96个时刻的负荷数据&…...

软考 系统架构设计师系列知识点之杂项集萃(42)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;41&#xff09; 第67题 Windows操作系统在图形界面处理方面采用的核心架构风格是&#xff08; &#xff09;风格。Java语言宣传的“一次编写&#xff0c;到处运行”的特性&#xff0c;从架构风格…...