Implemented actual record/replay; support for CICAM

This commit is contained in:
Klaus Schmidinger 2000-04-15 17:38:11 +02:00
parent 571686d909
commit 735093b8fa
22 changed files with 1944 additions and 567 deletions

23
BUGS Normal file
View File

@ -0,0 +1,23 @@
Video Disk Recorder - Known Bugs
--------------------------------
* Sometimes picture and sound drift apart.
Presumably this is a problem in the card driver or firmware?
* When the on-screen display is activated during recording,
the video data stream gets corrupted, which results in a
distorted picture when replaying such a recording.
I assume this is a problem in the driver of firmware.
There is no such problem in replay mode.
* After a replay session the screen may go blank.
Haven't figured out yet how to ensure that it switches back to
the current channel.
* Every now and then the on-screen display shows nothing but
"noise". If that occurs, I have to stop the 'osm' program
and do a 'make reload' for the card driver. After that it
works fine again.
Presumably this is a problem in the card driver or firmware?
Or could it be a problem with the hardware?
Does anybody else observe this?

View File

@ -10,3 +10,11 @@ Video Disk Recorder OSM Revision History
- Support for "Red", "Green", "Yellow", "Blue" buttons.
- Channels and Timers can now be added, deleted and moved.
- Basic record/play file handling support (no actual record/playback yet).
2000-04-15: Version 0.03
- Actual record/replay now works.
- Dropped the idea of different "recording qualities" (a 36GB harddisk is
able to store some 18 hours in full quality, so we don't really need that).
- Termination signals are now caught and the program cleans up before exiting.
- Support for CICAM.

39
MANUAL Normal file
View File

@ -0,0 +1,39 @@
Video Disk Recorder User's Manual
---------------------------------
* Selecting a Channel
You can select a channel either by pressing the "Up" or "Down" key (while
no On Screen Menu is displayed), or browsing through the channel list in
the menu and pressing "Ok" on the desired channel.
* Instant Recording
You can start recording the current channel by pressing the "Record"
button. This will create a timer event named "instant" that start
at the current time and records for two hours.
If you want to modify the recording time you need to edit the timer.
Stop instant recording by disabling or deleting the timer.
* Replaying a Recording
All recordings are listed in the "Recordings" menu. Browse through the
list with the "Up" and "Down" button and press "Ok" (or the "Red" button)
to start playback.
* Replay Control
- "Begin" Positions to beginning of the recording and starts playback
from there.
- "Pause" Halts playback at the current frame. Press again to continue
playback.
- "Stop" Stops playback and stores the current position, so that
playback can be resumed later at that point.
- "Search" Runs playback forward or backward at a higher speed. Press
again to resume normal speed.
- "Skip" Skips about 60 seconds forward or backward.
* Programming the Timer
Use the "Timer" menu to maintain your list of timer controlled recordings.

72
README
View File

@ -36,34 +36,13 @@ about that driver). For example, if the DVB driver was
extracted into the directory /home/kls/vdr/DVB, then this
package should be extracted into /home/kls/vdr/OSM.
In order for the menu colors to work correctly you may want
to replace the function RGB2YUV() in DVB/driver/dvb.c with
static u32 RGB2YUV(u16 R, u16 G, u16 B)
{
u16 y, u, v;
u16 Y, Cr, Cb;
y = R * 77 + G * 150 + B * 29; // Luma=0.299R+0.587G+0.114B 0..65535
u = 2048+B * 8 -(y>>5); // Cr 0..4095
v = 2048+R * 8 -(y>>5); // Cb 0..4095
Y = y >> 8;
Cb= u >> 4;
Cr= v >> 4;
return Cr|(Cb<<16)|(Y<<8);
}
(this may no longer be necessary with driver versions after 0.03c).
This program requires the card driver version 0.04 or higher
to work properly.
After extracting the package, change into the OSM directory
and type 'make'. This should produce an executable file
named 'osm', which can be run after the DVB driver has been
installed. There may be several warnings about "implicit declaration
of function `int asprintf(...)'" during the compilation, which I was
unable to avoid (anybody know how to avoid them?). Just ignore them,
the program will work, anyway.
installed.
There are two macros you can use to customize the 'osm' program
at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call
@ -88,28 +67,43 @@ The meaning of the data entries may still vary in future releases,
so for the moment please look at the source code (config.c) to see
the meaning of the various fields.
There is no way of adding or deleting channels or timers yet, this
will be implemented later.
Learning the remote control keys:
---------------------------------
The remote control configuration file 'keys.conf' that comes with
this package contains the codes for the "d-box" remote control unit.
If you want to use a different remote control unit, simply delete
the file 'keys.conf' and restart the 'osm' program. The program will
then start a key learning session in which it first attempts to determine
the basic data transfer mode and timing of your remote control unit,
and then will ask you to press one key after the other so that it can
learn the various key codes. You will at least need to provide an "Up"
and a "Down" key, so that you can switch channels. The rest of the key
definitions is optional, but the more keys you define, the more you
will be able to navigate through the menus.
There is no default 'keys.conf' file, so if you compile the program
without 'DEBUG_REMOTE=1' you will have to go through a "teach-in"
session that allows the program to learn your remote control codes.
It will first attempt to determine the basic data transfer mode and
timing of your remote control unit, and then will ask you to press one
key after the other so that it can learn the various key codes. You will
at least need to provide an "Up" and a "Down" key, so that you can switch
channels. The rest of the key definitions is optional, but the more keys
you define, the more you will be able to navigate through the menus and
control recording/replaying.
If the program has been built with "DEBUG_REMOTE=1", it will use the
key configuration file 'keys-pc.conf', so that you won't loose data
when switching between normal and debug mode.
The default PC key assignments are:
Up, Down, Left, Right Crsr keys in numeric block
Menu '5' in numeric block
Ok Enter
Back Backspace
0..9 '0'..'9' in top row
Red, Green, Yellow, Blue 'F1'..'F4'
Record 'r'
Pause 'p'
Stop 's'
Begin 'B'
SearchForward 'f'
SearchBack 'b'
SkipForward 'PgDn' in numeric block
SkipBack 'PgUp' in numeric block
If you prefer different key assignments, simply delete the file
'keys-pc.conf' and restart 'osm' to get into learning mode.
Navigating through the On Screen Menus:
---------------------------------------

6
TODO
View File

@ -1,7 +1,7 @@
TODO list for the Video Disk Recorder project
---------------------------------------------
* Implement recording to disk and playback from disk.
* Channel select via numeric keys.
* Make it work with two DVB-S PCI cards to allow simultaneous
recording of one programme, while replaying another programme
(or maybe the same one, but time delayed).
@ -10,3 +10,7 @@ TODO list for the Video Disk Recorder project
* Implement "on-disk editing" to allow "cutting out" of certain
scenes in order to archive them (or, reversely, cut out
commercial breaks).
* Implement on-screen display of replay progress (progress bar
and/or time index).
* Implement channel scanning.
* Better support for encrypted channels.

View File

@ -1,109 +1,109 @@
RTL:12188:h:1:27500:163:104
Sat.1:12552:v:1:22000:163:104
Pro 7:12480:v:1:27500:255:256
RTL2:12188:h:1:27500:166:128
ARD:11837:h:1:27500:101:102
BR3:11837:h:1:27500:201:202
Hessen 3:11837:h:1:27500:301:302
N3:11837:h:1:27500:401:402
SR3:11837:h:1:27500:501:502
WDR:11837:h:1:27500:601:602
BR alpha:11837:h:1:27500:701:702
SWR BW:11837:h:1:27500:801:802
Phoenix:11837:h:1:27500:901:902
ZDF:11954:h:1:27500:110:120
3sat:11954:h:1:27500:210:220
Kinderkanal:11954:h:1:27500:310:320
arte:11954:h:1:27500:360:370
phoenix:11954:h:1:27500:410:420
ORF Sat:11954:h:1:27500:506:507
ZDF Infobox:11954:h:1:27500:610:620
CNN:12168:v:1:27500:165:100
Super RTL:12188:h:1:27500:165:120
VOX:12188:h:1:27500:167:136
DW TV:12363:v:1:27500:305:306
Kabel 1:12480:v:1:27500:511:512
TM3:12480:v:1:27500:767:768
DSF:12480:v:1:27500:1023:1024
HOT:12480:v:1:27500:1279:1280
BloombergTV:12552:v:1:22000:162:99
Sky News:12552:v:1:22000:305:306
KinderNet:12574:h:1:22000:163:92
Alice:12610:v:1:22000:162:96
n-tv:12670:v:1:22000:162:96
Grand Tour.:12670:v:1:22000:289:290
TW1:12692:h:1:22000:166:167
Eins Extra:12722:h:1:22000:101:102
Eins Festival:12722:h:1:22000:201:202
Eins MuXx:12722:h:1:22000:301:302
MDR:12722:h:1:22000:401:402
ORB:12722:h:1:22000:501:502
B1:12722:h:1:22000:601:602
ARD Online-Kanal:12722:h:1:22000:8191:701
Premiere World Promo:11798:h:1:27500:255:256
TV Niepokalanow:11876:h:1:27500:305:321
test card:11798:h:1:27500:511:512
Mosaico:11934:v:1:27500:165:100
Andalucia TV:11934:v:1:27500:166:104
TVC Internacional:11934:v:1:27500:167:108
Nasza TV:11992:h:1:27500:165:98
WishLine test:12012:v:1:27500:163:90
Pro 7 Austria:12051:v:1:27500:161:84
Kabel 1 Schweiz:12051:v:1:27500:162:163
Kabel 1 Austria:12051:v:1:27500:166:167
Pro 7 Schweiz:12051:v:1:27500:289:290
Kiosque:12129:v:1:27500:160:80
KTO:12129:v:1:27500:170:120
TCM:12168:v:1:27500:160:80
Cartoon Network France & Spain:12168:v:1:27500:161:84
TVBS Europe:12168:v:1:27500:162:88
TVBS Europe:12168:v:1:27500:162:89
Travel:12168:v:1:27500:163:92
TCM Espania:12168:v:1:27500:164:96
MTV Spain:12168:v:1:27500:167:112
TCM France:12168:v:1:27500:169:64
RTL2 CH:12188:h:1:27500:164:112
La Cinquieme:12207:v:1:27500:160:80
ARTE:12207:v:1:27500:165:100
Post Filial TV:12226:h:1:27500:255:256
Canal Canaris:12246:v:1:27500:160:80
Canal Canaris:12246:v:1:27500:160:81
Canal Canaris:12246:v:1:27500:160:82
Canal Canaris:12246:v:1:27500:160:83
AB Sat Passion promo:12266:h:1:27500:160:80
AB Channel 1:12266:h:1:27500:161:84
Taquilla 0:12285:v:1:27500:165:100
CSAT:12324:v:1:27500:160:80
Mosaique:12324:v:1:27500:162:88
Mosaique 2:12324:v:1:27500:163:92
Mosaique 3:12324:v:1:27500:164:96
Le Sesame C+:12324:v:1:27500:165:1965
FEED:12344:h:1:27500:163:92
RTM 1:12363:v:1:27500:162:96
ESC 1:12363:v:1:27500:163:104
TV5 Europe:12363:v:1:27500:164:112
TV7 Tunisia:12363:v:1:27500:166:128
ARTE:12363:v:1:27500:167:137
RAI Uno:12363:v:1:27500:289:290
RTP International:12363:v:1:27500:300:301
Fashion TV:12402:v:1:27500:163:92
VideoService:12422:h:1:27500:255:256
Beta Research promo:12422:h:1:27500:1023:1024
Canal Canarias:12441:v:1:27500:160:80
TVC International:12441:v:1:27500:512:660
Fitur:12441:v:1:27500:514:662
Astra Info 1:12552:v:1:22000:164:112
Astra Info 2:12552:v:1:22000:165:120
Astra Vision 1:12552:v:1:22000:168:144
Astra Vision 1:12552:v:1:22000:168:145
Astra Vision 1:12552:v:1:22000:168:146
Astra Vision 1:12552:v:1:22000:168:147
Astra Vision 1:12552:v:1:22000:168:148
Astra Vision 1:12552:v:1:22000:168:149
Astra Vision 1:12552:v:1:22000:168:150
RTL Tele Letzebuerg:12552:v:1:22000:168:144
Astra Mosaic:12552:v:1:22000:175:176
MHP test:12604:h:1:22000:5632:8191
Bloomberg TV Spain:12610:v:1:22000:45:49
Video Italia:12610:v:1:22000:121:122
AC 3 promo:12670:v:1:22000:308:256
RTL:12188:h:1:27500:163:104:0:0
Sat.1:12552:v:1:22000:163:104:0:0
Pro 7:12480:v:1:27500:255:256:0:0
RTL2:12188:h:1:27500:166:128:0:0
ARD:11837:h:1:27500:101:102:0:0
BR3:11837:h:1:27500:201:202:0:0
Hessen 3:11837:h:1:27500:301:302:0:0
N3:11837:h:1:27500:401:402:0:0
SR3:11837:h:1:27500:501:502:0:0
WDR:11837:h:1:27500:601:602:0:0
BR alpha:11837:h:1:27500:701:702:0:0
SWR BW:11837:h:1:27500:801:802:0:0
Phoenix:11837:h:1:27500:901:902:0:0
ZDF:11954:h:1:27500:110:120:0:0
3sat:11954:h:1:27500:210:220:0:0
Kinderkanal:11954:h:1:27500:310:320:0:0
arte:11954:h:1:27500:360:370:0:0
phoenix:11954:h:1:27500:410:420:0:0
ORF Sat:11954:h:1:27500:506:507:0:0
ZDF Infobox:11954:h:1:27500:610:620:0:0
CNN:12168:v:1:27500:165:100:0:0
Super RTL:12188:h:1:27500:165:120:0:0
VOX:12188:h:1:27500:167:136:0:0
DW TV:12363:v:1:27500:305:306:0:0
Kabel 1:12480:v:1:27500:511:512:0:0
TM3:12480:v:1:27500:767:768:0:0
DSF:12480:v:1:27500:1023:1024:0:0
HOT:12480:v:1:27500:1279:1280:0:0
BloombergTV:12552:v:1:22000:162:99:0:0
Sky News:12552:v:1:22000:305:306:0:0
KinderNet:12574:h:1:22000:163:92:0:0
Alice:12610:v:1:22000:162:96:0:0
n-tv:12670:v:1:22000:162:96:0:0
Grand Tour.:12670:v:1:22000:289:290:0:0
TW1:12692:h:1:22000:166:167:0:0
Eins Extra:12722:h:1:22000:101:102:0:0
Eins Festival:12722:h:1:22000:201:202:0:0
Eins MuXx:12722:h:1:22000:301:302:0:0
MDR:12722:h:1:22000:401:402:0:0
ORB:12722:h:1:22000:501:502:0:0
B1:12722:h:1:22000:601:602:0:0
ARD Online-Kanal:12722:h:1:22000:8191:701:0:0
Premiere World Promo:11798:h:1:27500:255:256:0:0
TV Niepokalanow:11876:h:1:27500:305:321:0:0
Premiere:11798:h:1:27500:1023:1024:1:10
Mosaico:11934:v:1:27500:165:100:0:0
Andalucia TV:11934:v:1:27500:166:104:0:0
TVC Internacional:11934:v:1:27500:167:108:0:0
Nasza TV:11992:h:1:27500:165:98:0:0
WishLine test:12012:v:1:27500:163:90:0:0
Pro 7 Austria:12051:v:1:27500:161:84:0:0
Kabel 1 Schweiz:12051:v:1:27500:162:163:0:0
Kabel 1 Austria:12051:v:1:27500:166:167:0:0
Pro 7 Schweiz:12051:v:1:27500:289:290:0:0
Kiosque:12129:v:1:27500:160:80:0:0
KTO:12129:v:1:27500:170:120:0:0
TCM:12168:v:1:27500:160:80:0:0
Cartoon Network France & Spain:12168:v:1:27500:161:84:0:0
TVBS Europe:12168:v:1:27500:162:88:0:0
TVBS Europe:12168:v:1:27500:162:89:0:0
Travel:12168:v:1:27500:163:92:0:0
TCM Espania:12168:v:1:27500:164:96:0:0
MTV Spain:12168:v:1:27500:167:112:0:0
TCM France:12168:v:1:27500:169:64:0:0
RTL2 CH:12188:h:1:27500:164:112:0:0
La Cinquieme:12207:v:1:27500:160:80:0:0
ARTE:12207:v:1:27500:165:100:0:0
Post Filial TV:12226:h:1:27500:255:256:0:0
Canal Canaris:12246:v:1:27500:160:80:0:0
Canal Canaris:12246:v:1:27500:160:81:0:0
Canal Canaris:12246:v:1:27500:160:82:0:0
Canal Canaris:12246:v:1:27500:160:83:0:0
AB Sat Passion promo:12266:h:1:27500:160:80:0:0
AB Channel 1:12266:h:1:27500:161:84:0:0
Taquilla 0:12285:v:1:27500:165:100:0:0
CSAT:12324:v:1:27500:160:80:0:0
Mosaique:12324:v:1:27500:162:88:0:0
Mosaique 2:12324:v:1:27500:163:92:0:0
Mosaique 3:12324:v:1:27500:164:96:0:0
Le Sesame C+:12324:v:1:27500:165:1965:0:0
FEED:12344:h:1:27500:163:92:0:0
RTM 1:12363:v:1:27500:162:96:0:0
ESC 1:12363:v:1:27500:163:104:0:0
TV5 Europe:12363:v:1:27500:164:112:0:0
TV7 Tunisia:12363:v:1:27500:166:128:0:0
ARTE:12363:v:1:27500:167:137:0:0
RAI Uno:12363:v:1:27500:289:290:0:0
RTP International:12363:v:1:27500:300:301:0:0
Fashion TV:12402:v:1:27500:163:92:0:0
VideoService:12422:h:1:27500:255:256:0:0
Beta Research promo:12422:h:1:27500:1023:1024:0:0
Canal Canarias:12441:v:1:27500:160:80:0:0
TVC International:12441:v:1:27500:512:660:0:0
Fitur:12441:v:1:27500:514:662:0:0
Astra Info 1:12552:v:1:22000:164:112:0:0
Astra Info 2:12552:v:1:22000:165:120:0:0
Astra Vision 1:12552:v:1:22000:168:144:0:0
Astra Vision 1:12552:v:1:22000:168:145:0:0
Astra Vision 1:12552:v:1:22000:168:146:0:0
Astra Vision 1:12552:v:1:22000:168:147:0:0
Astra Vision 1:12552:v:1:22000:168:148:0:0
Astra Vision 1:12552:v:1:22000:168:149:0:0
Astra Vision 1:12552:v:1:22000:168:150:0:0
RTL Tele Letzebuerg:12552:v:1:22000:168:144:0:0
Astra Mosaic:12552:v:1:22000:175:176:0:0
MHP test:12604:h:1:22000:5632:8191:0:0
Bloomberg TV Spain:12610:v:1:22000:45:49:0:0
Video Italia:12610:v:1:22000:121:122:0:0
AC 3 promo:12670:v:1:22000:308:256:0:0

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: config.c 1.2 2000/03/05 16:14:27 kls Exp $
* $Id: config.c 1.3 2000/04/15 12:48:00 kls Exp $
*/
#include "config.h"
@ -16,28 +16,36 @@
// -- cKeys ------------------------------------------------------------------
tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ kUp, "Up", 0 },
{ kDown, "Down", 0 },
{ kMenu, "Menu", 0 },
{ kOk, "Ok", 0 },
{ kBack, "Back", 0 },
{ kLeft, "Left", 0 },
{ kRight, "Right", 0 },
{ k0, "0", 0 },
{ k1, "1", 0 },
{ k2, "2", 0 },
{ k3, "3", 0 },
{ k4, "4", 0 },
{ k5, "5", 0 },
{ k6, "6", 0 },
{ k7, "7", 0 },
{ k8, "8", 0 },
{ k9, "9", 0 },
{ kRed, "Red", 0 },
{ kGreen, "Green", 0 },
{ kYellow, "Yellow", 0 },
{ kBlue, "Blue", 0 },
{ kNone, "", 0 },
{ kUp, "Up", 0 },
{ kDown, "Down", 0 },
{ kMenu, "Menu", 0 },
{ kOk, "Ok", 0 },
{ kBack, "Back", 0 },
{ kLeft, "Left", 0 },
{ kRight, "Right", 0 },
{ k0, "0", 0 },
{ k1, "1", 0 },
{ k2, "2", 0 },
{ k3, "3", 0 },
{ k4, "4", 0 },
{ k5, "5", 0 },
{ k6, "6", 0 },
{ k7, "7", 0 },
{ k8, "8", 0 },
{ k9, "9", 0 },
{ kRed, "Red", 0 },
{ kGreen, "Green", 0 },
{ kYellow, "Yellow", 0 },
{ kBlue, "Blue", 0 },
{ kRecord, "Record", 0 },
{ kPause, "Pause", 0 },
{ kStop, "Stop", 0 },
{ kBegin, "Begin", 0 },
{ kSearchForward, "SearchForward", 0 },
{ kSearchBack, "SearchBack", 0 },
{ kSkipForward, "SkipForward", 0 },
{ kSkipBack, "SkipBack", 0 },
{ kNone, "", 0 },
};
cKeys::cKeys(void)
@ -88,7 +96,7 @@ bool cKeys::Load(char *FileName)
}
}
if (Name) {
fprintf(stderr, "unknown key in %s, line %d\n", fileName, line);
esyslog(LOG_ERR, "unknown key in %s, line %d\n", fileName, line);
result = false;
break;
}
@ -96,17 +104,17 @@ bool cKeys::Load(char *FileName)
}
continue;
}
fprintf(stderr, "error in %s, line %d\n", fileName, line);
esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line);
result = false;
break;
}
fclose(f);
}
else
fprintf(stderr, "can't open '%s'\n", fileName);
esyslog(LOG_ERR, "can't open '%s'\n", fileName);
}
else
fprintf(stderr, "no key configuration file name supplied!\n");
esyslog(LOG_ERR, "no key configuration file name supplied!\n");
return result;
}
@ -172,12 +180,14 @@ cChannel::cChannel(const cChannel *Channel)
srate = Channel ? Channel->srate : 27500;
vpid = Channel ? Channel->vpid : 255;
apid = Channel ? Channel->apid : 256;
ca = Channel ? Channel->ca : 0;
pnr = Channel ? Channel->pnr : 0;
}
bool cChannel::Parse(char *s)
{
char *buffer = NULL;
if (7 == sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid)) {
if (9 == sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &ca, &pnr)) {
strncpy(name, buffer, MaxChannelName - 1);
name[strlen(buffer)] = 0;
delete buffer;
@ -188,20 +198,21 @@ bool cChannel::Parse(char *s)
bool cChannel::Save(FILE *f)
{
return fprintf(f, "%s:%d:%c:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid) > 0;
return fprintf(f, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid, ca, pnr) > 0;
}
bool cChannel::Switch(void)
{
if (!ChannelLocked) {
if (!DvbApi.Recording()) {
isyslog(LOG_INFO, "switching to channel %d", Index() + 1);
CurrentChannel = Index();
Interface.DisplayChannel(CurrentChannel + 1, name);
for (int i = 3; --i;) {
if (DvbSetChannel(frequency, polarization, diseqc, srate, vpid, apid))
if (DvbApi.SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr))
return true;
esyslog(LOG_ERR, "retrying");
}
return false;
}
Interface.Info("Channel locked (recording)!");
return false;
@ -215,20 +226,23 @@ bool cChannel::SwitchTo(int i)
// -- cTimer -----------------------------------------------------------------
cTimer::cTimer(void)
cTimer::cTimer(bool Instant)
{
startTime = stopTime = 0;
recording = false;
active = 1;
active = Instant;
channel = CurrentChannel + 1;
day = 1; //XXX today!
start = 0; //XXX now!
stop = 0; //XXX now + 2h!
time_t t = time(NULL);
struct tm *now = localtime(&t);
day = now->tm_mday;
start = now->tm_hour * 100 + now->tm_min;
stop = start + 200; // "instant recording" records 2 hours by default
if (stop >= 2400)
stop -= 2400;
//TODO VPS???
quality = 'H';
priority = 99;
lifetime = 99;
*file = 0;
strcpy(file, Instant ? "instant" : "");
}
int cTimer::TimeToInt(int t)
@ -286,7 +300,7 @@ bool cTimer::Parse(char *s)
{
char *buffer1 = NULL;
char *buffer2 = NULL;
if (9 == sscanf(s, "%d:%d:%a[^:]:%d:%d:%c:%d:%d:%as", &active, &channel, &buffer1, &start, &stop, &quality, &priority, &lifetime, &buffer2)) {
if (8 == sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%as", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2)) {
day = ParseDay(buffer1);
strncpy(file, buffer2, MaxFileName - 1);
file[strlen(buffer2)] = 0;
@ -299,7 +313,7 @@ bool cTimer::Parse(char *s)
bool cTimer::Save(FILE *f)
{
return fprintf(f, "%d:%d:%s:%d:%d:%c:%d:%d:%s\n", active, channel, PrintDay(day), start, stop, quality, priority, lifetime, file) > 0;
return fprintf(f, "%d:%d:%s:%d:%d:%d:%d:%s\n", active, channel, PrintDay(day), start, stop, priority, lifetime, file) > 0;
}
bool cTimer::IsSingleEvent(void)
@ -383,7 +397,6 @@ cKeys Keys;
// -- cChannels --------------------------------------------------------------
int CurrentChannel = 0;
bool ChannelLocked = false;
cChannels Channels;

View File

@ -4,12 +4,13 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.2 2000/03/05 14:58:23 kls Exp $
* $Id: config.h 1.3 2000/04/15 12:44:23 kls Exp $
*/
#ifndef __CONFIG_H
#define __CONFIG_H
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <time.h>
@ -30,6 +31,14 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kGreen,
kYellow,
kBlue,
kRecord,
kPause,
kStop,
kBegin,
kSearchForward,
kSearchBack,
kSkipForward,
kSkipBack,
kNone
};
@ -64,6 +73,8 @@ public:
int srate;
int vpid;
int apid;
int ca;
int pnr;
cChannel(void);
cChannel(const cChannel *Channel);
bool Parse(char *s);
@ -84,11 +95,10 @@ public:
int start;
int stop;
//TODO VPS???
char quality;
int priority;
int lifetime;
char file[MaxFileName];
cTimer(void);
cTimer(bool Instant = false);
bool Parse(char *s);
bool Save(FILE *f);
bool IsSingleEvent(void);
@ -128,7 +138,7 @@ public:
if (l->Parse(buffer))
Add(l);
else {
fprintf(stderr, "error in %s, line %d\n", fileName, line);
esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line);
delete l;
result = false;
break;
@ -137,7 +147,7 @@ public:
fclose(f);
}
else {
fprintf(stderr, "can't open '%s'\n", fileName);
esyslog(LOG_ERR, "can't open '%s'\n", fileName);
result = false;
}
return result;
@ -168,7 +178,6 @@ class cChannels : public cConfig<cChannel> {};
class cTimers : public cConfig<cTimer> {};
extern int CurrentChannel;
extern bool ChannelLocked;
extern cChannels Channels;
extern cTimers Timers;

1420
dvbapi.c

File diff suppressed because it is too large Load Diff

121
dvbapi.h
View File

@ -4,20 +4,21 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.h 1.2 2000/03/06 19:47:20 kls Exp $
* $Id: dvbapi.h 1.3 2000/04/15 13:36:10 kls Exp $
*/
#ifndef __DVBAPI_H
#define __DVBAPI_H
// FIXME: these should be defined in ../DVB/driver/dvb.h!!!
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef unsigned int __u32;
typedef unsigned short __u16;
typedef unsigned char __u8;
#if defined(DEBUG_OSD) || defined(DEBUG_REMOTE)
#include <ncurses.h>
#endif
#include <stdio.h>
#include "../DVB/driver/dvb.h"
enum eDvbColor { clrBackground,
@ -36,56 +37,15 @@ enum eDvbColor { clrBackground,
clrWhite,
};
extern const char *DvbQuality; // Low, Medium, High
bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid);
class cDvbRecorder {
class cDvbApi {
private:
bool recording;
int videoDev;
public:
cDvbRecorder(void);
~cDvbRecorder();
bool Recording(void);
// Returns true if this recorder is currently recording, false if it
// is playing back or does nothing.
bool Record(const char *FileName, char Quality);
// Starts recording the current channel into the given file, with the
// given quality level. Any existing file will be overwritten.
// Returns true if recording was started successfully.
// If there is already a recording session active, false will be
// returned.
bool Play(const char *FileName, int Frame = 0);
// Starts playback of the given file, at the optional Frame (default
// is the beginning of the file). If Frame is beyond the last recorded
// frame in the file (or if it is negative), playback will be positioned
// to the last frame in the file (or the frame with the absolute value of
// Frame) and will do an implicit Pause() there.
// If there is already a playback session active, it will be stopped
// and the new file or frame (which may be in the same file) will
// be played back.
bool FastForward(void);
// Runs the current playback session forward at a higher speed.
// TODO allow different fast forward speeds???
bool FastRewind(void);
// Runs the current playback session backwards forward at a higher speed.
// TODO allow different fast rewind speeds???
bool Pause(void);
// Pauses the current recording or playback session, or resumes a paused
// session.
// Returns true if there is actually a recording or playback session
// active that was paused/resumed.
void Stop(void);
// Stops the current recording or playback session.
int Frame(void);
// Returns the number of the current frame in the current recording or
// playback session, which can be used to start playback at a given position.
// The number returned is the actual number of frames counted from the
// beginning of the current file.
// The very first frame has the number 1.
};
cDvbApi(void);
~cDvbApi();
// On Screen Display facilities
class cDvbOsd {
private:
enum { charWidth = 12, // average character width
lineHeight = 27 // smallest text height
@ -95,19 +55,70 @@ private:
enum { MaxColorPairs = 16 };
int colorPairs[MaxColorPairs];
void SetColor(eDvbColor colorFg, eDvbColor colorBg = clrBackground);
#else
void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL);
#endif
int cols, rows;
void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL);
public:
cDvbOsd(void);
~cDvbOsd();
void Open(int w, int h);
void Close(void);
void Clear(void);
void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground);
void ClrEol(int x, int y, eDvbColor color = clrBackground);
void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground);
// Channel facilities
bool SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr);
// Record/Replay facilities
private:
enum { dvbStop = 1, // let's not have 0 as a command
dvbPauseReplay,
dvbFastForward,
dvbFastRewind,
dvbSkip,
};
bool isMainProcess;
pid_t pidRecord, pidReplay;
int fromRecord, toRecord;
int fromReplay, toReplay;
void SetReplayMode(int Mode);
void KillProcess(pid_t pid);
public:
bool Recording(void);
// Returns true if we are currently recording.
bool Replaying(void);
// Returns true if we are currently replaying.
bool StartRecord(const char *FileName);
// Starts recording the current channel into the given file.
// In order to be able to record longer movies,
// a numerical suffix will be appended to the file name. The inital
// value of that suffix will be larger than any existing file under
// the given name, thus allowing an interrupted recording to continue
// gracefully.
// Returns true if recording was started successfully.
// If there is already a recording session active, false will be
// returned.
void StopRecord(void);
// Stops the current recording session (if any).
bool StartReplay(const char *FileName);
// Starts replaying the given file.
// If there is already a replay session active, it will be stopped
// and the new file will be played back.
void StopReplay(void);
// Stops the current replay session (if any).
void PauseReplay(void);
// Pauses the current replay session, or resumes a paused session.
void FastForward(void);
// Runs the current replay session forward at a higher speed.
void FastRewind(void);
// Runs the current replay session backwards at a higher speed.
void Skip(int Seconds);
// Skips the given number of seconds in the current replay session.
// The sign of 'Seconds' determines the direction in which to skip.
// Use a very large negative value to go all the way back to the
// beginning of the recording.
};
#endif //__DVBAPI_H

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: interface.c 1.2 2000/03/06 19:45:03 kls Exp $
* $Id: interface.c 1.3 2000/04/15 17:38:11 kls Exp $
*/
#include "interface.h"
@ -15,10 +15,10 @@
#define MenuColumns 40
#ifndef DEBUG_REMOTE
cRcIo RcIo("/dev/ttyS1");//XXX
cRcIo RcIo("/dev/ttyS1");
#endif
cDvbOsd DvbOsd; //XXX member of cInterface???
cDvbApi DvbApi; //XXX member of cInterface???
cInterface Interface;
@ -38,19 +38,22 @@ void cInterface::Init(void)
void cInterface::Open(void)
{
if (!open++)
DvbOsd.Open(MenuColumns, MenuLines);
DvbApi.Open(MenuColumns, MenuLines);
}
void cInterface::Close(void)
{
if (open == 1)
Clear();
if (!--open)
DvbOsd.Close();
DvbApi.Close();
}
unsigned int cInterface::GetCh(void)
{
#ifdef DEBUG_REMOTE
return getch();
int c = getch();
return (c > 0) ? c : 0;
#else
//XXX #ifdef DEBUG_OSD
//XXX wrefresh(window);//XXX
@ -80,13 +83,13 @@ eKeys cInterface::Wait(int Seconds)
void cInterface::Clear(void)
{
if (open)
DvbOsd.Clear();
DvbApi.Clear();
}
void cInterface::ClearEol(int x, int y, eDvbColor Color)
{
if (open)
DvbOsd.ClrEol(x, y, Color);
DvbApi.ClrEol(x, y, Color);
}
void cInterface::SetCols(int *c)
@ -101,7 +104,7 @@ void cInterface::SetCols(int *c)
void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor)
{
if (open)
DvbOsd.Text(x, y, s, FgColor, BgColor);
DvbApi.Text(x, y, s, FgColor, BgColor);
}
void cInterface::WriteText(int x, int y, const char *s, bool Current)
@ -187,8 +190,8 @@ void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvb
int l = (w - strlen(Text)) / 2;
if (l < 0)
l = 0;
DvbOsd.Fill(Index * w, -1, w, 1, BgColor);
DvbOsd.Text(Index * w + l, -1, Text, FgColor, BgColor);
DvbApi.Fill(Index * w, -1, w, 1, BgColor);
DvbApi.Text(Index * w + l, -1, Text, FgColor, BgColor);
}
}

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: interface.h 1.2 2000/02/27 14:54:02 kls Exp $
* $Id: interface.h 1.3 2000/03/19 14:03:28 kls Exp $
*/
#ifndef __INTERFACE_H
@ -45,5 +45,6 @@ public:
};
extern cInterface Interface;
extern cDvbApi DvbApi; //XXX member of cInterface???
#endif //__INTERFACE_H

Binary file not shown.

View File

@ -1,23 +0,0 @@
Code B
Address 0000
Up 000047E2
Down 000007E2
Menu 000011E2
Ok 000079E2
Back 00001AE2
Left 000005E2
Right 000045E2
0 00007FE2
1 00003FE2
2 00005FE2
3 00001FE2
4 00006FE2
5 00002FE2
6 00004FE2
7 00000FE2
8 000077E2
9 000037E2
Red 000025E2
Green 00002AE2
Yellow 00005AE2
Blue 00000000

29
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.2 2000/03/05 15:37:31 kls Exp $
* $Id: menu.c 1.3 2000/04/15 15:07:36 kls Exp $
*/
#include "menu.h"
@ -502,13 +502,15 @@ cMenuEditChannel::cMenuEditChannel(int Index)
channel = Channels.Get(Index);
if (channel) {
data = *channel;
Add(new cMenuEditStrItem("Name", data.name, sizeof(data.name), FileNameChars));
Add(new cMenuEditIntItem("Frequency", &data.frequency, 10000, 13000)); //TODO exact limits???
Add(new cMenuEditChrItem("Polarization", &data.polarization, "hv"));
Add(new cMenuEditIntItem("Diseqc", &data.diseqc, 0, 10)); //TODO exact limits???
Add(new cMenuEditIntItem("Srate", &data.srate, 22000, 27500)); //TODO exact limits - toggle???
Add(new cMenuEditIntItem("Vpid", &data.vpid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditIntItem("Apid", &data.apid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditStrItem( "Name", data.name, sizeof(data.name), FileNameChars));
Add(new cMenuEditIntItem( "Frequency", &data.frequency, 10000, 13000)); //TODO exact limits???
Add(new cMenuEditChrItem( "Polarization", &data.polarization, "hv"));
Add(new cMenuEditIntItem( "Diseqc", &data.diseqc, 0, 10)); //TODO exact limits???
Add(new cMenuEditIntItem( "Srate", &data.srate, 22000, 27500)); //TODO exact limits - toggle???
Add(new cMenuEditIntItem( "Vpid", &data.vpid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditIntItem( "Apid", &data.apid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditBoolItem("CA", &data.ca));
Add(new cMenuEditIntItem( "Pnr", &data.pnr, 0, 10000)); //TODO exact limits???
}
}
@ -599,7 +601,7 @@ eOSState cMenuChannels::Edit(void)
{
if (HasSubMenu() || Count() == 0)
return osContinue;
isyslog(LOG_INFO, "editing timer %d", Current() + 1);
isyslog(LOG_INFO, "editing channel %d", Current() + 1);
return AddSubMenu(new cMenuEditChannel(Current()));
}
@ -711,23 +713,24 @@ private:
cTimer *timer;
cTimer data;
public:
cMenuEditTimer(int Index);
cMenuEditTimer(int Index, bool New = false);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuEditTimer::cMenuEditTimer(int Index)
cMenuEditTimer::cMenuEditTimer(int Index, bool New)
:cOsdMenu("Edit Timer", 10)
{
timer = Timers.Get(Index);
if (timer) {
data = *timer;
if (New)
data.active = 1;
Add(new cMenuEditBoolItem("Active", &data.active));
Add(new cMenuEditChanItem("Channel", &data.channel));
Add(new cMenuEditDayItem( "Day", &data.day));
Add(new cMenuEditTimeItem("Start", &data.start));
Add(new cMenuEditTimeItem("Stop", &data.stop));
//TODO VPS???
Add(new cMenuEditChrItem( "Quality", &data.quality, DvbQuality));
Add(new cMenuEditIntItem( "Priority", &data.priority, 0, 99));
Add(new cMenuEditIntItem( "Lifetime", &data.lifetime, 0, 99));
Add(new cMenuEditStrItem( "File", data.file, sizeof(data.file), FileNameChars));
@ -843,7 +846,7 @@ eOSState cMenuTimers::New(void)
Add(new cMenuTimerItem(timer->Index()/*XXX*/, timer), true);
Timers.Save();
isyslog(LOG_INFO, "timer %d added", timer->Index() + 1);
return AddSubMenu(new cMenuEditTimer(Current()));
return AddSubMenu(new cMenuEditTimer(Current(), true));
}
eOSState cMenuTimers::Del(void)

150
osm.c
View File

@ -22,9 +22,10 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
* $Id: osm.c 1.2 2000/03/05 17:18:15 kls Exp $
* $Id: osm.c 1.3 2000/04/15 14:04:21 kls Exp $
*/
#include <signal.h>
#include "config.h"
#include "interface.h"
#include "menu.h"
@ -37,6 +38,13 @@
#define KEYS_CONF "keys.conf"
#endif
static int Interrupted = 0;
void SignalHandler(int signum)
{
Interrupted = signum;
}
int main(int argc, char *argv[])
{
openlog("vdr", LOG_PID | LOG_CONS, LOG_USER);
@ -50,69 +58,93 @@ int main(int argc, char *argv[])
cChannel::SwitchTo(CurrentChannel);
if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN);
if (signal(SIGINT, SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN);
if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
cMenuMain *Menu = NULL;
cTimer *Timer = NULL;
cRecording *Recording = NULL;
for (;;) {
AssertFreeDiskSpace();
if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) {
DELETENULL(Menu);
// make sure the timer won't be deleted:
Timer->SetRecording(true);
// switch to channel:
cChannel::SwitchTo(Timer->channel - 1);
ChannelLocked = true;
// start recording:
Recording = new cRecording(Timer);
if (!Recording->Record())
DELETENULL(Recording);
}
if (Timer && !Timer->Matches()) {
// stop recording:
if (Recording) {
Recording->Stop();
DELETENULL(Recording);
}
// release channel and timer:
ChannelLocked = false;
Timer->SetRecording(false);
// clear single event timer:
if (Timer->IsSingleEvent()) {
DELETENULL(Menu); // must make sure no menu uses it
isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1);
Timers.Del(Timer);
Timers.Save();
}
Timer = NULL;
}
eKeys key = Interface.GetKey();
if (Menu) {
switch (Menu->ProcessKey(key)) {
default: if (key != kMenu)
break;
case osBack:
case osEnd: DELETENULL(Menu);
break;
while (!Interrupted) {
AssertFreeDiskSpace();
if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) {
DELETENULL(Menu);
// make sure the timer won't be deleted:
Timer->SetRecording(true);
// switch to channel:
cChannel::SwitchTo(Timer->channel - 1);
// start recording:
Recording = new cRecording(Timer);
if (!Recording->Record())
DELETENULL(Recording);
}
}
else {
switch (key) {
case kMenu: Menu = new cMenuMain;
Menu->Display();
break;
case kUp:
case kDown: {
int n = CurrentChannel + (key == kUp ? 1 : -1);
cChannel *channel = Channels.Get(n);
if (channel)
channel->Switch();
}
break;
default: break;
if (Timer && !Timer->Matches()) {
// stop recording:
if (Recording) {
Recording->Stop();
DELETENULL(Recording);
}
// release timer:
Timer->SetRecording(false);
// clear single event timer:
if (Timer->IsSingleEvent()) {
DELETENULL(Menu); // must make sure no menu uses it
isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1);
Timers.Del(Timer);
Timers.Save();
}
Timer = NULL;
}
}
}
eKeys key = Interface.GetKey();
if (Menu) {
switch (Menu->ProcessKey(key)) {
default: if (key != kMenu)
break;
case osBack:
case osEnd: DELETENULL(Menu);
break;
}
}
else {
switch (key) {
// Record/Replay Control:
case kBegin: DvbApi.Skip(-INT_MAX); break;
case kRecord: if (!DvbApi.Recording()) {
cTimer *timer = new cTimer(true);
Timers.Add(timer);
Timers.Save();
}
else
Interface.Error("Already recording!");
break;
case kPause: DvbApi.PauseReplay(); break;
case kStop: DvbApi.StopReplay(); break;
case kSearchBack: DvbApi.FastRewind(); break;
case kSearchForward: DvbApi.FastForward(); break;
case kSkipBack: DvbApi.Skip(-60); break;
case kSkipForward: DvbApi.Skip(60); break;
// Menu Control:
case kMenu: Menu = new cMenuMain;
Menu->Display();
break;
case kUp:
case kDown: {
int n = CurrentChannel + (key == kUp ? 1 : -1);
cChannel *channel = Channels.Get(n);
if (channel)
channel->Switch();
}
break;
default: break;
}
}
}
isyslog(LOG_INFO, "caught signal %d", Interrupted);
DvbApi.StopRecord();
DvbApi.StopReplay();
//TODO kill any remaining sub-processes!
isyslog(LOG_INFO, "exiting", Interrupted);
closelog();
return 1;
return 0;
}

View File

@ -4,9 +4,10 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: recording.c 1.1 2000/03/05 17:16:22 kls Exp $
* $Id: recording.c 1.2 2000/04/15 13:29:02 kls Exp $
*/
#define _GNU_SOURCE
#include "recording.h"
#include <errno.h>
#include <stdio.h>
@ -16,17 +17,17 @@
#define RECEXT ".rec"
#define DELEXT ".del"
#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%c.%02d.%02d" RECEXT
#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT
#define NAMEFORMAT "%s/%s/" DATAFORMAT
#define FINDCMD "find %s -type f -name '%s'"
#define FINDCMD "find %s -type d -name '%s'"
#define DFCMD "df -m %s"
#define MINDISKSPACE 1024 // MB
const char *BaseDir = "/video";//XXX
#define DISKCHECKDELTA 300 // seconds between checks for free disk space
cDvbRecorder *Recorder = NULL;
const char *BaseDir = "/video";
static bool LowDiskSpace(void)
{
@ -58,51 +59,54 @@ void AssertFreeDiskSpace(void)
// With every call to this function we try to actually remove
// a file, or mark a file for removal ("delete" it), so that
// it will get removed during the next call.
if (Recorder && Recorder->Recording() && LowDiskSpace()) {
// Remove the oldest file that has been "deleted":
cRecordings Recordings;
if (Recordings.Load(true)) {
cRecording *r = Recordings.First();
cRecording *r0 = r;
while (r) {
if (r->start < r0->start)
r0 = r;
r = Recordings.Next(r);
}
if (r0 && r0->Remove())
return;
}
// No "deleted" files to remove, so let's see if we can delete a recording:
if (Recordings.Load(false)) {
cRecording *r = Recordings.First();
cRecording *r0 = NULL;
while (r) {
if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) {
if (r0) {
if (r->priority < r0->priority)
static time_t LastFreeDiskCheck = 0;
if (time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA) {
LastFreeDiskCheck = time(NULL);
if (DvbApi.Recording() && LowDiskSpace()) {
// Remove the oldest file that has been "deleted":
cRecordings Recordings;
if (Recordings.Load(true)) {
cRecording *r = Recordings.First();
cRecording *r0 = r;
while (r) {
if (r->start < r0->start)
r0 = r;
r = Recordings.Next(r);
}
if (r0 && r0->Remove())
return;
}
// No "deleted" files to remove, so let's see if we can delete a recording:
if (Recordings.Load(false)) {
cRecording *r = Recordings.First();
cRecording *r0 = NULL;
while (r) {
if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) {
if (r0) {
if (r->priority < r0->priority)
r0 = r;
}
else
r0 = r;
}
else
r0 = r;
r = Recordings.Next(r);
}
r = Recordings.Next(r);
}
if (r0 && r0->Delete())
return;
if (r0 && r0->Delete())
return;
}
// Unable to free disk space, but there's nothing we can do about that...
esyslog(LOG_ERR, "low disk space, but no recordings to delete");
}
// Unable to free disk space, but there's nothing we can do about that...
//TODO maybe a log entry - but make sure it doesn't come too often
}
}
// --- cRecording ------------------------------------------------------------
cRecording::cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime)
cRecording::cRecording(const char *Name, time_t Start, int Priority, int LifeTime)
{
fileName = NULL;
name = strdup(Name);
start = Start;
quality = Quality;
priority = Priority;
lifetime = LifeTime;
}
@ -112,7 +116,6 @@ cRecording::cRecording(cTimer *Timer)
fileName = NULL;
name = strdup(Timer->file);
start = Timer->StartTime();
quality = Timer->quality;
priority = Timer->priority;
lifetime = Timer->lifetime;
}
@ -127,7 +130,7 @@ cRecording::cRecording(const char *FileName)
if (p) {
time_t now = time(NULL);
struct tm t = *localtime(&now); // this initializes the time zone in 't'
if (8 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &quality, &priority, &lifetime)) {
if (7 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &priority, &lifetime)) {
t.tm_year -= 1900;
t.tm_mon--;
t.tm_sec = 0;
@ -149,7 +152,7 @@ const char *cRecording::FileName(void)
{
if (!fileName) {
struct tm *t = localtime(&start);
asprintf(&fileName, NAMEFORMAT, BaseDir, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, quality, priority, lifetime);
asprintf(&fileName, NAMEFORMAT, BaseDir, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime);
}
return fileName;
}
@ -163,7 +166,7 @@ bool cRecording::Delete(void)
strncpy(ext, DELEXT, strlen(ext));
isyslog(LOG_INFO, "deleting recording %s", FileName());
if (rename(FileName(), NewName) == -1) {
esyslog(LOG_ERR, "ERROR: %s", strerror(errno));
esyslog(LOG_ERR, "ERROR: %s: %s", FileName(), strerror(errno));
result = false;
}
}
@ -173,40 +176,23 @@ bool cRecording::Delete(void)
bool cRecording::Remove(void)
{
bool result = true;
isyslog(LOG_INFO, "removing recording %s", FileName());
if (remove(FileName()) == -1) {
esyslog(LOG_ERR, "ERROR: %s", strerror(errno));
result = false;
}
return result;
}
bool cRecording::AssertRecorder(void)
{
if (!Recorder || !Recorder->Recording()) {
if (!Recorder)
Recorder = new cDvbRecorder;
return true;
}
Interface.Error("Recorder is in use!");
return false;
return RemoveFileOrDir(FileName());
}
bool cRecording::Record(void)
{
return AssertRecorder() && Recorder->Record(FileName(), quality);
return DvbApi.StartRecord(FileName());
}
bool cRecording::Play(void)
{
return AssertRecorder() && Recorder->Play(FileName());
return DvbApi.StartReplay(FileName());
}
void cRecording::Stop(void)
{
if (Recorder)
Recorder->Stop();
DvbApi.StopRecord();
}
// --- cRecordings -----------------------------------------------------------

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: recording.h 1.1 2000/03/05 15:57:27 kls Exp $
* $Id: recording.h 1.2 2000/04/14 15:12:42 kls Exp $
*/
#ifndef __RECORDING_H
@ -15,21 +15,16 @@
#include "dvbapi.h"
#include "tools.h"
extern cDvbRecorder *Recorder;
void AssertFreeDiskSpace(void);
class cRecording : public cListObject {
private:
bool AssertRecorder(void);
public:
char *name;
char *fileName;
time_t start;
char quality;
int priority;
int lifetime;
cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime);
cRecording(const char *Name, time_t Start, int Priority, int LifeTime);
cRecording(cTimer *Timer);
cRecording(const char *FileName);
~cRecording();

View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: remote.c 1.1 2000/02/19 13:36:48 kls Exp $
* $Id: remote.c 1.2 2000/04/15 16:00:51 kls Exp $
*/
#include "remote.h"
@ -221,7 +221,7 @@ bool cRcIo::String(char *s)
}
}
}
return Number(n, mode == modeH);
return Number(n, true);
}
bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address)
@ -244,8 +244,11 @@ bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address)
String(buf);
SetCode(*Code, 0);
unsigned int Command;
if (GetCommand(&Command, Address))
if (GetCommand(&Command, Address)) {
SetMode(modeB);
String("----");
return true;
}
if (*Code < 'D') {
(*Code)++;
return false;

View File

@ -1,6 +1,9 @@
1:2:-----S-:2205:2320:H:99:99:Wochenshow
0:15:M------:2125:2205:H:99:99:Neues
1:15:MTWTF--:1828:1901:M:10:5:nano
1:3:M------:2110:2230:H:99:99:SevenDays
1:3:---T---:2215:2300:H:99:99:Switch
1:14:------S:2210:2255:H:99:99:Olli
1:15:MTWTF--:1828:1901:10:5:nano
1:3:M------:2110:2230:99:10:SevenDays
1:10:-T-----:2058:2150:99:10:Quarks
1:3:---T---:2158:2300:99:10:Switch
1:2:----F--:2110:2155:99:10:Anke
1:1:----F--:2210:2325:99:10:7Tage7Koepfe
1:15:-----S-:1358:1435:99:7:Neues
1:1:-----S-:1445:1600:99:10:Hammerman
1:2:-----S-:2205:2320:99:10:Wochenshow

91
tools.c
View File

@ -4,18 +4,46 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: tools.c 1.2 2000/03/05 14:33:58 kls Exp $
* $Id: tools.c 1.3 2000/04/15 15:10:05 kls Exp $
*/
#define _GNU_SOURCE
#include "tools.h"
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#define MaxBuffer 1000
int SysLogLevel = 3;
void writechar(int filedes, char c)
{
write(filedes, &c, sizeof(c));
}
void writeint(int filedes, int n)
{
write(filedes, &n, sizeof(n));
}
char readchar(int filedes)
{
char c;
read(filedes, &c, 1);
return c;
}
bool readint(int filedes, int &n)
{
//XXX timeout!!
return read(filedes, &n, sizeof(n));
}
char *readline(FILE *f)
{
static char buffer[MaxBuffer];
@ -30,36 +58,83 @@ char *readline(FILE *f)
int time_ms(void)
{
static time_t t0 = 0;
struct timeval t;
if (gettimeofday(&t, NULL) == 0)
return t.tv_sec * 1000 + t.tv_usec / 1000;
if (gettimeofday(&t, NULL) == 0) {
if (t0 == 0)
t0 = t.tv_sec; // this avoids an overflow (we only work with deltas)
return (t.tv_sec - t0) * 1000 + t.tv_usec / 1000;
}
return 0;
}
bool MakeDirs(const char *FileName)
void delay_ms(int ms)
{
int t0 = time_ms();
while (time_ms() - t0 < ms)
;
}
bool MakeDirs(const char *FileName, bool IsDirectory)
{
bool result = true;
char *s = strdup(FileName);
char *p = s;
if (*p == '/')
p++;
while ((p = strchr(p, '/')) != NULL) {
*p = 0;
while ((p = strchr(p, '/')) != NULL || IsDirectory) {
if (p)
*p = 0;
struct stat fs;
if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
isyslog(LOG_INFO, "creating directory %s", s);
if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) {
esyslog(LOG_ERR, "ERROR while creating directory %s: %s", s, strerror(errno));
esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno));
result = false;
break;
}
}
*p++ = '/';
if (p)
*p++ = '/';
else
break;
}
delete s;
return result;
}
bool RemoveFileOrDir(const char *FileName)
{
struct stat st;
if (stat(FileName, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
DIR *d = opendir(FileName);
if (d) {
struct dirent *e;
while ((e = readdir(d)) != NULL) {
if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
char *buffer;
asprintf(&buffer, "%s/%s", FileName, e->d_name);
if (remove(buffer) < 0)
esyslog(LOG_ERR, "ERROR: %s: %s", buffer, strerror(errno));
delete buffer;
}
}
closedir(d);
}
else {
esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno));
return false;
}
}
if (remove(FileName) == 0)
return true;
}
else
esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno));
return false;
}
// --- cListObject -----------------------------------------------------------
cListObject::cListObject(void)

24
tools.h
View File

@ -4,7 +4,7 @@
* See the main source file 'osm.c' for copyright information and
* how to reach the author.
*
* $Id: tools.h 1.2 2000/03/05 16:14:05 kls Exp $
* $Id: tools.h 1.3 2000/04/15 15:09:47 kls Exp $
*/
#ifndef __TOOLS_H
@ -13,18 +13,28 @@
#include <stdio.h>
#include <syslog.h>
//TODO
#define dsyslog syslog
#define esyslog syslog
#define isyslog syslog
extern int SysLogLevel;
#define esyslog if (SysLogLevel > 0) syslog
#define isyslog if (SysLogLevel > 1) syslog
#define dsyslog if (SysLogLevel > 2) syslog
#define LOG_ERROR esyslog(LOG_ERR, "ERROR (%s,%d): %s", __FILE__, __LINE__, strerror(errno))
#define LOG_ERROR_STR(s) esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno));
#define SECSINDAY 86400
#define DELETENULL(p) (delete (p), p = NULL)
void writechar(int filedes, char c);
void writeint(int filedes, int n);
char readchar(int filedes);
bool readint(int filedes, int &n);
char *readline(FILE *f);
int time_ms(void);
bool MakeDirs(const char *FileName);
void delay_ms(int ms);
bool MakeDirs(const char *FileName, bool IsDirectory = false);
bool RemoveFileOrDir(const char *FileName);
class cListObject {
private:
@ -47,7 +57,7 @@ public:
virtual ~cListBase();
void Add(cListObject *Object);
void Del(cListObject *Object);
void Move(int From, int To);
virtual void Move(int From, int To);
void Move(cListObject *From, cListObject *To);
void Clear(void);
cListObject *Get(int Index);