@@ -18,6 +18,7 @@ DEFAULT_MODE="hardware" |
||
| 18 | 18 |
DEFAULT_EXTENSIONS="mp4,mov,avi,m4v" |
| 19 | 19 |
DEFAULT_CRF_HEVC=20 |
| 20 | 20 |
DEFAULT_CRF_H264=19 |
| 21 |
+DEFAULT_STAGING_RAMDISK_MB=8192 |
|
| 21 | 22 |
|
| 22 | 23 |
# Garmin publicly declares a 140-degree field of view. |
| 23 | 24 |
# We infer practical focal metadata from this single spec. |
@@ -41,6 +42,15 @@ MOVE_SOURCE=false |
||
| 41 | 42 |
SOURCE_PROVIDED=false |
| 42 | 43 |
DEST_PROVIDED=false |
| 43 | 44 |
STAGING_PROVIDED=false |
| 45 |
+STAGING_RAMDISK_MB="$DEFAULT_STAGING_RAMDISK_MB" |
|
| 46 |
+AUTO_CREATED_STAGING_RAMDISK=false |
|
| 47 |
+AUTO_CREATED_STAGING_PATH="" |
|
| 48 |
+STAGING_RAMDISK_CREATED_AT=0 |
|
| 49 |
+RUN_STARTED_AT=0 |
|
| 50 |
+FIRST_ENCODE_STARTED_AT=0 |
|
| 51 |
+DEBUG_TIMING_LIMIT=0 |
|
| 52 |
+DEBUG_TIMING_FILES=0 |
|
| 53 |
+DEBUG_TIMING_STOPPED=false |
|
| 44 | 54 |
FAIL_FAST=true |
| 45 | 55 |
SOURCE_READABLE_MODE="normal" |
| 46 | 56 |
APPLE_REPACK_FALLBACK=true |
@@ -68,6 +78,8 @@ INVALID_SOURCES_SKIPPED=0 |
||
| 68 | 78 |
DESTINATION_FAILURES=0 |
| 69 | 79 |
TOTAL_VIDEO_TIME_SEC=0 |
| 70 | 80 |
TOTAL_FILE_REAL_TIME_SEC=0 |
| 81 |
+INPUT_BYTES_PROCESSED=0 |
|
| 82 |
+OUTPUT_BYTES_PROCESSED=0 |
|
| 71 | 83 |
|
| 72 | 84 |
DURATION_TOLERANCE_SEC=1.0 |
| 73 | 85 |
STOP_AFTER_CURRENT=false |
@@ -85,6 +97,9 @@ Options: |
||
| 85 | 97 |
-d, --destination, --output DIR Destination directory (default: current directory) |
| 86 | 98 |
--staging-dir DIR Temporary staging directory for intermediate output files |
| 87 | 99 |
(falls back to destination if staging cannot be used) |
| 100 |
+ --staging-ramdisk-mb N RAM disk size in MB when auto-creating missing /Volumes staging |
|
| 101 |
+ directory on macOS (default: 8192) |
|
| 102 |
+ --debug-timing N Process at most N video files, then stop and print timing stats |
|
| 88 | 103 |
--mode MODE Encoding mode (default: hardware); see Encoding Modes below |
| 89 | 104 |
--crf N CRF value for quality/compat modes (lower = better; default: 20/19) |
| 90 | 105 |
--no-overwrite Skip files that already exist at destination (default: overwrite) |
@@ -161,7 +176,7 @@ log_progress_start() {
|
||
| 161 | 176 |
local input_file="$1" |
| 162 | 177 |
local ts |
| 163 | 178 |
ts="$(date '+%Y-%m-%d %H:%M:%S')" |
| 164 |
- printf '%s : Transcoding %s ...' "$ts" "$input_file" |
|
| 179 |
+ printf '[%s] [INFO] Transcoding %s ...' "$ts" "$input_file" |
|
| 165 | 180 |
PROGRESS_LINE_OPEN=true |
| 166 | 181 |
} |
| 167 | 182 |
|
@@ -177,7 +192,7 @@ log_progress_done() {
|
||
| 177 | 192 |
local input_file="$1" |
| 178 | 193 |
local ts |
| 179 | 194 |
ts="$(date '+%Y-%m-%d %H:%M:%S')" |
| 180 |
- echo "$ts : Transcoding $input_file ... done in ${real_elapsed_sec}s (encode ${encode_elapsed_sec}s)"
|
|
| 195 |
+ echo "[$ts] [INFO] Transcoding $input_file ... done in ${real_elapsed_sec}s (encode ${encode_elapsed_sec}s)"
|
|
| 181 | 196 |
} |
| 182 | 197 |
|
| 183 | 198 |
log_progress_failed() {
|
@@ -195,7 +210,7 @@ log_progress_failed() {
|
||
| 195 | 210 |
|
| 196 | 211 |
local ts |
| 197 | 212 |
ts="$(date '+%Y-%m-%d %H:%M:%S')" |
| 198 |
- echo "$ts : Transcoding $input_file ... FAILED after ${real_elapsed_sec}s (encode ${encode_elapsed_sec}s, rc=$ffmpeg_rc, log=${ffmpeg_log:-n/a})"
|
|
| 213 |
+ echo "[$ts] [ERROR] Transcoding $input_file ... FAILED after ${real_elapsed_sec}s (encode ${encode_elapsed_sec}s, rc=$ffmpeg_rc, log=${ffmpeg_log:-n/a})"
|
|
| 199 | 214 |
} |
| 200 | 215 |
|
| 201 | 216 |
log_progress_skipped_unreadable() {
|
@@ -209,7 +224,7 @@ log_progress_skipped_unreadable() {
|
||
| 209 | 224 |
|
| 210 | 225 |
local ts |
| 211 | 226 |
ts="$(date '+%Y-%m-%d %H:%M:%S')" |
| 212 |
- echo "$ts : Transcoding $input_file ... SKIPPED (unreadable/corrupted source)" |
|
| 227 |
+ echo "[$ts] [INFO] Transcoding $input_file ... SKIPPED (unreadable/corrupted source)" |
|
| 213 | 228 |
} |
| 214 | 229 |
|
| 215 | 230 |
die() {
|
@@ -262,6 +277,23 @@ format_seconds() {
|
||
| 262 | 277 |
printf '%02d:%02d:%02d' "$h" "$m" "$s" |
| 263 | 278 |
} |
| 264 | 279 |
|
| 280 |
+format_bytes_human() {
|
|
| 281 |
+ local bytes="$1" |
|
| 282 |
+ awk -v b="$bytes" 'BEGIN {
|
|
| 283 |
+ split("B KiB MiB GiB TiB PiB", u, " ");
|
|
| 284 |
+ i = 1; |
|
| 285 |
+ while (b >= 1024 && i < 6) {
|
|
| 286 |
+ b = b / 1024; |
|
| 287 |
+ i++; |
|
| 288 |
+ } |
|
| 289 |
+ if (i == 1) {
|
|
| 290 |
+ printf "%d %s", b, u[i]; |
|
| 291 |
+ } else {
|
|
| 292 |
+ printf "%.2f %s", b, u[i]; |
|
| 293 |
+ } |
|
| 294 |
+ }' |
|
| 295 |
+} |
|
| 296 |
+ |
|
| 265 | 297 |
print_final_report() {
|
| 266 | 298 |
local total_elapsed_sec="$1" |
| 267 | 299 |
local total_elapsed_fmt="$2" |
@@ -273,6 +305,12 @@ print_final_report() {
|
||
| 273 | 305 |
local avg_file_real_time_fmt="$8" |
| 274 | 306 |
local avg_video_time_sec="$9" |
| 275 | 307 |
local avg_video_time_fmt="${10}"
|
| 308 |
+ local startup_warmup_sec="${11}"
|
|
| 309 |
+ local startup_warmup_fmt="${12}"
|
|
| 310 |
+ local staging_warmup_sec="${13}"
|
|
| 311 |
+ local staging_warmup_fmt="${14}"
|
|
| 312 |
+ local input_bytes_processed="${15}"
|
|
| 313 |
+ local output_bytes_processed="${16}"
|
|
| 276 | 314 |
|
| 277 | 315 |
printf '\n' |
| 278 | 316 |
printf 'Run Summary\n' |
@@ -297,8 +335,22 @@ print_final_report() {
|
||
| 297 | 335 |
printf '| %-25s | %7s | %-8s |\n' "Encode time total" "${TOTAL_VIDEO_TIME_SEC}s" "$(format_seconds "$TOTAL_VIDEO_TIME_SEC")"
|
| 298 | 336 |
printf '| %-25s | %7s | %-8s |\n' "Post-processing total" "${file_post_total_sec}s" "$file_post_total_fmt"
|
| 299 | 337 |
printf '| %-25s | %7s | %-8s |\n' "Non-file overhead" "${run_non_file_overhead_sec}s" "$run_non_file_overhead_fmt"
|
| 338 |
+ if [[ "$startup_warmup_sec" -ge 0 ]]; then |
|
| 339 |
+ printf '| %-25s | %7s | %-8s |\n' "Startup warm-up" "${startup_warmup_sec}s" "$startup_warmup_fmt"
|
|
| 340 |
+ fi |
|
| 341 |
+ if [[ "$staging_warmup_sec" -ge 0 ]]; then |
|
| 342 |
+ printf '| %-25s | %7s | %-8s |\n' "Staging warm-up" "${staging_warmup_sec}s" "$staging_warmup_fmt"
|
|
| 343 |
+ fi |
|
| 300 | 344 |
printf '+---------------------------+---------+----------+\n' |
| 301 | 345 |
|
| 346 |
+ printf '\nData Volume\n' |
|
| 347 |
+ printf '+---------------------------+----------------+-----------------+\n' |
|
| 348 |
+ printf '| %-25s | %-14s | %-15s |\n' "Metric" "Bytes" "Human" |
|
| 349 |
+ printf '+---------------------------+----------------+-----------------+\n' |
|
| 350 |
+ printf '| %-25s | %14s | %-15s |\n' "Input processed" "${input_bytes_processed} B" "$(format_bytes_human "$input_bytes_processed")"
|
|
| 351 |
+ printf '| %-25s | %14s | %-15s |\n' "Output written" "${output_bytes_processed} B" "$(format_bytes_human "$output_bytes_processed")"
|
|
| 352 |
+ printf '+---------------------------+----------------+-----------------+\n' |
|
| 353 |
+ |
|
| 302 | 354 |
printf '\nPer-File Averages\n' |
| 303 | 355 |
printf '+---------------------------+---------+----------+\n' |
| 304 | 356 |
printf '| %-25s | %-7s | %-8s |\n' "Metric" "Seconds" "Elapsed" |
@@ -416,6 +468,55 @@ path_is_within() {
|
||
| 416 | 468 |
[[ "$child" == "$parent" || "$child" == "$parent"/* ]] |
| 417 | 469 |
} |
| 418 | 470 |
|
| 471 |
+file_size_bytes_or_zero() {
|
|
| 472 |
+ local file_path="$1" |
|
| 473 |
+ local file_size="0" |
|
| 474 |
+ |
|
| 475 |
+ file_size="$(stat -f%z "$file_path" 2>/dev/null || true)" |
|
| 476 |
+ if [[ ! "$file_size" =~ ^[0-9]+$ ]]; then |
|
| 477 |
+ file_size="$(stat -c%s "$file_path" 2>/dev/null || true)" |
|
| 478 |
+ fi |
|
| 479 |
+ |
|
| 480 |
+ if [[ "$file_size" =~ ^[0-9]+$ ]]; then |
|
| 481 |
+ printf '%s\n' "$file_size" |
|
| 482 |
+ else |
|
| 483 |
+ printf '0\n' |
|
| 484 |
+ fi |
|
| 485 |
+} |
|
| 486 |
+ |
|
| 487 |
+dir_available_bytes_or_zero() {
|
|
| 488 |
+ local dir_path="$1" |
|
| 489 |
+ local avail_kb="" |
|
| 490 |
+ |
|
| 491 |
+ avail_kb="$(df -Pk "$dir_path" 2>/dev/null | awk 'NR==2 {print $4}' || true)"
|
|
| 492 |
+ if [[ "$avail_kb" =~ ^[0-9]+$ ]]; then |
|
| 493 |
+ printf '%s\n' $((avail_kb * 1024)) |
|
| 494 |
+ else |
|
| 495 |
+ printf '0\n' |
|
| 496 |
+ fi |
|
| 497 |
+} |
|
| 498 |
+ |
|
| 499 |
+staging_has_space_for_input() {
|
|
| 500 |
+ local staging_dir="$1" |
|
| 501 |
+ local input_file="$2" |
|
| 502 |
+ local input_size_bytes=0 |
|
| 503 |
+ local needed_bytes=0 |
|
| 504 |
+ local available_bytes=0 |
|
| 505 |
+ |
|
| 506 |
+ [[ -n "$staging_dir" && -d "$staging_dir" && -w "$staging_dir" ]] || return 1 |
|
| 507 |
+ |
|
| 508 |
+ input_size_bytes="$(file_size_bytes_or_zero "$input_file")" |
|
| 509 |
+ if [[ "$input_size_bytes" -le 0 ]]; then |
|
| 510 |
+ return 1 |
|
| 511 |
+ fi |
|
| 512 |
+ |
|
| 513 |
+ # Keep one simple rule: need roughly 2x input size in staging. |
|
| 514 |
+ # This covers temp output plus metadata rewrite overhead. |
|
| 515 |
+ needed_bytes=$((input_size_bytes * 2)) |
|
| 516 |
+ available_bytes="$(dir_available_bytes_or_zero "$staging_dir")" |
|
| 517 |
+ [[ "$available_bytes" -ge "$needed_bytes" ]] |
|
| 518 |
+} |
|
| 519 |
+ |
|
| 419 | 520 |
join_cmd_for_log() {
|
| 420 | 521 |
local out="" |
| 421 | 522 |
local arg |
@@ -446,6 +547,16 @@ parse_args() {
|
||
| 446 | 547 |
STAGING_PROVIDED=true |
| 447 | 548 |
shift 2 |
| 448 | 549 |
;; |
| 550 |
+ --staging-ramdisk-mb) |
|
| 551 |
+ require_value "$1" "${2:-}"
|
|
| 552 |
+ STAGING_RAMDISK_MB="$2" |
|
| 553 |
+ shift 2 |
|
| 554 |
+ ;; |
|
| 555 |
+ --debug-timing) |
|
| 556 |
+ require_value "$1" "${2:-}"
|
|
| 557 |
+ DEBUG_TIMING_LIMIT="$2" |
|
| 558 |
+ shift 2 |
|
| 559 |
+ ;; |
|
| 449 | 560 |
--mode) |
| 450 | 561 |
require_value "$1" "${2:-}"
|
| 451 | 562 |
MODE="$2" |
@@ -541,6 +652,22 @@ parse_args() {
|
||
| 541 | 652 |
if [[ -n "$CRF_OVERRIDE" && ! "$CRF_OVERRIDE" =~ ^[0-9]+$ ]]; then |
| 542 | 653 |
die "--crf must be an integer" |
| 543 | 654 |
fi |
| 655 |
+ |
|
| 656 |
+ if [[ "$DEBUG_TIMING_LIMIT" != "0" ]]; then |
|
| 657 |
+ if ! [[ "$DEBUG_TIMING_LIMIT" =~ ^[0-9]+$ ]]; then |
|
| 658 |
+ die "--debug-timing must be a positive integer" |
|
| 659 |
+ fi |
|
| 660 |
+ if [[ "$DEBUG_TIMING_LIMIT" -le 0 ]]; then |
|
| 661 |
+ die "--debug-timing must be greater than 0" |
|
| 662 |
+ fi |
|
| 663 |
+ fi |
|
| 664 |
+ |
|
| 665 |
+ if ! [[ "$STAGING_RAMDISK_MB" =~ ^[0-9]+$ ]]; then |
|
| 666 |
+ die "--staging-ramdisk-mb must be a positive integer" |
|
| 667 |
+ fi |
|
| 668 |
+ if [[ "$STAGING_RAMDISK_MB" -le 0 ]]; then |
|
| 669 |
+ die "--staging-ramdisk-mb must be greater than 0" |
|
| 670 |
+ fi |
|
| 544 | 671 |
} |
| 545 | 672 |
|
| 546 | 673 |
check_tools() {
|
@@ -957,6 +1084,96 @@ normalize_dest_dir() {
|
||
| 957 | 1084 |
DEST_DIR="$(to_abs_path "$DEST_DIR")" |
| 958 | 1085 |
} |
| 959 | 1086 |
|
| 1087 |
+create_missing_staging_ramdisk_if_needed() {
|
|
| 1088 |
+ local staging_path="$1" |
|
| 1089 |
+ local ramdisk_name="" |
|
| 1090 |
+ local sectors=0 |
|
| 1091 |
+ local dev="" |
|
| 1092 |
+ local mount_point="" |
|
| 1093 |
+ |
|
| 1094 |
+ staging_path="${staging_path%/}"
|
|
| 1095 |
+ |
|
| 1096 |
+ if [[ -d "$staging_path" ]]; then |
|
| 1097 |
+ printf '%s\n' "$staging_path" |
|
| 1098 |
+ return |
|
| 1099 |
+ fi |
|
| 1100 |
+ |
|
| 1101 |
+ if [[ "$(uname -s)" != "Darwin" ]]; then |
|
| 1102 |
+ return |
|
| 1103 |
+ fi |
|
| 1104 |
+ |
|
| 1105 |
+ case "$staging_path" in |
|
| 1106 |
+ /Volumes/*) |
|
| 1107 |
+ ;; |
|
| 1108 |
+ *) |
|
| 1109 |
+ return |
|
| 1110 |
+ ;; |
|
| 1111 |
+ esac |
|
| 1112 |
+ |
|
| 1113 |
+ ramdisk_name="$(basename "$staging_path")" |
|
| 1114 |
+ if [[ -z "$ramdisk_name" || "$ramdisk_name" == "." || "$ramdisk_name" == ".." ]]; then |
|
| 1115 |
+ return |
|
| 1116 |
+ fi |
|
| 1117 |
+ |
|
| 1118 |
+ if [[ "$staging_path" != "/Volumes/$ramdisk_name" ]]; then |
|
| 1119 |
+ # Only auto-create for top-level /Volumes/<Name>, not nested paths. |
|
| 1120 |
+ return |
|
| 1121 |
+ fi |
|
| 1122 |
+ |
|
| 1123 |
+ [[ -x "/usr/bin/hdiutil" ]] || die "hdiutil not found; cannot auto-create RAM disk" |
|
| 1124 |
+ [[ -x "/usr/sbin/diskutil" ]] || die "diskutil not found; cannot auto-create RAM disk" |
|
| 1125 |
+ |
|
| 1126 |
+ sectors=$((STAGING_RAMDISK_MB * 2048)) |
|
| 1127 |
+ vlog_msg "INFO" "Creating RAM disk for staging: /Volumes/$ramdisk_name (${STAGING_RAMDISK_MB}MB)"
|
|
| 1128 |
+ dev="$(/usr/bin/hdiutil attach -nomount "ram://$sectors" 2>/dev/null | /usr/bin/awk 'NR==1 {print $1}' || true)"
|
|
| 1129 |
+ if [[ -z "$dev" ]]; then |
|
| 1130 |
+ return |
|
| 1131 |
+ fi |
|
| 1132 |
+ |
|
| 1133 |
+ if ! /usr/sbin/diskutil eraseVolume APFS "$ramdisk_name" "$dev" >/dev/null 2>&1; then |
|
| 1134 |
+ /usr/bin/hdiutil detach "$dev" >/dev/null 2>&1 || true |
|
| 1135 |
+ return |
|
| 1136 |
+ fi |
|
| 1137 |
+ |
|
| 1138 |
+ mount_point="$(/usr/sbin/diskutil info "$dev" 2>/dev/null | /usr/bin/awk -F': *' '/Mount Point/ {print $2; exit}')"
|
|
| 1139 |
+ if [[ -n "$mount_point" && -d "$mount_point" ]]; then |
|
| 1140 |
+ AUTO_CREATED_STAGING_RAMDISK=true |
|
| 1141 |
+ AUTO_CREATED_STAGING_PATH="$mount_point" |
|
| 1142 |
+ STAGING_RAMDISK_CREATED_AT="$(date +%s)" |
|
| 1143 |
+ printf '%s\n' "$mount_point" |
|
| 1144 |
+ return |
|
| 1145 |
+ fi |
|
| 1146 |
+ |
|
| 1147 |
+ if [[ -d "$staging_path" ]]; then |
|
| 1148 |
+ AUTO_CREATED_STAGING_RAMDISK=true |
|
| 1149 |
+ AUTO_CREATED_STAGING_PATH="$staging_path" |
|
| 1150 |
+ STAGING_RAMDISK_CREATED_AT="$(date +%s)" |
|
| 1151 |
+ printf '%s\n' "$staging_path" |
|
| 1152 |
+ return |
|
| 1153 |
+ fi |
|
| 1154 |
+} |
|
| 1155 |
+ |
|
| 1156 |
+attempt_unmount_auto_staging_ramdisk() {
|
|
| 1157 |
+ if [[ "$AUTO_CREATED_STAGING_RAMDISK" != true || -z "$AUTO_CREATED_STAGING_PATH" ]]; then |
|
| 1158 |
+ return |
|
| 1159 |
+ fi |
|
| 1160 |
+ |
|
| 1161 |
+ if [[ "$(uname -s)" != "Darwin" ]]; then |
|
| 1162 |
+ return |
|
| 1163 |
+ fi |
|
| 1164 |
+ |
|
| 1165 |
+ if /usr/sbin/diskutil eject "$AUTO_CREATED_STAGING_PATH" >/dev/null 2>&1; then |
|
| 1166 |
+ log_msg "INFO" "Auto-created staging RAM disk unmounted: $AUTO_CREATED_STAGING_PATH" |
|
| 1167 |
+ return |
|
| 1168 |
+ fi |
|
| 1169 |
+ |
|
| 1170 |
+ if [[ -d "$AUTO_CREATED_STAGING_PATH" ]]; then |
|
| 1171 |
+ log_msg "WARN" "Could not unmount auto-created staging RAM disk; it remains mounted: $AUTO_CREATED_STAGING_PATH" |
|
| 1172 |
+ else |
|
| 1173 |
+ log_msg "WARN" "Could not confirm unmount status for auto-created staging RAM disk: $AUTO_CREATED_STAGING_PATH" |
|
| 1174 |
+ fi |
|
| 1175 |
+} |
|
| 1176 |
+ |
|
| 960 | 1177 |
normalize_staging_dir() {
|
| 961 | 1178 |
if [[ "$STAGING_PROVIDED" != true ]]; then |
| 962 | 1179 |
STAGING_DIR="" |
@@ -964,6 +1181,16 @@ normalize_staging_dir() {
|
||
| 964 | 1181 |
fi |
| 965 | 1182 |
|
| 966 | 1183 |
STAGING_DIR="$(to_abs_path "$STAGING_DIR")" |
| 1184 |
+ if [[ ! -d "$STAGING_DIR" ]]; then |
|
| 1185 |
+ local created_staging_dir="" |
|
| 1186 |
+ created_staging_dir="$(create_missing_staging_ramdisk_if_needed "$STAGING_DIR")" |
|
| 1187 |
+ if [[ -n "$created_staging_dir" && -d "$created_staging_dir" ]]; then |
|
| 1188 |
+ STAGING_DIR="$created_staging_dir" |
|
| 1189 |
+ log_msg "INFO" "Created staging RAM disk: $STAGING_DIR" |
|
| 1190 |
+ else |
|
| 1191 |
+ die "Staging directory not found: $STAGING_DIR" |
|
| 1192 |
+ fi |
|
| 1193 |
+ fi |
|
| 967 | 1194 |
[[ -d "$STAGING_DIR" ]] || die "Staging directory not found: $STAGING_DIR" |
| 968 | 1195 |
STAGING_DIR="$(cd "$STAGING_DIR" && pwd)" |
| 969 | 1196 |
[[ -w "$STAGING_DIR" ]] || die "Staging directory not writable: $STAGING_DIR" |
@@ -1047,7 +1274,9 @@ process_video_file() {
|
||
| 1047 | 1274 |
local rel_path output_file temp_output_file out_dir |
| 1048 | 1275 |
local display_path |
| 1049 | 1276 |
local encode_input_file |
| 1277 |
+ local preferred_temp_dir="" |
|
| 1050 | 1278 |
local repacked_input_file="" |
| 1279 |
+ local input_size_bytes=0 output_size_bytes=0 |
|
| 1051 | 1280 |
local file_started_at file_ended_at file_real_elapsed_sec |
| 1052 | 1281 |
local encode_started_at encode_ended_at encode_elapsed_sec=0 |
| 1053 | 1282 |
local post_elapsed_sec |
@@ -1101,14 +1330,22 @@ process_video_file() {
|
||
| 1101 | 1330 |
|
| 1102 | 1331 |
build_video_args |
| 1103 | 1332 |
|
| 1104 |
- temp_output_file="$(make_temp_output_file "$output_file" "$STAGING_DIR")" |
|
| 1333 |
+ preferred_temp_dir="$STAGING_DIR" |
|
| 1334 |
+ if [[ "$STAGING_PROVIDED" == true && -n "$STAGING_DIR" ]]; then |
|
| 1335 |
+ if ! staging_has_space_for_input "$STAGING_DIR" "$encode_input_file"; then |
|
| 1336 |
+ preferred_temp_dir="" |
|
| 1337 |
+ log_msg "WARN" "Insufficient staging space; using destination temp path for: $input_file" |
|
| 1338 |
+ fi |
|
| 1339 |
+ fi |
|
| 1340 |
+ |
|
| 1341 |
+ temp_output_file="$(make_temp_output_file "$output_file" "$preferred_temp_dir")" |
|
| 1105 | 1342 |
if [[ -z "$temp_output_file" ]]; then |
| 1106 | 1343 |
ERRORS=$((ERRORS + 1)) |
| 1107 | 1344 |
DESTINATION_FAILURES=$((DESTINATION_FAILURES + 1)) |
| 1108 | 1345 |
log_msg "ERROR" "Could not create temporary output file: $output_file" |
| 1109 | 1346 |
return 3 |
| 1110 | 1347 |
fi |
| 1111 |
- if [[ "$STAGING_PROVIDED" == true ]] && ! path_is_within "$temp_output_file" "$STAGING_DIR"; then |
|
| 1348 |
+ if [[ "$STAGING_PROVIDED" == true && -n "$STAGING_DIR" ]] && ! path_is_within "$temp_output_file" "$STAGING_DIR"; then |
|
| 1112 | 1349 |
log_msg "WARN" "Staging unavailable for temp output; using destination directory: $temp_output_file" |
| 1113 | 1350 |
fi |
| 1114 | 1351 |
|
@@ -1144,6 +1381,18 @@ process_video_file() {
|
||
| 1144 | 1381 |
fi |
| 1145 | 1382 |
|
| 1146 | 1383 |
vlog_msg "INFO" "Encoding: $input_file -> $output_file (temp: $temp_output_file)" |
| 1384 |
+ if [[ "$FIRST_ENCODE_STARTED_AT" -eq 0 ]]; then |
|
| 1385 |
+ local startup_warmup_sec=0 |
|
| 1386 |
+ local warmup_elapsed_sec=0 |
|
| 1387 |
+ FIRST_ENCODE_STARTED_AT="$(date +%s)" |
|
| 1388 |
+ if [[ "$AUTO_CREATED_STAGING_RAMDISK" == true && "$STAGING_RAMDISK_CREATED_AT" -gt 0 ]]; then |
|
| 1389 |
+ warmup_elapsed_sec=$((FIRST_ENCODE_STARTED_AT - STAGING_RAMDISK_CREATED_AT)) |
|
| 1390 |
+ if [[ "$warmup_elapsed_sec" -lt 0 ]]; then |
|
| 1391 |
+ warmup_elapsed_sec=0 |
|
| 1392 |
+ fi |
|
| 1393 |
+ log_msg "INFO" "Staging RAM disk warm-up before first encode: ${warmup_elapsed_sec}s / $(format_seconds "$warmup_elapsed_sec")"
|
|
| 1394 |
+ fi |
|
| 1395 |
+ fi |
|
| 1147 | 1396 |
encode_started_at="$(date +%s)" |
| 1148 | 1397 |
vlog_msg "CHECKPOINT" "encode_start: $input_file" |
| 1149 | 1398 |
|
@@ -1251,10 +1500,6 @@ process_video_file() {
|
||
| 1251 | 1500 |
if [[ "$MOVE_SOURCE" == true ]]; then |
| 1252 | 1501 |
if ! validate_transcoded_output "$encode_input_file" "$temp_output_file"; then |
| 1253 | 1502 |
cleanup_transcode_artifacts "$temp_output_file" "$output_file" |
| 1254 |
- if [[ "$STOP_AFTER_CURRENT" == true && "$INTERRUPT_COUNT" -gt 0 ]]; then |
|
| 1255 |
- cleanup_repacked_input "$repacked_input_file" |
|
| 1256 |
- return 4 |
|
| 1257 |
- fi |
|
| 1258 | 1503 |
ERRORS=$((ERRORS + 1)) |
| 1259 | 1504 |
if destination_cannot_accept_file "$input_file" "$out_dir" ""; then |
| 1260 | 1505 |
DESTINATION_FAILURES=$((DESTINATION_FAILURES + 1)) |
@@ -1263,6 +1508,7 @@ process_video_file() {
|
||
| 1263 | 1508 |
fi |
| 1264 | 1509 |
# Validation failed but destination is healthy: the source or encoder produced |
| 1265 | 1510 |
# a corrupt/truncated output. Treat as source error so --keep-going can skip it. |
| 1511 |
+ INVALID_SOURCES_SKIPPED=$((INVALID_SOURCES_SKIPPED + 1)) |
|
| 1266 | 1512 |
log_msg "ERROR" "Encode produced invalid output (source may be corrupt): $input_file" |
| 1267 | 1513 |
cleanup_repacked_input "$repacked_input_file" |
| 1268 | 1514 |
return 2 |
@@ -1291,6 +1537,11 @@ process_video_file() {
|
||
| 1291 | 1537 |
fi |
| 1292 | 1538 |
fi |
| 1293 | 1539 |
|
| 1540 |
+ input_size_bytes="$(file_size_bytes_or_zero "$input_file")" |
|
| 1541 |
+ output_size_bytes="$(file_size_bytes_or_zero "$output_file")" |
|
| 1542 |
+ INPUT_BYTES_PROCESSED=$((INPUT_BYTES_PROCESSED + input_size_bytes)) |
|
| 1543 |
+ OUTPUT_BYTES_PROCESSED=$((OUTPUT_BYTES_PROCESSED + output_size_bytes)) |
|
| 1544 |
+ |
|
| 1294 | 1545 |
if [[ "$MOVE_SOURCE" == true ]]; then |
| 1295 | 1546 |
if rm -f "$input_file"; then |
| 1296 | 1547 |
vlog_msg "INFO" "Removed source after successful validation: $input_file" |
@@ -1434,6 +1685,7 @@ EOF |
||
| 1434 | 1685 |
main() {
|
| 1435 | 1686 |
local total_started_at total_ended_at total_elapsed_sec total_elapsed_fmt |
| 1436 | 1687 |
total_started_at="$(date +%s)" |
| 1688 |
+ RUN_STARTED_AT="$total_started_at" |
|
| 1437 | 1689 |
|
| 1438 | 1690 |
trap 'handle_interrupt' INT TERM |
| 1439 | 1691 |
|
@@ -1472,13 +1724,33 @@ main() {
|
||
| 1472 | 1724 |
|
| 1473 | 1725 |
local process_rc=0 |
| 1474 | 1726 |
if process_video_file "$f"; then |
| 1475 |
- continue |
|
| 1727 |
+ process_rc=0 |
|
| 1476 | 1728 |
else |
| 1477 | 1729 |
process_rc=$? |
| 1478 | 1730 |
fi |
| 1479 | 1731 |
|
| 1732 |
+ if [[ "$DEBUG_TIMING_LIMIT" -gt 0 ]]; then |
|
| 1733 |
+ DEBUG_TIMING_FILES=$((DEBUG_TIMING_FILES + 1)) |
|
| 1734 |
+ if [[ "$DEBUG_TIMING_FILES" -ge "$DEBUG_TIMING_LIMIT" ]]; then |
|
| 1735 |
+ DEBUG_TIMING_STOPPED=true |
|
| 1736 |
+ fi |
|
| 1737 |
+ fi |
|
| 1738 |
+ |
|
| 1739 |
+ if [[ "$DEBUG_TIMING_STOPPED" == true ]]; then |
|
| 1740 |
+ log_msg "INFO" "Debug timing limit reached after $DEBUG_TIMING_FILES file(s); stopping before next file" |
|
| 1741 |
+ break |
|
| 1742 |
+ fi |
|
| 1743 |
+ |
|
| 1744 |
+ if [[ "$process_rc" -eq 0 ]]; then |
|
| 1745 |
+ continue |
|
| 1746 |
+ fi |
|
| 1747 |
+ |
|
| 1480 | 1748 |
case "$process_rc" in |
| 1481 | 1749 |
2) |
| 1750 |
+ if [[ "$STOP_AFTER_CURRENT" == true && "$INTERRUPT_COUNT" -gt 0 ]]; then |
|
| 1751 |
+ log_msg "INFO" "Stopped by user after current file" |
|
| 1752 |
+ break |
|
| 1753 |
+ fi |
|
| 1482 | 1754 |
log_msg "INFO" "Continuing after unreadable/corrupted source file" |
| 1483 | 1755 |
continue |
| 1484 | 1756 |
;; |
@@ -1501,7 +1773,9 @@ main() {
|
||
| 1501 | 1773 |
esac |
| 1502 | 1774 |
done |
| 1503 | 1775 |
|
| 1504 |
- if [[ "$STOP_AFTER_CURRENT" == true ]]; then |
|
| 1776 |
+ if [[ "$DEBUG_TIMING_STOPPED" == true ]]; then |
|
| 1777 |
+ log_msg "INFO" "Skipping sidecar copy and manifest because debug timing mode requested early stop" |
|
| 1778 |
+ elif [[ "$STOP_AFTER_CURRENT" == true ]]; then |
|
| 1505 | 1779 |
log_msg "INFO" "Skipping sidecar copy and manifest because run was stopped by user" |
| 1506 | 1780 |
elif [[ "$ERRORS" -eq 0 ]]; then |
| 1507 | 1781 |
copy_sidecars_json |
@@ -1518,6 +1792,8 @@ main() {
|
||
| 1518 | 1792 |
local avg_file_real_time_sec=0 avg_file_real_time_fmt="00:00:00" |
| 1519 | 1793 |
local file_post_total_sec=0 file_post_total_fmt="00:00:00" |
| 1520 | 1794 |
local run_non_file_overhead_sec=0 run_non_file_overhead_fmt="00:00:00" |
| 1795 |
+ local startup_warmup_sec=-1 startup_warmup_fmt="n/a" |
|
| 1796 |
+ local staging_warmup_sec=-1 staging_warmup_fmt="n/a" |
|
| 1521 | 1797 |
|
| 1522 | 1798 |
if [[ "$VIDEOS_PROCESSED" -gt 0 ]]; then |
| 1523 | 1799 |
avg_video_time_sec=$((TOTAL_VIDEO_TIME_SEC / VIDEOS_PROCESSED)) |
@@ -1538,6 +1814,22 @@ main() {
|
||
| 1538 | 1814 |
fi |
| 1539 | 1815 |
run_non_file_overhead_fmt="$(format_seconds "$run_non_file_overhead_sec")" |
| 1540 | 1816 |
|
| 1817 |
+ if [[ "$RUN_STARTED_AT" -gt 0 && "$FIRST_ENCODE_STARTED_AT" -gt 0 ]]; then |
|
| 1818 |
+ startup_warmup_sec=$((FIRST_ENCODE_STARTED_AT - RUN_STARTED_AT)) |
|
| 1819 |
+ if [[ "$startup_warmup_sec" -lt 0 ]]; then |
|
| 1820 |
+ startup_warmup_sec=0 |
|
| 1821 |
+ fi |
|
| 1822 |
+ startup_warmup_fmt="$(format_seconds "$startup_warmup_sec")" |
|
| 1823 |
+ fi |
|
| 1824 |
+ |
|
| 1825 |
+ if [[ "$AUTO_CREATED_STAGING_RAMDISK" == true && "$STAGING_RAMDISK_CREATED_AT" -gt 0 && "$FIRST_ENCODE_STARTED_AT" -gt 0 ]]; then |
|
| 1826 |
+ staging_warmup_sec=$((FIRST_ENCODE_STARTED_AT - STAGING_RAMDISK_CREATED_AT)) |
|
| 1827 |
+ if [[ "$staging_warmup_sec" -lt 0 ]]; then |
|
| 1828 |
+ staging_warmup_sec=0 |
|
| 1829 |
+ fi |
|
| 1830 |
+ staging_warmup_fmt="$(format_seconds "$staging_warmup_sec")" |
|
| 1831 |
+ fi |
|
| 1832 |
+ |
|
| 1541 | 1833 |
print_final_report \ |
| 1542 | 1834 |
"$total_elapsed_sec" \ |
| 1543 | 1835 |
"$total_elapsed_fmt" \ |
@@ -1548,7 +1840,15 @@ main() {
|
||
| 1548 | 1840 |
"$avg_file_real_time_sec" \ |
| 1549 | 1841 |
"$avg_file_real_time_fmt" \ |
| 1550 | 1842 |
"$avg_video_time_sec" \ |
| 1551 |
- "$avg_video_time_fmt" |
|
| 1843 |
+ "$avg_video_time_fmt" \ |
|
| 1844 |
+ "$startup_warmup_sec" \ |
|
| 1845 |
+ "$startup_warmup_fmt" \ |
|
| 1846 |
+ "$staging_warmup_sec" \ |
|
| 1847 |
+ "$staging_warmup_fmt" \ |
|
| 1848 |
+ "$INPUT_BYTES_PROCESSED" \ |
|
| 1849 |
+ "$OUTPUT_BYTES_PROCESSED" |
|
| 1850 |
+ |
|
| 1851 |
+ attempt_unmount_auto_staging_ramdisk |
|
| 1552 | 1852 |
|
| 1553 | 1853 |
if [[ "$ERRORS" -gt 0 ]]; then |
| 1554 | 1854 |
exit 1 |