# GStreamer 摄像头应用程序

Source: [https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html](https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html)

GStreamer 是一个用于创建流媒体应用程序的开源框架。此处提供了如何使用 GStreamer 和 Qualcomm Camera 开发摄像头应用程序的说明示例。

## 使用 gst-launch-1.0

Source: [https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html](https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html)

使用 gst-launch-1.0 命令行 GStreamer 实用工具编译并运行 GStreamer Pipeline。

Pipeline 被指定为元素的集合，其属性以 `!` 分隔。

### 前提条件

要使用 [gst-launch-1.0](https://gstreamer.freedesktop.org/documentation/tools/gst-launch.html?gi-language=c) 和 GStreamer 插件，必须在设备上安装 QIM SDK (meta-qcom-qim-product-sdk)。有关 QIM SDK 的编译和安装信息，请参见 [Qualcomm Linux 编译指南](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-254/introduction.html)。

Note: 使用 SSH 连接到设备控制台。相关说明，请参见 [如何使用 SSH？](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-254/how_to.html#use-ssh)

在 SSH 终端中运行以下命令：

    # mount -o rw,remount /
    # export XDG_RUNTIME_DIR=/dev/socket/weston
    # export WAYLAND_DISPLAY=wayland-1
    Copy to clipboard

### 单摄像头流启动

1. 在设备终端运行以下命令：

        gst-launch-1.0 -e qtiqmmfsrc name=camsrc ! 'video/x-raw(memory:GBM),format=NV12,\
        width=1280,height=720,framerate=30/1' ! fakesink
        Copy to clipboard
2. 此示例说明如何使用 720p@30 FPS 配置启动摄像头。来自摄像头传感器的帧被 fakesink 丢弃。如果 gst pipeline 状态更改为 "PLAYING"，如下所示，则表示摄像头正在运行。由于此命令会将摄像头帧转储到 fakesink，因此不会在设备上保存任何内容。有关操作摄像头和保存视频文件的信息，可参见 [视频编码](https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html#id_kfw_tg2_wcc__d7e82) 和 [视频编码和快照](https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html#id_kfw_tg2_wcc__d7e113)。

        gbm_create_device(187): Info: backend name is: msm_drm 
        Setting pipeline to PAUSED ...
        Pipeline is live and does not need PREROLL ...
        Setting pipeline to PLAYING ... 
        New clock: GstSystemClockCopy to clipboard

要停止摄像头，按 CTRL+C。

### 视频编码

1. 在设备终端运行以下命令：

        gst-launch-1.0 -e qtiqmmfsrc name=camsrc camera=0 ! \
        video/x-raw\(memory:GBM\),format=NV12,width=1280,height=720,framerate=30/1,\
        compression=ubwc,interlace-mode=progressive,colorimetry=bt601 ! v4l2h264enc \
        capture-io-mode=5 output-io-mode=5 extra-controls="controls,video_bitrate=6000000,\
        video_bitrate_mode=0;" ! h264parse ! mp4mux ! filesink location=/opt/mux_avc.mp4
        Copy to clipboard

    此命令以 720p@30 FPS 配置启动摄像头，并在 h264 视频编码后将其另存为视频文件。如果 gst pipeline 状态更改为 "PLAYING"，则表示摄像头正在运行。

    要停止摄像头，按 CTRL+C。
2. /opt/mux\_avc.mp4 在设备上生成。通过在主机 PC 上运行以下 scp 命令，可以从设备中提取录制的内容：

        $ scp -r root@[ip-addr]:/opt/mux_avc.mp4 .Copy to clipboard

### 视频编码和快照

1. 在设备终端运行以下命令：

        gst-pipeline-app -e qtiqmmfsrc name=camsrc camera=0 ! \
        video/x-raw\(memory:GBM\),format=NV12,width=1280,height=720,framerate=30/1,\
        compression=ubwc,interlace-mode=progressive,colorimetry=bt601 ! v4l2h264enc \
        capture-io-mode=5 output-io-mode=5 extra-controls="controls,video_bitrate=6000000,\
        video_bitrate_mode=0;" ! h264parse ! mp4mux ! filesink location=/opt/mux_avc.mp4 \
        camsrc.image_1 ! "image/jpeg,width=1280,height=720,framerate=30/1" \
        ! multifilesink location=/opt/frame%d.jpg async=false sync=true
        Copy to clipboard
2. 按下 Enter。此命令将打印以下菜单并等待用户输入。

        ##################################### MENU #####################################
        
         ============================== Pipeline Controls ==============================
           (0) NULL                     : Set the pipeline into NULL state
           (1) READY                    : Set the pipeline into READY state
           (2) PAUSED                   : Set the pipeline into PAUSED state
           (3) PLAYING                  : Set the pipeline into PLAYING state
         ==================================== Other ====================================
           (p) Plugin Mode              : Choose a plugin which to control
           (q) Quit                     : Exit the application

        Choose an option:
        Copy to clipboard
3. 使用以下菜单步骤在录制视频时拍摄快照。

        (1) ready -> (3) Playing -> (p)Plugin Mode : Select (8)camerasrc ->(36) capture-image -> (1): still – Snapshot ->(1) Snapshot count ('guint' value for arg1)Copy to clipboard
4. 若要停止摄像头，按 **Enter**，按 **b**（返回），然后按 **q**（退出）。录制的视频文件和快照保存在 /opt/ 中。通过在主机 PC 上运行以下 scp 命令，可以从设备中提取录制的内容：

        $ scp -r root@[ip-addr]:/opt/<file name> .Copy to clipboard

## 编写源代码

Source: [https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html](https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html)

使用示例和源代码示例使开发者能够使用 Qualcomm 的 qtiqmmfsrc GStreamer 插件创建摄像头应用程序。

GStreamer 社区为开发者提供了大量 [文档](https://gstreamer.freedesktop.org/documentation/?gi-language=c) 作为资源。

### 单 Pipeline 视频录制

以下是使用 Qualcomm 的 qtiqmmfsrc GStreamer 插件的单 Pipeline 视频录制用例的示例。qtiqmmfsrc 插件提供了各种属性来控制摄像头子系统，这些属性在 [Qualcomm Linux Intelligent Multimedia 软件开发工具包 (QIM SDK) 参考](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/qtiqmmfsrc.html)中进行了说明。

    #include <stdio.h>
    #include <glib-unix.h>
    #include <gst/gst.h>
    
    #define DISABLE_BITRATE        0
    #define VARIABLE_BITRATE       1
    #define CONSTANT_BITRATE       2
    #define FILE_SINK_LOCATION "/home/root/test_app_mux.mp4"
    
    typedef struct _AppContext {
        GstElement         *pipeline;
        GstElement         *qtiqmmfsrc;
        GstElement         *x_raw;
        GstElement         *v4l2h264enc;
        GstElement         *enc_queue;
        GstElement         *h264parse;
        GstElement         *mp4mux;
        GstElement         *mux_queue;
        GstElement         *filesink;
        GMainLoop          *mloop;             /* Main application event loop */
    } AppContext;
    
    /* Interreupt handler */
    static gboolean  handle_interrupt_signal (gpointer userdata) {
      AppContext *appctx = (AppContext *) userdata;
      GstState state = GST_STATE_VOID_PENDING;
      static gboolean waiting_eos = FALSE;
    
      g_print ("Received an interrupt signal!\n");
      if (!gst_element_get_state (appctx->pipeline, &state, NULL, GST_CLOCK_TIME_NONE)) {
        gst_printerr ("Failed to get current state!\n");
        gst_element_send_event (appctx->pipeline, gst_event_new_eos ());
        //gst_element_set_state (appctx->pipeline, GST_STATE_NULL);
        //g_main_loop_quit (appctx->mloop);
        return TRUE;
      }
    
      g_printerr ("current state is %d\n", state);
    
      //update_pipeline_state (appctx->pipeline, appctx->messages, GST_STATE_NULL);
      g_printerr ("Sending EOS event\n");
      gst_element_send_event (appctx->pipeline, gst_event_new_eos ());
    
      return TRUE;
    }
    
    /* Handle state change transition */
    static void state_changed_cb (GstBus * bus, GstMessage * message, gpointer userdata) {
      GstElement *pipeline = GST_ELEMENT (userdata);
      GstState old, new_st, pending;
    
      /* Handle pipeline state change only */
      if (GST_MESSAGE_SRC (message) != GST_OBJECT_CAST (pipeline))
        return;
    
      gst_message_parse_state_changed (message, &old, &new_st, &pending);
      g_print ("\nPipeline state changed from %s to %s, pending: %s\n",
       gst_element_state_get_name (old), gst_element_state_get_name (new_st),
       gst_element_state_get_name (pending));
    }
    
    /* Error handler */
    static void error_cb (GstBus *bus, GstMessage *msg, gpointer data) {
      AppContext *appctx = (AppContext *) data;
      GMainLoop *mloop = appctx->mloop;
      GError *error = NULL;
      gchar *debug = NULL;
    
      gst_message_parse_error (msg, &error, &debug);
      gst_object_default_error (GST_MESSAGE_SRC (msg), error, debug);
    
      g_free (debug);
      g_error_free (error);
    
      g_main_loop_quit (mloop);
    }
    
    /* EOS handler */
    static void eos_cb (GstBus *bus, GstMessage *msg, gpointer userdata)
    {
      AppContext *appctx = (AppContext *) userdata;
      g_print ("Received EOS from '%s' ... \n", GST_MESSAGE_SRC_NAME (msg));
    
      g_main_loop_quit (appctx->mloop);
    }
    
    static void destroy_pipeline (AppContext *appctx) {
      /* destroy pipeline */
      gst_element_unlink_many (appctx->qtiqmmfsrc, appctx->x_raw,
       appctx->v4l2h264enc, appctx->enc_queue, appctx->h264parse,
       appctx->mp4mux, appctx->mux_queue, appctx->filesink, NULL);
      gst_bin_remove_many (GST_BIN(appctx->pipeline), appctx->qtiqmmfsrc, appctx->x_raw,
       appctx->v4l2h264enc, appctx->enc_queue, appctx->h264parse, appctx->mp4mux,
       appctx->mux_queue, appctx->filesink, NULL);
      gst_object_unref (appctx->pipeline);
    }
    
    int main(int argc, char *argv[]) {
      AppContext appctx;
      GstBus *bus;
      GstMessage *msg;
      GstCaps *filtercaps;
      guint interrupt_watch_id;
    
      /* Initilize GStreamer */
      gst_init (&argc, &argv);
    
      /* Create all elements */
      appctx.qtiqmmfsrc = gst_element_factory_make ("qtiqmmfsrc", "qtiqmmfsrc");
      appctx.x_raw = gst_element_factory_make ("capsfilter", "x_raw");
      appctx.v4l2h264enc = gst_element_factory_make ("v4l2h264enc", "v4l2h264enc");
      appctx.enc_queue = gst_element_factory_make ("queue", "enc_queue");
      appctx.h264parse = gst_element_factory_make ("h264parse", "h264parse");
      appctx.mp4mux = gst_element_factory_make ("mp4mux", "mp4mux");
      appctx.mux_queue = gst_element_factory_make ("queue", "mux_queue");
      appctx.filesink = gst_element_factory_make ("filesink", "filesink");
    
      /* Create the pipeline */
      appctx.pipeline = gst_pipeline_new ("basic-recording");
    
      if (!appctx.pipeline || !appctx.qtiqmmfsrc || !appctx.x_raw ||
       !appctx.v4l2h264enc || !appctx.enc_queue || !appctx.h264parse ||
       !appctx.mp4mux || !appctx.mux_queue || !appctx.filesink) {
        g_printerr ("Failed to create pipeline or elements.\n");
        return -1;
      }
    
      /* Add the elements to the pipeline */
      gst_bin_add_many (GST_BIN(appctx.pipeline), appctx.qtiqmmfsrc, appctx.x_raw,
       appctx.v4l2h264enc, appctx.enc_queue, appctx.h264parse, appctx.mp4mux,
       appctx.mux_queue, appctx.filesink, NULL);
    
      /* Configure stream caps */
        filtercaps = gst_caps_new_simple ("video/x-raw",
       "format", G_TYPE_STRING, "NV12",
       "width", G_TYPE_INT, 1280,
       "height", G_TYPE_INT, 720,
       "framerate", GST_TYPE_FRACTION, 30, 1,
       "compression", G_TYPE_STRING, "ubwc",
       "interlace-mode", G_TYPE_STRING, "progressive",
       "colorimetry", G_TYPE_STRING, "bt601",
       NULL);
      gst_caps_set_features (filtercaps, 0,
       gst_caps_features_new ("memory:GBM", NULL));
      g_object_set (G_OBJECT (appctx.x_raw), "caps", filtercaps, NULL);
      gst_caps_unref (filtercaps);
    
      /* Set v4l2h264enc */
      g_object_set (G_OBJECT (appctx.v4l2h264enc), "capture-io-mode", 5, NULL);
      g_object_set (G_OBJECT (appctx.v4l2h264enc), "output-io-mode", 5, NULL);
      g_object_set (G_OBJECT (appctx.v4l2h264enc), "controls,video_bitrate", 5000000, NULL);
      g_object_set (G_OBJECT (appctx.v4l2h264enc), "video_bitrate_mode", 0, NULL);
    
      /* Set filesink */
      g_object_set (G_OBJECT (appctx.filesink), "location", FILE_SINK_LOCATION, NULL);
    
      /* Link elements */
      if (!gst_element_link_many (appctx.qtiqmmfsrc, appctx.x_raw,
       appctx.v4l2h264enc, appctx.enc_queue, appctx.h264parse, appctx.mp4mux,
       appctx.mux_queue, appctx.filesink, NULL)) {
        g_printerr ("Faile to link elements\n");
        gst_bin_remove_many (GST_BIN(appctx.pipeline), appctx.qtiqmmfsrc, appctx.x_raw,
         appctx.v4l2h264enc, appctx.enc_queue, appctx.h264parse, appctx.mp4mux,
         appctx.mux_queue, appctx.filesink, NULL);
        gst_object_unref (appctx.pipeline);
        return -1;
      }
    
      /* Initialize main loop */
      if ((appctx.mloop = g_main_loop_new (NULL, FALSE)) == NULL) {
        g_printerr ("ERROR: Failed to create Main loop!\n");
        destroy_pipeline(&appctx);
        return -1;
      }
    
      /* Retrieve reference of the pipeline bus */
      if ((bus = gst_pipeline_get_bus (GST_PIPELINE (appctx.pipeline))) == NULL) {
        g_printerr ("Failed to retrieve pipeline bus\n");
        g_main_loop_unref (appctx.mloop);
        destroy_pipeline(&appctx);
        return -1;
      }
    
      /* Connect watcher to bus signal */
      gst_bus_add_signal_watch (bus);
      g_signal_connect (bus, "message::state-changed",
       G_CALLBACK (state_changed_cb), appctx.pipeline);
      g_signal_connect (bus, "message::error", G_CALLBACK (error_cb), &appctx);
      g_signal_connect (bus, "message::eos", G_CALLBACK (eos_cb), &appctx);
      gst_object_unref (bus);
    
      /* Set pipeline state to PLAYING */
      gst_element_set_state (appctx.pipeline, GST_STATE_PLAYING);
    
      /* Register interrupt handler for main_loop */
      interrupt_watch_id = g_unix_signal_add (SIGINT, handle_interrupt_signal, &appctx);
    
      /* Run mainloop */
      g_main_loop_run (appctx.mloop);
    
      /* Release/Free resources */
      gst_element_set_state (appctx.pipeline, GST_STATE_NULL);
      g_main_loop_unref (appctx.mloop);
      /* destroy pipeline */
      destroy_pipeline(&appctx);
    
      return 0;
    }
    Copy to clipboard

可以使用 QIM 产品 SDK 编译代码。QIM SDK 可以从工作区下载或创建。要安装 QIM SDK，请执行以下操作：
- [下载 QIM 平台 SDK](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-51/install-sdk.html)
- 从工作区生成平台 SDK，可参见 [编译指南](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-254/introduction.html) 和 [如何生成 eSDK](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-254/how_to.html)。

安装 QIM SDK 后：

1. 将上述代码保存到 simple\_camera.c 并运行以下命令进行编译：

        unset LD_LIBRARY_PATH
        source <installation directory of platfom SDK>/environment-setup-armv8-2a-qcom-linux
        $CC -o simple_camera simple_camera.c `pkg-config --cflags --libs gstreamer-1.0 gstreamer-audio-1.0 gstreamer-pbutils-1.0`
        Copy to clipboard
2. 执行以下命令，将 `simple_camera` 二进制文件推送到设备：

        scp ./simple_camera root@[ip-addr]:/opt/simple_cameraCopy to clipboard
3. 使用以下命令在设备中运行 `simple_camera` ：

        cd /opt/
        ./simple_camera
        Copy to clipboard

### 演示

GStreamer Pipeline 包含使用 [GstElement](https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c) 的媒体 Pipeline 的基本构件。在此示例中， `qtiqmmfsrc`、 `capsfilter`、 `v4l2h264enc`、 `h264parse`、 `mp4mux` 和 `filesink` 元素用于创建单个视频录制 Pipeline。

![](data:image/png;base64,UklGRgQdAABXRUJQVlA4TPccAAAv3gY2ACI8zP67ehuJ5ZRTumTp0iVLllO6ZMlSJUuXLr9SpUuWLlmyVOmSpcopXU7OMwLO+f9/59z/vffwUqPP93CjAzdH2QQEXMIEuDkHChMPTLGYJHClYqIoAQ401pOjw7fEncA1xI0yqMkzmk2TadgTqo2TuZnF5G/ADcZOTsQBKKwAGADA1rGCDw+HwWEwOCweFoPBYd9/WBwOD4fB4nBYLB4evs/9f4OB/W8mKXh4uDi4uPjHwcXFw2Jw8XCxGDxcPAwGi4PB4ODgfV/uM/2nBUmS5bapkREADSL6enr3sIcXRf3tWqpZri7ebTtLNJfVfbermYWHnXOjqayWS/8p/af0n9J/Sv8p/af0n9J/Sv9p7sXvCV4Fh4fsc8/v8o+6/xYcHnL43NO7Sv/Z45wYya7WTg8R1ZRFZEX65G2WklwPEdWERfSsopLQa+ji/rCcdmtJ32vUAe1hlp6Karoi+rs6gHR1AQbEffQPO3tXpC7o6/YQUc1ZdAAGog6YPm7Aepcg9IJ6soBkx0jxAVN6Yi2q2Qmwy7yrPRTT44rogCnESlRTFDH6oXPvYGqw6+Oea7Pjk43cNkP7JHkMcPbpm+GNA9E9v7Dm7xobyr1LKLQb4lhUbLoidEH7wVffEwYkyWOA7Ybo43ojwkFIaD/fLCo2RzFwbuEgQx8AfdhZO4TG1rxvZLT3eyIG0d6vRU36iET52Az15YHcN1fWGWNrbKdJJHj/zpV1eGHNKwWTHopqeiKQmtvvzSxOBVLt/WbG1qAoH5ugbuhxQzm9jzaMPY7Umg1IVJPUBR9jtLxAygYkqknqKkoDAlwlHFQMnXXI0gIsqjkK0iXbG2pY2xxbswKJ8rHJirGGNfhy8hDaz1/zViBRsfnpkwoi+rwd8lie8f2+PNEGBFAFSFTz0+fMgR0jvwFvfCtnog0IIAqQqOaqH4KBIbuvLAsDfkNsWvsJvdgjeU1vP4Be6T+l/5T+U/pP6T+l/5T+U/rPnkU89PCJeaxIJh98+LykGGKUVBhjbKqC/EToXm4TIv3bEDRREb330Q/kdtJHKZX77gljay79A/5qB05xijvBTYGuGH+XN0hnISOFfrp1LBVSIijLw2o4zSMhIiv/Tv5Xsop2xcIGVM6Ozw2ZD2WnElEQXTY/RfQX83HIVSN3gptCXDHYBNQhnYWMDPTTaWMpFktwNmFTTaIiTvMIBbsQEehEb1fRqGJxahSIAJpyOj9JLnIHrJ30s+OT9Kpu8GJ2fGWdODH79M3Q/i1PXdGSuJKoHSO/vSmgMxYwokw/3fsH+VUQsTge9pGTJKzGXtPDaqDtoz6OaGATTQi93BuGsYdlnQohjM6OT3quZG12vMF6ZQi9rA/L/vQQ5ta9ScVWUHVw9soQ5l7o/bWbDen3rKxrvXP7fczvEU8ugOhgCvAidygr/Q0R0V+thlFZvizi1/NbgXFX+19X7wyjBOITUKLF7fvwGmUrIMMsvC00SPXTLrwWzc3vmLJIG/DLpMvsXAGDHQ+bHR/78fFJcxgjPKxGIBJGOLyz/Vur85tja0Nnv3Plw2Svw5RotIDQ/szqLZuT3qTCf3lqepXsq9TtKdrPHzBf01PW09u5/BPB7xfRuIqN0bzIRRiV5cqiyK63ONUrjXLt5kHv/V10p08KKPHXbo5SW7hOZqWNt4UGmX562/Ca45nbMeXNaQN+mXSZnYvDO1GwHrRPgGmKAnEDox0VwdjbKFlFkASdNIWITjTsy5NciWYU/KX2V9ZNKrQ6OkkNnbU39heSOUqrYFETyncWxgOaNvl61X+EHFzkK9w17+m6li5yT45PahbJ+tjPNqxtwhUvM0t+OMg7HOmh58Wpgz6q1n6Esq9X+gu9UqTpha5X7GseKNFfpwOb62SGaW+pRuA6xs6xYXbeNCDSTx5VHl5+KIQeGOHdNo6p1PIpKjZ607EbZA/LrYWuUZrocND7d6L7uJaZHPbCGb1kRa6VHw8bn5wdn0Rx4xOYEgNGPJmJ3xkO+pjKlj5sn7H4EefN2bHi2g7Gfh8xSAkbogymAqNO/nWN3RlHa7FoZYBdrDIwHiKAr1ffGU6u3hkOkhUuOcrI17V0kUvxZH2stX55HKx4KVFqa8Udi7DPtEVbK+te93eLtdr7yAZs+MzqRzZHPVRyE5vtuU5uGNJos1qP80kcGzbnzQiR6SeIKg8vDeSPs+CCmEa58RHTsSvaYDp2w+0BOTTpAqzdtbKupoakk8BwF87oZ5blagFNYmSK8gweNzCB4dlBsxVO4v+WBethPzkfix5x/n4/Twum8tGGrbaZrbYc5AkCc/sxMUZLAyxqYj4mGg8LlmVrYwTr1dkrP+PZpDnqiRF8XcvuBUyCC1Tr4tRBenSM/3fxdhPY2Bk98Qg7dhne33k6WCc98YYTIwkA3cXq3nIlfAhzndAwoBGt1mGjbR0bfv7D9iYZY1GmnyCqPLz0UAgPLo+paXeddFQksItptYyoBfjYDbSH59aoC6AG2l34XgDOZKK6ePfk47DCjOgJh8yoDDA7gfyBuUv19sfHR1U2TUmUq4WJAoifWJgwlI9ZO9H1v72R2vsFTh60zwlzLUz4RCzMTIgUh20xKQSZPvm61gJ6cJKPnBj5lJO8fmdBI+wYH0DIpMUp2iYImcSpBg1Qsjg16ZFRW9AwoNGq3/FB+zc7x4YjZhYShBIj008QVRJeMKWy4IKYmkgU0OVELCdQO28DHv3QHpBb+9lhKwR4J8CQySQ1szDsIPhlS0DcQP44kdDgPjVp6pPcP3ZHYcT6gjlEGKpEiK0ubuQxs4MENg1dOWq5eeZKzITUPT1MjJGsYkNg6PsHbF1rRyDFQAeMEtdEciaSHv4Fx7L0/0LQXwkfAihZnGIOUp3IMITdat3Kv4nhiRmZC0L9NEQVBZIFF8XUFKIklZBEDwQJAHOYkMV7xtYstz3Z2BqOEPs2W1DcWP6MtLsYK+vpNKpAkvzh6ujf2T6pHjLQdzPb/3q93uswJSIsTo19ePXp7CR647cluzclgcyTSwx4cmiIPugMlgB8XWvFyodXVa1R5O71PWyfFGnHLKbJd+ptD3D3SOd6CFTCADq5YTYnCZ+2MD9sIXIVoX7exA80sPAyeHBBTEmKJGKalERuyZ2A3NrzTnYie5UCAogbz58Boq3ok7zB9NV1tylmx8OohikRQb8iV3+ZIfl6OxkkMwrWq3pAAIg9fF1rAdXq/9dTxDZRisQubb2xi0nbtKrqI/Q1IPw3n4JgSmDbgU5uGMButf6BZI4Nv/NmlOnnj/Oo6vACPA8u67Zc6wipaBLClEMzk97TNI6+c2Vd+oYKCHx2QvkzMUpnrZEMreg9HYfgaBJWEluRSzGpMMiJRBMQlztaYL06O77yr1++MmjIwhetaw2Q9THR+pHNk3lkcYot89CFu1aGoq+qQgAlypabyHMNgU5uGNDIV+tFBpl+gqiy8FJAcEFMY76B9njv7S6QQz5PD2Nr5Fsmix88biB/ZugRq5EMLX0whMCOyxiUKF1AikGFQQ4RAcTlELBe9fvuCe3fugu8z8saWNcaIOtjP9swbIb2SZ8/WlF/dyTN5fBf5OVBAFDi/bX0N+0MdDLD0EoIrdYLDCL95FFF4SWHQlhwebdzf4LsIYbZMXslOeTzEW3tlv5SsYPHDeXPgsWpyTUfCztSDWfYKEkn8XmkFcF6lxU5dGRe15KvAzGmFW+uaEWwocQJi6diMCUGLyPVia0EGsFqvbjQisn7aYiqRQhwt1u5owXzZbCH59aoi7hmGFKFCpvBHY35g51Gwor9ieTYtVLiTFp4vRtjpPekzeta8nUgxqAoZ7TAhhInbJ7UYJKBl+LYSqoROlhkaCXvpyGqFiHA3c4hKF8Gewy5hYnkrgEdBYyWIWbG/MFOQ2GtkQ5kAFopcR72uimitmWPnFYhIA9RzRD5sac4kbIlhZ5UE+9WrJa8I3EyENU8kbI9j20guqYkkXxT5YwseQW2VAyz/Hxi2nIZXBRQKaz9SiVx2YmpBAncyqA9kq+3A7g1mlKxlChRMtCWwkmcd01FGWQMy97+SmBLoxhR3J8c+BdFcFJAxYhiocxPTKMAom7laGxFjmOjKRRLibpdsuEZaEssmMT5+/2ka+r2KEWcf9BPJt2A+Zi5Styir80LYSF/Puav5v/RvOUSuCig81EG4Fcemz1v71dy8u3W/D9aj6rIcG00U4llhhsut4kFE3/xNgeHckvdt6QX5KcusqyTlc9iXWRVJ6kdY/2UJO+Beld8HutrBsPE8DvnrN1SX/NCWPvl81GWfknRilx17iJqPQ0NTanCSXFqNEWQ8mooZWaCKOJVEaU/lFtqZ05RBodKuAWZHKcXdpVoMy+MJcp7oN7n53K+GejLYJgcF6Ws3VJiWPuVk/Za+nW/XXoxbCQ/Py+ZtKsdYwGcGs1PewGkvLowVmaCKORVAaX/o1xS4iTchAxWss0UR9afrBsoilsCKoxMKHMTU0nc4hbEpdEUhGxBPqYwCa8KKv3v5Y5KgWTbkMVKYlgKiPqTcQNlcUpAxREJZV5iKopT3MI4NJqElGKZ4X4LeLW7gfw5liHyb9hwSr7n+rTJr1vDDK6JZek/pf+U/lP6T+k/l+CL/jgJfb1hAGKedtCBSIdidwEwgCyLUEZhhcxiIxSMU3OSSboiHwaov+5sDB+NSK/nNhJ+QpVtKAohvNmOQmaOIOMJSjAqKn6oJqNbUh3HPR2ZYJ6a7Sfpqu4P0emoE6Rfq+726ES5tK7kg+gIqpoXMa/u9tQB3O9LfWuVS6RtstVpGYqqAFKBZrsJkTmiIuOJHuChk4RRUWED7z7ZLaF9KW9xVY1kqOoeRaBTc1U3gnQgtRuu6soK9fXjwtDs5RmDrbT6qLR5BDJ/5hFpm3ow6qpAU9WHgq5OQB9FXTmJRHOEEXKAR08SRZOq7gscDtQVb+7RaTopkBbTWWyEQzhAeWkgoONDVUVnbhYdw4EjLgMIwIeWaPaQHC6JSc8Z7R6yPm+6Glrk6K6GjgsLuzJJ9BBpmxq+an6gzq7FOBRcYMaIMaX5h7eSBo6mMokWp9AB6HN21VV9XjoJoRvMLo/m9uePJHME8IdCB1Rd1yCzYD3JvQQJyAT5iGYWianAGtofrIOofanipazjFWmxaRbLD9sShe0clO0FYRuYVqFrG9uuUoRdS3T1tLQrlTAnukDmrIXsXKxLKZyZGyw8qKE25aNu55hCp4YOVXB8SCuAcEFAcY31EMFAgQbK4ZK49HyhvCRHGk0gf4EnGST6hVS41OyHVYtZ2xnMt0wRvfcxld0TtqyqaCoTaXEH/FjCITzuLMYKsCubxCQkmSNAKxHGn6AHrCeZRpSADBBzEs3s4X0qsMn3VAhTrMWojLNYjqC7vgPPJJzZmWJ5+W2bVMrgwiE7HHhmF/AdyweeeWbO8Sx1E5H7lfWp0E1M7hV9+dvT4c/7XGglfSqdSKHdQ6YusNn7aCdRCJ3A/FCMUnVjCN0or0Z6VPiO9ShPhw7Ae7UCfhyyX4vI0bns8TwdLwXbJEv0fe35guFB75zShNzDIyYo+n1QT2ruAfCkyiKHz12fBpMJY7hLeqgTpKFyY2j3UNQVbHEjmG6xEnAzCkUNmpkhor9oXs4L9zPei1PVfcrT2opjdQ0CB2JsqaXKHtuUd6ThfUyNiiwOwDBCedw3HUI32qV1hezKHj3+bq/3MQEJ5gjYSg0c7GAGqOheADT/6DRJhX7wI3Wi//W9+Yhm1pj4+3XmVRrBVBNBt6N4KZ5G1S31axhnsSqL7N3ei7eiA7CzL83ORf6ki4kwR25vUEuxa7EOpVdmBLIJbGnqehpepqdqMo1Ptslsoo7LdTvopJwKj+tz1uelkyhQuAw2IvXI7ka56h3TS8eBHgURqiU3QnxpugetoVFjQrsbuYfsUrBNlYFIsS/fv7mGc+hw4fjofWY4TjxB/jJPUiWJYTumEcJ93HHd+1QgD0S1e8hIF0GL1azIW49CUaNmipLcsbOq3b1Xt78+Iw2wAoPaa6mlkkbg91pwOPz3uvcpA4YRz+Oh0IN2VY+H6i+2S54Y/bJPZld3M+/13h7rOcICONjRDEAAcwldGJ8ijyjLkcCtTyq3nBPNTyeLJjn5e5VMRSXOKdLlY6foMSc+jWqfzLNYlQqRgD3CTNzr5eazn/RmtoHQPd1bzjyTQveCRMlgYc6uJbYn3gzX7Ey1ceCZ29m2JYSwjWVOCZkO4ZrTirdthg7Adg3N9sKb4W+3J5yZYxKhELKbVvUj6v8RmDQX02640GnWcTmlIIfl2NhcOl6rwy+cb3/9ODrCrfQcq4kMpAcJpToQ9I4q2ia1D4OoUiT7vRCEQM6khy4K+jLyV3uS1gXvvSJRTYQQ9EwvDDtCRGZA3V7UYm0dbSzsMW6moGECjv19CP//6ztsE+1GVXNXDKD2Ii3YKWEE6ghpc2rQZy7gYcQbT5wy2CWNKkWSGjANQe2i7LGeIyyAgx3OABrkmNby+8o5Gbz3mgS1qt26IA7HRPPTPllpPhlC6ObT+eK1eDBJR49OH1CXSDjJVEV9Mc9idSWP7by7geopIagzJj56YunZek+6nQ3xxs0f0cvI07/EeUt7sI+dxZ659Gx14PTly2/bfCsRsrwtoX1640T7J5Yfr4WcCD+x/KZwZo5LREJ0fey6zy5vcLg0F9NwRXenS8dfyocqUaEPoKiRgC7UtR4SjFPkLumX+9QaPmqgR8ujCTNDFcBtggzNT3t1HXnc3kS1L5AzKRFITZnAHlC7qpvlabR+XrjXdfjXk9W+QM7smBZJAind8UOsaajFZATTxqJQoGYK8n+01ck6rVBnzm0uF7RPdSU79RArMLC9dlqEGZrXvQL1SdrmCwdPh7r+0vTScTS8gHmdwK8m98vSs2t9wIxY0r+5JrLrr0LQu6jzZNhuj/UckQw8AxxaOg4dq0+FToRSUwm4tb0bg2bakQHTZOEkbp2N83ky3BHNqt7ebr+UNJaPe9zeRuzErHPq0x/WlSz6ngA1Zop4QfsKwJmUj/z5svyS7SSwYxqoups5BHIGc2Znkc0fUQu7pV0pAL+n9nlqB/jWDQLfzf7BdWTdR7RpIVoZXV6q/TITcGaOS1RCjBcAXJqT4UsTTfXBQKp9qRoDJia/GUIIHD04q7oGeiSA2wTp77W7mXU9ZSpZ7QskWQOjGk6EnwL5ahPYA8rNKXBBWOXYd3hnWRXCNn0FES/lLWbPiya3hEKBminHhTG7m6NEqztxCqTuw2dBiB0WwPbaaRHmvHCZEqjnB1Jn42F7u9ZVGjdEH9C2GEZHp8Of95C8uq7Ss6t3fe3mWaDLTwmk7r2abCd72zlCFuiY9vhYXUm4dU49U0eS2bUPuJXpaMrS0/SvJo3lU57Ck9lZHVJI5tJxPQ8cImtuC8yZFL0n8HMSsTyr2gUye33dwNxbyO7uAIEIu+Y02VcyqAYtDXCCCfql9mm611W7SgqXqITYw6U5GR0alXhGJ0ifN1L9Wkbql4ZutGuvbah9EHNzVQM9EqBtEr/gNZ/9+kSWLmAPOJm8cPFuI+cW0rkAYS22BjQzYxcOa851TU8+KQPba6Ulgxc+TI8upHVDVzW0dLvNw0i1+0vdDtPhWXDUZPDCjmloOnH6q9p2eyznCGGAY0QlJQsXZoLirGp6n3Ir09HM3oUj5FzfWpVZ8tNXw5mKYn2K3JIZnEn5DRK58N9k9prZMPFL7dNv3FRLQv5t9Do/soEIpJLxJ6cpXKISYg+T5miOTr9XTeJwqNZ1XZvQg8HiQlU3QlzK9IiAtkn8KkPZyTnv072K6QL2AJDFq+wN+165kNJVMKDFhgtTpgt1nbGr/EAIvdKWR2XnNG2FBaC9lloyeJW/Io8Np3hDOp4Ww+haregQHpEZvMpf6XPe/suWc4Qw0LH6paGbQJ54kYWr7JiGdks/PSTb0czeVc7vLiE8v9FpncYVj05PdiAarnQeJ6cP2IAymcmrbJxd7+k5I2qnd+LMHGNuA+9Jw0cJS3csq5oTOeESE51waW7my1d3AlQ46DB8aeijUjSCvbo2XYU9QH4qUNDzLLgeCr4KHexaIcsh2qZK+IZ+VJ1L9du0UWaQv4gs3lCv8OGL5iW919tBkl4FNDMFEnV6Zt+blr2XhruiFiUocMgVpAU6lbkb+u+z6/0R72N6VyHjyTiMaEj1MRJsV/ZuSJ+L9iSYI0ArLYFXAc0nInVk1SZm4IYOd+L0V/mIZtZeb/eU5x9J4YZoHAOdBsLScRtwJjN4Q8vknAUbJ7oAd751w8SBZVWDhZfumNPQfeTOJTaMX97Ww+rLXGKiL3NpbqY+pdJCYE+t1S80Mt/QodCNclW3Q2CHVKq6L7CS0eflxqXjSA96GrSO4ePe1tBS2qLahMCB21TJMmC6POFjzA7UE+RBpplJ8d1SvlIjWIutbwg3M0OsLnsfU3y2eQUCB2NsqaXKGkdmfIzpQTWwYcTGCvTIYFfW+KT3MSYgyRzBW8mgA0oDZwANdOwQPeKQDQZMcxPNjL3e7oj3qXAze6iUvh2bATqL4Uxmj1V1zo43bnYATiNQ4W9Tz9Qc1AAYvu1t+Nu4RPZtdnBpTobekWO7oPrL3w6hrV9/Vh/VL2c+xCB6HvfXH2TJYa9xRnqIvHfQF7GS143q+1H6Ra19ZFdz4Dal8m4pGYJ6AjxgOOPNwAKtYxjWYvxychQKYGCWTlqRzPMpvla4qnjgYIwttWTz3VLSxjCMLiUeTdOmY7syBdeUgARzBGglgw72L1+NZwAKd4we9KHvCpOBd0vJTTQz924pMabFS8MBBX2mNMY8i1WZfLcUS8jOLiEH3rQZOgCDGhsA9Hq7xxtfb8ck8tfb2cGkufmTCipyvZvR99VIAX6HL66ICjbrISnjuirTGypROWibcvZJBRW1CRhs54ljPqnAwiKYBNhYi3czyxCtGFup7J5o+I6h8AooyDBphNPUeSuPkF15+6QCmTmCybCaASo8xqDmLLzXZW6iKY5kLNOJJusv98ZqFhuRfM4cvR78vgorML61bcVFm/XQpSHXZfN2uEhrlbfPmbvZZISdJ675nDlri0CvgUKDgfn/pAJiAAF6kVCBWz5nzth5G4+QXTn/nDluksEULsNuBsBjDGkW/aSCvEfTEaBeMVPwLRkG/wj2h2DgjPB/CAZGcfshGPI0A4iS82imQO5jeckt3FzRY94jTdIJX1XgfoShrM0AmSGj0dwt+xN6kWPeI07SCV+R+wm9MjYDZIdsRrPp7QfQK/2n9J/Sf0r/Kf3nkjDZzfA7XHaJY+Lk37Dh9He47By/RHGKW1K4qcVOjuVuhd/AuUtKmvwbNuz+Bs6dUqI4pYRwU4vdG8sCyvxPfc0t9VO3y+Akw74mh4MMk+PTznFLCCf5JYZj3Po0wLXRdHIsCyatOO/dUipOIjjJMH97lKIVb3ePYS1EMtfcE1AZ3OSXCG6yi+LYaLo5lrsR/mmO3OOYFG4wbPj8pzly1MCSwUl2MdwaTTfHcvfAP6yYowwDuNCx4fQfVsxFlkjgKLc4xTeWpf+U/jOixFHVRIKzqjDirHtNMripOK53rBAvCxLjLLeGIRYm3FXLBRF33WuSwFlFcb1jxXhZkBhn1XDD/MSCy+phP1kAmZ9YdllNzCdixmV+ERztmLNxd5cTseAyu2aGlXDGee+yUtNuocLVsUow8bis9LTjcMecXC7v8kggnNFt1SpWODxWDjas1XK+Y4V53nR3OItzFS32HKnSf0r/Kf2n9J/Sf0r/Kf2n9J/Sf3ans8d3FR72AK+Cw8Y39gCvjWGSPfir9J/Sf0r/Kf2n9J/Sf0r/Kf2n9J/iRpNZWfDI28+DD+/NZfWI6zdjAwA=)  

[gst_init](https://gstreamer.freedesktop.org/documentation/gstreamer/gst.html?gi-language=c#gst_init) 必须是第一个 GStreamer 命令。它会初始化所有内部 GStreamer 结构，检查哪些插件可用，并执行任何命令行选项。

    /* Initialize GStreamer */ 
     gst_init (&argc, &argv);
    Copy to clipboard

可以使用 [gst_element_factory_make](https://gstreamer.freedesktop.org/documentation/gstreamer/gstelementfactory.html?gi-language=c#gst_element_factory_make) 创建新元素。第一个参数是要创建的组件类型，第二个参数是赋予该实例的名称。

     /* Create all elements */
      appctx.qtiqmmfsrc = gst_element_factory_make ("qtiqmmfsrc", "qtiqmmfsrc");
      appctx.x_raw = gst_element_factory_make ("capsfilter", "x_raw");
      appctx.v4l2h264enc = gst_element_factory_make ("v4l2h264enc", "v4l2h264enc");
      appctx.enc_queue = gst_element_factory_make ("queue", "enc_queue");
      appctx.h264parse = gst_element_factory_make ("h264parse", "h264parse");
      appctx.mp4mux = gst_element_factory_make ("mp4mux", "mp4mux");
      appctx.mux_queue = gst_element_factory_make ("queue", "mux_queue");
      appctx.filesink = gst_element_factory_make ("filesink", "filesink");
    Copy to clipboard

可以使用 [gst_pipeline_new](https://gstreamer.freedesktop.org/documentation/gstreamer/gstpipeline.html?gi-language=c#gst_pipeline_new) 创建 Pipeline。然后，可以使用 [gst_bin_add_many](https://gstreamer.freedesktop.org/documentation/gstreamer/gstbin.html?gi-language=c#gst_bin_add_many) 将创建的元素添加到 Pipeline 中。

     /* Create the pipeline */
      appctx.pipeline = gst_pipeline_new ("basic-recording");
    
      if (!appctx.pipeline || !appctx.qtiqmmfsrc || !appctx.x_raw ||
       !appctx.v4l2h264enc || !appctx.enc_queue || !appctx.h264parse ||
       !appctx.mp4mux || !appctx.mux_queue || !appctx.filesink) {
        g_printerr ("Failed to create pipeline or elements.\n");
        return -1;
      }
    
      /* Add the elements to the pipeline */
      gst_bin_add_many (GST_BIN(appctx.pipeline), appctx.qtiqmmfsrc, appctx.x_raw,
       appctx.v4l2h264enc, appctx.enc_queue, appctx.h264parse, appctx.mp4mux,
       appctx.mux_queue, appctx.filesink, NULL);
    Copy to clipboard

Caps（功能）是描述媒体类型的对象。在这里，使用 [gst_caps_new_simple](https://gstreamer.freedesktop.org/documentation/gstreamer/gstcaps.html?gi-language=c#gst_caps_new_simple) 创建一个新的 [GstCaps](https://gstreamer.freedesktop.org/documentation/gstreamer/gstcaps.html?gi-language=c#GstCaps) (filtercaps)。此 filtercaps 描述了 [qtiqmmfsrc 接插口配置](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/qtiqmmfsrc.html)。

     /* Configure stream caps */
        filtercaps = gst_caps_new_simple ("video/x-raw",
       "format", G_TYPE_STRING, "NV12",
       "width", G_TYPE_INT, 1280,
       "height", G_TYPE_INT, 720,
       "framerate", GST_TYPE_FRACTION, 30, 1,
       "compression", G_TYPE_STRING, "ubwc",
       "interlace-mode", G_TYPE_STRING, "progressive",
       "colorimetry", G_TYPE_STRING, "bt601",
       NULL);
      gst_caps_set_features (filtercaps, 0,
       gst_caps_features_new ("memory:GBM", NULL));
      g_object_set (G_OBJECT (appctx.x_raw), "caps", filtercaps, NULL);
      gst_caps_unref (filtercaps);
    Copy to clipboard

GStreamer 元素都属于一种 [GObject](https://docs.gtk.org/gobject/#GObject-struct)。对象属性使用 [g_object_set](https://docs.gtk.org/gobject/#g-object-set) 写入，并使用 [g_object_get](https://docs.gtk.org/gobject/#g-object-get) 读取。

有关以下代码片段的详细信息，可参见：
- [v4l2h264enc 属性](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/v4l2h264enc.html)
- [filesink 属性](https://gstreamer.freedesktop.org/documentation/coreelements/filesink.html?gi-language=c)

/* Set v4l2h264enc */
      g_object_set (G_OBJECT (appctx.v4l2h264enc), "capture-io-mode", 5, NULL);
      g_object_set (G_OBJECT (appctx.v4l2h264enc), "output-io-mode", 5, NULL);
      g_object_set (G_OBJECT (appctx.v4l2h264enc), "controls,video_bitrate", 5000000, NULL);
      g_object_set (G_OBJECT (appctx.v4l2h264enc), "video_bitrate_mode", 0, NULL);
      /* Set filesink */
      g_object_set (G_OBJECT (appctx.filesink), "location", FILE_SINK_LOCATION, NULL);
    Copy to clipboard

[gst_element_link_many](https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c#gst_element_link_many) 链接每个元素：

    /* Link elements */
      if (!gst_element_link_many (appctx.qtiqmmfsrc, appctx.x_raw,
       appctx.v4l2h264enc, appctx.enc_queue, appctx.h264parse, appctx.mp4mux,
       appctx.mux_queue, appctx.filesink, NULL)) {
        g_printerr ("Faile to link elements\n");
        gst_bin_remove_many (GST_BIN(appctx.pipeline), appctx.qtiqmmfsrc, appctx.x_raw,
         appctx.v4l2h264enc, appctx.enc_queue, appctx.h264parse, appctx.mp4mux,
         appctx.mux_queue, appctx.filesink, NULL);
        gst_object_unref (appctx.pipeline);
        return -1;
      }
    Copy to clipboard

g\_main\_loop\_new() 初始化主循环。 gst\_pipeline\_get\_bus() 获取总线引用并注册特定总线消息的回调函数。在这里，针对 `state_changed`、`error` 和 `end-of-stream` (EoS) 总线消息设置了 state\_changed\_cb、 error\_cb 和 eos\_cb 函数。

之后，Pipeline 状态设置为 `GST_STATE_PLAYING`，摄像头流启动。

    /* Initialize main loop */
      if ((appctx.mloop = g_main_loop_new (NULL, FALSE)) == NULL) {
        g_printerr ("ERROR: Failed to create Main loop!\n");
        destroy_pipeline(&appctx);
        return -1;
      }
    
      /* Retrieve reference of the pipeline bus */
      if ((bus = gst_pipeline_get_bus (GST_PIPELINE (appctx.pipeline))) == NULL) {
        g_printerr ("Failed to retrieve pipeline bus\n");
        g_main_loop_unref (appctx.mloop);
        destroy_pipeline(&appctx);
        return -1;
      }
    
      /* Connect watcher to bus signal */
      gst_bus_add_signal_watch (bus);
      g_signal_connect (bus, "message::state-changed",
       G_CALLBACK (state_changed_cb), appctx.pipeline);
      g_signal_connect (bus, "message::error", G_CALLBACK (error_cb), &appctx);
      g_signal_connect (bus, "message::eos", G_CALLBACK (eos_cb), &appctx);
      gst_object_unref (bus);
    
      /* Set pipeline state to PLAYING */
      gst_element_set_state (appctx.pipeline, GST_STATE_PLAYING);
    Copy to clipboard

句柄函数使用 g\_unix\_signal\_add() 注册。如果 Pipeline 进程收到 `SIGINT` 信号，则调用 handle\_interrupt\_signal()。`Main_loop` 将一直持续，直至收到 Ctrl+C 中断信号。

接收到中断信号后， `main_loop` 退出，释放资源，销毁 Pipeline。

    /* Register interrupt handler for main_loop */
      interrupt_watch_id = g_unix_signal_add (SIGINT, handle_interrupt_signal, &appctx);
    
      /* Run mainloop */
    g_main_loop_run (appctx.mloop);
    
      /* Release/Free resources */
      gst_element_set_state (appctx.pipeline, GST_STATE_NULL);
      g_main_loop_unref (appctx.mloop);
      /* destroy pipeline */
      destroy_pipeline(&appctx);
    Copy to clipboard

## 示例

Source: [https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html](https://docs.qualcomm.com/doc/80-70015-17SC/topic/gstreamer_camera_application.html)

示例程序和使用示例演示了摄像头和多摄像头功能。

QIM SDK 包括 [用于摄像头的 GStreamer 示例程序](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/camera-sample-applications.html)，以及用于 [AI/ML 和其他多媒体应用程序](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/example-applications.html)的示例程序。

Note: 在使用示例程序之前，请确保满足 gst-launch-1.0 和 GStreamer 插件的安装先决条件。

下面列出的 [Gstreamer 使用示例](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/multimedia-use-cases.html) 使用了 gst-launch-1.0。

**摄像头和视频编码**

| 示例 | 说明 |
| --- | --- |
| [一个流 - 来自实时源的 1080p AVC RTSP](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/one-stream-1080p-avc-rtsp-from-live-source.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e72"><br>                                    <li class="li">使用单摄像头的单流用例</li><br><br>                                    <li class="li">一个 1080P 流视频编码</li><br><br>                                    <li class="li">使用 RTSP 的 1080P 网络流</li><br><br>                                </ul> |
| [来自实时源的三个 1080p AVC 数据流](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/three-1080p-avc-streams-from-live-source.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e94"><br>                                    <li class="li">使用单摄像头的三流用例</li><br><br>                                    <li class="li">三个 1,080P 流视频编码</li><br><br>                                    <li class="li">每个流的视频文件保存</li><br><br>                                </ul> |
| [三个流 - 来自实时源的 1080p AVC、1080p HEVC 和 1080p YUV](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/three-streams_1080p-avc-1080p-hevc-and-1080p-yuv-from-live-source.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e116"><br>                                    <li class="li">使用单摄像头的三流用例</li><br><br>                                    <li class="li">一个 H264 格式的 1080P 流视频编码并保存视频文件</li><br><br>                                    <li class="li">一个 HEVC 格式的 1080P 流视频编码并保存视频文件</li><br><br>                                    <li class="li">一个用于显示屏的 1080P 流</li><br><br>                                </ul> |
| [三个流 - 来自实时源的 1080p AVC MP4、1080p AVC MPEGTS 和 1080p AVC MP4](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/three-streams-1080p-avc-mp4-1080p-avc-mpegts-and-1080p-avc-mp4-from-live-source.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e141"><br>                                    <li class="li">使用单摄像头的三流用例</li><br><br>                                    <li class="li">一个 H264 格式的 1080P 流视频编码并保存视频文件</li><br><br>                                    <li class="li">一个 MPEGTS 格式的 1080P 流视频编码并保存视频文件</li><br><br>                                    <li class="li">一个 H265 格式的 1080P 流视频编码并保存视频文件</li><br><br>                                </ul> |
| [三个流 - 来自实时源的 1080p AVC 文件保存、1080p AVC RTSP 和 1080p YUV](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/three_streams-1080p-avc-file-save-1080p-avc-rtsp-and-1080p-yuv-from-live-source.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e166"><br>                                    <li class="li">使用单摄像头的三流用例</li><br><br>                                    <li class="li">一个 H264 格式的 1080P 流视频编码并保存视频文件</li><br><br>                                    <li class="li">使用 RTSP 的 1080P 网络流</li><br><br>                                    <li class="li">一个用于显示屏的 1080P 流</li><br><br>                                </ul> |
| [三个流 - 来自实时源的 4k JPEG 快照、1080p AVC MP4 和 1080p YUV](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/three-stream_4k_jpeg_snapshot_1080p_avc_mp4_1080p_yuv_from_live_source.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e192"><br>                                    <li class="li">使用单摄像头的三流用例</li><br><br>                                    <li class="li">一个 H264 格式的 1080P 流视频编码并保存视频文件</li><br><br>                                    <li class="li">一个用于 JPEG 编码的 4k 快照流</li><br><br>                                    <li class="li">一个用于显示屏的 1080P 流</li><br><br>                                </ul> |

**多摄像头/多客户端用例**

| 示例 | 说明 |
| --- | --- |
| [两个流数据流（均为 720p）- 每个摄像头各一个，采用并排拼接方式发送到显示屏](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/two-streams-both-720p-one-from-each-camera-with-side-by-side-stitching-sent-to-display.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e250"><br>                                    <li class="li">来自两个摄像头的两个流 - 每个摄像头一个流</li><br><br>                                    <li class="li">合成单帧（并排拼接）并发送到显示屏</li><br><br>                                </ul> |
| [两个数据流（均为 720p）- 每个摄像头各一个，采用并排拼接方式发送并编码以进行文件保存和 RTSP 流传输](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/two-streams-both-720p-one-from-each-camera-with-side-by-side-stitching-sent-to-encode-for-filesave-and-rtsp-streaming.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e269"><br>                                    <li class="li">来自两个摄像头的两个流 - 每个摄像头一个流</li><br><br>                                    <li class="li">合成单帧（并排拼接）</li><br><br>                                    <li class="li">分流为两个流 - 一个用于视频文件保存，另一个用于使用 RTSP 进行网络流式传输</li><br><br>                                </ul> |
| [两个数据流（均为 720p）- 每个摄像头各一个，采用画中画合成方式，并发送到显示屏](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/two-streams-both-720p-one-from-each-camera-with-picture-in-picture-composition-and-sent-to-display.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e291"><br>                                    <li class="li">来自两个摄像头的两个流 - 每个摄像头一个流</li><br><br>                                    <li class="li">合成单帧（画中画合成）并发送到显示屏</li><br><br>                                </ul> |
| [两个数据流（均为 720p）- 每个摄像头各一个，并采用画中画合成方式发送并编码以进行文件保存和 RTSP 流传输](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/two-streams-720p-one-camera-with-pip-composition-to-encode-filesave-rtsp-streaming.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e310"><br>                                    <li class="li">来自两个摄像头的两个流 - 每个摄像头一个流</li><br><br>                                    <li class="li">合成单帧（画中画合成）</li><br><br>                                    <li class="li">分流为两个流 - 一个用于视频文件保存，另一个用于使用 RTSP 进行网络流式传输</li><br><br>                                </ul> |
| [1080p 至 1080p – 旋转 (90/180/270)](https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-50/1080p-to-1080p-rotate-90-180-270.html) | <ul class="ul" id="id_pjy_wg2_wcc__d9e332"><br>                                    <li class="li">使用单摄像头的单流用例</li><br><br>                                    <li class="li">将帧旋转 180 度并发送到显示屏</li><br><br>                                </ul> |

Last Published: Dec 06, 2024

[Previous Topic
V4L2 接口](https://docs.qualcomm.com/bundle/publicresource/80-70015-17SC/topics/v4l2_interface.md) [Next Topic
高级摄像头功能](https://docs.qualcomm.com/bundle/publicresource/80-70015-17SC/topics/advanced_camera_features.md)