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

# QIM SDK Docker

> Build, configure, and run the QIM SDK Docker container on Qualcomm platforms.

## Overview

Containers are lightweight, isolated environments that package everything needed to run an application — code, dependencies, and system libraries — so it behaves consistently across platforms.

Advantages of containerization include:

* **Consistency:** Containers provide a consistent environment across multiple platforms and operating systems. Developers can create images that transform into containers when deployed, ensuring uniformity regardless of the underlying infrastructure.
* **Automation:** Containerization supports automated tasks. Developers can schedule actions without manual intervention, reducing repetitive work.
* **Stability:** Containers are based on Linux, with the Linux kernel present in every container. This stability extends to systems and devices, including when containers run on macOS or Windows.
* **Space efficiency:** Unlike traditional virtual machines, which consume significant server space and memory, containers include only application code and dependencies. They can run entirely in the cloud and minimize resource requirements.

<Frame>
  <img src="https://mintcdn.com/qimsdk/p8bRJ_K0_Mx14HV0/advanced/images/containers.png?fit=max&auto=format&n=p8bRJ_K0_Mx14HV0&q=85&s=38d6618346b5163a2fdb597b140d3bf7" alt="Container architecture overview" width="877" height="510" data-path="advanced/images/containers.png" />
</Frame>

## QIM SDK in Docker

QIM SDK in a Docker container means the full Qualcomm multimedia and AI software stack is delivered as containerized environments instead of being manually installed directly on a host or target system.

In practice, a build container compiles and assembles all required components, including cross-compiled artifacts for Qualcomm ARM64 targets. The build then produces a deploy container that contains only the runtime pieces needed on the device.

**Key benefits of this approach:**

* **Reproducible builds:** Use the same toolchain, package versions, and scripts across developers and CI. Reduces "works on my machine" failures.
* **Build and runtime separation:** Use a heavy build image to compile artifacts and a lean deploy image that contains only runtime essentials.
* **Efficient cross-compilation:** Build on the host and target ARM64 Qualcomm devices reliably, faster than compiling directly on the target.
* **Secure runtime posture:** Run as a non-root user by default, avoid broad privileged-container dependencies, and use CDI-based explicit hardware passthrough for GPU, camera, and media devices.
* **Operational consistency:** Use versioned images that are testable, promotable, and rollback-friendly, with a predictable deployment flow using environment and CDI configuration on the target.

### Features

* **Debian (Trixie) base:** Built on Debian Trixie for a streamlined and lightweight foundation.
* **No platform dependencies:** Entirely self-sufficient — no eSDK or host platform content required to build or deploy.
* **Self-contained dependencies:** All necessary dependencies are installed directly inside the container, minimizing host-container compatibility issues and simplifying deployment on edge devices.
* **GStreamer 1.26:** Includes GStreamer 1.26 with the latest `gst-qti-oss-patches` for optimized performance on Qualcomm platforms.
* **Broad target support:** Validated across QLI 2.x, Ubuntu Server, and Ubuntu Desktop. Supports IQ615, QCS6490, IQ8275, IQ9075, IQ-X5121 and IQ-X7181 platforms.

### Versions

| Version | Status |
| - | - |
| 2.1.0 | Latest |

This version of image targets only the following platforms. Support for more platforms & OS will be added in upcoming releases.

<Tabs>
  <Tab title="QLI 2.x">
    * QCS6490
    * IQ-9075
    * IQ-8275
    * IQ-615
    * IQ-X7181
    * IQ-X5121
  </Tab>

  <Tab title="Ubuntu 24.04">
    * QCS6490
    * IQ-9075
    * IQ-8275
  </Tab>

  <Tab title="Ubuntu 26.04">
    * IQ-X7181
    * IQ-X5121
  </Tab>
</Tabs>

## Architecture

The following diagram explains the build and deployment flow of the QIM SDK Docker image.

<Frame>
  <img src="https://mintcdn.com/qimsdk/2ihxAnX-B-ATkWe4/advanced/images/imsdkcontainer.png?fit=max&auto=format&n=2ihxAnX-B-ATkWe4&q=85&s=aacb89bf5f1b7b2c75a25226e4a0adb8" alt="QIM SDK Docker build and deployment flow" width="1489" height="754" data-path="advanced/images/imsdkcontainer.png" />
</Frame>

* The host machine runs a development container that compiles all QIM SDK sources and dependencies into Debian artifacts.
* The generated artifacts are transferred to a Debian-based deploy container with CDI-managed hardware access that runs on the Qualcomm device.

## Quick Start Guide

<Note>
  Before getting started, ensure the device is set up by following the [Installation](/installation) guide.
</Note>

<Warning>
  Camera is not supported in the container.
</Warning>

### Download configuration files

Before setting up the device, download the CDI and environment files for the target chipset and OS. The CDI JSON file provides platform-specific device mountings; the environment file sets the required variables inside the container.

Select your chipset to download the corresponding files:

