Version 0.95

- Fixed behaviour in case the shutdown didn't take place (there were many
  "next timer event at..." messages in that case).
- Reduced the default value for MinEventTimeout to 30 minutes.
- Fixed detecting manual start in shutdown feature.
- An error message is now displayed in case the Transfer Mode can't be
  started because the necessary DVB card is currently recording (or there
  is no DVB card that can access this channel).
- Fixed toggling channels with the '0' key in case the "Ok" button has been
  pressed to display the current/next information.
- Pressing the "Power" key now always initiates the shutdown sequence (after
  user confirmation in case of a recording timer), event if there is currently
  a menu or a replay session active. Note the additional remarks in INSTALL
  regarding the values of the two parameters given to the shutdown program
  in case of a currently recording timer.
- Switching through channel groups with the "Left" and "Right" keys now
  always starts at the group that contains the current channel.
- Implemented "Multi Speed Mode" (thanks to Stefan Huelswitt).
- Implemented backtracing to hit the right spot after fast forward/rewind
  (thanks to Stefan Huelswitt).
- Implemented replay mode display (thanks to Stefan Huelswitt, with a few
  rewrites by kls).
- Changed the size of all input buffers used to parse config files or receive
  SVDRP commands to the same value of 10KB. This allows long strings to be
  used in the 'summary' field of a timer, for instance.
- The pipe to the Dolby Digital replay command (option '-a') now closes all
  unused file descriptors in the child process to avoid crashing when the
  OSD is used (thanks to Andreas Vitting).
- Switched to the driver's new tuning API (VDR now requires a driver version
  dated 2001-09-14 or higher).
- Changed obsolete macro VIDEO_WINDOW_CHROMAKEY to VID_TYPE_CHROMAKEY (thanks
  to Guido Fiala).
- New version of the "Master-Timer" tool (thanks to Matthias Schniedermeyer).
- Better error handling when writing configuration files.
- Fixed putting the final editing mark into the edited version's marks file.
- Fixed manipulating an editing mark at the very end of a recording.
- Fixed starting a new replay immediately after stopping a previous one (had
  caused a mix between live video and replay).
- Three new keys ("Volume+", Volume-" and "Mute") to control the DVB card's
  audio output volume.
- New version of the 'epg2timers' tool (thanks to Carsten Koch).
This commit is contained in:
Klaus Schmidinger 2001-09-16 18:00:00 +02:00
parent bb18b9e0b4
commit 156831036e
39 changed files with 3989 additions and 1614 deletions

View File

@ -100,10 +100,13 @@ Stefan Huelswitt <huels@iname.com>
for making the position of the channel display configurable
for making the width and height of the OSD configurable
for implementing the "Jump" function in replay mode
for implementing "Multi Speed Mode"
for implementing backtracing for fast forward/rewind
for implementing the replay mode display
Ulrich Röder <dynamite@efr-net.de>
for pointing out that there are channels that have a symbol rate higher than
27500.
27500
Helmut Schächner <schaechner@yahoo.com>
for his support in keeping the Premiere World channels up to date in 'channels.conf'
@ -132,3 +135,7 @@ Werner Fink <werner@suse.de>
Rolf Hakenes <hakenes@hippomi.de>
for providing 'libdtv' and adapting the EIT mechanisms to it
Andreas Vitting <Andreas@huji.de>
for providing code that closes all unused file descriptors in the child
process of a pipe (used in cPipe)

43
HISTORY
View File

@ -715,3 +715,46 @@ Video Disk Recorder Revision History
definitions). Use your favourite text editor to delete that information.
That way every recording will store the actual summary data at the time of
the recording.
2001-09-16: Version 0.95
- Fixed behaviour in case the shutdown didn't take place (there were many
"next timer event at..." messages in that case).
- Reduced the default value for MinEventTimeout to 30 minutes.
- Fixed detecting manual start in shutdown feature.
- An error message is now displayed in case the Transfer Mode can't be
started because the necessary DVB card is currently recording (or there
is no DVB card that can access this channel).
- Fixed toggling channels with the '0' key in case the "Ok" button has been
pressed to display the current/next information.
- Pressing the "Power" key now always initiates the shutdown sequence (after
user confirmation in case of a recording timer), event if there is currently
a menu or a replay session active. Note the additional remarks in INSTALL
regarding the values of the two parameters given to the shutdown program
in case of a currently recording timer.
- Switching through channel groups with the "Left" and "Right" keys now
always starts at the group that contains the current channel.
- Implemented "Multi Speed Mode" (thanks to Stefan Huelswitt).
- Implemented backtracing to hit the right spot after fast forward/rewind
(thanks to Stefan Huelswitt).
- Implemented replay mode display (thanks to Stefan Huelswitt, with a few
rewrites by kls).
- Changed the size of all input buffers used to parse config files or receive
SVDRP commands to the same value of 10KB. This allows long strings to be
used in the 'summary' field of a timer, for instance.
- The pipe to the Dolby Digital replay command (option '-a') now closes all
unused file descriptors in the child process to avoid crashing when the
OSD is used (thanks to Andreas Vitting).
- Switched to the driver's new tuning API (VDR now requires a driver version
dated 2001-09-14 or higher).
- Changed obsolete macro VIDEO_WINDOW_CHROMAKEY to VID_TYPE_CHROMAKEY (thanks
to Guido Fiala).
- New version of the "Master-Timer" tool (thanks to Matthias Schniedermeyer).
- Better error handling when writing configuration files.
- Fixed putting the final editing mark into the edited version's marks file.
- Fixed manipulating an editing mark at the very end of a recording.
- Fixed starting a new replay immediately after stopping a previous one (had
caused a mix between live video and replay).
- Three new keys ("Volume+", Volume-" and "Mute") to control the DVB card's
audio output volume.
- New version of the 'epg2timers' tool (thanks to Carsten Koch).

15
INSTALL
View File

@ -27,11 +27,8 @@ You can find 'libdvdread' at
http://www.dtek.chalmers.se/groups/dvd/downloads.html
VDR requires the card driver version 0.9.0 or higher
to work properly. You need to load the dvb.o module *without* option
'outstream=0' (previous versions of VDR required this option to have
the driver supply the data in AV_PES format; as of version 0.70 VDR
works with PES format).
VDR requires the card driver version dated 2001-09-14 or higher
to work properly.
After extracting the package, change into the VDR directory
and type 'make'. This should produce an executable file
@ -126,6 +123,12 @@ and only perform the system shutdown. A program that uses the second parameter
to set the hardware for restart must therefore also check whether the first
parameter is '0'.
If a timer is currently recording, the parameters will reflect the start
time of that timer. This means that the first parameter will be a time in
the past, and the second parameter will be a negative number. This only
happens if the user presses the "Power" key while a timer is currently
recording.
Before the shutdown program is called, the user will be prompted to inform
him that the system is about to shut down. If any remote control key is
pressed while this prompt is visible, the shutdown will be cancelled (and
@ -291,6 +294,8 @@ The default PC key assignments are:
Red, Green, Yellow, Blue 'F1'..'F4'
0..9 '0'..'9' in top row
Power 'P'
Volume+/- '+', '-'
Mute 'm'
If you prefer different key assignments, or if the default doesn't work for
your keyboard, simply delete the file 'keys-pc.conf' and restart 'vdr' to get

22
MANUAL
View File

@ -8,7 +8,7 @@ Video Disk Recorder User's Manual
possible, several keys have different meanings in the various
modes:
Key Normal Main Channels Timers Edit/New Recordings Replay
Key Normal Main Channels Timers Edit/New Recordings Replay
Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play
Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause
@ -23,6 +23,9 @@ Video Disk Recorder User's Manual
Blue - Resume Mark Mark(1) - Summary Stop
0..9 Ch select - - - Numeric inp. - Editing
Power Shutdown - - - - - -
Volume+ Volume up - - - - - -
Volume- Volume down - - - - - -
Mute Mute - - - - - -
(1) The "Mark" button in the "Timers" menu only works if sorting the timers
has been disabled in the "Setup" menu.
@ -177,6 +180,10 @@ Video Disk Recorder User's Manual
backward at a slower speed; press again to return to pause mode.
Pressing and holding down the button performs the function until
the button is released again.
If "Multi Speed Mode" has been enabled in the "Setup" menu, the
function of these buttons changes in a way that gives you three
fast and slow speeds, through which you can switch by pressing
the respective button several times.
- Red Jump to a specific location. Enter the time you want to jump to
and then press "Left" or "Right" to jump relative to the current
position, "Up" to jump to an absolute position, and "Down" to
@ -442,7 +449,7 @@ Video Disk Recorder User's Manual
you may want to use smaller values if you are planning
on archiving a recording to CD.
MinEventTimeout=120 If the command line option '-s' has been set, VDR will
MinEventTimeout=30 If the command line option '-s' has been set, VDR will
MinUserInactivity=120 automatically shutdown the computer if the next timer
event is at least MinEventTimeout minutes in the future,
and the user has been inactive for at least
@ -451,6 +458,17 @@ Video Disk Recorder User's Manual
retaining the possibility to manually shutdown the
computer.
MultiSpeedMode = 0 Defines the function of the "Left" and "Right" keys in
replay mode. If set to 0, one speed will be used, while
if set to 1 there will be three speeds for fast and slow
search, respectively.
0 = off
1 = on
ShowReplayMode = 0 Turns displaying the current replay mode on or off.
0 = off
1 = on
* Executing system commands
The "Main" menu option "Commands" allows you to execute any system commands

151
Tools/epg2timers/README Normal file
View File

@ -0,0 +1,151 @@
Overview.
=========
The 4 modules in this directory are designed to allow vdr timer
programming via the http://tvtv.de web EPG (Electronic Program Guide).
Once you have these modules properly configured and installed,
you should be able to simply click on the things you want vdr
to record in the http://tvtv.de web EPG and be done with it.
Everything else can be handled automatically.
Module description.
===================
The http://tvtv.de web EPG creates a so-called "merkliste"
("a list of items to remember") containing all the broadcasts
you selected.
1. The perl script "get_merkliste.pl" transfers this "merkliste"
from the http://tvtv.de web site to a local file "merkliste.html".
2. The C++ program "epg2timers" converts this HTML file into vdr's
timers.conf format.
3. The perl script "loadvdr.pl" pumps these new timer entries
into a running vdr using telnet and the SVDRP protocol.
4. The shell script "update_timers" implements the overall
control of the entire process.
It retrieves the latest merkliste from http://tvtv.de,
converts it to timers.conf format and sends the timer entries
to vdr.
Configuration.
==============
get_merkliste.pl requires configuration of the "files_to_fetch"
variable preset.
Log in to your http://tvtv.de account and click on the "Bookmark"
item in the "Setup" submenu of the "Mein Programm" side bar menu.
This will open a window with a URL in the location field that ends
with an ID value. Replace the xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
in the "files_to_fetch" variable preset with your ID value.
If you are using an HTTP proxy, uncomment the line containing
the $ua->proxy call and put your proxy details in.
epg2timers.cxx allows various items to be configured, but it
should work out of the box. See "tvtv.de channel names" below.
update_timers must know where to find the get_merkliste.pl
perl script and the compiled epg2timers binary. Both must be
in a directory pointed to by the TOOLDIR variable.
update_timers also must know where to find vdr's current
channels.conf file. Put that into the CHANPATH.
Depending on the price of your internet access, you may want to
run update_timers more or less frequently. It may also be a good
idea to run it at times where it is unlikely to interfere with
your current use of vdr. Configure a crontab entry according to
these personal preferences. Here is the entry I use:
1 2 * * * /home/cko/bin/update_timers
It runs update_timers only once a night at 02:01 a.m.
Installation.
=============
Create your TOOLDIR directory if it does not already exist.
Copy get_merkliste.pl and loadvdr.pl into it, compile epg2timers.cxx
with the command:
g++ epg2timers.cxx -o epg2timers
and move the epg2timers binary into the TOOLDIR directory.
The get_merkliste.pl script requires certain packages to run.
Besides of course perl, install perl-libwww-perl (at least
that's the name on SuSE 7.2, it may have a different name in
your distribution).
If you have problems with SVDRP and loadvdr.pl, you may want to
try out the update_timers.old script, which replaces the timers.conf
file directly and kills vdr (assuming that it will be restarted
by the runvdr script) to make vdr reload the timers.conf file.
tvtv.de channel names.
======================
The file epg_channel_names contains the names of all channels
currently (as of September 9, 2001) supported by the tvtv.de
web EPG. The variable "channel_map" in epg2timers.cxx maps
these names into PNRs (aka Service IDs). I have initialized
this table with provider names converted from a d-box channel
scan of Astra 19.2E, so the PNRs should be correct for that
satellite, but most of the names propably aren't yet- I simply
had not enough time yet to go through epg_channel_names
and insert all its channel names at the proper places in the
channel map. Consider the map supplied an example. ;-)
If you fix any of the entries, please send me a patch.
For my own humble purposes, the table works well as it is.
Of course, your channels.conf must contain the matching
PNRs (last field in each line).
To Do.
======
These are just ideas. They MAY get implemented.
If you want them to happen, contribute a patch. ;-)
* Support vdr hierarchical directories (after vdr does)
by mapping the http://tvtv.de genre texts into
directory names.
* start_time_safety_margin for epg2timers.
Authors.
========
Carsten Koch: epg2timers.cxx, update_timers, this README file.
Axel Gruber and
Rolf Hakenes: get_merkliste.pl
Peter Ahlert: loadvdr.pl
Credits.
========
I am grateful (in chronological order) to
* Klaus Schmidinger for his excellent vdr program and for
keeping an open mind in all directions.
* Suse (my wife, not the Linux distributor ;-) for encouraging me to
write epg2timers in June 2000 and for her constant patience and support.
* Andreas Steinhauser for periodically criticizing the epg2timers
"manual mode" until I came up with the idea to fully automatize it
and for contributing ideas.
* Axel Gruber for reminding me half a year later, for pushing
the idea until it got implemented, for asking for new features
all the time and for contributing ideas.
* Axel Gruber and Rolf Hakenes for contributing the get_merkliste.pl
perl script.
* Peter Ahlert for contributing the loadvdr.pl perl script.
Carsten, September 2001.

View File

