ju
Last active
April 25, 2025 23:06
-
-
Save adamscybot/11160665643e41f362894222a5e9fec6 to your computer and use it in GitHub Desktop.
"LG+Sonos" optimized pipeline. Conditionally does non, either or both of: 1) Transcodes audio codecs that are incompatible with Sonos. 2) If input contains DV profile 8, but container is not mp4, changes container to mp4 such that DV will work on LG for this file -- ONLY if it comes at no cost to anything else (e.g. subs, audio)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -euo pipefail | |
INPUT_FILE="$1" | |
DEST_DIR="$2" | |
DRY_RUN="${3:-false}" | |
LOG_FILE="$DEST_DIR/convert.log" | |
mkdir -p "$DEST_DIR" | |
log() { | |
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" | |
} | |
run_cmd() { | |
log "$1" | |
if [[ "$DRY_RUN" != "true" ]]; then | |
eval "$1" | |
fi | |
} | |
if [[ ! -f "$INPUT_FILE" ]]; then | |
log "ERROR: Input file does not exist: $INPUT_FILE" | |
exit 1 | |
fi | |
log "LG+Sonos Optimize: $INPUT_FILE" | |
# Get container format | |
CONTAINER=$(ffprobe -v error -select_streams v:0 -show_entries format=format_name -of default=noprint_wrappers=1:nokey=1 "$INPUT_FILE") | |
# Get video codec | |
VIDEO_CODEC=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$INPUT_FILE") | |
# Get Dolby Vision profile | |
DV_PROFILE=$(dovi_tool info "$INPUT_FILE" 2>/dev/null | grep -oP 'profile: \K\d+(\.\d+)?' || echo "none") | |
# Get audio codec | |
AUDIO_CODEC=$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$INPUT_FILE") | |
# Get subtitle codecs | |
SUBTITLE_CODECS=$(ffprobe -v error -select_streams s -show_entries stream=codec_name -of csv=p=0 "$INPUT_FILE" | sort -u) | |
log "Container: $CONTAINER" | |
log "Video codec: $VIDEO_CODEC" | |
log "Audio codec: $AUDIO_CODEC" | |
log "Subtitle codecs: $SUBTITLE_CODECS" | |
log "Dolby Vision profile: $DV_PROFILE" | |
# Analyze subtitles | |
SUBS_OK=true | |
if echo "$SUBTITLE_CODECS" | grep -qvE '^(subrip|srt)$'; then | |
SUBS_OK=false | |
fi | |
# Analyze video and DV profile | |
VIDEO_HAS_LG_COMPAT_DV=true | |
if [[ "$VIDEO_CODEC" != "hevc" ]] || [[ "$DV_PROFILE" != "8.1" ]]; then | |
VIDEO_HAS_LG_COMPAT_DV=false | |
fi | |
# Analyze audio compatibility | |
AUDIO_TARGET="$AUDIO_CODEC" | |
NEEDS_AUDIO_TRANSCODE=false | |
if echo "$AUDIO_CODEC" | grep -qE '^(dts|dts_hd_ma|flac|opus)$'; then | |
AUDIO_TARGET="eac3" | |
NEEDS_AUDIO_TRANSCODE=true | |
fi | |
# Check if planned audio codec is MP4 compatible | |
AUDIO_MP4_COMPATIBLE=false | |
if echo "$AUDIO_TARGET" | grep -qE '^(aac|ac3|eac3)$'; then | |
AUDIO_MP4_COMPATIBLE=true | |
fi | |
BASENAME=$(basename "$INPUT_FILE") | |
EXTENSION="${BASENAME##*.}" | |
BASENAME_NOEXT="${BASENAME%.*}" | |
FFMPEG_CMD="ffmpeg -hide_banner -y -i \"$INPUT_FILE\" -map 0 -c:v copy" | |
# Logging audio plan | |
log "❓Plan operations to make audio compatible with Sonos?" | |
[[ "$NEEDS_AUDIO_TRANSCODE" == "true" ]] && log " ❌ Audio codec $AUDIO_CODEC incompatible with Sonos Arc" || log " ✅ Audio codec $AUDIO_CODEC is compatible with Sonos Arc" | |
[[ "$NEEDS_AUDIO_TRANSCODE" == "true" ]] && log "➡️ Audio will be converted to $AUDIO_TARGET" || log "➡️ $AUDIO_CODEC will be retained" | |
# Setup audio stream | |
if [[ "$NEEDS_AUDIO_TRANSCODE" == "true" ]]; then | |
FFMPEG_CMD+=" -c:a $AUDIO_TARGET -b:a 1024k" | |
else | |
FFMPEG_CMD+=" -c:a copy" | |
fi | |
# Logging decisions | |
log "❓Plan operations to make video Dolby Vision compatible with LG TVs?" | |
[[ "$CONTAINER" != "mp4" ]] && log " ✅ Not already MP4" || log " ❌ Already MP4. No need to swap." | |
[[ "$SUBS_OK" == "true" ]] && log " ✅ Subtitles OK (only SRT)" || log " ❌ Subtitles $SUBTITLE_CODECS not compatible inside MP4. Priorising retaining subs." | |
[[ "$VIDEO_HAS_LG_COMPAT_DV" == "true" ]] && log " ✅ Video codec HEVC and DV profile 8.1" || log " ❌ Video codec and/or DV profile incompatible (regardless of if we change to mp4)" | |
[[ "$AUDIO_MP4_COMPATIBLE" == "true" ]] && log " ✅ Audio codec $AUDIO_TARGET compatible with MP4" || log " ❌ Audio codec $AUDIO_TARGET not compatible with MP4, but is compatible with Sonos. Audio quality prioritised." | |
# Decide output container | |
if [[ "$CONTAINER" != "mp4" ]] && [[ "$SUBS_OK" == "true" ]] && [[ "$VIDEO_HAS_LG_COMPAT_DV" == "true" ]] && [[ "$AUDIO_MP4_COMPATIBLE" == "true" ]]; then | |
log "➡️ Container will be converted to MP4 for Dolby Vision LG Compat" | |
OUTPUT_FILE="$DEST_DIR/${BASENAME_NOEXT}.mp4" | |
FFMPEG_CMD+=" -c:s mov_text" | |
log "Planned output container: MP4" | |
else | |
[[ "$VIDEO_HAS_LG_COMPAT_DV" == "true" ]] && log " ➡️ Container will stay as MKV even though video track has DV that could be made to be LG compat via MP4. Prioritising other factors." || log " ➡️ Container will stay as MKV as no value in changing it (no DV compat gains)" | |
OUTPUT_FILE="$DEST_DIR/${BASENAME_NOEXT}.mkv" | |
log "Planned output container: MKV" | |
FFMPEG_CMD+=" -c:s copy" | |
fi | |
# Handle no-transcode, MKV direct copy | |
if [[ "$OUTPUT_FILE" == *".mkv" ]] && [[ "$NEEDS_AUDIO_TRANSCODE" == "false" ]]; then | |
log "✨ No actions needed. Copying file directly." | |
run_cmd "cp \"$INPUT_FILE\" \"$OUTPUT_FILE\"" | |
exit 0 | |
fi | |
FFMPEG_CMD+=" \"$OUTPUT_FILE\"" | |
log "✨ Performing actions, starting ffmpeg..." | |
run_cmd "$FFMPEG_CMD" | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment