PVR Cron

For about a year now, I’ve been playing around with my digital tuner card. It wasn’t until I turned off the cable that I have a need to use it. Using some cool linux tools, I’ve made a script to record HDTV broadcasts to my computer. It is a work in progress, but here’s what I’ve got so far.

The Tuner Card
The tuner card is DVB based on a Conextant chipset, so the first step was to get my kernel to make the card usable. A quick check will show if the driver is loaded:

dmesg | grep dvb

The Tools Required

  • dvb-atsc-tools
  • azap
  • ffmpeg

Channel Scan
Scan for channels using:

dvbscan /usr/share/dvb/atsc/us-ATSC-center-frequencies-8VSB > ~/.azap/channels.conf

Edit the file ~/.azap/channels.conf to make sure the channel names are correct. Your base frequencies file may be in a different location, but it is usually under /usr/share.

Iteration 1: Crontab Recording
At first, I used only the crontab to record. Here’s an example:

24 12 * * * /usr/bin/azap -c /home/dvr/.azap/channels.conf -r WRDW-HD
25 12 * * * /bin/cat /dev/dvb/adapter0/dvr0 > /data/dvr/young-restless.mpeg
35 13 * * * /usr/bin/pkill cat
36 13 * * * /usr/bin/pkill azap
37 13 * * * /usr/bin/ffmpeg -i /data/dvr/young-restless.mpeg -s 1024x476 -vcodec libxvid -b 1600000 -acodec copy /data/dvr/y-r-friday.avi

This is a very ugly solution with lots of cracks. For instance, if I were running cat from a console when /usr/bin/pkill cat were running, it would die. Heaven forbid another processes is using cat when that runs. Also, I had to change the name of the ffmpeg output file every day.

Iteration 2: Cronable Perl Script
This script does pretty much the same thing as the above 4 lines in the crontab does. This means you don’t have to write 4 lines in the crontab for each recording, just 1 line. Also, the file name is appended with the date in yyyy-mm-dd format.


