Skip to content

Instantly share code, notes, and snippets.

@YukinoAi
Created October 6, 2020 03:04
Show Gist options
  • Save YukinoAi/3002c3b5697e9b1b3781ae52c9e0c40f to your computer and use it in GitHub Desktop.
Save YukinoAi/3002c3b5697e9b1b3781ae52c9e0c40f to your computer and use it in GitHub Desktop.
Wrapper script for ld-decode toolset.
#/bin/bash
#exit script if an error occurs
set -e
if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ] ; then \
echo Syntax: $0 inputFile.ldf cavOrClv ntscOrPal combFilter digitalOrAnalogAudio length startAt white ntscj
echo Examples:
echo $0 /home/user/Downloads/myFile.lds clv ntsc
echo $0 myFile.lds cav ntsc ntsc3d digital 1000 500 true true
echo $0 myFile.ldf clv pal pal2d none 0 500
echo There must not be any spaces in "myFile.ldf".
exit 0
fi
#default settings
cavOrClv="cav"
#cav,clv
ntscOrPal="ntsc"
#ntsc, pal
defaultNtscCombFilter="ntsc2d"
defaultPalCombFilter="pal2d"
#ntsc1d, ntsc2d, ntsc3d, pal2d, transform2d, transform3d
lumaNoiseReduction="0.0"
#0.0,0.5,(1.0),1.5,2.0...
chromaNoiseReduction="0.0"
#(0.0),0.5,1.0,1.5,2.0...
videoCodec="ffv1"
#ffv1, ffvhuff, huffyuv, libx264, libx264rgb, libx265, libvpx-vp9, vp9_vaapi, h264_nvenc, hevc_nvenc, utvideo
outputColorspace="444"
#444, 422, 420; used in yuv420p, yuv422p, yuv444p
defaultDigitalOrAnalogAudioMode="digital"
#digital,analog, none
audioCodec="flac"
#flac,aac, libopus, ac3
defaultLength=0
#0,200,500,1000,any non-negative integer; "0" means no length limit=process entire disc, Also valid: full, all, entire, fullLength
defaultStartAt=500
#0,200,500,1000,any non-negative integer; "0" means 0, This is the amount of frames to skip. This might need to be a float instead of integer.
defaultSeekFrame=0
#0, 1; Use 0 for CLV, Use 1 for CAV. Instead of using seek and to start at the first frame, sometimes --start may need to be adjusted manually instead.
#This might be better off as true/false is there are no exceptions.
defaultWhite=true
#true,false
defaultNtscjSetting=false
#true,false
defaultWibbleSetting=false
#true,false
cpuThreads="16"
#suggested:4,8
cleanupFilesAfterMkv=false
#true,false
miscLdDecodeSettings=" --start 500"
#--NTSCJ, for CLV use seek=0 for , or for CAV use --seek 1
miscLdChromaDecodeSettings=""
#--white
#static variables, #this is for NTSC, what are the formats for PAL?
rawVideoFormatNtsc="rawvideo -pix_fmt gray16le -s 910x263 -r 60000/1001"
rawVideoFormatPal="rawvideo -pix_fmt gray16le -s 1135x313 -r 50000/1000"
#should resolution not instead be "910x525"? "[ld-decode outputs] 910x525 16-bit values [for NTSC]"
#https://github.com/happycube/ld-decode/wiki/File-formats
#263*2=500+13+13=526
rawVideoFormatAfterChromaNtsc="rawvideo -pix_fmt rgb48 -s 760x488 -r 30000/1001"
rawVideoFormatAfterChromaPal="rawvideo -pix_fmt rgb48 -s ------- -r 25000/1000"
#signed pcm 16-bit stereo little endian "s16le" @ 44.1 kHz, is PAL digital or PAL/NTSC analog audio different?
rawAudioFormat="s16le -ac 2 -r 44.1k"
#function definitions, these have to be defined prior to being invoked :-(
#usage: myVar=$(makeLowercaseFunct $myVar)
function makeLowercaseFunct() { echo $1 | tr '[:upper:]' '[:lower:]'
}
#ldprocess.sh inputFile.ldf cavOrClv ntscOrPal combFilter digitalOrAnalogAudio length startAt seekFrame white #choose to include seek frame or not
#ldprocess.sh inputFile.ldf cavOrClv ntscOrPal combFilter digitalOrAnalogAudio length startAt white ntscj #always include seek frame
#ldprocess.sh 1)inputFile.ldf 2)cavOrClv 3)ntscOrPal 4)combFilter 5)digitalOrAnalogAudio 6)length 7)startAt 8)white 9)ntscj
#not included: wibble, 8)seekFrame
#ldprocess.sh cav ntsc ntsc3d
#read input and assign variables
#debug code
echo User first entered:\"$1\"
echo second variable \"$2\"
echo third variable \"$3\"
echo fourth variable \"$4\"
echo fifth variable \"$5\"
echo sixth variable \"$6\"
echo seventh variable \"$7\"
echo eighth variable \"$8\"
echo ninth variable \"$9\"
#read input
#"-z" means "if the variable is empty", might want to make this output clearer to the user at some point
if [ ! -z "$1" ] ; then rawFileName=$1 ; echo Using file: \"$1\" ; else echo Error. Please specify a file. ; exit ; fi
if [ ! -z "$2" ] ; then cavOrClv=$2 ; echo Decoding as RF capture of \"$2\" disc. ; else echo Error. Please specify an LD format, cav or clv. ; exit ; fi
if [ ! -z "$3" ] ; then ntscOrPal=$3 ; echo Decoding disc as \"$3\". ; else echo Error. Please specify television standard, ntsc or pal. ; exit ; fi
if [ ! -z "$4" ] ; then combFilter=$4 ; echo Using CombFilter \"$4\" ; combFilterSpecified=true ; else echo No comb filter specified. ; combFilterSpecified=false ; fi
if [ ! -z "$5" ] ; then digitalOrAnalogAudio=$5 ; echo Audio mode:\"$5\". ; \
else echo Audio mode not specified. Defaulting to \"$defaultDigitalOrAnalogAudioMode\". ; digitalOrAnalogAudio=$defaultDigitalOrAnalogAudioMode ; fi
if [ ! -z "$6" ] ; then length=$6 ; echo Length=\"$6\". ; else echo Length not specified. Using length=\"$defaultLength\". ; length=$defaultLength ; fi
if [ ! -z "$7" ] ; then startAt=$7 ; echo Starting at frame=\"$7\". ; startAtSpecified=true ; \
else echo Seek amount not specified. ; startAt=$defaultStartAt ; startAtSpecified=false ; fi
#Using default of \"$defaultStartAt\". If a startAt was not specified, should there be a default startAt regardless?
#if [ ! -z "$8" ] ; then seekFrame=$8 ; echo Seeking to frame=\"$8\". ; seekFrameSpecified=true; else echo Seek frame not specified. Using default for CAV/CLV. ; seekFrameSpecified=false; fi
#same as above. If not specified, should this be included?, currently *always* being included as derivative value of $2 cavOrClv.
if [ ! -z "$8" ] ; then white=$8 ; echo "Use White point at 75%? "\"$8\". ; else echo 75% white point not specified. Defaulting to \"$defaultWhite\". ; white=$defaultWhite ; fi
if [ ! -z "$9" ] ; then ntscj=$9 ; echo "NTSCJ disc? "\"$9\". ; else echo NTSCJ not specified. Defaulting to \"$defaultNtscjSetting\". ; ntscj=$defaultNtscjSetting ; fi
#Validate input
#ldprocess.sh 1)inputFile.ldf 2)cavOrClv 3)ntscOrPal 4)combFilter 5)digitalOrAnalogAudio 6)length 7)startAt 8)white 9)ntscj
#-e means "if exists"
if [ ! -e "$rawFileName" ] ; then echo "Error: \"$rawFileName\" does not exist." ; exit 1 ; fi
#cavOrClv#cav,clv
#need to figure out how to pipe this properly at some point
#echo $cavOrClv | tr '[:upper:]' '[:lower:]' > temp.txt
#myvar2=$(cat temp.txt)
#rm temp.txt
#edit, moved to function, output gets assigned to variable via command substitution
cavOrClv=$(makeLowercaseFunct $cavOrClv)
if [ ! "$cavOrClv" = "cav" ] ; then \
if [ ! "$cavOrClv" = "clv" ] ; then \
echo Error: "cavOrClv" value is not "cav" or "clv"
echo Value:\"$cavOrClv\"
exit 1
fi fi
#ntscOrPal#ntsc, pal
ntscOrPal=$(makeLowercaseFunct $ntscOrPal)
if [ ! "$ntscOrPal" = "ntsc" ] && [ ! "ntscOrPal" = "pal" ] ; then \
echo Error: "ntscOrPal" value is not "ntsc" or "pal"
echo Value:\"$ntscOrPal\".
exit 1
fi
#combFilter#ntsc1d, ntsc2d, ntsc3d, pal2d, transform2d, transform3d
combFilter=$(makeLowercaseFunct $combFilter)
if [ "$combFilterSpecified" = "false" ] ; then \
if [ ! "$ntscOrPal" = "ntsc" ] ; then \
combFilter=$defaultNtscCombFilter ; else \
combFilter=$defaultPalCombFilter
fi fi
if [ ! "$combFilter" = "ntsc1d" ] && [ ! "$combFilter" = "ntsc2d" ] && [ ! "$combFilter" = "ntsc3d" ] && \
[ ! "$combFilter" = "pal2d" ] && [ ! "$combFilter" = "transform2d" ] && [ ! "$combFilter" = "transform3d" ] ; then \
echo Error: Selected "combFilter" is not valid.
echo Valid values: ntsc1d, ntsc2d, ntsc3d, pal2d, transform2d, transform3d
echo Actual Value:\"$ntscOrPal\"
exit 1
fi
#digitalOrAnalogAudio#digital,analog, none
digitalOrAnalogAudio=$(makeLowercaseFunct $digitalOrAnalogAudio)
if [ ! "$digitalOrAnalogAudio" = "digital" ] && [ ! "$digitalOrAnalogAudio" = "analog" ] && [ ! "$digitalOrAnalogAudio" = "none" ] && [ ! "$digitalOrAnalogAudio" = "no" ] ; then \
echo Error: "digitalOrAnalogAudio" value is not "digital" or "analog" or "none"
echo Value:\"$digitalOrAnalogAudio\"
exit 1
fi
if [ "$digitalOrAnalogAudio" = "no" ] ; then digitalOrAnalogAudio=none ; fi
#length#0, 1-1000+, full, all; maybe check if zero or an integer?
length=$(makeLowercaseFunct $length)
#check if integer, if an integer, assume it is valid, if not an integer, check for valid values, if integer, check if 0 and set to all
case $length in
''|*[!0-9]*) lengthIsInteger=false ;;
*) lengthIsInteger=true ;;
esac
if [ ! "$lengthIsInteger" = "true" ] ; then \
if [ ! "$length" = "full" ] && [ ! "$length" = "all" ] && [ ! "$length" = "entire" ] && [ ! "$length" = "fullLength" ] ; then \
echo Error: Selected length is not valid.
echo Valid values: Any non-negative integer 0, 200, 500, 100 and "full", "all", "entire", "fullLength".
echo Selected length:\"$length\".
exit 1
fi fi
#check if integer, if an integer, assume it is valid, if not an integer, check for valid values, if integer, check if 0 and set to all
#Technically float values are valid so may not be able to check if a valid value was entered at all. 2.3=string in bash
startAt=$(makeLowercaseFunct $startAt)
case $startAt in
''|*[!0-9]*) startAtIsInteger=false ;;
*) startAtIsInteger=true ;;
esac
if [ "$startAtIsInteger" = "false" ] ; then \
echo Error: Selected start/skip amount is not valid.
echo Entered skip amount \"$startAt\".
exit 1
fi
##seekFrame, 0 or 1; 0 for CLV, 1 for CAV, must be an integer
#if [ "$seekFrameSpecified"="false" ]
#then , currently using $2 cavOrClv to determine this instead as mandatory always included option, code below is for optionally including it if specified (as hardcoded values)
#if [ "$seekFrameSpecified" = "true" ] ; then \
#if [ "$cavOrClv" = "clv" ] ; then miscLdDecodeSettings="$miscLdDecodeSettings ""--seek 0" ; else \
#miscLdDecodeSettings="$miscLdDecodeSettings ""--seek 1" ; fi fi
#white, boolean
white=$(makeLowercaseFunct $white)
if [ ! "$white" = "true" ] ; then \
if [ ! "$white" = "false" ] ; then \
echo Error: "white" value is not true or false.
echo Value:\"$white\"
exit 1
fi fi
#ntscj, boolean
if [ -z $ntscj ] ; then ntscj=$defaultNtscjSetting ; fi
ntscj=$(makeLowercaseFunct $ntscj)
if [ ! "$ntscj" = "true" ] ; then \
if [ ! "$ntscj" = "false" ] ; then \
echo Error: "ntscj" value is not true or false.
echo Value:\"$ntscj\"
exit 1
fi fi
#wibble, boolean
if [ -z $wibble ] ; then wibble=$defaultWibbleSetting ; fi
wibble=$(makeLowercaseFunct $wibble)
if [ ! "$wibble" = "true" ] ; then \
if [ ! "$wibble" = "false" ] ; then \
echo Error: "wibble" value is not true or false.
echo Value:\"$wibble\".
exit 1
fi fi
#calculate variable names
#might want to remove the .tbc extension from the rawFileName
fileNameNoExt=$(basename -s .lds $rawFileName) #myfile.ldf->myfile.ldf; myfile.lds->myfile
fileNameNoExt=$(basename -s .ldf $fileNameNoExt) #myfile.ldf->myfile; myfile->myfile
tbcOutputFileName="$fileNameNoExt".raw
#.tbc gets appended to tbcOutputFileName and it becomes tbcFileName
tbcFileName="$fileNameNoExt".raw.tbc
audioTrackName="$fileNameNoExt".raw.pcm
efmFileName="$fileNameNoExt".raw.efm
ldsJson="$fileNameNoExt".raw.tbc.json
#VDIjson="$LDSjson".vdi.json #wrong name
#if --output-json is not specified when using "ld-process-vbi", then a "...tbc.json.bup" file is created as a backup and the original json is overwritten
ldsJsonBackup="$ldsJson".bup
chaptersFile="$fileNameNoExt".txt
#chapters file is also known as "ffmetadata"
outputFileName="$fileNameNoExt".mkv
#determine additional variables
#use seek=0 for CLV, or --seek 1 for CAV, append to miscLdDecodeSettings
#miscLdDecodeSettings="$miscLdDecodeSettings "--seek
if [ "$cavOrClv" = "clv" ] ; then miscLdDecodeSettings="$miscLdDecodeSettings ""--seek 0"
else miscLdDecodeSettings="$miscLdDecodeSettings ""--seek 1" ; fi
if [ "$ntscOrPal" = "ntsc" ] ; then \
rawVideoFormat=$rawVideoFormatNtsc
rawVideoFormatAfterChroma=$rawVideoFormatAfterChromaNtsc
else \
rawVideoFormat=$rawVideoFormatPal
rawVideoFormatAfterChroma=$rawVideoFormatAfterChromaPal
fi
#append length to ld-decode settings if it was specified
#if [ "$length" eq "0" ] ; then miscLdDecodeSettings=$miscLdDecodeSettings" --length $length" ; fi
if [ "$lengthIsInteger" = "true" ] ; then \
if [ "$length" = "0" ] ; then \
length=fullLength #pointless
#else if an non-zero integer, append --length $length to ld-decode
else miscLdDecodeSettings="$miscLdDecodeSettings ""--length $length"
fi fi
if [ ! "$startAtIsInteger" = "false" ] ; then \
if [ "$startAtSpecified" = "true" ] ; then \
miscLdDecodeSettings="$miscLdDecodeSettings ""--start $startAt"
fi fi
#miscLdChromaDecodeSettings --white, #white, boolean
if [ "$white" = "true" ] ; then miscLdChromaDecodeSettings="$miscLdChromaDecodeSettings ""--white" ; fi
#miscLdDecodeSettings --NTSCJ, #ntscj, boolean
if [ "$ntscj" = "true" ] ; then miscLdDecodeSettings="$miscLdDecodeSettings ""--NTSCJ" ; fi
#debug code, print out all variables
#debug code, exit early
#exit 0
#might want to also check if ld-decode is invokable first
#also, might want to skip running ld-decode, ld-process-vbi and ls-export-metadata if $tbcFileName already exists
#extract out 1) .tbc raw video, 2) .wav audio, 3) .efm data and 4) .json metadata
if [ -e "$tbcFileName" ] ; then \
echo \"$tbcFileName\" already exists. Will reuse existing .tbc file.
echo Delete/move/rename .tbc file if reuse is not desired.
else \
echo Starting LD-Decode....
echo ld-decode "$miscLdDecodeSettings" -t $cpuThreads --$ntscOrPal "$rawFileName" "$tbcOutputFileName"
ld-decode $miscLdDecodeSettings -t $cpuThreads --$ntscOrPal "$rawFileName" "$tbcOutputFileName"
#update vbi data
echo Updating VBI metadata...
echo ld-process-vbi --threads $cpuThreads --input-json "$ldsJson" "$tbcFileName"
ld-process-vbi --threads $cpuThreads --input-json "$ldsJson" "$tbcFileName"
echo Extracting ffmetadata chapters...
#extract out LD chapters (if present), how to check if present? how to exclude from next command if not present?
ld-export-metadata "$ldsJson" --ffmetadata "$chaptersFile"
#merge pieces and encode a/v losslessly
#ffmpeg -f $rawVideoFormat - | \ #this is used...when?
#\
fi
echo ld-dropout-correct --intra --overcorrect --input-json "$ldsJson" --output-json /dev/null --quiet "$tbcFileName" - \| \\
echo ld-chroma-decoder -t $cpuThreads --decoder $combFilter --luma-nr $lumaNoiseReduction --chroma-nr $chromaNoiseReduction --input-json "$ldsJson" -q $miscLdChromaDecodeSettings - - \| \\
echo ffmpeg -f $rawVideoFormatAfterChroma -i - -f $rawAudioFormat -i "$audioTrackName" -i "$chaptersFile" -c:v $videoCodec -pix_fmt yuv"$outputColorspace"p -y -c:a $audioCodec "$outputFileName"
#debug code
#echo end
#exit 0
echo Performing magic on black and white signal...
ld-dropout-correct --intra --overcorrect --input-json "$ldsJson" --output-json /dev/null --quiet "$tbcFileName" - | \
\
ld-chroma-decoder -t $cpuThreads --decoder $combFilter --luma-nr $lumaNoiseReduction --chroma-nr $chromaNoiseReduction --input-json "$ldsJson" -q $miscLdChromaDecodeSettings - - | \
\
ffmpeg -f $rawVideoFormatAfterChroma -i - -f $rawAudioFormat -i "$audioTrackName" -i "$chaptersFile" -c:v $videoCodec -pix_fmt yuv"$outputColorspace"p -y -c:a $audioCodec "$outputFileName"
#-aspect 4:3
#for flac use "-compression_level 5", higher is more compression, max is 12, default is 5, consider using 11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment