From e08522e6ee9d288ac592355c6fbc4e8ed75c62f8 Mon Sep 17 00:00:00 2001 From: Nitin Nakka Date: Fri, 13 Feb 2026 18:07:30 +0530 Subject: [PATCH 1/3] 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/3] 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/3] 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 +}