# VENC 模块接口文档

## VENC 概述

`VENC`（Video Encoder）模块是对 K230 硬件视频编码器的封装，提供了 H.264、H.265 和 JPEG 视频编码功能。

**主要特性：**

- 编码格式支持：兼容H.264、H.265及JPEG编码标准，可对原始数据进行高效编码处理。
- 全生命周期管理：提供从编码器实例创建、启动编码任务、执行编码操作，到停止任务及销毁实例的完整生命周期管理，确保编码过程全程可控。
- 多路并发编码：支持多通道并行编码，最大可同时运行4路编码通道，满足多源数据编码需求。
- 灵活参数配置：支持对编码核心参数进行自定义配置，包括分辨率、码率、帧率、GOP（图像组）等，适配不同场景下的编码质量与性能要求。
- 线程安全保障：编码流处理采用线程安全设计，确保多线程环境下数据交互的安全性与稳定性，避免并发操作引发的冲突问题。

**API 接口调用顺序：**

1. 创建编码器实例：`VideoEncoder(config)`（构造函数）
2. 初始化编码器：`create()`
3. 启动编码器：`start()`
4. 循环编码过程：
   - 发送原始帧：`send_frame()`
   - 获取编码流：`get_stream()`
   - 处理编码流后释放：`release_stream()`
5. 停止编码：`stop()`
6. 销毁编码器：`destroy()`（析构函数会自动调用）

## VENC 类定义

### 编码器类型枚举

```cpp
enum EncoderType {
    VENC_UNKNOWN, ///< 未知/不支持的编码类型
    VENC_H264,   ///< H.264 / AVC (Advanced Video Coding) 标准
    VENC_H265,   ///< H.265 / HEVC (High Efficiency Video Coding) 标准
    VENC_JPEG    ///< JPEG (Joint Photographic Experts Group) 图像压缩标准
};
```

### 编码数据包结构

```cpp
struct EncodedPacket {
    void* data;             ///< 编码数据缓冲区指针（虚拟地址）
    uint64_t phys_addr;     ///< 编码数据的物理地址
    uint32_t size;          ///< 编码数据的大小（字节）
    k_venc_pack_type type;  ///< 编码包类型（参考 k_venc_comm.h）
    uint64_t pts;           ///< 显示时间戳（微秒）
};
```

### 编码流结构

```cpp
typedef struct tag_EncodedStream {
    std::vector<EncodedPacket> packets;  ///< 编码包数组
    uint32_t packet_count;               ///< 编码包数量
} EncodedStream;
```

### 编码器配置结构

```cpp
struct EncoderConfig {
    EncoderType type;               ///< 目标编码标准（H264/H265/JPEG）
    k_venc_profile profile;         ///< 编码配置文件（参考 k_venc_comm.h）
    uint32_t width;                 ///< 输出视频流的宽度（像素）
    uint32_t height;                ///< 输出视频流的高度（像素）
    uint32_t bitrate;               ///< 目标码率（kbps，千比特每秒）
    uint32_t gop;                   ///< 图像组大小（I 帧之间的帧数）
    uint32_t src_fps;               ///< 输入源的帧率（帧每秒）
    uint32_t dst_fps;               ///< 编码输出的目标帧率
    uint32_t jpeg_quality;          ///< JPEG 编码质量级别（0-100，越高质量越好）
    uint32_t output_buffers;        ///< 视频编码缓冲池数量

    // 构造函数
    EncoderConfig(EncoderType enc_type, k_venc_profile prof, uint32_t w, uint32_t h,
                  uint32_t buf_num = 4, uint32_t br = 2048, uint32_t g = 30,
                  uint32_t sfps = 30, uint32_t dfps = 30,
                  uint32_t jq = 45);
};
```

### VideoEncoder 类

```cpp
class VideoEncoder {
public:
    VideoEncoder(const EncoderConfig& config);
    ~VideoEncoder();

    int create();
    int start();
    int send_frame(k_video_frame_info* frame, int timeout = 1000);
    int get_stream(EncodedStream& stream, int timeout = 1000);
    int release_stream(EncodedStream& stream);
    int stop();
    int destroy();
    int get_channel_id() const { return channel_id_; }

private:
    // 私有成员和方法...
};
```

## VENC 接口说明

### VideoEncoder 构造函数

```cpp
VideoEncoder(const EncoderConfig& config);
```

**功能：**
使用指定的编码配置创建视频编码器实例。

**参数说明：**

| 参数名    | 类型              | 描述           |
| ------ | --------------- | ------------ |
| config | `EncoderConfig` | 编码器配置参数     |

EncoderConfig 各参数详细说明：

| 参数名           | 类型              | 描述                                                         |
| ---------------- | ----------------- | ------------------------------------------------------------ |
| `type`           | `EncoderType`     | 目标编码标准，枚举值包括：<br>- `VENC_UNKNOWN`：未知或不支持的编码类型<br>- `VENC_H264`：H.264/AVC标准<br>- `VENC_H265`：H.265/HEVC标准<br>- `VENC_JPEG`：JPEG图像压缩标准<br>用于指定编码器输出的视频格式。 |
| `profile`        | `k_venc_profile`  | 编码配置文件，参考 `k_venc_comm.h` 定义，用于指定编码的复杂度和功能集（如H.264的Baseline、Main、High等）。 |
| `width`          | `uint32_t`        | 输出视频流的宽度（像素），决定编码后视频的水平分辨率。         |
| `height`         | `uint32_t`        | 输出视频流的高度（像素），决定编码后视频的垂直分辨率。         |
| `bitrate`        | `uint32_t`        | 目标码率（kbps，千比特每秒），控制编码后视频的质量和文件大小，默认值为2048。 |
| `gop`            | `uint32_t`        | 图像组大小（I帧之间的帧数），影响视频的随机访问能力和压缩效率，默认值为30。 |
| `src_fps`        | `uint32_t`        | 输入源的帧率（帧每秒），表示编码器输入原始视频的帧率，默认值为30。 |
| `dst_fps`        | `uint32_t`        | 编码输出的目标帧率，控制编码后视频的播放速度，默认值为30。     |
| `jpeg_quality`   | `uint32_t`        | JPEG编码质量级别（0-100），值越高质量越好，仅在`type`为`VENC_JPEG`时有效，默认值为45。 |
| `output_buffers` | `uint32_t`        | 视频编码缓冲区数量，用于缓存编码后的流数据，默认值为4。  |

**注意：**
构造函数仅初始化对象，需要调用 `create()` 方法才能真正创建编码器。

### VideoEncoder 析构函数

```cpp
~VideoEncoder();
```

**功能：**
销毁视频编码器实例，自动释放所有分配的资源。

**注意：**
析构函数会自动调用 `destroy()` 方法，确保资源正确释放。

### 创建编码器

```cpp
int create();
```

**功能：**
创建并初始化编码器实例。分配必要的资源并设置编码参数。

**返回值：**

* `0` - 成功
* `-1` - 失败（编码器已创建或硬件资源不足）

**使用示例：**
```cpp
EncoderConfig config(VENC_H264, VENC_PROFILE_H264_MAIN, 1920, 1080);
VideoEncoder encoder(config);
if (encoder.create() != 0) {
    std::cout << "Failed to create encoder" << std::endl;
    return -1;
}
```

### 启动编码器

```cpp
int start();
```

**功能：**
启动编码器操作，使编码器进入准备处理输入帧的活动状态。

**返回值：**

* `0` - 成功
* `-1` - 失败（编码器未创建或启动失败）

**使用示例：**
```cpp
if (encoder.start() != 0) {
    std::cout << "Failed to start encoder" << std::endl;
    encoder.destroy();
    return -1;
}
```

### 发送视频帧

```cpp
int send_frame(k_video_frame_info* frame, int timeout = 1000);
```

**功能：**
将原始视频帧发送到编码器进行处理。

**参数说明：**

| 参数名     | 类型                  | 描述                          |
| ------- | ------------------- | --------------------------- |
| frame   | `k_video_frame_info*` | 原始视频帧信息指针                  |
| timeout | `int`               | 帧提交的最大等待时间（毫秒，默认 1000） |

k_video_frame_info 主要成员详细说明：

