【GStreamer】GstAllocator的简单分析

目录

  • 1.GstAllocator
    • 1.1 查找分配器(gst_allocator_find)
    • 1.2 初始化分配器(gst_allocator_init)
      • 1.2.1 通用初始化(gst_allocator_init)
      • 1.2.2 sysmem初始化(gst_allocator_sysmem_init)
      • 1.2.3 初始化sysmem分配器的类(gst_allocator_sysmem_class_init)
        • 1.2.3.1 default_alloc()
        • 1.2.3.2 default_free()
    • 1.4 通用内存分配(gst_allocator_alloc)
    • 1.5 内存释放(gst_allocator_free)

1.GstAllocator

在GStreamer中,GstAllocator用于管理和分配内存,创建和管理的对象是GstMemory,GstMemory是一个引用计数对象,对一块内存区域进行了封装。GstAllocator实现的功能类似于malloc和free,只是底层调用的是GLib中的内存分配函数g_malloc和g_free

// GstAllocator的继承关系
GObject╰──GInitiallyUnowned╰──GstObject╰──GstAllocator/*** GstAllocator:* @mem_map: the implementation of the GstMemoryMapFunction* @mem_unmap: the implementation of the GstMemoryUnmapFunction* @mem_copy: the implementation of the GstMemoryCopyFunction* @mem_share: the implementation of the GstMemoryShareFunction* @mem_is_span: the implementation of the GstMemoryIsSpanFunction* @mem_map_full: the implementation of the GstMemoryMapFullFunction.*      Will be used instead of @mem_map if present. (Since: 1.6)* @mem_unmap_full: the implementation of the GstMemoryUnmapFullFunction.*      Will be used instead of @mem_unmap if present. (Since: 1.6)** The #GstAllocator is used to create new memory.*/
// GstAllocator的定义
struct _GstAllocator
{GstObject  object;/** mem_type的类型包括:* (1) GST_ALLOCATOR_SYSTEM : 系统内存分配器* (2) GST_ALLOCATOR_DMABUF : DMA缓冲区分配器* (3) GST_ALLOCATOR_FD : 文件描述符分配器* (4) GST_ALLOCATOR_DRM_DUMB : DRM Dumb Buffer分配器* 也可以自定义分配器,使用gst_allocator_register()来注册*/const gchar               *mem_type;/*< public >*/ // 公有成员// 内存映射函数GstMemoryMapFunction       mem_map;// 内存取消映射函数GstMemoryUnmapFunction     mem_unmap;// 内存拷贝函数GstMemoryCopyFunction      mem_copy;// 内存共享函数GstMemoryShareFunction     mem_share;// 检查内存是否连续GstMemoryIsSpanFunction    mem_is_span;// 包含更多参数的映射GstMemoryMapFullFunction   mem_map_full;// 包含更多参数的取消映射GstMemoryUnmapFullFunction mem_unmap_full;/*< private >*/ // 私有成员gpointer _gst_reserved[GST_PADDING - 2];GstAllocatorPrivate *priv;
};/*** GstAllocatorClass:* @object_class:  Object parent class* @alloc: implementation that acquires memory* @free: implementation that releases memory** The #GstAllocator is used to create new memory.*/
struct _GstAllocatorClass {GstObjectClass object_class;/*< public >*/ // 共有成员// 内存分配GstMemory *  (*alloc)      (GstAllocator *allocator, gsize size,GstAllocationParams *params);// 内存释放void         (*free)       (GstAllocator *allocator, GstMemory *memory);/*< private >*/gpointer _gst_reserved[GST_PADDING];
};

从上面类的定义来看,GstAllocator中声明了内存类型(由什么样的内存器分配),内存相关函数(访问,取消访问,拷贝,共享等),GstAllocatorClass中声明了具体的内存分配和内存释放函数。GstAllocator可以看作是GstAllocatorClass的一个实例,其中也包括了alloc和free的函数。使用GstAllocatorClass中的alloc和free函数之前,需要先将GstAllocator转换成GstAllocatorClass类,使用GST_ALLOCATOR_GET_CLASS这个宏可以实现这个功能。

