#!/bin/bash # # timeshift.sh - bash script for TV timeshift # # Copyright (C) 2006 Antonio Ruiz # # #This program is free software: you can redistribute it and/or modify it under #the terms of the GNU General Public License as published by the Free Software #Foundation, either version 3 of the License, or (at your option) any later #version. This program is distributed in the hope that it will be useful, but #WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more #details. You should have received a copy of the GNU General Public License along #with this program. If not, see the file /usr/share/common-licenses/GPL or #. #****************************************************************************************************************************** #START user configurable variables ( defaults without commandline parameters ) #****************************************************************************************************************************** # ... for all players set repeat all playlist, for vlc set skins 2 # REPRO=none is no player, m3u playlist and only player script will be created in $RUTA, press Ctrl-C inside "terminal" or configure LIVETV=preview for exit # All players have multiuser support, vlc and none too single user multi-instances support ( timeshift.sh copies with different configuration ) # See ./timeshift.sh --help for command line parameters # player executable (none, kaffeine, kplayer or vlc... may be others players that support m3u playlists as argument) REPRO=vlc # preview window mode (null - no preview window, pv - no closes transcode [uses only xv], preview - closes transcode [xv, sdl or gtk]) LIVETV=pv # directory for buffers (i.e.: /mnt/ramdisk0, $HOME/buffers_video0) RUTA=$HOME # optional directory for clients for client-server operation (i.e.: /mnt/channel01, $HOME/timeshift, T:\LINUX_TV), if any then playlists will has permisive permissions SERPA= # prefix name for buffers (for vlc and none m3u playlist will be create in $RUTA/playlist_$FNAME.m3u... FNAME must change for multiple instances with same directory) FNAME=buffer # number of file buffers BUF=6 # minutes for each buffer (total time = BUF*MIN) MIN=20 # delete buffers on exit? (0 = NO, 1 = YES, 2 = ask in terminal... if 0 you can continue from last session) BORRA=0 # launch xawtv (if REPRO=none ttv for tty instead) for tv-card initialization (0 = NO, 1 = wait until user closes xawtv, 2 or more = launch and kill xawtv after n seconds) TVINIT=1 # video capture device DISPV=/dev/video0 # video capture resolution (i.e.: 480x576, 320x240, ... max. PAL = 768x576, max. NTSC = 720x480) RESOL=320x240 # video bitrate (kbits/s) BIT=1800 # video framerate (PAL = 25, NTSC = 30) FRAME=25 # sound capture device (none = no sound) DISPA=/dev/dsp # audio bitrate (kbits/s) BAT=192 # audio mode (0 = Joint Stereo, 1 = Full stereo, 2 = Mono) AUD=0 # audio capture sampling frequency (khz: 32000, 44100, 48000,...) MUEST=44100 # bits per channel (must be supported by soundcard) BITA=16 #****************************************************************************************************************************** #END user configurable variables #****************************************************************************************************************************** # command line parameters # function: help output function usage() { echo echo -e 'Usage: timeshift.sh [OPTION1 value] [OPTION2 value] ...\n\nbash script for doing live TV timeshift (pause, fast forward and rewind while watching television) with kaffeine, vlc or kplayer. timeshift.sh do not need terminal window, stops when player closes.\n\nHelp:\n\nFor all players set repeat all playlist, for vlc set skins 2. Use --TVINIT 1 or 2 for tv-card initialization. --REPRO none is no player: m3u playlist and only player script will be created in RUTA, press Ctrl-C inside "terminal" or configure --LIVETV preview for exit. All players have multiuser support, vlc and none too single user multi-instances support ( timeshift.sh copies with different configuration ).\n\nOptions:\n\nOPTION [DEFAULT_VALUE] # COMMENTS\n\n-x or --REPRO ['"$REPRO"'] # player executable (none, kaffeine, kplayer or\n vlc... may be others players that support m3u\n playlists as argument)\n-l or --LIVETV ['"$LIVETV"'] # preview window mode (null = no preview window,\n pv = no closes transcode & xv, \n preview=xv/sdl/gtk = closes transcode)\n-d or --RUTA ['"$RUTA"'] # directory for buffers (i.e.: /mnt/ramdisk0,\n $HOME/buffers_video0)\n-f or --FNAME ['"$FNAME"'] # prefix name for buffers (for vlc and none m3u\n playlist will be create RUTA/playlist_FNAME.m3u.\n FNAME must change for multiple instances with\n same directory)\n-n or --BUF ['"$BUF"'] # number of file buffers\n-m or --MIN ['"$MIN"'] # minutes for each buffer (total time = BUF*MIN)\n-e or --BORRA ['"$BORRA"'] # delete buffers on exit? (0 = NO, 1 = YES, 2 =\n ask in terminal... if 0 you can continue from\n last session)\n-i or --TVINIT ['"$TVINIT"'] # launch xawtv (if REPRO=none then ttv for tty)\n for tv-card initialization ( 0 = NO,\n 1 = wait until user closes xawtv, 2 or more\n = launch and kill xawtv after n seconds )\n-v or --DISPV ['"$DISPV"'] # video capture device\n-r or --RESOL ['"$RESOL"'] # video capture resolution (i.e.: 480x576,\n 320x240, ... max. PAL = 768x576, max. NTSC =\n 720x480)\n-b or --BIT ['"$BIT"'] # video bitrate (kbits/s)\n-t or --FRAME ['"$FRAME"'] # video framerate (PAL = 25, NTSC = 30)\n-s or --DISPA ['"$DISPA"'] # sound capture device (none = no sound)\n-w or --BAT ['"$BAT"'] # audio bitrate (kbits/s)\n-a or --AUD ['"$AUD"'] # audio mode (0 = Joint Stereo, 1 = Full\n stereo, 2 = Mono)\n-y or --MUEST ['"$MUEST"'] # audio capture sampling frequency (khz: 32000,\n 44100, 48000,...)\n-q or --BITA ['"$BITA"'] # bits per channel (must be supported by\n soundcard)\n-h or --help # display this help message and exit' exit $SERROR } while (( "$#" )); do case $1 in -x | --REPRO ) shift; REPRO=$1;; -l | --LIVETV ) shift; LIVETV=$1;; -d | --RUTA ) shift; RUTA=$1;; -f | --FNAME ) shift; FNAME=$1;; -n | --BUF ) shift; BUF="10#"$1; BUF=$((1*BUF));; -m | --MIN ) shift; MIN="10#"$1; MIN=$((1*MIN));; -e | --BORRA ) shift; BORRA="10#"$1; BORRA=$((1*BORRA));; -i | --TVINIT ) shift; TVINIT="10#"$1; TVINIT=$((1*TVINIT));; -v | --DISPV ) shift; DISPV=$1;; -r | --RESOL ) shift; RESOL=$1;; -b | --BIT ) shift; BIT="10#"$1; BIT=$((1*BIT));; -t | --FRAME ) shift; FRAME="10#"$1; FRAME=$((1*FRAME));; -s | --DISPA ) shift; DISPA=$1;; -w | --BAT ) shift; BAT="10#"$1; BAT=$((1*BAT));; -a | --AUD ) shift; AUD="10#"$1; AUD=$((1*AUD));; -y | --MUEST ) shift; MUEST="10#"$1; MUEST=$((1*MUEST));; -q | --BITA ) shift; BITA="10#"$1; BITA=$((1*BITA));; -h | --help ) SERROR=0; usage;; * ) echo "*** Wrong option $1 ***"; SERROR=1; usage;; esac shift done if [ $BUF -lt 2 ] || [ $MIN -lt 1 ] || [ $BORRA -lt 0 ] || [ $BORRA -gt 2 ] || [ $TVINIT -lt 0 ] || [ $AUD -lt 0 ] || [ $AUD -gt 2 ] || [ $BIT -lt 0 ] || [ $FRAME -lt 0 ] || [ $BAT -lt 0 ] || [ $MUEST -lt 0 ] || [ $BITA -lt 0 ]; then # check values echo "*** Wrong value ***" SERROR=1 usage fi # general information output echo "timeshift.sh version 6.710 Copyright (C) 2006 Antonio Ruiz" echo "This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. For more details: http://www.gnu.org/copyleft/gpl.txt" echo echo "*** Configure TVINT = 1 or 2, OR, first of all, launch any television application to select the channel (or video input) and set the values of brightness, contrast and color ***" echo echo "**************************************************************************" echo "******* timeshift without terminal, with vlc, kaffeine or kplayer ********" echo "*************** timeshift stops when player closes **********************" echo "**************************************************************************" echo echo "*** Close all television applications before continuing ***" echo # TV timeshift function version 4 # function: check player and transcode, manage exit function salir5() { if [ $PIDTRANS -ne 0 ]; then ps $PIDTRANS 1>/dev/null # check transcode fi if [ $? -ne 0 ]; then echo echo "*** transcode finished ***" echo if [ $CEXIT -eq 0 ] && [ $LIVETV != "preview" ]; then SERROR=1 elif [ $LIVETV == "preview" ]; then PEXIT=1 fi fi if [ $REPRO != "none" ] && [ $PIDPLAY -ne 0 ]; then ps $PIDPLAY 1>/dev/null # check pidof player fi if [ $? -ne 0 ] || [ $CEXIT -eq 1 ] || [ $PEXIT -eq 1 ] || [ $PIDPLAY -eq 0 ]; then # timeshift.sh exit if [ $CEXIT -ne 1 ]; then trap 2 fi if [ $REPRO != "none" ] && [ $CEXIT -eq 1 ]; then kill $PIDPLAY 2>/dev/null ps $PIDPLAY 1>/dev/null while [ $? -eq 0 ]; do #wait kill sleep 0.50 echo echo "kill "$REPRO ps $PIDPLAY 1>/dev/null done elif [ $REPRO != "none" ] && [ $PEXIT -ne 1 ]; then kill $PIDTRANS 2>/dev/null ps $PIDTRANS 1>/dev/null while [ $? -eq 0 ]; do #wait kill sleep 0.50 echo echo "kill transcode" ps $PIDTRANS 1>/dev/null done fi if [ $BORRA -eq 2 ]; then # delete buffers, ask if option is configured echo echo "? Press ENTER to leave the "$BUF" file buffers "$RUTA"/"$FNAME"*.avi or input any character to delete them ..." read TECLA fi if [ "$TECLA" != "" ] || [ $BORRA -eq 1 ] && [ $SERROR -eq 0 ]; then rm $RUTA/play_$FNAME.sh # too delete playlist rm $RUTA/playlist_$FNAME.m3u 2>/dev/null X=0 rm $RUTA/"$FNAME"a.avi if [ -f $RUTA/"$FNAME"a.avi-$ABUF ]; then # may be there is one more rm $RUTA/"$FNAME"a.avi-$ABUF fi echo echo "*** Removing buffers ***" while [ $X -lt $BUF ]; do if [ -h $RUTA/$FNAME$X.avi ] || [ -f $RUTA/$FNAME$X.avi ]; then rm $RUTA/$FNAME$X.avi echo echo "*** Removing buffers ***" fi X=$((X+1)) done else echo echo "*** "$RUTA"/"$FNAME"*.avi have NOT been deleted ***" fi echo echo "*** Finished ..." exit 0 elif [ $SERROR -ne 0 ]; then # an error has occurred kill $PIDTRANS ps $PIDTRANS 1>/dev/null while [ $? -eq 0 ]; do #wait kill sleep 0.50 echo echo "kill transcode" ps $PIDTRANS 1>/dev/null done kill $PIDPLAY ps $PIDPLAY 1>/dev/null while [ $? -eq 0 ]; do #wait kill sleep 0.50 echo echo "kill "$REPRO ps $PIDPLAY 1>/dev/null done echo echo "An unknown error has occurred in timeshift.sh" exit $SERROR fi } # function: command transcode function zsplit() { transcode -x v4l2=resync_margin=1:resync_interval=250$SNULL -i $DISPV $PDISPA -y ffmpeg$SNULL -F mpeg4 -g $RESOL -f $FRAME -w $BIT -e $MUEST,$BITA,2 -b $BAT,0,2,$AUD -J smartyuv=highq=1:diffmode=2:cubic=1:Blend=1:chromath-res=4:threshold=8:doChroma=1,$LIVETV --avi_limit $((((MIN*60)*(BIT*1000+BAT*1024))/8388608)) -o $RUTA/"$FNAME"a.avi& PIDTRANS=$! } # function: Ctrl-C handler function ctrc() { trap 2 echo echo "*** Ctrl-C >> timeshift.sh stopping ***" echo kill $PIDTRANS ps $PIDTRANS 1>/dev/null while [ $? -eq 0 ]; do #wait kill sleep 0.50 echo echo "kill transcode" ps $PIDTRANS 1>/dev/null done CEXIT=1 salir5 } trap "ctrc" 2 # Ctrl-C handler LIM=1000 SERROR=0 CEXIT=0 PEXIT=0 PIDPLAY=0 PIDTRANS=0 N=0 if [ $DISPA == "none" ]; then # check no sound option SNULL=",null" BAT=0 PDISPA="" else PDISPA="-p "$DISPA SNULL="" fi if [ $TVINIT -eq 1 ]; then echo "*** timeshift.sh waiting xawtv or ttv exit ***" echo if [ $REPRO == "none" ]; then ttv -c $DISPV else xawtv -nodga -c $DISPV -C $DISPA fi elif [ $TVINIT -ne 0 ]; then echo "*** timeshift.sh waiting "$TVINIT" seconds for tv-card initialization ***" echo if [ $REPRO == "none" ]; then ttv -c $DISPV& else xawtv -nodga -c $DISPV -C $DISPA& fi PIDXAWTV=$! sleep $TVINIT kill $PIDXAWTV 2>/dev/null ps $PIDXAWTV 1>/dev/null while [ $? -eq 0 ]; do #wait kill sleep 0.50 echo echo "kill xawtv" ps $PIDXAWTV 1>/dev/null done fi # new N value searching old buffers if [ -f $RUTA/"$FNAME"a.avi ]; then X=$(stat -c%s $RUTA/"$FNAME"a.avi 2>/dev/null) sleep 1 if [ $X -eq $(stat -c%s $RUTA/"$FNAME"a.avi 2>/dev/null) ]; then # check timeshift.sh running with same buffer filename if [ -f $RUTA/"$FNAME"0.avi ]; then while [ -f $RUTA/$FNAME$((N+1)).avi ] && [ $RUTA/$FNAME$((N+1)).avi -nt $RUTA/$FNAME$N.avi ] && [ $((N+1)) -lt $BUF ]; do # search oldest buffer N=$((N+1)) done mv -f $RUTA/"$FNAME"a.avi $RUTA/$FNAME$N.avi # store last buffer N=$((N+1)) if [ $N -ge $BUF ]; then N=0 fi fi else # safe exit condition echo "*** timeshift.sh is already running with same buffer filename ***" REPRO="none" PEXIT=1 BORRA=0 salir5 fi fi #first run transcode install -d $RUTA # Create directory install -d $HOME/.ffmpeg # Patching ffmpeg export bug of transcode 1.7 echo '#' > $HOME/.ffmpeg/medium.ffpreset echo echo "*** Patching ffmpeg export bug of transcode 1.7" echo zsplit #launch transcode sleep 10 # wait to avoid a player jump buffer error echo echo "*** Buffers will use aproximately $((((BUF*MIN*60)*(BIT*1000+BAT*1024))/8388608)) MBytes of hard disk ***" echo #build playlist PLA="" if [ $REPRO == "kplayer" ]; then # kplayer arguments X=$N ARG="" while [ $X -lt $BUF ]; do ARG=""$ARG""$RUTA"/"$FNAME""$X".avi " X=$((X+1)) done X=0 while [ $X -lt $N ]; do ARG=""$ARG""$RUTA"/"$FNAME""$X".avi " X=$((X+1)) done else ARG='#EXTM3U' # vlc, kaffeine or others: build m3u playlist X=$N while [ $X -lt $BUF ]; do ARG="$ARG"'\n'"$FNAME"''"$X"'.avi' X=$((X+1)) done X=0 while [ $X -lt $N ]; do ARG="$ARG"'\n'"$FNAME"''"$X"'.avi' X=$((X+1)) done echo -e $ARG > $RUTA/playlist_$FNAME.m3u chmod 640 $RUTA/playlist_$FNAME.m3u fi # delete old $RUTA/"$FNAME"a.avi-* buffers at the beginning RBUF=-1 while [ $? -eq 0 ]; do while [ $RBUF -lt $LIM ]; do RBUF=$((RBUF+1)) if [ $RBUF -lt 10 ]; then # split number, character value ARBUF="00"$RBUF"" elif [ $RBUF -lt 100 ]; then ARBUF="0"$RBUF"" else ARBUF="$RBUF" fi if [ -h $RUTA/$FNAME$RBUF.avi ]; then rm $RUTA/$FNAME$RBUF.avi fi if [ -f $RUTA/"$FNAME"a.avi-$ARBUF ]; then rm $RUTA/"$FNAME"a.avi-$ARBUF echo echo "*** Removing old buffers ***" fi done LIM=$((LIM+1000)) ls $RUTA/"$FNAME"a.avi-* 2>/dev/null done # launch player ln -f -s $RUTA/"$FNAME"a.avi $RUTA/$FNAME$N.avi # symlink first buffer at start if [ $REPRO == "kplayer" ]; then TMPSCR="kplayer $ARG" elif [ $REPRO == "none" ]; then TMPSCR="vlc $RUTA/playlist_$FNAME.m3u" else TMPSCR="$REPRO $RUTA/playlist_$FNAME.m3u" fi echo -e '#!/bin/sh\n# temp script, play buffers by timeshift.sh\n'"$TMPSCR"' 2>/dev/null\necho "*** '"$RUTA"'/play_'"$FNAME"'.sh ***"\necho\n' > $RUTA/play_$FNAME.sh chmod 750 $RUTA/play_$FNAME.sh if [ $REPRO == "vlc" ]; then vlc $RUTA/playlist_$FNAME.m3u 2>/dev/null & PIDPLAY=$! # pidof vlc sleep 5 X=$(ps k -start_time exo pid,comm | grep ' vlc') # check pidof vlc X=${X%%vlc*} if [ ! $X ]; then PIDPLAY=0 salir5 fi elif [ $REPRO != "none" ]; then $TMPSCR 2>/dev/null & sleep 5 PIDPLAY=$(ps k -start_time exo pid,comm,tty | grep ' '"$REPRO"' ') PIDPLAY=${PIDPLAY%%$REPRO*} # pidof player ( $! no works for K-players ) if [ ! $PIDPLAY ]; then PIDPLAY=0 salir5 fi else PIDPLAY=$PIDTRANS fi # handle buffers, repeat until player closes TBUF=0 ABUF="000" CUC=0 ACU=0 HORAA=$(date +%H) MINUTA=$(date +%M) HORAA="10#"$HORAA"" #avoid octal value MINUTA="10#"$MINUTA"" HORAA=$((HORAA*1)) MINUTA=$((MINUTA*1)) TOMA=$((HORAA*60+MINUTA)) while [ $? -eq 0 ]; do sleep 5 salir5 #check player if [ -f $RUTA/"$FNAME"a.avi-$ABUF ]; then # check transcode split mv -f $RUTA/"$FNAME"a.avi-$ABUF $RUTA/$FNAME$N.avi if [ $N -eq $((BUF-1)) ]; then # restart buffer value when last buffer reached N=-1 fi TBUF=$((TBUF+1)) if [ $TBUF -lt 10 ]; then # split number, character value ABUF="00"$TBUF"" elif [ $TBUF -lt 100 ]; then ABUF="0"$TBUF"" else ABUF="$TBUF" fi N=$((N+1)) ln -f -s $RUTA/"$FNAME"a.avi $RUTA/$FNAME$N.avi fi HORAB=$(date +%H) # show internal information MINUTB=$(date +%M) HORAB="10#"$HORAB"" #avoid octal value MINUTB="10#"$MINUTB"" HORAB=$((HORAB*1)) MINUTB=$((MINUTB*1)) SEG=$(date +%S) TIME=$((CUC+HORAB*60+MINUTB-TOMA)) if [ $TIME -lt 0 ]; then CUC=1440 TIME=$((TIME+CUC)) elif [ $TIME -gt 1440 ]; then CUC=0 ACU=$((ACU+1)) fi echo echo "timeshift.sh->[Buffer "$N" # $((TIME+ACU*1440)):"$SEG"]" done SERROR=1 salir5 #******************************************************************************* # # timeshift.sh version 6.710 for CentOS-Red Hat (kernel 2.6.18, # gnome 2.16.0, transcode 1.1.0, vlc 0.9.9a, kplayer, kaffeine 0.8.7), also # should work in other linux distributions. # # script for doing live TV timeshift (pause, fast forward and rewind while #watching television) with kaffeine, vlc or kplayer. All players have multiuser #support, vlc and none too single user multi-instances support ( timeshift.sh #copies with different configuration ). # # timeshift.sh do not need terminal window, stops when player closes # # # Latest version release notes: # # 6.7xx: -supports kaffeine KDE4 and any others kaffeines # # -Patched ffmpeg export plugin bug of transcode 1.7 # # -Buffer directory created if not exists # # 6.6xx: -fixed echoed buffer size and split size in command transcode # # -added sound device=none for no sound # # -added command line parameters # # -added tv card initialization option # # -live TV preview now works with recent transcode # -changed #!/bin/bash , now it is compatible with squeeze # -ttv as option for tv-init # # Website: # # http://timeshift.110mb.com # http://www.geocities.ws/yrmateo/ # #*******************************************************************************