V4L channel script: Difference between revisions

From LinuxTVWiki
Jump to navigation Jump to search
(The channel script)
 
mNo edit summary
Line 41: Line 41:
# /usr/local/bin/channel
# /usr/local/bin/channel
#
#
# Script to record news programs to .avi files, using mencoder, and
# Script to record analog television programs to .avi files, using mencoder, and
# the associated closed captioning in a separate identically named .txt file
# the associated closed captioning in a separate identically named .txt file
#
#
Line 49: Line 49:
# Use the bash interpreter -- /bin/bash, not /bin/sh
# Use the bash interpreter -- /bin/bash, not /bin/sh
#
#
# Usage: channel <channel number> <recording time in minutes> <optional title>
# Usage: channel <channel number> <duration> <title> <capture card number>
# <capture card number>
#
#
# For instance,
# For instance,
#
#
# channel 28, 30min, "BBC World News", 0
# channel 28, 30min, "BBC World News", 1
#
#
# Input parameter rules:
# Input parameter rules:
# * commas are optional
# * commas are optional
# * give duration (recording time) in minutes
# * the word "min" (for minutes) is optional
# * the word "min" (for minutes) is optional
# * a space signals a new parameter
# * a space signals a new parameter

Revision as of 19:10, 22 December 2005

The channel script

Introduction

This simple script, with its companion timestamper, is designed to capture television programs on a regular schedule and store the recordings in a dated directory tree along with the closed captioning text files. Because the scripts are so elementary, they are very easy to debug, and the script has been running flawlessly for more than six months now.

The script is designed to handle several capture cards for simultaneous capture, and jobs are scheduled per card in a cron job or issued manually for a single program.

The use of bash is elementary and can surely be improved on; I'm self-taught. Since the wiki uses the GPL license, the scripts are hereby GPL'd; feel free to modify.

Hardware

My setup is an amd64 motherboard with on-board NICs, sound, and video, and five PCI slots (Gigabyte K8NS Ultra-939), so there's lots of room for grabber cards. It currently uses three FlyVideo3000FM NTSC (saa7134) cards, of slightly different iterations, so one has a different tuner. I chose them because I can get sound directly off the cards and don't need a patch cable for each one to a sound card.

The three capture cards are loaded as follows:

saa7134 video_nr=1,2,3 vbi_nr=1,2,3 mixer_nr=1,2,3 radio_nr=1,2,3 card=2,2,2 tuner=43,43,17 oss=1,1,1

The CPU is an AMD Athlon 64 3000+ 512K 90nm (939); each mencoder session uses about 30% of the CPU. Results from triple simultaneous capture is sometimes quite blocky, but generally acceptable. We pull the TV signal off the air and reception is variable.

I would like to switch to pcHDTV-3000, but these cards don't have closed captioning support yet.

I capture to SATA drives; the board has support for four of these. The OS is installed on a PATA drive.

Software

The OS is Debian sid with a custom 2.6.12-rc2 kernel. I generally leave the OS alone, but occasionally update some of the applications.

Mencoder is used to grab and compress the footage, using DIVX and mp3lame and an avi wrapper (suggestions for improvements are welcome). I'm currently running Christian Marillat's unofficial 1:1.0-pre7cvs20051102-0.1 Debian package.

We don't don't view the footage on the capture machine, but use NFS to view the captured files on other machines. On OSX, you can view the avi files with VLC; Windows is untested, but the files should play after installing the DIVX codec. Users can be given access to the recording machine's crontab. On X11, kcron provides a user-friendly interface. The status of the capture machine can usefully be monitored with gnome-system-monitor.

For listings, we use Freeguide.

Capture script


