[音视频学习笔记]八、FFMpeg结构体分析 -上一个项目用到的数据结构简单解析:AVFrame、AVFormatContext、AVCodecContext

前言

上次我们做了一个简单的视频解码,MediaPlay-FFmpeg - Public 这一次简单对这个代码进行一个剖析,对其中的数据结构进行一个解析。

这些数据结构之间的关系

AVFrame 、AVFormatContext 、AVCodecContext 、AVIOContext 、AVCodec 、AVStream 、AVPacket

最关键的结构体可以分成以下几类:

1. 解协议(http,rtsp,rtmp,mms)

AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。(注意:FFMPEG中文件也被当做一种协议“file”)

2. 解封装(flv,avi,rmvb,mp4)

AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。

3. 解码(h264,mpeg2,aac,mp3)

每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。

4. 存数据

视频的话,每个结构一般是存一帧;音频可能有好几帧

解码前数据:AVPacket

解码后数据:AVFrame

他们之间的对应关系如下所示:

在这里插入图片描述

AVFrame

AVFrame是包含码流参数较多的结构体。本文将会详细分析一下该结构体里主要变量的含义和作用。

首先看一下结构体的定义(位于avcodec.h):

AVFrame结构体一般用于存储原始数据(即非压缩数据,例如对视频来说是YUV,RGB,对音频来说是PCM),此外还包含了一些相关的信息。比如说,解码的时候存储了宏块类型表,QP表,运动矢量表等数据。编码的时候也存储了相关的数据。因此在使用FFMPEG进行码流分析的时候,AVFrame是一个很重要的结构体。

下面看几个主要变量的作用(在这里考虑解码的情况):