GstAllocator的使用流程大致为:

  1. 查找分配器(gst_allocator_find)
  2. 初始化分配器(gst_allocator_init)
  3. 内存分配(gst_allocator_alloc)
  4. 内存使用
  5. 内存释放(gst_allocator_free)

在GStreamer中,可以根据情况使用不同的内存分配器,包括GST_ALLOCATOR_SYSTEM(系统内存分配器)、GST_ALLOCATOR_DMABUF(DMA缓冲区分配器)、GST_ALLOCATOR_FD(文件描述符分配器)、GST_ALLOCATOR_DRM_DUMB(DRM Dumb Buffer分配器)。如果不指定内存分配器,默认会使用sysmem,sysmem内存相关定义位于gstreamer/subprojects/gstreamer/gst/gstallocator.c中,下面以sysmem做一下分析。另外,DMA缓冲区分配器、文件描述符分配器、和DRM Dumb Buffer分配器具体实现方式在各自的文件中,例如DMA缓冲区分配器相关的代码定义在gstreamer/subprojects/gst-plugins-base/gst-libs/gst/allocators/gstdmabuf.c中

1.1 查找分配器(gst_allocator_find)

/*** gst_allocator_find:* @name: (nullable): the name of the allocator** Find a previously registered allocator with @name. When @name is %NULL, the* default allocator will be returned.** Returns: (transfer full) (nullable): a #GstAllocator or %NULL when* the allocator with @name was not registered.*/
GstAllocator *
gst_allocator_find (const gchar * name)
{GstAllocator *allocator;g_rw_lock_reader_lock (&lock);// 从哈希表中寻找可用的allocator,如果找不到则使用_default_allocatorif (name) {allocator = g_hash_table_lookup (allocators, (gconstpointer) name);} else {allocator = _default_allocator;}if (allocator)gst_object_ref (allocator);g_rw_lock_reader_unlock (&lock);return allocator;
}

_default_allocator表示使用GStreamer内部的默认内存分配器,即sysmem内存分配器,在_priv_gst_allocator_initialize()中获取,这里的前缀priv表示内部函数,外部无法调用

void
_priv_gst_allocator_initialize (void)
{g_rw_lock_init (&lock);// 创建allocators的哈希表allocators = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,gst_object_unref);#ifdef HAVE_GETPAGESIZE
#ifdef MEMORY_ALIGNMENT_PAGESIZEgst_memory_alignment = getpagesize () - 1;
#endif
#endifGST_CAT_DEBUG (GST_CAT_MEMORY, "memory alignment: %" G_GSIZE_FORMAT,gst_memory_alignment);// 创建sysmem分配器_sysmem_allocator = g_object_new (gst_allocator_sysmem_get_type (), NULL);/* Clear floating flag */// 添加引用计数gst_object_ref_sink (_sysmem_allocator);// 将_sysmem_allocator注册为GST_ALLOCATOR_SYSTEM类型// 注册会将_sysmem_allocator插入到哈希表当中gst_allocator_register (GST_ALLOCATOR_SYSMEM,gst_object_ref (_sysmem_allocator));// 默认分配器为sysmem,也就是GST_ALLOCATOR_SYSTEM_default_allocator = gst_object_ref (_sysmem_allocator);
}

1.2 初始化分配器(gst_allocator_init)

1.2.1 通用初始化(gst_allocator_init)

static void
gst_allocator_init (GstAllocator * allocator)
{allocator->priv = gst_allocator_get_instance_private (allocator);// 内存拷贝allocator->mem_copy = _fallback_mem_copy;// 检查内存是否连续allocator->mem_is_span = _fallback_mem_is_span;
}

其中_fallback_mem_copy()为内存拷贝函数

