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

# qtijpegenc

>  JPEG encoding plugin

<Note>
  qtijpegenc is only available in `qcom-multimedia-proprietary-image` <br />
  For more information on QLI images refer to [Qualcomm Linux release](https://dragonwingdocs.qualcomm.com/Key-Documents/Yocto-Guide/add-image-recipes#qualcomm-reference-images)
</Note>

# Overview

`qtijpegenc` is a hardware-accelerated GStreamer element that performs JPEG encoding of raw video frames in ***NV12*** and ***NV21*** formats. Raw frames can be provided by either live source such as ISP Camera, or any other source which can generate NV12/21 frames. It is designed for use cases such as high-quality snapshot capture from an ISP camera and offline video sources. The element leverages the ***Camera Service*** and the ***Offline JPEG engine*** to generate JPEG images with low latency and high image quality. It is therefore well suited for camera snapshot pipelines, timelapse capture, and other still-image encoding workflows that require efficient, high-performance JPEG generation.

<img src="https://mintcdn.com/qimsdk/wRkQhG1eZWNSwiNj/plugin-reference/images/qtijpegenc1.png?fit=max&auto=format&n=wRkQhG1eZWNSwiNj&q=85&s=e16ffa29e094ed30a59fb2210185cf42" alt="" width="801" height="101" data-path="plugin-reference/images/qtijpegenc1.png" />

In contrast to software-based JPEG encoders, `qtijpegenc` leverages the Qualcomm hardware JPEG engine to offload encoding from the CPU, enabling efficient parallel processing with reduced CPU overhead.

It also supports downscaling, allowing the output JPEG image to be generated at a lower resolution than the input raw frame. This is particularly useful for use cases such as generating thumbnails alongside full-resolution image captures.

**Typical use cases include:**

* **Camera snapshots:** Capturing still JPEG images from a live camera stream
* **Timelapse recording:** Periodically saving frames as JPEG images alongside video recording
* **Thumbnail generation:** Encoding a downscaled JPEG image in parallel with a full-resolution stream
* **Multi-resolution capture:** Encoding the same frame at multiple resolutions simultaneously using a `tee`

## Example Pipeline

<img src="https://mintcdn.com/qimsdk/wRkQhG1eZWNSwiNj/plugin-reference/images/qtijpegenc_example_pipeline.png?fit=max&auto=format&n=wRkQhG1eZWNSwiNj&q=85&s=f21d9307a3c3a54fd088c5a8dbf4ca5f" alt="" width="1051" height="71" data-path="plugin-reference/images/qtijpegenc_example_pipeline.png" />

<Steps>
  <Step title="Download Required Files">
    | File         | Download                                                                                                                                               | Save as     |
    | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- |
    | Sample video | <a href="https://github.com/qualcomm/sample-apps-for-qualcomm-linux/raw/refs/heads/main/qualcomm-linux/artifacts/videos/demo_samples/">Input video</a> | `video.mp4` |
  </Step>

  <Step title="Copy files to device">
    <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/{media,media/output}"
      scp video.mp4   <user>@<device-ip>:$HOME/media/
      ```
    </CodeGroup>
  </Step>

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

  <Step title="Set environment variables">
    Run below command on your device

    ```bash theme={null}
    export SRC_VIDEO_NAME=video.mp4
    ```
  </Step>

  <Step title="Run the pipeline">
    ```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 ! \
    qtijpegenc quality=90 ! \
    multifilesink location=$HOME/media/output/frame_%05d.jpg
    ```
  </Step>
</Steps>

# Hierarchy

[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" />[GstVideoEncoder](https://gstreamer.freedesktop.org/documentation/video/gstvideoencoder.html?gi-language=c)<br />
            <Icon icon="arrow-turn-down-right" iconType="solid" />qtijpegenc

# Pad Templates

### sink

| Capabilities           |                                                                                                                         |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `video/x-raw`          | `format: { NV12, NV21 }` <br /> `width: [1, 32767]` <br /> `height: [1, 32767]` <br /> `framerate: [0/1, 2147483647/1]` |
| Availability: *Always* |                                                                                                                         |
| Direction: *sink*      |                                                                                                                         |

### src

| Capabilities           |                                                                                         |
| ---------------------- | --------------------------------------------------------------------------------------- |
| `image/jpeg`           | `width: [1, 32767]` <br /> `height: [1, 32767]` <br /> `framerate: [0/1, 2147483647/1]` |
| Availability: *Always* |                                                                                         |
| Direction: *source*    |                                                                                         |

# Element Properties

| Property      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `camera-id`   | The camera device ID associated with the JPEG encoding session. Passed to the offline JPEG engine to select the appropriate hardware encoder when multiple cameras are active.<br /><br />`Type: Unsigned Integer`<br />`Default: 0`<br />`Flags: readable/writable`                                                                                                                                                                                                                                           |
| `orientation` | Specifies the EXIF orientation to embed in the output JPEG. Available values correspond to rotation angles such as 0, 90, 180, and 270 degrees. Note that this is metadata orientation and does not rotate pixels.<br /><br />`Type: Enum `<br />`Default: 0, "0"`<br />`Range:`<br />    `(0): 0 - 0 degrees`<br />    `(90): 90 - 90 degrees`<br />    `(180): 180 - 180 degrees`<br />    `(270): 270 - 270 degrees`<br />`Flags: readable/writable` <br /> `Example: orientation="90" (or) orientation=90` |
| `quality`     | JPEG encoding quality. Higher values produce larger files with better image fidelity, while lower values produce smaller files with more compression artifacts. This property can be changed dynamically at runtime while the pipeline is playing.<br /><br />`Type: Integer`<br />`Default: 85`<br />`Range: 0 - 100`<br />`Flags: readable/writable (changeable in PLAYING state)`                                                                                                                           |

# Internal Architecture

The `qtijpegenc` element is organized around three key internal components:

* `GstJPEGEncoderContext` provides a C++ abstraction over the Camera Service recorder object and is responsible for managing the lifecycle of the Offline JPEG encoder session.
* `GstDataQueue (inframes)` serves as an internal producer-consumer queue that decouples the handle\_frame path from the encoding path. The streaming thread enqueues incoming GstVideoCodecFrame instances, while the worker task dequeues them for processing.
* `GstTask (worktask)` implements the dedicated processing thread, gst\_jpeg\_enc\_process\_task\_loop, which repeatedly retrieves frames from inframes, obtains an output buffer from the pool, and dispatches the encode request to the hardware JPEG engine.

<img src="https://mintcdn.com/qimsdk/wRkQhG1eZWNSwiNj/plugin-reference/images/qtijpegenc2.png?fit=max&auto=format&n=wRkQhG1eZWNSwiNj&q=85&s=b19302ca3eb7cfe0749b1fbe4656670b" alt="" width="641" height="951" data-path="plugin-reference/images/qtijpegenc2.png" />

# Buffer Management and Pool Requirements

DMA Buffer Requirements

`qtijpegenc` requires **FD-backed DMA buffers** on both the input and output paths. The Offline JPEG encode API operates directly on file descriptors (`in_buf_fd` and `out_buf_fd`), so both the upstream input buffer and the output buffer allocated by the element must be backed by FD memory. In practice, this means `gst_is_fd_memory()` must return `TRUE` for both buffers.

## Output Buffer Pool

The output buffer pool is created in `gst_jpeg_enc_create_pool()`.

* Buffers are allocated using `GstQtiAllocator`, DMA-capable allocator, instantiated through `gst_qti_allocator_new()`
* The allocator uses the flag `GST_FD_MEMORY_FLAG_KEEP_MAPPED`
* Each output buffer is sized according to `jpeg_size`, which is obtained from JPEG encode engine through `GetOfflineJpegParams`
* The pool is configured with a minimum of `DEFAULT_PROP_MIN_BUFFERS = 2` buffers
* The output caps are set to `image/jpeg` with the negotiated output resolution

## Input Buffer Requirements

`qtijpegenc` expects the upstream element to provide FD-backed input buffers. If upstream delivers buffers that are not backed by DMA/FD memory, `gst_jpeg_enc_context_execute()` fails with the error: `Input buffer is not FD memory`

`qtijpegenc` is intended to be used downstream of elements that natively produce DMA-backed buffers, such as `qticamsrc`, which provides GBM/DMA buffers, or `qtivtransform`, which also operates on DMA-backed buffer pools.

# Usage

### Basic Camera Snapshot

This example demonstrates live snapshot capture from the camera. NV12 frames are acquired from the camera plugin and passed to `qtijpegenc`, which encodes them into a JPEG image.

<img src="https://mintcdn.com/qimsdk/wRkQhG1eZWNSwiNj/plugin-reference/images/qtijpegencex1.png?fit=max&auto=format&n=wRkQhG1eZWNSwiNj&q=85&s=4410f06ff5db36d62e53b6f7598c7543" alt="" width="520" height="71" data-path="plugin-reference/images/qtijpegencex1.png" />

```
gst-launch-1.0 -e --gst-debug=2 qticamsrc ! \
  video/x-raw,format=NV12,width=1920,height=1080,framerate=30/1 ! \
  queue ! qtijpegenc quality=90 ! \
  image/jpeg,framerate=30/1 ! \
  multifilesink location=$HOME/media/snapshot_%d.jpg
```

### Concurrent 4K Video Recording and JPEG Capture

This example demonstrates how a 4K stream can be recorded as an H.264 MP4 file while JPEG snapshots are captured in parallel. A tee is used to branch the stream, enabling simultaneous video encoding and still-image generation.

<img src="https://mintcdn.com/qimsdk/wRkQhG1eZWNSwiNj/plugin-reference/images/qtijpegencex2.png?fit=max&auto=format&n=wRkQhG1eZWNSwiNj&q=85&s=faf4bb0dcfc6a97a151f958f6f4cb430" alt="" width="1040" height="192" data-path="plugin-reference/images/qtijpegencex2.png" />

```
gst-launch-1.0 -e --gst-debug=2 qticamsrc ! \
  video/x-raw,format=NV12,width=3840,height=2160,framerate=30/1 ! \
  tee name=tee_4k \
  tee_4k. ! queue ! v4l2h264enc ! h264parse ! mp4mux ! \
    filesink location=$HOME/media/timelapse_4k.mp4 async=false \
  tee_4k. ! queue ! qtijpegenc ! \
    multifilesink location=$HOME/media/timelapse_4k_%d.jpg max-files=1 async=false
```
