> ## 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.

# qtimetamux

> AI 元数据同步与复用插件

# 概述

**qtimetamux** 元素是支持 AI 的 GStreamer 流水线的核心组件。它的作用是将后处理的 AI/CV 结果与原始媒体缓冲区同步，并使用 GStreamer 提供的标准元数据机制将这些结果作为 **GstMeta** 附加。

```mermaid theme={null}
flowchart LR
    A[Media Source] -->|main stream| B[qtimetamux]
    C[ML Post-processor] -->|data pad| B
    B --> D[Sink element]
```

在实践中，ML 后处理阶段生成的输出——例如：

* **边界框坐标**
* **类别标签**
* **分割掩码**
* **关键点**
* **运动矢量**
* **其他自定义 AI/CV 元数据**

都可以与相应的视频或音频帧关联，并作为单个统一的缓冲区在流水线中向前传递。

这种设计使构建推理结果与原始帧紧密耦合的流水线变得更加容易。下游组件可以同时消费媒体缓冲区及其元数据，而无需单独的同步逻辑。

通过将元数据直接嵌入到帧中，**qtimetamux** 支持几种常见的 AI 流水线模式：

* **实时可视化**——元数据可以被 [`qtivoverlay`](qtivoverlay) 等叠加元素消费，将边界框、标签和其他推理结果直接渲染到视频输出上。
* **级联 AI 流水线**——携带元数据的缓冲区可以传递给后续的推理阶段，实现一个模型的输出馈入下一个模型的多阶段 AI 工作流。
* **应用层访问**——生成的缓冲区可以发送到 `appsink`，使自定义应用程序能够访问媒体帧及其附加的元数据，用于业务逻辑或决策。
* **元数据序列化与外部集成**——元数据可以转发给 `qtimlmetaparser`，后者将其转换为 JSON。该 JSON 随后可以通过 [`qtiredissink`](qtiredissink) 发布到外部系统，例如 MQTT、Kafka 或 REDIS 服务器。

除了 AI 推理输出外，**qtimetamux** 还能够附加其他元数据类型，例如**运动矢量**，使其对 AI 和更广泛的基于计算机视觉的工作流都很有用。

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

## 示例流水线