static GstMemory *
_fallback_mem_copy (GstMemory * mem, gssize offset, gssize size)
{GstMemory *copy;GstMapInfo sinfo, dinfo;GstAllocationParams params = { 0, mem->align, 0, 0, };GstAllocator *allocator;// 检查源内存块是否可读if (!gst_memory_map (mem, &sinfo, GST_MAP_READ))return NULL;if (size == -1)size = sinfo.size > offset ? sinfo.size - offset : 0;/* use the same allocator as the memory we copy */allocator = mem->allocator;if (GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC) ||GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_NO_COPY))allocator = NULL;// 使用相同的内存分配器和参数,分配内存copy = gst_allocator_alloc (allocator, size, &params);// 检查目标内存块是否可写if (!gst_memory_map (copy, &dinfo, GST_MAP_WRITE)) {GST_CAT_WARNING (GST_CAT_MEMORY, "could not write map memory %p", copy);gst_allocator_free (copy->allocator, copy);gst_memory_unmap (mem, &sinfo);return NULL;}GST_CAT_DEBUG (GST_CAT_PERFORMANCE,"memcpy %" G_GSSIZE_FORMAT " memory %p -> %p", size, mem, copy);// 将源地址中数据拷贝到目标地址中memcpy (dinfo.data, sinfo.data + offset, size);gst_memory_unmap (copy, &dinfo);gst_memory_unmap (mem, &sinfo);return copy;
}

_fallback_mem_is_span()还没有实现

static gboolean
_fallback_mem_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
{return FALSE;
}

1.2.2 sysmem初始化(gst_allocator_sysmem_init)

如果使用的是sysmem分配器,会调用gst_allocator_sysmem_init()进行初始化,该函数定义了内存处理的函数指针,包含内存映射(_sysmem_map)、内存拷贝(_sysmem_copy)、内存共享(_sysmem_share)等

static void
gst_allocator_sysmem_init (GstAllocatorSysmem * allocator)
{GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);GST_CAT_DEBUG (GST_CAT_MEMORY, "init allocator %p", allocator);alloc->mem_type = GST_ALLOCATOR_SYSMEM;alloc->mem_map = (GstMemoryMapFunction) _sysmem_map;alloc->mem_unmap = (GstMemoryUnmapFunction) _sysmem_unmap;alloc->mem_copy = (GstMemoryCopyFunction) _sysmem_copy;alloc->mem_share = (GstMemoryShareFunction) _sysmem_share;alloc->mem_is_span = (GstMemoryIsSpanFunction) _sysmem_is_span;
}

(1)内存映射(_sysmem_map)

static gpointer
_sysmem_map (GstMemorySystem * mem, gsize maxsize, GstMapFlags flags)
{return mem->data;
}

(2)取消内存映射(_sysmem_unmap)

static gboolean
_sysmem_unmap (GstMemorySystem * mem)
{return TRUE;
}

(3)内存拷贝(_sysmem_copy)

static GstMemorySystem *
_sysmem_copy (GstMemorySystem * mem, gssize offset, gsize size)
{GstMemorySystem *copy;if (size == -1)size = mem->mem.size > offset ? mem->mem.size - offset : 0;// 创建新内存块copy = _sysmem_new_block (0, size, mem->mem.align, 0, size);if (!copy)return NULL;GST_CAT_DEBUG (GST_CAT_PERFORMANCE,"memcpy %" G_GSIZE_FORMAT " memory %p -> %p", size, mem, copy);memcpy (copy->data, mem->data + mem->mem.offset + offset, size);return copy;
}

_sysmem_new_block()是GStreamer底层的分配函数,根据输入参数,分配一块内存,返回一个GstMemory对象来封装这块内存

