summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xvideo/vid2dvd200
1 files changed, 200 insertions, 0 deletions
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