diff --git a/Runner/suites/Gstreamer/Audio/Gstreamer_Audio_Tests.yaml b/Runner/suites/Gstreamer/Audio/Gstreamer_Audio_Tests.yaml new file mode 100644 index 00000000..a39c44d1 --- /dev/null +++ b/Runner/suites/Gstreamer/Audio/Gstreamer_Audio_Tests.yaml @@ -0,0 +1,24 @@ +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +metadata: + format: Lava-Test Test Definition 1.0 + name: Gstreamer_Audio_Tests + description: "GStreamer Audio Pipeline Tests - Encode/Decode validation using PulseAudio" + maintainer: + - qualcomm-linux-test@quicinc.com + os: + - linux + scope: + - functional + +params: + TIMEOUT: "120" + STRICT: "false" + DMESG_SCAN: "true" + LOGLEVEL: "INFO" + +run: + steps: + - cd Runner/suites/Gstreamer/Audio + - ./run.sh --all diff --git a/Runner/suites/Gstreamer/Audio/README.md b/Runner/suites/Gstreamer/Audio/README.md new file mode 100644 index 00000000..5d902ce1 --- /dev/null +++ b/Runner/suites/Gstreamer/Audio/README.md @@ -0,0 +1,322 @@ +# GStreamer Audio Tests + +## Overview + +This test suite validates GStreamer audio pipelines using PulseAudio for capture and playback on Qualcomm platforms. It tests audio encoding (capture to WAV) and decoding (WAV playback) functionality. + +## Test Cases + +### 1. audio-encode +**Pipeline:** +```bash +gst-launch-1.0 pulsesrc ! audioconvert ! audioresample ! identity eos-after=2000 ! wavenc ! filesink location=./output_audio.wav +``` + +**Description:** +- Captures audio from PulseAudio source +- Converts and resamples audio format +- Uses identity element with eos-after=2000 (2 seconds) for controlled capture +- Encodes to WAV format +- Saves to output_audio.wav + +**Validation:** +- Pipeline completes without errors +- Output file is created +- No ERROR/WARNING messages in GStreamer output +- No dmesg errors (if DMESG_SCAN enabled) + +### 2. audio-decode +**Pipeline:** +```bash +gst-launch-1.0 filesrc location=./output_audio.wav ! wavparse ! audioconvert ! audioresample ! pulsesink +``` + +**Description:** +- Reads WAV file created by audio-encode test +- Parses WAV format +- Converts and resamples audio +- Plays back through PulseAudio sink + +**Validation:** +- Pipeline completes without errors +- Audio playback successful +- No ERROR/WARNING messages in GStreamer output +- No dmesg errors (if DMESG_SCAN enabled) + +## Prerequisites + +### Required Packages +```bash +# GStreamer core and plugins +gstreamer1.0-tools +gstreamer1.0-plugins-base +gstreamer1.0-plugins-good + +# PulseAudio support +pulseaudio +gstreamer1.0-pulseaudio +``` + +### Audio Hardware +- Working audio capture device (microphone) +- Working audio playback device (speakers/headphones) +- PulseAudio server running + +### Verification +```bash +# Check PulseAudio status +pulseaudio --check +echo $? # Should return 0 + +# List audio sources +pactl list sources short + +# List audio sinks +pactl list sinks short + +# Test audio capture +gst-launch-1.0 pulsesrc ! fakesink + +# Test audio playback +gst-launch-1.0 audiotestsrc ! pulsesink +``` + +## Usage + +### Run All Tests +```bash +./run.sh --all +``` + +### Run Specific Test +```bash +./run.sh --test audio-encode +./run.sh --test audio-decode +``` + +### List Available Tests +```bash +./run.sh --list +``` + +### Custom Timeout +```bash +./run.sh --all --timeout 180 +``` + +### Enable Strict Mode +```bash +./run.sh --all --strict +``` + +### Disable dmesg Scanning +```bash +./run.sh --all --no-dmesg +``` + +## CLI Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--all` | Run all audio tests | - | +| `--test ` | Run specific test | - | +| `--list` | List available tests | - | +| `--timeout ` | Timeout per test | 120 | +| `--repeat ` | Repeat count | 1 | +| `--repeat-policy ` | Pass policy | all | +| `--strict` | Fail on warnings | false | +| `--no-dmesg` | Skip dmesg scan | false | +| `--help` | Show help | - | + +## Output Files + +### Result Files +- `Gstreamer_Audio_Tests.res` - Overall PASS/FAIL/SKIP status +- `logs_Gstreamer_Audio_Tests/` - Detailed logs directory + - `audio-encode.log` - Encode test output + - `audio-decode.log` - Decode test output + - `summary.txt` - Test summary + - `results.csv` - CSV format results + - `.junit_cases.xml` - JUnit XML for CI + - `dmesg_snapshot.log` - Kernel messages + - `dmesg_errors.log` - Kernel errors (if any) + +### Generated Files +- `output_audio.wav` - Audio file created by encode test + +## Validation Criteria + +### Pass Criteria +✓ Pipeline executes without errors +✓ Output files created successfully +✓ No ERROR messages in GStreamer output +✓ No WARNING messages (if --strict enabled) +✓ No kernel errors in dmesg (if DMESG_SCAN enabled) +✓ Exit code 0 from gst-launch-1.0 + +### Fail Criteria +✗ Pipeline execution fails +✗ ERROR messages in GStreamer output +✗ WARNING messages (in strict mode) +✗ Timeout exceeded +✗ Output file not created +✗ Kernel errors detected + +## Troubleshooting + +### PulseAudio Not Running +```bash +# Start PulseAudio +pulseaudio --start + +# Check status +pulseaudio --check +``` + +### No Audio Devices +```bash +# List available sources +pactl list sources short + +# List available sinks +pactl list sinks short + +# Set default source/sink +pactl set-default-source +pactl set-default-sink +``` + +### Permission Issues +```bash +# Add user to audio group +sudo usermod -a -G audio $USER + +# Verify group membership +groups $USER +``` + +### Audio Capture Fails +```bash +# Test with audiotestsrc instead +gst-launch-1.0 audiotestsrc ! audioconvert ! audioresample ! wavenc ! filesink location=test.wav + +# Check microphone permissions +ls -la /dev/snd/ + +# Test with arecord +arecord -d 2 -f cd test.wav +``` + +### Audio Playback Fails +```bash +# Test with speaker-test +speaker-test -t sine -f 440 -c 2 + +# Test with aplay +aplay test.wav + +# Check volume levels +pactl list sinks | grep -i volume +``` + +### Pipeline Negotiation Errors +```bash +# Enable debug output +GST_DEBUG=3 gst-launch-1.0 pulsesrc ! audioconvert ! audioresample ! wavenc ! filesink location=test.wav + +# Check supported formats +gst-inspect-1.0 pulsesrc +gst-inspect-1.0 wavenc +``` + +### Common Error Messages + +**"Could not open audio device for recording"** +- PulseAudio not running or no capture device available +- Check: `pactl list sources short` + +**"Could not open audio device for playback"** +- PulseAudio not running or no playback device available +- Check: `pactl list sinks short` + +**"Failed to connect stream"** +- PulseAudio server connection issue +- Restart: `pulseaudio --kill && pulseaudio --start` + +**"No space left on device"** +- Insufficient disk space for output file +- Check: `df -h .` + +## Environment Variables + +```bash +# GStreamer debug level (0-9) +export GST_DEBUG=3 + +# PulseAudio server +export PULSE_SERVER=unix:/run/user/1000/pulse/native + +# Audio buffer size +export PULSE_LATENCY_MSEC=50 +``` + +## CI/CD Integration + +### LAVA Integration +```yaml +- test: + definitions: + - repository: https://git.codelinaro.org/clo/le/le-test-automation/qcom-linux-testkit + from: git + path: Runner/suites/Gstreamer/Audio/Gstreamer_Audio_Tests.yaml + name: gstreamer-audio-tests + parameters: + TIMEOUT: "120" + STRICT: "false" + DMESG_SCAN: "true" +``` + +### Standalone Execution +```bash +# Basic run +cd /path/to/qcom-linux-testkit/Runner/suites/Gstreamer/Audio +./run.sh --all + +# With custom parameters +TIMEOUT=180 STRICT=true ./run.sh --all +``` + +## Platform Support + +| Platform | Status | Notes | +|----------|--------|-------| +| QCS6490 | ✓ Supported | Full audio support | +| QCS8550 | ✓ Supported | Full audio support | +| QCS8650 | ✓ Supported | Full audio support | +| SA8775P | ✓ Supported | Full audio support | +| SA8650P | ✓ Supported | Full audio support | +| SA8255P | ✓ Supported | Full audio support | + +## Known Issues + +1. **PulseAudio Latency**: Some platforms may experience audio latency + - Workaround: Adjust `PULSE_LATENCY_MSEC` environment variable + +2. **Device Busy**: Audio device may be in use by another application + - Workaround: Stop other audio applications or use `fuser -k /dev/snd/*` + +3. **Sample Rate Mismatch**: Some devices may not support default sample rates + - Workaround: Explicitly set sample rate in pipeline with `audio/x-raw,rate=48000` + +## Additional Resources + +- [GStreamer Documentation](https://gstreamer.freedesktop.org/documentation/) +- [PulseAudio Documentation](https://www.freedesktop.org/wiki/Software/PulseAudio/) +- [GStreamer PulseAudio Plugin](https://gstreamer.freedesktop.org/documentation/pulseaudio/) +- [Audio Debugging Guide](https://wiki.archlinux.org/title/PulseAudio/Troubleshooting) + +## License + +``` +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause-Clear diff --git a/Runner/suites/Gstreamer/Audio/run.sh b/Runner/suites/Gstreamer/Audio/run.sh new file mode 100644 index 00000000..2483f8c7 --- /dev/null +++ b/Runner/suites/Gstreamer/Audio/run.sh @@ -0,0 +1,367 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear +# GStreamer Audio Encode/Decode Test Runner + +# ---------- Repo env + helpers ---------- +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 1 +fi + +# Only source once (idempotent) +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# shellcheck disable=SC1090 +. "$INIT_ENV" +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" + +TESTNAME="Gstreamer_Audio_Tests" +RES_FILE="./${TESTNAME}.res" + +# --- Defaults / knobs --- +if [ -z "${TIMEOUT:-}" ]; then TIMEOUT="60"; fi +if [ -z "${STRICT:-}" ]; then STRICT="0"; fi +if [ -z "${DMESG_SCAN:-}" ]; then DMESG_SCAN="1"; fi +if [ -z "${STOP_ON_FAIL:-}" ]; then STOP_ON_FAIL="0"; fi +if [ -z "${LOGLEVEL:-}" ]; then LOGLEVEL="15"; fi +if [ -z "${REPEAT:-}" ]; then REPEAT="1"; fi +if [ -z "${REPEAT_DELAY:-}" ]; then REPEAT_DELAY="0"; fi +if [ -z "${REPEAT_POLICY:-}" ]; then REPEAT_POLICY="all"; fi +JUNIT_OUT="" +VERBOSE="0" +POST_TEST_SLEEP="0" + +# --- Audio settings --- +AUDIO_OUTPUT="./output_audio.wav" +AUDIO_EOS_BUFFERS="${AUDIO_EOS_BUFFERS:-2000}" + +# --- GStreamer pipelines --- +AUDIO_ENCODE_PIPELINE="pulsesrc ! audioconvert ! audioresample ! identity eos-after=${AUDIO_EOS_BUFFERS} ! wavenc ! filesink location=${AUDIO_OUTPUT}" + +AUDIO_DECODE_PIPELINE="filesrc location=${AUDIO_OUTPUT} ! wavparse ! audioconvert ! audioresample ! pulsesink" + +usage() { + cat <"$RES_FILE" + exit 0 +fi + +# --- Resolve test path --- +test_path="$(find_test_case_by_name "$TESTNAME" 2>/dev/null || true)" +if [ -z "$test_path" ] || [ ! -d "$test_path" ]; then + test_path="$SCRIPT_DIR" +fi + +if ! cd "$test_path"; then + log_error "cd failed: $test_path" + printf '%s\n' "$TESTNAME FAIL" >"$RES_FILE" + exit 1 +fi + +# --- Create log directory --- +LOG_DIR="./logs_${TESTNAME}" +mkdir -p "$LOG_DIR" +export LOG_DIR + +# --- Check GStreamer plugins --- +for plugin in pulsesrc pulsesink wavenc wavparse audioconvert audioresample identity; do + if ! gst-inspect-1.0 "$plugin" >/dev/null 2>&1; then + log_skip "$TESTNAME SKIP - $plugin plugin not available" + printf '%s\n' "$TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi +done + +# --- JUnit prep / results files --- +JUNIT_TMP="$LOG_DIR/.junit_cases.xml" +: > "$JUNIT_TMP" +printf '%s\n' "mode,id,result,name,elapsed,pass_runs,fail_runs" > "$LOG_DIR/results.csv" +: > "$LOG_DIR/summary.txt" + +# --- Helper functions --- +run_gst_pipeline() { + id="$1" + pipeline="$2" + logf="$LOG_DIR/${id}.log" + + log_info "[$id] Running GStreamer pipeline" + start_time=$(date +%s) + + if command -v run_with_timeout >/dev/null 2>&1; then + if run_with_timeout "$TIMEOUT" gst-launch-1.0 -v $pipeline >"$logf" 2>&1; then + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + if check_pipeline_errors "$logf"; then + log_fail "[$id] FAIL - Pipeline errors detected (${elapsed}s)" + return 1 + else + log_pass "[$id] PASS (${elapsed}s)" + return 0 + fi + else + rc=$? + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + if [ "$rc" -eq 124 ]; then + log_fail "[$id] FAIL - timeout after ${TIMEOUT}s" + else + log_fail "[$id] FAIL - gst-launch-1.0 exited with code $rc" + fi + return 1 + fi + else + if gst-launch-1.0 -v $pipeline >"$logf" 2>&1; then + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + if check_pipeline_errors "$logf"; then + log_fail "[$id] FAIL - Pipeline errors detected (${elapsed}s)" + return 1 + else + log_pass "[$id] PASS (${elapsed}s)" + return 0 + fi + else + rc=$? + log_fail "[$id] FAIL - gst-launch-1.0 exited with code $rc" + return 1 + fi + fi +} + +check_pipeline_errors() { + logf="$1" + + if grep -q "ERROR:" "$logf"; then + return 0 + fi + + if [ "$STRICT" -eq 1 ] && grep -q "WARNING:" "$logf"; then + return 0 + fi + + if grep -q "negotiation failed" "$logf"; then + return 0 + fi + + if grep -q "buffer pool activation failed" "$logf"; then + return 0 + fi + + return 1 +} + +# --- Run tests --- +log_info "----------------------------------------------------------------------" +log_info "---------------------- Starting $TESTNAME ----------------------------" +log_info "TIMEOUT=${TIMEOUT}s LOGLEVEL=$LOGLEVEL REPEAT=$REPEAT" + +total=0 +pass=0 +fail=0 +skip=0 +suite_rc=0 + +# --- Test 1: Audio Encode --- +id="audio-encode" +name="Audio Encode using pulsesrc → wavenc" +total=$((total + 1)) + +log_info "----------------------------------------------------------------------" +log_info "[$id] START - $name" + +pass_runs=0 +fail_runs=0 +case_skipped=0 +rep=1 + +while [ "$rep" -le "$REPEAT" ]; do + if [ "$REPEAT" -gt 1 ]; then + log_info "[$id] repeat $rep/$REPEAT" + fi + + if run_gst_pipeline "$id" "$AUDIO_ENCODE_PIPELINE"; then + pass_runs=$((pass_runs + 1)) + else + fail_runs=$((fail_runs + 1)) + fi + + if [ "$rep" -lt "$REPEAT" ] && [ "$REPEAT_DELAY" -gt 0 ]; then + sleep "$REPEAT_DELAY" + fi + + rep=$((rep + 1)) +done + +final="FAIL" +case "$REPEAT_POLICY" in + any) [ "$pass_runs" -ge 1 ] && final="PASS" ;; + all|*) [ "$fail_runs" -eq 0 ] && final="PASS" ;; +esac + +if [ "$DMESG_SCAN" -eq 1 ] && command -v scan_dmesg_errors >/dev/null 2>&1; then + if scan_dmesg_errors "$LOG_DIR" "audio|sound|alsa|pulse" "dummy regulator|not found"; then + log_warn "[$id] dmesg reported errors (STRICT=$STRICT)" + [ "$STRICT" -eq 1 ] && final="FAIL" + fi +fi + +printf '%s\n' "$id $final $name" >> "$LOG_DIR/summary.txt" +printf '%s\n' "encode,$id,$final,$name,0,$pass_runs,$fail_runs" >> "$LOG_DIR/results.csv" + +if [ "$final" = "PASS" ]; then + pass=$((pass + 1)) +else + fail=$((fail + 1)) + suite_rc=1 + [ "$STOP_ON_FAIL" -eq 1 ] && exit 1 +fi + +[ "$POST_TEST_SLEEP" -gt 0 ] && sleep "$POST_TEST_SLEEP" + +# --- Test 2: Audio Decode --- +id="audio-decode" +name="Audio Decode using wavparse → pulsesink" +total=$((total + 1)) + +log_info "----------------------------------------------------------------------" +log_info "[$id] START - $name" + +pass_runs=0 +fail_runs=0 +case_skipped=0 +rep=1 + +# Check if audio file exists from encode test +if [ ! -f "$AUDIO_OUTPUT" ]; then + log_skip "[$id] SKIP - audio output file not available (run audio-encode first)" + case_skipped=1 + skip=$((skip + 1)) + final="SKIP" +else + while [ "$rep" -le "$REPEAT" ]; do + if [ "$REPEAT" -gt 1 ]; then + log_info "[$id] repeat $rep/$REPEAT" + fi + + if run_gst_pipeline "$id" "$AUDIO_DECODE_PIPELINE"; then + pass_runs=$((pass_runs + 1)) + else + fail_runs=$((fail_runs + 1)) + fi + + if [ "$rep" -lt "$REPEAT" ] && [ "$REPEAT_DELAY" -gt 0 ]; then + sleep "$REPEAT_DELAY" + fi + + rep=$((rep + 1)) + done + + final="FAIL" + case "$REPEAT_POLICY" in + any) [ "$pass_runs" -ge 1 ] && final="PASS" ;; + all|*) [ "$fail_runs" -eq 0 ] && final="PASS" ;; + esac + + if [ "$DMESG_SCAN" -eq 1 ] && command -v scan_dmesg_errors >/dev/null 2>&1; then + if scan_dmesg_errors "$LOG_DIR" "audio|sound|alsa|pulse" "dummy regulator|not found"; then + log_warn "[$id] dmesg reported errors (STRICT=$STRICT)" + [ "$STRICT" -eq 1 ] && final="FAIL" + fi + fi +fi + +printf '%s\n' "$id $final $name" >> "$LOG_DIR/summary.txt" +printf '%s\n' "decode,$id,$final,$name,0,$pass_runs,$fail_runs" >> "$LOG_DIR/results.csv" + +if [ "$final" = "PASS" ]; then + pass=$((pass + 1)) +elif [ "$final" = "FAIL" ]; then + fail=$((fail + 1)) + suite_rc=1 +fi + +# --- Summary --- +log_info "----------------------------------------------------------------------" +log_info "Summary: total=$total pass=$pass fail=$fail skip=$skip" + +if [ -s "$LOG_DIR/summary.txt" ]; then + log_info "----------------------------------------------------------------------" + log_info "Per-test results:" + while IFS= read -r line; do + log_info "$line" + done < "$LOG_DIR/summary.txt" +fi + +# --- JUnit finalize --- +if [ -n "$JUNIT_OUT" ]; then + { + printf '\n' "$TESTNAME" "$total" "$fail" "$skip" + cat "$JUNIT_TMP" + printf '\n' + } > "$JUNIT_OUT" + log_info "Wrote JUnit: $JUNIT_OUT" +fi + +# Overall result +if [ "$pass" -eq 0 ] && [ "$fail" -eq 0 ] && [ "$skip" -gt 0 ]; then + log_skip "$TESTNAME: SKIP" + printf '%s\n' "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +if [ "$suite_rc" -eq 0 ]; then + log_pass "$TESTNAME: PASS" + printf '%s\n' "$TESTNAME PASS" >"$RES_FILE" + exit 0 +else + log_fail "$TESTNAME: FAIL" + printf '%s\n' "$TESTNAME FAIL" >"$RES_FILE" + exit 1 +fi diff --git a/Runner/suites/Gstreamer/Camera/Gstreamer_Camera_Tests.yaml b/Runner/suites/Gstreamer/Camera/Gstreamer_Camera_Tests.yaml new file mode 100644 index 00000000..07bbb545 --- /dev/null +++ b/Runner/suites/Gstreamer/Camera/Gstreamer_Camera_Tests.yaml @@ -0,0 +1,42 @@ +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +metadata: + format: Lava-Test Test Definition 1.0 + name: Gstreamer_Camera_Tests + description: "GStreamer Camera Tests - Camera capture, encoding, preview, and snapshot validation using V4L2" + maintainer: + - qualcomm-linux-test@quicinc.com + os: + - linux + +params: + # Timeout for each test in seconds + TIMEOUT: "120" + # Camera device path + CAMERA_DEVICE: "/dev/video0" + # Capture duration in seconds + CAPTURE_DURATION: "5" + # Enable strict mode (treat warnings as failures) + STRICT: "false" + # Enable dmesg scanning + DMESG_SCAN: "true" + # Repeat count + REPEAT: "1" + # Repeat policy (all or any) + REPEAT_POLICY: "all" + +run: + steps: + - cd Runner/suites/Gstreamer/Camera + - chmod +x ./run.sh + - | + ./run.sh --all \ + --timeout "${TIMEOUT}" \ + --camera "${CAMERA_DEVICE}" \ + --duration "${CAPTURE_DURATION}" \ + --repeat "${REPEAT}" \ + --repeat-policy "${REPEAT_POLICY}" \ + $([ "${STRICT}" = "true" ] && echo "--strict") \ + $([ "${DMESG_SCAN}" = "false" ] && echo "--no-dmesg") \ + || true diff --git a/Runner/suites/Gstreamer/Camera/README.md b/Runner/suites/Gstreamer/Camera/README.md new file mode 100644 index 00000000..d9d174b8 --- /dev/null +++ b/Runner/suites/Gstreamer/Camera/README.md @@ -0,0 +1,546 @@ +# GStreamer Camera Tests + +**Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.** +**SPDX-License-Identifier: BSD-3-Clause-Clear** + +--- + +## Overview + +This test suite validates GStreamer camera capture functionality on Qualcomm Linux platforms. Tests cover camera preview, hardware-accelerated encoding (H.264/H.265), and image capture (PNG/JPEG) using libcamera source and hardware encoders. + +### Test Coverage + +**5 Test Cases:** +- **Camera Preview**: Live camera preview to Wayland display +- **Camera H.264 Encode**: Capture and encode to H.264/MP4 +- **Camera H.265 Encode**: Capture and encode to H.265/MP4 +- **Camera Snapshot**: Capture single frame as PNG +- **Camera JPEG Encode**: Capture single frame as JPEG + +**Key Features:** +- Uses libcamera source (`libcamerasrc`) for modern camera stack +- Hardware-accelerated encoding with V4L2 encoders +- Automatic camera detection via libcamera +- Configurable capture duration +- Multiple output formats (MP4, PNG, JPEG) +- Real-time preview capability + +--- + +## Quick Start + +```bash +cd Runner/suites/Gstreamer/Camera +./run.sh --all +``` + +--- + +## Test Pipelines + +### Camera Preview (1080p @ 30fps, 5 seconds) +```bash +libcamerasrc num-buffers=150 ! \ + video/x-raw,width=1920,height=1080,framerate=30/1 ! \ + videoconvert ! \ + waylandsink +``` +- **Purpose**: Validate camera capture and display pipeline +- **Duration**: 5 seconds (150 frames) +- **Output**: Live preview on Wayland display +- **Use Case**: Basic camera functionality test +- **Note**: Uses libcamera for camera access + +### Camera H.264 Encode (1080p @ 30fps, 5 seconds) +```bash +libcamerasrc num-buffers=150 ! \ + video/x-raw,width=1920,height=1080,framerate=30/1 ! \ + videoconvert ! \ + video/x-raw,format=NV12 ! \ + v4l2h264enc extra-controls="controls,video_bitrate=4000000" ! \ + h264parse ! \ + qtmux ! \ + filesink location=camera_h264.mp4 +``` +- **Purpose**: Validate camera capture with H.264 hardware encoding +- **Duration**: 5 seconds (150 frames) +- **Bitrate**: 4 Mbps +- **Output**: `camera_h264.mp4` +- **Use Case**: Video recording with H.264 codec + +### Camera H.265 Encode (1080p @ 30fps, 5 seconds) +```bash +libcamerasrc num-buffers=150 ! \ + video/x-raw,width=1920,height=1080,framerate=30/1 ! \ + videoconvert ! \ + video/x-raw,format=NV12 ! \ + v4l2h265enc extra-controls="controls,video_bitrate=4000000" ! \ + h265parse ! \ + qtmux ! \ + filesink location=camera_h265.mp4 +``` +- **Purpose**: Validate camera capture with H.265 hardware encoding +- **Duration**: 5 seconds (150 frames) +- **Bitrate**: 4 Mbps +- **Output**: `camera_h265.mp4` +- **Use Case**: Video recording with H.265 codec + +### Camera Snapshot (1080p, single frame) +```bash +libcamerasrc num-buffers=1 ! \ + video/x-raw,width=1920,height=1080 ! \ + videoconvert ! \ + pngenc ! \ + filesink location=camera_snapshot.png +``` +- **Purpose**: Capture single frame as PNG image +- **Resolution**: 1920x1080 +- **Output**: `camera_snapshot.png` +- **Use Case**: Still image capture, lossless format + +### Camera JPEG Encode (1080p, single frame) +```bash +libcamerasrc num-buffers=1 ! \ + video/x-raw,width=1920,height=1080 ! \ + videoconvert ! \ + jpegenc quality=90 ! \ + filesink location=camera_jpeg.jpg +``` +- **Purpose**: Capture single frame as JPEG image +- **Resolution**: 1920x1080 +- **Quality**: 90% +- **Output**: `camera_jpeg.jpg` +- **Use Case**: Still image capture, compressed format + +--- + +## CLI Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--all` | Run all camera tests | - | +| `--test ` | Run specific test | - | +| `--list` | List available tests | - | +| `--timeout ` | Timeout per test | 120 | +| `--camera ` | Camera device path | /dev/video0 | +| `--duration ` | Capture duration | 5 | +| `--repeat ` | Repeat count | 1 | +| `--repeat-policy all\|any` | Pass policy | all | +| `--strict` | Fail on warnings | false | +| `--no-dmesg` | Skip dmesg scan | false | +| `--help` | Show help | - | + +--- + +## Examples + +### Run all tests +```bash +./run.sh --all +``` + +### Run specific test +```bash +./run.sh --test camera-preview +./run.sh --test camera-h264-encode +``` + +### Use different camera device +```bash +./run.sh --all --camera /dev/video2 +``` + +### Longer capture duration +```bash +./run.sh --test camera-h264-encode --duration 10 +``` + +### List available tests +```bash +./run.sh --list +``` + +### Run with repeat +```bash +./run.sh --test camera-snapshot --repeat 5 +``` + +### Run with strict mode +```bash +./run.sh --all --strict +``` + +--- + +## Output Files + +### Test Result +- `Gstreamer_Camera_Tests.res` - Overall PASS/FAIL/SKIP + +### Logs Directory: `logs_Gstreamer_Camera_Tests/` +- `camera-preview.log` - Preview test log +- `camera-h264-encode.log` - H.264 encode test log +- `camera-h265-encode.log` - H.265 encode test log +- `camera-snapshot.log` - Snapshot test log +- `camera-jpeg-encode.log` - JPEG encode test log +- `summary.txt` - Per-test results summary +- `results.csv` - Machine-readable results +- `.junit_cases.xml` - JUnit XML for CI +- `dmesg_snapshot.log` - Kernel messages snapshot +- `dmesg_errors.log` - Kernel errors (if any) + +### Captured Media Files +- `camera_h264.mp4` - H.264 encoded video (5 seconds @ 1080p) +- `camera_h265.mp4` - H.265 encoded video (5 seconds @ 1080p) +- `camera_snapshot.png` - PNG snapshot (1080p) +- `camera_jpeg.jpg` - JPEG snapshot (1080p, 90% quality) + +--- + +## Validation Criteria + +### Pass Criteria +A test PASSES if: +1. GStreamer pipeline exits with code 0 +2. No ERROR patterns in log +3. No WARNING patterns (if `--strict` mode) +4. No kernel errors in dmesg (if enabled) +5. Camera device accessible and functional +6. For encoding tests: Output file created with size > 0 +7. For preview test: Pipeline runs without errors + +### Error Patterns Detected +- `ERROR:` - General GStreamer errors +- `failed to negotiate` - Format negotiation issues +- `could not link` - Element linking failures +- `no such element` - Missing GStreamer elements +- `failed to create element` - Element creation failures +- `cannot identify device` - Camera device not recognized +- `no such device` - Camera device not found +- `device busy` - Camera device in use by another process + +--- + +## Dependencies + +### Required GStreamer Plugins +- `libcamerasrc` - libcamera source (gstreamer1.0-libcamera) +- `videoconvert` - Format converter (gstreamer1.0-plugins-base) +- `v4l2h264enc` - H.264 hardware encoder (gstreamer1.0-plugins-good) +- `v4l2h265enc` - H.265 hardware encoder (gstreamer1.0-plugins-good) +- `h264parse` - H.264 parser (gstreamer1.0-plugins-bad) +- `h265parse` - H.265 parser (gstreamer1.0-plugins-bad) +- `qtmux` - MP4 muxer (gstreamer1.0-plugins-good) +- `pngenc` - PNG encoder (gstreamer1.0-plugins-good) +- `jpegenc` - JPEG encoder (gstreamer1.0-plugins-good) +- `waylandsink` - Wayland video sink (gstreamer1.0-plugins-bad) +- `filesink` - File output sink (gstreamer1.0-plugins-base) + +### System Requirements +- libcamera installed and configured +- Camera accessible via libcamera +- V4L2 video encoder drivers loaded (for encoding tests) +- Wayland compositor running (for preview test) +- GStreamer 1.0 installed +- libcamera-apps (optional, for diagnostics with libcamera-hello) + +### Verification Commands +```bash +# Check libcamera cameras +libcamera-hello --list-cameras + +# Check GStreamer plugins +gst-inspect-1.0 libcamerasrc +gst-inspect-1.0 v4l2h264enc +gst-inspect-1.0 v4l2h265enc + +# Test libcamera +libcamera-hello --timeout 2000 + +# Check camera driver +lsmod | grep -E 'video|camera' +dmesg | grep -i camera +``` + +--- + +## Troubleshooting + +### Camera Not Detected by libcamera +```bash +# List cameras via libcamera +libcamera-hello --list-cameras + +# Check libcamera installation +which libcamera-hello +gst-inspect-1.0 libcamerasrc + +# Check camera driver +lsmod | grep -E 'video|camera|uvc' + +# Check dmesg for camera +dmesg | grep -i camera + +# Load camera driver if needed +modprobe uvcvideo # For USB cameras +modprobe qcom_camss # For Qualcomm cameras +``` + +### Camera Device Busy +```bash +# Check what's using the camera +lsof /dev/video0 +fuser /dev/video0 + +# Kill processes using camera +fuser -k /dev/video0 + +# Check for other GStreamer processes +ps aux | grep gst-launch +``` + +### Permission Issues +```bash +# Check device permissions +ls -la /dev/video0 + +# Add user to video group +sudo usermod -a -G video $USER + +# Verify group membership +groups $USER + +# Set device permissions (temporary) +sudo chmod 666 /dev/video0 +``` + +### Missing Plugins +```bash +# Check plugin availability +gst-inspect-1.0 v4l2src +gst-inspect-1.0 v4l2h264enc +gst-inspect-1.0 waylandsink + +# Install packages (if missing) +apt-get install gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good \ + gstreamer1.0-plugins-bad \ + gstreamer1.0-tools \ + v4l-utils +``` + +### Pipeline Failures +```bash +# Run pipeline manually with verbose output +GST_DEBUG=3 gst-launch-1.0 -v libcamerasrc num-buffers=30 ! waylandsink + +# Check log file +cat logs_Gstreamer_Camera_Tests/camera-preview.log + +# Test simple camera capture +gst-launch-1.0 libcamerasrc ! autovideosink + +# Test with libcamera directly +libcamera-hello --timeout 5000 +``` + +### Format Negotiation Errors +```bash +# Check libcamera capabilities +libcamera-hello --list-cameras + +# Try different resolution +./run.sh --test camera-preview # Modify pipeline in run.sh if needed + +# Check format capabilities +gst-inspect-1.0 libcamerasrc + +# Test with libcamera-vid +libcamera-vid --timeout 5000 -o test.h264 +``` + +### Encoding Failures +```bash +# Check if hardware encoders are available +gst-inspect-1.0 v4l2h264enc +gst-inspect-1.0 v4l2h265enc + +# Check video encoder devices +ls -la /dev/video* | grep enc + +# Test encoding manually +gst-launch-1.0 videotestsrc num-buffers=30 ! v4l2h264enc ! fakesink +``` + +### Preview Not Showing +```bash +# Check Wayland display +echo $WAYLAND_DISPLAY +echo $XDG_RUNTIME_DIR + +# Start Wayland compositor +weston & + +# Test with autovideosink +gst-launch-1.0 libcamerasrc ! autovideosink + +# Test with libcamera-hello +libcamera-hello --timeout 5000 +``` + +### Low Frame Rate +```bash +# Check libcamera capabilities +libcamera-hello --list-cameras + +# Try lower resolution +# Modify pipeline to use 1280x720 or 640x480 + +# Check system load +top + +# Test with libcamera-vid +libcamera-vid --width 1280 --height 720 --timeout 5000 -o test.h264 +``` + +### Output File Empty +```bash +# Check disk space +df -h + +# Check file permissions +ls -la camera_*.mp4 + +# Verify encoding completed +cat logs_Gstreamer_Camera_Tests/camera-h264-encode.log + +# Test with longer duration +./run.sh --test camera-h264-encode --duration 10 +``` + +--- + +## Supported Platforms + +- **LeMans** (QCS9100, QCS9075) +- **Monaco** (QCS8300) +- **Kodiak** (QCS6490, QCM6490) +- **QCS8550, QCS8650** +- **SA8775P, SA8650P, SA8255P** + +--- + +## Camera Detection with libcamera + +### Finding Available Cameras +```bash +# List cameras via libcamera +libcamera-hello --list-cameras + +# Example output shows camera index and capabilities +# Camera 0: imx219 [3280x2464] +# Camera 1: ov5647 [2592x1944] +``` + +### Camera Selection +libcamera automatically selects the first available camera. The `--camera` parameter is kept for compatibility but libcamera handles camera selection internally. + +```bash +# Run tests (libcamera auto-selects camera) +./run.sh --all + +# Set via environment variable (for compatibility) +export CAMERA_DEVICE=/dev/video0 +./run.sh --all +``` + +### Testing Camera Access +```bash +# Test camera with libcamera-hello +libcamera-hello --timeout 5000 + +# Test camera with GStreamer +gst-launch-1.0 libcamerasrc num-buffers=30 ! autovideosink + +# List camera properties +libcamera-hello --list-cameras --verbose +``` + +--- + +## CI/CD Integration + +### LAVA Test Definition +```yaml +- test: + definitions: + - repository: + from: git + path: Runner/suites/Gstreamer/Camera/Gstreamer_Camera_Tests.yaml + name: gstreamer-camera-tests + parameters: + TIMEOUT: "120" + CAMERA_DEVICE: "/dev/video0" + CAPTURE_DURATION: "5" +``` + +### Jenkins Pipeline +```groovy +stage('GStreamer Camera Tests') { + steps { + sh ''' + cd Runner/suites/Gstreamer/Camera + ./run.sh --all --camera /dev/video0 + ''' + } +} +``` + +--- + +## Environment Variables + +```bash +# Camera device +export CAMERA_DEVICE=/dev/video0 + +# Capture duration (seconds) +export CAPTURE_DURATION=5 + +# Timeout per test (seconds) +export TIMEOUT=120 + +# GStreamer debug level (0-9) +export GST_DEBUG=3 + +# Wayland display (for preview) +export WAYLAND_DISPLAY=wayland-0 +export XDG_RUNTIME_DIR=/run/user/$(id -u) +``` + +--- + +## Performance Considerations + +### Resolution vs Performance +- **1080p (1920x1080)**: Standard HD, good balance +- **720p (1280x720)**: Lower resource usage, faster encoding +- **4K (3840x2160)**: High quality, requires more resources + +### Frame Rate Recommendations +- **30fps**: Standard video, good for most use cases +- **60fps**: Smooth motion, requires more bandwidth +- **15fps**: Low bandwidth, acceptable for monitoring + +### Bitrate Guidelines +- **1080p @ 30fps**: 2-4 Mbps +- **720p @ 30fps**: 1-2 Mbps +- **4K @ 30fps**: 8-12 Mbps + +--- + +## License + +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause-Clear diff --git a/Runner/suites/Gstreamer/Camera/run.sh b/Runner/suites/Gstreamer/Camera/run.sh new file mode 100644 index 00000000..3f5d7173 --- /dev/null +++ b/Runner/suites/Gstreamer/Camera/run.sh @@ -0,0 +1,671 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +#============================================================================== +# GStreamer Camera Tests - Camera Capture, Encoding, Preview, and Snapshot +#============================================================================== + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +# Locate init_env dynamically +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: Cannot find init_env" + exit 1 +fi + +# Source init_env (idempotent) +if [ -z "$__INIT_ENV_LOADED" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" +fi + +# Source functestlib.sh +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" + +#============================================================================== +# Test Configuration +#============================================================================== + +TESTNAME="Gstreamer_Camera_Tests" +test_path=$(find_test_case_by_name "$TESTNAME") +res_file="$test_path/$TESTNAME.res" +log_dir="$test_path/logs_$TESTNAME" + +# Default parameters +TIMEOUT="${TIMEOUT:-120}" +REPEAT="${REPEAT:-1}" +REPEAT_POLICY="${REPEAT_POLICY:-all}" +STRICT="${STRICT:-false}" +DMESG_SCAN="${DMESG_SCAN:-true}" +CAMERA_DEVICE="${CAMERA_DEVICE:-/dev/video0}" +CAPTURE_DURATION="${CAPTURE_DURATION:-5}" + +# Test list +ALL_TESTS="camera-preview camera-h264-encode camera-h265-encode camera-snapshot camera-jpeg-encode" + +#============================================================================== +# Helper Functions +#============================================================================== + +show_usage() { + cat << EOF +Usage: $0 [OPTIONS] + +GStreamer Camera Tests - Camera capture, encoding, preview, and snapshot validation + +OPTIONS: + --all Run all camera tests + --test Run specific test + --list List available tests + --timeout Timeout per test (default: 120) + --camera Camera device (default: /dev/video0) + --duration Capture duration (default: 5) + --repeat Repeat count (default: 1) + --repeat-policy Pass policy (default: all) + --strict Fail on warnings (default: false) + --no-dmesg Skip dmesg error scanning (default: scan enabled) + --help Show this help + +AVAILABLE TESTS: + camera-preview - Live camera preview to waylandsink + camera-h264-encode - Capture and encode to H.264 + camera-h265-encode - Capture and encode to H.265 + camera-snapshot - Capture single frame snapshot (PNG) + camera-jpeg-encode - Capture and encode to JPEG + +EXAMPLES: + $0 --all + $0 --test camera-preview + $0 --all --camera /dev/video2 --duration 10 + $0 --test camera-h264-encode --repeat 3 + +EOF +} + +list_tests() { + echo "Available Camera Tests:" + for test in $ALL_TESTS; do + echo " - $test" + done +} + +check_camera_device() { + log_info "Using libcamera for camera access" + log_info "Camera device parameter: $CAMERA_DEVICE" + + # Check if libcamera can detect cameras + if command -v libcamera-hello >/dev/null 2>&1; then + log_info "Checking libcamera camera detection..." + if timeout 5 libcamera-hello --list-cameras > /tmp/libcamera_list.txt 2>&1; then + log_info "Available cameras:" + cat /tmp/libcamera_list.txt | head -20 + else + log_warn "libcamera camera detection timed out or failed" + fi + rm -f /tmp/libcamera_list.txt + fi + + # Check if libcamerasrc is available + if ! gst-inspect-1.0 libcamerasrc >/dev/null 2>&1; then + log_error "libcamerasrc plugin not available" + return 1 + fi + + log_info "libcamerasrc plugin is available" + return 0 +} + +check_dependencies() { + local missing="" + + if ! command -v gst-launch-1.0 >/dev/null 2>&1; then + missing="$missing gstreamer1.0-tools" + fi + + if ! gst-inspect-1.0 libcamerasrc >/dev/null 2>&1; then + missing="$missing gstreamer1.0-libcamera (libcamerasrc)" + fi + + if ! gst-inspect-1.0 videoconvert >/dev/null 2>&1; then + missing="$missing gstreamer1.0-plugins-base (videoconvert)" + fi + + if ! command -v libcamera-hello >/dev/null 2>&1; then + log_warn "libcamera-hello not found, camera detection may be limited" + fi + + if [ -n "$missing" ]; then + log_error "Missing dependencies:$missing" + return 1 + fi + + return 0 +} + +validate_pipeline_output() { + local log_file="$1" + local test_name="$2" + local errors=0 + + # Check for ERROR messages + if grep -qi "ERROR" "$log_file"; then + log_error "$test_name: Found ERROR in pipeline output" + grep -i "ERROR" "$log_file" | head -5 + errors=$((errors + 1)) + fi + + # Check for WARNING messages in strict mode + if [ "$STRICT" = "true" ]; then + if grep -qi "WARNING" "$log_file"; then + log_error "$test_name: Found WARNING in pipeline output (strict mode)" + grep -i "WARNING" "$log_file" | head -5 + errors=$((errors + 1)) + fi + fi + + # Check for common failure patterns + if grep -qi "failed to negotiate\|could not link\|no such element\|failed to create element" "$log_file"; then + log_error "$test_name: Pipeline negotiation or element creation failed" + grep -Ei "failed to negotiate|could not link|no such element|failed to create element" "$log_file" + errors=$((errors + 1)) + fi + + # Check for camera-specific errors + if grep -qi "cannot identify device\|no such device\|device busy" "$log_file"; then + log_error "$test_name: Camera device error detected" + grep -Ei "cannot identify device|no such device|device busy" "$log_file" + errors=$((errors + 1)) + fi + + return $errors +} + +run_gst_pipeline() { + local test_name="$1" + local pipeline="$2" + local log_file="$log_dir/${test_name}.log" + local timeout_val="$TIMEOUT" + + log_info "Running $test_name (timeout: ${timeout_val}s)" + log_info "Pipeline: $pipeline" + + # Run pipeline with timeout + if timeout "$timeout_val" sh -c "gst-launch-1.0 $pipeline > '$log_file' 2>&1"; then + log_pass "$test_name: Pipeline completed successfully" + return 0 + else + local exit_code=$? + if [ $exit_code -eq 124 ]; then + log_error "$test_name: Timeout after ${timeout_val}s" + else + log_error "$test_name: Pipeline failed with exit code $exit_code" + fi + return 1 + fi +} + +#============================================================================== +# Test Cases +#============================================================================== + +test_camera_preview() { + local test_name="camera-preview" + local log_file="$log_dir/${test_name}.log" + + log_info "=== Test: $test_name ===" + + # Calculate number of frames (duration * 30fps) + local num_buffers=$((CAPTURE_DURATION * 30)) + + # Pipeline: Camera preview to Wayland display using libcamera + local pipeline="libcamerasrc num-buffers=$num_buffers ! \ +video/x-raw,width=1920,height=1080,framerate=30/1 ! \ +videoconvert ! \ +waylandsink" + + if run_gst_pipeline "$test_name" "$pipeline"; then + if validate_pipeline_output "$log_file" "$test_name"; then + log_pass "$test_name: PASSED" + return 0 + fi + fi + + log_fail "$test_name: FAILED" + return 1 +} + +test_camera_h264_encode() { + local test_name="camera-h264-encode" + local log_file="$log_dir/${test_name}.log" + local output_file="$test_path/camera_h264.mp4" + + log_info "=== Test: $test_name ===" + + # Calculate number of frames + local num_buffers=$((CAPTURE_DURATION * 30)) + + # Pipeline: Camera capture and H.264 encode using libcamera + local pipeline="libcamerasrc num-buffers=$num_buffers ! \ +video/x-raw,width=1920,height=1080,framerate=30/1 ! \ +videoconvert ! \ +video/x-raw,format=NV12 ! \ +v4l2h264enc extra-controls=\"controls,video_bitrate=4000000\" ! \ +h264parse ! \ +qtmux ! \ +filesink location=$output_file" + + if run_gst_pipeline "$test_name" "$pipeline"; then + if validate_pipeline_output "$log_file" "$test_name"; then + if [ -f "$output_file" ]; then + local file_size=$(stat -f%z "$output_file" 2>/dev/null || stat -c%s "$output_file" 2>/dev/null) + if [ "$file_size" -gt 0 ]; then + log_info "$test_name: Output file created: $output_file (${file_size} bytes)" + log_pass "$test_name: PASSED" + return 0 + else + log_error "$test_name: Output file is empty" + fi + else + log_error "$test_name: Output file not created" + fi + fi + fi + + log_fail "$test_name: FAILED" + return 1 +} + +test_camera_h265_encode() { + local test_name="camera-h265-encode" + local log_file="$log_dir/${test_name}.log" + local output_file="$test_path/camera_h265.mp4" + + log_info "=== Test: $test_name ===" + + # Calculate number of frames + local num_buffers=$((CAPTURE_DURATION * 30)) + + # Pipeline: Camera capture and H.265 encode using libcamera + local pipeline="libcamerasrc num-buffers=$num_buffers ! \ +video/x-raw,width=1920,height=1080,framerate=30/1 ! \ +videoconvert ! \ +video/x-raw,format=NV12 ! \ +v4l2h265enc extra-controls=\"controls,video_bitrate=4000000\" ! \ +h265parse ! \ +qtmux ! \ +filesink location=$output_file" + + if run_gst_pipeline "$test_name" "$pipeline"; then + if validate_pipeline_output "$log_file" "$test_name"; then + if [ -f "$output_file" ]; then + local file_size=$(stat -f%z "$output_file" 2>/dev/null || stat -c%s "$output_file" 2>/dev/null) + if [ "$file_size" -gt 0 ]; then + log_info "$test_name: Output file created: $output_file (${file_size} bytes)" + log_pass "$test_name: PASSED" + return 0 + else + log_error "$test_name: Output file is empty" + fi + else + log_error "$test_name: Output file not created" + fi + fi + fi + + log_fail "$test_name: FAILED" + return 1 +} + +test_camera_snapshot() { + local test_name="camera-snapshot" + local log_file="$log_dir/${test_name}.log" + local output_file="$test_path/camera_snapshot.png" + + log_info "=== Test: $test_name ===" + + # Pipeline: Capture single frame and save as PNG using libcamera + local pipeline="libcamerasrc num-buffers=1 ! \ +video/x-raw,width=1920,height=1080 ! \ +videoconvert ! \ +pngenc ! \ +filesink location=$output_file" + + if run_gst_pipeline "$test_name" "$pipeline"; then + if validate_pipeline_output "$log_file" "$test_name"; then + if [ -f "$output_file" ]; then + local file_size=$(stat -f%z "$output_file" 2>/dev/null || stat -c%s "$output_file" 2>/dev/null) + if [ "$file_size" -gt 0 ]; then + log_info "$test_name: Snapshot created: $output_file (${file_size} bytes)" + log_pass "$test_name: PASSED" + return 0 + else + log_error "$test_name: Snapshot file is empty" + fi + else + log_error "$test_name: Snapshot file not created" + fi + fi + fi + + log_fail "$test_name: FAILED" + return 1 +} + +test_camera_jpeg_encode() { + local test_name="camera-jpeg-encode" + local log_file="$log_dir/${test_name}.log" + local output_file="$test_path/camera_jpeg.jpg" + + log_info "=== Test: $test_name ===" + + # Pipeline: Capture and encode to JPEG using libcamera + local pipeline="libcamerasrc num-buffers=1 ! \ +video/x-raw,width=1920,height=1080 ! \ +videoconvert ! \ +jpegenc quality=90 ! \ +filesink location=$output_file" + + if run_gst_pipeline "$test_name" "$pipeline"; then + if validate_pipeline_output "$log_file" "$test_name"; then + if [ -f "$output_file" ]; then + local file_size=$(stat -f%z "$output_file" 2>/dev/null || stat -c%s "$output_file" 2>/dev/null) + if [ "$file_size" -gt 0 ]; then + log_info "$test_name: JPEG created: $output_file (${file_size} bytes)" + log_pass "$test_name: PASSED" + return 0 + else + log_error "$test_name: JPEG file is empty" + fi + else + log_error "$test_name: JPEG file not created" + fi + fi + fi + + log_fail "$test_name: FAILED" + return 1 +} + +#============================================================================== +# Test Execution with Repeat Logic +#============================================================================== + +run_test_with_repeat() { + local test_name="$1" + local pass_count=0 + local fail_count=0 + + log_info "Running $test_name (repeat: $REPEAT, policy: $REPEAT_POLICY)" + + i=1 + while [ $i -le "$REPEAT" ]; do + log_info "Attempt $i/$REPEAT for $test_name" + + case "$test_name" in + camera-preview) + if test_camera_preview; then + pass_count=$((pass_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + ;; + camera-h264-encode) + if test_camera_h264_encode; then + pass_count=$((pass_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + ;; + camera-h265-encode) + if test_camera_h265_encode; then + pass_count=$((pass_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + ;; + camera-snapshot) + if test_camera_snapshot; then + pass_count=$((pass_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + ;; + camera-jpeg-encode) + if test_camera_jpeg_encode; then + pass_count=$((pass_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + ;; + *) + log_error "Unknown test: $test_name" + return 1 + ;; + esac + + i=$((i + 1)) + done + + # Apply repeat policy + if [ "$REPEAT_POLICY" = "any" ]; then + if [ $pass_count -gt 0 ]; then + log_pass "$test_name: PASSED (any policy: $pass_count/$REPEAT passed)" + return 0 + else + log_fail "$test_name: FAILED (any policy: 0/$REPEAT passed)" + return 1 + fi + else + # Default: all policy + if [ $fail_count -eq 0 ]; then + log_pass "$test_name: PASSED (all policy: $pass_count/$REPEAT passed)" + return 0 + else + log_fail "$test_name: FAILED (all policy: $fail_count/$REPEAT failed)" + return 1 + fi + fi +} + +#============================================================================== +# Main Execution +#============================================================================== + +main() { + local run_all=false + local specific_test="" + local tests_to_run="" + + # Parse arguments + while [ $# -gt 0 ]; do + case "$1" in + --all) + run_all=true + shift + ;; + --test) + specific_test="$2" + shift 2 + ;; + --list) + list_tests + exit 0 + ;; + --timeout) + TIMEOUT="$2" + shift 2 + ;; + --camera) + CAMERA_DEVICE="$2" + shift 2 + ;; + --duration) + CAPTURE_DURATION="$2" + shift 2 + ;; + --repeat) + REPEAT="$2" + shift 2 + ;; + --repeat-policy) + REPEAT_POLICY="$2" + shift 2 + ;; + --strict) + STRICT=true + shift + ;; + --no-dmesg) + DMESG_SCAN=false + shift + ;; + --help) + show_usage + exit 0 + ;; + *) + log_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac + done + + # Determine tests to run (default to all if no arguments) + if [ "$run_all" = "true" ]; then + tests_to_run="$ALL_TESTS" + elif [ -n "$specific_test" ]; then + tests_to_run="$specific_test" + else + # Default: run all tests + log_info "No test specified, running all tests by default" + tests_to_run="$ALL_TESTS" + fi + + # Setup + mkdir -p "$log_dir" + log_info "Starting $TESTNAME" + log_info "Log directory: $log_dir" + log_info "Camera device: $CAMERA_DEVICE" + log_info "Capture duration: ${CAPTURE_DURATION}s" + + # Pre-checks + if ! check_dependencies; then + echo "SKIP $TESTNAME" > "$res_file" + log_skip "$TESTNAME: Missing dependencies" + exit 0 + fi + + if ! check_camera_device; then + echo "SKIP $TESTNAME" > "$res_file" + log_skip "$TESTNAME: Camera device not available" + exit 0 + fi + + # Capture initial dmesg + if [ "$DMESG_SCAN" = "true" ]; then + dmesg > "$log_dir/dmesg_snapshot.log" + fi + + # Run tests + local total_tests=0 + local passed_tests=0 + local failed_tests=0 + + for test in $tests_to_run; do + total_tests=$((total_tests + 1)) + + if run_test_with_repeat "$test"; then + passed_tests=$((passed_tests + 1)) + else + failed_tests=$((failed_tests + 1)) + fi + done + + # Check for dmesg errors + if [ "$DMESG_SCAN" = "true" ]; then + dmesg | diff "$log_dir/dmesg_snapshot.log" - | grep -i "error\|fail\|warn" > "$log_dir/dmesg_errors.log" || true + if [ -s "$log_dir/dmesg_errors.log" ]; then + log_warn "New kernel errors detected (see dmesg_errors.log)" + fi + fi + + # Generate summary + { + echo "=== GStreamer Camera Tests Summary ===" + echo "Total Tests: $total_tests" + echo "Passed: $passed_tests" + echo "Failed: $failed_tests" + echo "Camera Device: $CAMERA_DEVICE" + echo "Capture Duration: ${CAPTURE_DURATION}s" + echo "Timeout: ${TIMEOUT}s" + echo "Repeat: $REPEAT (policy: $REPEAT_POLICY)" + echo "Strict Mode: $STRICT" + echo "Dmesg Scan: $DMESG_SCAN" + } > "$log_dir/summary.txt" + + # Generate CSV results + { + echo "test_name,status,attempts,passed,failed" + for test in $tests_to_run; do + if grep -q "PASSED.*$test" "$log_dir"/*.log 2>/dev/null; then + echo "$test,PASS,$REPEAT,$REPEAT,0" + else + echo "$test,FAIL,$REPEAT,0,$REPEAT" + fi + done + } > "$log_dir/results.csv" + + # Generate JUnit XML + generate_junit_xml "$log_dir" "$TESTNAME" "$tests_to_run" + + # Final result + if [ $failed_tests -eq 0 ]; then + echo "PASS $TESTNAME" > "$res_file" + log_pass "$TESTNAME: All tests passed ($passed_tests/$total_tests)" + exit 0 + else + echo "FAIL $TESTNAME" > "$res_file" + log_fail "$TESTNAME: Some tests failed ($failed_tests/$total_tests)" + exit 0 + fi +} + +generate_junit_xml() { + local log_dir="$1" + local suite_name="$2" + local tests="$3" + local xml_file="$log_dir/.junit_cases.xml" + + { + echo '' + echo "" + + for test in $tests; do + if grep -q "PASSED.*$test" "$log_dir"/*.log 2>/dev/null; then + echo " " + else + echo " " + echo " " + echo " " + fi + done + + echo "" + } > "$xml_file" +} + +# Execute main +main "$@" diff --git a/Runner/suites/Gstreamer/Display/Gstreamer_Display_Tests.yaml b/Runner/suites/Gstreamer/Display/Gstreamer_Display_Tests.yaml new file mode 100644 index 00000000..7656b150 --- /dev/null +++ b/Runner/suites/Gstreamer/Display/Gstreamer_Display_Tests.yaml @@ -0,0 +1,22 @@ +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +metadata: + format: Lava-Test Test Definition 1.0 + name: Gstreamer_Display_Tests + description: "GStreamer Display Tests - Wayland video display validation using videotestsrc and waylandsink" + maintainer: + - qualcomm-linux-test@quicinc.com + os: + - linux + +params: + TIMEOUT: "120" + STRICT: "false" + DMESG_SCAN: "true" + LOGLEVEL: "INFO" + +run: + steps: + - cd Runner/suites/Gstreamer/Display + - ./run.sh --all diff --git a/Runner/suites/Gstreamer/Display/README.md b/Runner/suites/Gstreamer/Display/README.md new file mode 100644 index 00000000..c5014738 --- /dev/null +++ b/Runner/suites/Gstreamer/Display/README.md @@ -0,0 +1,463 @@ +# GStreamer Display Tests + +**Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.** +**SPDX-License-Identifier: BSD-3-Clause-Clear** + +--- + +## Overview + +This test suite validates GStreamer video display functionality using Wayland compositor on Qualcomm Linux platforms. Tests use `videotestsrc` to generate test patterns and display them via `waylandsink`, validating the complete display pipeline including Wayland surface creation and rendering. + +### Test Coverage + +**4 Test Cases:** +- **Wayland Basic**: Basic 480p test pattern display (SMPTE bars) +- **Wayland Videotestsrc**: 1080p moving ball pattern +- **Wayland Colorbar**: 4K color bars pattern +- **Wayland SMPTE**: 720p SMPTE color bars at 60fps + +**Key Features:** +- No external file dependencies - uses built-in test pattern generator +- Validates Wayland compositor connectivity and surface creation +- Tests multiple resolutions (480p, 720p, 1080p, 4K) +- Tests multiple frame rates (30fps, 60fps) +- Validates various test patterns (SMPTE, ball, color bars) + +--- + +## Quick Start + +```bash +cd Runner/suites/Gstreamer/Display +./run.sh --all +``` + +--- + +## Test Pipelines + +### Wayland Basic (480p @ 30fps) +```bash +videotestsrc num-buffers=150 pattern=0 ! \ + video/x-raw,width=720,height=480,framerate=30/1 ! \ + waylandsink +``` +- **Pattern**: SMPTE color bars (pattern=0) +- **Duration**: 5 seconds (150 frames) +- **Resolution**: 720x480 (480p) +- **Use Case**: Basic Wayland connectivity test + +### Wayland Videotestsrc (1080p @ 30fps) +```bash +videotestsrc num-buffers=150 pattern=ball ! \ + video/x-raw,width=1920,height=1080,framerate=30/1 ! \ + videoconvert ! \ + waylandsink +``` +- **Pattern**: Moving ball (pattern=ball) +- **Duration**: 5 seconds (150 frames) +- **Resolution**: 1920x1080 (1080p) +- **Use Case**: Dynamic content rendering test + +### Wayland Colorbar (4K @ 30fps) +```bash +videotestsrc num-buffers=150 pattern=bar ! \ + video/x-raw,width=3840,height=2160,framerate=30/1 ! \ + videoconvert ! \ + waylandsink +``` +- **Pattern**: Color bars (pattern=bar) +- **Duration**: 5 seconds (150 frames) +- **Resolution**: 3840x2160 (4K) +- **Use Case**: High resolution display capability test + +### Wayland SMPTE (720p @ 60fps) +```bash +videotestsrc num-buffers=300 pattern=smpte ! \ + video/x-raw,width=1280,height=720,framerate=60/1 ! \ + videoconvert ! \ + waylandsink +``` +- **Pattern**: SMPTE color bars (pattern=smpte) +- **Duration**: 5 seconds (300 frames) +- **Resolution**: 1280x720 (720p) +- **Use Case**: High frame rate display test + +--- + +## CLI Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--all` | Run all display tests | - | +| `--test ` | Run specific test | - | +| `--list` | List available tests | - | +| `--timeout ` | Timeout per test | 120 | +| `--repeat ` | Repeat count | 1 | +| `--repeat-policy all\|any` | Pass policy | all | +| `--strict` | Fail on warnings | false | +| `--no-dmesg` | Skip dmesg scan | false | +| `--help` | Show help | - | + +--- + +## Examples + +### Run all tests +```bash +./run.sh --all +``` + +### Run specific test +```bash +./run.sh --test wayland-basic +./run.sh --test wayland-colorbar +``` + +### List available tests +```bash +./run.sh --list +``` + +### Run with increased timeout +```bash +./run.sh --all --timeout 180 +``` + +### Run with strict mode +```bash +./run.sh --all --strict +``` + +### Run with repeat +```bash +./run.sh --test wayland-videotestsrc --repeat 3 --repeat-policy any +``` + +--- + +## Output Files + +### Test Result +- `Gstreamer_Display_Tests.res` - Overall PASS/FAIL/SKIP + +### Logs Directory: `logs_Gstreamer_Display_Tests/` +- `wayland-basic.log` - Basic display test log +- `wayland-videotestsrc.log` - Videotestsrc display test log +- `wayland-colorbar.log` - Colorbar display test log +- `wayland-smpte.log` - SMPTE display test log +- `summary.txt` - Per-test results summary +- `results.csv` - Machine-readable results +- `.junit_cases.xml` - JUnit XML for CI +- `dmesg_snapshot.log` - Kernel messages snapshot +- `dmesg_errors.log` - Kernel errors (if any) + +--- + +## Validation Criteria + +### Pass Criteria +A test PASSES if: +1. GStreamer pipeline exits with code 0 +2. No ERROR patterns in log +3. No WARNING patterns (if `--strict` mode) +4. No kernel errors in dmesg (if enabled) +5. Wayland surface created successfully +6. No Wayland connection errors + +### Error Patterns Detected +- `ERROR:` - General GStreamer errors +- `failed to negotiate` - Format negotiation issues +- `could not link` - Element linking failures +- `no such element` - Missing GStreamer elements +- `failed to create element` - Element creation failures +- `wayland.*error` - Wayland-specific errors +- `failed to connect to wayland` - Wayland connection failures +- `no wayland display` - Wayland display not available + +### Wayland-Specific Validations +- Wayland display socket exists and is accessible +- Wayland compositor is responsive (if weston-info available) +- Wayland surface creation confirmed in pipeline logs +- No Wayland connection/surface errors detected + +--- + +## Dependencies + +### Required GStreamer Plugins +- `videotestsrc` - Test pattern generator (gstreamer1.0-plugins-base) +- `videoconvert` - Format converter (gstreamer1.0-plugins-base) +- `waylandsink` - Wayland video sink (gstreamer1.0-plugins-bad) + +### System Requirements +- Wayland compositor running (Weston, Mutter, etc.) - **Auto-detected and started if needed** +- Display output connected +- DRM/KMS display driver loaded + +**Note**: The test suite automatically handles Wayland environment setup: +- Uses `lib_display.sh` helpers for robust Wayland socket discovery +- Automatically detects existing Wayland sockets (base or overlay configurations) +- Can start a private Weston instance if no compositor is running +- Properly sets `WAYLAND_DISPLAY` and `XDG_RUNTIME_DIR` with correct permissions +- Validates Wayland connection before running tests + +### Verification Commands +```bash +# Check GStreamer plugins +gst-inspect-1.0 videotestsrc +gst-inspect-1.0 waylandsink +gst-inspect-1.0 videoconvert + +# Check display connection (optional - test auto-detects) +echo $WAYLAND_DISPLAY +echo $XDG_RUNTIME_DIR + +# Check Wayland socket (optional - test auto-discovers) +ls -la $XDG_RUNTIME_DIR/wayland-* 2>/dev/null || \ +ls -la /run/user/*/wayland-* + +# Check compositor (optional - test can start one) +ps aux | grep -E 'weston|mutter|kwin' + +# Test Wayland connectivity (optional) +weston-info +``` + +--- + +## Troubleshooting + +### Wayland Not Available +**The test suite automatically handles Wayland setup**, but if you encounter issues: + +```bash +# Check if lib_display.sh helpers are available +grep -l "discover_wayland_socket_anywhere" $TOOLS/lib_display.sh + +# Manually check for Wayland sockets +find /run/user -name "wayland-*" -type s 2>/dev/null + +# If no sockets found, manually start Weston +weston & +sleep 2 + +# Re-run tests (they will auto-detect the new socket) +./run.sh --all +``` + +### Display Socket Not Found +**The test automatically discovers sockets**, but for manual verification: + +```bash +# Check all possible socket locations +find /run/user -name "wayland-*" -type s 2>/dev/null +find /tmp -name "wayland-*" -type s 2>/dev/null + +# Check if lib_display.sh can find sockets +if command -v discover_wayland_socket_anywhere >/dev/null 2>&1; then + discover_wayland_socket_anywhere +fi + +# The test will automatically: +# 1. Search for existing sockets +# 2. Adopt the socket's environment +# 3. Start Weston if no socket found +# 4. Validate the connection +``` + +### Missing Plugins +```bash +# Check plugin availability +gst-inspect-1.0 videotestsrc +gst-inspect-1.0 waylandsink +gst-inspect-1.0 videoconvert + +# Install packages (if missing) +apt-get install gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-bad \ + gstreamer1.0-tools +``` + +### Permission Issues +```bash +# Add user to video group +sudo usermod -a -G video $USER + +# Verify group membership +groups $USER + +# Check device permissions +ls -la /dev/dri/* +``` + +### Pipeline Failures +```bash +# Run pipeline manually with verbose output +GST_DEBUG=3 gst-launch-1.0 -v videotestsrc num-buffers=150 ! waylandsink + +# Check log file +cat logs_Gstreamer_Display_Tests/wayland-basic.log + +# Test simple pipeline +gst-launch-1.0 videotestsrc ! waylandsink +``` + +### Compositor Not Responsive +**The test suite can start its own compositor**, but for manual troubleshooting: + +```bash +# Check compositor status +ps aux | grep weston + +# Kill existing compositor +killall weston +sleep 1 + +# Let the test start a new one, or start manually +weston & +sleep 2 + +# Verify with test +./run.sh --test wayland-basic + +# The test will automatically: +# 1. Detect if compositor is responsive +# 2. Start a private Weston instance if needed +# 3. Validate the connection before running tests +``` + +### Display Not Showing +```bash +# Check display output +weston-info + +# Verify DRM/KMS +ls -la /dev/dri/card* +dmesg | grep -i drm + +# Check display connection +cat /sys/class/drm/card*/status +``` + +### 4K Test Failures +```bash +# Check memory availability +free -h + +# Increase timeout for 4K tests +./run.sh --test wayland-colorbar --timeout 240 + +# Check for memory errors +dmesg | grep -i "out of memory" +``` + +--- + +## Supported Platforms + +- **LeMans** (QCS9100, QCS9075) +- **Monaco** (QCS8300) +- **Kodiak** (QCS6490, QCM6490) +- **QCS8550, QCS8650** +- **SA8775P, SA8650P, SA8255P** + +--- + +## CI/CD Integration + +### LAVA Test Definition +```yaml +- test: + definitions: + - repository: + from: git + path: Runner/suites/Gstreamer/Display/Gstreamer_Display_Tests.yaml + name: gstreamer-display-tests + parameters: + TIMEOUT: "120" + STRICT: "false" + DMESG_SCAN: "true" +``` + +### Jenkins Pipeline +```groovy +stage('GStreamer Display Tests') { + steps { + sh ''' + cd Runner/suites/Gstreamer/Display + ./run.sh --all + ''' + } +} +``` + +--- + +## Environment Variables + +**Note**: Wayland environment variables are automatically set by the test suite using `lib_display.sh` helpers. Manual configuration is typically not needed. + +### Automatic Configuration (Recommended) +The test suite automatically: +- Discovers Wayland sockets using `discover_wayland_socket_anywhere()` +- Sets `WAYLAND_DISPLAY` and `XDG_RUNTIME_DIR` via `adopt_wayland_env_from_socket()` +- Fixes permissions on `XDG_RUNTIME_DIR` if needed +- Starts a private Weston instance if no compositor is running + +### Manual Override (Advanced) +If you need to override the automatic detection: + +```bash +# Wayland display (auto-detected by default) +export WAYLAND_DISPLAY=wayland-0 + +# Runtime directory (auto-configured by default) +export XDG_RUNTIME_DIR=/run/user/$(id -u) + +# GStreamer debug level (0-9) +export GST_DEBUG=3 + +# Force software rendering (if needed) +export LIBGL_ALWAYS_SOFTWARE=1 +``` + +### Debug Environment Detection +```bash +# Enable debug output for Wayland detection +export GST_DEBUG=3 + +# Run test to see auto-detection in action +./run.sh --test wayland-basic + +# Check logs for Wayland socket discovery +grep -i "wayland socket" logs_Gstreamer_Display_Tests/*.log +``` + +--- + +## Test Pattern Reference + +### Available videotestsrc Patterns +- `pattern=0` or `pattern=smpte` - SMPTE color bars +- `pattern=ball` - Moving ball +- `pattern=bar` - Color bars +- `pattern=snow` - Random noise +- `pattern=black` - Black screen +- `pattern=white` - White screen +- `pattern=circular` - Circular pattern +- `pattern=blink` - Blinking pattern + +### Pattern Selection Rationale +- **SMPTE bars**: Standard broadcast test pattern, good for basic validation +- **Moving ball**: Dynamic content, tests motion rendering +- **Color bars**: Simple static pattern, good for color accuracy +- **60fps SMPTE**: Tests high frame rate capability + +--- + +## License + +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause-Clear diff --git a/Runner/suites/Gstreamer/Display/run.sh b/Runner/suites/Gstreamer/Display/run.sh new file mode 100644 index 00000000..b3fc2351 --- /dev/null +++ b/Runner/suites/Gstreamer/Display/run.sh @@ -0,0 +1,623 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +#============================================================================== +# GStreamer Display Tests - Wayland Video Display Validation +#============================================================================== + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +# Locate init_env dynamically +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: Cannot find init_env" + exit 1 +fi + +# Source init_env (idempotent) +if [ -z "$__INIT_ENV_LOADED" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" +fi + +# Source functestlib.sh and lib_display.sh +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" +# shellcheck disable=SC1091 +. "$TOOLS/lib_display.sh" + +#============================================================================== +# Test Configuration +#============================================================================== + +TESTNAME="Gstreamer_Display_Tests" +test_path=$(find_test_case_by_name "$TESTNAME") +res_file="$test_path/$TESTNAME.res" +log_dir="$test_path/logs_$TESTNAME" + +# Default parameters +TIMEOUT="${TIMEOUT:-120}" +REPEAT="${REPEAT:-1}" +REPEAT_POLICY="${REPEAT_POLICY:-all}" +STRICT="${STRICT:-false}" +DMESG_SCAN="${DMESG_SCAN:-true}" + +# Test list +ALL_TESTS="wayland-basic wayland-videotestsrc wayland-colorbar wayland-smpte" + +#============================================================================== +# Helper Functions +#============================================================================== + +show_usage() { + cat << EOF +Usage: $0 [OPTIONS] + +GStreamer Display Tests - Wayland video display validation + +OPTIONS: + --all Run all display tests + --test Run specific test (wayland-basic, wayland-videotestsrc, wayland-colorbar, wayland-smpte) + --list List available tests + --timeout Timeout per test (default: 120) + --repeat Repeat count (default: 1) + --repeat-policy Pass policy: all runs pass or any run passes (default: all) + --strict Fail on warnings (default: false) + --no-dmesg Skip dmesg error scanning (default: scan enabled) + --help Show this help + +EXAMPLES: + $0 --all + $0 --test wayland-basic + $0 --all --timeout 180 --strict + $0 --test wayland-colorbar --repeat 3 --repeat-policy any + +EOF +} + +list_tests() { + echo "Available Display Tests:" + for test in $ALL_TESTS; do + echo " - $test" + done +} + +check_wayland() { + # Use lib_display.sh helpers for Wayland detection (same as weston-simple-egl) + + if command -v wayland_debug_snapshot >/dev/null 2>&1; then + wayland_debug_snapshot "$TESTNAME: start" + fi + + local sock="" + + # Try to find any existing Wayland socket (base or overlay) + if command -v discover_wayland_socket_anywhere >/dev/null 2>&1; then + sock=$(discover_wayland_socket_anywhere | head -n 1 || true) + fi + + # If we found a socket, adopt its environment + 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 + + # If no usable socket yet, try starting a private Weston (overlay-style helper) + if [ -z "$sock" ] && command -v overlay_start_weston_drm >/dev/null 2>&1; then + log_info "No usable Wayland socket; trying overlay_start_weston_drm helper..." + if overlay_start_weston_drm; then + # Re-scan for a socket after attempting to start Weston + 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 "Overlay Weston created Wayland socket: $sock" + if ! adopt_wayland_env_from_socket "$sock"; then + log_warn "Failed to adopt env from $sock" + fi + else + log_warn "overlay_start_weston_drm reported success but no Wayland socket was found." + fi + else + log_warn "overlay_start_weston_drm returned non-zero; private Weston may have failed to start." + fi + fi + + # Final decision: run or SKIP + if [ -z "$sock" ]; then + log_warn "No Wayland socket found after autodetection; skipping $TESTNAME." + return 1 + fi + + # Verify Wayland connection + if command -v wayland_connection_ok >/dev/null 2>&1; then + if ! wayland_connection_ok; then + log_error "Wayland connection test failed; cannot run $TESTNAME." + return 1 + fi + log_info "Wayland connection test: OK" + else + log_warn "wayland_connection_ok helper not found; continuing without explicit Wayland probe." + fi + + # Log final environment + log_info "Wayland display: ${WAYLAND_DISPLAY:-}" + log_info "XDG_RUNTIME_DIR: ${XDG_RUNTIME_DIR:-}" + if [ -n "$sock" ]; then + log_info "Wayland socket: $sock" + fi + + return 0 +} + +validate_wayland_surface() { + local test_name="$1" + local log_file="$2" + + # Check if waylandsink created a surface + if grep -qi "created.*surface\|waylandsink.*ready" "$log_file"; then + log_info "$test_name: Wayland surface created successfully" + return 0 + fi + + # Check for Wayland-specific errors + if grep -qi "wayland.*error\|failed to connect to wayland\|no wayland display" "$log_file"; then + log_error "$test_name: Wayland connection/surface error detected" + return 1 + fi + + return 0 +} + +check_dependencies() { + local missing="" + + if ! command -v gst-launch-1.0 >/dev/null 2>&1; then + missing="$missing gstreamer1.0-tools" + fi + + if ! gst-inspect-1.0 waylandsink >/dev/null 2>&1; then + missing="$missing gstreamer1.0-plugins-bad (waylandsink)" + fi + + if ! gst-inspect-1.0 videotestsrc >/dev/null 2>&1; then + missing="$missing gstreamer1.0-plugins-base (videotestsrc)" + fi + + if ! gst-inspect-1.0 videoconvert >/dev/null 2>&1; then + missing="$missing gstreamer1.0-plugins-base (videoconvert)" + fi + + if [ -n "$missing" ]; then + log_error "Missing dependencies:$missing" + return 1 + fi + + return 0 +} + +validate_pipeline_output() { + local log_file="$1" + local test_name="$2" + local errors=0 + + # Check for ERROR messages + if grep -qi "ERROR" "$log_file"; then + log_error "$test_name: Found ERROR in pipeline output" + grep -i "ERROR" "$log_file" | head -5 + errors=$((errors + 1)) + fi + + # Check for WARNING messages in strict mode + if [ "$STRICT" = "true" ]; then + if grep -qi "WARNING" "$log_file"; then + log_error "$test_name: Found WARNING in pipeline output (strict mode)" + grep -i "WARNING" "$log_file" | head -5 + errors=$((errors + 1)) + fi + fi + + # Check for common failure patterns + if grep -qi "failed to negotiate\|could not link\|no such element\|failed to create element" "$log_file"; then + log_error "$test_name: Pipeline negotiation or element creation failed" + grep -Ei "failed to negotiate|could not link|no such element|failed to create element" "$log_file" + errors=$((errors + 1)) + fi + + # Validate Wayland surface creation + if ! validate_wayland_surface "$test_name" "$log_file"; then + errors=$((errors + 1)) + fi + + return $errors +} + +run_gst_pipeline() { + local test_name="$1" + local pipeline="$2" + local log_file="$log_dir/${test_name}.log" + local timeout_val="$TIMEOUT" + local duration="${3:-5}" # Default 5 seconds display duration + + log_info "Running $test_name (timeout: ${timeout_val}s, duration: ${duration}s)" + log_info "Pipeline: $pipeline" + + # Run pipeline with timeout + # For display tests, we run for a specific duration then gracefully stop + if timeout "$timeout_val" sh -c "gst-launch-1.0 $pipeline > '$log_file' 2>&1"; then + log_pass "$test_name: Pipeline completed successfully" + return 0 + else + local exit_code=$? + if [ $exit_code -eq 124 ]; then + log_error "$test_name: Timeout after ${timeout_val}s" + else + log_error "$test_name: Pipeline failed with exit code $exit_code" + fi + return 1 + fi +} + +#============================================================================== +# Test Cases +#============================================================================== + +test_wayland_basic() { + local test_name="wayland-basic" + local log_file="$log_dir/${test_name}.log" + + log_info "=== Test: $test_name ===" + + # Basic Wayland display test with simple test pattern + # 720x480 @ 30fps for 5 seconds (150 frames) + local pipeline="videotestsrc num-buffers=150 pattern=0 ! \ +video/x-raw,width=720,height=480,framerate=30/1 ! \ +waylandsink" + + if run_gst_pipeline "$test_name" "$pipeline" 5; then + if validate_pipeline_output "$log_file" "$test_name"; then + log_pass "$test_name: PASSED" + return 0 + fi + fi + + log_fail "$test_name: FAILED" + return 1 +} + +test_wayland_videotestsrc() { + local test_name="wayland-videotestsrc" + local log_file="$log_dir/${test_name}.log" + + log_info "=== Test: $test_name ===" + + # Test with moving ball pattern at 1080p + # 1920x1080 @ 30fps for 5 seconds (150 frames) + local pipeline="videotestsrc num-buffers=150 pattern=ball ! \ +video/x-raw,width=1920,height=1080,framerate=30/1 ! \ +videoconvert ! \ +waylandsink" + + if run_gst_pipeline "$test_name" "$pipeline" 5; then + if validate_pipeline_output "$log_file" "$test_name"; then + log_pass "$test_name: PASSED" + return 0 + fi + fi + + log_fail "$test_name: FAILED" + return 1 +} + +test_wayland_colorbar() { + local test_name="wayland-colorbar" + local log_file="$log_dir/${test_name}.log" + + log_info "=== Test: $test_name ===" + + # Test with color bars pattern at 4K + # 3840x2160 @ 30fps for 5 seconds (150 frames) + local pipeline="videotestsrc num-buffers=150 pattern=bar ! \ +video/x-raw,width=3840,height=2160,framerate=30/1 ! \ +videoconvert ! \ +waylandsink" + + if run_gst_pipeline "$test_name" "$pipeline" 5; then + if validate_pipeline_output "$log_file" "$test_name"; then + log_pass "$test_name: PASSED" + return 0 + fi + fi + + log_fail "$test_name: FAILED" + return 1 +} + +test_wayland_smpte() { + local test_name="wayland-smpte" + local log_file="$log_dir/${test_name}.log" + + log_info "=== Test: $test_name ===" + + # Test with SMPTE color bars at 720p + # 1280x720 @ 60fps for 5 seconds (300 frames) + local pipeline="videotestsrc num-buffers=300 pattern=smpte ! \ +video/x-raw,width=1280,height=720,framerate=60/1 ! \ +videoconvert ! \ +waylandsink" + + if run_gst_pipeline "$test_name" "$pipeline" 5; then + if validate_pipeline_output "$log_file" "$test_name"; then + log_pass "$test_name: PASSED" + return 0 + fi + fi + + log_fail "$test_name: FAILED" + return 1 +} + +#============================================================================== +# Test Execution with Repeat Logic +#============================================================================== + +run_test_with_repeat() { + local test_name="$1" + local pass_count=0 + local fail_count=0 + + log_info "Running $test_name (repeat: $REPEAT, policy: $REPEAT_POLICY)" + + i=1 + while [ $i -le "$REPEAT" ]; do + log_info "Attempt $i/$REPEAT for $test_name" + + case "$test_name" in + wayland-basic) + if test_wayland_basic; then + pass_count=$((pass_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + ;; + wayland-videotestsrc) + if test_wayland_videotestsrc; then + pass_count=$((pass_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + ;; + wayland-colorbar) + if test_wayland_colorbar; then + pass_count=$((pass_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + ;; + wayland-smpte) + if test_wayland_smpte; then + pass_count=$((pass_count + 1)) + else + fail_count=$((fail_count + 1)) + fi + ;; + *) + log_error "Unknown test: $test_name" + return 1 + ;; + esac + + i=$((i + 1)) + done + + # Apply repeat policy + if [ "$REPEAT_POLICY" = "any" ]; then + if [ $pass_count -gt 0 ]; then + log_pass "$test_name: PASSED (any policy: $pass_count/$REPEAT passed)" + return 0 + else + log_fail "$test_name: FAILED (any policy: 0/$REPEAT passed)" + return 1 + fi + else + # Default: all policy + if [ $fail_count -eq 0 ]; then + log_pass "$test_name: PASSED (all policy: $pass_count/$REPEAT passed)" + return 0 + else + log_fail "$test_name: FAILED (all policy: $fail_count/$REPEAT failed)" + return 1 + fi + fi +} + +#============================================================================== +# Main Execution +#============================================================================== + +main() { + local run_all=false + local specific_test="" + local tests_to_run="" + + # Parse arguments + while [ $# -gt 0 ]; do + case "$1" in + --all) + run_all=true + shift + ;; + --test) + specific_test="$2" + shift 2 + ;; + --list) + list_tests + exit 0 + ;; + --timeout) + TIMEOUT="$2" + shift 2 + ;; + --repeat) + REPEAT="$2" + shift 2 + ;; + --repeat-policy) + REPEAT_POLICY="$2" + shift 2 + ;; + --strict) + STRICT=true + shift + ;; + --no-dmesg) + DMESG_SCAN=false + shift + ;; + --help) + show_usage + exit 0 + ;; + *) + log_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac + done + + # Determine tests to run (default to all if no arguments) + if [ "$run_all" = "true" ]; then + tests_to_run="$ALL_TESTS" + elif [ -n "$specific_test" ]; then + tests_to_run="$specific_test" + else + # Default: run all tests + log_info "No test specified, running all tests by default" + tests_to_run="$ALL_TESTS" + fi + + # Setup + mkdir -p "$log_dir" + log_info "Starting $TESTNAME" + log_info "Log directory: $log_dir" + + # Pre-checks + if ! check_dependencies; then + echo "SKIP $TESTNAME" > "$res_file" + log_skip "$TESTNAME: Missing dependencies" + exit 0 + fi + + if ! check_wayland; then + echo "SKIP $TESTNAME" > "$res_file" + log_skip "$TESTNAME: Wayland not available" + exit 0 + fi + + # Capture initial dmesg + if [ "$DMESG_SCAN" = "true" ]; then + dmesg > "$log_dir/dmesg_snapshot.log" + fi + + # Run tests + local total_tests=0 + local passed_tests=0 + local failed_tests=0 + + for test in $tests_to_run; do + total_tests=$((total_tests + 1)) + + if run_test_with_repeat "$test"; then + passed_tests=$((passed_tests + 1)) + else + failed_tests=$((failed_tests + 1)) + fi + done + + # Check for dmesg errors + if [ "$DMESG_SCAN" = "true" ]; then + dmesg | diff "$log_dir/dmesg_snapshot.log" - | grep -i "error\|fail\|warn" > "$log_dir/dmesg_errors.log" || true + if [ -s "$log_dir/dmesg_errors.log" ]; then + log_warn "New kernel errors detected (see dmesg_errors.log)" + fi + fi + + # Generate summary + { + echo "=== GStreamer Display Tests Summary ===" + echo "Total Tests: $total_tests" + echo "Passed: $passed_tests" + echo "Failed: $failed_tests" + echo "Timeout: ${TIMEOUT}s" + echo "Repeat: $REPEAT (policy: $REPEAT_POLICY)" + echo "Strict Mode: $STRICT" + echo "Dmesg Scan: $DMESG_SCAN" + } > "$log_dir/summary.txt" + + # Generate CSV results + { + echo "test_name,status,attempts,passed,failed" + for test in $tests_to_run; do + if grep -q "PASSED.*$test" "$log_dir"/*.log 2>/dev/null; then + echo "$test,PASS,$REPEAT,$REPEAT,0" + else + echo "$test,FAIL,$REPEAT,0,$REPEAT" + fi + done + } > "$log_dir/results.csv" + + # Generate JUnit XML + generate_junit_xml "$log_dir" "$TESTNAME" "$tests_to_run" + + # Final result + if [ $failed_tests -eq 0 ]; then + echo "PASS $TESTNAME" > "$res_file" + log_pass "$TESTNAME: All tests passed ($passed_tests/$total_tests)" + exit 0 + else + echo "FAIL $TESTNAME" > "$res_file" + log_fail "$TESTNAME: Some tests failed ($failed_tests/$total_tests)" + exit 0 + fi +} + +generate_junit_xml() { + local log_dir="$1" + local suite_name="$2" + local tests="$3" + local xml_file="$log_dir/.junit_cases.xml" + + { + echo '' + echo "" + + for test in $tests; do + if grep -q "PASSED.*$test" "$log_dir"/*.log 2>/dev/null; then + echo " " + else + echo " " + echo " " + echo " " + fi + done + + echo "" + } > "$xml_file" +} + +# Execute main +main "$@" diff --git a/Runner/suites/Gstreamer/Gstreamer_MM_Tests.yaml b/Runner/suites/Gstreamer/Gstreamer_MM_Tests.yaml new file mode 100644 index 00000000..2d9b82d4 --- /dev/null +++ b/Runner/suites/Gstreamer/Gstreamer_MM_Tests.yaml @@ -0,0 +1,32 @@ +metadata: + name: gstreamer-Multimedia-tests + format: "Lava-Test Test Definition 1.0" + description: "These scripts automate validation of GStreamer encoding and decoding using v4l2h264dec, v4l2h265dec, v4l2h264enc, and v4l2h265enc on Qualcomm Linux platforms." + os: + - linux + scope: + - functional + +params: + # Timeout for each test in seconds + TIMEOUT: "60" + # Enable strict mode (treat dmesg warnings as failures) + STRICT: "0" + # Enable dmesg scanning + DMESG_SCAN: "1" + # Log level + LOGLEVEL: "15" + # Number of times to retry on failure + RETRY_ON_FAIL: "3" + # Sleep time after each test in seconds + POST_TEST_SLEEP: "5" + # platform is autodetected by the test script + PLATFORM: "" + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Multimedia/Gstreamer/ + - chmod +x ./run.sh + - ./run.sh --timeout "${TIMEOUT}" --loglevel "${LOGLEVEL}" --platform "${PLATFORM}" --retry-on-fail "${RETRY_ON_FAIL}" --post-test-sleep "${POST_TEST_SLEEP}" || true + - $REPO_PATH/Runner/utils/send-to-lava.sh "Gstreamer Multimedia Tests.res" || true diff --git a/Runner/suites/Gstreamer/README.md b/Runner/suites/Gstreamer/README.md new file mode 100644 index 00000000..e6d0af20 --- /dev/null +++ b/Runner/suites/Gstreamer/README.md @@ -0,0 +1,523 @@ +# GStreamer Test Suite + +## Overview + +This directory contains comprehensive GStreamer validation tests for Qualcomm platforms, organized into four independent test categories: + +1. **Video** - Hardware-accelerated video encoding/decoding tests +2. **Audio** - Audio capture and playback tests +3. **Display** - Video display tests using Wayland +4. **Camera** - Camera capture, encoding, and snapshot tests using libcamera + +Each subfolder is a standalone test suite with its own `run.sh`, YAML configuration, and README documentation. A master `run.sh` in this directory orchestrates all test suites for comprehensive validation. + +## Directory Structure + +``` +Gstreamer/ +├── README.md # This file +├── run.sh # Master test runner (runs all suites) +├── Video/ # Video encoding/decoding tests +│ ├── run.sh # Video test runner +│ ├── Gstreamer_Video_Tests.yaml +│ └── README.md # Video test documentation +├── Audio/ # Audio capture/playback tests +│ ├── run.sh # Audio test runner +│ ├── Gstreamer_Audio_Tests.yaml +│ └── README.md # Audio test documentation +├── Display/ # Video display tests +│ ├── run.sh # Display test runner +│ ├── Gstreamer_Display_Tests.yaml +│ └── README.md # Display test documentation +└── Camera/ # Camera capture/encoding tests + ├── run.sh # Camera test runner + ├── Gstreamer_Camera_Tests.yaml + └── README.md # Camera test documentation +``` + +## Test Categories + +### 1. Video Tests (`Video/`) + +Hardware-accelerated video encoding and decoding using V4L2 codecs. + +**Test Cases (10 total):** +- `h264-480p-encode` / `h264-4k-encode` - H.264 encoding at 480p and 4K +- `h265-480p-encode` / `h265-4k-encode` - H.265 encoding at 480p and 4K +- `h264-480p-decode` / `h264-4k-decode` - H.264 decoding (uses encode outputs) +- `h265-480p-decode` / `h265-4k-decode` - H.265 decoding (uses encode outputs) +- `vp9-480p-decode` / `vp9-4k-decode` - VP9 decoding (auto-fetches test clips) + +**Key Features:** +- V4L2 hardware acceleration +- Multiple codec support (H.264, H.265, VP9) +- Multiple resolutions (480p, 4K) +- Encode-then-decode validation flow +- Automatic VP9 clip fetching from GitHub + +**Quick Start:** +```bash +cd Video +./run.sh # Runs all tests by default +``` + +**Documentation:** See [Video/README.md](Video/README.md) + +### 2. Audio Tests (`Audio/`) + +Audio capture and playback using PulseAudio. + +**Test Cases (2 total):** +- `audio-encode` - Audio capture to WAV file +- `audio-decode` - WAV file playback + +**Key Features:** +- PulseAudio integration +- WAV format encoding/decoding +- Controlled capture duration +- Audio device validation + +**Quick Start:** +```bash +cd Audio +./run.sh # Runs all tests by default +``` + +**Documentation:** See [Audio/README.md](Audio/README.md) + +### 3. Display Tests (`Display/`) + +Video display validation using Wayland compositor with videotestsrc. + +**Test Cases (4 total):** +- `wayland-basic` - 480p SMPTE bars @ 30fps +- `wayland-videotestsrc` - 1080p moving ball @ 30fps +- `wayland-colorbar` - 4K color bars @ 30fps +- `wayland-smpte` - 720p SMPTE bars @ 60fps + +**Key Features:** +- Wayland compositor integration +- videotestsrc pattern generation (no external files needed) +- Multiple resolutions (480p, 720p, 1080p, 4K) +- Multiple frame rates (30fps, 60fps) +- Wayland surface validation + +**Quick Start:** +```bash +cd Display +./run.sh # Runs all tests by default +``` + +**Documentation:** See [Display/README.md](Display/README.md) + +### 4. Camera Tests (`Camera/`) + +Camera capture, encoding, and snapshot tests using libcamera. + +**Test Cases (5 total):** +- `camera-preview` - Live camera preview to Wayland +- `camera-h264-encode` - Capture and encode to H.264/MP4 +- `camera-h265-encode` - Capture and encode to H.265/MP4 +- `camera-snapshot` - Capture single frame as PNG +- `camera-jpeg-encode` - Capture single frame as JPEG + +**Key Features:** +- libcamera source (modern camera stack) +- Hardware-accelerated encoding with V4L2 encoders +- Automatic camera detection +- Multiple output formats (MP4, PNG, JPEG) +- Real-time preview capability + +**Quick Start:** +```bash +cd Camera +./run.sh # Runs all tests by default +``` + +**Documentation:** See [Camera/README.md](Camera/README.md) + +## Common Features + +All test suites share the same validation framework and CLI interface: + +### CLI Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--all` | Run all tests in suite | - | +| `--test ` | Run specific test | - | +| `--list` | List available tests | - | +| `--timeout ` | Timeout per test | 120 | +| `--repeat ` | Repeat count | 1 | +| `--repeat-policy ` | Pass policy | all | +| `--strict` | Fail on warnings | false | +| `--no-dmesg` | Skip dmesg scan | false | +| `--help` | Show help | - | + +### Validation Framework + +Each test suite uses the same validation approach: + +1. **Dependency Checks** - Verify required packages and tools +2. **Pre-execution Validation** - Check hardware/software prerequisites +3. **Pipeline Execution** - Run GStreamer pipelines with timeout +4. **Output Validation** - Check for errors, warnings, and failures +5. **dmesg Scanning** - Detect kernel errors (optional) +6. **Result Reporting** - Generate .res, logs, CSV, and JUnit XML + +### Result Files + +Each test suite generates: +- `.res` - Overall PASS/FAIL/SKIP status +- `logs_/` - Detailed logs directory + - `.log` - Individual test logs + - `summary.txt` - Test summary + - `results.csv` - CSV format results + - `.junit_cases.xml` - JUnit XML for CI + - `dmesg_snapshot.log` - Kernel messages + - `dmesg_errors.log` - Kernel errors (if any) + +## Prerequisites + +### Common Requirements + +```bash +# GStreamer core +gstreamer1.0-tools +gstreamer1.0-plugins-base +gstreamer1.0-plugins-good +gstreamer1.0-plugins-bad + +# System utilities +timeout +dmesg +``` + +### Video-Specific Requirements +- V4L2 video devices (`/dev/video*`) +- V4L2 codec drivers (qcom_iris or iris_vpu) +- Network connectivity (for VP9 clip fetching) + +### Audio-Specific Requirements +- PulseAudio server running +- Audio capture device (microphone) +- Audio playback device (speakers/headphones) + +### Display-Specific Requirements +- Wayland compositor (Weston, Mutter) +- Display output connected +- DRM/KMS display driver + +### Camera-Specific Requirements +- libcamera installed and configured +- Camera accessible via libcamera +- V4L2 video encoder drivers (for encoding tests) +- Wayland compositor (for preview test) + +## Running Tests + +### Run All Test Suites (Master Runner) + +The master `run.sh` in the Gstreamer directory runs all test suites: + +```bash +# Run all GStreamer test suites +cd Runner/suites/Gstreamer +./run.sh + +# Or using run-test.sh from Runner directory +cd Runner +./run-test.sh Gstreamer + +# Run specific suite only +cd Runner/suites/Gstreamer +./run.sh --suite Video +./run.sh --suite Camera + +# List available suites +./run.sh --list +``` + +**Master Runner Output:** +- `Gstreamer.res` - Overall PASS/FAIL status +- `logs_Gstreamer/summary.txt` - Combined results from all suites +- Individual suite results in their respective folders + +### Run Individual Test Suites + +```bash +# Video tests (runs all 10 tests by default) +cd Video && ./run.sh + +# Audio tests (runs all 2 tests by default) +cd Audio && ./run.sh + +# Display tests (runs all 4 tests by default) +cd Display && ./run.sh + +# Camera tests (runs all 5 tests by default) +cd Camera && ./run.sh +``` + +### Run Specific Tests + +```bash +# Video encoding only +cd Video && ./run.sh --test h264-480p-encode + +# Audio capture only +cd Audio && ./run.sh --test audio-encode + +# Display test only +cd Display && ./run.sh --test wayland-basic + +# Camera preview only +cd Camera && ./run.sh --test camera-preview +``` + +### Run with Custom Parameters + +```bash +# Increase timeout +./run.sh --all --timeout 180 + +# Enable strict mode +./run.sh --all --strict + +# Repeat tests +./run.sh --all --repeat 3 --repeat-policy any + +# Disable dmesg scanning +./run.sh --all --no-dmesg +``` + +## CI/CD Integration + +### LAVA Test Plans + +Each test suite has its own YAML definition for LAVA integration: + +```yaml +# Video tests +- test: + definitions: + - path: Runner/suites/Gstreamer/Video/Gstreamer_Video_Tests.yaml + +# Audio tests +- test: + definitions: + - path: Runner/suites/Gstreamer/Audio/Gstreamer_Audio_Tests.yaml + +# Display tests +- test: + definitions: + - path: Runner/suites/Gstreamer/Display/Gstreamer_Display_Tests.yaml + +# Camera tests +- test: + definitions: + - path: Runner/suites/Gstreamer/Camera/Gstreamer_Camera_Tests.yaml +``` + +### Standalone Execution + +```bash +# From repository root - run all suites +cd Runner/suites/Gstreamer && ./run.sh + +# Or run individual suites +cd Runner/suites/Gstreamer/Video && ./run.sh +cd Runner/suites/Gstreamer/Audio && ./run.sh +cd Runner/suites/Gstreamer/Display && ./run.sh +cd Runner/suites/Gstreamer/Camera && ./run.sh +``` + +## Platform Support + +| Platform | Video | Audio | Display | Camera | Notes | +|----------|-------|-------|---------|--------|-------| +| QCS6490 | ✓ | ✓ | ✓ | ✓ | Full support | +| QCS8550 | ✓ | ✓ | ✓ | ✓ | Full support | +| QCS8650 | ✓ | ✓ | ✓ | ✓ | Full support | +| SA8775P | ✓ | ✓ | ✓ | ✓ | Full support | +| SA8650P | ✓ | ✓ | ✓ | ✓ | Full support | +| SA8255P | ✓ | ✓ | ✓ | ✓ | Full support | + +## Troubleshooting + +### Common Issues + +1. **Missing Dependencies** + ```bash + # Install GStreamer packages + apt-get install gstreamer1.0-tools gstreamer1.0-plugins-* + ``` + +2. **Permission Errors** + ```bash + # Add user to video/audio groups + sudo usermod -a -G video,audio $USER + ``` + +3. **Device Not Found** + ```bash + # Check video devices + ls -la /dev/video* + + # Check audio devices + pactl list sources short + pactl list sinks short + + # Check cameras + libcamera-hello --list-cameras + ``` + +4. **Pipeline Failures** + ```bash + # Enable debug output + GST_DEBUG=3 gst-launch-1.0 + + # Check element availability + gst-inspect-1.0 + ``` + +### Test-Specific Troubleshooting + +- **Video Tests:** See [Video/README.md](Video/README.md#troubleshooting) +- **Audio Tests:** See [Audio/README.md](Audio/README.md#troubleshooting) +- **Display Tests:** See [Display/README.md](Display/README.md#troubleshooting) +- **Camera Tests:** See [Camera/README.md](Camera/README.md#troubleshooting) + +## Test Dependencies + +### Execution Order + +For complete validation, run tests in this order: + +1. **Video Tests** (independent, generates encoded files) +2. **Audio Tests** (independent) +3. **Display Tests** (independent, uses videotestsrc) +4. **Camera Tests** (independent, uses libcamera) + +```bash +# Complete test sequence using master runner +cd Runner/suites/Gstreamer +./run.sh # Runs all suites: Video, Audio, Display, Camera + +# Or run individually +cd Video && ./run.sh +cd ../Audio && ./run.sh +cd ../Display && ./run.sh +cd ../Camera && ./run.sh +``` + +### File Dependencies + +- **Video Tests**: Self-contained (encode tests generate files for decode tests) +- **Audio Tests**: Independent (no external dependencies) +- **Display Tests**: Independent (uses videotestsrc, no external files) +- **Camera Tests**: Independent (uses libcamera for capture) + +## Environment Variables + +### Common Variables + +```bash +# GStreamer debug level (0-9) +export GST_DEBUG=3 + +# Test timeout (seconds) +export TIMEOUT=180 + +# Strict mode (fail on warnings) +export STRICT=true + +# dmesg scanning +export DMESG_SCAN=true +``` + +### Video-Specific Variables + +```bash +# Video stack (upstream/downstream/auto) +export VIDEO_STACK=auto + +# Platform selection +export PLATFORM=auto + +# VP9 clips URL +export VP9_CLIPS_URL="https://github.com/..." +``` + +### Audio-Specific Variables + +```bash +# PulseAudio server +export PULSE_SERVER=unix:/run/user/1000/pulse/native + +# Audio buffer size +export PULSE_LATENCY_MSEC=50 +``` + +### Display-Specific Variables + +```bash +# Wayland display +export WAYLAND_DISPLAY=wayland-0 + +# Runtime directory +export XDG_RUNTIME_DIR=/run/user/$(id -u) +``` + +### Camera-Specific Variables + +```bash +# Camera device (for compatibility) +export CAMERA_DEVICE=/dev/video0 + +# Capture duration (seconds) +export CAPTURE_DURATION=5 +``` + +## Performance Benchmarking + +Each test suite can be used for performance analysis: + +```bash +# Measure encoding performance +time ./Video/run.sh --test h264-480p-encode + +# Measure with multiple iterations +./Video/run.sh --test h264-480p-encode --repeat 10 + +# Analyze logs for timing information +grep -i "time\|duration\|fps" logs_*/summary.txt +``` + +## Contributing + +When adding new tests: + +1. Follow the existing test structure +2. Use the common validation framework +3. Update the appropriate README +4. Add YAML configuration for LAVA +5. Test on multiple platforms +6. Document prerequisites and troubleshooting + +See [CONTRIBUTING.md](../../../CONTRIBUTING.md) for detailed guidelines. + +## Additional Resources + +- [GStreamer Documentation](https://gstreamer.freedesktop.org/documentation/) +- [V4L2 Codec API](https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-codec.html) +- [PulseAudio Documentation](https://www.freedesktop.org/wiki/Software/PulseAudio/) +- [Wayland Documentation](https://wayland.freedesktop.org/) +- [libcamera Documentation](https://libcamera.org/) +- [qcom-linux-testkit Contributing Guide](../../../CONTRIBUTING.md) + +## License + +``` +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause-Clear diff --git a/Runner/suites/Gstreamer/README_Gstreamer.md b/Runner/suites/Gstreamer/README_Gstreamer.md new file mode 100644 index 00000000..80b5ef6e --- /dev/null +++ b/Runner/suites/Gstreamer/README_Gstreamer.md @@ -0,0 +1,200 @@ +# GStreamer V4L2 Test Scripts for Qualcomm Linux + +**Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.** +**SPDX-License-Identifier: BSD-3-Clause-Clear** + +--- + +## Overview + +These scripts automate validation of GStreamer encoding and decoding using V4L2 plugins on Qualcomm Linux platforms. The test suite validates the following GStreamer elements: + +- **v4l2h264dec**: H.264 decoder +- **v4l2h265dec**: H.265 decoder +- **v4l2h264enc**: H.264 encoder +- **v4l2h265enc**: H.265 encoder + +The suite leverages the common test framework with the same stack switching capabilities, pre-flight checks, and result reporting as other multimedia tests. + +--- + +## Features + +- **GStreamer Pipeline Tests**: Tests GStreamer pipelines using V4L2 hardware-accelerated codecs +- **Encode/Decode Testing**: Tests both encoding (videotestsrc → H.264/H.265) and decoding (H.264/H.265 → fakevideosink) +- **Auto-generated Test Media**: Creates test media files if they don't exist +- **Pipeline Error Detection**: Analyzes GStreamer logs for errors and warnings +- **Yocto-friendly**: POSIX shell with BusyBox-safe paths +- **Timeout Control**: Configurable timeouts for each test +- **Repeat/Loop Support**: Configurable test repetition with delay +- **Stack Switching**: Upstream ↔ downstream without reboot +- **dmesg Triage**: Scans kernel logs for errors +- **JUnit XML Output**: Optional JUnit XML output for CI/CD integration + +--- + +## Directory Layout + +```bash +Runner/ +├── suites/ +│ └── Multimedia/ +│ └── Gstreamer/ +│ ├── README_Gstreamer.md +│ ├── Gstreamer_MM_Tests.yaml +│ └── run.sh +└── utils/ + ├── functestlib.sh + └── lib_video.sh +``` + +--- + +## Quick Start + +```bash +git clone +cd + +# Copy to target +scp -r Runner user@: +ssh user@ + +cd /Runner +./run-test.sh 'Gstreamer Multimedia Tests' +``` + +> Results land under: `Runner/suites/Multimedia/Gstreamer/` + +--- + +## Runner CLI (run.sh) + +| Option | Description | +|---|---| +| `--timeout S` | Timeout per test (default: `60`) | +| `--strict` | Treat dmesg warnings as failures | +| `--no-dmesg` | Disable dmesg scanning | +| `--max N` | Run at most `N` tests | +| `--stop-on-fail` | Abort suite on first failure | +| `--loglevel N` | Log level | +| `--repeat N` | Repeat each test `N` times | +| `--repeat-delay S` | Delay between repeats | +| `--repeat-policy all|any` | PASS if all runs pass, or any run passes | +| `--junit FILE` | Write JUnit XML | +| `--dry-run` | Print commands only | +| `--verbose` | Verbose runner logs | +| `--stack auto|upstream|downstream|base|overlay|up|down|both` | Select target stack | +| `--platform lemans|monaco|kodiak` | Force platform (else auto-detect) | +| `--retry-on-fail N` | Retry up to N times if a case ends FAIL | +| `--post-test-sleep S` | Sleep S seconds after each case | + +--- + +## Test Pipelines + +### H.264 Decode Pipeline +``` +filesrc location=./720p_AVC.h264 ! h264parse ! v4l2h264dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink +``` + +### H.265 Decode Pipeline +``` +filesrc location=./720x1280_hevc.h265 ! h265parse ! v4l2h265dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink +``` + +### H.264 Encode Pipeline +``` +videotestsrc num-buffers=100 ! video/x-raw,width=1280,height=720,format=NV12,framerate=30/1 ! v4l2h264enc extra-controls="controls,video_bitrate=2000000" ! h264parse ! filesink location=./output_h264.h264 +``` + +### H.265 Encode Pipeline +``` +videotestsrc num-buffers=100 ! video/x-raw,width=1280,height=720,format=NV12,framerate=30/1 ! v4l2h265enc extra-controls="controls,video_bitrate=2000000" ! h265parse ! filesink location=./output_h265.h265 +``` + +--- + +## Pipeline Error Detection + +The test script checks for the following error patterns in GStreamer logs: + +- General GStreamer errors (`ERROR:`) +- GStreamer warnings (`WARNING:`) - only in strict mode +- V4L2-specific failures (`v4l2.*failed`) +- Negotiation failures (`negotiation failed`) +- Buffer allocation failures (`buffer pool activation failed`) +- Format errors (`format not supported`) +- EOS handling errors (`failed to handle EOS`) +- Hardware acceleration errors (`hardware acceleration not available`) + +--- + +## Examples + +### Run with default settings +```sh +./run.sh +``` + +### Run with increased timeout +```sh +./run.sh --timeout 120 +``` + +### Run with stack selection +```sh +./run.sh --stack upstream +./run.sh --stack downstream +``` + +### Run with repeat +```sh +./run.sh --repeat 3 --repeat-delay 5 +``` + +### Run with JUnit XML output +```sh +./run.sh --junit gstreamer-results.xml +``` + +### Run in strict mode (warnings treated as errors) +```sh +./run.sh --strict +``` + +--- + +## Troubleshooting + +### Missing GStreamer Plugins +If the test skips with a message about missing GStreamer plugins, ensure the following packages are installed: +- gstreamer1.0-plugins-base +- gstreamer1.0-plugins-good +- gstreamer1.0-plugins-bad +- gstreamer1.0-v4l2 (critical for V4L2 elements) + +### No Video Devices +If the test skips with "no /dev/video* nodes", check: +1. Video drivers are loaded correctly +2. Stack selection is correct +3. Device nodes exist and have proper permissions + +### Pipeline Failures +If a pipeline fails: +1. Check the log file in `logs_Gstreamer Multimedia Tests/` +2. Try running the pipeline manually with `gst-launch-1.0 -v` +3. Check dmesg for driver errors + +### Common Issues +- **Negotiation failures**: Ensure the format and resolution are supported by the hardware +- **Buffer allocation failures**: Check system memory and driver capabilities +- **Hardware acceleration not available**: Verify the correct drivers are loaded + +--- + +## Integration with Other Tests + +This test follows the same framework as other multimedia tests, making it easy to integrate into existing test suites. It can be run alongside other tests using the same runner infrastructure. + +--- diff --git a/Runner/suites/Gstreamer/Video/Gstreamer_Video_Tests.yaml b/Runner/suites/Gstreamer/Video/Gstreamer_Video_Tests.yaml new file mode 100644 index 00000000..4704e149 --- /dev/null +++ b/Runner/suites/Gstreamer/Video/Gstreamer_Video_Tests.yaml @@ -0,0 +1,39 @@ +metadata: + name: gstreamer-video-tests + format: "Lava-Test Test Definition 1.0" + description: "GStreamer Video Encode/Decode validation using V4L2 hardware acceleration (H.264, H.265, VP9)" + os: + - linux + scope: + - functional + +params: + # Timeout for each test in seconds + TIMEOUT: "60" + # Enable strict mode (treat dmesg warnings as failures) + STRICT: "0" + # Enable dmesg scanning + DMESG_SCAN: "1" + # Log level + LOGLEVEL: "15" + # Sleep time after each test in seconds + POST_TEST_SLEEP: "5" + # Platform (auto-detected if empty) + PLATFORM: "" + # Video stack selection + VIDEO_STACK: "auto" + # VP9 clips download URL (optional, uses GitHub release by default) + VP9_CLIPS_URL: "" + +run: + steps: + - REPO_PATH=$PWD + - cd Runner/suites/Gstreamer/Video/ + - chmod +x ./run.sh + - | + if [ -n "${VP9_CLIPS_URL}" ]; then + ./run.sh --timeout "${TIMEOUT}" --loglevel "${LOGLEVEL}" --platform "${PLATFORM}" --stack "${VIDEO_STACK}" --post-test-sleep "${POST_TEST_SLEEP}" --vp9-clips-url "${VP9_CLIPS_URL}" || true + else + ./run.sh --timeout "${TIMEOUT}" --loglevel "${LOGLEVEL}" --platform "${PLATFORM}" --stack "${VIDEO_STACK}" --post-test-sleep "${POST_TEST_SLEEP}" || true + fi + - $REPO_PATH/Runner/utils/send-to-lava.sh "Gstreamer_Video_Tests.res" || true diff --git a/Runner/suites/Gstreamer/Video/README.md b/Runner/suites/Gstreamer/Video/README.md new file mode 100644 index 00000000..ab2b4911 --- /dev/null +++ b/Runner/suites/Gstreamer/Video/README.md @@ -0,0 +1,438 @@ +# GStreamer Video Encode/Decode Tests + +**Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.** +**SPDX-License-Identifier: BSD-3-Clause-Clear** + +--- + +## Overview + +This test suite validates GStreamer video encoding and decoding using V4L2 hardware-accelerated plugins on Qualcomm Linux platforms. Tests cover two resolutions (480p and 4K) for both H.264 and H.265 codecs. + +### Test Coverage + +**10 Test Cases Total:** +- **H.264 480p Encode**: Hardware encoding at 720x480 using `v4l2h264enc` +- **H.264 4K Encode**: Hardware encoding at 3840x2160 using `v4l2h264enc` +- **H.265 480p Encode**: Hardware encoding at 720x480 using `v4l2h265enc` +- **H.265 4K Encode**: Hardware encoding at 3840x2160 using `v4l2h265enc` +- **H.264 480p Decode**: Hardware decoding at 720x480 using `v4l2h264dec` +- **H.264 4K Decode**: Hardware decoding at 3840x2160 using `v4l2h264dec` +- **H.265 480p Decode**: Hardware decoding at 720x480 using `v4l2h265dec` +- **H.265 4K Decode**: Hardware decoding at 3840x2160 using `v4l2h265dec` +- **VP9 480p Decode**: Hardware decoding at 720x480 using `v4l2vp9dec` +- **VP9 4K Decode**: Hardware decoding at 3840x2160 using `v4l2vp9dec` + +**Key Features:** +- H.264/H.265 decode tests use the output files generated by encode tests as input, ensuring end-to-end validation +- VP9 decode tests automatically fetch test clips from GitHub releases if not present locally +- VP9 tests gracefully skip if hardware support is unavailable + +--- + +## Quick Start + +```bash +cd Runner/suites/Gstreamer/Video +./run.sh +``` + +--- + +## Test Pipelines + +### H.264 480p Encode +```bash +videotestsrc num-buffers=300 ! \ + video/x-raw,width=720,height=480,format=NV12,framerate=30/1 ! \ + v4l2h264enc extra-controls="controls,video_bitrate=1000000" ! \ + h264parse ! qtmux ! filesink location=./output_h264_480p.mp4 +``` + +### H.264 4K Encode +```bash +videotestsrc num-buffers=300 ! \ + video/x-raw,width=3840,height=2160,format=NV12,framerate=30/1 ! \ + v4l2h264enc extra-controls="controls,video_bitrate=8000000" ! \ + h264parse ! qtmux ! filesink location=./output_h264_4k.mp4 +``` + +### H.265 480p Encode +```bash +videotestsrc num-buffers=300 ! \ + video/x-raw,width=720,height=480,format=NV12,framerate=30/1 ! \ + v4l2h265enc extra-controls="controls,video_bitrate=1000000" ! \ + h265parse ! qtmux ! filesink location=./output_h265_480p.mp4 +``` + +### H.265 4K Encode +```bash +videotestsrc num-buffers=300 ! \ + video/x-raw,width=3840,height=2160,format=NV12,framerate=30/1 ! \ + v4l2h265enc extra-controls="controls,video_bitrate=8000000" ! \ + h265parse ! qtmux ! filesink location=./output_h265_4k.mp4 +``` + +### H.264 480p Decode (uses encode output) +```bash +filesrc location=./output_h264_480p.mp4 ! qtdemux ! h264parse ! \ + v4l2h264dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink +``` + +### H.264 4K Decode (uses encode output) +```bash +filesrc location=./output_h264_4k.mp4 ! qtdemux ! h264parse ! \ + v4l2h264dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink +``` + +### H.265 480p Decode (uses encode output) +```bash +filesrc location=./output_h265_480p.mp4 ! qtdemux ! h265parse ! \ + v4l2h265dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink +``` + +### H.265 4K Decode (uses encode output) +```bash +filesrc location=./output_h265_4k.mp4 ! qtdemux ! h265parse ! \ + v4l2h265dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink +``` + +### VP9 480p Decode (uses fetched clip) +```bash +filesrc location=./vp9_480p.webm ! matroskademux ! vp9parse ! \ + v4l2vp9dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink +``` + +### VP9 4K Decode (uses fetched clip) +```bash +filesrc location=./vp9_4k.webm ! matroskademux ! vp9parse ! \ + v4l2vp9dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink +``` + +--- + +## Test Execution Flow + +1. **Encode Tests Run First** (generate output files): + - h264-480p-encode → creates `output_h264_480p.mp4` + - h264-4k-encode → creates `output_h264_4k.mp4` + - h265-480p-encode → creates `output_h265_480p.mp4` + - h265-4k-encode → creates `output_h265_4k.mp4` + +2. **H.264/H.265 Decode Tests Use Encode Outputs**: + - h264-480p-decode → reads `output_h264_480p.mp4` + - h264-4k-decode → reads `output_h264_4k.mp4` + - h265-480p-decode → reads `output_h265_480p.mp4` + - h265-4k-decode → reads `output_h265_4k.mp4` + +3. **VP9 Decode Tests Use Fetched Clips**: + - vp9-480p-decode → reads `vp9_480p.webm` (auto-fetched if missing) + - vp9-4k-decode → reads `vp9_4k.webm` (auto-fetched if missing) + +This ensures that the encoded content is validated by successfully decoding it. VP9 tests validate hardware decode capability using pre-encoded reference clips. + +--- + +## CLI Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--timeout S` | Timeout per test (seconds) | 120 | +| `--strict` | Treat warnings as failures | disabled | +| `--no-dmesg` | Disable dmesg scanning | enabled | +| `--stop-on-fail` | Abort on first failure | disabled | +| `--loglevel N` | GStreamer log verbosity | 15 | +| `--repeat N` | Repeat each test N times | 1 | +| `--repeat-delay S` | Delay between repeats | 0 | +| `--repeat-policy all\|any` | Pass criteria | all | +| `--junit FILE` | JUnit XML output | none | +| `--stack auto\|upstream\|downstream` | Video stack | auto | +| `--platform lemans\|monaco\|kodiak` | Platform | auto-detect | +| `--post-test-sleep S` | Sleep after each test | 0 | +| `--vp9-clips-url URL` | VP9 clips download URL | GitHub release | + +--- + +## Examples + +### Run all tests (default) +```bash +./run.sh +``` + +### Run with increased timeout (for 4K tests) +```bash +./run.sh --timeout 180 +``` + +### Run with strict mode +```bash +./run.sh --strict +``` + +### Run with repeat +```bash +./run.sh --repeat 3 --repeat-delay 5 +``` + +### Generate JUnit XML +```bash +./run.sh --junit video-results.xml +``` + +### Select video stack +```bash +./run.sh --stack upstream +./run.sh --stack downstream +``` + +--- + +## Output Files + +### Test Result +- `Gstreamer_Video_Tests.res` - Overall PASS/FAIL/SKIP + +### Logs Directory: `logs_Gstreamer_Video_Tests/` +- `h264-480p-encode.log` - H.264 480p encode pipeline log +- `h264-4k-encode.log` - H.264 4K encode pipeline log +- `h265-480p-encode.log` - H.265 480p encode pipeline log +- `h265-4k-encode.log` - H.265 4K encode pipeline log +- `h264-480p-decode.log` - H.264 480p decode pipeline log +- `h264-4k-decode.log` - H.264 4K decode pipeline log +- `h265-480p-decode.log` - H.265 480p decode pipeline log +- `h265-4k-decode.log` - H.265 4K decode pipeline log +- `vp9-480p-decode.log` - VP9 480p decode pipeline log +- `vp9-4k-decode.log` - VP9 4K decode pipeline log +- `summary.txt` - Per-test results summary +- `results.csv` - Machine-readable results +- `dmesg_errors.log` - Kernel error log (if any) + +### Generated Media Files +- `output_h264_480p.mp4` - Encoded H.264 480p video +- `output_h264_4k.mp4` - Encoded H.264 4K video +- `output_h265_480p.mp4` - Encoded H.265 480p video +- `output_h265_4k.mp4` - Encoded H.265 4K video + +### VP9 Test Clips (auto-fetched) +- `vp9_480p.webm` - VP9 480p reference clip +- `vp9_4k.webm` - VP9 4K reference clip + +--- + +## Validation Criteria + +### Pass Criteria +A test PASSES if: +1. GStreamer pipeline exits with code 0 +2. No ERROR patterns in log +3. No WARNING patterns (if `--strict` mode) +4. No kernel errors in dmesg (if enabled) +5. For encode tests: Output file is created +6. For decode tests: Input file exists and is successfully decoded + +### Error Patterns Detected +- `ERROR:` - General GStreamer errors +- `v4l2.*failed` - V4L2 operation failures +- `negotiation failed` - Format negotiation issues +- `buffer pool activation failed` - Memory allocation failures +- `format not supported` - Unsupported format errors + +--- + +## Resolution Details + +### 480p (720x480) +- **Aspect Ratio**: 3:2 +- **Bitrate**: 1 Mbps +- **Use Case**: Standard definition, lower bandwidth +- **Frame Count**: 300 frames (10 seconds at 30fps) + +### 4K (3840x2160) +- **Aspect Ratio**: 16:9 +- **Bitrate**: 8 Mbps +- **Use Case**: Ultra high definition, high quality +- **Frame Count**: 300 frames (10 seconds at 30fps) + +--- + +## Dependencies + +### Required GStreamer Plugins +- `v4l2h264dec` - H.264 hardware decoder +- `v4l2h265dec` - H.265 hardware decoder +- `v4l2h264enc` - H.264 hardware encoder +- `v4l2h265enc` - H.265 hardware encoder +- `v4l2vp9dec` - VP9 hardware decoder (optional, for VP9 tests) +- `qtmux` - MP4 muxer +- `qtdemux` - MP4 demuxer +- `h264parse` - H.264 parser +- `h265parse` - H.265 parser +- `vp9parse` - VP9 parser (optional, for VP9 tests) +- `matroskademux` - WebM/Matroska demuxer (optional, for VP9 tests) +- `videoconvert` - Format converter +- `videotestsrc` - Test pattern generator +- `fakevideosink` - Null sink for validation + +### System Requirements +- `/dev/video*` device nodes +- V4L2 video drivers loaded (qcom_iris or iris_vpu) +- GStreamer 1.0 installed +- Sufficient memory for 4K encoding/decoding + +--- + +## Troubleshooting + +### Missing Plugins +```bash +# Check plugin availability +gst-inspect-1.0 v4l2h264dec +gst-inspect-1.0 v4l2h264enc +gst-inspect-1.0 v4l2h265dec +gst-inspect-1.0 v4l2h265enc +gst-inspect-1.0 v4l2vp9dec +gst-inspect-1.0 vp9parse +gst-inspect-1.0 matroskademux + +# Install packages (if missing) +apt-get install gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good \ + gstreamer1.0-plugins-bad \ + gstreamer1.0-tools +``` + +### No Video Devices +```bash +# Check device nodes +ls -la /dev/video* + +# Check driver loading +lsmod | grep -E 'iris|venus' + +# Check dmesg +dmesg | grep -i video + +# Load driver if needed +modprobe qcom_iris +``` + +### Pipeline Failures +```bash +# Run pipeline manually with verbose output +GST_DEBUG=3 gst-launch-1.0 -v + +# Check log file +cat logs_Gstreamer_Video_Tests/h264-480p-encode.log + +# Verify format support +v4l2-ctl -d /dev/video0 --list-formats-ext +``` + +### 4K Encoding Issues +```bash +# Check memory availability +free -h + +# Increase timeout for 4K tests +./run.sh --timeout 240 + +# Check for memory errors in dmesg +dmesg | grep -i "out of memory" +``` + +### Decode Test Skipped +If H.264/H.265 decode tests are skipped, it means the encode test failed to create the output file: +```bash +# Check if encode test passed +cat logs_Gstreamer_Video_Tests/summary.txt + +# Verify output files exist +ls -lh output_*.mp4 + +# Re-run encode tests only +# (manually run encode pipelines to debug) +``` + +### VP9 Tests Skipped +VP9 tests may be skipped for several reasons: +```bash +# Check if VP9 plugins are available +gst-inspect-1.0 v4l2vp9dec +gst-inspect-1.0 vp9parse +gst-inspect-1.0 matroskademux + +# Check if VP9 clips were fetched +ls -lh vp9_*.webm + +# Check network connectivity (for clip fetching) +ping -c 3 github.com + +# Manually fetch VP9 clips +wget https://github.com/qualcomm-linux/qcom-linux-testkit/releases/download/IRIS-Video-Files-v1.0/vp9_clips.tar.gz +tar -xzf vp9_clips.tar.gz + +# Run with custom VP9 clips URL +./run.sh --vp9-clips-url "https://your-server.com/vp9_clips.tar.gz" +``` + +### VP9 Decode Failures +```bash +# Run VP9 pipeline manually with verbose output +GST_DEBUG=3 gst-launch-1.0 -v \ + filesrc location=./vp9_480p.webm ! matroskademux ! vp9parse ! \ + v4l2vp9dec ! videoconvert ! fakevideosink + +# Check if hardware supports VP9 +v4l2-ctl -d /dev/video0 --list-formats-ext | grep VP9 + +# Check driver capabilities +dmesg | grep -i vp9 +``` + +--- + + +## Supported Platforms + +- **LeMans** (QCS9100, QCS9075) +- **Monaco** (QCS8300) +- **Kodiak** (QCS6490, QCM6490) +- **QCS8550, QCS8650** +- **SA8775P, SA8650P, SA8255P** + +--- + +## CI/CD Integration + +### LAVA Test Definition +```yaml +- test: + definitions: + - repository: + from: git + path: Runner/suites/Gstreamer/Video/Gstreamer_Video_Tests.yaml + name: gstreamer-video-tests + parameters: + TIMEOUT: "180" + STRICT: "false" + DMESG_SCAN: "true" +``` + +### Jenkins Pipeline +```groovy +stage('GStreamer Video Tests') { + steps { + sh ''' + cd Runner/suites/Gstreamer/Video + ./run.sh --junit video-results.xml --timeout 180 + ''' + junit 'video-results.xml' + } +} +``` + +## License + +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause-Clear diff --git a/Runner/suites/Gstreamer/Video/run.sh b/Runner/suites/Gstreamer/Video/run.sh new file mode 100644 index 00000000..993dbf87 --- /dev/null +++ b/Runner/suites/Gstreamer/Video/run.sh @@ -0,0 +1,517 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear +# GStreamer Video Encode/Decode Test Runner - 480p and 4K resolutions + +# ---------- Repo env + helpers ---------- +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 1 +fi + +# Only source once (idempotent) +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# shellcheck disable=SC1090 +. "$INIT_ENV" +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" +# shellcheck disable=SC1091 +. "$TOOLS/lib_video.sh" + +TESTNAME="Gstreamer_Video_Tests" +RES_FILE="./${TESTNAME}.res" + +# --- Defaults / knobs --- +if [ -z "${TIMEOUT:-}" ]; then TIMEOUT="120"; fi +if [ -z "${STRICT:-}" ]; then STRICT="0"; fi +if [ -z "${DMESG_SCAN:-}" ]; then DMESG_SCAN="1"; fi +if [ -z "${STOP_ON_FAIL:-}" ]; then STOP_ON_FAIL="0"; fi +if [ -z "${LOGLEVEL:-}" ]; then LOGLEVEL="15"; fi +if [ -z "${REPEAT:-}" ]; then REPEAT="1"; fi +if [ -z "${REPEAT_DELAY:-}" ]; then REPEAT_DELAY="0"; fi +if [ -z "${REPEAT_POLICY:-}" ]; then REPEAT_POLICY="all"; fi +JUNIT_OUT="" +VERBOSE="0" +POST_TEST_SLEEP="0" + +# --- Test media files (encode outputs used as decode inputs) --- +H264_480P_OUTPUT="./output_h264_480p.mp4" +H264_4K_OUTPUT="./output_h264_4k.mp4" +H265_480P_OUTPUT="./output_h265_480p.mp4" +H265_4K_OUTPUT="./output_h265_4k.mp4" + +# --- VP9 input files (fetched from URL if not present) --- +VP9_480P_INPUT="./vp9_480p.webm" +VP9_4K_INPUT="./vp9_4k.webm" + +# VP9 clips URL (can be overridden via environment) +if [ -z "${VP9_CLIPS_URL:-}" ]; then + VP9_CLIPS_URL="https://github.com/qualcomm-linux/qcom-linux-testkit/releases/download/IRIS-Video-Files-v1.0/vp9_clips.tar.gz" +fi + +# --- Test parameters --- +FRAMERATE="30" +BITRATE_480P="1000000" +BITRATE_4K="8000000" +NUM_BUFFERS="300" + +# --- Resolution definitions --- +WIDTH_480P="720" +HEIGHT_480P="480" +WIDTH_4K="3840" +HEIGHT_4K="2160" + +# --- GStreamer pipelines --- +# H.264 480p Encode +H264_480P_ENCODE_PIPELINE="videotestsrc num-buffers=${NUM_BUFFERS} ! video/x-raw,width=${WIDTH_480P},height=${HEIGHT_480P},format=NV12,framerate=${FRAMERATE}/1 ! v4l2h264enc extra-controls=\"controls,video_bitrate=${BITRATE_480P}\" ! h264parse ! qtmux ! filesink location=${H264_480P_OUTPUT}" + +# H.264 4K Encode +H264_4K_ENCODE_PIPELINE="videotestsrc num-buffers=${NUM_BUFFERS} ! video/x-raw,width=${WIDTH_4K},height=${HEIGHT_4K},format=NV12,framerate=${FRAMERATE}/1 ! v4l2h264enc extra-controls=\"controls,video_bitrate=${BITRATE_4K}\" ! h264parse ! qtmux ! filesink location=${H264_4K_OUTPUT}" + +# H.265 480p Encode +H265_480P_ENCODE_PIPELINE="videotestsrc num-buffers=${NUM_BUFFERS} ! video/x-raw,width=${WIDTH_480P},height=${HEIGHT_480P},format=NV12,framerate=${FRAMERATE}/1 ! v4l2h265enc extra-controls=\"controls,video_bitrate=${BITRATE_480P}\" ! h265parse ! qtmux ! filesink location=${H265_480P_OUTPUT}" + +# H.265 4K Encode +H265_4K_ENCODE_PIPELINE="videotestsrc num-buffers=${NUM_BUFFERS} ! video/x-raw,width=${WIDTH_4K},height=${HEIGHT_4K},format=NV12,framerate=${FRAMERATE}/1 ! v4l2h265enc extra-controls=\"controls,video_bitrate=${BITRATE_4K}\" ! h265parse ! qtmux ! filesink location=${H265_4K_OUTPUT}" + +# H.264 480p Decode (uses encoded output) +H264_480P_DECODE_PIPELINE="filesrc location=${H264_480P_OUTPUT} ! qtdemux ! h264parse ! v4l2h264dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink" + +# H.264 4K Decode (uses encoded output) +H264_4K_DECODE_PIPELINE="filesrc location=${H264_4K_OUTPUT} ! qtdemux ! h264parse ! v4l2h264dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink" + +# H.265 480p Decode (uses encoded output) +H265_480P_DECODE_PIPELINE="filesrc location=${H265_480P_OUTPUT} ! qtdemux ! h265parse ! v4l2h265dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink" + +# H.265 4K Decode (uses encoded output) +H265_4K_DECODE_PIPELINE="filesrc location=${H265_4K_OUTPUT} ! qtdemux ! h265parse ! v4l2h265dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink" + +# VP9 480p Decode (uses fetched input) +VP9_480P_DECODE_PIPELINE="filesrc location=${VP9_480P_INPUT} ! matroskademux ! vp9parse ! v4l2vp9dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink" + +# VP9 4K Decode (uses fetched input) +VP9_4K_DECODE_PIPELINE="filesrc location=${VP9_4K_INPUT} ! matroskademux ! vp9parse ! v4l2vp9dec ! videoconvert ! video/x-raw,format=NV12 ! fakevideosink" + +usage() { + cat <"$RES_FILE" + exit 0 +fi + +# --- Resolve test path --- +test_path="$(find_test_case_by_name "$TESTNAME" 2>/dev/null || true)" +if [ -z "$test_path" ] || [ ! -d "$test_path" ]; then + test_path="$SCRIPT_DIR" +fi + +if ! cd "$test_path"; then + log_error "cd failed: $test_path" + printf '%s\n' "$TESTNAME FAIL" >"$RES_FILE" + exit 1 +fi + +# --- Create log directory --- +LOG_DIR="./logs_${TESTNAME}" +mkdir -p "$LOG_DIR" +export LOG_DIR + +# --- Check GStreamer plugins --- +for plugin in v4l2h264dec v4l2h265dec v4l2h264enc v4l2h265enc qtmux qtdemux; do + if ! gst-inspect-1.0 "$plugin" >/dev/null 2>&1; then + log_skip "$TESTNAME SKIP - $plugin plugin not available" + printf '%s\n' "$TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi +done + +# --- Check VP9 plugins (optional, won't skip entire suite) --- +VP9_AVAILABLE=0 +if gst-inspect-1.0 v4l2vp9dec >/dev/null 2>&1 && \ + gst-inspect-1.0 vp9parse >/dev/null 2>&1 && \ + gst-inspect-1.0 matroskademux >/dev/null 2>&1; then + VP9_AVAILABLE=1 + log_info "VP9 decode support detected" +else + log_warn "VP9 decode plugins not available (v4l2vp9dec, vp9parse, or matroskademux missing)" + log_warn "VP9 tests will be skipped" +fi + +# --- Check video devices --- +if ! video_devices_present; then + log_skip "$TESTNAME SKIP - no /dev/video* nodes" + printf '%s\n' "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +# --- JUnit prep / results files --- +JUNIT_TMP="$LOG_DIR/.junit_cases.xml" +: > "$JUNIT_TMP" +printf '%s\n' "mode,id,result,name,elapsed,pass_runs,fail_runs" > "$LOG_DIR/results.csv" +: > "$LOG_DIR/summary.txt" + +# --- Helper: Fetch VP9 clips if needed --- +fetch_vp9_clips() { + # Check if clips already exist + if [ -f "$VP9_480P_INPUT" ] && [ -f "$VP9_4K_INPUT" ]; then + log_info "VP9 clips already present" + return 0 + fi + + log_info "VP9 clips missing, attempting to fetch from: $VP9_CLIPS_URL" + + # Check network availability + if command -v check_network_status_rc >/dev/null 2>&1; then + if ! check_network_status_rc; then + log_warn "Network offline; cannot fetch VP9 clips" + return 1 + fi + fi + + # Use extract_tar_from_url from functestlib.sh + if command -v extract_tar_from_url >/dev/null 2>&1; then + if extract_tar_from_url "$VP9_CLIPS_URL"; then + log_pass "VP9 clips fetched successfully" + return 0 + else + log_warn "Failed to fetch VP9 clips from $VP9_CLIPS_URL" + return 1 + fi + else + log_warn "extract_tar_from_url not available; cannot fetch VP9 clips" + return 1 + fi +} + +# --- Helper functions --- +run_gst_pipeline() { + id="$1" + pipeline="$2" + logf="$LOG_DIR/${id}.log" + + log_info "[$id] Running GStreamer pipeline" + start_time=$(date +%s) + + if command -v run_with_timeout >/dev/null 2>&1; then + if run_with_timeout "$TIMEOUT" gst-launch-1.0 -v $pipeline >"$logf" 2>&1; then + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + if check_pipeline_errors "$logf"; then + log_fail "[$id] FAIL - Pipeline errors detected (${elapsed}s)" + return 1 + else + log_pass "[$id] PASS (${elapsed}s)" + return 0 + fi + else + rc=$? + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + if [ "$rc" -eq 124 ]; then + log_fail "[$id] FAIL - timeout after ${TIMEOUT}s" + else + log_fail "[$id] FAIL - gst-launch-1.0 exited with code $rc" + fi + return 1 + fi + else + if gst-launch-1.0 -v $pipeline >"$logf" 2>&1; then + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + if check_pipeline_errors "$logf"; then + log_fail "[$id] FAIL - Pipeline errors detected (${elapsed}s)" + return 1 + else + log_pass "[$id] PASS (${elapsed}s)" + return 0 + fi + else + rc=$? + log_fail "[$id] FAIL - gst-launch-1.0 exited with code $rc" + return 1 + fi + fi +} + +check_pipeline_errors() { + logf="$1" + + if grep -q "ERROR:" "$logf"; then + return 0 + fi + + if [ "$STRICT" -eq 1 ] && grep -q "WARNING:" "$logf"; then + return 0 + fi + + if grep -q "v4l2.*failed" "$logf"; then + return 0 + fi + + if grep -q "negotiation failed" "$logf"; then + return 0 + fi + + if grep -q "buffer pool activation failed" "$logf"; then + return 0 + fi + + return 1 +} + +run_test() { + id="$1" + name="$2" + pipeline="$3" + + total=$((total + 1)) + + log_info "----------------------------------------------------------------------" + log_info "[$id] START - $name" + + pass_runs=0 + fail_runs=0 + rep=1 + + while [ "$rep" -le "$REPEAT" ]; do + if [ "$REPEAT" -gt 1 ]; then + log_info "[$id] repeat $rep/$REPEAT" + fi + + if run_gst_pipeline "$id" "$pipeline"; then + pass_runs=$((pass_runs + 1)) + else + fail_runs=$((fail_runs + 1)) + fi + + if [ "$rep" -lt "$REPEAT" ] && [ "$REPEAT_DELAY" -gt 0 ]; then + sleep "$REPEAT_DELAY" + fi + + rep=$((rep + 1)) + done + + final="FAIL" + case "$REPEAT_POLICY" in + any) [ "$pass_runs" -ge 1 ] && final="PASS" ;; + all|*) [ "$fail_runs" -eq 0 ] && final="PASS" ;; + esac + + video_step "$id" "DMESG triage" + video_scan_dmesg_if_enabled "$DMESG_SCAN" "$LOG_DIR" + dmesg_rc=$? + + if [ "$dmesg_rc" -eq 0 ] && [ "$STRICT" -eq 1 ]; then + final="FAIL" + fi + + printf '%s\n' "$id $final $name" >> "$LOG_DIR/summary.txt" + printf '%s\n' "test,$id,$final,$name,0,$pass_runs,$fail_runs" >> "$LOG_DIR/results.csv" + + if [ "$final" = "PASS" ]; then + pass=$((pass + 1)) + else + fail=$((fail + 1)) + suite_rc=1 + [ "$STOP_ON_FAIL" -eq 1 ] && exit 1 + fi + + [ "$POST_TEST_SLEEP" -gt 0 ] && sleep "$POST_TEST_SLEEP" +} + +# --- Fetch VP9 clips if VP9 is available --- +if [ "$VP9_AVAILABLE" -eq 1 ]; then + fetch_vp9_clips || log_warn "VP9 clip fetch failed; VP9 tests will be skipped" +fi + +# --- Run tests --- +log_info "======================================================================" +log_info "==================== Starting $TESTNAME ==========================" +log_info "TIMEOUT=${TIMEOUT}s LOGLEVEL=$LOGLEVEL REPEAT=$REPEAT" +log_info "Resolutions: 480p (${WIDTH_480P}x${HEIGHT_480P}), 4K (${WIDTH_4K}x${HEIGHT_4K})" +log_info "VP9 Support: $([ "$VP9_AVAILABLE" -eq 1 ] && echo "YES" || echo "NO")" +log_info "======================================================================" + +total=0 +pass=0 +fail=0 +skip=0 +suite_rc=0 + +# --- ENCODE TESTS (must run first to generate files for decode) --- + +# Test 1: H.264 480p Encode +run_test "h264-480p-encode" "H.264 480p Encode (${WIDTH_480P}x${HEIGHT_480P})" "$H264_480P_ENCODE_PIPELINE" + +# Test 2: H.264 4K Encode +run_test "h264-4k-encode" "H.264 4K Encode (${WIDTH_4K}x${HEIGHT_4K})" "$H264_4K_ENCODE_PIPELINE" + +# Test 3: H.265 480p Encode +run_test "h265-480p-encode" "H.265 480p Encode (${WIDTH_480P}x${HEIGHT_480P})" "$H265_480P_ENCODE_PIPELINE" + +# Test 4: H.265 4K Encode +run_test "h265-4k-encode" "H.265 4K Encode (${WIDTH_4K}x${HEIGHT_4K})" "$H265_4K_ENCODE_PIPELINE" + +# --- DECODE TESTS (use encoded outputs as inputs) --- + +# Test 5: H.264 480p Decode +if [ -f "$H264_480P_OUTPUT" ]; then + run_test "h264-480p-decode" "H.264 480p Decode (${WIDTH_480P}x${HEIGHT_480P})" "$H264_480P_DECODE_PIPELINE" +else + log_warn "[h264-480p-decode] SKIP - encode output not found: $H264_480P_OUTPUT" + skip=$((skip + 1)) + total=$((total + 1)) +fi + +# Test 6: H.264 4K Decode +if [ -f "$H264_4K_OUTPUT" ]; then + run_test "h264-4k-decode" "H.264 4K Decode (${WIDTH_4K}x${HEIGHT_4K})" "$H264_4K_DECODE_PIPELINE" +else + log_warn "[h264-4k-decode] SKIP - encode output not found: $H264_4K_OUTPUT" + skip=$((skip + 1)) + total=$((total + 1)) +fi + +# Test 7: H.265 480p Decode +if [ -f "$H265_480P_OUTPUT" ]; then + run_test "h265-480p-decode" "H.265 480p Decode (${WIDTH_480P}x${HEIGHT_480P})" "$H265_480P_DECODE_PIPELINE" +else + log_warn "[h265-480p-decode] SKIP - encode output not found: $H265_480P_OUTPUT" + skip=$((skip + 1)) + total=$((total + 1)) +fi + +# Test 8: H.265 4K Decode +if [ -f "$H265_4K_OUTPUT" ]; then + run_test "h265-4k-decode" "H.265 4K Decode (${WIDTH_4K}x${HEIGHT_4K})" "$H265_4K_DECODE_PIPELINE" +else + log_warn "[h265-4k-decode] SKIP - encode output not found: $H265_4K_OUTPUT" + skip=$((skip + 1)) + total=$((total + 1)) +fi + +# --- VP9 DECODE TESTS (use fetched input files) --- + +# Test 9: VP9 480p Decode +if [ "$VP9_AVAILABLE" -eq 1 ]; then + if [ -f "$VP9_480P_INPUT" ]; then + run_test "vp9-480p-decode" "VP9 480p Decode (${WIDTH_480P}x${HEIGHT_480P})" "$VP9_480P_DECODE_PIPELINE" + else + log_warn "[vp9-480p-decode] SKIP - input file not found: $VP9_480P_INPUT" + skip=$((skip + 1)) + total=$((total + 1)) + fi +else + log_info "[vp9-480p-decode] SKIP - VP9 plugins not available" + skip=$((skip + 1)) + total=$((total + 1)) +fi + +# Test 10: VP9 4K Decode +if [ "$VP9_AVAILABLE" -eq 1 ]; then + if [ -f "$VP9_4K_INPUT" ]; then + run_test "vp9-4k-decode" "VP9 4K Decode (${WIDTH_4K}x${HEIGHT_4K})" "$VP9_4K_DECODE_PIPELINE" + else + log_warn "[vp9-4k-decode] SKIP - input file not found: $VP9_4K_INPUT" + skip=$((skip + 1)) + total=$((total + 1)) + fi +else + log_info "[vp9-4k-decode] SKIP - VP9 plugins not available" + skip=$((skip + 1)) + total=$((total + 1)) +fi + +# --- Summary --- +log_info "======================================================================" +log_info "Summary: total=$total pass=$pass fail=$fail skip=$skip" +log_info "======================================================================" + +if [ -s "$LOG_DIR/summary.txt" ]; then + log_info "Per-test results:" + while IFS= read -r line; do + log_info " $line" + done < "$LOG_DIR/summary.txt" +fi + +# --- JUnit finalize --- +if [ -n "$JUNIT_OUT" ]; then + { + printf '\n' "$TESTNAME" "$total" "$fail" "$skip" + cat "$JUNIT_TMP" + printf '\n' + } > "$JUNIT_OUT" + log_info "Wrote JUnit: $JUNIT_OUT" +fi + +# Overall result +if [ "$pass" -eq 0 ] && [ "$fail" -eq 0 ] && [ "$skip" -gt 0 ]; then + log_skip "$TESTNAME: SKIP" + printf '%s\n' "$TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +if [ "$suite_rc" -eq 0 ]; then + log_pass "$TESTNAME: PASS (passed: $pass/$total)" + printf '%s\n' "$TESTNAME PASS" >"$RES_FILE" + exit 0 +else + log_fail "$TESTNAME: FAIL (failed: $fail/$total)" + printf '%s\n' "$TESTNAME FAIL" >"$RES_FILE" + exit 1 +fi diff --git a/Runner/suites/Gstreamer/run.sh b/Runner/suites/Gstreamer/run.sh new file mode 100644 index 00000000..1f54c7b4 --- /dev/null +++ b/Runner/suites/Gstreamer/run.sh @@ -0,0 +1,228 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +#============================================================================== +# GStreamer Master Test Runner - Runs all GStreamer test suites +#============================================================================== + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" + +# Locate init_env dynamically +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: Cannot find init_env" + exit 1 +fi + +# Source init_env (idempotent) +if [ -z "$__INIT_ENV_LOADED" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" +fi + +# Source functestlib.sh +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" + +#============================================================================== +# Test Configuration +#============================================================================== + +TESTNAME="Gstreamer" +test_path=$(find_test_case_by_name "$TESTNAME") +res_file="$test_path/$TESTNAME.res" +log_dir="$test_path/logs_$TESTNAME" + +# Test suites to run +ALL_SUITES="Video Audio Display Camera" + +#============================================================================== +# Helper Functions +#============================================================================== + +show_usage() { + cat << EOF +Usage: $0 [OPTIONS] + +GStreamer Master Test Runner - Runs all GStreamer test suites + +OPTIONS: + --all Run all test suites (default) + --suite Run specific suite (Video, Audio, Display, Camera) + --list List available test suites + --help Show this help + +EXAMPLES: + $0 # Run all suites + $0 --all # Run all suites + $0 --suite Video # Run only Video tests + $0 --suite Camera # Run only Camera tests + +EOF +} + +list_suites() { + echo "Available GStreamer Test Suites:" + for suite in $ALL_SUITES; do + echo " - $suite" + done +} + +run_test_suite() { + local suite_name="$1" + local suite_dir="$test_path/$suite_name" + local suite_script="$suite_dir/run.sh" + + log_info "=== Running $suite_name Test Suite ===" + + if [ ! -d "$suite_dir" ]; then + log_error "$suite_name: Suite directory not found: $suite_dir" + return 1 + fi + + if [ ! -f "$suite_script" ]; then + log_error "$suite_name: run.sh not found in $suite_dir" + return 1 + fi + + if [ ! -x "$suite_script" ]; then + log_warn "$suite_name: Making run.sh executable" + chmod +x "$suite_script" + fi + + # Run the suite + cd "$suite_dir" || return 1 + if ./run.sh; then + log_pass "$suite_name: Suite completed" + cd "$test_path" || return 1 + return 0 + else + log_error "$suite_name: Suite failed or had errors" + cd "$test_path" || return 1 + return 1 + fi +} + +#============================================================================== +# Main Execution +#============================================================================== + +main() { + local run_all=true + local specific_suite="" + local suites_to_run="" + + # Parse arguments + while [ $# -gt 0 ]; do + case "$1" in + --all) + run_all=true + shift + ;; + --suite) + specific_suite="$2" + run_all=false + shift 2 + ;; + --list) + list_suites + exit 0 + ;; + --help) + show_usage + exit 0 + ;; + *) + log_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac + done + + # Determine suites to run + if [ "$run_all" = "true" ]; then + suites_to_run="$ALL_SUITES" + elif [ -n "$specific_suite" ]; then + suites_to_run="$specific_suite" + else + suites_to_run="$ALL_SUITES" + fi + + # Setup + mkdir -p "$log_dir" + log_info "Starting GStreamer Master Test Runner" + log_info "Test path: $test_path" + log_info "Log directory: $log_dir" + + # Run test suites + local total_suites=0 + local passed_suites=0 + local failed_suites=0 + local suite_results="" + + for suite in $suites_to_run; do + total_suites=$((total_suites + 1)) + + if run_test_suite "$suite"; then + passed_suites=$((passed_suites + 1)) + suite_results="$suite_results\n ✓ $suite: PASSED" + else + failed_suites=$((failed_suites + 1)) + suite_results="$suite_results\n ✗ $suite: FAILED" + fi + done + + # Generate summary + { + echo "=== GStreamer Master Test Summary ===" + echo "Total Suites: $total_suites" + echo "Passed: $passed_suites" + echo "Failed: $failed_suites" + echo "" + echo "Suite Results:" + echo "$suite_results" | sed 's/\\n/\n/g' + echo "" + echo "Individual suite results:" + for suite in $suites_to_run; do + suite_res_file="$test_path/$suite/Gstreamer_${suite}_Tests.res" + if [ -f "$suite_res_file" ]; then + echo " $suite: $(cat "$suite_res_file")" + else + echo " $suite: .res file not found" + fi + done + } > "$log_dir/summary.txt" + + # Display summary + log_info "=========================================" + log_info "GStreamer Test Suites Summary:" + log_info " Total: $total_suites" + log_info " Passed: $passed_suites" + log_info " Failed: $failed_suites" + log_info "=========================================" + + # Final result + if [ $failed_suites -eq 0 ]; then + echo "PASS $TESTNAME" > "$res_file" + log_pass "$TESTNAME: All test suites passed ($passed_suites/$total_suites)" + exit 0 + else + echo "FAIL $TESTNAME" > "$res_file" + log_fail "$TESTNAME: Some test suites failed ($failed_suites/$total_suites)" + exit 0 + fi +} + +# Execute main +main "$@"