/* allocate the memory and structure in one block */
static GstMemorySystem *
_sysmem_new_block (GstMemoryFlags flags,gsize maxsize, gsize align, gsize offset, gsize size)
{GstMemorySystem *mem;gsize aoffset, slice_size, padding;guint8 *data;/* ensure configured alignment */// 确保对齐align |= gst_memory_alignment;/* allocate more to compensate for alignment */if (align > G_MAXSIZE || maxsize > G_MAXSIZE - align) {GST_CAT_WARNING (GST_CAT_MEMORY,"Allocating %" G_GSIZE_FORMAT " bytes with alignment %" G_GSIZE_FORMAT"x overflows", maxsize, align);return NULL;}maxsize += align;/* alloc header and data in one block */if (maxsize > G_MAXSIZE - sizeof (GstMemorySystem)) {GST_CAT_WARNING (GST_CAT_MEMORY,"Allocating %" G_GSIZE_FORMAT " bytes with alignment %" G_GSIZE_FORMAT"x overflows", maxsize, align);return NULL;}slice_size = sizeof (GstMemorySystem) + maxsize;// 分配大小为slice_size的内存,使用GLib中的g_malloc函数mem = g_malloc (slice_size);if (mem == NULL)return NULL;// 计算数据指针的位置data = (guint8 *) mem + sizeof (GstMemorySystem);/* do alignment */// 对齐数据指针if ((aoffset = ((guintptr) data & align))) {aoffset = (align + 1) - aoffset;data += aoffset;maxsize -= aoffset;}// 检查是否需要进行零填充if (offset && (flags & GST_MEMORY_FLAG_ZERO_PREFIXED))memset (data, 0, offset);padding = maxsize - (offset + size);if (padding && (flags & GST_MEMORY_FLAG_ZERO_PADDED))memset (data + offset + size, 0, padding);// 初始化内存对象_sysmem_init (mem, flags, NULL, data, maxsize,align, offset, size, NULL, NULL);return mem;
}

(4)内存共享(_sysmem_share)

static GstMemorySystem *
_sysmem_share (GstMemorySystem * mem, gssize offset, gsize size)
{GstMemorySystem *sub;GstMemory *parent;/* find the real parent */if ((parent = mem->mem.parent) == NULL)parent = (GstMemory *) mem;if (size == -1)size = mem->mem.size - offset;/* the shared memory is always readonly */// 分配新的内存空间sub =_sysmem_new (GST_MINI_OBJECT_FLAGS (parent) |GST_MINI_OBJECT_FLAG_LOCK_READONLY, parent, mem->data, mem->mem.maxsize,mem->mem.align, mem->mem.offset + offset, size, NULL, NULL);return sub;
}

_sysmem_new()的定义如下,与_sysmem_new_block()区别在于,_sysmem_new_block()会处理内存对齐,将内存分配到一个连续的内存块之中,减少内存碎片并提高访问效率,

/* create a new memory block that manages the given memory */
static inline GstMemorySystem *
_sysmem_new (GstMemoryFlags flags,GstMemory * parent, gpointer data, gsize maxsize, gsize align, gsize offset,gsize size, gpointer user_data, GDestroyNotify notify)
{GstMemorySystem *mem;mem = g_new (GstMemorySystem, 1);// 初始化分配的memory_sysmem_init (mem, flags, parent,data, maxsize, align, offset, size, user_data, notify);return mem;
}

_sysmem_init()是一个内联函数,作用是初始化内存对象GstMemorySystem

/* initialize the fields */
static inline void
_sysmem_init (GstMemorySystem * mem, GstMemoryFlags flags,GstMemory * parent,gpointer data, gsize maxsize, gsize align, gsize offset, gsize size,gpointer user_data, GDestroyNotify notify)
{// 初始化memory// gst_memory_init()定义在gstmemory.c中gst_memory_init (GST_MEMORY_CAST (mem),flags, _sysmem_allocator, parent, maxsize, align, offset, size);// 初始化GstMemorySystem的字段mem->data = data;mem->user_data = user_data;mem->notify = notify;
}

(5)检查内存连续(_sysmem_is_span)

static gboolean
_sysmem_is_span (GstMemorySystem * mem1, GstMemorySystem * mem2, gsize * offset)
{if (offset) {GstMemorySystem *parent;parent = (GstMemorySystem *) mem1->mem.parent;*offset = mem1->mem.offset - parent->mem.offset;}/* and memory is contiguous */return mem1->data + mem1->mem.offset + mem1->mem.size ==mem2->data + mem2->mem.offset;
}