<Steps>
  <Step title="下载所需文件">
    | 文件            | 下载                                                                                                                           | 保存为                         |
    | ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
    | YOLOX W8A8 模型 | [Qualcomm AI Hub — YOLOX](https://aihub.qualcomm.com/iot/models/yolox)                                                       | `yolo_x_w8a8.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 yolo_x_w8a8.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}
    mkdir -p $HOME/{models,labels,media,media/output}
    export MODEL_NAME=yolo_x_w8a8.tflite
    export LABELS_NAME=yolov8.json
    export SRC_VIDEO_NAME=Draw_1080p_180s_30FPS.mp4
    ```
  </Step>

  <Step title="运行流水线">
    ```bash theme={null}
    gst-launch-1.0 -e --gst-debug=2 \
    filesrc location=$HOME/media/$SRC_VIDEO_NAME ! qtdemux ! h264parse ! \
    v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw,format=NV12 ! queue ! \
    tee name=t ! qtimetamux name=obj_mux ! qtivoverlay ! waylandsink fullscreen=true sync=false \
    t. ! queue ! qtimlvconverter ! queue ! \
    qtimltflite model=$HOME/models/$MODEL_NAME delegate=external external-delegate-path=libQnnTFLiteDelegate.so \
      external-delegate-options="QNNExternalDelegate,backend_type=htp,log_level=(string)1;" ! queue ! \
    qtimlpostprocess module=yolov8 labels=$HOME/labels/$LABELS_NAME \
      settings="{\"confidence\": 51.0}" ! text/x-raw ! queue ! obj_mux.
    ```
  </Step>
</Steps>

# 层次结构

[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" />qtimetamux

# Pad 模板

### sink

| 能力                 |              |
| ------------------ | ------------ |
| `video/x-raw(ANY)` | `format: NA` |
| `audio/x-raw(ANY)` | `format: NA` |
| 可用性：*始终*           |              |
| 方向：*sink*          |              |
| Pad 名称：`sink`      |              |

| 能力                  |                |
| ------------------- | -------------- |
| `text/x-raw`        | `format: utf8` |
| `cv/x-optical-flow` | `format: NA`   |
| 可用性：*按请求*           |                |
| 方向：*sink*           |                |
| Pad 名称：`data_%u`    |                |

### src

| 能力                 |              |
| ------------------ | ------------ |
| `video/x-raw(ANY)` | `format: NA` |
| `audio/x-raw(ANY)` | `format: NA` |
| 可用性：*始终*           |              |
| 方向：*source*        |              |

# 元素属性

| 属性           | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `latency`    | 以纳秒为单位的附加延迟，为上游生成当前位置的元数据条目留出更多时间。在同步模式下，当元数据生成时间超过默认保持窗口时非常有用。<br /><br />`Type: Unsigned Integer64`<br />`Default: 0`<br />`Range: 0 - 18446744073709551615`<br />`Flags: readable/writable (changeable only in NULL or READY state)`                                                                                                                                                                                                                                                                                                                                                                                                            |
| `mode`       | 控制用于将元数据缓冲区与主媒体帧关联的同步策略。<br /><br />`Type: Enum `<br />`Default: 0, "async"`<br />`Range:`<br />    `(0): async - No timestamp synchronization. The N-th incoming media frame is held until the N-th data buffer has been received on all data pads. Suitable for fixed, predictable sequences`<br />    `(1): sync - Timestamp-based synchronization. Each incoming frame is held for up to 1 / framerate (video) or 1 / rate (audio). Metadata with matching timestamps is attached before the frame is forwarded downstream`<br />`Flags: readable/writable (changeable only in NULL or READY state)` <br /> `Example: mode="sync" (or) mode=1` |
| `queue-size` | 设置内部输入和输出队列的大小。<br /><br />`Type: Unsigned Integer`<br />`Default: 10`<br />`Range: 3 - 4294967295`<br />`Flags: readable/writable (changeable only in NULL or READY state)`                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |

## 主缓冲区、元数据同步与延迟控制

该插件设计有一个接收主视频或音频缓冲区的**单一主 sink pad**，以及多个收集 ML 后处理结果或 CV 运动矢量的**辅助数据 pad**。到达辅助 pad 的数据可以以字符串或 blob 形式提供，并被解析为结构化表示。解析后，插件将每个数据缓冲区与其对应的主媒体帧匹配，并将结果作为 **GstMeta** 附加。

## 异步模式

这是默认的同步模式。不执行基于时间戳的匹配。相反，元数据缓冲区以严格的 **1:1 顺序**与主帧关联：

* 第 N 个传入的视频/音频帧被保持，直到在**所有**数据 pad 上都收到第 N 个数据缓冲区。
* 一旦该帧所需的所有数据可用，即附加元数据。
* 然后将增强后的缓冲区推送到下游。

当媒体缓冲区和元数据缓冲区以固定、可预测的顺序生成时，此模式很适用。

## 同步模式

在同步模式下，插件执行**基于时间戳的同步**。每个传入的主帧最多保持 `1 / framerate` 秒（视频）或 `1 / rate` 秒（音频）的有限时间窗口。例如，在 30 fps 时，帧可能被保持约 **33.3 毫秒**。

在此保持期间，插件在其辅助 pad 上等待时间戳与主帧时间戳匹配的数据缓冲区：

* 如果所有预期的数据缓冲区在时间窗口内到达，则在转发之前附加它们。
* 如果一个或多个辅助 pad 未能及时提供匹配的缓冲区，则仅附加成功匹配的元数据，并将主缓冲区释放到下游。

## 延迟控制

在某些用例中，同步模式下的默认保持时间可能太短——尤其是在元数据生成耗时超出预期时。`latency` 属性通过接受以**纳秒**为单位的整数值来延长等待时间，允许插件在转发主帧之前为迟到的数据缓冲区等待更长时间。

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

# 用法

### 人员检测

<div style={{ width: '100%', overflowX: 'scroll' }}>
  ```mermaid theme={null}
  %%{init: {'theme': 'default', 'themeVariables': {'fontSize': '50px', 'nodePadding': 120, 'nodeSpacing': 120, 'rankSpacing': 140}}}%%
  flowchart LR
      A[qticamsrc] --> Q1[queue] --> T[tee]
      T -->|main path| Q2[queue] --> M[qtimetamux]
      T -->|inference path| Q3[queue] --> C[qtimlvconverter]
      C --> Q4[queue] --> I[qtimlqnn]
      I --> Q5[queue] --> P[qtimlpostprocess]
      P -->|text/x-raw| Q6[queue] --> M
      M --> Q7[queue] --> O[qtivoverlay]
      O --> Q8[queue] --> W[waylandsink]
  ```
</div>

<Steps>
  <Step title="下载所需文件">
    | 文件            | 下载                                                                                                                           | 保存为                         |
    | ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
    | YOLOX W8A8 模型 | [Qualcomm AI Hub — YOLOX](https://aihub.qualcomm.com/iot/models/yolox)                                                       | `yolo_x_w8a8.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` |

    <Note>
      如果任何下载的文件是 `.zip` 压缩包，请在复制之前在主机上解压：
      `unzip filename.zip`
    </Note>
  </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 yolo_x_w8a8.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=yolo_x_w8a8.tflite
    export LABELS_NAME=yolov8.json
    export SRC_VIDEO_NAME=Draw_1080p_180s_30FPS.mp4
    ```
  </Step>

  <Step title="运行流水线">
    ```bash theme={null}
    gst-launch-1.0 -e --gst-debug=2 \
    filesrc location=$HOME/media/$SRC_VIDEO_NAME ! qtdemux ! h264parse ! \
    v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw,format=NV12 ! queue ! \
    tee name=t ! qtimetamux name=obj_mux ! qtivoverlay ! waylandsink fullscreen=true sync=false \
    t. ! queue ! qtimlvconverter ! queue ! \
    qtimltflite model=$HOME/models/$MODEL_NAME delegate=external external-delegate-path=libQnnTFLiteDelegate.so \
    external-delegate-options="QNNExternalDelegate,backend_type=htp,log_level=(string)1;" ! queue ! \
    qtimlpostprocess module=yolov8 labels=$HOME/labels/$LABELS_NAME \
    settings="{\"confidence\": 51.0}" ! text/x-raw ! queue ! obj_mux.
    ```
  </Step>
</Steps>

### 检测-分类级联流水线

此流水线演示了一种级联推理方法，其中一个模型（检测）的输出用于裁剪感兴趣区域（ROI），然后将其馈入辅助模型（分类）。

<div style={{ width: '100%', overflowX: 'scroll' }}>
  ```mermaid theme={null}
  %%{init: {'theme': 'default', 'themeVariables': {'fontSize': '32px', 'nodeSpacing': 120 'rankSpacing': 140}}}%%
  flowchart LR
      FS[filesrc\nvideo.mp4] --> DM[qtdemux] --> HP[h264parse]
      HP --> DEC[v4l2h264dec\nNV12] --> Q1[queue] --> ST[tee\nsrc_tee]

      ST -->|main path| Q2[queue] --> DX[qtimetamux\ndet_mux]
      ST -->|det inference| Q3[queue] --> DC[qtimlvconverter\ndet_conv]
      DC --> Q4[queue] --> DI[qtimltflite\ndet_infer yolox]
      DI --> Q5[queue] --> DP[qtimlpostprocess\ndet_post yolov8]
      DP -->|text/x-raw| Q6[queue] --> DX

      DX --> Q7[queue] --> MT[tee\nmeta_tee]

      MT -->|main path| Q8[queue] --> CX[qtimetamux\ncls_mux]
      MT -->|cls inference| Q9[queue] --> CC[qtimlvconverter\ncls_conv]
      CC --> Q10[queue] --> CI[qtimltflite\ncls_infer mobilenet_v2]
      CI --> Q11[queue] --> CP[qtimlpostprocess\ncls_post mobilenet]
      CP -->|text/x-raw| Q12[queue] --> CX

      CX --> Q13[queue] --> CO[qtivoverlay\ncls_overlay]
      CO --> Q14[queue] --> WS[waylandsink\nfullscreen=true]
  ```
</div>

<Steps>
  <Step title="下载所需文件">
    | 文件           | 下载                                                                                                                           | 保存为                                     |
    | ------------ | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
    | YOLOX 模型     | [Qualcomm AI Hub — YOLOX](https://aihub.qualcomm.com/iot/models/yolox)                                                       | `yolox-yolo-x-w8a8.tflite`              |
    | YOLO 标签      | <a href="/SDKs/IMSDK/labels/yolov8.json" download="yolov8.json">yolov8.json</a>                                              | `yolov8.json`                           |
    | MobileNet 模型 | <a href="https://aihub.qualcomm.com/iot/models/mobilenet_v2" target="_blank">mobilenet-softmax</a>                           | `mobilenet_v2-mobilenet-v2-w8a8.tflite` |
    | MobileNet 标签 | <a href="/SDKs/IMSDK/labels/mobilenet.json" download="mobilenet.json">mobilenet.json</a>                                     | `mobilenet_v2.json`                     |
    | 输入视频         | <a href="https://github.com/qualcomm/sample-apps-for-qualcomm-linux/raw/refs/heads/main/artifacts/videos/video.mp4">输入视频</a> | `video.mp4`                             |
  </Step>

  <Step title="将文件复制到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      ssh <user>@<device-ip> "mkdir -p $HOME/{models,labels,media}"
      scp yolox-yolo-x-w8a8.tflite                     <user>@<device-ip>:$HOME/models/
      scp yolov8.json                                  <user>@<device-ip>:$HOME/labels/
      scp mobilenet_v2-mobilenet-v2-w8a8.tflite        <user>@<device-ip>:$HOME/models/
      scp mobilenet_v2.json                            <user>@<device-ip>:$HOME/labels/
      scp video.mp4                                    <user>@<device-ip>:$HOME/media/
      ```
    </CodeGroup>
  </Step>

  <Step title="连接到设备">
    <CodeGroup>
      ```bash SCP (SSH) theme={null}
      ssh <user>@<device-ip>
      ```
    </CodeGroup>
  </Step>

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

    ```bash theme={null}
    mkdir -p $HOME/{models,labels,media}
    ```
  </Step>

  <Step title="运行流水线">
    ```bash theme={null}
    gst-launch-1.0 -e --gst-debug=2 \
      qtimlvconverter name=det_conv \
      qtimltflite name=det_infer delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp,log_level=(string)1;" model=$HOME/models/yolox-yolo-x-w8a8.tflite \
      qtimlpostprocess name=det_post module=yolov8 labels=$HOME/labels/yolov8.json settings="{\"confidence\": 51.0}" \
      qtimetamux name=det_mux \
      qtivoverlay name=main_overlay \
      qtimlvconverter name=cls_conv \
      qtimltflite name=cls_infer delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp,log_level=(string)1;" model=$HOME/models/mobilenet_v2-mobilenet-v2-w8a8.tflite \
      qtimlpostprocess name=cls_post module=mobilenet labels=$HOME/labels/mobilenet_v2.json settings="{\"confidence\": 51.0}" \
      qtimetamux name=cls_mux \
      qtivoverlay name=cls_overlay \
      filesrc location=$HOME/media/video.mp4 ! qtdemux ! h264parse ! v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw,format=NV12 ! queue ! tee name=src_tee \
      src_tee. ! queue ! det_mux. \
      src_tee. ! queue ! det_conv. det_conv. ! queue ! det_infer. det_infer. ! queue ! det_post. det_post. ! text/x-raw ! queue ! det_mux. \
      det_mux. ! queue ! tee name=meta_tee \
      meta_tee. ! queue ! cls_mux. \
      meta_tee. ! queue ! cls_conv. cls_conv. ! queue ! cls_infer. cls_infer. ! queue ! cls_post. cls_post. ! text/x-raw ! queue ! cls_mux. \
      cls_mux. ! queue ! cls_overlay. cls_overlay. ! queue ! waylandsink fullscreen=true sync=false
    ```
  </Step>
</Steps>
