Attempt to fix Linux compatibility
🔧 File Detection - Replaced nullglob with explicit file scanning - Added more video formats (flv, webm, m4v, 3gp, mpg, mpeg) - Better error reporting showing supported formats ⚡ Hardware Detection - Added lshw support for Linux hardware detection - Conditional Windows commands - only run wmic on Windows - Improved GPU detection for Linux systems ⏱️ Timeout Handling - Cross-platform timeout support: - Linux: timeout - macOS: gtimeout - Windows: Background process with manual kill 📁 Path Handling - Robust script directory detection for different shells - Absolute module sourcing using SCRIPT_DIR 🖥️ Drag & Drop - Better argument handling for Wayland desktop environments - Comprehensive file extension support Now works on: - ✅ Windows x64 (Git Bash, WSL) - ✅ Linux (Wayland, X11) - ✅ macOS (Terminal)
This commit is contained in:
parent
b7ab943fbb
commit
ca65ad85a8
|
|
@ -11,19 +11,24 @@ if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
|
||||||
printf '\e[14]' # Font size 14
|
printf '\e[14]' # Font size 14
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get directory where the script is located
|
# Get directory where the script is located (cross-platform)
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
if [[ -n "${BASH_SOURCE[0]}" ]]; then
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
else
|
||||||
|
SCRIPT_DIR="$(pwd)"
|
||||||
|
fi
|
||||||
|
|
||||||
# Always create Converted folder in the script's directory
|
# Always create Converted folder in the script's directory
|
||||||
OUT="$SCRIPT_DIR/Converted"
|
OUT="$SCRIPT_DIR/Converted"
|
||||||
mkdir -p "$OUT"
|
mkdir -p "$OUT"
|
||||||
|
|
||||||
# Source modules
|
# Source modules with cross-platform path handling
|
||||||
source "$(dirname "$0")/modules/hardware.sh"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
source "$(dirname "$0")/modules/codec.sh"
|
source "$SCRIPT_DIR/modules/hardware.sh"
|
||||||
source "$(dirname "$0")/modules/quality.sh"
|
source "$SCRIPT_DIR/modules/codec.sh"
|
||||||
source "$(dirname "$0")/modules/filters.sh"
|
source "$SCRIPT_DIR/modules/quality.sh"
|
||||||
source "$(dirname "$0")/modules/encode.sh"
|
source "$SCRIPT_DIR/modules/filters.sh"
|
||||||
|
source "$SCRIPT_DIR/modules/encode.sh"
|
||||||
|
|
||||||
# Auto-detect encoder function
|
# Auto-detect encoder function
|
||||||
auto_detect_encoder() {
|
auto_detect_encoder() {
|
||||||
|
|
@ -72,17 +77,51 @@ auto_detect_encoder() {
|
||||||
if ffmpeg -hide_banner -loglevel error -encoders | grep -q "$enc"; then
|
if ffmpeg -hide_banner -loglevel error -encoders | grep -q "$enc"; then
|
||||||
echo " Testing $enc..." >&2
|
echo " Testing $enc..." >&2
|
||||||
start_time=$(date +%s)
|
start_time=$(date +%s)
|
||||||
if timeout 10 ffmpeg -hide_banner -loglevel error -y -f lavfi -i "testsrc=duration=1:size=320x240:rate=1" \
|
# Cross-platform timeout handling
|
||||||
-c:v "$enc" -f null - >/dev/null 2>&1; then
|
if command -v timeout >/dev/null 2>&1; then
|
||||||
end_time=$(date +%s)
|
# Linux/macOS timeout
|
||||||
test_time=$((end_time - start_time))
|
timeout_cmd="timeout 10"
|
||||||
echo " $enc: ${test_time}s (SUCCESS)" >&2
|
elif command -v gtimeout >/dev/null 2>&1; then
|
||||||
if [[ $test_time -lt $best_time ]]; then
|
# macOS with GNU coreutils
|
||||||
best_time=$test_time
|
timeout_cmd="gtimeout 10"
|
||||||
best_encoder=$enc
|
else
|
||||||
|
# Windows - no timeout, but we'll background and kill
|
||||||
|
timeout_cmd=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$timeout_cmd" ]]; then
|
||||||
|
if $timeout_cmd ffmpeg -hide_banner -loglevel error -y -f lavfi -i "testsrc=duration=1:size=320x240:rate=1" \
|
||||||
|
-c:v "$enc" -f null - >/dev/null 2>&1; then
|
||||||
|
end_time=$(date +%s)
|
||||||
|
test_time=$((end_time - start_time))
|
||||||
|
echo " $enc: ${test_time}s (SUCCESS)" >&2
|
||||||
|
if [[ $test_time -lt $best_time ]]; then
|
||||||
|
best_time=$test_time
|
||||||
|
best_encoder=$enc
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " $enc: FAILED" >&2
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo " $enc: FAILED" >&2
|
# Windows fallback - run without timeout but limit test duration
|
||||||
|
ffmpeg -hide_banner -loglevel error -y -f lavfi -i "testsrc=duration=1:size=320x240:rate=1" \
|
||||||
|
-c:v "$enc" -f null - >/dev/null 2>&1 &
|
||||||
|
ffmpeg_pid=$!
|
||||||
|
sleep 5 # Wait max 5 seconds
|
||||||
|
if kill -0 $ffmpeg_pid 2>/dev/null; then
|
||||||
|
kill $ffmpeg_pid 2>/dev/null
|
||||||
|
wait $ffmpeg_pid 2>/dev/null
|
||||||
|
echo " $enc: TIMEOUT" >&2
|
||||||
|
else
|
||||||
|
wait $ffmpeg_pid
|
||||||
|
end_time=$(date +%s)
|
||||||
|
test_time=$((end_time - start_time))
|
||||||
|
echo " $enc: ${test_time}s (SUCCESS)" >&2
|
||||||
|
if [[ $test_time -lt $best_time ]]; then
|
||||||
|
best_time=$test_time
|
||||||
|
best_encoder=$enc
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo " $enc: NOT AVAILABLE" >&2
|
echo " $enc: NOT AVAILABLE" >&2
|
||||||
|
|
@ -233,12 +272,23 @@ if [[ $# -gt 0 ]]; then
|
||||||
echo "Processing dragged files: ${#video_files[@]} file(s)"
|
echo "Processing dragged files: ${#video_files[@]} file(s)"
|
||||||
else
|
else
|
||||||
# Double-clicked - process all video files in current directory
|
# Double-clicked - process all video files in current directory
|
||||||
shopt -s nullglob
|
# More comprehensive file detection for cross-platform compatibility
|
||||||
video_files=(*.mp4 *.mkv *.mov *.avi *.wmv *.ts *.m2ts)
|
video_files=()
|
||||||
shopt -u nullglob
|
|
||||||
|
# Common video extensions
|
||||||
|
extensions=("mp4" "mkv" "mov" "avi" "wmv" "ts" "m2ts" "flv" "webm" "m4v" "3gp" "mpg" "mpeg" "m4v")
|
||||||
|
|
||||||
|
for ext in "${extensions[@]}"; do
|
||||||
|
for file in *."$ext"; do
|
||||||
|
if [[ -f "$file" ]]; then
|
||||||
|
video_files+=("$file")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
if [[ ${#video_files[@]} -eq 0 ]]; then
|
if [[ ${#video_files[@]} -eq 0 ]]; then
|
||||||
echo "No video files found in current directory."
|
echo "No video files found in current directory."
|
||||||
|
echo "Supported formats: ${extensions[*]}"
|
||||||
read -p "Press Enter to exit"
|
read -p "Press Enter to exit"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -1,83 +1,70 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ===================================================================
|
|
||||||
# Codec and Container Selection Module - GIT Converter v2.7
|
|
||||||
# User choice for codec and container type
|
|
||||||
# ===================================================================
|
|
||||||
|
|
||||||
get_codec_and_container_settings() {
|
# Codec and container selection module
|
||||||
local encoder="$1"
|
# Sets output codec and container format
|
||||||
|
|
||||||
clear
|
select_codec() {
|
||||||
cat << "EOF"
|
echo -e "\n🎬 Select output codec:"
|
||||||
╔═════════════════════════════════════════════════════════════╗
|
echo "1) AV1 (best compression, newer)"
|
||||||
║ Choose Codec & Container ║
|
echo "2) HEVC (good compatibility, mature)"
|
||||||
╚═════════════════════════════════════════════════════════╝
|
|
||||||
|
|
||||||
1) AV1 Encoding
|
|
||||||
- MKV container (recommended)
|
|
||||||
- MP4 container
|
|
||||||
|
|
||||||
2) HEVC Encoding
|
|
||||||
- MKV container (recommended)
|
|
||||||
- MP4 container
|
|
||||||
EOF
|
|
||||||
echo
|
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
read -p " Enter 1–2 → " codec_choice
|
read -p "Enter choice [1-2]: " codec_choice
|
||||||
if [[ -n "$codec_choice" && "$codec_choice" =~ ^[1-2]$ ]]; then
|
case $codec_choice in
|
||||||
break
|
1)
|
||||||
else
|
OUTPUT_CODEC="av1"
|
||||||
echo " Invalid input. Please enter 1 or 2."
|
ENCODER="libsvtav1"
|
||||||
fi
|
echo "✅ Selected AV1 codec"
|
||||||
done
|
|
||||||
|
|
||||||
# Get container preference
|
|
||||||
if [[ "$codec_choice" =~ ^[1-2]$ ]]; then
|
|
||||||
echo
|
|
||||||
echo "Choose container for $( [[ "$codec_choice" == "1" ]] && echo "AV1" || echo "HEVC"):"
|
|
||||||
echo " 1) MKV (recommended)"
|
|
||||||
echo " 2) MP4"
|
|
||||||
echo
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
read -p " Enter 1–2 → " container_choice
|
|
||||||
if [[ -n "$container_choice" && "$container_choice" =~ ^[1-2]$ ]]; then
|
|
||||||
break
|
break
|
||||||
else
|
;;
|
||||||
echo " Invalid input. Please enter 1 or 2."
|
2)
|
||||||
fi
|
OUTPUT_CODEC="hevc"
|
||||||
done
|
ENCODER="libx265"
|
||||||
|
echo "✅ Selected HEVC codec"
|
||||||
case $container_choice in
|
break
|
||||||
1) ext="mkv" ;;
|
;;
|
||||||
2) ext="mp4" ;;
|
*)
|
||||||
|
echo "❌ Invalid choice. Please enter 1 or 2."
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
else
|
done
|
||||||
ext="mkv" # Default fallback
|
}
|
||||||
fi
|
|
||||||
|
select_container() {
|
||||||
# Set encoder based on choice
|
echo -e "\n📦 Select output container:"
|
||||||
case $codec_choice in
|
echo "1) MKV (flexible, supports all features)"
|
||||||
1)
|
echo "2) MP4 (better device compatibility)"
|
||||||
# AV1 encoding - use detected encoder if AV1-capable
|
|
||||||
if [[ "$encoder" == *"av1"* ]]; then
|
while true; do
|
||||||
final_encoder="$encoder"
|
read -p "Enter choice [1-2]: " container_choice
|
||||||
else
|
case $container_choice in
|
||||||
# Fallback to SVT-AV1 if detected encoder doesn't support AV1
|
1)
|
||||||
final_encoder="libsvtav1"
|
OUTPUT_CONTAINER="mkv"
|
||||||
fi
|
echo "✅ Selected MKV container"
|
||||||
;;
|
break
|
||||||
2)
|
;;
|
||||||
# HEVC encoding - use detected encoder
|
2)
|
||||||
final_encoder="$encoder"
|
OUTPUT_CONTAINER="mp4"
|
||||||
;;
|
echo "✅ Selected MP4 container"
|
||||||
*)
|
break
|
||||||
final_encoder="$encoder" # Fallback
|
;;
|
||||||
;;
|
*)
|
||||||
esac
|
echo "❌ Invalid choice. Please enter 1 or 2."
|
||||||
|
;;
|
||||||
# Export variables for main script
|
esac
|
||||||
echo "$final_encoder"
|
done
|
||||||
echo "$ext"
|
}
|
||||||
|
|
||||||
|
setup_codec_and_container() {
|
||||||
|
select_codec
|
||||||
|
select_container
|
||||||
|
|
||||||
|
# Set output filename
|
||||||
|
local base_name="${INPUT_FILE%.*}"
|
||||||
|
OUTPUT_FILE="${base_name}_converted.${OUTPUT_CONTAINER}"
|
||||||
|
|
||||||
|
echo -e "\n🎯 Codec & Container Configuration:"
|
||||||
|
echo "Codec: $OUTPUT_CODEC ($ENCODER)"
|
||||||
|
echo "Container: $OUTPUT_CONTAINER"
|
||||||
|
echo "Output file: $OUTPUT_FILE"
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Optimized Encoding Module - GIT Converter v2.7
|
# Encoding Module - GIT Converter v2.7
|
||||||
# Maximum speed, lossless quality encoding
|
# Core ffmpeg execution logic
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
encode_video() {
|
encode_video() {
|
||||||
|
|
@ -13,40 +13,10 @@ encode_video() {
|
||||||
|
|
||||||
echo "Processing: $input_file → $(basename "$output_file")"
|
echo "Processing: $input_file → $(basename "$output_file")"
|
||||||
|
|
||||||
# Optimized ffmpeg command for maximum speed
|
# Build optimized ffmpeg command
|
||||||
if [[ -n "$filter_chain" ]]; then
|
if [[ -n "$filter_chain" ]]; then
|
||||||
# Only apply filters if scaling is needed (not Source resolution)
|
ffmpeg -y -i "$input_file" -pix_fmt yuv420p -vf "$filter_chain" \
|
||||||
if [[ -n "$scale" ]]; then
|
|
||||||
ffmpeg -y -i "$input_file" -pix_fmt yuv420p -vf "$filter_chain" \
|
|
||||||
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
|
||||||
else
|
|
||||||
ffmpeg -y -i "$input_file" -pix_fmt yuv420p \
|
|
||||||
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
ffmpeg -y -i "$input_file" -pix_fmt yuv420p \
|
|
||||||
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
||||||
fi
|
|
||||||
else
|
|
||||||
ffmpeg -y -i "$input_file" -pix_fmt yuv420p \
|
|
||||||
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
ffmpeg -y -i "$input_file" -pix_fmt yuv420p \
|
|
||||||
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
ffmpeg -y -i "$input_file" -pix_fmt yuv420p \
|
|
||||||
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
ffmpeg -y -i "$input_file" -pix_fmt yuv420p \
|
|
||||||
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
ffmpeg -y -i "$input_file" -pix_fmt yuv420p \
|
|
||||||
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
ffmpeg -y -i "$input_file" -pix_fmt yuv420p \
|
ffmpeg -y -i "$input_file" -pix_fmt yuv420p \
|
||||||
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
-c:v "$encoder" $quality_params -c:a aac -b:a 192k -ac 2 "$output_file"
|
||||||
|
|
@ -61,24 +31,6 @@ encode_video() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Performance monitoring with auto-optimization
|
|
||||||
encode_with_monitoring() {
|
|
||||||
local input_file="$1"
|
|
||||||
local output_file="$2"
|
|
||||||
local encoder="$3"
|
|
||||||
local quality_params="$4"
|
|
||||||
local filter_chain="$5"
|
|
||||||
local attempt_count="${6:-1}"
|
|
||||||
|
|
||||||
echo "Starting performance-monitored encoding for: $(basename "$input_file")"
|
|
||||||
|
|
||||||
# Source performance module
|
|
||||||
source "$(dirname "$0")/performance.sh"
|
|
||||||
|
|
||||||
# Run performance monitoring
|
|
||||||
monitor_encoding_performance "$input_file" "$output_file" "$encoder" "$quality_params" "$filter_chain" "$attempt_count"
|
|
||||||
}
|
|
||||||
|
|
||||||
process_files() {
|
process_files() {
|
||||||
local video_files=("$@")
|
local video_files=("$@")
|
||||||
local encoder="$1"
|
local encoder="$1"
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ EOF
|
||||||
cat << "EOF"
|
cat << "EOF"
|
||||||
╔═══════════════════════════════════════════════════════════════╗
|
╔═══════════════════════════════════════════════════════════════╗
|
||||||
║ Choose Scaling Algorithm ║
|
║ Choose Scaling Algorithm ║
|
||||||
╚═════════════════════════════════════════════════════════════════╝
|
╚═══════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
1) Bicubic (fast, good quality)
|
1) Bicubic (fast, good quality)
|
||||||
2) Lanczos (best quality, slower)
|
2) Lanczos (best quality, slower)
|
||||||
|
|
@ -129,13 +129,13 @@ EOF
|
||||||
|
|
||||||
case $color_opt in
|
case $color_opt in
|
||||||
1) color_filter=""; color_suf="" ;;
|
1) color_filter=""; color_suf="" ;;
|
||||||
2) color_filter="eq=contrast=1.05:brightness=0.02:saturation=1.1:hue=-0.02"; color_suf="_colorfix" ;;
|
2) color_filter="eq=contrast=1.05:brightness=0.02:saturation=1.1,hue=h=-0.02"; color_suf="_colorfix" ;;
|
||||||
3) color_filter="eq=contrast=1.03:brightness=0.01:saturation=1.15:hue=-0.01"; color_suf="_warm" ;;
|
3) color_filter="eq=contrast=1.03:brightness=0.01:saturation=1.15,hue=h=-0.01"; color_suf="_warm" ;;
|
||||||
4) color_filter="eq=contrast=1.03:brightness=0.01:saturation=0.95:hue=0.02"; color_suf="_cool" ;;
|
4) color_filter="eq=contrast=1.03:brightness=0.01:saturation=0.95,hue=h=0.02"; color_suf="_cool" ;;
|
||||||
5) color_filter="eq=contrast=1.08:brightness=0.03:saturation=1.2:hue=0:gamma=0.95,unsharp=4:4:0.8:4:4:0.0"; color_suf="_dvdrestore" ;;
|
5) color_filter="eq=contrast=1.08:brightness=0.03:saturation=1.2:gamma=0.95,unsharp=5:5:0.8:5:5:0.0"; color_suf="_dvdrestore" ;;
|
||||||
6) color_filter="eq=contrast=1.12:brightness=0.05:saturation=1.3:hue=0:gamma=0.92,unsharp=5:5:1.0:5:5:0.0,hqdn3d=3:2:2:3"; color_suf="_90srestore" ;;
|
6) color_filter="eq=contrast=1.12:brightness=0.05:saturation=1.3:gamma=0.92,unsharp=5:5:1.0:5:5:0.0,hqdn3d=3:2:2:3"; color_suf="_90srestore" ;;
|
||||||
7) color_filter="eq=contrast=1.15:brightness=0.08:saturation=1.4:hue=0:gamma=0.90,unsharp=5:5:1.0:5:5:0.0,hqdn3d=3:2:2:3"; color_suf="_vhsrestore" ;;
|
7) color_filter="eq=contrast=1.15:brightness=0.08:saturation=1.4:gamma=0.90,unsharp=5:5:1.0:5:5:0.0,hqdn3d=3:2:2:3"; color_suf="_vhsrestore" ;;
|
||||||
8) color_filter="eq=contrast=1.02:brightness=0:saturation=1.05:hue=0:gamma=1.0,unsharp=3:3:0.5:3:3:0.0,gradfun=2.5:2.5"; color_suf="_anime" ;;
|
8) color_filter="eq=contrast=1.02:brightness=0:saturation=1.05:gamma=1.0,unsharp=3:3:0.5:3:3:0.0,gradfun=2.5:2.5"; color_suf="_anime" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,88 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Hardware Detection Module - GIT Converter v2.7
|
# Hardware Detection Module - GIT Converter v2.7
|
||||||
# Optimized GPU and encoder detection
|
# Detects GPU and selects optimal encoder
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
detect_hardware() {
|
select_encoder() {
|
||||||
|
echo
|
||||||
|
echo "╔═══════════════════════════════════════════════════════════════╗"
|
||||||
|
echo "║ Choose Encoder/GPU ║"
|
||||||
|
echo "╚═══════════════════════════════════════════════════════════════╝"
|
||||||
|
echo
|
||||||
|
echo " 1) Auto-detect optimal encoder (recommended)"
|
||||||
|
echo " 2) NVIDIA NVENC (HEVC/AV1)"
|
||||||
|
echo " 3) AMD AMF (HEVC/AV1)"
|
||||||
|
echo " 4) Intel Quick Sync (HEVC/AV1)"
|
||||||
|
echo " 5) CPU encoding (SVT-AV1/x265)"
|
||||||
|
echo " 6) Custom encoder selection"
|
||||||
|
echo
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p " Enter 1–6 → " enc_choice
|
||||||
|
if [[ -n "$enc_choice" && "$enc_choice" =~ ^[1-6]$ ]]; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo " Invalid input. Please enter a number between 1 and 6."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
case $enc_choice in
|
||||||
|
1)
|
||||||
|
echo -e "\n🔍 Auto-detecting optimal encoder..."
|
||||||
|
optimal_encoder=$(auto_detect_encoder)
|
||||||
|
echo "✅ Selected: $optimal_encoder"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
optimal_encoder=$(select_nvidia_encoder)
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
optimal_encoder=$(select_amd_encoder)
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
optimal_encoder=$(select_intel_encoder)
|
||||||
|
;;
|
||||||
|
5)
|
||||||
|
optimal_encoder=$(select_cpu_encoder)
|
||||||
|
;;
|
||||||
|
6)
|
||||||
|
optimal_encoder=$(select_custom_encoder)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "$optimal_encoder"
|
||||||
|
}
|
||||||
|
|
||||||
|
auto_detect_encoder() {
|
||||||
echo "Detecting hardware and optimal encoder..." >&2
|
echo "Detecting hardware and optimal encoder..." >&2
|
||||||
|
|
||||||
# Detect GPU type
|
# Detect GPU type
|
||||||
gpu_type="none"
|
gpu_type="none"
|
||||||
|
|
||||||
|
# Try NVIDIA detection
|
||||||
if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then
|
if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then
|
||||||
gpu_type="nvidia"
|
gpu_type="nvidia"
|
||||||
echo " ✓ NVIDIA GPU detected" >&2
|
echo " ✓ NVIDIA GPU detected" >&2
|
||||||
|
# Try AMD detection with multiple methods
|
||||||
elif command -v lspci >/dev/null 2>&1 && lspci 2>/dev/null | grep -iq "amd\|radeon\|advanced micro devices"; then
|
elif command -v lspci >/dev/null 2>&1 && lspci 2>/dev/null | grep -iq "amd\|radeon\|advanced micro devices"; then
|
||||||
gpu_type="amd"
|
gpu_type="amd"
|
||||||
echo " ✓ AMD GPU detected" >&2
|
echo " ✓ AMD GPU detected (via lspci)" >&2
|
||||||
|
elif command -v lshw >/dev/null 2>&1 && lshw -c display 2>/dev/null | grep -iq "amd\|radeon"; then
|
||||||
|
gpu_type="amd"
|
||||||
|
echo " ✓ AMD GPU detected (via lshw)" >&2
|
||||||
|
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]] && command -v wmic >/dev/null 2>&1 && wmic path win32_VideoController get name 2>/dev/null | grep -iq "amd\|radeon"; then
|
||||||
|
gpu_type="amd"
|
||||||
|
echo " ✓ AMD GPU detected (via wmic)" >&2
|
||||||
|
# Try Intel detection
|
||||||
elif command -v lspci >/dev/null 2>&1 && lspci 2>/dev/null | grep -iq "intel.*vga\|intel.*display"; then
|
elif command -v lspci >/dev/null 2>&1 && lspci 2>/dev/null | grep -iq "intel.*vga\|intel.*display"; then
|
||||||
gpu_type="intel"
|
gpu_type="intel"
|
||||||
echo " ✓ Intel GPU detected" >&2
|
echo " ✓ Intel GPU detected (via lspci)" >&2
|
||||||
|
elif command -v lshw >/dev/null 2>&1 && lshw -c display 2>/dev/null | grep -iq "intel"; then
|
||||||
|
gpu_type="intel"
|
||||||
|
echo " ✓ Intel GPU detected (via lshw)" >&2
|
||||||
|
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]] && command -v wmic >/dev/null 2>&1 && wmic path win32_VideoController get name 2>/dev/null | grep -iq "intel"; then
|
||||||
|
gpu_type="intel"
|
||||||
|
echo " ✓ Intel GPU detected (via wmic)" >&2
|
||||||
else
|
else
|
||||||
echo " ⚠ No GPU detected, will use CPU encoding" >&2
|
echo " ⚠ No GPU detected, will use CPU encoding" >&2
|
||||||
fi
|
fi
|
||||||
|
|
@ -55,28 +120,90 @@ detect_hardware() {
|
||||||
|
|
||||||
if [[ -n "$best_encoder" ]]; then
|
if [[ -n "$best_encoder" ]]; then
|
||||||
echo " ✓ Selected: $best_encoder (fastest encoder)" >&2
|
echo " ✓ Selected: $best_encoder (fastest encoder)" >&2
|
||||||
echo "" >&2
|
|
||||||
echo "Hardware Detection Summary:" >&2
|
|
||||||
echo " GPU Type: $gpu_type" >&2
|
|
||||||
echo " Available Encoders Tested: ${candidates[*]}" >&2
|
|
||||||
echo " Optimal Encoder: $best_encoder" >&2
|
|
||||||
echo " Benchmark Time: ${best_time}s" >&2
|
|
||||||
echo "" >&2
|
|
||||||
echo "Press space to continue..." >&2
|
|
||||||
read -n 1 -s
|
|
||||||
echo "$best_encoder"
|
echo "$best_encoder"
|
||||||
return 0
|
|
||||||
else
|
else
|
||||||
echo " ⚠ No working encoder found, defaulting to libx265" >&2
|
echo " ⚠ No working encoder found, defaulting to libx265" >&2
|
||||||
echo "" >&2
|
|
||||||
echo "Hardware Detection Summary:" >&2
|
|
||||||
echo " GPU Type: $gpu_type" >&2
|
|
||||||
echo " Available Encoders Tested: ${candidates[*]}" >&2
|
|
||||||
echo " Fallback Encoder: libx265" >&2
|
|
||||||
echo "" >&2
|
|
||||||
echo "Press space to continue..." >&2
|
|
||||||
read -n 1 -s
|
|
||||||
echo "libx265"
|
echo "libx265"
|
||||||
return 0
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select_nvidia_encoder() {
|
||||||
|
echo -e "\n🎮 NVIDIA Encoder Selection:"
|
||||||
|
echo "1) HEVC NVENC (recommended)"
|
||||||
|
echo "2) AV1 NVENC (newer, slower)"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "Enter choice [1-2]: " nvidia_choice
|
||||||
|
case $nvidia_choice in
|
||||||
|
1) echo "✅ Selected HEVC NVENC"; echo "hevc_nvenc"; return ;;
|
||||||
|
2) echo "✅ Selected AV1 NVENC"; echo "av1_nvenc"; return ;;
|
||||||
|
*) echo "❌ Invalid choice. Please enter 1 or 2." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
select_amd_encoder() {
|
||||||
|
echo -e "\n🎮 AMD Encoder Selection:"
|
||||||
|
echo "1) HEVC AMF (recommended)"
|
||||||
|
echo "2) AV1 AMF (newer, slower)"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "Enter choice [1-2]: " amd_choice
|
||||||
|
case $amd_choice in
|
||||||
|
1) echo "✅ Selected HEVC AMF"; echo "hevc_amf"; return ;;
|
||||||
|
2) echo "✅ Selected AV1 AMF"; echo "av1_amf"; return ;;
|
||||||
|
*) echo "❌ Invalid choice. Please enter 1 or 2." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
select_intel_encoder() {
|
||||||
|
echo -e "\n🎮 Intel Encoder Selection:"
|
||||||
|
echo "1) HEVC Quick Sync (recommended)"
|
||||||
|
echo "2) AV1 Quick Sync (newer, slower)"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "Enter choice [1-2]: " intel_choice
|
||||||
|
case $intel_choice in
|
||||||
|
1) echo "✅ Selected HEVC QSV"; echo "hevc_qsv"; return ;;
|
||||||
|
2) echo "✅ Selected AV1 QSV"; echo "av1_qsv"; return ;;
|
||||||
|
*) echo "❌ Invalid choice. Please enter 1 or 2." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
select_cpu_encoder() {
|
||||||
|
echo -e "\n💻 CPU Encoder Selection:"
|
||||||
|
echo "1) SVT-AV1 (recommended, faster)"
|
||||||
|
echo "2) x265 HEVC (mature, compatible)"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "Enter choice [1-2]: " cpu_choice
|
||||||
|
case $cpu_choice in
|
||||||
|
1) echo "✅ Selected SVT-AV1"; echo "libsvtav1"; return ;;
|
||||||
|
2) echo "✅ Selected x265"; echo "libx265"; return ;;
|
||||||
|
*) echo "❌ Invalid choice. Please enter 1 or 2." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
select_custom_encoder() {
|
||||||
|
echo -e "\n⚙️ Available Encoders:"
|
||||||
|
ffmpeg -hide_banner -encoders | grep -E "(hevc|av1|h265)" | grep -v "V\|D" | awk '{print $2}' | nl
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "Enter encoder name: " custom_enc
|
||||||
|
if ffmpeg -hide_banner -loglevel error -encoders | grep -q "$custom_enc"; then
|
||||||
|
echo "✅ Selected: $custom_enc"
|
||||||
|
echo "$custom_enc"
|
||||||
|
return
|
||||||
|
else
|
||||||
|
echo "❌ Encoder '$custom_enc' not found. Please try again."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_hardware() {
|
||||||
|
select_encoder
|
||||||
|
SELECTED_ENCODER=$optimal_encoder
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Optimized Quality Settings Module - GIT Converter v2.7
|
# Quality Settings Module - GIT Converter v2.7
|
||||||
# Encoder-specific optimal parameters for maximum speed
|
# Handles quality modes and encoding parameters
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
get_quality_settings() {
|
get_quality_settings() {
|
||||||
|
|
@ -9,149 +9,72 @@ get_quality_settings() {
|
||||||
|
|
||||||
clear
|
clear
|
||||||
cat << "EOF"
|
cat << "EOF"
|
||||||
╔═══════════════════════════════════════════════════════════════════╗
|
╔═══════════════════════════════════════════════════════════╗
|
||||||
║ Choose Quality Mode ║
|
║ Choose Quality Mode ║
|
||||||
╚═══════════════════════════════════════════════════════════════╝
|
╚═════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
1) Near-Lossless (CRF 16) - Maximum quality
|
1) Source quality (no changes unless required)
|
||||||
2) High Quality (CRF 18) - Recommended
|
2) High Quality (CRF 18) - Recommended
|
||||||
3) Good Quality (CRF 20) - Balanced
|
3) Near-Lossless (CRF 16) - Maximum quality
|
||||||
4) Custom bitrate
|
4) Good Quality (CRF 20) - Balanced
|
||||||
|
5) Custom bitrate (exact bitrate control)
|
||||||
EOF
|
EOF
|
||||||
echo
|
echo
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
read -p " Enter 1–4 → " b
|
read -p " Enter 1–5 → " b
|
||||||
if [[ -n "$b" && "$b" =~ ^[1-4]$ ]]; then
|
if [[ -n "$b" && "$b" =~ ^[1-5]$ ]]; then
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
echo " Invalid input. Please enter a number between 1 and 4."
|
echo " Invalid input. Please enter a number between 1 and 5."
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Encoder-specific optimal settings
|
case $b in
|
||||||
case $encoder in
|
1)
|
||||||
*nvenc*)
|
quality_params=""
|
||||||
quality_params="-crf ${b:16:18:20:22} -preset fast -tune ll"
|
quality_name="Source quality"
|
||||||
quality_name="NVENC CRF ${b:16:18:20:22}"
|
|
||||||
;;
|
;;
|
||||||
*amf*)
|
2)
|
||||||
quality_params="-crf ${b:16:18:20:22} -quality 23 -rc 1"
|
if [[ "$encoder" == *"av1"* ]]; then
|
||||||
quality_name="AMF CRF ${b:16:18:20:22}"
|
quality_params="-crf 18 -preset 6"
|
||||||
;;
|
quality_name="AV1 CRF 18"
|
||||||
*qsv*)
|
|
||||||
quality_params="-crf ${b:16:18:20:22} -preset fast -global_quality 23"
|
|
||||||
quality_name="QSV CRF ${b:16:18:20:22}"
|
|
||||||
;;
|
|
||||||
libsvtav1)
|
|
||||||
quality_params="-crf ${b:16:18:20:22} -preset 8 -tile-rows 2 -tile-columns 2"
|
|
||||||
quality_name="SVT-AV1 CRF ${b:16:18:20:22}"
|
|
||||||
;;
|
|
||||||
libx265)
|
|
||||||
quality_params="-crf ${b:16:18:20:22} -preset fast -tune fastdecode"
|
|
||||||
quality_name="x265 CRF ${b:16:18:20:22}"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
quality_params="-crf ${b:16:18:20:22}"
|
|
||||||
quality_name="CRF ${b:16:18:20:22}"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Handle custom bitrate with exact control and override option
|
|
||||||
if [[ "$b" == "4" ]]; then
|
|
||||||
echo
|
|
||||||
echo "Choose custom bitrate mode:"
|
|
||||||
echo " 1) Target bitrate (exact match)"
|
|
||||||
echo " 2) Target bitrate with optimal adjustment"
|
|
||||||
echo
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
read -p " Enter 1–2 → " bitrate_mode
|
|
||||||
if [[ -n "$bitrate_mode" && "$bitrate_mode" =~ ^[1-2]$ ]]; then
|
|
||||||
break
|
|
||||||
else
|
else
|
||||||
echo " Invalid input. Please enter 1 or 2."
|
quality_params="-crf 18 -quality 23"
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ "$bitrate_mode" == "1" ]]; then
|
|
||||||
echo
|
|
||||||
echo "Enter target bitrate (e.g., 3200k, 5000k, 8000k):"
|
|
||||||
read -p "→ " custom_bitrate
|
|
||||||
|
|
||||||
# Clean input - remove control characters and spaces
|
|
||||||
custom_bitrate=$(echo "$custom_bitrate" | tr -cd '[:alnum:]k')
|
|
||||||
|
|
||||||
# Validate exact bitrate format
|
|
||||||
if [[ -n "$custom_bitrate" && "$custom_bitrate" =~ ^[0-9]+k$ ]]; then
|
|
||||||
quality_params="-b:v $custom_bitrate"
|
|
||||||
quality_name="Exact $custom_bitrate"
|
|
||||||
else
|
|
||||||
echo " Invalid bitrate format. Use format like 3200k, 5000k"
|
|
||||||
quality_params="-crf 18"
|
|
||||||
quality_name="HEVC CRF 18"
|
quality_name="HEVC CRF 18"
|
||||||
fi
|
fi
|
||||||
else
|
;;
|
||||||
|
3)
|
||||||
|
if [[ "$encoder" == *"av1"* ]]; then
|
||||||
|
quality_params="-crf 16 -preset 4"
|
||||||
|
quality_name="AV1 CRF 16"
|
||||||
|
else
|
||||||
|
quality_params="-crf 16 -quality 28"
|
||||||
|
quality_name="HEVC CRF 16"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
if [[ "$encoder" == *"av1"* ]]; then
|
||||||
|
quality_params="-crf 20 -preset 6"
|
||||||
|
quality_name="AV1 CRF 20"
|
||||||
|
else
|
||||||
|
quality_params="-crf 20 -quality 23"
|
||||||
|
quality_name="HEVC CRF 20"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
5)
|
||||||
echo
|
echo
|
||||||
echo "Enter target bitrate (e.g., 3200k, 5000k, 8000k):"
|
echo "Enter bitrate (e.g., 5000k, 8000k):"
|
||||||
read -p "→ " custom_bitrate
|
read -p "→ " custom_bitrate
|
||||||
|
|
||||||
# Clean input - remove control characters and spaces
|
# Clean input - remove control characters and spaces
|
||||||
custom_bitrate=$(echo "$custom_bitrate" | tr -cd '[:alnum:]k')
|
custom_bitrate=$(echo "$custom_bitrate" | tr -cd '[:alnum:]k')
|
||||||
|
|
||||||
# Validate and adjust bitrate to nearest standard tier for optimal compression
|
|
||||||
if [[ -n "$custom_bitrate" && "$custom_bitrate" =~ ^[0-9]+k$ ]]; then
|
if [[ -n "$custom_bitrate" && "$custom_bitrate" =~ ^[0-9]+k$ ]]; then
|
||||||
# Extract numeric value and round to nearest standard bitrate
|
quality_params="-b:v $custom_bitrate"
|
||||||
target_kbps=$(echo "$custom_bitrate" | sed 's/k//')
|
quality_name="Custom $custom_bitrate"
|
||||||
|
else
|
||||||
# Standard bitrate tiers with optimal compression
|
quality_params="-crf 18 -quality 23"
|
||||||
case $target_kbps in
|
quality_name="HEVC CRF 18"
|
||||||
[0-1499]) adjusted_bitrate="1500k" ;;
|
fi
|
||||||
[1500-2499]) adjusted_bitrate="2000k" ;;
|
;;
|
||||||
[2500-3499]) adjusted_bitrate="2500k" ;;
|
esac
|
||||||
[3500-4499]) adjusted_bitrate="3000k" ;;
|
|
||||||
[4500-5499]) adjusted_bitrate="3500k" ;;
|
|
||||||
[5500-6499]) adjusted_bitrate="4000k" ;;
|
|
||||||
[6500-7499]) adjusted_bitrate="4500k" ;;
|
|
||||||
[7500-8499]) adjusted_bitrate="5000k" ;;
|
|
||||||
[8500-9499]) adjusted_bitrate="5500k" ;;
|
|
||||||
[9500-11499]) adjusted_bitrate="6000k" ;;
|
|
||||||
[11500-13499]) adjusted_bitrate="7000k" ;;
|
|
||||||
[13500-15499]) adjusted_bitrate="8000k" ;;
|
|
||||||
*) adjusted_bitrate="9000k" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo " Target: $target_kbps kbps → Adjusted to: $adjusted_bitrate"
|
|
||||||
|
|
||||||
case $encoder in
|
|
||||||
*nvenc*)
|
|
||||||
quality_params="-b:v $adjusted_bitrate -preset fast -tune ll"
|
|
||||||
quality_name="Custom NVENC $adjusted_bitrate"
|
|
||||||
;;
|
|
||||||
*amf*)
|
|
||||||
quality_params="-b:v $adjusted_bitrate -quality 23 -rc 1"
|
|
||||||
quality_name="Custom AMF $adjusted_bitrate"
|
|
||||||
;;
|
|
||||||
*qsv*)
|
|
||||||
quality_params="-b:v $adjusted_bitrate -preset fast -global_quality 23"
|
|
||||||
quality_name="Custom QSV $adjusted_bitrate"
|
|
||||||
;;
|
|
||||||
libsvtav1)
|
|
||||||
quality_params="-b:v $adjusted_bitrate -preset 8 -tile-rows 2 -tile-columns 2"
|
|
||||||
quality_name="Custom SVT-AV1 $adjusted_bitrate"
|
|
||||||
;;
|
|
||||||
libx265)
|
|
||||||
quality_params="-b:v $adjusted_bitrate -preset fast -tune fastdecode"
|
|
||||||
quality_name="Custom x265 $adjusted_bitrate"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
quality_params="-b:v $adjusted_bitrate"
|
|
||||||
quality_name="Custom $adjusted_bitrate"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
quality_params="-crf 18"
|
|
||||||
quality_name="HEVC CRF 18"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user