1.2.3 初始化sysmem分配器的类(gst_allocator_sysmem_class_init)

前面初始化了sysmem的函数,这里还需要初始化sysmem_class的函数,也就是sysmem的基类。使用的函数是gst_allocator_sysmem_class_init(),主要作用是初始化内存分配函数alloc()内存释放函数free()

static void
gst_allocator_sysmem_class_init (GstAllocatorSysmemClass * klass)
{GObjectClass *gobject_class;GstAllocatorClass *allocator_class;gobject_class = (GObjectClass *) klass;allocator_class = (GstAllocatorClass *) klass;gobject_class->finalize = gst_allocator_sysmem_finalize;// 默认内存分配allocator_class->alloc = default_alloc;// 默认内存释放allocator_class->free = default_free;
}
1.2.3.1 default_alloc()

default_alloc()的作用是sysmem的内存分配

static GstMemory *
default_alloc (GstAllocator * allocator, gsize size,GstAllocationParams * params)
{gsize maxsize = size + params->prefix + params->padding;return (GstMemory *) _sysmem_new_block (params->flags,maxsize, params->align, params->prefix, size);
}
1.2.3.2 default_free()

函数的作用是释放内存

static void
default_free (GstAllocator * allocator, GstMemory * mem)
{GstMemorySystem *dmem = (GstMemorySystem *) mem;if (dmem->notify)dmem->notify (dmem->user_data);#ifdef USE_POISONING/* just poison the structs, not all the data */memset (mem, 0xff, sizeof (GstMemorySystem));
#endif// Glib中的g_free函数g_free (mem);
}

1.4 通用内存分配(gst_allocator_alloc)

gst_allocator_alloc()用于内存分配,会接受入参allocator,指定内存分配器,并使用这个分配器的内存分配函数执行任务。

/*** gst_allocator_alloc:* @allocator: (transfer none) (nullable): a #GstAllocator to use* @size: size of the visible memory area* @params: (transfer none) (nullable): optional parameters** Use @allocator to allocate a new memory block with memory that is at least* @size big.** The optional @params can specify the prefix and padding for the memory. If* %NULL is passed, no flags, no extra prefix/padding and a default alignment is* used.** The prefix/padding will be filled with 0 if flags contains* #GST_MEMORY_FLAG_ZERO_PREFIXED and #GST_MEMORY_FLAG_ZERO_PADDED respectively.** When @allocator is %NULL, the default allocator will be used.** The alignment in @params is given as a bitmask so that @align + 1 equals* the amount of bytes to align to. For example, to align to 8 bytes,* use an alignment of 7.** Returns: (transfer full) (nullable): a new #GstMemory.*/
GstMemory *
gst_allocator_alloc (GstAllocator * allocator, gsize size,GstAllocationParams * params)
{GstMemory *mem;static GstAllocationParams defparams = { 0, 0, 0, 0, };GstAllocatorClass *aclass;if (params) {g_return_val_if_fail (((params->align + 1) & params->align) == 0, NULL);} else {params = &defparams;}if (allocator == NULL)allocator = _default_allocator;aclass = GST_ALLOCATOR_GET_CLASS (allocator);// 根据内存分配器进行内存分配// 如果入参是sysmem的allocator,aclass->alloc()调用的函数就是_default_alloc()if (aclass->alloc)mem = aclass->alloc (allocator, size, params);elsemem = NULL;return mem;
}

1.5 内存释放(gst_allocator_free)

/*** gst_allocator_free:* @allocator: (transfer none): a #GstAllocator to use* @memory: (transfer full): the memory to free** Free @memory that was previously allocated with gst_allocator_alloc().*/
void
gst_allocator_free (GstAllocator * allocator, GstMemory * memory)
{GstAllocatorClass *aclass;g_return_if_fail (GST_IS_ALLOCATOR (allocator));g_return_if_fail (memory != NULL);g_return_if_fail (memory->allocator == allocator);// 内存释放aclass = GST_ALLOCATOR_GET_CLASS (allocator);if (aclass->free)aclass->free (allocator, memory);
}

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

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

