//**Building a script with functions that encodes and shrinks videos**// ---- The previous tutorials were on the short side. Heres one to make up for my brevity :^) If something is unclear check those other tutorials to see if it is explained there. For more insight into the use of any of the commands below check out the man page. I often save movies and documentaries for viewing later and sometimes I want to burn them onto a DVD to share with family and friends. In order to burn the show I crop anything extra before and after plus remove any commercials in the middle. I use gopdit http://gopdit.ath.cx/ for my mpg-ps editing because its fast and simple. I have it set to save without encoding so I'm left with the basic mpg-ps (program stream) format that I saved the original show with. I can use a a short one command script to save me the trouble of remembering (and typing) a very long //mencoder// command that encodes the video to a good DVD quality mpg-ps but the problem is that often I end up with a video that is too big to fit on a DVD and then I have to shrink the video before I can burn it. Below is an example of a movie before and after encoding. bash-4.1$ ls -l total 8796992 -rwx------ 1 rick root 5070583808 Jun 19 09:24 encoded-hidden-blade.mpg -rwx------ 1 rick root 3937532284 Jan 12 2011 hidden-blade.mpg In order to save the time and bother of encoding and shrinking separately I can do them both in the same script. Here's what it looks like #!/bin/bash #################################################################### # con2vob # Converts and shrinks an mpg-ps video. # Requires mencoder, vamps, bc and assumes system (not file system) # block size = 1024 bytes (1kB). #################################################################### # Variables input_file=$1 dvd_size=4400000 # Test input. test -n "$input_file" if [ $? -eq 1 ]; then echo -e "\nUsage: con2vob [input file]" exit fi # Encode video. mencoder -oac lavc -ovc lavc -of mpeg -mpegopts format=dvd:tsaf \ -vf scale=720:576,harddup -srate 48000 -af lavcresample=48000 \ -lavcopts vcodec=mpeg2video:vrc_buf_size=1835:vrc_maxrate=9800:vbitrate=5000:keyint=15:vstrict=0:acodec=ac3:abitrate=192:aspect=16/9 -ofps 25 \ -o encoded-$input_file $input_file # Shrink video (if necessary). file_size=`ls -s encoded-$input_file | awk -F " " '{ print $1 }'` if [ $file_size -gt $dvd_size ]; then requant_factor=`echo "scale=2; $file_size/$dvd_size" | bc -l` vamps -v -E $requant_factor -a 1 < encoded-$input_file > shrunk-encoded-$input_file fi # End of script. In this script the video is assigned to the variable //input_file// and then //input_file// is encoded with mencoder. If no video file was entered the user is given the correct usage of the script and the script exits. I use mencoder (from MPlayer)for encoding my videos. The command options in the script are provided in the MPlayer manual //**7.8. Using MEncoder to create VCD/SVCD/DVD-compliant files**// http://www.mplayerhq.hu/DOCS/HTML/en/menc-feat-vcd-dvd.html and work fine with anything I have saved on my two DVB-T cards from ABC and SBS. Note that MPlayer has been forked. There is now an MPlayer2 which does not include mencoder. The mencoder command can be substituded with an ffmpeg command. The output of //mencoder// is named //encoded-input_file// and if its size is greater than my variable //dvd_size// the script will shrink the video using //vamps//. The linux operating systems use a block size of 1024 bytes, i.e.1kb. I want the script to shrink the video if the video exceeds 4.2gb and 4,400,000kb equals 1.19gb, close enough for me. I will need to compare the size of //encoded-input_file// to my //dvd_size// of 4400000 so first I need to get the size of //encoded-input_file// in kilobytes. I use //ls -s// to give me the file size in blocks which you now know is a good as asking for the size in kilobytes and use //awk// to print just the file size. bash-4.1$ ls -l encoded-hidden-blade.mpg -rwx------ 1 rick root 5070583808 Jun 19 09:24 encoded-hidden-blade.mpg bash-4.1$ ls -s encoded-hidden-blade.mpg 4951744 encoded-hidden-blade.mpg bash-4.1$ ls -s encoded-hidden-blade.mpg | awk -F " " '{ print $1 }' 4951744 Bash will do simple math but for floating point math I have to use //bc//. The requant factor (read shrink factor) is found by dividing the file size by my set limit of 4,400,000kb which will result in a decimal. In this usage the equation is piped to //bc// using an //echo// command. The parameter //scale=X// cab be passed to bc to limit the number of decimal places printed to stdout. bash-4.1$ bash-4.1$ file_size=`ls -s encoded-hidden-blade.mpg | awk -F " " '{ print $1 }'` \ > echo "$file_size/4400000" | bc -l 1.12539636363636363636 bash-4.1$ file_size=`ls -s encoded-hidden-blade.mpg | awk -F " " '{ print $1 }'` \ > echo "scale=2; $file_size/4400000" | bc -l 1.12 The vamps command syntax might seem a bit different. It uses redirection for input and output files. vamps -e $requant_factor -a 1 < encoded-$input_file > shrunk-encoded-$input_file The //encoded-input_file// is redirected to //stdin// with "<" and //shrunk-encoded-input_file// is redirected to stdout with ">". The shrink factor is passed to vamps using "-e" The ausio stream is nominated using an "-a" flag. Here are the results when con2vob was run and the movie //hidden-blade// has been shrunk. bash-4.1$ ls -lSr total 13196704 -rwx------ 1 rick root 3937532284 Jan 12 2011 hidden-blade.mpg -rwx------ 1 rick root 4505305088 Jun 19 09:36 shrunk-encoded-hidden-blade.mpg -rwx------ 1 rick root 5070583808 Jun 19 09:24 encoded-hidden-blade.mpg bash-4.1$ ls -sSr -1 total 13196704 3845248 hidden-blade.mpg 4399712 shrunk-encoded-hidden-blade.mpg 4951744 encoded-hidden-blade.mpg The video file //shrunk-encoded-hidden-blade.mpg// has been reduced to 4399712kb. One gigabyte is 1048576kb. Consequently //shrunk-encoded-hidden-blade.mpg// is 4399712kb / 1048576kb = 4.19589gb. ---- **the same script with functions** ---- In programming a //function// is a subroutine that contains a command or more usually a group of commands that is called by the script when required. It is intended to do just one thing. For me it is much easier to write a long script using functions. Each subroutine can be written and tested as a mini script and then be incorporated into the final script. The syntax for a function in a bash script is: function_name() { commands......... ) or alternatively: function function_name { commands........ } Functions are called by invoking their names in a script and they must be listed in the script before they are called. My //con2vob// script listed above is too short to require functions but it will serve as a good example of how to use functions. //Con2vob// above comprises declaring variables and then three sections each beginning with a comment that explain what is happening. These comments will now become my function names and the sections of code will become the functions. #!/bin/bash #################################################################### # new-con2vob # Converts and shrinks an mpg-ps video. # Requires mencoder, vamps, bc and assumes system (not file system) # block size = 1024 bytes (1kB). #################################################################### # Variables input_file=$1 dvd_size=4400000 test_input() { test -n "$input_file" if [ $? -eq 1 ]; then echo -e "\nUsage: con2vob [input file]" exit fi } encode_video() { mencoder -oac lavc -ovc lavc -of mpeg -mpegopts format=dvd:tsaf \ -vf scale=720:576,harddup -srate 48000 -af lavcresample=48000 \ -lavcopts vcodec=mpeg2video:vrc_buf_size=1835:vrc_maxrate=9800:vbitrate=5000:keyint=15:vstrict=0:acodec=ac3:abitrate=192:aspect=16/9 -ofps 25 \ -o encoded-$input_file $input_file } shrink_video() # (if necessary). { file_size=$(ls -s encoded-$input_file | awk -F " " '{ print $1 }') if [ $file_size -gt $dvd_size ]; then requant_factor=$(echo "scale=2; $file_size/$dvd_size" | bc -l) vamps -v -E $requant_factor -a 1 < encoded-$input_file > shrunk-encoded-$input_file fi } #################################################################### # Now call the functions test_input encode_video shrink_video # End of script. In this script two variable declarations are listed first. The variable //input_file// must be declared before the three functions because that variable is used in all three functions. The variable //dvd_size// does not have to be declared until required in the function //shrink_video// but I like to list all all variables I may want to change at the beginning of the script where they are easy to find if I want to change them. Note that I have changed the notation when I use stdout from a command to assign a value to a variable. The use of backticks, e.g. //variable=`some command`// for command substitution has been depreciated and the new way is to use " $() " like this //variable=$(some command)// Backticks can still be used but you may have mixed results and they should not be used when using nested commands. It is possible to do math in Bash if the numbers involved are all integers. In such instances you must use double quotes. bash-4.1$ result=`8-2` ; echo "$result" bash: 8-2: command not found bash-4.1$ result=$(8-2) ; echo "$result" bash: 8-2: command not found bash-4.1$ result=$((8-2)) ; echo "$result" 6 In //new-con2vob// I have three distinct operations which are easily tucked away into three functions. They are called one after the other by listing their names after they have been declared. In bash, functions can only be called after they have been declared. In **Part 5** of this series I will present a script that encodes shrinks and burns to a DVD. It is a little more complicated so it is a good example to show how handy functions can be in both planning and writing a script. ---- //There are gui programs out there which will do exactly what my con2vob script does but how many mouse clicks, how much time and how much memory does it take? I started scripted encoding and burning when I had a server for printer and file shares that also had a dvb card on board so saved movies and docos would be availble to any client on demand. Encoding takes a long time and is resource intensive but it didn't matter to a headless box with memory to spare and it could be done any time, day or night. It was just a matter of ssh'ing into the server and running a script.// I//'m not running that server now but I still prefer to do this sort of thing with scripts. I only use it on saved DVB broadcasts so the settings can remain the same. I either run con2vob with //nice// and go about doing something else or else run it when I go to bed or walk out the door and let the machine shut itself down when it is finished.// ---- **Cheers!**