FFmpeg——avio_reading实例(学习)

目录

  • 前言
  • 一、源码
  • 二、分析
    • 1、av_file_map函数
    • 2、avformat_alloc_context函数
    • 3、avio_alloc_context函数
    • 4、avformat_open_input函数
    • 5、avformat_find_stream_info函数

前言

avio_reading是关于对音视频流内存读取操作的应用实例,将文件中获取的数据流映射到内存再进行读取解析。(刚开始学习这块,主要作为学习记录,可能会存在很多问题)

一、源码

官方示例源码
如果使用c++需要注意一定要对头文件进行 extern"C"

#include <stdio.h>#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavutil/file.h"struct buffer_data {uint8_t* ptr;size_t size; ///< size left in the buffer
};static int read_packet(void* opaque, uint8_t* buf, int buf_size)
{struct buffer_data* bd = (struct buffer_data*)opaque;buf_size = FFMIN(buf_size, bd->size);if (!buf_size)return AVERROR_EOF;printf("ptr:%p size:%zu\n", bd->ptr, bd->size);/* copy internal buffer data to buf */memcpy(buf, bd->ptr, buf_size);bd->ptr += buf_size;bd->size -= buf_size;return buf_size;
}int main()
{AVFormatContext* fmt_ctx = NULL;       //IO上下文格式AVIOContext* avio_ctx = NULL;         // 字节流上下文uint8_t* buffer = NULL, * avio_ctx_buffer = NULL;size_t buffer_size, avio_ctx_buffer_size = 4096;char* input_filename = NULL;int ret = 0;struct buffer_data bd = { 0 };input_filename = "test.264";/* slurp file content into buffer 读取所有数据*/ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);if (ret < 0){goto end;}/* fill opaque structure used by the AVIOContext read callback */bd.ptr = buffer;          //数据内容指针bd.size = buffer_size;    //数据字节大小if (!(fmt_ctx = avformat_alloc_context())) {ret = AVERROR(ENOMEM);goto end;}avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);if (!avio_ctx_buffer) {ret = AVERROR(ENOMEM);goto end;}avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,0, &bd, &read_packet, NULL, NULL);if (!avio_ctx) {ret = AVERROR(ENOMEM);goto end;}fmt_ctx->pb = avio_ctx;ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL); //  init_input——>av_probe_input_buffer2——>avio_read——>read_packet_wrapper  中调用read_packetif (ret < 0) {fprintf(stderr, "Could not open input\n");goto end;}//获取数据包中的流信息ret = avformat_find_stream_info(fmt_ctx, NULL);    //read_frame_internal——>ff_read_packet  中调用read_packetif (ret < 0) {fprintf(stderr, "Could not find stream information\n");goto end;}//抛出数据流信息av_dump_format(fmt_ctx, 0, input_filename, 0);end:avformat_close_input(&fmt_ctx);/* note: the internal buffer could have changed, and be != avio_ctx_buffer */if (avio_ctx)av_freep(&avio_ctx->buffer);avio_context_free(&avio_ctx);av_file_unmap(buffer, buffer_size);if (ret < 0) {fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));return 1;}return 0;
}

二、分析

1、av_file_map函数

mmap映射
mmap 是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。
进程就可以采用指针的方式读写操作这一段内存,对文件的操作而不必再调用 read、write 等系统调用函数。

具有如下的特点:

1、mmap 提供的内存访问接口是内存地址连续的;
2、mmap 提供的内存空间是虚拟空间(虚拟内存),而不是物理空间(物理内存),因此可以分配远远大于物理内存大小的虚拟空间(例如 8G 内存主机分配 100G 的 mmap 内存空间);
3、mmap 负责映射文件逻辑上一段连续的数据(物理上可以不连续存储)映射为连续内存,而这里的文件可以是磁盘文件、驱动假造出的文件(例如 DMA 技术)以及设备;
4、mmap 由操作系统负责管理,对同一个文件地址的映射将被所有线程共享,操作系统确保线程安全以及线程可见性;

原文链接:https://blog.csdn.net/agonie201218/article/details/123791047

