diff options
| -rwxr-xr-x | video/vid2dvd | 200 | 
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  | 
