diff options
author | Timmy Keller <tjk@tjkeller.xyz> | 2024-02-02 13:42:36 -0600 |
---|---|---|
committer | Timmy Keller <tjk@tjkeller.xyz> | 2024-02-02 13:42:36 -0600 |
commit | 988cadef2c2e51adbfa64da83ec7d25a8de3d924 (patch) | |
tree | cdf19760f118a49352e58576a2ff0a87eb09b517 | |
parent | 4063c8f3f1808b114d15186f24817f269a88ce4e (diff) | |
parent | 35ea75e1e19add2ffabbf4a8648c808a5d1bebfa (diff) | |
download | scripts-988cadef2c2e51adbfa64da83ec7d25a8de3d924.tar.xz scripts-988cadef2c2e51adbfa64da83ec7d25a8de3d924.zip |
Merge branch 'master' of localgit:scripts
-rwxr-xr-x | launch/launch | 16 | ||||
-rwxr-xr-x | video/vid2dvd | 200 |
2 files changed, 215 insertions, 1 deletions
diff --git a/launch/launch b/launch/launch index b8757e6..050f522 100755 --- a/launch/launch +++ b/launch/launch @@ -1,4 +1,5 @@ #!/bin/sh +awk=awk me() { basename "$0"; } printhelp() { @@ -20,8 +21,20 @@ Config Syntax: HELPDOC } +# Make sure user is using GNU Awk (gawk) +checkawk() { + if ! ($awk -V >/dev/null 2>/dev/null && $awk -V | grep "GNU Awk" >/dev/null); then + if command -v gawk > /dev/null; then + awk=gawk + else + echo "$(me) requires GNU Awk (gawk) to function properly. Please install GNU Awk and try again." + exit 0 + fi + fi +} + gencache() { -awk ' +$awk ' BEGIN { print "run=\"$1\"; shift" print "case \"$run\" in" @@ -89,6 +102,7 @@ cache=$cachedir/cache [ $conf -nt $cache ] && gencache # Command line options +checkawk case "$1" in -g|--gen-cache) echo "Generating new cache: $cache"; gencache && cat $cache ;; -h|--help|'') printhelp ;; diff --git a/video/vid2dvd b/video/vid2dvd new file mode 100755 index 0000000..67a9cb2 --- /dev/null +++ b/video/vid2dvd @@ -0,0 +1,200 @@ +#!/bin/sh + +# settings +d_bitrate_audio=448 # kb/s - max for dvd is 448 +d_disc_size=4700000 # KB - standard dvd is 4.7GB so 4.7*1000*1000 +d_min_bitrate_video=2300 # kb/s - video bitrate is calculated to saturate the disc +d_max_bitrate_video=9000 # kb/s - max for dvd is 9800. mpeg2video is capped at 9000 however difference is negligible + +# functions +notify() { [ -n "$V2D_NOTIFICATIONS" ] && notify-send -t 10 "$0" "$1" ; } + +confirm_or_quit() { + notify "Confirmation needed:\n$1" + while true; do + printf "\n$1 [y/n] " >&2 + read response + case "$response" in + y|Y) break ;; + n|N) echo "Quitting" && exit 1 ;; + esac + printf "\nPlease reply with [y/n]" >&2 + done +} + +echomsg() { echo "$@" 1>&2; } + +get_duration() { + for video in "$@"; do + ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$1" + done | paste -sd+ | bc | sed 's/\..*//' +} + +create_ffconcat_file() { + # ARGUMENTS + concatfile="$1/ffconcat" + shift + + for video in "$@"; do + echo "file '$(realpath "$video")'" >> "$concatfile" + done + + echo "$concatfile" +} + +calculate_max_video_bitrate() { + # ARGUMENTS + duration=$1 + + bitrate_audio=${V2D_BITRATE_AUDIO:-$d_bitrate_audio} + disc_size=${V2D_DISC_SIZE:-$d_disc_size} + min_bitrate_video=${V2D_MIN_BITRATE_VIDEO:-$d_min_bitrate_video} + max_bitrate_video=${V2D_MAX_BITRATE_VIDEO:-$d_max_bitrate_video} + + audio_filesize=$(( (bitrate_audio / 8) * duration )) # convert kb/s to KB/s + + bitrate_video=$(( ((disc_size - audio_filesize) / duration) * 8 )) # convert KB/s to kb/s + + # check bitrate + if [ $bitrate_video -gt $max_bitrate_video ]; then + bitrate_video=$max_bitrate_video + saturated=$(( 100 * disc_size / (audio_filesize + (max_bitrate_video * duration)) )) + echomsg "Video bitrate is capped to ${max_bitrate_video}kb/s" + echomsg "Disc saturation: $(( saturated ))%" + echomsg "Even at maximum bitrate, you are wasting $(( 100 - saturated))% of the disc! Do you still want to proceed?" + # TODO + #echo "Keep in mind, you can add multiple video files to a single disc by calling $0 [vid1] [vid2] ..." + + confirm_or_quit "Continue?" + elif [ $bitrate_video -lt $min_bitrate_video ]; then + echomsg "Warning low calculated bitrate: ${bitrate_video}kb/s" + echomsg "This bitrate is lower than the quality threshold will allow (${min_bitrate_video}kb/s)" + # TODO + ##echo "At lower than ~2300kb/s, the dvd creation will likely fail since that is approximately the lowest bitrate achievable by mpeg2video" + # TODO + #echo + #echo "You can split the video into multiple discs by using one of the following command flags:" + #echo " --max-quality Split the video into multiple discs after it falls below the max dvd quality" + #echo " --split-bitrate [min video bitrate] Split the video into multiple discs after it falls below the minimum bitrate" + #echo " --split-time [time] Split the video into multiple discs after a max length" + #echo " --split-discs [discs] Split the video evenly into X discs" + + confirm_or_quit "Would you still like to continue at a low bitrate?" + # TODO + ##if [ $bitrate_video -lt 2300 ]; then + ## echo "The bitrate is below 2300kb/s, so it is nearly certain to fail" + ##fi + fi + + echo $bitrate_video +} + +vids_to_iso() { + # ARGUMENTS + iso="$1" + shift + + bitrate_audio=${V2D_BITRATE_AUDIO:-$d_bitrate_audio} + + # make and trap temporary files + # TODO + #tmpfs=${TMPDIR:-/tmp} + #tmpfs_size=$(df -k --output=avail /tmp | tail -1) # Size in kB. Should be size in KB (--block-size=KB over -k) but this is more convenient and allows for extra space + + #[ $tmpfs_size -lt $(( disc_size * 2 )) ] && tmpfs=. # Just create it in local directory instead. Not ideal since it could persist between reboots if the trap doesnt function + tmpfs=. + + tmpdir="$(mktemp -d "$tmpfs/vid2dvd.XXXXXX")" + + trap "{ rm -rf '$tmpdir'; exit 1; }" EXIT INT + + # create concat file + concat_file="$(create_ffconcat_file "$tmpdir" "$@")" + + # get bitrate + echomsg "Finding optimal bitrate for video..." + videos_duration=$(get_duration "$@") + bitrate_video=$(calculate_max_video_bitrate $videos_duration) + echomsg "Audio bitrate: ${bitrate_audio}kb/s" + echomsg "Video bitrate: ${bitrate_video}kb/s (Calculated)" + echomsg + + # transcode with ffmpeg, author with dvdauthor, convert to iso with genisoimage + echomsg "Transcoding videos to correct ntsc dvd-video codecs. This could take a while..." + mpegvid="$tmpdir/vid.mpg" + ffmpeg -hide_banner -f concat -safe 0 -i "$concat_file" -target ntsc-dvd -b:a ${bitrate_audio}k -b:v ${bitrate_video}k "$mpegvid" + + mpegvid_size=$(du "$mpegvid" | grep -o "^[0-9]*") + #if [ $mpegvid_size -gt $disc_size ]; then + # echomsg "Conversion failed! Converted video ($mpegvid) is larger than the set disc size!" + # echomsg "Video size: $mpegvid_size" + # echomsg "Disc size: $disc_size" + + # confirm_or_quit "Continue regardless? The final iso will be larger than a normal disc" + #fi + echomsg "Done\n" + + echomsg "Authoring DVD. This will also take some time..." + dvddir="$tmpdir/dvd" + mkdir -p "$dvddir" + dvdauthor -o "$dvddir" --title "$mpegvid" 2>/dev/null # Generates the VIDEO_TS and AUDIO_TS folders with VOB files from the video stream + dvdauthor -o "$dvddir" --toc 2>/dev/null # Generate table of contents for disc + echomsg "Done\n" + + echomsg "Creating ISO image. You thought the last two steps were long? Well lucky you, this will be quick... relatively speaking..." + genisoimage -dvd-video -o "$iso" "$dvddir" # Generate the disc image + echomsg "Done\n" + notify "Job completed iso created\n$@" + + echo "$iso" +} + +# TODO +# burn to blank dvd + +help() { + echomsg "Usage: $0 [arguments] [video] ... [[-c append video] ...]" + echomsg + echomsg "Standard arguments:" + echomsg " -h, --help Output this menu" + echomsg " -n, --enable-notifications Enable sending notifications with notify-send" + echomsg " -o, --output-directory [directory] Put created isos into directory" + echomsg " -d, --output-iso-size [size in kb] Maximum size of iso to be created (Default: $d_disc_size)" + echomsg " -a, --bitrate-audio [bitrate in kb/s] Audio bitrate. Max for standard dvd is 448 (Default: $d_bitrate_audio)" + echomsg " -V, --bitrate-video-max [bitrate in kb/s] Maximum video bitrate. Max for standard dvd is 9800, but max for ffmpeg is 9000 (Default: $d_min_bitrate_video)" + echomsg " -v, --bitrate-video-min [bitrate in kb/s] Minimum video bitrate. Realistic minimum is ~2300 (Default: $d_min_bitrate_video)" + echomsg + echomsg "Video arguments:" + echomsg " [video1] [-c, --concat] [video2] ... Concatenate each video in the chain into a single dvd (still a single track)" + exit ${1:-1} +} + +# process arguments +while [ -n "$1" ]; do + case "$1" in + -o|--output-directory) shift && export V2D_OUTDIR=$1 ;; + -d|--output-iso-size) shift && export V2D_DISC_SIZE=$1 ;; + -a|--bitrate-audio) shift && export V2D_BITRATE_AUDIO=$1 ;; + -V|--bitrate-video-max) shift && export V2D_BITRATE_VIDEO_MAX=$1 ;; + -v|--bitrate-video-min) shift && export V2D_BITRATE_VIDEO_MIN=$1 ;; + -n|--enable-notifications) export V2D_NOTIFICATIONS=1 ;; + -h|--help) help 0 ;; + -*) echo "Invalid argument '$1'\n" && help 1 ;; + *) break ;; + esac + shift +done + +for video in "$@"; do + if [ -n "$V2D_OUTDIR" ]; then + mkdir -p "$V2D_OUTDIR" + mvideo="$V2D_OUTDIR/$(basename "$video")" + fi + out="$(echo "${mvideo:-$video}" | sed 's/\.[^.]*$//').iso" + if [ -f "$out" ]; then + echomsg "Output file already exists! => $out" + echomsg "Skipping" + continue + fi + vids_to_iso "$out" "$video" +done |