| 结构体         | 成员名称               | 类型                  | 描述                                                                 |
|----------------|------------------------|-----------------------|----------------------------------------------------------------------|
| `k_video_frame_info` | `v_frame`            | `k_video_frame`       | 视频图像帧，包含当前帧的详细图像信息（如下述 `k_video_frame` 结构体内容）。 |
|                | `pool_id`              | `k_u32`               | 视频缓存池 ID，标识当前帧数据所在的视频缓存池，用于管理缓存资源的分配与释放。         |
|                | `mod_id`               | `k_mod_id`            | 生成视频帧的硬件逻辑模块标识，指示当前帧数据是由哪个硬件逻辑单元输出的。               |
| `k_video_frame` | `width`                | `k_u32`               | 图像宽度（像素），表示视频帧的水平像素数量。                         |
|                | `height`               | `k_u32`               | 图像高度（像素），表示视频帧的垂直像素数量。                         |
|                | `field`                | `k_video_field`       | 帧场模式，指示视频帧的场结构（如逐行、隔行等）。                     |
|                | `pixel_format`         | `k_pixel_format`      | 视频图像像素格式，定义像素的编码方式（如 YUV420、RGB 等）。          |
|                | `video_format`         | `k_video_format`      | 视频图像格式，描述视频的整体格式属性。                               |
|                | `dynamic_range`        | `k_dynamic_range`     | 动态范围，指示视频帧的亮度动态范围（如 SDR、HDR 等）。                |
|                | `compress_mode`        | `k_compress_mode`     | 视频压缩模式，说明图像数据的压缩方式。                               |
|                | `color_gamut`          | `k_color_gamut`       | 色域范围，定义视频帧的色彩空间范围（如 BT.601、BT.709 等）。          |
|                | `header_stride`        | `k_u32`               | 图像压缩头跨距，压缩头数据每行的字节数。                             |
|                | `stride`               | `k_u32`               | 图像数据跨距，图像数据每行实际占用的字节数（可能包含内存对齐部分）。 |
|                | `header_phys_addr`     | `k_u64`               | 压缩头物理地址，图像压缩头数据在物理内存中的地址。                   |
|                | `header_virt_addr`     | `k_u64`               | 压缩头虚拟地址（内核态），内核空间可访问的压缩头数据虚拟地址。       |
|                | `phys_addr`            | `k_u64`               | 图像数据物理地址，图像像素数据在物理内存中的地址。                   |
|                | `virt_addr`            | `k_u64`               | 图像数据虚拟地址（内核态），内核空间可访问的图像像素数据虚拟地址。   |
|                | `offset_top`           | `k_s16`               | 图像顶部剪裁宽度，视频帧顶部需要裁剪的像素数量。                     |
|                | `offset_bottom`        | `k_s16`               | 图像底部剪裁宽度，视频帧底部需要裁剪的像素数量。                     |
|                | `offset_left`          | `k_s16`               | 图像左侧裁剪宽度，视频帧左侧需要裁剪的像素数量。                     |
|                | `offset_right`         | `k_s16`               | 图像右侧裁剪宽度，视频帧右侧需要裁剪的像素数量。                     |
|                | `time_ref`             | `k_u32`               | 图像帧序列号，用于标识视频帧的顺序。                                 |
|                | `pts`                  | `k_u64`               | 图像时间戳，用于音视频同步的 Presentation Time Stamp。               |
|                | `priv_data`            | `k_u64`               | 私有数据，供内部或扩展使用的额外数据。                               |
|                | `supplement`           | `k_video_supplement`  | 图像的补充信息，包含图像的额外辅助数据。                             |

**返回值：**

* `0` - 成功
* `-1` - 失败（编码器未启动或超时）

**使用示例：**
```cpp
k_video_frame_info frame_info;
// 填充 frame_info...
if (encoder.send_frame(&frame_info, 100) != 0) {
    std::cout << "Failed to send frame to encoder" << std::endl;
}
```

### 获取编码流

```cpp
int get_stream(EncodedStream& stream, int timeout = 1000);
```

**功能：**
从编码器检索编码后的流数据。

**参数说明：**

| 参数名     | 类型              | 描述                          |
| ------- | --------------- | --------------------------- |
| stream  | `EncodedStream&` | 输出参数，用于存储编码流数据            |
| timeout | `int`           | 等待可用流数据的最大时间（毫秒，默认 1000） |

EncodedStream 及包含的 EncodedPacket 成员详细说明：

| 结构体           | 成员名称       | 类型                  | 描述                                                         |
|------------------|----------------|-----------------------|--------------------------------------------------------------|
| `EncodedStream`  | `packets`      | `std::vector<EncodedPacket>` | 编码包数组，存储一帧或多帧编码数据                 |
|                  | `packet_count` | `uint32_t`            | 编码包数量，即 `packets` 数组的元素个数                       |
| `EncodedPacket`  | `data`         | `void*`               | 编码数据缓冲区指针（虚拟地址），指向编码后的数据内容           |
|                  | `phys_addr`    | `uint64_t`            | 编码数据的物理地址                 |
|                  | `size`         | `uint32_t`            | 编码数据的大小（字节），表示当前编码包的数据长度               |
|                  | `type`         | `k_venc_pack_type`    | 编码包类型：如I帧、P帧、SPS、PPS等    |
|                  | `pts`          | `uint64_t`            | 显示时间戳（微秒）                          |

