FFMpeg源码分析,关键结构体分析(一)

http://lazybing.github.io/blog/categories/ffmpegyuan-ma-fen-xi/

一、下载FFmpeg的编译源码

 进入网站:http://ffmpeg.org/download.html

二、编译源码

执行下述命令:

./configure --prefix=/usr/local/ffmpeg --enable-debug=3 --enable-ffplay
sudo make -j 4
sudo make install

如果编译成功,那么将会在安装路径/user/local/ffmpeg下出现如下子目录
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

FFMpeg 作为音视频领域的开源工具,它几乎可以实现所有针对音视频的处理。本文详细记录使用 FFMpeg 开发过程中,经常使用到的结构体的含义以及使用场景。
首先,我们从 FFMpeg 主要完成的功能视频编解码开始,编解码的大致流程可以使用如下图表
在这里插入图片描述
AVPacket结构体解析
从上面的图中可以看出,解复用器 Demuxer 输出的 packets data 作为解码器 Decoder 的输入;同时也是编码器 Encoder 的输出,复用器 Muxer 的输入。

FFMpeg 中使用 AVpacket 结构定义图中描述的 packet。该结构保存了压缩数据,它由 demuxers 输出,之后作为 decoders 的输入;或作为 encoders 的输出,之后作为 muxers 的输入。

对于视频数据,它只包含一帧压缩数据;对于音频数据,它可能包含多帧压缩数据。

typedef struct AVPacket{
	AVBufferRef *buf;
	int64_t      pts;
	int64_t      dts;
	uint8_t    *data;
	int         size;
	int stream_index;
	int        flags;
	AVPacketSideData *side_data;
	int side_data_elems;
	int   duration;
	int64_t pos;
	int64_t convergence_duration;
}

pts:显示时间戳,它的单位是 AVStream->time_base;如果在文件中没有保存这个值,它被设置为 AV_NOPTS_VALUE。由于图像显示不可能早于图像解压,因此 PTS 必须比 DTS(解码时间戳)大或者相等。某些文件格式中可能会使用 PTS/DTS 表示其他含义,此时时间戳必须转为真正的时间戳才能保存到 AVPacket 结构中。
dts:解码时间戳,它的单位是 AVStream->time_base,表示压缩视频解码的时间,如果文件中没有保存该值,它被设置为 AV_NOPTS_VALUE。
data:指向真正的压缩编码的数据。
size:表示该 AVPacket 结构中 data 字段所指向的压缩数据的大小。
stream_index:标识该 AVPacket 结构所属的视频流或音频流。
duration:该 AVPacket 包以 AVStream->time_base 为单位,所持续的时间,0 表示未知,或者为显示时间戳的差值(next_pts - this pts)。
pos:表示该 AVPacket 数据在媒体中的位置,即字节偏移量。
由上面的图可以看出,该结构主要用于解码器(Decoder)或编码器(Encoder),一般使用方法代码示例如下:

AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.size = ...
avpkt.data = ...

AVFrame结构体解析
上面已经分析了压缩域的表示结构体 AVPacket 结构,与之相对于的,FFMpeg 为之提供的表示像素域的结构体为 AVFrame 结构。从上面的图中也可以看出,Frame 主要作为解码器的输出、编码器的输入。AVFrame 结构主要用来描述未压缩的视频或音频数据,比如视频的 YUV 数据、RGB 数据,音频的 PCM 数据等。

AVFrame 结构体必须使用av_frame_alloc()分配,注意该函数只是分配了 AVFrame 结构本身,它的 data 区域要用其他方式管理;该结构体的释放要用av_frame_free()。

AVFrame 结构体通常只需分配一次,之后即可通过保存不同的数据来重复多次使用,比如一个 AVFrame 结构可以保存从解码器中解码出的多帧数据。此时,就可以使用av_frame_unref()释放任何由 Frame 保存的参考帧并还原回最原始的状态。

