mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							
								
								
									
										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. | - Support for "Red", "Green", "Yellow", "Blue" buttons. | ||||||
| - Channels and Timers can now be added, deleted and moved. | - Channels and Timers can now be added, deleted and moved. | ||||||
| - Basic record/play file handling support (no actual record/playback yet). | - 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 | extracted into the directory /home/kls/vdr/DVB, then this | ||||||
| package should be extracted into /home/kls/vdr/OSM. | package should be extracted into /home/kls/vdr/OSM. | ||||||
|  |  | ||||||
| In order for the menu colors to work correctly you may want | This program requires the card driver version 0.04 or higher | ||||||
| to replace the function RGB2YUV() in DVB/driver/dvb.c with | to work properly. | ||||||
|  |  | ||||||
| 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). |  | ||||||
|  |  | ||||||
| After extracting the package, change into the OSM directory | After extracting the package, change into the OSM directory | ||||||
| and type 'make'. This should produce an executable file | and type 'make'. This should produce an executable file | ||||||
| named 'osm', which can be run after the DVB driver has been | named 'osm', which can be run after the DVB driver has been | ||||||
| installed. There may be several warnings about "implicit declaration | installed. | ||||||
| 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. |  | ||||||
|  |  | ||||||
| There are two macros you can use to customize the 'osm' program | There are two macros you can use to customize the 'osm' program | ||||||
| at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call | 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 | so for the moment please look at the source code (config.c) to see | ||||||
| the meaning of the various fields. | 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: | Learning the remote control keys: | ||||||
| --------------------------------- | --------------------------------- | ||||||
|  |  | ||||||
| The remote control configuration file 'keys.conf' that comes with | There is no default 'keys.conf' file, so if you compile the program | ||||||
| this package contains the codes for the "d-box" remote control unit. | without 'DEBUG_REMOTE=1' you will have to go through a "teach-in" | ||||||
| If you want to use a different remote control unit, simply delete | session that allows the program to learn your remote control codes. | ||||||
| the file 'keys.conf' and restart the 'osm' program. The program will | It will first attempt to determine the basic data transfer mode and | ||||||
| then start a key learning session in which it first attempts to determine | timing of your remote control unit, and then will ask you to press one | ||||||
| the basic data transfer mode and timing of your remote control unit, | key after the other so that it can learn the various key codes. You will | ||||||
| and then will ask you to press one key after the other so that it can | at least need to provide an "Up" and a "Down" key, so that you can switch | ||||||
| learn the various key codes. You will at least need to provide an "Up" | channels. The rest of the key definitions is optional, but the more keys | ||||||
| and a "Down" key, so that you can switch channels. The rest of the key | you define, the more you will be able to navigate through the menus and | ||||||
| definitions is optional, but the more keys you define, the more you | control recording/replaying. | ||||||
| will be able to navigate through the menus. |  | ||||||
|  |  | ||||||
| If the program has been built with "DEBUG_REMOTE=1", it will use the | 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 | key configuration file 'keys-pc.conf', so that you won't loose data | ||||||
| when switching between normal and debug mode. | 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: | Navigating through the On Screen Menus: | ||||||
| --------------------------------------- | --------------------------------------- | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								TODO
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| TODO list for the Video Disk Recorder project | 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 | * Make it work with two DVB-S PCI cards to allow simultaneous | ||||||
|   recording of one programme, while replaying another programme |   recording of one programme, while replaying another programme | ||||||
|   (or maybe the same one, but time delayed). |   (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 | * Implement "on-disk editing" to allow "cutting out" of certain | ||||||
|   scenes in order to archive them (or, reversely, cut out |   scenes in order to archive them (or, reversely, cut out | ||||||
|   commercial breaks). |   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 | RTL:12188:h:1:27500:163:104:0:0 | ||||||
| Sat.1:12552:v:1:22000:163:104 | Sat.1:12552:v:1:22000:163:104:0:0 | ||||||
| Pro 7:12480:v:1:27500:255:256 | Pro 7:12480:v:1:27500:255:256:0:0 | ||||||
| RTL2:12188:h:1:27500:166:128 | RTL2:12188:h:1:27500:166:128:0:0 | ||||||
| ARD:11837:h:1:27500:101:102 | ARD:11837:h:1:27500:101:102:0:0 | ||||||
| BR3:11837:h:1:27500:201:202 | BR3:11837:h:1:27500:201:202:0:0 | ||||||
| Hessen 3:11837:h:1:27500:301:302 | Hessen 3:11837:h:1:27500:301:302:0:0 | ||||||
| N3:11837:h:1:27500:401:402 | N3:11837:h:1:27500:401:402:0:0 | ||||||
| SR3:11837:h:1:27500:501:502 | SR3:11837:h:1:27500:501:502:0:0 | ||||||
| WDR:11837:h:1:27500:601:602 | WDR:11837:h:1:27500:601:602:0:0 | ||||||
| BR alpha:11837:h:1:27500:701:702 | BR alpha:11837:h:1:27500:701:702:0:0 | ||||||
| SWR BW:11837:h:1:27500:801:802 | SWR BW:11837:h:1:27500:801:802:0:0 | ||||||
| Phoenix:11837:h:1:27500:901:902 | Phoenix:11837:h:1:27500:901:902:0:0 | ||||||
| ZDF:11954:h:1:27500:110:120 | ZDF:11954:h:1:27500:110:120:0:0 | ||||||
| 3sat:11954:h:1:27500:210:220 | 3sat:11954:h:1:27500:210:220:0:0 | ||||||
| Kinderkanal:11954:h:1:27500:310:320 | Kinderkanal:11954:h:1:27500:310:320:0:0 | ||||||
| arte:11954:h:1:27500:360:370 | arte:11954:h:1:27500:360:370:0:0 | ||||||
| phoenix:11954:h:1:27500:410:420 | phoenix:11954:h:1:27500:410:420:0:0 | ||||||
| ORF Sat:11954:h:1:27500:506:507 | ORF Sat:11954:h:1:27500:506:507:0:0 | ||||||
| ZDF Infobox:11954:h:1:27500:610:620 | ZDF Infobox:11954:h:1:27500:610:620:0:0 | ||||||
| CNN:12168:v:1:27500:165:100 | CNN:12168:v:1:27500:165:100:0:0 | ||||||
| Super RTL:12188:h:1:27500:165:120 | Super RTL:12188:h:1:27500:165:120:0:0 | ||||||
| VOX:12188:h:1:27500:167:136 | VOX:12188:h:1:27500:167:136:0:0 | ||||||
| DW TV:12363:v:1:27500:305:306 | DW TV:12363:v:1:27500:305:306:0:0 | ||||||
| Kabel 1:12480:v:1:27500:511:512 | Kabel 1:12480:v:1:27500:511:512:0:0 | ||||||
| TM3:12480:v:1:27500:767:768 | TM3:12480:v:1:27500:767:768:0:0 | ||||||
| DSF:12480:v:1:27500:1023:1024 | DSF:12480:v:1:27500:1023:1024:0:0 | ||||||
| HOT:12480:v:1:27500:1279:1280 | HOT:12480:v:1:27500:1279:1280:0:0 | ||||||
| BloombergTV:12552:v:1:22000:162:99 | BloombergTV:12552:v:1:22000:162:99:0:0 | ||||||
| Sky News:12552:v:1:22000:305:306 | Sky News:12552:v:1:22000:305:306:0:0 | ||||||
| KinderNet:12574:h:1:22000:163:92 | KinderNet:12574:h:1:22000:163:92:0:0 | ||||||
| Alice:12610:v:1:22000:162:96 | Alice:12610:v:1:22000:162:96:0:0 | ||||||
| n-tv:12670:v:1:22000:162:96 | n-tv:12670:v:1:22000:162:96:0:0 | ||||||
| Grand Tour.:12670:v:1:22000:289:290 | Grand Tour.:12670:v:1:22000:289:290:0:0 | ||||||
| TW1:12692:h:1:22000:166:167 | TW1:12692:h:1:22000:166:167:0:0 | ||||||
| Eins Extra:12722:h:1:22000:101:102 | Eins Extra:12722:h:1:22000:101:102:0:0 | ||||||
| Eins Festival:12722:h:1:22000:201:202 | Eins Festival:12722:h:1:22000:201:202:0:0 | ||||||
| Eins MuXx:12722:h:1:22000:301:302 | Eins MuXx:12722:h:1:22000:301:302:0:0 | ||||||
| MDR:12722:h:1:22000:401:402 | MDR:12722:h:1:22000:401:402:0:0 | ||||||
| ORB:12722:h:1:22000:501:502 | ORB:12722:h:1:22000:501:502:0:0 | ||||||
| B1:12722:h:1:22000:601:602 | B1:12722:h:1:22000:601:602:0:0 | ||||||
| ARD Online-Kanal:12722:h:1:22000:8191:701 | ARD Online-Kanal:12722:h:1:22000:8191:701:0:0 | ||||||
| Premiere World Promo:11798:h:1:27500:255:256 | Premiere World Promo:11798:h:1:27500:255:256:0:0 | ||||||
| TV Niepokalanow:11876:h:1:27500:305:321 | TV Niepokalanow:11876:h:1:27500:305:321:0:0 | ||||||
| test card:11798:h:1:27500:511:512 | Premiere:11798:h:1:27500:1023:1024:1:10 | ||||||
| Mosaico:11934:v:1:27500:165:100 | Mosaico:11934:v:1:27500:165:100:0:0 | ||||||
| Andalucia TV:11934:v:1:27500:166:104 | Andalucia TV:11934:v:1:27500:166:104:0:0 | ||||||
| TVC Internacional:11934:v:1:27500:167:108 | TVC Internacional:11934:v:1:27500:167:108:0:0 | ||||||
| Nasza TV:11992:h:1:27500:165:98 | Nasza TV:11992:h:1:27500:165:98:0:0 | ||||||
| WishLine test:12012:v:1:27500:163:90 | WishLine test:12012:v:1:27500:163:90:0:0 | ||||||
| Pro 7 Austria:12051:v:1:27500:161:84 | Pro 7 Austria:12051:v:1:27500:161:84:0:0 | ||||||
| Kabel 1 Schweiz:12051:v:1:27500:162:163 | Kabel 1 Schweiz:12051:v:1:27500:162:163:0:0 | ||||||
| Kabel 1 Austria:12051:v:1:27500:166:167 | Kabel 1 Austria:12051:v:1:27500:166:167:0:0 | ||||||
| Pro 7 Schweiz:12051:v:1:27500:289:290 | Pro 7 Schweiz:12051:v:1:27500:289:290:0:0 | ||||||
| Kiosque:12129:v:1:27500:160:80 | Kiosque:12129:v:1:27500:160:80:0:0 | ||||||
| KTO:12129:v:1:27500:170:120 | KTO:12129:v:1:27500:170:120:0:0 | ||||||
| TCM:12168:v:1:27500:160:80 | TCM:12168:v:1:27500:160:80:0:0 | ||||||
| Cartoon Network France & Spain:12168:v:1:27500:161:84 | Cartoon Network France & Spain:12168:v:1:27500:161:84:0:0 | ||||||
| TVBS Europe:12168:v:1:27500:162:88 | TVBS Europe:12168:v:1:27500:162:88:0:0 | ||||||
| TVBS Europe:12168:v:1:27500:162:89 | TVBS Europe:12168:v:1:27500:162:89:0:0 | ||||||
| Travel:12168:v:1:27500:163:92 | Travel:12168:v:1:27500:163:92:0:0 | ||||||
| TCM Espania:12168:v:1:27500:164:96 | TCM Espania:12168:v:1:27500:164:96:0:0 | ||||||
| MTV Spain:12168:v:1:27500:167:112 | MTV Spain:12168:v:1:27500:167:112:0:0 | ||||||
| TCM France:12168:v:1:27500:169:64 | TCM France:12168:v:1:27500:169:64:0:0 | ||||||
| RTL2 CH:12188:h:1:27500:164:112 | RTL2 CH:12188:h:1:27500:164:112:0:0 | ||||||
| La Cinquieme:12207:v:1:27500:160:80 | La Cinquieme:12207:v:1:27500:160:80:0:0 | ||||||
| ARTE:12207:v:1:27500:165:100 | ARTE:12207:v:1:27500:165:100:0:0 | ||||||
| Post Filial TV:12226:h:1:27500:255:256 | Post Filial TV:12226:h:1:27500:255:256:0:0 | ||||||
| Canal Canaris:12246:v:1:27500:160:80 | Canal Canaris:12246:v:1:27500:160:80:0:0 | ||||||
| Canal Canaris:12246:v:1:27500:160:81 | Canal Canaris:12246:v:1:27500:160:81:0:0 | ||||||
| Canal Canaris:12246:v:1:27500:160:82 | Canal Canaris:12246:v:1:27500:160:82:0:0 | ||||||
| Canal Canaris:12246:v:1:27500:160:83 | Canal Canaris:12246:v:1:27500:160:83:0:0 | ||||||
| AB Sat Passion promo:12266:h:1:27500:160:80 | AB Sat Passion promo:12266:h:1:27500:160:80:0:0 | ||||||
| AB Channel 1:12266:h:1:27500:161:84 | AB Channel 1:12266:h:1:27500:161:84:0:0 | ||||||
| Taquilla 0:12285:v:1:27500:165:100 | Taquilla 0:12285:v:1:27500:165:100:0:0 | ||||||
| CSAT:12324:v:1:27500:160:80 | CSAT:12324:v:1:27500:160:80:0:0 | ||||||
| Mosaique:12324:v:1:27500:162:88 | Mosaique:12324:v:1:27500:162:88:0:0 | ||||||
| Mosaique 2:12324:v:1:27500:163:92 | Mosaique 2:12324:v:1:27500:163:92:0:0 | ||||||
| Mosaique 3:12324:v:1:27500:164:96 | Mosaique 3:12324:v:1:27500:164:96:0:0 | ||||||
| Le Sesame C+:12324:v:1:27500:165:1965 | Le Sesame C+:12324:v:1:27500:165:1965:0:0 | ||||||
| FEED:12344:h:1:27500:163:92 | FEED:12344:h:1:27500:163:92:0:0 | ||||||
| RTM 1:12363:v:1:27500:162:96 | RTM 1:12363:v:1:27500:162:96:0:0 | ||||||
| ESC 1:12363:v:1:27500:163:104 | ESC 1:12363:v:1:27500:163:104:0:0 | ||||||
| TV5 Europe:12363:v:1:27500:164:112 | TV5 Europe:12363:v:1:27500:164:112:0:0 | ||||||
| TV7 Tunisia:12363:v:1:27500:166:128 | TV7 Tunisia:12363:v:1:27500:166:128:0:0 | ||||||
| ARTE:12363:v:1:27500:167:137 | ARTE:12363:v:1:27500:167:137:0:0 | ||||||
| RAI Uno:12363:v:1:27500:289:290 | RAI Uno:12363:v:1:27500:289:290:0:0 | ||||||
| RTP International:12363:v:1:27500:300:301 | RTP International:12363:v:1:27500:300:301:0:0 | ||||||
| Fashion TV:12402:v:1:27500:163:92 | Fashion TV:12402:v:1:27500:163:92:0:0 | ||||||
| VideoService:12422:h:1:27500:255:256 | VideoService:12422:h:1:27500:255:256:0:0 | ||||||
| Beta Research promo:12422:h:1:27500:1023:1024 | Beta Research promo:12422:h:1:27500:1023:1024:0:0 | ||||||
| Canal Canarias:12441:v:1:27500:160:80 | Canal Canarias:12441:v:1:27500:160:80:0:0 | ||||||
| TVC International:12441:v:1:27500:512:660 | TVC International:12441:v:1:27500:512:660:0:0 | ||||||
| Fitur:12441:v:1:27500:514:662 | Fitur:12441:v:1:27500:514:662:0:0 | ||||||
| Astra Info 1:12552:v:1:22000:164:112 | Astra Info 1:12552:v:1:22000:164:112:0:0 | ||||||
| Astra Info 2:12552:v:1:22000:165:120 | Astra Info 2:12552:v:1:22000:165:120:0:0 | ||||||
| Astra Vision 1:12552:v:1:22000:168:144 | Astra Vision 1:12552:v:1:22000:168:144:0:0 | ||||||
| Astra Vision 1:12552:v:1:22000:168:145 | Astra Vision 1:12552:v:1:22000:168:145:0:0 | ||||||
| Astra Vision 1:12552:v:1:22000:168:146 | Astra Vision 1:12552:v:1:22000:168:146:0:0 | ||||||
| Astra Vision 1:12552:v:1:22000:168:147 | Astra Vision 1:12552:v:1:22000:168:147:0:0 | ||||||
| Astra Vision 1:12552:v:1:22000:168:148 | Astra Vision 1:12552:v:1:22000:168:148:0:0 | ||||||
| Astra Vision 1:12552:v:1:22000:168:149 | Astra Vision 1:12552:v:1:22000:168:149:0:0 | ||||||
| Astra Vision 1:12552:v:1:22000:168:150 | Astra Vision 1:12552:v:1:22000:168:150:0:0 | ||||||
| RTL Tele Letzebuerg:12552:v:1:22000:168:144 | RTL Tele Letzebuerg:12552:v:1:22000:168:144:0:0 | ||||||
| Astra Mosaic:12552:v:1:22000:175:176 | Astra Mosaic:12552:v:1:22000:175:176:0:0 | ||||||
| MHP test:12604:h:1:22000:5632:8191 | MHP test:12604:h:1:22000:5632:8191:0:0 | ||||||
| Bloomberg TV Spain:12610:v:1:22000:45:49 | Bloomberg TV Spain:12610:v:1:22000:45:49:0:0 | ||||||
| Video Italia:12610:v:1:22000:121:122 | Video Italia:12610:v:1:22000:121:122:0:0 | ||||||
| AC 3 promo:12670:v:1:22000:308:256 | 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 |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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" | #include "config.h" | ||||||
| @@ -37,6 +37,14 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! | |||||||
|                     { kGreen,         "Green",         0 }, |                     { kGreen,         "Green",         0 }, | ||||||
|                     { kYellow,        "Yellow",        0 }, |                     { kYellow,        "Yellow",        0 }, | ||||||
|                     { kBlue,          "Blue",          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 }, |                     { kNone,          "",              0 }, | ||||||
|                   }; |                   }; | ||||||
|  |  | ||||||
| @@ -88,7 +96,7 @@ bool cKeys::Load(char *FileName) | |||||||
|                               } |                               } | ||||||
|                            } |                            } | ||||||
|                         if (Name) { |                         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; |                            result = false; | ||||||
|                            break; |                            break; | ||||||
|                            } |                            } | ||||||
| @@ -96,17 +104,17 @@ bool cKeys::Load(char *FileName) | |||||||
|                     } |                     } | ||||||
|                  continue; |                  continue; | ||||||
|                  } |                  } | ||||||
|               fprintf(stderr, "error in %s, line %d\n", fileName, line); |               esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); | ||||||
|               result = false; |               result = false; | ||||||
|               break; |               break; | ||||||
|               } |               } | ||||||
|         fclose(f); |         fclose(f); | ||||||
|         } |         } | ||||||
|      else |      else | ||||||
|         fprintf(stderr, "can't open '%s'\n", fileName); |         esyslog(LOG_ERR, "can't open '%s'\n", fileName); | ||||||
|      } |      } | ||||||
|   else |   else | ||||||
|      fprintf(stderr, "no key configuration file name supplied!\n"); |      esyslog(LOG_ERR, "no key configuration file name supplied!\n"); | ||||||
|   return result; |   return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -172,12 +180,14 @@ cChannel::cChannel(const cChannel *Channel) | |||||||
|   srate        = Channel ? Channel->srate        : 27500; |   srate        = Channel ? Channel->srate        : 27500; | ||||||
|   vpid         = Channel ? Channel->vpid         : 255; |   vpid         = Channel ? Channel->vpid         : 255; | ||||||
|   apid         = Channel ? Channel->apid         : 256; |   apid         = Channel ? Channel->apid         : 256; | ||||||
|  |   ca           = Channel ? Channel->ca           : 0; | ||||||
|  |   pnr          = Channel ? Channel->pnr          : 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool cChannel::Parse(char *s) | bool cChannel::Parse(char *s) | ||||||
| { | { | ||||||
|   char *buffer = NULL; |   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); |      strncpy(name, buffer, MaxChannelName - 1); | ||||||
|      name[strlen(buffer)] = 0; |      name[strlen(buffer)] = 0; | ||||||
|      delete buffer; |      delete buffer; | ||||||
| @@ -188,20 +198,21 @@ bool cChannel::Parse(char *s) | |||||||
|  |  | ||||||
| bool cChannel::Save(FILE *f) | 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) | bool cChannel::Switch(void) | ||||||
| { | { | ||||||
|   if (!ChannelLocked) { |   if (!DvbApi.Recording()) { | ||||||
|      isyslog(LOG_INFO, "switching to channel %d", Index() + 1); |      isyslog(LOG_INFO, "switching to channel %d", Index() + 1); | ||||||
|      CurrentChannel = Index(); |      CurrentChannel = Index(); | ||||||
|      Interface.DisplayChannel(CurrentChannel + 1, name); |      Interface.DisplayChannel(CurrentChannel + 1, name); | ||||||
|      for (int i = 3; --i;) { |      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; |             return true; | ||||||
|          esyslog(LOG_ERR, "retrying"); |          esyslog(LOG_ERR, "retrying"); | ||||||
|          } |          } | ||||||
|  |      return false; | ||||||
|      } |      } | ||||||
|   Interface.Info("Channel locked (recording)!"); |   Interface.Info("Channel locked (recording)!"); | ||||||
|   return false; |   return false; | ||||||
| @@ -215,20 +226,23 @@ bool cChannel::SwitchTo(int i) | |||||||
|  |  | ||||||
| // -- cTimer ----------------------------------------------------------------- | // -- cTimer ----------------------------------------------------------------- | ||||||
|  |  | ||||||
| cTimer::cTimer(void) | cTimer::cTimer(bool Instant) | ||||||
| { | { | ||||||
|   startTime = stopTime = 0; |   startTime = stopTime = 0; | ||||||
|   recording = false; |   recording = false; | ||||||
|   active = 1; |   active = Instant; | ||||||
|   channel = CurrentChannel + 1; |   channel = CurrentChannel + 1; | ||||||
|   day = 1; //XXX today! |   time_t t = time(NULL); | ||||||
|   start = 0; //XXX now! |   struct tm *now = localtime(&t); | ||||||
|   stop = 0; //XXX now + 2h! |   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??? | //TODO VPS??? | ||||||
|   quality = 'H'; |  | ||||||
|   priority = 99; |   priority = 99; | ||||||
|   lifetime = 99; |   lifetime = 99; | ||||||
|   *file = 0; |   strcpy(file, Instant ? "instant" : ""); | ||||||
| } | } | ||||||
|  |  | ||||||
| int cTimer::TimeToInt(int t) | int cTimer::TimeToInt(int t) | ||||||
| @@ -286,7 +300,7 @@ bool cTimer::Parse(char *s) | |||||||
| { | { | ||||||
|   char *buffer1 = NULL; |   char *buffer1 = NULL; | ||||||
|   char *buffer2 = 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); |      day = ParseDay(buffer1); | ||||||
|      strncpy(file, buffer2, MaxFileName - 1); |      strncpy(file, buffer2, MaxFileName - 1); | ||||||
|      file[strlen(buffer2)] = 0; |      file[strlen(buffer2)] = 0; | ||||||
| @@ -299,7 +313,7 @@ bool cTimer::Parse(char *s) | |||||||
|  |  | ||||||
| bool cTimer::Save(FILE *f) | 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) | bool cTimer::IsSingleEvent(void) | ||||||
| @@ -383,7 +397,6 @@ cKeys Keys; | |||||||
| // -- cChannels -------------------------------------------------------------- | // -- cChannels -------------------------------------------------------------- | ||||||
|  |  | ||||||
| int CurrentChannel = 0; | int CurrentChannel = 0; | ||||||
| bool ChannelLocked = false; |  | ||||||
|  |  | ||||||
| cChannels Channels; | cChannels Channels; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								config.h
									
									
									
									
									
								
							| @@ -4,12 +4,13 @@ | |||||||
|  * See the main source file 'osm.c' for copyright information and |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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 | #ifndef __CONFIG_H | ||||||
| #define __CONFIG_H | #define __CONFIG_H | ||||||
|  |  | ||||||
|  | #define _GNU_SOURCE | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <time.h> | #include <time.h> | ||||||
| @@ -30,6 +31,14 @@ enum eKeys { // "Up" and "Down" must be the first two keys! | |||||||
|              kGreen, |              kGreen, | ||||||
|              kYellow, |              kYellow, | ||||||
|              kBlue, |              kBlue, | ||||||
|  |              kRecord, | ||||||
|  |              kPause, | ||||||
|  |              kStop, | ||||||
|  |              kBegin, | ||||||
|  |              kSearchForward, | ||||||
|  |              kSearchBack, | ||||||
|  |              kSkipForward, | ||||||
|  |              kSkipBack, | ||||||
|              kNone |              kNone | ||||||
|            }; |            }; | ||||||
|  |  | ||||||
| @@ -64,6 +73,8 @@ public: | |||||||
|   int srate; |   int srate; | ||||||
|   int vpid; |   int vpid; | ||||||
|   int apid; |   int apid; | ||||||
|  |   int ca; | ||||||
|  |   int pnr; | ||||||
|   cChannel(void); |   cChannel(void); | ||||||
|   cChannel(const cChannel *Channel); |   cChannel(const cChannel *Channel); | ||||||
|   bool Parse(char *s); |   bool Parse(char *s); | ||||||
| @@ -84,11 +95,10 @@ public: | |||||||
|   int start; |   int start; | ||||||
|   int stop; |   int stop; | ||||||
| //TODO VPS??? | //TODO VPS??? | ||||||
|   char quality; |  | ||||||
|   int priority; |   int priority; | ||||||
|   int lifetime; |   int lifetime; | ||||||
|   char file[MaxFileName]; |   char file[MaxFileName]; | ||||||
|   cTimer(void); |   cTimer(bool Instant = false); | ||||||
|   bool Parse(char *s); |   bool Parse(char *s); | ||||||
|   bool Save(FILE *f); |   bool Save(FILE *f); | ||||||
|   bool IsSingleEvent(void); |   bool IsSingleEvent(void); | ||||||
| @@ -128,7 +138,7 @@ public: | |||||||
|              if (l->Parse(buffer)) |              if (l->Parse(buffer)) | ||||||
|                 Add(l); |                 Add(l); | ||||||
|              else { |              else { | ||||||
|                 fprintf(stderr, "error in %s, line %d\n", fileName, line); |                 esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); | ||||||
|                 delete l; |                 delete l; | ||||||
|                 result = false; |                 result = false; | ||||||
|                 break; |                 break; | ||||||
| @@ -137,7 +147,7 @@ public: | |||||||
|        fclose(f); |        fclose(f); | ||||||
|        } |        } | ||||||
|     else { |     else { | ||||||
|        fprintf(stderr, "can't open '%s'\n", fileName); |        esyslog(LOG_ERR, "can't open '%s'\n", fileName); | ||||||
|        result = false; |        result = false; | ||||||
|        } |        } | ||||||
|     return result; |     return result; | ||||||
| @@ -168,7 +178,6 @@ class cChannels : public cConfig<cChannel> {}; | |||||||
| class cTimers : public cConfig<cTimer> {}; | class cTimers : public cConfig<cTimer> {}; | ||||||
|  |  | ||||||
| extern int CurrentChannel; | extern int CurrentChannel; | ||||||
| extern bool ChannelLocked; |  | ||||||
|  |  | ||||||
| extern cChannels Channels; | extern cChannels Channels; | ||||||
| extern cTimers Timers; | extern cTimers Timers; | ||||||
|   | |||||||
							
								
								
									
										121
									
								
								dvbapi.h
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								dvbapi.h
									
									
									
									
									
								
							| @@ -4,20 +4,21 @@ | |||||||