@ -1,13 +1,13 @@
/*
* epg2timers.cxx: Convert an EPG "merkliste" page (http://www.tvtv.de) to a timers.conf
* file for Klaus Schmidinger's vdr (http://www.cadsoft.de/people/kls/vdr).
* epg2timers.cxx: Convert an EPG "merkliste" HTML page (http://tvtv.de)
* to timers.conf format for Klaus Schmidinger's vdr
* (http://www.cadsoft.de/people/kls/vdr).
*
* Copyright (C) 2000 Carsten Koch
* Copyright (C) 2000, 2001 Carsten Koch
*
* 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 2
* of the License, or (at your option) any later version.
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -23,65 +23,349 @@
*/
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// User-configurable options.
static const int stop_time_safety_margin = 10; // add 10 minutes to stop time in case start was delayed
static const int recording_priority = 50; // vdr recording priority setting for all timer entries generated
static const int recording_lifetime = 98; // vdr recording life time setting for all timer entries generated
// Usually, you should not want to change any of these.
static const int max_title = 256; // maximum length+1 of title file name generated
static const int max_genre = 32; // maximum length+1 of genre text parsed
static const int max_line = 1024; // line buffer (not used when parsing summary text)
static const int max_summary = 9000; // Summary can be up to 9000 bytes long (a bit shorter than vdr's SVDRP command buffer)
static const int max_vdr_channel = 1000; // maximum size+1 of your channels.conf
// The following table maps http://tvtv.de channel names into Astra 19.2E PIDs.
// It is incomplete. Contributions welcome.
typedef struct
{
const char * tvtv_name;
unsigned short pnr;
} map_entry;
static const map_entry channel_map[] =
{
// Deutschsprachig
{"13th Street", 42},
{"3sat", 28007},
{"ARTE", 28109},
{"B1", 28206},
{"BR3", 28107},
{"BR-alpha", 28112},
{"ARD", 28106},
{"Discovery", 14},
{"Disney Channel", 34},
{"Eins Extra", 28201},
{"Eins Festival", 28202},
{"Eins MuXx", 28203},
{"Filmpalast", 516},
{"FOX KIDS", 28},
{"Heimatkanal", 517},
{"HR", 28108},
{"Junior", 19},
{"Kabel 1", 899},
{"Kinderkanal", 28008},
{"Krimi&Co", 23},
{"K-Toon", 12},
{"Liberty TV.com", 12199},
{"MDR", 28204},
{"NDR", 28224},
{"NEUN LIVE", 897},
{"ORB", 28205},
{"ORF1", 13001},
{"ORF2", 13002},
{"Phoenix", 28114},
{"Planet", 13},
{"Premiere 1", 10},
{"Premiere 2", 11},
{"Premiere 3", 43},
{"Premiere Action", 20},
{"Premiere Comedy", 29},
{"Premiere SCI-FI", 41},
{"Premiere Star", 9},
{"PREMIERE WORLD", 8},
{"ProSieben", 898},
{"RTL", 12003},
{"RTL2", 12020},
{"SAT.1", 46},
{"SeaSonS", 33},
{"SR", 28110},
{"Studio Universal", 36},
{"Sunset", 16},
{"Super RTL", 12040},
{"Test-Z1", 28305},
{"TW1", 13013},
{"Via 1 - Schöner Reise", 44},
{"VOX", 12060},
{"WDR", 28111},
{"ZDF", 28006},
{"ZDF.doku", 28014},
{"ZDF.info", 28011},
// Movies
{"AXN", 29506},
{"CANAL+", 29100},
{"CANAL+ AZUL", 29101},
{"CANAL+ ROJO", 29102},
{"CANAL+ VERT", 8208},
{"CANAL+ 16/9", 8204},
{"CANAL+ 16|9", 29024},
{"C+ROOD", 4005},
{"CINE CINEMA I", 8206},
{"CINE CINEMA II", 8002},
{"CINE CINEMA III", 8003},
{"CINE CLASSICS", 8709},
{"CINE CINEMA 16/9", 8301},
{"cinecinemas", 4008},
{"CINECLASSICS", 29203},
{"Cinedom 1", 176},
{"Cinedom 1B", 178},
{"Cinedom 1C", 180},
{"Cinedom 1D", 190},
{"Cinedom 2", 179},
{"Cinedom 2B", 183},
{"Cinedom 2C", 184},
{"Cinedom 2D", 188},
{"Cinedom 2E", 193},
{"Cinedom 3", 182},
{"Cinedom 3B", 185},
{"Cinedom 3C", 192},
{"Cinedom 3D", 195},
{"Cinedom 4", 181},
{"Cinedom 4B", 187},
{"Cinedom 4C", 191},
{"Cinedom 5", 186},
{"Cinedom 5B", 194},
{"Cindedom Deluxe", 189},
{"CINEMANÍA AZUL", 29501},
{"CINEMANÍA ROJO", 29605},
{"CINEMANÍA", 29500},
{"K1", 8401},
{"K2", 8402},
{"K3", 8403},
{"K4", 8404},
{"K5", 8405},
{"K6", 8406},
{"K7", 8407},
{"K9", 8409},
{"K12", 8412},
{"TAQUILLA 1", 29206},
{"TAQUILLA 2", 29207},
{"TAQUILLA 3", 29502},
{"TAQUILLA 4", 29503},
{"TAQUILLA 5", 29504},
{"TAQUILLA 6", 29301},
{"TAQUILLA 7", 29302},
{"TAQUILLA 8", 29303},
{"TAQUILLA 11", 29316},
{"TAQUILLA 12", 29610},
{"TAQUILLA 13", 29402},
{"TAQUILLA 14", 29212},
{"TAQUILLA 16|9", 29606},
// Music
{"40 LATINO", 29031},
{"40 TV", 29110},
{"CANAL+ JAUNE", 8203},
{"CLASSICA", 15},
{"GOLDSTAR TV", 518},
{"MCM 2", 8305},
{"MCM AFRICA", 8307},
{"MCM", 8302},
{"MTV 2", 28649},
{"MTV 6", 28641},
{"MTV Base", 28645},
{"MTV Central", 28643},
{"MTV F", 28642},
{"MTV Hits", 28644},
{"MUZZIK", 8007},
{"RFM TV", 17008},
{"TMF", 5015},
{"VH1 Classic", 28647},
{"VH1", 28646},
{"Video Italia", 12220},
{"VIVA ZWEI", 12120},
{"VIVA", 12732},
{"ZIK'/XXL", 17004},
// News
{"BBC WORLD", 17007},
{"Bloomberg TV", 12160},
{"CNBC", 28010},
{"CNBC", 35},
{"CNBC-NBC", 29202},
{"CNN", 28512},
{"DW-tv", 9005},
{"EuroNews", 28015},
{"FOX NEWS", 29032},
{"N24", 47},
{"n-tv", 12730},
{"Sky News", 3995},
// Netherlands
{"NED1", 4011},
{"NED2", 4012},
{"NED3", 4013},
{"NET5", 5004},
{"RTL4", 2004},
{"RTL5", 2005},
{"SBS6", 5005},
{"V8/Fox Kids", 5020},
{"Yorin", 5010},
// Porn
{"BEATE-UHSE.TV", 21},
{"Blue Movie1", 513},
{"Blue Movie2", 514},
{"Blue Movie3", 515},
{"K10", 8410},
{"TAQUILLA X", 29213},
{"TAQUILLA X", 29602},
{"TAQUILLA XX", 29607},
{"X-ZONE", 4009},
// Sports
{"C+BLAUW", 4006},
{"DSF", 900},
{"EUROSPORT", 8101},
{"Eurosport", 28009},
{"EUROSPORT", 29310},
{"EUROSPORTNEWS", 29037},
{"PATHE SPORT|", 8009},
{"PREMIERE SPORT 1", 17},
{"PREMIERE SPORT 2", 27},
{"SUPERDOM", 26},
// French
{"13EME RUE", 8703},
{"AB 1", 17001},
{"AB MOTEURS", 17000},
{"ACTION", 17010},
{"ALLOCINE TV", 8308},
{"ANIMAUX", 17002},
{"ARTE", 9009},
{"BLOOMBERG TV", 8004},
{"CA TV", 8610},
{"CANAL+", 8201},
{"CANAL+ BLEU", 8202},
{"CANAL J", 8108},
{"CANAL JIMMY", 8006},
{"CANALCLUB", 8812},
{"Cartoon Network", 28511},
{"CLUB TELEACHAT", 8303},
{"COMEDIE !", 8702},
{"CONTACT TV", 8804},
{"CUISINE.TV", 8112},
{"DEMAIN !", 8701},
{"DISNEY CHANNEL", 8207},
{"DT CSAT 10", 9159},
{"ENCYCLOPEDIA", 17003},
{"ESCALES", 17005},
{"EURONEWS", 8505},
{"FORUM", 8707},
{"FRANCE 2", 8801},
{"FRANCE 3", 8802},
{"GAME ONE", 8717},
{"i TELEVISION", 8010},
{"KIOSQUE", 8704},
{"KTO", 8304},
{"LA CHAINE METEO", 8008},
{"LA CINQUIEME", 8501},
{"LaChaîneHistoire", 17006},
{"LCI", 8107},
{"LCP", 8506},
{"L'EQUIPE TV", 8706},
{"LibertyTV.com", 12280},
{"MANGAS", 17011},
{"MONTECARLO TMC", 8102},
{"Motors TV", 12300},
{"NAT GEOGRAPHIC", 8310},
{"PAD", 8211},
{"PARIS PREMIERE", 8104},
{"PLANETE 2", 8507},
{"PLANETE", 8103},
{"PMU sur Canal+", 8210},
{"RFO SAT", 8708},
{"SANTE - VIE", 8110},
{"SEASONS", 8001},
{"TCM", 28515},
{"TEST CDN 1", 8616},
{"TEST CDN 3", 8627},
{"TiJi", 8309},
{"TV 5", 9001},
{"TV BREIZH", 8502},
{"TV Puls", 20601},
{"TV5 Europe", 12240},
{"VOYAGE", 8105},
// Spanish
{"ANDALUCÍA TV", 29011},
{"Bloomberg", 12721},
{"CALLE 13", 29609},
{"Canal Canarias", 29700},
{"Cartoon Network", 29314},
{"CNN+", 29020},
{"DISCOVERY", 29116},
{"DISNEY CHANNEL", 29111},
{"DOCUMANÍA", 29200},
{"ESTILO", 29305},
{"ETB", 29035},
{"FASHION TV", 29115},
{"FOX KIDS", 29209},
{"FOX", 29507},
{"MOSAICO", 29315},
{"MÉTEO", 29014},
{"Nat Geo Channel", 29034},
{"NICK-PARAMOUNT", 29312},
{"RTPI", 9006},
{"SEASONS", 29204},
{"TAQUILLA 0", 29205},
{"TCM.", 28516},
{"TVC INT.", 29701},
{"VIAJAR", 29306},
// Miscellaneous
{"Alice", 12200},
{"Canal Algerie", 9008},
{"CANALPRO TV", 8516},
{"ESC1 - EGYPTE", 9003},
{"FASHION TV.COM", 17009},
{"Home Shopping Euro", 45},
{"Home Shopping Euro", 40},
{"Kabel 1 Austria", 20004},
{"Kabel 1 Schweiz", 20003},
{"Polonia 1/Top Sho", 20366},
{"ProSieben A", 20002},
{"ProSieben Schweiz", 20001},
{"QVC GERMANY", 12100},
{"RAI 1", 9004},
{"REAL MADRID TV", 29019},
{"RealityTV", 20309},
{"RTL TELE Letzebuerg", 3994},
{"RTM - MAROC", 9002},
{"SÜDWEST BW", 28113},
{"SÜDWEST RP", 28231},
{"Super 1", 20364},
{"Travel", 28001},
{"TV7", 9007},
{"TV-NIEP II", 12740},
{"Wishline", 12320}
};
// Nothing user-configurable below this line.
static const char date_line[] = "\t<td align=center valign=middle colspan=3><span id=fb-b10>";
static const char start_time_line[] = " \t\t<td bgcolor=\"#7f98bf\" align=center><span id=\"fb-w14\"><nobr>&nbsp;";
static const char stop_time_line[] = "\t\t\t<tr><td bgcolor=\"#002b64\" align=center><span id=\"fn-w9\">bis ";
static const char channel_line[] = "\t\t\t<tr><td bgcolor=\"#002b64\" align=center><span id=\"fb-w9\">";
static const char title_line[] = "\t\t\t\t<td bgcolor=\"#002b64\" align=left width=100%><span id=\"fb-w10\">";
static const char summary_line[] = "\t\t\t<table border=0 cellpadding=10 cellspacing=0 bgcolor=\"white\" width=100%>";
static const char * const channel_names[] =
{
"3sat",
"ARTE",
"*B1 Berlin",
"BR3",
"Bloomberg TV",
"BR Alpha",
"CNN",
"ARD",
"*DW-tv",
"Eins Extra",
"Eins Festival",
"Eins MuXx",
"euroNEWS",
"HR3",
"Kabel1",
"Kinderkanal",
"MDR",
"MTV",
"NDR",
"NTV",
"ORB",
"*ORF1",
"Phoenix",
"PRO7",
"RTL",
"RTL2",
"SAT1",
"skynews",
"SWF",
"Super RTL",
"TM3",
"TW1",
"VOX",
"WDR",
"Theaterkanal",
"ZDF",
"ZDF.doku",
"ZDF.info",
""
};
static const char start_time_line[] = " \t\t<td id=\"jobview-box-date\" align=center><nobr>&nbsp;";
static const char stop_time_line[] = "\t\t\t<tr><td id=\"line\" align=center><span id=\"fn-w9\">bis ";
static const char channel_line[] = "\t\t\t<tr><td align=center><span id=\"fb-w9\">";
static const char title_line[] = "\t\t\t\t<td align=left width=100%><span id=\"fb-w10\">";
static const char summary_line[] = "<span id=\"fn-b8\">";
static const char genre_line[] = "\t\t\t\t<td align=right valign=center nowrap><span id=\"fn-w10\">";
static const int month_lengths[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const int max_channel = sizeof(channel_names)/sizeof(char *);
static const int max_title = 50; // maximum length of title file name generated
static const int max_line = 1024; // line buffer (not used when parsing summary text)
static const int max_summary = 5000; // Summary can be up to 5000 bytes long
static const int stop_time_safety_margin = 10; // add 10 minutes to stop time in case start was delayed
@ -102,6 +386,10 @@ char map_special_char(const char * const word)
return 'Ü';
else if (strcmp(word, "szlig") == 0)
return 'ß';
else if (strcmp(word, "nbsp") == 0)
return ' ';
else if (strcmp(word, "amp") == 0)
return '&';
return ' ';
}
@ -109,40 +397,52 @@ char map_special_char(const char * const word)
void read_file_name(const char * const line, char * const file_name)
void read_file_name_and_title(const char * const line, char * const file_name, char * const title)
{
int line_index = sizeof(title_line) - 1;
int title_index = 0;
char ch = line[line_index++];
int file_name_index = 0;
char ch;
do
{
ch = line[line_index++];
if (ch == '&')
{
char word[10];
int i = 0;
while ((line[line_index + i] != ';') && (i < 9))
word[i++] = line[line_index + i];
word[i] = 0;
ch = map_special_char(word);
line_index += i;
{
word[i] = line[line_index + i]; i++;
}
if (line[line_index + i] == ';')
{
word[i] = 0;
ch = map_special_char(word);
line_index += i;
}
}
switch (ch)
{
case 'ä': file_name[title_index++] = 'a'; file_name[title_index++] = 'e'; break;
case 'ö': file_name[title_index++] = 'o'; file_name[title_index++] = 'e'; break;
case 'ü': file_name[title_index++] = 'u'; file_name[title_index++] = 'e'; break;
case 'Ä': file_name[title_index++] = 'A'; file_name[title_index++] = 'e'; break;
case 'Ö': file_name[title_index++] = 'O'; file_name[title_index++] = 'e'; break;
case 'Ü': file_name[title_index++] = 'U'; file_name[title_index++] = 'e'; break;
case 'ß': file_name[title_index++] = 's'; file_name[title_index++] = 's'; break;
case 'ä': file_name[file_name_index++] = 'a'; file_name[file_name_index++] = 'e'; break;
case 'ö': file_name[file_name_index++] = 'o'; file_name[file_name_index++] = 'e'; break;
case 'ü': file_name[file_name_index++] = 'u'; file_name[file_name_index++] = 'e'; break;
case 'Ä': file_name[file_name_index++] = 'A'; file_name[file_name_index++] = 'e'; break;
case 'Ö': file_name[file_name_index++] = 'O'; file_name[file_name_index++] = 'e'; break;
case 'Ü': file_name[file_name_index++] = 'U'; file_name[file_name_index++] = 'e'; break;
case 'ß': file_name[file_name_index++] = 's'; file_name[file_name_index++] = 's'; break;
case ' ': file_name[file_name_index++] = '_'; break;
case '&':
file_name[file_name_index++] = 'u'; file_name[file_name_index++] = 'n'; file_name[file_name_index++] = 'd';
break;
default:
if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')))
file_name[title_index++] = ch;
if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || (ch == '-'))
file_name[file_name_index++] = ch;
}
ch = int(line[line_index++]);
} while ((title_index < max_title-1) && (ch != '<') && (ch != 0) && (line_index < max_line-1));
file_name[title_index] = 0;
title[title_index++] = ch;
} while ((file_name_index < max_title-5) && (ch != '<') && (ch != 0));
file_name[file_name_index] = 0;
title[title_index-1] = 0;
}
@ -184,7 +484,7 @@ void read_summary(char * const summary)
word[word_index++] = ch;
} while ((word_index < 6) && (ch != '>') && (ch != EOF));
while ((ch != '>') && (ch != EOF)) ch = getchar();
if (strncmp("/table", word, 6) == 0)
if (strncmp("/span", word, 4) == 0)
done = true;
}
break;
@ -207,62 +507,150 @@ void read_summary(char * const summary)
main()
int find_channel_number(const unsigned short * const vdr_pnrs, const char * const channel_name)
{
int channel = 0;
for (int tvtv_channel_number = 0; tvtv_channel_number < sizeof(channel_map)/sizeof(map_entry); tvtv_channel_number++)
if (strcmp(channel_name, channel_map[tvtv_channel_number].tvtv_name) == 0)
for (int vdr_channel_number = 0; vdr_pnrs[vdr_channel_number] != 0xFFFF; vdr_channel_number++)
if (vdr_pnrs[vdr_channel_number] == channel_map[tvtv_channel_number].pnr)
return vdr_channel_number;
fprintf(stderr, "Error - channel '%s' not recognized.\n", channel_name);
exit(1);
/*NOTREACHED*/
}
unsigned short * read_vdr_pnrs(const char * const channels_conf_file_name)
{
FILE * channels_conf = fopen(channels_conf_file_name, "r");
if (channels_conf == NULL)
{
perror("unable to open channels.conf.");
exit(1);
}
unsigned short * vdr_pnrs = (unsigned short *) malloc(max_vdr_channel * sizeof(unsigned short));
int vdr_channel_number = 0;
while (!feof(channels_conf) && (vdr_channel_number < max_vdr_channel-1))
{
char line[1024];
fgets(line, sizeof(line)-1, channels_conf);
int pnr;
if ((line[0] != ':') &&
(sscanf(line, "%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%d", &pnr) == 1))
vdr_pnrs[vdr_channel_number++] = pnr;
}
vdr_pnrs[vdr_channel_number++] = 0xFFFF; // sentinel
fprintf(stderr, "%d pnrs.\n", vdr_channel_number);
return (unsigned short *) realloc(vdr_pnrs, vdr_channel_number * sizeof(unsigned short));
}
void process_input(const unsigned short * const vdr_pnrs)
{
int channel = -1;
int day = -1;
int next_day = -1;
int start_time = -1;
int stop_time = -1;
int stop_hour = -1;
int stop_minute= -1;
char genre[max_genre] = {0};
char summary[max_summary] = {0};
char file_name[max_title] = {0};
char title[max_title] = {0};
while (!feof(stdin))
{
char line[max_line];
fgets(line, max_line-1, stdin);
line[max_line-1] = 0;
if (strncmp(line, date_line, sizeof(date_line)-1) == 0)
{
const int month = (line[sizeof(date_line) + 6]- '0') * 10 + line[sizeof(date_line) + 7]-'0';
day = (line[sizeof(date_line) + 3]- '0') * 10 + line[sizeof(date_line) + 4]-'0';
next_day = day == month_lengths[month]? 1 : day + 1;
next_day = day == month_lengths[month-1]? 1 : day + 1;
}
else if (strncmp(line, start_time_line, sizeof(start_time_line)-1) == 0)
{
start_time = (line[sizeof(start_time_line) - 1] - '0') * 1000 +
(line[sizeof(start_time_line) ] - '0') * 100 +
(line[sizeof(start_time_line) + 2] - '0') * 10 +
(line[sizeof(start_time_line) + 3] - '0');
}
else if (strncmp(line, stop_time_line, sizeof(stop_time_line)-1) == 0)
{
stop_time = ((line[sizeof(stop_time_line) - 1] - '0') * 1000 +
(line[sizeof(stop_time_line) ] - '0') * 100 +
(line[sizeof(stop_time_line) + 2] - '0') * 10 +
(line[sizeof(stop_time_line) + 3] - '0') + stop_time_safety_margin) % 2400;
if ((day < 0) || (start_time < 0) || (file_name[0] == 0) || (channel == max_channel))
stop_hour = (line[sizeof(stop_time_line) - 1] - '0') * 10 +
(line[sizeof(stop_time_line) ] - '0');
stop_minute = (line[sizeof(stop_time_line) + 2] - '0') * 10 +
(line[sizeof(stop_time_line) + 3] - '0') +
stop_time_safety_margin;
if (stop_minute > 59)
{
stop_minute -= 60;
if (stop_hour == 23)
stop_hour = 0;
else
stop_hour++;
}
if ((day < 0) || (start_time < 0) || (file_name[0] == 0) || (channel == -1))
{
fprintf(stderr, "Input data error.\n");
exit(1);
}
else
printf("1:%03d:%02d:%04d:%04d:2:7:%s:%s\n", channel+1, start_time < 600? next_day : day, start_time, stop_time, file_name, summary);
start_time = -1; stop_time = -1; file_name[0] = 0; summary[0] = 0; channel = max_channel;
printf("1:%03d:%02d:%04d:%02d%02d:%d:%d:%s:\"%s\" %s||%s||||||(epg2timers)\n",
channel+1, start_time < 600? next_day : day, start_time, stop_hour, stop_minute,
recording_priority, recording_lifetime, file_name,
title, genre, summary);
start_time = -1; channel = -1;
file_name[0] = 0; summary[0] = 0; genre[0] = 0;
}
else if (strncmp(line, title_line, sizeof(title_line)-1) == 0)
read_file_name(line, file_name);
read_file_name_and_title(line, file_name, title);
else if (strncmp(line, channel_line, sizeof(channel_line)-1) == 0)
{
int i = sizeof(channel_line);
while ((i < max_line-1) && (line[i] != '<')) i++;
while ((line[i] != '<') && (line[i] != 0)) i++;
line[i] = 0; // end of string
for (channel = 0; (channel < max_channel) &&
(strcmp(line + sizeof(channel_line) - 1, channel_names[channel]) != 0);
channel++);
if (channel == max_channel)
fprintf(stderr, "Error - channel '%s' not recognized.\n", line + sizeof(channel_line) - 1);
channel = find_channel_number(vdr_pnrs, line + sizeof(channel_line) - 1);
}
else if (strncmp(line, summary_line, sizeof(summary_line)-1) == 0)
read_summary(summary);
else if (strncmp(line, genre_line, sizeof(genre_line)-1) == 0)
{
int genre_index;
for (genre_index = 0; genre_index < max_genre-1; genre_index++)
{
const char ch = line[genre_index + sizeof(genre_line)-1];
if ((ch == 0) || (ch == '&') || (ch == '<'))
break;
genre[genre_index] = ch;
}
genre[genre_index] = 0;
}
}
}
main(int argc, char *argv[])
{
fprintf(stderr, "epg2timers Version 0.5, 15-Sep-2001.\n");
if (argc != 2)
{
fprintf(stderr, "usage: %s channels.conf\n", argv[0]);
exit(1);
}
const unsigned short * const vdr_pnrs = read_vdr_pnrs(argv[1]);
process_input(vdr_pnrs);
exit(0);
}