typedef struct AVFrame{
	uint8_t *data[AV_NUM_DATA_POINTERS];
	int linesize[AV_NUM_DATA_POINTERS];
	uint8_t **extended_data;
	int width, height;
	int nb_samples; /* number of audio samples(per channel) described by this frame */
	int format;
	int key_frame; /* 1->keyframe, 0->not*/
	enum AVPictureType pict_type;
	AVRational sample_aspect_ratio;
	int64_t pts;
	int64_t pkt_pts;
	int64_t pkt_dts;
	int coded_picture_number;
	int display_picture_number;
	int quality;
	void *opaque; /* for some private data of the user */
	uint64_t error[AV_NUM_DATA_POINTERS];
	int repeat_pict;
	int interlaced_frame;
	int top_field_first;	/* If the content is interlaced, is top field displayed first */
	int palette_has_changed;
    int64_t reordered_opaque;
    int sample_rate;    /*Sample rate of the audio data*/
    uint64_t channel_layout; /*channel layout of the audio data*/
    AVBufferRef *buf[AV_NUM_DATA_POINTERS];
    AVBufferRef **extended_buf;
    int nb_exteneded_buf;
    AVFrameSideData **side_data;
    int nb_side_data;

    int flags;
    enum AVColorRange color_range;
    enum AVColorPrimaries color_primaries;
    enum AVColorTransferCharacteristic color_trc;
    enum AVColorSpace colorspace;
    enum AVChromaLocation chroma_location;

    int64_t best_effort_timestamp;
    int64_t pkt_pos;
    int64_t pkt_duration;
    AVDictionary *metadata;
    int decode _error_flags;

    int channels;
    int pkt_size;
    AVBufferRef *qp_table_buf;
}

data:指向图片或信道的指针,与初始化时分配的大小可能不同,一些解码器取数据范围超出(0,0)-(width, height),具体请查看avcodec_align_dimensions2()方法。一些过滤器或扫描器读数据时可能会超过 16 字节,所以当它们使用时,必须额外分配 16 字节。对于 packed 格式的数据(例如 RGB24),会存放到 data[0] 里面;对于 planar 格式的数据(例如 YUV420P),则会分开 data[0]/data[1]/data[2](YUV420P 中 data[0] 存放 Y,data[1] 存放 U,data[2] 存放 V)。
linesize:对于视频数据,表示每个图像行的字节大小;对于音频数据,表示每个 Plane 的字节大小,只有linesize[0]可以设置,对于plane 音频,每个信道 channel 必须是相同的。对于视频的 linesize 应为 CPU 的对准要求的倍数,一般为 32。注意 linesize 可大于可用的数据的尺寸,有可能存在由于性能原因额外填充。
width/height:视频的宽高
format:帧格式,-1表示未设置的帧格式。对于视频帧,该值为 enum 类型的 AVPixelFormat,例如 AV_PIX_FMT_YUV420P;对于音频帧,该值为 enum 型的 AVSampleFormat,例如 AV_SAMPLE_FMT_S16。
key_frame:关键帧,1 表示关键帧,0 表示非关键帧。
pict_type:帧图片类型,例如 I/P/B。
sample_aspect_ration:帧像素的宽高比,使用 AVRational 表示。
pts:显示时间戳,单位为 time_base。
pkt_pts:该 PTS 是从 AVPacket 结构中拷贝过来的;与之对应的是pkt_dts。
coded_picture_number/display_picture_number:解码序列号和显示序列号(Display Order/Decoded Order)。
interlaced_frame:表示该帧为 interlace 码流或者为 progressive 码流。
top_field_first:对于 interlace 码流,表示该它是 top first or bottom first。

AVCodec结构体解析
上面分析了像素域的表示结构体 AVFrame 和 压缩域的表示结构体 AVPacket,两者之间的转换是通过编解码器来完成的,FFMpeg 中使用 AVCodec 结构体表示编解码。本小节就来看一下 AVCodec 结构体。

typedef struct AVCodec{
	const char *name;
    const char *long_name;
    enum AVMediaType type;
    enum AVCodecID id;
    int capabilities;
    const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0}
    const enum AVPixelFormat *pix_fmts;     ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1
    const int *supported_samplerates;       ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
    const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
    const uint64_t *channel_layouts;         ///< array of support channel layouts, or NULL if unknown. array is terminated by 0
    uint8_t max_lowres;                     ///< maximum value for lowres supported by the decoder, no direct access, use av_codec_get_max_lowres()
    const AVClass *priv_class;              ///< AVClass for the private context
    const AVProfile *profiles;              ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN}
    int priv_data_size;
    struct AVCodec *next;
    int (*init_thread_copy)(AVCodecContext *);
    int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src);
    const AVCodecDefault *defaults;
    void (*init_static_data)(struct AVCodec *codec);

    int (*init)(AVCodecContext *);
    int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size,
    int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame,
                   int *got_packet_ptr);
    int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt);
    int (*close)(AVCodecContext *);
    void (*flush)(AVCodecContext *);
    int caps_internal;
}