相关文章

Angular 2 表单深度解析

Angular 2 表单深度解析 引言 Angular 2作为现代前端开发的框架之一,以其灵活性和强大的功能赢得了众多开发者的青睐。在Angular 2中,表单处理是其中一个重要且复杂的部分。本文将深入解析Angular 2的表单,从基础知识到高级应用,旨在帮助开发者更好地理解和运用Angular 2…

STM32+W5500+以太网应用开发+003_TCP服务器添加OLED(u8g2)显示状态

STM32W5500以太网应用开发003_TCP服务器添加OLED&#xff08;u8g2&#xff09;显示状态 实验效果3-TCP服务器OLED1 拷贝显示驱动代码1.1 拷贝源代码1.2 将源代码添加到工程1.3 修改代码优化等级1.4 添加头文件路径1.5 修改STM32CubeMX工程 2 修改源代码2.1 添加头文件2.2 main函…

MySQL命令及用法(精华版)

目录 DDL&#xff08;数据定义语言&#xff09; 数据库操作 表操作 DML&#xff08;数据操作语言&#xff09; DQL&#xff08;数据查询语言&#xff09; 基本查询 条件查询 聚合函数 分组查询 排序查询 分页查询 DCL&#xff08;数据控制语言&#xff09; 用户…

postgresql根据主键ID字段分批删除表数据

生产环境针对大表的处理相对比较麻烦。 方案1、直接truncate&#xff0c;可能会遇到系统卡主的情况&#xff0c;因为truncate的过程中会对表进行加锁&#xff0c;会导致数据不能正常的写入 方案2、创建一个同结构的表结构&#xff0c;rename旧表&#xff0c;不停业务rename表担…

基于微信小程序的英语学习交流平台设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

ORB-SLAM2源码学习:Initializer.cc⑧: Initializer::CheckRT检验三角化结果

前言 ORB-SLAM2源码学习&#xff1a;Initializer.cc⑦: Initializer::Triangulate特征点对的三角化_cv::svd::compute-CSDN博客 经过上面的三角化我们成功得到了三维点&#xff0c;但是经过三角化成功的三维点并不一定是有效的&#xff0c;需要筛选才能作为初始化地图点。 …

macOS如何进入 Application Support 目录(cd: string not in pwd: Application)

错误信息 cd: string not in pwd: Application 表示在当前目录下找不到名为 Application Support 的目录。可能的原因如下&#xff1a; 拼写错误或路径错误&#xff1a;确保你输入的目录名称正确。目录名称是区分大小写的&#xff0c;因此请确保使用正确的大小写。正确的目录名…

记录一个连不上docker中的mysql的问题

引言 使用的debian12,不同发行版可能有些许差异&#xff0c;连接使用的工具是navicat lite 本来是毫无思绪的&#xff0c;以前在云服务器上可能是防火墙的问题&#xff0c;但是这个桌面环境我压根没有使用防火墙。 直到 ying192:~$ mysql -h127.0.0.1 -uroot ERROR 1045 (28…

Gradle自定义任务指南 —— 释放构建脚本的无限可能

文章目录 &#x1f50d;Gradle任务⚙️ 自定义任务的5大核心配置项1. 任务注册&#xff08;Registering Tasks&#xff09;2. group & description3. dependsOn4. inputs & outputs5. 类型化任务&#xff08;Task Types&#xff09; 任务常见配置参数传递方式1&#xf…

【FISCO BCOS】二十四、通过Java SDK对FISCO BCOS进行压力测试

Java SDK Demo是基于Java SDK的基准测试集合,能够对FISCO BCOS节点进行压力测试。Java SDK Demo提供有合约编译功能,能够将Solidity合约文件转换成Java合约文件,此外还提供了针对转账合约、CRUD合约以及AMOP功能的压力测试示例程序。本篇我们来讲讲使用java SDK压力测试的操…