View File

@ -0,0 +1,400 @@
ATV,at
ORF1,at
ORF2,at
TW1,at
Club RTL,be
Ketnet/Canvas,be
TVI,be
tv1,be
SF1,ch
sf2,ch
13th Street,de
3sat,de,at,ch
ARD,de
ARTE,de
B1,de
BBC World,de
BEATE-UHSE.TV,de
BR-alpha,de
BR3,de
Bet on Jazz,de
Bloomberg TV,de
Blue Movie1,de
Blue Movie2,de
Blue Movie3,de
CNBC,de
CNN,de
Cartoon,de
Cindedom Deluxe,de
Cinedom 1,de
Cinedom 2,de
Cinedom 3,de
Cinedom 4,de
Cinedom 5,de
Classica,de
DSF,de
Discovery,de
Disney Channel,de
Eins Extra,de
Eins Festival,de
Eins MuXx,de
EuroNews,de
Eurosport,de
FOX KIDS,de
Filmpalast,de
Goldstar TV,de
HH-1,de
HR,de
Heimatkanal,de
Junior,de
K-Toon,de
Kabel 1,de
Kinderkanal,de
Krimi&Co,de
MDR,de
MTV,de
MTV2,de
N24,de
NBC,de
NDR,de
NEUN LIVE,de
ONYX,de
ORB,de
Phoenix,de
Planet,de
Premiere 1,de
Premiere 2,de
Premiere 3,de
Premiere Action,de
Premiere Comedy,de
Premiere SCI-FI,de
Premiere Sport1,de
Premiere Sport2,de
Premiere Sport3,de
Premiere Star,de
Premiere analog,de
ProSieben,de
QVC,de
RTL,de
RTL2,de
SAT.1,de
SR,de
SWR BW,de
SWR RP,de
SeaSonS,de
Studio Universal,de
Sunset,de
Super RTL,de
TNT,de
TRT,de,tr
TV.BERLIN,de
Theaterkanal,de
VIVA,de
VIVA2,de
VOX,de
WDR,de
ZDF,de
ZDF.doku,de
ZDF.info,de
n-tv,de
skynews,de
tv.m,de
Danmark 1,dk
TV2 Danmark,dk
MTV3,fi
Nelonen 4,fi
Subtv,fi
TV1,fi
TV2,fi
13ème Rue,fr
AB 1,fr
Arte,fr
Arte Sat,fr
Canal J,fr
Canal Jimmy,fr
Canal+,fr
Canal+ Bel. bleu,fr
Canal+ Bel. jaune,fr
Canal+ Belgique,fr
Canal+ bleu,fr
Canal+ jaune,fr
Canal+ vert,fr
Ciné Cinémas 1,fr
Ciné Cinémas 2,fr
Ciné Cinémas 3,fr
Ciné Classics,fr
Cinéfaz,fr
Cinéstar 1,fr
Cinéstar 2,fr
Cinétoile,fr
Comédie !,fr
Disney Channel,fr
Escale,fr
Eurosport,fr
Festival,fr
Fox Kids,fr
France 2,fr
France 3,fr
Histoire,fr
LCI,fr
La Cinquième Sat,fr
La chaîne histoire,fr
La cinquième,fr
M6,fr
M6 Music,fr
MCM,fr
MTV,fr
Mangas,fr
Mezzo,fr
Muzzik,fr
Odyssée,fr
Paris Première,fr
Pathé sport,fr
Planète,fr
RTBF 1,fr
RTBF 2,fr
RTL 9,fr
Série Club,fr
TCM,fr
TF1,fr
TMC,fr
TSR 1,fr
TSR 2,fr
TV5,fr
Télétoon,fr
Téva,fr
Voyage,fr
XXL,fr
ANIMALplanet,hu
Budapest TV,hu
Duna TV,hu
FILMMÚZEUM,hu
FOX KIDS/SPORTS,hu
FÕNIX TV,hu
Game Channel,hu
HBO,hu
Hallmark,hu
MAGYAR ATV,hu
Minimax,hu
National Geographic,hu
Nickelodeon,hu
RTL Klub,hu
Romantica,hu
SATeLIT,hu
SPORT1,hu
Spektrum TV,hu
TV2,hu
VIASAT3,hu
VIVA+,hu
fix.tv,hu
m1,hu
m2,hu
+ Calcio,it
+ F1,it
Adult +,it
CANALE 5,it
Canal Jimmy,it
Canale Viaggi,it
Cartoon Network,it
Cine Classics,it
CineCinemas 1,it
CineCinemas 2,it
Classica,it
Cult Network,it
Discovery Channel,it
Disney Channel,it
Euro News,it
Eurosport,it
Hallmark,it
Happy Channel,it
ITALIA 1,it
La 7,it
MTV,it
MTV - TMC 2,it
Marcopolo,it
Match Music,it
Milan Channel,it
Nuvolari Motor,it
Odeon,it
Planete,it
Primafila,it
RAI 1,it
RAI 2,it
RAI 3,it
RAI Sat Fiction,it
RETE 4,it
Raisat Album,it
Raisat Art,it
Raisat Cinema,it
Raisat Educational,it
Raisat Gambero Rosso,it
Raisat Nettuno 1,it
Raisat Nettuno 2,it
Raisat Ragazzi,it
Raisat Show,it
Raisat Sport,it
SNAI Sat,it
Salute e benessere,it
Sat 2000,it
Satisfation Club TV,it
Seasons,it
Stream Calcio,it
Stream News,it
Studio Universal,it
TSI 1,it
TSI 2,it
TVL,it
Tele+ 16:9,it
Tele+ Bianco,it
Tele+ Grigio,it
Tele+ Nero,it
VIVA - Rete A,it
Netherland 1,nl
Netherland 2,nl
Netherland 3,nl
ATV Avrupa,tr
Kanal D,tr
Kral TV,tr
NTV Turkey,tr
Show TV,tr
Star TV,tr
Adult Channel,uk
Adventure One,uk
Anglia,uk
BBC Choice,uk
BBC Choice NI,uk
BBC Choice Scotland,uk
BBC Choice Wales,uk
BBC Knowledge,uk
BBC News 24,uk
BBC Parliament,uk
BBC Prime,uk
BBC World,uk
BBC1,uk
BBC1 North. Ireland,uk
BBC1 Scotland,uk
BBC1 Wales,uk
BBC2,uk
BBC2 North. Ireland,uk
BBC2 Scotland,uk
BBC2 Wales,uk
Bangla TV,uk
Bloomberg TV,uk
Border,uk
Bravo (Analogue),uk
Bravo (Digital),uk
British Eurosport,uk
CNBC Europe,uk
CNN,uk
Carlton Central,uk
Carlton Cinema,uk
Carlton Food,uk
Carlton Westcountry,uk
Carlton/LWT,uk
Cartoon Network,uk
Challenge TV,uk
Channel 4,uk
Channel 5,uk
Channel Television,uk
Disc. Animal Planet,uk
Disc. Channel (Ana.),uk
Disc. Civilisations,uk
Disc. Home Leisure,uk
Disc. Sci-Trek,uk
Disc. Travel Advent.,uk
Discovery Channel,uk
Discovery Kids,uk
Discovery Wings,uk
Disney,uk
Euronews,uk
Fantasy Ch. Dig.,uk
Fantasy Channel,uk
Film Four,uk
Fox Kids,uk
Grampian,uk
Granada,uk
Granada Breeze,uk
Granada Men & Motors,uk
Granada Plus,uk
HTV Wales,uk
HTV West,uk
Hallmark,uk
History Channel,uk
ITN News Channel,uk
ITV Sport Channel,uk
ITV Sport Plus,uk
ITV2,uk
Landscape,uk
Living,uk
MTV UK,uk
MUTV,uk
Meridian,uk
National Geographic,uk
Network 2,uk
Nick Junior,uk
Nick Junior Analogue,uk
Nickelodeon (dig.),uk
Nickleodeon (ana.),uk
Pakistani Channel,uk
Paramount Comedy,uk
Performance,uk
Play UK,uk
Playboy TV,uk
QVC,uk
RTE1,uk
Racing Channel,uk
Rapture TV,uk
S2,uk
S4C,uk
S4C digidol,uk
SKY Cinema,uk
SKY Movie Max(SDig.),uk
SKY Movie Max(ana.),uk
SKY News,uk
SKY Premier(Digital),uk
SKY Premier(OnDigi),uk
SKY Sports 1,uk
SKY Sports 2,uk
SKY Sports 3,uk
Sci-Fi Cable,uk
Sci-Fi Satelite,uk
Scottish,uk
Screenshop,uk
Shop!,uk
Sky Movie Max(OnDig),uk
Sky One,uk
Sky One (OnDigital),uk
Sky Premier(Ana.),uk
Sky Sports .com,uk
Sky Sports Extra,uk
Sky Travel,uk
Sony Entertainment,uk
TCM,uk
TCM (Analogue),uk
TG4,uk
TV3,uk
Tara Television,uk
The Box,uk
Trouble Analogue,uk
Trouble Digital,uk
Tyne Tees Television,uk
UK Drama,uk
UK Gold,uk
UK Gold 2,uk
UK Horizons,uk
UK Style,uk
Ulster ,uk
VH1,uk
Yorkshire,uk
Zee TV,uk

View File