#!/bin/bash
#
# /usr/local/bin/channel
#
# Script to record analog television programs to .avi files, using mencoder, and
# the associated closed captioning in a separate identically named .txt file
#
# Written by David Liontooth 19 November 2004
#
# You need to include /usr/local/bin in cron's PATH (see kcron's Variables)
# Use the bash interpreter -- /bin/bash, not /bin/sh
#
# Usage: channel <channel number> <duration> <title> <capture card number>
#
# For instance,
#
#       channel 28, 30min, "BBC World News", 1
#
# Input parameter rules:
#    * commas are optional
#    * give duration (recording time) in minutes 
#    * the word "min" (for minutes) is optional
#    * a space signals a new parameter
#    * enclose multi-word titles in quotes
#    * don't use apostrophes in titles -- messes up searching of captured text
#    * the default card number is currently 1
#
# To do
#    * card choice could be based on which one is available --
#      no need to select one in the command
#    * alternatively, you can try a different card if the chosen one is busy
#    * convert seconds to minutes:seconds
#    * check /dev/vbi$DEV in addition to or instead of /dev/dsp$DEV?
#    * add a confirmation at the end showing the size of the completed file 
#      (for manual mode)
#
# Changelog
#    2005-01-12: added $! to terminate ntsc-cc and channel-timestamp
#    2005-01-13: file names start with the date and time rather than channel
#    2005-01-14: changed the transition time to 15 seconds
#    2005-03-14: changed the transition time to 20 seconds
#    2005-04-01: changed storage directory to /tv1
#    2005-04-15: added $DEV input parameter to handle multiple tv cards
#    2005-04-23: added aumix -d /dev/mixer1 -1 R for sound off the saa
#    2005-05-13: added mixer device number 
#    2005-05-16: new directories are created with 775
#    2005-05-22: added busy test
#    2005-10-07: use zvbi-ntsc-cc, soon in libzvbi 0.2.17
#    2005-10-11: added KCET 28, or PBS, which works with the us-bcast frequency table
#                (note user tna's ~.xawtv must also specify this table)
#    2005-10-26: increased bitrate from 800 to 1200kbps as an experiment
#    2005-11-03: decreased bitrate from 1200 to 800kbps to save space
#
# ***************************************************************************

# First some checks triggered by manual mode

if [ "$1" = "" ] ; then
 echo "Use news <channel number> <recording time in minutes>";
 echo "Please give a channel! Valid channels are 2, 4, 5, 7, 9, 11, 13, and 28.";
 exit
fi

if [ "$2" = "" ] ; then
 echo "Use news <channel number> <recording time in minutes>";
 echo "Please give a recording length in minutes!";
 exit
fi

if [ "$3" = "" ] ; then
 echo "Use news <number> <duration> <title>";
 echo "Please give a title to the recording!";
 exit
fi

# Define the video and VBI (vertical blanking interval) device to use
# Default is /dev/video1 and /dev/vbi1
if [ "$4" = "" ] ;
 then DEV=1
 else DEV=$4
fi

# Define variable DIR to contain nested directories for
#  yyyy, yyyy-mm, and yyyy-mm-dd (today's date)
DIR=/tv5/$(date +%Y)/$(date +%Y-%m)/$(date +%F)

# Create the directory (and any missing parents) if needed
if test ! -d $DIR
  then mkdir -p -m 775 $DIR
fi

# Strip the comma, if any, from the channel name
CH=${1%,*}

# Set the channel (current user needs X11 access)
# You can also set this in mencoder with tv://$CH or channel=$CH
v4lctl -c /dev/video$DEV setchannel $CH

# Convert channel number to name for the base file name
case $CH in
  2) CH=KCBS;;
  4) CH=KNBC;;
  5) CH=KTLA-WB;;
  7) CH=KABC;;
  9) CH=KCAL;;
 11) CH=KTTV-FOX;;
 13) CH=KCOP-UPN;;
 28) CH=KCET;;
esac

# Strip the {min,|min|,} if it's there, from the duration
TIM=${2%m*}; TIM=${TIM%,*}

# Strip the comma, if any, from the title, and convert spaces to underscores
TIT=_`echo ${3%,*} | sed -e "s/ /_/g"`

# Define the file name (escape underscore before $) and print it to screen
FIL=$(date +%F_%H:%M)\_$CH$TIT; echo Preparing to record $FIL

# Check if the capture device is busy
BUSY="Capture card $DEV is busy -- will try for another five minutes \n"
START=$(date +%s); TARGET=$[$START + $[5*60]]

while [ "$(sudo lsof /dev/dsp$DEV)" != "" ]; do
  if [ $TARGET -gt $(date +%s) ]
    then echo -ne $BUSY
      sleep 5; BUSY=""
    else echo "Recording of $FIL aborted -- capture card $DEV is not available"
      exit
  fi