<Tabs>
  <Tab title="QCS6490">
    | Target OS | CDI file | Environment file |
    | - | - | - |
    | QLI 2.x | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs6490_qli_2x_qimsdk.json?inline=false" download>qcs6490\_qli\_2x\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs6490_qli_2x_qimsdk.env?inline=false" download>qcs6490\_qli\_2x\_qimsdk.env</a> |
    | Ubuntu 24.04 Server | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs6490_ubuntu_server_qimsdk.json?inline=false" download>qcs6490\_ubuntu\_server\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs6490_ubuntu_server_qimsdk.env?inline=false" download>qcs6490\_ubuntu\_server\_qimsdk.env</a> |
    | Ubuntu 24.04 Desktop | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs6490_ubuntu_desktop_qimsdk.json?inline=false" download>qcs6490\_ubuntu\_desktop\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs6490_ubuntu_desktop_qimsdk.env?inline=false" download>qcs6490\_ubuntu\_desktop\_qimsdk.env</a> |
  </Tab>

  <Tab title="IQ-8275">
    | Target OS | CDI file | Environment file |
    | - | - | - |
    | QLI 2.x | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs8275_qli_2x_qimsdk.json?inline=false" download>qcs8275\_qli\_2x\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs8275_qli_2x_qimsdk.env?inline=false" download>qcs8275\_qli\_2x\_qimsdk.env</a> |
    | Ubuntu 24.04 Server | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs8275_ubuntu_server_qimsdk.json?inline=false" download>qcs8275\_ubuntu\_server\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs8275_ubuntu_server_qimsdk.env?inline=false" download>qcs8275\_ubuntu\_server\_qimsdk.env</a> |
    | Ubuntu 24.04 Desktop | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs8275_ubuntu_desktop_qimsdk.json?inline=false" download>qcs8275\_ubuntu\_desktop\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs8275_ubuntu_desktop_qimsdk.env?inline=false" download>qcs8275\_ubuntu\_desktop\_qimsdk.env</a> |
  </Tab>

  <Tab title="IQ-9075">
    | Target OS | CDI file | Environment file |
    | - | - | - |
    | QLI 2.x | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs9075_qli_2x_qimsdk.json?inline=false" download>qcs9075\_qli\_2x\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs9075_qli_2x_qimsdk.env?inline=false" download>qcs9075\_qli\_2x\_qimsdk.env</a> |
    | Ubuntu 24.04 Server | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs9075_ubuntu_server_qimsdk.json?inline=false" download>qcs9075\_ubuntu\_server\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs9075_ubuntu_server_qimsdk.env?inline=false" download>qcs9075\_ubuntu\_server\_qimsdk.env</a> |
    | Ubuntu 24.04 Desktop | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs9075_ubuntu_desktop_qimsdk.json?inline=false" download>qcs9075\_ubuntu\_desktop\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs9075_ubuntu_desktop_qimsdk.env?inline=false" download>qcs9075\_ubuntu\_desktop\_qimsdk.env</a> |
  </Tab>

  <Tab title="IQ-615">
    | Target OS | CDI file | Environment file |
    | - | - | - |
    | QLI 2.x | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/qcs615_qli_2x_qimsdk.json?inline=false" download>qcs615\_qli\_2x\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/qcs615_qli_2x_qimsdk.env?inline=false" download="qcs615_qli_2x_qimsdk.env">qcs615\_qli\_2x\_qimsdk.env</a> |
  </Tab>

  <Tab title="IQ-X7181">
    | Target OS | CDI file | Environment file |
    | - | - | - |
    | QLI 2.x | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/iqx7181_qli_2x_qimsdk.json?inline=false" download>iqx7181\_qli\_2x\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/iqx7181_qli_2x_qimsdk.env?inline=false" download>iqx7181\_qli\_2x\_qimsdk.env</a> |
    | Ubuntu 26.04 Server | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/iqx7181_ubuntu_server_qimsdk.json?inline=false" download>iqx7181\_ubuntu\_server\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/iqx7181_ubuntu_server_qimsdk.env?inline=false" download>iqx7181\_ubuntu\_server\_qimsdk.env</a> |
    | Ubuntu 26.04 Desktop | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/iqx7181_ubuntu_desktop_qimsdk.json?inline=false" download>iqx7181\_ubuntu\_desktop\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/iqx7181_ubuntu_desktop_qimsdk.env?inline=false" download>iqx7181\_ubuntu\_desktop\_qimsdk.env</a> |
  </Tab>

  <Tab title="IQ-X5121">
    | Target OS | CDI file | Environment file |
    | - | - | - |
    | QLI 2.x | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/iqx5121_qli_2x_qimsdk.json?inline=false" download>iqx5121\_qli\_2x\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/iqx5121_qli_2x_qimsdk.env?inline=false" download>iqx5121\_qli\_2x\_qimsdk.env</a> |
    | Ubuntu 26.04 Server | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/iqx5121_ubuntu_server_qimsdk.json?inline=false" download>iqx5121\_ubuntu\_server\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/iqx5121_ubuntu_server_qimsdk.env?inline=false" download>iqx5121\_ubuntu\_server\_qimsdk.env</a> |
    | Ubuntu 26.04 Desktop | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/cdi/iqx5121_ubuntu_desktop_qimsdk.json?inline=false" download>iqx5121\_ubuntu\_desktop\_qimsdk.json</a> | <a href="https://git.codelinaro.org/clo/le/sdk-tools/-/raw/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/env/iqx5121_ubuntu_desktop_qimsdk.env?inline=false" download>iqx5121\_ubuntu\_desktop\_qimsdk.env</a> |
  </Tab>