@ -0,0 +1,82 @@
#!/usr/bin/perl
# Create a user agent object
use HTML::Entities;
use HTML::Parser;
use LWP::UserAgent;
use IO::Handle;
STDOUT->autoflush(1);
$ua = new LWP::UserAgent;
$ua->agent("Mozilla/9.1 " . $ua->agent);
# $ua->proxy('http', 'http://localhost:8080/');
$filename = "merkliste.html";
$base_url = "http://www.tvtv.de";
# Hier das Bookmark von TVTV eintragen:
@files_to_fetch = ("/cgi-bin/bookmark.cgi?id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
$num = 0;
$state = 0;
$p = HTML::Parser->new( api_version => 3,
start_h => [\&fparser_start, "tagname, attr"],
unbroken_text => 1 );
foreach $url (@files_to_fetch) {
$nurl = $base_url . $url;
print "Getting " . $nurl . "...\n";
$req = new HTTP::Request GET => $nurl;
$res = $ua->request($req);
if ($res->is_success) {
open (OUTFILE, ">" . $filename);
print OUTFILE $res->content;
close (OUTFILE);
$p->parse ($res->content);
$p->eof;
} else {
print "...FAILED\n";
}
}
# Zielordner fuer die Speicherung der Merkliste:
print "...saved to 'merkliste.html'\n";
sub fparser_start {
my($tagname, $attr_t) = @_;
my(%attr) = %$attr_t;
if ($tagname eq "frame") {
if ($state == 1) {
if (($attr{name} eq "frame_main") ||
($attr{name} eq "frame_nav") ||
($attr{name} eq "frame_nav_bottom")) {
push @files_to_fetch, $attr{src};
}
}
if ($state == 2) {
if (($attr{name} eq "frame_content")) {
push @files_to_fetch, $attr{src};
}
}
}
if ($tagname eq "a") {
if ($attr{href} ne "") {
$last_href = $attr{href};
if ($state == 0) {
push @files_to_fetch, $last_href;
$state = 1;
}
}
}
if ($tagname eq "img") {
if ($state == 1) {
if ($attr{src} =~ /b_joblist/i) {
$state = 2;
push @files_to_fetch, $last_href;
}
}
}
}

89
Tools/epg2timers/loadvdr.pl Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/perl
#
# 0.01 loadvdr (peter)
# 0.02 delete old entries before updating (peter)
# 0.03 dumped Net::Telnet because of lost connections
#
# please submit diffs to petera@gmx.net
#
# ./epg2timers < merkliste.html | perl -w loadvdr.pl
#
#
use Socket;
use Getopt::Std;
@resp = ();
$Dest = "localhost";
$Port = 2001;
$Timeout = 10; # max. seconds to wait for response
$SIG{ALRM} = sub { Error("timeout"); };
alarm($Timeout);
$iaddr = inet_aton($Dest) || Error("no host: $Dest");
$paddr = sockaddr_in($Port, $iaddr);
$proto = getprotobyname('tcp');
socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!");
connect(SOCK, $paddr) || Error("connect: $!");
select(SOCK); $| = 1;
Receive_void();
Send("lstt");
foreach $item (reverse @resp){
if ($item =~ /^250.(\d{1,2}).*\(epg2timers\)/) {
Send_void("DELT $1");
}
}
while (defined ($line = <STDIN>)) {
chomp $line;
Send_void("UPDT $line");
}
Send("quit");
close(SOCK) || Error("close: $!");
sub Send
{
my $cmd = shift || Error("no command to send");
print SOCK "$cmd\r\n";
Receive();
}
sub Send_void
{
my $cmd = $_[0];
print SOCK "$cmd\r\n";
Receive_void();
}
sub Receive
{
while (<SOCK>) {
chomp;
push @resp,$_;
last if substr($_, 3, 1) ne "-";
}
}
sub Receive_void
{
while (<SOCK>) {
last if substr($_, 3, 1) ne "-";
}
}
sub Error
{
print STDERR "@_\n";
close(SOCK);
exit 0;
}

22
Tools/epg2timers/update_timers Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
# update_timers: retrieve a new "merkliste" from http://tvtv.de,
# convert it to vdr format and transmit it to vdr via SVDRP.
TOOLDIR="/home/cko/bin"
CHANPATH="/home/cko/VDR/channels.conf"
cd /tmp
rm -f merkliste.html
# if you have a slow dial up connection to your name server and/or ISP,
# this will avoid a timeout in get_merkliste.pl.
ping -c 2 www.tvtv.de
# get the "merkliste".
$TOOLDIR/get_merkliste.pl
if [ -s merkliste.html ] ; then
# convert merkliste.html to timers.conf format and transmit it to vdr.
$TOOLDIR/epg2timers $CHANPATH < merkliste.html | $TOOLDIR/loadvdr.pl
fi

View File

@ -0,0 +1,24 @@
#!/bin/sh
# update_timers: load a new "merkliste" from http://tvtv.de
# and create a new VDR timer configuration file (timers.conf)
# from it. Restart VDR if the timers have changed.
TOOLDIR="/home/cko/bin"
VDRDIR="/home/cko/VDR"
cd /tmp
rm -f merkliste.html epgtimers.new epgtimers.old vdrtimers.old
ping -c 2 www.tvtv.de
$TOOLDIR/get_merkliste.pl
if [ -s merkliste.html ] ; then
$TOOLDIR/epg2timers $VDRDIR/channels.conf < merkliste.html | sort -t: +2.0 -5.0 > epgtimers.new
fgrep '(epg2timers)' $VDRDIR/timers.conf | sort -t: +2.0 -5.0 > epgtimers.old
if ! cmp -s epgtimers.old epgtimers.new ; then
/sbin/killproc $VDRDIR/vdr
fgrep -v '(epg2timers)' $VDRDIR/timers.conf > vdrtimers.old
cat epgtimers.new vdrtimers.old | sort -t: +2.0 -5.0 > $VDRDIR/timers.conf
echo "Timers updated."
fi
fi
rm -f merkliste.html epgtimers.new epgtimers.old vdrtimers.old

View File

@ -1,106 +1,70 @@
Master-Timer
============
Master-Timer
============
(w) by Matthias Schniedermeyer (ms@citd.de)
1. Einleitung
-------------
Master-Timer ist ein System zum automatischen Aufnehmen von Serien und Filmen.
Beim Aufruf werden die Konfigurationsdateien gelesen, die Datei "epg.data" im
aktuellen Verzeichnis nach passenden Sendungen durchsucht und die ermittelten
Timer per SVDRP in VDR programmiert. Danach beendet sich Master-Timer.
2. Voraussetzungen
------------------
Entsprechend empfiehlt es sich, Master-Timer per cronjob aufzurufen.
VDR liefert die "epg.data".
3. Konfigurationsdateien
2. Konfigurationsdateien
------------------------
Alle Konfigurationsdateien liegen unter "<HOME>.master-timer"
Alle Konfigurationsdateien liegen unter "~/.master-timer". Es werden
regulaere Ausdruecke ohne Unterscheidung der Gross-/Kleinschreibung
benutzt.
config: Eine Ansammlung von Key-Value Paaren. Alle sind "optional" und
erhalten dann die angegebenen Default-Werte
config: Die Hauptkonfigurationsdatei.
(# = Kommentarzeilen)
marginstart (Default 600)
Anzahl der "Sicherheits" Sekunden die ein Timer frueher beginnen soll
deepblack: Eine Negativliste von Titeln, die man NIEMALS NIMMER sehen will.
Die epg-datensaetze werden beim Parsen einfach entfernt.
marginstop (Default 600)
Anzahl der "Sicherheits" Sekunden die ein Timer laenger dauern soll
subtitle-movies: Eine Liste der "Subtitel", die ein Zeichen fuer einen Film
sind (soweit die von den Sendern richtig ausgefuellt sind). Die
Einstellungen in dieser Datei werden fuer das Makro "MOVIE" in torecord
benutzt.
Kommentarzeilen sind nicht erlaubt.
defaultprio (Default 50)
Die Prioritaet die fuer Timer verwendet wird wo keine Prioritaet
angegeben ist
torecord: Liste der aufzunehmenden Filme.
DVBCards (Default 1)
Anzahl der vorhandenen DVB-Karten (Derzeit nicht verwendet)
done: Liste der Titel/Subtitel, die bereits aufgenommen wurden. Timer, die
hier auftauchen, werden in VDR automatisch geloescht.
Dest-Host (Default "localhost")
Host-name oder IP des Rechners auf dem VDR laeuft
channels-to-scan: Diese Kanaele werden vom Skript "scan-channels" durch-
geschaltet (zwecks Einlesen der EPG-Daten). Die Datei wird von Master-
Timer selbst nicht benutzt.
Dest-Port (Default "2001")
Port der VDR verwendet
3. Anmerkungen
--------------
jointimers (Default 0)
Sollen aufeinanderfolgende Timer auf den gleichen Kanal zusammengefasst
werden (0 = "Nein", alles andere "Ja")
- einige Sender fuellen die EPG-Felder nicht korrekt aus. Diese Fehler
werden von Master-Timer automatisch korrigiert.
debug (Default 0)
Debug-Level, die einzelnen Debug-Werte muessen aus folgenden Werten
zusammengezaehlt werden
1 : Dump "torecord"
2 : Dump all timers
4 : Show when a timer will be deleted
8 : Dump the "Done" REs
16 : Verbose Config-Reading
Pro7: Title aus dem Subtitle entfernen '<Title> / <Subtitle>'
Pro7: Timer zwischen 00:00 und 05:00 werden einen Tag in die Zukunft
verschoben (Als unguten Nebeneffekt hat dies zur Folge das zum
aktuellen Tag NICHT die epg-Daten das folgenden Tags (=Das was in
der Fernsehzeitschrift noch auf der gleichen Seite ist) mehr gesendet
werden. Wenn man also "Last Minute" etwas aufnehmen will, dann muss
man (leider) einen Timer "per Hand" in VDR einprogrammieren!)
VOX/VIVA: Subtitle ist in "" eingeschlossen nd nach ". " steht die description
VIVA: Wenn der Subtitle mit einem Space beginnt, dann wird der komplette
Subtitle in die Description verschoben
RTL2: Wenn der EPG-Datensatz eine Dauer von kleiner/gleich 1 Sekunde hat,
wird er einfach verworfen.
deepblack: Eine Liste von Titeln die man NIEMALS NIMMER sehen will
Jede Zeile = 1 Titel
Bis auf den jeweils 2ten VIVA&Pro-7 Bug werden die Fixes an jedem
epg-Datensatz ausprobiert.
subtitle-movies: Eine Liste der "Subtitel" die ein Zeichen fuer einen Film sind
(Soweit die von den Sendern richtig ausgefuellt sind.)
Jede Zeile = 1 Subtitel
4. Bekannte Bugs
----------------
torecord: Die Sachen die man Aufnehmen will
Jede Zeile = 1 Timer
# Format: (Every field is "optional".
# [Title RE|Subtitle RE|Description RE|Channel-Name|Timeframe|Prio|Timer-Title]
#
# To record something at least one of the "Title", "Subtitle" or "Description"
# Fields has to be provided. This 3 fields are "include" and the rest are
# "exclude" fields!
#
# More than one channel definition can be provided. The delimiter is ";"
# Additionaly you can make a "blacklist" of Channels when you prepent a "!" to the first Channel Definition
# The "!" is only tested for the FIRST Channel definition.
# You can only have a white or a blacklist (Mixing doesn't make sense!)
#
# ex. Record the series "Deep Space Nine" on Sci-Fantasy in the timeframe 09:00 - 14:00
# Deep Space Nine|||Sci-Fantasy|0900-1400|99|DS9
#
# Record all "Actionfilm"s with "Schwarzenegger"
# |Actionfilm|Schwarzenegger
#
done: The titles/subtitles which are already recorded/should not be recorded
(Programmed Timers which got inserted into "done" will be deleted
automaticaly)
4. Notices
----------
- Recordings "overlapping" on the same channel, will be joined into one Timer
- Title/Subtitle/Descriptions are "fixed" for Channel that don't fill them
out "correctly" (Currently the "Bugs" from Pro-7/VOX/VIVA)
Pro7: Remove the Title from the Subtitle '<Title> / <Subtitle>'
VOX/VIVA: Subtitle is enclosed into "" and after ". " is the description
VIVA: When the Subtitle beginns with space the subtitle is moved to
description
All (except the second VIVA one) fixes are tried onto ALL Subtitles.
5. Known-Bugs
-------------
- It isn't checked if there are enough DVB-Cards
- Overlapping Timers, on the same channel, are always joined
- JOINed timers which are "done" don't get deleted automaticaly
- Es wird nicht geprueft ob noch genug DVB-Karten vorhanden sind
- "Joined timers" werden nur automatisch geloescht wenn alle dazugehoerigen
Sendungen "done" sind.

View File

@ -1,43 +1,49 @@
Master-Timer (w) by Matthias Schniedermeyer (ms@citd.de)
============
Master-Timer
============
(w) by Matthias Schniedermeyer (ms@citd.de)
1. Introduction
---------------
Master-Timer ist a system for recording Films/Series automaticaly
Master-Timer is a system designed for automatically recording movies.
Upon execution it reads its configuration files, scans the file "epg.data"
in the current directory for matching titles and programs them via SVDRP
into VDR.
2. Requierements
----------------
You may for example run Master-Timer as a cron job.
epg.data
3. Config-Files
2. Config files
---------------
For all files: One Entry per Line. Each line is a "Regular Expresion"
So you can use all Perl-Style REs you want.
The RE are matched with "i" so they are case insensitive!
(Except for the "done"-list, these must match excatly!)
Configuration files are located in "~/.master-timer". Each entry is a
regular expression so you can use all Perl style REs you want. They are
processed case insensitive.
deepblack: Blacklist of "Titles" you NEVER EVER want to get to you eyes
config: Main configuration file.
subtitle-movies: A list of "Subtitles" which indicate a movie.
(For Channels that correctly fill out the Subtitle.
e.g. it won't work for *eRTL*)
deepblack: Blacklist of "titles" you NEVER EVER want to see.
torecord: The titles/subtitles/Description you want to record
subtitle-movies: A list of "Subtitles" which indicate a movie (used
by the "MOVIE" macro in torecord).
For channels that correctly fill out the subtitle e.g. it will not
work with *eRTL*.
torecord: The titles you want to record.
done: The titles/subtitles which are already recorded/should not be recorded
(Programmed Timers which got inserted into "done" will be deleted
automaticaly)
Programmed timers which got inserted into "done" will be deleted
automatically.
channels-to-scan: Used only by the separate "scan-channels" script which
switches through channels in order to get EPG data.
4. Notices
----------
- Recordings "overlapping" on the same channel, will be joined into one Timer
- Title/Subtitle/Descriptions are "fixed" for Channel that don't fill them
out "correctly" (Currently the "Bugs" from Pro-7/VOX/VIVA)
- Recordings overlapping on the same channel will be joined into one timer
- Title/Subtitle/Descriptions are "fixed" for channels that don't fill them
out correctly (Pro-7/VOX/VIVA)
Pro7: Remove the Title from the Subtitle '<Title> / <Subtitle>'
VOX/VIVA: Subtitle is enclosed into "" and after ". " is the description
VIVA: When the Subtitle beginns with space the subtitle is moved to
@ -48,5 +54,5 @@ done: The titles/subtitles which are already recorded/should not be recorded
-------------
- It isn't checked if there are enough DVB-Cards
- Overlapping Timers, on the same channel, are always joined
- JOINed timers which are "done" don't get deleted automaticaly
- Overlapping timers on the same channel are always joined
- Joined timers which are "done" don't get deleted automatically

18
Tools/master-timer/THANKS Normal file
View File

@ -0,0 +1,18 @@
Klaus Schmidinger
- VDR
Malte Kiesel
- Suggestions
- Bug Reports
- Documentation Updates for README/LIESMICH/torecord/deepblack/config
Guido Fiala
- Suggestions
- Bug Repots
- finding bugs i found just before i read that part of his mails
(First the bug, then the errormessages! Otherwise i will search/find
the bug myself :-))) )
Axel Gruber
- Suggestions
- Bug Reports

View File

@ -1,9 +1,5 @@
- "Intelligenter" Kanal-Scanner (z.B. nur 1 Kanal fuer ein
Sender-"Gruppe")
- Filtern nach Serie/Film
- "Komfortable" Anzeige, mit Black & Whitelisten, fuer Genres/Titeln usw.
- Unterstueztung von 1xVDR pro Karte
- Abspielen (mit automatischen "killen" des "Frontend"-VDRs) von
Aufzeichnungen
- "View"-Timer d.h. Timer der nicht Aufnimmt sondern nur den Kanal aendert

View File

@ -0,0 +1,151 @@
#!/usr/bin/perl -w
use strict;
# The EPG-Entrys
my (%Entry, %channel, $mode);
# 0 = VDR -> DTV
# 1 = DTV -> VDR
$mode = 0;
read_channel_list();
if ($mode) {
&read_dtv();
&read_epgdata();
} else {
&read_epgdata();
&read_dtv();
}
&print_VDR();
sub read_epgdata {
my ($channel, $duration, $title, $subtitle, $description, $time);
open (FI,"epg.data") or die ("Can't open file \"epg.data\"\n");
while (<FI>) {
# Begin Channel
if (/^C\s(\d+)\s+(.+)/) {
$channel=$2;
while (<FI>) {
# End Channel
if (/^c$/) {
last;
}
# Begin Timer
elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/) {
# Undef this Variables because it is possibel that not every timer uses this values
undef $duration;
undef $subtitle;
undef $description;
$time=$2;
$duration=$3;
}
# Title
elsif (/^T\s(.*)/) {
$title=$1;
}
# Subtitle
elsif (/^S\s(.*)/) {
$subtitle=$1;
}
# Description
elsif (/^D\s(.*)/) {
$description=$1;
}
# End Timer
elsif (/^e$/) {
if ($mode) {
# DTV -> VDR
$Entry{$channel}{$time}{subtitle}=$subtitle if ($subtitle);
if ($description) {
if ($Entry{$channel}{$time}{description}) {
$Entry{$channel}{$time}{description} = "DTV: '$Entry{$channel}{$time}{description}' VDR: '$description'";
} else {
$Entry{$channel}{$time}{description} = "DTV: '' VDR: '$description'";
}
}
} else {
# VDR -> DTV
$Entry{$channel}{$time}{title}=$title;
$Entry{$channel}{$time}{duration}=$duration;
$Entry{$channel}{$time}{subtitle}=$subtitle if ($subtitle);
$Entry{$channel}{$time}{description}=$description if ($description);
}
}
}
}
}
close (FI);
}
sub read_dtv {
my ($channel, $time, $duration, $title, $category, $subtitle, $description);
open (FI,$ARGV[0]) or die "Can't open DTV-File";
while (<FI>) {
chomp;
($channel, $time, $duration, $title, $category, $subtitle, $description) = split (/\|/);
if (!$channel{$channel}) {
next;
}
$channel = $channel{$channel};
if ($mode) {
# DTV -> VDR
if (!$subtitle && $description =~ /^\"(.*?)\"\:\s(.*)/) {
$Entry{$channel}{$time}{subtitle} = $1;
$description = $2;
}
$Entry{$channel}{$time}{title} = $title;
$Entry{$channel}{$time}{duration} = $duration;
$Entry{$channel}{$time}{subtitle} = $subtitle if ($subtitle);
$Entry{$channel}{$time}{category} = $category if ($category);
$Entry{$channel}{$time}{description} = $description if ($description);
} else {
# VDR -> DTV
$Entry{$channel}{$time}{category} = $category if ($category);
if ($description) {
if (!$Entry{$channel}{$time}{subtitle} && $description =~ /^\"(.*?)\"\:\s(.*)/) {
$Entry{$channel}{$time}{subtitle} = $1;
$description = $2;
}
if ($Entry{$channel}{$time}{description}) {
$Entry{$channel}{$time}{description} = "DTV: '$description' VDR: '$Entry{$channel}{$time}{description}'";
} else {
$Entry{$channel}{$time}{description} = "DTV: '$description' VDR: ''";
}
}
}
}
close (FI);
}
sub read_channel_list {
my ($old, $new);
open (FI,"$ENV{HOME}/.master-timer/convert-channel-list") or die ("Can't read channel-List");
while (<FI>) {
chomp;
($old, $new) = split (/\|/);
$channel{$old} = $new;
}
close (FI);
}
sub print_VDR() {
my ($channel, $title, $time);
foreach $channel (sort keys %Entry) {
print "C 1 $channel\n";
foreach $time (sort keys %{%Entry->{$channel}}) {
if ($Entry{$channel}{$time}{duration}) {
print "E 1 $time $Entry{$channel}{$time}{duration}\n";
print "K $Entry{$channel}{$time}{category}\n" if ($Entry{$channel}{$time}{category});
print "T $Entry{$channel}{$time}{title}\n";
print "S $Entry{$channel}{$time}{subtitle}\n" if ($Entry{$channel}{$time}{subtitle});
print "D $Entry{$channel}{$time}{description}\n" if ($Entry{$channel}{$time}{description});
print "e\n";
}
}
print "c\n";
}
}

View File

