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

# 自定义现有示例应用程序

调整并增强现有示例应用程序，以满足特定用例需求。本节将指导您在运行 Canonical Ubuntu 的 Dragonwing 设备上，使用 Qualcomm® Intelligent Multimedia Product（QIMP）SDK 下载、构建和自定义源代码——让您完全掌控应用程序行为，并可在各运行时环境中进行性能优化。

预构建应用程序非常适合快速评估，但自定义它们可以让您：

* 集成您自己的**模型、媒体或逻辑**
* 针对特定的**运行时目标**（CPU、GPU、NPU）优化性能
* **添加新功能**或**修改现有功能**以匹配您的用例
* 使用 GStreamer 试验**不同的管线配置**
* 从可运行的基线出发，构建**可用于生产的应用程序**

要开始在目标设备上自定义现有示例应用程序，请按照以下分步说明安装所需的依赖项并配置系统。

**前提条件：**

* 完成设备设置。
* 确保 IQ‑9075 设备正在运行 Ubuntu 操作系统。
* 设置 Wi-Fi 并通过 SSH 访问 IQ-9075 EVK 设备。
* 如果尚未安装 PPA 软件包，请执行**安装所需软件包**步骤。

## 安装所需软件包

要安装所需的预构建软件包，请参阅[**🔗安装所需软件包**](../devices/iq9075-evk/Install_required_software_packages)章节，并运行提供的"Install PPA Packages 脚本"。

## 从源码构建

按照以下步骤下载、配置和编译示例应用程序源代码。这样您就可以按需修改应用程序行为并集成自己的逻辑。

安装以下软件包以下载源代码：

```shell theme={null}
sudo apt-add-repository -s ppa:ubuntu-qcom-iot/qcom-ppa
sudo apt-get install adreno-dev
sudo apt-get install gstreamer1.0-qcom-sample-apps-utils-dev
```

## 构建依赖项

运行以下命令获取源代码编译所需的插件：

```shell theme={null}
sudo apt build-dep gst-plugins-qti-oss
```

## 下载源代码

下载示例应用程序源代码：

```shell theme={null}
cd /home/ubuntu
sudo apt source gst-plugins-qti-oss
```

## 示例应用程序代码讲解

我们以 ***gst-ai-usb-camera-app*** 为例进行代码讲解。这是 Qualcomm 开发的一个基于 GStreamer 的应用程序，用于演示如何将 USB 摄像头用于不同用途：

* 在显示器上显示实时视频
* 将视频保存到文件
* 通过 RTSP 流式传输视频
* 使用 AI 模型运行目标检测

gst-ai-usb-camera-app 的源代码位于：

```shell theme={null}
cd gst-plugins-qti-oss/gst-sample-apps/gst-ai-usb-camera-app
```

### **详情**

**头文件和常量：**

```c theme={null}
#include <glib-unix.h>
#include <stdio.h>
#include <gst/gst.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <json-glib/json-glib.h>
```

这些头文件提供以下支持：

* GLib：实用函数和主循环
* GStreamer：多媒体框架
* Video4Linux2（V4L2）：访问 USB 摄像头
* JSON-GLib：从 JSON 读取配置

然后我们定义默认值：

```c theme={null}
#define DEFAULT_WIDTH 1280
#define DEFAULT_HEIGHT 720
#define DEFAULT_FRAMERATE 30
#define DEFAULT_OUTPUT_FILENAME "/etc/media/video.mp4"
#define DEFAULT_IP "127.0.0.1"
#define DEFAULT_PORT "8900"
```

当用户没有提供自定义设置时，将使用这些默认值。

**应用程序上下文结构体：**

* **GstCameraAppCtx**\
  此结构体保存应用程序的状态：

```c theme={null}
struct GstCameraAppCtx {
    GstElement *pipeline;
    GMainLoop *mloop;
    gchar *output_file;
    gchar *ip_address;
    gchar *port_num;
    gchar *enable_ml;
    gchar dev_video[16];
    enum GstSinkType sinktype;
    enum GstVideoFormat video_format;
    gint width;
    gint height;
    gint framerate;
};
```