name:具体的 CODEC 的名称的简短描述,比如”HEVC”/”H264”等。
long_name: CODEC 名称的详细描述,比如”HEVC (High Efficiency Video Coding)”。
type:媒体类型的字段,它是 enum 型的,表示视频、音频、字幕等,比如AVMEDIA_TYPE_VIDEO、AVMEIDA_TYPE_AUDIO。
id:唯一标识的 CODEC 类型,比如 AV_CODEC_ID_HEVC。
supported_framerates:支持的视频帧率的数组,以{0,0}作为结束。
pix_fmts:编解码器支持的图像格式的数组,以 -1 作为结束。
profiles:编解码器支持的 Profile,以 HEVC 为例,包含”Main”“Main10”“Main Still Picture”。
每一个编解码器对应一个 AVCodec 结构体,对应一种编解码方式,比如 HEVC、AVC、MPEG2、MPEG4、VP6、VP8、VP9等。以 HEVC 为例,FFMpeg中关于 AVCodec 的定义如下:

AVCodec ff_hevc_decoder = {
    .name                  = "hevc",
    .long_name             = NULL_IF_CONFIG_SMALL("HEVC (High Efficiency Video Coding)"),
    .type                  = AVMEDIA_TYPE_VIDEO,
    .id                    = AV_CODEC_ID_HEVC,
    .priv_data_size        = sizeof(HEVCContext),
    .priv_class            = &hevc_decoder_class,
    .init                  = hevc_decode_init,
    .close                 = hevc_decode_free,
    .decode                = hevc_decode_frame,
    .flush                 = hevc_decode_flush,
    .update_thread_context = hevc_update_thread_context,
    .init_thread_copy      = hevc_init_thread_copy,
    .capabilities          = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
                             AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
    .profiles              = NULL_IF_CONFIG_SMALL(profiles),
};

各种不同的编解码器,FFMpeg 使用注册函数avcodec_register_all()来完成。

关于 AVCodec 的通常使用方法:首先,根据特定的 ID 找到特定的编解码器;其次,根据特定的编解码器分配出特定的描述编解码上下文的 AVCodecContext 结构体;之后,打开编解码器;最后,调用编解码器进行编解码。示例代码如下:

AVCodec *codec = NULL;
AVCodecContext *ctx = NULL;

codec = avcodec_find_decoder(origin_ctx->codec_id);
ctx = avcodec_alloc_context3(codec);
avcodec_open2(ctx, codec, NULL);
...

AVCodecContext结构体解析
AVCodecContext 可能是最复杂的结构体了。因为结构体内的变量非常多,不可能一一分析,而且有的变量是编码时候用到、有的是解码时候用到,此处只对几个常用的变量做简要的记录。

typedef struct AVCodecContext{
	const AVClass *av_class;
	int log_level_offset;
	enum AVMediaType codec_type;
	const struct AVCodec *codec;
	enum AVCodecID     codec_id;
	unsigned int codec_tag;
	void *priv_data;
	struct AVCodecInternal *internal;
	void *opaque;
	int bit_rate;
	int bit_rate_tolerance;
	int global_quality;
	int compression_level;
	int flags;
	int flags2;
	uint8_t *extradata;
	int extradata_size;
	AVRational time_base;
	int ticks_per_frame;
	int delay;
	int width, height;
	int coded_width, coded_height;
	int gop_size;
	enum AVPixelFormat pix_fmt;
	void (*draw_horiz_band)(struct AVCodecContext *s,
                            const AVFrame *src, int offset[AV_NUM_DATA_POINTERS],
                            int y, int type, int height);
	enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt);
	int max_b_frames;
	float b_quant_factor;
	int b_frame_strategy;
	float b_quant_offset;
	int has_b_frames;
	int mpeg_quant; 		/*decoding: unused*/
	float i_quant_factor; 	/*decoding: unused*/
	float i_quant_offset; 	/*decoding: unused*/
	float lumi_masking;		/*decoding: unused*/
	float temporal_cplx_masking; /*decoding: unused*/
	float spatial_cplx_masking;  /*decoding: unused*/
	float p_masking;		/*decoding: unused*/
	float dark_masking;		/*decoding: unused*/
	int slice_count;
	int prediction_method;	/*decoding: unused*/
	int *slice_offset;
	AVRational sample_aspect_ratio;
	int me_cmp;				/*decoding: unused*/
	int me_sub_cmp;			/*decoding: unused*/
	int mb_cmp;				/*decoding: unused*/
    ...
}AVCodecContext;