#Does someone need a reminder?
if ( $#ARGV != 2 ) {
print “Usage:\n”;
print “record.pl \n”;

#Creates a random 16 character (a-z) string
sub randstr {
my @chars=(‘a’..’z’);
my $res = “”;
for(my $i=0;$i<16;$i++) {
$res .= $chars[rand($#chars)];
return $res;

#Grab the command line args
my ( $channel, $length, $finalFileName ) = @ARGV;

#Temporary mpeg filename
my $tempFileName = randstr();

#Add date to final filename
$finalFileName .= “-“.`date +%Y-%m-%d`;
$finalFileName =~ s/\n//;

#Start Azap in the background
print “Starting azap\n”;
system( “/usr/bin/azap -c /home/barry/.azap/channels.conf -r $channel >/dev/null 2>/dev/null &” );
sleep 5;

#Start cat in the background
print “Starting cat\n”;
system( “/bin/cat /dev/dvb/adapter0/dvr0 > /data/dvr/$tempFileName.mpeg &” );

#Sleep the required seconds for the show to record
print “Recording for “.(60*$length).” seconds…\n”;
sleep 60*$length;

#TODO: Remove pkill, as it may cause problems
print “Killing cat and azap.\n”;
`pkill cat`;
`pkill azap`;

#Resize & Encode to XVID using ffmpeg
#ffmpeg sometimes stops working b/c of bad mpeg data
#TODO: Replace with mencoder
print “Encoding…\n”;
`/usr/bin/ffmpeg -i /data/dvr/$tempFileName.mpeg -s 1024×476 -vcodec libxvid -b 1600000 -acodec copy /data/dvr/$finalFileName.avi`;

#Remove the temporary mpeg file
`rm $tempFileName.mpeg`;

print “Done!\n”;

I know it’s not the most elegant of perl scripts, but it gets the job done. Here’s a sample cron:

25 12 * * * /home/dvr/record.pl WRDW-HD 70 young-restless

As you can see from the TODO comments, I continue to tinker with the script. When I make a good development, I’ll post it. If you have any suggestions, feel free to post a comment or contact me.

Regular Expressions Part 2

In the previous post, simple regular expressions were explained. Today, regex becomes useful. If you didn’t read the previous post, you should at least skim it.

For this post, all examples will be using perl.

Getting a Match
Parentheses are used to extract a match from a string. Let’s say you want to know what is inside the “head” html tags, here’s the code:

if ( $html =~ m/(.*)<\/head>/is ) {
print "HTML Header:\n$1\n";

The match is given to the code as the variable $1. Note that this example has an “s” after the closing forward slash. The s treats the string to be compared as a single line. Without it, you probably wouldn’t get a match. Also, this simple regex will not match the entire head in all cases. If you put “</head>” inside a meta keyword list, it would match, but stop at the first “</head>”.

Here’s another example:

if ( $text =~ m/ a ([aeiou][a-z]+)/i ) {
print "Grammar error: use \"an\" when the following word starts with a vowel.\n i.e. an $1\n";

Yup, it’s a grammar rule check. Now you know where that green squiggly underline comes from.

Whitespace and Non-whitespace matching
Whitespace refers to a space, tab, and carriage returns. “\s” matches a whitespace character and “\S” matches a non-whitespace character.

That’s the basic of regular expressions. These magically expressions work in almost every language, including perl, php, javascript, and python.

Happy pattern matching.

Regular Expressions Part 1/2

Regular Expressions, those oddities that live between two forward slashes, are very powerful and quite mysterious. Staring at something like /([abcdef0123456789]+)/i all day can give you a heaadache. With a little luck and a bit of hard work, you’ll know exactly what the previous expression means.

For this post, all examples will be using Perl.

Text Search
A regular expression, or regex, in its simplest form is a text search. Here’s an example:

$var = "Hello World";
if ( $var =~ m/Hello/ ) {
print "Match\n";

In perl, the operator =~ is used to run a regex against a variable. The m/Hello/ will match if the variable has “Hello” anywhere.

To make the match case-insensitive, simply add an i after the last forward slash. So change the regex to m/Hello/i to match “Hello”, “HeLlO” and “hello”.

Carets and Dollar Signs
A caret (^) at the beginning of a regex represents the beginning of a string. Here’s an example:

$var = "Hello World";
if ( $var =~ m/^Hello/ ) {
print "Match\n";

A dollar sign ($) at the end of a regex represents the end of a string. Another example:

$var = "Hello World";
if ( $var =~ m/World$/ ) {
print "Match\n";

If you want to match one of these special characters, put a backslash before it.

$var = "Hello^ $World";
if ( $var =~ m/e\^ \$W/ ) {
print "Match\n";

Putting a list of characters inside braces “[]” will match any of these characters.

$var = "Hello World";
if ( $var =~ m/[aeiou]/ ) {
print "There is a vowel.\n";

You can even tell if a string contains a hexadecimal value. This example uses the special character +. It means that the previous character must appear 1 or more times.

$var = "0x157afde";
if ( $var =~ m/^0x[0123456789abcdef]+$/ ) {
print "It is hexadecimal\n";

Within the braces, instead of listing every possible character, you can specify a range to be matched. For instance, 0-9 will match any digit 0 through 9. Here’s a slightly shorter example:

$var = "0x157afde";
if ( $var =~ m/^0x[0-9a-f]+$/ ) {
print "It is hexadecimal\n";

The caret (^) continues its job as a special character within braces. Putting one at the beginning of the braces will match anything but those listed inside the braces.

$var = "0x157afde";
if ( $var =~ m/^[^0-9a-fx]+$/ ) {
print "It is not hexadecimal\n";

Periods and Asterisks
A period (.) will match any character.

$var = "Hello World";
if ( $var =~ m/^H.llo W.+$/ ) {
print "Match\n";

An asterisks (*) is similar to a plus sign (+), but an asterisks will match 0 or more of the previous character.

$var = "Hello World";
if ( $var =~ m/^Hello .*$/ ) {
print "Saying hello\n";

Tomorrow, more special characters, including white-space characters, non-whitespace characters, and matching parentheses.

Learn to program through Project Euler

About 6 months ago, I was surfing and came across a math/programming site that has fascinated me ever since, Project Euler. They have over 200 problems to solve and continue to add more. The problems start off very easy and get difficult rather quickly. Some of the beginning problems can even be solved using paper and pencil.

If you are just starting to learn computer programming, you should check out this site. The first problem can be solved fairly easily, and I will show you how I did it in perl.

First, let’s look at the problem. They want you to “Find the sum of all the multiples of 3 or 5 below 1000.” What the program will have to do is loop through all whole numbers from 1 to 999. Inside the loop, there is a check to see if the number is a multiple of 3 or 5. If it is, it is added to the sum. After the loop, print the sum to the screen.

Here’s the code:

$sum = 0;
$counter = 1;
while( $counter < 1000 ) {
if ( $counter % 3 == 0 || $counter % 5 == 0 ) {
$sum = $sum + $counter;
$counter = $counter + 1;
print "The answer is $sumn";

This program, just like every other computer program, uses flow control. Basically flow control tell the computer what to do and when to do it. There are 2 flow control structures here, a while loop and an if statement. Both of these are started by a comparison inside parenteses, then an opening curly brace. They are ended by the closing curly brace.

The while statement should be fairly straightforward, but the if statement is a little complex. The percent(%) sign means modulus(mod for short), which is simply the remainder of division. For example, 4 % 3 is 1, 4 % 5 is 4, and 9 % 3 is 0. The double pipe(||) means OR. When reading line 4, you say “If counter mod 3 equals 0 or counter mod 5 equals 0, then.”

Let’s go line by line.

Line:1$sum = 0;Set a variable named “sum” to 0.
Line:2$counter = 1;Set a variable named “counter” to 1.
Line:3while( $counter < 1000 ) {Start a loop and continue the loop while counter is less than 1000.
Line:4if ( $counter % 3 == 0 || $counter % 5 == 0 ) {Check to see if the remainder of counter divided by 3 is zero OR the remainder of counter divided by 5 is zero.
Line:5$sum = $sum + $counter;Add counter to sum if so.
Line:6}Close the if block.
Line:7$counter = $counter + 1;Add 1 to counter.
Line:8}Close the while loop.
At this point, the program will repeat the check at line 3 if check is true goto line 4.
Line:9print “The answer is $sumn”;Print the answer to the screen.

You can download perl from perl.com. Once it is installed, you can copy and paste the source code into notepad and save it as euler-1.pl or whatever you want. To run the code, double click on the file.

Play around with the code. Poke it. Prod it. Change the while comparison so it only goes to 10, 100, 100000, etc. Changed the if to check for numbers divisble by 2 and 3. If you mess it up, copy and paste the code back into the file.

If you have any problems, leave a comment.

Computer Math Part 5: Octal

Octal, or base-8, is commonly used in Unix style operating systems. This number system, being base-8, uses digits 0-7. It’s easily translated to binary, but hex and decimal are a little harder.

Each digit in octal is 3 digits in binary, so 08 is 0002, 18 is 0012, … 78 is 1112. Because it is simple to convert octal to binary, I would suggest that you convert octal to binary and then to decimal or hex.

Unix style operating systems use octal to define file permissions. Each file has a 3 octal digit code. The first digit defines the user’s permissions. The second defines the group’s permissions. The final digit defines everyone else’s permissions.

These permissions are based in binary. The first digit is to allow reading of the file. The second digit is to allow writing to the file. The third digit is to allow execution of the file.

A file with permissions of 777 allows everyone to do everything, while 664 allows the owner and group to read and write, but everyone else only gets to read the file.

Check back Wednesday for a discussion of binary truth tables.

Home work:

Convert the following from octal to decimal:

Computer Math, Part 4: Hexadecimal

Now that you understand binary, let’s move onto hexadecimal, or base 16. This is the numbering system most programmers use, because it translates easily to and from binary. Also, 2 hexadecimal digits make up a byte, or 8 bits.

How do we have 16 digits? Simple, hexadecimal uses the digits 0-9 and the letter A-F. 0-9 is the same in hexadecimal as decimal. The digits A-F in hexadecimal are 10-15 in decimal. Here is a conversion chart of single digit hexadecimal:


Hexadecimal, sometimes simply called hex, is very easy to translate to and from binary. This is because each digit in hex is 4 digits in binary. All you have to do is replace the hexadecimal digit with the binary equivalent. For instance, the number FF16 is 111111112.

Converting a binary number to hex works just slightly different. When you convert a number from hex to binary, you can work from left to right or right to left. When you convert a number from binary to hex, you must work from right to left. This is because a binary number might not be the correct length to work from left to right.

That’s all for today, check back Friday for Octal, or base 8. Here’s some homework:

Convert the following hexadecimal numbers to binary and decimal:

Computer Math Part 3: Adding Binary numbers

Since it is Monday, I won’t ask you to think too much today. Adding binary numbers is actually easier than adding decimal numbers, if you can believe that.

Here’s how to do it. Write 210 binary numbers down, say 11112 and 1112. Make sure to align them on the right, same as you would to add decimal numbers. This should be on your paper/notepad:

+ 111

Starting from the right, add the first two digits. 12 + 12 is 102, so write 0 as the right most digit and carry the 1.

Moving on to the next digit, 12 + 12 + 12(carried) = 112, or 310, so write 1 as the next digit and carry the 1.

Third digit is the exact same. 12 + 12 + 12(carried) = 112, or 310, so write 1 as the next digit and carry the 1.

For the Forth digit, 12 + 12(carried) is 102, so write 0 as the right most digit and carry the 1. Drop down the carry, because 1 + 0 is 1 no matter what base you are working with. There’s the answer.

+ 111

Checking the solution is as simple as opening Windows calculator. If you’re not in scientific view, switch to it from the view menu. Select “Bin” for binary mode. Then put in the math problem, same as any other. Now that you know about calculator, try not using it.

Vocab: A digit in binary can be refered to as a bit, so 64-bit, means 64 binary digits.


Create 8 or 9 random binary addition problems. If you want to make it hard, write out 64 digits, or bits, for each binary number.

Computer Math Part 2: Converting Decimal to/from Binary

Wednesday, I discussed the very basics of binary and how to count, or increment, in binary. Today I’ll be discussing converting decimal numbers to and from binary numbers.

Before I cover conversion, let’s talk for a second about bases. That’s what this series boils down to. I’m not talking about military bases, but number bases. Binary is base 2, meaning that there are 2 digits. Because decimal uses 10 digits, it is base 10.

When a number is of a certain base, you denote that by putting a subscripted 2, or 10, immediately after the number. So 1002 means 100 in binary, while 10010 means 100 in decimal. If you don’t fully grasp this, I’m sure you will once you finish the exercises for today.

So, we all know that 12 is 110, but what does 102 equal in base 10? It’s 210. Check out this chart:


For every extra zero on the binary side, the decimal side doubles. This is because binary is base 2. You can say that, counting from the right in binary, each digit placement is worth double the previous.

You can use this chart to convert a binary number to a decimal number. For every 1, add the decimal equivilent. For instance, the number 1112 is 110 + 210 + 410 which is 710. Another example is 10012, which is 810 + 110, or 9.

OK, converting binary to decimal is the easier part for today. On to converting decimal to binary. You do pretty much the same thing as converting binary to decimal, but in reverse. The first step is to grab a scrap piece of paper, or open notepad.

To walk through the process, I’ll convert 10510 to binary. The first step is to find the decimal number in the chart that is closest to 10510 without going over, which is 6410. 6410 is 10000002, so write that binary number on the first line. The second step is to subtract 6410 from 10510, which is 4110.

Then we repeat. So, 3210, or 1000002, is the next number. Write 1000002 on the second line, making sure to line up the numbers on the right side, same as you would for decimal. Then subtract 3210 from 4110, which is 910.

Then we repeat. So, 810, or 10002, is the next number. Write 10002 on the second line, making sure to line up the numbers on the right side, same as you would for decimal. Then subtract 810 from 910, which is 110.

Then we repeat. So, 110, or 12, is the next number. Write 12 on the second line, making sure to line up the numbers on the right side, same as you would for decimal. Then subtract 110 from 110, which is 010.
Because, we have reached zero, we can move on the last step. On your paper/notepad should be:


All you have to do is combine these. Starting on the left, any column that has a 1 in it, write a 1, or if the column only has zeros, write a 0. This yeilds: 11010012. Converting this back to decimal will let you know you did it right.


Convert the following binary numbers to decimal:

Convert the following decimal numbers to binary:

Remember to convert it back to check your work. Check back Monday when I’ll discuss adding binary numbers.