@ -0,0 +1,61 @@
#!/usr/bin/perl
while (<>)
{
chomp;
if ($_ && !(/^\#/))
{
($title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine) = split (/\|/,$_);
if ($timer_title) {
print "[$timer_title]\n";
} elsif ($title) {
print "[$title]\n";
} elsif ($subtitle) {
print "[$subtitle]\n";
} elsif ($description) {
print "[$description]\n";
} else {
die ("Illegal Format");
}
# Accept torecord only if it is for the current machine
if ($title)
{
print "Title = $title\n";
}
if ($subtitle)
{
print "Subtitle = $subtitle\n";
}
if ($description)
{
print "Description = $description\n";
}
if ($channel)
{
print "Channel = $channel\n";
}
if ($timeframe)
{
print "Timeframe = $timeframe\n";
}
if ($prio)
{
print "Prio = $prio\n";
}
if ($timer_title)
{
print "Timertitle = $timer_title\n";
}
if ($margin)
{
print "Margin = $margin\n";
}
if ($machine)
{
print "Instance = $machine\n";
}
print "\n";
}
}

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,4 @@
3
4
5
13
18
21
49

View File

@ -1,14 +1,32 @@
# How Many Seconds "too early" should the timer begin
# Master-Timer config file. Values shown here are defaults.
# How many seconds "too early" should the timer begin
marginstart = 600
# How Many Seocnds "too long" should the timer end
# How many seconds "too long" should the timer end
marginstop = 600
# When the Prio isn't provied in the config-File use this value
# When the Prio isn't provided in the config file use this value
defaultprio = 50
# How many DVB-Cards are installed in the Computer (Not used yet)
DVBCards = 3
# IP/Hostname:Port of the Destinations (Space is used for delimiter)
Dest-Host = localhost:2001
# Should Timers on the same channels be joined when they overlapp (0 = off)
jointimers = 1
# Debug-Level
# How many DVB cards are installed in the computer (not used yet)
DVBCards = 1
# IP/Hostname:Port of the destination (space is used for delimiter)
Dest = localhost:2001
# Should timers on the same channels be joined when they overlap (0 = off)
jointimers = 0
# Should the description be transfered to VDR?
description = 0
# Debug level
# 1 : Dump "torecord"
# 2 : Dump all timers
# 4 : Show when a timer will be deleted
# 8 : Dump the "Done" REs
# 16 : Verbose config reading
# 32 : Dump program variables
# 64 : Excessive deepblack/torecord debuging
debug = 0

View File

@ -0,0 +1,26 @@
Kabel 1|Kabel 1
MTV|MTV Central
PRW 13TH Street|13th Street
PRW Discovery Channel|Discovery Channel
PRW Disney Channel|Disney Channel
PRW FOX KIDS|Fox Kids
PRW Junior|Junior
PRW K-Toon|K-Toon
PRW Krimi & Co|Krimi &Co
PRW Planet|Planet
PRW Sci-Fantasy|Premiere Sci-Fi
PRW Studio Universal|Studio Universal
PRW Sunset|Sunset
Premiere Action|Premiere Action
Premiere Comedy|Premiere Comedy
Premiere STAR|Premiere Star
Premiere World 1|Premiere 1
Premiere World 2|Premiere 2
Premiere World 3|premiere 3
Pro Sieben|Pro-7
RTL|RTL
RTL 2|RTL2
Sat.1|Sat.1
Super RTL|Super RTL
Viva|VIVA
Vox|VOX

View File

@ -1,79 +1,172 @@
Für alle Fälle Stefanie
'MAX' - Das ganze Leben!
10 vor 11
17:30 live
18:30
24 Stunden
Andreas Türck
Arabella
^BIZZ$
Big Brother
Britt - Der Talk um Eins
Bärbel Schäfer
Call TV
Chicago Hope - Endstation Hoffnung
Chicago Hope
DIE REDAKTION
Dauerwerbesendungen
Die Harald Schmidt Show
Die Oliver Geissen Show
Die Quiz Show
Doppelter Einsatz
Dr. Stefan Frank - Der Arzt, dem die Frauen vertrauen
EXCLUSIV
EXTRA
Ehekriege
Ein Bayer auf Rügen
Emergency Room
Explosiv - Das Magazin
GIRLSCAMP
Glücksrad
Gute Zeiten, schlechte Zeiten
Hallo, Onkel Doc!
Hans Meiser
Hercules
Hinter Gittern - Der Frauenknast
Infomercials
Jeder gegen Jeden
K1 DIE REPORTAGE
K1 Das Magazin
K1 Nachrichten
Kickers
Kochduell
Nachrichten
Nicole - Entscheidung am Nachmittag
OP ruft Dr. Bruckner
PREMIERE WORLD - Das Programm
PROSIEBEN REPORTAGE
Peter Imhof
Programm ab
Programm von
Punkt 12
Punkt 6
Punkt 9
RTL II News
RTL SHOP
RTL aktuell
RTL-Nachtjournal
SAT.1-FRÜHSTÜCKSFERNSEHEN
Spiegel TV-Reportage
UEFA Champions
fussball
fßball
Vera am Mittag
Wolffs Revier
Zapping
alphateam
peep!
s.a.m.
taff.
^blitz$
SK Kölsch
^Becker$
Kommissar Rex
Fit For Fun TV
Nur die Liebe zählt
Unsere kleine Farm
Die Waltons
^Die Zwei$
^Sieben$
# [<Anytext>]
# This marks the beginning of a deepblack-entry
# Title = <text>
# This matches a title
# Subtitle = <text>
# This matches a subtitle
# Description = <text>
# This matches a description
# Category = <left>/<right>
# This matches a DTV-Category
# Channel = <Channel>
# Restricts a deepblack-entry to a specific channel.
# A single "!" at start of channel list negates the selection.
# Timeframe = <begin>-<end>
# Restricts a deepblack-entry to a specific timeframe.
# No timers with start time in the timeframe will be programmed.
# minlength = <Number>
# Restricts a deepblack-entry to a specific minimum length
# (postfix "m" for minutes, "h" for hours.)
# maxlength = <Number>
# Restricts a deepblack-entry to a specific maximum length
# (postfix "m" for minutes, "h" for hours.)
# weekday = MTWTFSS
# Restricts a deepblack-entry to a specific weekday
# instance = <Number>
# Only apply this deepblack-entry for a specific Instance
# "s" is a special value used for "-s"-Mode
#
# The "Title", "Subtitle", "Description", "Channel"-Lines can be
# supplied any number of times for a specific entry
#
# To deepblack something at least one of the "Title", "Subtitle" or
# "Description" (If you don't have anything "better" use "Title = ."
# for this matches everything) fields has to be provided.
# These three fields are "include" and the rest are "exclude" fields.
[Blacklist all Talkshows]
Title = .
Category = Talk
[Blacklist all Lifestyles]
Title = .
Category = /Lifestyles
[Blacklist Sport/Tennis]
Title = .
Category = Sport/Tennis
[Record only ZDF and Pro7]
Title = .
Channel = !ZDF
Channel = ProSieben
[Blacklist a timeframe]
Title = .
Timeframe = 1000-1400
[Blacklist everything with less than 5 minutes duration]
Title = .
maxlength = 5m
[Sinnlose Serien]
Title = Für alle Fälle Stefanie
Title = Chicago Hope - Endstation Hoffnung
Title = Chicago Hope
Title = Doppelter Einsatz
Title = Dr. Stefan Frank - Der Arzt, dem die Frauen vertrauen
Title = Ehekriege
Title = Ein Bayer auf Rügen
Title = Emergency Room
Title = Gute Zeiten, schlechte Zeiten
Title = Hallo, Onkel Doc!
Title = Hercules
Title = Hinter Gittern - Der Frauenknast
Title = OP ruft Dr. Bruckner
Title = Wolffs Revier
Title = alphateam
Title = SK Kölsch
Title = ^Becker$
Title = Kommissar Rex
Title = Nur die Liebe zählt
Title = Unsere kleine Farm
Title = Die Waltons
Title = ^Die Zwei$
[Glueckspiele]
Title = Die Quiz Show
Title = Glücksrad
Title = Jeder gegen Jeden
Title = Kochduell
[Infotainment und Boulevardzeug]
Title = 'MAX' - Das ganze Leben!
Title = ^BIZZ$
Title = Big Brother
Title = GIRLSCAMP
Title = Call TV
Title = DIE REDAKTION
Title = EXCLUSIV
Title = EXTRA
Title = Explosiv - Das Magazin
Title = K1 DIE REPORTAGE
Title = K1 Das Magazin
Title = PROSIEBEN REPORTAGE
Title = Fit For Fun TV
Title = peep!
Title = s.a.m.
Title = taff.
Title = ^blitz$
Title = Die Harald Schmidt Show
Title = Spiegel TV-Reportage
[Nachrichten]
Title = 10 vor 11
Title = 17:30 live
Title = 18:30
Title = 24 Stunden
Title = Punkt 12
Title = Punkt 6
Title = Punkt 9
Title = RTL II News
Title = RTL aktuell
Title = RTL-Nachtjournal
Title = K1 Nachrichten
Title = Nachrichten
[Talkshows]
Title = Andreas Türck
Title = Arabella
Title = Britt - Der Talk um Eins
Title = Bärbel Schäfer
Title = Die Oliver Geissen Show
Title = Peter Imhof
Title = Vera am Mittag
Title = Hans Meiser
Title = Nicole - Entscheidung am Nachmittag
Title = Franklin
[So richtig Sinnloses]
Title = Dauerwerbesendungen
Title = Infomercials
Title = Kickers
Title = RTL SHOP
Title = SAT.1-FRÜHSTÜCKSFERNSEHEN
Title = Zapping
[PREMIERE WORLD - Das Programm]
Title = PREMIERE WORLD - Das Programm
Title = Programm ab
Title = Programm von
[Fussball]
Title = fussball
Title = fußball
Title = UEFA Champions
#Sonstiges
[^Sieben$]
Title = ^Sieben$
[Starporträt Kevin Spacey]
Title = Starporträt Kevin Spacey
[All Movies for -s]
Subtitle = MOVIE
Instance = s
[All >= 65m for -s]
Title = .
minlength = 65m
Instance = s

View File

@ -3,6 +3,7 @@
^Actionkomödie$
^Actionthriller$
^Agentenfilm$
^Beziehungskomödie$
^Biografie$
^Biographie$
^Computeranimation$
@ -12,19 +13,24 @@
^Familiendrama$
^Fantasy$
^Fantasykomödie$
^Fantasy-Komödie$
^Gangsterfilm$
^Gerichtsfilm$
^Gesellschaftsdrama$
^Historiendrama$
^Horrorfilm$
^Horrorkomödie$
^Jugenddrama$
^Kinderfilm$
^Komödie$
^Kriegsfilm$
^Krimikomödie$
^Kriminalfilm$
^Liebesfilm$
^Liebeskomödie$
^Melodram$
^Melodrama$
^Monumentalfilm$
^Musical$
^Politthriller$
^Psychothriller$
@ -32,10 +38,15 @@
^Romanze$
^Satire$
^Science-Fiction$
^Science-Fiction-Komödie$
^Spielfilm$
^TV Movie$
^TV-Drama$
^Teil .$
^Teil 0.$
^Thriller$
^Tragikomödie$
^Western$
^Westernkomödie$
^Zeichentrick$
^Zeichentrickkomödie$

View File

@ -1,32 +1,90 @@
# Format: (Every field is "optional".
# [Title RE|Subtitle RE|Description RE|Channel-Name|Timeframe|Prio|Timer-Title|Marginstart;Marginstop|VDR-Instance]
# [<Anytext>]
# This marks the beginning of a timer entry
# Title = <text>
# This matches a title
# Subtitle = <text>
# This matches a subtitle.
# You may use the magic "MOVIE" or "!MOVIE" which matches
# all entries from file "subtitle-movie".
# Description = <text>
# This matches a description
# Category = <left>/<right>
# This matches a DTV-Category
# Channel = <Channel>
# Restricts a time to a specific channel.
# A single "!" at start of channel list negates the selection.
# Timeframe = <begin>-<end>
# Restricts timer to a specific timeframe.
# Only timers with start time in the timeframe will be programmed.
# minlength = <Number>
# Restricts timer entry to a specific minimum length
# (postfix "m" for minutes, "h" for hours.)
# maxlength = <Number>
# Restricts a timer entry to a specific maximum length
# (postfix "m" for minutes, "h" for hours.)
# weekday = MTWTFSS
# Restricts a timer to a specific weekday
# Timertitle = <text>
# The title used for this timer.
# If this is not provided "Title" will be used.
# If "Title" is not provided the EPG title will be used.
# Margin = <Number>;<Number>
# Seconds added to the beginning and end of the timer.
# Positive numbers will lengthen the recording.
# instance = <Number>
# The instance of VDR for which this timer is.
# If this is not provided the timer is valid for ALL instances.
#
# To record something at least one of the "Title", "Subtitle" or "Description"
# Fields has to be provided. This 3 fields are "include" and the rest are
# The "Title", "Subtitle", "Description", "Channel"-Lines can be
# supplied any number of times for a specific entry
#
# To record something at least one of the "Title", "Subtitle" or "Description"
# fields has to be provided. These three fields are "include" and the rest are
# "exclude" fields!
#
# More than one channel definition can be provided. The delimiter is ";"
# Additionaly you can make a "blacklist" of Channels when you prepent a "!" to the first Channel Definition
# The "!" is only tested for the FIRST Channel definition.
# You can only have a white or a blacklist (Mixing doesn't make sense!)
#
# ex. Record the series "Deep Space Nine" on Sci-Fantasy in the timeframe 09:00 - 14:00 with 60 Seconds Marginstart and -60 Seconds Marginstop
# Deep Space Nine|||Sci-Fantasy|0900-1400|99|DS9|60;-60
#
# Record all "Actionfilm"s with "Schwarzenegger"
# |Actionfilm|Schwarzenegger
#
Babylon 5|||!Pro-7||99|60;-60|1
Deep Space Nine|||||99|DS9|60;-60|2
Seven Days|||||99|
Stargate|||||99|
Futurama||||2100-2300|50|
Ally McBeal|||||99|
Snoops|||||50|
^Friends$|||||99|Friends|
Pensacola|||||50|
seaQuest|||||50|
||Paltrow|Sci Fantasy;13th Street;Star Kino;Cine Action;Cine Comedy;Romantic Movies;Studio Universal;Premiere||99|
||Aniston|||99|
Matrix
[Dies ist ein Test-Timer]
Title = Titel
Subtitle = Subtitel
Description = Description
Category = Serie/Krimi
Channel = Pro-7
Channel = VIVA
Timeframe = 1230-1830
Prio = 50
Lifetime = 50
minlength = 10m
maxlength = 3h
weekday = ---T---
Timertitle = Test
Margin = 600;600
instance = 2
# Record Babylon 5 only if NOT playing on Pro 7;
# recording starts one minute too early and ends
# one minute too early (to skip following ads).
[Babylon 5]
Title = Babylon 5
Channel = !Pro-7
Prio = 99
Margin = 60;-60
[DS9]
Title = Deep Space Nine
Prio = 99
Timertitle = DS9
Margin = 60;-60
[Seven Days]
Title = Seven Days
Prio = 99
[Stargate]
Title = Stargate
Prio = 99
[Aniston]
Description = Aniston
Prio = 99
[Matrix]
Title = Matrix

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.c 1.64 2001/09/02 15:04:13 kls Exp $
* $Id: config.c 1.72 2001/09/16 14:54:32 kls Exp $
*/
#include "config.h"
@ -39,6 +39,9 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ k8, "8", 0 },
{ k9, "9", 0 },
{ kPower, "Power", 0 },
{ kVolUp, "Volume+", 0 },
{ kVolDn, "Volume-", 0 },
{ kMute, "Mute", 0 },
{ kNone, "", 0 },
};
@ -72,7 +75,7 @@ bool cKeys::Load(const char *FileName)
FILE *f = fopen(fileName, "r");
if (f) {
int line = 0;
char buffer[MaxBuffer];
char buffer[MAXPARSEBUFFER];
result = true;
while (fgets(buffer, sizeof(buffer), f) > 0) {
line++;
@ -122,24 +125,14 @@ bool cKeys::Load(const char *FileName)
bool cKeys::Save(void)
{
bool result = true;
cSafeFile f(fileName);
if (f.Open()) {
if (fprintf(f, "Code\t%c\nAddress\t%04X\n", code, address) > 0) {
for (tKey *k = keys; k->type != kNone; k++) {
if (fprintf(f, "%s\t%08X\n", k->name, k->code) <= 0) {
result = false;
break;
}
}
}
else
result = false;
f.Close();
fprintf(f, "Code\t%c\nAddress\t%04X\n", code, address);
for (tKey *k = keys; k->type != kNone; k++)
fprintf(f, "%s\t%08X\n", k->name, k->code);
return f.Close();
}
else
result = false;
return result;
return false;
}
eKeys cKeys::Get(unsigned int Code)
@ -303,14 +296,19 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log)
isyslog(LOG_INFO, "switching to channel %d", number);
}
for (int i = 3; i--;) {
if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr))
return true;
switch (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr)) {
case scrOk: return true;
case scrNoTransfer: if (Interface)
Interface->Error(tr("Can't start Transfer Mode!"));
return false;
case scrFailed: break; // loop will retry
}
esyslog(LOG_ERR, "retrying");
}
return false;
}
if (DvbApi->Recording())
Interface->Info(tr("Channel locked (recording)!"));
Interface->Error(tr("Channel locked (recording)!"));
return false;
}
@ -649,8 +647,6 @@ cCommands Commands;
// -- cChannels --------------------------------------------------------------
int CurrentGroup = -1;
cChannels Channels;
bool cChannels::Load(const char *FileName)
@ -807,8 +803,10 @@ cSetup::cSetup(void)
OSDheight = 18;
OSDMessageTime = 1;
MaxVideoFileSize = MAXVIDEOFILESIZE;
MinEventTimeout = 120;
MinEventTimeout = 30;
MinUserInactivity = 120;
MultiSpeedMode = 0;
ShowReplayMode = 0;
CurrentChannel = -1;
}
@ -846,6 +844,8 @@ bool cSetup::Parse(char *s)
else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value);
else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value);
else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value);
else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value);
else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
else
return false;
@ -862,7 +862,7 @@ bool cSetup::Load(const char *FileName)
FILE *f = fopen(fileName, "r");
if (f) {
int line = 0;
char buffer[MaxBuffer];
char buffer[MAXPARSEBUFFER];
bool result = true;
while (fgets(buffer, sizeof(buffer), f) > 0) {
line++;
@ -918,13 +918,14 @@ bool cSetup::Save(const char *FileName)
fprintf(f, "MaxVideoFileSize = %d\n", MaxVideoFileSize);
fprintf(f, "MinEventTimeout = %d\n", MinEventTimeout);
fprintf(f, "MinUserInactivity = %d\n", MinUserInactivity);
fprintf(f, "MultiSpeedMode = %d\n", MultiSpeedMode);
fprintf(f, "ShowReplayMode = %d\n", ShowReplayMode);
fprintf(f, "CurrentChannel = %d\n", CurrentChannel);
f.Close();
isyslog(LOG_INFO, "saved setup to %s", FileName);
return true;
if (f.Close()) {
isyslog(LOG_INFO, "saved setup to %s", FileName);
return true;
}
}
else
LOG_ERROR_STR(FileName);
}
else
esyslog(LOG_ERR, "attempt to save setup without file name");

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.72 2001/09/02 15:45:17 kls Exp $
* $Id: config.h 1.79 2001/09/16 14:54:36 kls Exp $
*/
#ifndef __CONFIG_H
@ -19,9 +19,7 @@
#include "eit.h"
#include "tools.h"
#define VDRVERSION "0.94"
#define MaxBuffer 10000
#define VDRVERSION "0.95"
#define MAXPRIORITY 99
#define MAXLIFETIME 99
@ -45,6 +43,9 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kBlue,
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
kPower,
kVolUp,
kVolDn,
kMute,
kNone,
// The following flags are OR'd with the above codes:
k_Repeat = 0x8000,
@ -61,9 +62,9 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
#define kEditCut k2
#define kEditTest k8
#define RAWKEY(k) ((k) & ~k_Flags)
#define RAWKEY(k) (eKeys((k) & ~k_Flags))
#define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0)
#define NORMALKEY(k) ((k) & ~k_Repeat)
#define NORMALKEY(k) (eKeys((k) & ~k_Repeat))
struct tKey {
eKeys type;
@ -192,7 +193,7 @@ public:
FILE *f = fopen(fileName, "r");
if (f) {
int line = 0;
char buffer[MaxBuffer];
char buffer[MAXPARSEBUFFER];
result = true;
while (fgets(buffer, sizeof(buffer), f) > 0) {
line++;
@ -228,7 +229,8 @@ public:
}
l = (T *)l->Next();
}
f.Close();
if (!f.Close())
result = false;
}
else
result = false;
@ -262,8 +264,6 @@ public:
class cCommands : public cConfig<cCommand> {};
extern int CurrentGroup;
extern cChannels Channels;
extern cTimers Timers;
extern cKeys Keys;
@ -299,6 +299,8 @@ public:
int OSDMessageTime;
int MaxVideoFileSize;
int MinEventTimeout, MinUserInactivity;
int MultiSpeedMode;
int ShowReplayMode;
int CurrentChannel;
cSetup(void);
bool Load(const char *FileName);