windows11关闭系统更新详细操作步骤

文章目录 1.打开注册表2.修改注册表内容2.1 新建文件2.2 修改值 3.修改设置 1.打开注册表 winR输入regedit(如下图所示) 2.修改注册表内容 进HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings 2.1 新建文件 右侧界面右键即可 2.2 修改值 重命名为如下…

matlab绘图——彩色螺旋图

代码生成的图形是一个动态的彩色螺旋&#xff0c;展示了如何利用极坐标和颜色映射创建视觉吸引力强的图形。该图形可以用于数据可视化、艺术创作或数学演示&#xff0c;展示了 MATLAB 在图形处理方面的强大能力。通过调整 theta 和 r 的范围&#xff0c;可以创建出不同形状和复…

啥是EPS?

文章目录 1. 什么是EPS?2. 主要构成3. EPS的设计如何符合功能安全?4. 代表性的厂家1. 什么是EPS? EPS(Electric Power Steering,电动助力转向系统)是一种利用电动机提供转向助力的系统,取代了传统的液压助力转向系统(HPS)。EPS通过传感器检测驾驶员的转向意图,并由电…

QT:控件属性及常用控件(3)-----输入类控件(正则表达式)

输入类控件既可以进行显示&#xff0c;也能让用户输入一些内容&#xff01; 文章目录 1.Line Edit1.1 用户输入个人信息1.2 基于正则表达式的文本限制1.3 验证两次输入的密码是否一致1.4 让输入的密码可以被查看 2.Text Edit2.1 输入和显示同步2.1 其他信号出发情况 3.ComboBox…

MyBatis 写法

MyBatis 高效使用技巧 常见 MyBatis 使用技巧&#xff0c;这些技巧有助于简化数据库操作&#xff0c;提高开发效率&#xff0c;并增强系统的性能。 1. 动态 SQL 动态 SQL 让开发者能够依据参数灵活地构建 SQL 语句&#xff0c;避免了手动拼接字符串带来的复杂性和错误风险。…

24_游戏启动逻辑梳理总结

首先这个项目从游戏根入口GameRoot.cs的初始化开始 分为 服务层初始化Svc.cs 与 业务系统层初始化Sys.cs 而服务层 分为 资源加载服务层ResSvc.cs 与 音乐播放服务层AudioSvc.cs 而在 资源加载服务层ResSvc.cs中 初始化了 名字的 配置文件 而音乐播放服务层AudioSvc.cs 暂时没…

【25考研】中科院软件考研复试难度分析!

中科院软件复试不需要上机&#xff01;且对专业综合能力要求较高&#xff01;提醒同学一定要认真复习&#xff01; 一、复试内容 二、参考书目 官方并未明确给出&#xff0c;建议同学参考初试书目&#xff1a; 1&#xff09;《数据结构&#xff08;C语言版&#xff09;》严蔚…

Kafka生产者ACK参数与同步复制

目录 生产者的ACK参数 ack等于0 ack等于1&#xff08;默认&#xff09; ack等于-1或all Kafka的同步复制 使用误区 生产者的ACK参数 Kafka的ack机制可以保证生产者发送的消息被broker接收成功。 Kafka producer有三种ack机制 &#xff0c;分别是 0&#xff0c;1&#xf…

大华相机DH-IPC-HFW3237M支持的ONVIF协议

使用libONVIF C库。 先发现相机。 配置 lib目录 包含 编译提示缺的文件&#xff0c;到libonvif里面拷贝过来。 改UDP端口 代码 使用msvc 2022的向导生成空项目&#xff0c;从项目的main示例拷贝过来。 CameraOnvif.h #pragma once#include <QObject> #include &l…

16.好数python解法——2024年省赛蓝桥杯真题

问题描述 一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位…)上的数字是奇数,偶数位(十位、千位、十万位…)上的数字是偶数,我们就称之为“好数”。 给定一个正整数N,请计算从1到N一共有多少个好数。 输入格式 一个整数N。 输出格式 一个整数代表答案。 样例输入 1 …