//根据文件名称 读取所有的数据到bufptr,并返回字节 同时可添加日志等级与日志的上下文              
int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, int log_offset, void *log_ctx)
{//日志 FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx };int err, fd = avpriv_open(filename, O_RDONLY); //只读的方式打开文件 (fopen)struct stat st;    //系统中的文件属性的结构  (结构体内容在后面)av_unused void *ptr;off_t off_size;char errbuf[128];*bufptr = NULL;*size = 0;if (fd < 0) {err = AVERROR(errno);av_strerror(err, errbuf, sizeof(errbuf));av_log(&file_log_ctx, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename, errbuf);return err;}//通过文件描述符 获取文件状态if (fstat(fd, &st) < 0) {err = AVERROR(errno);av_strerror(err, errbuf, sizeof(errbuf));av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in fstat(): %s\n", errbuf);close(fd);return err;}off_size = st.st_size;   //文件的字节数//SIZE_MAX 系统最大的字节数(和系统相关)if (off_size > SIZE_MAX) {av_log(&file_log_ctx, AV_LOG_ERROR,"File size for file '%s' is too big\n", filename);close(fd);return AVERROR(EINVAL);}*size = off_size;if (!*size) {*bufptr = NULL;goto out;}//内存映射 linux 
#if HAVE_MMAPptr = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);if (ptr == MAP_FAILED) {err = AVERROR(errno);av_strerror(err, errbuf, sizeof(errbuf));av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in mmap(): %s\n", errbuf);close(fd);*size = 0;return err;}*bufptr = ptr;
//windows 系统的内存映射
#elif HAVE_MAPVIEWOFFILE{HANDLE mh, fh = (HANDLE)_get_osfhandle(fd);//创建映射句柄mh = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL);if (!mh) {av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in CreateFileMapping()\n");close(fd);*size = 0;return -1;}//获取映射地址ptr = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, *size);CloseHandle(mh);if (!ptr) {av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in MapViewOfFile()\n");close(fd);*size = 0;return -1;}*bufptr = ptr;}
#else
//通过read函数获取数据*bufptr = av_malloc(*size);if (!*bufptr) {av_log(&file_log_ctx, AV_LOG_ERROR, "Memory allocation error occurred\n");close(fd);*size = 0;return AVERROR(ENOMEM);}read(fd, *bufptr, *size);
#endifout:close(fd);return 0;
}/*struct stat  {   dev_t       st_dev;     /* ID of device containing file -文件所在设备的ID*/  ino_t       st_ino;     /* inode number -inode节点号*/    mode_t      st_mode;    /* protection -保护模式?*/    nlink_t     st_nlink;   /* number of hard links -链向此文件的连接数(硬连接)*/    uid_t       st_uid;     /* user ID of owner -user id*/    gid_t       st_gid;     /* group ID of owner - group id*/    dev_t       st_rdev;    /* device ID (if special file) -设备号,针对设备文件*/    off_t       st_size;    /* total size, in bytes -文件大小,字节为单位*/    blksize_t   st_blksize; /* blocksize for filesystem I/O -系统块的大小*/    blkcnt_t    st_blocks;  /* number of blocks allocated -文件所占块数*/    time_t      st_atime;   /* time of last access -最近存取时间*/    time_t      st_mtime;   /* time of last modification -最近修改时间*/    time_t      st_ctime;   /* time of last status change - */    };  */

2、avformat_alloc_context函数

分配 媒体格式上下文空间
函数原型