AVMediaType codec_type:编解码器的类型,如音频、视频、字幕。
AVCdec *codec:采用的解码器 AVCodec。
bit_rate: 平均比特率。
int width, height: 视频的宽高。
int refs: 运动估计参考帧的个数。
int sample_rate: 采样率。
int channels: 声道数。
AVCodecContext 使用 avcodec_alloc_context3 分配,该函数除了分配 AVCodecContext 外,还会初始化默认的字段。分配的内存必须通过 avcodec_free_context 释放。

上面提到的几个结构体 AVCodec/AVCodecContext,联合使用,通常是如下形式:

avcodec_register_all();
...
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if(!codec)
    exit(1);

context = avcodec_alloc_context3(codec);

if(avcodec_open2(context, codec, opts) < 0)
    exit(1);

AVStream结构体解析
AVStream用于存储一个视频流、音频流的结构体。

typedef struct AVStream{
	int index;	//stream index in AVFormatContext
	int id;
	AVCodecContext *codec;
	void *priv_data;
	AVRational time_base;
	int64_t start_time;
	int64_t duration;
	int64_t nb_frames;
	int disposition;
	enum AVDiscard discard;
	AVRational sample_aspect_ratio;
	AVDictionary *metadata;
	AVRational avg_frame_rate;
	AVPacket attached_pic;
	AVPacketSideData *side_data;
	int            nb_side_data;
	int event_flags;
	int pts_wrap_bits;
    int64_t first_dts;
    int64_t cur_dts;
    int64_t last_IP_pts;
    int last_IP_duration;
	int probe_packets;
	int codec_info_nb_frames;

    /* av_read_frame() support */
    enum AVStreamParseType need_parsing;
    struct AVCodecParserContext *parser;
    struct AVPacketList *last_in_packet_buffer;
    AVProbeData probe_data;
	#define MAX_REORDER_DELAY 16
    int64_t pts_buffer[MAX_REORDER_DELAY+1];

    AVIndexEntry *index_entries; /**< Only used if the format does not
                                    support seeking natively. */
    int nb_index_entries;
    unsigned int index_entries_allocated_size;
    AVRational r_frame_rate;
    int stream_identifier;

    int64_t interleaver_chunk_size;
    int64_t interleaver_chunk_duration;
    int request_probe;
    int skip_to_keyframe;
    int skip_samples;
    int64_t start_skip_samples;
    int64_t first_discard_sample;
    int64_t last_discard_sample;
    int nb_decoded_frames;
    int64_t mux_ts_offset;
    int64_t pts_wrap_reference;
    int pts_wrap_behavior;
    int update_initial_durations_done;
    int64_t pts_reorder_error[MAX_REORDER_DELAY+1];
    uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1];
    int64_t last_dts_for_order_check;
    uint8_t dts_ordered;
    uint8_t dts_misordered;
    int inject_global_side_data;
    char *recommended_encoder_configuration;
    AVRational display_aspect_ratio;

    struct FFFrac *priv_pts;
}AVStream;

index:标识该视频流、音频流,是 AVFormatContext 中的流索引。
AVCodecContext *codec:指向该视频、音频流的内容。
AVRational time_base:通过该值可以把 PTS/DTS 转化为真正的时间。
int64_t duration:该视频、音频流长度。
AVDictionary *metadata: 元数据信息。
AVRational avg_frame_rate: 帧率。

AVFormatContext 结构体解析
AVFormatContext 是包含码流参数比较多的结构体, 它是 FFmpeg 解封装(flv、mp4、rmvb、avi)功能的结构体。 一般使用 avformat_alloc_context() 来创建该结构体,使用 avformat_free_context 释放该结构体。