</Tabs>

### Set up and run on the device

<Tabs>
  <Tab title="QLI 2.x">
    <Steps>
      <Step title="SSH into the device">
        ```bash theme={null}
        ssh <user>@<device-ip>
        ```
      </Step>

      <Step title="Create required directories">
        ```bash theme={null}
        mkdir -p /etc/cdi
        mkdir -p /etc/docker/env
        mkdir -p $HOME/Downloads/qimsdk_samples

        mkdir -p $HOME/Downloads/qimsdk_samples/media
        mkdir -p $HOME/Downloads/qimsdk_samples/models
        mkdir -p $HOME/Downloads/qimsdk_samples/labels
        ```
      </Step>

      <Step title="Copy the downloaded configuration files to the device">
        ```bash theme={null}
        scp <downloaded-cdi-file>.json <user>@<device-ip>:/etc/cdi/qimsdk.json
        scp <downloaded-env-file>.env <user>@<device-ip>:/etc/docker/env/qimsdk.env
        ```

        <AccordionGroup>
          <Accordion title="Additional step to configure nodes for video driver and USB camera">
            On platforms such as iq615, iqx7181, and iqx8121, the Qualcomm downstream video drivers (`video32` and `video33`) are unavailable. Therefore, the upstream video driver is used. Since the upstream driver may be assigned to any device node between `/dev/video0` and `/dev/video28`, an additional configuration step is required to determine and configure the appropriate video nodes.

            Run the following command to list the video devices:

            ```bash theme={null}
            v4l2-ctl --list-devices
            ```

            Example:

            ```bash theme={null}
                Qualcomm Venus video decoder (plat:aa00000.video-codec:dec):
                    /dev/video2

                Qualcomm Venus video encoder (plat:aa00000.video-codec:enc):
                    /dev/video3

                USB Camera (usb-0000:00:14.0-3):
                    /dev/video4
                    /dev/video5
            ```

            Identify the relevant video device nodes and add them to the cdi.json file that has been deployed to the target system before creating the container.

            ```
            "deviceNodes": [
              ...
              {
                "path": "/dev/video2",
                "uid": 0,
                "gid": 44
              },
              {
                "path": "/dev/video3",
                "uid": 0,
                "gid": 44
              },
              {
                "path": "/dev/video4",
                "uid": 0,
                "gid": 44
              },
              {
                "path": "/dev/video5",
                "uid": 0,
                "gid": 44
              },
              ...
            ]
            ```
          </Accordion>
        </AccordionGroup>
      </Step>

      <Step title="Pull the container image">
        <Tabs>
          <Tab title="Native Image">
            The QIM SDK native image is intended for native pipeline execution and includes all required runtime dependencies for QIM SDK applications. Python dependencies are intentionally excluded to keep the image lightweight and user can use the QIM SDK Python image for python support.

            ```bash theme={null}
            docker pull artifacts.codelinaro.org/iot-solutions-microservices/qimsdk:latest
            ```

            Tag the image locally:

            ```bash theme={null}
            docker tag artifacts.codelinaro.org/iot-solutions-microservices/qimsdk:latest qimsdk:latest
            ```
          </Tab>

          <Tab title="Python Image">
            The QIM SDK Python image includes all functionality available in the base image, along with Python support.

            ```bash theme={null}
            docker pull artifacts.codelinaro.org/iot-solutions-microservices/qimsdk-python:latest
            ```

            Tag the image locally:

            ```bash theme={null}
              docker tag artifacts.codelinaro.org/iot-solutions-microservices/qimsdk-python:latest qimsdk-python:latest
            ```
          </Tab>
        </Tabs>
      </Step>

      <Step title="Run the container">
        <AccordionGroup>
          <Accordion title="Additional step for SE-Linux enabled builds">
            An additional step is required for SE-Linux enabled builds to provide access to cdi, env & media artifacts.

            ```bash theme={null}
            # After pushing the CDI file to the device run the following command
            restorecon -Rv /etc/cdi

            # To get access to wayland and pipewire sockets.
            setsebool -P dockerd_connect_user_services on

            # To get access to the user Downloads directory
            setsebool -P dockerd_mounton_xdg_downloads on
            ```

            ```bash theme={null}
            # Run the following commands whenever new artifacts are uploaded to the paths below.
            chcon -t xdg_downloads_t /var/roothome/Downloads
            chcon -R -t xdg_downloads_t /var/roothome/Downloads/qimsdk_samples
            ```
          </Accordion>
        </AccordionGroup>

        ```bash theme={null}
        # The following docker run command mounts $HOME/Downloads/qimsdk_samples
        # into the container for media assets and application artifacts.
        # Using this path is recommended to avoid potential SELinux permission issues.

        docker run -it -d \
            --net host \
            --env-file /etc/docker/env/qimsdk.env \
            -v $HOME/Downloads/qimsdk_samples:/home/qimsdk/Downloads/qimsdk_samples \
            --device qualcomm.com/device=qimsdk \
            -h <host_name> \
            --name <desired-container-name> \
            <generated-image-name>
        ```

        After the container is running, execute a new terminal process in it:

        ```bash theme={null}
        docker exec -ti <desired-container-name> bash
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Ubuntu">
    <Steps>
      <Step title="SSH into the device">
        ```bash theme={null}
        ssh <user>@<device-ip>
        ```
      </Step>

      <Step title="Install docker">
        ```bash theme={null}
        sudo apt update
        sudo apt install docker.io
        sudo usermod -aG docker $USER
        # Log out and log back in for the group membership changes to take effect.
        ```
      </Step>

      <Step title="Create required directories">
        ```bash theme={null}
        sudo mkdir -p /etc/cdi
        sudo mkdir -p /etc/docker/env
        mkdir -p $HOME/Downloads/qimsdk_samples

        mkdir -p $HOME/Downloads/qimsdk_samples/media
        mkdir -p $HOME/Downloads/qimsdk_samples/models
        mkdir -p $HOME/Downloads/qimsdk_samples/labels

        ```
      </Step>

      <Step title="Copy the downloaded configuration files to the device">
        ```bash theme={null}
        scp <downloaded-cdi-file>.json <user>@<device-ip>:/etc/cdi/qimsdk.json
        scp <downloaded-env-file>.env <user>@<device-ip>:/etc/docker/env/qimsdk.env
        ```

        <AccordionGroup>
          <Accordion title="Additional step to configure nodes for video driver and USB camera">
            On platforms such as iq615, iqx7181, and iqx8121, the Qualcomm downstream video drivers (`video32` and `video33`) are unavailable. Therefore, the upstream video driver is used. Since the upstream driver may be assigned to any device node between `/dev/video0` and `/dev/video28`, an additional configuration step is required to determine and configure the appropriate video nodes.

            Run the following command to list the video devices:

            ```bash theme={null}
              sudo apt install v4l-utils
              v4l2-ctl --list-devices
            ```

            Example:

            ```bash theme={null}
                Qualcomm Venus video decoder (plat:aa00000.video-codec:dec):
                    /dev/video2

                Qualcomm Venus video encoder (plat:aa00000.video-codec:enc):
                    /dev/video3

                USB Camera (usb-0000:00:14.0-3):
                    /dev/video4
                    /dev/video5
            ```

            Identify the relevant video device nodes and add them to the cdi.json file that has been deployed to the target system before creating the container.

            ```
             "deviceNodes": [
               ...
               {
                 "path": "/dev/video2",
                 "uid": 0,
                 "gid": 44
               },
               {
                 "path": "/dev/video3",
                 "uid": 0,
                 "gid": 44
               },
               {
                 "path": "/dev/video4",
                 "uid": 0,
                 "gid": 44
               },
               {
                 "path": "/dev/video5",
                 "uid": 0,
                 "gid": 44
               },
               ...
             ]
            ```
          </Accordion>
        </AccordionGroup>
      </Step>

      <Step title="Pull the container image">
        <Tabs>
          <Tab title="Native Image">
            The QIM SDK native image is intended for native pipeline execution and includes all required runtime dependencies for QIM SDK applications. Python dependencies are intentionally excluded to keep the image lightweight and user can use the QIM SDK Python image for python support.

            ```bash theme={null}
            docker pull artifacts.codelinaro.org/iot-solutions-microservices/qimsdk:latest
            ```

            Tag the image locally:

            ```bash theme={null}
            docker tag artifacts.codelinaro.org/iot-solutions-microservices/qimsdk:latest qimsdk:latest
            ```
          </Tab>

          <Tab title="Python Image">
            The QIM SDK Python image includes all functionality available in the base image, along with Python support.

            ```bash theme={null}
            docker pull artifacts.codelinaro.org/iot-solutions-microservices/qimsdk-python:latest
            ```

            Tag the image locally:

            ```bash theme={null}
            docker tag artifacts.codelinaro.org/iot-solutions-microservices/qimsdk-python:latest qimsdk-python:latest
            ```
          </Tab>
        </Tabs>
      </Step>

      <Step title="Run the container">
        ```bash theme={null}
        # The following docker run command mounts $HOME/Downloads/qimsdk_samples
        # into the container for media assets and application artifacts.
        # Using this path is recommended to avoid potential SELinux permission issues.

        # Automatically detect and pass the active Wayland display to the container,
        # as the WAYLAND_DISPLAY name may vary across systems and display configurations

        sudo docker run -it -d \
          --net host \
          -e WAYLAND_DISPLAY=$(basename \
              $(ls ${XDG_RUNTIME_DIR}/wayland-* 2>/dev/null | head -n1) \
              2>/dev/null) \
          --env-file /etc/docker/env/qimsdk.env \
          -v $HOME/Downloads/qimsdk_samples:/home/qimsdk/Downloads/qimsdk_samples \
          --device qualcomm.com/device=qimsdk \
          -h <host_name> \
          --name <desired-container-name> \
          <generated-image-name>
        ```

        After the container is running, execute a new terminal process in it:

        ```bash theme={null}
        sudo docker exec -ti <desired-container-name> bash
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