486
dvbapi.c
View File

@ -7,7 +7,7 @@
* DVD support initially written by Andreas Schultz <aschultz@warp10.net>
* based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>
*
* $Id: dvbapi.c 1.111 2001/09/01 13:27:52 kls Exp $
* $Id: dvbapi.c 1.125 2001/09/16 13:55:03 kls Exp $
*/
//#define DVDDEBUG 1
@ -40,18 +40,14 @@ extern "C" {
#include "tools.h"
#include "videodir.h"
#define DEV_VIDEO "/dev/video"
#define DEV_OST_OSD "/dev/ost/osd"
#define DEV_OST_QAMFE "/dev/ost/qamfe"
#define DEV_OST_QPSKFE "/dev/ost/qpskfe"
#define DEV_OST_SEC "/dev/ost/sec"
#define DEV_OST_DVR "/dev/ost/dvr"
#define DEV_OST_DEMUX "/dev/ost/demux"
#define DEV_OST_VIDEO "/dev/ost/video"
#define DEV_OST_AUDIO "/dev/ost/audio"
#define KILOBYTE(n) ((n) * 1024)
#define MEGABYTE(n) ((n) * 1024 * 1024)
#define DEV_VIDEO "/dev/video"
#define DEV_OST_OSD "/dev/ost/osd"
#define DEV_OST_FRONTEND "/dev/ost/frontend"
#define DEV_OST_SEC "/dev/ost/sec"
#define DEV_OST_DVR "/dev/ost/dvr"
#define DEV_OST_DEMUX "/dev/ost/demux"
#define DEV_OST_VIDEO "/dev/ost/video"
#define DEV_OST_AUDIO "/dev/ost/audio"
// The size of the array used to buffer video data:
// (must be larger than MINVIDEODATA - see remux.h)
@ -288,7 +284,7 @@ int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *F
int d = Forward ? 1 : -1;
for (;;) {
Index += d;
if (Index >= 0 && Index <= last - 100) { // '- 100': need to stay off the end!
if (Index >= 0 && Index <= last) {
if (index[Index].type == I_FRAME) {
if (FileNumber)
*FileNumber = index[Index].number;
@ -628,19 +624,84 @@ int ReadFrame(int f, uchar *b, int Length, int Max)
return r;
}
// --- cBackTrace ----------------------------------------------------------
#define AVG_FRAME_SIZE 15000 // an assumption about the average frame size
#define DVB_BUF_SIZE (256 * 1024) // an assumption about the dvb firmware buffer size
#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) // how many entries are needed to backtrace buffer contents
class cBackTrace {
private:
int index[BACKTRACE_ENTRIES];
int length[BACKTRACE_ENTRIES];
int pos, num;
public:
cBackTrace(void);
void Clear(void);
void Add(int Index, int Length);
int Get(bool Forward);
};
cBackTrace::cBackTrace(void)
{
Clear();
}
void cBackTrace::Clear(void)
{
pos = num = 0;
}
void cBackTrace::Add(int Index, int Length)
{
index[pos] = Index;
length[pos] = Length;
if (++pos >= BACKTRACE_ENTRIES)
pos = 0;
if (num < BACKTRACE_ENTRIES)
num++;
}
int cBackTrace::Get(bool Forward)
{
int p = pos;
int n = num;
int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); //XXX (256 * 1024) == DVB_BUF_SIZE ???
int i = -1;
while (n && l > 0) {
if (--p < 0)
p = BACKTRACE_ENTRIES - 1;
i = index[p] - 1;
l -= length[p];
n--;
}
return i;
}
// --- cPlayBuffer ---------------------------------------------------------
#define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct?
class cPlayBuffer : public cRingBufferFrame {
private:
cBackTrace backTrace;
protected:
enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill };
enum ePlayDirs { pdForward, pdBackward };
static int Speeds[];
cDvbApi *dvbApi;
int videoDev, audioDev;
FILE *dolbyDev;
cPipe dolbyDev;
int blockInput, blockOutput;
bool still, paused, fastForward, fastRewind;
ePlayModes playMode;
ePlayDirs playDir;
int trickSpeed;
int readIndex, writeIndex;
bool canDoTrickMode;
bool canToggleAudioTrack;
uchar audioTrack;
void TrickSpeed(int Increment);
virtual void Empty(bool Block = false);
virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {}
virtual void Output(void);
@ -655,34 +716,38 @@ public:
virtual void SkipSeconds(int Seconds) {}
virtual void Goto(int Position, bool Still = false) {}
virtual void GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { Current = Total = -1; }
bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
bool CanToggleAudioTrack(void) { return canToggleAudioTrack; };
virtual void ToggleAudioTrack(void);
};
#define NORMAL_SPEED 4 // the index of the '1' entry in the following array
#define MAX_SPEEDS 3 // the offset of the maximum speed from normal speed in either direction
#define SPEED_MULT 12 // the speed multiplier
int cPlayBuffer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 };
cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev)
:cRingBufferFrame(VIDEOBUFSIZE)
{
dvbApi = DvbApi;
videoDev = VideoDev;
audioDev = AudioDev;
dolbyDev = NULL;
blockInput = blockOutput = false;
still = paused = fastForward = fastRewind = false;
playMode = pmPlay;
playDir = pdForward;
trickSpeed = NORMAL_SPEED;
readIndex = writeIndex = -1;
canDoTrickMode = false;
canToggleAudioTrack = false;
audioTrack = 0xC0;
if (cDvbApi::AudioCommand()) {
dolbyDev = popen(cDvbApi::AudioCommand(), "w");
if (!dolbyDev)
if (!dolbyDev.Open(cDvbApi::AudioCommand(), "w"))
esyslog(LOG_ERR, "ERROR: can't open pipe to audio command '%s'", cDvbApi::AudioCommand());
}
}
cPlayBuffer::~cPlayBuffer()
{
if (dolbyDev)
pclose(dolbyDev);
}
void cPlayBuffer::Output(void)
@ -697,25 +762,24 @@ void cPlayBuffer::Output(void)
}
const cFrame *frame = Get();
if (frame) {
StripAudioPackets((uchar *)frame->Data(), frame->Count(), (fastForward || fastRewind) ? 0x00 : audioTrack);//XXX
for (int i = 0; i < ((paused && fastRewind) ? 24 : 1); i++) { // show every I_FRAME 24 times in slow rewind mode to achieve roughly the same speed as in slow forward mode
const uchar *p = frame->Data();
int r = frame->Count();
while (r > 0 && Busy() && !blockOutput) {
cFile::FileReadyForWriting(videoDev, 100);
int w = write(videoDev, p, r);
if (w > 0) {
p += w;
r -= w;
}
else if (w < 0 && FATALERRNO) {
LOG_ERROR;
Stop();
return;
}
}
writeIndex = frame->Index();
}
StripAudioPackets((uchar *)frame->Data(), frame->Count(), (playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX
const uchar *p = frame->Data();
int r = frame->Count();
while (r > 0 && Busy() && !blockOutput) {
cFile::FileReadyForWriting(videoDev, 100);
int w = write(videoDev, p, r);
if (w > 0) {
p += w;
r -= w;
}
else if (w < 0 && FATALERRNO) {
LOG_ERROR;
Stop();
return;
}
}
writeIndex = frame->Index();
backTrace.Add(frame->Index(), frame->Count());
Drop(frame);
}
}
@ -723,6 +787,26 @@ void cPlayBuffer::Output(void)
dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
}
void cPlayBuffer::TrickSpeed(int Increment)
{
int nts = trickSpeed + Increment;
if (Speeds[nts] == 1) {
trickSpeed = nts;
if (playMode == pmFast)
Play();
else
Pause();
}
else if (Speeds[nts]) {
trickSpeed = nts;
int Mult = (playMode == pmSlow && playDir == pdForward) ? 1 : SPEED_MULT;
int sp = (Speeds[nts] > 0) ? Mult / Speeds[nts] : -Speeds[nts] * Mult;
if (sp > MAX_VIDEO_SLOWMOTION)
sp = MAX_VIDEO_SLOWMOTION;
CHECK(ioctl(videoDev, VIDEO_SLOWMOTION, sp));
}
}
void cPlayBuffer::Empty(bool Block)
{
if (!(blockInput || blockOutput)) {
@ -733,83 +817,153 @@ void cPlayBuffer::Empty(bool Block)
while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2)
usleep(1);
Lock();
readIndex = writeIndex;
if ((readIndex = backTrace.Get(playDir == pdForward)) < 0)
readIndex = writeIndex;
cRingBufferFrame::Clear();
CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER));
CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER));
}
if (!Block) {
blockInput = blockOutput = 0;
backTrace.Clear();
Unlock();
}
}
void cPlayBuffer::Pause(void)
{
paused = !paused;
bool empty = fastForward || fastRewind;
if (empty)
Empty(true);
fastForward = fastRewind = false;
CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE));
//CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); //XXX this caused chirping sound when playing a DVD
still = false;
if (empty)
Empty(false);
if (playMode == pmPause || playMode == pmStill)
Play();
else {
bool empty = (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward));
if (empty)
Empty(true);
CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false));
CHECK(ioctl(videoDev, VIDEO_FREEZE));
playMode = pmPause;
if (empty)
Empty(false);
}
}
void cPlayBuffer::Play(void)
{
if (fastForward || fastRewind || paused) {
bool empty = !paused || fastRewind;
if (playMode != pmPlay) {
bool empty = (playMode == pmStill || playMode == pmFast || (playMode == pmSlow && playDir == pdBackward));
if (empty)
Empty(true);
still = false;
CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY));
CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true));
//CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); //XXX this caused chirping sound when playing a DVD
CHECK(ioctl(videoDev, VIDEO_CONTINUE));
playMode = pmPlay;
playDir = pdForward;
if (empty)
Empty(false);
fastForward = fastRewind = paused = false;
}
}
}
void cPlayBuffer::Forward(void)
{
if (canDoTrickMode || paused) {
bool empty = !paused || fastRewind;
if (empty) {
Empty(true);
if (fastForward)
readIndex -= 150; // this about compensates for the buffered data, so that we don't get too far ahead
}
still = false;
fastForward = !fastForward;
fastRewind = false;
if (paused)
CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2));
CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward));
CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused));
if (empty)
Empty(false);
if (canDoTrickMode) {
switch (playMode) {
case pmFast:
if (Setup.MultiSpeedMode) {
TrickSpeed(playDir == pdForward ? 1 : -1);
break;
}
else if (playDir == pdForward) {
Play();
break;
}
// run into pmPlay
case pmPlay:
Empty(true);
CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false));
playMode = pmFast;
playDir = pdForward;
trickSpeed = NORMAL_SPEED;
TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS);
Empty(false);
break;
case pmSlow:
if (Setup.MultiSpeedMode) {
TrickSpeed(playDir == pdForward ? -1 : 1);
break;
}
else if (playDir == pdForward) {
Pause();
break;
}
// run into pmPause
case pmStill:
case pmPause:
CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false));
playMode = pmSlow;
playDir = pdForward;
trickSpeed = NORMAL_SPEED;
TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS);
break;
}
}
}
void cPlayBuffer::Backward(void)
{
if (canDoTrickMode) {
Empty(true);
still = false;
fastRewind = !fastRewind;
fastForward = false;
if (paused)
CHECK(ioctl(videoDev, fastRewind ? VIDEO_CONTINUE : VIDEO_FREEZE));
CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind));
CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused));
Empty(false);
switch (playMode) {
case pmFast:
if (Setup.MultiSpeedMode) {
TrickSpeed(playDir == pdBackward ? 1 : -1);
break;
}
else if (playDir == pdBackward) {
Play();
break;
}
// run into pmPlay
case pmPlay:
Empty(true);
CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false));
playMode = pmFast;
playDir = pdBackward;
trickSpeed = NORMAL_SPEED;
TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS);
Empty(false);
break;
case pmSlow:
if (Setup.MultiSpeedMode) {
TrickSpeed(playDir == pdBackward ? -1 : 1);
break;
}
else if (playDir == pdBackward) {
Pause();
break;
}
// run into pmPause
case pmStill:
case pmPause:
Empty(true);
CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false));
playMode = pmSlow;
playDir = pdBackward;
trickSpeed = NORMAL_SPEED;
TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS);
Empty(false);
break;
}
}
}
bool cPlayBuffer::GetReplayMode(bool &Play, bool &Forward, int &Speed)
{
Play = (playMode == pmPlay || playMode == pmFast);
Forward = (playDir == pdForward);
if (playMode == pmFast || playMode == pmSlow)
Speed = Setup.MultiSpeedMode ? abs(trickSpeed - NORMAL_SPEED) : 0;
else
Speed = -1;
return true;
}
void cPlayBuffer::ToggleAudioTrack(void)
{
if (CanToggleAudioTrack()) {
@ -890,18 +1044,17 @@ void cReplayBuffer::Input(void)
blockInput = 1;
continue;
}
if (!still) {
if (playMode != pmStill) {
int r = 0;
if (fastForward && !paused || fastRewind) {
if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
uchar FileNumber;
int FileOffset, Length;
int Index = index->GetNextIFrame(readIndex, fastForward, &FileNumber, &FileOffset, &Length);
int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length);
if (Index >= 0) {
if (!NextFile(FileNumber, FileOffset))
break;
}
else {
paused = fastForward = fastRewind = false;
Play();
continue;
}
@ -1073,23 +1226,21 @@ void cReplayBuffer::Goto(int Index, bool Still)
{
if (index) {
Empty(true);
if (paused)
CHECK(ioctl(videoDev, VIDEO_CONTINUE));
if (++Index <= 0)
Index = 1; // not '0', to allow GetNextIFrame() below to work!
uchar FileNumber;
int FileOffset, Length;
Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
still = true;
uchar b[MAXFRAMESIZE];
int r = ReadFrame(replayFile, b, Length, sizeof(b));
if (r > 0)
if (r > 0) {
if (playMode == pmPause)
CHECK(ioctl(videoDev, VIDEO_CONTINUE));
DisplayFrame(b, r);
paused = true;
}
playMode = pmStill;
}
else
still = false;
readIndex = writeIndex = Index;
Empty(false);
}
@ -1098,7 +1249,7 @@ void cReplayBuffer::Goto(int Index, bool Still)
void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
{
if (index) {
if (still)
if (playMode == pmStill)
Current = readIndex;
else {
Current = writeIndex;
@ -1180,7 +1331,7 @@ private:
int is_nav_pack(unsigned char *buffer);
void Close(void);
virtual void Empty(bool Block = false);
int decode_packet(unsigned char *sector, int iframe);
int decode_packet(unsigned char *sector, bool trickmode);
int ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType);
bool PacketStart(uchar **Data, int len);
int GetPacketType(const uchar *Data);
@ -1460,7 +1611,7 @@ void cDVDplayBuffer::Input(void)
}
// init settings for next state
if (!fastRewind)
if (playDir == pdForward)
cur_pack = cur_pgc->cell_playback[cur_cell].first_sector;
else
cur_pack = cur_pgc->cell_playback[cur_cell].last_vobu_start_sector;
@ -1478,7 +1629,7 @@ void cDVDplayBuffer::Input(void)
* We loop until we're out of this cell.
*/
if (!fastRewind) {
if (playDir == pdForward) {
if (cur_pack >= cur_pgc->cell_playback[cur_cell].last_sector) {
cur_cell = next_cell;
#ifdef DVDDEBUG
@ -1573,7 +1724,7 @@ void cDVDplayBuffer::Input(void)
case cREADFRAME:
{
int trickMode = (fastForward && !paused || fastRewind);
bool trickMode = (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward));
/* FIXME:
* the entire trickMode code relies on the assumtion
@ -1582,7 +1733,7 @@ void cDVDplayBuffer::Input(void)
* I have no clue wether that is correct or not !!!
*/
if (trickMode && (skipCnt++ % 4 != 0)) {
cur_pack = (!fastRewind) ? next_vobu : prev_vobu;
cur_pack = (playDir == pdForward) ? next_vobu : prev_vobu;
NextState(cOUTPACK);
break;
}
@ -1609,7 +1760,7 @@ void cDVDplayBuffer::Input(void)
case cOUTFRAMES:
{
int trickMode = (fastForward && !paused || fastRewind);
bool trickMode = (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward));
/**
* Output cursize packs.
@ -1624,7 +1775,7 @@ void cDVDplayBuffer::Input(void)
if (decode_packet(&data[pktcnt * DVD_VIDEO_LB_LEN], trickMode) != 1) { //we've got a video packet
if (trickMode) {
//dsyslog(LOG_INFO, "DVD: did pack: %d", pktcnt);
cur_pack = (!fastRewind) ? next_vobu : prev_vobu;
cur_pack = (playDir == pdForward) ? next_vobu : prev_vobu;
NextState(cOUTPACK);
break;
}
@ -1835,7 +1986,7 @@ void cDVDplayBuffer::putFrame(unsigned char *sector, int length)
;
}
int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
{
uchar pt = 1;
#if 0
@ -2213,6 +2364,8 @@ void cCuttingBuffer::Action(void)
// Write one frame:
if (PictureType == I_FRAME) { // every file shall start with an I_FRAME
if (!Mark) // edited version shall end before next I-frame
break;
if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) {
toFile = toFileName->NextFile();
if (toFile < 0)
@ -2231,16 +2384,18 @@ void cCuttingBuffer::Action(void)
if (Mark && Index >= Mark->position) {
Mark = fromMarks.Next(Mark);
toMarks.Add(LastIFrame);
if (Mark)
toMarks.Add(toIndex->Last() + 1);
toMarks.Save();
if (Mark) {
Index = Mark->position;
Mark = fromMarks.Next(Mark);
CurrentFileNumber = 0; // triggers SetOffset before reading next frame
toMarks.Add(LastIFrame);
toMarks.Add(toIndex->Last() + 1);
toMarks.Save();
}
else
break; // final end mark reached
// the 'else' case (i.e. 'final end mark reached') is handled above
// in 'Write one frame', so that the edited version will end right
// before the next I-frame.
}
}
}
@ -2322,9 +2477,8 @@ cDvbApi::cDvbApi(int n)
// Devices that are only present on DVB-C or DVB-S cards:
fd_qamfe = OstOpen(DEV_OST_QAMFE, n, O_RDWR);
fd_qpskfe = OstOpen(DEV_OST_QPSKFE, n, O_RDWR);
fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR);
fd_frontend = OstOpen(DEV_OST_FRONTEND, n, O_RDWR);
fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR);
// Devices that all DVB cards must have:
@ -2355,7 +2509,7 @@ cDvbApi::cDvbApi(int n)
// We only check the devices that must be present - the others will be checked before accessing them:
if (((fd_qpskfe >= 0 && fd_sec >= 0) || fd_qamfe >= 0) && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxd1 >= 0 && fd_demuxd2 >= 0 && fd_demuxt >= 0) {
if (fd_frontend >= 0 && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxd1 >= 0 && fd_demuxd2 >= 0 && fd_demuxt >= 0) {
siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n));
if (!dvbApi[0]) // only the first one shall set the system time
siProcessor->SetUseTSTime(Setup.SetSystemTime);
@ -2385,6 +2539,8 @@ cDvbApi::cDvbApi(int n)
osd = NULL;
#endif
currentChannel = 1;
mute = false;
volume = 255;
}
cDvbApi::~cDvbApi()
@ -2475,7 +2631,7 @@ bool cDvbApi::Init(void)
NumDvbApis = 0;
for (int i = 0; i < MAXDVBAPI; i++) {
if (useDvbApi == 0 || (useDvbApi & (1 << i)) != 0) {
if (Probe(OstName(DEV_OST_QPSKFE, i)) || Probe(OstName(DEV_OST_QAMFE, i)))
if (Probe(OstName(DEV_OST_FRONTEND, i)))
dvbApi[NumDvbApis++] = new cDvbApi(i);
else
break;
@ -2674,7 +2830,10 @@ bool cDvbApi::OvlG(int SizeX, int SizeY, int PosX, int PosY)
vw.width = SizeX;
vw.height = SizeY;
vw.chromakey = ovlPalette;
vw.flags = VIDEO_WINDOW_CHROMAKEY; // VIDEO_WINDOW_INTERLACE; //VIDEO_CLIP_BITMAP;
#ifndef VID_TYPE_CHROMAKEY // name changed somewhere down the road in kernel 2.4.x
#define VID_TYPE_CHROMAKEY VIDEO_WINDOW_CHROMAKEY
#endif
vw.flags = VID_TYPE_CHROMAKEY; // VIDEO_WINDOW_INTERLACE; //VIDEO_CLIP_BITMAP;
vw.clips = ovlClipRects;
vw.clipcount = ovlClipCount;
result |= ioctl(videoDev, VIDIOCSWIN, &vw);
@ -2781,7 +2940,7 @@ void cDvbApi::Open(int w, int h)
cols = w;
rows = h;
#ifdef DEBUG_OSD
window = subwin(stdscr, h, w, d, 0);
window = subwin(stdscr, h, w, d, (Setup.OSDwidth - w) / 2);
syncok(window, true);
#define B2C(b) (((b) * 1000) / 255)
#define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b))
@ -2799,7 +2958,7 @@ void cDvbApi::Open(int w, int h)
w *= charWidth;
h *= lineHeight;
d *= lineHeight;
int x = (720 - (Setup.OSDwidth - 1) * charWidth) / 2; //TODO PAL vs. NTSC???
int x = (720 - w + charWidth) / 2; //TODO PAL vs. NTSC???
int y = (576 - Setup.OSDheight * lineHeight) / 2 + d;
//XXX
osd = new cDvbOsd(fd_osd, x, y);
@ -3031,7 +3190,7 @@ bool cDvbApi::SetPids(bool ForRecording)
SetDpid2(ForRecording ? dPid2 : 0, DMX_OUT_TS_TAP);
}
bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr)
eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr)
{
// Make sure the siProcessor won't access the device while switching
cThreadLock ThreadLock(siProcessor);
@ -3075,7 +3234,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
bool ChannelSynced = false;
if (fd_qpskfe >= 0 && fd_sec >= 0) { // DVB-S
if (fd_sec >= 0) { // DVB-S
// Frequency offsets:
@ -3091,10 +3250,10 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
tone = SEC_TONE_ON;
}
qpskParameters qpsk;
qpsk.iFrequency = freq * 1000UL;
qpsk.SymbolRate = Srate * 1000UL;
qpsk.FEC_inner = FEC_AUTO;
FrontendParameters Frontend;
Frontend.Frequency = freq * 1000UL;
Frontend.u.qpsk.SymbolRate = Srate * 1000UL;
Frontend.u.qpsk.FEC_inner = FEC_AUTO;
int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
@ -3118,65 +3277,65 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
// Tuning:
CHECK(ioctl(fd_qpskfe, QPSK_TUNE, &qpsk));
CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
// Wait for channel sync:
if (cFile::FileReady(fd_qpskfe, 5000)) {
qpskEvent event;
int res = ioctl(fd_qpskfe, QPSK_GET_EVENT, &event);
if (cFile::FileReady(fd_frontend, 5000)) {
FrontendEvent event;
int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
if (res >= 0)
ChannelSynced = event.type == FE_COMPLETION_EV;
else
esyslog(LOG_ERR, "ERROR %d in qpsk get event", res);
esyslog(LOG_ERR, "ERROR %d in frontend get event", res);
}
else
esyslog(LOG_ERR, "ERROR: timeout while tuning");
}
else if (fd_qamfe >= 0) { // DVB-C
else if (fd_frontend >= 0) { // DVB-C
// Frequency and symbol rate:
qamParameters qam;
qam.Frequency = FrequencyMHz * 1000000UL;
qam.SymbolRate = Srate * 1000UL;
qam.FEC_inner = FEC_AUTO;
qam.QAM = QAM_64;
FrontendParameters Frontend;
Frontend.Frequency = FrequencyMHz * 1000000UL;
Frontend.u.qam.SymbolRate = Srate * 1000UL;
Frontend.u.qam.FEC_inner = FEC_AUTO;
Frontend.u.qam.QAM = QAM_64;
// Tuning:
CHECK(ioctl(fd_qamfe, QAM_TUNE, &qam));
CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
// Wait for channel sync:
if (cFile::FileReady(fd_qamfe, 5000)) {
qamEvent event;
int res = ioctl(fd_qamfe, QAM_GET_EVENT, &event);
if (cFile::FileReady(fd_frontend, 5000)) {
FrontendEvent event;
int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
if (res >= 0)
ChannelSynced = event.type == FE_COMPLETION_EV;
else
esyslog(LOG_ERR, "ERROR %d in qam get event", res);
esyslog(LOG_ERR, "ERROR %d in frontend get event", res);
}
else
esyslog(LOG_ERR, "ERROR: timeout while tuning");
}
else {
esyslog(LOG_ERR, "ERROR: attempt to set channel without DVB-S or DVB-C device");
return false;
return scrFailed;
}
if (!ChannelSynced) {
esyslog(LOG_ERR, "ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1);
if (this == PrimaryDvbApi)
cThread::RaisePanic();
return false;
return scrFailed;
}
// PID settings:
if (!SetPids(false)) {
esyslog(LOG_ERR, "ERROR: failed to set PIDs for channel %d", ChannelNumber);
return false;
return scrFailed;
}
SetTpid(Tpid, DMX_OUT_DECODER);
if (fd_audio >= 0)
@ -3186,19 +3345,21 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
if (this == PrimaryDvbApi && siProcessor)
siProcessor->SetCurrentServiceID(Pnr);
eSetChannelResult Result = scrOk;
// If this DVB card can't receive this channel, let's see if we can
// use the card that actually can receive it and transfer data from there:
if (NeedsTransferMode) {
cDvbApi *CaDvbApi = GetDvbApi(Ca, 0);
if (CaDvbApi) {
if (!CaDvbApi->Recording()) {
if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) {
SetModeReplay();
transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video);
}
if (CaDvbApi && !CaDvbApi->Recording()) {
if ((Result = CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) == scrOk) {
SetModeReplay();
transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video);
}
}
else
Result = scrNoTransfer;
}
if (fd_video >= 0 && fd_audio >= 0) {
@ -3206,7 +3367,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
}
return true;
return Result;
}
bool cDvbApi::Transferring(void)
@ -3372,8 +3533,10 @@ void cDvbApi::StopReplay(void)
if (this == PrimaryDvbApi) {
// let's explicitly switch the channel back in case it was in Transfer Mode:
cChannel *Channel = Channels.GetByNumber(currentChannel);
if (Channel)
if (Channel) {
Channel->Switch(this, false);
usleep(100000); // allow driver to sync in case a new replay will start immediately
}
}
}
}
@ -3424,6 +3587,11 @@ bool cDvbApi::GetIndex(int &Current, int &Total, bool SnapToIFrame)
return false;
}
bool cDvbApi::GetReplayMode(bool &Play, bool &Forward, int &Speed)
{
return replayBuffer && replayBuffer->GetReplayMode(Play, Forward, Speed);
}
void cDvbApi::Goto(int Position, bool Still)
{
if (replayBuffer)
@ -3456,6 +3624,24 @@ bool cDvbApi::ToggleAudioTrack(void)
return false;
}
void cDvbApi::ToggleMute(void)
{
int OldVolume = volume;
mute = !mute;
SetVolume(0, mute);
volume = OldVolume;
}
void cDvbApi::SetVolume(int Volume, bool Absolute)
{
if (fd_audio >= 0) {
volume = min(max(Absolute ? Volume : volume + Volume, 0), 255);
audioMixer_t am;
am.volume_left = am.volume_right = volume;
CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am));
}
}
void cDvbApi::SetAudioCommand(const char *Command)
{
delete audioCommand;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.h 1.47 2001/08/25 13:37:00 kls Exp $
* $Id: dvbapi.h 1.51 2001/09/16 13:54:23 kls Exp $
*/
#ifndef __DVBAPI_H
@ -56,6 +56,8 @@ const char *IndexToHMSF(int Index, bool WithFrame = false);
int HMSFToIndex(const char *HMSF);
// Converts the given string (format: "hh:mm:ss.ff") to an index.
enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed };
class cChannel;
class cRecordBuffer;
@ -85,7 +87,7 @@ class cDvbApi {
friend class cTransferBuffer;
private:
int videoDev;
int fd_osd, fd_qpskfe, fd_qamfe, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxd1, fd_demuxd2, fd_demuxv, fd_demuxt;
int fd_osd, fd_frontend, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxd1, fd_demuxd2, fd_demuxv, fd_demuxt;
int vPid, aPid1, aPid2, dPid1, dPid2;
bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output);
bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO, Vpid, Output); }
@ -203,7 +205,7 @@ public:
private:
int currentChannel;
public:
bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr);
eSetChannelResult SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr);
static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; }
int Channel(void) { return currentChannel; }
@ -287,6 +289,12 @@ public:
bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
// Returns the current and total frame index, optionally snapped to the
// nearest I-frame.
bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
// Returns the current replay mode (if applicable).
// 'Play' tells whether we are playing or pausing, 'Forward' tells whether
// we are going forward or backward and 'Speed' is -1 if this is normal
// play/pause mode, 0 if it is single speed fast/slow forward/back mode
// and >0 if this is multi speed mode.
void Goto(int Index, bool Still = false);
// Positions to the given index and displays that frame as a still picture
// if Still is true.
@ -307,6 +315,18 @@ private:
public:
static void SetAudioCommand(const char *Command);
static const char *AudioCommand(void) { return audioCommand; }
// Volume facilities:
private:
bool mute;
int volume;
public:
void ToggleMute(void);
// Turns the volume off or on.
void SetVolume(int Volume, bool Absolute = false);
// Sets the volume to the given value, either absolutely or relative to
// the current volume.
};
class cEITScanner {

56
i18n.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: i18n.c 1.39 2001/09/02 15:17:33 kls Exp $
* $Id: i18n.c 1.43 2001/09/16 14:43:05 kls Exp $
*
* Slovenian translations provided by Miha Setina <mihasetina@softhome.net>
* Italian translations provided by Alberto Carraro <bertocar@tin.it>
@ -658,6 +658,15 @@ const tPhrase Phrases[] = {
"Chaîne verrouillée (enregistrement en cours)!",
"Kanalen er låst (opptak)!",
},
{ "Can't start Transfer Mode!",
"Transfer-Mode kann nicht gestartet werden!",
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
},
{ "Can't start editing process!",
"Schnitt kann nicht gestartet werden!",
"Ne morem zaceti urejanja!",
@ -938,6 +947,24 @@ const tPhrase Phrases[] = {
"", // TODO
"", // TODO
},
{ "MultiSpeedMode",
"MultiSpeed Modus",
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
},
{ "ShowReplayMode",
"Wiedergabe Status",
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
},
// The days of the week:
{ "MTWTFSS",
"MDMDFSS",
@ -1184,6 +1211,33 @@ const tPhrase Phrases[] = {
"", // TODO
"", // TODO
},
{ "Volume+",
"Lautstärke+",
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
},
{ "Volume-",
"Lautstärke-",
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
},
{ "Mute",
"Stumm",
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
},
// Miscellaneous:
{ "yes",
"ja",

View File

@ -22,3 +22,6 @@ Blue 0000010C
8 00000038
9 00000039
Power 00000050
Volume+ 0000002B
Volume- 0000002D
Mute 0000006D

112
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.115 2001/09/02 15:27:54 kls Exp $
* $Id: menu.c 1.120 2001/09/15 10:36:31 kls Exp $
*/
#include "menu.h"
@ -16,8 +16,9 @@
#include "eit.h"
#include "i18n.h"
#define MENUTIMEOUT 120 // seconds
#define MAXWAIT4EPGINFO 10 // seconds
#define MENUTIMEOUT 120 // seconds
#define MAXWAIT4EPGINFO 10 // seconds
#define MODETIMEOUT 3 // seconds
const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#~^";
@ -1725,6 +1726,8 @@ void cMenuSetup::Set(void)
Add(new cMenuEditIntItem( tr("MaxVideoFileSize"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE));
Add(new cMenuEditIntItem( tr("MinEventTimeout"), &data.MinEventTimeout));
Add(new cMenuEditIntItem( tr("MinUserInactivity"), &data.MinUserInactivity));
Add(new cMenuEditBoolItem(tr("MultiSpeedMode"), &data.MultiSpeedMode));
Add(new cMenuEditBoolItem(tr("ShowReplayMode"), &data.ShowReplayMode));
}
eOSState cMenuSetup::ProcessKey(eKeys Key)
@ -1920,14 +1923,14 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
#define DIRECTCHANNELTIMEOUT 1000 //ms
#define INFOTIMEOUT 5000 //ms
cDisplayChannel::cDisplayChannel(int Number, bool Switched, bool Group)
cDisplayChannel::cDisplayChannel(int Number, bool Switched)
:cOsdBase(true)
{
group = Group;
withInfo = !group && (!Switched || Setup.ShowInfoOnChSwitch);
group = -1;
withInfo = !Switched || Setup.ShowInfoOnChSwitch;
lines = 0;
oldNumber = number = 0;
cChannel *channel = Group ? Channels.Get(Number) : Channels.GetByNumber(Number);
cChannel *channel = Channels.GetByNumber(Number);
Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? 5 : -5);
if (channel) {
DisplayChannel(channel);
@ -1939,6 +1942,7 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched, bool Group)
cDisplayChannel::cDisplayChannel(eKeys FirstKey)
:cOsdBase(true)
{
group = -1;
oldNumber = cDvbApi::CurrentChannel();
number = 0;
lastTime = time_ms();
@ -2049,6 +2053,32 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key)
}
}
break;
case kLeft:
case kRight:
withInfo = false;
if (group < 0) {
cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel());
if (channel)
group = channel->Index();
}
if (group >= 0) {
int SaveGroup = group;
if (Key == kRight)
group = Channels.GetNextGroup(group) ;
else
group = Channels.GetPrevGroup(group < 1 ? 1 : group);
if (group < 0)
group = SaveGroup;
cChannel *channel = Channels.Get(group);
if (channel) {
Interface->Clear();
DisplayChannel(channel);
if (!channel->groupSep)
group = -1;
}
}
lastTime = time_ms();
break;
case kNone:
if (number && time_ms() - lastTime > DIRECTCHANNELTIMEOUT) {
if (number > 0 && !Channels.SwitchTo(number))
@ -2059,8 +2089,8 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key)
//TODO
//XXX case kGreen: return osEventNow;
//XXX case kYellow: return osEventNext;
case kOk: if (group)
Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(CurrentGroup))->number);
case kOk: if (group >= 0)
Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(group))->number);
return osEnd;
default: Interface->PutKey(Key);
return osEnd;
@ -2304,7 +2334,7 @@ int cReplayControl::titleid = 0;//XXX
cReplayControl::cReplayControl(void)
{
dvbApi = cDvbApi::PrimaryDvbApi;
visible = shown = displayFrames = false;
visible = modeOnly = shown = displayFrames = false;
lastCurrent = lastTotal = -1;
timeoutShow = 0;
timeSearchActive = false;
@ -2367,7 +2397,51 @@ void cReplayControl::Hide(void)
{
if (visible) {
Interface->Close();
needsFastResponse = visible = false;
needsFastResponse = visible = modeOnly = false;
}
}
void cReplayControl::DisplayAtBottom(const char *s)
{
if (s) {
int w = dvbApi->WidthInCells(s);
int d = max(Width() - w, 0) / 2;
Interface->Write(d, -1, s);
Interface->Flush();
}
else
Interface->Fill(12, 2, Width() - 22, 1, clrBackground);
}
void cReplayControl::ShowMode(void)
{
if (Setup.ShowReplayMode && !timeSearchActive) {
bool Play, Forward;
int Speed;
if (dvbApi->GetReplayMode(Play, Forward, Speed)) {
if (!visible) {
// open small display
Interface->Open(9, -1);
Interface->Clear();
visible = modeOnly = true;
}
timeoutShow = (modeOnly && !timeoutShow && Speed == -1 && Play) ? time(NULL) + MODETIMEOUT : 0;
const char *Mode;
if (Speed == -1) Mode = Play ? " > " : " || ";
else if (Play) Mode = Forward ? " X>> " : " <<X ";
else Mode = Forward ? " X|> " : " <|X ";
char buf[16];
strn0cpy(buf, Mode, sizeof(buf));
char *p = strchr(buf, 'X');
if (p)
*p = Speed > 0 ? '1' + Speed - 1 : ' ';
eDvbFont OldFont = Interface->SetFont(fontFix);
DisplayAtBottom(buf);
Interface->SetFont(OldFont);
}
}
}
@ -2407,6 +2481,7 @@ bool cReplayControl::ShowProgress(bool Initial)
lastCurrent = Current;
}
lastTotal = Total;
ShowMode();
return true;
}
return false;
@ -2428,7 +2503,7 @@ void cReplayControl::TimeSearchDisplay(void)
default: sprintf(buf + len, "--:--"); break;
}
Interface->Write(12, 2, buf);
DisplayAtBottom(buf);
}
void cReplayControl::TimeSearchProcess(eKeys Key)
@ -2485,7 +2560,8 @@ void cReplayControl::TimeSearchProcess(eKeys Key)
if (timeSearchHide)
Hide();
else
Interface->Fill(12, 2, Width() - 22, 1, clrBackground);
DisplayAtBottom();
ShowMode();
}
}
@ -2493,6 +2569,8 @@ void cReplayControl::TimeSearch(void)
{
timeSearchHH = timeSearchMM = timeSearchPos = 0;
timeSearchHide = false;
if (modeOnly)
Hide();
if (!visible) {
Show();
if (visible)
@ -2596,7 +2674,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
Hide();
timeoutShow = 0;
}
else
else if (!modeOnly)
shown = ShowProgress(!shown) || shown;
}
bool DisplayedFrames = displayFrames;
@ -2605,13 +2683,16 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
TimeSearchProcess(Key);
return osContinue;
}
bool DoShowMode = true;
switch (Key) {
// Positioning:
case kUp: dvbApi->Play(); break;
case kDown: dvbApi->Pause(); break;
case kLeft|k_Release:
if (Setup.MultiSpeedMode) break;
case kLeft: dvbApi->Backward(); break;
case kRight|k_Release:
if (Setup.MultiSpeedMode) break;
case kRight: dvbApi->Forward(); break;
case kRed: TimeSearch(); break;
case kGreen|k_Repeat:
@ -2622,6 +2703,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
dvbApi->StopReplay();
return osEnd;
default: {
DoShowMode = false;
switch (Key) {
// Editing:
//XXX should we do this only when the ProgressDisplay is on???
@ -2647,6 +2729,8 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
}
}
}
if (DoShowMode)
ShowMode();
if (DisplayedFrames && !displayFrames)
Interface->Fill(0, 2, 11, 1, clrBackground);
return osContinue;

