From e08522e6ee9d288ac592355c6fbc4e8ed75c62f8 Mon Sep 17 00:00:00 2001 From: Nitin Nakka Date: Fri, 13 Feb 2026 18:07:30 +0530 Subject: [PATCH 1/6] Added Multimedia Video and Display GStreamer test scripts Signed-off-by: Nitin Nakka --- .../Display/Waylandsink_Playback/README.md | 155 ++++ .../Waylandsink_Playback.yaml | 51 ++ .../Display/Waylandsink_Playback/run.sh | 339 +++++++++ .../Video/Video_Encode_Decode/README.md | 453 +++++++++++ .../Video_Encode_Decode.yaml | 63 ++ .../Video/Video_Encode_Decode/run.sh | 706 ++++++++++++++++++ 6 files changed, 1767 insertions(+) create mode 100644 Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/README.md create mode 100644 Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/Waylandsink_Playback.yaml create mode 100644 Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh create mode 100644 Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md create mode 100644 Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/Video_Encode_Decode.yaml create mode 100644 Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh diff --git a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/README.md b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/README.md new file mode 100644 index 00000000..4fcbb7e1 --- /dev/null +++ b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/README.md @@ -0,0 +1,155 @@ +# Waylandsink_Playback (GStreamer) — Runner Test + +This directory contains the **Waylandsink_Playback** validation test for Qualcomm Linux Testkit runners. + +It validates **Wayland display** using **GStreamer waylandsink** with: +- Weston/Wayland server connectivity checks +- DRM display connectivity validation +- Video playback using `waylandsink` element +- Uses `videotestsrc` to generate test patterns + +The script is designed to be **CI/LAVA-friendly**: +- Writes **PASS/FAIL/SKIP** into `Waylandsink_Playback.res` +- Always **exits 0** (even on FAIL/SKIP) +- Comprehensive Weston/Wayland environment detection +- Automatic Weston startup if needed + +--- + +## What this test does + +1. Sources framework utilities (`functestlib.sh`, `lib_gstreamer.sh`, `lib_display.sh`) +2. **Display connectivity check**: Verifies connected DRM display via sysfs +3. **Weston/Wayland server check**: + - Discovers existing Wayland socket + - Attempts to start Weston if no socket found + - Validates Wayland connection +4. **waylandsink element check**: Verifies GStreamer waylandsink is available +5. **Playback test**: Runs videotestsrc → videoconvert → waylandsink pipeline +6. **Validation**: Checks playback duration and exit code + +--- + +## PASS / FAIL / SKIP criteria + +### PASS +- Playback completes successfully (exit code 0 or 143) +- Elapsed time ≥ (duration - 2) seconds + +### FAIL +- Playback exits with error code (not 0 or 143) +- Playback exits too quickly (< duration - 2 seconds) + +### SKIP +- Missing GStreamer tools (`gst-launch-1.0`, `gst-inspect-1.0`) +- No connected DRM display found +- No Wayland socket found (and cannot start Weston) +- Wayland connection test fails +- `waylandsink` element not available + +--- + +## Dependencies + +### Required +- `gst-launch-1.0` +- `gst-inspect-1.0` +- `videotestsrc` GStreamer plugin +- `videoconvert` GStreamer plugin +- `waylandsink` GStreamer plugin + +### Display/Wayland +- Weston compositor (running or startable) +- Connected DRM display +- Wayland socket (`/run/user/*/wayland-*` or `/dev/socket/weston/wayland-*`) + +--- + +## Usage + +```bash +./run.sh [options] +``` + +### Options + +- `--duration ` - Playback duration (default: 10) +- `--pattern ` - videotestsrc pattern (default: smpte) +- `--width ` - Video width (default: 1920) +- `--height ` - Video height (default: 1080) +- `--framerate ` - Video framerate (default: 30) +- `--gst-debug ` - GStreamer debug level 1-9 (default: 2) + +--- + +## Examples + +```bash +# Run default test (1920x1080 SMPTE for 30s) +./run.sh + +# Run with 30 second duration +./run.sh --duration 30 + +# Run with ball pattern +./run.sh --pattern ball + +# Run with custom resolution +./run.sh --width 1280 --height 720 +``` + +--- + +## Pipeline + +``` +videotestsrc num-buffers= pattern= + ! video/x-raw,width=,height=,framerate=/1 + ! videoconvert + ! waylandsink +``` + +--- + +## Logs + +``` +./Waylandsink_Playback.res +./logs/Waylandsink_Playback/ + gst.log # GStreamer debug output + run.log # Pipeline execution log +``` + +--- + +## Troubleshooting + +### "SKIP: No connected DRM display found" +- Check physical display connection +- Verify DRM drivers loaded: `ls -l /dev/dri/` + +### "SKIP: No Wayland socket found" +- Check if Weston is running: `pgrep weston` +- Try starting Weston manually +- Check `XDG_RUNTIME_DIR` and `WAYLAND_DISPLAY` environment variables + +### "SKIP: waylandsink element not available" +- Install GStreamer Wayland plugin +- Check: `gst-inspect-1.0 waylandsink` + +### "FAIL: Playback failed" +- Check logs in `logs/Waylandsink_Playback/` +- Increase debug level: `./run.sh --gst-debug 5` +- Verify Weston is running properly + +--- + +## LAVA Environment Variables + +- `VIDEO_DURATION` - Playback duration +- `VIDEO_PATTERN` - videotestsrc pattern +- `VIDEO_WIDTH` - Video width +- `VIDEO_HEIGHT` - Video height +- `VIDEO_FRAMERATE` - Video framerate +- `VIDEO_GST_DEBUG` - GStreamer debug level +- `RUNTIMESEC` - Alternative to VIDEO_DURATION diff --git a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/Waylandsink_Playback.yaml b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/Waylandsink_Playback.yaml new file mode 100644 index 00000000..664e3777 --- /dev/null +++ b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/Waylandsink_Playback.yaml @@ -0,0 +1,51 @@ +metadata: + name: gstreamer-waylandsink-playback + format: "Lava-Test Test Definition 1.0" + description: > + GStreamer waylandsink playback validation with Weston/Wayland server checks + on Qualcomm Linux platforms. Uses videotestsrc to generate test patterns + and displays them via waylandsink. Validates display connectivity and + Wayland compositor functionality. + os: + - linux + scope: + - functional + +params: + # Video resolution (WIDTHxHEIGHT) + VIDEO_RESOLUTION: "1920x1080" + + # Test pattern for videotestsrc + VIDEO_PATTERN: "smpte" # smpte|snow|black|white|red|green|blue|checkers-1|checkers-2 + + # Playback duration in seconds + PLAYBACK_DURATION: "30" + + # Frame rate + FRAMERATE: "30" + + # GStreamer debug level + VIDEO_GST_DEBUG: "2" # 1-9 + +run: + steps: + - REPO_PATH="$PWD" + + # Navigate to test directory + - cd Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/ + + # Build CLI args only when params are non-empty + - | + CMD="./run.sh" + + [ -n "${VIDEO_RESOLUTION}" ] && CMD="${CMD} --resolution ${VIDEO_RESOLUTION}" + [ -n "${VIDEO_PATTERN}" ] && CMD="${CMD} --pattern ${VIDEO_PATTERN}" + [ -n "${PLAYBACK_DURATION}" ] && CMD="${CMD} --duration ${PLAYBACK_DURATION}" + [ -n "${FRAMERATE}" ] && CMD="${CMD} --framerate ${FRAMERATE}" + [ -n "${VIDEO_GST_DEBUG}" ] && CMD="${CMD} --gst-debug ${VIDEO_GST_DEBUG}" + + echo "[LAVA] Running: ${CMD}" + sh -c "${CMD}" || true + + # Send result to LAVA + - "${REPO_PATH}/Runner/utils/send-to-lava.sh Waylandsink_Playback.res || true" diff --git a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh new file mode 100644 index 00000000..2e6e951f --- /dev/null +++ b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh @@ -0,0 +1,339 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear +# Waylandsink Playback validation using GStreamer +# Tests video playback using waylandsink with videotestsrc +# Validates Weston/Wayland server and display connectivity +# CI/LAVA-friendly (always exits 0, writes .res file) + +SCRIPT_DIR="$( + cd "$(dirname "$0")" || exit 1 + pwd +)" + +INIT_ENV="" +SEARCH="$SCRIPT_DIR" +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 0 +fi + +# shellcheck disable=SC1090 +. "$INIT_ENV" + +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" + +# shellcheck disable=SC1091 +. "$TOOLS/lib_gstreamer.sh" + +# shellcheck disable=SC1091 +[ -f "$TOOLS/lib_display.sh" ] && . "$TOOLS/lib_display.sh" + +TESTNAME="Waylandsink_Playback" +RES_FILE="${SCRIPT_DIR}/${TESTNAME}.res" +LOG_DIR="${SCRIPT_DIR}/logs" +OUTDIR="$LOG_DIR/$TESTNAME" +GST_LOG="$OUTDIR/gst.log" +RUN_LOG="$OUTDIR/run.log" + +mkdir -p "$OUTDIR" >/dev/null 2>&1 || true +: >"$RES_FILE" +: >"$GST_LOG" +: >"$RUN_LOG" + +result="FAIL" +reason="unknown" + +# -------------------- Defaults -------------------- +duration="${VIDEO_DURATION:-${RUNTIMESEC:-30}}" +pattern="${VIDEO_PATTERN:-smpte}" +width="${VIDEO_WIDTH:-1920}" +height="${VIDEO_HEIGHT:-1080}" +framerate="${VIDEO_FRAMERATE:-30}" +gstDebugLevel="${VIDEO_GST_DEBUG:-${GST_DEBUG_LEVEL:-2}}" + +cleanup() { + pkill -x gst-launch-1.0 >/dev/null 2>&1 || true +} +trap cleanup INT TERM EXIT + +# -------------------- Arg parse -------------------- +while [ $# -gt 0 ]; do + case "$1" in + --duration) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --duration" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + duration="$2" + shift 2 + ;; + + --pattern) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --pattern" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + pattern="$2" + shift 2 + ;; + + --width) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --width" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + width="$2" + shift 2 + ;; + + --height) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --height" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + height="$2" + shift 2 + ;; + + --framerate) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --framerate" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + framerate="$2" + shift 2 + ;; + + --gst-debug) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --gst-debug" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + gstDebugLevel="$2" + shift 2 + ;; + + -h|--help) + cat < + Playback duration in seconds + Default: ${duration} + + --pattern + videotestsrc pattern + Default: ${pattern} + + --width + Video width + Default: ${width} + + --height + Video height + Default: ${height} + + --framerate + Video framerate + Default: ${framerate} + + --gst-debug + Sets GST_DEBUG= (1-9) + Default: ${gstDebugLevel} + +Examples: + # Run default test (1920x1080 SMPTE pattern for 10s) + ./run.sh + + # Run with custom duration + ./run.sh --duration 20 + + # Run with different pattern + ./run.sh --pattern ball + +EOF + echo "SKIP" >"$RES_FILE" + exit 0 + ;; + + *) + log_warn "Unknown argument: $1" + echo "SKIP" >"$RES_FILE" + exit 0 + ;; + esac +done + +# -------------------- Pre-checks -------------------- +check_dependencies "gst-launch-1.0" "gst-inspect-1.0" >/dev/null 2>&1 || { + log_warn "Missing gstreamer runtime (gst-launch-1.0/gst-inspect-1.0)" + echo "SKIP" >"$RES_FILE" + exit 0 +} + +log_info "Test: $TESTNAME" +log_info "Duration: ${duration}s, Resolution: ${width}x${height}, Framerate: ${framerate}fps" +log_info "Pattern: $pattern" +log_info "GST debug: GST_DEBUG=$gstDebugLevel" +log_info "Logs: $OUTDIR" + +# -------------------- Display connectivity check -------------------- +if command -v display_debug_snapshot >/dev/null 2>&1; then + display_debug_snapshot "pre-test" +fi + +have_connector=0 +if command -v display_connected_summary >/dev/null 2>&1; then + sysfs_summary=$(display_connected_summary) + if [ -n "$sysfs_summary" ] && [ "$sysfs_summary" != "none" ]; then + have_connector=1 + log_info "Connected display (sysfs): $sysfs_summary" + fi +fi + +if [ "$have_connector" -eq 0 ]; then + log_warn "No connected DRM display found, skipping ${TESTNAME}." + echo "SKIP" >"$RES_FILE" + exit 0 +fi + +# -------------------- Wayland/Weston environment check -------------------- +if command -v wayland_debug_snapshot >/dev/null 2>&1; then + wayland_debug_snapshot "${TESTNAME}: start" +fi + +sock="" + +# Try to find existing Wayland socket +if command -v discover_wayland_socket_anywhere >/dev/null 2>&1; then + sock=$(discover_wayland_socket_anywhere | head -n 1 || true) +fi + +# Adopt socket environment if found +if [ -n "$sock" ] && command -v adopt_wayland_env_from_socket >/dev/null 2>&1; then + log_info "Found existing Wayland socket: $sock" + if ! adopt_wayland_env_from_socket "$sock"; then + log_warn "Failed to adopt env from $sock" + fi +fi + +# Try starting Weston if no socket found +if [ -z "$sock" ] && command -v overlay_start_weston_drm >/dev/null 2>&1; then + log_info "No usable Wayland socket; trying to start Weston..." + if overlay_start_weston_drm; then + if command -v discover_wayland_socket_anywhere >/dev/null 2>&1; then + sock=$(discover_wayland_socket_anywhere | head -n 1 || true) + fi + if [ -n "$sock" ] && command -v adopt_wayland_env_from_socket >/dev/null 2>&1; then + log_info "Weston created Wayland socket: $sock" + if ! adopt_wayland_env_from_socket "$sock"; then + log_warn "Failed to adopt env from $sock" + fi + fi + fi +fi + +# Final check +if [ -z "$sock" ]; then + log_warn "No Wayland socket found; skipping ${TESTNAME}." + echo "SKIP" >"$RES_FILE" + exit 0 +fi + +# Verify Wayland connection +if command -v wayland_connection_ok >/dev/null 2>&1; then + if ! wayland_connection_ok; then + log_fail "Wayland connection test failed; cannot run ${TESTNAME}." + echo "SKIP" >"$RES_FILE" + exit 0 + fi + log_info "Wayland connection test: OK" +fi + +# -------------------- Check waylandsink element -------------------- +if ! has_element waylandsink; then + log_warn "waylandsink element not available" + echo "SKIP" >"$RES_FILE" + exit 0 +fi + +log_info "waylandsink element: available" + +# -------------------- GStreamer debug capture -------------------- +export GST_DEBUG_NO_COLOR=1 +export GST_DEBUG="$gstDebugLevel" +export GST_DEBUG_FILE="$GST_LOG" + +# -------------------- Build and run pipeline -------------------- +num_buffers=$((duration * framerate)) + +pipeline="videotestsrc num-buffers=${num_buffers} pattern=${pattern} ! video/x-raw,width=${width},height=${height},framerate=${framerate}/1 ! videoconvert ! waylandsink" + +log_info "Pipeline: $pipeline" + +# Run with timeout +start_ts=$(date +%s) + +if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$RUN_LOG" 2>&1; then + gstRc=0 +else + gstRc=$? +fi + +end_ts=$(date +%s) +elapsed=$((end_ts - start_ts)) + +log_info "Playback finished: rc=${gstRc} elapsed=${elapsed}s" + +# -------------------- Validation -------------------- +# Check for GStreamer errors in log +if ! gstreamer_validate_log "$RUN_LOG" "$TESTNAME"; then + result="FAIL" + reason="GStreamer errors detected in log" +else + # Accept 0 (normal) and 143 (timeout/SIGTERM) as success + if [ "$gstRc" -eq 0 ] || [ "$gstRc" -eq 143 ]; then + if [ "$elapsed" -ge "$((duration - 2))" ]; then + result="PASS" + reason="Playback completed successfully (rc=$gstRc, elapsed=${elapsed}s)" + else + result="FAIL" + reason="Playback exited too quickly (elapsed=${elapsed}s, expected ~${duration}s)" + fi + else + result="FAIL" + reason="Playback failed (rc=$gstRc)" + fi +fi + +# -------------------- Emit result -------------------- +case "$result" in + PASS) + log_pass "$TESTNAME $result: $reason" + echo "PASS" >"$RES_FILE" + ;; + *) + log_fail "$TESTNAME $result: $reason" + echo "FAIL" >"$RES_FILE" + ;; +esac + +exit 0 diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md new file mode 100644 index 00000000..2a73b7bf --- /dev/null +++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md @@ -0,0 +1,453 @@ +# Video_Encode_Decode (GStreamer) — Runner Test + +This directory contains the **Video_Encode_Decode** validation test for Qualcomm Linux Testkit runners. + +It validates video **encoding and decoding** using **GStreamer (`gst-launch-1.0`)** with V4L2 hardware-accelerated codecs: +- **v4l2h264enc** / **v4l2h264dec** (H.264/AVC) +- **v4l2h265enc** / **v4l2h265dec** (H.265/HEVC) +- **v4l2vp9dec** (VP9 decode only - uses pre-downloaded clips) + +The script is designed to be **CI/LAVA-friendly**: +- Writes **PASS/FAIL/SKIP** into `Video_Encode_Decode.res` +- Always **exits 0** (even on FAIL/SKIP) to avoid terminating LAVA jobs early +- Logs the **final `gst-launch-1.0` command** to console and to log files +- Uses **videotestsrc** plugin to generate test patterns for H.264/H.265 (no external video files needed) +- For VP9: Downloads pre-encoded clips from git repo (requires network connectivity) + +--- + +## Location in repo + +Expected path: + +``` +Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh +``` + +Required shared utils (sourced from `Runner/utils` via `init_env`): +- `functestlib.sh` +- `lib_gstreamer.sh` +- optional: `lib_video.sh` (for video stack management) + +--- + +## What this test does + +At a high level, the test: + +1. Finds and sources `init_env` +2. Sources: + - `$TOOLS/functestlib.sh` + - `$TOOLS/lib_gstreamer.sh` + - optionally `$TOOLS/lib_video.sh` +3. Checks for required GStreamer elements (v4l2h264enc, v4l2h265enc, v4l2h264dec, v4l2h265dec, v4l2vp9dec) +4. **Network connectivity check** (for VP9): + - Checks network connectivity using `ensure_network_online()` + - Downloads VP9 clips from git repo if not already present + - URL: https://github.com/qualcomm-linux/qcom-linux-testkit/releases/download/IRIS-Video-Files-v1.0/video_clips_iris.tar.gz +5. **Encoding phase**: + - Uses `videotestsrc` to generate test video patterns (SMPTE color bars) + - Encodes to H.264 or H.265 using V4L2 hardware encoders + - Saves encoded files to `logs/Video_Encode_Decode/encoded/` + - Tests 4K resolution (3840x2160) by default +6. **Decoding phase**: + - Reads the previously encoded files (H.264/H.265) or downloaded clips (VP9) + - Decodes using V4L2 hardware decoders + - Outputs to fakesink (no display needed) +7. Collects test results and emits PASS/FAIL/SKIP + +--- + +## Test Cases + +By default, the test runs the following test cases at 4K resolution for H.264/H.265, plus VP9 decode: + +### Encoding Tests +1. **encode_h264_4k** - Encode H.264 at 3840x2160 resolution +2. **encode_h265_4k** - Encode H.265 at 3840x2160 resolution + +**Note:** VP9 encoding is not supported (no v4l2vp9enc available) + +### Decoding Tests +1. **decode_h264_4k** - Decode H.264 4K encoded file +2. **decode_h265_4k** - Decode H.265 4K encoded file +3. **decode_vp9** - Decode VP9 pre-downloaded clip (320_240_10fps.ivf) - **runs by default** + +--- + +## PASS / FAIL / SKIP criteria + +### PASS +- **Encoding**: Output file is created and has size > 1000 bytes +- **Decoding**: Pipeline completes successfully (exit code 0 or "Setting pipeline to NULL" in log) +- **Overall**: At least one test passes and no tests fail + +### FAIL +- **Encoding**: No output file created or file size too small +- **Decoding**: Pipeline fails or crashes +- **Overall**: One or more tests fail + +### SKIP +- Missing required tools (`gst-launch-1.0`, `gst-inspect-1.0`) +- Required V4L2 encoder/decoder elements not available +- For H.264/H.265 decode tests: corresponding encoded file not found (encode must run first) +- For VP9 decode tests: network connectivity unavailable or clip download failed + +**Note:** The test always exits `0` even for FAIL/SKIP. The `.res` file is the source of truth. + +--- + +## Logs and artifacts + +By default, logs are written relative to the script working directory: + +``` +./Video_Encode_Decode.res +./logs/Video_Encode_Decode/ + gst.log # GStreamer debug output + encode_h264_480p.log # Individual test logs + encode_h264_4k.log + encode_h265_480p.log + encode_h265_4k.log + decode_h264_480p.log + decode_h264_4k.log + decode_h265_480p.log + decode_h265_4k.log + decode_vp9.log # VP9 decode test log + encoded/ # Encoded video files + encode_h264_480p.h264 + encode_h264_4k.h264 + encode_h265_480p.h265 + encode_h265_4k.h265 + 320_240_10fps.ivf # Downloaded VP9 clip (if network available) + dmesg/ # dmesg scan outputs (if available) +``` + +--- + +## Dependencies + +### Required +- `gst-launch-1.0` +- `gst-inspect-1.0` +- `videotestsrc` GStreamer plugin +- `videoconvert` GStreamer plugin + +### V4L2 Encoder/Decoder Elements +- `v4l2h264enc` - H.264 hardware encoder +- `v4l2h265enc` - H.265 hardware encoder +- `v4l2h264dec` - H.264 hardware decoder +- `v4l2h265dec` - H.265 hardware decoder +- `v4l2vp9dec` - VP9 hardware decoder + +### Parser Elements +- `h264parse` - H.264 stream parser +- `h265parse` - H.265 stream parser +- `ivfparse` - IVF container parser (for VP9) + +### Network Requirements (for VP9) +- Network connectivity (Ethernet or WiFi) +- Access to GitHub releases: https://github.com/qualcomm-linux/qcom-linux-testkit/releases/ + +--- + +## Usage + +Run: + +```bash +./run.sh [options] +``` + +Help: + +```bash +./run.sh --help +``` + +### Options + +- `--mode ` + - Default: `all` (run both encode and decode tests) + - `encode`: Run only encoding tests + - `decode`: Run only decoding tests (requires encoded files from previous encode run) + +- `--codecs ` + - Comma-separated list of codecs to test + - Default: `h264,h265,vp9` (all three codecs run by default) + - Examples: `h264`, `h265`, `h264,h265`, `vp9`, `h264,vp9` + - Note: VP9 only supports decode (no encode) + +- `--resolutions <480p,4k>` + - Comma-separated list of resolutions to test + - Default: `480p,4k` + - Supported: `480p` (640x480), `720p` (1280x720), `1080p` (1920x1080), `4k` (3840x2160) + - Examples: `480p`, `4k`, `480p,1080p,4k` + +- `--duration ` + - Duration for encoding (in seconds) + - Default: `5` + - This determines how many frames are generated (duration × framerate) + +- `--framerate ` + - Framerate for video generation + - Default: `30` + +- `--stack ` + - Video stack selection (uses lib_video.sh if available) + - Default: `auto` + +- `--gst-debug ` + - Sets `GST_DEBUG=` (1-9) + - Values: + - `1` ERROR + - `2` WARNING (default) + - `3` FIXME + - `4` INFO + - `5` DEBUG + - `6` LOG + - `7` TRACE + - `8` MEMDUMP + - `9` MEMDUMP + - Default: `2` + +--- + +## Examples + +### 1) Run all tests (default - encode + decode for H.264/H.265 at 4K, plus VP9 decode) + +```bash +./run.sh +``` + +### 2) Run only encoding tests + +```bash +./run.sh --mode encode +``` + +### 3) Run only decoding tests (requires encoded files from previous run) + +```bash +./run.sh --mode decode +``` + +### 4) Test only H.264 codec + +```bash +./run.sh --codecs h264 +``` + +### 5) Test only H.265 codec at 4K resolution + +```bash +./run.sh --codecs h265 --resolutions 4k +``` + +### 6) Test all codecs at 480p only + +```bash +./run.sh --resolutions 480p +``` + +### 7) Test with longer duration (10 seconds) + +```bash +./run.sh --duration 10 +``` + +### 8) Test with higher framerate (60fps) + +```bash +./run.sh --framerate 60 +``` + +### 9) Test multiple resolutions + +```bash +./run.sh --resolutions 480p,720p,1080p,4k +``` + +### 10) Increase GStreamer debug verbosity + +```bash +./run.sh --gst-debug 5 +``` + +### 11) Quick test - H.264 only at 480p with 3 second duration + +```bash +./run.sh --codecs h264 --resolutions 480p --duration 3 +``` + +### 12) Test VP9 decode only (requires network connectivity) + +```bash +./run.sh --codecs vp9 --mode decode +``` + +### 13) Test all codecs including VP9 + +```bash +./run.sh --codecs h264,h265,vp9 +``` + +--- + +## Pipeline Details + +### Encoding Pipeline + +``` +videotestsrc num-buffers= pattern=smpte + ! video/x-raw,width=,height=,format=NV12,framerate=/1 + ! v4l2h264enc extra-controls="controls,video_bitrate=" (or v4l2h265enc) + ! h264parse (or h265parse) + ! filesink location= +``` + +Where: +- `num-buffers` = duration × framerate +- `pattern=smpte` generates SMPTE color bars test pattern +- `format=NV12` specifies the native format for V4L2 encoders (no videoconvert needed) +- `extra-controls="controls,video_bitrate="` sets encoder bitrate + - 480p: 1 Mbps (1000000) + - 720p: 2 Mbps (2000000) + - 1080p: 4 Mbps (4000000) + - 4K: 8 Mbps (8000000) +- Parser element ensures proper format negotiation + +### Decoding Pipeline (H.264/H.265) + +``` +filesrc location= + ! h264parse (or h265parse) + ! v4l2h264dec (or v4l2h265dec) + ! videoconvert + ! fakesink +``` + +Where: +- Parser ensures proper stream format +- `fakesink` discards output (no display needed for validation) + +### Decoding Pipeline (VP9) + +``` +filesrc location=320_240_10fps.ivf + ! ivfparse + ! v4l2vp9dec + ! videoconvert + ! fakesink +``` + +Where: +- `ivfparse` parses IVF container format (VP9 native container) +- No `qtdemux` needed (unlike H.264/H.265 in MP4) +- Input file is pre-downloaded from git repo +- Resolution: 320x240 + +--- + +## Troubleshooting + +### A) "SKIP: Missing gstreamer runtime" +- Ensure `gst-launch-1.0` and `gst-inspect-1.0` are installed in the image. + +### B) "Encoder not available for h264/h265" +- Check if V4L2 encoder elements are available: + ```bash + gst-inspect-1.0 v4l2h264enc + gst-inspect-1.0 v4l2h265enc + ``` +- Ensure video hardware acceleration drivers are loaded +- Check video stack configuration (upstream vs downstream) + +### C) "Decoder not available for h264/h265/vp9" +- Check if V4L2 decoder elements are available: + ```bash + gst-inspect-1.0 v4l2h264dec + gst-inspect-1.0 v4l2h265dec + gst-inspect-1.0 v4l2vp9dec + ``` + +### D) Decode tests skip with "Input file not found" +- Run encode tests first: `./run.sh --mode encode` +- Or run all tests: `./run.sh --mode all` + +### E) Encoding fails or produces small files +- Check available memory (4K encoding requires significant memory) +- Check `logs/Video_Encode_Decode/encode_*.log` for errors +- Try with lower resolution: `./run.sh --resolutions 480p` +- Increase debug level: `./run.sh --gst-debug 5` + +### F) "FAIL: file too small" +- Encoding may have failed silently +- Check individual test logs in `logs/Video_Encode_Decode/` +- Verify V4L2 video devices exist: `ls -l /dev/video*` + +### G) Video stack issues +- Check loaded modules: + ```bash + lsmod | grep -E 'iris|venus|video' + ``` +- Try forcing stack: `./run.sh --stack upstream` or `./run.sh --stack downstream` + +### H) VP9 decode fails with "Input file not found" +- Ensure network connectivity is available +- Check if clip was downloaded: `ls -l logs/Video_Encode_Decode/320_240_10fps.ivf` +- Manually download if needed: + ```bash + cd logs/Video_Encode_Decode/ + wget https://github.com/qualcomm-linux/qcom-linux-testkit/releases/download/IRIS-Video-Files-v1.0/video_clips_iris.tar.gz + tar -xzf video_clips_iris.tar.gz + ``` +- Check network connectivity: + ```bash + ping -c 3 github.com + ``` + +### I) VP9 decode fails with "ivfparse not found" +- Ensure `ivfparse` GStreamer plugin is installed: + ```bash + gst-inspect-1.0 ivfparse + ``` +- This is typically part of `gst-plugins-bad` package + +--- + +## Notes for CI / LAVA + +- The test always exits `0`. +- Use the `.res` file for result: + - `PASS` - All tests passed + - `FAIL` - One or more tests failed + - `SKIP` - No tests executed or all skipped +- Test summary is logged showing pass/fail/skip counts +- Individual test logs are available in `logs/Video_Encode_Decode/` +- Encoded files are preserved in `logs/Video_Encode_Decode/encoded/` for debugging + +### LAVA Environment Variables + +The test supports these environment variables (can be set in LAVA job definition): + +- `VIDEO_TEST_MODE` - Test mode (all/encode/decode) +- `VIDEO_CODECS` - Comma-separated codec list (default: `h264,h265,vp9`) +- `VIDEO_RESOLUTIONS` - Comma-separated resolution list +- `VIDEO_DURATION` - Encoding duration in seconds +- `VIDEO_FRAMERATE` - Video framerate +- `VIDEO_STACK` - Video stack selection +- `VIDEO_GST_DEBUG` - GStreamer debug level +- `VIDEO_CLIP_URL` - URL for VP9 clip download (default: GitHub releases) +- `RUNTIMESEC` - Alternative to VIDEO_DURATION + +### VP9-Specific Notes for CI/LAVA + +- VP9 tests require network connectivity to download clips +- The test uses `ensure_network_online()` to establish connectivity automatically +- If network is unavailable, VP9 tests will SKIP (not FAIL) +- Downloaded clips are cached in the output directory for subsequent runs +- VP9 clip: 320_240_10fps.ivf (320x240 resolution, IVF container) + +--- diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/Video_Encode_Decode.yaml b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/Video_Encode_Decode.yaml new file mode 100644 index 00000000..12caa21b --- /dev/null +++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/Video_Encode_Decode.yaml @@ -0,0 +1,63 @@ +metadata: + name: gstreamer-video-encode-decode + format: "Lava-Test Test Definition 1.0" + description: > + Video encode/decode validation using GStreamer (gst-launch-1.0) with V4L2 hardware-accelerated codecs + on Qualcomm Linux platforms. Supports v4l2h264enc, v4l2h265enc, v4l2h264dec, v4l2h265dec, v4l2vp9dec. + Uses videotestsrc to generate test patterns for H.264/H.265 (no external video files needed). + For VP9 decode, downloads pre-encoded clips from git repo (requires network connectivity). + Tests encoding at 480p and 4K resolutions, then decodes the encoded files. + os: + - linux + scope: + - functional + +params: + # Test mode: all (encode+decode), encode (only), decode (only) + VIDEO_TEST_MODE: "all" # all|encode|decode + + # Codecs to test (comma-separated) + VIDEO_CODECS: "h264,h265,vp9" # h264,h265,vp9 (VP9 decode only) + + # Resolutions to test (comma-separated) + VIDEO_RESOLUTIONS: "4k" # 4k (3840x2160) + + # Encoding duration in seconds + VIDEO_DURATION: "30" # seconds + + # Video framerate + VIDEO_FRAMERATE: "30" # fps + + # Video stack selection + VIDEO_STACK: "auto" # auto|upstream|downstream + + # GStreamer debug level + VIDEO_GST_DEBUG: "2" # 1-9 + + # Alternative duration variable (for compatibility) + RUNTIMESEC: "" # if set, overrides VIDEO_DURATION + +run: + steps: + - REPO_PATH="$PWD" + + # Navigate to test directory + - cd Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/ + + # Build CLI args only when params are non-empty + - | + CMD="./run.sh" + + [ -n "${VIDEO_TEST_MODE}" ] && CMD="${CMD} --mode ${VIDEO_TEST_MODE}" + [ -n "${VIDEO_CODECS}" ] && CMD="${CMD} --codecs ${VIDEO_CODECS}" + [ -n "${VIDEO_RESOLUTIONS}" ] && CMD="${CMD} --resolutions ${VIDEO_RESOLUTIONS}" + [ -n "${VIDEO_DURATION}" ] && CMD="${CMD} --duration ${VIDEO_DURATION}" + [ -n "${VIDEO_FRAMERATE}" ] && CMD="${CMD} --framerate ${VIDEO_FRAMERATE}" + [ -n "${VIDEO_STACK}" ] && CMD="${CMD} --stack ${VIDEO_STACK}" + [ -n "${VIDEO_GST_DEBUG}" ] && CMD="${CMD} --gst-debug ${VIDEO_GST_DEBUG}" + + echo "[LAVA] Running: ${CMD}" + sh -c "${CMD}" || true + + # Send result to LAVA + - "${REPO_PATH}/Runner/utils/send-to-lava.sh Video_Encode_Decode.res || true" diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh new file mode 100644 index 00000000..ef9ca47c --- /dev/null +++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh @@ -0,0 +1,706 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear +# Video Encode/Decode validation using GStreamer with V4L2 hardware accelerated codecs +# Supports: v4l2h264dec, v4l2h265dec, v4l2h264enc, v4l2h265enc +# Uses videotestsrc for encoding, then decodes the encoded files +# Logs everything to console and also to local log files. +# PASS/FAIL/SKIP is emitted to .res. Always exits 0 (LAVA-friendly). + +SCRIPT_DIR="$( + cd "$(dirname "$0")" || exit 1 + pwd +)" + +INIT_ENV="" +SEARCH="$SCRIPT_DIR" +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 0 +fi + +# shellcheck disable=SC1090 +. "$INIT_ENV" + +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" + +# shellcheck disable=SC1091 +. "$TOOLS/lib_gstreamer.sh" + +# shellcheck disable=SC1091 +[ -f "$TOOLS/lib_video.sh" ] && . "$TOOLS/lib_video.sh" + +TESTNAME="Video_Encode_Decode" +RES_FILE="${SCRIPT_DIR}/${TESTNAME}.res" +LOG_DIR="${SCRIPT_DIR}/logs" +OUTDIR="$LOG_DIR/$TESTNAME" +GST_LOG="$OUTDIR/gst.log" +DMESG_DIR="$OUTDIR/dmesg" +ENCODED_DIR="$OUTDIR/encoded" + +mkdir -p "$OUTDIR" "$DMESG_DIR" "$ENCODED_DIR" >/dev/null 2>&1 || true +: >"$RES_FILE" +: >"$GST_LOG" + +result="FAIL" +reason="unknown" +pass_count=0 +fail_count=0 +skip_count=0 +total_tests=0 + +# -------------------- Defaults (LAVA env vars -> defaults; CLI overrides) -------------------- +testMode="${VIDEO_TEST_MODE:-all}" +codecList="${VIDEO_CODECS:-h264,h265,vp9}" +resolutionList="${VIDEO_RESOLUTIONS:-4k}" +duration="${VIDEO_DURATION:-${RUNTIMESEC:-30}}" +framerate="${VIDEO_FRAMERATE:-30}" +gstDebugLevel="${VIDEO_GST_DEBUG:-${GST_DEBUG_LEVEL:-2}}" +videoStack="${VIDEO_STACK:-auto}" +clipUrl="${VIDEO_CLIP_URL:-https://github.com/qualcomm-linux/qcom-linux-testkit/releases/download/IRIS-Video-Files-v1.0/video_clips_iris.tar.gz}" + +cleanup() { + pkill -x gst-launch-1.0 >/dev/null 2>&1 || true +} +trap cleanup INT TERM EXIT + +# -------------------- Arg parse -------------------- +while [ $# -gt 0 ]; do + case "$1" in + --mode) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --mode" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + testMode="$2" + shift 2 + ;; + + --codecs) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --codecs" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + codecList="$2" + shift 2 + ;; + + --clip-url) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --clip-url" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + clipUrl="$2" + shift 2 + ;; + + --resolutions) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --resolutions" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + resolutionList="$2" + shift 2 + ;; + + --duration) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --duration" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + duration="$2" + shift 2 + ;; + + --framerate) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --framerate" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + framerate="$2" + shift 2 + ;; + + --stack) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --stack" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + videoStack="$2" + shift 2 + ;; + + --gst-debug) + if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --gst-debug" + echo "SKIP" >"$RES_FILE" + exit 0 + fi + gstDebugLevel="$2" + shift 2 + ;; + + -h|--help) + cat < + Default: all (run both encode and decode tests) + + --codecs + Comma-separated list of codecs to test + Default: h264,h265 + Note: VP9 only supports decode mode with pre-existing clips + + --resolutions <480p,4k> + Comma-separated list of resolutions to test + Default: 480p,4k (480p=640x480, 4k=3840x2160) + + --duration + Duration for encoding (in seconds) + Default: ${duration} + + --framerate + Framerate for video generation + Default: ${framerate} + + --stack + Video stack selection + Default: auto + + --gst-debug + Sets GST_DEBUG= (1-9) + Default: ${gstDebugLevel} + + --clip-url + URL to download video clips for VP9 decode tests + Default: ${clipUrl} + +Examples: + # Run all tests (encode + decode) for H264 and H265 at 480p and 4K + ./run.sh + + # Run only encoding tests + ./run.sh --mode encode + + # Run only H264 tests at 480p + ./run.sh --codecs h264 --resolutions 480p + + # Run with 10 second duration + ./run.sh --duration 10 + + # Run VP9 decode test + ./run.sh --mode decode --codecs vp9 + +EOF + echo "SKIP" >"$RES_FILE" + exit 0 + ;; + + *) + log_warn "Unknown argument: $1" + echo "SKIP" >"$RES_FILE" + exit 0 + ;; + esac +done + +# -------------------- Validate parsed values -------------------- +case "$testMode" in all|encode|decode) : ;; *) + log_warn "Invalid --mode '$testMode'" + echo "SKIP" >"$RES_FILE" + exit 0 + ;; +esac + +case "$gstDebugLevel" in 1|2|3|4|5|6|7|8|9) : ;; *) + log_warn "Invalid --gst-debug '$gstDebugLevel' (allowed: 1-9)" + echo "SKIP" >"$RES_FILE" + exit 0 + ;; +esac + +# -------------------- Pre-checks -------------------- +check_dependencies "gst-launch-1.0" "gst-inspect-1.0" >/dev/null 2>&1 || { + log_warn "Missing gstreamer runtime (gst-launch-1.0/gst-inspect-1.0)" + echo "SKIP" >"$RES_FILE" + exit 0 +} + +log_info "Test: $TESTNAME" +log_info "Mode: $testMode" +log_info "Codecs: $codecList" +log_info "Resolutions: $resolutionList" +log_info "Duration: ${duration}s, Framerate: ${framerate}fps" +log_info "GST debug: GST_DEBUG=$gstDebugLevel" +log_info "Logs: $OUTDIR" + +# -------------------- Video stack handling -------------------- +detected_stack="$videoStack" +if command -v video_ensure_stack >/dev/null 2>&1; then + log_info "Ensuring video stack: $videoStack" + stack_result=$(video_ensure_stack "$videoStack" "" 2>&1) + if printf '%s' "$stack_result" | grep -q "downstream"; then + detected_stack="downstream" + log_info "Detected stack: downstream" + elif printf '%s' "$stack_result" | grep -q "upstream"; then + detected_stack="upstream" + log_info "Detected stack: upstream" + else + log_info "Stack detection result: $stack_result" + fi +fi + +# -------------------- GStreamer debug capture -------------------- +export GST_DEBUG_NO_COLOR=1 +export GST_DEBUG="$gstDebugLevel" +export GST_DEBUG_FILE="$GST_LOG" + +# -------------------- Helper functions -------------------- +get_resolution_params() { + res="$1" + case "$res" in + 480p) + printf '%s %s\n' "640" "480" + ;; + 720p) + printf '%s %s\n' "1280" "720" + ;; + 1080p) + printf '%s %s\n' "1920" "1080" + ;; + 4k) + printf '%s %s\n' "3840" "2160" + ;; + *) + printf '%s %s\n' "640" "480" + ;; + esac +} + +get_encoder_element() { + codec="$1" + case "$codec" in + h264) + if has_element v4l2h264enc; then + printf '%s\n' "v4l2h264enc" + return 0 + fi + ;; + h265|hevc) + if has_element v4l2h265enc; then + printf '%s\n' "v4l2h265enc" + return 0 + fi + ;; + esac + printf '%s\n' "" + return 1 +} + +get_decoder_element() { + codec="$1" + case "$codec" in + h264) + if has_element v4l2h264dec; then + printf '%s\n' "v4l2h264dec" + return 0 + fi + ;; + h265|hevc) + if has_element v4l2h265dec; then + printf '%s\n' "v4l2h265dec" + return 0 + fi + ;; + vp9) + if has_element v4l2vp9dec; then + printf '%s\n' "v4l2vp9dec" + return 0 + fi + ;; + esac + printf '%s\n' "" + return 1 +} + +get_file_extension() { + codec="$1" + case "$codec" in + vp9) + printf '%s\n' "ivf" + ;; + *) + # Use mp4 container format for h264/h265 + printf '%s\n' "mp4" + ;; + esac +} + +# -------------------- Encode test function -------------------- +run_encode_test() { + codec="$1" + resolution="$2" + width="$3" + height="$4" + + testname="encode_${codec}_${resolution}" + log_info "==========================================" + log_info "Running: $testname" + log_info "==========================================" + + encoder=$(get_encoder_element "$codec") + if [ -z "$encoder" ]; then + log_warn "Encoder not available for $codec" + skip_count=$((skip_count + 1)) + return 1 + fi + + ext=$(get_file_extension) + output_file="$ENCODED_DIR/${testname}.${ext}" + test_log="$OUTDIR/${testname}.log" + + : >"$test_log" + + # Build pipeline: videotestsrc -> NV12 format -> encoder with bitrate -> parser -> filesink + case "$codec" in + h264) + parser="h264parse" + ;; + h265|hevc) + parser="h265parse" + ;; + *) + parser="" + ;; + esac + + # Calculate bitrate based on resolution (8Mbps for 4K, scaled for others) + bitrate=8000000 + if [ "$width" -le 640 ]; then + bitrate=1000000 + elif [ "$width" -le 1280 ]; then + bitrate=2000000 + elif [ "$width" -le 1920 ]; then + bitrate=4000000 + fi + + # Detect video stack and add IO mode parameters for downstream + encoder_params="extra-controls=\"controls,video_bitrate=${bitrate}\"" + if [ "$detected_stack" = "downstream" ]; then + encoder_params="${encoder_params} capture-io-mode=4 output-io-mode=4" + log_info "Using downstream stack: adding IO mode parameters" + else + log_info "Using upstream stack: no IO mode parameters needed" + fi + + # Build pipeline with mp4mux for MP4 container + if [ -n "$parser" ]; then + pipeline="videotestsrc num-buffers=$((duration * framerate)) pattern=smpte ! video/x-raw,width=${width},height=${height},format=NV12,framerate=${framerate}/1 ! ${encoder} ${encoder_params} ! ${parser} ! mp4mux ! filesink location=${output_file}" + else + pipeline="videotestsrc num-buffers=$((duration * framerate)) pattern=smpte ! video/x-raw,width=${width},height=${height},format=NV12,framerate=${framerate}/1 ! ${encoder} ${encoder_params} ! mp4mux ! filesink location=${output_file}" + fi + + log_info "Pipeline: $pipeline" + + # Run encoding + if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then + gstRc=0 + else + gstRc=$? + fi + + log_info "Encode exit code: $gstRc" + + # Check for GStreamer errors in log + if ! gstreamer_validate_log "$test_log" "$testname"; then + log_fail "$testname: FAIL (GStreamer errors detected)" + fail_count=$((fail_count + 1)) + return 1 + fi + + # Check if output file was created and has content + if [ -f "$output_file" ] && [ -s "$output_file" ]; then + file_size=$(stat -f%z "$output_file" 2>/dev/null || stat -c%s "$output_file" 2>/dev/null || echo 0) + log_info "Encoded file: $output_file (size: $file_size bytes)" + + if [ "$file_size" -gt 1000 ]; then + log_pass "$testname: PASS" + pass_count=$((pass_count + 1)) + return 0 + else + log_fail "$testname: FAIL (file too small: $file_size bytes)" + fail_count=$((fail_count + 1)) + return 1 + fi + else + log_fail "$testname: FAIL (no output file created)" + fail_count=$((fail_count + 1)) + return 1 + fi +} + +# -------------------- Decode test function -------------------- +run_decode_test() { + codec="$1" + resolution="$2" + + testname="decode_${codec}_${resolution}" + log_info "==========================================" + log_info "Running: $testname" + log_info "==========================================" + + decoder=$(get_decoder_element "$codec") + if [ -z "$decoder" ]; then + log_warn "Decoder not available for $codec" + skip_count=$((skip_count + 1)) + return 1 + fi + + ext=$(get_file_extension "$codec") + + # For VP9, use pre-downloaded clip; for others, use encoded file + if [ "$codec" = "vp9" ]; then + input_file="$OUTDIR/320_240_10fps.ivf" + if [ ! -f "$input_file" ]; then + log_warn "VP9 clip not found: $input_file (download may have failed)" + skip_count=$((skip_count + 1)) + return 1 + fi + else + input_file="$ENCODED_DIR/encode_${codec}_${resolution}.${ext}" + if [ ! -f "$input_file" ]; then + log_warn "Input file not found: $input_file (run encode first)" + skip_count=$((skip_count + 1)) + return 1 + fi + fi + + test_log="$OUTDIR/${testname}.log" + : >"$test_log" + + # Build pipeline: filesrc -> parser -> decoder -> fakesink + case "$codec" in + h264) + parser="h264parse" + container="qtdemux" + ;; + h265|hevc) + parser="h265parse" + container="qtdemux" + ;; + vp9) + parser="ivfparse" + container="" + ;; + *) + parser="identity" + container="" + ;; + esac + + # Add IO mode parameters for downstream stack + decoder_params="" + if [ "$detected_stack" = "downstream" ]; then + decoder_params="capture-io-mode=4 output-io-mode=4" + log_info "Using downstream stack: adding IO mode parameters to decoder" + else + log_info "Using upstream stack: no IO mode parameters needed for decoder" + fi + + # Build pipeline based on container format + if [ -n "$container" ]; then + # MP4 container (h264/h265) + if [ -n "$decoder_params" ]; then + pipeline="filesrc location=${input_file} ! ${container} ! ${parser} ! ${decoder} ${decoder_params} ! videoconvert ! fakesink" + else + pipeline="filesrc location=${input_file} ! ${container} ! ${parser} ! ${decoder} ! videoconvert ! fakesink" + fi + else + # IVF container (vp9) or no container + if [ -n "$decoder_params" ]; then + pipeline="filesrc location=${input_file} ! ${parser} ! ${decoder} ${decoder_params} ! videoconvert ! fakesink" + else + pipeline="filesrc location=${input_file} ! ${parser} ! ${decoder} ! videoconvert ! fakesink" + fi + fi + + log_info "Pipeline: $pipeline" + + # Run decoding + if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then + gstRc=0 + else + gstRc=$? + fi + + log_info "Decode exit code: $gstRc" + + # Check for successful completion in log + if grep -q "Setting pipeline to NULL" "$test_log" 2>/dev/null || [ "$gstRc" -eq 0 ]; then + log_pass "$testname: PASS" + pass_count=$((pass_count + 1)) + return 0 + else + log_fail "$testname: FAIL (rc=$gstRc)" + fail_count=$((fail_count + 1)) + return 1 + fi +} + +# -------------------- Main test execution -------------------- +log_info "Starting video encode/decode tests..." + +# Parse codec list +codecs=$(printf '%s' "$codecList" | tr ',' ' ') + +# Parse resolution list +resolutions=$(printf '%s' "$resolutionList" | tr ',' ' ') + +# -------------------- VP9 clip download (if VP9 in codec list) -------------------- +need_vp9_clip=0 +for codec in $codecs; do + if [ "$codec" = "vp9" ]; then + need_vp9_clip=1 + break + fi +done + +if [ "$need_vp9_clip" -eq 1 ] && [ "$testMode" != "encode" ]; then + log_info "==========================================" + log_info "VP9 CLIP DOWNLOAD" + log_info "==========================================" + + vp9_clip="$OUTDIR/320_240_10fps.ivf" + + if [ -f "$vp9_clip" ]; then + log_info "VP9 clip already exists: $vp9_clip" + else + log_info "Checking network connectivity and downloading VP9 clips..." + + # Use ensure_network_online from functestlib.sh to bring up connectivity + if ensure_network_online; then + log_pass "Network connectivity established" + + # Download and extract clips using functestlib helper + log_info "Downloading VP9 clips from: $clipUrl" + if extract_tar_from_url "$clipUrl" "$OUTDIR"; then + log_pass "VP9 clips downloaded and extracted successfully" + else + log_warn "Failed to download/extract VP9 clips" + fi + + # Verify clip exists after download attempt + if [ ! -f "$vp9_clip" ]; then + log_warn "VP9 clip not found after download attempt: $vp9_clip" + log_warn "VP9 decode tests will be skipped" + fi + else + log_warn "Could not establish network connectivity" + log_warn "VP9 decode tests will be skipped" + fi + fi +fi + +# Run encode tests (skip VP9 as it doesn't support encoding in this test) +if [ "$testMode" = "all" ] || [ "$testMode" = "encode" ]; then + log_info "==========================================" + log_info "ENCODE TESTS" + log_info "==========================================" + + for codec in $codecs; do + # Skip VP9 for encode tests (no v4l2vp9enc support in this test) + if [ "$codec" = "vp9" ]; then + log_info "Skipping VP9 encode (not supported in this test suite)" + continue + fi + + for res in $resolutions; do + params=$(get_resolution_params "$res") + width=$(printf '%s' "$params" | awk '{print $1}') + height=$(printf '%s' "$params" | awk '{print $2}') + + total_tests=$((total_tests + 1)) + run_encode_test "$codec" "$res" "$width" "$height" || true + done + done +fi + +# Run decode tests +if [ "$testMode" = "all" ] || [ "$testMode" = "decode" ]; then + log_info "==========================================" + log_info "DECODE TESTS" + log_info "==========================================" + + for codec in $codecs; do + # For VP9, only run once (not per resolution, as we use a fixed clip) + if [ "$codec" = "vp9" ]; then + total_tests=$((total_tests + 1)) + run_decode_test "$codec" "720p" || true + else + for res in $resolutions; do + total_tests=$((total_tests + 1)) + run_decode_test "$codec" "$res" || true + done + fi + done +fi + +# -------------------- Summary -------------------- +log_info "==========================================" +log_info "TEST SUMMARY" +log_info "==========================================" +log_info "Total tests: $total_tests" +log_info "Passed: $pass_count" +log_info "Failed: $fail_count" +log_info "Skipped: $skip_count" + +# -------------------- Emit result -------------------- +if [ "$pass_count" -gt 0 ] && [ "$fail_count" -eq 0 ]; then + result="PASS" + reason="All tests passed ($pass_count/$total_tests)" +elif [ "$pass_count" -gt 0 ] && [ "$fail_count" -gt 0 ]; then + result="FAIL" + reason="Some tests failed (passed: $pass_count, failed: $fail_count)" +elif [ "$fail_count" -gt 0 ]; then + result="FAIL" + reason="All tests failed ($fail_count/$total_tests)" +else + result="SKIP" + reason="No tests executed or all skipped" +fi + +case "$result" in + PASS) + log_pass "$TESTNAME $result: $reason" + echo "PASS" >"$RES_FILE" + ;; + FAIL) + log_fail "$TESTNAME $result: $reason" + echo "FAIL" >"$RES_FILE" + ;; + *) + log_warn "$TESTNAME $result: $reason" + echo "SKIP" >"$RES_FILE" + ;; +esac + +exit 0 From 79fd143d7cb7e7b5f9ece3ebac60e4ac4fc2e84b Mon Sep 17 00:00:00 2001 From: Nitin Nakka Date: Fri, 13 Feb 2026 18:27:27 +0530 Subject: [PATCH 2/6] Fix: make run.sh executables for both video and display scripts Signed-off-by: Nitin Nakka --- .../Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh | 0 .../suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh mode change 100644 => 100755 Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh diff --git a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh old mode 100644 new mode 100755 diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh old mode 100644 new mode 100755 From 93f6153f36bc6f25d9481b2b9f3bdf460624192f Mon Sep 17 00:00:00 2001 From: Nitin Nakka Date: Fri, 13 Feb 2026 18:43:11 +0530 Subject: [PATCH 3/6] Updated lib gstreamer sh utils file to support logs based post processing Signed-off-by: Nitin Nakka --- Runner/utils/lib_gstreamer.sh | 70 +++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/Runner/utils/lib_gstreamer.sh b/Runner/utils/lib_gstreamer.sh index 95b90f19..7d225c4f 100755 --- a/Runner/utils/lib_gstreamer.sh +++ b/Runner/utils/lib_gstreamer.sh @@ -498,3 +498,73 @@ gstreamer_build_playback_pipeline() { printf '%s\n' "filesrc location=${file} ! ${dec} ! audioconvert ! audioresample ! ${sinkElem}" return 0 } + +# -------------------- GStreamer error log checker -------------------- +# gstreamer_check_errors +# Returns: 0 if no critical errors found, 1 if errors found +# Checks for common GStreamer ERROR patterns that indicate failure +gstreamer_check_errors() { + logfile="$1" + + [ -f "$logfile" ] || return 0 + + # Check for critical ERROR messages + if grep -q -E "^ERROR:|ERROR: from element|Internal data stream error|streaming stopped, reason not-negotiated|Could not open|No such file|Permission denied|Failed to|Cannot" "$logfile" 2>/dev/null; then + return 1 + fi + + # Check for pipeline preroll failures + if grep -q -E "pipeline doesn't want to preroll|pipeline doesn't want to play" "$logfile" 2>/dev/null; then + return 1 + fi + + # Check for state change failures + if grep -q -E "failed to change state|state change failed" "$logfile" 2>/dev/null; then + return 1 + fi + + return 0 +} + +# -------------------- GStreamer log validation with detailed reporting -------------------- +# gstreamer_validate_log +# Returns: 0 if validation passes, 1 if errors found +# Logs detailed error information if errors are detected +gstreamer_validate_log() { + logfile="$1" + testname="${2:-test}" + + [ -f "$logfile" ] || { + log_warn "$testname: Log file not found: $logfile" + return 1 + } + + if ! gstreamer_check_errors "$logfile"; then + log_fail "$testname: GStreamer errors detected in log" + + # Extract and log specific error messages + if grep -q "ERROR:" "$logfile" 2>/dev/null; then + log_fail "Error messages found:" + grep "ERROR:" "$logfile" 2>/dev/null | head -n 5 | while IFS= read -r line; do + log_fail " $line" + done + fi + + # Check for specific failure reasons + if grep -q "not-negotiated" "$logfile" 2>/dev/null; then + log_fail " Reason: Format negotiation failed (caps mismatch)" + fi + + if grep -q "Could not open" "$logfile" 2>/dev/null; then + log_fail " Reason: File or device access failed" + fi + + if grep -q "No such file" "$logfile" 2>/dev/null; then + log_fail " Reason: File not found" + fi + + return 1 + fi + + return 0 +} From bd8ef68be6a8d8df27593ef21bc03db2623e22ca Mon Sep 17 00:00:00 2001 From: Nitin Nakka Date: Sun, 15 Feb 2026 16:48:29 +0530 Subject: [PATCH 4/6] Extract V4L2 video helpers to reusable library. Move generic GStreamer V4L2 video helper functions from Video_Encode_Decode test to shared lib_gstreamer.sh for code reuse across all GStreamer tests Signed-off-by: Nitin Nakka --- .../Video/Video_Encode_Decode/README.md | 149 ++++++++++- .../Video/Video_Encode_Decode/run.sh | 186 ++------------ Runner/utils/lib_gstreamer.sh | 237 ++++++++++++++++++ 3 files changed, 407 insertions(+), 165 deletions(-) diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md index 2a73b7bf..0954e52f 100644 --- a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md +++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md @@ -26,7 +26,7 @@ Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh Required shared utils (sourced from `Runner/utils` via `init_env`): - `functestlib.sh` -- `lib_gstreamer.sh` +- `lib_gstreamer.sh` - **Contains reusable V4L2 video helpers** (see Library Functions section below) - optional: `lib_video.sh` (for video stack management) --- @@ -417,6 +417,153 @@ Where: --- +## Library Functions (Runner/utils/lib_gstreamer.sh) + +This test uses reusable helper functions from `lib_gstreamer.sh` that other GStreamer tests can leverage: + +### Resolution and Codec Helpers + +**`gstreamer_resolution_to_wh `** +- Converts resolution names to width/height +- Input: `480p`, `720p`, `1080p`, `4k` +- Output: `" "` (e.g., `"1920 1080"`) +- Example: + ```sh + params=$(gstreamer_resolution_to_wh "1080p") + width=$(printf '%s' "$params" | awk '{print $1}') # 1920 + height=$(printf '%s' "$params" | awk '{print $2}') # 1080 + ``` + +**`gstreamer_v4l2_encoder_for_codec `** +- Returns V4L2 encoder element for codec +- Input: `h264`, `h265`/`hevc` +- Output: `v4l2h264enc` or `v4l2h265enc` (or empty if not available) +- Example: + ```sh + encoder=$(gstreamer_v4l2_encoder_for_codec "h264") # v4l2h264enc + ``` + +**`gstreamer_v4l2_decoder_for_codec `** +- Returns V4L2 decoder element for codec +- Input: `h264`, `h265`/`hevc`, `vp9` +- Output: `v4l2h264dec`, `v4l2h265dec`, or `v4l2vp9dec` (or empty if not available) +- Example: + ```sh + decoder=$(gstreamer_v4l2_decoder_for_codec "vp9") # v4l2vp9dec + ``` + +**`gstreamer_container_ext_for_codec `** +- Returns file extension for codec +- Input: `h264`, `h265`, `vp9` +- Output: `mp4` (for h264/h265) or `ivf` (for vp9) +- Example: + ```sh + ext=$(gstreamer_container_ext_for_codec "h264") # mp4 + ``` + +### Bitrate and File Size Helpers + +**`gstreamer_bitrate_for_resolution `** +- Calculates recommended bitrate based on resolution +- Returns bitrate in bps +- Bitrate mapping: + - ≤640px width: 1 Mbps (1000000 bps) + - ≤1280px width: 2 Mbps (2000000 bps) + - ≤1920px width: 4 Mbps (4000000 bps) + - >1920px width: 8 Mbps (8000000 bps) +- Example: + ```sh + bitrate=$(gstreamer_bitrate_for_resolution 1920 1080) # 4000000 + ``` + +**`gstreamer_file_size_bytes `** +- Returns file size in bytes (portable across BSD/GNU stat) +- Returns `0` if file doesn't exist +- Example: + ```sh + size=$(gstreamer_file_size_bytes "/tmp/video.mp4") + if [ "$size" -gt 1000 ]; then + echo "File is valid" + fi + ``` + +### Pipeline Builders + +**`gstreamer_build_v4l2_encode_pipeline `** +- Builds complete V4L2 encode pipeline with videotestsrc +- Parameters: + - `codec`: `h264` or `h265` + - `width`, `height`: Video dimensions + - `duration`: Duration in seconds + - `framerate`: Frames per second + - `bitrate`: Bitrate in bps + - `output_file`: Output file path + - `video_stack`: `upstream` or `downstream` (adds IO mode parameters for downstream) +- Returns: Complete pipeline string (or empty if encoder not available) +- Example: + ```sh + pipeline=$(gstreamer_build_v4l2_encode_pipeline \ + "h264" 1920 1080 30 30 4000000 "/tmp/test.mp4" "upstream") + gstreamer_run_gstlaunch_timeout 40 "$pipeline" + ``` + +**`gstreamer_build_v4l2_decode_pipeline `** +- Builds complete V4L2 decode pipeline +- Parameters: + - `codec`: `h264`, `h265`, or `vp9` + - `input_file`: Input file path + - `video_stack`: `upstream` or `downstream` +- Returns: Complete pipeline string (or empty if decoder not available) +- Automatically handles: + - Container format (MP4 for h264/h265, IVF for vp9) + - Parser selection (h264parse, h265parse, ivfparse) + - IO mode parameters for downstream stack +- Example: + ```sh + pipeline=$(gstreamer_build_v4l2_decode_pipeline \ + "h264" "/tmp/test.mp4" "upstream") + gstreamer_run_gstlaunch_timeout 40 "$pipeline" + ``` + +### Usage in Other Tests + +To use these functions in your GStreamer test: + +```sh +#!/bin/sh +# Source init_env and lib_gstreamer.sh +. "$INIT_ENV" +. "$TOOLS/functestlib.sh" +. "$TOOLS/lib_gstreamer.sh" + +# Use the helpers +params=$(gstreamer_resolution_to_wh "4k") +width=$(printf '%s' "$params" | awk '{print $1}') +height=$(printf '%s' "$params" | awk '{print $2}') + +bitrate=$(gstreamer_bitrate_for_resolution "$width" "$height") + +pipeline=$(gstreamer_build_v4l2_encode_pipeline \ + "h264" "$width" "$height" 10 30 "$bitrate" "/tmp/output.mp4" "upstream") + +if [ -n "$pipeline" ]; then + gstreamer_run_gstlaunch_timeout 20 "$pipeline" +fi +``` + +### Testing Pipeline Builders + +A test script is provided to verify the pipeline builders: + +```bash +cd Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode +sh test_pipeline_builders.sh +``` + +This will output example pipelines for various codecs, resolutions, and video stacks. + +--- + ## Notes for CI / LAVA - The test always exits `0`. diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh index ef9ca47c..badfc11e 100755 --- a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh +++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh @@ -274,86 +274,6 @@ export GST_DEBUG_NO_COLOR=1 export GST_DEBUG="$gstDebugLevel" export GST_DEBUG_FILE="$GST_LOG" -# -------------------- Helper functions -------------------- -get_resolution_params() { - res="$1" - case "$res" in - 480p) - printf '%s %s\n' "640" "480" - ;; - 720p) - printf '%s %s\n' "1280" "720" - ;; - 1080p) - printf '%s %s\n' "1920" "1080" - ;; - 4k) - printf '%s %s\n' "3840" "2160" - ;; - *) - printf '%s %s\n' "640" "480" - ;; - esac -} - -get_encoder_element() { - codec="$1" - case "$codec" in - h264) - if has_element v4l2h264enc; then - printf '%s\n' "v4l2h264enc" - return 0 - fi - ;; - h265|hevc) - if has_element v4l2h265enc; then - printf '%s\n' "v4l2h265enc" - return 0 - fi - ;; - esac - printf '%s\n' "" - return 1 -} - -get_decoder_element() { - codec="$1" - case "$codec" in - h264) - if has_element v4l2h264dec; then - printf '%s\n' "v4l2h264dec" - return 0 - fi - ;; - h265|hevc) - if has_element v4l2h265dec; then - printf '%s\n' "v4l2h265dec" - return 0 - fi - ;; - vp9) - if has_element v4l2vp9dec; then - printf '%s\n' "v4l2vp9dec" - return 0 - fi - ;; - esac - printf '%s\n' "" - return 1 -} - -get_file_extension() { - codec="$1" - case "$codec" in - vp9) - printf '%s\n' "ivf" - ;; - *) - # Use mp4 container format for h264/h265 - printf '%s\n' "mp4" - ;; - esac -} # -------------------- Encode test function -------------------- run_encode_test() { @@ -367,56 +287,30 @@ run_encode_test() { log_info "Running: $testname" log_info "==========================================" - encoder=$(get_encoder_element "$codec") + # Check if encoder is available + encoder=$(gstreamer_v4l2_encoder_for_codec "$codec") if [ -z "$encoder" ]; then log_warn "Encoder not available for $codec" skip_count=$((skip_count + 1)) return 1 fi - ext=$(get_file_extension) + ext=$(gstreamer_container_ext_for_codec "$codec") output_file="$ENCODED_DIR/${testname}.${ext}" test_log="$OUTDIR/${testname}.log" : >"$test_log" - # Build pipeline: videotestsrc -> NV12 format -> encoder with bitrate -> parser -> filesink - case "$codec" in - h264) - parser="h264parse" - ;; - h265|hevc) - parser="h265parse" - ;; - *) - parser="" - ;; - esac + # Calculate bitrate based on resolution + bitrate=$(gstreamer_bitrate_for_resolution "$width" "$height") - # Calculate bitrate based on resolution (8Mbps for 4K, scaled for others) - bitrate=8000000 - if [ "$width" -le 640 ]; then - bitrate=1000000 - elif [ "$width" -le 1280 ]; then - bitrate=2000000 - elif [ "$width" -le 1920 ]; then - bitrate=4000000 - fi + # Build pipeline using library function + pipeline=$(gstreamer_build_v4l2_encode_pipeline "$codec" "$width" "$height" "$duration" "$framerate" "$bitrate" "$output_file" "$detected_stack") - # Detect video stack and add IO mode parameters for downstream - encoder_params="extra-controls=\"controls,video_bitrate=${bitrate}\"" - if [ "$detected_stack" = "downstream" ]; then - encoder_params="${encoder_params} capture-io-mode=4 output-io-mode=4" - log_info "Using downstream stack: adding IO mode parameters" - else - log_info "Using upstream stack: no IO mode parameters needed" - fi - - # Build pipeline with mp4mux for MP4 container - if [ -n "$parser" ]; then - pipeline="videotestsrc num-buffers=$((duration * framerate)) pattern=smpte ! video/x-raw,width=${width},height=${height},format=NV12,framerate=${framerate}/1 ! ${encoder} ${encoder_params} ! ${parser} ! mp4mux ! filesink location=${output_file}" - else - pipeline="videotestsrc num-buffers=$((duration * framerate)) pattern=smpte ! video/x-raw,width=${width},height=${height},format=NV12,framerate=${framerate}/1 ! ${encoder} ${encoder_params} ! mp4mux ! filesink location=${output_file}" + if [ -z "$pipeline" ]; then + log_fail "$testname: FAIL (could not build pipeline)" + fail_count=$((fail_count + 1)) + return 1 fi log_info "Pipeline: $pipeline" @@ -439,7 +333,7 @@ run_encode_test() { # Check if output file was created and has content if [ -f "$output_file" ] && [ -s "$output_file" ]; then - file_size=$(stat -f%z "$output_file" 2>/dev/null || stat -c%s "$output_file" 2>/dev/null || echo 0) + file_size=$(gstreamer_file_size_bytes "$output_file") log_info "Encoded file: $output_file (size: $file_size bytes)" if [ "$file_size" -gt 1000 ]; then @@ -468,14 +362,15 @@ run_decode_test() { log_info "Running: $testname" log_info "==========================================" - decoder=$(get_decoder_element "$codec") + # Check if decoder is available + decoder=$(gstreamer_v4l2_decoder_for_codec "$codec") if [ -z "$decoder" ]; then log_warn "Decoder not available for $codec" skip_count=$((skip_count + 1)) return 1 fi - ext=$(get_file_extension "$codec") + ext=$(gstreamer_container_ext_for_codec "$codec") # For VP9, use pre-downloaded clip; for others, use encoded file if [ "$codec" = "vp9" ]; then @@ -497,50 +392,13 @@ run_decode_test() { test_log="$OUTDIR/${testname}.log" : >"$test_log" - # Build pipeline: filesrc -> parser -> decoder -> fakesink - case "$codec" in - h264) - parser="h264parse" - container="qtdemux" - ;; - h265|hevc) - parser="h265parse" - container="qtdemux" - ;; - vp9) - parser="ivfparse" - container="" - ;; - *) - parser="identity" - container="" - ;; - esac - - # Add IO mode parameters for downstream stack - decoder_params="" - if [ "$detected_stack" = "downstream" ]; then - decoder_params="capture-io-mode=4 output-io-mode=4" - log_info "Using downstream stack: adding IO mode parameters to decoder" - else - log_info "Using upstream stack: no IO mode parameters needed for decoder" - fi + # Build pipeline using library function + pipeline=$(gstreamer_build_v4l2_decode_pipeline "$codec" "$input_file" "$detected_stack") - # Build pipeline based on container format - if [ -n "$container" ]; then - # MP4 container (h264/h265) - if [ -n "$decoder_params" ]; then - pipeline="filesrc location=${input_file} ! ${container} ! ${parser} ! ${decoder} ${decoder_params} ! videoconvert ! fakesink" - else - pipeline="filesrc location=${input_file} ! ${container} ! ${parser} ! ${decoder} ! videoconvert ! fakesink" - fi - else - # IVF container (vp9) or no container - if [ -n "$decoder_params" ]; then - pipeline="filesrc location=${input_file} ! ${parser} ! ${decoder} ${decoder_params} ! videoconvert ! fakesink" - else - pipeline="filesrc location=${input_file} ! ${parser} ! ${decoder} ! videoconvert ! fakesink" - fi + if [ -z "$pipeline" ]; then + log_fail "$testname: FAIL (could not build pipeline)" + fail_count=$((fail_count + 1)) + return 1 fi log_info "Pipeline: $pipeline" @@ -634,7 +492,7 @@ if [ "$testMode" = "all" ] || [ "$testMode" = "encode" ]; then fi for res in $resolutions; do - params=$(get_resolution_params "$res") + params=$(gstreamer_resolution_to_wh "$res") width=$(printf '%s' "$params" | awk '{print $1}') height=$(printf '%s' "$params" | awk '{print $2}') diff --git a/Runner/utils/lib_gstreamer.sh b/Runner/utils/lib_gstreamer.sh index 7d225c4f..89a09833 100755 --- a/Runner/utils/lib_gstreamer.sh +++ b/Runner/utils/lib_gstreamer.sh @@ -568,3 +568,240 @@ gstreamer_validate_log() { return 0 } + +# -------------------- Video codec helpers (V4L2) -------------------- +# gstreamer_resolution_to_wh +# Converts resolution name to width and height +# Prints: " " +gstreamer_resolution_to_wh() { + res="$1" + case "$res" in + 480p) + printf '%s %s\n' "640" "480" + ;; + 720p) + printf '%s %s\n' "1280" "720" + ;; + 1080p) + printf '%s %s\n' "1920" "1080" + ;; + 4k) + printf '%s %s\n' "3840" "2160" + ;; + *) + printf '%s %s\n' "640" "480" + ;; + esac +} + +# gstreamer_v4l2_encoder_for_codec +# Returns the V4L2 encoder element for the given codec +# Prints: encoder element name or empty string if not available +gstreamer_v4l2_encoder_for_codec() { + codec="$1" + case "$codec" in + h264) + if has_element v4l2h264enc; then + printf '%s\n' "v4l2h264enc" + return 0 + fi + ;; + h265|hevc) + if has_element v4l2h265enc; then + printf '%s\n' "v4l2h265enc" + return 0 + fi + ;; + esac + printf '%s\n' "" + return 1 +} + +# gstreamer_v4l2_decoder_for_codec +# Returns the V4L2 decoder element for the given codec +# Prints: decoder element name or empty string if not available +gstreamer_v4l2_decoder_for_codec() { + codec="$1" + case "$codec" in + h264) + if has_element v4l2h264dec; then + printf '%s\n' "v4l2h264dec" + return 0 + fi + ;; + h265|hevc) + if has_element v4l2h265dec; then + printf '%s\n' "v4l2h265dec" + return 0 + fi + ;; + vp9) + if has_element v4l2vp9dec; then + printf '%s\n' "v4l2vp9dec" + return 0 + fi + ;; + esac + printf '%s\n' "" + return 1 +} + +# gstreamer_container_ext_for_codec +# Returns the file extension for the given codec +# Prints: file extension (without dot) +gstreamer_container_ext_for_codec() { + codec="$1" + case "$codec" in + vp9) + printf '%s\n' "ivf" + ;; + *) + # Use mp4 container format for h264/h265 + printf '%s\n' "mp4" + ;; + esac +} + +# -------------------- Bitrate and file size helpers -------------------- +# gstreamer_bitrate_for_resolution +# Returns recommended bitrate in bps based on resolution +# Prints: bitrate in bps +gstreamer_bitrate_for_resolution() { + width="$1" + height="$2" + + # Default bitrate calculation + bitrate=8000000 + if [ "$width" -le 640 ]; then + bitrate=1000000 + elif [ "$width" -le 1280 ]; then + bitrate=2000000 + elif [ "$width" -le 1920 ]; then + bitrate=4000000 + fi + + printf '%s\n' "$bitrate" +} + +# gstreamer_file_size_bytes +# Returns file size in bytes (portable across BSD/GNU stat) +# Prints: file size in bytes or 0 if file doesn't exist +gstreamer_file_size_bytes() { + filepath="$1" + + [ -f "$filepath" ] || { printf '%s\n' "0"; return 1; } + + # Try BSD stat first, then GNU stat + file_size=$(stat -f%z "$filepath" 2>/dev/null || stat -c%s "$filepath" 2>/dev/null || echo 0) + printf '%s\n' "$file_size" +} + +# -------------------- V4L2 encode pipeline builder -------------------- +# gstreamer_build_v4l2_encode_pipeline +# Builds a complete V4L2 encode pipeline string +# Prints: pipeline string or empty if encoder not available +gstreamer_build_v4l2_encode_pipeline() { + codec="$1" + width="$2" + height="$3" + duration="$4" + framerate="$5" + bitrate="$6" + output_file="$7" + video_stack="${8:-upstream}" + + encoder=$(gstreamer_v4l2_encoder_for_codec "$codec") + if [ -z "$encoder" ]; then + printf '%s\n' "" + return 1 + fi + + # Determine parser based on codec + case "$codec" in + h264) + parser="h264parse" + ;; + h265|hevc) + parser="h265parse" + ;; + *) + parser="" + ;; + esac + + # Build encoder parameters + encoder_params="extra-controls=\"controls,video_bitrate=${bitrate}\"" + if [ "$video_stack" = "downstream" ]; then + encoder_params="${encoder_params} capture-io-mode=4 output-io-mode=4" + fi + + # Build pipeline with mp4mux for MP4 container + if [ -n "$parser" ]; then + printf '%s\n' "videotestsrc num-buffers=$((duration * framerate)) pattern=smpte ! video/x-raw,width=${width},height=${height},format=NV12,framerate=${framerate}/1 ! ${encoder} ${encoder_params} ! ${parser} ! mp4mux ! filesink location=${output_file}" + else + printf '%s\n' "videotestsrc num-buffers=$((duration * framerate)) pattern=smpte ! video/x-raw,width=${width},height=${height},format=NV12,framerate=${framerate}/1 ! ${encoder} ${encoder_params} ! mp4mux ! filesink location=${output_file}" + fi + + return 0 +} + +# -------------------- V4L2 decode pipeline builder -------------------- +# gstreamer_build_v4l2_decode_pipeline +# Builds a complete V4L2 decode pipeline string +# Prints: pipeline string or empty if decoder not available +gstreamer_build_v4l2_decode_pipeline() { + codec="$1" + input_file="$2" + video_stack="${3:-upstream}" + + decoder=$(gstreamer_v4l2_decoder_for_codec "$codec") + if [ -z "$decoder" ]; then + printf '%s\n' "" + return 1 + fi + + # Determine parser and container based on codec + case "$codec" in + h264) + parser="h264parse" + container="qtdemux" + ;; + h265|hevc) + parser="h265parse" + container="qtdemux" + ;; + vp9) + parser="ivfparse" + container="" + ;; + *) + parser="identity" + container="" + ;; + esac + + # Build decoder parameters + decoder_params="" + if [ "$video_stack" = "downstream" ]; then + decoder_params="capture-io-mode=4 output-io-mode=4" + fi + + # Build pipeline based on container format + if [ -n "$container" ]; then + # MP4 container (h264/h265) + if [ -n "$decoder_params" ]; then + printf '%s\n' "filesrc location=${input_file} ! ${container} ! ${parser} ! ${decoder} ${decoder_params} ! videoconvert ! fakesink" + else + printf '%s\n' "filesrc location=${input_file} ! ${container} ! ${parser} ! ${decoder} ! videoconvert ! fakesink" + fi + else + # IVF container (vp9) or no container + if [ -n "$decoder_params" ]; then + printf '%s\n' "filesrc location=${input_file} ! ${parser} ! ${decoder} ${decoder_params} ! videoconvert ! fakesink" + else + printf '%s\n' "filesrc location=${input_file} ! ${parser} ! ${decoder} ! videoconvert ! fakesink" + fi + fi + + return 0 +} From 55d63f0c7c794dd4fbd793df82416acd1b5804c2 Mon Sep 17 00:00:00 2001 From: Nitin Nakka Date: Sun, 15 Feb 2026 23:12:44 +0530 Subject: [PATCH 5/6] rebased lib_gstreamer.sh and added changes, modified the display and video scripts based on review comments Signed-off-by: Nitin Nakka --- .../Display/Waylandsink_Playback/README.md | 39 +++- .../Waylandsink_Playback.yaml | 45 ++-- .../Display/Waylandsink_Playback/run.sh | 136 +++++++---- .../Video/Video_Encode_Decode/README.md | 92 ++++++-- .../Video_Encode_Decode.yaml | 48 ++-- .../Video/Video_Encode_Decode/run.sh | 214 +++++++++++++----- Runner/utils/lib_gstreamer.sh | 68 ++++-- 7 files changed, 464 insertions(+), 178 deletions(-) diff --git a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/README.md b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/README.md index 4fcbb7e1..6f752886 100644 --- a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/README.md +++ b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/README.md @@ -73,10 +73,11 @@ The script is designed to be **CI/LAVA-friendly**: ### Options -- `--duration ` - Playback duration (default: 10) +- `--resolution ` - Video resolution (e.g., 1920x1080, 3840x2160) (default: 1920x1080) +- `--duration ` - Playback duration (default: 30) - `--pattern ` - videotestsrc pattern (default: smpte) -- `--width ` - Video width (default: 1920) -- `--height ` - Video height (default: 1080) +- `--width ` - Video width (alternative to --resolution) (default: 1920) +- `--height ` - Video height (alternative to --resolution) (default: 1080) - `--framerate ` - Video framerate (default: 30) - `--gst-debug ` - GStreamer debug level 1-9 (default: 2) @@ -88,14 +89,23 @@ The script is designed to be **CI/LAVA-friendly**: # Run default test (1920x1080 SMPTE for 30s) ./run.sh -# Run with 30 second duration -./run.sh --duration 30 +# Run with custom resolution using --resolution +./run.sh --resolution 3840x2160 + +# Run with custom resolution and duration +./run.sh --resolution 3840x2160 --duration 20 # Run with ball pattern ./run.sh --pattern ball -# Run with custom resolution +# Run with custom resolution using separate width/height ./run.sh --width 1280 --height 720 + +# Run with different framerate +./run.sh --framerate 60 + +# Run with higher debug level +./run.sh --gst-debug 5 ``` --- @@ -146,10 +156,15 @@ videotestsrc num-buffers= pattern= ## LAVA Environment Variables -- `VIDEO_DURATION` - Playback duration -- `VIDEO_PATTERN` - videotestsrc pattern -- `VIDEO_WIDTH` - Video width -- `VIDEO_HEIGHT` - Video height -- `VIDEO_FRAMERATE` - Video framerate -- `VIDEO_GST_DEBUG` - GStreamer debug level +The test supports these environment variables (can be set in LAVA job definition): + +- `VIDEO_DURATION` - Playback duration in seconds (default: 30) - `RUNTIMESEC` - Alternative to VIDEO_DURATION +- `VIDEO_PATTERN` - videotestsrc pattern (default: smpte) +- `VIDEO_WIDTH` - Video width (default: 1920) +- `VIDEO_HEIGHT` - Video height (default: 1080) +- `VIDEO_FRAMERATE` - Video framerate (default: 30) +- `VIDEO_GST_DEBUG` - GStreamer debug level (default: 2) +- `GST_DEBUG_LEVEL` - Alternative to VIDEO_GST_DEBUG + +**Priority order for duration**: `VIDEO_DURATION` > `RUNTIMESEC` > default (30) diff --git a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/Waylandsink_Playback.yaml b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/Waylandsink_Playback.yaml index 664e3777..2356d5b6 100644 --- a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/Waylandsink_Playback.yaml +++ b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/Waylandsink_Playback.yaml @@ -12,20 +12,27 @@ metadata: - functional params: - # Video resolution (WIDTHxHEIGHT) - VIDEO_RESOLUTION: "1920x1080" + # Playback duration in seconds (default: 30) + # Priority: VIDEO_DURATION > RUNTIMESEC + VIDEO_DURATION: "30" + RUNTIMESEC: "" # if set, used as fallback - # Test pattern for videotestsrc - VIDEO_PATTERN: "smpte" # smpte|snow|black|white|red|green|blue|checkers-1|checkers-2 + # Test pattern for videotestsrc (default: smpte) + VIDEO_PATTERN: "smpte" # smpte|snow|black|white|red|green|blue|checkers-1|checkers-2|ball - # Playback duration in seconds - PLAYBACK_DURATION: "30" + # Video width in pixels (default: 1920) + VIDEO_WIDTH: "1920" - # Frame rate - FRAMERATE: "30" + # Video height in pixels (default: 1080) + VIDEO_HEIGHT: "1080" - # GStreamer debug level + # Frame rate (default: 30) + VIDEO_FRAMERATE: "30" + + # GStreamer debug level (default: 2) + # Priority: VIDEO_GST_DEBUG > GST_DEBUG_LEVEL VIDEO_GST_DEBUG: "2" # 1-9 + GST_DEBUG_LEVEL: "" # if set, used as fallback run: steps: @@ -34,14 +41,26 @@ run: # Navigate to test directory - cd Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/ - # Build CLI args only when params are non-empty + # Export environment variables (script reads these directly) + - export VIDEO_DURATION="${VIDEO_DURATION}" + - export RUNTIMESEC="${RUNTIMESEC}" + - export VIDEO_PATTERN="${VIDEO_PATTERN}" + - export VIDEO_WIDTH="${VIDEO_WIDTH}" + - export VIDEO_HEIGHT="${VIDEO_HEIGHT}" + - export VIDEO_FRAMERATE="${VIDEO_FRAMERATE}" + - export VIDEO_GST_DEBUG="${VIDEO_GST_DEBUG}" + - export GST_DEBUG_LEVEL="${GST_DEBUG_LEVEL}" + + # Build CLI args for overrides (optional - can also rely on env vars) - | CMD="./run.sh" - [ -n "${VIDEO_RESOLUTION}" ] && CMD="${CMD} --resolution ${VIDEO_RESOLUTION}" + # Use CLI args to override defaults if needed + # Note: Script reads env vars by default, CLI args override env vars + [ -n "${VIDEO_WIDTH}" ] && [ -n "${VIDEO_HEIGHT}" ] && CMD="${CMD} --resolution ${VIDEO_WIDTH}x${VIDEO_HEIGHT}" [ -n "${VIDEO_PATTERN}" ] && CMD="${CMD} --pattern ${VIDEO_PATTERN}" - [ -n "${PLAYBACK_DURATION}" ] && CMD="${CMD} --duration ${PLAYBACK_DURATION}" - [ -n "${FRAMERATE}" ] && CMD="${CMD} --framerate ${FRAMERATE}" + [ -n "${VIDEO_DURATION}" ] && CMD="${CMD} --duration ${VIDEO_DURATION}" + [ -n "${VIDEO_FRAMERATE}" ] && CMD="${CMD} --framerate ${VIDEO_FRAMERATE}" [ -n "${VIDEO_GST_DEBUG}" ] && CMD="${CMD} --gst-debug ${VIDEO_GST_DEBUG}" echo "[LAVA] Running: ${CMD}" diff --git a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh index 2e6e951f..ad99f073 100755 --- a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh +++ b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause-Clear +# SPDX-License-Identifier: BSD-3-Clause# # Waylandsink Playback validation using GStreamer # Tests video playback using waylandsink with videotestsrc # Validates Weston/Wayland server and display connectivity @@ -69,63 +69,83 @@ trap cleanup INT TERM EXIT # -------------------- Arg parse -------------------- while [ $# -gt 0 ]; do case "$1" in + --resolution) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --resolution" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + # Parse WIDTHxHEIGHT format (e.g., 1920x1080) + if [ -n "$2" ]; then + width="${2%%x*}" + height="${2#*x}" + fi + shift 2 + ;; + --duration) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --duration" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - duration="$2" + # If $2 is empty, keep default and shift 2 + [ -n "$2" ] && duration="$2" shift 2 ;; --pattern) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --pattern" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - pattern="$2" + # If $2 is empty, keep default and shift 2 + [ -n "$2" ] && pattern="$2" shift 2 ;; --width) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --width" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - width="$2" + # If $2 is empty, keep default and shift 2 + [ -n "$2" ] && width="$2" shift 2 ;; --height) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --height" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - height="$2" + # If $2 is empty, keep default and shift 2 + [ -n "$2" ] && height="$2" shift 2 ;; --framerate) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --framerate" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - framerate="$2" + # If $2 is empty, keep default and shift 2 + [ -n "$2" ] && framerate="$2" shift 2 ;; --gst-debug) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --gst-debug" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - gstDebugLevel="$2" + # If $2 is empty, keep default and shift 2 + [ -n "$2" ] && gstDebugLevel="$2" shift 2 ;; @@ -135,6 +155,10 @@ Usage: $0 [options] Options: + --resolution + Video resolution (e.g., 1920x1080, 3840x2160) + Default: ${width}x${height} + --duration Playback duration in seconds Default: ${duration} @@ -144,11 +168,11 @@ Options: Default: ${pattern} --width - Video width + Video width (alternative to --resolution) Default: ${width} --height - Video height + Video height (alternative to --resolution) Default: ${height} --framerate @@ -160,32 +184,41 @@ Options: Default: ${gstDebugLevel} Examples: - # Run default test (1920x1080 SMPTE pattern for 10s) + # Run default test (1920x1080 SMPTE pattern for 30s) ./run.sh - # Run with custom duration - ./run.sh --duration 20 + # Run with custom resolution and duration + ./run.sh --resolution 3840x2160 --duration 20 # Run with different pattern ./run.sh --pattern ball + # Run with separate width/height + ./run.sh --width 1280 --height 720 + EOF - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 ;; *) log_warn "Unknown argument: $1" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 ;; esac done # -------------------- Pre-checks -------------------- -check_dependencies "gst-launch-1.0" "gst-inspect-1.0" >/dev/null 2>&1 || { +check_dependencies "gst-launch-1.0 gst-inspect-1.0" >/dev/null 2>&1 || { log_warn "Missing gstreamer runtime (gst-launch-1.0/gst-inspect-1.0)" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +} + +check_dependencies "grep head sed" >/dev/null 2>&1 || { + log_warn "Missing required tools (grep, head, sed)" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 } @@ -211,7 +244,7 @@ fi if [ "$have_connector" -eq 0 ]; then log_warn "No connected DRM display found, skipping ${TESTNAME}." - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi @@ -236,25 +269,42 @@ if [ -n "$sock" ] && command -v adopt_wayland_env_from_socket >/dev/null 2>&1; t fi # Try starting Weston if no socket found -if [ -z "$sock" ] && command -v overlay_start_weston_drm >/dev/null 2>&1; then - log_info "No usable Wayland socket; trying to start Weston..." - if overlay_start_weston_drm; then - if command -v discover_wayland_socket_anywhere >/dev/null 2>&1; then - sock=$(discover_wayland_socket_anywhere | head -n 1 || true) +if [ -z "$sock" ]; then + if command -v weston_pick_env_or_start >/dev/null 2>&1; then + log_info "No usable Wayland socket; trying weston_pick_env_or_start..." + if weston_pick_env_or_start "${TESTNAME}"; then + # Re-discover socket after Weston start + if command -v discover_wayland_socket_anywhere >/dev/null 2>&1; then + sock=$(discover_wayland_socket_anywhere | head -n 1 || true) + fi + if [ -n "$sock" ]; then + log_info "Weston started successfully with socket: $sock" + fi + else + log_warn "weston_pick_env_or_start failed" fi - if [ -n "$sock" ] && command -v adopt_wayland_env_from_socket >/dev/null 2>&1; then - log_info "Weston created Wayland socket: $sock" - if ! adopt_wayland_env_from_socket "$sock"; then - log_warn "Failed to adopt env from $sock" + elif command -v overlay_start_weston_drm >/dev/null 2>&1; then + log_info "No usable Wayland socket; trying overlay_start_weston_drm (fallback)..." + if overlay_start_weston_drm; then + if command -v discover_wayland_socket_anywhere >/dev/null 2>&1; then + sock=$(discover_wayland_socket_anywhere | head -n 1 || true) + fi + if [ -n "$sock" ] && command -v adopt_wayland_env_from_socket >/dev/null 2>&1; then + log_info "Weston created Wayland socket: $sock" + if ! adopt_wayland_env_from_socket "$sock"; then + log_warn "Failed to adopt env from $sock" + fi fi fi + else + log_warn "No Weston startup helper available (weston_pick_env_or_start or overlay_start_weston_drm)" fi fi # Final check if [ -z "$sock" ]; then log_warn "No Wayland socket found; skipping ${TESTNAME}." - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi @@ -262,7 +312,7 @@ fi if command -v wayland_connection_ok >/dev/null 2>&1; then if ! wayland_connection_ok; then log_fail "Wayland connection test failed; cannot run ${TESTNAME}." - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi log_info "Wayland connection test: OK" @@ -271,7 +321,7 @@ fi # -------------------- Check waylandsink element -------------------- if ! has_element waylandsink; then log_warn "waylandsink element not available" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi @@ -328,11 +378,11 @@ fi case "$result" in PASS) log_pass "$TESTNAME $result: $reason" - echo "PASS" >"$RES_FILE" + echo "$TESTNAME PASS" >"$RES_FILE" ;; *) log_fail "$TESTNAME $result: $reason" - echo "FAIL" >"$RES_FILE" + echo "$TESTNAME FAIL" >"$RES_FILE" ;; esac diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md index 0954e52f..adf22c5b 100644 --- a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md +++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md @@ -5,7 +5,7 @@ This directory contains the **Video_Encode_Decode** validation test for Qualcomm It validates video **encoding and decoding** using **GStreamer (`gst-launch-1.0`)** with V4L2 hardware-accelerated codecs: - **v4l2h264enc** / **v4l2h264dec** (H.264/AVC) - **v4l2h265enc** / **v4l2h265dec** (H.265/HEVC) -- **v4l2vp9dec** (VP9 decode only - uses pre-downloaded clips) +- **v4l2vp9dec** (VP9 decode only - uses pre-downloaded clips converted to WebM) The script is designed to be **CI/LAVA-friendly**: - Writes **PASS/FAIL/SKIP** into `Video_Encode_Decode.res` @@ -63,15 +63,15 @@ At a high level, the test: By default, the test runs the following test cases at 4K resolution for H.264/H.265, plus VP9 decode: ### Encoding Tests -1. **encode_h264_4k** - Encode H.264 at 3840x2160 resolution -2. **encode_h265_4k** - Encode H.265 at 3840x2160 resolution +1. **encode_h264_4k** - Encode H.264 at 3840x2160 resolution for 30 seconds +2. **encode_h265_4k** - Encode H.265 at 3840x2160 resolution for 30 seconds **Note:** VP9 encoding is not supported (no v4l2vp9enc available) ### Decoding Tests 1. **decode_h264_4k** - Decode H.264 4K encoded file 2. **decode_h265_4k** - Decode H.265 4K encoded file -3. **decode_vp9** - Decode VP9 pre-downloaded clip (320_240_10fps.ivf) - **runs by default** +3. **decode_vp9_320p** - Decode VP9 pre-downloaded clip (converted to WebM: vp9_test_320p.webm) - **runs by default** --- @@ -91,7 +91,7 @@ By default, the test runs the following test cases at 4K resolution for H.264/H. - Missing required tools (`gst-launch-1.0`, `gst-inspect-1.0`) - Required V4L2 encoder/decoder elements not available - For H.264/H.265 decode tests: corresponding encoded file not found (encode must run first) -- For VP9 decode tests: network connectivity unavailable or clip download failed +- For VP9 decode tests: network connectivity unavailable, clip download failed, or IVF to WebM conversion failed **Note:** The test always exits `0` even for FAIL/SKIP. The `.res` file is the source of truth. @@ -113,13 +113,14 @@ By default, logs are written relative to the script working directory: decode_h264_4k.log decode_h265_480p.log decode_h265_4k.log - decode_vp9.log # VP9 decode test log + decode_vp9_320p.log # VP9 decode test log encoded/ # Encoded video files - encode_h264_480p.h264 - encode_h264_4k.h264 - encode_h265_480p.h265 - encode_h265_4k.h265 - 320_240_10fps.ivf # Downloaded VP9 clip (if network available) + encode_h264_480p.mp4 + encode_h264_4k.mp4 + encode_h265_480p.mp4 + encode_h265_4k.mp4 + 320_240_10fps.ivf # Downloaded VP9 clip (IVF format) + vp9_test_320p.webm # Converted VP9 clip (WebM format - used for decode test) dmesg/ # dmesg scan outputs (if available) ``` @@ -186,7 +187,7 @@ Help: - `--duration ` - Duration for encoding (in seconds) - - Default: `5` + - Default: `30` - This determines how many frames are generated (duration × framerate) - `--framerate ` @@ -215,12 +216,14 @@ Help: ## Examples -### 1) Run all tests (default - encode + decode for H.264/H.265 at 4K, plus VP9 decode) +### 1) Run all tests (default - encode + decode for H.264/H.265/VP9 at 4K for 30 seconds) ```bash ./run.sh ``` +**Note:** Default behavior runs H.264, H.265, and VP9 tests at 4K resolution with 30 second duration. + ### 2) Run only encoding tests ```bash @@ -332,21 +335,38 @@ Where: - Parser ensures proper stream format - `fakesink` discards output (no display needed for validation) -### Decoding Pipeline (VP9) +### VP9 Clip Conversion Pipeline + +Before decoding, the downloaded IVF file is converted to WebM (Matroska) container: ``` filesrc location=320_240_10fps.ivf ! ivfparse + ! matroskamux + ! filesink location=vp9_test_320p.webm +``` + +Where: +- `ivfparse` parses the downloaded IVF container +- `matroskamux` remuxes to WebM/Matroska container +- **If conversion fails**: Test is skipped with reason "GST conversion failure" +- **No IVF fallback**: The test will not use IVF directly if conversion fails + +### Decoding Pipeline (VP9) + +``` +filesrc location=vp9_test_320p.webm + ! matroskademux ! v4l2vp9dec ! videoconvert ! fakesink ``` Where: -- `ivfparse` parses IVF container format (VP9 native container) -- No `qtdemux` needed (unlike H.264/H.265 in MP4) -- Input file is pre-downloaded from git repo +- `matroskademux` parses WebM/Matroska container format +- Input file is the converted WebM file (not IVF directly) - Resolution: 320x240 +- **Important**: Test skips if WebM conversion failed (no IVF fallback) --- @@ -415,6 +435,27 @@ Where: ``` - This is typically part of `gst-plugins-bad` package +### J) VP9 test skips with "GST conversion failure" +- The IVF to WebM conversion failed +- Check if `matroskamux` plugin is available: + ```bash + gst-inspect-1.0 matroskamux + ``` +- Check if `ivfparse` plugin is available: + ```bash + gst-inspect-1.0 ivfparse + ``` +- Manually test the conversion: + ```bash + cd logs/Video_Encode_Decode/ + gst-launch-1.0 filesrc location=320_240_10fps.ivf ! ivfparse ! matroskamux ! filesink location=test.webm + ``` +- Check GStreamer debug output for errors: + ```bash + GST_DEBUG=3 gst-launch-1.0 filesrc location=320_240_10fps.ivf ! ivfparse ! matroskamux ! filesink location=test.webm + ``` +- **Note**: The test will NOT fall back to using IVF directly. If conversion fails, the test skips to ensure proper container format validation + --- ## Library Functions (Runner/utils/lib_gstreamer.sh) @@ -579,15 +620,18 @@ This will output example pipelines for various codecs, resolutions, and video st The test supports these environment variables (can be set in LAVA job definition): -- `VIDEO_TEST_MODE` - Test mode (all/encode/decode) +- `VIDEO_TEST_MODE` - Test mode (all/encode/decode) (default: all) - `VIDEO_CODECS` - Comma-separated codec list (default: `h264,h265,vp9`) -- `VIDEO_RESOLUTIONS` - Comma-separated resolution list -- `VIDEO_DURATION` - Encoding duration in seconds -- `VIDEO_FRAMERATE` - Video framerate -- `VIDEO_STACK` - Video stack selection -- `VIDEO_GST_DEBUG` - GStreamer debug level -- `VIDEO_CLIP_URL` - URL for VP9 clip download (default: GitHub releases) +- `VIDEO_RESOLUTIONS` - Comma-separated resolution list (default: `4k`) +- `VIDEO_DURATION` - Encoding duration in seconds (default: 30) - `RUNTIMESEC` - Alternative to VIDEO_DURATION +- `VIDEO_FRAMERATE` - Video framerate (default: 30) +- `VIDEO_STACK` - Video stack selection (auto/upstream/downstream) (default: auto) +- `VIDEO_GST_DEBUG` - GStreamer debug level (default: 2) +- `GST_DEBUG_LEVEL` - Alternative to VIDEO_GST_DEBUG +- `VIDEO_CLIP_URL` - URL for VP9 clip download (default: GitHub releases) + +**Priority order for duration**: `VIDEO_DURATION` > `RUNTIMESEC` > default (30) ### VP9-Specific Notes for CI/LAVA diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/Video_Encode_Decode.yaml b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/Video_Encode_Decode.yaml index 12caa21b..5c11d51f 100644 --- a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/Video_Encode_Decode.yaml +++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/Video_Encode_Decode.yaml @@ -5,7 +5,8 @@ metadata: Video encode/decode validation using GStreamer (gst-launch-1.0) with V4L2 hardware-accelerated codecs on Qualcomm Linux platforms. Supports v4l2h264enc, v4l2h265enc, v4l2h264dec, v4l2h265dec, v4l2vp9dec. Uses videotestsrc to generate test patterns for H.264/H.265 (no external video files needed). - For VP9 decode, downloads pre-encoded clips from git repo (requires network connectivity). + For VP9 decode, downloads pre-encoded IVF clips from git repo, converts them to WebM container format, + then decodes using v4l2vp9dec. Test skips if IVF to WebM conversion fails (no IVF fallback). Tests encoding at 480p and 4K resolutions, then decodes the encoded files. os: - linux @@ -13,29 +14,35 @@ metadata: - functional params: - # Test mode: all (encode+decode), encode (only), decode (only) + # Test mode: all (encode+decode), encode (only), decode (only) (default: all) VIDEO_TEST_MODE: "all" # all|encode|decode - # Codecs to test (comma-separated) - VIDEO_CODECS: "h264,h265,vp9" # h264,h265,vp9 (VP9 decode only) + # Codecs to test (comma-separated) (default: h264,h265,vp9) + # Note: VP9 only supports decode (no encode) + VIDEO_CODECS: "h264,h265,vp9" # h264,h265,vp9 - # Resolutions to test (comma-separated) - VIDEO_RESOLUTIONS: "4k" # 4k (3840x2160) + # Resolutions to test (comma-separated) (default: 4k) + # Supported: 480p (640x480), 720p (1280x720), 1080p (1920x1080), 4k (3840x2160) + VIDEO_RESOLUTIONS: "4k" # 480p,720p,1080p,4k - # Encoding duration in seconds + # Encoding duration in seconds (default: 30) + # Priority: VIDEO_DURATION > RUNTIMESEC VIDEO_DURATION: "30" # seconds + RUNTIMESEC: "" # if set, used as fallback - # Video framerate + # Video framerate (default: 30) VIDEO_FRAMERATE: "30" # fps - # Video stack selection + # Video stack selection (default: auto) VIDEO_STACK: "auto" # auto|upstream|downstream - # GStreamer debug level + # GStreamer debug level (default: 2) + # Priority: VIDEO_GST_DEBUG > GST_DEBUG_LEVEL VIDEO_GST_DEBUG: "2" # 1-9 + GST_DEBUG_LEVEL: "" # if set, used as fallback - # Alternative duration variable (for compatibility) - RUNTIMESEC: "" # if set, overrides VIDEO_DURATION + # URL for VP9 clip download (default: GitHub releases) + VIDEO_CLIP_URL: "" # if set, overrides default GitHub URL run: steps: @@ -44,10 +51,24 @@ run: # Navigate to test directory - cd Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/ - # Build CLI args only when params are non-empty + # Export environment variables (script reads these directly) + - export VIDEO_TEST_MODE="${VIDEO_TEST_MODE}" + - export VIDEO_CODECS="${VIDEO_CODECS}" + - export VIDEO_RESOLUTIONS="${VIDEO_RESOLUTIONS}" + - export VIDEO_DURATION="${VIDEO_DURATION}" + - export RUNTIMESEC="${RUNTIMESEC}" + - export VIDEO_FRAMERATE="${VIDEO_FRAMERATE}" + - export VIDEO_STACK="${VIDEO_STACK}" + - export VIDEO_GST_DEBUG="${VIDEO_GST_DEBUG}" + - export GST_DEBUG_LEVEL="${GST_DEBUG_LEVEL}" + - export VIDEO_CLIP_URL="${VIDEO_CLIP_URL}" + + # Build CLI args for overrides (optional - can also rely on env vars) - | CMD="./run.sh" + # Use CLI args to override defaults if needed + # Note: Script reads env vars by default, CLI args override env vars [ -n "${VIDEO_TEST_MODE}" ] && CMD="${CMD} --mode ${VIDEO_TEST_MODE}" [ -n "${VIDEO_CODECS}" ] && CMD="${CMD} --codecs ${VIDEO_CODECS}" [ -n "${VIDEO_RESOLUTIONS}" ] && CMD="${CMD} --resolutions ${VIDEO_RESOLUTIONS}" @@ -55,6 +76,7 @@ run: [ -n "${VIDEO_FRAMERATE}" ] && CMD="${CMD} --framerate ${VIDEO_FRAMERATE}" [ -n "${VIDEO_STACK}" ] && CMD="${CMD} --stack ${VIDEO_STACK}" [ -n "${VIDEO_GST_DEBUG}" ] && CMD="${CMD} --gst-debug ${VIDEO_GST_DEBUG}" + [ -n "${VIDEO_CLIP_URL}" ] && CMD="${CMD} --clip-url ${VIDEO_CLIP_URL}" echo "[LAVA] Running: ${CMD}" sh -c "${CMD}" || true diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh index badfc11e..b3a0272a 100755 --- a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh +++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause-Clear +# SPDX-License-Identifier: BSD-3-Clause# # Video Encode/Decode validation using GStreamer with V4L2 hardware accelerated codecs # Supports: v4l2h264dec, v4l2h265dec, v4l2h264enc, v4l2h265enc # Uses videotestsrc for encoding, then decodes the encoded files @@ -77,82 +77,90 @@ trap cleanup INT TERM EXIT while [ $# -gt 0 ]; do case "$1" in --mode) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --mode" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - testMode="$2" + # If empty, keep default; otherwise use provided value + [ -n "$2" ] && testMode="$2" shift 2 ;; --codecs) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --codecs" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - codecList="$2" + # If empty, keep default; otherwise use provided value + [ -n "$2" ] && codecList="$2" shift 2 ;; --clip-url) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --clip-url" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - clipUrl="$2" + # If empty, keep default; otherwise use provided value + [ -n "$2" ] && clipUrl="$2" shift 2 ;; --resolutions) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --resolutions" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - resolutionList="$2" + # If empty, keep default; otherwise use provided value + [ -n "$2" ] && resolutionList="$2" shift 2 ;; --duration) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --duration" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - duration="$2" + # If empty, keep default; otherwise use provided value + [ -n "$2" ] && duration="$2" shift 2 ;; --framerate) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --framerate" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - framerate="$2" + # If empty, keep default; otherwise use provided value + [ -n "$2" ] && framerate="$2" shift 2 ;; --stack) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --stack" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - videoStack="$2" + # If empty, keep default; otherwise use provided value + [ -n "$2" ] && videoStack="$2" shift 2 ;; --gst-debug) - if [ $# -lt 2 ] || [ -z "$2" ] || [ "${2#--}" != "$2" ]; then + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then log_warn "Missing/invalid value for --gst-debug" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 fi - gstDebugLevel="$2" + # If empty, keep default; otherwise use provided value + [ -n "$2" ] && gstDebugLevel="$2" shift 2 ;; @@ -211,13 +219,13 @@ Examples: ./run.sh --mode decode --codecs vp9 EOF - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 ;; *) log_warn "Unknown argument: $1" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 ;; esac @@ -226,22 +234,28 @@ done # -------------------- Validate parsed values -------------------- case "$testMode" in all|encode|decode) : ;; *) log_warn "Invalid --mode '$testMode'" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 ;; esac case "$gstDebugLevel" in 1|2|3|4|5|6|7|8|9) : ;; *) log_warn "Invalid --gst-debug '$gstDebugLevel' (allowed: 1-9)" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 ;; esac # -------------------- Pre-checks -------------------- -check_dependencies "gst-launch-1.0" "gst-inspect-1.0" >/dev/null 2>&1 || { +check_dependencies "gst-launch-1.0 gst-inspect-1.0" >/dev/null 2>&1 || { log_warn "Missing gstreamer runtime (gst-launch-1.0/gst-inspect-1.0)" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +} + +check_dependencies "awk grep head sed tr stat" >/dev/null 2>&1 || { + log_warn "Missing required tools (awk, grep, head, sed, tr, stat)" + echo "$TESTNAME SKIP" >"$RES_FILE" exit 0 } @@ -372,11 +386,11 @@ run_decode_test() { ext=$(gstreamer_container_ext_for_codec "$codec") - # For VP9, use pre-downloaded clip; for others, use encoded file + # For VP9, use pre-downloaded and converted WebM clip; for others, use encoded file if [ "$codec" = "vp9" ]; then - input_file="$OUTDIR/320_240_10fps.ivf" + input_file="$OUTDIR/vp9_test_320p.webm" if [ ! -f "$input_file" ]; then - log_warn "VP9 clip not found: $input_file (download may have failed)" + log_warn "VP9 WebM clip not found: $input_file (conversion may have failed)" skip_count=$((skip_count + 1)) return 1 fi @@ -412,8 +426,15 @@ run_decode_test() { log_info "Decode exit code: $gstRc" - # Check for successful completion in log - if grep -q "Setting pipeline to NULL" "$test_log" 2>/dev/null || [ "$gstRc" -eq 0 ]; then + # Check for GStreamer errors in log + if ! gstreamer_validate_log "$test_log" "$testname"; then + log_fail "$testname: FAIL (GStreamer errors detected)" + fail_count=$((fail_count + 1)) + return 1 + fi + + # Check for successful completion + if [ "$gstRc" -eq 0 ]; then log_pass "$testname: PASS" pass_count=$((pass_count + 1)) return 0 @@ -444,36 +465,90 @@ done if [ "$need_vp9_clip" -eq 1 ] && [ "$testMode" != "encode" ]; then log_info "==========================================" - log_info "VP9 CLIP DOWNLOAD" + log_info "VP9 CLIP DOWNLOAD & CONVERSION" log_info "==========================================" - vp9_clip="$OUTDIR/320_240_10fps.ivf" + vp9_clip_ivf="$OUTDIR/320_240_10fps.ivf" + vp9_clip_webm="$OUTDIR/vp9_test_320p.webm" - if [ -f "$vp9_clip" ]; then - log_info "VP9 clip already exists: $vp9_clip" + # Check if WebM file already exists + if [ -f "$vp9_clip_webm" ]; then + log_info "VP9 WebM clip already exists: $vp9_clip_webm" else - log_info "Checking network connectivity and downloading VP9 clips..." - - # Use ensure_network_online from functestlib.sh to bring up connectivity - if ensure_network_online; then - log_pass "Network connectivity established" + # Download IVF file if not present + if [ ! -f "$vp9_clip_ivf" ]; then + log_info "Checking network connectivity and downloading VP9 clips..." + + # Check network status first + net_rc=1 + if command -v check_network_status_rc >/dev/null 2>&1; then + check_network_status_rc + net_rc=$? + elif command -v check_network_status >/dev/null 2>&1; then + check_network_status >/dev/null 2>&1 + net_rc=$? + fi - # Download and extract clips using functestlib helper + # If offline, try to bring network online + if [ "$net_rc" -ne 0 ]; then + if command -v bring_network_online >/dev/null 2>&1; then + log_info "Attempting to bring network online..." + bring_network_online + # Stabilization sleep after bringing network up + sleep 5 + else + log_warn "Could not establish network connectivity" + fi + else + log_info "Network already online" + # Brief stabilization sleep + sleep 2 + fi + + # Attempt download if we have connectivity + if command -v check_network_status_rc >/dev/null 2>&1; then + if check_network_status_rc; then + log_info "Downloading VP9 clips from: $clipUrl" + if extract_tar_from_url "$clipUrl" "$OUTDIR"; then + log_pass "VP9 clips downloaded and extracted successfully" + else + log_warn "Failed to download/extract VP9 clips (network online but download failed)" + fi + else + log_warn "Network still offline after connectivity attempt" + fi + else + # Fallback: attempt download without explicit network check log_info "Downloading VP9 clips from: $clipUrl" if extract_tar_from_url "$clipUrl" "$OUTDIR"; then log_pass "VP9 clips downloaded and extracted successfully" else log_warn "Failed to download/extract VP9 clips" fi - - # Verify clip exists after download attempt - if [ ! -f "$vp9_clip" ]; then - log_warn "VP9 clip not found after download attempt: $vp9_clip" - log_warn "VP9 decode tests will be skipped" - fi - else - log_warn "Could not establish network connectivity" + fi + fi + + # Verify clip exists after download attempt + if [ ! -f "$vp9_clip_ivf" ]; then + log_warn "VP9 clip not found after download attempt: $vp9_clip_ivf" log_warn "VP9 decode tests will be skipped" + else + # Convert IVF to WebM container using GStreamer for better compatibility + if [ ! -f "$vp9_clip_webm" ]; then + log_info "Converting IVF to WebM container using GStreamer..." + + # Use GStreamer pipeline to remux IVF to WebM (Matroska container) + if gst-launch-1.0 filesrc location="$vp9_clip_ivf" ! ivfparse ! matroskamux ! filesink location="$vp9_clip_webm" >/dev/null 2>&1; then + log_pass "Successfully converted IVF to WebM (320x240)" + else + log_fail "GStreamer IVF to WebM conversion failed" + log_warn "VP9 decode tests will be skipped (reason: GST conversion failure)" + rm -f "$vp9_clip_webm" 2>/dev/null || true + rm -f "$vp9_clip_ivf" 2>/dev/null || true + fi + else + log_info "WebM file already exists: $vp9_clip_webm" + fi fi fi fi @@ -509,10 +584,10 @@ if [ "$testMode" = "all" ] || [ "$testMode" = "decode" ]; then log_info "==========================================" for codec in $codecs; do - # For VP9, only run once (not per resolution, as we use a fixed clip) + # For VP9, only run once (not per resolution, as we use a fixed 320p clip) if [ "$codec" = "vp9" ]; then total_tests=$((total_tests + 1)) - run_decode_test "$codec" "720p" || true + run_decode_test "$codec" "320p" || true else for res in $resolutions; do total_tests=$((total_tests + 1)) @@ -522,6 +597,27 @@ if [ "$testMode" = "all" ] || [ "$testMode" = "decode" ]; then done fi +# -------------------- Dmesg error scan -------------------- +log_info "==========================================" +log_info "DMESG ERROR SCAN" +log_info "==========================================" + +# Scan for video-related errors in dmesg +module_regex="venus|vcodec|v4l2|video|gstreamer" +exclude_regex="dummy regulator|supply [^ ]+ not found|using dummy regulator" + +if command -v scan_dmesg_errors >/dev/null 2>&1; then + scan_dmesg_errors "$DMESG_DIR" "$module_regex" "$exclude_regex" || true + + if [ -s "$DMESG_DIR/dmesg_errors.log" ]; then + log_warn "dmesg scan found video-related warnings or errors in $DMESG_DIR/dmesg_errors.log" + else + log_info "No relevant video-related errors found in dmesg" + fi +else + log_info "scan_dmesg_errors not available, skipping dmesg scan" +fi + # -------------------- Summary -------------------- log_info "==========================================" log_info "TEST SUMMARY" @@ -549,15 +645,15 @@ fi case "$result" in PASS) log_pass "$TESTNAME $result: $reason" - echo "PASS" >"$RES_FILE" + echo "$TESTNAME PASS" >"$RES_FILE" ;; FAIL) log_fail "$TESTNAME $result: $reason" - echo "FAIL" >"$RES_FILE" + echo "$TESTNAME FAIL" >"$RES_FILE" ;; *) log_warn "$TESTNAME $result: $reason" - echo "SKIP" >"$RES_FILE" + echo "$TESTNAME SKIP" >"$RES_FILE" ;; esac diff --git a/Runner/utils/lib_gstreamer.sh b/Runner/utils/lib_gstreamer.sh index 89a09833..53c8ff27 100755 --- a/Runner/utils/lib_gstreamer.sh +++ b/Runner/utils/lib_gstreamer.sh @@ -1,7 +1,6 @@ #!/bin/sh # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause-Clear -# +# SPDX-License-Identifier: BSD-3-Clause# # Runner/utils/lib_gstreamer.sh # # GStreamer helpers. @@ -503,23 +502,44 @@ gstreamer_build_playback_pipeline() { # gstreamer_check_errors # Returns: 0 if no critical errors found, 1 if errors found # Checks for common GStreamer ERROR patterns that indicate failure +# Uses severity-based matching to avoid false positives on benign logs gstreamer_check_errors() { logfile="$1" [ -f "$logfile" ] || return 0 - # Check for critical ERROR messages - if grep -q -E "^ERROR:|ERROR: from element|Internal data stream error|streaming stopped, reason not-negotiated|Could not open|No such file|Permission denied|Failed to|Cannot" "$logfile" 2>/dev/null; then + # Check for explicit ERROR: prefixed messages (most reliable) + if grep -q -E "^ERROR:|^0:[0-9]+:[0-9]+\.[0-9]+ [0-9]+ [^ ]+ ERROR" "$logfile" 2>/dev/null; then + return 1 + fi + + # Check for ERROR messages from GStreamer elements + if grep -q -E "ERROR: from element|gst.*ERROR" "$logfile" 2>/dev/null; then return 1 fi - # Check for pipeline preroll failures - if grep -q -E "pipeline doesn't want to preroll|pipeline doesn't want to play" "$logfile" 2>/dev/null; then + # Check for critical streaming errors + if grep -q -E "Internal data stream error|streaming stopped, reason not-negotiated" "$logfile" 2>/dev/null; then return 1 fi - # Check for state change failures - if grep -q -E "failed to change state|state change failed" "$logfile" 2>/dev/null; then + # Check for pipeline failures (more specific patterns) + if grep -q -E "pipeline doesn't want to preroll|pipeline doesn't want to play|ERROR.*pipeline" "$logfile" 2>/dev/null; then + return 1 + fi + + # Check for state change failures (require ERROR context) + if grep -q -E "ERROR.*failed to change state|ERROR.*state change failed" "$logfile" 2>/dev/null; then + return 1 + fi + + # Check for critical file/device access errors (require ERROR context or specific patterns) + if grep -q -E "ERROR.*(Could not open|No such file|Permission denied|Failed to|Cannot)" "$logfile" 2>/dev/null; then + return 1 + fi + + # Check for CRITICAL or FATAL level messages + if grep -q -E "CRITICAL|FATAL" "$logfile" 2>/dev/null; then return 1 fi @@ -596,6 +616,7 @@ gstreamer_resolution_to_wh() { # gstreamer_v4l2_encoder_for_codec # Returns the V4L2 encoder element for the given codec +# Supports: H.264, H.265 (VP9 is decode-only, no encoder support) # Prints: encoder element name or empty string if not available gstreamer_v4l2_encoder_for_codec() { codec="$1" @@ -612,6 +633,11 @@ gstreamer_v4l2_encoder_for_codec() { return 0 fi ;; + vp9) + # VP9 is decode-only, no encoder support + printf '%s\n' "" + return 1 + ;; esac printf '%s\n' "" return 1 @@ -647,16 +673,30 @@ gstreamer_v4l2_decoder_for_codec() { } # gstreamer_container_ext_for_codec -# Returns the file extension for the given codec -# Prints: file extension (without dot) +# Returns the default container file extension for the given video codec. +# This standardizes container format selection across encode/decode operations: +# - H.264/H.265: mp4 container (ISO BMFF/MP4) - encode & decode supported +# - VP9: webm container (WebM) - decode-only +# +# The encode pipeline builders (gstreamer_build_v4l2_encode_pipeline) use +# appropriate muxers (mp4mux for H.264/H.265). VP9 encoding is not supported. +# The decode pipeline builders (gstreamer_build_v4l2_decode_pipeline) use +# appropriate demuxers (qtdemux for MP4, matroskademux for WebM). +# +# Prints: file extension (without dot) - "mp4", "webm", etc. gstreamer_container_ext_for_codec() { codec="$1" case "$codec" in vp9) - printf '%s\n' "ivf" + # VP9 uses WebM container format (Matroska-based) + printf '%s\n' "webm" + ;; + h264|h265|hevc) + # H.264/H.265 use MP4 container format (ISO BMFF) + printf '%s\n' "mp4" ;; *) - # Use mp4 container format for h264/h265 + # Default to MP4 for unknown codecs printf '%s\n' "mp4" ;; esac @@ -771,8 +811,8 @@ gstreamer_build_v4l2_decode_pipeline() { container="qtdemux" ;; vp9) - parser="ivfparse" - container="" + parser="" + container="matroskademux" ;; *) parser="identity" From 77b5d425651b5af1aad12a44a80ce1cf105f0476 Mon Sep 17 00:00:00 2001 From: Nitin Nakka Date: Sun, 15 Feb 2026 23:39:09 +0530 Subject: [PATCH 6/6] Added license identifier for all 3 shell files: BSD-3-Clause per legal request Signed-off-by: Nitin Nakka --- .../Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh | 2 +- .../Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh | 2 +- Runner/utils/lib_gstreamer.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh index ad99f073..a32da1c7 100755 --- a/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh +++ b/Runner/suites/Multimedia/GSTreamer/Display/Waylandsink_Playback/run.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause# +# SPDX-License-Identifier: BSD-3-Clause per legal request. # Waylandsink Playback validation using GStreamer # Tests video playback using waylandsink with videotestsrc # Validates Weston/Wayland server and display connectivity diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh index b3a0272a..effa6a80 100755 --- a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh +++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause# +# SPDX-License-Identifier: BSD-3-Clause per legal request. # Video Encode/Decode validation using GStreamer with V4L2 hardware accelerated codecs # Supports: v4l2h264dec, v4l2h265dec, v4l2h264enc, v4l2h265enc # Uses videotestsrc for encoding, then decodes the encoded files diff --git a/Runner/utils/lib_gstreamer.sh b/Runner/utils/lib_gstreamer.sh index 53c8ff27..05a82cb2 100755 --- a/Runner/utils/lib_gstreamer.sh +++ b/Runner/utils/lib_gstreamer.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause# +# SPDX-License-Identifier: BSD-3-Clause per legal request. # Runner/utils/lib_gstreamer.sh # # GStreamer helpers.