Once inside the container, refer to the **Examples** section to run

* [AI pipelines](/sample-pipelines/aipipelines)
* [multimedia pipelines](/sample-pipelines/multimediapipelines)
* [GStreamer C/C++ AI applications](/sample-application/ai-sample-applications)
* [GStreamer C/C++ multimedia applications](/sample-application/multimedia-sample-applications)
* [C++ App Builder](/app-builder/cpp-quickstart)
* [Python App Builder](/app-builder/python-quickstart)

### Running GStreamer Sample applications inside container

By default, sample application configuration files are installed under `/etc/configs`. However, this location cannot be mounted into the container due to SELinux restrictions.

On the platform, copy the configuration files to `$HOME/Downloads/qimsdk_samples/configs`. Because `$HOME/Downloads/qimsdk_samples` is mounted into the container by the previous docker run command, the `configs` directory will be accessible from within the container.

```bash theme={null}
mkdir -p $HOME/Downloads/qimsdk_samples/configs
cp /etc/configs/* $HOME/Downloads/qimsdk_samples/configs
chmod -R 0777 $HOME/Downloads/qimsdk_samples/configs
```

Inside the container, use `--config-file` argument to pass config file to sample app:

```bash theme={null}
gst-ai-classification \
    --config-file=$HOME/Downloads/qimsdk_samples/configs/config_classification.json
```

