|
| 1 | +# Iris V4L2 Video Test Scripts for Qualcomm Linux (Yocto) |
| 2 | + |
| 3 | +**Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.** |
| 4 | +**SPDX-License-Identifier: BSD-3-Clause-Clear** |
| 5 | + |
| 6 | +--- |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +These scripts automate validation of video **encoding** and **decoding** on Qualcomm Linux platforms running a Yocto-based rootfs. |
| 11 | +They drive the public `iris_v4l2_test` app: <https://github.com/quic/v4l-video-test-app>. |
| 12 | + |
| 13 | +The suite includes a **reboot-free video stack switcher** (upstream ↔ downstream), a **Kodiak (QCS6490/RB3gen2) firmware swap flow**, and robust **pre-flight checks** (rootfs size, network bootstrap, module sanity, device nodes). |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## What’s New (since 2025‑09‑26) |
| 18 | + |
| 19 | +- **Pre-download rootfs auto‑resize** |
| 20 | + - New `ensure_rootfs_min_size` (now in `functestlib.sh`) verifies `/` has at least **2 GiB** available and, if the root partition is `/dev/disk/by-partlabel/rootfs`, runs: |
| 21 | + ```sh |
| 22 | + resize2fs /dev/disk/by-partlabel/rootfs |
| 23 | + ``` |
| 24 | + - Invoked **before** any clip bundle download. |
| 25 | + |
| 26 | +- **Kodiak upstream: auto‑install backup firmware before switching** |
| 27 | + - `video_kodiak_install_firmware` (in `lib_video.sh`) looks for a recent backup blob under **`$VIDEO_FW_BACKUP_DIR`** (defaults to `/opt/video-fw-backups`) **and legacy `/opt` patterns**, then copies it to: |
| 28 | + ``` |
| 29 | + /lib/firmware/qcom/vpu/vpu20_p1_gen2.mbn |
| 30 | + ``` |
| 31 | + - Attempts **remoteproc stop → firmware swap → start**, with fallback to **module reload** and **platform unbind/bind**. |
| 32 | + - Automatically runs when `--platform kodiak --stack upstream`. |
| 33 | + |
| 34 | +- **Network bootstrap before downloads (Ethernet → Wi‑Fi)** |
| 35 | + - `ensure_network_online` first tries wired DHCP; if still offline and **Wi‑Fi credentials are available**, it attempts: |
| 36 | + 1) `nmcli dev wifi connect` (with a **key‑mgmt fallback** that creates a PSK connection if NM complains: `802-11-wireless-security.key-mgmt: property is missing`), then |
| 37 | + 2) `wpa_supplicant + udhcpc` as a final fallback. |
| 38 | + - Credentials are taken from environment **`SSID`/`PASSWORD`** or an optional `./ssid_list.txt` (first line: `ssid password`). |
| 39 | + |
| 40 | +- **App path hardening** |
| 41 | + - If `--app` points to a file that exists but is not executable, the runner does a best‑effort `chmod +x` and proceeds. |
| 42 | + |
| 43 | +- **Platform‑aware hard gates & clearer logging** |
| 44 | + - Upstream/Downstream validation is **platform specific** (lemans/monaco vs. kodiak). |
| 45 | + - udev refresh + stale node pruning for `/dev/video*` and `/dev/media*` after any stack change. |
| 46 | + |
| 47 | +--- |
| 48 | + |
| 49 | +## Features |
| 50 | + |
| 51 | +- Pure **V4L2** driver-level tests using `iris_v4l2_test` |
| 52 | +- **Encode** (YUV → H.264/H.265) and **Decode** (H.264/H.265/VP9 → YUV) |
| 53 | +- **Yocto**-friendly, POSIX shell with BusyBox-safe paths |
| 54 | +- Parse & run multiple JSON configs; auto-detect **encode/decode** |
| 55 | +- **Auto-fetch** missing input clips (retries, BusyBox `wget` compatible) |
| 56 | +- **Rootfs size guard** (auto‑resize) **before** fetching assets |
| 57 | +- **Network bootstrap** (Ethernet → Wi‑Fi via `nmcli`/`wpa_supplicant`) when needed for downloads |
| 58 | +- Timeout, repeat, dry-run, JUnit XML, dmesg triage |
| 59 | +- **Stack switcher**: upstream ↔ downstream without reboot |
| 60 | +- **Kodiak firmware live swap** with backup/restore helpers |
| 61 | +- **udev refresh + prune** of stale device nodes |
| 62 | + |
| 63 | +--- |
| 64 | + |
| 65 | +## Directory Layout |
| 66 | + |
| 67 | +```bash |
| 68 | +Runner/ |
| 69 | +├── suites/ |
| 70 | +│ └── Multimedia/ |
| 71 | +│ └── Video/ |
| 72 | +│ ├── README_Video.md |
| 73 | +│ └── Video_V4L2_Runner/ |
| 74 | +│ ├── h264Decoder.json |
| 75 | +│ ├── h265Decoder.json |
| 76 | +│ ├── vp9Decoder.json |
| 77 | +│ ├── h264Encoder.json |
| 78 | +│ ├── h265Encoder.json |
| 79 | +│ └── run.sh |
| 80 | +└── utils/ |
| 81 | + ├── functestlib.sh |
| 82 | + └── lib_video.sh |
| 83 | +``` |
| 84 | + |
| 85 | +--- |
| 86 | + |
| 87 | +## Quick Start |
| 88 | + |
| 89 | +```bash |
| 90 | +git clone <this-repo> |
| 91 | +cd <this-repo> |
| 92 | +
|
| 93 | +# Copy to target |
| 94 | +scp -r Runner user@<target_ip>:<target_path> |
| 95 | +ssh user@<target_ip> |
| 96 | +
|
| 97 | +cd <target_path>/Runner |
| 98 | +./run-test.sh Video_V4L2_Runner |
| 99 | +``` |
| 100 | + |
| 101 | +> Results land under: `Runner/suites/Multimedia/Video/Video_V4L2_Runner/` |
| 102 | + |
| 103 | +--- |
| 104 | + |
| 105 | +## Runner CLI (run.sh) |
| 106 | + |
| 107 | +| Option | Description | |
| 108 | +|---|---| |
| 109 | +| `--config path.json` | Run a specific config file | |
| 110 | +| `--dir DIR` | Directory to search for configs | |
| 111 | +| `--pattern GLOB` | Filter configs by glob pattern | |
| 112 | +| `--extract-input-clips true|false` | Auto-fetch missing clips (default: `true`) | |
| 113 | +| `--timeout S` | Timeout per test (default: `60`) | |
| 114 | +| `--strict` | Treat dmesg warnings as failures | |
| 115 | +| `--no-dmesg` | Disable dmesg scanning | |
| 116 | +| `--max N` | Run at most `N` tests | |
| 117 | +| `--stop-on-fail` | Abort suite on first failure | |
| 118 | +| `--loglevel N` | Log level passed to `iris_v4l2_test` | |
| 119 | +| `--repeat N` | Repeat each test `N` times | |
| 120 | +| `--repeat-delay S` | Delay between repeats | |
| 121 | +| `--repeat-policy all|any` | PASS if all runs pass, or any run passes | |
| 122 | +| `--junit FILE` | Write JUnit XML | |
| 123 | +| `--dry-run` | Print commands only | |
| 124 | +| `--verbose` | Verbose runner logs | |
| 125 | +| `--app /path/to/iris_v4l2_test` | Override test app path | |
| 126 | +| `--stack auto|upstream|downstream|base|overlay|up|down` | Select target stack | |
| 127 | +| `--platform lemans|monaco|kodiak` | Force platform (else auto-detect) | |
| 128 | +| `--downstream-fw PATH` | **Kodiak**: path to DS firmware (e.g. `vpu20_1v.mbn`) | |
| 129 | + |
| 130 | +--- |
| 131 | + |
| 132 | +## Pre‑Flight: Rootfs Size & Network |
| 133 | + |
| 134 | +### Auto‑resize before downloads |
| 135 | +The runner calls `ensure_rootfs_min_size 2` **before** any download. If `/` is on `/dev/disk/by-partlabel/rootfs` and total size is below ~2 GiB, it executes: |
| 136 | +```sh |
| 137 | +resize2fs /dev/disk/by-partlabel/rootfs |
| 138 | +``` |
| 139 | + |
| 140 | +### Network bootstrap (if offline) |
| 141 | +If the target is offline when a clip bundle is needed: |
| 142 | + |
| 143 | +1. Tries Ethernet DHCP (safe retries) |
| 144 | +2. If **Wi‑Fi creds** are available, tries: |
| 145 | + - `nmcli dev wifi connect "<ssid>" password "<pass>" ifname <iface>` |
| 146 | + If NetworkManager complains about missing key‑mgmt, it auto‑falls back to: |
| 147 | + ```sh |
| 148 | + nmcli con add type wifi ifname <iface> con-name auto-<ssid> ssid "<ssid>" \ |
| 149 | + wifi-sec.key-mgmt wpa-psk wifi-sec.psk "<pass>" |
| 150 | + nmcli con up auto-<ssid> |
| 151 | + ``` |
| 152 | + - If still offline, uses `wpa_supplicant + udhcpc` |
| 153 | + |
| 154 | +**Provide credentials via:** |
| 155 | +```sh |
| 156 | +export SSID="Hydra" |
| 157 | +export PASSWORD="K5x48Vz3" |
| 158 | +# or create ./ssid_list.txt with: Hydra K5x48Vz3 |
| 159 | +``` |
| 160 | + |
| 161 | +--- |
| 162 | + |
| 163 | +## Stack Selection & Validation |
| 164 | + |
| 165 | +- **lemans/monaco** |
| 166 | + - **Upstream**: `qcom_iris` + `iris_vpu` |
| 167 | + - **Downstream**: `iris_vpu` only (and *no* `qcom_iris`) |
| 168 | + |
| 169 | +- **kodiak** |
| 170 | + - **Upstream**: `venus_core`, `venus_dec`, `venus_enc` |
| 171 | + - **Downstream**: `iris_vpu` |
| 172 | + |
| 173 | +The runner: |
| 174 | +1. Prints **pre/post** module snapshots and any runtime/persistent modprobe blocks |
| 175 | +2. Switches stacks without reboot (uses runtime blacklists under `/run/modprobe.d`) |
| 176 | +3. **Refreshes** `/dev/video*` & `/dev/media*` with udev and **prunes** stale nodes |
| 177 | + |
| 178 | +--- |
| 179 | + |
| 180 | +## Kodiak Firmware Flows |
| 181 | + |
| 182 | +### Downstream (custom blob) |
| 183 | +When `--stack downstream` and you pass `--downstream-fw /path/to/vpu20_1v.mbn`: |
| 184 | +1. The blob is copied to: `/lib/firmware/qcom/vpu/vpu20_p1_gen2.mbn` |
| 185 | +2. Previous image is backed up to: `/opt/video-fw-backups/vpu20_p1_gen2.mbn.<timestamp>.bak` |
| 186 | +3. Runner tries **remoteproc restart**, then **module reload**, then **unbind/bind** |
| 187 | + |
| 188 | +### Upstream (restore a backup before switch) |
| 189 | +When `--stack upstream` on **kodiak**, the runner tries to **restore a known‑good backup** to `/lib/firmware/qcom/vpu/vpu20_p1_gen2.mbn` **before** switching: |
| 190 | +- Search order: |
| 191 | + 1. `$VIDEO_FW_BACKUP_DIR` (default `/opt/video-fw-backups`), newest `vpu20_p1_gen2.mbn.*.bak` |
| 192 | + 2. Legacy `/opt` patterns (e.g., `vpu20_p1_gen2.mbn.*.bak`) |
| 193 | +- Then it attempts **remoteproc restart**; falls back as needed. |
| 194 | + |
| 195 | +**Tip:** If you maintain backups under a custom path: |
| 196 | +```sh |
| 197 | +export VIDEO_FW_BACKUP_DIR=/opt |
| 198 | +./run.sh --platform kodiak --stack upstream |
| 199 | +``` |
| 200 | + |
| 201 | +--- |
| 202 | + |
| 203 | +## Examples |
| 204 | + |
| 205 | +### Run all configs with auto stack |
| 206 | +```sh |
| 207 | +./run.sh |
| 208 | +``` |
| 209 | + |
| 210 | +### Force downstream on lemans/monaco |
| 211 | +```sh |
| 212 | +./run.sh --stack downstream |
| 213 | +``` |
| 214 | + |
| 215 | +### Force upstream on lemans/monaco |
| 216 | +```sh |
| 217 | +./run.sh --stack upstream |
| 218 | +``` |
| 219 | + |
| 220 | +### Kodiak: downstream with custom firmware (live swap) |
| 221 | +```sh |
| 222 | +./run.sh --platform kodiak --stack downstream --downstream-fw /data/fw/vpu20_1v.mbn |
| 223 | +``` |
| 224 | + |
| 225 | +### Kodiak: upstream with automatic backup restore |
| 226 | +```sh |
| 227 | +./run.sh --platform kodiak --stack upstream |
| 228 | +# optionally pin the backup directory |
| 229 | +VIDEO_FW_BACKUP_DIR=/opt ./run.sh --platform kodiak --stack upstream |
| 230 | +``` |
| 231 | + |
| 232 | +### Ensure Wi‑Fi is used for downloads (if needed) |
| 233 | +```sh |
| 234 | +export SSID="Hydra" |
| 235 | +export PASSWORD="K5x48Vz3" |
| 236 | +./run.sh --extract-input-clips true |
| 237 | +``` |
| 238 | + |
| 239 | +### Use a specific app binary |
| 240 | +```sh |
| 241 | +./run.sh --app /data/vendor/iris_test_app/iris_v4l2_test --stack upstream |
| 242 | +``` |
| 243 | + |
| 244 | +### Run only H.265 decode |
| 245 | +```sh |
| 246 | +./run.sh --pattern '*h265*Decoder.json' |
| 247 | +``` |
| 248 | + |
| 249 | +--- |
| 250 | + |
| 251 | +## Troubleshooting |
| 252 | + |
| 253 | +- **“No backup firmware found” on kodiak upstream switch** |
| 254 | + Ensure your backups exist under `/opt/video-fw-backups` **or** legacy `/opt` with a name like `vpu20_p1_gen2.mbn.<timestamp>.bak`, or set `VIDEO_FW_BACKUP_DIR`. |
| 255 | + |
| 256 | +- **Upstream/Downstream mismatch** |
| 257 | + Check the **pre/post module snapshots**; the runner will explicitly log which modules are present/absent. |
| 258 | + |
| 259 | +- **No `/dev/video*`** |
| 260 | + The runner triggers udev and prunes stale nodes; verify udev is available and rules are active. |
| 261 | + |
| 262 | +- **Download fails** |
| 263 | + Ensure time is sane (TLS), network is reachable, and provide Wi‑Fi creds via env or `ssid_list.txt`. The downloader uses BusyBox‑compatible flags with retries. |
| 264 | + |
| 265 | +--- |
0 commit comments