> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# qtibatch

> GStreamer 缓冲区批处理元素

# 概述

`qtibatch` 是一个 GStreamer 元素，它将多个视频或音频缓冲区聚合为单个批处理缓冲区，供下游处理使用。它适用于下游元素在分组输入上比在单个缓冲区上运行更高效的多媒体和 AI 流水线。

该元素支持两种批处理模式：

* **多流批处理**——合并来自多个并行流的同时到达的缓冲区
* **顺序批处理**——合并来自单个流的连续缓冲区

这使得 `qtibatch` 既适用于并行多流工作负载，也适用于需要将多个连续帧或采样作为单个输入单元的时序工作流。

批处理通常用于：

* 提高硬件利用率
* 提升下游推理或分析阶段的吞吐量
* 支持需要批量输入的模型
* 从连续帧构建时序或深度维度的输入张量
* 创建重叠批次以进行滑动窗口式处理

典型用例包括：

* **多流视频批处理**——将来自多个视频源的帧聚合为单个批次进行并行处理
* **多流音频批处理**——将来自多个源的音频缓冲区聚合为单个批次进行并行处理
* **深度批处理**——将来自同一流的连续帧分组，以创建具有额外时间或深度维度的张量
* **重叠批次构建**——为时序模型或基于窗口的分析构建相邻批次之间共享帧的批次

<Note>
  `qtibatch` 仅执行缓冲区聚合。它不会修改视频像素或音频采样，也不执行推理、预处理或后处理。它的唯一职责是将多个输入缓冲区打包为单个逻辑批次，以便下游高效消费。
</Note>

<img src="https://mintlify.s3.us-west-1.amazonaws.com/qualcomm-prod/zh/SDKs/IMSDK/plugin-reference/images/qtibatch_pipeline.png" alt="qtibatch 流水线" />

# 层次结构