* **GstAppOptions**\
  此结构体保存来自配置文件的用户定义选项：

```c theme={null}
typedef struct {
    gchar *file_path;
    gchar *model_path;
    gchar *labels_path;
    gchar *constants;
    gchar **snpe_layers;
    GstCameraSourceType camera_type;
    GstModelType model_type;
    GstYoloModelType yolo_model_type;
    gdouble threshold;
    gint delegate_type;
    gint snpe_layer_count;
    gboolean use_cpu;
    gboolean use_gpu;
    gboolean use_dsp;
} GstAppOptions;
```

**从 JSON 读取配置：**

函数 parse\_json() 读取配置文件并在 appctx 和 options 中设置值。\
示例配置：

```c theme={null}
{
  "width": 1280,
  "height": 720,
  "framerate": 30,
  "output": "waylandsink",
  "enable-object-detection": "TRUE",
  "yolo-model-type": "yolov8",
  "ml-framework": "tflite"
}
```

代码片段：

```c theme={null}
if (json_object_has_member(root_obj, "width")) {
    appctx->width = json_object_get_int_member(root_obj, "width");
}
```

这会根据配置文件设置摄像头分辨率的宽度。

**查找 USB 摄像头：**

函数：find\_usb\_camera\_node()\
此函数遍历 /dev/video0 到 /dev/video63，以查找有效的 USB 摄像头。

```c theme={null}
while (idx < MAX_VID_DEV_CNT) {
    snprintf(appctx->dev_video, sizeof(appctx->dev_video), "/dev/video%d", idx);
    mFd = open(appctx->dev_video, O_RDWR);
    ioctl(mFd, VIDIOC_QUERYCAP, &v2cap);
    if (strcmp((const char *)v2cap.driver, "uvcvideo") == 0) {
        break;
    }
    idx++;
}
```

**创建 GStreamer 管线：**

函数：create\_preview\_pipe()\
此函数根据输出类型（显示、文件或 RTSP）构建管线。

***示例 1：实时预览***\
v4l2src → capsfilter → waylandsink\
代码：

```c theme={null}
v4l2src = gst_element_factory_make("v4l2src", "v4l2src");
capsfilter = gst_element_factory_make("capsfilter", "capsfilter");
waylandsink = gst_element_factory_make("waylandsink", "waylandsink");
```

***示例 2：保存到文件***\
v4l2src → capsfilter → qtivtransform → v4l2h264enc → h264parse → filesink\
代码：

```c theme={null}
filesink = gst_element_factory_make("filesink", "filesink");
v4l2h264enc = gst_element_factory_make("v4l2h264enc", "v4l2h264enc");
h264parse = gst_element_factory_make("h264parse", "h264parse");
```

***示例 3：RTSP 流式传输***\
v4l2src → capsfilter → qtivtransform → v4l2h264enc → h264parse → qtirtspbin

**目标检测管线：**

函数：create\_pipe()\
此函数构建一个更复杂的、基于 AI 的目标检测管线。

管线流程：\
v4l2src → capsfilter → tee → qtivcomposer → waylandsink

代码：

```c theme={null}
qtimlvconverter = gst_element_factory_make("qtimlvconverter", "qtimlvconverter");
qtimlelement = gst_element_factory_make("qtimltflite", "qtimlelement");
qtimlvdetection = gst_element_factory_make("qtimlvdetection", "qtimlvdetection");
qtivcomposer = gst_element_factory_make("qtivcomposer", "qtivcomposer");
```

这些插件负责：

* 预处理：qtimlvconverter
* 推理：qtimltflite、qtimlsnpe 或 qtimlqnn
* 后处理：qtimlvdetection
* 叠加：qtivcomposer

**主函数：**

一切从这里开始：