AVFormatContext *avformat_alloc_context(void)
{//  I/O 上下文内容AVFormatContext *ic;//数据流相关AVFormatInternal *internal;ic = av_malloc(sizeof(AVFormatContext));if (!ic) return ic;internal = av_mallocz(sizeof(*internal));if (!internal) {av_free(ic);return NULL;}//获取压缩数据包(音频或视频)临时的internal->pkt = av_packet_alloc();/*  AVPacket *av_packet_alloc(void)
{AVPacket *pkt = av_mallocz(sizeof(AVPacket));if (!pkt)return pkt;get_packet_defaults(pkt);return pkt;
}    */  //数据包internal->parse_pkt = av_packet_alloc();if (!internal->pkt || !internal->parse_pkt) {av_packet_free(&internal->pkt);av_packet_free(&internal->parse_pkt);av_free(internal);av_free(ic);return NULL;}//设置默认参数avformat_get_context_defaults(ic);ic->internal = internal;ic->internal->offset = AV_NOPTS_VALUE;ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;ic->internal->shortest_end = AV_NOPTS_VALUE;return ic;

3、avio_alloc_context函数

分配I/O上下文空间,必须使用avio_context_free().进行清理
函数原型

@param buffer Memory block for input/output operations via AVIOContext.* @param write_flag Set to 1 if the buffer should be writable, 0 otherwise.
* @param opaque An opaque pointer to user-specific data.
* @param read_packet  A function for refilling the buffer, may be NULL.
* @param write_packet A function for writing the buffer contents, may be NULL.
* @param seek A function for seeking to specified byte position, may be NULL.
* @return Allocated AVIOContext or NULL on failure.//需要注意read_packet 、write_packet 这两个回调函数 函数的调用在avformat_open_input和avformat_find_stream_info中
AVIOContext *avio_alloc_context(unsigned char *buffer,int buffer_size,int write_flag,void *opaque,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))
{AVIOContext *s = av_malloc(sizeof(AVIOContext));if (!s)return NULL;//参数初始化 将参数赋值到 AVIOContext ffio_init_context(s, buffer, buffer_size, write_flag, opaque,read_packet, write_packet, seek);/*int ffio_init_context(AVIOContext *s,unsigned char *buffer,int buffer_size,int write_flag,void *opaque,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))
{memset(s, 0, sizeof(AVIOContext));s->buffer      = buffer;s->orig_buffer_size =s->buffer_size = buffer_size;s->buf_ptr     = buffer;s->buf_ptr_max = buffer;s->opaque      = opaque;s->direct      = 0;url_resetbuf(s, write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ);s->write_packet    = write_packet;s->read_packet     = read_packet;s->seek            = seek;s->pos             = 0;s->eof_reached     = 0;s->error           = 0;s->seekable        = seek ? AVIO_SEEKABLE_NORMAL : 0;s->min_packet_size = 0;s->max_packet_size = 0;s->update_checksum = NULL;s->short_seek_threshold = SHORT_SEEK_THRESHOLD;if (!read_packet && !write_flag) {s->pos     = buffer_size;s->buf_end = s->buffer + buffer_size;}s->read_pause = NULL;s->read_seek  = NULL;s->write_data_type       = NULL;s->ignore_boundary_point = 0;s->current_type          = AVIO_DATA_MARKER_UNKNOWN;s->last_time             = AV_NOPTS_VALUE;s->short_seek_get        = NULL;s->written               = 0;return 0;
}*/return s;
}

4、avformat_open_input函数

Open an input stream and read the header. The codecs are not opened.
The stream must be closed with avformat_close_input().
函数原型