typedef struct AVFormatContext {
	const AVClass *av_class;
	struct AVInputFormat *iformat;
	struct AVOutputFormat *oformat;
	void *priv_data;
	AVIOContext *pb;
	int ctx_flags;
	unsigned int nb_streams;
	AVStream **streams;
	char filename[1024];
	int64_t start_time;
	int64_t duration;
	int bit_rate;
    unsigned int packet_size;
    int max_delay;
    int flags;
    const uint8_t *key;
    int keylen;

    unsigned int nb_programs;
    AVProgram **programs;

    enum AVCodecID video_codec_id;
    enum AVCodecID audio_codec_id;
    enum AVCodecID subtitle_codec_id;

    unsigned int max_index_size;
    unsigned int max_picture_buffer;
    unsigned int nb_chapters;
    AVChapter **chapters;
    AVDictionary *metadata;
    int64_t start_time_realtime;
    int fps_probe_size;
    int error_recognition;
    AVIOInterruptCB interrupt_callback;
    int64_t max_interleave_delta;
    int strict_std_compliance;
    int event_flags;
    int max_ts_probe;
    int avoid_negative_ts;
    int ts_id;
    int audio_preload;
    int max_chunk_duration;
    int max_chunk_size;
    int use_wallclock_as_timestamps;
    int avio_flags;
    enum AVDurationEstimationMethod duration_estimation_method;
    int64_t skip_initial_bytes;
    unsigned int correct_ts_overflow;
    int seek2any;
    int probe_score;
    int format_probesize;
    char *codec_whitelist;
    char *format_whitelist;
    AVFormatInternal *internal;
    int io_repositioned;
    AVCodec *video_codec;
    AVCodec *audio_codec;
    AVCodec *subtitle_codec;
    AVCodec *data_codec;
    int metadata_header_padding;
    void *opaque;
    av_format_control_message control_message_cb;
    int64_t output_ts_offset;
    uint8_t *dump_separator;
    enum AVCodecID data_codec_id;
    int (*open_cb)(struct AVFormatContext *s, AVIOContext **p, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options);	
}

struct AVInputFormat *iformat; 输入数据的封装格式,由avformat_open_input设置,仅仅在Demuxing使用。
struct AVOutputFormat *oformat; 输出数据的封装格式,必须由使用者在avformat_write_header前设置,由Muxing使用。
priv_data,在muxing中,由avformat_write_header设置;在demuxing中,由avformat_open_input设置。
AVIOContext *pb;输入数据的缓存。如果iformat/oformat.flags设置为AVFMT_NOFILE的话,该字段不需要设置。对于Demuxing ,需要在avformat_open_input前设置,或由avformat_open_input设置;对于Muxing,在avformat_write_header前设置。
ctx_flags,码流的信息,表明码流属性的的信号。由libavformat设置,例如AVFMTCTX_NOHEADER。
nb_streams 指AVFormatContext.streams的数量,必须由avformat_new_stream设置,不能由其他代码改动。
AVStream **streams;文件中所有码流的列表,新的码流创建使用avformat_new_stream函数。Demuxing中,码流由avformat_open_input创建。 如果AVFMTCTX_NOHEADER被设置,新的码流可以出现在av_read_frame中。Muxing中,码流在avformat_write_header之前由用户创建。它的释放是由avformat_free_context完成的。
filename,输入或输出的文件名,Demuxing中由avformat_open_input设置,Muxing中在使用avformat_write_header前由调用者设置。
int64_t duration;码流的时长。
bit_rate,比特率。
enum AVCodecID video_codec_id;
AVDictionary *metadata; 元数据,适用于整个文件。 ·

AVIOContext 结构体解析
AVIOContext 是 FFMpeg 管理输入输出数据的结构体。

typedef struct AVIOContext{
    const AVClass *av_class;
    unsigned char *buffer;  /**< Start of the buffer. */
    int buffer_size;        /**< Maximum buffer size */
    unsigned char *buf_ptr; /**< Current position in the buffer */
    unsigned char *buf_end; /**< End of the data */
    int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
    int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
    int64_t (*seek)(void *opaque, int64_t offset, int whence);
    int64_t pos;            /**< position in the file of the current buffer */
    int must_flush;         /**< true if the next seek should flush */
    int eof_reached;        /**< true if eof reached */
    int write_flag;         /**< true if open for writing */
    int max_packet_size;
    unsigned long checksum;
    unsigned char *checksum_ptr;
    unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
    int error;              /**< contains the error code or 0 if no error happened */
    int (*read_pause)(void *opaque, int pause);
    int64_t (*read_seek)(void *opaque, int stream_index,
                         int64_t timestamp, int flags);
    int seekable;
    int64_t maxsize;
    int direct;
    int64_t bytes_read;
    int seek_count;
    int writeout_count;
    int orig_buffer_size;
    int short_seek_threshold;
}

