From cf4725ec6b57765f4a8d550b87a62185458cad9b Mon Sep 17 00:00:00 2001 From: nitinn Date: Sat, 18 Apr 2026 08:01:33 +0530 Subject: [PATCH 1/2] Runner/utils: extend lib_gstreamer helpers for camera tests Signed-off-by: nitinn --- Runner/utils/lib_gstreamer.sh | 225 +++++++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 2 deletions(-) diff --git a/Runner/utils/lib_gstreamer.sh b/Runner/utils/lib_gstreamer.sh index 0e312528..5a883e80 100755 --- a/Runner/utils/lib_gstreamer.sh +++ b/Runner/utils/lib_gstreamer.sh @@ -529,11 +529,12 @@ gstreamer_run_gstlaunch_timeout() { # shellcheck disable=SC2086 audio_timeout_run "${secs}s" "$GSTBIN" $GSTLAUNCHFLAGS $pipe return $? - fi - if command -v timeout >/dev/null 2>&1; then + elif command -v timeout >/dev/null 2>&1; then # shellcheck disable=SC2086 timeout "$secs" "$GSTBIN" $GSTLAUNCHFLAGS $pipe return $? + else + log_warn "No timeout command available (audio_timeout_run or timeout), running without timeout" fi fi @@ -684,6 +685,12 @@ gstreamer_check_errors() { return 1 fi + # Segmentation faults and signals + if grep -q -E 'Caught SIGSEGV|Segmentation fault|SIGABRT|SIGBUS|SIGILL' "$check_log" 2>/dev/null; then + rm -f "$filtered_log" 2>/dev/null || true + return 1 + fi + # Element-reported hard failures. if grep -q -E 'ERROR: from element|gst.*ERROR|gst.*FATAL' "$check_log" 2>/dev/null; then rm -f "$filtered_log" 2>/dev/null || true @@ -745,6 +752,14 @@ gstreamer_validate_log() { log_fail " Reason: File not found" fi + if grep -q -E 'Caught SIGSEGV|Segmentation fault' "$logfile" 2>/dev/null; then + log_fail " Reason: Segmentation fault (SIGSEGV) - critical crash" + fi + + if grep -q -E 'SIGABRT|SIGBUS|SIGILL' "$logfile" 2>/dev/null; then + log_fail " Reason: Fatal signal caught - process crashed" + fi + return 1 fi @@ -1419,3 +1434,209 @@ check_file_size() { return 1 fi } + +# ==================== Camera Pipeline Builders ==================== + +# -------------------- Camera format helpers -------------------- +# camera_format_to_gst_string +# Converts camera format name to GStreamer format string +# Prints: GStreamer format string (NV12 or NV12_Q08C) +camera_format_to_gst_string() { + format="$1" + case "$format" in + nv12) printf '%s\n' "NV12" ;; + ubwc) printf '%s\n' "NV12_Q08C" ;; + *) printf '%s\n' "" ;; + esac +} + +# -------------------- qtiqmmfsrc pipeline builders -------------------- +# camera_build_qtiqmmfsrc_fakesink_pipeline +# Builds qtiqmmfsrc fakesink test pipeline (uses timeout for duration control) +# Prints: pipeline string +camera_build_qtiqmmfsrc_fakesink_pipeline() { + camera_id="$1" + format="$2" + width="$3" + height="$4" + framerate="$5" + + gst_format=$(camera_format_to_gst_string "$format") + [ -z "$gst_format" ] && return 1 + + if [ "$format" = "ubwc" ]; then + printf '%s\n' "qtiqmmfsrc camera=${camera_id} name=camsrc ! video/x-raw,format=${gst_format},width=${width},height=${height},framerate=${framerate}/1,interlace-mode=progressive,colorimetry=bt601 ! queue ! fakesink" + else + printf '%s\n' "qtiqmmfsrc camera=${camera_id} name=camsrc ! video/x-raw,format=${gst_format},width=${width},height=${height},framerate=${framerate}/1 ! fakesink" + fi +} + +# camera_build_qtiqmmfsrc_preview_pipeline +# Builds qtiqmmfsrc preview pipeline with waylandsink +# Prints: pipeline string +camera_build_qtiqmmfsrc_preview_pipeline() { + camera_id="$1" + format="$2" + width="$3" + height="$4" + framerate="$5" + + gst_format=$(camera_format_to_gst_string "$format") + [ -z "$gst_format" ] && return 1 + + if [ "$format" = "ubwc" ]; then + printf '%s\n' "qtiqmmfsrc camera=${camera_id} name=camsrc ! video/x-raw,format=${gst_format},width=${width},height=${height},framerate=${framerate}/1 ! waylandsink fullscreen=true async=true sync=false" + else + printf '%s\n' "qtiqmmfsrc camera=${camera_id} name=camsrc ! video/x-raw,format=${gst_format},width=${width},height=${height},framerate=${framerate}/1 ! waylandsink fullscreen=true async=true sync=false" + fi +} + +# camera_build_qtiqmmfsrc_encode_pipeline +# Builds qtiqmmfsrc encode pipeline with v4l2h264enc +# Prints: pipeline string +camera_build_qtiqmmfsrc_encode_pipeline() { + camera_id="$1" + format="$2" + width="$3" + height="$4" + framerate="$5" + output_file="$6" + + gst_format=$(camera_format_to_gst_string "$format") + [ -z "$gst_format" ] && return 1 + + if [ "$format" = "ubwc" ]; then + printf '%s\n' "qtiqmmfsrc camera=${camera_id} name=camsrc ! video/x-raw,format=${gst_format},width=${width},height=${height},framerate=${framerate}/1,interlace-mode=progressive,colorimetry=bt601 ! queue ! v4l2h264enc capture-io-mode=4 output-io-mode=5 ! h264parse ! mp4mux ! queue ! filesink location=${output_file}" + else + printf '%s\n' "qtiqmmfsrc camera=${camera_id} name=camsrc ! video/x-raw,format=${gst_format},width=${width},height=${height},framerate=${framerate}/1 ! queue ! v4l2h264enc capture-io-mode=4 output-io-mode=4 ! h264parse ! mp4mux ! queue ! filesink location=${output_file}" + fi +} + +# -------------------- libcamerasrc pipeline builders -------------------- +# camera_build_libcamera_fakesink_pipeline +# Builds libcamerasrc fakesink pipeline with optional resolution caps (uses timeout for duration control) +# Parameters: +# width: Video width (0 for no caps filter) +# height: Video height (0 for no caps filter) +# framerate: Framerate in fps +# Prints: pipeline string +camera_build_libcamera_fakesink_pipeline() { + width="$1" + height="$2" + framerate="${3:-30}" + + # If width/height are 0 or empty, build pipeline without caps filter + if [ -z "$width" ] || [ -z "$height" ] || [ "$width" -eq 0 ] 2>/dev/null || [ "$height" -eq 0 ] 2>/dev/null; then + printf '%s\n' "libcamerasrc ! fakesink" + else + printf '%s\n' "libcamerasrc ! video/x-raw,width=${width},height=${height},framerate=${framerate}/1 ! fakesink" + fi +} + +# camera_build_libcamera_preview_pipeline +# Builds libcamerasrc preview pipeline with optional resolution caps (uses timeout for duration control) +# Parameters: +# width: Video width (0 for no caps filter) +# height: Video height (0 for no caps filter) +# framerate: Framerate in fps +# Prints: pipeline string +camera_build_libcamera_preview_pipeline() { + width="$1" + height="$2" + framerate="${3:-30}" + + # If width/height are 0 or empty, build pipeline without caps filter + if [ -z "$width" ] || [ -z "$height" ] || [ "$width" -eq 0 ] 2>/dev/null || [ "$height" -eq 0 ] 2>/dev/null; then + printf '%s\n' "libcamerasrc ! videoconvert ! waylandsink fullscreen=true" + else + printf '%s\n' "libcamerasrc ! video/x-raw,width=${width},height=${height},framerate=${framerate}/1 ! videoconvert ! waylandsink fullscreen=true" + fi +} + +# camera_build_libcamera_encode_pipeline +# Builds libcamerasrc encode pipeline with NV12 format (uses timeout for duration control) +# Parameters: +# width: Video width +# height: Video height +# output_file: Output MP4 file path +# framerate: Framerate in fps +# Prints: pipeline string +camera_build_libcamera_encode_pipeline() { + width="$1" + height="$2" + output_file="$3" + framerate="${4:-30}" + + printf '%s\n' "libcamerasrc ! videoconvert ! video/x-raw,format=NV12,width=${width},height=${height},framerate=${framerate}/1 ! v4l2h264enc capture-io-mode=4 output-io-mode=4 ! h264parse ! mp4mux ! filesink location=${output_file}" +} + +# -------------------- Wayland/Weston setup helper -------------------- +# camera_setup_wayland_environment +# Sets up Wayland/Weston environment for camera preview tests +# Sets wayland_ready=1 if successful, 0 otherwise +# Parameters: +# test_name: Name of the test for logging purposes +# Returns: 0 if Wayland is ready, 1 otherwise +camera_setup_wayland_environment() { + test_name="${1:-Camera_Test}" + + wayland_ready=0 + sock="" + + # Try to find existing Wayland socket + if command -v discover_wayland_socket_anywhere >/dev/null 2>&1; then + sock=$(discover_wayland_socket_anywhere | head -n 1 || true) + if [ -n "$sock" ]; then + log_info "Found existing Wayland socket: $sock" + if command -v adopt_wayland_env_from_socket >/dev/null 2>&1; then + if adopt_wayland_env_from_socket "$sock"; then + wayland_ready=1 + log_info "Adopted Wayland environment from socket" + fi + fi + fi + fi + + # Try starting Weston if no socket found + if [ "$wayland_ready" -eq 0 ] && [ -z "$sock" ]; then + if command -v weston_pick_env_or_start >/dev/null 2>&1; then + log_info "No Wayland socket found, attempting to start Weston..." + if weston_pick_env_or_start "$test_name"; then + # Re-discover socket after Weston start + if command -v discover_wayland_socket_anywhere >/dev/null 2>&1; then + sock=$(discover_wayland_socket_anywhere | head -n 1 || true) + if [ -n "$sock" ]; then + log_info "Weston started successfully with socket: $sock" + if command -v adopt_wayland_env_from_socket >/dev/null 2>&1; then + if adopt_wayland_env_from_socket "$sock"; then + wayland_ready=1 + fi + fi + fi + fi + fi + fi + fi + + # Verify Wayland connection + if [ "$wayland_ready" -eq 1 ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then + if command -v wayland_connection_ok >/dev/null 2>&1; then + if wayland_connection_ok; then + wayland_ready=1 + log_info "Wayland connection verified: OK" + else + wayland_ready=0 + log_warn "Wayland connection test failed" + fi + else + # Assume ready if WAYLAND_DISPLAY is set and no verification available + wayland_ready=1 + log_info "Wayland environment set (WAYLAND_DISPLAY=${WAYLAND_DISPLAY})" + fi + fi + + # Export wayland_ready for caller + export wayland_ready + + return $((1 - wayland_ready)) +} From 79aee01ddb8e3e8b896776671e84f1fed11bfcc3 Mon Sep 17 00:00:00 2001 From: nitinn Date: Sat, 18 Apr 2026 08:01:59 +0530 Subject: [PATCH 2/2] Camera_Tests: add GStreamer imsdk camera test suite Signed-off-by: nitinn --- .../Camera/Camera_Tests/Camera_Tests.yaml | 32 + .../GSTreamer/Camera/Camera_Tests/README.md | 205 +++ .../GSTreamer/Camera/Camera_Tests/run.sh | 1188 +++++++++++++++++ 3 files changed, 1425 insertions(+) create mode 100644 Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/Camera_Tests.yaml create mode 100644 Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/README.md create mode 100755 Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/run.sh diff --git a/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/Camera_Tests.yaml b/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/Camera_Tests.yaml new file mode 100644 index 00000000..d3426ecf --- /dev/null +++ b/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/Camera_Tests.yaml @@ -0,0 +1,32 @@ +metadata: + name: gstreamer-camera-tests + format: "Lava-Test Test Definition 1.0" + description: > + Comprehensive camera validation using GStreamer with qtiqmmfsrc or libcamerasrc. + Auto-detects available plugin (qtiqmmfsrc: 10 tests, libcamerasrc: 7 tests). + Tests run in sequence: Fakesink -> Preview -> Encode. + qtiqmmfsrc supports NV12 (linear) and UBWC (Qualcomm compressed) formats. + libcamerasrc supports NV12 only. + os: + - linux + scope: + - functional + +params: + CAMERA_ID: "0" + CAMERA_PLUGIN: "auto" + CAMERA_TEST_MODES: "fakesink,preview,encode" + CAMERA_FORMATS: "nv12,ubwc" + CAMERA_RESOLUTIONS: "720p,1080p,4k" + CAMERA_FRAMERATE: "30" + CAMERA_DURATION: "10" + CAMERA_GST_DEBUG: "2" + LAVA_TESTCASE_ID: "Camera_Tests" + +run: + steps: + - REPO_PATH="$PWD" + - cd "$REPO_PATH/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests" + - export CAMERA_ID CAMERA_PLUGIN CAMERA_TEST_MODES CAMERA_FORMATS CAMERA_RESOLUTIONS CAMERA_FRAMERATE CAMERA_DURATION CAMERA_GST_DEBUG + - ./run.sh --lava-testcase-id "${LAVA_TESTCASE_ID}" || true + - $REPO_PATH/Runner/utils/send-to-lava.sh Camera_Tests.res diff --git a/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/README.md b/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/README.md new file mode 100644 index 00000000..9787d897 --- /dev/null +++ b/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/README.md @@ -0,0 +1,205 @@ +# Camera Tests - GStreamer Camera Validation + +## Overview + +Validates camera functionality using GStreamer with two camera source plugins: +- **qtiqmmfsrc** (Qualcomm CAMX downstream) - 10 tests +- **libcamerasrc** (upstream) - 7 tests + +Auto-detects available plugin (prioritizes qtiqmmfsrc). Use `--plugin` to explicitly select. + +## Prerequisites + +### Required Tools +- `gst-launch-1.0` - GStreamer command-line tool +- `gst-inspect-1.0` - GStreamer plugin inspector + +### Required Plugins + +**qtiqmmfsrc:** +- `qtiqmmfsrc` - Qualcomm camera source +- `v4l2h264enc` - H.264 encoder (for encode tests) +- `waylandsink` - Display sink (for preview tests) + +**libcamerasrc:** +- `libcamerasrc` - Upstream camera source +- `videoconvert` - Format converter (required) +- `v4l2h264enc` - H.264 encoder (for encode tests) +- `waylandsink` - Display sink (for preview tests) + +### Hardware +- Camera hardware +- Weston display server (for preview tests) +- Write permissions to output directories + +## Test Matrix + +### qtiqmmfsrc Tests (10 Total) + +| Category | Tests | Formats | Resolutions | Description | +|----------|-------|---------|-------------|-------------| +| Fakesink | 2 | NV12, UBWC | 720p | Basic capture validation | +| Preview | 2 | NV12, UBWC | 4K | Display on Weston | +| Encode | 6 | NV12, UBWC | 720p, 1080p, 4K | H.264 encoding to MP4 | + +**Format Notes:** +- **NV12**: Standard linear format (universal support) +- **UBWC**: Qualcomm compressed format (Qualcomm optimized) + +### libcamerasrc Tests (7 Total) + +| Category | Tests | Resolutions | Description | +|----------|-------|-------------|-------------| +| Fakesink | 2 | 720p, 1080p | Basic capture validation | +| Preview | 2 | 720p, 1080p | Display on Weston | +| Encode | 3 | 720p, 1080p, 4K | H.264 encoding to MP4 | + +**Format Notes:** +- Only supports NV12 format +- Requires `videoconvert` element + +## Parameters + +### Command Line Options + +```bash +./run.sh [OPTIONS] + +--camera-id Camera device ID (qtiqmmfsrc only, default: 0) +--plugin Plugin: qtiqmmfsrc, libcamerasrc, auto (default: auto) +--test-modes Modes: fakesink,preview,encode (default: all) +--formats Formats: nv12,ubwc (qtiqmmfsrc only, default: both) +--resolutions Resolutions: 720p,1080p,4k (default: all) +--framerate Framerate (default: 30) +--duration Test duration (default: 10) +--gst-debug Debug level 1-9 (default: 2) +-h, --help Display help +``` + +### Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| `CAMERA_ID` | Camera device ID (qtiqmmfsrc only) | 0 | +| `CAMERA_PLUGIN` | Plugin: qtiqmmfsrc, libcamerasrc, auto | auto | +| `CAMERA_TEST_MODES` | Test modes (comma-separated) | fakesink,preview,encode | +| `CAMERA_FORMATS` | Formats (qtiqmmfsrc only) | nv12,ubwc | +| `CAMERA_RESOLUTIONS` | Resolutions | 720p,1080p,4k | +| `CAMERA_FRAMERATE` | Framerate (fps) | 30 | +| `CAMERA_DURATION` | Duration (seconds) | 10 | +| `CAMERA_GST_DEBUG` | Debug level (1-9) | 2 | + +### Usage Examples + +```bash +# Run all tests (auto-detect) +./run.sh + +# Test specific plugin +./run.sh --plugin qtiqmmfsrc +./run.sh --plugin libcamerasrc + +# Run specific test modes +./run.sh --plugin qtiqmmfsrc --test-modes fakesink +./run.sh --plugin libcamerasrc --test-modes preview,encode + +# Test specific formats/resolutions +./run.sh --plugin qtiqmmfsrc --formats nv12 --resolutions 720p,1080p +./run.sh --plugin libcamerasrc --resolutions 4k --duration 20 + +# Using environment variables +export CAMERA_PLUGIN="qtiqmmfsrc" +export CAMERA_FORMATS="ubwc" +./run.sh +``` + +## Output + +### Result Files +- `Camera_Tests.res` - Overall result (PASS/FAIL/SKIP) + +### Logs +``` +logs/Camera_Tests/ +├── .log # Individual test logs +├── gst.log # GStreamer debug output +├── dmesg/ # Kernel logs +└── encoded/ # Encoded MP4 files + └── *.mp4 +``` + +## Troubleshooting + +### Test Skipped + +**Plugin not available:** +```bash +gst-inspect-1.0 qtiqmmfsrc +gst-inspect-1.0 libcamerasrc +gst-inspect-1.0 v4l2h264enc +gst-inspect-1.0 waylandsink +gst-inspect-1.0 videoconvert # libcamerasrc only +``` + +**Camera not detected:** +```bash +ls -l /dev/video* +dmesg | grep camera +``` + +**Weston not running:** +```bash +echo $WAYLAND_DISPLAY +# Start Weston if needed +``` + +### Test Failed + +**Permission denied:** +```bash +# Add user to video group +sudo usermod -a -G video $USER +# Logout and login required +``` + +**No output file / File too small:** +- Check camera connection and power +- Verify camera permissions: `ls -l /dev/video*` +- Check output directory write permissions +- Review logs in `logs/Camera_Tests/` + +**Format not supported:** +- qtiqmmfsrc: Check capabilities with `v4l2-ctl --list-formats-ext` +- libcamerasrc: Only supports NV12 +- UBWC is qtiqmmfsrc-specific (Qualcomm compressed format) + +**Preview not displaying:** +- Verify Weston is running: `echo $WAYLAND_DISPLAY` +- Check XDG_RUNTIME_DIR is set +- Ensure display permissions are correct + +### Common Issues + +1. **Camera not detected** + - Verify hardware connection + - Check kernel logs: `dmesg | grep camera` + - List devices: `ls -l /dev/video*` + +2. **GStreamer errors** + - Check `logs/Camera_Tests/gst.log` + - Check `logs/Camera_Tests/.log` + - Check `logs/Camera_Tests/dmesg/` + +3. **Weston required for preview** + - Preview tests require Weston compositor + - Tests will be skipped if Weston not available + +## Notes + +- Auto-detection prioritizes qtiqmmfsrc when both available +- qtiqmmfsrc supports NV12 and UBWC formats +- libcamerasrc supports NV12 only +- UBWC is Qualcomm's compressed format (qtiqmmfsrc-specific) +- libcamerasrc requires `videoconvert` element +- All tests clean up GStreamer processes on exit +- LAVA-compatible (always exits 0) diff --git a/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/run.sh b/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/run.sh new file mode 100755 index 00000000..ffcd47f2 --- /dev/null +++ b/Runner/suites/Multimedia/GSTreamer/Camera/Camera_Tests/run.sh @@ -0,0 +1,1188 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause +# Comprehensive Camera Tests using GStreamer with qtiqmmfsrc +# Test sequence: Fakesink -> Preview -> Encode +# Supports both NV12 (linear) and UBWC (NV12_Q08C compressed) formats +# libcamera supports NV12 only. +# Logs everything to console and also to local log files. +# PASS/FAIL/SKIP is emitted to .res. Always exits 0 (LAVA-friendly). + +SCRIPT_DIR="$( + cd "$(dirname "$0")" || exit 1 + pwd +)" + +TESTNAME="Camera_Tests" +RESULT_TESTNAME="$TESTNAME" +RES_FILE="${SCRIPT_DIR}/${TESTNAME}.res" +LOG_DIR="${SCRIPT_DIR}/logs" +OUTDIR="$LOG_DIR/$TESTNAME" +GST_LOG="$OUTDIR/gst.log" +DMESG_DIR="$OUTDIR/dmesg" +ENCODED_DIR="$OUTDIR/encoded" + +mkdir -p "$OUTDIR" "$DMESG_DIR" "$ENCODED_DIR" >/dev/null 2>&1 || true +: >"$RES_FILE" +: >"$GST_LOG" + +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 + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" 2>/dev/null || true + exit 0 +fi + +if [ -z "${__INIT_ENV_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" + __INIT_ENV_LOADED=1 +fi + +# shellcheck disable=SC1091 +. "$TOOLS/functestlib.sh" + +# shellcheck disable=SC1091 +. "$TOOLS/lib_gstreamer.sh" + +# shellcheck disable=SC1091 +[ -f "$TOOLS/lib_display.sh" ] && . "$TOOLS/lib_display.sh" + +# shellcheck disable=SC1091 +[ -f "$TOOLS/camera/lib_camera.sh" ] && . "$TOOLS/camera/lib_camera.sh" + +result="FAIL" +reason="unknown" +pass_count=0 +fail_count=0 +skip_count=0 +total_tests=0 + +# -------------------- Defaults -------------------- +cameraId="${CAMERA_ID:-0}" +cameraPlugin="${CAMERA_PLUGIN:-auto}" +testModeList="${CAMERA_TEST_MODES:-fakesink,preview,encode}" +formatList="${CAMERA_FORMATS:-nv12,ubwc}" +resolutionList="${CAMERA_RESOLUTIONS:-720p,1080p,4k}" +framerate="${CAMERA_FRAMERATE:-30}" +duration="${CAMERA_DURATION:-10}" +gstDebugLevel="${CAMERA_GST_DEBUG:-${GST_DEBUG_LEVEL:-2}}" + +# Validate environment variables if set (POSIX-safe; no indirect expansion) +for param in CAMERA_DURATION CAMERA_FRAMERATE CAMERA_GST_DEBUG GST_DEBUG_LEVEL; do + val="" + case "$param" in + CAMERA_DURATION) val="${CAMERA_DURATION-}" ;; + CAMERA_FRAMERATE) val="${CAMERA_FRAMERATE-}" ;; + CAMERA_GST_DEBUG) val="${CAMERA_GST_DEBUG-}" ;; + GST_DEBUG_LEVEL) val="${GST_DEBUG_LEVEL-}" ;; + esac + + if [ -n "$val" ]; then + case "$val" in + ''|*[!0-9]*) + log_warn "$param must be numeric (got '$val')" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + ;; + *) + if [ "$val" -le 0 ] 2>/dev/null; then + log_warn "$param must be positive (got '$val')" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + ;; + esac + fi +done + +# shellcheck disable=SC2317,SC2329 +cleanup() { + # Only kill gst-launch-1.0 processes that are children of this shell + # This prevents killing unrelated GStreamer pipelines running on the system + pkill -P "$$" -x gst-launch-1.0 >/dev/null 2>&1 || true +} +trap cleanup INT TERM EXIT + +# -------------------- Arg parse -------------------- +while [ $# -gt 0 ]; do + case "$1" in + --camera-id) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --camera-id" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + [ -n "$2" ] && cameraId="$2" + shift 2 + ;; + --plugin) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --plugin" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + if [ -n "$2" ]; then + case "$2" in + qtiqmmfsrc|libcamerasrc|auto) + cameraPlugin="$2" + ;; + *) + log_warn "Invalid --plugin '$2' (must be: qtiqmmfsrc, libcamerasrc, or auto)" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + ;; + esac + fi + shift 2 + ;; + --test-modes) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --test-modes" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + [ -n "$2" ] && testModeList="$2" + shift 2 + ;; + --formats) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --formats" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + [ -n "$2" ] && formatList="$2" + shift 2 + ;; + --resolutions) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --resolutions" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + [ -n "$2" ] && resolutionList="$2" + shift 2 + ;; + --framerate) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --framerate" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + if [ -n "$2" ]; then + case "$2" in + ''|*[!0-9]*) + log_warn "Invalid --framerate '$2' (must be numeric)" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + ;; + *) + if [ "$2" -le 0 ] 2>/dev/null; then + log_warn "Framerate must be positive (got '$2')" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + framerate="$2" + ;; + esac + fi + shift 2 + ;; + --duration) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --duration" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + if [ -n "$2" ]; then + case "$2" in + ''|*[!0-9]*) + log_warn "Invalid --duration '$2' (must be numeric)" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + ;; + *) + if [ "$2" -le 0 ] 2>/dev/null; then + log_warn "Duration must be positive (got '$2')" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + duration="$2" + ;; + esac + fi + shift 2 + ;; + --gst-debug) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --gst-debug" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + [ -n "$2" ] && gstDebugLevel="$2" + shift 2 + ;; + --lava-testcase-id) + if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then + log_warn "Missing/invalid value for --lava-testcase-id" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + [ -n "$2" ] && RESULT_TESTNAME="$2" + shift 2 + ;; + -h|--help) + cat < Camera device ID (default: 0) + Specify which camera to use if multiple cameras available + + --plugin Camera plugin to use (default: auto) + Options: qtiqmmfsrc, libcamerasrc, auto + auto - Auto-detect (prioritizes qtiqmmfsrc if both available) + qtiqmmfsrc - Use CAMX downstream camera (10 tests) + libcamerasrc - Use upstream camera (7 tests) + + --test-modes Test modes to run (default: fakesink,preview,encode) + Options: fakesink, preview, encode + Use comma-separated list to run specific modes + + --formats Formats to test (qtiqmmfsrc only, default: nv12,ubwc) + nv12 - Linear NV12 format (standard) + ubwc - UBWC compressed format (Qualcomm optimized) + Note: libcamerasrc only supports NV12 + + --resolutions Resolutions for tests (default: 720p,1080p,4k) + 720p - 1280x720 + 1080p - 1920x1080 + 4k - 3840x2160 + + --framerate Capture framerate in fps (default: 30) + Adjust based on camera capabilities + + --duration Test duration in seconds (default: 10) + Longer duration for stability testing + + --gst-debug GStreamer debug level 1-9 (default: 2) + Higher levels provide more detailed debug output + + -h, --help Display this help message + +ENVIRONMENT VARIABLES: + CAMERA_ID Same as --camera-id (qtiqmmfsrc only) + CAMERA_PLUGIN Same as --plugin + CAMERA_TEST_MODES Same as --test-modes + CAMERA_FORMATS Same as --formats (qtiqmmfsrc only) + CAMERA_RESOLUTIONS Same as --resolutions + CAMERA_FRAMERATE Same as --framerate + CAMERA_DURATION Same as --duration + CAMERA_GST_DEBUG Same as --gst-debug + +EXAMPLES: + # Run all tests with auto-detected camera plugin + $0 + + # Explicitly test qtiqmmfsrc (10 tests) + $0 --plugin qtiqmmfsrc + + # Explicitly test libcamerasrc (7 tests) + $0 --plugin libcamerasrc + + # Run only fakesink tests with qtiqmmfsrc + $0 --plugin qtiqmmfsrc --test-modes fakesink + + # Run only fakesink tests with libcamerasrc + $0 --plugin libcamerasrc --test-modes fakesink + + # Run libcamerasrc preview tests (2 tests) + $0 --plugin libcamerasrc --test-modes preview + + # Run libcamerasrc encode tests (3 tests) + $0 --plugin libcamerasrc --test-modes encode + + # qtiqmmfsrc: Run fakesink and encode tests (8 tests) + $0 --plugin qtiqmmfsrc --test-modes fakesink,encode + + # qtiqmmfsrc: Test only NV12 format (6 tests) + $0 --plugin qtiqmmfsrc --formats nv12 + + # qtiqmmfsrc: Test only UBWC format + $0 --plugin qtiqmmfsrc --formats ubwc + + # Test specific resolutions for encode tests + $0 --resolutions 720p,1080p + + # qtiqmmfsrc: Run encode tests with NV12 at 4K for 20 seconds + $0 --plugin qtiqmmfsrc --test-modes encode --formats nv12 --resolutions 4k --duration 20 + + # qtiqmmfsrc: Use camera 1 with custom framerate + $0 --plugin qtiqmmfsrc --camera-id 1 --framerate 60 + + # Using environment variables + export CAMERA_PLUGIN="qtiqmmfsrc" + export CAMERA_FORMATS="nv12" + export CAMERA_RESOLUTIONS="720p" + $0 + +TEST DETAILS: + + qtiqmmfsrc Tests (10): + Fakesink (2): + - fakesink_nv12 : NV12 format, 720p, no encoding + - fakesink_ubwc : UBWC format, 720p, no encoding + + Preview (2): + - preview_nv12_4k : NV12 format, 4K, Weston display + - preview_ubwc_4k : UBWC format, 4K, Weston display + + Encode (6): + - encode_nv12_720p : NV12, 1280x720, H.264 encode + - encode_nv12_1080p : NV12, 1920x1080, H.264 encode + - encode_nv12_4k : NV12, 3840x2160, H.264 encode + - encode_ubwc_720p : UBWC, 1280x720, H.264 encode + - encode_ubwc_1080p : UBWC, 1920x1080, H.264 encode + - encode_ubwc_4k : UBWC, 3840x2160, H.264 encode + + libcamerasrc Tests (7): + Fakesink (2): + - libcam_720p_Fakesink : 720p, no encoding + - libcam_1080p_Fakesink : 1080p, no encoding + + Preview (2): + - libcam_720p_Preview : 720p, Weston display + - libcam_1080p_Preview : 1080p, Weston display + + Encode (3): + - libcam_720p_NV12_Encode : NV12, 1280x720, H.264 encode + - libcam_1080p_NV12_Encode : NV12, 1920x1080, H.264 encode + - libcam_4k_NV12_Encode : NV12, 3840x2160, H.264 encode + +FORMAT DETAILS: + NV12 (Linear): + - Standard uncompressed YUV 4:2:0 format + - Higher memory bandwidth usage + - Universal hardware support + - Pipeline: qtiqmmfsrc ! video/x-raw,format=NV12 ! ... + + UBWC (Compressed): + - Qualcomm's Universal Bandwidth Compression + - Reduced memory bandwidth (optimized) + - Qualcomm-specific hardware support + - Pipeline: qtiqmmfsrc ! video/x-raw,format=NV12_Q08C ! ... + +OUTPUT: + Result File: Camera_Tests.res (PASS/FAIL/SKIP) + Logs: logs/Camera_Tests/*.log + Videos: logs/Camera_Tests/encoded/*.mp4 + GStreamer: logs/Camera_Tests/gst.log + Kernel Logs: logs/Camera_Tests/dmesg/ + +PREREQUISITES: + Required Tools: + - gst-launch-1.0 (GStreamer command-line tool) + - gst-inspect-1.0 (GStreamer plugin inspector) + + Required Plugins: + For qtiqmmfsrc (10 tests): + - qtiqmmfsrc (Qualcomm camera source) + - v4l2h264enc (V4L2 H.264 encoder, for encode) + - waylandsink (Wayland display, for preview) + + For libcamerasrc (7 tests): + - libcamerasrc (Upstream camera source) + - videoconvert (Video format converter, required) + - v4l2h264enc (V4L2 H.264 encoder, for encode) + - waylandsink (Wayland display, for preview) + + Hardware: + - Qualcomm camera hardware + - Weston display server (for preview tests) + - Write permissions to output directories + +SUCCESS CRITERIA: + Fakesink: Pipeline runs without errors, exit code 0 + Preview: Pipeline runs, video displays on screen, exit code 0 + Encode: Pipeline runs, MP4 file created (size > 1000 bytes) + +TROUBLESHOOTING: + Test Skipped: + - Check if required plugins are installed (gst-inspect-1.0 ) + - Verify camera hardware is connected + - Ensure Weston is running for preview tests + + Test Failed: + - Check logs in logs/Camera_Tests/ directory + - Review gst.log for GStreamer errors + - Check dmesg/ for kernel errors + - Verify camera permissions (ls -l /dev/video*) + +For detailed documentation, see README.md in this directory. + +EOF + exit 0 + ;; + *) shift ;; + esac +done + +# -------------------- Pre-checks -------------------- +# shellcheck disable=SC2034 +CHECK_DEPS_NO_EXIT=1 +if ! check_dependencies "gst-launch-1.0 gst-inspect-1.0"; then + log_skip "Missing required tools" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi +unset CHECK_DEPS_NO_EXIT + +log_info "Test: $TESTNAME" +log_info "Camera ID: $cameraId" +log_info "Test Modes: $testModeList" +log_info "Formats: $formatList" +log_info "Resolutions: $resolutionList" +log_info "Framerate: ${framerate}fps" +log_info "Duration: ${duration}s" + +# -------------------- Camera source detection -------------------- +log_info "==========================================" +log_info "CAMERA SOURCE DETECTION" +log_info "==========================================" + +qtiqmmfsrc_available=0 +libcamerasrc_available=0 + +# Check for qtiqmmfsrc (Qualcomm CAMX downstream camera) +if has_element qtiqmmfsrc; then + qtiqmmfsrc_available=1 + log_info "✓ qtiqmmfsrc detected - CAMX downstream camera available" +else + log_info "✗ qtiqmmfsrc not detected" +fi + +# Check for libcamerasrc (upstream camera) +if has_element libcamerasrc; then + libcamerasrc_available=1 + log_info "✓ libcamerasrc detected - Upstream camera available" +else + log_info "✗ libcamerasrc not detected" +fi + +# Determine which camera source to use based on --plugin argument or auto-detection +case "$cameraPlugin" in + qtiqmmfsrc) + if [ "$qtiqmmfsrc_available" -eq 1 ]; then + camera_source="qtiqmmfsrc" + log_info "Using qtiqmmfsrc (CAMX downstream camera) - explicitly requested" + log_info "Will run 10 qtiqmmfsrc tests: fakesink(2) + preview(2) + encode(6)" + else + log_skip "qtiqmmfsrc explicitly requested but not available" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + ;; + libcamerasrc) + if [ "$libcamerasrc_available" -eq 1 ]; then + camera_source="libcamerasrc" + log_info "Using libcamerasrc (upstream camera) - explicitly requested" + log_info "Will run 7 libcamerasrc tests: fakesink(2) + preview(2) + encode(3)" + else + log_skip "libcamerasrc explicitly requested but not available" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + ;; + auto|*) + # Auto-detection: Priority qtiqmmfsrc > libcamerasrc > skip if neither + if [ "$qtiqmmfsrc_available" -eq 1 ]; then + camera_source="qtiqmmfsrc" + log_info "Using qtiqmmfsrc (CAMX downstream camera) for tests" + if [ "$libcamerasrc_available" -eq 1 ]; then + log_info "Note: Both qtiqmmfsrc and libcamerasrc detected, prioritizing qtiqmmfsrc" + log_info "Use --plugin libcamerasrc to explicitly test libcamerasrc instead" + fi + log_info "Will run 10 qtiqmmfsrc tests: fakesink(2) + preview(2) + encode(6)" + elif [ "$libcamerasrc_available" -eq 1 ]; then + camera_source="libcamerasrc" + log_info "Using libcamerasrc (upstream camera) for tests" + log_info "Will run 7 libcamerasrc tests: fakesink(2) + preview(2) + encode(3)" + else + log_skip "No camera source plugin available (neither qtiqmmfsrc nor libcamerasrc detected)" + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 + fi + ;; +esac + +log_info "==========================================" + +# Function: Essential pre-flight checks +# Only checks that directly affect whether tests can run +camera_preflight_checks() { + log_info "==========================================" + log_info "CAMERA PRE-FLIGHT CHECKS" + log_info "==========================================" + + checks_passed=0 + checks_failed=0 + + # Check 1: GStreamer plugin validation (CRITICAL) + log_info "[1/2] GStreamer plugin validation..." + if has_element "$camera_source"; then + log_pass " ✓ GStreamer plugin available: $camera_source" + checks_passed=$((checks_passed + 1)) + else + log_fail " ✗ GStreamer plugin missing: $camera_source" + checks_failed=$((checks_failed + 1)) + fi + + # Check 2: Required encoder plugin (only if encode tests are requested) + if echo "$testModeList" | grep -q "encode"; then + log_info "[2/2] H.264 encoder plugin check..." + if has_element v4l2h264enc; then + log_pass " ✓ v4l2h264enc available" + checks_passed=$((checks_passed + 1)) + else + log_warn " ⚠ v4l2h264enc not available (encode tests will be skipped)" + fi + else + log_info "[2/2] H.264 encoder plugin check... skipped (encode tests not requested)" + checks_passed=$((checks_passed + 1)) + fi + + log_info "==========================================" + log_info "Pre-flight summary: $checks_passed passed, $checks_failed failed" + log_info "==========================================" + + if [ "$checks_failed" -gt 0 ]; then + return 1 + fi + + return 0 +} + +# Function: Enhanced failure diagnostics +diagnose_camera_failure() { + testname="$1" + log_file="$2" + + log_info "==========================================" + log_info "FAILURE DIAGNOSTICS: $testname" + log_info "==========================================" + + # Check for common GStreamer errors + if grep -qi "Could not open camera\|cannot open camera\|failed to open camera" "$log_file"; then + log_fail "Issue: Camera device not accessible" + log_info "Possible causes:" + log_info " - Camera hardware not connected" + log_info " - Insufficient permissions" + log_info " - Camera in use by another process" + log_info "" + log_info "Diagnostics:" + log_info " Video devices:" + # shellcheck disable=SC2012 + ls -l /dev/video* 2>&1 | head -5 | while IFS= read -r line; do + log_info " $line" + done + fi + + if grep -qi "not-negotiated\|negotiation failed\|could not negotiate" "$log_file"; then + log_fail "Issue: Format negotiation failed" + log_info "Possible causes:" + log_info " - Requested format/resolution not supported by camera" + log_info " - Pipeline element incompatibility" + log_info " - Missing caps filter or incorrect format string" + log_info "" + + # Show what was requested + if grep -q "video/x-raw" "$log_file"; then + requested=$(grep -o "video/x-raw[^!]*" "$log_file" | head -1) + log_info " Requested caps: $requested" + fi + fi + + if grep -qi "firmware" "$log_file"; then + log_fail "Issue: Firmware-related error detected" + + if command -v camx_find_icp_firmware >/dev/null 2>&1; then + icp_fw=$(camx_find_icp_firmware 2>/dev/null || echo "") + if [ -z "$icp_fw" ]; then + log_fail " ICP firmware not found" + log_info " Expected location: /lib/firmware/qcom/*/CAMERA_ICP*.{mbn,elf}" + else + log_info " ICP firmware present: $icp_fw" + log_info " Firmware may be corrupted or incompatible" + fi + fi + fi + + if grep -qi "device.*not.*found\|no such device" "$log_file"; then + log_fail "Issue: Device not found" + log_info "" + log_info "Hardware check:" + + # Check Device Tree camera nodes + if command -v camx_fdtdump_has_cam_nodes >/dev/null 2>&1; then + if camx_fdtdump_has_cam_nodes >/dev/null 2>&1; then + log_info " ✓ Camera nodes found in Device Tree" + else + log_fail " ✗ No camera nodes in Device Tree" + log_info " Hardware may not be properly configured" + fi + fi + + # Check video devices + # shellcheck disable=SC2012 + video_count=$(ls /dev/video* 2>/dev/null | wc -l) + if [ "$video_count" -eq 0 ]; then + log_fail " ✗ No /dev/video* devices found" + log_info " Camera driver may not be loaded" + else + log_info " ✓ Video devices present: $video_count" + fi + fi + + if grep -qi "timeout\|timed out" "$log_file"; then + log_fail "Issue: Operation timeout" + log_info "Possible causes:" + log_info " - Camera hardware not responding" + log_info " - Driver issue or hang" + log_info " - Insufficient system resources" + fi + + if grep -qi "permission denied\|access denied" "$log_file"; then + log_fail "Issue: Permission denied" + log_info "Solution: Add user to video group:" + log_info " sudo usermod -a -G video \$USER" + log_info " (logout and login required)" + fi + + # Check for UBWC-specific issues + if echo "$testname" | grep -q "ubwc" && grep -qi "format.*not.*supported" "$log_file"; then + log_fail "Issue: UBWC format not supported" + log_info "Verify pipeline includes: qtiqmmfsrc ! video/x-raw,format=NV12_Q08C" + fi + + # Check kernel logs for related errors + if [ -d "$DMESG_DIR" ] && [ -f "$DMESG_DIR/dmesg_errors.log" ]; then + if grep -qi "camera\|video\|v4l2" "$DMESG_DIR/dmesg_errors.log"; then + log_warn "Kernel errors detected (see dmesg_errors.log):" + grep -i "camera\|video\|v4l2" "$DMESG_DIR/dmesg_errors.log" | head -3 | while IFS= read -r line; do + log_info " $line" + done + fi + fi + + log_info "==========================================" +} + +# Run essential pre-flight checks +if ! camera_preflight_checks; then + log_fail "==========================================" + log_fail "CRITICAL: Pre-flight checks failed" + log_fail "==========================================" + log_fail "GStreamer plugin not available - cannot run tests" + log_fail "" + log_fail "Recommended actions:" + log_fail " 1. Check GStreamer plugin installation" + log_fail " 2. Verify camera hardware is connected" + log_fail " 3. Check camera driver is loaded" + log_fail "==========================================" + + echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" + exit 0 +fi + +# -------------------- GStreamer debug capture -------------------- +export GST_DEBUG_NO_COLOR=1 +export GST_DEBUG="$gstDebugLevel" +export GST_DEBUG_FILE="$GST_LOG" + +# -------------------- Test Functions -------------------- + +# Centralized camera test runner +# Handles common pattern: build pipeline -> log -> run -> validate -> diagnose -> update counters +# Parameters: +# $1: testname +# $2: pipeline +# $3: output_file (optional, for encode tests) +# $4: restart_cam_server (optional, "yes" to restart cam-server before test - qtiqmmfsrc only) +run_camera_test() { + testname="$1" + pipeline="$2" + output_file="${3:-}" + restart_cam_server="${4:-no}" + + log_info "=========================================="; log_info "Running: $testname"; log_info "==========================================" + + # Restart cam-server if requested (temporary workaround for qtiqmmfsrc only) + # libcamerasrc doesn't use cam-server, so this is skipped for libcamerasrc tests + if [ "$restart_cam_server" = "yes" ] && [ "$camera_source" = "qtiqmmfsrc" ]; then + log_info "Restarting cam-server..." + systemctl restart cam-server >/dev/null 2>&1 || log_warn "Failed to restart cam-server (may not be critical)" + sleep 1 + fi + + test_log="$OUTDIR/${testname}.log" + : >"$test_log" + + if [ -z "$pipeline" ]; then + log_warn "$testname: Failed to build pipeline"; skip_count=$((skip_count + 1)); return 1 + fi + + log_info "Pipeline: gst-launch-1.0 -e $pipeline" + + # Run pipeline with timeout + if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then gstRc=0; else gstRc=$?; fi + + # Validate log + if ! gstreamer_validate_log "$test_log" "$testname"; then + diagnose_camera_failure "$testname" "$test_log" + log_fail "$testname: FAIL"; fail_count=$((fail_count + 1)); return 1 + fi + + # Check for output file if encode test + if [ -n "$output_file" ]; then + if [ -f "$output_file" ] && [ -s "$output_file" ]; then + file_size=$(gstreamer_file_size_bytes "$output_file") + # Treat timeout (124) as success if file was created - test is designed to run until timeout + if [ "$file_size" -gt 1000 ] && { [ "$gstRc" -eq 0 ] || [ "$gstRc" -eq 124 ]; }; then + log_info "Output file size: $file_size bytes ($(awk "BEGIN {printf \"%.2f\", $file_size/1024/1024}") MB)" + log_pass "$testname: PASS"; pass_count=$((pass_count + 1)); return 0 + else + diagnose_camera_failure "$testname" "$test_log" + log_fail "$testname: FAIL (file too small or bad exit code)"; fail_count=$((fail_count + 1)); return 1 + fi + else + diagnose_camera_failure "$testname" "$test_log" + log_fail "$testname: FAIL (no output)"; fail_count=$((fail_count + 1)); return 1 + fi + else + # Non-encode test: treat timeout (124) as success + if [ "$gstRc" -eq 0 ] || [ "$gstRc" -eq 124 ]; then + log_pass "$testname: PASS"; pass_count=$((pass_count + 1)); return 0 + else + diagnose_camera_failure "$testname" "$test_log" + log_fail "$testname: FAIL (rc=$gstRc)"; fail_count=$((fail_count + 1)); return 1 + fi + fi +} + +# qtiqmmfsrc Fakesink test +run_qtiqmmf_fakesink_test() { + format="$1" + + case "$format" in + nv12) format_name="NV12" ;; + ubwc) format_name="UBWC" ;; + *) log_warn "Unknown format: $format"; skip_count=$((skip_count + 1)); return 1 ;; + esac + + testname="fakesink_${format}" + log_info "Format: $format_name" + + pipeline=$(camera_build_qtiqmmfsrc_fakesink_pipeline "$cameraId" "$format" 1280 720 "$framerate") + run_camera_test "$testname" "$pipeline" "" "yes" +} + +# qtiqmmfsrc Preview test +run_qtiqmmf_preview_test() { + format="$1" + + case "$format" in + nv12) format_name="NV12" ;; + ubwc) format_name="UBWC" ;; + *) log_warn "Unknown format: $format"; skip_count=$((skip_count + 1)); return 1 ;; + esac + + if ! has_element waylandsink; then + log_warn "waylandsink not available, skipping preview test" + skip_count=$((skip_count + 1)); return 1 + fi + + testname="preview_${format}_4k" + log_info "Format: $format_name" + + pipeline=$(camera_build_qtiqmmfsrc_preview_pipeline "$cameraId" "$format" 3840 2160 "$framerate") + run_camera_test "$testname" "$pipeline" "" "yes" +} + +# qtiqmmfsrc Encode test +run_qtiqmmf_encode_test() { + format="$1" + resolution="$2" + width="$3" + height="$4" + + case "$format" in + nv12) format_name="NV12" ;; + ubwc) format_name="UBWC" ;; + *) log_warn "Unknown format: $format"; skip_count=$((skip_count + 1)); return 1 ;; + esac + + if ! has_element v4l2h264enc; then + log_warn "v4l2h264enc not available, skipping encode test" + skip_count=$((skip_count + 1)); return 1 + fi + + testname="encode_${format}_${resolution}" + output_file="$ENCODED_DIR/${testname}.mp4" + + log_info "Format: $format_name" + log_info "Resolution: $resolution (${width}x${height})" + + pipeline=$(camera_build_qtiqmmfsrc_encode_pipeline "$cameraId" "$format" "$width" "$height" "$framerate" "$output_file") + run_camera_test "$testname" "$pipeline" "$output_file" "yes" +} + +# -------------------- libcamerasrc Test Functions -------------------- + +# Fakesink test (parameterized) +run_libcam_fakesink_test() { + width="$1" + height="$2" + + # Determine test name based on resolution + if [ "$width" -eq 0 ] 2>/dev/null || [ "$height" -eq 0 ] 2>/dev/null; then + testname="libcam_Default_Fakesink" + res_name="default" + else + testname="libcam_${width}x${height}_Fakesink" + res_name="${width}x${height}" + fi + + log_info "Resolution: $res_name" + + pipeline=$(camera_build_libcamera_fakesink_pipeline "$width" "$height" "$framerate") + run_camera_test "$testname" "$pipeline" +} + +# Preview test (parameterized) +run_libcam_preview_test() { + width="$1" + height="$2" + + if ! has_element waylandsink; then + log_warn "waylandsink not available, skipping libcam preview test" + skip_count=$((skip_count + 1)); return 1 + fi + + if ! has_element videoconvert; then + log_warn "videoconvert not available, skipping libcam preview test" + skip_count=$((skip_count + 1)); return 1 + fi + + # Determine test name based on resolution + if [ "$width" -eq 0 ] 2>/dev/null || [ "$height" -eq 0 ] 2>/dev/null; then + testname="libcam_Default_Preview" + res_name="default" + elif [ "$width" -eq 1280 ] && [ "$height" -eq 720 ]; then + testname="libcam_720p_Preview" + res_name="720p" + elif [ "$width" -eq 1920 ] && [ "$height" -eq 1080 ]; then + testname="libcam_1080p_Preview" + res_name="1080p" + else + testname="libcam_${width}x${height}_Preview" + res_name="${width}x${height}" + fi + + log_info "Resolution: $res_name" + + pipeline=$(camera_build_libcamera_preview_pipeline "$width" "$height" "$framerate") + run_camera_test "$testname" "$pipeline" +} + +# Encode test (parameterized) +run_libcam_encode_test() { + width="$1" + height="$2" + resolution_name="$3" + + if ! has_element v4l2h264enc; then + log_warn "v4l2h264enc not available, skipping libcam encode test" + skip_count=$((skip_count + 1)); return 1 + fi + + if ! has_element videoconvert; then + log_warn "videoconvert not available, skipping libcam encode test" + skip_count=$((skip_count + 1)); return 1 + fi + + testname="libcam_${resolution_name}_NV12_Encode" + output_file="$ENCODED_DIR/sample_${resolution_name}.mp4" + + log_info "Resolution: $resolution_name (${width}x${height})" + + pipeline=$(camera_build_libcamera_encode_pipeline "$width" "$height" "$output_file" "$framerate") + run_camera_test "$testname" "$pipeline" "$output_file" +} + +# -------------------- Main test execution -------------------- +if [ "$camera_source" = "libcamerasrc" ]; then + log_info "Starting libcamerasrc tests: fakesink -> preview -> encode" + + # Parse test modes and resolutions for libcamerasrc + test_modes=$(printf '%s' "$testModeList" | tr ',' ' ') + resolutions=$(printf '%s' "$resolutionList" | tr ',' ' ') + + # Wayland/Weston environment setup for libcamerasrc preview tests + log_info "==========================================" + log_info "LIBCAMERA - WAYLAND SETUP" + log_info "==========================================" + + wayland_ready=0 + camera_setup_wayland_environment "Libcamera_Tests" + + # Run tests based on test modes filter + for mode in $test_modes; do + case "$mode" in + fakesink) + log_info "==========================================" + log_info "LIBCAMERA FAKESINK TESTS" + log_info "==========================================" + + # Run fakesink tests based on resolution filter (only 720p and 1080p supported) + for res in $resolutions; do + case "$res" in + 720p) + total_tests=$((total_tests + 1)) + run_libcam_fakesink_test 1280 720 || true # 720p + ;; + 1080p) + total_tests=$((total_tests + 1)) + run_libcam_fakesink_test 1920 1080 || true # 1080p + ;; + default|4k|*) + # Only 720p and 1080p fakesink supported for libcamerasrc + total_tests=$((total_tests + 1)) + skip_count=$((skip_count + 1)) + log_warn "libcamerasrc fakesink: Resolution '$res' not supported (only 720p and 1080p are supported)" + ;; + esac + done + ;; + + preview) + # Preview tests - require Wayland + if [ "$wayland_ready" -eq 1 ]; then + log_info "==========================================" + log_info "LIBCAMERA PREVIEW TESTS" + log_info "==========================================" + + # Run preview tests based on resolution filter (only 720p and 1080p supported) + for res in $resolutions; do + case "$res" in + 720p) + total_tests=$((total_tests + 1)) + run_libcam_preview_test 1280 720 || true # 720p + ;; + 1080p) + total_tests=$((total_tests + 1)) + run_libcam_preview_test 1920 1080 || true # 1080p + ;; + default|4k|*) + # Only 720p and 1080p preview supported for libcamerasrc + total_tests=$((total_tests + 1)) + skip_count=$((skip_count + 1)) + log_warn "libcamerasrc preview: Resolution '$res' not supported (only 720p and 1080p are supported)" + ;; + esac + done + else + log_warn "Wayland/Weston not available, skipping libcamera preview tests" + log_warn "To run preview tests, ensure Weston is running or WAYLAND_DISPLAY is set" + # Count skipped tests based on resolutions (only 720p and 1080p) + for res in $resolutions; do + case "$res" in + 720p|1080p) + total_tests=$((total_tests + 1)) + skip_count=$((skip_count + 1)) + ;; + esac + done + fi + ;; + + encode) + log_info "==========================================" + log_info "LIBCAMERA ENCODE TESTS" + log_info "==========================================" + + # Run encode tests based on resolution filter + for res in $resolutions; do + case "$res" in + 720p) + total_tests=$((total_tests + 1)) + run_libcam_encode_test 1280 720 "720p" || true + ;; + 1080p) + total_tests=$((total_tests + 1)) + run_libcam_encode_test 1920 1080 "1080p" || true + ;; + 4k) + total_tests=$((total_tests + 1)) + run_libcam_encode_test 3840 2160 "4k" || true + ;; + *) + log_warn "Unknown resolution for encode: $res" + ;; + esac + done + ;; + + *) + log_warn "Unknown test mode for libcamerasrc: $mode" + ;; + esac + done + +else + # qtiqmmfsrc tests + log_info "Starting camera tests in sequence: fakesink -> preview -> encode" + + test_modes=$(printf '%s' "$testModeList" | tr ',' ' ') + formats=$(printf '%s' "$formatList" | tr ',' ' ') + resolutions=$(printf '%s' "$resolutionList" | tr ',' ' ') + + for mode in $test_modes; do + case "$mode" in + fakesink) + log_info "==========================================" + log_info "FAKESINK TESTS" + log_info "==========================================" + for format in $formats; do + total_tests=$((total_tests + 1)) + run_qtiqmmf_fakesink_test "$format" || true + done + ;; + preview) + log_info "==========================================" + log_info "PREVIEW TESTS - WAYLAND SETUP" + log_info "==========================================" + + # Wayland/Weston environment setup for preview tests + wayland_ready=0 + camera_setup_wayland_environment "Camera_Preview" + + # Run preview tests if Wayland is ready + if [ "$wayland_ready" -eq 1 ]; then + log_info "==========================================" + log_info "PREVIEW TESTS" + log_info "==========================================" + for format in $formats; do + total_tests=$((total_tests + 1)) + run_qtiqmmf_preview_test "$format" || true + done + else + log_warn "Wayland/Weston not available, skipping preview tests" + log_warn "To run preview tests, ensure Weston is running or WAYLAND_DISPLAY is set" + # Count skipped tests + for format in $formats; do + total_tests=$((total_tests + 1)) + skip_count=$((skip_count + 1)) + done + fi + ;; + encode) + log_info "==========================================" + log_info "ENCODE TESTS" + log_info "==========================================" + for format in $formats; do + for res in $resolutions; do + case "$res" in + 720p) width=1280; height=720 ;; + 1080p) width=1920; height=1080 ;; + 4k) width=3840; height=2160 ;; + *) log_warn "Unknown resolution: $res"; skip_count=$((skip_count + 1)); continue ;; + esac + total_tests=$((total_tests + 1)) + run_qtiqmmf_encode_test "$format" "$res" "$width" "$height" || true + done + done + ;; + *) + log_warn "Unknown test mode: $mode" + ;; + esac + done +fi + +# -------------------- Dmesg error scan -------------------- +log_info "==========================================" +log_info "DMESG ERROR SCAN" +log_info "==========================================" + +module_regex="camera|qmmf|venus|vcodec|v4l2|video|gstreamer|wayland" +exclude_regex="dummy regulator|supply [^ ]+ not found|using dummy regulator" + +if command -v scan_dmesg_errors >/dev/null 2>&1; then + scan_dmesg_errors "$DMESG_DIR" "$module_regex" "$exclude_regex" || true + if [ -s "$DMESG_DIR/dmesg_errors.log" ]; then + log_warn "dmesg scan found warnings or errors" + else + log_info "No relevant errors found in dmesg" + fi +fi + +# -------------------- Summary -------------------- +log_info "==========================================" +log_info "TEST SUMMARY" +log_info "==========================================" +log_info "Total testcases: $total_tests" +log_info "Passed: $pass_count" +log_info "Failed: $fail_count" +log_info "Skipped: $skip_count" + +# -------------------- Emit result -------------------- +if [ "$fail_count" -eq 0 ] && [ "$pass_count" -gt 0 ]; then + result="PASS" + reason="All tests passed ($pass_count/$total_tests)" +elif [ "$fail_count" -gt 0 ]; then + result="FAIL" + reason="Some tests failed (passed: $pass_count, failed: $fail_count, skipped: $skip_count)" +else + result="SKIP" + reason="No tests passed (skipped: $skip_count)" +fi + +case "$result" in + PASS) log_pass "$TESTNAME $result: $reason"; echo "$RESULT_TESTNAME PASS" >"$RES_FILE" ;; + FAIL) log_fail "$TESTNAME $result: $reason"; echo "$RESULT_TESTNAME FAIL" >"$RES_FILE" ;; + *) log_warn "$TESTNAME $result: $reason"; echo "$RESULT_TESTNAME SKIP" >"$RES_FILE" ;; +esac + +exit 0