int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options)
{AVFormatContext *s = *ps;int i, ret = 0;AVDictionary *tmp = NULL;ID3v2ExtraMeta *id3v2_extra_meta = NULL;if (!s && !(s = avformat_alloc_context()))return AVERROR(ENOMEM);if (!s->av_class) {av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");return AVERROR(EINVAL);}//判断是否有外部格式设置if (fmt)s->iformat = fmt;//其他设置if (options)av_dict_copy(&tmp, *options, 0);//I/O上下文if (s->pb) // must be before any goto fails->flags |= AVFMT_FLAG_CUSTOM_IO;   //官方自定义的I/O上下文//参数设置不为空时生效if ((ret = av_opt_set_dict(s, &tmp)) < 0)goto fail;//av_strdup  复制字符串if (!(s->url = av_strdup(filename ? filename : ""))) {ret = AVERROR(ENOMEM);goto fail;}#if FF_API_FORMAT_FILENAME
FF_DISABLE_DEPRECATION_WARNINGSav_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename));
FF_ENABLE_DEPRECATION_WARNINGS
#endif
//init_input 打开文件 并进行格式探测if ((ret = init_input(s, filename, &tmp)) < 0)goto fail;s->probe_score = ret;if (!s->protocol_whitelist && s->pb && s->pb->protocol_whitelist) {s->protocol_whitelist = av_strdup(s->pb->protocol_whitelist);if (!s->protocol_whitelist) {ret = AVERROR(ENOMEM);goto fail;}}if (!s->protocol_blacklist && s->pb && s->pb->protocol_blacklist) {s->protocol_blacklist = av_strdup(s->pb->protocol_blacklist);if (!s->protocol_blacklist) {ret = AVERROR(ENOMEM);goto fail;}}//av_match_list :Check if a name is in a list 在列表中查找字符产if (s->format_whitelist && av_match_list(s->iformat->name, s->format_whitelist, ',') <= 0) {av_log(s, AV_LOG_ERROR, "Format not on whitelist \'%s\'\n", s->format_whitelist);ret = AVERROR(EINVAL);goto fail;}avio_skip(s->pb, s->skip_initial_bytes);/* Check filename in case an image number is expected. */if (s->iformat->flags & AVFMT_NEEDNUMBER) {if (!av_filename_number_test(filename)) {ret = AVERROR(EINVAL);goto fail;}}s->duration = s->start_time = AV_NOPTS_VALUE;/* Allocate private data. */if (s->iformat->priv_data_size > 0) {if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {ret = AVERROR(ENOMEM);goto fail;}if (s->iformat->priv_class) {*(const AVClass **) s->priv_data = s->iformat->priv_class;av_opt_set_defaults(s->priv_data);if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)goto fail;}}/* e.g. AVFMT_NOFILE formats will not have a AVIOContext */if (s->pb)ff_id3v2_read_dict(s->pb, &s->internal->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);#if FF_API_DEMUXER_OPENif (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
#elseif (s->iformat->read_header)
#endifif ((ret = s->iformat->read_header(s)) < 0)goto fail;if (!s->metadata) {s->metadata = s->internal->id3v2_meta;s->internal->id3v2_meta = NULL;} else if (s->internal->id3v2_meta) {av_log(s, AV_LOG_WARNING, "Discarding ID3 tags because more suitable tags were found.\n");av_dict_free(&s->internal->id3v2_meta);}if (id3v2_extra_meta) {if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") ||!strcmp(s->iformat->name, "tta") || !strcmp(s->iformat->name, "wav")) {if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0)goto close;if ((ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0)goto close;if ((ret = ff_id3v2_parse_priv(s, id3v2_extra_meta)) < 0)goto close;} elseav_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n");}ff_id3v2_free_extra_meta(&id3v2_extra_meta);if ((ret = avformat_queue_attached_pictures(s)) < 0)goto close;#if FF_API_DEMUXER_OPENif (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->internal->data_offset)
#elseif (s->pb && !s->internal->data_offset)
#endifs->internal->data_offset = avio_tell(s->pb);s->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;update_stream_avctx(s);for (i = 0; i < s->nb_streams; i++)s->streams[i]->internal->orig_codec_id = s->streams[i]->codecpar->codec_id;if (options) {av_dict_free(options);*options = tmp;}*ps = s;return 0;close:if (s->iformat->read_close)s->iformat->read_close(s);
fail:ff_id3v2_free_extra_meta(&id3v2_extra_meta);av_dict_free(&tmp);if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))avio_closep(&s->pb);avformat_free_context(s);*ps = NULL;return ret;
}/* Open input file and probe the format if necessary. */
static int init_input(AVFormatContext *s, const char *filename,AVDictionary **options)
{int ret;AVProbeData pd = { filename, NULL, 0 };int score = AVPROBE_SCORE_RETRY;if (s->pb) {s->flags |= AVFMT_FLAG_CUSTOM_IO;if (!s->iformat){/* 探测字节流以确定输入格式。每次探测器返回的数过低时,探测器缓冲区的大小就会增加,并进行另一次尝试。当达到最大探针大小时,将返回输入格式*/return av_probe_input_buffer2(s->pb, &s->iformat, filename,    s, 0, s->format_probesize);}else if (s->iformat->flags & AVFMT_NOFILE)av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and ""will be ignored with AVFMT_NOFILE format.\n");return 0;}if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||(!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))   //Guess the file format 探测文件格式return score;//io_open 回调函数 打开一个新的数据流if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)return ret;if (s->iformat)return 0;return av_probe_input_buffer2(s->pb, &s->iformat, filename,s, 0, s->format_probesize);
}

5、avformat_find_stream_info函数

函数原型

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

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

相关文章

go使用trpc案例

1.go下载trpc go install trpc.group/trpc-go/trpc-cmdline/trpclatest 有报错的话尝试配置一些代理&#xff08;选一个&#xff09; go env -w GOPROXYhttps://goproxy.cn,direct go env -w GOPROXYhttps://goproxy.io,direct go env -w GOPROXYhttps://goproxy.baidu.com/…

普中51单片机学习(红外通信)

红外通信 红外线系统的组成 外线遥控器已被广泛使用在各种类型的家电产品上&#xff0c;它的出现给使用电器提供了很多的便利。红外线系统一般由红外发射装置和红外接收设备两大部分组成。红外发射装置又可由键盘电路、红外编码芯片、电源和红外发射电路组成。红外接收设备可由…

igolang学习2,golang开发配置国内镜像

go env -w GO111MODULEon go env -w GOPROXYhttps://goproxy.cn,direct

什么是系统工程(字幕)36

0 00:00:00,980 --> 00:00:03,240 那首先的话是给 1 00:00:03,820 --> 00:00:06,646 给水加上这个值属性 2 00:00:06,646 --> 00:00:11,170 你看&#xff0c;水之前在这里嘛&#xff0c;没有 3 00:00:11,450 --> 00:00:12,959 属性的&#xff0c;对吧 4 00:00:…

Modern C++ std::visit从实践到原理

前言 std::visit 是 C17 中引入的一个模板函数&#xff0c;它用于对给定的 variant、union 类型或任何其他兼容的类型执行一个访问者操作。这个函数为多种可能类型的值提供了一种统一的访问机制。使用 std::visit&#xff0c;你可以编写更通用和灵活的代码&#xff0c;而无需关…

持续集成,持续交付和持续部署的概念,以及GitLab CI / CD的介绍

引言&#xff1a;上一期我们部署好了gitlab极狐网页版&#xff0c;今天我们介绍一下GitLabCI / CD 目录 一、为什么要 CI / CD 方法 1、持续集成 2、持续交付 3、持续部署 二、GitLab CI / CD简介 三、GitLab CI / CD 的工作原理 4、基本CI / CD工作流程 5、首次设置 …

SQL防止注入工具类,可能用于SQL注入的字符有哪些

SQL注入是一种攻击技术&#xff0c;攻击者试图通过在输入中注入恶意的SQL代码来干扰应用程序的数据库查询。为了防止SQL注入&#xff0c;你需要了解可能用于注入的一些常见字符和技术。以下是一些常见的SQL注入字符和技术&#xff1a; 单引号 ​&#xff1a; 攻击者可能会尝试…

【Spring】声明式事务 spring-tx

文章目录 声明式事务是什么&#xff1f;一、Spring事务管理器二、基于注解的声明式事务1.1 准备工作1.2 基本事务控制1.3 事务属性&#xff1a;只读1.4 事务属性&#xff1a;超时时间1.5 事务属性&#xff1a;事务异常1.6 事务属性&#xff1a;事务隔离级别1.7 事务属性&#x…

【vscode】按F5无法执行调试python或go

原因&#xff1a; 找不到解析器&#xff0c;需要安装插件&#xff08;python&#xff0c;或go 等&#xff09; 安装插件后&#xff0c;还是无法执行&#xff0c;按 ctrlshiftp,看不到解析器 正常应该是&#xff1a; 解决方法&#xff1a; 1、判断python是否安装成功 pyth…

QT之QString.arg输出固定位数

问题描述 我需要用QString输出一个固定位数的数字字符串。起初我的代码是这样&#xff1a; int img_num 1 auto new_name QString("%1.png").arg((int)img_num, 3, 10, 0); //最后一个参数用u0也是一样的 qDebug() << "new_name:" << new…

2024Node.js零基础教程(小白友好型),nodejs新手到高手,(八)NodeJS入门——http模块

一念心清净&#xff0c;处处莲花开。 055_http模块_网页资源加载基本过程 哈喽&#xff0c;大家好&#xff0c;这一课节我们来介绍一下网页资源加载的基本过程。首先先强调一点&#xff0c;这个内容对于我们后续学习非常非常的关键&#xff0c;所以大家务必要将其掌握。 首先先…

安科瑞企业微电网智慧能源管理系统生态交流会顺利举行

2024年1月12日&#xff0c;安科瑞企业微电网智慧能源管理系统生态交流会顺利举行&#xff0c;本次会议旨在围绕双碳目标&#xff0c;共同探讨如何抓住新机遇、新市场&#xff0c;充分利用安科瑞企业微电网智慧能源的一站式服务&#xff0c;为企业节能、减碳、降本赋能&#xff…

Ansible 简介及部署 基础模块学习 ansible部署rsync 及时监控远程同步

Ansible介绍&#xff1a; Ansible 是一个配置管理系统&#xff0c;当下最流行的批量自动化运维工具之一&#xff0c;它是一款开源的自动化工具&#xff0c;基于Python开发的配置管理和应用部署的工具。 Ansible 是基于模块工作的&#xff0c;它只是提供了一种运行框架&#xff…

STM32控制max30102读取血氧心率数据(keil5工程)

一、前言 MAX30102是一款由Maxim Integrated推出的低功耗、高精度的心率和血氧饱和度检测传感器模块&#xff0c;适用于可穿戴设备如智能手环、智能手表等健康管理类电子产品。 该传感器主要特性如下&#xff1a; &#xff08;1&#xff09;光学测量&#xff1a;MAX30102内置…

从Spring-Boot-Starters学习如何治理maven依赖冲突问题

做中间件对接业务的同学&#xff0c;肯定对jar依赖冲突问题印象深刻。 Spring Boot Starters 实质上是Maven依赖和插件模块化管理&#xff0c;见spring-boot-starter-parent的 pom.xml 描述&#xff0c;其初衷是解决jar依赖冲突问题。 Spring Boot Starters 文档 罗列了所有s…

nginx-------- 高性能的 Web服务端 (三) 验证模块 页面配置

一、http设置 1.1 验证模块 需要输入用户名和密码 htpasswd 此命令来自于 httpd-tools 包&#xff0c;如果没有安装 安装一下即可 也可以安装httpd 直接yum install httpd -y 也一样 第一次生成文件htpasswd -c 文件路径 姓名 交互式生成密码 htpasswd -bc 文…

c语言的数据结构:找环状链表入口处

一起<(&#xffe3;︶&#xffe3;)↗[GO!] 1.如何判断一个链表是否有环 思路:设定两个快慢指针fast和slow,fast每次走两个结点,slow每次走一个节点 如果fast指针遇到了Null,那么这个链表没有环,如果fast和slow可以相遇,则代表这个链表有环 代码如下 N:fast先进环,slow后…

[C#]winform基于opencvsharp结合CSRNet算法实现低光图像增强黑暗图片变亮变清晰

【算法介绍】 "Conditional Sequential Modulation for Efficient Global Image Retouching" 是一种图像修饰方法&#xff0c;主要用于对图像进行全局的高效调整。该方法基于深度学习技术&#xff0c;通过引入条件向量来实现对图像特征的调制&#xff0c;以达到改善…

DAY28--learning English

一、积累 1.hood 2.peripheral 3.gallery 4.cord 5.cart 6.permanent 7.democratic 8.republican 9.bride 10.jet-lagged 11.vet 12.lease 13.landlord 14.aisle 15.lousy 16.via 17.order in 18.forecast 19.initiation 20.credit 二、练习 1.牛津原译 Hood /hʊd/ 1. a par…

Unity3D MVC开发模式与开发流程详解

前言 MVC&#xff08;Model-View-Controller&#xff09;是一种常用的软件架构模式。将MVC应用于Unity3D开发可以提高项目的可维护性和可扩展性&#xff0c;使代码更加清晰和易于理解。本文将详细介绍Unity3D中MVC开发模式的应用以及开发流程&#xff0c;并给出技术详解和代码…