# 内存管理 - hbmem

## 模块描述

X5 SoC 提供了多种硬件加速单元，包括 ISP、 GDC、 VSE、 GPU、 BPU 等。这些硬件加速单元之间以及与 CPU 之间的数据传输依赖 DDR。<br>
由于硬件加速单元在访问 DDR 数据时需要物理地址连续，而 Linux 系统用户空间的内存分配接口仅能保证虚拟地址连续，且随着系统运行，<br>
尽管物理内存充足，由于内存碎片问题也可能导致无法分配大块连续的物理内存，因此在设备树中为这些硬件加速单元预留了物理内存。<br>
详细信息请参阅：[ 系统预留内存 ](../linux_development/system_component_development/39-ION_Debug_Guide.html)。

hbmem 模块在应用层提供了丰富的接口，支持对系统预留内存的五种管理方式：内存分配、内存共享、内存队列管理、内存池管理以及共享内存池管理。

| 功能名称     | 功能描述                      |
|-------------|------------------------------|
| 内存分配     | 从系统预留内存上分配连续物理内存， 并且支持 DMA 拷贝 |
| 内存共享     | 支持用户使用内存 handle 在不同的线程或进程间共享内存空间，且自动管理内存引用计数，保证使用中的内存不被意外释放；|
| 内存队列管理  | 提供输入输出队列管理，内存分配端将内存送入输入队列供内存消费端使用，<br> 内存消费端将不再使用的内存送入输出队列由分配端释放；( **注意** 不支持多进程 )|
| 内存池        | 支持用户通过内存分配功能创建本地内存池，再从该内存池中分配和释放小块的内存。|
| 共享内存池    | 支持多进程共享，但是从共享内存池上分配的 buffer 大小相同，且 buffer 的大小只能在创建共享内存池时指定 |


