mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented actual record/replay; support for CICAM
This commit is contained in:
parent
571686d909
commit
735093b8fa
23
BUGS
Normal file
23
BUGS
Normal 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?
|
8
HISTORY
8
HISTORY
@ -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
39
MANUAL
Normal 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
72
README
@ -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
6
TODO
@ -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.
|
||||
|
218
channels.conf
218
channels.conf
@ -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
|
||||
|
51
config.c
51
config.c
@ -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"
|
||||
@ -37,6 +37,14 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
|
||||
{ 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 },
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
|
21
config.h
21
config.h
@ -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;
|
||||
|
121
dvbapi.h
121
dvbapi.h
@ -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
|
||||
|
25
interface.c
25
interface.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
BIN
keys-pc.conf
BIN
keys-pc.conf
Binary file not shown.
23
keys.conf
23
keys.conf
@ -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
|
15
menu.c
15
menu.c
@ -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"
|
||||
@ -509,6 +509,8 @@ cMenuEditChannel::cMenuEditChannel(int Index)
|
||||
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)
|
||||
|
44
osm.c
44
osm.c
@ -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,11 +58,15 @@ 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 (;;) {
|
||||
while (!Interrupted) {
|
||||
AssertFreeDiskSpace();
|
||||
if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) {
|
||||
DELETENULL(Menu);
|
||||
@ -62,7 +74,6 @@ int main(int argc, char *argv[])
|
||||
Timer->SetRecording(true);
|
||||
// switch to channel:
|
||||
cChannel::SwitchTo(Timer->channel - 1);
|
||||
ChannelLocked = true;
|
||||
// start recording:
|
||||
Recording = new cRecording(Timer);
|
||||
if (!Recording->Record())
|
||||
@ -74,8 +85,7 @@ int main(int argc, char *argv[])
|
||||
Recording->Stop();
|
||||
DELETENULL(Recording);
|
||||
}
|
||||
// release channel and timer:
|
||||
ChannelLocked = false;
|
||||
// release timer:
|
||||
Timer->SetRecording(false);
|
||||
// clear single event timer:
|
||||
if (Timer->IsSingleEvent()) {
|
||||
@ -98,6 +108,23 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
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;
|
||||
@ -113,6 +140,11 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
54
recording.c
54
recording.c
@ -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,7 +59,10 @@ 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()) {
|
||||
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)) {
|
||||
@ -91,18 +95,18 @@ void AssertFreeDiskSpace(void)
|
||||
return;
|
||||
}
|
||||
// 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
|
||||
esyslog(LOG_ERR, "low disk space, but no recordings to delete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 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 -----------------------------------------------------------
|
||||
|
@ -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();
|
||||
|
9
remote.c
9
remote.c
@ -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;
|
||||
|
15
timers.conf
15
timers.conf
@ -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
|
||||
|
87
tools.c
87
tools.c
@ -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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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
24
tools.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user