diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md
index 2b9b5fe8f..8b1242688 100644
--- a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md
+++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/README.md
@@ -75,6 +75,191 @@ By default, the test runs the following test cases at 4K resolution for H.264/H.
---
+## Advanced Test Cases
+
+The test suite includes 9 advanced test cases that can be run using the `--test-type` parameter. These tests validate specific video features and scenarios.
+
+### Test Type: UVC Camera Preview
+
+**Test: UVC_Live_Preview_1080p (PR76474)**
+- **Description**: UVC camera live preview at 1080p@5fps with Wayland display output
+- **Requirements**: UVC camera device, Wayland compositor
+- **Pipeline**: `v4l2src → videoconvert → qtivtransform (optional) → waylandsink`
+- **Usage**: `./run.sh --test-type uvc --duration 30`
+- **Features**:
+ - Automatic UVC camera detection
+ - Wayland display setup (auto-starts Weston if needed)
+ - Optional rotation support via qtivtransform
+
+### Test Type: Dynamic Resolution Change (DRC)
+
+**Test: DRC_H264_Decode_1080p_720p (FR82787)**
+- **Description**: Validates dynamic resolution change during H.264 decode (1080p → 720p)
+- **Requirements**: Special DRC test clip, Wayland display, fpsdisplaysink
+- **Pipeline**: `filesrc → qtdemux → h264parse → v4l2h264dec → fpsdisplaysink → waylandsink`
+- **Usage**: `./run.sh --test-type drc --clip-path /path/to/clips`
+- **Test Clip**: `1080_720_h264.mp4` (automatically downloaded or copied from --clip-path)
+- **Features**:
+ - Monitors FPS and resolution changes during playback
+ - Validates seamless resolution transitions
+
+### Test Type: Concurrent Decode
+
+**Concurrency Tests (PR43865, PR43866, FR98277)**
+
+These tests validate concurrent decode sessions using qtivcomposer for multi-stream composition.
+
+**1. H264_Decode_Concurrency_16x480p (PR43865)**
+- **Description**: 16 concurrent H.264 480p@30fps decode sessions
+- **Requirements**: qtivcomposer, Wayland display
+- **Test Clip**: `H264_480p_30fps.mp4`
+- **Pipeline (per session)**: `filesrc → qtdemux → h264parse → v4l2h264dec → qtivcomposer → waylandsink`
+
+**2. H265_Decode_Concurrency_16x480p (PR43866)**
+- **Description**: 16 concurrent H.265 480p decode sessions
+- **Requirements**: qtivcomposer, Wayland display
+- **Test Clip**: `H265_480p_30fps.mp4`
+- **Pipeline (per session)**: `filesrc → qtdemux → h265parse → v4l2h265dec → qtivcomposer → waylandsink`
+
+**3. MJPEG_Decode_Concurrency_16x1080p (FR98277)**
+- **Description**: 16 concurrent MJPEG 1080p decode sessions
+- **Requirements**: jpegdec (software decoder), qtivcomposer, Wayland display
+- **Test Clip**: `mjpeg1.avi`
+- **Pipeline (per session)**: `filesrc → avidemux → jpegdec → qtivcomposer → waylandsink`
+
+**Usage**:
+```bash
+# Run all 3 concurrency tests with default 16 sessions
+./run.sh --test-type concurrency --clip-path /path/to/clips
+
+# Run with custom session count
+./run.sh --test-type concurrency --concurrency-sessions 16 --clip-path /path/to/clips
+```
+
+**Features**:
+- Configurable number of concurrent sessions (default: 16)
+- Background process management
+- Per-session log files
+- Aggregate error checking across all sessions
+
+### Test Type: Advanced Encoding (Downstream Only)
+
+**Advanced Encoding Tests (FR74943, FR82773, FR82771, FR72846)**
+
+These tests require downstream video driver (Config2) and Qualcomm camera source (qtiqmmfsrc).
+
+**1. HEVC_Encode_Smart_Bitrate_FPS_720p (FR74943)**
+- **Description**: HEVC 720p encode with smart FPS and bitrate adaptation using dual camera streams
+- **Requirements**: Downstream driver, qtiqmmfsrc, qtismartvencbin
+- **Pipeline**: `qtiqmmfsrc (dual streams: video + control) → qtismartvencbin (smart-fps=true, smart-bitrate=true, smart-gop=false) → h265parse → mp4mux → filesink`
+- **Features**:
+ - Adaptive FPS and bitrate control
+ - Dual camera streams (720p video + 480p control)
+ - Noise reduction (noise-reduction=2)
+ - Extra buffers (extra-buffers=20)
+ - Control sink for smart encoding decisions
+
+**2. HEVC_Encode_UHD_Cyclic_IR (FR82773)**
+- **Description**: HEVC UHD (3840x2160) encode with Cyclic Intra Refresh
+- **Requirements**: Downstream driver, qtiqmmfsrc, v4l2h265enc
+- **Pipeline**: `qtiqmmfsrc → v4l2h265enc (intra_refresh_period_type=1) → h265parse → mp4mux → filesink`
+- **Features**: Cyclic intra refresh mode for error resilience
+
+**3. H264_Encode_Slice_MB_VGA (FR82771)**
+- **Description**: H.264 VGA (640x480) encode with Slice MB mode
+- **Requirements**: Downstream driver, qtiqmmfsrc, v4l2h264enc
+- **Pipeline**: `qtiqmmfsrc → v4l2h264enc (slice_partitioning_method=1, number_of_mbs_in_a_slice=368) → h264parse → mp4mux → filesink`
+- **Features**: Macroblock-based slice partitioning
+
+**4. HEVC_Encode_4K_Rotate90 (FR72846)**
+- **Description**: HEVC 4K (3840x2160) encode with 90° VPU rotation
+- **Requirements**: qtiqmmfsrc, v4l2h265enc (rotate control requires downstream driver)
+- **Pipeline**: `qtiqmmfsrc → v4l2h265enc (rotate=90) → h265parse → mp4mux → filesink`
+- **Features**: Hardware-accelerated rotation during encoding
+
+**Usage**:
+```bash
+# Run all 4 advanced encoding tests (requires downstream driver + camera)
+./run.sh --test-type advanced-encode --stack downstream --duration 30
+```
+
+**Note**: These tests will automatically skip if:
+- Downstream video driver is not detected
+- Camera source (qtiqmmfsrc) is not available
+- Required encoder elements are missing
+
+---
+
+## Test Clip Requirements
+
+### Automatic Download
+
+Test clips are automatically downloaded from the configured URL (default: GitHub releases) or copied from a local path if provided via `--clip-path`.
+
+### Required Clips by Test Type
+
+| Test Type | Clips Required | Auto-Download |
+|-----------|----------------|---------------|
+| basic | VP9_640x480_10s.webm | ✅ Yes |
+| uvc | None (uses camera) | N/A |
+| drc | 1080_720_h264.mp4 | ✅ Yes |
+| concurrency | H264_480p_30fps.mp4
H265_480p_30fps.mp4
mjpeg1.avi | ✅ Yes |
+| advanced-encode | None (uses camera) | N/A |
+| all (default) | All clips above | ✅ Yes |
+
+### Clip Download Behavior
+
+1. **Check if clip exists** in output directory
+2. **Try local path** if `--clip-path` is provided
+3. **Download from URL** if not found locally
+4. **Skip test** if download fails (offline mode)
+
+### Manual Clip Provision
+
+If you have clips locally, provide the path:
+
+```bash
+./run.sh --test-type concurrency --clip-path /path/to/clips
+```
+
+The script will look for clips in the specified directory and copy them to the output directory.
+
+---
+
+## Advanced Test Examples
+
+### 1) Run UVC camera preview for 60 seconds
+
+```bash
+./run.sh --test-type uvc --duration 60
+```
+
+### 2) Run DRC test with local clips
+
+```bash
+./run.sh --test-type drc --clip-path /mnt/test_clips
+```
+
+### 3) Run concurrency tests with 8 sessions
+
+```bash
+./run.sh --test-type concurrency --concurrency-sessions 8
+```
+
+### 4) Run all advanced encoding tests (downstream only)
+
+```bash
+./run.sh --test-type advanced-encode --stack downstream
+```
+
+### 5) Run basic tests with custom settings
+
+```bash
+./run.sh --test-type basic --codecs h264,h265 --resolutions 480p,1080p --duration 10
+```
+
+---
+
## PASS / FAIL / SKIP criteria
### PASS
@@ -167,6 +352,14 @@ Help:
### Options
+- `--test-type `
+ - Default: `all` (run ALL tests - basic + uvc + drc + concurrency + advanced-encode)
+ - `basic`: Standard encode/decode tests only (H.264, H.265, VP9)
+ - `uvc`: UVC camera live preview test
+ - `drc`: Dynamic Resolution Change H.264 decode test
+ - `concurrency`: Concurrent decode tests (H.264, H.265, MJPEG)
+ - `advanced-encode`: Advanced encoding tests (downstream only)
+
- `--mode `
- Default: `all` (run both encode and decode tests)
- `encode`: Run only encoding tests
@@ -178,12 +371,27 @@ Help:
- Examples: `h264`, `h265`, `h264,h265`, `vp9`, `h264,vp9`
- Note: VP9 only supports decode (no encode)
-- `--resolutions <480p,4k>`
+- `--resolutions <480p,720p,1080p,4k>`
- Comma-separated list of resolutions to test
- - Default: `480p,4k`
+ - Default: `480p`
- Supported: `480p` (640x480), `720p` (1280x720), `1080p` (1920x1080), `4k` (3840x2160)
- Examples: `480p`, `4k`, `480p,1080p,4k`
+- `--concurrency-sessions `
+ - Number of concurrent sessions for concurrency tests
+ - Default: `16`
+ - Example: `--concurrency-sessions 8`
+
+- `--clip-path `
+ - Local path to test video files
+ - Overrides --clip-url if files exist
+ - Example: `--clip-path /opt` or `--clip-path /mnt/test_clips`
+
+- `--clip-url `
+ - URL to download test video files
+ - Default: GitHub release URL
+ - Example: `--clip-url https://example.com/clips.tar.gz`
+
- `--duration `
- Duration for encoding (in seconds)
- Default: `30`
@@ -222,84 +430,109 @@ Help:
## Examples
-### 1) Run all tests (default - encode + decode for H.264/H.265/VP9 at 4K for 30 seconds)
+### 1) Run all tests (default - ALL test types including basic, uvc, drc, concurrency, advanced-encode)
```bash
./run.sh
```
-**Note:** Default behavior runs H.264, H.265, and VP9 tests at 4K resolution with 30 second duration.
+**Note:** Default behavior (`--test-type all`) runs ALL 9+ tests:
+- Basic encode/decode tests (H.264, H.265, VP9) at 480p for 30 seconds
+- UVC camera preview (if camera available)
+- DRC H.264 decode (if clip available)
+- Concurrency tests: 16x H.264, 16x H.265, 16x MJPEG (if clips available)
+- Advanced encode tests (if downstream stack + camera available)
+
+Tests that require missing hardware or clips will be gracefully skipped.
-### 2) Run only encoding tests
+### 2) Run only basic encode/decode tests
```bash
-./run.sh --mode encode
+./run.sh --test-type basic
```
-### 3) Run only decoding tests (requires encoded files from previous run)
+### 3) Run only UVC camera test
```bash
-./run.sh --mode decode
+./run.sh --test-type uvc --duration 60
+```
+
+### 4) Run only concurrency tests
+
+```bash
+./run.sh --test-type concurrency --clip-path /opt
+```
+
+### 5) Run only advanced encoding tests (downstream only)
+
+```bash
+./run.sh --test-type advanced-encode --stack downstream
```
-### 4) Test only H.264 codec
+### 6) Run basic tests with specific codecs and resolutions
```bash
-./run.sh --codecs h264
+./run.sh --test-type basic --codecs h264,h265 --resolutions 480p,1080p
```
-### 5) Test only H.265 codec at 4K resolution
+### 7) Run only encoding tests
```bash
-./run.sh --codecs h265 --resolutions 4k
+./run.sh --mode encode
```
-### 6) Test all codecs at 480p only
+### 8) Run only decoding tests (requires encoded files from previous run)
```bash
-./run.sh --resolutions 480p
+./run.sh --mode decode
```
-### 7) Test with longer duration (10 seconds)
+### 9) Test only H.264 codec
+
+```bash
+./run.sh --test-type basic --codecs h264
+```
+
+### 10) Test with shorter duration (10 seconds)
```bash
./run.sh --duration 10
```
-### 8) Test with higher framerate (60fps)
+### 11) Test with higher framerate (60fps)
```bash
-./run.sh --framerate 60
+./run.sh --test-type basic --framerate 60
```
-### 9) Test multiple resolutions
+### 12) Test multiple resolutions
```bash
-./run.sh --resolutions 480p,720p,1080p,4k
+./run.sh --test-type basic --resolutions 480p,720p,1080p,4k
```
-### 10) Increase GStreamer debug verbosity
+### 13) Increase GStreamer debug verbosity
```bash
./run.sh --gst-debug 5
```
-### 11) Quick test - H.264 only at 480p with 3 second duration
+### 14) Quick test - H.264 only at 480p with 3 second duration
```bash
-./run.sh --codecs h264 --resolutions 480p --duration 3
+./run.sh --test-type basic --codecs h264 --resolutions 480p --duration 3
```
-### 12) Test VP9 decode only (requires network connectivity)
+### 15) Test VP9 decode only (requires network connectivity)
```bash
-./run.sh --codecs vp9 --mode decode
+./run.sh --test-type basic --codecs vp9 --mode decode
```
-### 13) Test all codecs including VP9
+### 16) Provide local test clips
```bash
-./run.sh --codecs h264,h265,vp9
+./run.sh --clip-path /opt
```
---
@@ -528,6 +761,89 @@ This test uses reusable helper functions from `lib_gstreamer.sh` that other GStr
gstreamer_run_gstlaunch_timeout 40 "$pipeline"
```
+#### 5. `gstreamer_build_uvc_preview_pipeline`
+
+Build pipeline for UVC camera live preview (used by UVC test).
+
+- **Parameters**:
+ - `device`: UVC device path (e.g., `/dev/video2`)
+ - `width`: Video width (default: 1920)
+ - `height`: Video height (default: 1080)
+ - `framerate`: Framerate (default: 5)
+- Returns: Complete pipeline string for UVC preview
+- Automatically includes `qtivtransform` if available
+- Example:
+ ```sh
+ uvc_dev=$(gstreamer_detect_uvc_camera)
+ pipeline=$(gstreamer_build_uvc_preview_pipeline "$uvc_dev" "1920" "1080" "5")
+ gstreamer_run_gstlaunch_timeout 30 "$pipeline"
+ ```
+
+#### 6. `gstreamer_build_drc_decode_pipeline`
+
+Build pipeline for Dynamic Resolution Change H.264 decode test.
+
+- **Parameters**:
+ - `clip_path`: Path to DRC test clip
+ - `video_stack`: `upstream` or `downstream`
+- Returns: Complete pipeline string with fpsdisplaysink wrapper
+- Example:
+ ```sh
+ pipeline=$(gstreamer_build_drc_decode_pipeline "/tmp/drc_clip.mp4" "downstream")
+ gstreamer_run_gstlaunch_timeout 60 "$pipeline"
+ ```
+
+#### 7. `gstreamer_build_concurrency_decode_pipeline`
+
+Build pipeline for concurrent decode tests with qtivcomposer (4x4 grid).
+
+- **Parameters**:
+ - `codec`: `h264`, `h265`, or `mjpeg`
+ - `clip_path`: Path to test clip
+ - `sessions`: Number of concurrent sessions (default: 16)
+- Returns: Complete pipeline string with 4x4 grid layout
+- Automatically handles codec-specific decode chains
+- Example:
+ ```sh
+ pipeline=$(gstreamer_build_concurrency_decode_pipeline \
+ "h264" "/tmp/test.mp4" "16")
+ gstreamer_run_gstlaunch_timeout 40 "$pipeline"
+ ```
+
+#### 8. `gstreamer_build_smart_encode_pipeline`
+
+Build pipeline for HEVC Smart Encode with dual camera streams.
+
+- **Parameters**:
+ - `output_file`: Output file path
+- Returns: Complete pipeline string with qtismartvencbin
+- Requires: qtiqmmfsrc, qtismartvencbin (downstream only)
+- Example:
+ ```sh
+ pipeline=$(gstreamer_build_smart_encode_pipeline "/tmp/output.mp4")
+ gstreamer_run_gstlaunch_timeout 40 "$pipeline"
+ ```
+
+#### 9. `gstreamer_build_camera_encode_pipeline`
+
+Build pipeline for camera-based encoding with custom controls.
+
+- **Parameters**:
+ - `codec`: `h264` or `h265`
+ - `width`: Video width
+ - `height`: Video height
+ - `output_file`: Output file path
+ - `extra_controls`: Custom encoder controls string (optional)
+ - `video_stack`: `upstream` or `downstream`
+- Returns: Complete pipeline string with qtiqmmfsrc
+- Example:
+ ```sh
+ controls="controls,video_bitrate=8000000,intra_refresh_period_type=1"
+ pipeline=$(gstreamer_build_camera_encode_pipeline \
+ "h265" "3840" "2160" "/tmp/output.mp4" "$controls" "downstream")
+ gstreamer_run_gstlaunch_timeout 40 "$pipeline"
+ ```
+
### Usage in Other Tests
To use these functions in your GStreamer test:
@@ -582,16 +898,19 @@ This will output example pipelines for various codecs, resolutions, and video st
The test supports these environment variables (can be set in LAVA job definition):
+- `VIDEO_TEST_TYPE` - Test type (all/basic/uvc/drc/concurrency/advanced-encode) (default: all)
- `VIDEO_TEST_MODE` - Test mode (all/encode/decode) (default: all)
- `VIDEO_CODECS` - Comma-separated codec list (default: `h264,h265,vp9`)
-- `VIDEO_RESOLUTIONS` - Comma-separated resolution list (default: `4k`)
+- `VIDEO_RESOLUTIONS` - Comma-separated resolution list (default: `480p`)
- `VIDEO_DURATION` - Encoding duration in seconds (default: 30)
- `RUNTIMESEC` - Alternative to VIDEO_DURATION
- `VIDEO_FRAMERATE` - Video framerate (default: 30)
- `VIDEO_STACK` - Video stack selection (auto/upstream/downstream) (default: auto)
- `VIDEO_GST_DEBUG` - GStreamer debug level (default: 2)
- `GST_DEBUG_LEVEL` - Alternative to VIDEO_GST_DEBUG
-- `VIDEO_CLIP_URL` - URL for VP9 clip download (default: GitHub releases)
+- `VIDEO_CLIP_URL` - URL for test clip download (default: GitHub releases)
+- `VIDEO_CLIP_PATH` - Local path to test clips (overrides VIDEO_CLIP_URL)
+- `VIDEO_CONCURRENCY_SESSIONS` - Number of concurrent sessions (default: 16)
- `LAVA_TESTCASE_ID` - Override test case name for LAVA reporting (default: Video_Encode_Decode)
**Priority order for duration**: `VIDEO_DURATION` > `RUNTIMESEC` > default (30)
diff --git a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh
index a0e556ee8..dd77b3f66 100755
--- a/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh
+++ b/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/run.sh
@@ -51,6 +51,9 @@ fi
# shellcheck disable=SC1091
[ -f "$TOOLS/lib_video.sh" ] && . "$TOOLS/lib_video.sh"
+# shellcheck disable=SC1091
+[ -f "$TOOLS/lib_display.sh" ] && . "$TOOLS/lib_display.sh"
+
# Use the shared encoded directory if supported; otherwise default to $OUTDIR/encoded.
if command -v gstreamer_shared_encoded_dir >/dev/null 2>&1; then
ENCODED_DIR="$(gstreamer_shared_encoded_dir "$SCRIPT_DIR" "$OUTDIR")"
@@ -79,6 +82,7 @@ total_tests=0
# -------------------- Defaults (LAVA env vars -> defaults; CLI overrides) --------------------
testMode="${VIDEO_TEST_MODE:-all}"
+testType="${VIDEO_TEST_TYPE:-all}"
codecList="${VIDEO_CODECS:-h264,h265,vp9}"
resolutionList="${VIDEO_RESOLUTIONS:-480p}"
duration="${VIDEO_DURATION:-${RUNTIMESEC:-30}}"
@@ -87,6 +91,7 @@ gstDebugLevel="${VIDEO_GST_DEBUG:-${GST_DEBUG_LEVEL:-2}}"
videoStack="${VIDEO_STACK:-auto}"
clipUrl="${VIDEO_CLIP_URL:-https://github.com/qualcomm-linux/qcom-linux-testkit/releases/download/GST-Video-Files-v1.0/video_clips_gst.tar.gz}"
clipPath="${VIDEO_CLIP_PATH:-}"
+concurrencySessions="${VIDEO_CONCURRENCY_SESSIONS:-16}"
# Validate environment variables if set
# Validate numeric parameters (POSIX-safe; no indirect expansion)
@@ -141,6 +146,37 @@ while [ $# -gt 0 ]; do
shift 2
;;
+ --test-type)
+ if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then
+ log_warn "Missing/invalid value for --test-type"
+ echo "$RESULT_TESTNAME SKIP" >"$RES_FILE"
+ exit 0
+ fi
+ [ -n "$2" ] && testType="$2"
+ shift 2
+ ;;
+
+ --concurrency-sessions)
+ if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then
+ log_warn "Missing/invalid value for --concurrency-sessions"
+ echo "$RESULT_TESTNAME SKIP" >"$RES_FILE"
+ exit 0
+ fi
+ if [ -n "$2" ]; then
+ case "$2" in
+ ''|*[!0-9]*)
+ log_warn "Invalid --concurrency-sessions '$2' (must be numeric)"
+ echo "$RESULT_TESTNAME SKIP" >"$RES_FILE"
+ exit 0
+ ;;
+ *)
+ concurrencySessions="$2"
+ ;;
+ esac
+ fi
+ shift 2
+ ;;
+
--codecs)
if [ $# -lt 2 ] || [ "${2#--}" != "$2" ]; then
log_warn "Missing/invalid value for --codecs"
@@ -275,6 +311,26 @@ OPTIONS:
- encode: Run only encoding tests
- decode: Run only decoding tests
+ --test-type
+ Test type (default: all)
+ - all: Run ALL tests (basic + uvc + drc + concurrency + advanced-encode)
+ - basic: Standard encode/decode tests only (H.264, H.265, VP9)
+ - uvc: UVC camera live preview at 1080p@5fps (PR76474)
+ - drc: Dynamic Resolution Change H.264 decode (FR82787)
+ - concurrency: Concurrent decode tests (PR43865, PR43866, FR98277)
+ * 16x H.264 480p decode sessions
+ * 16x H.265 1080p decode sessions
+ * 16x MJPEG 1080p decode sessions
+ - advanced-encode: Advanced encoding tests (downstream only)
+ * HEVC Smart encode 720p (FR74943)
+ * HEVC UHD Cyclic IR (FR82773)
+ * H.264 VGA Slice MB (FR82771)
+ * HEVC 4K Rotate 90° (FR72846)
+
+ --concurrency-sessions
+ Number of concurrent sessions for concurrency tests
+ (default: 16)
+
--codecs
Comma-separated list of codecs to test
(default: h264,h265,vp9)
@@ -303,6 +359,7 @@ OPTIONS:
--clip-path Local path to test video files
(overrides --clip-url if files exist)
+ Example: --clip-path /opt
--lava-testcase-id
Override the test case name reported to LAVA
@@ -311,6 +368,35 @@ OPTIONS:
-h, --help Display this help message
+FILE LOCATIONS:
+ Test clips and logs are stored in:
+ $SCRIPT_DIR/logs/Video_Encode_Decode/
+
+ On device, this typically resolves to:
+ /var/Runner/suites/Multimedia/GSTreamer/Video/Video_Encode_Decode/logs/Video_Encode_Decode/
+
+ Downloaded/copied clips:
+ - VP9_640x480_10s.webm
+ - H264_480p_30fps.mp4
+ - H265_480p_30fps.mp4
+ - mjpeg1.avi
+ - 1080_720_h264.mp4
+
+ Encoded files:
+ logs/Video_Encode_Decode/encoded/
+ - encode_h264_480p.mp4
+ - encode_h265_480p.mp4
+ - (etc.)
+
+ Log files:
+ - gst.log (GStreamer debug output)
+ - encode_*.log (individual test logs)
+ - decode_*.log
+ - UVC_*.log
+ - DRC_*.log
+ - H264_Decode_Concurrency_*.log
+ - (etc.)
+
ENVIRONMENT VARIABLES:
VIDEO_TEST_MODE Same as --mode
VIDEO_CODECS Same as --codecs
@@ -361,6 +447,13 @@ case "$testMode" in all|encode|decode) : ;; *)
;;
esac
+case "$testType" in basic|uvc|drc|concurrency|advanced-encode|all) : ;; *)
+ log_warn "Invalid --test-type '$testType' (allowed: basic, uvc, drc, concurrency, advanced-encode, all)"
+ echo "$RESULT_TESTNAME SKIP" >"$RES_FILE"
+ exit 0
+ ;;
+esac
+
case "$gstDebugLevel" in 1|2|3|4|5|6|7|8|9) : ;; *)
log_warn "Invalid --gst-debug '$gstDebugLevel' (allowed: 1-9)"
echo "$RESULT_TESTNAME SKIP" >"$RES_FILE"
@@ -597,63 +690,993 @@ run_decode_test() {
fi
}
-# -------------------- Main test execution --------------------
-log_info "Starting video encode/decode tests..."
-
-# Parse codec list
-codecs=$(printf '%s' "$codecList" | tr ',' ' ')
-
-# Parse resolution list
-resolutions=$(printf '%s' "$resolutionList" | tr ',' ' ')
+# -------------------- Helper: Check display connection --------------------
+check_display_connected() {
+ # Check if a physical display is connected
+ # Returns 0 if display is confirmed connected, 1 otherwise
+ if ! command -v display_connected_summary >/dev/null 2>&1; then
+ log_warn "display_connected_summary not available, cannot verify display connection"
+ return 1
+ fi
+
+ display_status=$(display_connected_summary)
+ if [ "$display_status" = "none" ] || [ -z "$display_status" ]; then
+ log_warn "No display connected (status: ${display_status:-empty})"
+ return 1
+ fi
+
+ log_info "Display connected: $display_status"
+ return 0
+}
-# -------------------- VP9 clip prep --------------------
-need_vp9_clip=0
-for codec in $codecs; do
- if [ "$codec" = "vp9" ]; then
- need_vp9_clip=1
- break
+# -------------------- UVC Live Preview Test --------------------
+# Test: UVC_Live_Preview_1080p (PR76474)
+run_uvc_preview_test() {
+ testname="UVC_Live_Preview_1080p"
+ log_info "=========================================="
+ log_info "Running: $testname (PR76474)"
+ log_info "=========================================="
+
+ total_tests=$((total_tests + 1))
+
+ # Check for required elements first (fast checks)
+ if ! has_element v4l2src; then
+ log_skip "$testname: v4l2src not available"
+ skip_count=$((skip_count + 1))
+ return 1
fi
-done
+
+ if ! has_element waylandsink; then
+ log_skip "$testname: waylandsink not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Detect UVC camera
+ uvc_dev=$(gstreamer_detect_uvc_camera)
+ if [ -z "$uvc_dev" ]; then
+ log_skip "$testname: No UVC camera detected"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ log_info "UVC camera detected: $uvc_dev"
+
+ # Check if display is connected (required for waylandsink)
+ if ! check_display_connected; then
+ log_skip "$testname: No display connected (required for waylandsink)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Set up Wayland display using shared function
+ if ! camera_setup_wayland_environment "uvc-preview"; then
+ log_skip "$testname: Failed to set up Wayland environment"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ test_log="$OUTDIR/${testname}.log"
+ : >"$test_log"
+
+ # Build pipeline using library function
+ pipeline=$(gstreamer_build_uvc_preview_pipeline "$uvc_dev" "1920" "1080" "5")
+
+ if [ -z "$pipeline" ]; then
+ log_fail "$testname: FAIL (could not build pipeline)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ log_info "Pipeline: $pipeline"
+
+ # Run for specified duration (default 30s)
+ if gstreamer_run_gstlaunch_timeout "$duration" "$pipeline" >>"$test_log" 2>&1; then
+ gstRc=0
+ else
+ gstRc=$?
+ fi
+
+ log_info "Exit code: $gstRc"
+
+ # Validate log
+ if ! gstreamer_validate_log "$test_log" "$testname"; then
+ log_fail "$testname: FAIL (GStreamer errors detected)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ if [ "$gstRc" -eq 0 ] || [ "$gstRc" -eq 124 ]; then
+ log_pass "$testname: PASS"
+ pass_count=$((pass_count + 1))
+ return 0
+ else
+ log_fail "$testname: FAIL (rc=$gstRc)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+}
-if [ "$need_vp9_clip" -eq 1 ] && [ "$testMode" != "encode" ]; then
+# -------------------- DRC H.264 Decode Test --------------------
+# Test: DRC_H264_Decode_1080p_UHD_1080p (FR82787)
+run_drc_decode_test() {
+ testname="DRC_H264_Decode_1080p_UHD_1080p"
log_info "=========================================="
- log_info "VP9 CLIP PREP"
+ log_info "Running: $testname (FR82787)"
log_info "=========================================="
- vp9_clip_webm="$OUTDIR/VP9_640x480_10s.webm"
+ total_tests=$((total_tests + 1))
+
+ # Check for required elements first (fast checks)
+ if ! has_element v4l2h264dec; then
+ log_skip "$testname: v4l2h264dec not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element fpsdisplaysink; then
+ log_skip "$testname: fpsdisplaysink not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element waylandsink; then
+ log_skip "$testname: waylandsink not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Check for DRC test clip
+ drc_clip="$OUTDIR/1080_720_h264.mp4"
+ if [ ! -f "$drc_clip" ]; then
+ if [ -n "$clipPath" ] && [ -f "$clipPath/1080_720_h264.mp4" ]; then
+ cp "$clipPath/1080_720_h264.mp4" "$drc_clip"
+ else
+ log_skip "$testname: DRC test clip not found (1080_720_h264.mp4)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+ fi
+
+ # Check if display is connected (required for waylandsink)
+ if ! check_display_connected; then
+ log_skip "$testname: No display connected (required for waylandsink)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Set up Wayland display using shared function
+ if ! camera_setup_wayland_environment "drc-test"; then
+ log_skip "$testname: Failed to set up Wayland environment"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ test_log="$OUTDIR/${testname}.log"
+ : >"$test_log"
+
+ # Build pipeline using library function
+ pipeline=$(gstreamer_build_drc_decode_pipeline "$drc_clip" "$detected_stack")
+
+ if [ -z "$pipeline" ]; then
+ log_fail "$testname: FAIL (could not build pipeline)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ log_info "Pipeline: $pipeline"
- # Check if WebM file already exists
- if [ -f "$vp9_clip_webm" ]; then
- log_info "VP9 WebM clip already exists: $vp9_clip_webm"
+ # Run for duration or until clip ends
+ if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then
+ gstRc=0
else
- # Try to get WebM file from provided path or URL
- if [ -n "$clipPath" ]; then
- log_info "Attempting to get VP9 WebM clip from local path: $clipPath"
- if [ -f "$clipPath/VP9_640x480_10s.webm" ]; then
- cp "$clipPath/VP9_640x480_10s.webm" "$vp9_clip_webm"
- log_info "VP9 WebM clip copied from local path"
- else
- log_warn "VP9 WebM clip not found in local path: $clipPath"
- fi
+ gstRc=$?
+ fi
+
+ log_info "Exit code: $gstRc"
+
+ # Validate log
+ if ! gstreamer_validate_log "$test_log" "$testname"; then
+ log_fail "$testname: FAIL (GStreamer errors detected)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ if [ "$gstRc" -eq 0 ] || [ "$gstRc" -eq 124 ]; then
+ log_pass "$testname: PASS"
+ pass_count=$((pass_count + 1))
+ return 0
+ else
+ log_fail "$testname: FAIL (rc=$gstRc)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+}
+
+# -------------------- H.264 Concurrency Decode Test --------------------
+# Test: H264_Decode_Concurrency_16x480p (PR43865)
+run_h264_concurrency_test() {
+ testname="H264_Decode_Concurrency_16x480p"
+ log_info "=========================================="
+ log_info "Running: $testname (PR43865)"
+ log_info "=========================================="
+
+ total_tests=$((total_tests + 1))
+
+ # Check for required elements first (fast checks)
+ if ! has_element v4l2h264dec; then
+ log_skip "$testname: v4l2h264dec not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element qtivcomposer; then
+ log_skip "$testname: qtivcomposer not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element waylandsink; then
+ log_skip "$testname: waylandsink not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Check for test clip
+ h264_clip="$OUTDIR/H264_480p_30fps.mp4"
+ if [ ! -f "$h264_clip" ]; then
+ if [ -n "$clipPath" ] && [ -f "$clipPath/H264_480p_30fps.mp4" ]; then
+ cp "$clipPath/H264_480p_30fps.mp4" "$h264_clip"
+ else
+ log_skip "$testname: Test clip not found (H264_480p_30fps.mp4)"
+ skip_count=$((skip_count + 1))
+ return 1
fi
+ fi
+
+ # Set up Wayland display using shared function
+ if ! camera_setup_wayland_environment "h264-concurrency"; then
+ log_skip "$testname: Failed to set up Wayland environment"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ test_log="$OUTDIR/${testname}.log"
+ : >"$test_log"
+
+ log_info "Building single pipeline with $concurrencySessions concurrent H.264 decode sessions..."
+
+ # Increase file descriptor limit
+ ulimit -n 4096 2>/dev/null || true
+
+ # Build pipeline using library function
+ pipeline=$(gstreamer_build_concurrency_decode_pipeline "h264" "$h264_clip" "$concurrencySessions")
+
+ if [ -z "$pipeline" ]; then
+ log_fail "$testname: FAIL (could not build pipeline)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ log_info "Pipeline: gst-launch-1.0 -e $pipeline"
+
+ # Run single pipeline with all 16 sessions
+ if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then
+ gstRc=0
+ else
+ gstRc=$?
+ fi
+
+ log_info "Exit code: $gstRc"
+
+ # Validate log
+ if ! gstreamer_validate_log "$test_log" "$testname"; then
+ log_fail "$testname: FAIL (GStreamer errors detected)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ if [ "$gstRc" -eq 0 ] || [ "$gstRc" -eq 124 ]; then
+ log_pass "$testname: PASS (all $concurrencySessions sessions in single pipeline)"
+ pass_count=$((pass_count + 1))
+ return 0
+ else
+ log_fail "$testname: FAIL (rc=$gstRc)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+}
- # If not found locally, try URL download
- if [ ! -f "$vp9_clip_webm" ]; then
- log_info "VP9 WebM clip not found locally; attempting download from URL..."
- if extract_tar_from_url "$clipUrl" "$OUTDIR"; then
- # Move the extracted file from current directory to OUTDIR
- if [ -f "VP9_640x480_10s.webm" ]; then
- mv "VP9_640x480_10s.webm" "$vp9_clip_webm"
- log_pass "VP9 WebM clip downloaded and moved successfully"
- else
- log_warn "VP9 WebM clip not found in downloaded content"
- fi
- else
- log_warn "VP9 WebM clip download failed (offline or URL issue)"
- fi
+# -------------------- H.265 Concurrency Decode Test --------------------
+# Test: H265_Decode_Concurrency_16x1080p (PR43866)
+run_h265_concurrency_test() {
+ testname="H265_Decode_Concurrency_16x1080p"
+ log_info "=========================================="
+ log_info "Running: $testname (PR43866)"
+ log_info "=========================================="
+
+ total_tests=$((total_tests + 1))
+
+ # Check for required elements first (fast checks)
+ if ! has_element v4l2h265dec; then
+ log_skip "$testname: v4l2h265dec not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element qtivcomposer; then
+ log_skip "$testname: qtivcomposer not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element waylandsink; then
+ log_skip "$testname: waylandsink not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Check for test clip
+ h265_clip="$OUTDIR/H265_480p_30fps.mp4"
+ if [ ! -f "$h265_clip" ]; then
+ if [ -n "$clipPath" ] && [ -f "$clipPath/H265_480p_30fps.mp4" ]; then
+ cp "$clipPath/H265_480p_30fps.mp4" "$h265_clip"
+ else
+ log_skip "$testname: Test clip not found (H265_480p_30fps.mp4)"
+ skip_count=$((skip_count + 1))
+ return 1
fi
fi
-fi
+
+ # Check if display is connected (required for waylandsink)
+ if ! check_display_connected; then
+ log_skip "$testname: No display connected (required for waylandsink)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Set up Wayland display using shared function
+ if ! camera_setup_wayland_environment "h265-concurrency"; then
+ log_skip "$testname: Failed to set up Wayland environment"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ test_log="$OUTDIR/${testname}.log"
+ : >"$test_log"
+
+ log_info "Building single pipeline with $concurrencySessions concurrent H.265 decode sessions..."
+
+ # Increase file descriptor limit
+ ulimit -n 4096 2>/dev/null || true
+
+ # Build pipeline using library function
+ pipeline=$(gstreamer_build_concurrency_decode_pipeline "h265" "$h265_clip" "$concurrencySessions")
+
+ if [ -z "$pipeline" ]; then
+ log_fail "$testname: FAIL (could not build pipeline)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ log_info "Pipeline: gst-launch-1.0 -e $pipeline"
+
+ # Run single pipeline with all 16 sessions
+ if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then
+ gstRc=0
+ else
+ gstRc=$?
+ fi
+
+ log_info "Exit code: $gstRc"
+
+ # Validate log
+ if ! gstreamer_validate_log "$test_log" "$testname"; then
+ log_fail "$testname: FAIL (GStreamer errors detected)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ if [ "$gstRc" -eq 0 ] || [ "$gstRc" -eq 124 ]; then
+ log_pass "$testname: PASS (all $concurrencySessions sessions in single pipeline)"
+ pass_count=$((pass_count + 1))
+ return 0
+ else
+ log_fail "$testname: FAIL (rc=$gstRc)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+}
+
+# -------------------- MJPEG Concurrency Decode Test --------------------
+# Test: MJPEG_Decode_Concurrency_16x1080p (FR98277)
+run_mjpeg_concurrency_test() {
+ testname="MJPEG_Decode_Concurrency_16x1080p"
+ log_info "=========================================="
+ log_info "Running: $testname (FR98277)"
+ log_info "=========================================="
+
+ total_tests=$((total_tests + 1))
+
+ # Check for required elements first (fast checks)
+ if ! has_element jpegdec; then
+ log_skip "$testname: jpegdec not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element qtivcomposer; then
+ log_skip "$testname: qtivcomposer not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element waylandsink; then
+ log_skip "$testname: waylandsink not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Check for test clip
+ mjpeg_clip="$OUTDIR/mjpeg1.avi"
+ if [ ! -f "$mjpeg_clip" ]; then
+ if [ -n "$clipPath" ] && [ -f "$clipPath/mjpeg1.avi" ]; then
+ cp "$clipPath/mjpeg1.avi" "$mjpeg_clip"
+ else
+ log_skip "$testname: Test clip not found (mjpeg1.avi)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+ fi
+
+ # Check if display is connected (required for waylandsink)
+ if ! check_display_connected; then
+ log_skip "$testname: No display connected (required for waylandsink)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Set up Wayland display using shared function
+ if ! camera_setup_wayland_environment "mjpeg-concurrency"; then
+ log_skip "$testname: Failed to set up Wayland environment"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ test_log="$OUTDIR/${testname}.log"
+ : >"$test_log"
+
+ log_info "Building single pipeline with $concurrencySessions concurrent MJPEG decode sessions..."
+
+ # Build pipeline using library function
+ pipeline=$(gstreamer_build_concurrency_decode_pipeline "mjpeg" "$mjpeg_clip" "$concurrencySessions")
+
+ if [ -z "$pipeline" ]; then
+ log_fail "$testname: FAIL (could not build pipeline)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ log_info "Pipeline: gst-launch-1.0 -e $pipeline"
+
+ # Run single pipeline with all 16 sessions
+ if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then
+ gstRc=0
+ else
+ gstRc=$?
+ fi
+
+ log_info "Exit code: $gstRc"
+
+ # Validate log
+ if ! gstreamer_validate_log "$test_log" "$testname"; then
+ log_fail "$testname: FAIL (GStreamer errors detected)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ if [ "$gstRc" -eq 0 ] || [ "$gstRc" -eq 124 ]; then
+ log_pass "$testname: PASS (all $concurrencySessions sessions in single pipeline)"
+ pass_count=$((pass_count + 1))
+ return 0
+ else
+ log_fail "$testname: FAIL (rc=$gstRc)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+}
+
+# -------------------- HEVC Smart Encode Test --------------------
+# Test: HEVC_Encode_Smart_Bitrate_FPS_720p (FR74943) - Downstream only
+run_smart_encode_test() {
+ testname="HEVC_Encode_Smart_Bitrate_FPS_720p"
+ log_info "=========================================="
+ log_info "Running: $testname (FR74943)"
+ log_info "=========================================="
+
+ total_tests=$((total_tests + 1))
+
+ # Check if downstream stack
+ if ! gstreamer_is_downstream_stack; then
+ log_skip "$testname: Requires downstream video driver (Config2)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Check for required elements
+ if ! has_element qtiqmmfsrc; then
+ log_skip "$testname: qtiqmmfsrc not available (camera source required)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element qtismartvencbin; then
+ log_skip "$testname: qtismartvencbin not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ test_log="$OUTDIR/${testname}.log"
+ output_file="$ENCODED_DIR/${testname}.mp4"
+ : >"$test_log"
+
+ # Build pipeline matching production command with control sink
+ # Production: qtiqmmfsrc camera=0 noise-reduction=2 video_0::extra-buffers=20 video_0::type=preview name=camsrc
+ # video_0::type=video ! video/x-raw,format=NV12,width=1280,height=720,framerate=30/1 ! queue ! scb.sink
+ # qtismartvencbin default-gop=30 max-gop=600 smart-framerate=true smart-gop=false max-bitrate=4200000 name=scb encoder=v4l2h265enc ! queue ! h265parse ! queue ! mp4mux ! queue ! filesink location=...
+ # camsrc. ! video/x-raw,format=NV12,width=640,height=480,framerate=15/1 ! queue ! scb.sink_ctrl
+ pipeline="qtiqmmfsrc camera=0 noise-reduction=2 video_0::extra-buffers=20 video_0::type=preview name=camsrc video_0::type=video ! video/x-raw,format=NV12,width=1280,height=720,framerate=30/1 ! queue ! scb.sink qtismartvencbin default-gop=30 max-gop=600 smart-framerate=true smart-gop=false max-bitrate=4200000 name=scb encoder=v4l2h265enc ! queue ! h265parse ! queue ! mp4mux ! queue ! filesink location=${output_file} camsrc. ! video/x-raw,format=NV12,width=640,height=480,framerate=15/1 ! queue ! scb.sink_ctrl"
+
+ log_info "Pipeline: $pipeline"
+
+ # Run encoding
+ if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then
+ gstRc=0
+ else
+ gstRc=$?
+ fi
+
+ log_info "Exit code: $gstRc"
+
+ # Validate log
+ if ! gstreamer_validate_log "$test_log" "$testname"; then
+ log_fail "$testname: FAIL (GStreamer errors detected)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ # Check output file
+ if [ -f "$output_file" ] && [ -s "$output_file" ]; then
+ file_size=$(gstreamer_file_size_bytes "$output_file")
+ log_info "Encoded file: $output_file (size: $file_size bytes)"
+
+ if [ "$file_size" -gt 1000 ]; then
+ log_pass "$testname: PASS"
+ pass_count=$((pass_count + 1))
+ return 0
+ fi
+ fi
+
+ log_fail "$testname: FAIL (no valid output)"
+ fail_count=$((fail_count + 1))
+ return 1
+}
+
+# -------------------- HEVC Cyclic IR Encode Test --------------------
+# Test: HEVC_Encode_UHD_Cyclic_IR (FR82773) - Downstream only
+run_cyclic_ir_encode_test() {
+ testname="HEVC_Encode_UHD_Cyclic_IR"
+ log_info "=========================================="
+ log_info "Running: $testname (FR82773)"
+ log_info "=========================================="
+
+ total_tests=$((total_tests + 1))
+
+ # Check if downstream stack
+ if ! gstreamer_is_downstream_stack; then
+ log_skip "$testname: Requires downstream video driver (Config2)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Check for required elements
+ if ! has_element qtiqmmfsrc; then
+ log_skip "$testname: qtiqmmfsrc not available (camera source required)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element v4l2h265enc; then
+ log_skip "$testname: v4l2h265enc not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ test_log="$OUTDIR/${testname}.log"
+ output_file="$ENCODED_DIR/${testname}.mp4"
+ : >"$test_log"
+
+ # Build pipeline with cyclic intra refresh
+ pipeline="qtiqmmfsrc name=qmmf ! video/x-raw,format=NV12,width=3840,height=2160,framerate=30/1 ! v4l2h265enc extra-controls=\"controls,video_bitrate=8000000,intra_refresh_period_type=1\" capture-io-mode=4 output-io-mode=4 ! h265parse ! mp4mux ! filesink location=${output_file}"
+
+ log_info "Pipeline: $pipeline"
+
+ # Run encoding
+ if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then
+ gstRc=0
+ else
+ gstRc=$?
+ fi
+
+ log_info "Exit code: $gstRc"
+
+ # Validate log
+ if ! gstreamer_validate_log "$test_log" "$testname"; then
+ log_fail "$testname: FAIL (GStreamer errors detected)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ # Check output file
+ if [ -f "$output_file" ] && [ -s "$output_file" ]; then
+ file_size=$(gstreamer_file_size_bytes "$output_file")
+ log_info "Encoded file: $output_file (size: $file_size bytes)"
+
+ if [ "$file_size" -gt 1000 ]; then
+ log_pass "$testname: PASS"
+ pass_count=$((pass_count + 1))
+ return 0
+ fi
+ fi
+
+ log_fail "$testname: FAIL (no valid output)"
+ fail_count=$((fail_count + 1))
+ return 1
+}
+
+# -------------------- H.264 Slice MB Encode Test --------------------
+# Test: H264_Encode_Slice_MB_VGA (FR82771) - Downstream only
+run_slice_mb_encode_test() {
+ testname="H264_Encode_Slice_MB_VGA"
+ log_info "=========================================="
+ log_info "Running: $testname (FR82771)"
+ log_info "=========================================="
+
+ total_tests=$((total_tests + 1))
+
+ # Check if downstream stack
+ if ! gstreamer_is_downstream_stack; then
+ log_skip "$testname: Requires downstream video driver (Config2)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ # Check for required elements
+ if ! has_element qtiqmmfsrc; then
+ log_skip "$testname: qtiqmmfsrc not available (camera source required)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element v4l2h264enc; then
+ log_skip "$testname: v4l2h264enc not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ test_log="$OUTDIR/${testname}.log"
+ output_file="$ENCODED_DIR/${testname}.mp4"
+ : >"$test_log"
+
+ # Build pipeline with slice MB mode
+ pipeline="qtiqmmfsrc name=qmmf ! video/x-raw,format=NV12,width=640,height=480,framerate=30/1 ! v4l2h264enc extra-controls=\"controls,video_bitrate=1000000,slice_partitioning_method=1,number_of_mbs_in_a_slice=368\" capture-io-mode=4 output-io-mode=4 ! h264parse ! mp4mux ! filesink location=${output_file}"
+
+ log_info "Pipeline: $pipeline"
+
+ # Run encoding
+ if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then
+ gstRc=0
+ else
+ gstRc=$?
+ fi
+
+ log_info "Exit code: $gstRc"
+
+ # Validate log
+ if ! gstreamer_validate_log "$test_log" "$testname"; then
+ log_fail "$testname: FAIL (GStreamer errors detected)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ # Check output file
+ if [ -f "$output_file" ] && [ -s "$output_file" ]; then
+ file_size=$(gstreamer_file_size_bytes "$output_file")
+ log_info "Encoded file: $output_file (size: $file_size bytes)"
+
+ if [ "$file_size" -gt 1000 ]; then
+ log_pass "$testname: PASS"
+ pass_count=$((pass_count + 1))
+ return 0
+ fi
+ fi
+
+ log_fail "$testname: FAIL (no valid output)"
+ fail_count=$((fail_count + 1))
+ return 1
+}
+
+# -------------------- HEVC 4K Rotate90 Encode Test --------------------
+# Test: HEVC_Encode_4K_Rotate90 (FR72846)
+run_rotate_encode_test() {
+ testname="HEVC_Encode_4K_Rotate90"
+ log_info "=========================================="
+ log_info "Running: $testname (FR72846)"
+ log_info "=========================================="
+
+ total_tests=$((total_tests + 1))
+
+ # Check for required elements
+ if ! has_element qtiqmmfsrc; then
+ log_skip "$testname: qtiqmmfsrc not available (camera source required)"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ if ! has_element v4l2h265enc; then
+ log_skip "$testname: v4l2h265enc not available"
+ skip_count=$((skip_count + 1))
+ return 1
+ fi
+
+ test_log="$OUTDIR/${testname}.log"
+ output_file="$ENCODED_DIR/${testname}.mp4"
+ : >"$test_log"
+
+ # Build pipeline with 90-degree rotation
+ # Note: rotate control may require downstream driver
+ if [ "$detected_stack" = "downstream" ]; then
+ pipeline="qtiqmmfsrc name=qmmf ! video/x-raw,format=NV12,width=3840,height=2160,framerate=30/1 ! v4l2h265enc extra-controls=\"controls,video_bitrate=8000000,rotate=90\" capture-io-mode=4 output-io-mode=4 ! h265parse ! mp4mux ! filesink location=${output_file}"
+ else
+ # Upstream may not support rotate control
+ pipeline="qtiqmmfsrc name=qmmf ! video/x-raw,format=NV12,width=3840,height=2160,framerate=30/1 ! v4l2h265enc extra-controls=\"controls,video_bitrate=8000000\" ! h265parse ! mp4mux ! filesink location=${output_file}"
+ log_warn "Rotate control may not be supported on upstream driver"
+ fi
+
+ log_info "Pipeline: $pipeline"
+
+ # Run encoding
+ if gstreamer_run_gstlaunch_timeout "$((duration + 10))" "$pipeline" >>"$test_log" 2>&1; then
+ gstRc=0
+ else
+ gstRc=$?
+ fi
+
+ log_info "Exit code: $gstRc"
+
+ # Validate log
+ if ! gstreamer_validate_log "$test_log" "$testname"; then
+ log_fail "$testname: FAIL (GStreamer errors detected)"
+ fail_count=$((fail_count + 1))
+ return 1
+ fi
+
+ # Check output file
+ if [ -f "$output_file" ] && [ -s "$output_file" ]; then
+ file_size=$(gstreamer_file_size_bytes "$output_file")
+ log_info "Encoded file: $output_file (size: $file_size bytes)"
+
+ if [ "$file_size" -gt 1000 ]; then
+ log_pass "$testname: PASS"
+ pass_count=$((pass_count + 1))
+ return 0
+ fi
+ fi
+
+ log_fail "$testname: FAIL (no valid output)"
+ fail_count=$((fail_count + 1))
+ return 1
+}
+
+# -------------------- Main test execution --------------------
+log_info "Starting video encode/decode tests..."
+log_info "Test type: $testType"
+
+# Route to appropriate test based on test type
+case "$testType" in
+ basic)
+ # Run only basic encode/decode tests
+ log_info "Running basic encode/decode tests only"
+ ;;
+ uvc)
+ # Run only UVC test
+ run_uvc_preview_test
+ # Skip to summary
+ log_info "Skipping other tests (test type: uvc)"
+ ;;
+ drc)
+ # Run only DRC test
+ run_drc_decode_test
+ # Skip to summary
+ log_info "Skipping other tests (test type: drc)"
+ ;;
+ concurrency)
+ # Run only concurrency tests
+ run_h264_concurrency_test
+ run_h265_concurrency_test
+ run_mjpeg_concurrency_test
+ # Skip to summary
+ log_info "Skipping other tests (test type: concurrency)"
+ ;;
+ advanced-encode)
+ # Run only advanced encoding tests (downstream only)
+ run_smart_encode_test
+ run_cyclic_ir_encode_test
+ run_slice_mb_encode_test
+ run_rotate_encode_test
+ # Skip to summary
+ log_info "Skipping other tests (test type: advanced-encode)"
+ ;;
+ all)
+ # Run ALL tests (new default behavior)
+ log_info "Running ALL video tests (basic + advanced)"
+
+ # Run basic tests (will be executed below in normal flow)
+ log_info "Will run: basic encode/decode tests"
+
+ # Run UVC test
+ log_info "Will run: UVC camera test"
+ run_uvc_preview_test || true
+
+ # Run DRC test
+ log_info "Will run: DRC decode test"
+ run_drc_decode_test || true
+
+ # Run concurrency tests
+ log_info "Will run: Concurrency tests"
+ run_h264_concurrency_test || true
+ run_h265_concurrency_test || true
+ run_mjpeg_concurrency_test || true
+
+ # Run advanced encode tests
+ log_info "Will run: Advanced encode tests"
+ run_smart_encode_test || true
+ run_cyclic_ir_encode_test || true
+ run_slice_mb_encode_test || true
+ run_rotate_encode_test || true
+ ;;
+ *)
+ log_warn "Unknown test type: $testType"
+ echo "$RESULT_TESTNAME SKIP" >"$RES_FILE"
+ exit 0
+ ;;
+esac
+
+# Skip basic tests if we ran a specific test type (not 'basic' or 'all')
+if [ "$testType" != "basic" ] && [ "$testType" != "all" ]; then
+ # Jump directly to dmesg scan and summary
+ log_info "Skipping basic encode/decode tests (test type: $testType)"
+else
+ # Continue with basic tests below
+ :
+fi
+
+# Parse codec list
+codecs=$(printf '%s' "$codecList" | tr ',' ' ')
+
+# Parse resolution list
+resolutions=$(printf '%s' "$resolutionList" | tr ',' ' ')
+
+# -------------------- Test clip preparation --------------------
+log_info "=========================================="
+log_info "TEST CLIP PREPARATION"
+log_info "=========================================="
+
+# Function to get clip from local path or download
+get_test_clip() {
+ clip_name="$1"
+ dest_path="$2"
+
+ # Check if clip already exists
+ if [ -f "$dest_path" ]; then
+ log_info "Clip already exists: $clip_name"
+ return 0
+ fi
+
+ # Try to get from provided local path first
+ if [ -n "$clipPath" ] && [ -f "$clipPath/$clip_name" ]; then
+ log_info "Copying $clip_name from local path: $clipPath"
+ if cp "$clipPath/$clip_name" "$dest_path"; then
+ log_info "Successfully copied $clip_name"
+ return 0
+ else
+ log_warn "Failed to copy $clip_name from local path"
+ fi
+ fi
+
+ # Try to download from URL
+ log_info "Attempting to download $clip_name from URL..."
+ if extract_tar_from_url "$clipUrl" "$OUTDIR"; then
+ # Check if file was extracted
+ if [ -f "$clip_name" ]; then
+ mv "$clip_name" "$dest_path"
+ log_info "Successfully downloaded and moved $clip_name"
+ return 0
+ elif [ -f "$OUTDIR/$clip_name" ]; then
+ log_info "Clip $clip_name already in correct location"
+ return 0
+ else
+ log_warn "Clip $clip_name not found in downloaded content"
+ return 1
+ fi
+ else
+ log_warn "Download failed for $clip_name (offline or URL issue)"
+ return 1
+ fi
+}
+
+# Prepare clips based on test type
+case "$testType" in
+ basic)
+ # VP9 clip for basic decode tests
+ need_vp9_clip=0
+ for codec in $codecs; do
+ if [ "$codec" = "vp9" ]; then
+ need_vp9_clip=1
+ break
+ fi
+ done
+
+ if [ "$need_vp9_clip" -eq 1 ] && [ "$testMode" != "encode" ]; then
+ get_test_clip "VP9_640x480_10s.webm" "$OUTDIR/VP9_640x480_10s.webm"
+ fi
+ ;;
+
+ drc)
+ # DRC test clip
+ get_test_clip "1080_720_h264.mp4" "$OUTDIR/1080_720_h264.mp4"
+ ;;
+
+ concurrency)
+ # Concurrency test clips
+ get_test_clip "H264_480p_30fps.mp4" "$OUTDIR/H264_480p_30fps.mp4"
+ get_test_clip "H265_480p_30fps.mp4" "$OUTDIR/H265_480p_30fps.mp4"
+ get_test_clip "mjpeg1.avi" "$OUTDIR/mjpeg1.avi"
+ ;;
+
+ all)
+ # All test clips needed
+ log_info "Preparing all test clips..."
+
+ # VP9 clip for basic decode tests
+ need_vp9_clip=0
+ for codec in $codecs; do
+ if [ "$codec" = "vp9" ]; then
+ need_vp9_clip=1
+ break
+ fi
+ done
+
+ if [ "$need_vp9_clip" -eq 1 ] && [ "$testMode" != "encode" ]; then
+ get_test_clip "VP9_640x480_10s.webm" "$OUTDIR/VP9_640x480_10s.webm"
+ fi
+
+ # DRC test clip
+ get_test_clip "1080_720_h264.mp4" "$OUTDIR/1080_720_h264.mp4"
+
+ # Concurrency test clips
+ get_test_clip "H264_480p_30fps.mp4" "$OUTDIR/H264_480p_30fps.mp4"
+ get_test_clip "H265_480p_30fps.mp4" "$OUTDIR/H265_480p_30fps.mp4"
+ get_test_clip "mjpeg1.avi" "$OUTDIR/mjpeg1.avi"
+ ;;
+
+ uvc|advanced-encode)
+ # No clips needed - uses camera
+ log_info "No test clips needed for test type: $testType"
+ ;;
+esac
+
+log_info "Test clip preparation complete"
# Run encode tests (skip VP9 as it doesn't support encoding in this test)
if [ "$testMode" = "all" ] || [ "$testMode" = "encode" ]; then
diff --git a/Runner/utils/lib_gstreamer.sh b/Runner/utils/lib_gstreamer.sh
index d852bbf47..389a1e3ad 100755
--- a/Runner/utils/lib_gstreamer.sh
+++ b/Runner/utils/lib_gstreamer.sh
@@ -1198,6 +1198,7 @@ prepare_vp9_from_local_path() {
return 1
}
+
# --------------------------------------------------------------
# download_resource
# $1 url – URL to download
@@ -1682,3 +1683,198 @@ camera_setup_wayland_environment() {
return $((1 - wayland_ready))
}
+
+# -------------------- Downstream-Only Test Detection --------------------
+# gstreamer_is_downstream_stack
+# Checks if current video stack is downstream
+# Returns: 0 if downstream, 1 otherwise
+gstreamer_is_downstream_stack() {
+ if ! command -v video_stack_status >/dev/null 2>&1; then
+ return 1
+ fi
+ stack=$(video_stack_status "" 2>/dev/null || echo "unknown")
+ [ "$stack" = "downstream" ]
+}
+
+# -------------------- UVC Camera Detection --------------------
+# gstreamer_detect_uvc_camera
+# Detects UVC camera device by checking kernel driver via sysfs
+# Prints: device path (e.g., /dev/video2) or empty if not found
+gstreamer_detect_uvc_camera() {
+ for dev in /dev/video*; do
+ [ -c "$dev" ] || continue
+
+ # Check if device uses uvcvideo driver via sysfs
+ drv=$(readlink -f "/sys/class/video4linux/${dev##*/}/device/driver" 2>/dev/null)
+
+ if printf '%s\n' "$drv" | grep -q "/uvcvideo$"; then
+ printf '%s\n' "$dev"
+ return 0
+ fi
+ done
+
+ return 1
+}
+
+# -------------------- Advanced Test Pipeline Builders --------------------
+
+# gstreamer_build_uvc_preview_pipeline
+# Build pipeline for UVC camera live preview
+# Args: device width height framerate
+# Returns: pipeline string or empty on error
+gstreamer_build_uvc_preview_pipeline() {
+ device="$1"
+ width="$2"
+ height="$3"
+ framerate="$4"
+
+ [ -n "$device" ] || return 1
+ [ -n "$width" ] || width="1920"
+ [ -n "$height" ] || height="1080"
+ [ -n "$framerate" ] || framerate="5"
+
+ if has_element qtivtransform; then
+ printf 'v4l2src device=%s ! qtivtransform rotate=0 ! video/x-raw,width=%s,height=%s,framerate=%s/1 ! waylandsink fullscreen=true' \
+ "$device" "$width" "$height" "$framerate"
+ else
+ printf 'v4l2src device=%s ! video/x-raw,width=%s,height=%s,framerate=%s/1 ! waylandsink fullscreen=true' \
+ "$device" "$width" "$height" "$framerate"
+ fi
+}
+
+# gstreamer_build_drc_decode_pipeline
+# Build pipeline for Dynamic Resolution Change H.264 decode test
+# Args: clip_path video_stack
+# Returns: pipeline string or empty on error
+gstreamer_build_drc_decode_pipeline() {
+ clip_path="$1"
+ video_stack="$2"
+
+ [ -n "$clip_path" ] || return 1
+ [ -f "$clip_path" ] || return 1
+
+ printf 'filesrc location=%s ! qtdemux ! queue ! h264parse ! v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw,format=NV12 ! fpsdisplaysink video-sink="waylandsink fullscreen=true" text-overlay=false' \
+ "$clip_path"
+}
+
+# gstreamer_build_concurrency_decode_pipeline
+# Build pipeline for concurrent decode tests (H.264, H.265, MJPEG)
+# Args: codec clip_path sessions
+# Returns: pipeline string or empty on error
+gstreamer_build_concurrency_decode_pipeline() {
+ codec="$1"
+ clip_path="$2"
+ sessions="$3"
+
+ [ -n "$codec" ] || return 1
+ [ -n "$clip_path" ] || return 1
+ [ -f "$clip_path" ] || return 1
+ [ -n "$sessions" ] || sessions="16"
+
+ # Build qtivcomposer with 4x4 grid layout
+ pipeline="qtivcomposer name=mix"
+ pipeline="$pipeline sink_0::position=\"<0,0>\" sink_0::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_1::position=\"<480,0>\" sink_1::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_2::position=\"<960,0>\" sink_2::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_3::position=\"<1440,0>\" sink_3::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_4::position=\"<0,270>\" sink_4::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_5::position=\"<480,270>\" sink_5::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_6::position=\"<960,270>\" sink_6::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_7::position=\"<1440,270>\" sink_7::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_8::position=\"<0,540>\" sink_8::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_9::position=\"<480,540>\" sink_9::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_10::position=\"<960,540>\" sink_10::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_11::position=\"<1440,540>\" sink_11::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_12::position=\"<0,810>\" sink_12::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_13::position=\"<480,810>\" sink_13::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_14::position=\"<960,810>\" sink_14::dimensions=\"<480,270>\""
+ pipeline="$pipeline sink_15::position=\"<1440,810>\" sink_15::dimensions=\"<480,270>\""
+
+ # Different output for MJPEG (needs mix. before waylandsink)
+ case "$codec" in
+ mjpeg)
+ pipeline="$pipeline mix. ! queue ! waylandsink fullscreen=true"
+ ;;
+ *)
+ pipeline="$pipeline ! queue ! waylandsink fullscreen=true"
+ ;;
+ esac
+
+ # Add decode chains based on codec
+ i=0
+ while [ "$i" -lt "$sessions" ]; do
+ case "$codec" in
+ h264)
+ pipeline="$pipeline filesrc location=${clip_path} ! qtdemux ! queue ! h264parse ! v4l2h264dec capture-io-mode=4 output-io-mode=4 ! video/x-raw,format=NV12 ! queue ! mix."
+ ;;
+ h265)
+ pipeline="$pipeline filesrc location=${clip_path} ! qtdemux ! queue ! h265parse ! v4l2h265dec capture-io-mode=4 output-io-mode=4 ! video/x-raw,format=NV12 ! queue ! mix."
+ ;;
+ mjpeg)
+ pipeline="$pipeline filesrc location=${clip_path} ! avidemux ! queue ! jpegdec ! videoconvert ! video/x-raw,format=RGB ! queue ! mix."
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+ i=$((i + 1))
+ done
+
+ printf '%s' "$pipeline"
+}
+
+# gstreamer_build_smart_encode_pipeline
+# Build pipeline for HEVC Smart Encode with dual camera streams
+# Args: output_file
+# Returns: pipeline string or empty on error
+gstreamer_build_smart_encode_pipeline() {
+ output_file="$1"
+
+ [ -n "$output_file" ] || return 1
+
+ printf 'qtiqmmfsrc camera=0 noise-reduction=2 video_0::extra-buffers=20 video_0::type=preview name=camsrc video_0::type=video ! video/x-raw,format=NV12,width=1280,height=720,framerate=30/1 ! queue ! scb.sink qtismartvencbin default-gop=30 max-gop=600 smart-framerate=true smart-gop=false max-bitrate=4200000 name=scb encoder=v4l2h265enc ! queue ! h265parse ! queue ! mp4mux ! queue ! filesink location=%s camsrc. ! video/x-raw,format=NV12,width=640,height=480,framerate=15/1 ! queue ! scb.sink_ctrl' \
+ "$output_file"
+}
+
+# gstreamer_build_camera_encode_pipeline
+# Build pipeline for camera-based encoding with custom controls
+# Args: codec width height output_file extra_controls video_stack
+# Returns: pipeline string or empty on error
+gstreamer_build_camera_encode_pipeline() {
+ codec="$1"
+ width="$2"
+ height="$3"
+ output_file="$4"
+ extra_controls="$5"
+ video_stack="$6"
+
+ [ -n "$codec" ] || return 1
+ [ -n "$width" ] || return 1
+ [ -n "$height" ] || return 1
+ [ -n "$output_file" ] || return 1
+
+ # Determine encoder and parser
+ case "$codec" in
+ h264)
+ encoder="v4l2h264enc"
+ parser="h264parse"
+ ;;
+ h265|hevc)
+ encoder="v4l2h265enc"
+ parser="h265parse"
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+
+ # Build pipeline
+ if [ -n "$extra_controls" ]; then
+ printf 'qtiqmmfsrc name=qmmf ! video/x-raw,format=NV12,width=%s,height=%s,framerate=30/1 ! %s extra-controls="%s" capture-io-mode=4 output-io-mode=4 ! %s ! mp4mux ! filesink location=%s' \
+ "$width" "$height" "$encoder" "$extra_controls" "$parser" "$output_file"
+ else
+ printf 'qtiqmmfsrc name=qmmf ! video/x-raw,format=NV12,width=%s,height=%s,framerate=30/1 ! %s capture-io-mode=4 output-io-mode=4 ! %s ! mp4mux ! filesink location=%s' \
+ "$width" "$height" "$encoder" "$parser" "$output_file"
+ fi
+}
+