11
menu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.h 1.25 2001/09/01 14:52:48 kls Exp $
* $Id: menu.h 1.28 2001/09/14 15:09:49 kls Exp $
*/
#ifndef _MENU_H
@ -31,14 +31,15 @@ public:
class cDisplayChannel : public cOsdBase {
private:
bool withInfo, group;
int group;
bool withInfo;
int lines;
int lastTime;
int oldNumber, number;
void DisplayChannel(const cChannel *Channel);
void DisplayInfo(void);
public:
cDisplayChannel(int Number, bool Switched, bool Group = false);
cDisplayChannel(int Number, bool Switched);
cDisplayChannel(eKeys FirstKey);
virtual ~cDisplayChannel();
virtual eOSState ProcessKey(eKeys Key);
@ -101,7 +102,7 @@ class cReplayControl : public cOsdBase {
private:
cDvbApi *dvbApi;
cMarks marks;
bool visible, shown, displayFrames;
bool visible, modeOnly, shown, displayFrames;
int lastCurrent, lastTotal;
time_t timeoutShow;
bool timeSearchActive, timeSearchHide;
@ -117,6 +118,8 @@ private:
static int titleid;//XXX
#endif //DVDSUPPORT
static char *title;
void DisplayAtBottom(const char *s = NULL);
void ShowMode(void);
bool ShowProgress(bool Initial);
void MarkToggle(void);
void MarkJump(bool Forward);

View File

@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
* $Id: svdrp.c 1.22 2001/09/01 09:50:03 kls Exp $
* $Id: svdrp.c 1.23 2001/09/14 14:31:22 kls Exp $
*/
#define _GNU_SOURCE
@ -262,7 +262,7 @@ void cSVDRP::Close(bool Timeout)
{
if (file.IsOpen()) {
//TODO how can we get the *full* hostname?
char buffer[MAXCMDBUFFER];
char buffer[BUFSIZ];
gethostname(buffer, sizeof(buffer));
Reply(221, "%s closing connection%s", buffer, Timeout ? " (timeout)" : "");
isyslog(LOG_INFO, "closing SVDRP connection"); //TODO store IP#???
@ -944,7 +944,7 @@ void cSVDRP::Process(void)
if (file.IsOpen() || file.Open(socket.Accept())) {
if (SendGreeting) {
//TODO how can we get the *full* hostname?
char buffer[MAXCMDBUFFER];
char buffer[BUFSIZ];
gethostname(buffer, sizeof(buffer));
time_t now = time(NULL);
Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now));

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: svdrp.h 1.10 2001/09/01 09:24:50 kls Exp $
* $Id: svdrp.h 1.11 2001/09/14 14:35:34 kls Exp $
*/
#ifndef __SVDRP_H
@ -26,15 +26,13 @@ public:
int Accept(void);
};
#define MAXCMDBUFFER 1024
class cSVDRP {
private:
cSocket socket;
cFile file;
CRect ovlClipRects[MAXCLIPRECTS];
uint numChars;
char cmdLine[MAXCMDBUFFER];
char cmdLine[MAXPARSEBUFFER];
char *message;
time_t lastActivity;
void Close(bool Timeout = false);

106
thread.c
View File

@ -4,12 +4,13 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.c 1.11 2001/08/05 10:36:52 kls Exp $
* $Id: thread.c 1.12 2001/09/15 13:00:58 kls Exp $
*/
#include "thread.h"
#include <errno.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>
#include "tools.h"
@ -235,3 +236,106 @@ bool cThreadLock::Locked(void)
return locked;
}
// --- cPipe -----------------------------------------------------------------
// cPipe::Open() and cPipe::Close() are based on code originally received from
// Andreas Vitting <Andreas@huji.de>
cPipe::cPipe(void)
{
pid = -1;
f = NULL;
}
cPipe::~cPipe()
{
Close();
}
bool cPipe::Open(const char *Command, const char *Mode)
{
int fd[2];
if (pipe(fd) < 0) {
LOG_ERROR;
return false;
}
if ((pid = fork()) < 0) { // fork failed
LOG_ERROR;
close(fd[0]);
close(fd[1]);
return false;
}
char *mode = "w";
int iopipe = 0;
if (pid > 0) { // parent process
if (strcmp(Mode, "r") == 0) {
mode = "r";
iopipe = 1;
}
close(fd[iopipe]);
f = fdopen(fd[1 - iopipe], mode);
if ((f = fdopen(fd[1 - iopipe], mode)) == NULL) {
LOG_ERROR;
close(fd[1 - iopipe]);
}
return f != NULL;
}
else { // child process
int iofd = STDOUT_FILENO;
if (strcmp(Mode, "w") == 0) {
mode = "r";
iopipe = 1;
iofd = STDIN_FILENO;
}
close(fd[iopipe]);
if (dup2(fd[1 - iopipe], iofd) == -1) { // now redirect
LOG_ERROR;
close(fd[1 - iopipe]);
_exit(-1);
}
else {
for (int i = STDERR_FILENO + 1; i < fd[1 - iopipe]; i++)
close(i); //close all dup'ed filedescriptors
if (execl("/bin/sh", "sh", "-c", Command, NULL) == -1) {
LOG_ERROR_STR(Command);
close(fd[1 - iopipe]);
_exit(-1);
}
}
_exit(0);
}
}
int cPipe::Close(void)
{
int ret = -1;
if (f) {
fclose(f);
f = NULL;
}
if (pid >= 0) {
int status = 0;
struct rusage ru;
int i = 5;
while (ret == -1 && i > 0) {
usleep(1000);
ret = wait4(pid, &status, WNOHANG, &ru);
i--;
}
if (!i) {
kill(pid, SIGKILL);
ret = -1;
}
else if (ret == -1 || !WIFEXITED(status))
ret = -1;
pid = -1;
}
return ret;
}

View File

@ -4,13 +4,14 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.h 1.8 2001/08/05 10:36:47 kls Exp $
* $Id: thread.h 1.9 2001/09/15 12:46:52 kls Exp $
*/
#ifndef __THREAD_H
#define __THREAD_H
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
class cMutex;
@ -88,4 +89,19 @@ public:
#define LOCK_THREAD cThreadLock ThreadLock(this)
// cPipe implements a pipe that closes all unnecessary file descriptors in
// the child process.
class cPipe {
private:
pid_t pid;
FILE *f;
public:
cPipe(void);
~cPipe();
operator FILE* () { return f; }
bool Open(const char *Command, const char *Mode);
int Close(void);
};
#endif //__THREAD_H

26
tools.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.c 1.43 2001/08/26 15:45:41 kls Exp $
* $Id: tools.c 1.45 2001/09/15 15:41:16 kls Exp $
*/
#define _GNU_SOURCE
@ -21,8 +21,6 @@
#include <unistd.h>
#include "i18n.h"
#define MaxBuffer 1000
int SysLogLevel = 3;
ssize_t safe_read(int filedes, void *buffer, size_t size)
@ -56,7 +54,7 @@ void writechar(int filedes, char c)
char *readline(FILE *f)
{
static char buffer[MaxBuffer];
static char buffer[MAXPARSEBUFFER];
if (fgets(buffer, sizeof(buffer), f) > 0) {
int l = strlen(buffer) - 1;
if (l >= 0 && buffer[l] == '\n')
@ -556,13 +554,27 @@ bool cSafeFile::Open(void)
return f != NULL;
}
void cSafeFile::Close(void)
bool cSafeFile::Close(void)
{
bool result = true;
if (f) {
fclose(f);
if (ferror(f) != 0) {
LOG_ERROR_STR(tempName);
result = false;
}
if (fclose(f) < 0) {
LOG_ERROR_STR(tempName);
result = false;
}
f = NULL;
rename(tempName, fileName);
if (result && rename(tempName, fileName) < 0) {
LOG_ERROR_STR(fileName);
result = false;
}
}
else
result = false;
return result;
}
// --- cListObject -----------------------------------------------------------

13
tools.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.h 1.31 2001/08/26 12:52:49 kls Exp $
* $Id: tools.h 1.34 2001/09/15 15:22:57 kls Exp $
*/
#ifndef __TOOLS_H
@ -29,9 +29,16 @@ extern int SysLogLevel;
#define SECSINDAY 86400
#define KILOBYTE(n) ((n) * 1024)
#define MEGABYTE(n) ((n) * 1024 * 1024)
#define MAXPARSEBUFFER KILOBYTE(10)
#define DELETENULL(p) (delete (p), p = NULL)
template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; };
template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
ssize_t safe_read(int filedes, void *buffer, size_t size);
ssize_t safe_write(int filedes, const void *buffer, size_t size);
@ -86,7 +93,7 @@ public:
~cSafeFile();
operator FILE* () { return f; }
bool Open(void);
void Close(void);
bool Close(void);
};
class cListObject {

59
vdr.c
View File

@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
* $Id: vdr.c 1.68 2001/09/01 14:50:40 kls Exp $
* $Id: vdr.c 1.73 2001/09/16 14:54:45 kls Exp $
*/
#define _GNU_SOURCE
@ -50,6 +50,9 @@
#define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
#define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown
#define MANUALSTART 600 // seconds the next timer must be in the future to assume manual start
#define VOLUMEDELTA 5 // used to increase/decrease the volume
static int Interrupted = 0;
@ -328,7 +331,8 @@ int main(int argc, char *argv[])
if (!EITScanner.Active() && cDvbApi::CurrentChannel() != LastChannel) {
if (!Menu)
Menu = new cDisplayChannel(cDvbApi::CurrentChannel(), LastChannel > 0);
PreviousChannel = LastChannel;
if (LastChannel > 0)
PreviousChannel = LastChannel;
LastChannel = cDvbApi::CurrentChannel();
}
// Timers and Recordings:
@ -348,7 +352,7 @@ int main(int argc, char *argv[])
EITScanner.Activity();
LastActivity = time(NULL);
}
if (*Interact) {
if (*Interact && key != kPower) {
switch ((*Interact)->ProcessKey(key)) {
case osMenu: DELETENULL(Menu);
Menu = new cMenuMain(ReplayControl);
@ -390,10 +394,12 @@ int main(int argc, char *argv[])
else {
switch (key) {
// Toggle channels:
case k0:
if (PreviousChannel != cDvbApi::CurrentChannel())
Channels.SwitchTo(PreviousChannel);
case k0: {
int CurrentChannel = cDvbApi::CurrentChannel();
Channels.SwitchTo(PreviousChannel);
PreviousChannel = CurrentChannel;
break;
}
// Direct Channel Select:
case k1 ... k9:
Menu = new cDisplayChannel(key);
@ -402,17 +408,9 @@ int main(int argc, char *argv[])
case kLeft|k_Repeat:
case kLeft:
case kRight|k_Repeat:
case kRight: {
int SaveGroup = CurrentGroup;
if (NORMALKEY(key) == kRight)
CurrentGroup = Channels.GetNextGroup(CurrentGroup) ;
else
CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup);
if (CurrentGroup < 0)
CurrentGroup = SaveGroup;
Menu = new cDisplayChannel(CurrentGroup, false, true);
case kRight:
Menu = new cDisplayChannel(NORMALKEY(key));
break;
}
// Up/Down Channel Select:
case kUp|k_Repeat:
case kUp:
@ -428,8 +426,19 @@ int main(int argc, char *argv[])
case kMenu: Menu = new cMenuMain(ReplayControl); break;
// Viewing Control:
case kOk: LastChannel = -1; break; // forces channel display
// Volume Control:
case kVolUp|k_Repeat:
case kVolUp:
case kVolDn|k_Repeat:
case kVolDn:
cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA);
break;
case kMute:
cDvbApi::PrimaryDvbApi->ToggleMute();
break;
// Power off:
case kPower: isyslog(LOG_INFO, "Power button pressed");
DELETENULL(*Interact);
if (!Shutdown) {
Interface->Error(tr("Can't shutdown - option '-s' not given!"));
break;
@ -451,20 +460,24 @@ int main(int argc, char *argv[])
time_t Now = time(NULL);
if (Now - LastActivity > ACTIVITYTIMEOUT) {
// Shutdown:
if (Shutdown && (Setup.MinUserInactivity && Now - LastActivity > Setup.MinUserInactivity * 60 || ForceShutdown)) {
ForceShutdown = false;
if (Shutdown && Setup.MinUserInactivity && Now - LastActivity > Setup.MinUserInactivity * 60) {
cTimer *timer = Timers.GetNextActiveTimer();
time_t Next = timer ? timer->StartTime() : 0;
time_t Delta = timer ? Next - Now : 0;
if (timer)
dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next));
if (!Next || Delta > Setup.MinEventTimeout * 60) {
if (!LastActivity) {
if (!LastActivity) {
if (!timer || Delta > MANUALSTART) {
// Apparently the user started VDR manually
dsyslog(LOG_INFO, "assuming manual start of VDR");
LastActivity = Now;
continue; // skip the rest of the housekeeping for now
continue; // don't run into the actual shutdown procedure below
}
else
LastActivity = 1;
}
if (!Next || Delta > Setup.MinEventTimeout * 60 || ForceShutdown) {
ForceShutdown = false;
if (timer)
dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next));
if (WatchdogTimeout > 0)
signal(SIGALRM, SIG_IGN);
if (Interface->Confirm(tr("Press any key to cancel shutdown"), LastActivity == 1 ? 5 : SHUTDOWNWAIT, true)) {