bwkaz
04-26-2004, 10:25 PM
OK, what you need:
1) A cron daemon. Most distros come with one already; if yours does not (LFS is the only one I know of), then I would say to follow the BLFS instructions for installing fcron.
2) A TV tuner card. Mine is a BT878, so I use the V4L "bttv" kernel module.
2.5) XawTV. Should come with your distro, but if not, see http://linux.bytesex.org/xawtv/ to get it. You can use xawtv itself to just watch TV with your TV card, and you can use the v4lctl program installed by transcode to programmatically set channels and set other stuff.
3) A sound card (omit both of these if your TV card has an audio input that actually works; the bttv V4L2 driver seems to only produce static on the audio in for me), along with a cable from the audio out of your TV card to the line in on your sound card.
4) Transcode, from http://www.theorie.physik.uni-goettingen.de/~ostreich/transcode/. Yes, there are other ways to get the signal encoded, but I found transcode to be the easiest to get installed (it doesn't depend on anything but V4L and the codecs that it uses). gv4l, while it looked nice, required a large chunk of Gnome 1, which I wasn't going to try to get installed (LFS, so I don't have any way to automatically compile dependencies).
5) Codecs. I used XviD4, but anything that Transcode supports will work pretty well.
OK, how to do it:
0) Set up V4L (at the X server layer and the kernel layer). I expect most distros will do this for you; if not, load up the bttv (or whichever) module at boot time using your distro's tools for that, and make sure there's a Load "v4l" line in your /etc/X11/XF86Config (or XF86Config-4 if that file exists in that directory).
1) Install the cron daemon, if it isn't already. This is how you'll schedule the start of a recording.
2) Install XawTV, if it isn't already.
3) Install the codec(s) that you want. You could just install all of them. I've noticed that XviD, with MP3 audio at "medium" quality, is about 800 megs per hour of video. This seems really high to me, but I've got a 160GB hard drive, so it's not a huge deal. :p I would expect that other codecs can probably get better compression (and twiddling with the settings might help me out, too, I'm not sure).
4) Install transcode. If you're compiling yourself, make sure you enable the proper codecs (and you may want to disable some stuff too; check the output of ./configure --help to see what's changeable).
5) Test transcode. With your TV card plugged into the video source, do a:
v4lctl setchannel X where X is a channel number in your XawTV setup. This will set the channel you want to record from, as I can't currently get transcode to do that on its own. Then:
transcode -i /dev/video0 --import_v4l 1 -p /dev/dsp -x v4l2 -g 384x288
-e 44100,16,2 -y xvid4 -Q 3 -w 1700 -N 0x55 -o test.avi -V -u 500 -q 1
-c 0:0:0-0:0:20 -f 29.97,4 -s 10,4,4,4 -J denoise3d=pre=1 This should all be on one line, but is broken out here to avoid gratuitous post-widening. ;) The stuff in bold is what I think is customizable. The meaning of those options (and a few others):
--import_v4l 1: Use the first V4L device. My BT878 says that device 1 is the TV tuner. If the first device you try doesn't work (gives you static or something), try another. I believe they start at 0.
-p /dev/dsp: This device file is used to get sound from. If you went with the audio cable, it'll be /dev/dsp. If you think you can get your TV card to do sound for you, then you can omit the -p option altogether, and make some changes to the -x option's argument (see below).
-x v4l2: Use the V4L2 input driver. You need a recent V4L installation (most 2.6 kernels have V4L2, but not all kernel headers do; if in doubt, try it and see whether it works). Specify -x v4l2,v4l2 if you want to try to capture audio from the TV card.
-g whatever: The resolution to write the video out at. This is XawTV's resolution, so I used it.
-y xvid4: Use the XviD4 output codec. Specify whatever codec you want; to see what you have, do a tcmodinfo -p to show the base transcode library directory, and then ls /that/directory/export_*.so to see the export modules available. Some are video codecs, and some are audio encoders. I'm not sure how to tell the difference if you don't know what one is...
-o test.avi: Filename to write the output to. Default is /dev/null (not very useful...).
-f 29.97,4: Required if you live in the U.S. and are therefore using an NTSC cable signal. If you live in Europe, the default frequency is suitable for PAL; leave out the -f option. See the transcode manpage for other possible frequencies if neither 29.97 nor the default comes out right.
FYI: The -c option specifies to record 20 seconds of video. As this is just a test, leave it for now.
-s 10,4,4,4: The 10 is the overall audio "gain". For some reason, my soundcard required a lot of gain (50 is the number I ended up using), which introduced a lot of hissing into the audio signal. The other 3 numbers are the volume factors for left, right, and center channels (or something like that; check the manpage to be sure, or just leave them all at the same value as each other).
The -V option may not work with your codec; it tells transcode to try to use the YV12 colorspace all the way through encoding. This increases performance, but doesn't work with all codecs. If it doesn't work, then remove that option and try again.
You'll also want to look at the manpage for the other options (esp. -N; note that XviD+AVI doesn't seem to like -N 0x2000, for Ogg/Vorbis audio).
Anyway, you should get a bunch of output for 20 seconds, and then transcode should exit. If it does not exit after 20 seconds, then wait a few more, and if it still doesn't exit, then hit ctrl-\ to send it SIGQUIT. As long as your CPU isn't still being used a lot by transcode (check gkrellm or top to be sure), the ctrl-\ should kill it cleanly. I'm not sure which conditions make it not exit on its own, but I think it may be related to NPTL.
Anyway, hopefully you have a 20-second AVI file now. Play it with any player (mplayer works well with XviD4), just to make sure your volume is loud enough, etc. If you don't like it, twiddle the settings until you do.
Once you're satisfied, now's the time to set up the recording script:
#!/bin/bash
rectime=NUMBEROFSECONDS # CHANGEME
saverectime=$rectime
basedir=/whatever/path/to/use # CHANGEME
dir=$basedir/$(date +%Y%m%d)
rechours=0
recminutes=0
if ! [ -d $dir ] ; then
mkdir -p $dir || exit 1
fi
if [ $rectime -gt 3600 ] ; then # >1 hour
addhours=$(($rectime / 3600))
rechours=$(($rechours + $addhours))
rectime=$(($rectime % 3600))
fi
if [ $rectime -gt 60 ] ; then # >1 minute left
addminutes=$(($rectime / 60))
recminutes=$(($recminutes + $addminutes))
rectime=$(($rectime % 60))
fi
recseconds=$rectime
extrasleep=$(($saverectime * 10 / 100))
rectime=$(($saverectime + $extrasleep))
killall -2 transcode >/dev/null 2>&1
killall -2 sleep >/dev/null 2>&1
sleep 1
killall -9 transcode >/dev/null 2>&1
killall -9 sleep >/dev/null 2>&1
v4lctl setchannel CHANNELNUM # CHANGEME
transcode -i /dev/video0 --import_v4l 1 -p /dev/dsp0 -x v4l2 -g 384x288
-e 44100,16,2 -y xvid4 -Q 3 -w 1700 -N 0x55 -o $dir/daily.avi -V -u 500
-q 0 -c 0:0:0-$rechours:$recminutes:$recseconds -f 29.97,4 -s 10,4,4,4
-J denoise3d=pre=1 &
pid=$!
sleep $rectime
kill -9 $pid Make sure you edit all CHANGEME lines to use the values you want. What this script does, in a nutshell:
1) Sets up some variables to use later. These could come from command line arguments too.
2) Sets up the base directory to record the file to. This directory is named after the date in pseudo-ISO format (4 digits of year, 2 digits of month, 2 digits of day), after a common base directory. If you only want to schedule this once, then get rid of the line that calls date, and make it dir=$basedir instead.
3) Creates that directory if it doesn't already exist.
4) Does a bunch of integer math in bash to turn the rectime variable (whose units is seconds, BTW!) into three separate variables -- hours, minutes, and seconds. This is what transcode's -c option takes (hh:mm:ss to stop recording at). Also does some math to add another 10% on to the number of seconds (skip these two lines -- the two just before the killall's -- if your transcode exits by itself when it's done).
5) Kill any previous instance of transcode that may be running, first with SIGINT (equivalent of hitting Ctrl-C when it's running interactively, which transcode catches and closes file handles, etc., then shuts down gracefully), then after sleeping for a second, with SIGKILL (which cannot be caught). If your transcode shut itself down gracefully, then remove the killall -9's, but leave the sleep in there.
This is required because the bttv driver only allows once program to use it at once. If your V4L2 driver allows more than one, then forget all the killall's (and the sleep).
6) Set the channel, using XawTV's tools for doing that.
7) Start up a transcode instance in the background (the &). You may want to add a >/dev/null before the &, if your cron daemon insists on mailing you the output (in fcron, you can set !nomail(true) at the beginning of the crontab file to suppress the mail for all cron jobs). If you had to change any of these parameters before to get the test to run properly, change them here also.
8) Capture the PID of the transcode process (pid=$!), then sleep for a number of seconds.
9) Forcefully kill the previous transcode instance. Skip this if your transcode exits on its own (actually, in that case, skip step 8 also, and then there's no point in starting transcode in the background either, so skip the & on the end of it).
Save this script as record.sh somewhere, and make it executable by you (chmod u+x it).
Then, set up a cron job to run this script whenever you want to record for that amount of time. You could take the time as a parameter also (like I do). If you're going to record more than one thing per day, you'll want to either change the date invocation to put each file in a new directory, or you'll want to add a suffix to the end of each file (most likely as another command-line argument).
How to schedule a cron job is documented elsewhere, but if you can't find it, look into man 5 crontab (or man 5 fcrontab if you use fcron).
I think that's it -- if you run into issues, post away. ;)
1) A cron daemon. Most distros come with one already; if yours does not (LFS is the only one I know of), then I would say to follow the BLFS instructions for installing fcron.
2) A TV tuner card. Mine is a BT878, so I use the V4L "bttv" kernel module.
2.5) XawTV. Should come with your distro, but if not, see http://linux.bytesex.org/xawtv/ to get it. You can use xawtv itself to just watch TV with your TV card, and you can use the v4lctl program installed by transcode to programmatically set channels and set other stuff.
3) A sound card (omit both of these if your TV card has an audio input that actually works; the bttv V4L2 driver seems to only produce static on the audio in for me), along with a cable from the audio out of your TV card to the line in on your sound card.
4) Transcode, from http://www.theorie.physik.uni-goettingen.de/~ostreich/transcode/. Yes, there are other ways to get the signal encoded, but I found transcode to be the easiest to get installed (it doesn't depend on anything but V4L and the codecs that it uses). gv4l, while it looked nice, required a large chunk of Gnome 1, which I wasn't going to try to get installed (LFS, so I don't have any way to automatically compile dependencies).
5) Codecs. I used XviD4, but anything that Transcode supports will work pretty well.
OK, how to do it:
0) Set up V4L (at the X server layer and the kernel layer). I expect most distros will do this for you; if not, load up the bttv (or whichever) module at boot time using your distro's tools for that, and make sure there's a Load "v4l" line in your /etc/X11/XF86Config (or XF86Config-4 if that file exists in that directory).
1) Install the cron daemon, if it isn't already. This is how you'll schedule the start of a recording.
2) Install XawTV, if it isn't already.
3) Install the codec(s) that you want. You could just install all of them. I've noticed that XviD, with MP3 audio at "medium" quality, is about 800 megs per hour of video. This seems really high to me, but I've got a 160GB hard drive, so it's not a huge deal. :p I would expect that other codecs can probably get better compression (and twiddling with the settings might help me out, too, I'm not sure).
4) Install transcode. If you're compiling yourself, make sure you enable the proper codecs (and you may want to disable some stuff too; check the output of ./configure --help to see what's changeable).
5) Test transcode. With your TV card plugged into the video source, do a:
v4lctl setchannel X where X is a channel number in your XawTV setup. This will set the channel you want to record from, as I can't currently get transcode to do that on its own. Then:
transcode -i /dev/video0 --import_v4l 1 -p /dev/dsp -x v4l2 -g 384x288
-e 44100,16,2 -y xvid4 -Q 3 -w 1700 -N 0x55 -o test.avi -V -u 500 -q 1
-c 0:0:0-0:0:20 -f 29.97,4 -s 10,4,4,4 -J denoise3d=pre=1 This should all be on one line, but is broken out here to avoid gratuitous post-widening. ;) The stuff in bold is what I think is customizable. The meaning of those options (and a few others):
--import_v4l 1: Use the first V4L device. My BT878 says that device 1 is the TV tuner. If the first device you try doesn't work (gives you static or something), try another. I believe they start at 0.
-p /dev/dsp: This device file is used to get sound from. If you went with the audio cable, it'll be /dev/dsp. If you think you can get your TV card to do sound for you, then you can omit the -p option altogether, and make some changes to the -x option's argument (see below).
-x v4l2: Use the V4L2 input driver. You need a recent V4L installation (most 2.6 kernels have V4L2, but not all kernel headers do; if in doubt, try it and see whether it works). Specify -x v4l2,v4l2 if you want to try to capture audio from the TV card.
-g whatever: The resolution to write the video out at. This is XawTV's resolution, so I used it.
-y xvid4: Use the XviD4 output codec. Specify whatever codec you want; to see what you have, do a tcmodinfo -p to show the base transcode library directory, and then ls /that/directory/export_*.so to see the export modules available. Some are video codecs, and some are audio encoders. I'm not sure how to tell the difference if you don't know what one is...
-o test.avi: Filename to write the output to. Default is /dev/null (not very useful...).
-f 29.97,4: Required if you live in the U.S. and are therefore using an NTSC cable signal. If you live in Europe, the default frequency is suitable for PAL; leave out the -f option. See the transcode manpage for other possible frequencies if neither 29.97 nor the default comes out right.
FYI: The -c option specifies to record 20 seconds of video. As this is just a test, leave it for now.
-s 10,4,4,4: The 10 is the overall audio "gain". For some reason, my soundcard required a lot of gain (50 is the number I ended up using), which introduced a lot of hissing into the audio signal. The other 3 numbers are the volume factors for left, right, and center channels (or something like that; check the manpage to be sure, or just leave them all at the same value as each other).
The -V option may not work with your codec; it tells transcode to try to use the YV12 colorspace all the way through encoding. This increases performance, but doesn't work with all codecs. If it doesn't work, then remove that option and try again.
You'll also want to look at the manpage for the other options (esp. -N; note that XviD+AVI doesn't seem to like -N 0x2000, for Ogg/Vorbis audio).
Anyway, you should get a bunch of output for 20 seconds, and then transcode should exit. If it does not exit after 20 seconds, then wait a few more, and if it still doesn't exit, then hit ctrl-\ to send it SIGQUIT. As long as your CPU isn't still being used a lot by transcode (check gkrellm or top to be sure), the ctrl-\ should kill it cleanly. I'm not sure which conditions make it not exit on its own, but I think it may be related to NPTL.
Anyway, hopefully you have a 20-second AVI file now. Play it with any player (mplayer works well with XviD4), just to make sure your volume is loud enough, etc. If you don't like it, twiddle the settings until you do.
Once you're satisfied, now's the time to set up the recording script:
#!/bin/bash
rectime=NUMBEROFSECONDS # CHANGEME
saverectime=$rectime
basedir=/whatever/path/to/use # CHANGEME
dir=$basedir/$(date +%Y%m%d)
rechours=0
recminutes=0
if ! [ -d $dir ] ; then
mkdir -p $dir || exit 1
fi
if [ $rectime -gt 3600 ] ; then # >1 hour
addhours=$(($rectime / 3600))
rechours=$(($rechours + $addhours))
rectime=$(($rectime % 3600))
fi
if [ $rectime -gt 60 ] ; then # >1 minute left
addminutes=$(($rectime / 60))
recminutes=$(($recminutes + $addminutes))
rectime=$(($rectime % 60))
fi
recseconds=$rectime
extrasleep=$(($saverectime * 10 / 100))
rectime=$(($saverectime + $extrasleep))
killall -2 transcode >/dev/null 2>&1
killall -2 sleep >/dev/null 2>&1
sleep 1
killall -9 transcode >/dev/null 2>&1
killall -9 sleep >/dev/null 2>&1
v4lctl setchannel CHANNELNUM # CHANGEME
transcode -i /dev/video0 --import_v4l 1 -p /dev/dsp0 -x v4l2 -g 384x288
-e 44100,16,2 -y xvid4 -Q 3 -w 1700 -N 0x55 -o $dir/daily.avi -V -u 500
-q 0 -c 0:0:0-$rechours:$recminutes:$recseconds -f 29.97,4 -s 10,4,4,4
-J denoise3d=pre=1 &
pid=$!
sleep $rectime
kill -9 $pid Make sure you edit all CHANGEME lines to use the values you want. What this script does, in a nutshell:
1) Sets up some variables to use later. These could come from command line arguments too.
2) Sets up the base directory to record the file to. This directory is named after the date in pseudo-ISO format (4 digits of year, 2 digits of month, 2 digits of day), after a common base directory. If you only want to schedule this once, then get rid of the line that calls date, and make it dir=$basedir instead.
3) Creates that directory if it doesn't already exist.
4) Does a bunch of integer math in bash to turn the rectime variable (whose units is seconds, BTW!) into three separate variables -- hours, minutes, and seconds. This is what transcode's -c option takes (hh:mm:ss to stop recording at). Also does some math to add another 10% on to the number of seconds (skip these two lines -- the two just before the killall's -- if your transcode exits by itself when it's done).
5) Kill any previous instance of transcode that may be running, first with SIGINT (equivalent of hitting Ctrl-C when it's running interactively, which transcode catches and closes file handles, etc., then shuts down gracefully), then after sleeping for a second, with SIGKILL (which cannot be caught). If your transcode shut itself down gracefully, then remove the killall -9's, but leave the sleep in there.
This is required because the bttv driver only allows once program to use it at once. If your V4L2 driver allows more than one, then forget all the killall's (and the sleep).
6) Set the channel, using XawTV's tools for doing that.
7) Start up a transcode instance in the background (the &). You may want to add a >/dev/null before the &, if your cron daemon insists on mailing you the output (in fcron, you can set !nomail(true) at the beginning of the crontab file to suppress the mail for all cron jobs). If you had to change any of these parameters before to get the test to run properly, change them here also.
8) Capture the PID of the transcode process (pid=$!), then sleep for a number of seconds.
9) Forcefully kill the previous transcode instance. Skip this if your transcode exits on its own (actually, in that case, skip step 8 also, and then there's no point in starting transcode in the background either, so skip the & on the end of it).
Save this script as record.sh somewhere, and make it executable by you (chmod u+x it).
Then, set up a cron job to run this script whenever you want to record for that amount of time. You could take the time as a parameter also (like I do). If you're going to record more than one thing per day, you'll want to either change the date invocation to put each file in a new directory, or you'll want to add a suffix to the end of each file (most likely as another command-line argument).
How to schedule a cron job is documented elsewhere, but if you can't find it, look into man 5 crontab (or man 5 fcrontab if you use fcron).
I think that's it -- if you run into issues, post away. ;)