done

# Convert minutes to seconds and adjust down five seconds for the hardware to reset
TIM=$[$[TIM*60]-5]

# Adjust the duration down by the delay added by the busy check, exit if no time left
TIM=$[TIM-$[$(date +%s) -$START]]; if [ $TIM -lt 1 ]; then exit; fi

# Start the timestamp script and background
news-timestamp $CH $TIT $DIR $FIL &

# Get the PID for the timestamper
TMSP=$!

# Start cc capture and background the process
zvbi-ntsc-cc -d /dev/vbi$DEV -cp >> $DIR/$FIL.txt &

# Get the PID for the closed captioning
NTSC=$!

# Sound settings (alsa not needed?)
alsactl restore
aumix -d /dev/mixer$DEV -1 R

# Set any additional values (none currently needed)
#v4lctl -c /dev/video0 color "50%"

# Record the footage (note this assumes direct audio)
# Adding -ovc lavc -lavcopts vcodec=mpeg4:vhq may improve quality --
# as may vcodec=msmpeg4:vbitrate=1800:vhq:keyint=250
# but what you need is fast antialiasing, i.e., scanline interpolation

# Use this to control the bitrate -- default is around 800
#lavc -lavcopts vbitrate=1800 -oac mp3lame -lameopts cbr:br=128 -endpos $TIM -o \

echo "Initiating recording of $FIL from channel $1"
echo "on capture card $DEV, at $(date +%r), duration $TIM seconds"

mencoder -tv driver=v4l2:device=/dev/video$DEV:fps=30000/1001:chanlist=us-bcast:\
audiorate=32000:adevice=/dev/dsp$DEV:input=0:amode=1:normid=4 -ffourcc DIVX -ovc \
lavc -oac mp3lame -lameopts cbr:br=128 -endpos $TIM -o $DIR/$FIL.avi tv:// > /dev/null

# Terminate the closed captioning and the timestamper
kill $NTSC $TMSP

# EOF

The only part of the script that gave me trouble over a prolonged period is the transition between recordings. Sometimes it takes the kernel several seconds to activate a card, and if the recording length doesn't compensate down, the next scheduled recording bumps into a busy device. However, this problem appears to have been fully solved in the current busy script, which waits for up to five minutes and shortens the recording time by the time waited.

Time-stamping script

The main script calls this little routine for timestamping the closed captioning files. this is useful only if you want to set up a searchable database of text.

#!/bin/bash
#
# /usr/local/bin/channel-timestamp
#
# This shell script is used to add timestamps to closed captioning
# It is called by the main recording script, /usr/local/bin/channel.
#
# Add -xv to the top line to get verbose messages
#
# Changelog
# Written by David Liontooth on 19 November 2004
#
# Changelog:
#  2005-01-12: The parent script now handles child process terminations
#  2005-01-13: Timestamps could use XDS data -- start with the date and
#              include title (not implemented)
#
# *****************************************************************

# Write the first timestamp
echo $(date +%F_%H:%M:%S)_$1$2 >> $3/$4.txt

# Write a timestamp every ten seconds
while true
 do
  sleep 10
  echo $(date +%F_%H:%M:%S)_$1$2 >> $3/$4.txt
done

# EOF

Crontabs

While programs can be captured manually using the channel script, I use cron for scheduled recordings.

Here are some examples of crontab usage:


# Folders to search for program files.
PATH=/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Email output to specified account.
MAILTO=tna
# KCAL 9 News at 9pm
0 21 * * 6      channel 9, 60min, "News at 9pm", 1
# KNBC 4 Meet the Press
0 8 * * 7       channel 4, 60min, "Meet the Press", 2
# KABC 7 World News Tonight
30 17 * * 7     channel 7, 30min, "World News Tonight", 1
# KCBS 2 60 Minutes
0 19 * * 7      channel 2, 60min, "60 Minutes", 1
# Fox 11 Morning News at 6 AM/ Good Day LA
0 6 * * 1,2,3,4,5       channel 11, 60min, "Morning News at 6", 1
# KCET 28 BBC World News
30 5 * * 1,2,3,4,5      channel 28, 30min, "BBC World News", 3