uint8_t *data[AV_NUM_DATA_POINTERS]:解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM)int linesize[AV_NUM_DATA_POINTERS]:data中“一行”数据的大小。注意:未必等于图像的宽,一般大于图像的宽。int width, height:视频帧宽和高(1920x1080,1280x720...int nb_samples:音频的一个AVFrame中可能包含多个音频帧,在此标记包含了几个int format:解码后原始数据类型(YUV420,YUV422,RGB24...int key_frame:是否是关键帧enum AVPictureType pict_type:帧类型(I,B,P...)AVRational sample_aspect_ratio:宽高比(16:94:3...int64_t pts:显示时间戳int coded_picture_number:编码帧序号int display_picture_number:显示帧序号int8_t *qscale_table:QP表uint8_t *mbskip_table:跳过宏块表int16_t (*motion_val[2])[2]:运动矢量表uint32_t *mb_type:宏块类型表short *dct_coeff:DCT系数,这个没有提取过int8_t *ref_index[2]:运动估计参考帧列表(貌似H.264这种比较新的标准才会涉及到多参考帧)int interlaced_frame:是否是隔行扫描uint8_t motion_subsample_log2:一个宏块中的运动矢量采样个数,取log的

具体细节说明:

1.data[]

对于packed格式的数据(例如RGB24),会存到data[0]里面。

对于planar格式的数据(例如YUV420P),则会分开成data[0],data[1],data[2]…(YUV420P中data[0]存Y,data[1]存U,data[2]存V)

取帧转换相关的内容详情参考 : [音视频学习笔记]一、YUV和RGB像素数据的常见处理

2. pict_type

包含以下类型:

enum AVPictureType {AV_PICTURE_TYPE_NONE = 0, ///< 未定义AV_PICTURE_TYPE_I,     ///< I帧AV_PICTURE_TYPE_P,     ///< P帧AV_PICTURE_TYPE_B,     ///< B帧AV_PICTURE_TYPE_S,     ///< S帧AV_PICTURE_TYPE_SI,    ///< SI 帧AV_PICTURE_TYPE_SP,    ///< SP 帧AV_PICTURE_TYPE_BI,    ///< BI 帧
};
3. sample_aspect_ratio

采样宽高比:

宽高比是一个分数,FFMPEG中用AVRational表达分数:

/*** 有理数分子/分母*/
typedef struct AVRational{int num; ///< 分子int den; ///< 分母
} AVRational;
4. qscale_table

QP表指向一块内存,里面存储的是每个宏块的QP值。宏块的标号是从左往右,一行一行的来的。每个宏块对应1个QP。

qscale_table[0]就是第1行第1列宏块的QP值;qscale_table[1]就是第1行第2列宏块的QP值;qscale_table[2]就是第1行第3列宏块的QP值。以此类推…

宏块的个数用下式计算:

注:宏块大小是16x16的。

每行宏块数:

int mb_stride = pCodecCtx->width/16+1

宏块的总数:

int mb_sum = ((pCodecCtx->height+15)>>4)*(pCodecCtx->width/16+1)
5. motion_subsample_log2

1个运动矢量所能代表的画面大小(用宽或者高表示,单位是像素),注意,这里取了log2。

代码注释中给出以下数据:

4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2

即1个运动矢量代表16x16的画面的时候,该值取4;1个运动矢量代表8x8的画面的时候,该值取3…以此类推

6. motion_val

运动矢量表存储了一帧视频中的所有运动矢量。

该值的存储方式比较特别:

int16_t (*motion_val[2])[2];

注释中给了一段代码:

int mv_sample_log2= 4 - motion_subsample_log2;
int mb_width= (width+15)>>4;
int mv_stride= (mb_width << mv_sample_log2) + 1;
motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y];

大概知道了该数据的结构:

1.首先分为两个列表L0和L1

2.每个列表(L0或L1)存储了一系列的MV(每个MV对应一个画面,大小由motion_subsample_log2决定)

3.每个MV分为横坐标和纵坐标(x,y)

注意,在FFMPEG中MV和MB在存储的结构上是没有什么关联的,第1个MV是屏幕上左上角画面的MV(画面的大小取决于motion_subsample_log2),第2个MV是屏幕上第1行第2列的画面的MV,以此类推。因此在一个宏块(16x16)的运动矢量很有可能如下图所示(line代表一行运动矢量的个数):

//例如8x8划分的运动矢量与宏块的关系://-------------------------//|          |            |//|mv[x]     |mv[x+1]     |//-------------------------//|          |	          |//|mv[x+line]|mv[x+line+1]|//-------------------------
7. mb_type

宏块类型表存储了一帧视频中的所有宏块的类型。其存储方式和QP表差不多。只不过其是uint32类型的,而QP表是uint8类型的。每个宏块对应一个宏块类型变量。

宏块类型如下定义所示:

//The following defines may change, don't expect compatibility if you use them.
#define MB_TYPE_INTRA4x4   0x0001
#define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific
#define MB_TYPE_INTRA_PCM  0x0004 //FIXME H.264-specific
#define MB_TYPE_16x16      0x0008
#define MB_TYPE_16x8       0x0010
#define MB_TYPE_8x16       0x0020
#define MB_TYPE_8x8        0x0040
#define MB_TYPE_INTERLACED 0x0080
#define MB_TYPE_DIRECT2    0x0100 //FIXME
#define MB_TYPE_ACPRED     0x0200
#define MB_TYPE_GMC        0x0400
#define MB_TYPE_SKIP       0x0800
#define MB_TYPE_P0L0       0x1000
#define MB_TYPE_P1L0       0x2000
#define MB_TYPE_P0L1       0x4000
#define MB_TYPE_P1L1       0x8000
#define MB_TYPE_L0         (MB_TYPE_P0L0 | MB_TYPE_P1L0)
#define MB_TYPE_L1         (MB_TYPE_P0L1 | MB_TYPE_P1L1)
#define MB_TYPE_L0L1       (MB_TYPE_L0   | MB_TYPE_L1)
#define MB_TYPE_QUANT      0x00010000
#define MB_TYPE_CBP        0x00020000
//Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...)

一个宏块如果包含上述定义中的一种或两种类型,则其对应的宏块变量的对应位会被置1。
注:一个宏块可以包含好几种类型,但是有些类型是不能重复包含的,比如说一个宏块不可能既是16x16又是8x8。

8. ref_index

运动估计参考帧列表存储了一帧视频中所有宏块的参考帧索引。这个列表其实在比较早的压缩编码标准中是没有什么用的。只有像H.264这样的编码标准才有多参考帧的概念。但是这个字段目前我还没有研究透。只是知道每个宏块包含有4个该值,该值反映的是参考帧的索引。以后有机会再进行细研究吧。

使用解析:

我们在使用的时候,主要是使用avcodec_receive_frame函数,将packet解码成AVFrame数据,然后通过sws_scale转换成RGB数据,然后将获得的二进制数据转换成一张照片进行播放。

大概流程:

...
AVFrame* ptr_avframe, * ptr_avframeRGB = nullptr;
...//初始化数据帧空间
ptr_avframe = av_frame_alloc();
ptr_avframeRGB = av_frame_alloc();//av_image_get_buffer_size一帧大小buf = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32, ptr_avctx->width, ptr_avctx->height, 1));av_image_fill_arrays(ptr_avframeRGB->data, ptr_avframeRGB->linesize, buf, AV_PIX_FMT_RGB32, ptr_avctx->width, ptr_avctx->height, 1);...//解码视频数据AVCodecContext
ret = avcodec_receive_frame(ptr_avctx, ptr_avframe);...
// 处理解码后的图像帧
sws_scale(ptr_swsCtx, (const unsigned char* const*)ptr_avframe->data, ptr_avframe->linesize, 0, ptr_avctx->height, ptr_avframeRGB->data, ptr_avframeRGB->linesize);...
//释放资源
av_frame_free(&ptr_avframeRGB);
av_frame_free(&ptr_avframe);

AVCodecContext

AVCodecContext是包含变量较多的结构体(感觉差不多是变量最多的结构体)。本文将会大概分析一下该结构体里每个变量的含义和作用。因为如果每个变量都分析的话,工作量太大,实在来不及。
首先看一下结构体的定义(位于avcodec.h):

主要挑一些常用参数

enum AVMediaType codec_type:编解码器的类型(视频,音频...struct AVCodec  *codec:采用的解码器AVCodec(H.264,MPEG2...int bit_rate:平均比特率uint8_t *extradata; int extradata_size:针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)AVRational time_base:根据该参数,可以把PTS转化为实际的时间(单位为秒s)int width, height:如果是视频的话,代表宽和高int refs:运动估计参考帧的个数(H.264的话会有多帧,MPEG2这类的一般就没有了)int sample_rate:采样率(音频)int channels:声道数(音频)enum AVSampleFormat sample_fmt:采样格式int profile:型(H.264里面就有,其他编码标准应该也有)int level:级(和profile差不太多)

在这里需要注意:AVCodecContext中很多的参数是编码的时候使用的,而不是解码的时候使用的。

1. codec_type

编解码器类型有以下几种:

enum AVMediaType {AVMEDIA_TYPE_UNKNOWN = -1,  ///< Usually treated as AVMEDIA_TYPE_DATAAVMEDIA_TYPE_VIDEO,AVMEDIA_TYPE_AUDIO,AVMEDIA_TYPE_DATA,          ///< Opaque data information usually continuousAVMEDIA_TYPE_SUBTITLE,AVMEDIA_TYPE_ATTACHMENT,    ///< Opaque data information usually sparseAVMEDIA_TYPE_NB
};

2. sample_fmt

在FFMPEG中音频采样格式有以下几种:

enum AVSampleFormat {AV_SAMPLE_FMT_NONE = -1,AV_SAMPLE_FMT_U8,          ///< unsigned 8 bitsAV_SAMPLE_FMT_S16,         ///< signed 16 bitsAV_SAMPLE_FMT_S32,         ///< signed 32 bitsAV_SAMPLE_FMT_FLT,         ///< floatAV_SAMPLE_FMT_DBL,         ///< doubleAV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planarAV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planarAV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planarAV_SAMPLE_FMT_FLTP,        ///< float, planarAV_SAMPLE_FMT_DBLP,        ///< double, planarAV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};

3. profile

在FFMPEG中型有以下几种,可以看出AAC,MPEG2,H.264,VC-1,MPEG4都有型的概念。

#define FF_PROFILE_UNKNOWN -99
#define FF_PROFILE_RESERVED -100#define FF_PROFILE_AAC_MAIN 0
#define FF_PROFILE_AAC_LOW  1
#define FF_PROFILE_AAC_SSR  2
#define FF_PROFILE_AAC_LTP  3
#define FF_PROFILE_AAC_HE   4
#define FF_PROFILE_AAC_HE_V2 28
#define FF_PROFILE_AAC_LD   22
#define FF_PROFILE_AAC_ELD  38#define FF_PROFILE_DTS         20
#define FF_PROFILE_DTS_ES      30
#define FF_PROFILE_DTS_96_24   40
#define FF_PROFILE_DTS_HD_HRA  50
#define FF_PROFILE_DTS_HD_MA   60#define FF_PROFILE_MPEG2_422    0
#define FF_PROFILE_MPEG2_HIGH   1
#define FF_PROFILE_MPEG2_SS     2
#define FF_PROFILE_MPEG2_SNR_SCALABLE  3
#define FF_PROFILE_MPEG2_MAIN   4
#define FF_PROFILE_MPEG2_SIMPLE 5#define FF_PROFILE_H264_CONSTRAINED  (1<<9)  // 8+1; constraint_set1_flag
#define FF_PROFILE_H264_INTRA        (1<<11) // 8+3; constraint_set3_flag#define FF_PROFILE_H264_BASELINE             66
#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED)
#define FF_PROFILE_H264_MAIN                 77
#define FF_PROFILE_H264_EXTENDED             88
#define FF_PROFILE_H264_HIGH                 100
#define FF_PROFILE_H264_HIGH_10              110
#define FF_PROFILE_H264_HIGH_10_INTRA        (110|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_HIGH_422             122
#define FF_PROFILE_H264_HIGH_422_INTRA       (122|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_HIGH_444             144
#define FF_PROFILE_H264_HIGH_444_PREDICTIVE  244
#define FF_PROFILE_H264_HIGH_444_INTRA       (244|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_CAVLC_444            44#define FF_PROFILE_VC1_SIMPLE   0
#define FF_PROFILE_VC1_MAIN     1
#define FF_PROFILE_VC1_COMPLEX  2
#define FF_PROFILE_VC1_ADVANCED 3#define FF_PROFILE_MPEG4_SIMPLE                     0
#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE            1
#define FF_PROFILE_MPEG4_CORE                       2
#define FF_PROFILE_MPEG4_MAIN                       3
#define FF_PROFILE_MPEG4_N_BIT                      4
#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE           5
#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION      6
#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE     7
#define FF_PROFILE_MPEG4_HYBRID                     8
#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME         9
#define FF_PROFILE_MPEG4_CORE_SCALABLE             10
#define FF_PROFILE_MPEG4_ADVANCED_CODING           11
#define FF_PROFILE_MPEG4_ADVANCED_CORE             12
#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13
#define FF_PROFILE_MPEG4_SIMPLE_STUDIO             14
#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE           15

使用解析

AVCodeContext主要通过AVFormatContext来查找到需要的编码器,来解码视频数据

...
AVCodecContext* ptr_avctx = nullptr;
...
//获取视频流编码
ptr_avctx = avcodec_alloc_context3(nullptr);...//查找编码器avcodec_parameters_to_context(ptr_avctx, ptr_formatCtx->streams[streamIndex]->codecpar);ptr_codec = avcodec_find_decoder(ptr_avctx->codec_id);...
avcodec_close(ptr_avctx);...
if (avcodec_open2(ptr_avctx, ptr_codec, nullptr) < 0) {avcodec_close(ptr_avctx);
...
buf = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32, ptr_avctx->width, ptr_avctx->height, 1));av_image_fill_arrays(ptr_avframeRGB->data, ptr_avframeRGB->linesize, buf, AV_PIX_FMT_RGB32, ptr_avctx->width, ptr_avctx->height, 1);

AVFormatContext

AVFormatContext是包含码流参数较多的结构体。
在使用FFMPEG进行开发的时候,AVFormatContext是一个贯穿始终的数据结构,很多函数都要用到它作为参数。它是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体。下面看几个主要变量的作用(在这里考虑解码的情况):

AVIOContext *pb:输入数据的缓存unsigned int nb_streams:视音频流的个数AVStream **streams:视音频流char filename[1024]:文件名int64_t duration:时长(单位:微秒us,转换为秒需要除以1000000int bit_rate:比特率(单位bps,转换为kbps需要除以1000)AVDictionary *metadata:元数据

视频的时长可以转换成HH:MM:SS的形式,示例代码如下:

AVFormatContext *pFormatCtx;
CString timelong;
...
//duration是以微秒为单位
//转换成hh:mm:ss形式
int tns, thh, tmm, tss;
tns  = (pFormatCtx->duration)/1000000;
thh  = tns / 3600;
tmm  = (tns % 3600) / 60;
tss  = (tns % 60);
timelong.Format("%02d:%02d:%02d",thh,tmm,tss);

视频的原数据(metadata)信息可以通过AVDictionary获取。元数据存储在AVDictionaryEntry结构体中,如下所示

typedef struct AVDictionaryEntry {char *key;char *value;
} AVDictionaryEntry;

每一条元数据分为key和value两个属性。
在ffmpeg中通过av_dict_get()函数获得视频的原数据。

下列代码显示了获取元数据并存入meta字符串变量的过程,注意每一条key和value之间有一个"\t:“,value之后有一个”\r\n"

//MetaData------------------------------------------------------------
//从AVDictionary获得
//需要用到AVDictionaryEntry对象
//CString author,copyright,description;
CString meta=NULL,key,value;
AVDictionaryEntry *m = NULL;
//不用一个一个找出来
/*	m=av_dict_get(pFormatCtx->metadata,"author",m,0);
author.Format("作者:%s",m->value);
m=av_dict_get(pFormatCtx->metadata,"copyright",m,0);
copyright.Format("版权:%s",m->value);
m=av_dict_get(pFormatCtx->metadata,"description",m,0);
description.Format("描述:%s",m->value);
*/
//使用循环读出
//(需要读取的数据,字段名称,前一条字段(循环时使用),参数)
while(m=av_dict_get(pFormatCtx->metadata,"",m,AV_DICT_IGNORE_SUFFIX)){key.Format(m->key);value.Format(m->value);meta+=key+"\t:"+value+"\r\n" ;
}

调用示例

...
AVFormatContext* ptr_formatCtx = nullptr;...//创建AVFormatContext
ptr_formatCtx = avformat_alloc_context();
...//初始化ptr_formatCtx 
if (avformat_open_input(&ptr_formatCtx, videopath, nullptr, nullptr) != 0) {qDebug() << "AVFormat open input Error";return -1;
}//获取音频流数据信息
if (avformat_find_stream_info(ptr_formatCtx, nullptr) < 0) {avformat_close_input(&ptr_formatCtx);qDebug() << "AVFormat find stream info Error";return -2;
}...
for (int i = 0; i < ptr_formatCtx->nb_streams; ++i) {if (ptr_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {streamIndex = i;blnVideo = true;break;}
}
...
//查找编码器
avcodec_parameters_to_context(ptr_avctx, ptr_formatCtx->streams[streamIndex]->codecpar);...if (av_read_frame(ptr_formatCtx, ptr_avpkg) >= 0) {	//读取一帧未解码的数据...avformat_close_input(&ptr_formatCtx);

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

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

相关文章

flask_restful规范返回值之类型设置

大型的互联网项目中&#xff0c;返回的数据格式&#xff0c;有时是比较复杂的结构。 如&#xff1a;豆瓣电影 https://movie.douban.com/j/chart/top_list?type24&interval_id 100%3A90&action&start20&limit20 返回的值里有 json 或者列表数据&#xff0c…

第十一届蓝桥杯大赛第二场省赛试题 CC++ 研究生组-子串分值和

solution1&#xff08;通过40%&#xff09; 依次求子串并统计出现过的字母个数 #include<iostream> #include<string> #include<set> using namespace std; int main(){string s, subs;cin >> s;int len s.size(), ans 0;for(int j 1; j < len…

vscode下c++的boost库安装

Boost Downloadshttps://www.boost.org/users/download/下载最新的库文件。在shell中&#xff0c;使用命令bootstrap.bat gcc生成b2.exe文件。然后是.\b2.exe toolsetgcc生成库文件&#xff0c;在stage\lib文件夹下把stage\lib文件夹中的库文件拷贝到mingw64\x86_64-w64-mingw3…

Node.js之沙盒专题

​ Node.js一直是薄弱项&#xff0c;今天特意整理一下&#xff0c;基本上是各个大佬写的大杂烩&#xff0c;仅用于学习记录~~~ 1. child_process 首先介绍一下nodejs中用来执行系统命令的模块child_process。Nodejs通过使用child_process模块来生成多个子进程来处理其他事物…

(三)Qt+OpenCV调用海康工业相机SDK抓拍示例

系列文章目录 提示&#xff1a;这里是该系列文章的所有文章的目录 第一章&#xff1a; &#xff08;一&#xff09;QtOpenCV调用海康工业相机SDK示例开发 第二章&#xff1a; &#xff08;二&#xff09;Qt多线程实现海康工业相机图像实时采集 第三章&#xff1a; &#xff08;…

命令模式(请求与具体实现解耦)

目录 前言 UML plantuml 类图 实战代码 模板 Command Invoker Receiver Client 前言 命令模式解耦了命令请求者&#xff08;Invoker&#xff09;和命令执行者&#xff08;receiver&#xff09;&#xff0c;使得 Invoker 不再直接引用 receiver&#xff0c;而是依赖于…

学习vue3第十一节(依赖注入:provide/inject)

本机介绍&#xff1a;provide/inject 注意&#xff1a;大家在看此小节时候&#xff0c;默认大家已经了解一些组件的使用方法 1、依赖注入的用途&#xff1a; 当嵌套层级多的时候&#xff0c;某个子组件需要较远层级的父组件数据时候&#xff0c;如果我们依然使用props 传递数…

数据挖掘与机器学习 1. 绪论

于高山之巅&#xff0c;方见大河奔涌&#xff1b;于群峰之上&#xff0c;便觉长风浩荡 —— 24.3.24 一、数据挖掘和机器学习的定义 1.数据挖掘的狭义定义 背景&#xff1a;大数据时代——知识贫乏 数据挖掘的狭义定义&#xff1a; 数据挖掘就是从大量的、不完全的、有噪声的、…

CI/CD实战-jenkins结合docker 5

实验准备&#xff1a; 在docker主机要下载git工具 禁掉key的校验 确保在立即构建项目时不会出现任何报错&#xff1a; 自动化构建docker镜像 在server3上安装docker-ce 修改内核参数 拷贝证书 添加默认仓库 添加harbor仓库的解析 测试拉取 登录harbor私有仓库 在jenkins安装d…

微服务day06 -- Elasticsearch的数据搜索功能。分别使用DSL和RestClient实现搜索

1.DSL查询文档 elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1.1.DSL查询分类 Elasticsearch提供了基于JSON的DSL&#xff08;Domain Specific Language&#xff09;来定义查询。常见的查询类型包括&#xff1a; 查询所有&#xff1a;查询出所有数据&#xff0c;一…

linux用户管理1

linux系统可以多用户同时登录&#xff0c;在各自权限下做各自的事情 useradd添加普通用户&#xff0c;之后使用suusername切换用户 所有用户中&#xff0c;root用户权限最大&#xff0c;对应uid&#xff0c;gid均为0&#xff0c;uid为用户编号&#xff0c;gid为用户所在组编号…

AcWing 4609:火柴棍数字 ← 贪心算法

【题目来源】 https://www.acwing.com/problem/content/4612/【题目描述】 给定 n 个火柴棍&#xff0c;你可以用它们摆出数字 0∼9。 摆出每个数字所需要的具体火柴棍数量如下图所示&#xff1a; 请你用这些火柴棍摆成若干个数字&#xff0c;并把这些数字排成一排组成一个整数…

【数据结构和算法初阶(C语言)】二叉树的链式结构--前、中、后序遍历实现详解,节点数目计算及oj题目详解---二叉树学习日记③

目录 ​编辑 1.二叉树的链式存储 2.二叉树链式结构的实现 2.1树的创建 2.2二叉树的再理解 3.链式结构二叉树的遍历 3.1前序遍历实现&#xff1a; ​编辑 3.2中序遍历实现 3.3后序遍历 ​编辑 4.链式二叉树节点数目的计算 4.1 总节点个数的计算 错误代码1&#xff1a; 错误代…

使用git下载github/gitee仓库部分或单个文件的方法

前言 有些时候在github或者gitee仓库中我们只需要下载整个项目中的我门需要的那一部分文件夹或文件就行了&#xff0c;不需要下载所有的项目。这样可以节省很多流量和时间 步骤 1.建立一个新的 git 本地仓库 这里我在D:\test中初始化 命令&#xff1a; git init2.在本地仓…

【Yolov7】踩坑记录

#windows上调用cuda去 使用GPU来进行预测 -需要下载cudnn&#xff0c;cuDNN 9.0.0 Downloads | NVIDIA Developer -环境变量要配置 比如 &#xff1a; C:\Program Files\NVIDIA\CUDNN\v9.0\bin\11.8 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.7\bin 也可…

学习笔记Day15:Shell脚本编程

Shell脚本编程 Linux系统环境 Linux系统的4个主要部分&#xff1a;内核、shell、文件系统和应用程序。 内核是操作系统的核心&#xff0c;决定系统性能和稳定性shell &#xff1a;一种应用程序&#xff0c;是用户和内核交互操作的接口&#xff0c;是套在内核外的壳&#xff…

Stable Diffusion 进阶教程 - 二次开发(制作您的文生图应用)

目录 1. 引言 2. 基于Rest API 开发 2.1 前置条件 2.2 代码实现 2.3 效果演示 2.4 常见错误 3. 总结 1. 引言 Stable Diffusion作为一种强大的文本到图像生成模型&#xff0c;已经在艺术、设计和创意领域引起了广泛的关注和应用。然而&#xff0c;对于许多开发者来说&#xff…

使用倒模耳机壳UV树脂胶液制作舞台监听耳返入耳式耳机壳推荐的材料和工艺流程?

推荐的材料和工艺流程如下&#xff1a; 材料&#xff1a; UV树脂胶液&#xff1a;选择适合倒模工艺的UV树脂胶液&#xff0c;要求具有高透明度、良好的流动性和固化性能。模具材料&#xff1a;建议使用硅胶模具&#xff0c;因为硅胶模具具有较高的耐用性和稳定性&#xff0c;…

Linux 安装 JDK、MySQL、Tomcat(图文并茂)

所需资料 下载 1.1 软件安装方式 在Linux系统中&#xff0c;安装软件的方式主要有四种&#xff0c;这四种安装方式的特点如下&#xff1a; 安装方式特点二进制发布包安装软件已经针对具体平台编译打包发布&#xff0c;只要解压&#xff0c;修改配置即可rpm安装软件已经按照re…

C#自定义控件 生成 与 加入到项目

C#自定义控件生成 在C#中&#xff0c;自定义控件通常是通过继承现有的控件类&#xff08;如UserControl、Form等&#xff09;并添加或修改其属性和方法来实现的。以下是一个简单的示例&#xff0c;演示如何创建一个自定义控件&#xff1a; 首先&#xff0c;创建一个新的Window…