11#! /bin/sh
22# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
3- # SPDX-License-Identifier: BSD-3-Clause
3+ # SPDX-License-Identifier: BSD-3-Clause#
44# Runner/utils/lib_gstreamer.sh
55#
66# GStreamer helpers.
@@ -20,77 +20,31 @@ GSTLAUNCHFLAGS="${GSTLAUNCHFLAGS:--e -v -m}"
2020# GST_ALSA_PLAYBACK_DEVICE=hw:0,0
2121# GST_ALSA_CAPTURE_DEVICE=hw:0,1
2222
23- # -------------------- Shared artifact directory (generic) --------------------
24- # gstreamer_shared_artifact_dir <env_var_name> <shared_subdir> <local_subdir> <script_dir> <outdir>
25- # Generic function to get shared artifact directory for any test type .
23+ # -------------------- Shared encoded- artifact directory --------------------
24+ # gstreamer_shared_encoded_dir <script_dir> <outdir>
25+ # Prints a directory path to use for encoded video artifacts .
2626# Priority:
27- # 1. Environment variable if explicitly provided (e.g., VIDEO_SHARED_ENCODE_DIR, AUDIO_SHARED_RECORDED_DIR)
27+ # 1. VIDEO_SHARED_ENCODE_DIR if explicitly provided
2828# 2. A job-shared path derived from the common LAVA prefix before /tests/
29- # 3. Fallback to <outdir>/<local_subdir> for local/manual runs
30- #
31- # Parameters:
32- # env_var_name: Name of environment variable to check (e.g., "VIDEO_SHARED_ENCODE_DIR")
33- # shared_subdir: Subdirectory name for shared path (e.g., "video-encode-decode", "audio-record-playback")
34- # local_subdir: Subdirectory name for local fallback (e.g., "encoded", "recorded")
35- # script_dir: Script directory path
36- # outdir: Output directory path
37- #
38- # Example usage:
39- # gstreamer_shared_artifact_dir "VIDEO_SHARED_ENCODE_DIR" "video-encode-decode" "encoded" "$SCRIPT_DIR" "$OUTDIR"
40- # gstreamer_shared_artifact_dir "AUDIO_SHARED_RECORDED_DIR" "audio-record-playback" "recorded" "$SCRIPT_DIR" "$OUTDIR"
41- gstreamer_shared_artifact_dir () {
42- env_var_name=" $1 "
43- shared_subdir=" $2 "
44- local_subdir=" $3 "
45- script_dir=" $4 "
46- outdir=" $5 "
47-
48- # Check if environment variable is set (using eval for dynamic variable name)
49- env_value=$( eval " printf '%s' \"\$ {${env_var_name} :-}\" " )
50- if [ -n " $env_value " ]; then
51- printf ' %s\n' " $env_value "
29+ # 3. Fallback to <outdir>/encoded for local/manual runs
30+ gstreamer_shared_encoded_dir () {
31+ script_dir=" $1 "
32+ outdir=" $2 "
33+
34+ if [ -n " ${VIDEO_SHARED_ENCODE_DIR:- } " ]; then
35+ printf ' %s\n' " $VIDEO_SHARED_ENCODE_DIR "
5236 return 0
5337 fi
5438
55- # Check if we're in a LAVA test structure (contains /tests/)
5639 case " $script_dir " in
5740 * /tests/* )
58- printf ' %s/shared/%s \n' " ${script_dir%%/ tests/* } " " $shared_subdir "
41+ printf ' %s/shared/video-encode-decode \n' " ${script_dir%%/ tests/* } "
5942 ;;
6043 * )
61- printf ' %s/%s \n' " $outdir " " $local_subdir "
44+ printf ' %s/encoded \n' " $outdir "
6245 ;;
6346 esac
6447}
65-
66- # -------------------- Shared encoded-artifact directory (video) --------------------
67- # gstreamer_shared_encoded_dir <script_dir> <outdir>
68- # Prints a directory path to use for encoded video artifacts.
69- # This is a wrapper around gstreamer_shared_artifact_dir for backward compatibility.
70- # Priority:
71- # 1. VIDEO_SHARED_ENCODE_DIR if explicitly provided
72- # 2. A job-shared path derived from the common LAVA prefix before /tests/
73- # 3. Fallback to <outdir>/encoded for local/manual runs
74- gstreamer_shared_encoded_dir () {
75- script_dir=" $1 "
76- outdir=" $2 "
77-
78- gstreamer_shared_artifact_dir " VIDEO_SHARED_ENCODE_DIR" " video-encode-decode" " encoded" " $script_dir " " $outdir "
79- }
80-
81- # -------------------- Shared recorded-artifact directory (audio) --------------------
82- # gstreamer_shared_recorded_dir <script_dir> <outdir>
83- # Prints a directory path to use for recorded audio artifacts.
84- # Priority:
85- # 1. AUDIO_SHARED_RECORDED_DIR if explicitly provided
86- # 2. A job-shared path derived from the common LAVA prefix before /tests/
87- # 3. Fallback to <outdir>/recorded for local/manual runs
88- gstreamer_shared_recorded_dir () {
89- script_dir=" $1 "
90- outdir=" $2 "
91-
92- gstreamer_shared_artifact_dir " AUDIO_SHARED_RECORDED_DIR" " audio-record-playback" " recorded" " $script_dir " " $outdir "
93- }
9448# -------------------- Element check --------------------
9549has_element () {
9650 elem=" $1 "
@@ -1122,3 +1076,241 @@ prepare_vp9_from_local_path() {
11221076
11231077 return 1
11241078}
1079+ # --------------------------------------------------------------
1080+ # download_resource
1081+ # $1 url – URL to download
1082+ # $2 dest – Either a file name or an existing directory.
1083+ # Prints the full path of the downloaded file on stdout.
1084+ # --------------------------------------------------------------
1085+ download_resource () {
1086+ url=$1
1087+ dest=$2
1088+
1089+ if [ -d " ${dest} " ]; then
1090+ filename=$( basename " ${url} " )
1091+ dest=" ${dest%/ } /${filename} "
1092+ fi
1093+
1094+ # Check if file already exists and is non-empty
1095+ if [ -f " ${dest} " ] && [ -s " ${dest} " ]; then
1096+ if command -v realpath > /dev/null 2>&1 ; then
1097+ realpath " ${dest} "
1098+ else
1099+ case " ${dest} " in
1100+ ./* ) echo " ${dest# ./ } " ;;
1101+ * ) echo " ${dest} " ;;
1102+ esac
1103+ fi
1104+ return 0
1105+ fi
1106+ if command -v ensure_network_online > /dev/null 2>&1 ; then
1107+ if ! ensure_network_online; then
1108+ echo " Network offline/limited; cannot fetch assets"
1109+ return 1
1110+ fi
1111+ fi
1112+
1113+ mkdir -p " $( dirname " ${dest} " ) "
1114+ if command -v curl > /dev/null 2>&1 ; then
1115+ curl -fkL " ${url} " -o " ${dest} " || { echo " Error: curl failed to download ${url} " >&2 ; return 1; }
1116+ elif command -v wget > /dev/null 2>&1 ; then
1117+ wget -q " ${url} " -O " ${dest} " || { echo " Error: wget failed to download ${url} " >&2 ; return 1; }
1118+ else
1119+ echo " Error: neither 'curl' nor 'wget' is installed." >&2
1120+ return 1
1121+ fi
1122+
1123+ # Verify successful download with non-empty file
1124+ if [ ! -s " ${dest} " ]; then
1125+ echo " Error: downloaded file is empty: ${dest} " >&2
1126+ return 1
1127+ fi
1128+
1129+ if command -v realpath > /dev/null 2>&1 ; then
1130+ realpath " ${dest} "
1131+ else
1132+ case " ${dest} " in
1133+ ./* ) echo " ${dest# ./ } " ;;
1134+ * ) echo " ${dest} " ;;
1135+ esac
1136+ fi
1137+ }
1138+ # --------------------------------------------------------------
1139+ # extract_zip_to_dir
1140+ # --------------------------------------------------------------
1141+ extract_zip_to_dir () {
1142+ zip_path=$1
1143+ dest_dir=$2
1144+
1145+ mkdir -p " ${dest_dir} "
1146+ if ! unzip -o " ${zip_path} " -d " ${dest_dir} " > /dev/null; then
1147+ echo " Unzip of ${zip_path} failed" >&2
1148+ return 1
1149+ fi
1150+ }
1151+ # -------------------------------------------------------------------------
1152+ # check_pipeline_elements <pipeline-string>
1153+ # Verify that every GStreamer element that appears in a gst-launch
1154+ # pipeline is installed on the system (via `has_element`).
1155+ # Returns:
1156+ # 0 – all elements are present
1157+ # 1 – at least one element is missing
1158+ # -------------------------------------------------------------------------
1159+ check_pipeline_elements () {
1160+ pipeline=" ${1:? missing pipeline argument} "
1161+ missing_count=0
1162+ missing_list=" "
1163+ total_elements=0
1164+
1165+ log_info " Checking elements in pipeline"
1166+
1167+ # ---------------------------------------------------------
1168+ # Normalise the pipeline string
1169+ # ---------------------------------------------------------
1170+ pipeline=$( printf ' %s' " $pipeline " | tr -d ' \\\n' )
1171+ pipeline=${pipeline# gst-launch-1.0* }
1172+ # Remove the literal "gst-launch-1.0" if present
1173+ pipeline=${pipeline# gst-launch-1.0}
1174+ # Trim any leading whitespace left by the previous step
1175+ pipeline=${pipeline# " ${pipeline%% [![:space:]]* } " }
1176+ # Drop leading option tokens (e.g. "-e", "-v", "--no-fault")
1177+ while [ " ${pipeline# -} " != " $pipeline " ]; do
1178+ # Remove the first token (option) and any following whitespace
1179+ pipeline=${pipeline#* }
1180+ pipeline=${pipeline# " ${pipeline%% [![:space:]]* } " }
1181+ done
1182+
1183+ # ---------------------------------------------------------
1184+ # Write the token list to a temporary file
1185+ # ---------------------------------------------------------
1186+ tmpfile=$( mktemp)
1187+ printf ' %s' " $pipeline " | tr ' !' ' \n' > " $tmpfile "
1188+
1189+ # ---------------------------------------------------------
1190+ # Read the file line‑by‑line – this runs in the *current*
1191+ # shell, so variable updates survive.
1192+ # ---------------------------------------------------------
1193+ while IFS= read -r element_spec; do
1194+ # ---- NEW ----
1195+ # Strip surrounding whitespace; skip blank lines
1196+ # element_spec=$(printf '%s' "$element_spec" | xargs)
1197+ element_spec=$( printf ' %s\n' " $element_spec " | awk ' {$1=$1; print}' )
1198+ [ -z " $element_spec " ] && continue
1199+ # --------------
1200+
1201+ element_name=$( printf ' %s' " $element_spec " | cut -d' ' -f1)
1202+
1203+ case " $element_name " in
1204+ * .) log_info " Skipping element reference: $element_name " ; continue ;;
1205+ name=* ) log_info " Skipping property assignment: $element_name " ; continue ;;
1206+ * _::* ) log_info " Skipping property assignment: $element_name " ; continue ;;
1207+ video/* |audio/* |application/* |text/* |image/* )
1208+ log_info " Skipping caps filter: $element_name " ; continue ;;
1209+ * )
1210+ total_elements=$(( total_elements + 1 ))
1211+ if ! has_element " $element_name " ; then
1212+ missing_count=$(( missing_count + 1 ))
1213+ missing_list=" ${missing_list}${element_name} "
1214+ log_error " Required element missing: $element_name "
1215+ fi
1216+ ;;
1217+ esac
1218+ done < " $tmpfile "
1219+ # Clean up the temporary file
1220+ rm -f " $tmpfile "
1221+
1222+ if [ " $missing_count " -eq 0 ]; then
1223+ log_pass " All $total_elements elements in pipeline are available"
1224+ return 0
1225+ else
1226+ log_fail " Missing $missing_count /$total_elements elements: $missing_list "
1227+ return 1
1228+ fi
1229+ }
1230+ # ----------------------------------------------------------------------
1231+ # Run a pipeline with timeout, capture console output and GST debug logs.
1232+ # ----------------------------------------------------------------------
1233+ run_pipeline_with_logs () {
1234+ name=$1
1235+ cmd=$2
1236+ logdir=${3:- logs}
1237+ TIMEOUT=${4:- 60} # default 60 seconds
1238+
1239+ console_log=" ${logdir} /${name} _console.log"
1240+ gst_debug_log=" ${logdir} /${name} _gst_debug.log"
1241+
1242+ export GST_DEBUG_FILE=" ${gst_debug_log} "
1243+
1244+ log_info " Running ${name} (timeout=${TIMEOUT} s)"
1245+ gstreamer_run_gstlaunch_timeout " $TIMEOUT " " $cmd " > " $console_log " 2>&1
1246+ rc=$?
1247+
1248+ # Look for a successful PLAYING state and the absence of ERROR messages.
1249+ playing=$( grep -c " Setting pipeline to PLAYING" " $console_log " || true)
1250+ error_present=$( grep -c " ERROR:" " $console_log " || true)
1251+
1252+ if [ " $playing " -gt 0 ] && [ " $error_present " -eq 0 ]; then
1253+ log_pass " ${name} PASS"
1254+ return 0
1255+ fi
1256+
1257+ # Special case: timeout (rc = 124) but PLAYING was already reached.
1258+ if [ " $rc " -eq 124 ] && [ " $playing " -gt 0 ]; then
1259+ log_pass " ${name} PASS (completed before timeout)"
1260+ return 0
1261+ fi
1262+
1263+ # Anything else is a failure.
1264+ log_fail " ${name} FAIL (rc=${rc} )"
1265+ log_info " === ERROR DETAILS ==="
1266+ if [ " $error_present " -gt 0 ]; then
1267+ grep -A10 -B5 " ERROR:" " $console_log " | tail -n 30 |
1268+ while IFS= read -r line; do log_info " $line " ; done
1269+ else
1270+ tail -n 30 " $console_log " |
1271+ while IFS= read -r line; do log_info " $line " ; done
1272+ fi
1273+ log_info " ====================="
1274+ return 1
1275+ }
1276+ # ------------------------------------------------------------------
1277+ # Function: check_file_size
1278+ # Purpose : Check that a file exists and its size > 0.
1279+ # Returns : 0 → file size > 0 (success)
1280+ # 1 → file missing, unreadable, or size == 0 (failure)
1281+ # Requires: GNU coreutils (stat -c %s)
1282+ # ------------------------------------------------------------------
1283+ check_file_size () {
1284+ input_file_path=" $1 "
1285+ expected_file_size=" $2 "
1286+
1287+ if [ -z " $input_file_path " ]; then
1288+ log_fail " No input file path provided"
1289+ return 1
1290+ fi
1291+ if [ ! -e " $input_file_path " ]; then
1292+ log_fail " Encoded video file does not exist: $input_file_path "
1293+ return 1
1294+ fi
1295+
1296+ # ---- Ensure we have `stat` ------------------------------------------------
1297+ if ! command -v stat > /dev/null 2>&1 ; then
1298+ log_fail " stat command not found – cannot determine file size"
1299+ return 1
1300+ fi
1301+
1302+ # ---- Get the actual size -------------------------------------------------
1303+ size_in_bytes=$( stat -c %s " $input_file_path " 2> /dev/null || wc -c < " $input_file_path " 2> /dev/null) || {
1304+ log_fail " Unable to read size of file: $input_file_path "
1305+ return 1
1306+ }
1307+
1308+ # ---- Compare with the expected size --------------------------------------
1309+ if [ " $size_in_bytes " -ge " $expected_file_size " ]; then
1310+ log_pass " File OK (size ${size_in_bytes} bytes ≥ ${expected_file_size} bytes): $input_file_path "
1311+ return 0
1312+ else
1313+ log_info " File too small (size ${size_in_bytes} bytes < ${expected_file_size} bytes): $input_file_path "
1314+ return 1
1315+ fi
1316+ }
0 commit comments