|  * See the main source file 'osm.c' for copyright information and |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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 | #ifndef __DVBAPI_H | ||||||
| #define __DVBAPI_H | #define __DVBAPI_H | ||||||
|  |  | ||||||
| // FIXME: these should be defined in ../DVB/driver/dvb.h!!! | // FIXME: these should be defined in ../DVB/driver/dvb.h!!! | ||||||
| typedef unsigned int u32; | typedef unsigned int __u32; | ||||||
| typedef unsigned short u16; | typedef unsigned short __u16; | ||||||
| typedef unsigned char u8; | typedef unsigned char __u8; | ||||||
|  |  | ||||||
| #if defined(DEBUG_OSD) || defined(DEBUG_REMOTE) | #if defined(DEBUG_OSD) || defined(DEBUG_REMOTE) | ||||||
| #include <ncurses.h> | #include <ncurses.h> | ||||||
| #endif | #endif | ||||||
|  | #include <stdio.h> | ||||||
| #include "../DVB/driver/dvb.h" | #include "../DVB/driver/dvb.h" | ||||||
|  |  | ||||||
| enum eDvbColor { clrBackground, | enum eDvbColor { clrBackground, | ||||||
| @@ -36,56 +37,15 @@ enum eDvbColor { clrBackground, | |||||||
|                  clrWhite, |                  clrWhite, | ||||||
|                }; |                }; | ||||||
|                    |                    | ||||||
| extern const char *DvbQuality; // Low, Medium, High | class cDvbApi { | ||||||
|  |  | ||||||
| bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid); |  | ||||||
|  |  | ||||||
| class cDvbRecorder { |  | ||||||
| private: | private: | ||||||
|   bool recording; |   int videoDev; | ||||||
| public: | public: | ||||||
|   cDvbRecorder(void); |   cDvbApi(void); | ||||||
|   ~cDvbRecorder(); |   ~cDvbApi(); | ||||||
|   bool Recording(void); |  | ||||||
|        // Returns true if this recorder is currently recording, false if it |   // On Screen Display facilities | ||||||
|        // 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. |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
| class cDvbOsd { |  | ||||||
| private: | private: | ||||||
|   enum { charWidth  = 12, // average character width |   enum { charWidth  = 12, // average character width | ||||||
|          lineHeight = 27  // smallest text height |          lineHeight = 27  // smallest text height | ||||||
| @@ -95,19 +55,70 @@ private: | |||||||
|   enum { MaxColorPairs = 16 }; |   enum { MaxColorPairs = 16 }; | ||||||
|   int colorPairs[MaxColorPairs]; |   int colorPairs[MaxColorPairs]; | ||||||
|   void SetColor(eDvbColor colorFg, eDvbColor colorBg = clrBackground); |   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 | #endif | ||||||
|   int cols, rows; |   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: | public: | ||||||
|   cDvbOsd(void); |  | ||||||
|   ~cDvbOsd(); |  | ||||||
|   void Open(int w, int h); |   void Open(int w, int h); | ||||||
|   void Close(void); |   void Close(void); | ||||||
|   void Clear(void); |   void Clear(void); | ||||||
|   void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground); |   void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground); | ||||||
|   void ClrEol(int x, int y, 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); |   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 | #endif //__DVBAPI_H | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								interface.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								interface.c
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | |||||||
|  * See the main source file 'osm.c' for copyright information and |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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" | #include "interface.h" | ||||||
| @@ -15,10 +15,10 @@ | |||||||
| #define MenuColumns 40 | #define MenuColumns 40 | ||||||
|  |  | ||||||
| #ifndef DEBUG_REMOTE | #ifndef DEBUG_REMOTE | ||||||
| cRcIo RcIo("/dev/ttyS1");//XXX | cRcIo RcIo("/dev/ttyS1"); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| cDvbOsd DvbOsd; //XXX member of cInterface??? | cDvbApi DvbApi; //XXX member of cInterface??? | ||||||
|  |  | ||||||
| cInterface Interface; | cInterface Interface; | ||||||
|  |  | ||||||
| @@ -38,19 +38,22 @@ void cInterface::Init(void) | |||||||
| void cInterface::Open(void) | void cInterface::Open(void) | ||||||
| { | { | ||||||
|   if (!open++) |   if (!open++) | ||||||
|      DvbOsd.Open(MenuColumns, MenuLines); |      DvbApi.Open(MenuColumns, MenuLines); | ||||||
| } | } | ||||||
|  |  | ||||||
| void cInterface::Close(void) | void cInterface::Close(void) | ||||||
| { | { | ||||||
|  |   if (open == 1) | ||||||
|  |      Clear(); | ||||||
|   if (!--open) |   if (!--open) | ||||||
|      DvbOsd.Close(); |      DvbApi.Close(); | ||||||
| } | } | ||||||
|  |  | ||||||
| unsigned int cInterface::GetCh(void) | unsigned int cInterface::GetCh(void) | ||||||
| { | { | ||||||
| #ifdef DEBUG_REMOTE | #ifdef DEBUG_REMOTE | ||||||
|   return getch(); |   int c = getch(); | ||||||
|  |   return (c > 0) ? c : 0; | ||||||
| #else | #else | ||||||
| //XXX #ifdef DEBUG_OSD | //XXX #ifdef DEBUG_OSD | ||||||
| //XXX   wrefresh(window);//XXX | //XXX   wrefresh(window);//XXX | ||||||
| @@ -80,13 +83,13 @@ eKeys cInterface::Wait(int Seconds) | |||||||
| void cInterface::Clear(void) | void cInterface::Clear(void) | ||||||
| { | { | ||||||
|   if (open) |   if (open) | ||||||
|      DvbOsd.Clear(); |      DvbApi.Clear(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void cInterface::ClearEol(int x, int y, eDvbColor Color) | void cInterface::ClearEol(int x, int y, eDvbColor Color) | ||||||
| { | { | ||||||
|   if (open) |   if (open) | ||||||
|      DvbOsd.ClrEol(x, y, Color); |      DvbApi.ClrEol(x, y, Color); | ||||||
| } | } | ||||||
|  |  | ||||||
| void cInterface::SetCols(int *c) | 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) | void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor) | ||||||
| { | { | ||||||
|   if (open) |   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) | 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; |      int l = (w - strlen(Text)) / 2; | ||||||
|      if (l < 0) |      if (l < 0) | ||||||
|         l = 0; |         l = 0; | ||||||
|      DvbOsd.Fill(Index * w, -1, w, 1, BgColor); |      DvbApi.Fill(Index * w, -1, w, 1, BgColor); | ||||||
|      DvbOsd.Text(Index * w + l, -1, Text, FgColor, 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 |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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 | #ifndef __INTERFACE_H | ||||||
| @@ -45,5 +45,6 @@ public: | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
| extern cInterface Interface; | extern cInterface Interface; | ||||||
|  | extern cDvbApi DvbApi; //XXX member of cInterface??? | ||||||
|  |  | ||||||
| #endif //__INTERFACE_H | #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 |  | ||||||
							
								
								
									
										29
									
								
								menu.c
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								menu.c
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | |||||||
|  * See the main source file 'osm.c' for copyright information and |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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" | #include "menu.h" | ||||||
| @@ -502,13 +502,15 @@ cMenuEditChannel::cMenuEditChannel(int Index) | |||||||
|   channel = Channels.Get(Index); |   channel = Channels.Get(Index); | ||||||
|   if (channel) { |   if (channel) { | ||||||
|      data = *channel; |      data = *channel; | ||||||
|      Add(new cMenuEditStrItem("Name",          data.name, sizeof(data.name), FileNameChars)); |      Add(new cMenuEditStrItem( "Name",          data.name, sizeof(data.name), FileNameChars)); | ||||||
|      Add(new cMenuEditIntItem("Frequency",    &data.frequency, 10000, 13000)); //TODO exact limits??? |      Add(new cMenuEditIntItem( "Frequency",    &data.frequency, 10000, 13000)); //TODO exact limits??? | ||||||
|      Add(new cMenuEditChrItem("Polarization", &data.polarization, "hv")); |      Add(new cMenuEditChrItem( "Polarization", &data.polarization, "hv")); | ||||||
|      Add(new cMenuEditIntItem("Diseqc",       &data.diseqc, 0, 10)); //TODO exact limits??? |      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( "Srate",        &data.srate, 22000, 27500)); //TODO exact limits - toggle??? | ||||||
|      Add(new cMenuEditIntItem("Vpid",         &data.vpid, 0, 10000)); //TODO exact limits??? |      Add(new cMenuEditIntItem( "Vpid",         &data.vpid, 0, 10000)); //TODO exact limits??? | ||||||
|      Add(new cMenuEditIntItem("Apid",         &data.apid, 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) |   if (HasSubMenu() || Count() == 0) | ||||||
|      return osContinue; |      return osContinue; | ||||||
|   isyslog(LOG_INFO, "editing timer %d", Current() + 1); |   isyslog(LOG_INFO, "editing channel %d", Current() + 1); | ||||||
|   return AddSubMenu(new cMenuEditChannel(Current())); |   return AddSubMenu(new cMenuEditChannel(Current())); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -711,23 +713,24 @@ private: | |||||||
|   cTimer *timer; |   cTimer *timer; | ||||||
|   cTimer data; |   cTimer data; | ||||||
| public: | public: | ||||||
|   cMenuEditTimer(int Index); |   cMenuEditTimer(int Index, bool New = false); | ||||||
|   virtual eOSState ProcessKey(eKeys Key); |   virtual eOSState ProcessKey(eKeys Key); | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
| cMenuEditTimer::cMenuEditTimer(int Index) | cMenuEditTimer::cMenuEditTimer(int Index, bool New) | ||||||
| :cOsdMenu("Edit Timer", 10) | :cOsdMenu("Edit Timer", 10) | ||||||
| { | { | ||||||
|   timer = Timers.Get(Index); |   timer = Timers.Get(Index); | ||||||
|   if (timer) { |   if (timer) { | ||||||
|      data = *timer; |      data = *timer; | ||||||
|  |      if (New) | ||||||
|  |         data.active = 1; | ||||||
|      Add(new cMenuEditBoolItem("Active",       &data.active)); |      Add(new cMenuEditBoolItem("Active",       &data.active)); | ||||||
|      Add(new cMenuEditChanItem("Channel",      &data.channel));  |      Add(new cMenuEditChanItem("Channel",      &data.channel));  | ||||||
|      Add(new cMenuEditDayItem( "Day",          &data.day));  |      Add(new cMenuEditDayItem( "Day",          &data.day));  | ||||||
|      Add(new cMenuEditTimeItem("Start",        &data.start));  |      Add(new cMenuEditTimeItem("Start",        &data.start));  | ||||||
|      Add(new cMenuEditTimeItem("Stop",         &data.stop));  |      Add(new cMenuEditTimeItem("Stop",         &data.stop));  | ||||||
| //TODO VPS??? | //TODO VPS??? | ||||||
|      Add(new cMenuEditChrItem( "Quality",      &data.quality, DvbQuality)); |  | ||||||
|      Add(new cMenuEditIntItem( "Priority",     &data.priority, 0, 99)); |      Add(new cMenuEditIntItem( "Priority",     &data.priority, 0, 99)); | ||||||
|      Add(new cMenuEditIntItem( "Lifetime",     &data.lifetime, 0, 99)); |      Add(new cMenuEditIntItem( "Lifetime",     &data.lifetime, 0, 99)); | ||||||
|      Add(new cMenuEditStrItem( "File",          data.file, sizeof(data.file), FileNameChars)); |      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); |   Add(new cMenuTimerItem(timer->Index()/*XXX*/, timer), true); | ||||||
|   Timers.Save(); |   Timers.Save(); | ||||||
|   isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); |   isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); | ||||||
|   return AddSubMenu(new cMenuEditTimer(Current())); |   return AddSubMenu(new cMenuEditTimer(Current(), true)); | ||||||
| } | } | ||||||
|  |  | ||||||
| eOSState cMenuTimers::Del(void) | 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 |  * 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 "config.h" | ||||||
| #include "interface.h" | #include "interface.h" | ||||||
| #include "menu.h" | #include "menu.h" | ||||||
| @@ -37,6 +38,13 @@ | |||||||
| #define KEYS_CONF "keys.conf" | #define KEYS_CONF "keys.conf" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | static int Interrupted = 0; | ||||||
|  |  | ||||||
|  | void SignalHandler(int signum) | ||||||
|  | { | ||||||
|  |   Interrupted = signum; | ||||||
|  | } | ||||||
|  |  | ||||||
| int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||||||
| { | { | ||||||
|   openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); |   openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); | ||||||
| @@ -50,11 +58,15 @@ int main(int argc, char *argv[]) | |||||||
|  |  | ||||||
|   cChannel::SwitchTo(CurrentChannel); |   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; |   cMenuMain *Menu = NULL; | ||||||
|   cTimer *Timer = NULL; |   cTimer *Timer = NULL; | ||||||
|   cRecording *Recording = NULL; |   cRecording *Recording = NULL; | ||||||
|  |  | ||||||
|   for (;;) { |   while (!Interrupted) { | ||||||
|         AssertFreeDiskSpace(); |         AssertFreeDiskSpace(); | ||||||
|         if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) { |         if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) { | ||||||
|            DELETENULL(Menu); |            DELETENULL(Menu); | ||||||
| @@ -62,7 +74,6 @@ int main(int argc, char *argv[]) | |||||||
|            Timer->SetRecording(true); |            Timer->SetRecording(true); | ||||||
|            // switch to channel: |            // switch to channel: | ||||||
|            cChannel::SwitchTo(Timer->channel - 1); |            cChannel::SwitchTo(Timer->channel - 1); | ||||||
|          ChannelLocked = true; |  | ||||||
|            // start recording: |            // start recording: | ||||||
|            Recording = new cRecording(Timer); |            Recording = new cRecording(Timer); | ||||||
|            if (!Recording->Record()) |            if (!Recording->Record()) | ||||||
| @@ -74,8 +85,7 @@ int main(int argc, char *argv[]) | |||||||
|               Recording->Stop(); |               Recording->Stop(); | ||||||
|               DELETENULL(Recording); |               DELETENULL(Recording); | ||||||
|               } |               } | ||||||
|          // release channel and timer: |            // release timer: | ||||||
|          ChannelLocked = false; |  | ||||||
|            Timer->SetRecording(false); |            Timer->SetRecording(false); | ||||||
|            // clear single event timer: |            // clear single event timer: | ||||||
|            if (Timer->IsSingleEvent()) { |            if (Timer->IsSingleEvent()) { | ||||||
| @@ -98,6 +108,23 @@ int main(int argc, char *argv[]) | |||||||
|            } |            } | ||||||
|         else { |         else { | ||||||
|            switch (key) { |            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; |              case kMenu: Menu = new cMenuMain; | ||||||
|                          Menu->Display(); |                          Menu->Display(); | ||||||
|                          break; |                          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(); |   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 |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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 "recording.h" | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| @@ -16,17 +17,17 @@ | |||||||
|  |  | ||||||
| #define RECEXT       ".rec" | #define RECEXT       ".rec" | ||||||
| #define DELEXT       ".del" | #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 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 DFCMD        "df -m %s" | ||||||
| #define MINDISKSPACE 1024 // MB | #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) | static bool LowDiskSpace(void) | ||||||
| { | { | ||||||
| @@ -58,7 +59,10 @@ void AssertFreeDiskSpace(void) | |||||||
|   // With every call to this function we try to actually remove |   // With every call to this function we try to actually remove | ||||||
|   // a file, or mark a file for removal ("delete" it), so that |   // a file, or mark a file for removal ("delete" it), so that | ||||||
|   // it will get removed during the next call. |   // 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": |         // Remove the oldest file that has been "deleted": | ||||||
|         cRecordings Recordings; |         cRecordings Recordings; | ||||||
|         if (Recordings.Load(true)) { |         if (Recordings.Load(true)) { | ||||||
| @@ -91,18 +95,18 @@ void AssertFreeDiskSpace(void) | |||||||
|               return; |               return; | ||||||
|            } |            } | ||||||
|         // Unable to free disk space, but there's nothing we can do about that... |         // 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::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; |   fileName = NULL; | ||||||
|   name = strdup(Name); |   name = strdup(Name); | ||||||
|   start = Start; |   start = Start; | ||||||
|   quality = Quality; |  | ||||||
|   priority = Priority; |   priority = Priority; | ||||||
|   lifetime = LifeTime; |   lifetime = LifeTime; | ||||||
| } | } | ||||||
| @@ -112,7 +116,6 @@ cRecording::cRecording(cTimer *Timer) | |||||||
|   fileName = NULL; |   fileName = NULL; | ||||||
|   name = strdup(Timer->file); |   name = strdup(Timer->file); | ||||||
|   start = Timer->StartTime(); |   start = Timer->StartTime(); | ||||||
|   quality = Timer->quality; |  | ||||||
|   priority = Timer->priority; |   priority = Timer->priority; | ||||||
|   lifetime = Timer->lifetime; |   lifetime = Timer->lifetime; | ||||||
| } | } | ||||||
| @@ -127,7 +130,7 @@ cRecording::cRecording(const char *FileName) | |||||||
|   if (p) { |   if (p) { | ||||||
|      time_t now = time(NULL); |      time_t now = time(NULL); | ||||||
|      struct tm t = *localtime(&now); // this initializes the time zone in 't' |      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_year -= 1900; | ||||||
|         t.tm_mon--; |         t.tm_mon--; | ||||||
|         t.tm_sec = 0; |         t.tm_sec = 0; | ||||||
| @@ -149,7 +152,7 @@ const char *cRecording::FileName(void) | |||||||
| { | { | ||||||
|   if (!fileName) { |   if (!fileName) { | ||||||
|      struct tm *t = localtime(&start); |      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; |   return fileName; | ||||||
| } | } | ||||||
| @@ -163,7 +166,7 @@ bool cRecording::Delete(void) | |||||||
|      strncpy(ext, DELEXT, strlen(ext)); |      strncpy(ext, DELEXT, strlen(ext)); | ||||||
|      isyslog(LOG_INFO, "deleting recording %s", FileName()); |      isyslog(LOG_INFO, "deleting recording %s", FileName()); | ||||||
|      if (rename(FileName(), NewName) == -1) { |      if (rename(FileName(), NewName) == -1) { | ||||||
|         esyslog(LOG_ERR, "ERROR: %s", strerror(errno)); |         esyslog(LOG_ERR, "ERROR: %s: %s", FileName(), strerror(errno)); | ||||||
|         result = false; |         result = false; | ||||||
|         } |         } | ||||||
|      } |      } | ||||||
| @@ -173,40 +176,23 @@ bool cRecording::Delete(void) | |||||||
|  |  | ||||||
| bool cRecording::Remove(void) | bool cRecording::Remove(void) | ||||||
| { | { | ||||||
|   bool result = true; |  | ||||||
|   isyslog(LOG_INFO, "removing recording %s", FileName()); |   isyslog(LOG_INFO, "removing recording %s", FileName()); | ||||||
|   if (remove(FileName()) == -1) { |   return RemoveFileOrDir(FileName()); | ||||||
|      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; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bool cRecording::Record(void) | bool cRecording::Record(void) | ||||||
| { | { | ||||||
|   return AssertRecorder() && Recorder->Record(FileName(), quality); |   return DvbApi.StartRecord(FileName()); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool cRecording::Play(void) | bool cRecording::Play(void) | ||||||
| { | { | ||||||
|   return AssertRecorder() && Recorder->Play(FileName()); |   return DvbApi.StartReplay(FileName()); | ||||||
| } | } | ||||||
|  |  | ||||||
| void cRecording::Stop(void) | void cRecording::Stop(void) | ||||||
| { | { | ||||||
|   if (Recorder) |   DvbApi.StopRecord(); | ||||||
|      Recorder->Stop(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // --- cRecordings ----------------------------------------------------------- | // --- cRecordings ----------------------------------------------------------- | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
|  * See the main source file 'osm.c' for copyright information and |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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 | #ifndef __RECORDING_H | ||||||
| @@ -15,21 +15,16 @@ | |||||||
| #include "dvbapi.h" | #include "dvbapi.h" | ||||||
| #include "tools.h" | #include "tools.h" | ||||||
|  |  | ||||||
| extern cDvbRecorder *Recorder; |  | ||||||
|  |  | ||||||
| void AssertFreeDiskSpace(void); | void AssertFreeDiskSpace(void); | ||||||
|  |  | ||||||
| class cRecording : public cListObject { | class cRecording : public cListObject { | ||||||
| private: |  | ||||||
|   bool AssertRecorder(void); |  | ||||||
| public: | public: | ||||||
|   char *name; |   char *name; | ||||||
|   char *fileName; |   char *fileName; | ||||||
|   time_t start; |   time_t start; | ||||||
|   char quality; |  | ||||||
|   int priority; |   int priority; | ||||||
|   int lifetime; |   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(cTimer *Timer); | ||||||
|   cRecording(const char *FileName); |   cRecording(const char *FileName); | ||||||
|   ~cRecording(); |   ~cRecording(); | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								remote.c
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								remote.c
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | |||||||
|  * See the main source file 'osm.c' for copyright information and |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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" | #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) | bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address) | ||||||
| @@ -244,8 +244,11 @@ bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address) | |||||||
|      String(buf); |      String(buf); | ||||||
|      SetCode(*Code, 0); |      SetCode(*Code, 0); | ||||||
|      unsigned int Command; |      unsigned int Command; | ||||||
|      if (GetCommand(&Command, Address)) |      if (GetCommand(&Command, Address)) { | ||||||
|  |         SetMode(modeB); | ||||||
|  |         String("----"); | ||||||
|         return true; |         return true; | ||||||
|  |         } | ||||||
|      if (*Code < 'D') { |      if (*Code < 'D') { | ||||||
|         (*Code)++; |         (*Code)++; | ||||||
|         return false; |         return false; | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								timers.conf
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								timers.conf
									
									
									
									
									
								
							| @@ -1,6 +1,9 @@ | |||||||
| 1:2:-----S-:2205:2320:H:99:99:Wochenshow | 1:15:MTWTF--:1828:1901:10:5:nano | ||||||
| 0:15:M------:2125:2205:H:99:99:Neues | 1:3:M------:2110:2230:99:10:SevenDays | ||||||
| 1:15:MTWTF--:1828:1901:M:10:5:nano | 1:10:-T-----:2058:2150:99:10:Quarks | ||||||
| 1:3:M------:2110:2230:H:99:99:SevenDays | 1:3:---T---:2158:2300:99:10:Switch | ||||||
| 1:3:---T---:2215:2300:H:99:99:Switch | 1:2:----F--:2110:2155:99:10:Anke | ||||||
| 1:14:------S:2210:2255:H:99:99:Olli | 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 |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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 "tools.h" | ||||||
|  | #include <dirent.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <sys/time.h> | #include <sys/time.h> | ||||||
|  | #include <unistd.h> | ||||||
|  |  | ||||||
| #define MaxBuffer 1000 | #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) | char *readline(FILE *f) | ||||||
| { | { | ||||||
|   static char buffer[MaxBuffer]; |   static char buffer[MaxBuffer]; | ||||||
| @@ -30,36 +58,83 @@ char *readline(FILE *f) | |||||||
|  |  | ||||||
| int time_ms(void) | int time_ms(void) | ||||||
| { | { | ||||||
|  |   static time_t t0 = 0; | ||||||
|   struct timeval t; |   struct timeval t; | ||||||
|   if (gettimeofday(&t, NULL) == 0) |   if (gettimeofday(&t, NULL) == 0) { | ||||||
|      return t.tv_sec * 1000 + t.tv_usec / 1000; |      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; |   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; |   bool result = true; | ||||||
|   char *s = strdup(FileName); |   char *s = strdup(FileName); | ||||||
|   char *p = s; |   char *p = s; | ||||||
|   if (*p == '/') |   if (*p == '/') | ||||||
|      p++; |      p++; | ||||||
|   while ((p = strchr(p, '/')) != NULL) { |   while ((p = strchr(p, '/')) != NULL || IsDirectory) { | ||||||
|  |         if (p) | ||||||
|            *p = 0; |            *p = 0; | ||||||
|         struct stat fs; |         struct stat fs; | ||||||
|         if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) { |         if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) { | ||||||
|            isyslog(LOG_INFO, "creating directory %s", s); |            isyslog(LOG_INFO, "creating directory %s", s); | ||||||
|            if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) { |            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; |               result = false; | ||||||
|               break; |               break; | ||||||
|               } |               } | ||||||
|            } |            } | ||||||
|  |         if (p) | ||||||
|            *p++ = '/'; |            *p++ = '/'; | ||||||
|  |         else | ||||||
|  |            break; | ||||||
|         } |         } | ||||||
|   delete s; |   delete s; | ||||||
|   return result; |   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::cListObject(void) | cListObject::cListObject(void) | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								tools.h
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								tools.h
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | |||||||
|  * See the main source file 'osm.c' for copyright information and |  * See the main source file 'osm.c' for copyright information and | ||||||
|  * how to reach the author. |  * 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 | #ifndef __TOOLS_H | ||||||
| @@ -13,18 +13,28 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <syslog.h> | #include <syslog.h> | ||||||
|  |  | ||||||
| //TODO | extern int SysLogLevel; | ||||||
| #define dsyslog syslog |  | ||||||
| #define esyslog syslog | #define esyslog if (SysLogLevel > 0) syslog | ||||||
| #define isyslog 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 SECSINDAY  86400 | ||||||
|  |  | ||||||
| #define DELETENULL(p) (delete (p), p = NULL) | #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); | char *readline(FILE *f); | ||||||
| int time_ms(void); | 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 { | class cListObject { | ||||||
| private: | private: | ||||||
| @@ -47,7 +57,7 @@ public: | |||||||
|   virtual ~cListBase(); |   virtual ~cListBase(); | ||||||
|   void Add(cListObject *Object); |   void Add(cListObject *Object); | ||||||
|   void Del(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 Move(cListObject *From, cListObject *To); | ||||||
|   void Clear(void); |   void Clear(void); | ||||||
|   cListObject *Get(int Index); |   cListObject *Get(int Index); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user