```c theme={null}
int main(int argc, char *argv[]) {
    appctx = gst_app_context_new();
    parse_json(config_file, &options, appctx);
    find_usb_camera_node(appctx);
    create_pipe(appctx, &options);
    gst_element_set_state(pipeline, GST_STATE_PAUSED);
    g_main_loop_run(appctx->mloop);
}
```

这段代码将：

* 初始化应用程序上下文
* 读取配置文件
* 查找 USB 摄像头
* 构建管线
* 运行主循环

## 编译示例应用工具

```shell theme={null}
cd gst-plugins-qti-oss/gst-sample-apps/gst-sample-apps-utils
mkdir build; cd build
cmake \
   -DGST_VERSION_REQUIRED=1.20.1 \
   -DSYSROOT_INCDIR=/usr/include \
   -DSYSROOT_LIBDIR=/usr/lib \
   -DGST_PLUGINS_QTI_OSS_INSTALL_BINDIR=/usr/bin \
   -DGST_PLUGINS_QTI_OSS_INSTALL_CONFIG=/etc/configs \
   -DENABLE_CAMERA=TRUE \
   -DENABLE_VIDEO_ENCODE=TRUE \
   -DENABLE_VIDEO_DECODE=TRUE \
   -DENABLE_DISPLAY=TRUE \
   -DENABLE_ML=TRUE \
   -DENABLE_AUDIO=TRUE \
   -DCAMERA_SERVICE=LECAM \
   -DGST_PLUGINS_QTI_OSS_INSTALL_INCDIR=/usr/include \
   ..
make
make install
```

## 编译

此示例演示如何构建目标检测应用程序。

```shell theme={null}
cd gst-plugins-qti-oss/gst-sample-apps/gst-ai-object-detection
mkdir build; cd build
cmake \
   -DGST_VERSION_REQUIRED=1.20.1 \
   -DSYSROOT_INCDIR=/usr/include \
   -DSYSROOT_LIBDIR=/usr/lib \
   -DGST_PLUGINS_QTI_OSS_INSTALL_BINDIR=/usr/bin \
   -DGST_PLUGINS_QTI_OSS_INSTALL_CONFIG=/etc/configs \
   -DENABLE_CAMERA=TRUE \
   -DENABLE_VIDEO_ENCODE=TRUE \
   -DENABLE_VIDEO_DECODE=TRUE \
   -DENABLE_DISPLAY=TRUE \
   -DENABLE_ML=TRUE \
   -DENABLE_AUDIO=TRUE \
   -DCAMERA_SERVICE=LECAM \
   -DGST_PLUGINS_QTI_OSS_INSTALL_INCDIR=/usr/include \
   ..
make
make install
```

<Note>
  **注意：**  每个示例应用都需要单独编译。
</Note>

## 运行编译好的示例应用程序

1. 设置所需的环境变量，将 Wayland 应用程序连接到当前的用户会话。

```bash theme={null}
export XDG_RUNTIME_DIR=/run/user/$(id -u ubuntu)
export WAYLAND_DISPLAY=wayland-1
```

2. 对于 Ubuntu Desktop，运行以下命令以创建缺失的符号链接（针对 TensorFlow Lite C 库）。

```bash theme={null}
sudo ln -s /lib/aarch64-linux-gnu/libtensorflowlite_c.so.2 /lib/aarch64-linux-gnu/libtensorflowlite_c.so  
```

3. 使用以下命令运行 `gst-ai-usb-camera-app` 应用程序：

```shell theme={null}
gst-ai-usb-camera-app
```

4. 要显示可用的帮助选项，请在 SSH shell 中运行以下命令：

```shell theme={null}
gst-ai-usb-camera-app -h
```

**调试消息：**\
设置 GStreamer 用于控制调试消息详细程度和类别的 GST\_DEBUG 环境变量。

```shell theme={null}
export GST_DEBUG=3
```

5. 要停止该用例，请按 **CTRL + C**

## 参考文档：

[AI 开发者工作流程 - Qualcomm® IoT 平台上的 Ubuntu 文档](https://docs.qualcomm.com/doc/80-90441-15/topic/develop-your-own-application-im-sdk.html)