[GObject](https://docs.gtk.org/gobject/)<br />
   <Icon icon="arrow-turn-down-right" iconType="solid" />[GstObject](https://gstreamer.freedesktop.org/documentation/gstreamer/gstobject.html?gi-language=c)<br />
      <Icon icon="arrow-turn-down-right" iconType="solid" />[GstElement](https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c)<br />
         <Icon icon="arrow-turn-down-right" iconType="solid" />qtibatch

# Pad 模板

### sink

| 能力               |                   |
| ---------------- | ----------------- |
| `video/x-raw`    | `format: { ANY }` |
| `audio/x-raw`    | `format: { ANY }` |
| 可用性：*按请求*        |                   |
| 方向：*sink*        |                   |
| Pad 名称：`sink_%u` |                   |

### src

| 能力            |                                                  |
| ------------- | ------------------------------------------------ |
| `video/x-raw` | `format: { ANY }` <br /> `note: batched buffers` |
| `audio/x-raw` | `format: { ANY }` <br /> `note: batched buffers` |
| 可用性：*始终*      |                                                  |
| 方向：*source*   |                                                  |

# 元素属性

| 属性                   | 描述                                                                                                                                                        |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `moving-window-size` | 用于输出帧的新缓冲区数量。<br /><br />`Type: Unsigned Integer`<br />`Default: 1`<br />`Range: 1 - 16`<br />`Flags: readable/writable (changeable only in NULL, READY)` |

# 内部架构详情

`qtibatch` 由三个功能组件构成：

## Sink Pad

`qtibatch` 支持单个 sink pad 或多个 sink pad，具体取决于批处理模式：

* **单个 sink pad** 用于对来自同一流的连续缓冲区进行顺序批处理
* **多个 sink pad** 用于对来自多个输入流的缓冲区进行并行批处理

每个 sink pad 从上游元素接收单独的视频或音频缓冲区。

## 聚合逻辑

聚合逻辑收集传入的缓冲区，跟踪它们的到达状态，并确定批次何时可以生成。批次的形成由协商好的批处理配置和当前批处理模式驱动。

## Source Pad

单个 source pad 发出批处理后的输出缓冲区。输出缓冲区携带对聚合的输入缓冲区的引用，以及描述批次内容的批次元数据。

## 处理流程

### Caps 协商

在 caps 协商期间，`qtibatch` 会验证所有 sink pad 使用兼容的媒体（音频或视频）类型和格式。它还会推导出有效的批处理配置，包括批次大小以及下游处理所需的预期输入/输出张量或媒体特性。

### 缓冲区接收

传入的视频或音频缓冲区在 sink pad 上异步接收，并按 pad 分别在内部排队。

### 同步

`qtibatch` 根据所选的批处理模式同步缓冲区：

* 对于**并行流**，元素等待所有活动 sink pad 上对应同一时间间隔的缓冲区
* 对于**单个流**，元素等待来自同一输入流的所需数量的连续缓冲区

对于并行批处理，如果某个 pad 上的缓冲区未在预期的时间窗口内到达，则该 pad 在当前批次中被视为缺失。对于单流批处理，不应用基于超时的跳过机制。

### 批次形成

缓冲区根据所选的批处理策略分组为批次：

* 来自单个流的连续缓冲区
* 来自多个流的时间对齐的缓冲区

生成的批次保留缓冲区的顺序，并在适用时保持跨输入的时间对齐。

### 元数据附加

`qtibatch` 将批次元数据附加到输出缓冲区。该元数据描述：

* 有效批次大小
* 聚合缓冲区的排序
* 并行流模式下缺失的任何输入

### 输出交付

批次完成后，批处理缓冲区被推送到下游进行进一步处理。

# 批处理行为

`qtibatch` 中的批次形成由协商好的批次大小和当前批处理模式共同决定。

传入的缓冲区始终按 pad 分别在内部排队。批次完成逻辑取决于元素是聚合来自单个流还是来自多个并行流的缓冲区。

## 顺序批处理（单流）

在顺序模式下，`qtibatch` 聚合来自单个输入流的连续缓冲区，直到达到配置的批次大小。批次的形成基于计数。

该模式支持由 `moving-window-size` 属性控制的移动窗口机制：

* 值为 **0** 时生成不重叠的批次
* 值**大于 0** 时生成重叠的批次，在下一个批次中复用上一个批次中指定数量的缓冲区

此行为对于时序推理工作负载（例如动作识别或基于序列的模型）非常有用，因为相邻批次之间的连续性很重要。

顺序批处理严格由缓冲区计数驱动，不使用基于超时的 GAP 插入。

## 并行批处理（多流）

在并行模式下，`qtibatch` 聚合来自多个 sink pad 的缓冲区。目标是从所有输入流中属于同一时间间隔的缓冲区形成批次。

如果在预期的同步窗口内某个 sink pad 上未收到缓冲区，则该输入在当前批次中被视为缺失。在这种情况下，批次元数据会记录缺失的输入，以便下游元素能够正确解读批次——这是通过插入 GAP 缓冲区来实现的。

同步窗口和超时行为由缓冲区持续时间推导得出，缓冲区持续时间根据协商好的输入帧率或音频时序信息计算。

# 内存与缓冲区管理

`qtibatch` 旨在集成到高性能和零拷贝的多媒体流水线中。

## 缓冲区处理

`qtibatch` 在构建批次时不复制媒体载荷。批处理后的输出缓冲区持有的是对原始输入缓冲区的引用。

## 分配与缓冲池行为

`qtibatch` 不需要自定义分配器、特定内存类型或专用缓冲池。缓冲区分配和内存布局仍由上游和下游元素控制。

这种设计使 `qtibatch` 可以适应各种流水线拓扑，而不会施加额外的内存管理约束。

# 用法

### 使用合成器的四源批处理目标检测

对 4 个源进行批处理的演示流水线。运行检测推理，并通过合成器将结果叠加显示在屏幕上。

<img src="https://mintlify.s3.us-west-1.amazonaws.com/qualcomm-prod/zh/SDKs/IMSDK/plugin-reference/images/use3.png" alt="use" />

<Steps>
  <Step title="下载所需文件">
    | 文件                        | 下载                                                                                                                            | 保存为                              |
    | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
    | Yolov8 检测 W8A8 Batch 4 模型 | [从 Qualcomm AI Hub 导出](https://github.com/qualcomm/ai-hub-models/blob/v0.55.0/src/qai_hub_models/models/yolov8_det/README.md) | `yolov8_det_w8a8_batch_4.tflite` |
    | 检测标签                      | <a href="/SDKs/IMSDK/labels/yolov8.json" download="yolov8.json">yolov8.json</a>                                               | `yolov8.json`                    |
    | 示例视频                      | <a href="https://github.com/qualcomm/sample-apps-for-qualcomm-linux/raw/refs/heads/main/artifacts/videos/video.mp4">输入视频</a>  | `Draw_1080p_180s_30FPS.mp4`      |
  </Step>

  <Step title="将文件复制到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      # Replace $HOME to the appropriate device path before running the commands.
      # For QLI:    /root
      # For Ubuntu: /home/ubuntu
      # Modify this based on your platform and ensure files are copied to the correct location on the device.
      # Run from your host machine — replace <user> and <device-ip>

      ssh <user>@<device-ip> "mkdir -p $HOME/{models,labels,media,media/output}"
      scp yolov8_det_w8a8_batch_4.tflite        <user>@<device-ip>:$HOME/models/
      scp yolov8.json                           <user>@<device-ip>:$HOME/labels/
      scp Draw_1080p_180s_30FPS.mp4             <user>@<device-ip>:$HOME/media/
      ```
    </CodeGroup>
  </Step>

  <Step title="连接到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      # Run from your host machine — replace <user> and <device-ip>
      ssh <user>@<device-ip>
      ```
    </CodeGroup>
  </Step>

  <Step title="设置环境变量">
    在设备上运行以下命令

    ```bash theme={null}
    export MODEL_NAME=yolov8_det_w8a8_batch_4.tflite
    export LABELS_NAME=yolov8.json
    export SRC_VIDEO_NAME_1=Draw_1080p_180s_30FPS.mp4
    export SRC_VIDEO_NAME_2=Draw_1080p_180s_30FPS.mp4
    export SRC_VIDEO_NAME_3=Draw_1080p_180s_30FPS.mp4
    export SRC_VIDEO_NAME_4=Draw_1080p_180s_30FPS.mp4
    ```
  </Step>

  <Step title="运行流水线">
    ```bash Run the pipeline theme={null}
    gst-launch-1.0 -e --gst-debug=2 \
    qtimltflite name=inference delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp,htp_performance_mode=(string)2;" model=$HOME/models/$MODEL_NAME \
    filesrc location=$HOME/media/$SRC_VIDEO_NAME_1 ! qtdemux ! queue ! h264parse ! v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw ! qtivtransform ! video/x-raw,format=NV12,width=640,height=360 ! queue ! tee name=tee_0 \
    filesrc location=$HOME/media/$SRC_VIDEO_NAME_2 ! qtdemux ! queue ! h264parse ! v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw ! qtivtransform ! video/x-raw,format=NV12,width=640,height=360 ! queue ! tee name=tee_1 \
    filesrc location=$HOME/media/$SRC_VIDEO_NAME_3 ! qtdemux ! queue ! h264parse ! v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw ! qtivtransform ! video/x-raw,format=NV12,width=640,height=360 ! queue ! tee name=tee_2 \
    filesrc location=$HOME/media/$SRC_VIDEO_NAME_4 ! qtdemux ! queue ! h264parse ! v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw ! qtivtransform ! video/x-raw,format=NV12,width=640,height=360 ! queue ! tee name=tee_3 \
    tee_0. ! video/x-raw,format=NV12 ! mixer. \
    tee_0. ! video/x-raw,format=NV12 ! batch. \
    tee_1. ! video/x-raw,format=NV12 ! mixer. \
    tee_1. ! video/x-raw,format=NV12 ! batch. \
    tee_2. ! video/x-raw,format=NV12 ! mixer. \
    tee_2. ! video/x-raw,format=NV12 ! batch. \
    tee_3. ! video/x-raw,format=NV12 ! mixer. \
    tee_3. ! video/x-raw,format=NV12 ! batch. \
    qtibatch name=batch ! queue ! qtimlvconverter ! queue ! inference. inference. ! queue ! qtimldemux name=mldemux \
    mldemux. ! queue ! qtimlpostprocess results=10 module=yolov8 labels=$HOME/labels/$LABELS_NAME settings="{\"confidence\": 70.0}" ! video/x-raw,width=640,height=360 ! queue ! mixer. \
    mldemux. ! queue ! qtimlpostprocess results=10 module=yolov8 labels=$HOME/labels/$LABELS_NAME settings="{\"confidence\": 70.0}" ! video/x-raw,width=640,height=360 ! queue ! mixer. \
    mldemux. ! queue ! qtimlpostprocess results=10 module=yolov8 labels=$HOME/labels/$LABELS_NAME settings="{\"confidence\": 70.0}" ! video/x-raw,width=640,height=360 ! queue ! mixer. \
    mldemux. ! queue ! qtimlpostprocess results=10 module=yolov8 labels=$HOME/labels/$LABELS_NAME settings="{\"confidence\": 70.0}" ! video/x-raw,width=640,height=360 ! queue ! mixer. \
    qtivcomposer name=mixer \
    sink_0::position="<0, 0>" sink_0::dimensions="<960, 540>" \
    sink_1::position="<960,  0>" sink_1::dimensions="<960, 540>" \
    sink_2::position="<0, 540>" sink_2::dimensions="<960, 540>" \
    sink_3::position="<960, 540>" sink_3::dimensions="<960, 540>" \
    sink_4::position="<0, 0>" sink_4::dimensions="<960, 540>" \
    sink_5::position="<960, 0>" sink_5::dimensions="<960, 540>" \
    sink_6::position="<0, 540>" sink_6::dimensions="<960, 540>" \
    sink_7::position="<960, 540>" sink_7::dimensions="<960, 540>" \
    mixer. ! video/x-raw,format=NV12 ! queue ! waylandsink sync=false fullscreen=true
    ```
  </Step>
</Steps>