## Build an QIM SDK container

<Note>
  All steps in this section are performed on a Ubuntu 22.04 or 24.04 machine which can be x86 or ARM64.
</Note>

### Prerequisites

<AccordionGroup>
  <Accordion title="Ubuntu packages">
    Install prerequisite packages on the host (one time only).

    <Tabs>
      <Tab title="ARM64">
        ```bash theme={null}
        sudo apt install -y jq tofrodos
        sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq
        sudo chmod +x /usr/bin/yq
        ```
      </Tab>

      <Tab title="x86">
        ```bash theme={null}
        sudo apt install -y jq tofrodos qemu-user-static qemu-system-arm
        sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq
        sudo chmod +x /usr/bin/yq
        wget http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu/qemu-user-static_6.2+dfsg-2ubuntu6_amd64.deb
        sudo dpkg -i qemu-user-static_6.2+dfsg-2ubuntu6_amd64.deb
        rm qemu-user-static_6.2+dfsg-2ubuntu6_amd64.deb
        ```
      </Tab>
    </Tabs>

    <Warning>
      Do **not** install `yq` via snap. If it was installed via snap, remove it and reinstall using the commands above:

      ```bash theme={null}
      sudo snap remove yq
      sudo systemctl stop snapd
      ```
    </Warning>
  </Accordion>

  <Accordion title="File watcher limits">
    Increase the maximum user watches and instances on the host to prevent this error during development:

    ```text theme={null}
    System limit for number of file watchers reached
    ```

    Add these lines to `/etc/sysctl.conf`:

    ```text theme={null}
    fs.inotify.max_user_instances=8192
    fs.inotify.max_user_watches=542288
    ```

    Save the file and reboot the host system.
  </Accordion>

  <Accordion title="Swap image">
    To build Docker image files, the host system requires at least 64 GB of RAM and a swap image of at least half the available RAM plus a small reserve.

    For example, with 64 GB of RAM, the recommended swap size is at least 32 GB. With an 8 GB reserve, total RAM + swap + reserved memory is 104 GB.

    Check whether swap is enabled:

    ```bash theme={null}
    sudo swapon --show
    ```

    If swap is missing or too small, create a new swap file:

    ```bash theme={null}
    MEM_AVAIL=$(grep MemAvailable /proc/meminfo | awk '{printf "%.0f\n", $2/1024/1024}')
    let MEM_SWAP="$MEM_AVAIL / 2 + 8"
    sudo swapoff /swap.img
    sudo fallocate -l "${MEM_SWAP}G" /swap.img
    sudo chmod 600 /swap.img
    sudo mkswap /swap.img
    sudo swapon /swap.img
    ```

    Edit `/etc/default/grub` and set:

    ```text theme={null}
    GRUB_CMDLINE_LINUX_DEFAULT="text cgroup_enable=memory swapaccount=1"
    ```

    Update GRUB:

    ```bash theme={null}
    sudo update-grub
    ```

    Edit `/etc/fstab` and add this line at the end of the file:

    ```text theme={null}
    /swap.img none swap sw 0 0
    ```

    Save and close all opened system files, then reboot the host system.

    After rebooting, verify the swap image matches the expected size:

    ```bash theme={null}
    sudo swapon --show
    ```
  </Accordion>

  <Accordion title="Configure Docker">
    Docker must be configured on the host system once before building images.

    <AccordionGroup>
      <Accordion title="Remove old versions">
        Remove old Docker Desktop versions if present:

        ```bash theme={null}
        sudo apt remove docker-desktop
        rm -r ~/.docker/desktop
        sudo rm /usr/local/bin/com.docker.cli
        sudo apt purge docker-desktop
        ```
      </Accordion>

      <Accordion title="Set up the Docker repository">
        Install repository dependencies:

        ```bash theme={null}
        sudo apt-get update
        sudo apt-get install \
          ca-certificates \
          curl \
          gnupg \
          lsb-release
        ```

        Create the Docker keyring directory:

        ```bash theme={null}
        sudo mkdir -p /etc/apt/keyrings
        ```

        Add the Docker GPG key:

        ```bash theme={null}
        curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
        ```

        Add the Docker repository:

        ```bash theme={null}
        echo \
          "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
          $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
        ```
      </Accordion>

      <Accordion title="Install Docker Engine">
        ```bash theme={null}
        sudo apt-get update
        sudo apt-get install docker-ce docker-ce-cli
        ```
      </Accordion>

      <Accordion title="Add user to the Docker group">
        Add the user to the Docker group to run Docker commands without `sudo`:

        ```bash theme={null}
        sudo groupadd docker
        sudo usermod -aG docker $USER
        newgrp docker
        ```

        <Note>
          Until the host is rebooted, run `newgrp docker` in every newly opened terminal.
        </Note>
      </Accordion>

      <Accordion title="Add a registry mirror (optional)">
        <Warning>
          Tabs, unexpected spaces, and other invisible whitespace characters can break JSON configuration files and may cause a `docker.service failed to start` error.
        </Warning>

        Add the registry mirror configuration to `/etc/docker/daemon.json`:

        ```json theme={null}
        {
          "registry-mirrors": ["<docker-registry-mirror-url>"]
        }
        ```

        Restart Docker:

        ```bash theme={null}
        sudo fromdos -f /etc/docker/daemon.json
        sudo systemctl daemon-reload
        sudo systemctl restart docker
        ```
      </Accordion>

      <Accordion title="Configure proxy (optional)">
        If network downloads require a proxy, add the proxy configuration to the Docker daemon.

        <Warning>
          Tabs, unexpected spaces, and other invisible whitespace characters can break JSON configuration files and may cause a `docker.service failed to start` error.
        </Warning>

        Add the proxy configuration to `/etc/docker/daemon.json`:

        ```json theme={null}
        {
          "proxies": {
            "http-proxy": "<http-proxy-url>",
            "https-proxy": "<https-proxy-url>",
            "no-proxy": "<no-proxy-url>"
          }
        }
        ```

        Restart Docker:

        ```bash theme={null}
        sudo fromdos -f /etc/docker/daemon.json
        sudo systemctl daemon-reload
        sudo systemctl restart docker
        ```

        Set proxy environment variables before invoking Docker build commands:

        ```bash theme={null}
        export http_proxy=<http-proxy-url>
        export https_proxy=<https-proxy-url>
        export no_proxy=<no-proxy-url>
        ```

        This ensures that both the Docker daemon and build processes use the same proxy settings as the host system.

        <Note>
          Until the host is rebooted, run `newgrp docker` in every newly opened terminal.
        </Note>
      </Accordion>

      <Accordion title="Test the Docker setup (optional)">
        Run the Docker hello-world container:

        ```bash theme={null}
        docker run hello-world
        ```
      </Accordion>

      <Accordion title="Move the Docker directory (optional)">
        If the build image script fails with a `No space left on device` error, move the Docker directory to `/local/mnt`.

        <Warning>
          All containers must be restarted after moving the Docker directory because the Docker service is stopped during this procedure.
        </Warning>

        Stop Docker:

        ```bash theme={null}
        service docker stop
        ```

        Verify that no Docker process is running:

        ```bash theme={null}
        ps faux
        ```

        Check the Docker directory structure:

        ```bash theme={null}
        sudo ls /var/lib/docker/
        ```

        Back up the current Docker directory:

        ```bash theme={null}
        tar -zcC /var/lib docker > /mnt/pd0/var_lib_docker-backup-$(date +%s).tar.gz
        ```

        Move the Docker directory to the new partition:

        ```bash theme={null}
        mv /var/lib/docker /local/mnt/docker
        ```

        Create a symlink to the Docker directory in the new partition:

        ```bash theme={null}
        ln -s /local/mnt/docker /var/lib/docker
        ```

        Verify that the Docker directory structure is unchanged:

        ```bash theme={null}
        sudo ls /var/lib/docker/
        ```

        Start Docker:

        ```bash theme={null}
        service docker start
        ```

        List container names:

        ```bash theme={null}
        docker ps -a
        ```

        Start a listed container:

        ```bash theme={null}
        docker start <container-name>
        ```
      </Accordion>
    </AccordionGroup>
  </Accordion>

  <Accordion title="Configure system memory">
    Check that there are no active cgroup CPU and memory utilization restrictions on the host. The Docker service cgroup memory configuration entries should have `max` set as the value.

    ```bash theme={null}
    sudo systemctl list-unit-files | grep -Ei docker
    sudo systemctl status docker.service
    cat /sys/fs/cgroup/system.slice/docker.service/
    cat /sys/fs/cgroup/system.slice/docker.service/memory.max
    cat /sys/fs/cgroup/system.slice/docker.service/memory.swap.max
    ```

    <AccordionGroup>
      <Accordion title="Tune VM settings (optional)">
        If the host system has 64 GB RAM or less, tune system VM page swap and dentry and inode cache reclaim behavior.

        **`vm.swappiness`**

        Higher values cause more aggressive application memory page swapping; lower values favor keeping pages in memory longer. The default is usually `60` on recent Ubuntu and Debian versions, which may not fit the Docker build environment on systems with low available RAM. A value of `10` is recommended.

        **`vm.vfs_cache_pressure`**

        Intermittent high VFS pressure can result from creating many small temporary files during package installation, causing the OS to prematurely swap memory pages associated with cached dentries and inodes. The default is usually `100`. Setting it to `400` relaxes cache management by freeing cached pages earlier, reducing the chance of running out of memory during high multi-threaded load.

        **`vm.min_free_kbytes`**

        In heavy multi-stage Docker builds with many buildx threads, the host OS can exhaust available RAM quickly. The mandatory VM free memory watermark is controlled by `vm.min_free_kbytes`. Too low risks deadlocks under load; too high causes premature OOM kills. A value of `262144` KB better balances free memory under excessive load.

        Edit `/etc/sysctl.conf` and add:

        ```text theme={null}
        vm.swappiness=10
        vm.vfs_cache_pressure=400
        vm.min_free_kbytes=262144
        ```
      </Accordion>
    </AccordionGroup>
  </Accordion>