unsigned char *buffer:缓存开始位置。
int buffer_size:缓存大小。
unsigned char *buf_ptr:当前指针读取到的位置。
unsigned char *buf_end:缓存结束的位置。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Ffmpeg 中 Demux 这一步是通过 avformat_open_input()这个 api 来做的,这个 api 读出文件的头部信息,并做 demux, 在此之后我们就可以读取媒体文件中的音频和视频流,然后通过 av_read_frame()从音频和视频流中读取出基本数据 流 packet,然后将 packet 送到 avcodec_decode_video2()和相对应的 api 进行解码。

在这里插入图片描述
在这里插入图片描述
FFMpeg 的 output_example.c 例子分析

该例子讲了如何输出一个 libavformat 库所支持格式的媒体文件。
在这里插入图片描述
在这里插入图片描述

FFmpeg命令及其用途

FFmpeg是一个功能强大的开源项目,用于处理音视频数据。它支持记录、转换和流化数字音频和视频。
FFmpeg命令行工具提供了丰富的功能,包括但不限于视频格式转换、视频剪辑、音频处理等。以下是一些常用的FFmpeg命令及其用途:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

还有很多命令参数,不说了

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

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

相关文章

Redis主从复制机制详解

目录 一、主从复制介绍二、搭建主从复制三、主从复制流程四、关于Replication ID五、主从复制核心知识六、主从复制应用场景七、主从复制的注意事项八、读写分离实战 一、主从复制介绍 1、什么是主从复制&#xff1f; 2、为什么要使用主从复制&#xff1f; redis-server单点…

谷歌浏览器 文件下载提示网络错误

情况描述&#xff1a; 谷歌版本&#xff1a;129.0.6668.90 (正式版本) &#xff08;64 位&#xff09; (cohort: Control)其他浏览器&#xff0c;比如火狐没有问题&#xff0c;但是谷歌会下载失败&#xff0c;故推断为谷歌浏览器导致的问题小文件比如1、2M会成功&#xff0c;大…

【问题分析】使用gperftools分析排查内存问题

背景 当程序长时间允许时(压测、服务器程序)&#xff0c;就会面临更大的挑战&#xff0c;其中内存泄漏就是一类典型的问题&#xff0c;内存泄漏往往不易发现&#xff0c;导致的现象更是千奇百怪&#xff0c;本文主要介绍如何借助gperftools分析一个模块的内存泄漏 案例代码 …

yum仓库安装rabbitmq

yum仓库安装rabbitmq 1、配置yum仓库 vim /etc/yum.repos.d/rabbitmq.repo # In /etc/yum.repos.d/rabbitmq.repo## ## Zero dependency Erlang ##[rabbitmq_erlang] namerabbitmq_erlang baseurlhttps://packagecloud.io/rabbitmq/erlang/el/7/$basearch repo_gpgcheck1 gpg…

软件工程:需求规格说明书(图书管理系统)

目录 1 导言 1.1 编写目的 1.2 参考资料 2 项目介绍 2.1 项目背景 2.2 项目目标 3 应用环境 3.1 系统运行网络环境 ​编辑 3.2 系统软硬件环境 4 功能模型 4.1 功能角色分析 4.1.1 图书管理员 4.1.2 普通读者 4.1.3 邮件系统 4.2 功能性需求 4.2.1 预定图…

【一步步开发AI运动小程序】二十、AI运动小程序如何适配相机全屏模式?

引言 受小程序camera组件预览和抽帧图像不一致的特性影响&#xff0c;一直未全功能支持全屏模式&#xff0c;详见本系列文件第四节小程序如何抽帧&#xff1b;随着插件在云上赛事、健身锻炼、AI体测、AR互动场景的深入应用&#xff0c;各开发者迫切的希望能在全屏模式下应用&am…

Excel中Ctrl+e的用法

重点&#xff1a;想要使用ctrle&#xff0c;前提是整合或拆分后的结果放置的单元格必须和被提取信息的单元格相邻&#xff0c;且被提取信息的单元格也必须相连。 下图为错误示例 这样则可以使用ctrle 1、信息整合 2、提取信息 3、添加符号 4、信息顺序调换 5、数字提取 crtle还…

Vue3 + Element plus 实现切换el-radio前二次确认

Vue3 Element plus 实现切换el-radio前二次确认 场景&#xff1a;点击切换el-radio之前判断当前内容是否有改变&#xff0c;如有改变弹窗提示切换el-radio将销毁操作&#xff0c;弹窗二次确认是否切换 问题&#xff1a; el-radio 没有提供类似于beforeUpdate这样的钩子去处理这…

