Skip to content

Commit e421daa

Browse files
authored
Merge pull request #398 from smuppand/gstreamer
fix(gstreamer): harden log validation for successful decode pipelines
2 parents 604e57f + 51fc893 commit e421daa

File tree

1 file changed

+109
-50
lines changed

1 file changed

+109
-50
lines changed

Runner/utils/lib_gstreamer.sh

Lines changed: 109 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -664,44 +664,51 @@ gstreamer_build_audio_playback_pipeline() {
664664
# Uses severity-based matching to avoid false positives on benign logs
665665
gstreamer_check_errors() {
666666
logfile="$1"
667-
667+
668668
[ -f "$logfile" ] || return 0
669-
670-
# Check for explicit ERROR: prefixed messages (most reliable)
671-
if grep -q -E "^ERROR:|^0:[0-9]+:[0-9]+\.[0-9]+ [0-9]+ [^ ]+ ERROR" "$logfile" 2>/dev/null; then
672-
return 1
673-
fi
674-
675-
# Check for ERROR messages from GStreamer elements
676-
if grep -q -E "ERROR: from element|gst.*ERROR" "$logfile" 2>/dev/null; then
677-
return 1
669+
670+
filtered_log="${logfile}.filtered.$$"
671+
check_log="$logfile"
672+
673+
# Ignore known benign warnings seen on successful downstream V4L2 decode paths.
674+
if sed \
675+
-e '/gst_video_info_dma_drm_to_caps: assertion .*drm_fourcc != DRM_FORMAT_INVALID/d' \
676+
-e "/gst_structure_remove_field: assertion 'IS_MUTABLE (structure)' failed/d" \
677+
"$logfile" >"$filtered_log" 2>/dev/null; then
678+
check_log="$filtered_log"
678679
fi
679-
680-
# Check for critical streaming errors
681-
if grep -q -E "Internal data stream error|streaming stopped, reason not-negotiated" "$logfile" 2>/dev/null; then
680+
681+
# Explicit gst-launch / GStreamer ERROR/FATAL lines.
682+
if grep -q -E '^ERROR:|^FATAL:|^0:[0-9]+:[0-9]+\.[0-9]+ [0-9]+ [^ ]+ (ERROR|FATAL)' "$check_log" 2>/dev/null; then
683+
rm -f "$filtered_log" 2>/dev/null || true
682684
return 1
683685
fi
684-
685-
# Check for pipeline failures (more specific patterns)
686-
if grep -q -E "pipeline doesn't want to preroll|pipeline doesn't want to play|ERROR.*pipeline" "$logfile" 2>/dev/null; then
686+
687+
# Element-reported hard failures.
688+
if grep -q -E 'ERROR: from element|gst.*ERROR|gst.*FATAL' "$check_log" 2>/dev/null; then
689+
rm -f "$filtered_log" 2>/dev/null || true
687690
return 1
688691
fi
689-
690-
# Check for state change failures (require ERROR context)
691-
if grep -q -E "ERROR.*failed to change state|ERROR.*state change failed" "$logfile" 2>/dev/null; then
692+
693+
# Known fatal streaming / negotiation failures.
694+
if grep -q -E 'Internal data stream error|streaming stopped, reason not-negotiated|not-negotiated' "$check_log" 2>/dev/null; then
695+
rm -f "$filtered_log" 2>/dev/null || true
692696
return 1
693697
fi
694-
695-
# Check for specific error patterns with proper grouping
696-
if grep -q -E '(^ERROR:|ERROR: from element|Internal data stream error|streaming stopped, reason not-negotiated|pipeline.*failed|state change failed|Could not open resource|No such file or directory)' "$logfile" 2>/dev/null; then
698+
699+
# Pipeline / state transition failures.
700+
if grep -q -E "pipeline doesn't want to preroll|pipeline doesn't want to play|ERROR.*pipeline|ERROR.*failed to change state|ERROR.*state change failed|failed to change state|state change failed" "$check_log" 2>/dev/null; then
701+
rm -f "$filtered_log" 2>/dev/null || true
697702
return 1
698703
fi
699-
700-
# Check for CRITICAL or FATAL level messages (keep these as they are actual severity indicators)
701-
if grep -q -E '(^CRITICAL:|^FATAL:|gst.*(CRITICAL|FATAL))' "$logfile" 2>/dev/null; then
704+
705+
# Resource / file failures.
706+
if grep -q -E 'Could not open resource|No such file or directory|Failed to open|failed to open' "$check_log" 2>/dev/null; then
707+
rm -f "$filtered_log" 2>/dev/null || true
702708
return 1
703709
fi
704-
710+
711+
rm -f "$filtered_log" 2>/dev/null || true
705712
return 0
706713
}
707714

@@ -712,42 +719,94 @@ gstreamer_check_errors() {
712719
gstreamer_validate_log() {
713720
logfile="$1"
714721
testname="${2:-test}"
715-
722+
716723
[ -f "$logfile" ] || {
717724
log_warn "$testname: Log file not found: $logfile"
718725
return 1
719726
}
720-
727+
721728
if ! gstreamer_check_errors "$logfile"; then
722-
log_fail "$testname: GStreamer errors detected in log"
723-
724-
# Extract and log specific error messages
725-
if grep -q "ERROR:" "$logfile" 2>/dev/null; then
726-
log_fail "Error messages found:"
727-
grep "ERROR:" "$logfile" 2>/dev/null | head -n 5 | while IFS= read -r line; do
728-
log_fail " $line"
729-
done
729+
log_fail "$testname: GStreamer fatal errors detected in log"
730+
731+
grep -E '^ERROR:|^FATAL:|ERROR: from element|gst.*ERROR|gst.*FATAL|Internal data stream error|streaming stopped, reason not-negotiated|not-negotiated|pipeline doesn'\''t want to preroll|pipeline doesn'\''t want to play|failed to change state|state change failed|Could not open resource|No such file or directory|Failed to open|failed to open' \
732+
"$logfile" 2>/dev/null | head -n 5 | while IFS= read -r line; do
733+
[ -n "$line" ] && log_fail " $line"
734+
done
735+
736+
if grep -q 'not-negotiated' "$logfile" 2>/dev/null; then
737+
log_fail " Reason: Format negotiation failed (caps mismatch)"
730738
fi
731-
732-
# Check for specific failure reasons
733-
if grep -q "not-negotiated" "$logfile" 2>/dev/null; then
734-
log_fail " Reason: Format negotiation failed (caps mismatch)"
739+
740+
if grep -q -E 'Could not open resource|Failed to open|failed to open' "$logfile" 2>/dev/null; then
741+
log_fail " Reason: File or device access failed"
735742
fi
736-
737-
if grep -q "Could not open" "$logfile" 2>/dev/null; then
738-
log_fail " Reason: File or device access failed"
743+
744+
if grep -q 'No such file or directory' "$logfile" 2>/dev/null; then
745+
log_fail " Reason: File not found"
739746
fi
740-
741-
if grep -q "No such file" "$logfile" 2>/dev/null; then
742-
log_fail " Reason: File not found"
747+
748+
return 1
749+
fi
750+
751+
filtered_log="${logfile}.filtered.$$"
752+
check_log="$logfile"
753+
754+
# Ignore known benign warnings seen on successful downstream V4L2 decode paths.
755+
if sed \
756+
-e '/gst_video_info_dma_drm_to_caps: assertion .*drm_fourcc != DRM_FORMAT_INVALID/d' \
757+
-e "/gst_structure_remove_field: assertion 'IS_MUTABLE (structure)' failed/d" \
758+
"$logfile" >"$filtered_log" 2>/dev/null; then
759+
check_log="$filtered_log"
760+
fi
761+
762+
# If any CRITICAL lines remain after filtering, decide using success evidence
763+
# instead of failing blindly on severity alone.
764+
if grep -q -E '(^CRITICAL:|^FATAL:|gst.*(CRITICAL|FATAL))' "$check_log" 2>/dev/null; then
765+
playing_seen=0
766+
eos_seen=0
767+
complete_seen=0
768+
caps_seen=0
769+
770+
if grep -q -E 'Setting pipeline to PLAYING|new-state=\(GstState\)playing' "$logfile" 2>/dev/null; then
771+
playing_seen=1
743772
fi
744-
773+
774+
if grep -q -E 'Got EOS from element|EOS received - stopping pipeline' "$logfile" 2>/dev/null; then
775+
eos_seen=1
776+
fi
777+
778+
if grep -q -E 'Execution ended after|Freeing pipeline' "$logfile" 2>/dev/null; then
779+
complete_seen=1
780+
fi
781+
782+
if grep -q -E 'caps = (video|audio)/x-|caps = image/' "$logfile" 2>/dev/null; then
783+
caps_seen=1
784+
fi
785+
786+
if [ "$eos_seen" -eq 1 ]; then
787+
complete_seen=1
788+
fi
789+
790+
if [ "$playing_seen" -eq 1 ] && [ "$complete_seen" -eq 1 ] && [ "$caps_seen" -eq 1 ]; then
791+
log_warn "$testname: Non-fatal GStreamer criticals detected, but pipeline completed successfully"
792+
grep -E '(^CRITICAL:|^FATAL:|gst.*(CRITICAL|FATAL))' "$check_log" 2>/dev/null | head -n 5 | while IFS= read -r line; do
793+
[ -n "$line" ] && log_warn " $line"
794+
done
795+
rm -f "$filtered_log" 2>/dev/null || true
796+
return 0
797+
fi
798+
799+
log_fail "$testname: GStreamer critical/fatal messages detected without clear success evidence"
800+
grep -E '(^CRITICAL:|^FATAL:|gst.*(CRITICAL|FATAL))' "$check_log" 2>/dev/null | head -n 5 | while IFS= read -r line; do
801+
[ -n "$line" ] && log_fail " $line"
802+
done
803+
rm -f "$filtered_log" 2>/dev/null || true
745804
return 1
746805
fi
747-
806+
807+
rm -f "$filtered_log" 2>/dev/null || true
748808
return 0
749809
}
750-
751810
# -------------------- Video codec helpers (V4L2) --------------------
752811
# gstreamer_resolution_to_wh <resolution>
753812
# Converts resolution name to width and height
@@ -1359,4 +1418,4 @@ check_file_size() {
13591418
log_info "File too small (size ${size_in_bytes} bytes < ${expected_file_size} bytes): $input_file_path"
13601419
return 1
13611420
fi
1362-
}
1421+
}

0 commit comments

Comments
 (0)