</AccordionGroup>

### Build steps

<Steps>
  <Step title="Fetch the source code">
    Run the following commands on the host machine:

    ```bash theme={null}
    git clone https://git.codelinaro.org/clo/le/sdk-tools.git -b imsdk-tools.lnx.1.0
    cd sdk-tools/qimsdk-debian/
    git checkout fcc71f5f12791f77d8174cb5772eab6c785578d7
    ```
  </Step>

  <Step title="Build the image">
    <Tabs>
      <Tab title="Native image">
        Build `qimsdk_deploy_arm64`, which contains the minimal set of runtime binaries needed to execute GStreamer use cases:

        ```bash theme={null}
        docker build \
          --build-arg QIMSDK_ARG_QNP_VERSION=<QAIRT_SDK_VERSION> \
          --build-arg QIMSDK_ARG_CAMERA_SERVICE_TAG=<CAMERA_SERVICE_TAG_OR_COMMIT> \
          --build-arg QIMSDK_ARG_GST_PLUGINS_TAG=<QIMSDK_PLUGINS_TAG_OR_COMMIT>\
          --build-arg QIMSDK_ARG_SOLUTIONS_MICROSERVICES_TAG=<SOLUTIONS_MICROSERVICES_TAG_OR_COMIT> \
          --build-arg QIMSDK_ARG_GST_QTI_OSS_PATCHES_TAG=<GST_QTI_OSS_PATCHES_TAG_OR_COMMIT> \
          --build-arg QIMSDK_ARG_MAX_JOBS=<MAX_JOB_THREADS> \
          --target qimsdk_deploy_arm64 \
          -t qimsdk \
          .
        ```

        For example:
        Docker build command for `2.1.0` release

        ```bash theme={null}
          docker build \
            --build-arg QIMSDK_ARG_QNP_VERSION=2.50.0.260828 \
            --build-arg QIMSDK_ARG_CAMERA_SERVICE_TAG=1.0.6 \
            --build-arg QIMSDK_ARG_GST_PLUGINS_TAG=2.0.2 \
            --build-arg QIMSDK_ARG_SOLUTIONS_MICROSERVICES_TAG=805fd443c8ffe75eed16ca54a68602535c80e232 \
            --build-arg QIMSDK_ARG_GST_QTI_OSS_PATCHES_TAG=a4db6968a1f467875407a2008d7c13974a826fe4 \
            --build-arg QIMSDK_ARG_MAX_JOBS=8 \
            --target qimsdk_deploy_arm64 \
            -t qimsdk \
            .
        ```
      </Tab>

      <Tab title="Python image">
        Build `qimsdk_deploy_py_arm64`, which contains the minimal set of runtime binaries needed to execute GStreamer use cases along with python support:

        ```bash theme={null}
        docker build \
          --build-arg QIMSDK_ARG_QNP_VERSION=<QAIRT_SDK_VERSION> \
          --build-arg QIMSDK_ARG_CAMERA_SERVICE_TAG=<CAMERA_SERVICE_TAG_OR_COMMIT> \
          --build-arg QIMSDK_ARG_GST_PLUGINS_TAG=<QIMSDK_PLUGINS_TAG_OR_COMMIT>\
          --build-arg QIMSDK_ARG_SOLUTIONS_MICROSERVICES_TAG=<SOLUTIONS_MICROSERVICES_TAG_OR_COMIT> \
          --build-arg QIMSDK_ARG_GST_QTI_OSS_PATCHES_TAG=<GST_QTI_OSS_PATCHES_TAG_OR_COMMIT> \
          --build-arg QIMSDK_ARG_MAX_JOBS=<MAX_JOB_THREADS> \
          --target qimsdk_deploy_py_arm64 \
          -t qimsdk-python \
          .
        ```

        For example:
        Docker build command for `2.1.0` release

        ```bash theme={null}
          docker build \
            --build-arg QIMSDK_ARG_QNP_VERSION=2.50.0.260828 \
            --build-arg QIMSDK_ARG_CAMERA_SERVICE_TAG=1.0.6 \
            --build-arg QIMSDK_ARG_GST_PLUGINS_TAG=2.0.2 \
            --build-arg QIMSDK_ARG_SOLUTIONS_MICROSERVICES_TAG=805fd443c8ffe75eed16ca54a68602535c80e232 \
            --build-arg QIMSDK_ARG_GST_QTI_OSS_PATCHES_TAG=a4db6968a1f467875407a2008d7c13974a826fe4 \
            --build-arg QIMSDK_ARG_MAX_JOBS=8 \
            --target qimsdk_deploy_py_arm64 \
            -t qimsdk-python \
            .
        ```
      </Tab>
    </Tabs>

    #### Build Arguments

    | Argument | Description | Default |
    | - | - | - |
    | *QIMSDK\_ARG\_QNP\_VERSION* | Specifies the QAIRT SDK version to use. If not provided, the QNN and SNPE plugins are not built. | Not set |
    | *QIMSDK\_ARG\_CAMERA\_SERVICE\_TAG* | Commit ID or tag from the [Qualcomm Camera Service repository](https://github.com/qualcomm/camera-service) | `main` |
    | *QIMSDK\_ARG\_GST\_PLUGINS\_TAG* | Commit ID or tag from the [qimsdk](https://github.com/qualcomm/qimsdk) repository. | `main` |
    | *QIMSDK\_ARG\_SOLUTIONS\_MICROSERVICES\_TAG* | Commit ID or tag from the [solutions-microservices](https://git.codelinaro.org/clo/le/solutions-microservices/) repository. | `iot-solutions.lnx.1.0` |
    | *QIMSDK\_ARG\_GST\_QTI\_OSS\_PATCHES\_TAG* | Commit ID or tag from the [gst-qti-oss-patches](https://github.com/qualcomm/gst-qti-oss-patches) repository. | `1.26.2` |
    | *QIMSDK\_ARG\_MAX\_JOBS* | Limits the maximum number of parallel build jobs used during image creation. Valid values range from `1` to the number of available CPU cores (`nproc`). | All available CPU cores |

    <Info>
      See [qimsdk-debian/README.md](https://git.codelinaro.org/clo/le/sdk-tools/-/blob/fcc71f5f12791f77d8174cb5772eab6c785578d7/qimsdk-debian/README.md) for more information about the Docker image composition and workflow.
    </Info>
  </Step>

  <Step title="Save the image">
    Save the built image as a tar file:

    ```bash theme={null}
    docker save -o <image_name>.tar <generated-image-name>
    ```
  </Step>

  <Step title="Copy and load the image on the device">
    Copy the tar file to the device:

    ```bash theme={null}
    scp <image_name>.tar <user>@<device-ip>:~/Downloads/
    ```

    Load the image on the device:

    ```bash theme={null}
    docker load -i ~/Downloads/<image_name>.tar
    ```

    <Note>
      The home directory (\~) varies by platform:

      * QLI 2.x: /root
      * Ubuntu Noble: /home/ubuntu
      * Ubuntu Resolute: /home/qcom
    </Note>
  </Step>

  <Step title="Run the container on the device">
    With the image copied to the device, follow the [Set up and run on the device](#set-up-and-run-on-the-device) steps to configure CDI and start the container.
  </Step>
</Steps>

## Install additional packages inside the container

Use this procedure to install packages into an already running `qimsdk-debian` deploy container. The container must have been started with the `--net host` option. The following steps use vi as an example.

<Steps>
  <Step title="Execute a shell in the container as root">
    ```bash theme={null}
    docker exec -ti qimsdk sh
    ```
  </Step>

  <Step title="Install apt packages">
    In the root shell, install the required packages:

    ```bash theme={null}
    apt-get update
    DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC \
        apt-get install -y --no-install-recommends vi
    apt -y upgrade
    apt-get autoremove -y
    apt-get clean
    ```
  </Step>
</Steps>

After installing the vi package in the previous step, it can be launched from any new shell session started as the `qimsdk` user:

```bash theme={null}
docker exec -ti qimsdk bash
```

## Debugging

The following techniques apply to the QIM SDK container running on the Qualcomm device.

### Check container logs

<Steps>
  <Step title="Stream live logs">
    ```bash theme={null}
    docker logs -f <container-name>
    ```
  </Step>

  <Step title="Print the last 100 lines and follow">
    ```bash theme={null}
    docker logs --tail 100 -f <container-name>
    ```
  </Step>
</Steps>

### Inspect container state

<Steps>
  <Step title="List all containers and their status">
    ```bash theme={null}
    docker ps -a
    ```
  </Step>

  <Step title="Inspect container metadata">
    Inspect detailed container metadata including environment variables, mounts, and network settings:

    ```bash theme={null}
    docker inspect <container-name>
    ```
  </Step>
</Steps>

### Restart a container

<Steps>
  <Step title="Stop the container">
    ```bash theme={null}
    docker stop <container-name>
    ```
  </Step>

  <Step title="Start the container">
    ```bash theme={null}
    docker start <container-name>
    ```
  </Step>
</Steps>