### 内存分配
内存分配是 hbmem 功能的基础，其他四种管理功能（内存共享、内存队列管理、内存池以及共享内存池）都与内存分配功能相关。<br>
内存分配相关接口主要实现：
1. 提供最基本的连续物理内存的分配、释放接口，详细见：[内存分配接口](#memory_alloction)
2. 内存分配成功后，用户可获得对应的文件句柄，基于该文件句柄，用户可对相关的物理内存进行： <br>
   Cache 操作、 DMA 拷贝、获取 buffer 信息等，详细见：[内存分配接口](#memory_alloction)
3. 支持设置 多种属性配置，包括 Cache 属性、内存 heap 属性、硬件加速单元标识属性，详细见：[内存分配属性](#hbmem_alloc_att)
4. 内存分配软件模块，提供了三种类别的内存单元：整块连续内存单元、图像数据内存单元、图像数据内存组单元

**注意**：不建议用户直接对物理地址进行 mmap 或传递等操作，这些操作 **不会增加该内存的引用计数** ，存在内存释放后用户仍在访问的情况。

<span id=" memory_alloc_unit "/> </sapn>

#### 内存分配单元说明

| 内存类别                | 结构体                                                                        | 场景                                         | 特点                    |
|------------------------|-------------------------------------------------------------------------------|---------------------------------------------|-------------------------|
| 整块连续内存            | [hb_mem_common_buf_t](./3-Hbmem_index_zh_CN.html#span-id-hb-mem-common-buf-t-hb-mem-common-buf-t)         | 编码器输出的码流或 BPU 使用的纯 featuremap     | 简单的一段连续的物理空间 |
|图像数据内存组             | [hb_mem_graphic_buf_group_t](./3-Hbmem_index_zh_CN.html#hb-mem-graphic-buf-group-t) | ISP、 GDC、 VSE 使用的图像数据                | 支持多个 plane 的多个连续空间 |
|图像数据内存        | [hb_mem_graphic_buf_t ](./3-Hbmem_index_zh_CN.html#hb-mem-graphic-buf-group-t)      | PYM 模块使用多层图像数据                      | 多个图像数据存储到 1 个数组中 |

#### Cache 操作说明
现代 CPU 为了加速数据访问，引入了 Cache，用于存储主存（ DDR）中的部分数据以提升访问速度：
1. CPU 写 DDR 操作：当 CPU 修改某块数据时，通常不会立即将数据写回 DDR，而是先更新 Cache 中的副本。<br>
   这种机制称为“写回缓存”，有效减少了对 DDR 的直接写操作，提高性能。
2. CPU 读 DDR 操作：当 CPU 从 DDR 中读取数据时，会优先检查 Cache。如果 Cache 中已经存在目标数据的副本，<br>
   CPU 将直接从 Cache 中读取，而无需访问 DDR。这种机制显著提升了读操作效率。

Cache 是专属于 CPU 的硬件单元，在仅有 CPU 访问 DDR 时，数据的一致性由 CPU 内部机制自动保障，不会出现问题。<br>
然而，当其他硬件加速单元（如 ISP、 VSE、 GDC、 GPU 等）也需要访问 DDR 时，由于这些单元无法感知 CPU 的 Cache 状态，<br>
会引发数据一致性问题。

因此 hbmem 模块提供了两种 API 接口，实现在应用层主动操作 CPU Cache：
1. Cache 刷新 : [hb_mem_flush_buf](./3-Hbmem_index_zh_CN.html#spin-id-hb-mem-flush-buf-hb-mem-flush-buf)
2. Cache 无效 : [hb_mem_invalidate_buf](./3-Hbmem_index_zh_CN.html#hb_mem_invalidate_buf)

下面针对两种 API 接口进行详细说明
##### Cache 刷新

Cache 刷新的操作是将 Cache 中已经缓存了 DDR 的数据，回写到 DDR 中，<br>
下面针对从 EMMC 中读取视频帧到 DDR，然后交给 VSE 处理的场景举例
1. 左图：没有调用 Cache 刷新的情况
2. 右图：在合适的时机调用 Cache 刷新的情况（[hb_mem_flush_buf](./3-Hbmem_index_zh_CN.html#spin-id-hb-mem-flush-buf-hb-mem-flush-buf)）

![ 框图 ](./media/hbm_cache_flush.png)

左图流程解释（存在缓存一致性的问题）：
- 步骤 1: CPU 从 eMMC 读取视频数据，数据传输过程中经过 Cache 缓存
- 步骤 2: 读取的视频数据被存储到 DDR 中。然而，在视频数据读取完成后，部分数据可能在 Cache 中未完全写入 DDR
- 步骤 3: VSE 从 DDR 读取视频数据进行处理，但由于数据不完整 ( 部分数据在 Cache 中 )，导致 VSE 处理后的数据是错误的

右图流程解释（解决缓存一致性的问题）：
- 步骤 1: 同左图
- 步骤 2: 同左图
- 步骤 3: 调用 Cache 刷新接口 [hb_mem_flush_buf](./3-Hbmem_index_zh_CN.html#spin-id-hb-mem-flush-buf-hb-mem-flush-buf)，将 Cache 中的数据回写到 DDR 中
- 步骤 4: VSE 从 DDR 中读取视频数据，进行处理，可以读到完整的视频数据

##### Cache 无效
Cache 无效化操作指的是将 Cache 中已缓存的 DDR 数据丢弃，使其进入未命中状态。<br>
当后续访问 DDR 时，系统将不再使用 Cache 中的旧数据，而是强制从 DDR 读取最新数据。

下面针对 VSE 从 DDR 读取视频数据处理后保存到 EMMC 的的场景举例：
1. 左图：没有调用 Cache 无效接口的情况
2. 右图：在合适的时机调用 Cache 无效接口的情况（[hb_mem_invalidate_buf](./3-Hbmem_index_zh_CN.html#hb_mem_invalidate_buf)）

![ 框图 ](./media/hbm_cache_invalidate.png)

左图流程解释（存在缓存一致性的问题）：
- 步骤 1: CPU 读取 DDR 中的视频数据进行某种算法处理后，此时 Cache 中缓存了部分 DDR 中的数据
- 步骤 2: VSE 从 DDR 中读取视频数据
- 步骤 3: VSE 内部进行 OSD 叠加文字后，继续回写到 DDR 中
- 步骤 4: CPU 继续读取 DDR 中的视频数据，由于步骤 3 中的 VSE 写入了新的数据，但是 Cache 中有步骤 1 缓存了部分 DDR 数据，<br>
  因此 CPU 只会从 DDR 中读取未在 Cache 中的数据
- 步骤 5: CPU 将读取的数据写入到 EMMC 中，由于步骤 4 只读取了部分新数据，导致写入 EMMC 中的数据是错误的。

右图流程解释（解决缓存一致性的问题）：
- 步骤 1: 同左图
- 步骤 2: 同左图
- 步骤 3: 同左图
- 步骤 4: 调用 Cache 无效接口 [hb_mem_invalidate_buf](./3-Hbmem_index_zh_CN.html#hb_mem_invalidate_buf)，将 Cache 中的数据丢弃，使其进入未命中状态。
- 步骤 5: CPU 读取 DDR 中的视频数据，由于步骤 4 将 Cache 中的旧数据丢弃了，所以 CPU 会从 DDR 中读取全部的最新视频数据
- 步骤 6: CPU 将读取的数据写入到 EMMC 中，由于步骤 5 中读取的数据全部都是最新的数据，所以写入 EMMC 的数据是没问题的


### 内存共享

内存共享模块相关接口实现了多个线程 / 进程之间的内存安全共享 , 使用流程如下：
1. 用户可直接传递内存分配单元对应的结构体到到另一个线程或进程中 <br>
2. 另外一个进程接收到结构体信息后，通过 `hb_mem_import_xxx` 接口（参见下面的表格） 完成导入，实现 buffer 的安全共享。<br>

内存分配单元对应的结构体和接口，如下所示：
1. 整块连续内存：`hb_mem_common_buf_t`
2. 图像数据内存：`hb_mem_graphic_buf_t`
3. 图像数据内存组：`hb_mem_graphic_buf_group_t`

| 内存类别       | 结构体                                                                        | `hb_mem_import_xxx` 接口                                                  |
|---------------|-------------------------------------------------------------------------------|--------------------------------------------------------------------------|
| 整块连续内存   | [hb_mem_common_buf_t](./3-Hbmem_index_zh_CN.html#span-id-hb-mem-common-buf-t-hb-mem-common-buf-t)         | [hb_mem_import_com_buf](./3-Hbmem_index_zh_CN.html#hb_mem_import_com_buf)|
| 图像数据内存   | [hb_mem_import_graph_buf](./3-Hbmem_index_zh_CN.html#hb-mem-import-graph-buf) | [hb_mem_import_graph_buf](./3-Hbmem_index_zh_CN.html#hb_mem_import_graph_buf)|
| 图像数据内存组 | [hb_mem_import_graph_buf_group ](./3-Hbmem_index_zh_CN.html#hb-mem-graphic-buf-group-t)      | [hb_mem_import_graph_buf_group](./3-Hbmem_index_zh_CN.html#hb_mem_import_graph_buf_group)|

下图展示多进程之间内存共享的流程 ( 以 `hb_mem_common_buf_t` 在多进程之间共享举例：)

![ 框图 ](./media/hbm_share_flow.png)

### 内存队列管理

内存队列管理模块提供了一种通用的队列管理机制 , 该机制支持生产者和消费者完成数据的流转。<br>
内存队列管理模块内部有两个队列：`空数据队列` 和 `有效数据队列`，通过两个队列实现生成者和消费者之间的数据流转，<br>
具体步骤如下：
1. 生产者从 `空数据队列` 中获取一个 Item，然后填充有效数据
2. 生产者将填充了有效数据的 Item, 存储到 `有效数据队列` 中
3. 消费者从 `有效数据队列` 中获取一个 Item，读出其中的有效数据
4. 消费者把已经处理后的 Item, 再存储到 `空数据队列` 中

![ 框图 ](./media/hbm_queue.png)

注意事项：
1. 只支持单进程内操作
2. 内存队列本身使用 malloc 申请内存， 队列中存储的数据可以是内存分配单元中提到的数据结构体
3. 内存队列为一个环形队列，所以要当队列满了之后，再往队列中写入事件，就会将之前的第一个事件给覆盖

### 内存池

内存池模块提供接口，支持用户创建本地内存池，并通过该内存池高效分配和释放小块内存。

1. 实现方法：在程序初始化阶段，预先分配一块大内存作为内存池资源，后续通过内存池分配接口从该大内存中分配所需的小块内存。
2. 实现目标：通过内存池模块，用户可在用户态快速完成内存分配，无需频繁切换到内核态，从而提升内存管理效率。

### 共享内存池
共享内存池功能同内存池：支持用户创建本地内存池，但是存在如下几个不同点：
1. 共享内存池分配的内存支持多进程共享
2. 从共享内存池上分配的 buffer 大小相同，且 buffer 的大小只能在创建共享内存池时指定。

## 参考示例
- hbmem 部分示例代码可以参考 [sample_hbmem](../samples/sample_hbmem.html)  章节

## API 参考

1. 链接库： libhbmem.so
2. 头文件： hb_mem_mgr.h、 hbmem.h 和 hb_mem_err.h。

<a id="memory_alloction"></a>
### 内存分配接口

| API 接口                        | 接口功能                      |
|---------------------------------|------------------------------|
[hb_mem_get_version](#hb_mem_get_version)| 获取模块版本号 |
[hb_mem_module_open](#hb_mem_module_open)| 打开内存模块 |
[hb_mem_module_close](#hb_mem_module_close)| 关闭内存模块 |
[hb_mem_alloc_com_buf](#hb_mem_alloc_com_buf)| 分配 common buffer|
[hb_mem_get_com_buf](#hb_mem_get_com_buf)| 通过 fd 获取 common buffer 信息 |
[hb_mem_alloc_graph_buf](#hb_mem_alloc_graph_buf)| 分配 graphic buffer|
[hb_mem_get_graph_buf](#hb_mem_get_graph_buf)| 通过 fd 获取 graphic buffer 信息 |
[hb_mem_free_buf](#hb_mem_free_buf)| 通过 fd 释放 buffer|
[hb_mem_invalidate_buf](#hb_mem_invalidate_buf)| 使 fd 对应的缓冲区无效，当用户分配的 buffer 属性 |
[hb_mem_flush_buf](./3-Hbmem_index_zh_CN.html#spin-id-hb-mem-flush-buf-hb-mem-flush-buf)|Flush fd 对应的缓冲区，当用户分配的 buffer 属性 |
[hb_mem_is_valid_buf](#hb_mem_is_valid_buf)| 判断输入的虚拟地址是否为从 memory module 分配的有效地址 |
[hb_mem_get_phys_addr](#hb_mem_get_phys_addr)| 获取输入虚拟地址对应的物理地址信息 |
[hb_mem_get_buf_info](#hb_mem_get_buf_info)| 获取输入虚拟地址对应的起始虚拟地址和 buffer 大小信息 |
[hb_mem_invalidate_buf_with_vaddr](#hb_mem_invalidate_buf_with_vaddr)| 使虚拟地址对应的缓冲区无效，当用户分配的 buffer 属性 |
[hb_mem_flush_buf_with_vaddr](#hb_mem_flush_buf_with_vaddr)|Flush 虚拟地址对应的缓冲区，当用户分配的 buffer 属性 |
[hb_mem_get_com_buf_with_vaddr](#hb_mem_get_com_buf_with_vaddr)| 通过虚拟地址获取 common buffer 信息 |
[hb_mem_get_graph_buf_with_vaddr](#hb_mem_get_graph_buf_with_vaddr)| 通过虚拟地址获取 graphic buffer 信息 |
[hb_mem_free_buf_with_vaddr](#hb_mem_free_buf_with_vaddr)| 通过虚拟地址释放 buffer|
[hb_mem_alloc_graph_buf_group](#hb_mem_alloc_graph_buf_group)| 申请一组 graphic buffer|
[hb_mem_get_graph_buf_group](#hb_mem_get_graph_buf_group)| 通过 fd（ graphic buffer group 中任意一个有效的 fd）获取 graphic buffer group|
[hb_mem_get_graph_buf_group_with_vaddr](#hb_mem_get_graph_buf_group_with_vaddr)| 通过虚拟地址（ graphic buffer group 中任意一个有效的虚拟地址）获取 graphic buffer group|
[hb_mem_dma_copy](#hb_mem_dma_copy)| 将源地址的数据拷贝到目的地址 |

### 内存共享接口

| API 接口                        | 接口功能                      |
|---------------------------------|------------------------------|
[hb_mem_import_com_buf](#hb_mem_import_com_buf)| 导入 common buffer 的共享内存，获取新的 common buffer 信息 |
[hb_mem_import_com_buf_with_paddr](#hb_mem_import_com_buf_with_paddr)| 通过物理地址共享内存，只能用于 hbmem 申请的内存 |
[hb_mem_import_graph_buf](#hb_mem_import_graph_buf)| 导入 graphic buffer 的共享内存，获取新的 graphic buffer 信息 |
[hb_mem_import_graph_buf_group](#hb_mem_import_graph_buf_group)| 共享一组 graphic buffer|
[hb_mem_get_share_info](#hb_mem_get_share_info)| 通过 fd 获取对应 buffer 的共享客户端的个数 |
[hb_mem_get_share_info_with_vaddr](#hb_mem_get_share_info_with_vaddr)| 通过虚拟地址获取对应 buffer 的共享客户端的个数 |
[hb_mem_wait_share_status](#hb_mem_wait_share_status)| 等待 fd 对应 buffer 的共享客户端个数小于等于目标值 |
[hb_mem_wait_share_status_with_vaddr](#hb_mem_wait_share_status_with_vaddr)| 等待虚拟地址对应 buffer 的共享客户端个数小于等于目标值 |


### 内存队列管理接口

| API 接口                        | 接口功能                      |
|---------------------------------|------------------------------|
[hb_mem_create_buf_queue](#hb_mem_create_buf_queue)| 创建内存队列 |
[hb_mem_destroy_buf_queue](#hb_mem_destroy_buf_queue)| 销毁内存队列 |
[hb_mem_dequeue_buf](#hb_mem_dequeue_buf)| 生产者获取可用的 slot 信息 |
[hb_mem_queue_buf](#hb_mem_queue_buf)| 生产者填充元素信息后将其入队到该 slot 中 |
[hb_mem_request_buf](#hb_mem_request_buf)| 消费者从队列中获取生产者入队的元素信息 |
[hb_mem_release_buf](#hb_mem_release_buf)| 消费者释放使用完的元素索引 |
[hb_mem_cancel_buf](#hb_mem_cancel_buf)| 生产者取消 dequeue 获得的 slot 或者消费者取消 request 获得的 slot 信息 |

### 内存池接口

| API 接口                        | 接口功能                      |
|---------------------------------|------------------------------|
[hb_mem_pool_create](#hb_mem_pool_create)| 创建一个内存池 |
[hb_mem_pool_destroy](#hb_mem_pool_destroy)| 销毁一个内存池 |
[hb_mem_pool_alloc_buf](#hb_mem_pool_alloc_buf)| 从内存池中分配一块 common buffer|
[hb_mem_pool_free_buf](#hb_mem_pool_free_buf)| 释放从内存池中分配的 buffer|
[hb_mem_pool_get_info](#hb_mem_pool_get_info)| 获取内存池的实时信息 |

### 共享内存池接口

| API 接口                        | 接口功能                      |
|---------------------------------|------------------------------|
[hb_mem_share_pool_create](#hb_mem_share_pool_create)| 创建一个共享内存池 |
[hb_mem_share_pool_destroy](#hb_mem_share_pool_destroy)| 销毁一个共享内存池 |
[hb_mem_share_pool_alloc_buf](#hb_mem_share_pool_alloc_buf)| 从共享内存池中分配一块 common buffer|
[hb_mem_share_pool_free_buf](#hb_mem_share_pool_free_buf)| 释放从共享内存池中分配的 buffer|
[hb_mem_share_pool_get_info](#hb_mem_share_pool_get_info)| 获取共享内存池的实时信息 |

### 通用信息获取或设置接口

| API 接口                        | 接口功能                      |
|---------------------------------|------------------------------|
[hb_mem_get_buf_type_with_vaddr](#hb_mem_get_buf_type_with_vaddr)| 获取 virt_addr 对应 buffer 的类型 |
[hb_mem_get_buf_type_and_buf_with_vaddr](#hb_mem_get_buf_type_and_buf_with_vaddr)| 获取 virt_addr 对应 buffer 的类型，并将其转换成 com buf 或 graph buf|
[hb_mem_get_buffer_process_info](#hb_mem_get_buffer_process_info)| 通过虚拟地址获取持有该 buffer 的进程 pid|
[hb_mem_get_buffer_process_info_with_share_id](#hb_mem_get_buffer_process_info_with_share_id)| 通过 share_id 获取持有对应 buffer 的进程 pid|
[hb_mem_get_consume_info](#hb_mem_get_consume_info)| 通过 fd 获取对应 buffer 的 consume cnt|
[hb_mem_get_consume_info_with_vaddr](#hb_mem_get_consume_info_with_vaddr)| 通过 virt_addr 获取对应 buffer 的 consume cnt|
[hb_mem_wait_consume_status](#hb_mem_wait_consume_status)| 等待 fd 对应 buffer 的 consume cnt 变成 share_consume_cnt，超时时间为 timeout|
[hb_mem_wait_consume_status_with_vaddr](#hb_mem_wait_consume_status_with_vaddr)| 等待 virt_addr 对应 buffer 的 consume cnt 变成 share_consume_cnt，超时时间为 timeout|
[hb_mem_inc_com_buf_consume_cnt](#hb_mem_inc_com_buf_consume_cnt)| 增加对应 common buffer 的 consume cnt|
[hb_mem_inc_graph_buf_consume_cnt](#hb_mem_inc_graph_buf_consume_cnt)| 增加对应 graphic buffer 的 consume cnt|
[hb_mem_inc_graph_buf_group_consume_cnt](#hb_mem_inc_graph_buf_group_consume_cnt)| 增加 graphic buffer group 中所有 buffer 的 consume cnt|
[hb_mem_dec_consume_cnt](#hb_mem_dec_consume_cnt)| 通过 fd 减少对应 buffer 的 consume cnt|
[hb_mem_dec_consume_cnt_with_vaddr](#hb_mem_dec_consume_cnt_with_vaddr)| 通过虚拟地址减少对应 buffer 的 consume cnt|
[hb_mem_get_buf_and_type_with_vaddr](#hb_mem_get_buf_and_type_with_vaddr)| 通过虚拟地址获取对应 buffer 的类型和对应的 buffer，该接口可以获取 graphic buffer group|
[hb_mem_inc_user_consume_cnt](#hb_mem_inc_user_consume_cnt)| 通过 fd 增加指定 buffer 的用户态引用计数 |
[hb_mem_dec_user_consume_cnt](#hb_mem_dec_user_consume_cnt)| 通过 fd 减少指定 buffer 的用户态引用计数 |
[hb_mem_inc_user_consume_cnt_with_vaddr](#hb_mem_inc_user_consume_cnt_with_vaddr)| 通过虚拟地址增加指定 buffer 的用户态引用计数 |
[hb_mem_dec_user_consume_cnt_with_vaddr](#hb_mem_dec_user_consume_cnt_with_vaddr)| 通过虚拟地址减少指定 buffer 的用户态引用计数 |


### 兼容性接口 ( 新功能开发时不建议使用 )

| API 接口                        | 接口功能                      |
|---------------------------------|------------------------------|
[hbmem_alloc](#hbmem_alloc)| 分配物理连续的内存空间 |
[hbmem_free](#hbmem_free)| 释放由 hbmem_alloc 分配的内存空间 |
[hbmem_mmap](#hbmem_mmap)| 将已知物理地址的内存空间进行 hbmem 映射，只允许落在 ion heap 中的内存调用该接口 |
[hbmem_munmap](#hbmem_munmap)| 释放由 hbmem_mmap 的映射 |
[hbmem_phyaddr](#hbmem_phyaddr)| 获取 hbmem 内存空间地址对应的实际 ddr 物理地址 |
[hbmem_dmacpy](#hbmem_dmacpy)| 使用系统的 dma，完成两块 hbmem 内存空间内数据的 copy 操作 |
[hbmem_virtaddr](#hbmem_virtaddr)| 获取 hbmem 内存空间地址对应的实虚拟地址 |
[hbmem_info](#hbmem_info)| 获取传入 hbmem_addr_t 地址值的信息 |
[hbmem_version](#hbmem_version)| 获取当前使用 hbmem 库的版本情况 |
[hbmem_is_cacheable](#hbmem_is_cacheable)| 获取 hbmem_addr_t 对应 hbmem 空间的 cache 类型 |
[hbmem_cache_invalid](#hbmem_cache_invalid)| 对 hbmem 内存空间的 cache 进行 invalid 操作 |
[hbmem_cache_clean](#hbmem_cache_clean)| 对 hbmem 内存空间的 cache 进行 clean 操作 |
[hbmem_mmap_with_share_id](#hbmem_mmap_with_share_id)| 使用 share_id 将已知物理地址的内存空间进行 hbmem 映射 |
[hbmem_get_share_id](#hbmem_get_share_id)| 获取虚拟地址的 share_id|

## 接口说明


<spin id="hb_mem_get_version"/> </span>

### hb_mem_get_version

【函数声明】
```
int32_t hb_mem_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch);
```


【参数描述】

- [OUT] major：主版本号

- [OUT] minor：次版本号

- [OUT] patch：补丁版本号


【返回值】

- 0 ：成功

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性


【功能描述】

获取模块版本号。





【示例代码】

```c

    int main(int argc, char *argv[])
    {
        uint32_t major, minor, patch;
        hb_mem_get_version(&major, &minor, &patch);
        return 0;
    }
```

<spin id="hb_mem_module_open"/> </span>

### hb_mem_module_open

【函数声明】
```
int32_t hb_mem_module_open(void);

```

【参数描述】

- NA


【返回值】

- 0 ：操作成功

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_MODULE_OPEN_FAIL：内存模块打开失败


【功能描述】

打开内存模块。

【注意事项】

- hbn_vflow_create 内部已经调用了 hb_mem_module_open，不需要再额外调用一次 hb_mem_module_open。
- 多线程场景下调用 hb_mem_module_open 后再调用 hbn_vflow_create 可能导致主进程占用的 fd 超过上限，进而导致内存分配失败。
- 需要与 hb_mem_module_close 成对调用


<span id="hb_mem_module_open_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        hb_mem_module_open();
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_module_close"/> </span>

### hb_mem_module_close

【函数声明】
```
int32_t hb_mem_module_close(void);

```

【参数描述】

- NA


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块


【功能描述】

关闭内存模块。


【注意事项】

- 需要与 hb_mem_module_open 成对调用。



【示例代码】

参考 :[hb_mem_module_open](#hb_mem_module_open)


<spin id="hb_mem_alloc_com_buf"/> </span>

### hb_mem_alloc_com_buf

【函数声明】
```
int32_t hb_mem_alloc_com_buf(uint64_t size, int64_t flags, hb_mem_common_buf_t  *buf);
```


【参数描述】

- [IN] size： buffer 大小

- [IN] flags： buffer 属性，见 : [hbmem 内存分配属性 ](#hbmem_alloc_att)

- [OUT] buf：分配得到的 common buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_TOO_MANY_FD：文件句柄个数超过上限，无法分配更多文件句柄，建议使用 ulimit 增加用户可打开的文件句柄上限


【功能描述】

分配 common buffer。



<span id="hb_mem_alloc_com_buf_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int32_t w = 1920, h = 1080, format = MEM_PIX_FMT_NV12, stride = 0,
        vstride = 0;
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        uint64_t offset = 0, offset_size;
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_common_buf_t com_buf_info = {0, };
        hb_mem_graphic_buf_t graph_buf = {0, };
        hb_mem_module_open();
        // test cached graph buffer
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_graph_buf(w, h, format, flags, stride, vstride,
            &graph_buf);
        offset_size = graph_buf.size[0];
        hb_mem_invalidate_buf(graph_buf.fd[0], offset, offset_size);
        hb_mem_free_buf(graph_buf.fd[0]);
        // test cached common buffer
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        offset_size = size;
        hb_mem_get_com_buf(com_buf.fd, &com_buf_info);
        hb_mem_invalidate_buf(com_buf.fd, offset, offset_size);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_get_com_buf"/> </span>

### hb_mem_get_com_buf

【函数声明】
```
int32_t hb_mem_get_com_buf(int32_t fd, hb_mem_common_buf_t *buf);

```

【参数描述】

- [IN] fd： buffer 相关文件描述符

- [OUT] buf： common buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

通过 fd 获取 common buffer 信息。





【示例代码】

参考 :[hb_mem_alloc_com_buf](#hb_mem_alloc_com_buf_demo)


<spin id="hb_mem_alloc_graph_buf"/> </span>

### hb_mem_alloc_graph_buf

【函数声明】
```
int32_t hb_mem_alloc_graph_buf(int32_t w, int32_t h, int32_t format, int64_t flags, int32_t stride, int32_t vstride, hb_mem_graphic_buf_t * buf);
```

【参数描述】

- [IN] w：图像宽度，(0 ， )

- [IN] h：图像高度，(0 ， )

- [IN] format：图像格式 , 见 :[hbmem 图像格式 ](#hbmem_alloc_format)

- [IN] flags： buffer 属性，见 : [hbmem 内存分配属性 ](#hbmem_alloc_att)

- [IN] stride：图像水平跨距， 0 或者 [w， )， 0 表示内部决定

- [IN] vstride：图像垂直跨距， 0 或者 [h， )， 0 表示内部决定

- [OUT] buf： graphic buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_TOO_MANY_FD：文件句柄个数超过上限，无法分配更多文件句柄，建议使用 ulimit 增加用户可打开的文件句柄上限


【功能描述】

分配 graphic buffer。



<span id="hb_mem_alloc_graph_buf_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int32_t w = 1280, h = 720, format = MEM_PIX_FMT_NV12, stride = 0, vstride = 0;
        int64_t flags = HB_MEM_USAGE_CPU_READ_NEVER;
        hb_mem_graphic_buf_t graph_buf = {0, };
        hb_mem_graphic_buf_t info = {0, };
        hb_mem_module_open();
        hb_mem_alloc_graph_buf(w, h, format, flags, stride, vstride,
            &graph_buf);
        hb_mem_get_graph_buf(graph_buf.fd[0], &info);
        hb_mem_free_buf(graph_buf.fd[0]);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_get_graph_buf"/> </span>

### hb_mem_get_graph_buf

【函数声明】
```
int32_t hb_mem_get_graph_buf(int32_t fd, hb_mem_graphic_buf_t *buf);

```

【参数描述】

- [IN] fd： buffer 相关文件描述符，取值范围 [0, )

- [OUT] buf： graphic buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

通过 fd 获取 graphic buffer 信息。





【示例代码】

参考 :[hb_mem_alloc_graph_buf](#hb_mem_alloc_graph_buf_demo)


<spin id="hb_mem_free_buf"/> </span>

### hb_mem_free_buf

【函数声明】
```
int32_t hb_mem_free_buf(int32_t fd);

```

【参数描述】

- [IN] fd： buffer 相关文件描述符，取值范围 [0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

通过 fd 释放 buffer。





【示例代码】

参考 :[hb_mem_alloc_graph_buf](#hb_mem_alloc_graph_buf_demo)


<spin id="hb_mem_invalidate_buf"/> </span>

### hb_mem_invalidate_buf

【函数声明】
```
int32_t hb_mem_invalidate_buf(int32_t fd, uint64_t offset, uint64_t size);
```


【参数描述】

- [IN] fd： buffer 相关文件描述符，取值范围是 [0, )

- [IN] offset：需要 invalidate 的 buffer 地址偏移，取值范围是 [0, )

- [IN] size：需要 invalidate 的 buffer 大小，取值范围是 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

使 fd 对应的缓冲区无效，当用户分配的 buffer 属性，见 : [hbmem 内存分配属性 ](#hbmem_alloc_att)，
带有 HB_MEM_USAGE_CACHED 时，表明该 buffer 具备 cache 属性，用户需要在读取 buffer 之前执行该操作。

【示例代码】

参考 :[hb_mem_alloc_com_buf](#hb_mem_alloc_com_buf_demo)


### <spin id="hb_mem_flush_buf"/> hb_mem_flush_buf

【函数声明】
```
int32_t hb_mem_flush_buf(int32_t fd, uint64_t offset, uint64_t size);

```

【参数描述】

- [IN] fd： buffer 相关文件描述符，取值范围 [0, )

- [IN] offset：需要 flush 的 buffer 地址偏移，取值范围是 [0, )

- [IN] size：需要 flush 的 buffer 大小，取值范围是 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

Flush fd 对应的缓冲区，当用户分配的 buffer 属性，见 : [hbmem 内存分配属性 ](#hbmem_alloc_att)，
带有 HB_MEM_USAGE_CACHED 时，表明该 buffer 具备 cache 属性，用户需要在写入 buffer 之后执行该操作；



<span id="hb_mem_flush_buf_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags = HB_MEM_USAGE_CPU_READ_OFTEN |
        HB_MEM_USAGE_CPU_WRITE_OFTEN | HB_MEM_USAGE_CACHED;
        uint64_t size = 1024 * 4; // 4k
        uint64_t offset = 0;
        int32_t valid;
        uint64_t phys_addr;
        uint64_t start_virt;
        uint64_t total_size;
        int64_t out_flags;
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_module_open();
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_is_valid_buf((uint64_t)com_buf.virt_addr, com_buf.size,
            &valid);
        hb_mem_get_phys_addr((uint64_t)com_buf.virt_addr, &phys_addr);
        hb_mem_get_buf_info((uint64_t)com_buf.virt_addr, &start_virt,
            &total_size, &out_flags);
        hb_mem_flush_buf(com_buf.fd, offset, size);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_is_valid_buf"/> </span>

### hb_mem_is_valid_buf

【函数声明】
```
int32_t hb_mem_is_valid_buf(uint64_t virt_addr, uint64_t size, int32_t *valid);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围是 (0, )

- [IN] size： buffer 大小，取值范围是 (0, )

- [OUT] valid：该虚拟地址是否有效， 0 ：无效， 1 ：有效


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性


【功能描述】

判断输入的虚拟地址是否为从 memory module 分配的有效地址。





【示例代码】

参考 :[hb_mem_flush_buf](./3-Hbmem_index_zh_CN.html#spin-id-hb-mem-flush-buf-hb-mem-flush-buf)


<spin id="hb_mem_get_phys_addr"/> </span>

### hb_mem_get_phys_addr

【函数声明】
```
int32_t hb_mem_get_phys_addr(uint64_t virt_addr, uint64_t *phys_addr);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围是 (0, )

- [OUT] phys_addr：对应的物理地址，取值范围是 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

获取输入虚拟地址对应的物理地址信息。





【示例代码】

参考 :[hb_mem_flush_buf](./3-Hbmem_index_zh_CN.html#spin-id-hb-mem-flush-buf-hb-mem-flush-buf)


<spin id="hb_mem_get_buf_info"/> </span>

### hb_mem_get_buf_info

【函数声明】
```
int32_t hb_mem_get_buf_info(uint64_t virt_addr, uint64_t *start, uint64_t *size, int64_t *flags);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围是 (0, )

- [OUT] start：对应的起始虚拟地址，取值范围是 (0, )

- [OUT] size：对应的 buffer 大小，取值范围是 (0, )

- [OUT] flags：对应的 buffer 属性，见 : [hbmem 内存分配属性 ](#hbmem_alloc_att)


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

获取输入虚拟地址对应的起始虚拟地址和 buffer 大小信息。





【示例代码】

参考 :[hb_mem_flush_buf](./3-Hbmem_index_zh_CN.html#spin-id-hb-mem-flush-buf-hb-mem-flush-buf)


<spin id="hb_mem_invalidate_buf_with_vaddr"/> </span>

### hb_mem_invalidate_buf_with_vaddr

【函数声明】
```
int32_t hb_mem_invalidate_buf_with_vaddr(uint64_t virt_addr, uint64_t size);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围是 (0, )

- [IN] size：需要 invalidate 的 buffer 大小，取值范围是 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

使虚拟地址对应的缓冲区无效，当用户分配的 buffer 属性，见 : [hbmem 内存分配属性 ](#hbmem_alloc_att)，
带有 HB_MEM_USAGE_CACHED 时，表明该 buffer 具备 cache 属性，用户需要在读取 buffer 之前执行该操作





【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_invalidate_buf_with_vaddr((uint64_t)com_buf.virt_addr, size);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_flush_buf_with_vaddr"/> </span>

### hb_mem_flush_buf_with_vaddr

【函数声明】
```
int32_t hb_mem_flush_buf_with_vaddr(uint64_t virt_addr, uint64_t size);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围是 (0, )

- [IN] size：需要 flush 的 buffer 大小，取值范围是 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

Flush 虚拟地址对应的缓冲区，当用户分配的 buffer 属性，见 : [hbmem 内存分配属性 ](#hbmem_alloc_att)，
带有 HB_MEM_USAGE_CACHED 时，表明该 buffer 具备 cache 属性，用户需要在写入 buffer 之后执行该操作。



<span id="hb_mem_flush_buf_with_vaddr_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_common_buf_t info = {0, };
        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_get_com_buf_with_vaddr((uint64_t)com_buf.virt_addr, &info);
        hb_mem_flush_buf_with_vaddr((uint64_t)com_buf.virt_addr, size);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_get_com_buf_with_vaddr"/> </span>

### hb_mem_get_com_buf_with_vaddr

【函数声明】
```
int32_t hb_mem_get_com_buf_with_vaddr(uint64_t virt_addr, hb_mem_common_buf_t *buf);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围是 (0, )

- [OUT] buf： common buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址获取 common buffer 信息。





【示例代码】

参考 :[hb_mem_flush_buf_with_vaddr](#hb_mem_flush_buf_with_vaddr_demo)

<spin id="hb_mem_get_graph_buf_with_vaddr"/> </span>

### hb_mem_get_graph_buf_with_vaddr

【函数声明】
```
int32_t hb_mem_get_graph_buf_with_vaddr(uint64_t virt_addr, hb_mem_graphic_buf_t *buf);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围是 (0, )

- [OUT] buf： graphic buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址获取 graphic buffer 信息。





【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int32_t w = 1920, h = 1080, format = MEM_PIX_FMT_NV12, stride = 0,
        vstride = 0;
        int64_t flags = HB_MEM_USAGE_CPU_READ_NEVER;
        uint64_t tmp_vaddr;
        hb_mem_graphic_buf_t graph_buf = {0, };
        hb_mem_graphic_buf_t info = {0, };
        hb_mem_module_open();
        hb_mem_alloc_graph_buf(w, h, format, flags, stride, vstride,
            &graph_buf);
        for (int i = 0; i < graph_buf.plane_cnt; i++) {
            tmp_vaddr = (uint64_t)graph_buf.virt_addr[i] + graph_buf.size[i]/2;
            hb_mem_get_graph_buf_with_vaddr(tmp_vaddr, &info);
        }
        hb_mem_free_buf_with_vaddr(tmp_vaddr);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_free_buf_with_vaddr"/> </span>

### hb_mem_free_buf_with_vaddr

【函数声明】
```
int32_t hb_mem_free_buf_with_vaddr(uint64_t virt_addr);

```

【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围是 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址释放 buffer。





【示例代码】

参考 :[hb_mem_get_graph_buf_with_vaddr](#hb_mem_get_graph_buf_with_vaddr)


<spin id="hb_mem_import_com_buf"/> </span>

### hb_mem_import_com_buf

【函数声明】
```
int32_t hb_mem_import_com_buf(hb_mem_common_buf_t  *buf, hb_mem_common_buf_t  *out_buf);
```


【参数描述】

- [IN] buf：输入的 common buffer

- [OUT] out_buf：导出的 common buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_TOO_MANY_FD：文件句柄个数超过上限，无法分配更多文件句柄，建议使用 ulimit 增加用户可打开的文件句柄上限


【功能描述】

导入 common buffer 的共享内存，获取新的 common buffer 信息。





【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int32_t ret;
        pid_t child;
        uint64_t size = 1024 * 4; // 4k
        int64_t flags = HB_MEM_USAGE_CPU_READ_NEVER;
        int32_t sd[2];
        socketpair(AF_UNIX, SOCK_STREAM, 0, sd);
        child = fork();
        if (child < 0) {
            printf("%s Fail to create child process(current %d, parent %d)!\n",
                __func__, getpid(), getppid());
            exit(1);
        } else if (child == 0) {
            hb_mem_common_buf_t recv_buf = {0, };
            hb_mem_common_buf_t out_buf = {0, };
            struct msghdr msg;
            struct iovec io;
            printf("%s In child process %d(parent %d).\n",
                getpid(), getppid());
            close(sd[1]);
            memset(&msg, 0x00, sizeof(msg));
            msg.msg_name = NULL;
            msg.msg_namelen = 0;
            msg.msg_iov = &io;
            msg.msg_iovlen = 1;
            io.iov_base = &recv_buf;
            io.iov_len = sizeof(recv_buf);
            ret = recvmsg(sd[0], &msg, 0);
            printf("%s [%d:%d] child recv msg 1\n", __func__, getpid(),
                getppid());
            hb_mem_module_open();
            hb_mem_import_com_buf(&recv_buf, &out_buf);
            ret = sendmsg(sd[0], &msg, 0);
            printf("%s [%d:%d] child send msg to parent to free buffer safely\n",
                __func__, getpid(), getppid());
            // do anything to the buffer
            hb_mem_free_buf(out_buf.fd);
            hb_mem_module_close();
            close(sd[0]);
            printf("%s [%d:%d] child quit\n", __func__, getpid(), getppid());
            exit(0);
        } else {
            hb_mem_common_buf_t recv_buf = {0, };
            hb_mem_common_buf_t in_buf = {0, };
            struct msghdr msg;
            struct iovec io;
            printf( "%s In parent process %d(pparent %d).\n",
                __func__, getpid(), getppid());
            hb_mem_module_open();
            hb_mem_alloc_com_buf(size, flags, &in_buf);
            close(sd[0]);
            memset(&msg, 0x00, sizeof(msg));
            msg.msg_name = NULL;
            msg.msg_namelen = 0;
            msg.msg_iov = &io;
            msg.msg_iovlen = 1;
            io.iov_base = &in_buf;
            io.iov_len = sizeof(in_buf);
            ret = sendmsg(sd[1], &msg, 0);
            printf("%s [%d:%d] parent send msg to share the buffer\n", __func__,
                getpid(), getppid());
            // wait message to free buffer
            io.iov_base = &recv_buf;
            io.iov_len = sizeof(recv_buf);
            ret = recvmsg(sd[1], &msg, 0);
            printf("%s [%d:%d] parent recv msg to free the buffer safely\n",
                __func__, getpid(), getppid());
            hb_mem_free_buf(in_buf.fd);
            hb_mem_module_close();
            printf("%s [%d:%d] parent quit\n", __func__, getpid(), getppid());
            close(sd[1]);
            exit(0);
        }
        return 0;
    }
```

<spin id="hb_mem_import_graph_buf"/> </span>

### hb_mem_import_graph_buf

【函数声明】
```
int32_t hb_mem_import_graph_buf(hb_mem_graphic_buf_t * buf, hb_mem_graphic_buf_t * out_buf);
```


【参数描述】

- [IN] buf：输入的 graphic buffer

- [OUT] out_buf：导出的 graphic buffer


【返回值】

- 0 ：操作成功

- HB_MEM_ERR_UNKNOWN： 未知的错误

- HB_MEM_ERR_NOT_ALLOW：操作不允许

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性


【功能描述】

导入 graphic buffer 的共享内存，获取新的 graphic buffer 信息。
<span id="hb_mem_import_graph_buf_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int32_t ret;
        pid_t child;
        int32_t w = 1920, h = 1080, format = MEM_PIX_FMT_NV12, stride = 0,
        vstride = 0;
        int64_t flags = HB_MEM_USAGE_CPU_READ_OFTEN |
        HB_MEM_USAGE_CPU_WRITE_OFTEN;
        hb_mem_graphic_buf_t in_info = {0, };
        int32_t sd[2];
        int32_t status;
        for (format = MEM_PIX_FMT_RGB565; format <= MEM_PIX_FMT_YUV400;
            format++) {
            printf("%s [%d:%d] Start Test format %d scenario 1.\n", TAG,
            getpid(), getppid(), format);
            socketpair(AF_UNIX, SOCK_STREAM, 0, sd);
            child = fork();
            if (child < 0) {
                printf("%s [%d:%d] Fail to create child process!\n",
                TAG, getpid(), getppid());
                exit(1);
            } else if (child == 0) {
                hb_mem_graphic_buf_t recv_buf = {0, };
                hb_mem_graphic_buf_t out_buf = {0, };
                struct msghdr msg;
                struct iovec io;
                printf("%s [%d:%d] In child process.\n",
                    TAG, getpid(), getppid());
                close(sd[1]);
                memset(&msg, 0x00, sizeof(msg));
                msg.msg_name = NULL;
                msg.msg_namelen = 0;
                msg.msg_iov = &io;
                msg.msg_iovlen = 1;
                io.iov_base = &recv_buf;
                io.iov_len = sizeof(recv_buf);
                ret = recvmsg(sd[0], &msg, 0);
                ASSERT_NE(ret, 0);
                ASSERT_EQ(flags, recv_buf.flags);
                printf("%s [%d:%d] child recv msg 1\n", TAG, getpid(), getppid());
                ASSERT_EQ(hb_mem_import_graph_buf(&recv_buf, &out_buf),
                (int32_t)HB_MEM_ERR_MODULE_NOT_FOUND);
                ASSERT_EQ(hb_mem_module_open(), 0);
                recv_buf.offset[0] = recv_buf.size[0]/2;
                recv_buf.offset[1] = recv_buf.size[1]/2;
                recv_buf.offset[2] = recv_buf.size[2]/2;
                ASSERT_EQ(hb_mem_import_graph_buf(&recv_buf, &out_buf), (int32_t)0);
                //compare_import_graphic_buf(&recv_buf, &out_buf, out_buf.plane_cnt);
                ASSERT_EQ(out_buf.offset[0], recv_buf.offset[0]);
                ASSERT_EQ(out_buf.offset[1], recv_buf.offset[1]);
                ASSERT_EQ(out_buf.offset[2], recv_buf.offset[2]);
                ASSERT_EQ(do_sys_command(flags & HB_MEM_USAGE_PRIV_MASK), 0);
                ret = sendmsg(sd[0], &msg, 0);
                ASSERT_NE(ret, 0);
                printf("%s [%d:%d] child send msg 2\n", TAG, getpid(), getppid());
                ASSERT_EQ(hb_mem_free_buf(out_buf.fd[0]), 0);
                ASSERT_NE(do_sys_command(flags & HB_MEM_USAGE_PRIV_MASK), 0);
                ASSERT_EQ(hb_mem_module_close(), 0);
                ASSERT_NE(do_sys_command(HB_MEM_USAGE_PRIV_MASK), 0);
                printf("%s [%d:%d] child quit\n", TAG, getpid(), getppid());
                close(sd[0]);
                exit(0);
        } else {
            hb_mem_graphic_buf_t in_buf = {0, };
            hb_mem_graphic_buf_t recv_buf = {0, };
            struct msghdr msg;
            struct iovec io;
            printf( "%s [%d:%d] In parent process.\n",
                TAG, getpid(), getppid());
            close(sd[0]);
            ASSERT_EQ(hb_mem_module_open(), 0);
            ASSERT_EQ(hb_mem_alloc_graph_buf(w, h, format, flags, stride,
                vstride, &in_buf),
                (int32_t)0);
            ASSERT_EQ(hb_mem_get_graph_buf(in_buf.fd[0], &in_info), (int32_t)0);
            ASSERT_EQ(do_sys_command(flags & HB_MEM_USAGE_PRIV_MASK), 0);
            memset(&msg, 0x00, sizeof(msg));
            msg.msg_name = NULL;
            msg.msg_namelen = 0;
            msg.msg_iov = &io;
            msg.msg_iovlen = 1;
            io.iov_base = &in_buf;
            io.iov_len = sizeof(in_buf);
            ret = sendmsg(sd[1], &msg, 0);
            ASSERT_NE(ret, 0);
            printf("%s [%d:%d] parent send msg 1\n", TAG, getpid(), getppid());
            io.iov_base = &recv_buf;
            io.iov_len = sizeof(recv_buf);
            ret = recvmsg(sd[1], &msg, 0);
            printf("%s [%d:%d] parent recv msg 2\n", TAG, getpid(), getppid());
            ASSERT_EQ(hb_mem_wait_share_status(in_buf.fd[0], 1, -1), (int32_t)0);
            ASSERT_EQ(hb_mem_free_buf(in_buf.fd[0]), 0);
            ASSERT_EQ(hb_mem_module_close(), 0);
            printf("%s [%d:%d] parent quit\n", TAG, getpid(), getppid());
            waitpid(child, &status, 0);
            close(sd[1]);
        }
        return 0;
    }
```

<spin id="hb_mem_get_share_info"/> </span>

### hb_mem_get_share_info

【函数声明】
```
int32_t hb_mem_get_share_info(int32_t fd, int32_t *share_client_cnt);
```


【参数描述】

- [IN] fd： buffer 相关文件描述符，取值范围 [0, )

- [OUT] share_client_cnt： fd 对应 buffer 的共享客户端的个数，取值范围 [0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

通过 fd 获取对应 buffer 的共享客户端的个数。



<span id="hb_mem_get_share_info_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        pid_t child;
        uint64_t size = 1024 * 4; // 4k
        int64_t flags = HB_MEM_USAGE_CPU_READ_NEVER;
        hb_mem_common_buf_t in_buf = {0, };
        int32_t status;
        hb_mem_module_open();
        hb_mem_alloc_com_buf(size, flags, &in_buf);
        child = fork();
        if (child < 0) {
            printf("%s [%d:%d] Fail to create child process!\n",
            __func__, getpid(), getppid());
            exit(1);
        } else if (child == 0) {
            int32_t share_client_cnt;
            printf("%s [%d:%d] In child process.\n",
                __func__, getpid(), getppid());
            hb_mem_get_share_info(in_buf.fd, &share_client_cnt);
            hb_mem_free_buf(in_buf.fd);
            hb_mem_module_close();
            printf("%s [%d:%d] child quit\n", __func__, getpid(), getppid());
            exit(0);
        } else {
            printf( "%s [%d:%d] In parent process.\n",
                __func__, getpid(), getppid());
            hb_mem_free_buf(in_buf.fd);
            hb_mem_wait_share_status_with_vaddr((uint64_t)in_buf.virt_addr, 0,
                -1);
            printf("%s [%d:%d] parent wait successfully\n", __func__, getpid(),
                getppid());
            hb_mem_module_close();
            printf("%s [%d:%d] parent quit\n", __func__, getpid(), getppid());
            waitpid(child, &status, 0);
        }
        return 0;
    }
```

<spin id="hb_mem_get_share_info_with_vaddr"/> </span>

### hb_mem_get_share_info_with_vaddr

【函数声明】
```
int32_t hb_mem_get_share_info_with_vaddr(uint64_t virt_addr, int32_t *share_client_cnt);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [OUT] share_client_cnt： fd 对应 buffer 的共享客户端的个数，取值范围 [0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址获取对应 buffer 的共享客户端的个数。





【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        int32_t share_client_cnt;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_get_share_info_with_vaddr((uint64_t)com_buf.virt_addr,
            &share_client_cnt);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_wait_share_status"/> </span>

### hb_mem_wait_share_status

【函数声明】
```
int32_t hb_mem_wait_share_status(int32_t fd, int32_t share_client_cnt, int64_t timeout);
```


【参数描述】

- [IN] fd： buffer 相关文件描述符，取值范围 [0, )

- [IN] share_client_cnt：目标共享客户端的个数，取值范围 [0, )

- [IN] timeout：超时时间（ ms），<0 ：阻塞等待；=0 ：立即返回；>0 ：超时时间


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_TIMEOUT：等待超时，共享客户端个数没有在预设时间内达到目标值

- HB_MEM_ERR_WAIT_SHARE_FAILURE：等待 share client 状态失败


【功能描述】

等待 fd 对应 buffer 的共享客户端个数小于等于目标值。





【示例代码】

参考 :[hb_mem_import_graph_buf](#hb_mem_import_graph_buf_demo)


<spin id="hb_mem_wait_share_status_with_vaddr"/> </span>

### hb_mem_wait_share_status_with_vaddr

【函数声明】
```
int32_t hb_mem_wait_share_status_with_vaddr(uint64_t virt_addr, int32_t share_client_cnt, int64_t timeout);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [IN] share_client_cnt：目标共享客户端的个数，取值范围 [0, )

- [IN] timeout：超时时间（ ms），<0 ：阻塞等待；=0 ：立即返回；>0 ：超时时间


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）

- HB_MEM_ERR_TIMEOUT：等待超时，共享客户端个数没有在预设时间内达到目标值

- HB_MEM_ERR_WAIT_SHARE_FAILURE：等待 share client 状态失败


【功能描述】

等待虚拟地址对应 buffer 的共享客户端个数小于等于目标值。





【示例代码】

参考 :[hb_mem_get_share_info](#hb_mem_get_share_info_demo)


<spin id="hb_mem_create_buf_queue"/> </span>

### hb_mem_create_buf_queue

【函数声明】
```
int32_t hb_mem_create_buf_queue(hb_mem_buf_queue_t *queue);

```

【参数描述】

- [IN] queue->count：内存队列元素数量，取值范围 (0, ]

- [IN] queue->item_size：内存队列元素 size，取值范围 (0, ]

- [OUT] queue->unique_id：内存队列标识符


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_QUEUE_ALREADY_EXIST：内存队列已经创建


【功能描述】

创建内存队列。



<span id="hb_mem_create_buf_queue_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_common_buf_t out_buf = {0, };
        hb_mem_common_buf_t in_buf = {0, };
        hb_mem_buf_queue_t queue;
        #define QUEUE_ITEM_CNT 5
        int64_t timeout = 0;
        int32_t slot_array[QUEUE_ITEM_CNT];
        uint32_t i;
        memset(&queue, 0x00, sizeof(queue));
        // test after open
        hb_mem_module_open();
        queue.count = QUEUE_ITEM_CNT;
        queue.item_size = sizeof(com_buf);
        hb_mem_create_buf_queue(&queue);
        // producer do dequeue/queue
        for (i = 0; i < queue.count; i++) {
            hb_mem_dequeue_buf(&queue, &slot_array[i], &out_buf, timeout);
        }
        for (i = 0; i < queue.count; i++) {
            hb_mem_queue_buf(&queue, slot_array[i], &in_buf);
        }
        for (i = 0; i < queue.count; i++) {
            hb_mem_request_buf(&queue, &slot_array[i], &out_buf, timeout);
        }
        for (i = 0; i < queue.count; i++) {
            hb_mem_cancel_buf(&queue, slot_array[i]);
        }
        // comsumer do request/release
        for (i = 0; i < queue.count; i++) {
            hb_mem_request_buf(&queue, &slot_array[i], &out_buf, timeout);
        }
        for (i = 0; i < queue.count; i++) {
            hb_mem_release_buf(&queue, slot_array[i]);
        }
        hb_mem_destroy_buf_queue(&queue);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_destroy_buf_queue"/> </span>

### hb_mem_destroy_buf_queue

【函数声明】
```
int32_t hb_mem_destroy_buf_queue(hb_mem_buf_queue_t *queue);

```

【参数描述】

- [IN] queue：要销毁的内存队列


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_QUEUE_NOT_FOUND：无法找到指定的 queue，请检查 queue 的参数是否正常


【功能描述】

销毁内存队列。





【示例代码】

参考 :[hb_mem_create_buf_queue](#hb_mem_create_buf_queue_demo)


<spin id="hb_mem_dequeue_buf"/> </span>

### hb_mem_dequeue_buf

【函数声明】
```
int32_t hb_mem_dequeue_buf(hb_mem_buf_queue_t *queue, int32_t *slot, void  *buf, int64_t timeout);
```


【参数描述】

- [IN] queue：内存队列，参数应该非空

- [IN] timeout：超时时间（ ms），<0 ：阻塞等待；=0 ：立即返回；>0 ：超时时间

- [OUT] slot：内存队列元素索引，取值范围 [0, count)

- [OUT] buffer：元素信息，大小为创建内存队列时指定的 item_size，参数应该非空


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_QUEUE_NOT_FOUND：无法找到指定的 queue，请检查 queue 的参数是否正常

- HB_MEM_ERR_QUEUE_DESTROYED： queue 已经被销毁，建议检查代码逻辑

- HB_MEM_ERR_QUEUE_NO_AVAILABLE_SLOT：没有可用的 slot，建议继续 dequeue

- HB_MEM_ERR_TIMEOUT： dequeue 超时，可能的原因有空闲队列没有可用的 slot，建议继续 dequeue


【功能描述】

生产者获取可用的 slot 信息。





【示例代码】

参考 :[hb_mem_create_buf_queue](#hb_mem_create_buf_queue_demo)


<spin id="hb_mem_queue_buf"/> </span>

### hb_mem_queue_buf

【函数声明】
```
int32_t hb_mem_queue_buf(hb_mem_buf_queue_t * queue, int32_t slot, const void  *buf);
```


【参数描述】

- [IN] queue：内存队列，参数应该非空

- [IN] slot：内存队列元素索引，取值范围 [0, )

- [IN] buf：元素信息，大小为创建内存队列时指定的 item_size，参数应该非空


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_QUEUE_NOT_FOUND：无法找到指定的 queue，请检查 queue 的参数是否正常

- HB_MEM_ERR_QUEUE_DESTROYED： queue 已经被销毁，建议检查代码逻辑

- HB_MEM_ERR_QUEUE_WRONG_SLOT： slot 异常，建议检查 slot 是否为 dequeue 获得


【功能描述】

生产者填充元素信息后将其入队到该 slot 中。





【示例代码】

参考 :[hb_mem_create_buf_queue](#hb_mem_create_buf_queue_demo)


<spin id="hb_mem_request_buf"/> </span>

### hb_mem_request_buf

【函数声明】
```
int32_t hb_mem_request_buf(hb_mem_buf_queue_t *queue, int32_t *slot, void  *buf, int64_t timeout);
```


【参数描述】

- [IN] queue：内存队列，参数应该非空

- [IN] timeout：超时时间（ ms），<0 ：阻塞等待；=0 ：立即返回；>0 ：超时时间

- [OUT] slot：内存队列元素索引，取值范围 [0, count)

- [OUT] buf：元素信息，大小为创建内存队列时指定的 item_size，参数应该非空


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_QUEUE_NOT_FOUND：无法找到指定的 queue，请检查 queue 的参数是否正常

- HB_MEM_ERR_QUEUE_DESTROYED： queue 已经被销毁，建议检查代码逻辑

- HB_MEM_ERR_QUEUE_NO_AVAILABLE_SLOT：没有可用的 slot，建议继续 request

- HB_MEM_ERR_TIMEOUT： request 超时，可能的原因有 queued 队列没有可用的 slot，建议继续 request


【功能描述】

消费者从队列中获取生产者入队的元素信息。





【示例代码】

参考 :[hb_mem_create_buf_queue](#hb_mem_create_buf_queue_demo)


<spin id="hb_mem_release_buf"/> </span>

### hb_mem_release_buf

【函数声明】
```
int32_t hb_mem_release_buf(hb_mem_buf_queue_t * queue, int32_t slot);
```


【参数描述】

- [IN] queue：内存队列，参数应该非空

- [IN] slot：内存队列元素索引，取值范围 [0, count)


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_QUEUE_NOT_FOUND：无法找到指定的 queue，请检查 queue 的参数是否正常

- HB_MEM_ERR_QUEUE_DESTROYED： queue 已经被销毁，建议检查代码逻辑

- HB_MEM_ERR_QUEUE_WRONG_SLOT： slot 异常，建议检查 slot 是否为 request 获得


【功能描述】

消费者释放使用完的元素索引。





【示例代码】

参考 :[hb_mem_create_buf_queue](#hb_mem_create_buf_queue_demo)


<spin id="hb_mem_cancel_buf"/> </span>

### hb_mem_cancel_buf

【函数声明】
```
int32_t hb_mem_cancel_buf(hb_mem_buf_queue_t  *queue, int32_t slot);

```

【参数描述】

- [IN] queue：内存队列，参数应该非空

- [IN] slot：内存队列元素索引，取值范围 [0, count)


【返回值】

- 0 ：操作成功

- HB_MEM_ERR_UNKNOWN：未知的错误

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性


【功能描述】

生产者取消 dequeue 获得的 slot 或者消费者取消 request 获得的 slot 信息。





【示例代码】

参考 :[hb_mem_create_buf_queue](#hb_mem_create_buf_queue_demo)


<spin id="hb_mem_pool_create"/> </span>

### hb_mem_pool_create

【函数声明】
```
int32_t hb_mem_pool_create(uint64_t size, int64_t flags, hb_mem_pool_t * pool);
```


【参数描述】

- [IN] size： Memory pool 的大小，取值范围 (0 ，]

- [IN] flags： Memory pool 的 buffer 属性，见 :[hbmem 内存分配属性 ](#hbmem_alloc_att)

- [OUT] pool：导出的 memory pool


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_TOO_MANY_FD：文件句柄个数超过上限，无法分配更多文件句柄，建议使用 ulimit 增加用户可打开的文件句柄上限


【功能描述】

创建一个内存池。



<span id="hb_mem_pool_create_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        uint64_t i, num, size = 1024 * 1024 * 4, alloc_size; // 4M
        int64_t flags;
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_common_buf_t out_buf = {0, };
        hb_mem_pool_t pool = {0, };
        hb_mem_pool_t out_pool = {0, };
        hb_mem_common_buf_t import_buf = {0, };
        char * tmp_vaddr;
        char tmp_val = 0x5a;
        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN |
            HB_MEM_USAGE_CPU_WRITE_OFTEN ;
        hb_mem_pool_create(size, flags, &pool);
        hb_mem_get_com_buf(pool.fd, &com_buf);
        num = size / pool.page_size;
        alloc_size = pool.page_size;
        for (i = 0; i < num; i++) {
            hb_mem_pool_alloc_buf(pool.fd, alloc_size, &out_buf);
            tmp_vaddr = (char *)out_buf.virt_addr;
            *tmp_vaddr = tmp_val;
            hb_mem_pool_get_info(pool.fd, &out_pool);
            hb_mem_pool_free_buf((uint64_t)out_buf.virt_addr);
        }
        hb_mem_pool_destroy(pool.fd);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_pool_destroy"/> </span>

### hb_mem_pool_destroy

【函数声明】
```
int32_t hb_mem_pool_destroy(int32_t fd);

```

【参数描述】

- [IN] fd： Memory pool 的文件描述符，取值范围 [0,)


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_POOL_DESTROYED：内存池已被销毁，建议检查代码逻辑

- HB_MEM_ERR_POOL_BUSY：内存池无法销毁，内存池中有未释放内存片，建议用户先释放从内存池中分配的内存片，再销毁内存池


【功能描述】

销毁一个内存池。





【示例代码】

参考 :[hb_mem_pool_create](#hb_mem_pool_create_demo)


<spin id="hb_mem_pool_alloc_buf"/> </span>

### hb_mem_pool_alloc_buf

【函数声明】
```
int32_t hb_mem_pool_alloc_buf(int32_t fd, uint64_t size, hb_mem_common_buf_t * buf);
```


【参数描述】

- [IN] fd： Memory pool 的文件描述符，取值范围 [0,)

- [IN] size： Buffer 的大小，取值范围 [0,)

- [OUT] buf： common buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_POOL_NOT_FOUND：无法找到指定的 memory pool，请检查参数是否正常

- HB_MEM_ERR_POOL_DESTROYED：内存池已被销毁，建议检查代码逻辑


【功能描述】

从内存池中分配一块 common buffer；





【示例代码】

参考 :[hb_mem_pool_create](#hb_mem_pool_create_demo)


<spin id="hb_mem_pool_free_buf"/> </span>

### hb_mem_pool_free_buf

【函数声明】
```
int32_t hb_mem_pool_free_buf(uint64_t virt_addr);

```

【参数描述】

- [IN] virt_addr：虚拟地址，取值范围 (0,]


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）

- HB_MEM_ERR_POOL_DESTROYED：内存池已被销毁，建议检查代码逻辑

- HB_MEM_ERR_POOL_NOT_FOUND：无法找到指定的 memory pool，请检查参数是否正常


【功能描述】

释放从内存池中分配的 buffer。





【示例代码】

参考 :[hb_mem_pool_create](#hb_mem_pool_create_demo)


<spin id="hb_mem_pool_get_info"/> </span>

### hb_mem_pool_get_info

【函数声明】
```
int32_t hb_mem_pool_get_info(int32_t fd, hb_mem_pool_t  *pool);

```

【参数描述】

- [IN] fd： Memory pool 的文件描述符，取值范围 [0,)

- [OUT] pool： memory pool 信息


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_POOL_DESTROYED：内存池已被销毁，建议检查代码逻辑

- HB_MEM_ERR_POOL_NOT_FOUND：无法找到指定的 memory pool，请检查参数是否正常


【功能描述】

获取内存池的实时信息。





【示例代码】

参考 :[hb_mem_pool_create](#hb_mem_pool_create_demo)


<spin id="hb_mem_share_pool_create"/> </span>

### hb_mem_share_pool_create

【函数声明】
```
int32_t hb_mem_share_pool_create(uint32_t num, uint64_t size, int64_t flags, hb_mem_share_pool_t * pool);
```


【参数描述】

- [IN] num： Memory share pool 分配的 buffer 个数，取值范围 (0 ，]

- [IN] size： Memory share pool 分配的 Buffer 大小，取值范围 (0 ，]

- [IN] flags： Memory share pool 的 buffer 属性，见 : [hbmem 内存分配属性 ](#hbmem_alloc_att)

- [OUT] pool：导出的 memory share pool


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_TOO_MANY_FD：文件句柄个数超过上限，无法分配更多文件句柄，建议使用 ulimit 增加用户可打开的文件句柄上限


【功能描述】

创建一个共享内存池。



<span id="hb_mem_share_pool_create_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        uint64_t i = 0, num = 5, size = 1024 * 1024 * 4; // 4M
        int64_t flags;
        hb_mem_common_buf_t com_buf[10] = {0, };
        hb_mem_share_pool_t out_pool = {0, };
        hb_mem_share_pool_t pool = {0, };

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN;
        hb_mem_share_pool_create(num, size, flags, &pool);
        for (i = 0; i < num; i++) {
            hb_mem_share_pool_alloc_buf(pool.fd, &com_buf[i]);
        }
        for (i = 0; i < num; i++) {
            hb_mem_share_pool_free_buf((uint64_t)(com_buf[i].virt_addr));
        }
        hb_mem_share_pool_get_info(pool.fd, &out_pool);
        hb_mem_share_pool_destroy(pool.fd);
        hb_mem_module_close();
        return 0;
    }
```

<spin id="hb_mem_share_pool_destroy"/> </span>

### hb_mem_share_pool_destroy

【函数声明】
```
int32_t hb_mem_share_pool_destroy(int32_t fd);

```

【参数描述】

- [IN] fd： Memory share pool 的文件描述符，取值范围 [0,)


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_POOL_DESTROYED：内存池已被销毁，建议检查代码逻辑

- HB_MEM_ERR_POOL_BUSY：内存池无法销毁，内存池中有未释放内存片，建议用户先释放从内存池中分配的内存片，再销毁内存池


【功能描述】

销毁一个共享内存池。





【示例代码】

参考 :[hb_mem_share_pool_create](#hb_mem_share_pool_create_demo)


<spin id="hb_mem_share_pool_alloc_buf"/> </span>

### hb_mem_share_pool_alloc_buf

【函数声明】
```
int32_t hb_mem_share_pool_alloc_buf(int32_t fd, hb_mem_common_buf_t * buf);
```


【参数描述】

- [IN] fd： Memory share pool 的文件描述符，取值范围 [0,)

- [OUT] buf： common buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_POOL_NOT_FOUND：无法找到指定的 memory share pool，请检查参数是否正常

- HB_MEM_ERR_POOL_DESTROYED：内存池已被销毁，建议检查代码逻辑


【功能描述】

从共享内存池中分配一块 common buffer；





【示例代码】

参考 :[hb_mem_share_pool_create](#hb_mem_share_pool_create_demo)


<spin id="hb_mem_share_pool_free_buf"/> </span>

### hb_mem_share_pool_free_buf

【函数声明】
```
int32_t hb_mem_share_pool_free_buf(uint64_t virt_addr);

```

【参数描述】

- [IN] virt_addr：虚拟地址，取值范围 (0,]


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）

- HB_MEM_ERR_POOL_DESTROYED：内存池已被销毁，建议检查代码逻辑

- HB_MEM_ERR_POOL_NOT_FOUND：无法找到指定的 memory share pool，请检查参数是否正常


【功能描述】

释放从共享内存池中分配的 buffer。





【示例代码】

参考 :[hb_mem_share_pool_create](#hb_mem_share_pool_create_demo)


<spin id="hb_mem_share_pool_get_info"/> </span>

### hb_mem_share_pool_get_info

【函数声明】
```
int32_t hb_mem_share_pool_get_info(int32_t fd, hb_mem_share_pool_t * pool);

```

【参数描述】

- [IN] fd： Memory share pool 的文件描述符，取值范围 [0,)

- [OUT] pool： memory share pool 信息


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_POOL_DESTROYED：内存池已被销毁，建议检查代码逻辑

- HB_MEM_ERR_POOL_NOT_FOUND：无法找到指定的 memory share pool，请检查参数是否正常


【功能描述】

获取共享内存池的实时信息。





【示例代码】

参考 :[hb_mem_share_pool_create](#hb_mem_share_pool_create_demo)



<spin id="hb_mem_get_buf_type_with_vaddr"/> </span>

### hb_mem_get_buf_type_with_vaddr

【函数声明】
```
int32_t hb_mem_get_buf_type_with_vaddr(uint64_t virt_addr, hb_mem_buffer_type_t * type);

```

【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [OUT] type： buffer 类型


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

获取 virt_addr 对应 buffer 的类型。

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_buffer_type_t type;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_get_buf_type_with_vaddr((uint64_t)com_buf.virt_addr, &type);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```


<spin id="hb_mem_get_buf_type_and_buf_with_vaddr"/> </span>

### hb_mem_get_buf_type_and_buf_with_vaddr

【函数声明】
```
int32_t hb_mem_get_buf_type_and_buf_with_vaddr(uint64_t virt_addr, hb_mem_buffer_type_t * type, hb_mem_common_buf_t * com_buf, hb_mem_graphic_buf_t * graph_buf);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [OUT] type： buffer 类型

- [OUT] com_buf： common buffer

- [OUT] graph_buf： graph buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

获取 virt_addr 对应 buffer 的类型，并将其转换成 com buf 或 graph buf。

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_buffer_type_t type;
        hb_mem_common_buf_t com_outbuf = {0, };
        hb_mem_graphic_buf_t graph_outbuf = {0, };

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_get_buf_type_and_buf_with_vaddr((uint64_t)com_buf.virt_addr, &type, &com_outbuf, &graph_outbuf);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```



<spin id="hb_mem_get_buffer_process_info"/> </span>

### hb_mem_get_buffer_process_info

【函数声明】
```
int32_t hb_mem_get_buffer_process_info(uint64_t virt_addr, int32_t * pid, int32_t num, int32_t * ret_num);

```

【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [IN] pid：进程 pid 数组，存储返回的进程 pid

- [IN] num：进程 pid 数组大小，取值范围 (0, )

- [OUT] ret_num：持有 virt_addr 对应 buffer 的进程个数，取值范围 [0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址获取持有该 buffer 的进程 pid。

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        int32_t pid[16];
        int32_t ret_num = 0;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_get_buffer_process_info((uint64_t)com_buf.virt_addr, pid, 16, &ret_num);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```



<spin id="hb_mem_get_buffer_process_info_with_share_id"/> </span>

### hb_mem_get_buffer_process_info_with_share_id

【函数声明】
```
int32_t hb_mem_get_buffer_process_info_with_share_id(int32_t share_id, int32_t * pid, int32_t num, int32_t * ret_num);

```

【参数描述】

- [IN] share_id：取值范围 (0, )

- [IN] pid：进程 pid 数组，存储返回的进程 pid

- [IN] num：进程 pid 数组大小，取值范围 (0, )

- [OUT] ret_num：持有 share_id 对应 buffer 的进程个数，取值范围 [0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性


【功能描述】

通过 share_id 获取持有对应 buffer 的进程 pid。

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        int32_t pid[16];
        int32_t ret_num = 0;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_get_buffer_process_info_with_share_id(com_buf.share_id, pid, 16, &ret_num);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```



<spin id="hb_mem_get_consume_info"/> </span>

### hb_mem_get_consume_info

【函数声明】
```
int32_t hb_mem_get_consume_info(int32_t fd, int32_t * share_consume_cnt);

```

【参数描述】

- [IN] fd： buffer fd，取值范围 (0, )

- [OUT] share_consume_cnt： buffer consume cnt，取值范围 [0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

通过 fd 获取对应 buffer 的 consume cnt。

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        int32_t share_consume_cnt;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_get_consume_info(com_buf.fd, &share_consume_cnt);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```


<spin id="hb_mem_get_consume_info_with_vaddr"/> </span>

### hb_mem_get_consume_info_with_vaddr

【函数声明】
```
int32_t hb_mem_get_consume_info_with_vaddr(uint64_t virt_addr, int32_t * share_consume_cnt);

```

【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [OUT] share_consume_cnt： buffer consume cnt，取值范围 [0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过 virt_addr 获取对应 buffer 的 consume cnt。

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        int32_t share_consume_cnt;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_get_consume_info_with_vaddr((uint64_t)com_buf.virt_addr, &share_consume_cnt);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```



<spin id="hb_mem_wait_consume_status"/> </span>

### hb_mem_wait_consume_status

【函数声明】
```
int32_t hb_mem_wait_consume_status(int32_t fd, int32_t share_consume_cnt, int64_t timeout);

```

【参数描述】

- [IN] fd： buffer fd，取值范围 (0, )

- [IN] share_consume_cnt： buffer consume cnt，取值范围 [0, )

- [IN] timeout：超时时间，取值范围 [0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_WAIT_SHARE_FAILURE：等待 share client 状态失败


【功能描述】

等待 fd 对应 buffer 的 consume cnt 变成 share_consume_cnt，超时时间为 timeout。

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        int32_t share_consume_cnt = 0;
        int32_t timeout = 100;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_wait_consume_status(com_buf.fd, share_consume_cnt, timeout);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```



<spin id="hb_mem_wait_consume_status_with_vaddr"/> </span>

### hb_mem_wait_consume_status_with_vaddr

【函数声明】
```
int32_t hb_mem_wait_consume_status_with_vaddr(uint64_t virt_addr, int32_t share_consume_cnt, int64_t timeout);

```

【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [IN] share_consume_cnt： consume cnt，取值范围 [0, )

- [IN] timeout：超时时间，取值范围 [0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）

- HB_MEM_ERR_WAIT_SHARE_FAILURE：等待 share client 状态失败


【功能描述】

等待 virt_addr 对应 buffer 的 consume cnt 变成 share_consume_cnt，超时时间为 timeout。

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        int32_t share_consume_cnt = 0;
        int32_t timeout = 100;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_wait_consume_status_with_vaddr((uint64_t)com_buf.virt_addr, share_consume_cnt, timeout);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```



<spin id="hb_mem_inc_com_buf_consume_cnt"/> </span>

### hb_mem_inc_com_buf_consume_cnt

【函数声明】
```
int32_t hb_mem_inc_com_buf_consume_cnt(hb_mem_common_buf_t * buf);

```

【参数描述】

- [IN] buf： common buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性


【功能描述】

增加对应 common buffer 的 consume cnt

<span id="hb_mem_inc_com_buf_consume_cnt_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        int32_t timeout = 100;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_inc_com_buf_consume_cnt(&com_buf);
        hb_mem_dec_consume_cnt(com_buf.fd);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```


<spin id="hb_mem_inc_graph_buf_consume_cnt"/> </span>

### hb_mem_inc_graph_buf_consume_cnt

【函数声明】
```
int32_t hb_mem_inc_graph_buf_consume_cnt(hb_mem_graphic_buf_t * buf);

```

【参数描述】

- [IN] buf： graphic buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性


【功能描述】

增加对应 graphic buffer 的 consume cnt

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        hb_mem_graphic_buf_t graph_buf = {0, };
        int32_t w = 1920, h = 1080, format = MEM_PIX_FMT_NV12, stride = 0, vstride = 0;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_graph_buf(w, h, format, flags, stride, vstride,
            &graph_buf);
        hb_mem_inc_graph_buf_consume_cnt(&graph_buf);
        hb_mem_dec_consume_cnt(graph_buf.fd[0]);
        hb_mem_free_buf(graph_buf.fd[0]);
        hb_mem_module_close();
        return 0;
    }
```


<spin id="hb_mem_dec_consume_cnt"/> </span>

### hb_mem_dec_consume_cnt

【函数声明】
```
int32_t hb_mem_dec_consume_cnt(int32_t fd);

```

【参数描述】

- [IN] fd： buffer fd，取值范围 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

通过 fd 减少对应 buffer 的 consume cnt

【示例代码】

参考 :[hb_mem_inc_com_buf_consume_cnt](#hb_mem_inc_com_buf_consume_cnt_demo)





<spin id="hb_mem_dec_consume_cnt_with_vaddr"/> </span>

### hb_mem_dec_consume_cnt_with_vaddr

【函数声明】
```
int32_t hb_mem_dec_consume_cnt_with_vaddr(uint64_t virt_addr);

```

【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址减少对应 buffer 的 consume cnt

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t com_buf = {0, };
        int32_t timeout = 100;

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN
            | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &com_buf);
        hb_mem_inc_com_buf_consume_cnt(&com_buf);
        hb_mem_dec_consume_cnt_with_vaddr((uint64_t)com_buf.virt_addr);
        hb_mem_free_buf(com_buf.fd);
        hb_mem_module_close();
        return 0;
    }
```


<spin id="hb_mem_import_com_buf_with_paddr"/> </span>

### hb_mem_import_com_buf_with_paddr

【函数声明】
```
int32_t hb_mem_import_com_buf_with_paddr(uint64_t phys_addr,
			uint64_t size, int64_t flags, hb_mem_common_buf_t * buf);
```


【参数描述】

- [IN] phys_addr：需要 import 的 buffer 的地址，可以带偏移量，取值范围 (0, )

- [IN] size： import 的 buffer size，需要针对 PAGE_SIZE 对齐，取值范围 (0, )

- [IN] flags： import 的 buffer flag，取值范围 [0, )

- [OUT] buf： import 返回的 common buffer


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_TOO_MANY_FD：文件句柄个数超过上限，无法分配更多文件句柄，建议使用 ulimit 增加用户可打开的文件句柄上限


【功能描述】

通过物理地址共享内存，只能用于 hbmem 申请的内存。

由于上层无法直接获得物理地址，示例代码中只显示接口的使用方式。hbmem 申请得到的内存使用接口 hb_mem_import_com_buf 。hb_mem_import_com_buf_with_paddr 导
入的共享内存，需要使用 hb_mem_free_buf_with_vaddr 接口释放。

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        uint32_t size = 1024 * 8, out_size; // 8k
        uint64_t flags;
        const char * lable = NULL;
        hbmem_addr_t start, vaddr;
        uint64_t paddr = 0;
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_common_buf_t out_buf = {0, };

        flags = BACKEND_TYPE(BACKEND_ION_CMA) | MEM_CACHEABLE;
        vaddr = hbmem_alloc(size, flags, lable);
        hbmem_info(vaddr, &start, &out_size);
        paddr = hbmem_phyaddr(vaddr);
        hb_mem_get_com_buf_with_vaddr(vaddr, &com_buf);
        hb_mem_import_com_buf_with_paddr(paddr, com_buf.size, flags, &out_buf);
        hb_mem_free_buf_with_vaddr((uint64_t)out_buf.virt_addr);
        hbmem_free(vaddr);
        return 0;
    }
```



<spin id="hb_mem_dma_copy"/> </span>

### hb_mem_dma_copy

【函数声明】
```
int32_t hb_mem_dma_copy(uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size);

```

【参数描述】

- [IN] dst_vaddr：目的虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [IN] src_vaddr：源虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [IN] size： dma 的内存大小，取值范围 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

将源地址的数据拷贝到目的地址

【示例代码】

```c
    int main(int argc, char *argv[])
    {
        int64_t flags;
        uint64_t size = 1024 * 4; // 4k
        hb_mem_common_buf_t dst_com_buf = {0, };
        hb_mem_common_buf_t src_com_buf = {0, };

        hb_mem_module_open();
        flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN | HB_MEM_USAGE_CACHED;
        hb_mem_alloc_com_buf(size, flags, &dst_com_buf);
        hb_mem_alloc_com_buf(size, flags, &src_com_buf);
        hb_mem_dma_copy((uint64_t)dst_com_buf.virt_addr, (uint64_t)src_com_buf.virt_addr, size);
        hb_mem_free_buf(dst_com_buf.fd);
        hb_mem_free_buf(src_com_buf.fd);
        hb_mem_module_close();

        return 0;
    }
```

<spin id="hb_mem_alloc_graph_buf_group"/> </span>

### hb_mem_alloc_graph_buf_group

【函数声明】
```
int32_t hb_mem_alloc_graph_buf_group(int32_t * w, int32_t * h, int32_t * format, int64_t * flags, int32_t * stride,
			int32_t * vstride, hb_mem_graphic_buf_group_t * buf_group, uint32_t bitmap);
```


【参数描述】

- [IN] w：图像宽度数组

- [IN] h：图像高度数组

- [IN] format：图像格式数组 , 见 :[hbmem 图像格式 ](#hbmem_alloc_format)

- [IN] flags： buffer 属性数组，见 : [hbmem 内存分配属性 ](#hbmem_alloc_att)

- [IN] stride：图像水平跨距数组

- [IN] vstride：图像垂直跨距数组

- [OUT] buf_group： graphic buffer group

- [IN] bitmap：表示有效 graphic buffer 的位图


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息

- HB_MEM_ERR_TOO_MANY_FD：文件句柄个数超过上限，无法分配更多文件句柄，建议使用 ulimit 增加用户可打开的文件句柄上限


【功能描述】

申请一组 graphic buffer

<span id="hb_mem_alloc_graph_buf_group_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        hb_mem_graphic_buf_group_t buf_group = {0, };
        hb_mem_graphic_buf_group_t info = {0, };
        hb_mem_graphic_buf_group_t out_buf = {0, };
        hb_mem_graphic_buf_t graph_buf = {0, };
        hb_mem_common_buf_t com_buf = {0, };
        hb_mem_buffer_type_t *type;
        uint32_t bitmap = 0xFF;
        int32_t w[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int32_t h[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int32_t format[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int32_t stride[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int32_t vstride[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int64_t flags[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int32_t i;

        // open module
        hb_mem_module_open();

        // test DMA heap type
        for (i = 0; i < HB_MEM_MAXIMUM_GRAPH_BUF; i++) {
            if (bitmap & (1u << i)) {
                w[i] = 1280;
                h[i] = 720;
                format[i] = MEM_PIX_FMT_NV12;
                flags[i] = HB_MEM_USAGE_PRIV_HEAP_DMA | HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN;
                stride[i] = 0;
                vstride[i] = 0;
            }
        }

        hb_mem_alloc_graph_buf_group(w, h, format, flags, stride, vstride, &buf_group, bitmap);
        hb_mem_get_graph_buf_group(buf_group.graph_group[0].fd[0], &info);
        hb_mem_get_graph_buf_group_with_vaddr((uint64_t)buf_group.graph_group[0].virt_addr[0], &info);
        hb_mem_get_buf_and_type_with_vaddr((uint64_t)buf_group.graph_group[0].virt_addr[0], type, &com_buf, &graph_buf, &info);
        hb_mem_import_graph_buf_group(&buf_group, &out_buf);
        hb_mem_inc_graph_buf_group_consume_cnt(&buf_group);
        hb_mem_dec_consume_cnt(buf_group.graph_group[0].fd[0]);
        hb_mem_free_buf(buf_group.graph_group[0].fd[0]);
        hb_mem_free_buf(out_buf.graph_group[0].fd[0]);
        hb_mem_module_close();

        return 0;
    }
```


<spin id="hb_mem_import_graph_buf_group"/> </span>

### hb_mem_import_graph_buf_group

【函数声明】
```
int32_t hb_mem_import_graph_buf_group(hb_mem_graphic_buf_group_t * in_group, hb_mem_graphic_buf_group_t * out_group);

```

【参数描述】

- [IN] in_group：输入的 graphic buffer group

- [OUT] out_group：输出共享的 graphic buffer group


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INSUFFICIENT_MEM：内存不足，建议检查 ion 预留内存空间和系统内存使用情况

- HB_MEM_ERR_TOO_MANY_FD：文件句柄个数超过上限，无法分配更多文件句柄，建议使用 ulimit 增加用户可打开的文件句柄上限


【功能描述】

共享一组 graphic buffer

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int32_t ret;
        pid_t child;
        int32_t input_format = MEM_PIX_FMT_NV12, i;
        hb_mem_graphic_buf_group_t in_info = {0, };
        int32_t sd[2];
        int32_t status, m;
        uint32_t bitmap = 0xFF;
        int32_t w[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int32_t h[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int32_t format[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int32_t stride[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int32_t vstride[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };
        int64_t flags[HB_MEM_MAXIMUM_GRAPH_BUF] = {0, };

        for (m = 0; m < HB_MEM_MAXIMUM_GRAPH_BUF; m++) {
            if (bitmap & (1u << m)) {
                w[m] = 1280;
                h[m] = 720;
                flags[m] = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN;
                stride[m] = 0;
                vstride[m] = 0;
            }
        }

        printf("%s [%d:%d] Start Test format %d scenario 1.\n", TAG, getpid(), getppid(), input_format);
        socketpair(AF_UNIX, SOCK_STREAM, 0, sd);
        child = fork();
        if (child < 0) {
            printf("%s [%d:%d] Fail to create child process!\n",
                TAG, getpid(), getppid());
            exit(1);
        } else if (child == 0) {
            hb_mem_graphic_buf_group_t recv_buf = {0, };
            hb_mem_graphic_buf_group_t out_buf = {0, };
            struct msghdr msg;
            struct iovec io;

            printf("%s [%d:%d] In child process.\n",
                TAG, getpid(), getppid());

            close(sd[1]);
            memset(&msg, 0x00, sizeof(msg));
            msg.msg_name = NULL;
            msg.msg_namelen = 0;
            msg.msg_iov = &io;
            msg.msg_iovlen = 1;

            io.iov_base = &recv_buf;
            io.iov_len = sizeof(recv_buf);

            ret = recvmsg(sd[0], &msg, 0);
            printf("%s [%d:%d] child recv msg 1\n", TAG, getpid(), getppid());

            hb_mem_module_open();
            hb_mem_import_graph_buf_group(&recv_buf, &out_buf);

            ret = sendmsg(sd[0], &msg, 0);
            printf("%s [%d:%d] child send msg 2\n", TAG, getpid(), getppid());

            ret = recvmsg(sd[0], &msg, 0);
            printf("%s [%d:%d] child recv msg 3\n", TAG, getpid(), getppid());

            hb_mem_free_buf(out_buf.graph_group[0].fd[0]);
            ASSERT_EQ(hb_mem_module_close(), 0);
            printf("%s [%d:%d] child quit\n", TAG, getpid(), getppid());
            close(sd[0]);

            exit(0);
        } else {
            hb_mem_graphic_buf_group_t in_buf = {0, };
            hb_mem_graphic_buf_group_t recv_buf = {0, };
            struct msghdr msg;
            struct iovec io;

            printf( "%s [%d:%d] In parent process.\n",
                TAG, getpid(), getppid());
            close(sd[0]);

            hb_mem_module_open();
            for (m = 0; m < HB_MEM_MAXIMUM_GRAPH_BUF; m++) {
                if (bitmap & (1u << m)) {
                    format[m] = input_format;
                }
            }
            hb_mem_alloc_graph_buf_group(w, h, format, flags, stride, vstride, &in_buf, bitmap);
            hb_mem_get_graph_buf_group(in_buf.graph_group[0].fd[0], &in_info);

            memset(&msg, 0x00, sizeof(msg));
            msg.msg_name = NULL;
            msg.msg_namelen = 0;
            msg.msg_iov = &io;
            msg.msg_iovlen = 1;

            io.iov_base = &in_buf;
            io.iov_len = sizeof(in_buf);

            ret = sendmsg(sd[1], &msg, 0);
            printf("%s [%d:%d] parent send msg 1\n", TAG, getpid(), getppid());

            io.iov_base = &recv_buf;
            io.iov_len = sizeof(recv_buf);
            ret = recvmsg(sd[1], &msg, 0);
            printf("%s [%d:%d] parent recv msg 2\n", TAG, getpid(), getppid());

            hb_mem_free_buf(in_buf.graph_group[0].fd[0]);

            io.iov_base = &in_buf;
            io.iov_len = sizeof(in_buf);
            ret = sendmsg(sd[1], &msg, 0);
            printf("%s [%d:%d] parent send msg 3\n", TAG, getpid(), getppid());

            hb_mem_module_close();
            printf("%s [%d:%d] parent quit\n", TAG, getpid(), getppid());
            waitpid(child, &status, 0);
            close(sd[1]);
        }

        return 0;
    }
```



<spin id="hb_mem_get_graph_buf_group"/> </span>

### hb_mem_get_graph_buf_group

【函数声明】
```
int32_t hb_mem_get_graph_buf_group(int32_t fd, hb_mem_graphic_buf_group_t * buf_group);

```

【参数描述】

- [IN] fd： buffer fd， graphic buffer group 中任意一个 fd，取值范围 (0, )

- [OUT] buf_group：通过 fd 获取到的 graphic buffer group


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

通过 fd（ graphic buffer group 中任意一个有效的 fd）获取 graphic buffer group

【示例代码】

参考 :[hb_mem_alloc_graph_buf_group](#hb_mem_alloc_graph_buf_group_demo)




<spin id="hb_mem_get_graph_buf_group_with_vaddr"/> </span>

### hb_mem_get_graph_buf_group_with_vaddr

【函数声明】
```
int32_t hb_mem_get_graph_buf_group_with_vaddr(uint64_t virt_addr, hb_mem_graphic_buf_group_t * buf_group);

```

【参数描述】

- [IN] virt_addr：虚拟地址， graphic buffer group 中任意一个虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [OUT] buf_group：通过虚拟地址获取到的 graphic buffer group


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址（ graphic buffer group 中任意一个有效的虚拟地址）获取 graphic buffer group

【示例代码】

参考 :[hb_mem_alloc_graph_buf_group](#hb_mem_alloc_graph_buf_group_demo)




<spin id="hb_mem_inc_graph_buf_group_consume_cnt"/> </span>

### hb_mem_inc_graph_buf_group_consume_cnt

【函数声明】
```
int32_t hb_mem_inc_graph_buf_group_consume_cnt(hb_mem_graphic_buf_group_t * buf_group);

```

【参数描述】

- [IN] buf_group： graphic buffer group


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性


【功能描述】

增加 graphic buffer group 中所有 buffer 的 consume cnt




<spin id="hb_mem_get_buf_and_type_with_vaddr"/> </span>

### hb_mem_get_buf_and_type_with_vaddr

【函数声明】
```
int32_t hb_mem_get_buf_and_type_with_vaddr(uint64_t virt_addr, hb_mem_buffer_type_t * type, hb_mem_common_buf_t * com_buf,
hb_mem_graphic_buf_t * graph_buf, hb_mem_graphic_buf_group_t * graph_group);
```


【参数描述】

- [IN] virt_addr：虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )

- [OUT] type： buffer 类型

- [OUT] com_buf： common buffer

- [OUT] graph_buf： graphic buffer

- [OUT] graph_group： graphic buffer group


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址获取对应 buffer 的类型和对应的 buffer，该接口可以获取 graphic buffer group

【示例代码】

参考 :[hb_mem_alloc_graph_buf_group](#hb_mem_alloc_graph_buf_group_demo)



<spin id="hbmem_alloc"/> </span>

### hbmem_alloc

【函数声明】
```
hbmem_addr_t hbmem_alloc(uint32_t size, uint64_t flag, const char
label);
```


【参数描述】

- [IN] size：需要分配的内存空间大小

- [IN] flag：申请标识符，具体见下对 flag 的详细说明

- [IN] label：字符串以标识该内存空间（后续增加的 debug 功能会使用该字段进行区分，取 <10 字符部分），如果不对内存空间做标记设置为 NULL


【返回值】

- 0 ：申请失败

- 非 0 ：申请成功，该 hbmem_addr_t 的值可作为虚拟地址被用户直接使用


【功能描述】

分配 hobot memory, 分配出物理连续的内存空间（兼容性接口，新功能开发时不建议使用）



<span id="hbmem_alloc_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        uint32_t major, minor, patch;
        uint32_t size = 1024 * 8, i, out_size, size2; // 8k
        uint64_t flags = BACKEND_ION_CMA;
        const char * lable = NULL;
        hbmem_addr_t dst_vaddr, src_vaddr, start, vaddr, vaddr2, vaddr_out;
        uint64_t paddr = 0;
        uint8_t *tmp_vaddr;
        uint8_t value = 55;
        int32_t share_id = 1;
        hb_mem_common_buf_t com_buf = {0, };
        flags = BACKEND_TYPE(BACKEND_ION_CMA) | MEM_CACHEABLE;
        hbmem_version(&major, &minor, &patch);
        vaddr = hbmem_alloc(size, flags, lable);
        hbmem_info(vaddr, &start, &out_size);
        paddr = hbmem_phyaddr(vaddr);
        vaddr_out = hbmem_virtaddr(vaddr);
        hbmem_is_cacheable(vaddr);
        hb_mem_get_com_buf_with_vaddr(vaddr, &com_buf);
        paddr = com_buf.phys_addr;
        size2 = com_buf.size;
        share_id = com_buf.share_id;
        vaddr2 = hbmem_mmap_with_share_id(paddr, size2, flags, share_id);
        share_id = 0;
        hbmem_get_share_id(vaddr2, &share_id);
        hbmem_munmap(vaddr2);
        vaddr2 = hbmem_mmap(paddr, size, flags);
        hbmem_munmap(vaddr2);
        hbmem_free(vaddr);
        dst_vaddr = hbmem_alloc(size, flags, lable);
        src_vaddr = hbmem_alloc(size, flags, lable);
        tmp_vaddr = (uint8_t *)src_vaddr;
        for (i = 0; i < size; i++) {
            tmp_vaddr[i] = value;
        }
        hbmem_cache_clean(src_vaddr, size);
        hbmem_dmacpy(dst_vaddr, src_vaddr, size);
        hbmem_cache_invalid(dst_vaddr, size);
        hbmem_free(src_vaddr);
        hbmem_free(dst_vaddr);
        return 0;
    }
```

<spin id="hbmem_free"/> </span>

### hbmem_free

【函数声明】
```
void hbmem_free(hbmem_addr_t addr);

```

【参数描述】

- [IN] addr： hbmem_alloc 返回的有效 hbmem_addr_t


【返回值】

- 无


【功能描述】

释放由 hbmem_alloc 分配的内存空间（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_mmap"/> </span>

### hbmem_mmap

【函数声明】
```
hbmem_addr_t hbmem_mmap(uint64_t phyaddr, uint32_t size, uint64_t
flag);
```


【参数描述】

- [IN] phyaddr：合法物理地址内存空间的起始地址（ PAGE_SIZE 对齐）

- [IN] size：需要映射的内存空间大小

- [IN] flag：申请标识符


【返回值】

- 0 ：映射失败

- 非 0 ：映射成功，该 hbmem_addr_t 的值可作为虚拟地址被用户直接使用


【功能描述】

将已知物理地址的内存空间进行 hbmem 映射，只允许落在 ion heap 中的内存调用该接口（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_munmap"/> </span>

### hbmem_munmap

【函数声明】
```
void hbmem_munmap(hbmem_addr_t addr);

```

【参数描述】

- [IN] addr： hbmem_mmap 返回的有效 hbmem_addr_t


【返回值】

- 无


【功能描述】

释放由 hbmem_mmap 的映射（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_phyaddr"/> </span>

### hbmem_phyaddr

【函数声明】
```
uint64_t hbmem_phyaddr(hbmem_addr_t addr);

```

【参数描述】

- [IN] addr： hbmem_mmap 返回的有效 hbmem_addr_t


【返回值】

- 0 ：无效物理地址，表明传入的 hbmem_addr_t 非有效 hbmem 中的地址

- 非 0 ：物理地址


【功能描述】

获取 hbmem 内存空间地址对应的实际 ddr 物理地址（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_dmacpy"/> </span>

### hbmem_dmacpy

【函数声明】
```
int32_t hbmem_dmacpy(hbmem_addr_t dst, hbmem_addr_t src, uint32_t
size);
```


【参数描述】

- [IN] dst：目标 hbmem 空间的起始地址

- [IN] src：源 hbmem 空间的起始地址

- [IN] size：需要拷贝的内存空间大小


【返回值】

- 0 ：传输成功

- <0 ：失败


【功能描述】

使用系统的 dma，完成两块 hbmem 内存空间内数据的 copy 操作（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_virtaddr"/> </span>

### hbmem_virtaddr

【函数声明】
```
uint64_t hbmem_virtaddr(hbmem_addr_t addr);

```

【参数描述】

- [IN] addr：有效 hbmem_addr_t


【返回值】

- 0 ：无效虚拟地址，表明传入的 hbmem_addr_t 非有效 hbmem 中的地址

- 非 0 ：虚拟地址


【功能描述】

获取 hbmem 内存空间地址对应的实虚拟地址（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_info"/> </span>

### hbmem_info

【函数声明】
```
int32_t hbmem_info(hbmem_addr_t addr, hbmem_addr_t *start, uint32_t
*size);
```


【参数描述】

- [IN] addr: 有效 hbmem_addr_t

- [IN] start: 传入归属 hbmem 内存空间的 buffer 起始地址

- [IN] size: 传入归属的 hbmem 内存空间的 buffer 大小


【返回值】

- <0: 该 hbmem_addr_t 不属于任何 hbmem 内存空间，此时 start/size 参数不会被赋值

- >=0: 该 hbmem_addr_t 所属任何 hbmem 内存空间的类型。 0 ： UNKNOWN 未知； 1 ： ALLOCED 通过 hbmem_alloc 申请的空间； 2 ： MAPPED 通过 hbmem_mmap 映射的空间


【功能描述】

获取传入 hbmem_addr_t 地址值的信息（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_version"/> </span>

### hbmem_version

【函数声明】
```
int32_t hbmem_version(uint32_t *major, uint32_t *minor, uint32_t *patch);
```


【参数描述】

- [OUT] major：版本 major 值

- [OUT] minor：版本 minor 值

- [OUT] patch：版本 patch 值


【返回值】

- 0 ：获取成功

- <0: 参数异常，有为 NULL 的参数传入


【功能描述】

获取当前使用 hbmem 库的版本情况（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_is_cacheable"/> </span>

### hbmem_is_cacheable

【函数声明】
```
int32_t hbmem_is_cacheable(hbmem_addr_t addr);

```

【参数描述】

- [IN] addr：有效 hbmem_addr_t


【返回值】

- <0 ：该地址为无效 hbmem_addr_t

- 0 ： uncache 类型

- >0 ： cacheable 类型


【功能描述】

获取 hbmem_addr_t 对应 hbmem 空间的 cache 类型（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_cache_invalid"/> </span>

### hbmem_cache_invalid

【函数声明】
```
void hbmem_cache_invalid(hbmem_addr_t addr, uint32_t size);

```

【参数描述】

- [IN] addr：有效 hbmem_addr_t

- [IN] size：操作的空间大小


【返回值】

无

【功能描述】

对 hbmem 内存空间的 cache 进行 invalid 操作（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_cache_clean"/> </span>

### hbmem_cache_clean

【函数声明】
```
void hbmem_cache_clean(hbmem_addr_t addr, uint32_t size);

```

【参数描述】

- [IN] addr：有效 hbmem_addr_t

- [IN] size：操作的空间大小


【返回值】

无

【功能描述】

对 hbmem 内存空间的 cache 进行 clean 操作（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_mmap_with_share_id"/> </span>

### hbmem_mmap_with_share_id

【函数声明】
```
hbmem_addr_t hbmem_mmap_with_share_id(uint64_t phyaddr, uint32_t
size,
```


uint64_t flag, int32_t share_id);

【参数描述】

- [IN] phyaddr：合法物理地址内存空间的起始地址（ 0x1000 对齐）

- [IN] size：需要映射的内存空间大小

- [IN] flag：申请标识符

- [IN] share_id：全局唯一的共享 id


【返回值】

- 0 ：映射失败

- 非 0 ：映射成功，该 hbmem_addr_t 的值可作为虚拟地址被用户直接使用


【功能描述】

使用 share_id 将已知物理地址的内存空间进行 hbmem 映射（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hbmem_get_share_id"/> </span>

### hbmem_get_share_id

【函数声明】
```
int32_t hbmem_get_share_id(hbmem_addr_t addr, int32_t *share_id);

```

【参数描述】

- [IN] addr：有效 hbmem_addr_t

- [OUT] share_id： addr 对应的 share_id


【返回值】

- 0: 成功获取虚拟地址对应的 share_id

- <0 ：未找到虚拟地址


【功能描述】

获取虚拟地址的 share_id（兼容性接口，新功能开发时不建议使用）





【示例代码】

参考 :[hbmem_alloc](#hbmem_alloc_demo)


<spin id="hb_mem_inc_user_consume_cnt"/> </span>

### hb_mem_inc_user_consume_cnt

【函数声明】
```
int32_t hb_mem_inc_user_consume_cnt(int32_t hb_fd);

```

【参数描述】

- [IN] hb_fd: buffer 相关文件描述符


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

通过 fd 增加指定 buffer 的用户态引用计数，不支持 graphic buffer group， pool buffer 与 share pool buffer
<span id="hb_mem_inc_user_consume_cnt_demo"/> </sapn>

【示例代码】

```c

    int main(int argc, char *argv[])
    {
        int32_t ret = 0;
        uint64_t size = 4 * 1024 * 1024;
        int64_t flags = HB_MEM_USAGE_CPU_READ_OFTEN | HB_MEM_USAGE_CPU_WRITE_OFTEN | HB_MEM_USAGE_CACHED;
        hb_mem_common_buf_t com_buf = {0, };

        ret = hb_mem_module_open();
        if (ret != 0) {
            printf("hb_mem_module_open failed\n");
            return ret;
        }

        ret = hb_mem_alloc_com_buf(size, flags, &com_buf);
        if (ret != 0) {
            printf("hb_mem_alloc_com_buf failed\n");
            (void)hb_mem_module_close();
            return ret;
        }
        printf("alloc com buf, share_id: %d\n", com_buf.share_id);
        do_sys_command(flags & HB_MEM_USAGE_PRIV_MASK);

        //inc/dec user consume with fd
        ret = hb_mem_inc_user_consume_cnt(com_buf.fd);
        if (ret != 0) {
            printf("hb_mem_inc_user_consume_cnt failed\n");
            (void)hb_mem_module_close();
            return ret;
        }

        ret = hb_mem_dec_user_consume_cnt(com_buf.fd);
        if (ret != 0) {
            printf("hb_mem_dec_user_consume_cnt failed\n");
            (void)hb_mem_module_close();
            return ret;
        }

        //inc/dec user consume with vaddr
        ret = hb_mem_inc_user_consume_cnt_with_vaddr((uint64_t)com_buf.virt_addr);
        if (ret != 0) {
            printf("hb_mem_inc_user_consume_cnt_with_vaddr failed\n");
            (void)hb_mem_module_close();
            return ret;
        }

        ret = hb_mem_dec_user_consume_cnt_with_vaddr((uint64_t)com_buf.virt_addr);
        if (ret != 0) {
            printf("hb_mem_dec_user_consume_cnt_with_vaddr failed\n");
            (void)hb_mem_module_close();
            return ret;
        }

        ret = hb_mem_free_buf(com_buf.fd);
        if (ret != 0) {
            printf("hb_mem_free_buf failed\n");
            (void)hb_mem_module_close();
            return ret;
        }
        printf("free com buf\n");
        do_sys_command(flags & HB_MEM_USAGE_PRIV_MASK);
        ret = hb_mem_module_close();
        if (ret != 0) {
            printf("hb_mem_module_close failed\n");
            return ret;
        }

        return 0;
    }
```


<spin id="hb_mem_dec_user_consume_cnt"/> </span>

### hb_mem_dec_user_consume_cnt

【函数声明】
```
int32_t hb_mem_dec_user_consume_cnt(int32_t hb_fd);

```

【参数描述】

- [IN] hb_fd: buffer 相关文件描述符


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_FD：文件句柄异常，存在异常的文件句柄，无法找到对应的 buffer 信息，可查看日志获取具体信息


【功能描述】

通过 fd 减少指定 buffer 的用户态引用计数，不支持 graphic buffer group， pool buffer 与 share pool buffer


【示例代码】

参考 :[hb_mem_inc_user_consume_cnt](#hb_mem_inc_user_consume_cnt_demo)



<spin id="hb_mem_inc_user_consume_cnt_with_vaddr"/> </span>

### hb_mem_inc_user_consume_cnt_with_vaddr

【函数声明】
```
int32_t hb_mem_inc_user_consume_cnt_with_vaddr(uint64_t virt_addr);

```

【参数描述】

- [IN] virt_addr: 虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址增加指定 buffer 的用户态引用计数，不支持 graphic buffer group， pool buffer 与 share pool buffer


【示例代码】

参考 :[hb_mem_inc_user_consume_cnt](#hb_mem_inc_user_consume_cnt_demo)



<spin id="hb_mem_dec_user_consume_cnt_with_vaddr"/> </span>

### hb_mem_dec_user_consume_cnt_with_vaddr

【函数声明】
```
int32_t hb_mem_dec_user_consume_cnt_with_vaddr(uint64_t virt_addr);

```

【参数描述】

- [IN] virt_addr: 虚拟地址，可以是偏移后的虚拟地址，取值范围 (0, )


【返回值】

- 0 ：成功

- HB_MEM_ERR_MODULE_NOT_FOUND：内存模块并未打开，建议先打开内存模块

- HB_MEM_ERR_INVALID_PARAMS：无效参数，建议按照日志提醒检查输入参数的有效性

- HB_MEM_ERR_INVALID_VADDR：虚拟地址异常，存在异常的虚拟地址，无法找到对应的 buffer 信息，可查看日志获取具体信息（调高日志等级）


【功能描述】

通过虚拟地址减少指定 buffer 的用户态引用计数，不支持 graphic buffer group， pool buffer 与 share pool buffer


【示例代码】

参考 :[hb_mem_inc_user_consume_cnt](#hb_mem_inc_user_consume_cnt_demo)

<span id="hbmem_alloc_struc"/> </sapn>

## 数据结构

### <span id="hb_mem_common_buf_t"/> hb_mem_common_buf_t

```c
    /**
    * @struct hb_mem_common_buf_t
    * Define the descriptor of common buffer.
    */
    typedef struct hb_mem_common_buf_t {
        int32_t fd;			/**< File descriptors of the buffer.*/
        int32_t share_id;	/**< Share id of the buffer.*/
        int64_t flags;		/**< Buffer flags for allocation */
        uint64_t size;		/**< Total Buffer size specified by user during allocation.*/
        uint8_t *virt_addr;	/**< Buffer starting virtual address.*/
        /**
        * - Note: It's not recommended to use or transfer the physical address directly.
        *         There is no memory object to keep track of the physical address.
        */
        uint64_t phys_addr;	/**< Buffer starting physical address.*/
        uint64_t offset;	/**< Buffer offset.*/
    } hb_mem_common_buf_t;
```

### <spin id="hb_mem_graphic_buf_t"/> hb_mem_graphic_buf_t

```c
    /**
    * @struct hb_mem_graphic_buf_t
    * Define the descriptor of graphic buffer.
    */
    typedef struct hb_mem_graphic_buf_t {
        //#define MAX_GRAPHIC_BUF_COMP 3
        int32_t fd[MAX_GRAPHIC_BUF_COMP];	/**< File descriptors of the buffer for each component.*/
        /**
        * Values [1, MAX_GRAPHIC_BUF_COMP]
        */
        int32_t plane_cnt;					/**< Plane count of this graphic buffer*/
        int32_t format;						/**< Buffer format for allocation.@mem_pixel_format_t*/
        int32_t width;						/**< Buffer width.*/
        int32_t height;						/**< Buffer height.*/
        int32_t stride;						/**< Buffer horizontal stride.*/
        int32_t vstride;					/**< Buffer vertical stride.*/
        int32_t is_contig;					/**< Buffer physical memory is contiguous.@mem_usage_t*/
        int32_t share_id[MAX_GRAPHIC_BUF_COMP];	/**< Share id of the buffer.*/
        int64_t flags;						/**< Buffer flags for allocation.@mem_usage_t*/
        uint64_t size[MAX_GRAPHIC_BUF_COMP];	/**< Total Buffer size for each component.*/
        uint8_t *virt_addr[MAX_GRAPHIC_BUF_COMP];	/**< Buffer virtual address for each component.*/
        /**
        * - Note: It's not recommended to use or transfer the physical address directly.
        *         There is no memory object to keep track of the physical address.
        */
        uint64_t phys_addr[MAX_GRAPHIC_BUF_COMP];	/**< Buffer physical address for each component.*/
        uint64_t offset[MAX_GRAPHIC_BUF_COMP];	/**< Buffer offset.*/
    } hb_mem_graphic_buf_t;
```


<spin id="hb_mem_graphic_buf_group_t"/> </span>

### hb_mem_graphic_buf_group_t

```c

    /**
    * @struct hb_mem_graphic_buf_group_t
    * Define the descriptor of graphic buffer group
    */
    typedef struct hb_mem_graphic_buf_group_t {
        //#define HB_MEM_MAXIMUM_GRAPH_BUF 8
        hb_mem_graphic_buf_t graph_group[HB_MEM_MAXIMUM_GRAPH_BUF];	/**graphic buffer array*/
        int32_t group_id;		/**< graphic buffer group id which alloc from ION driver*/
        uint32_t bit_map;		/**< graphic buffer group bitmap*/
    } hb_mem_graphic_buf_group_t;
```

<spin id="hb_mem_buf_queue_t"/> </span>

### hb_mem_buf_queue_t

```c

    /**
    * @struct hb_mem_buf_queue_t
    * Define the descriptor of buffer queue.
    */
    typedef struct hb_mem_buf_queue_t {
        uint64_t unique_id;	/**< Uinque id specified by memory manager. Should no be modified.*/
        uint32_t count;		/**< Total items of the buffer queue.*/
        uint32_t item_size;	/**< Size of each item.*/
    } hb_mem_buf_queue_t;
```

<spin id="hb_mem_pool_t"/> </span>

### hb_mem_pool_t

```c

    /**
    * @struct hb_mem_pool_t
    * Define the descriptor of memory pool.
    */
    typedef struct hb_mem_pool_t {
        int64_t flags;		/**< Buffer flags for allocation.@mem_usage_t*/
        uint64_t size;		/**< Total Buffer size specified by user during allocation.*/
        int32_t fd;			/**< File descriptors of the pool.*/
        int32_t page_size;	/**< Page size in byte.*/
        int32_t total_page_cnt;	/**< Total page count.*/
        int32_t avail_page_cnt;	/**< Available page count.*/
        int32_t cur_client_cnt;	/**< Current pool client count.*/

        int32_t reserved;		/**< reserved*/
    } hb_mem_pool_t;
```

<spin id="hb_mem_share_pool_t"/> </span>

### hb_mem_share_pool_t

```c

    /**
    * @struct hb_mem_share_pool_t
    * Define the descriptor of share memory pool.
    */
    typedef struct hb_mem_share_pool_t {
        int64_t flags;		/**< Buffer flags for allocation.@mem_usage_t*/
        uint32_t size;		/**< Buffer size specified by user during allocation.*/
        int32_t fd;			/**< File descriptors of the pool.*/
        int32_t total_buf_cnt;	/**< Total buf count.*/
        int32_t avail_buf_cnt;	/**< Available buffer count.*/

        int32_t reserved;		/**< reserved*/
    } hb_mem_share_pool_t;
```

<a id="hbmem_alloc_att"></a>

### hbmem 内存分配属性

内存分配属性参考。

| 数据项                               | 描述                                                                           |
|--------------------------------------|--------------------------------------------------------------------------------|
| HB_MEM_USAGE_CPU_READ_NEVER          | CPU 不会读该内存，内存将不会被分配读属性                                       |
| HB_MEM_USAGE_CPU_READ_OFTEN          | CPU 经常读该内存，内存将被分配读属性                                           |
| HB_MEM_USAGE_CPU_READ_MASK           | 用于获取 read 相关属性的掩码， HB_MEM_USAGE_CPU_READ_OFTEN 属性优先级高于 HB_MEM_USAGE_CPU_READ_NEVER |
| HB_MEM_USAGE_CPU_WRITE_NEVER         | CPU 不会写该内存，内存将不会被分配写属性                                       |
| HB_MEM_USAGE_CPU_WRITE_OFTEN         | CPU 经常写该内存，内存将被分配写属性，该属性会自动添加读属性                   |
| HB_MEM_USAGE_CPU_WRITE_MASK          | 用于获取 write 相关属性的掩码， HB_MEM_USAGE_CPU_WRITE_OFTEN 属性优先级高于 HB_MEM_USAGE_CPU_WRITE_NEVER |
| HB_MEM_USAGE_HW_CIM                  | 表明该内存用于 Camera Interface Module 相关模块，不影响内存分配，用于 debug 信息 |
| HB_MEM_USAGE_HW_PYRAMID              | 表明该内存用于 Pyramid 相关模块，不影响内存分配，用于 debug 信息               |
| HB_MEM_USAGE_HW_GDC                  | 表明该内存用于 Geometric Distortion Correction 相关模块输入 buffer，不影响内存分配，用于 debug 信息 |
| HB_MEM_USAGE_HW_GDC_OUT              | 表明该内存用于 Geometric Distortion Correction 相关模块输出 buffer，不影响内存分配，用于 debug 信息 |
| HB_MEM_USAGE_HW_STITCH               | 表明该内存用于 Stitch 相关模块，不影响内存分配，用于 debug 信息                |
| HB_MEM_USAGE_HW_OPTICAL_FLOW         | 表明该内存用于 Optical Flow 相关模块，不影响内存分配，用于 debug 信息          |
| HB_MEM_USAGE_HW_BPU                  | 表明该内存用于 BPU 模块，不影响内存分配，用于 debug 信息                       |
| HB_MEM_USAGE_HW_ISP                  | 表明该内存用于 ISP 模块，不影响内存分配，用于 debug 信息                       |
| HB_MEM_USAGE_HW_DISPLAY              | 表明该内存用于 Display 相关模块，不影响内存分配，用于 debug 信息               |
| HB_MEM_USAGE_HW_VIDEO_CODEC          | 表明该内存用于 Video Codec 相关模块，不影响内存分配，用于 debug 信息           |
| HB_MEM_USAGE_HW_JPEG_CODEC           | 表明该内存用于 JPEG Codec 相关模块，不影响内存分配，用于 debug 信息            |
| HB_MEM_USAGE_HW_VDSP                 | 表明该内存用于 VDSP 相关模块，不影响内存分配，用于 debug 信息                  |
| HB_MEM_USAGE_HW_IPC                  | 表明该内存用于 IPC 相关模块，不影响内存分配，用于 debug 信息                   |
| HB_MEM_USAGE_HW_PCIE                 | 表明该内存用于 PCIe 相关模块，不影响内存分配，用于 debug 信息                  |
| HB_MEM_USAGE_HW_YNR                  | 表明该内存用于 YNR 相关模块，不影响内存分配，用于 debug 信息                   |
| HB_MEM_USAGE_HW_MASK                 | 用于获取硬件相关属性的掩码，该掩码下的属性互斥，从上到下优先级依次降低，当指定多个属性或非上述值时，默认指定为 "other" |
| HB_MEM_USAGE_MAP_INITIALIZED         | 需要初始化该内存，内存分配后被初始化为 0 ，当未指定 MAP_INITIALIZED 和 MAP_UNINITIALIZED 时， DMA heap 会被默认初始化， RESERVERD heap 不会被初始化。该属性和 HB_MEM_USAGE_MAP_UNINITIALIZED 互斥，且优先级较高 |
| HB_MEM_USAGE_MAP_UNINITIALIZED       | 不需要初始化该内存，内存分配后不被初始化为 0 ，该属性和 HB_MEM_USAGE_MAP_INITIALIZED 互斥，且优先级较低 |
| HB_MEM_USAGE_CACHED                  | 表明该块 buffer 具有 cache 属性                                               |
| HB_MEM_USAGE_GRAPHIC_CONTIGUOUS_BUF  | 指定 graphic buffer 分配连续的物理内存                                        |
| HB_MEM_USAGE_MEM_POOL                | 用于表明该 buffer 用于 memory pool，用户分配 buffer 时无需指定该参数，即使指定该参数，内部默认忽略 |
| HB_MEM_USAGE_MEM_SHARE_POOL          | 用于表明该 buffer 用于 memory share pool，用户分配 buffer 时无需指定该参数，即使指定该参数，内部默认忽略 |
| HB_MEM_USAGE_TRIVIAL_MASK            | 用于获取杂项相关属性的掩码，该掩码下的属性，除了 HB_MEM_USAGE_MAP_INITIALIZED 和 HB_MEM_USAGE_MAP_UNINITIALIZED 互斥，其他可以并存 |
| HB_MEM_USAGE_PRIV_HEAP_DMA           | 指定从 DMA heap 分配内存                                                      |
| HB_MEM_USAGE_PRIV_HEAP_RESERVERD     | 指定从 Carveout heap 分配内存，第一个是原始定义（兼容客户已使用的枚举），第二个是最新定义，建议使用第二个 |
| HB_MEM_USAGE_PRIV_HEAP_2_RESERVERD   | 指定从 Carveout heap2 分配内存，第一个是原始定义（兼容客户已使用的枚举），第二个是最新定义，建议使用第二个 |
| HB_MEM_USAGE_PRIV_MASK               | 用于获取私有属性的掩码，该掩码下的属性互斥，从上到下优先级依次降低，当指定多个属性时，默认选用高优属性，当指定为非上述值时，默认从 DMA heap 分配 buffer |


<span id="hbmem_alloc_format"/> </sapn>

### hbmem 图像格式

| 数据项              | 描述                                                                                |
|---------------------|-------------------------------------------------------------------------------------|
| MEM_PIX_FMT_NONE    | 无效格式                                                                            |
| MEM_PIX_FMT_RGB565  | packed RGB 5:6:5, 16bpp                                                             |
| MEM_PIX_FMT_RGB24   | packed RGB 8:8:8, 24bpp                                                             |
| MEM_PIX_FMT_BGR24   | packed RGB 8:8:8, 24bpp                                                             |
| MEM_PIX_FMT_ARGB    | packed ARGB 8:8:8:8, 32bpp                                                          |
| MEM_PIX_FMT_RGBA    | packed RGBA 8:8:8:8, 32bpp                                                          |
| MEM_PIX_FMT_ABGR    | packed ABGR 8:8:8:8, 32bpp                                                          |
| MEM_PIX_FMT_BGRA    | packed BGRA 8:8:8:8                                                                 |
| MEM_PIX_FMT_YUV420P | planar YUV 4:2:0, 12bpp (1 Cr & Cb sample per 2x2 Y samples)                        |
| MEM_PIX_FMT_NV12    | planar YUV 4:2:0, 12bpp (1 plane for Y and 1 plane for the UV component)            |
| MEM_PIX_FMT_NV21    | planar YUV 4:2:0, 12bpp (1 plane for Y and 1 plane for the VU component)            |
| MEM_PIX_FMT_YUV422P | planar YUV 4:2:2, 16bpp (1 Cr & Cb sample per 2x1 Y samples)                        |
| MEM_PIX_FMT_NV16    | planar YUV 4:2:2, 16bpp (interleaved chroma (first byte U and the following byte V)) |
| MEM_PIX_FMT_NV61    | planar YUV 4:2:2, 16bpp (interleaved chroma (first byte V and the following byte U)) |
| MEM_PIX_FMT_YUYV422 | packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr                                                |
| MEM_PIX_FMT_YVYU422 | packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb                                                |
| MEM_PIX_FMT_UYVY422 | packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1                                                |
| MEM_PIX_FMT_VYUY422 | packed YUV 4:2:2, 16bpp, Cr Y0 Cb Y1                                                |
| MEM_PIX_FMT_YUV444  | packed YUV 4:4:4, 24bpp                                                             |
| MEM_PIX_FMT_YUV444P | planar YUV 4:4:4, 24bpp                                                             |
| MEM_PIX_FMT_NV24    | YUV 4:4:4, 24bpp (interleaved chroma (first byte U and the following byte V))        |
| MEM_PIX_FMT_NV42    | YUV 4:4:4, 24bpp (interleaved chroma (first byte V and the following byte U))        |
| MEM_PIX_FMT_YUV440P | planar YUV 4:4:0                                                                    |
| MEM_PIX_FMT_YUV400  | Gray Y, YUV 4:0:0                                                                   |
| MEM_PIX_FMT_RAW8    | raw8 format                                                                         |
| MEM_PIX_FMT_RAW10   | raw10 format                                                                        |
| MEM_PIX_FMT_RAW12   | raw12 format                                                                        |
| MEM_PIX_FMT_RAW14   | raw14 format                                                                        |
| MEM_PIX_FMT_RAW16   | raw16 format                                                                        |
| MEM_PIX_FMT_RAW20   | raw20 format                                                                        |
| MEM_PIX_FMT_RAW24   | raw24 format                                                                        |
| MEM_PIX_FMT_TOTAL   | total format count                                                                  |

## hbmem 返回值

错误码信息参考。

| **错误码**    | **宏定义**                          | **描述**                                |
|---------------|-------------------------------------|-----------------------------------------|
| 0xFF000001    | HB_MEM_ERR_UNKNOWN                 | 未知的错误                              |
| 0xFF000002    | HB_MEM_ERR_INVALID_PARAMS          | 无效参数                                |
| 0xFF000003    | HB_MEM_ERR_INVALID_FD              | 无效 fd                                 |
| 0xFF000004    | HB_MEM_ERR_INVALID_VADDR           | 无效虚拟地址                            |
| 0xFF000005    | HB_MEM_ERR_INSUFFICIENT_MEM        | 内存资源不足                            |
| 0xFF000006    | HB_MEM_ERR_TOO_MANY_FD             | 文件句柄打开超过上限                    |
| 0xFF000007    | HB_MEM_ERR_TIMEOUT                 | 超时                                    |
| 0xFF000008    | HB_MEM_ERR_MODULE_NOT_FOUND        | 内存模块未打开                          |
| 0xFF000009    | HB_MEM_ERR_MODULE_OPEN_FAIL        | 内存模块打开失败                        |
| 0xFF00000A    | HB_MEM_ERR_QUEUE_NOT_FOUND         | 内存队列未创建                          |
| 0xFF00000B    | HB_MEM_ERR_QUEUE_DESTROYED         | 内存队列已销毁                          |
| 0xFF00000C    | HB_MEM_ERR_QUEUE_WRONG_SLOT        | 错误的内存队列索引                      |
| 0xFF00000D    | HB_MEM_ERR_QUEUE_NO_AVAILABLE_SLOT | 无法获得可用的内存队列索引              |
| 0xFF00000E    | HB_MEM_ERR_QUEUE_ALREADY_EXIST     | 内存队列已经创建                        |
| 0xFF00000F    | HB_MEM_ERR_POOL_NOT_FOUND          | 内存池未打开                            |
| 0xFF000010    | HB_MEM_ERR_POOL_DESTROYED          | 内存池已销毁                            |
| 0xFF000011    | HB_MEM_ERR_POOL_BUSY               | 内存池中仍有 buffer 未释放               |
| 0xFF000012    | HB_MEM_ERR_WAIT_SHARE_FAILURE      | 等待 share client 状态失败              |
| 0xFF000013    | HB_MEM_ERR_NOT_ALLOW               | 该操作不允许                            |
| 0xFF000014    | HB_MEM_ERR_CHECK_VER_FAIL          | 版本检查失败                            |
| 0xFF000015    | HB_MEM_ERR_REGISTER_FAIL           | register graphic buffer group 失败      |
| 0xFF000016    | HB_MEM_ERR_INVALID_GROUPID         | 无效的 group ID                         |