**返回值：**

* `0` - 成功
* `-1` - 失败（编码器未启动或超时）

**使用示例：**
```cpp
EncodedStream stream;
if (encoder.get_stream(stream, 100) == 0) {
    for (uint32_t i = 0; i < stream.packet_count; i++) {
        printf("Got stream packet: size=%d, type=%d\n",
               stream.packets[i].size, stream.packets[i].type);
    }
}
```

### 释放编码流

```cpp
int release_stream(EncodedStream& stream);
```

**功能：**
将编码流缓冲区释放回编码器。必须在处理完流数据后调用以避免内存泄漏。

**参数说明：**

| 参数名   | 类型              | 描述         |
| ----- | --------------- | ---------- |
| stream | `EncodedStream&` | 要释放的编码流 |

**返回值：**

* `0` - 成功
* `-1` - 失败（编码器未启动）

**使用示例：**
```cpp
EncodedStream stream;
if (encoder.get_stream(stream, 100) == 0) {
    // 处理流数据...
    encoder.release_stream(stream);  // 处理完成后释放
}
```

### 停止编码器

```cpp
int stop();
```

**功能：**
停止编码器操作。暂停编码处理同时保留分配的资源。

**返回值：**

* `0` - 成功
* `-1` - 失败（编码器未启动）

**使用示例：**
```cpp
encoder.stop();  // 暂停编码
// ... 后续可以重新调用 start() 恢复编码
```

### 销毁编码器

```cpp
int destroy();
```

**功能：**
销毁编码器实例，释放所有分配的资源并清理编码器。

**返回值：**

* `0` - 成功
* `-1` - 失败（编码器已销毁）

**使用示例：**
```cpp
encoder.stop();
encoder.destroy();  // 完全释放资源
```

### 获取编码器通道ID

```cpp
int get_channel_id() const { return channel_id_; }
```

**功能：**
获取编码器的通道标识符。这个ID在编码器创建后由系统分配，用于标识唯一的编码通道。

**返回值：**

* 成功：返回编码器的通道ID（非负整数）
* 失败：返回 `K_INVALID_CHANNEL`（-1U），表示无效通道

**使用示例：**
```cpp
EncoderConfig config(VENC_H264, VENC_PROFILE_H264_MAIN, 1920, 1080);
VideoEncoder encoder(config);

if (encoder.create() == 0) {
    int channel_id = encoder.get_channel_id();
    std::cout << "Encoder created successfully, channel ID: " << channel_id << std::endl;
}
```

## 使用示例

### 摄像头视频编码示例

```cpp
#include <k230_sensor.h>
#include <k230_venc.h>

Sensor *sensor = nullptr;
VideoEncoder *venc = nullptr;

void setup() {
    int width = 1920;
    int height = 1080;

    // 初始化传感器
    sensor = new Sensor(2);
    sensor->reset();
    sensor->set_framesize(width, height, VICAP_CHN_ID_0);
    sensor->set_pixformat(SensorPixelFormat::YUV420SP);
    sensor->run();

    // 创建编码器
    EncoderConfig config(VENC_H264, VENC_PROFILE_H264_MAIN, width, height);
    venc = new VideoEncoder(config);
    venc->create();
    venc->start();
}

void loop() {
    k_video_frame_info vf_info;
    EncodedStream stream;

    if (sensor->snapshot(vf_info) == 0) {
        if (venc->send_frame(&vf_info, 10) == 0) {
            if (venc->get_stream(stream) == 0) {
                // 处理编码流数据
                for (int i = 0; i < stream.packet_count; i++) {
                    printf("Stream packet: size=%d, type=%d\n",
                           stream.packets[i].size, stream.packets[i].type);
                }
                venc->release_stream(stream);
            }
        }
    }
}
```

## 注意事项

1. **生命周期管理**：必须按照 `create() → start() → send_frame()/get_stream() -> stop() → destroy()` 的顺序调用接口

2. **帧释放**：每次成功调用 `get_stream()` 后必须调用 `release_stream()`，否则会导致内存泄漏。

3. **线程安全**：`send_frame()` 与 `get_stream()` 支持在不同线程中并发调用，且保证线程安全。需要注意的是，send_frame() 返回成功仅代表数据已成功提交给编码器，并不意味着对应帧已完成编码；编码后的结果需通过 get_stream() 另行获取，其获取时机与编码提交操作相互独立，无法通过 send_frame() 的返回状态预判。