手写mybatis之细化XML语句构建器,完善静态SQL解析

前言 1&#xff1a;在流程上&#xff0c;通过 DefaultSqlSession#selectOne 方法调用执行器&#xff0c;并通过预处理语句处理器 PreparedStatementHandler 执行参数设置和结果查询。 2&#xff1a;那么这个流程中我们所处理的参数信息&#xff0c;也就是每个 SQL 执行时&#…

基于yolov10的芒果成熟度检测系统,支持图像、视频和摄像实时检测【pytorch框架、python】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; yolov10&#xff0c;芒果成熟度检测系统&#xff0c;支持图像、视频和摄像实时检测【pytorch框架、python】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov10的芒果成熟度检测系统是…

npm install报错一堆sass gyp ERR!

执行npm install &#xff0c;出现一堆gyp含有sass错误的情况下。 解决办法&#xff1a; 首页可能是node版本问题&#xff0c;太高或者太低&#xff0c;也会导致npm install安装错误&#xff08;不会自动生成node_modules文件&#xff09;&#xff0c;本次试验&#xff0c;刚开…

【JavaEE】——初始网络原理

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;局域网 1&#xff1a;概念 二&#xff1a;局域网的连接方式 1&#xff1a;网线直连 …

flask项目框架搭建

目录结构 blueprints python包&#xff0c;蓝图文件&#xff0c;相当于路由组的概念,方便模块化开发 例如auth.py文件 from flask import Blueprint, render_templatebp Blueprint("auth", __name__, url_prefix"/auth")bp.route("/login") d…

空间解析几何3-空间点到线段和平面的距离【附MATLAB代码】

目录 空间中点到线段的距离 空间中点到平面的投影和距离 matlab代码 空间中点到线段的距离 空间中点到平面的投影和距离 matlab代码 function [dis,P2,t] point2Line (A1,B1,C1) %求空间一点到一线段的最短距离 %[dis,P2,Q2]pointSegmentDistance(A,B,C) %A B为线段首末端…

问卷调查毕设计算机毕业设计投票系统SpringBootSSM框架

目录 一、引言‌ ‌二、需求分析‌ 用户角色‌&#xff1a; ‌功能需求‌&#xff1a; ‌非功能需求‌&#xff1a; ‌三、系统设计‌ ‌技术选型‌&#xff1a; ‌数据库设计‌&#xff1a; ‌界面设计‌&#xff1a; ‌四、实现步骤‌ ‌后端实现‌&#xff1a; …

蓝桥杯【物联网】零基础到国奖之路:十八. 扩展模块之光敏和AS312

蓝桥杯【物联网】零基础到国奖之路:十八.扩展模块之光敏和AS312 第一节 硬件解读第二节 CubeMX配置第二节 代码 第一节 硬件解读 光敏和AS312如下图&#xff1a; 光敏电阻接到了扩展模块的5号引脚&#xff0c;5号引脚接了2个电阻&#xff0c;R8和光敏电阻。我们通过ADC读取这…

vue+ElementUI—实现基础后台管理布局(sideBar+header+appMain)(附源码)

后台管理的模板很多&#xff0c;vue本身就提供了完整的vue-template-admin&#xff0c;vue-admin-beautiful等后台管理系统化框架&#xff0c;但是这些框架正是因为成体系而显得繁重。假如你想搭建一个静态的后台管理模板页面和几个单独的菜单页面&#xff0c;直接就上框架是否…

维生素对于生活的重要性

在探索健康奥秘的旅途中&#xff0c;维生素作为人体不可或缺的微量营养素&#xff0c;扮演着至关重要的角色。它们虽不直接提供能量&#xff0c;却是酶促反应、细胞代谢、免疫功能乃至心理健康的基石。今天&#xff0c;让我们一同深入探讨人体所需补充的维生素&#xff0c;这些…

VSCode 使用 EmmyLua 对lua进行调试

时间&#xff1a;2024年10月 其他&#xff1a;win10&#xff0c;EmmyLua v0.8.20 参考&#xff1a;https://blog.csdn.net/ShenHaoDeHao/article/details/140268354 有几个概念搞清楚就好理解了。一般开发中&#xff0c;我们编写的lua文件由宿主程序的来解析、执行&#xff1…

【计算机网络 - 基础问题】每日 3 题(三十九)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…