From c475c637aba78366763cb122673ff836dd9e7e85 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 19 Feb 2000 18:00:00 +0100 Subject: [PATCH 001/307] Version 0.01 (Initial revision). --- Makefile | 37 +++ README | 122 +++++++++ TODO | 13 + channels.conf | 109 ++++++++ config.c | 333 ++++++++++++++++++++++ config.h | 163 +++++++++++ dvbapi.c | 166 +++++++++++ dvbapi.h | 65 +++++ interface.c | 298 ++++++++++++++++++++ interface.h | 41 +++ keys-pc.conf | Bin 0 -> 225 bytes keys.conf | 19 ++ menu.c | 745 ++++++++++++++++++++++++++++++++++++++++++++++++++ menu.h | 21 ++ osd.c | 196 +++++++++++++ osd.h | 68 +++++ osm.c | 119 ++++++++ remote.c | 257 +++++++++++++++++ remote.h | 43 +++ timers.conf | 9 + tools.c | 124 +++++++++ tools.h | 54 ++++ 22 files changed, 3002 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 TODO create mode 100644 channels.conf create mode 100644 config.c create mode 100644 config.h create mode 100644 dvbapi.c create mode 100644 dvbapi.h create mode 100644 interface.c create mode 100644 interface.h create mode 100644 keys-pc.conf create mode 100644 keys.conf create mode 100644 menu.c create mode 100644 menu.h create mode 100644 osd.c create mode 100644 osd.h create mode 100644 osm.c create mode 100644 remote.c create mode 100644 remote.h create mode 100644 timers.conf create mode 100644 tools.c create mode 100644 tools.h diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..6696dff11 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +# +# Makefile for the On Screen Menu of the Video Disk Recorder +# +# See the main source file 'osm.c' for copyright information and +# how to reach the author. +# +# $Id: Makefile 1.1 2000/02/19 13:36:48 kls Exp $ + +OBJS = config.o dvbapi.o interface.o menu.o osd.o remote.o tools.o osm.o + +ifdef DEBUG_REMOTE +DEFINES += -DDEBUG_REMOTE +endif + +ifdef DEBUG_OSD +DEFINES += -DDEBUG_OSD +endif + +%.o: %.c + g++ -g -O2 -Wall -c $(DEFINES) $< + +all: osm + +config.o : config.c config.h dvbapi.h interface.h tools.h +dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h +interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h +menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h tools.h +osd.o : osd.c config.h interface.h osd.h tools.h +osm.o : osm.c config.h dvbapi.h interface.h menu.h osd.h tools.h +remote.o : remote.c remote.h tools.h +tools.o : tools.c tools.h + +osm: $(OBJS) + g++ -g -O2 $(OBJS) -lncurses -o osm + +clean: + -rm $(OBJS) osm diff --git a/README b/README new file mode 100644 index 000000000..e4fa836ec --- /dev/null +++ b/README @@ -0,0 +1,122 @@ +On Screen Menu for the Video Disk Recorder +------------------------------------------ + +These files contain the source code of an on screen +menu for a video disk recorder based on the DVB driver +of the LinuxTV project (http://linuxtv.org). +For details about the "Video Disk Recorder" project please +refer to http://www.cadsoft.de/people/kls/vdr. + +The author can be contacted at kls@cadsoft.de. + +Yet another "set-top-box"? +-------------------------- + +The "set-top-boxes" available from commercial companies all have +one major drawback: they are not "open". This project's goal is +to build an "open" digital satellite receiver and timer controlled +video disk recorder, based upon open standards and freely available +driver software (of course, the hardware still has to be bought). + +The on screen menu system is simple, but shall provide all the +possibilites necessary to perform timer controlled recording, +file management and, maybe, even "on disk editing". The menus +of commercial set-top-boxes usually are a lot more fancy than +the ones in this system, but here we have the full source code +and can modify the menus in whatever way desired. + +Compiling and running the program: +---------------------------------- + +Make sure the files from this package are located in a +directory that is "parallel" to the DVB directory of the +driver source for the Siemens DVB-S PCI card (refer to +http://linuxtv.org/dvb/siemens_dvb.html for more information +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. + +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 are two macros you can use to customize the 'osm' program +at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call +will use the PC's keyboard as input device instead of the "Remote +Control Unit" (see http://www.cadsoft.de/people/kls/vdr/remote.htm). +Adding "DEBUG_OSD=1" will use the PC screen (or current window) +to display texts instead of the DVB card's on-screen display +interface. These modes are useful when testing new menus if you +only have a remote connection to the VDR (which, in my case, is +located in the living room and has neither a monitor nor a keyboard). + +Configuration files: +-------------------- + +There are three configuration files that hold information about +channels, remote control keys and timers. These files are currrently +assumed to be located in the directory from which the 'osm' program +was started (this will become configurable later). The configuration +files can be edited with any text editor, or will be written by the +'osm' program if any changes are made inside the on-screen menus. +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 tranfer 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 os the key +definitions is optional, but the more keys you define, the more you +will be able to navigate through the menus. + +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. + +Navigating through the On Screen Menus: +--------------------------------------- + +The "Main" menu can be called up with the "Menu" key of your remote +control unit. The "Up" and "Down" keys are used to select a specific +item. The "Left" and "Right" keys can be used to change options, and +the numeric keys allow direct input of numeric data. The "Ok" key +confirms any changes (or switches to a channel in the "Channels" menu). +The "Back" key goes back one level in the menu structure, discarding +any changes that might have been made in the current menu. + +In the "Channels" menu, the current channel can be edited by pressing +the "Right" key. + +In the "Timers" menu, the current timer can be enabled or disabled with +the "Right" or "Left" key, respectively (enabled timers are marked with ">"). +"Ok" here opens the "Edit timer" menu. + +Textual options, like channel names or recording file names, can be edited +by pressing the "Right" button (which puts brackets around the current +character as in "[R]TL"), selecting the desired character position with +"Left" and "Right", and changing the character with the "Up" and "Down" +keys. "Ok" then confirms the changes. + +At any point in the menu system, pressing the "Menu" key again will +immediately leave the menu system. + +What do you think? +------------------ + +So, what do you think about this project? Does it make sense? Were you +able to use it? Do you have suggestions on how to improve it? +Please send email to kls@cadsoft.de if you'd like to comment on this. + diff --git a/TODO b/TODO new file mode 100644 index 000000000..32793469c --- /dev/null +++ b/TODO @@ -0,0 +1,13 @@ +TODO list for the Video Disk Recorder project +--------------------------------------------- + +* Implement a way to add and delete channels and timers. +* Implement recording to disk and playback from disk. +* Implement disk file management (delete old/viewed files to make + room for new recordings if necessary). +* 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). +* Implement "on-disk editing" to allow "cutting out" of certain + scenes in order to archive them (or, reversely, cut out + commercial breaks). diff --git a/channels.conf b/channels.conf new file mode 100644 index 000000000..9daca0aff --- /dev/null +++ b/channels.conf @@ -0,0 +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:11876:h:1:27500:306:322 +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 diff --git a/config.c b/config.c new file mode 100644 index 000000000..50315691e --- /dev/null +++ b/config.c @@ -0,0 +1,333 @@ +/* + * config.c: Configuration file handling + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: config.c 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#include "config.h" +#include +#include +#include +#include "dvbapi.h" +#include "interface.h" + +// -- cKeys ------------------------------------------------------------------ + +tKey keyTable[] = { // "Up" and "Down" must be the first two keys! + { kUp, "Up", 0 }, + { kDown, "Down", 0 }, + { kMenu, "Menu", 0 }, + { kOk, "Ok", 0 }, + { kBack, "Back", 0 }, + { kLeft, "Left", 0 }, + { kRight, "Right", 0 }, + { k0, "0", 0 }, + { k1, "1", 0 }, + { k2, "2", 0 }, + { k3, "3", 0 }, + { k4, "4", 0 }, + { k5, "5", 0 }, + { k6, "6", 0 }, + { k7, "7", 0 }, + { k8, "8", 0 }, + { k9, "9", 0 }, + { kNone, "", 0 }, + }; + +cKeys::cKeys(void) +{ + fileName = NULL; + code = 0; + address = 0; + keys = keyTable; +} + +void cKeys::Clear(void) +{ + for (tKey *k = keys; k->type != kNone; k++) + k->code = 0; +} + +bool cKeys::Load(char *FileName) +{ + isyslog(LOG_INFO, "loading %s", FileName); + bool result = false; + if (FileName) + fileName = strdup(FileName); + if (fileName) { + FILE *f = fopen(fileName, "r"); + if (f) { + int line = 0; + char buffer[MaxBuffer]; + result = true; + while (fgets(buffer, sizeof(buffer), f) > 0) { + line++; + char *Name = buffer; + char *p = strpbrk(Name, " \t"); + if (p) { + *p = 0; // terminates 'Name' + while (*++p && isspace(*p)) + ; + if (*p) { + if (strcasecmp(Name, "Code") == 0) + code = *p; + else if (strcasecmp(Name, "Address") == 0) + address = strtol(p, NULL, 16); + else { + for (tKey *k = keys; k->type != kNone; k++) { + if (strcasecmp(Name, k->name) == 0) { + k->code = strtol(p, NULL, 16); + Name = NULL; // to indicate that we found it + break; + } + } + if (Name) { + fprintf(stderr, "unknown key in %s, line %d\n", fileName, line); + result = false; + break; + } + } + } + continue; + } + fprintf(stderr, "error in %s, line %d\n", fileName, line); + result = false; + break; + } + fclose(f); + } + else + fprintf(stderr, "can't open '%s'\n", fileName); + } + else + fprintf(stderr, "no key configuration file name supplied!\n"); + return result; +} + +bool cKeys::Save(void) +{ + //TODO make backup copies??? + bool result = true; + FILE *f = fopen(fileName, "w"); + if (f) { + if (fprintf(f, "Code\t%c\nAddress\t%04X\n", code, address) > 0) { + for (tKey *k = keys; k->type != kNone; k++) { + if (fprintf(f, "%s\t%08X\n", k->name, k->code) <= 0) { + result = false; + break; + } + } + } + else + result = false; + fclose(f); + } + else + result = false; + return result; +} + +eKeys cKeys::Get(unsigned int Code) +{ + if (Code != 0) { + tKey *k; + for (k = keys; k->type != kNone; k++) { + if (k->code == Code) + break; + } + return k->type; + } + return kNone; +} + +void cKeys::Set(eKeys Key, unsigned int Code) +{ + for (tKey *k = keys; k->type != kNone; k++) { + if (k->type == Key) { + k->code = Code; + break; + } + } +} + +// -- cChannel --------------------------------------------------------------- + +cChannel::cChannel(void) +{ + *name = 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)) { + strncpy(name, buffer, MaxChannelName - 1); + name[strlen(buffer)] = 0; + delete buffer; + return true; + } + return false; +} + +bool cChannel::Save(FILE *f) +{ + return fprintf(f, "%s:%d:%c:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid) > 0; +} + +bool cChannel::Switch(void) +{ + if (!ChannelLocked) { + 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)) + return true; + esyslog(LOG_ERR, "retrying"); + } + } + Interface.Info("Channel locked (recording)!"); + return false; +} + +bool cChannel::SwitchTo(int i) +{ + cChannel *channel = Channels.Get(i); + return channel && channel->Switch(); +} + +// -- cTimer ----------------------------------------------------------------- + +cTimer::cTimer(void) +{ + *file = 0; +} + +int cTimer::TimeToInt(int t) +{ + return (t / 100 * 60 + t % 100) * 60; +} + +int cTimer::ParseDay(char *s) +{ + char *tail; + int d = strtol(s, &tail, 10); + if (tail && *tail) { + d = 0; + if (tail == s) { + if (strlen(s) == 7) { + for (char *p = s + 6; p >= s; p--) { + d <<= 1; + d |= (*p != '-'); + } + d |= 0x80000000; + } + } + } + else if (d < 1 || d > 31) + d = 0; + return d; +} + +char *cTimer::PrintDay(int d) +{ + static char buffer[8]; + if ((d & 0x80000000) != 0) { + char *b = buffer; + char *w = "MTWTFSS"; + *b = 0; + while (*w) { + *b++ = (d & 1) ? *w : '-'; + d >>= 1; + w++; + } + } + else + sprintf(buffer, "%d", d); + return buffer; +} + +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)) { + day = ParseDay(buffer1); + strncpy(file, buffer2, MaxFileName - 1); + file[strlen(buffer2)] = 0; + delete buffer1; + delete buffer2; + return day != 0; + } + return false; +} + +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; +} + +bool cTimer::Matches(void) +{ + if (active) { + time_t t = time(NULL); + struct tm *now = localtime(&t); + int weekday = now->tm_wday == 0 ? 6 : now->tm_wday - 1; // we start with monday==0! + int current = (now->tm_hour * 60 + now->tm_min) * 60 + now->tm_sec; + int begin = TimeToInt(start); + int end = TimeToInt(stop); + bool twoDays = (end < begin); + + bool todayMatches = false, yesterdayMatches = false; + if ((day & 0x80000000) != 0) { + if ((day & (1 << weekday)) != 0) + todayMatches = true; + else if (twoDays) { + int yesterday = weekday == 0 ? 6 : weekday - 1; + if ((day & (1 << yesterday)) != 0) + yesterdayMatches = true; + } + } + else if (day == now->tm_mday) + todayMatches = true; + else if (twoDays) { + t -= 86400; + now = localtime(&t); + if (day == now->tm_mday) + yesterdayMatches = true; + } + return (todayMatches && current >= begin && (current <= end || twoDays)) + || (twoDays && yesterdayMatches && current <= end); + } + return false; +} + +cTimer *cTimer::GetMatch(void) +{ + cTimer *t = (cTimer *)Timers.First(); + while (t) { + if (t->Matches()) + return t; + t = (cTimer *)t->Next(); + } + return NULL; +} + +// -- cKeys ------------------------------------------------------------------ + +cKeys Keys; + +// -- cChannels -------------------------------------------------------------- + +int CurrentChannel = 0; +bool ChannelLocked = false; + +cChannels Channels; + +// -- cTimers ---------------------------------------------------------------- + +cTimers Timers; + diff --git a/config.h b/config.h new file mode 100644 index 000000000..3abb7a1ac --- /dev/null +++ b/config.h @@ -0,0 +1,163 @@ +/* + * config.h: Configuration file handling + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: config.h 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include +#include +#include "tools.h" + +#define MaxBuffer 1000 + +enum eKeys { // "Up" and "Down" must be the first two keys! + kUp, + kDown, + kMenu, + kOk, + kBack, + kLeft, + kRight, + k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, + kNone + }; + +struct tKey { + eKeys type; + char *name; + unsigned int code; + }; + +class cKeys { +private: + char *fileName; +public: + unsigned char code; + unsigned short address; + tKey *keys; + cKeys(void); + void Clear(void); + bool Load(char *FileName = NULL); + bool Save(void); + eKeys Get(unsigned int Code); + void Set(eKeys Key, unsigned int Code); + }; + +class cChannel : public cListObject { +public: + enum { MaxChannelName = 32 }; // 31 chars + terminating 0! + char name[MaxChannelName]; + int frequency; // MHz + char polarization; + int diseqc; + int srate; + int vpid; + int apid; + cChannel(void); + bool Parse(char *s); + bool Save(FILE *f); + bool Switch(void); + static bool SwitchTo(int i); + }; + +class cTimer : public cListObject { +public: + enum { MaxFileName = 256 }; + int active; + int channel; + int day; + int start; + int stop; +//TODO VPS??? + char quality; + int priority; + int lifetime; + char file[MaxFileName]; + cTimer(void); + bool Parse(char *s); + bool Save(FILE *f); + bool Matches(void); + static cTimer *GetMatch(void); + static int TimeToInt(int t); + static int ParseDay(char *s); + static char *PrintDay(int d); + }; + +template class cConfig : public cList { +private: + char *fileName; + void Clear(void) + { + delete fileName; + cList::Clear(); + } +public: + bool Load(char *FileName) + { + isyslog(LOG_INFO, "loading %s", FileName); + bool result = true; + Clear(); + fileName = strdup(FileName); + FILE *f = fopen(fileName, "r"); + if (f) { + int line = 0; + char buffer[MaxBuffer]; + while (fgets(buffer, sizeof(buffer), f) > 0) { + line++; + T *l = new T; + if (l->Parse(buffer)) + Add(l); + else { + fprintf(stderr, "error in %s, line %d\n", fileName, line); + delete l; + result = false; + break; + } + } + fclose(f); + } + else { + fprintf(stderr, "can't open '%s'\n", fileName); + result = false; + } + return result; + } + bool Save(void) + { + //TODO make backup copies??? + bool result = true; + T *l = (T *)First(); + FILE *f = fopen(fileName, "w"); + if (f) { + while (l) { + if (!l->Save(f)) { + result = false; + break; + } + l = (T *)l->Next(); + } + fclose(f); + } + else + result = false; + return result; + } + }; + +class cChannels : public cConfig {}; +class cTimers : public cConfig {}; + +extern int CurrentChannel; +extern bool ChannelLocked; + +extern cChannels Channels; +extern cTimers Timers; +extern cKeys Keys; + +#endif //__CONFIG_H diff --git a/dvbapi.c b/dvbapi.c new file mode 100644 index 000000000..5597fbd50 --- /dev/null +++ b/dvbapi.c @@ -0,0 +1,166 @@ +/* + * dvbapi.c: Interface to the DVB driver + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: dvbapi.c 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +// FIXME: these should be defined in ../DVB/driver/dvb.h!!! +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; + +#include "dvbapi.h" +#include +#include +#include +#include +#include "../DVB/driver/dvb.h" +#include "interface.h" +#include "tools.h" + +#define VIDEODEVICE "/dev/video" + +const char *DvbQuality = "LMH"; // Low, Medium, High + +bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid) +{ + int v = open(VIDEODEVICE, O_RDWR); + + if (v >= 0) { + struct frontend front; + ioctl(v, VIDIOCGFRONTEND, &front); + unsigned int freq = FrequencyMHz; + front.ttk = (freq < 11800UL) ? 0 : 1; + if (freq < 11800UL) + freq -= 9750UL; + else + freq -= 10600UL; + front.freq = freq * 1000000UL; + front.diseqc = Diseqc; + front.srate = Srate * 1000; + front.volt = (Polarization == 'v') ? 0 : 1; + front.video_pid = Vpid; + front.audio_pid = Apid; + front.AFC = 1; + ioctl(v, VIDIOCSFRONTEND, &front); + close(v); + if (front.sync & 0x1F == 0x1F) + return true; + esyslog(LOG_ERR, "channel not sync'ed (front.sync=%X)!", front.sync); + } + else + Interface.Error("can't open VIDEODEVICE");//XXX + return false; +} + +// -- cDvbRecorder ----------------------------------------------------------- + +cDvbRecorder::cDvbRecorder(void) +{ +} + +cDvbRecorder::~cDvbRecorder() +{ + Stop(); +} + +bool cDvbRecorder::Record(const char *FileName, char Quality) +{ + isyslog(LOG_INFO, "record %s (%c)", FileName, Quality); + return true; + // TODO + return false; +} + +bool cDvbRecorder::Play(const char *FileName, int Frame) +{ + isyslog(LOG_INFO, "play %s (%d)", FileName, Frame); + // TODO + return false; +} + +bool cDvbRecorder::FastForward(void) +{ + isyslog(LOG_INFO, "fast forward"); + // TODO + return false; +} + +bool cDvbRecorder::FastRewind(void) +{ + isyslog(LOG_INFO, "fast rewind"); + // TODO + return false; +} + +bool cDvbRecorder::Pause(void) +{ + isyslog(LOG_INFO, "pause"); + // TODO + return false; +} + +void cDvbRecorder::Stop(void) +{ + isyslog(LOG_INFO, "stop"); + // TODO +} + +int cDvbRecorder::Frame(void) +{ + isyslog(LOG_INFO, "frame"); + // TODO + return 0; +} + +// --------------------------------------------------------------------------- + +static void DvbOsdCmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, void *data = NULL) +{ + int v = open(VIDEODEVICE, O_RDWR); + + if (v >= 0) { + struct drawcmd dc; + dc.cmd = cmd; + dc.color = color; + dc.x0 = x0; + dc.y0 = y0; + dc.x1 = x1; + dc.y1 = y1; + dc.data = data; + ioctl(v, VIDIOCSOSDCOMMAND, &dc); + close(v); + } + else + Interface.Error("can't open VIDEODEVICE");//XXX +} + +void DvbOsdOpen(int x, int y, int w, int h) +{ + DvbOsdCmd(OSD_Open, 1, x, y, x + w - 1, y + h - 1); + DvbOsdCmd(OSD_SetColor, 0, 0, 0, 0, 127); // background 50% gray + DvbOsdCmd(OSD_SetColor, 1, 255, 255, 255, 255); // text white +} + +void DvbOsdClose(void) +{ + DvbOsdCmd(OSD_Close); +} + +void DvbOsdClear(void) +{ + DvbOsdCmd(OSD_Clear); +} + +void DvbOsdClrEol(int x, int y) +{ + DvbOsdCmd(OSD_FillBlock, 0, x, y * DvbOsdLineHeight, x + 490, (y + 1) * DvbOsdLineHeight);//XXX +} + +void DvbOsdText(int x, int y, char *s) +{ + DvbOsdCmd(OSD_Text, 1, x, y, 1, 0, s); +} diff --git a/dvbapi.h b/dvbapi.h new file mode 100644 index 000000000..6a8f0400e --- /dev/null +++ b/dvbapi.h @@ -0,0 +1,65 @@ +/* + * dvbapi.h: Interface to the DVB driver + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: dvbapi.h 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#ifndef __DVBAPI_H +#define __DVBAPI_H + +const int DvbOsdCharWidth = 12; //XXX +const int DvbOsdLineHeight = 25; + +extern const char *DvbQuality; // Low, Medium, High + +bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid); + +class cDvbRecorder { +public: + cDvbRecorder(void); + ~cDvbRecorder(); + 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 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. + }; + +void DvbOsdOpen(int x, int y, int w, int h); +void DvbOsdClose(void); +void DvbOsdClear(void); +void DvbOsdClrEol(int x, int y); +void DvbOsdText(int x, int y, char *s); + +#endif //__DVBAPI_H diff --git a/interface.c b/interface.c new file mode 100644 index 000000000..58c28f1f9 --- /dev/null +++ b/interface.c @@ -0,0 +1,298 @@ +/* + * interface.c: Abstract user interface layer + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: interface.c 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#include "interface.h" +#include +#include +#include "dvbapi.h" +#include "remote.h" + +#ifndef DEBUG_REMOTE +cRcIo RcIo("/dev/ttyS1");//XXX +#endif + +WINDOW *window; + +cInterface Interface; + +cInterface::cInterface(void) +{ + open = 0; + cols[0] = 0; +#ifdef DEBUG_OSD + initscr(); + keypad(stdscr, TRUE); + nonl(); + cbreak(); + noecho(); + leaveok(stdscr, TRUE); + window = stdscr; +#else +#endif +} + +void cInterface::Init(void) +{ +#ifndef DEBUG_REMOTE + RcIo.SetCode(Keys.code, Keys.address); +#endif +} + +void cInterface::Open(void) +{ + if (!open++) { +#ifdef DEBUG_OSD +#else +//TODO + DvbOsdOpen(100, 100, 500, 400); +#endif + } +} + +void cInterface::Close(void) +{ + if (!--open) { +#ifdef DEBUG_OSD +#else +//TODO + DvbOsdClose(); +#endif + } +} + +unsigned int cInterface::GetCh(void) +{ +#ifdef DEBUG_REMOTE + return getch(); +#else +#ifdef DEBUG_OSD + wrefresh(window);//XXX +#endif + unsigned int Command; + return RcIo.GetCommand(&Command) ? Command : 0; +#endif +} + +eKeys cInterface::GetKey(void) +{ + return Keys.Get(GetCh()); +} + +void cInterface::Clear(void) +{ + if (open) { +#ifdef DEBUG_OSD + wclear(window); +#else +//TODO + DvbOsdClear(); +#endif + } +} + +void cInterface::SetCols(int *c) +{ + for (int i = 0; i < MaxCols; i++) { + cols[i] = *c++; + if (cols[i] == 0) + break; + } +} + +void cInterface::Write(int x, int y, char *s) +{ + if (open) { +#ifdef DEBUG_OSD + wmove(window, y, x); // ncurses wants 'y' before 'x'! + waddstr(window, s); +#else + DvbOsdText(x * DvbOsdCharWidth, y * DvbOsdLineHeight, s); +#endif + } +} + +void cInterface::WriteText(int x, int y, char *s, bool Current) +{ + if (open) { +#ifdef DEBUG_OSD + wmove(window, y, x); // ncurses wants 'y' before 'x'! + wclrtoeol(window);//XXX +#else +//TODO + DvbOsdClrEol(x * DvbOsdCharWidth, y);//XXX +#endif + Write(x, y, Current ? "*" : " "); + x++; + int col = 0; + for (;;) { + char *t = strchr(s, '\t'); + char *p = s; + char buf[1000]; + if (t && col < MaxCols && cols[col] > 0) { + unsigned int n = t - s; + if (n >= sizeof(buf)) + n = sizeof(buf) - 1; + strncpy(buf, s, n); + buf[n] = 0; + p = buf; + s = t + 1; + } + Write(x, y, p); + if (p == s) + break; + x += cols[col++]; + } + } +} + +void cInterface::Info(char *s) +{ + Open(); + isyslog(LOG_ERR, s); + WriteText(0, 11, s);//TODO +#ifdef DEBUG_OSD + wrefresh(window);//XXX +#endif + sleep(1); + WriteText(0, 11, "");//TODO +#ifdef DEBUG_OSD + wrefresh(window);//XXX +#endif + Close(); +} + +void cInterface::Error(char *s) +{ + Open(); + esyslog(LOG_ERR, s); + WriteText(0, 12, s);//TODO +#ifdef DEBUG_OSD + wrefresh(window);//XXX +#endif + sleep(1); + WriteText(0, 12, "");//TODO +#ifdef DEBUG_OSD + wrefresh(window);//XXX +#endif + Close(); +} + +void cInterface::QueryKeys(void) +{ + Keys.Clear(); + WriteText(1, 1, "Learning Remote Control Keys"); + WriteText(1, 3, "Phase 1: Detecting RC code type"); + WriteText(1, 5, "Press any key on the RC unit"); +#ifndef DEBUG_REMOTE + unsigned char Code = 0; + unsigned short Address; +#endif + for (;;) { +#ifdef DEBUG_REMOTE + if (GetCh()) + break; +#else + //TODO on screen display... + if (RcIo.DetectCode(&Code, &Address)) { + Keys.code = Code; + Keys.address = Address; + WriteText(1, 5, "RC code detected!"); + WriteText(1, 6, "Do not press any key..."); + RcIo.Flush(3); + WriteText(1, 5, ""); + WriteText(1, 6, ""); + break; + } +#endif + } + WriteText(1, 3, "Phase 2: Learning specific key codes"); + tKey *k = Keys.keys; + while (k->type != kNone) { + char *Prompt; + asprintf(&Prompt, "Press key for '%s'", k->name); + WriteText(1, 5, Prompt); + delete Prompt; + for (;;) { + unsigned int ch = GetCh(); + if (ch != 0) { + switch (Keys.Get(ch)) { + case kUp: if (k > Keys.keys) { + k--; + break; + } + case kDown: if (k > Keys.keys + 1) { + WriteText(1, 5, "Press 'Up' to confirm"); + WriteText(1, 6, "Press 'Down' to continue"); + WriteText(1, 7, ""); + WriteText(1, 8, ""); + for (;;) { + eKeys key = GetKey(); + if (key == kUp) { + Clear(); + return; + } + else if (key == kDown) { + WriteText(1, 6, ""); + break; + } + } + break; + } + case kNone: k->code = ch; + k++; + break; + default: break; + } + break; + } + } + if (k > Keys.keys) + WriteText(1, 7, "(press 'Up' to go back)"); + else + WriteText(1, 7, ""); + if (k > Keys.keys + 1) + WriteText(1, 8, "(press 'Down' to end key definition)"); + else + WriteText(1, 8, ""); + } +} + +void cInterface::LearnKeys(void) +{ + isyslog(LOG_INFO, "learning keys"); + for (;;) { + Clear(); + QueryKeys(); + Clear(); + WriteText(1, 1, "Learning Remote Control Keys"); + WriteText(1, 3, "Phase 3: Saving key codes"); + WriteText(1, 5, "Press 'Up' to save, 'Down' to cancel"); + for (;;) { + eKeys key = GetKey(); + if (key == kUp) { + Keys.Save(); + Clear(); + return; + } + else if (key == kDown) { + Keys.Load(); + Clear(); + return; + } + } + } +} + +void cInterface::DisplayChannel(int Number, char *Name) +{ +//TODO +#ifndef DEBUG_REMOTE + RcIo.Number(Number); +#endif +} diff --git a/interface.h b/interface.h new file mode 100644 index 000000000..e387ab91f --- /dev/null +++ b/interface.h @@ -0,0 +1,41 @@ +/* + * interface.h: Abstract user interface layer + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: interface.h 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#ifndef __INTERFACE_H +#define __INTERFACE_H + +#include "config.h" + +class cInterface { +public: + enum { MaxCols = 5 }; +private: + int open; + int cols[MaxCols]; + unsigned int GetCh(void); + void QueryKeys(void); + void Write(int x, int y, char *s); +public: + cInterface(void); + void Init(void); + void Open(void); + void Close(void); + eKeys GetKey(void); + void Clear(void); + void SetCols(int *c); + void WriteText(int x, int y, char *s, bool Current = false); + void Info(char *s); + void Error(char *s); + void LearnKeys(void); + void DisplayChannel(int Number, char *Name); + }; + +extern cInterface Interface; + +#endif //__INTERFACE_H diff --git a/keys-pc.conf b/keys-pc.conf new file mode 100644 index 0000000000000000000000000000000000000000..c57613f03256f252e5e7ccac9e89c4954e3a3d15 GIT binary patch literal 225 zcmX}jNeY8N5QSm4zSC6Cx{PtD2!R|Rq&ouv4Gwtygy>6c>iePUIK-4^IK()nY0Bk0 zIKO{elo-^*+Oss;)GsWL?zLH@Ms>OFr6iz9x0!bqr|13gPY2n*j6jhJn$$3)fh8>* Q>EKC^Kn4_Kfs!oo0V-T99smFU literal 0 HcmV?d00001 diff --git a/keys.conf b/keys.conf new file mode 100644 index 000000000..f56222c34 --- /dev/null +++ b/keys.conf @@ -0,0 +1,19 @@ +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 diff --git a/menu.c b/menu.c new file mode 100644 index 000000000..4f525ff7c --- /dev/null +++ b/menu.c @@ -0,0 +1,745 @@ +/* + * menu.c: The actual menu implementations + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: menu.c 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#include "menu.h" +#include +#include +#include +#include "config.h" +#include "dvbapi.h" + +const char *FileNameChars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789/-.# ";//TODO more? + +// --- cMenuEditItem --------------------------------------------------------- + +class cMenuEditItem : public cOsdItem { +private: + const char *name; + const char *value; +public: + cMenuEditItem(const char *Name); + ~cMenuEditItem(); + void SetValue(const char *Value); + }; + +cMenuEditItem::cMenuEditItem(const char *Name) +{ + name = strdup(Name); + value = NULL; +} + +cMenuEditItem::~cMenuEditItem() +{ + delete name; + delete value; +} + +void cMenuEditItem::SetValue(const char *Value) +{ + delete value; + value = strdup(Value); + char *buffer = NULL; + asprintf(&buffer, "%s:\t%s", name, value); + SetText(buffer, false); + Display(); +} + +// --- cMenuEditIntItem ------------------------------------------------------ + +class cMenuEditIntItem : public cMenuEditItem { +protected: + int *value; + int min, max; + virtual void Set(void); +public: + cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max) +:cMenuEditItem(Name) +{ + value = Value; + min = Min; + max = Max; + Set(); +} + +void cMenuEditIntItem::Set(void) +{ + char buf[16]; + snprintf(buf, sizeof(buf), "%d", *value); + SetValue(buf); +} + +eOSStatus cMenuEditIntItem::ProcessKey(eKeys Key) +{ + eOSStatus status = cMenuEditItem::ProcessKey(Key); + + if (status == osUnknown) { + int newValue; + if (k0 <= Key && Key <= k9) { + if (fresh) { + *value = 0; + fresh = false; + } + newValue = *value * 10 + (Key - k0); + } + else if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly? + newValue = *value - 1; + fresh = true; + } + else if (Key == kRight) { + newValue = *value + 1; + fresh = true; + } + else + return status; + if ((!fresh || min <= newValue) && newValue <= max) { + *value = newValue; + Set(); + } + status = osContinue; + } + return status; +} + +// --- cMenuEditBoolItem ----------------------------------------------------- + +class cMenuEditBoolItem : public cMenuEditIntItem { +protected: + virtual void Set(void); +public: + cMenuEditBoolItem(const char *Name, int *Value); + }; + +cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value) +:cMenuEditIntItem(Name, Value, 0, 1) +{ + Set(); +} + +void cMenuEditBoolItem::Set(void) +{ + char buf[16]; + snprintf(buf, sizeof(buf), "%s", *value ? "yes" : "no"); + SetValue(buf); +} + +// --- cMenuEditChanItem ----------------------------------------------------- + +class cMenuEditChanItem : public cMenuEditIntItem { +protected: + virtual void Set(void); +public: + cMenuEditChanItem(const char *Name, int *Value); + }; + +cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value) +:cMenuEditIntItem(Name, Value, 1, Channels.Count()) +{ + Set(); +} + +void cMenuEditChanItem::Set(void) +{ + char buf[255]; + cChannel *channel = Channels.Get(*value - 1); + if (channel) + snprintf(buf, sizeof(buf), "%d %s", *value, channel->name); + else + *buf = 0; + SetValue(buf); +} + +// --- cMenuEditDayItem ------------------------------------------------------ + +class cMenuEditDayItem : public cMenuEditIntItem { +protected: + static int days[]; + int d; + virtual void Set(void); +public: + cMenuEditDayItem(const char *Name, int *Value); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +int cMenuEditDayItem::days[] ={ cTimer::ParseDay("M------"), + cTimer::ParseDay("-T-----"), + cTimer::ParseDay("--W----"), + cTimer::ParseDay("---T---"), + cTimer::ParseDay("----F--"), + cTimer::ParseDay("-----S-"), + cTimer::ParseDay("------S"), + cTimer::ParseDay("MTWTF--"), + cTimer::ParseDay("MTWTFS-"), + cTimer::ParseDay("MTWTFSS"), + cTimer::ParseDay("-----SS"), + 0 }; + +cMenuEditDayItem::cMenuEditDayItem(const char *Name, int *Value) +:cMenuEditIntItem(Name, Value, -INT_MAX, 31) +{ + d = -1; + if (*value < 0) { + int n = 0; + while (days[n]) { + if (days[n] == *value) { + d = n; + break; + } + n++; + } + } + Set(); +} + +void cMenuEditDayItem::Set(void) +{ + SetValue(cTimer::PrintDay(*value)); +} + +eOSStatus cMenuEditDayItem::ProcessKey(eKeys Key) +{ + switch (Key) { + case kLeft: if (d > 0) + *value = days[--d]; + else if (d == 0) { + *value = 31; + d = -1; + } + else if (*value == 1) { + d = sizeof(days) / sizeof(int) - 2; + *value = days[d]; + } + else + return cMenuEditIntItem::ProcessKey(Key); + Set(); + break; + case kRight: if (d >= 0) { + *value = days[++d]; + if (*value == 0) { + *value = 1; + d = -1; + } + } + else if (*value == 31) { + d = 0; + *value = days[d]; + } + else + return cMenuEditIntItem::ProcessKey(Key); + Set(); + break; + default : return cMenuEditIntItem::ProcessKey(Key); + } + return osContinue; +} + +// --- cMenuEditTimeItem ----------------------------------------------------- + +class cMenuEditTimeItem : public cMenuEditItem { +protected: + int *value; + int hh, mm; + int pos; + virtual void Set(void); +public: + cMenuEditTimeItem(const char *Name, int *Value); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value) +:cMenuEditItem(Name) +{ + value = Value; + hh = *value / 100; + mm = *value % 100; + pos = 0; + Set(); +} + +void cMenuEditTimeItem::Set(void) +{ + char buf[10]; + snprintf(buf, sizeof(buf), "%02d:%02d", hh, mm); + SetValue(buf); +} + +eOSStatus cMenuEditTimeItem::ProcessKey(eKeys Key) +{ + eOSStatus status = cMenuEditItem::ProcessKey(Key); + + if (status == osUnknown) { + if (k0 <= Key && Key <= k9) { + if (fresh || pos > 3) { + pos = 0; + fresh = false; + } + int n = Key - k0; + switch (pos) { + case 0: if (n <= 2) { + hh = n * 10; + mm = 0; + pos++; + } + break; + case 1: if (hh + n <= 23) { + hh += n; + pos++; + } + break; + case 2: if (n <= 5) { + mm += n * 10; + pos++; + } + break; + case 3: if (mm + n <= 59) { + mm += n; + pos++; + } + break; + } + } + else if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly? + if (--mm < 0) { + mm = 59; + if (--hh < 0) + hh = 23; + } + fresh = true; + } + else if (Key == kRight) { + if (++mm > 59) { + mm = 0; + if (++hh > 23) + hh = 0; + } + fresh = true; + } + else + return status; + *value = hh * 100 + mm; + Set(); + status = osContinue; + } + return status; +} + +// --- cMenuEditChrItem ------------------------------------------------------ + +class cMenuEditChrItem : public cMenuEditItem { +private: + char *value; + const char *allowed; + const char *current; + virtual void Set(void); +public: + cMenuEditChrItem(const char *Name, char *Value, const char *Allowed); + ~cMenuEditChrItem(); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed) +:cMenuEditItem(Name) +{ + value = Value; + allowed = strdup(Allowed); + current = strchr(allowed, *Value); + if (!current) + current = allowed; + Set(); +} + +cMenuEditChrItem::~cMenuEditChrItem() +{ + delete allowed; +} + +void cMenuEditChrItem::Set(void) +{ + char buf[2]; + snprintf(buf, sizeof(buf), "%c", *value); + SetValue(buf); +} + +eOSStatus cMenuEditChrItem::ProcessKey(eKeys Key) +{ + eOSStatus status = cMenuEditItem::ProcessKey(Key); + + if (status == osUnknown) { + if (Key == kLeft) { + if (current > allowed) + current--; + } + else if (Key == kRight) { + if (*(current + 1)) + current++; + } + else + return status; + *value = *current; + Set(); + status = osContinue; + } + return status; +} + +// --- cMenuEditStrItem ------------------------------------------------------ + +class cMenuEditStrItem : public cMenuEditItem { +private: + char *value; + int length; + const char *allowed; + int pos; + virtual void Set(void); + char Inc(char c, bool Up); +public: + cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed); + ~cMenuEditStrItem(); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed) +:cMenuEditItem(Name) +{ + value = Value; + length = Length; + allowed = strdup(Allowed); + pos = -1; + Set(); +} + +cMenuEditStrItem::~cMenuEditStrItem() +{ + delete allowed; +} + +void cMenuEditStrItem::Set(void) +{ + char buf[1000]; + if (pos >= 0) { + strncpy(buf, value, pos); + char *s = value[pos] != ' ' ? value + pos + 1 : ""; + snprintf(buf + pos, sizeof(buf) - pos - 2, "[%c]%s", *(value + pos), s); + SetValue(buf); + } + else + SetValue(value); +} + +char cMenuEditStrItem::Inc(char c, bool Up) +{ + const char *p = strchr(allowed, c); + if (!p) + p = allowed; + if (Up) { + if (!*++p) + p = allowed; + } + else if (--p < allowed) + p = allowed + strlen(allowed) - 1; + return *p; +} + +eOSStatus cMenuEditStrItem::ProcessKey(eKeys Key) +{ + switch (Key) { + case kLeft: if (pos > 0) { + if (value[pos] == ' ') + value[pos] = 0; + pos--; + } + break; + case kRight: if (pos < length && value[pos] != ' ') { + if (++pos >= int(strlen(value))) { + value[pos] = ' '; + value[pos + 1] = 0; + } + } + break; + case kUp: + case kDown: if (pos >= 0) + value[pos] = Inc(value[pos], Key == kUp); + else + return cMenuEditItem::ProcessKey(Key); + break; + case kOk: if (pos >= 0) { + if (value[pos] == ' ') + value[pos] = 0; + pos = -1; + break; + } + // run into default + default: return cMenuEditItem::ProcessKey(Key); + } + Set(); + return osContinue; +} + +// --- cMenuEditChannel ------------------------------------------------------ + +class cMenuEditChannel : public cOsdMenu { +private: + cChannel *channel; + cChannel data; +public: + cMenuEditChannel(int Index); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +cMenuEditChannel::cMenuEditChannel(int Index) +:cOsdMenu("Edit channel", 14) +{ + channel = Channels.Get(Index); + if (channel) { + data = *channel; + Add(new cMenuEditStrItem("Name", data.name, sizeof(data.name), FileNameChars)); + Add(new cMenuEditIntItem("Frequency", &data.frequency, 10000, 13000)); //TODO exact limits??? + Add(new cMenuEditChrItem("Polarization", &data.polarization, "hv")); + Add(new cMenuEditIntItem("Diseqc", &data.diseqc, 0, 10)); //TODO exact limits??? + Add(new cMenuEditIntItem("Srate", &data.srate, 22000, 27500)); //TODO exact limits - toggle??? + Add(new cMenuEditIntItem("Vpid", &data.vpid, 0, 10000)); //TODO exact limits??? + Add(new cMenuEditIntItem("Apid", &data.apid, 0, 10000)); //TODO exact limits??? + } +} + +eOSStatus cMenuEditChannel::ProcessKey(eKeys Key) +{ + eOSStatus status = cOsdMenu::ProcessKey(Key); + + if (status == osUnknown) { + if (Key == kOk) { + if (channel) + *channel = data; + Channels.Save(); + status = osBack; + } + } + return status; +} + +// --- cMenuChannelItem ------------------------------------------------------ + +class cMenuChannelItem : public cOsdItem { +private: + int index; + cChannel *channel; +public: + cMenuChannelItem(int Index, cChannel *Channel); + virtual void Set(void); + }; + +cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel) +{ + index = Index; + channel = Channel; + Set(); +} + +void cMenuChannelItem::Set(void) +{ + char *buffer = NULL; + asprintf(&buffer, "%d\t%s", index + 1, channel->name); // user visible channel numbers start with '1' + SetText(buffer, false); +} + +// --- cMenuChannels --------------------------------------------------------- + +class cMenuChannels : public cOsdMenu { +public: + cMenuChannels(void); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +cMenuChannels::cMenuChannels(void) +:cOsdMenu("Channels", 4) +{ + //TODO + int i = 0; + cChannel *channel; + + while ((channel = Channels.Get(i)) != NULL) { + Add(new cMenuChannelItem(i, channel), i == CurrentChannel); + i++; + } +} + +eOSStatus cMenuChannels::ProcessKey(eKeys Key) +{ + eOSStatus status = cOsdMenu::ProcessKey(Key); + + if (status == osUnknown) { + switch (Key) { + //TODO need to block this if we are already editing a channel! + case kRight: return AddSubMenu(new cMenuEditChannel(Current())); + case kOk: { + cChannel *ch = Channels.Get(Current()); + if (ch) + ch->Switch(); + return osEnd; + } + default: break; + } + } + return status; +} + +// --- cMenuEditTimer -------------------------------------------------------- + +class cMenuEditTimer : public cOsdMenu { +private: + cTimer *timer; + cTimer data; +public: + cMenuEditTimer(int Index); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +cMenuEditTimer::cMenuEditTimer(int Index) +:cOsdMenu("Edit timer", 10) +{ + timer = Timers.Get(Index); + if (timer) { + data = *timer; + 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)); + } +} + +eOSStatus cMenuEditTimer::ProcessKey(eKeys Key) +{ + eOSStatus status = cOsdMenu::ProcessKey(Key); + + if (status == osUnknown) { + if (Key == kOk) { + if (timer && memcmp(timer, &data, sizeof(data)) != 0) { + *timer = data; + Timers.Save(); + isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); + } + status = osBack; + } + } + return status; +} + +// --- cMenuTimerItem -------------------------------------------------------- + +class cMenuTimerItem : public cOsdItem { +private: + int index; + cTimer *timer; +public: + cMenuTimerItem(int Index, cTimer *Timer); + virtual void Set(void); + }; + +cMenuTimerItem::cMenuTimerItem(int Index, cTimer *Timer) +{ + index = Index; + timer = Timer; + Set(); +} + +void cMenuTimerItem::Set(void) +{ + char *buffer = NULL; + asprintf(&buffer, "%d\t%c\t%d\t%s\t%02d:%02d\t%02d:%02d", index + 1, + timer->active ? '>' : ' ', + timer->channel, + timer->PrintDay(timer->day), + timer->start / 100, + timer->start % 100, + timer->stop / 100, + timer->stop % 100); // user visible timer numbers start with '1' + SetText(buffer, false); +} + +// --- cMenuTimer ------------------------------------------------------------ + +class cMenuTimer : public cOsdMenu { +public: + cMenuTimer(void); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +cMenuTimer::cMenuTimer(void) +:cOsdMenu("Timer", 3, 2, 4, 10, 6) +{ + int i = 0; + cTimer *timer; + + while ((timer = Timers.Get(i)) != NULL) { + Add(new cMenuTimerItem(i, timer)); + i++; + } +} + +eOSStatus cMenuTimer::ProcessKey(eKeys Key) +{ + eOSStatus status = cOsdMenu::ProcessKey(Key); + + if (status == osUnknown) { + switch (Key) { + //TODO need to block this if we are already editing a channel! + case kOk: return AddSubMenu(new cMenuEditTimer(Current())); + //TODO new timer + //TODO delete timer + case kLeft: + case kRight: + { + cTimer *timer = Timers.Get(Current()); + if (timer) { + timer->active = (Key == kRight); + isyslog(LOG_INFO, "timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de"); + RefreshCurrent(); + DisplayCurrent(true); + Timers.Save(); + } + } + default: break; + } + } + return status; +} + +// --- cMenuMain ------------------------------------------------------------- + +cMenuMain::cMenuMain(void) +:cOsdMenu("Main") +{ + //TODO + Add(new cOsdItem("Channels", osChannels)); + Add(new cOsdItem("Timer", osTimer)); + Add(new cOsdItem("Recordings", osRecordings)); +} + +eOSStatus cMenuMain::ProcessKey(eKeys Key) +{ + eOSStatus status = cOsdMenu::ProcessKey(Key); + + switch (status) { + case osChannels: return AddSubMenu(new cMenuChannels); + case osTimer: return AddSubMenu(new cMenuTimer); + //TODO Replay + default: break; + } + return status; +} + diff --git a/menu.h b/menu.h new file mode 100644 index 000000000..849d8ee3d --- /dev/null +++ b/menu.h @@ -0,0 +1,21 @@ +/* + * menu.h: The actual menu implementations + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: menu.h 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#ifndef _MENU_H +#define _MENU_H + +#include "osd.h" + +class cMenuMain : public cOsdMenu { +public: + cMenuMain(void); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +#endif //_MENU_H diff --git a/osd.c b/osd.c new file mode 100644 index 000000000..d7ab69935 --- /dev/null +++ b/osd.c @@ -0,0 +1,196 @@ +/* + * osd.c: Abstract On Screen Display layer + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: osd.c 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#include "osd.h" +#include +#include + +// --- cOsdItem -------------------------------------------------------------- + +cOsdItem::cOsdItem(eOSStatus Status) +{ + text = NULL; + offset = -1; + status = Status; + fresh = false; +} + +cOsdItem::cOsdItem(char *Text, eOSStatus Status) +{ + text = NULL; + offset = -1; + status = Status; + fresh = false; + SetText(Text); +} + +cOsdItem::~cOsdItem() +{ + delete text; +} + +void cOsdItem::SetText(char *Text, bool Copy) +{ + delete text; + text = Copy ? strdup(Text) : Text; +} + +void cOsdItem::Display(int Offset, bool Current) +{ + fresh |= Offset >= 0; + Current |= Offset < 0; + if (Offset >= 0) + offset = Offset; + //TODO current if Offset == -1 ??? + if (offset >= 0) + Interface.WriteText(0, offset + 2, text, Current); +} + +eOSStatus cOsdItem::ProcessKey(eKeys Key) +{ + return Key == kOk ? status : osUnknown; +} + +// --- cOsdMenu -------------------------------------------------------------- + +cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4) +{ + title = strdup(Title); + cols[0] = c0; + cols[1] = c1; + cols[2] = c2; + cols[3] = c3; + cols[4] = c4; + first = count = 0; + current = -1; + subMenu = NULL; + Interface.Open(); +} + +cOsdMenu::~cOsdMenu() +{ + delete title; + delete subMenu; + Interface.Clear(); + Interface.Close(); +} + +void cOsdMenu::Add(cOsdItem *Item, bool Current) +{ + cList::Add(Item); + count++; + if (Current && current < 0) + current = Item->Index(); +} + +void cOsdMenu::Display(void) +{ + Interface.Clear(); + Interface.SetCols(cols); + Interface.WriteText(0, 0, title); + if (current < 0 && count) + current = 0; // just for safety - there HAS to be a current item! + int n = 0; + if (current - first >= MAXOSDITEMS) { + first = current - MAXOSDITEMS / 2; + if (first + MAXOSDITEMS > count) + first = count - MAXOSDITEMS; + if (first < 0) + first = 0; + } + for (int i = first; i < count; i++) { + cOsdItem *item = Get(i); + if (item) + item->Display(i - first, i == current); + if (++n == MAXOSDITEMS) //TODO get this from Interface!!! + break; + } +} + +void cOsdMenu::RefreshCurrent(void) +{ + cOsdItem *item = Get(current); + if (item) + item->Set(); +} + +void cOsdMenu::DisplayCurrent(bool Current) +{ + cOsdItem *item = Get(current); + if (item) + item->Display(current - first, Current); +} + +void cOsdMenu::CursorUp(void) +{ + if (current > 0) { + DisplayCurrent(false); + if (--current < first) { + first -= MAXOSDITEMS; + if (first < 0) + first = 0; + Display(); + } + else + DisplayCurrent(true); + } +} + +void cOsdMenu::CursorDown(void) +{ + if (current < count - 1) { + DisplayCurrent(false); + if (++current >= first + MAXOSDITEMS) { + first += MAXOSDITEMS; + if (first > count - MAXOSDITEMS) + first = count - MAXOSDITEMS; + Display(); + } + else + DisplayCurrent(true); + } +} + +eOSStatus cOsdMenu::AddSubMenu(cOsdMenu *SubMenu) +{ + delete subMenu; + subMenu = SubMenu; + subMenu->Display(); + return osContinue; // convenience return value (see cMenuMain) +} + +eOSStatus cOsdMenu::ProcessKey(eKeys Key) +{ + if (subMenu) { + eOSStatus status = subMenu->ProcessKey(Key); + if (status == osBack) { + delete subMenu; + subMenu = NULL; + RefreshCurrent(); + Display(); + status = osContinue; + } + return status; + } + + cOsdItem *item = Get(current); + if (item) { + eOSStatus status = item->ProcessKey(Key); + if (status != osUnknown) + return status; + } + switch (Key) { + case kUp: CursorUp(); break; + case kDown: CursorDown(); break; + case kBack: return osBack; + default: return osUnknown; + } + return osContinue; +} + diff --git a/osd.h b/osd.h new file mode 100644 index 000000000..392f1a752 --- /dev/null +++ b/osd.h @@ -0,0 +1,68 @@ +/* + * osd.h: Abstract On Screen Display layer + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: osd.h 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#ifndef __OSD_H +#define __OSD_H + +#include "config.h" +#include "interface.h" +#include "tools.h" + +#define MAXOSDITEMS 9 + +enum eOSStatus { osUnknown, + osContinue, + osProcessed, + osChannels, + osTimer, + osRecordings, + osBack, + osEnd, + }; + +class cOsdItem : public cListObject { +private: + char *text; + int offset; + eOSStatus status; +protected: + bool fresh; +public: + cOsdItem(eOSStatus Status = osUnknown); + cOsdItem(char *Text, eOSStatus Status = osUnknown); + virtual ~cOsdItem(); + void SetText(char *Text, bool Copy = true); + char *Text(void) { return text; } + void Display(int Offset = -1, bool Current = false); + virtual void Set(void) {} + virtual eOSStatus ProcessKey(eKeys Key); + }; + +class cOsdMenu : public cList { +private: + char *title; + int cols[cInterface::MaxCols]; + int first, current, count; + cOsdMenu *subMenu; +protected: + void RefreshCurrent(void); + void DisplayCurrent(bool Current); + void CursorUp(void); + void CursorDown(void); + eOSStatus AddSubMenu(cOsdMenu *SubMenu); +public: + cOsdMenu(char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0); + virtual ~cOsdMenu(); + int Current(void) { return current; } + void Add(cOsdItem *Item, bool Current = false); + void Display(void); + virtual eOSStatus ProcessKey(eKeys Key); + }; + +#endif //__OSD_H diff --git a/osm.c b/osm.c new file mode 100644 index 000000000..cc017451a --- /dev/null +++ b/osm.c @@ -0,0 +1,119 @@ +/* + * osm.c: On Screen Menu for the Video Disk Recorder + * + * Copyright (C) 2000 Klaus Schmidinger + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * The author can be reached at kls@cadsoft.de + * + * The project's page is at http://www.cadsoft.de/people/kls/vdr + * + * $Id: osm.c 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#include "config.h" +#include "dvbapi.h" +#include "interface.h" +#include "menu.h" +#include "tools.h" + +#ifdef DEBUG_REMOTE +#define KEYS_CONF "keys-pc.conf" +#else +#define KEYS_CONF "keys.conf" +#endif + +int main(int argc, char *argv[]) +{ + openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); + isyslog(LOG_INFO, "started"); + + Channels.Load("channels.conf"); + Timers.Load("timers.conf"); + if (!Keys.Load(KEYS_CONF)) + Interface.LearnKeys(); + Interface.Init(); + + cChannel::SwitchTo(CurrentChannel); + + cMenuMain *Menu = NULL; + cTimer *Timer = NULL; + cDvbRecorder *Recorder = NULL; + + for (;;) { + //TODO check for free disk space and delete files if necessary/possible + // in case there is an ongoing recording + if (!Timer && (Timer = cTimer::GetMatch()) != NULL) { + // switch to channel: + isyslog(LOG_INFO, "timer %d start", Timer->Index() + 1); + delete Menu; + Menu = NULL; + cChannel::SwitchTo(Timer->channel - 1); + ChannelLocked = true; + // start recording: + delete Recorder; + Recorder = new cDvbRecorder; + //TODO special filename handling!!! + if (!Recorder->Record(Timer->file, Timer->quality)) { + delete Recorder; + Recorder = NULL; + } + } + if (Timer) { + if (!Timer->Matches()) { + // stop recording: + if (Recorder) + Recorder->Stop(); + // end timer: + ChannelLocked = false; + isyslog(LOG_INFO, "timer %d stop", Timer->Index() + 1); + Timer = NULL; + //TODO switch back to the previous channel??? + //TODO clear single event timer??? + } + } + eKeys key = Interface.GetKey(); + if (Menu) { + switch (Menu->ProcessKey(key)) { + default: if (key != kMenu) + break; + case osBack: + case osEnd: delete Menu; + Menu = NULL; + break; + } + } + else { + switch (key) { + case kMenu: Menu = new cMenuMain; + Menu->Display(); + break; + case kUp: + case kDown: { + int n = CurrentChannel + (key == kUp ? 1 : -1); + cChannel *channel = Channels.Get(n); + if (channel) + channel->Switch(); + } + break; + default: break; + } + } + } + closelog(); + return 1; +} diff --git a/remote.c b/remote.c new file mode 100644 index 000000000..c2fb36f61 --- /dev/null +++ b/remote.c @@ -0,0 +1,257 @@ +/* + * remote.c: Interface to the Remote Control Unit + * + * 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 $ + */ + +#include "remote.h" +#include +#include +#include +#include +#include +#include +#include +#include "tools.h" + +cRcIo::cRcIo(char *DeviceName) +{ + dp = 0; + mode = modeB; + code = 0; + address = 0xFFFF; + t = 0; + firstTime = lastTime = 0; + minDelta = 0; + lastCommand = 0; + if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) { + struct termios t; + if (tcgetattr(f, &t) == 0) { + cfsetspeed(&t, B9600); + cfmakeraw(&t); + if (tcsetattr(f, TCSAFLUSH, &t) == 0) + return; + } + close(f); + } + f = -1; +} + +cRcIo::~cRcIo() +{ + if (f >= 0) + close(f); +} + +int cRcIo::ReceiveByte(bool Wait) +{ + // Returns the byte if one was received within 1 second, -1 otherwise + if (f >= 0) { + fd_set set; + struct timeval timeout; + timeout.tv_sec = Wait ? 1 : 0; + timeout.tv_usec = Wait ? 0 : 10000; + FD_ZERO(&set); + FD_SET(f, &set); + if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) { + if (FD_ISSET(f, &set)) { + unsigned char b; + if (read(f, &b, 1) == 1) + return b; + } + } + } + return -1; +} + +bool cRcIo::SendByteHandshake(unsigned char c) +{ + if (f >= 0 && write(f, &c, 1) == 1) { + for (int reply = ReceiveByte(); reply >= 0;) { + if (reply == c) + return true; + else if (reply == 'X') { + // skip any incoming RC code - it will come again + for (int i = 6; i--;) { + if (ReceiveByte(false) < 0) + return false; + } + } + else + return false; + } + } + return false; +} + +bool cRcIo::SendByte(unsigned char c) +{ + for (int retry = 5; retry--;) { + if (SendByteHandshake(c)) + return true; + } + return false; +} + +void cRcIo::Flush(int WaitSeconds) +{ + time_t t0 = time(NULL); + + for (;;) { + while (ReceiveByte(false) >= 0) + t0 = time(NULL); + if (time(NULL) - t0 >= WaitSeconds) + break; + } +} + +bool cRcIo::SetCode(unsigned char Code, unsigned short Address) +{ + code = Code; + address = Address; + minDelta = 200; + return SendCommand(code); +} + +bool cRcIo::SetMode(unsigned char Mode) +{ + mode = Mode; + return SendCommand(mode); +} + +bool cRcIo::GetCommand(unsigned int *Command, unsigned short *Address) +{ +#pragma pack(1) + union { + struct { + unsigned short address; + unsigned int command; + } data; + unsigned char raw[6]; + } buffer; +#pragma pack() + + Flush(); + if (Command && ReceiveByte() == 'X') { + for (int i = 0; i < 6; i++) { + int b = ReceiveByte(false); + if (b >= 0) + buffer.raw[i] = b; + else + return false; + } + if (Address) + *Address = ntohs(buffer.data.address); // the PIC sends bytes in "network order" + else if (address != ntohs(buffer.data.address)) + return false; + *Command = ntohl(buffer.data.command); + if (code == 'B' && address == 0x0000 && *Command == 0x00004000) + // Well, well, if it isn't the "d-box"... + // This remote control sends the above command before and after + // each keypress - let's just drop this: + return false; + if (*Command == lastCommand) { + // let's have a timeout to avoid getting overrun by commands + int now = time_ms(); + int delta = now - lastTime; + if (delta < minDelta) + minDelta = delta; // dynamically adjust to the smallest delta + lastTime = now; + if (delta < minDelta * 1.3) { // if commands come in rapidly... + if (now - firstTime < 250) + return false; // ...repeat function kicks in after 250ms + return true; + } + } + lastTime = firstTime = time_ms(); + lastCommand = *Command; + return true; + } + if (time(NULL) - t > 60) { + SendCommand(code); // in case the PIC listens to the wrong code + t = time(NULL); + } + return false; +} + +bool cRcIo::SendCommand(unsigned char Cmd) +{ + return SendByte(Cmd | 0x80); +} + +bool cRcIo::Digit(int n, int v) +{ + return SendByte(((n & 0x03) << 5) | (v & 0x0F) | (((dp >> n) & 0x01) << 4)); +} + +bool cRcIo::Number(int n, bool Hex) +{ + if (!Hex) { + char buf[8]; + sprintf(buf, "%4d", n & 0xFFFF); + n = 0; + for (char *d = buf; *d; d++) { + if (*d == ' ') + *d = 0xF; + n = (n << 4) | ((*d - '0') & 0x0F); + } + } + for (int i = 0; i < 4; i++) { + if (!Digit(i, n)) + return false; + n >>= 4; + } + return SendCommand(mode); +} + +bool cRcIo::String(char *s) +{ + char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP "; + int n = 0; + + for (int i = 0; *s && i < 4; s++, i++) { + n <<= 4; + for (char *c = chars; *c; c++) { + if (*c == *s) { + n |= c - chars; + break; + } + } + } + return Number(n, mode == modeH); +} + +bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address) +{ + // Caller should initialize 'Code' to 0 and call DetectCode() + // until it returns true. Whenever DetectCode() returns false + // and 'Code' is not 0, the caller can use 'Code' to display + // a message like "Trying code '%c'". If false is returned and + // 'Code' is 0, all possible codes have been tried and the caller + // can either stop calling DetectCode() (and give some error + // message), or start all over again. + if (*Code < 'A' || *Code > 'D') { + *Code = 'A'; + return false; + } + if (*Code <= 'D') { + SetMode(modeH); + char buf[5]; + sprintf(buf, "C0D%c", *Code); + String(buf); + SetCode(*Code, 0); + unsigned int Command; + if (GetCommand(&Command, Address)) + return true; + if (*Code < 'D') { + (*Code)++; + return false; + } + } + *Code = 0; + return false; +} + diff --git a/remote.h b/remote.h new file mode 100644 index 000000000..682792912 --- /dev/null +++ b/remote.h @@ -0,0 +1,43 @@ +/* + * remote.h: Interface to the Remote Control Unit + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: remote.h 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#ifndef __REMOTE_H +#define __REMOTE_H + +#include +#include + +class cRcIo { +private: + int f; + unsigned char dp, code, mode; + unsigned short address; + time_t t; + int firstTime, lastTime, minDelta; + unsigned int lastCommand; + bool SendCommand(unsigned char Cmd); + int ReceiveByte(bool Wait = true); + bool SendByteHandshake(unsigned char c); + bool SendByte(unsigned char c); +public: + enum { modeH = 'h', modeB = 'b', modeS = 's' }; + cRcIo(char *DeviceName); + ~cRcIo(); + void Flush(int WaitSeconds = 0); + bool SetCode(unsigned char Code, unsigned short Address); + bool SetMode(unsigned char Mode); + bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); + bool Digit(int n, int v); + bool Number(int n, bool Hex = false); + void Points(unsigned char Dp) { dp = Dp; } + bool String(char *s); + bool DetectCode(unsigned char *Code, unsigned short *Address); + }; + +#endif //__REMOTE_H diff --git a/timers.conf b/timers.conf new file mode 100644 index 000000000..ac002a996 --- /dev/null +++ b/timers.conf @@ -0,0 +1,9 @@ +1:2:-----S-:2210:2320:H:99:99:Wochenshow +1:3:M------:2125:2205:H:99:99:Neues +1:15:MTWTF--:1828:1901:M:10:5:nano +1:2:-----S-:1737:1827:H:99:99:kls/StarTrek/DS9 +1:3:M------:2110:2230:H:99:99:SevenDays +1:3:---T---:2215:2300:H:99:99:SwItch +0:1:1:0:0:H:99:99:# +0:1:1:0:0:H:99:99:# +0:1:1:0:0:L:0:5:# diff --git a/tools.c b/tools.c new file mode 100644 index 000000000..e0eeaefda --- /dev/null +++ b/tools.c @@ -0,0 +1,124 @@ +/* + * tools.c: Various tools + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: tools.c 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#include "tools.h" +#include +#include + +int time_ms(void) +{ + struct timeval t; + if (gettimeofday(&t, NULL) == 0) + return t.tv_sec * 1000 + t.tv_usec / 1000; + return 0; +} + +// --- cListObject ----------------------------------------------------------- + +cListObject::cListObject(void) +{ + prev = next = NULL; +} + +cListObject::~cListObject() +{ +} + +void cListObject::Append(cListObject *Object) +{ + next = Object; + Object->prev = this; +} + +void cListObject::Unlink(void) +{ + if (next) + next->prev = prev; + if (prev) + prev->next = next; +} + +int cListObject::Index(void) +{ + cListObject *p = prev; + int i = 0; + + while (p) { + i++; + p = p->prev; + } + return i; +} + +// --- cListBase ------------------------------------------------------------- + +cListBase::cListBase(void) +{ + objects = lastObject = NULL; +} + +cListBase::~cListBase() +{ + Clear(); + while (objects) { + cListObject *object = objects->Next(); + delete objects; + objects = object; + } +} + +void cListBase::Add(cListObject *Object) +{ + if (lastObject) + lastObject->Append(Object); + else + objects = Object; + lastObject = Object; +} + +void cListBase::Del(cListObject *Object) +{ + if (Object == objects) + objects = Object->Next(); + if (Object == lastObject) + lastObject = Object->Prev(); + Object->Unlink(); + delete Object; +} + +void cListBase::Clear(void) +{ + while (objects) { + cListObject *object = objects->Next(); + delete objects; + objects = object; + } + objects = lastObject = NULL; +} + +cListObject *cListBase::Get(int Index) +{ + cListObject *object = objects; + while (object && Index-- > 0) + object = object->Next(); + return object; +} + +int cListBase::Count(void) +{ + int n = 0; + cListObject *object = objects; + + while (object) { + n++; + object = object->Next(); + } + return n; +} + diff --git a/tools.h b/tools.h new file mode 100644 index 000000000..43f852542 --- /dev/null +++ b/tools.h @@ -0,0 +1,54 @@ +/* + * tools.h: Various tools + * + * See the main source file 'osm.c' for copyright information and + * how to reach the author. + * + * $Id: tools.h 1.1 2000/02/19 13:36:48 kls Exp $ + */ + +#ifndef __TOOLS_H +#define __TOOLS_H + +#include + +//TODO +#define dsyslog syslog +#define esyslog syslog +#define isyslog syslog + +class cListObject { +private: + cListObject *prev, *next; +public: + cListObject(void); + virtual ~cListObject(); + void Append(cListObject *Object); + void Unlink(void); + int Index(void); + cListObject *Prev(void) { return prev; } + cListObject *Next(void) { return next; } + }; + +class cListBase { +protected: + cListObject *objects, *lastObject; + cListBase(void); +public: + virtual ~cListBase(); + void Add(cListObject *Object); + void Del(cListObject *Object); + void Clear(void); + cListObject *Get(int Index); + int Count(void); + }; + +template class cList : public cListBase { +public: + T *Get(int Index) { return (T *)cListBase::Get(Index); } + T *First(void) { return (T *)objects; } + }; + +int time_ms(void); + +#endif //__TOOLS_H From 6feebe674c09b65e43012bf439c201cfb65aa82c Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 11 Mar 2000 18:00:00 +0100 Subject: [PATCH 002/307] Version 0.02 - Fixed compilation with only DEBUG_REMOTE=1. - Menus now use colors. - 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). --- HISTORY | 12 ++ Makefile | 11 +- README | 36 +++- TODO | 5 +- channels.conf | 2 +- config.c | 118 +++++++++---- config.h | 16 +- dvbapi.c | 168 ++++++++++++++++--- dvbapi.h | 70 ++++++-- interface.c | 202 ++++++++++++---------- interface.h | 20 ++- keys-pc.conf | Bin 225 -> 283 bytes keys.conf | 4 + menu.c | 454 ++++++++++++++++++++++++++++++++++++++++---------- menu.h | 4 +- osd.c | 131 ++++++++++----- osd.h | 42 +++-- osm.c | 57 ++++--- recording.c | 238 ++++++++++++++++++++++++++ recording.h | 56 +++++++ timers.conf | 11 +- tools.c | 71 +++++++- tools.h | 16 +- 23 files changed, 1378 insertions(+), 366 deletions(-) create mode 100644 HISTORY create mode 100644 recording.c create mode 100644 recording.h diff --git a/HISTORY b/HISTORY new file mode 100644 index 000000000..f7eeb65ef --- /dev/null +++ b/HISTORY @@ -0,0 +1,12 @@ +Video Disk Recorder OSM Revision History +---------------------------------------- + +2000-02-19: Version 0.01 (Initial revision). + +2000-03-11: Version 0.02 + +- Fixed compilation with only DEBUG_REMOTE=1. +- Menus now use colors. +- 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). diff --git a/Makefile b/Makefile index 6696dff11..b5153cfc8 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,9 @@ # See the main source file 'osm.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.1 2000/02/19 13:36:48 kls Exp $ +# $Id: Makefile 1.2 2000/03/05 13:51:57 kls Exp $ -OBJS = config.o dvbapi.o interface.o menu.o osd.o remote.o tools.o osm.o +OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o tools.o osm.o ifdef DEBUG_REMOTE DEFINES += -DDEBUG_REMOTE @@ -24,9 +24,10 @@ all: osm config.o : config.c config.h dvbapi.h interface.h tools.h dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h -menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h tools.h -osd.o : osd.c config.h interface.h osd.h tools.h -osm.o : osm.c config.h dvbapi.h interface.h menu.h osd.h tools.h +menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h +osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h +osm.o : osm.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h +recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h remote.o : remote.c remote.h tools.h tools.o : tools.c tools.h diff --git a/README b/README index e4fa836ec..5c6928cb4 100644 --- a/README +++ b/README @@ -36,10 +36,34 @@ 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). + 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. +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. There are two macros you can use to customize the 'osm' program at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call @@ -75,10 +99,10 @@ 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 tranfer mode and timing of your remote control unit, +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 os the key +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. @@ -97,9 +121,6 @@ confirms any changes (or switches to a channel in the "Channels" menu). The "Back" key goes back one level in the menu structure, discarding any changes that might have been made in the current menu. -In the "Channels" menu, the current channel can be edited by pressing -the "Right" key. - In the "Timers" menu, the current timer can be enabled or disabled with the "Right" or "Left" key, respectively (enabled timers are marked with ">"). "Ok" here opens the "Edit timer" menu. @@ -110,6 +131,9 @@ character as in "[R]TL"), selecting the desired character position with "Left" and "Right", and changing the character with the "Up" and "Down" keys. "Ok" then confirms the changes. +The "Red", "Green", "Yellow" and "Blue" buttons have special meanings +in the various menus and are listed at the bottom of the on-screen-display. + At any point in the menu system, pressing the "Menu" key again will immediately leave the menu system. diff --git a/TODO b/TODO index 32793469c..35e3aa306 100644 --- a/TODO +++ b/TODO @@ -1,13 +1,12 @@ TODO list for the Video Disk Recorder project --------------------------------------------- -* Implement a way to add and delete channels and timers. * Implement recording to disk and playback from disk. -* Implement disk file management (delete old/viewed files to make - room for new recordings if necessary). * 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). + Maybe we can do this with only a single card, if the card + driver/firmware allows simultaneuos record/playback? * Implement "on-disk editing" to allow "cutting out" of certain scenes in order to archive them (or, reversely, cut out commercial breaks). diff --git a/channels.conf b/channels.conf index 9daca0aff..1b5796363 100644 --- a/channels.conf +++ b/channels.conf @@ -42,7 +42,7 @@ 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:11876:h:1:27500:306:322 +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 diff --git a/config.c b/config.c index 50315691e..af97a5cb4 100644 --- a/config.c +++ b/config.c @@ -4,37 +4,40 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: config.c 1.2 2000/03/05 16:14:27 kls Exp $ */ #include "config.h" #include #include -#include #include "dvbapi.h" #include "interface.h" // -- cKeys ------------------------------------------------------------------ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! - { kUp, "Up", 0 }, - { kDown, "Down", 0 }, - { kMenu, "Menu", 0 }, - { kOk, "Ok", 0 }, - { kBack, "Back", 0 }, - { kLeft, "Left", 0 }, - { kRight, "Right", 0 }, - { k0, "0", 0 }, - { k1, "1", 0 }, - { k2, "2", 0 }, - { k3, "3", 0 }, - { k4, "4", 0 }, - { k5, "5", 0 }, - { k6, "6", 0 }, - { k7, "7", 0 }, - { k8, "8", 0 }, - { k9, "9", 0 }, - { kNone, "", 0 }, + { kUp, "Up", 0 }, + { kDown, "Down", 0 }, + { kMenu, "Menu", 0 }, + { kOk, "Ok", 0 }, + { kBack, "Back", 0 }, + { kLeft, "Left", 0 }, + { kRight, "Right", 0 }, + { k0, "0", 0 }, + { k1, "1", 0 }, + { k2, "2", 0 }, + { k3, "3", 0 }, + { k4, "4", 0 }, + { k5, "5", 0 }, + { k6, "6", 0 }, + { k7, "7", 0 }, + { k8, "8", 0 }, + { k9, "9", 0 }, + { kRed, "Red", 0 }, + { kGreen, "Green", 0 }, + { kYellow, "Yellow", 0 }, + { kBlue, "Blue", 0 }, + { kNone, "", 0 }, }; cKeys::cKeys(void) @@ -160,6 +163,17 @@ cChannel::cChannel(void) *name = 0; } +cChannel::cChannel(const cChannel *Channel) +{ + strcpy(name, Channel ? Channel->name : "Pro7"); + frequency = Channel ? Channel->frequency : 12480; + polarization = Channel ? Channel->polarization : 'v'; + diseqc = Channel ? Channel->diseqc : 1; + srate = Channel ? Channel->srate : 27500; + vpid = Channel ? Channel->vpid : 255; + apid = Channel ? Channel->apid : 256; +} + bool cChannel::Parse(char *s) { char *buffer = NULL; @@ -203,6 +217,17 @@ bool cChannel::SwitchTo(int i) cTimer::cTimer(void) { + startTime = stopTime = 0; + recording = false; + active = 1; + channel = CurrentChannel + 1; + day = 1; //XXX today! + start = 0; //XXX now! + stop = 0; //XXX now + 2h! +//TODO VPS??? + quality = 'H'; + priority = 99; + lifetime = 99; *file = 0; } @@ -211,6 +236,13 @@ int cTimer::TimeToInt(int t) return (t / 100 * 60 + t % 100) * 60; } +time_t cTimer::Day(time_t t) +{ + struct tm d = *localtime(&t); + d.tm_hour = d.tm_min = d.tm_sec = 0; + return mktime(&d); +} + int cTimer::ParseDay(char *s) { char *tail; @@ -270,13 +302,17 @@ 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; } +bool cTimer::IsSingleEvent(void) +{ + return (day & 0x80000000) == 0; +} + bool cTimer::Matches(void) { if (active) { time_t t = time(NULL); - struct tm *now = localtime(&t); - int weekday = now->tm_wday == 0 ? 6 : now->tm_wday - 1; // we start with monday==0! - int current = (now->tm_hour * 60 + now->tm_min) * 60 + now->tm_sec; + struct tm now = *localtime(&t); + int weekday = now.tm_wday == 0 ? 6 : now.tm_wday - 1; // we start with monday==0! int begin = TimeToInt(start); int end = TimeToInt(stop); bool twoDays = (end < begin); @@ -291,20 +327,44 @@ bool cTimer::Matches(void) yesterdayMatches = true; } } - else if (day == now->tm_mday) + else if (day == now.tm_mday) todayMatches = true; else if (twoDays) { - t -= 86400; - now = localtime(&t); - if (day == now->tm_mday) + time_t ty = t - SECSINDAY; + if (day == localtime(&ty)->tm_mday) yesterdayMatches = true; } - return (todayMatches && current >= begin && (current <= end || twoDays)) - || (twoDays && yesterdayMatches && current <= end); + if (todayMatches || (twoDays && yesterdayMatches)) { + startTime = Day(t - (yesterdayMatches ? SECSINDAY : 0)) + begin; + stopTime = startTime + (twoDays ? SECSINDAY - begin + end : end - begin); + } + else + startTime = stopTime = 0; + return startTime <= t && t <= stopTime; } return false; } +time_t cTimer::StartTime(void) +{ + if (!startTime) + Matches(); + return startTime; +} + +time_t cTimer::StopTime(void) +{ + if (!stopTime) + Matches(); + return stopTime; +} + +void cTimer::SetRecording(bool Recording) +{ + recording = Recording; + isyslog(LOG_INFO, "timer %d %s", Index() + 1, recording ? "start" : "stop"); +} + cTimer *cTimer::GetMatch(void) { cTimer *t = (cTimer *)Timers.First(); diff --git a/config.h b/config.h index 3abb7a1ac..51fd22e01 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: config.h 1.2 2000/03/05 14:58:23 kls Exp $ */ #ifndef __CONFIG_H @@ -12,6 +12,7 @@ #include #include +#include #include "tools.h" #define MaxBuffer 1000 @@ -25,6 +26,10 @@ enum eKeys { // "Up" and "Down" must be the first two keys! kLeft, kRight, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, + kRed, + kGreen, + kYellow, + kBlue, kNone }; @@ -60,6 +65,7 @@ class cChannel : public cListObject { int vpid; int apid; cChannel(void); + cChannel(const cChannel *Channel); bool Parse(char *s); bool Save(FILE *f); bool Switch(void); @@ -67,8 +73,11 @@ class cChannel : public cListObject { }; class cTimer : public cListObject { +private: + time_t startTime, stopTime; public: enum { MaxFileName = 256 }; + bool recording; int active; int channel; int day; @@ -82,9 +91,14 @@ class cTimer : public cListObject { cTimer(void); bool Parse(char *s); bool Save(FILE *f); + bool IsSingleEvent(void); bool Matches(void); + time_t StartTime(void); + time_t StopTime(void); + void SetRecording(bool Recording); static cTimer *GetMatch(void); static int TimeToInt(int t); + static time_t Day(time_t t); static int ParseDay(char *s); static char *PrintDay(int d); }; diff --git a/dvbapi.c b/dvbapi.c index 5597fbd50..484a22e56 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,20 +4,14 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: dvbapi.c 1.2 2000/03/11 10:39:09 kls Exp $ */ -// FIXME: these should be defined in ../DVB/driver/dvb.h!!! -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; - #include "dvbapi.h" #include #include #include #include -#include "../DVB/driver/dvb.h" #include "interface.h" #include "tools.h" @@ -60,6 +54,7 @@ bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, i cDvbRecorder::cDvbRecorder(void) { + recording = false; } cDvbRecorder::~cDvbRecorder() @@ -67,18 +62,41 @@ cDvbRecorder::~cDvbRecorder() Stop(); } +bool cDvbRecorder::Recording(void) +{ + return recording; +} + bool cDvbRecorder::Record(const char *FileName, char Quality) { isyslog(LOG_INFO, "record %s (%c)", FileName, Quality); - return true; + if (MakeDirs(FileName)) { + FILE *f = fopen(FileName, "a"); + if (f) { + fprintf(f, "%s, %c\n", FileName, Quality); + fclose(f); + recording = true; + // TODO + Interface.Error("Recording not yet implemented!"); + return true; + } + else { + Interface.Error("Can't write to file!"); + return false; + } + } // TODO return false; } bool cDvbRecorder::Play(const char *FileName, int Frame) { - isyslog(LOG_INFO, "play %s (%d)", FileName, Frame); - // TODO + if (!recording) { + isyslog(LOG_INFO, "play %s (%d)", FileName, Frame); + // TODO + Interface.Error("Playback not yet implemented!"); + return true; + } return false; } @@ -106,6 +124,7 @@ bool cDvbRecorder::Pause(void) void cDvbRecorder::Stop(void) { isyslog(LOG_INFO, "stop"); + recording = false; // TODO } @@ -116,9 +135,57 @@ int cDvbRecorder::Frame(void) return 0; } -// --------------------------------------------------------------------------- +// --- cDvbOsd --------------------------------------------------------------- -static void DvbOsdCmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, void *data = NULL) +cDvbOsd::cDvbOsd(void) +{ + cols = rows = 0; +#ifdef DEBUG_OSD + memset(&colorPairs, 0, sizeof(colorPairs)); + initscr(); + start_color(); + keypad(stdscr, TRUE); + nonl(); + cbreak(); + noecho(); + timeout(1000); + leaveok(stdscr, TRUE); + window = stdscr; +#endif +#ifdef DEBUG_REMOTE + initscr(); + keypad(stdscr, TRUE); + nonl(); + cbreak(); + noecho(); + timeout(1000); +#endif +} + +cDvbOsd::~cDvbOsd() +{ + Close(); +} + +#ifdef DEBUG_OSD +void cDvbOsd::SetColor(eDvbColor colorFg, eDvbColor colorBg) +{ + int color = (colorBg << 16) | colorFg | 0x80000000; + for (int i = 0; i < MaxColorPairs; i++) { + if (!colorPairs[i]) { + colorPairs[i] = color; + init_pair(i + 1, colorFg, colorBg); + wattrset(window, COLOR_PAIR(i + 1)); + break; + } + else if (color == colorPairs[i]) { + wattrset(window, COLOR_PAIR(i + 1)); + break; + } + } +} +#else +void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) { int v = open(VIDEODEVICE, O_RDWR); @@ -130,37 +197,88 @@ static void DvbOsdCmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, in dc.y0 = y0; dc.x1 = x1; dc.y1 = y1; - dc.data = data; + dc.data = (void *)data; ioctl(v, VIDIOCSOSDCOMMAND, &dc); close(v); } else Interface.Error("can't open VIDEODEVICE");//XXX } +#endif + +void cDvbOsd::Open(int w, int h) +{ + cols = w; + rows = h; +#ifdef DEBUG_OSD + //XXX size... + #define B2C(b) (((b) * 1000) / 255) + #define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b)) +#else + w *= charWidth; + h *= lineHeight; + int x = (720 - w) / 2; //TODO PAL vs. NTSC??? + int y = (576 - h) / 2; + Cmd(OSD_Open, 4, x, y, x + w - 1, y + h - 1); + #define SETCOLOR(n, r, g, b, o) Cmd(OSD_SetColor, n, r, g, b, o) +#endif + SETCOLOR(clrBackground, 0x00, 0x00, 0x00, 127); // background 50% gray + SETCOLOR(clrBlack, 0x00, 0x00, 0x00, 255); + SETCOLOR(clrRed, 0xFC, 0x14, 0x14, 255); + SETCOLOR(clrGreen, 0x24, 0xFC, 0x24, 255); + SETCOLOR(clrYellow, 0xFC, 0xC0, 0x24, 255); + SETCOLOR(clrBlue, 0x00, 0x00, 0xFC, 255); + SETCOLOR(clrCyan, 0x00, 0xFC, 0xFC, 255); + SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255); + SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255); +} -void DvbOsdOpen(int x, int y, int w, int h) +void cDvbOsd::Close(void) { - DvbOsdCmd(OSD_Open, 1, x, y, x + w - 1, y + h - 1); - DvbOsdCmd(OSD_SetColor, 0, 0, 0, 0, 127); // background 50% gray - DvbOsdCmd(OSD_SetColor, 1, 255, 255, 255, 255); // text white +#ifndef DEBUG_OSD + Cmd(OSD_Close); +#endif } -void DvbOsdClose(void) +void cDvbOsd::Clear(void) { - DvbOsdCmd(OSD_Close); +#ifdef DEBUG_OSD + SetColor(clrBackground, clrBackground); + Fill(0, 0, cols, rows, clrBackground); +#else + Cmd(OSD_Clear); +#endif } -void DvbOsdClear(void) +void cDvbOsd::Fill(int x, int y, int w, int h, eDvbColor color) { - DvbOsdCmd(OSD_Clear); + if (x < 0) x = cols + x; + if (y < 0) y = rows + y; +#ifdef DEBUG_OSD + SetColor(color, color); + for (int r = 0; r < h; r++) { + wmove(window, y + r, x); // ncurses wants 'y' before 'x'! + whline(window, ' ', w); + } +#else + Cmd(OSD_FillBlock, color, x * charWidth, y * lineHeight, (x + w) * charWidth - 1, (y + h) * lineHeight - 1); +#endif } -void DvbOsdClrEol(int x, int y) +void cDvbOsd::ClrEol(int x, int y, eDvbColor color) { - DvbOsdCmd(OSD_FillBlock, 0, x, y * DvbOsdLineHeight, x + 490, (y + 1) * DvbOsdLineHeight);//XXX + Fill(x, y, cols - x, 1, color); } -void DvbOsdText(int x, int y, char *s) +void cDvbOsd::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg) { - DvbOsdCmd(OSD_Text, 1, x, y, 1, 0, s); + if (x < 0) x = cols + x; + if (y < 0) y = rows + y; +#ifdef DEBUG_OSD + SetColor(colorFg, colorBg); + wmove(window, y, x); // ncurses wants 'y' before 'x'! + waddstr(window, s); +#else + Cmd(OSD_Text, (int(colorBg) << 16) | colorFg, x * charWidth, y * lineHeight, 1, 0, s); +#endif } diff --git a/dvbapi.h b/dvbapi.h index 6a8f0400e..2e8406ee8 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,23 +4,51 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: dvbapi.h 1.2 2000/03/06 19:47:20 kls Exp $ */ #ifndef __DVBAPI_H #define __DVBAPI_H -const int DvbOsdCharWidth = 12; //XXX -const int DvbOsdLineHeight = 25; +// FIXME: these should be defined in ../DVB/driver/dvb.h!!! +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; +#if defined(DEBUG_OSD) || defined(DEBUG_REMOTE) +#include +#endif +#include "../DVB/driver/dvb.h" + +enum eDvbColor { clrBackground, +#ifndef DEBUG_OSD + clrOBSOLETE, //FIXME apparently color '1' can't be used as FgColor with e.g. clrRed as BgColor??? + clrBlack, +#else + clrBlack = clrBackground, +#endif + clrRed, + clrGreen, + clrYellow, + clrBlue, + clrMagenta, + clrCyan, + clrWhite, + }; + extern const char *DvbQuality; // Low, Medium, High bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid); class cDvbRecorder { +private: + bool recording; 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. @@ -30,8 +58,9 @@ class cDvbRecorder { 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 and will do an implicit Pause() there. + // 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. @@ -56,10 +85,29 @@ class cDvbRecorder { // The very first frame has the number 1. }; -void DvbOsdOpen(int x, int y, int w, int h); -void DvbOsdClose(void); -void DvbOsdClear(void); -void DvbOsdClrEol(int x, int y); -void DvbOsdText(int x, int y, char *s); - +class cDvbOsd { +private: + enum { charWidth = 12, // average character width + lineHeight = 27 // smallest text height + }; +#ifdef DEBUG_OSD + WINDOW *window; + 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; +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); + }; + #endif //__DVBAPI_H diff --git a/interface.c b/interface.c index 58c28f1f9..6a4b2a4e2 100644 --- a/interface.c +++ b/interface.c @@ -4,20 +4,21 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: interface.c 1.2 2000/03/06 19:45:03 kls Exp $ */ #include "interface.h" -#include #include -#include "dvbapi.h" #include "remote.h" +#define MenuLines 15 +#define MenuColumns 40 + #ifndef DEBUG_REMOTE cRcIo RcIo("/dev/ttyS1");//XXX #endif -WINDOW *window; +cDvbOsd DvbOsd; //XXX member of cInterface??? cInterface Interface; @@ -25,16 +26,6 @@ cInterface::cInterface(void) { open = 0; cols[0] = 0; -#ifdef DEBUG_OSD - initscr(); - keypad(stdscr, TRUE); - nonl(); - cbreak(); - noecho(); - leaveok(stdscr, TRUE); - window = stdscr; -#else -#endif } void cInterface::Init(void) @@ -46,24 +37,14 @@ void cInterface::Init(void) void cInterface::Open(void) { - if (!open++) { -#ifdef DEBUG_OSD -#else -//TODO - DvbOsdOpen(100, 100, 500, 400); -#endif - } + if (!open++) + DvbOsd.Open(MenuColumns, MenuLines); } void cInterface::Close(void) { - if (!--open) { -#ifdef DEBUG_OSD -#else -//TODO - DvbOsdClose(); -#endif - } + if (!--open) + DvbOsd.Close(); } unsigned int cInterface::GetCh(void) @@ -71,9 +52,9 @@ unsigned int cInterface::GetCh(void) #ifdef DEBUG_REMOTE return getch(); #else -#ifdef DEBUG_OSD - wrefresh(window);//XXX -#endif +//XXX #ifdef DEBUG_OSD +//XXX wrefresh(window);//XXX +//XXX #endif unsigned int Command; return RcIo.GetCommand(&Command) ? Command : 0; #endif @@ -84,16 +65,28 @@ eKeys cInterface::GetKey(void) return Keys.Get(GetCh()); } +eKeys cInterface::Wait(int Seconds) +{ + int t0 = time_ms(); + + while (time_ms() - t0 < Seconds * 1000) { + eKeys Key = GetKey(); + if (Key != kNone) + return Key; + } + return kNone; +} + void cInterface::Clear(void) { - if (open) { -#ifdef DEBUG_OSD - wclear(window); -#else -//TODO - DvbOsdClear(); -#endif - } + if (open) + DvbOsd.Clear(); +} + +void cInterface::ClearEol(int x, int y, eDvbColor Color) +{ + if (open) + DvbOsd.ClrEol(x, y, Color); } void cInterface::SetCols(int *c) @@ -105,34 +98,22 @@ void cInterface::SetCols(int *c) } } -void cInterface::Write(int x, int y, char *s) +void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor) { - if (open) { -#ifdef DEBUG_OSD - wmove(window, y, x); // ncurses wants 'y' before 'x'! - waddstr(window, s); -#else - DvbOsdText(x * DvbOsdCharWidth, y * DvbOsdLineHeight, s); -#endif - } + if (open) + DvbOsd.Text(x, y, s, FgColor, BgColor); } -void cInterface::WriteText(int x, int y, char *s, bool Current) +void cInterface::WriteText(int x, int y, const char *s, bool Current) { if (open) { -#ifdef DEBUG_OSD - wmove(window, y, x); // ncurses wants 'y' before 'x'! - wclrtoeol(window);//XXX -#else -//TODO - DvbOsdClrEol(x * DvbOsdCharWidth, y);//XXX -#endif - Write(x, y, Current ? "*" : " "); - x++; + eDvbColor FgColor = Current ? clrBlack : clrWhite; + eDvbColor BgColor = Current ? clrCyan : clrBackground; + ClearEol(x, y, BgColor); int col = 0; for (;;) { - char *t = strchr(s, '\t'); - char *p = s; + const char *t = strchr(s, '\t'); + const char *p = s; char buf[1000]; if (t && col < MaxCols && cols[col] > 0) { unsigned int n = t - s; @@ -143,7 +124,7 @@ void cInterface::WriteText(int x, int y, char *s, bool Current) p = buf; s = t + 1; } - Write(x, y, p); + Write(x, y, p, FgColor, BgColor); if (p == s) break; x += cols[col++]; @@ -151,38 +132,74 @@ void cInterface::WriteText(int x, int y, char *s, bool Current) } } -void cInterface::Info(char *s) +void cInterface::Title(const char *s) +{ + int x = (MenuColumns - strlen(s)) / 2; + if (x < 0) + x = 0; + ClearEol(0, 0, clrCyan); + Write(x, 0, s, clrBlack, clrCyan); +} + +void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor) +{ + ClearEol(0, -3, s ? BgColor : clrBackground); + if (s) + Write(0, -3, s, FgColor, BgColor); +} + +void cInterface::Info(const char *s) { Open(); - isyslog(LOG_ERR, s); - WriteText(0, 11, s);//TODO -#ifdef DEBUG_OSD - wrefresh(window);//XXX -#endif - sleep(1); - WriteText(0, 11, "");//TODO -#ifdef DEBUG_OSD - wrefresh(window);//XXX -#endif + isyslog(LOG_INFO, s); + Status(s, clrWhite, clrGreen); + Wait(); + Status(NULL); Close(); } -void cInterface::Error(char *s) +void cInterface::Error(const char *s) { Open(); esyslog(LOG_ERR, s); - WriteText(0, 12, s);//TODO -#ifdef DEBUG_OSD - wrefresh(window);//XXX -#endif - sleep(1); - WriteText(0, 12, "");//TODO -#ifdef DEBUG_OSD - wrefresh(window);//XXX -#endif + Status(s, clrWhite, clrRed); + Wait(); + Status(NULL); Close(); } +bool cInterface::Confirm(const char *s) +{ + Open(); + isyslog(LOG_INFO, "confirm: %s", s); + Status(s, clrBlack, clrGreen); + bool result = Wait(10) == kOk; + Status(NULL); + Close(); + isyslog(LOG_INFO, "%sconfirmed", result ? "" : "not "); + return result; +} + +void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor) +{ + if (open && Text) { + const int w = MenuColumns / 4; + 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); + } +} + +void cInterface::Help(const char *Red, const char *Green, const char *Yellow, const char *Blue) +{ + HelpButton(0, Red, clrBlack, clrRed); + HelpButton(1, Green, clrBlack, clrGreen); + HelpButton(2, Yellow, clrBlack, clrYellow); + HelpButton(3, Blue, clrWhite, clrBlue); +} + void cInterface::QueryKeys(void) { Keys.Clear(); @@ -205,8 +222,8 @@ void cInterface::QueryKeys(void) WriteText(1, 5, "RC code detected!"); WriteText(1, 6, "Do not press any key..."); RcIo.Flush(3); - WriteText(1, 5, ""); - WriteText(1, 6, ""); + ClearEol(0, 5); + ClearEol(0, 6); break; } #endif @@ -229,8 +246,8 @@ void cInterface::QueryKeys(void) case kDown: if (k > Keys.keys + 1) { WriteText(1, 5, "Press 'Up' to confirm"); WriteText(1, 6, "Press 'Down' to continue"); - WriteText(1, 7, ""); - WriteText(1, 8, ""); + ClearEol(0, 7); + ClearEol(0, 8); for (;;) { eKeys key = GetKey(); if (key == kUp) { @@ -238,7 +255,7 @@ void cInterface::QueryKeys(void) return; } else if (key == kDown) { - WriteText(1, 6, ""); + ClearEol(0, 6); break; } } @@ -255,17 +272,18 @@ void cInterface::QueryKeys(void) if (k > Keys.keys) WriteText(1, 7, "(press 'Up' to go back)"); else - WriteText(1, 7, ""); + ClearEol(0, 7); if (k > Keys.keys + 1) WriteText(1, 8, "(press 'Down' to end key definition)"); else - WriteText(1, 8, ""); + ClearEol(0, 8); } } void cInterface::LearnKeys(void) { isyslog(LOG_INFO, "learning keys"); + Open(); for (;;) { Clear(); QueryKeys(); @@ -277,19 +295,19 @@ void cInterface::LearnKeys(void) eKeys key = GetKey(); if (key == kUp) { Keys.Save(); - Clear(); + Close(); return; } else if (key == kDown) { Keys.Load(); - Clear(); + Close(); return; } } } } -void cInterface::DisplayChannel(int Number, char *Name) +void cInterface::DisplayChannel(int Number, const char *Name) { //TODO #ifndef DEBUG_REMOTE diff --git a/interface.h b/interface.h index e387ab91f..9322cf39d 100644 --- a/interface.h +++ b/interface.h @@ -4,13 +4,14 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: interface.h 1.2 2000/02/27 14:54:02 kls Exp $ */ #ifndef __INTERFACE_H #define __INTERFACE_H #include "config.h" +#include "dvbapi.h" class cInterface { public: @@ -20,7 +21,8 @@ class cInterface { int cols[MaxCols]; unsigned int GetCh(void); void QueryKeys(void); - void Write(int x, int y, char *s); + void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor); + eKeys Wait(int Seconds = 1); public: cInterface(void); void Init(void); @@ -28,12 +30,18 @@ class cInterface { void Close(void); eKeys GetKey(void); void Clear(void); + void ClearEol(int x, int y, eDvbColor Color = clrBackground); void SetCols(int *c); - void WriteText(int x, int y, char *s, bool Current = false); - void Info(char *s); - void Error(char *s); + void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); + void WriteText(int x, int y, const char *s, bool Current = false); + void Title(const char *s); + void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan); + void Info(const char *s); + void Error(const char *s); + bool Confirm(const char *s); + void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); void LearnKeys(void); - void DisplayChannel(int Number, char *Name); + void DisplayChannel(int Number, const char *Name); }; extern cInterface Interface; diff --git a/keys-pc.conf b/keys-pc.conf index c57613f03256f252e5e7ccac9e89c4954e3a3d15..cfbe4587144cd511eac35a937b408cb2fc648c1a 100644 GIT binary patch delta 65 zcmaFJIGbt0L#v?F6ix#WFf_2_axY3v&4Y0rxgt|@a`MYzd?zlaoYGVn&zTDVVfqlt delta 6 NcmbQu^pJ7FLjVan0`UL< diff --git a/keys.conf b/keys.conf index f56222c34..0e3c07bc7 100644 --- a/keys.conf +++ b/keys.conf @@ -17,3 +17,7 @@ Right 000045E2 7 00000FE2 8 000077E2 9 000037E2 +Red 000025E2 +Green 00002AE2 +Yellow 00005AE2 +Blue 00000000 diff --git a/menu.c b/menu.c index 4f525ff7c..45f25a46a 100644 --- a/menu.c +++ b/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.1 2000/02/19 13:36:48 kls Exp $ + * $Id: menu.c 1.2 2000/03/05 15:37:31 kls Exp $ */ #include "menu.h" @@ -13,8 +13,9 @@ #include #include "config.h" #include "dvbapi.h" +#include "recording.h" -const char *FileNameChars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789/-.# ";//TODO more? +const char *FileNameChars = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.# "; // --- cMenuEditItem --------------------------------------------------------- @@ -59,7 +60,7 @@ class cMenuEditIntItem : public cMenuEditItem { virtual void Set(void); public: cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max) @@ -78,11 +79,11 @@ void cMenuEditIntItem::Set(void) SetValue(buf); } -eOSStatus cMenuEditIntItem::ProcessKey(eKeys Key) +eOSState cMenuEditIntItem::ProcessKey(eKeys Key) { - eOSStatus status = cMenuEditItem::ProcessKey(Key); + eOSState state = cMenuEditItem::ProcessKey(Key); - if (status == osUnknown) { + if (state == osUnknown) { int newValue; if (k0 <= Key && Key <= k9) { if (fresh) { @@ -100,14 +101,14 @@ eOSStatus cMenuEditIntItem::ProcessKey(eKeys Key) fresh = true; } else - return status; + return state; if ((!fresh || min <= newValue) && newValue <= max) { *value = newValue; Set(); } - status = osContinue; + state = osContinue; } - return status; + return state; } // --- cMenuEditBoolItem ----------------------------------------------------- @@ -167,7 +168,7 @@ class cMenuEditDayItem : public cMenuEditIntItem { virtual void Set(void); public: cMenuEditDayItem(const char *Name, int *Value); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; int cMenuEditDayItem::days[] ={ cTimer::ParseDay("M------"), @@ -205,7 +206,7 @@ void cMenuEditDayItem::Set(void) SetValue(cTimer::PrintDay(*value)); } -eOSStatus cMenuEditDayItem::ProcessKey(eKeys Key) +eOSState cMenuEditDayItem::ProcessKey(eKeys Key) { switch (Key) { case kLeft: if (d > 0) @@ -252,7 +253,7 @@ class cMenuEditTimeItem : public cMenuEditItem { virtual void Set(void); public: cMenuEditTimeItem(const char *Name, int *Value); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value) @@ -272,11 +273,11 @@ void cMenuEditTimeItem::Set(void) SetValue(buf); } -eOSStatus cMenuEditTimeItem::ProcessKey(eKeys Key) +eOSState cMenuEditTimeItem::ProcessKey(eKeys Key) { - eOSStatus status = cMenuEditItem::ProcessKey(Key); + eOSState state = cMenuEditItem::ProcessKey(Key); - if (status == osUnknown) { + if (state == osUnknown) { if (k0 <= Key && Key <= k9) { if (fresh || pos > 3) { pos = 0; @@ -324,12 +325,12 @@ eOSStatus cMenuEditTimeItem::ProcessKey(eKeys Key) fresh = true; } else - return status; + return state; *value = hh * 100 + mm; Set(); - status = osContinue; + state = osContinue; } - return status; + return state; } // --- cMenuEditChrItem ------------------------------------------------------ @@ -343,7 +344,7 @@ class cMenuEditChrItem : public cMenuEditItem { public: cMenuEditChrItem(const char *Name, char *Value, const char *Allowed); ~cMenuEditChrItem(); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed) @@ -369,11 +370,11 @@ void cMenuEditChrItem::Set(void) SetValue(buf); } -eOSStatus cMenuEditChrItem::ProcessKey(eKeys Key) +eOSState cMenuEditChrItem::ProcessKey(eKeys Key) { - eOSStatus status = cMenuEditItem::ProcessKey(Key); + eOSState state = cMenuEditItem::ProcessKey(Key); - if (status == osUnknown) { + if (state == osUnknown) { if (Key == kLeft) { if (current > allowed) current--; @@ -383,12 +384,12 @@ eOSStatus cMenuEditChrItem::ProcessKey(eKeys Key) current++; } else - return status; + return state; *value = *current; Set(); - status = osContinue; + state = osContinue; } - return status; + return state; } // --- cMenuEditStrItem ------------------------------------------------------ @@ -404,7 +405,7 @@ class cMenuEditStrItem : public cMenuEditItem { public: cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed); ~cMenuEditStrItem(); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed) @@ -449,7 +450,7 @@ char cMenuEditStrItem::Inc(char c, bool Up) return *p; } -eOSStatus cMenuEditStrItem::ProcessKey(eKeys Key) +eOSState cMenuEditStrItem::ProcessKey(eKeys Key) { switch (Key) { case kLeft: if (pos > 0) { @@ -492,11 +493,11 @@ class cMenuEditChannel : public cOsdMenu { cChannel data; public: cMenuEditChannel(int Index); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; cMenuEditChannel::cMenuEditChannel(int Index) -:cOsdMenu("Edit channel", 14) +:cOsdMenu("Edit Channel", 14) { channel = Channels.Get(Index); if (channel) { @@ -511,19 +512,19 @@ cMenuEditChannel::cMenuEditChannel(int Index) } } -eOSStatus cMenuEditChannel::ProcessKey(eKeys Key) +eOSState cMenuEditChannel::ProcessKey(eKeys Key) { - eOSStatus status = cOsdMenu::ProcessKey(Key); + eOSState state = cOsdMenu::ProcessKey(Key); - if (status == osUnknown) { + if (state == osUnknown) { if (Key == kOk) { if (channel) *channel = data; Channels.Save(); - status = osBack; + state = osBack; } } - return status; + return state; } // --- cMenuChannelItem ------------------------------------------------------ @@ -535,6 +536,7 @@ class cMenuChannelItem : public cOsdItem { public: cMenuChannelItem(int Index, cChannel *Channel); virtual void Set(void); + void SetIndex(int Index); }; cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel) @@ -551,12 +553,24 @@ void cMenuChannelItem::Set(void) SetText(buffer, false); } +void cMenuChannelItem::SetIndex(int Index) +{ + index = Index; + Set(); +} + // --- cMenuChannels --------------------------------------------------------- class cMenuChannels : public cOsdMenu { +protected: + eOSState Switch(void); + eOSState Edit(void); + eOSState New(void); + eOSState Del(void); + virtual void Move(int From, int To); public: cMenuChannels(void); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; cMenuChannels::cMenuChannels(void) @@ -570,26 +584,124 @@ cMenuChannels::cMenuChannels(void) Add(new cMenuChannelItem(i, channel), i == CurrentChannel); i++; } + SetHelp("Edit", "New", "Delete", "Mark"); +} + +eOSState cMenuChannels::Switch(void) +{ + cChannel *ch = Channels.Get(Current()); + if (ch) + ch->Switch(); + return osEnd; +} + +eOSState cMenuChannels::Edit(void) +{ + if (HasSubMenu() || Count() == 0) + return osContinue; + isyslog(LOG_INFO, "editing timer %d", Current() + 1); + return AddSubMenu(new cMenuEditChannel(Current())); +} + +eOSState cMenuChannels::New(void) +{ + if (HasSubMenu()) + return osContinue; + cChannel *channel = new cChannel(Channels.Get(Current())); + Channels.Add(channel); + Add(new cMenuChannelItem(channel->Index()/*XXX*/, channel), true); + Channels.Save(); + isyslog(LOG_INFO, "channel %d added", channel->Index() + 1); + return AddSubMenu(new cMenuEditChannel(Current())); } -eOSStatus cMenuChannels::ProcessKey(eKeys Key) +eOSState cMenuChannels::Del(void) { - eOSStatus status = cOsdMenu::ProcessKey(Key); + if (Count() > 0) { + int Index = Current(); + // Check if there is a timer using this channel: + for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { + if (ti->channel == Index + 1) { + Interface.Error("Channel is being used by a timer!"); + return osContinue; + } + } + if (Interface.Confirm("Delete Channel?")) { + // Move and renumber the channels: + Channels.Del(Channels.Get(Index)); + cOsdMenu::Del(Index); + int i = 0; + for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) + ci->SetIndex(i++); + Channels.Save(); + isyslog(LOG_INFO, "channel %d deleted", Index + 1); + // Fix the timers: + bool TimersModified = false; + Index++; // user visible channel numbers start with '1' + for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { + int OldChannel = ti->channel; + if (ti->channel > Index) + ti->channel--; + if (ti->channel != OldChannel) { + TimersModified = true; + isyslog(LOG_INFO, "timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel); + } + } + if (TimersModified) + Timers.Save(); + Display(); + } + } + return osContinue; +} - if (status == osUnknown) { +void cMenuChannels::Move(int From, int To) +{ + // Move and renumber the channels: + Channels.Move(From, To); + cOsdMenu::Move(From, To); + int i = 0; + for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) + ci->SetIndex(i++); + Channels.Save(); + isyslog(LOG_INFO, "channel %d moved to %d", From + 1, To + 1); + // Fix the timers: + bool TimersModified = false; + From++; // user visible channel numbers start with '1' + To++; + for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { + int OldChannel = ti->channel; + if (ti->channel == From) + ti->channel = To; + else if (ti->channel > From && ti->channel <= To) + ti->channel--; + else if (ti->channel < From && ti->channel >= To) + ti->channel++; + if (ti->channel != OldChannel) { + TimersModified = true; + isyslog(LOG_INFO, "timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel); + } + } + if (TimersModified) + Timers.Save(); + Display(); +} + +eOSState cMenuChannels::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { switch (Key) { - //TODO need to block this if we are already editing a channel! - case kRight: return AddSubMenu(new cMenuEditChannel(Current())); - case kOk: { - cChannel *ch = Channels.Get(Current()); - if (ch) - ch->Switch(); - return osEnd; - } + case kOk: return Switch(); + case kRed: return Edit(); + case kGreen: return New(); + case kYellow: return Del(); + case kBlue: Mark(); break; default: break; } } - return status; + return state; } // --- cMenuEditTimer -------------------------------------------------------- @@ -600,11 +712,11 @@ class cMenuEditTimer : public cOsdMenu { cTimer data; public: cMenuEditTimer(int Index); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; cMenuEditTimer::cMenuEditTimer(int Index) -:cOsdMenu("Edit timer", 10) +:cOsdMenu("Edit Timer", 10) { timer = Timers.Get(Index); if (timer) { @@ -622,21 +734,23 @@ cMenuEditTimer::cMenuEditTimer(int Index) } } -eOSStatus cMenuEditTimer::ProcessKey(eKeys Key) +eOSState cMenuEditTimer::ProcessKey(eKeys Key) { - eOSStatus status = cOsdMenu::ProcessKey(Key); + eOSState state = cOsdMenu::ProcessKey(Key); - if (status == osUnknown) { + if (state == osUnknown) { if (Key == kOk) { + if (!*data.file) + strcpy(data.file, "unnamed"); if (timer && memcmp(timer, &data, sizeof(data)) != 0) { *timer = data; Timers.Save(); isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); } - status = osBack; + state = osBack; } } - return status; + return state; } // --- cMenuTimerItem -------------------------------------------------------- @@ -660,27 +774,34 @@ cMenuTimerItem::cMenuTimerItem(int Index, cTimer *Timer) void cMenuTimerItem::Set(void) { char *buffer = NULL; - asprintf(&buffer, "%d\t%c\t%d\t%s\t%02d:%02d\t%02d:%02d", index + 1, + asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s", timer->active ? '>' : ' ', timer->channel, timer->PrintDay(timer->day), timer->start / 100, timer->start % 100, timer->stop / 100, - timer->stop % 100); // user visible timer numbers start with '1' + timer->stop % 100, + timer->file); SetText(buffer, false); } -// --- cMenuTimer ------------------------------------------------------------ +// --- cMenuTimers ----------------------------------------------------------- -class cMenuTimer : public cOsdMenu { +class cMenuTimers : public cOsdMenu { +private: + eOSState Activate(bool On); + eOSState Edit(void); + eOSState New(void); + eOSState Del(void); + virtual void Move(int From, int To); public: - cMenuTimer(void); - virtual eOSStatus ProcessKey(eKeys Key); + cMenuTimers(void); + virtual eOSState ProcessKey(eKeys Key); }; -cMenuTimer::cMenuTimer(void) -:cOsdMenu("Timer", 3, 2, 4, 10, 6) +cMenuTimers::cMenuTimers(void) +:cOsdMenu("Timer", 2, 4, 10, 6, 6) { int i = 0; cTimer *timer; @@ -689,34 +810,190 @@ cMenuTimer::cMenuTimer(void) Add(new cMenuTimerItem(i, timer)); i++; } + SetHelp("Edit", "New", "Delete", "Mark"); +} + +eOSState cMenuTimers::Activate(bool On) +{ + cTimer *timer = Timers.Get(Current()); + if (timer && timer->active != On) { + timer->active = On; + RefreshCurrent(); + DisplayCurrent(true); + isyslog(LOG_INFO, "timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de"); + Timers.Save(); + } + return osContinue; +} + +eOSState cMenuTimers::Edit(void) +{ + if (HasSubMenu() || Count() == 0) + return osContinue; + isyslog(LOG_INFO, "editing timer %d", Current() + 1); + return AddSubMenu(new cMenuEditTimer(Current())); +} + +eOSState cMenuTimers::New(void) +{ + if (HasSubMenu()) + return osContinue; + cTimer *timer = new cTimer; + Timers.Add(timer); + Add(new cMenuTimerItem(timer->Index()/*XXX*/, timer), true); + Timers.Save(); + isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + return AddSubMenu(new cMenuEditTimer(Current())); +} + +eOSState cMenuTimers::Del(void) +{ + // Check if this timer is active: + int Index = Current(); + cTimer *ti = Timers.Get(Index); + if (ti) { + if (!ti->recording) { + if (Interface.Confirm("Delete Timer?")) { + Timers.Del(Timers.Get(Index)); + cOsdMenu::Del(Index); + Timers.Save(); + Display(); + isyslog(LOG_INFO, "timer %d deleted", Index + 1); + } + } + else + Interface.Error("Timer is recording!"); + } + return osContinue; } -eOSStatus cMenuTimer::ProcessKey(eKeys Key) +void cMenuTimers::Move(int From, int To) { - eOSStatus status = cOsdMenu::ProcessKey(Key); + Timers.Move(From, To); + cOsdMenu::Move(From, To); + Timers.Save(); + Display(); + isyslog(LOG_INFO, "timer %d moved to %d", From + 1, To + 1); +} - if (status == osUnknown) { +eOSState cMenuTimers::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { switch (Key) { - //TODO need to block this if we are already editing a channel! - case kOk: return AddSubMenu(new cMenuEditTimer(Current())); - //TODO new timer - //TODO delete timer case kLeft: - case kRight: - { - cTimer *timer = Timers.Get(Current()); - if (timer) { - timer->active = (Key == kRight); - isyslog(LOG_INFO, "timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de"); - RefreshCurrent(); - DisplayCurrent(true); - Timers.Save(); - } - } + case kRight: return Activate(Key == kRight); + case kOk: + case kRed: return Edit(); + case kGreen: return New(); + case kYellow: return Del(); + case kBlue: Mark(); break; default: break; } } - return status; + return state; +} + +// --- cMenuRecordingItem ---------------------------------------------------- + +class cMenuRecordingItem : public cOsdItem { +public: + cRecording *recording; + cMenuRecordingItem(cRecording *Recording); + virtual void Set(void); + }; + +cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording) +{ + recording = Recording; + Set(); +} + +void cMenuRecordingItem::Set(void) +{ + char *buffer = NULL; + struct tm *t = localtime(&recording->start); + asprintf(&buffer, "%02d.%02d.%04d\t%02d:%02d\t%s", + t->tm_mday, + t->tm_mon + 1, + t->tm_year + 1900, + t->tm_hour, + t->tm_min, + recording->name); + SetText(buffer, false); +} + +// --- cMenuRecordings ------------------------------------------------------- + +class cMenuRecordings : public cOsdMenu { +private: + cRecordings Recordings; + eOSState Play(void); + eOSState Del(void); +public: + cMenuRecordings(void); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuRecordings::cMenuRecordings(void) +:cOsdMenu("Recordings", 11, 6) +{ + if (Recordings.Load()) { + cRecording *recording = Recordings.First(); + while (recording) { + Add(new cMenuRecordingItem(recording)); + recording = Recordings.Next(recording); + } + } + SetHelp("Play", NULL/*XXX"Resume"*/, "Delete"); +} + +eOSState cMenuRecordings::Play(void) +{ + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri) { +//XXX what if this recording's file is currently in use??? + if (ri->recording->Play()) + return osEnd; + } + return osContinue; +} + +eOSState cMenuRecordings::Del(void) +{ + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri) { +//XXX what if this recording's file is currently in use??? +//XXX if (!ti->recording) { + if (Interface.Confirm("Delete Recording?")) { + if (ri->recording->Delete()) { + cOsdMenu::Del(Current()); + Display(); + } + else + Interface.Error("Error while deleting recording!"); + } +//XXX } +//XXX else +//XXX Interface.Error("Timer is recording!"); + } + return osContinue; +} + +eOSState cMenuRecordings::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case kOk: + case kRed: return Play(); + case kYellow: return Del(); + default: break; + } + } + return state; } // --- cMenuMain ------------------------------------------------------------- @@ -724,22 +1001,21 @@ eOSStatus cMenuTimer::ProcessKey(eKeys Key) cMenuMain::cMenuMain(void) :cOsdMenu("Main") { - //TODO Add(new cOsdItem("Channels", osChannels)); Add(new cOsdItem("Timer", osTimer)); Add(new cOsdItem("Recordings", osRecordings)); } -eOSStatus cMenuMain::ProcessKey(eKeys Key) +eOSState cMenuMain::ProcessKey(eKeys Key) { - eOSStatus status = cOsdMenu::ProcessKey(Key); + eOSState state = cOsdMenu::ProcessKey(Key); - switch (status) { - case osChannels: return AddSubMenu(new cMenuChannels); - case osTimer: return AddSubMenu(new cMenuTimer); - //TODO Replay + switch (state) { + case osChannels: return AddSubMenu(new cMenuChannels); + case osTimer: return AddSubMenu(new cMenuTimers); + case osRecordings: return AddSubMenu(new cMenuRecordings); default: break; } - return status; + return state; } diff --git a/menu.h b/menu.h index 849d8ee3d..813beecdd 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: menu.h 1.2 2000/03/05 10:57:27 kls Exp $ */ #ifndef _MENU_H @@ -15,7 +15,7 @@ class cMenuMain : public cOsdMenu { public: cMenuMain(void); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; #endif //_MENU_H diff --git a/osd.c b/osd.c index d7ab69935..673d075c0 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: osd.c 1.2 2000/02/27 17:23:07 kls Exp $ */ #include "osd.h" @@ -13,19 +13,19 @@ // --- cOsdItem -------------------------------------------------------------- -cOsdItem::cOsdItem(eOSStatus Status) +cOsdItem::cOsdItem(eOSState State) { text = NULL; offset = -1; - status = Status; + state = State; fresh = false; } -cOsdItem::cOsdItem(char *Text, eOSStatus Status) +cOsdItem::cOsdItem(char *Text, eOSState State) { text = NULL; offset = -1; - status = Status; + state = State; fresh = false; SetText(Text); } @@ -52,24 +52,27 @@ void cOsdItem::Display(int Offset, bool Current) Interface.WriteText(0, offset + 2, text, Current); } -eOSStatus cOsdItem::ProcessKey(eKeys Key) +eOSState cOsdItem::ProcessKey(eKeys Key) { - return Key == kOk ? status : osUnknown; + return Key == kOk ? state : osUnknown; } // --- cOsdMenu -------------------------------------------------------------- cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4) { + visible = false; title = strdup(Title); cols[0] = c0; cols[1] = c1; cols[2] = c2; cols[3] = c3; cols[4] = c4; - first = count = 0; - current = -1; + first = 0; + current = marked = -1; subMenu = NULL; + helpRed = helpGreen = helpYellow = helpBlue = NULL; + status = NULL; Interface.Open(); } @@ -77,40 +80,72 @@ cOsdMenu::~cOsdMenu() { delete title; delete subMenu; + delete status; Interface.Clear(); Interface.Close(); } +void cOsdMenu::SetStatus(const char *s) +{ + delete status; + status = s ? strdup(s) : NULL; + if (visible) + Interface.Status(status); +} + +void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue) +{ + // strings are NOT copied - must be constants!!! + helpRed = Red; + helpGreen = Green; + helpYellow = Yellow; + helpBlue = Blue; +} + +void cOsdMenu::Del(int Index) +{ + cList::Del(Get(Index)); + if (current == Count()) + current--; + if (Index == first && first > 0) + first--; +} + void cOsdMenu::Add(cOsdItem *Item, bool Current) { cList::Add(Item); - count++; - if (Current && current < 0) + if (Current) current = Item->Index(); } void cOsdMenu::Display(void) { + visible = true; Interface.Clear(); Interface.SetCols(cols); - Interface.WriteText(0, 0, title); - if (current < 0 && count) - current = 0; // just for safety - there HAS to be a current item! - int n = 0; - if (current - first >= MAXOSDITEMS) { - first = current - MAXOSDITEMS / 2; - if (first + MAXOSDITEMS > count) - first = count - MAXOSDITEMS; - if (first < 0) - first = 0; + Interface.Title(title); + Interface.Help(helpRed, helpGreen, helpYellow, helpBlue); + int count = Count(); + if (count > 0) { + if (current < 0) + current = 0; // just for safety - there HAS to be a current item! + int n = 0; + if (current - first >= MAXOSDITEMS) { + first = current - MAXOSDITEMS / 2; + if (first + MAXOSDITEMS > count) + first = count - MAXOSDITEMS; + if (first < 0) + first = 0; + } + for (int i = first; i < count; i++) { + cOsdItem *item = Get(i); + if (item) + item->Display(i - first, i == current); + if (++n == MAXOSDITEMS) //TODO get this from Interface!!! + break; + } } - for (int i = first; i < count; i++) { - cOsdItem *item = Get(i); - if (item) - item->Display(i - first, i == current); - if (++n == MAXOSDITEMS) //TODO get this from Interface!!! - break; - } + Interface.Status(status); } void cOsdMenu::RefreshCurrent(void) @@ -144,6 +179,7 @@ void cOsdMenu::CursorUp(void) void cOsdMenu::CursorDown(void) { + int count = Count(); if (current < count - 1) { DisplayCurrent(false); if (++current >= first + MAXOSDITEMS) { @@ -157,7 +193,15 @@ void cOsdMenu::CursorDown(void) } } -eOSStatus cOsdMenu::AddSubMenu(cOsdMenu *SubMenu) +void cOsdMenu::Mark(void) +{ + if (Count() && marked < 0) { + marked = current; + SetStatus("Up/Dn for new location - OK to move"); + } +} + +eOSState cOsdMenu::AddSubMenu(cOsdMenu *SubMenu) { delete subMenu; subMenu = SubMenu; @@ -165,31 +209,40 @@ eOSStatus cOsdMenu::AddSubMenu(cOsdMenu *SubMenu) return osContinue; // convenience return value (see cMenuMain) } -eOSStatus cOsdMenu::ProcessKey(eKeys Key) +eOSState cOsdMenu::ProcessKey(eKeys Key) { if (subMenu) { - eOSStatus status = subMenu->ProcessKey(Key); - if (status == osBack) { + eOSState state = subMenu->ProcessKey(Key); + if (state == osBack) { delete subMenu; subMenu = NULL; RefreshCurrent(); Display(); - status = osContinue; + state = osContinue; } - return status; + return state; } cOsdItem *item = Get(current); - if (item) { - eOSStatus status = item->ProcessKey(Key); - if (status != osUnknown) - return status; + if (marked < 0 && item) { + eOSState state = item->ProcessKey(Key); + if (state != osUnknown) + return state; } switch (Key) { case kUp: CursorUp(); break; case kDown: CursorDown(); break; case kBack: return osBack; - default: return osUnknown; + case kOk: if (marked >= 0) { + SetStatus(NULL); + if (marked != current) + Move(marked, current); + marked = -1; + break; + } + // else run into default + default: if (marked < 0) + return osUnknown; } return osContinue; } diff --git a/osd.h b/osd.h index 392f1a752..5ec13349f 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: osd.h 1.2 2000/03/05 11:33:11 kls Exp $ */ #ifndef __OSD_H @@ -16,53 +16,61 @@ #define MAXOSDITEMS 9 -enum eOSStatus { osUnknown, - osContinue, - osProcessed, - osChannels, - osTimer, - osRecordings, - osBack, - osEnd, - }; +enum eOSState { osUnknown, + osContinue, + osProcessed, + osChannels, + osTimer, + osRecordings, + osBack, + osEnd, + }; class cOsdItem : public cListObject { private: char *text; int offset; - eOSStatus status; + eOSState state; protected: bool fresh; public: - cOsdItem(eOSStatus Status = osUnknown); - cOsdItem(char *Text, eOSStatus Status = osUnknown); + cOsdItem(eOSState State = osUnknown); + cOsdItem(char *Text, eOSState State = osUnknown); virtual ~cOsdItem(); void SetText(char *Text, bool Copy = true); char *Text(void) { return text; } void Display(int Offset = -1, bool Current = false); virtual void Set(void) {} - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; class cOsdMenu : public cList { private: char *title; int cols[cInterface::MaxCols]; - int first, current, count; + int first, current, marked; cOsdMenu *subMenu; + const char *helpRed, *helpGreen, *helpYellow, *helpBlue; + const char *status; protected: + bool visible; void RefreshCurrent(void); void DisplayCurrent(bool Current); void CursorUp(void); void CursorDown(void); - eOSStatus AddSubMenu(cOsdMenu *SubMenu); + void Mark(void); + eOSState AddSubMenu(cOsdMenu *SubMenu); + bool HasSubMenu(void) { return subMenu; } + void SetStatus(const char *s); + void SetHelp(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); + virtual void Del(int Index); public: cOsdMenu(char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0); virtual ~cOsdMenu(); int Current(void) { return current; } void Add(cOsdItem *Item, bool Current = false); void Display(void); - virtual eOSStatus ProcessKey(eKeys Key); + virtual eOSState ProcessKey(eKeys Key); }; #endif //__OSD_H diff --git a/osm.c b/osm.c index cc017451a..7031d6893 100644 --- a/osm.c +++ b/osm.c @@ -22,13 +22,13 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: osm.c 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: osm.c 1.2 2000/03/05 17:18:15 kls Exp $ */ #include "config.h" -#include "dvbapi.h" #include "interface.h" #include "menu.h" +#include "recording.h" #include "tools.h" #ifdef DEBUG_REMOTE @@ -52,39 +52,39 @@ int main(int argc, char *argv[]) cMenuMain *Menu = NULL; cTimer *Timer = NULL; - cDvbRecorder *Recorder = NULL; + cRecording *Recording = NULL; for (;;) { - //TODO check for free disk space and delete files if necessary/possible - // in case there is an ongoing recording - if (!Timer && (Timer = cTimer::GetMatch()) != NULL) { + AssertFreeDiskSpace(); + if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) { + DELETENULL(Menu); + // make sure the timer won't be deleted: + Timer->SetRecording(true); // switch to channel: - isyslog(LOG_INFO, "timer %d start", Timer->Index() + 1); - delete Menu; - Menu = NULL; cChannel::SwitchTo(Timer->channel - 1); ChannelLocked = true; // start recording: - delete Recorder; - Recorder = new cDvbRecorder; - //TODO special filename handling!!! - if (!Recorder->Record(Timer->file, Timer->quality)) { - delete Recorder; - Recorder = NULL; - } + Recording = new cRecording(Timer); + if (!Recording->Record()) + DELETENULL(Recording); } - if (Timer) { - if (!Timer->Matches()) { - // stop recording: - if (Recorder) - Recorder->Stop(); - // end timer: - ChannelLocked = false; - isyslog(LOG_INFO, "timer %d stop", Timer->Index() + 1); - Timer = NULL; - //TODO switch back to the previous channel??? - //TODO clear single event timer??? + if (Timer && !Timer->Matches()) { + // stop recording: + if (Recording) { + Recording->Stop(); + DELETENULL(Recording); + } + // release channel and timer: + ChannelLocked = false; + Timer->SetRecording(false); + // clear single event timer: + if (Timer->IsSingleEvent()) { + DELETENULL(Menu); // must make sure no menu uses it + isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1); + Timers.Del(Timer); + Timers.Save(); } + Timer = NULL; } eKeys key = Interface.GetKey(); if (Menu) { @@ -92,8 +92,7 @@ int main(int argc, char *argv[]) default: if (key != kMenu) break; case osBack: - case osEnd: delete Menu; - Menu = NULL; + case osEnd: DELETENULL(Menu); break; } } diff --git a/recording.c b/recording.c new file mode 100644 index 000000000..afc2d8b3e --- /dev/null +++ b/recording.c @@ -0,0 +1,238 @@ +/* + * recording.h: Recording file handling + * + * 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 $ + */ + +#include "recording.h" +#include +#include +#include +#include "interface.h" +#include "tools.h" + +#define RECEXT ".rec" +#define DELEXT ".del" +#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%c.%02d.%02d" RECEXT +#define NAMEFORMAT "%s/%s/" DATAFORMAT + +#define FINDCMD "find %s -type f -name '%s'" + +#define DFCMD "df -m %s" +#define MINDISKSPACE 1024 // MB + +const char *BaseDir = "/video";//XXX + +cDvbRecorder *Recorder = NULL; + +static bool LowDiskSpace(void) +{ + //TODO Find a simpler way to determine the amount of free disk space! + bool result = true; + char *cmd = NULL; + asprintf(&cmd, DFCMD, BaseDir); + FILE *p = popen(cmd, "r"); + if (p) { + char *s; + while ((s = readline(p)) != NULL) { + if (*s == '/') { + int available; + sscanf(s, "%*s %*d %*d %d", &available); + result = available < MINDISKSPACE; + break; + } + } + pclose(p); + } + else + esyslog(LOG_ERR, "ERROR: can't open pipe for cmd '%s'", cmd); + delete cmd; + return result; +} + +void AssertFreeDiskSpace(void) +{ + // With every call to this function we try to actually remove + // a file, or mark a file for removal ("delete" it), so that + // it will get removed during the next call. + if (Recorder && Recorder->Recording() && LowDiskSpace()) { + // Remove the oldest file that has been "deleted": + cRecordings Recordings; + if (Recordings.Load(true)) { + cRecording *r = Recordings.First(); + cRecording *r0 = r; + while (r) { + if (r->start < r0->start) + r0 = r; + r = Recordings.Next(r); + } + if (r0 && r0->Remove()) + return; + } + // No "deleted" files to remove, so let's see if we can delete a recording: + if (Recordings.Load(false)) { + cRecording *r = Recordings.First(); + cRecording *r0 = NULL; + while (r) { + if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) { + if (r0) { + if (r->priority < r0->priority) + r0 = r; + } + else + r0 = r; + } + r = Recordings.Next(r); + } + if (r0 && r0->Delete()) + 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 + } +} + +// --- cRecording ------------------------------------------------------------ + +cRecording::cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime) +{ + fileName = NULL; + name = strdup(Name); + start = Start; + quality = Quality; + priority = Priority; + lifetime = LifeTime; +} + +cRecording::cRecording(cTimer *Timer) +{ + fileName = NULL; + name = strdup(Timer->file); + start = Timer->StartTime(); + quality = Timer->quality; + priority = Timer->priority; + lifetime = Timer->lifetime; +} + +cRecording::cRecording(const char *FileName) +{ + fileName = strdup(FileName); + FileName += strlen(BaseDir) + 1; + char *p = strrchr(FileName, '/'); + + name = NULL; + 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)) { + t.tm_year -= 1900; + t.tm_mon--; + t.tm_sec = 0; + start = mktime(&t); + name = new char[p - FileName + 1]; + strncpy(name, FileName, p - FileName); + name[p - FileName] = 0; + } + } +} + +cRecording::~cRecording() +{ + delete fileName; + delete name; +} + +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); + } + return fileName; +} + +bool cRecording::Delete(void) +{ + bool result = true; + char *NewName = strdup(FileName()); + char *ext = strrchr(NewName, '.'); + if (strcmp(ext, RECEXT) == 0) { + strncpy(ext, DELEXT, strlen(ext)); + isyslog(LOG_INFO, "deleting recording %s", FileName()); + if (rename(FileName(), NewName) == -1) { + esyslog(LOG_ERR, "ERROR: %s", strerror(errno)); + result = false; + } + } + delete NewName; + return result; +} + +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; +} + +bool cRecording::Record(void) +{ + return AssertRecorder() && Recorder->Record(FileName(), quality); +} + +bool cRecording::Play(void) +{ + return AssertRecorder() && Recorder->Play(FileName()); +} + +void cRecording::Stop(void) +{ + if (Recorder) + Recorder->Stop(); +} + +// --- cRecordings ----------------------------------------------------------- + +bool cRecordings::Load(bool Deleted) +{ + Clear(); + bool result = false; + char *cmd = NULL; + asprintf(&cmd, FINDCMD, BaseDir, Deleted ? "*" DELEXT : "*" RECEXT); + FILE *p = popen(cmd, "r"); + if (p) { + char *s; + while ((s = readline(p)) != NULL) { + cRecording *r = new cRecording(s); + if (r->name) + Add(r); + else + delete r; + } + pclose(p); + result = Count() > 0; + } + else + Interface.Error("Error while opening pipe!"); + delete cmd; + return result; +} + diff --git a/recording.h b/recording.h new file mode 100644 index 000000000..5b093a043 --- /dev/null +++ b/recording.h @@ -0,0 +1,56 @@ +/* + * recording.h: Recording file handling + * + * 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 $ + */ + +#ifndef __RECORDING_H +#define __RECORDING_H + +#include +#include "config.h" +#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(cTimer *Timer); + cRecording(const char *FileName); + ~cRecording(); + const char *FileName(void); + bool Delete(void); + // Changes the file name so that it will no longer be visible in the OSM + // Returns false in case of error + bool Remove(void); + // Actually removes the file from the disk + // Returns false in case of error + bool Record(void); + // Starts recording of the file + bool Play(void); + // Starts playback of the file + void Stop(void); + // Stops recording or playback of the file + }; + +class cRecordings : public cList { +public: + bool Load(bool Deleted = false); + }; + +#endif //__RECORDING_H diff --git a/timers.conf b/timers.conf index ac002a996..de4df9dac 100644 --- a/timers.conf +++ b/timers.conf @@ -1,9 +1,6 @@ -1:2:-----S-:2210:2320:H:99:99:Wochenshow -1:3:M------:2125:2205:H:99:99:Neues +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:2:-----S-:1737:1827:H:99:99:kls/StarTrek/DS9 1:3:M------:2110:2230:H:99:99:SevenDays -1:3:---T---:2215:2300:H:99:99:SwItch -0:1:1:0:0:H:99:99:# -0:1:1:0:0:H:99:99:# -0:1:1:0:0:L:0:5:# +1:3:---T---:2215:2300:H:99:99:Switch +1:14:------S:2210:2255:H:99:99:Olli diff --git a/tools.c b/tools.c index e0eeaefda..5a21a9307 100644 --- a/tools.c +++ b/tools.c @@ -4,13 +4,30 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: tools.c 1.2 2000/03/05 14:33:58 kls Exp $ */ #include "tools.h" +#include #include +#include +#include #include +#define MaxBuffer 1000 + +char *readline(FILE *f) +{ + static char buffer[MaxBuffer]; + if (fgets(buffer, sizeof(buffer), f) > 0) { + int l = strlen(buffer) - 1; + if (l >= 0 && buffer[l] == '\n') + buffer[l] = 0; + return buffer; + } + return NULL; +} + int time_ms(void) { struct timeval t; @@ -19,6 +36,30 @@ int time_ms(void) return 0; } +bool MakeDirs(const char *FileName) +{ + bool result = true; + char *s = strdup(FileName); + char *p = s; + if (*p == '/') + p++; + while ((p = strchr(p, '/')) != NULL) { + *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)); + result = false; + break; + } + } + *p++ = '/'; + } + delete s; + return result; +} + // --- cListObject ----------------------------------------------------------- cListObject::cListObject(void) @@ -42,6 +83,7 @@ void cListObject::Unlink(void) next->prev = prev; if (prev) prev->next = next; + next = prev = NULL; } int cListObject::Index(void) @@ -92,6 +134,33 @@ void cListBase::Del(cListObject *Object) delete Object; } +void cListBase::Move(int From, int To) +{ + Move(Get(From), Get(To)); +} + +void cListBase::Move(cListObject *From, cListObject *To) +{ + if (From && To) { + if (From->Index() < To->Index()) + To = To->Next(); + if (From == objects) + objects = From->Next(); + if (From == lastObject) + lastObject = From->Prev(); + From->Unlink(); + if (To) { + if (To->Prev()) + To->Prev()->Append(From); + From->Append(To); + } + else + lastObject->Append(From); + if (!From->Prev()) + objects = From; + } +} + void cListBase::Clear(void) { while (objects) { diff --git a/tools.h b/tools.h index 43f852542..9f87bbde1 100644 --- a/tools.h +++ b/tools.h @@ -4,12 +4,13 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: tools.h 1.2 2000/03/05 16:14:05 kls Exp $ */ #ifndef __TOOLS_H #define __TOOLS_H +#include #include //TODO @@ -17,6 +18,14 @@ #define esyslog syslog #define isyslog syslog +#define SECSINDAY 86400 + +#define DELETENULL(p) (delete (p), p = NULL) + +char *readline(FILE *f); +int time_ms(void); +bool MakeDirs(const char *FileName); + class cListObject { private: cListObject *prev, *next; @@ -38,6 +47,8 @@ class cListBase { virtual ~cListBase(); void Add(cListObject *Object); void Del(cListObject *Object); + void Move(int From, int To); + void Move(cListObject *From, cListObject *To); void Clear(void); cListObject *Get(int Index); int Count(void); @@ -47,8 +58,7 @@ template class cList : public cListBase { public: T *Get(int Index) { return (T *)cListBase::Get(Index); } T *First(void) { return (T *)objects; } + T *Next(T *object) { return (T *)object->Next(); } }; -int time_ms(void); - #endif //__TOOLS_H From 37250a0568d5b1d689d5c59f983e9be228ed49c2 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 15 Apr 2000 18:00:00 +0200 Subject: [PATCH 003/307] 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. --- BUGS | 23 + HISTORY | 8 + MANUAL | 39 ++ README | 72 ++- TODO | 6 +- channels.conf | 218 ++++---- config.c | 95 ++-- config.h | 21 +- dvbapi.c | 1394 +++++++++++++++++++++++++++++++++++++++++++++---- dvbapi.h | 121 +++-- interface.c | 25 +- interface.h | 3 +- keys-pc.conf | Bin 283 -> 425 bytes keys.conf | 23 - menu.c | 29 +- osm.c | 150 +++--- recording.c | 110 ++-- recording.h | 9 +- remote.c | 9 +- timers.conf | 15 +- tools.c | 91 +++- tools.h | 24 +- 22 files changed, 1931 insertions(+), 554 deletions(-) create mode 100644 BUGS create mode 100644 MANUAL delete mode 100644 keys.conf diff --git a/BUGS b/BUGS new file mode 100644 index 000000000..bcb37728a --- /dev/null +++ b/BUGS @@ -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? diff --git a/HISTORY b/HISTORY index f7eeb65ef..c013340dd 100644 --- a/HISTORY +++ b/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. diff --git a/MANUAL b/MANUAL new file mode 100644 index 000000000..9e5036c10 --- /dev/null +++ b/MANUAL @@ -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. + diff --git a/README b/README index 5c6928cb4..e2b27a4ff 100644 --- a/README +++ b/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: --------------------------------------- diff --git a/TODO b/TODO index 35e3aa306..8154c01d8 100644 --- a/TODO +++ b/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. diff --git a/channels.conf b/channels.conf index 1b5796363..c0e191aca 100644 --- a/channels.conf +++ b/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 diff --git a/config.c b/config.c index af97a5cb4..c29fea8b7 100644 --- a/config.c +++ b/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" @@ -16,28 +16,36 @@ // -- cKeys ------------------------------------------------------------------ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! - { kUp, "Up", 0 }, - { kDown, "Down", 0 }, - { kMenu, "Menu", 0 }, - { kOk, "Ok", 0 }, - { kBack, "Back", 0 }, - { kLeft, "Left", 0 }, - { kRight, "Right", 0 }, - { k0, "0", 0 }, - { k1, "1", 0 }, - { k2, "2", 0 }, - { k3, "3", 0 }, - { k4, "4", 0 }, - { k5, "5", 0 }, - { k6, "6", 0 }, - { k7, "7", 0 }, - { k8, "8", 0 }, - { k9, "9", 0 }, - { kRed, "Red", 0 }, - { kGreen, "Green", 0 }, - { kYellow, "Yellow", 0 }, - { kBlue, "Blue", 0 }, - { kNone, "", 0 }, + { kUp, "Up", 0 }, + { kDown, "Down", 0 }, + { kMenu, "Menu", 0 }, + { kOk, "Ok", 0 }, + { kBack, "Back", 0 }, + { kLeft, "Left", 0 }, + { kRight, "Right", 0 }, + { k0, "0", 0 }, + { k1, "1", 0 }, + { k2, "2", 0 }, + { k3, "3", 0 }, + { k4, "4", 0 }, + { k5, "5", 0 }, + { k6, "6", 0 }, + { k7, "7", 0 }, + { k8, "8", 0 }, + { k9, "9", 0 }, + { kRed, "Red", 0 }, + { kGreen, "Green", 0 }, + { kYellow, "Yellow", 0 }, + { kBlue, "Blue", 0 }, + { kRecord, "Record", 0 }, + { kPause, "Pause", 0 }, + { kStop, "Stop", 0 }, + { kBegin, "Begin", 0 }, + { kSearchForward, "SearchForward", 0 }, + { kSearchBack, "SearchBack", 0 }, + { kSkipForward, "SkipForward", 0 }, + { kSkipBack, "SkipBack", 0 }, + { kNone, "", 0 }, }; cKeys::cKeys(void) @@ -88,7 +96,7 @@ bool cKeys::Load(char *FileName) } } if (Name) { - fprintf(stderr, "unknown key in %s, line %d\n", fileName, line); + esyslog(LOG_ERR, "unknown key in %s, line %d\n", fileName, line); result = false; break; } @@ -96,17 +104,17 @@ bool cKeys::Load(char *FileName) } continue; } - fprintf(stderr, "error in %s, line %d\n", fileName, line); + esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); result = false; break; } fclose(f); } else - fprintf(stderr, "can't open '%s'\n", fileName); + esyslog(LOG_ERR, "can't open '%s'\n", fileName); } else - fprintf(stderr, "no key configuration file name supplied!\n"); + esyslog(LOG_ERR, "no key configuration file name supplied!\n"); return result; } @@ -172,12 +180,14 @@ cChannel::cChannel(const cChannel *Channel) srate = Channel ? Channel->srate : 27500; vpid = Channel ? Channel->vpid : 255; apid = Channel ? Channel->apid : 256; + ca = Channel ? Channel->ca : 0; + pnr = Channel ? Channel->pnr : 0; } bool cChannel::Parse(char *s) { char *buffer = NULL; - if (7 == sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid)) { + if (9 == sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &ca, &pnr)) { strncpy(name, buffer, MaxChannelName - 1); name[strlen(buffer)] = 0; delete buffer; @@ -188,20 +198,21 @@ bool cChannel::Parse(char *s) bool cChannel::Save(FILE *f) { - return fprintf(f, "%s:%d:%c:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid) > 0; + return fprintf(f, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid, ca, pnr) > 0; } bool cChannel::Switch(void) { - if (!ChannelLocked) { + if (!DvbApi.Recording()) { isyslog(LOG_INFO, "switching to channel %d", Index() + 1); CurrentChannel = Index(); Interface.DisplayChannel(CurrentChannel + 1, name); for (int i = 3; --i;) { - if (DvbSetChannel(frequency, polarization, diseqc, srate, vpid, apid)) + if (DvbApi.SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) return true; esyslog(LOG_ERR, "retrying"); } + return false; } Interface.Info("Channel locked (recording)!"); return false; @@ -215,20 +226,23 @@ bool cChannel::SwitchTo(int i) // -- cTimer ----------------------------------------------------------------- -cTimer::cTimer(void) +cTimer::cTimer(bool Instant) { startTime = stopTime = 0; recording = false; - active = 1; + active = Instant; channel = CurrentChannel + 1; - day = 1; //XXX today! - start = 0; //XXX now! - stop = 0; //XXX now + 2h! + time_t t = time(NULL); + struct tm *now = localtime(&t); + day = now->tm_mday; + start = now->tm_hour * 100 + now->tm_min; + stop = start + 200; // "instant recording" records 2 hours by default + if (stop >= 2400) + stop -= 2400; //TODO VPS??? - quality = 'H'; priority = 99; lifetime = 99; - *file = 0; + strcpy(file, Instant ? "instant" : ""); } int cTimer::TimeToInt(int t) @@ -286,7 +300,7 @@ bool cTimer::Parse(char *s) { char *buffer1 = NULL; char *buffer2 = NULL; - if (9 == sscanf(s, "%d:%d:%a[^:]:%d:%d:%c:%d:%d:%as", &active, &channel, &buffer1, &start, &stop, &quality, &priority, &lifetime, &buffer2)) { + if (8 == sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%as", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2)) { day = ParseDay(buffer1); strncpy(file, buffer2, MaxFileName - 1); file[strlen(buffer2)] = 0; @@ -299,7 +313,7 @@ bool cTimer::Parse(char *s) bool cTimer::Save(FILE *f) { - return fprintf(f, "%d:%d:%s:%d:%d:%c:%d:%d:%s\n", active, channel, PrintDay(day), start, stop, quality, priority, lifetime, file) > 0; + return fprintf(f, "%d:%d:%s:%d:%d:%d:%d:%s\n", active, channel, PrintDay(day), start, stop, priority, lifetime, file) > 0; } bool cTimer::IsSingleEvent(void) @@ -383,7 +397,6 @@ cKeys Keys; // -- cChannels -------------------------------------------------------------- int CurrentChannel = 0; -bool ChannelLocked = false; cChannels Channels; diff --git a/config.h b/config.h index 51fd22e01..6184f5628 100644 --- a/config.h +++ b/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 #include #include @@ -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 @@ class cChannel : public cListObject { int srate; int vpid; int apid; + int ca; + int pnr; cChannel(void); cChannel(const cChannel *Channel); bool Parse(char *s); @@ -84,11 +95,10 @@ class cTimer : public cListObject { 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 @@ template class cConfig : public cList { 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 @@ template class cConfig : public cList { 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 {}; class cTimers : public cConfig {}; extern int CurrentChannel; -extern bool ChannelLocked; extern cChannels Channels; extern cTimers Timers; diff --git a/dvbapi.c b/dvbapi.c index 484a22e56..ef2f80862 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,171 +4,1024 @@ * See the main source file 'osm.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.2 2000/03/11 10:39:09 kls Exp $ + * $Id: dvbapi.c 1.3 2000/04/15 14:45:04 kls Exp $ */ #include "dvbapi.h" +#include #include -#include +#include +#include #include +#include +#include +#include #include #include "interface.h" #include "tools.h" #define VIDEODEVICE "/dev/video" -const char *DvbQuality = "LMH"; // Low, Medium, High +// The size of the array used to buffer video data: +#define VIDEOBUFSIZE (1024*1024) -bool DvbSetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid) +// The minimum amount of video data necessary to identify frames +// (must be smaller than VIDEOBUFSIZE!): +#define MINVIDEODATA (20*1024) // just a safe guess (max. size of any AV_PES block, plus some safety) + +// The maximum time the buffer is allowed to write data to disk when recording: +#define MAXRECORDWRITETIME 50 // ms + +#define AV_PES_HEADER_LEN 8 + +// AV_PES block types: +#define AV_PES_VIDEO 1 +#define AV_PES_AUDIO 2 + +// Picture types: +#define NO_PICTURE 0 +#define I_FRAME 1 +#define P_FRAME 2 +#define B_FRAME 3 + +#define FRAMESPERSEC 25 + +// The maximum file size is limited by the range that can be covered +// with 'int'. 4GB might be possible (if the range is considered +// 'unsigned'), 2GB should be possible (even if the range is considered +// 'signed'), so let's use 1GB for absolute safety (the actual file size +// may be slightly higher because we stop recording only before the next +// 'I' frame, to have a complete Group Of Pictures): +#define MAXVIDEOFILESIZE (1024*1024*1024) +#define MAXFILESPERRECORDING 255 + +#define INDEXFILESUFFIX "/index.vdr" +#define RESUMEFILESUFFIX "/resume.vdr" +#define RECORDFILESUFFIX "/%03d.vdr" +#define RECORDFILESUFFIXLEN 20 // some additional bytes for safety... +#define MAXPROCESSTIMEOUT 3 // seconds + +// The number of frames to back up when resuming an interrupted replay session: +#define RESUMEBACKUP (10 * FRAMESPERSEC) + +typedef unsigned char uchar; + +// --- cIndexFile ------------------------------------------------------------ + +class cIndexFile { +private: + struct tIndex { int offset; uchar type; uchar number; short reserved; }; + int f; + char *fileName, *pFileExt; + int last, resume; + tIndex *index; +public: + cIndexFile(const char *FileName, bool Record = false); + ~cIndexFile(); + void Write(uchar PictureType, uchar FileNumber, int FileOffset); + bool Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType = NULL); + int GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length = NULL); + int Get(uchar FileNumber, int FileOffset); + int Last(void) { return last; } + int GetResume(void) { return resume; } + bool StoreResume(int Index); + static char *Str(int Index); + }; + +cIndexFile::cIndexFile(const char *FileName, bool Record) { - int v = open(VIDEODEVICE, O_RDWR); - - if (v >= 0) { - struct frontend front; - ioctl(v, VIDIOCGFRONTEND, &front); - unsigned int freq = FrequencyMHz; - front.ttk = (freq < 11800UL) ? 0 : 1; - if (freq < 11800UL) - freq -= 9750UL; + f = -1; + fileName = pFileExt = NULL; + last = resume = -1; + index = NULL; + if (FileName) { + fileName = new char[strlen(FileName) + strlen(INDEXFILESUFFIX) + strlen(RESUMEFILESUFFIX) + 1]; + if (fileName) { // no max() function at hand... + strcpy(fileName, FileName); + pFileExt = fileName + strlen(fileName); + strcpy(pFileExt, INDEXFILESUFFIX); + int delta = 0; + if (access(fileName, R_OK) == 0) { + struct stat buf; + if (stat(fileName, &buf) == 0) { + delta = buf.st_size % sizeof(tIndex); + if (delta) { + delta = sizeof(tIndex) - delta; + esyslog(LOG_ERR, "ERROR: invalid file size (%d) in '%s'", buf.st_size, fileName); + } + last = (buf.st_size + delta) / sizeof(tIndex) - 1; + if (!Record && last >= 0) { + index = new tIndex[last + 1]; + int fi = open(fileName, O_RDONLY); + if (fi >= 0) { + if ((int)read(fi, index, buf.st_size) != buf.st_size) { + esyslog(LOG_ERR, "ERROR: can't read from file '%s'", fileName); + delete index; + index = NULL; + } + close(fi); + } + else + LOG_ERROR_STR(fileName); + } + } + else + LOG_ERROR; + } + if (Record) { + if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) >= 0) { + if (delta) { + esyslog(LOG_ERR, "ERROR: padding index file with %d '0' bytes", delta); + while (delta--) + writechar(f, 0); + } + } + else + LOG_ERROR_STR(fileName); + delete fileName; + fileName = pFileExt = NULL; + } + else { + strcpy(pFileExt, RESUMEFILESUFFIX); + int resumeFile = open(fileName, O_RDONLY); + if (resumeFile >= 0) { + if (read(resumeFile, &resume, sizeof(resume)) != sizeof(resume)) { + resume = -1; + LOG_ERROR_STR(fileName); + } + close(resumeFile); + } + else if (errno != ENOENT) + LOG_ERROR_STR(fileName); + } + } else - freq -= 10600UL; - front.freq = freq * 1000000UL; - front.diseqc = Diseqc; - front.srate = Srate * 1000; - front.volt = (Polarization == 'v') ? 0 : 1; - front.video_pid = Vpid; - front.audio_pid = Apid; - front.AFC = 1; - ioctl(v, VIDIOCSFRONTEND, &front); - close(v); - if (front.sync & 0x1F == 0x1F) + esyslog(LOG_ERR, "ERROR: can't copy file name '%s'", FileName); + } +} + +cIndexFile::~cIndexFile() +{ + if (f >= 0) + close(f); + delete fileName; +} + +void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) +{ + if (f >= 0) { + tIndex i = { FileOffset, PictureType, FileNumber, 0 }; + if (write(f, &i, sizeof(i)) != sizeof(i)) { + esyslog(LOG_ERR, "ERROR: can't write to index file"); + close(f); + f = -1; + return; + } + last++; + } +} + +bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType) +{ + if (index) { + if (Index >= 0 && Index <= last) { + *FileNumber = index[Index].number; + *FileOffset = index[Index].offset; + if (PictureType) + *PictureType = index[Index].type; return true; - esyslog(LOG_ERR, "channel not sync'ed (front.sync=%X)!", front.sync); + } } - else - Interface.Error("can't open VIDEODEVICE");//XXX return false; } -// -- cDvbRecorder ----------------------------------------------------------- +int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length) +{ + if (index) { + int d = Forward ? 1 : -1; + for (;;) { + Index += d; + if (Index >= 0 && Index <= last) { + if (index[Index].type == I_FRAME) { + *FileNumber = index[Index].number; + *FileOffset = index[Index].offset; + if (Length) { + // all recordings end with a non-I_FRAME, so the following should be safe: + int fn = index[Index + 1].number; + int fo = index[Index + 1].offset; + if (fn == *FileNumber) + *Length = fo - *FileOffset; + else { + esyslog(LOG_ERR, "ERROR: 'I' frame at end of file #%d", *FileNumber); + *Length = -1; + } + } + return Index; + } + } + else + break; + } + } + return -1; +} + +int cIndexFile::Get(uchar FileNumber, int FileOffset) +{ + if (index) { + //TODO implement binary search! + int i; + for (i = 0; i < last; i++) { + if (index[i].number > FileNumber || (index[i].number == FileNumber) && index[i].offset >= FileOffset) + break; + } + return i; + } + return -1; +} -cDvbRecorder::cDvbRecorder(void) +bool cIndexFile::StoreResume(int Index) { - recording = false; + if (fileName) { + int resumeFile = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (resumeFile >= 0) { + if (write(resumeFile, &Index, sizeof(Index)) != sizeof(Index)) + LOG_ERROR_STR(fileName); + close(resumeFile); + return true; + } + else if (errno != ENOENT) + LOG_ERROR_STR(fileName); + } + return false; } -cDvbRecorder::~cDvbRecorder() +char *cIndexFile::Str(int Index) { - Stop(); + static char buffer[16]; + int f = (Index % FRAMESPERSEC) + 1; + int s = (Index / FRAMESPERSEC); + int m = s / 60 % 60; + int h = s / 3600; + s %= 60; + snprintf(buffer, sizeof(buffer), "%d:%02d:%02d.%02d", h, m, s, f); + return buffer; } -bool cDvbRecorder::Recording(void) +// --- cRingBuffer ----------------------------------------------------------- + +/* cRingBuffer reads data from an input file, stores it in a buffer and writes + it to an output file upon request. The Read() and Write() functions should + be called only when the associated file is ready to provide or receive data + (use the 'select()' function to determine that), and the files should be + opened in non-blocking mode. + The '...Limit' parameters define safety limits. If they are exceeded a log entry + will be made. +*/ + +class cRingBuffer { +private: + uchar *buffer; + int size, head, tail, freeLimit, availLimit; + int countLimit, countOverflow; + int minFree; + bool eof; + int *inFile, *outFile; +protected: + int Free(void) { return ((tail >= head) ? size + head - tail : head - tail) - 1; } + int Available(void) { return (tail >= head) ? tail - head : size - head + tail; } + int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap! + int Writeable(void) { return (tail > head) ? tail - head : size - head; } + int Byte(int Offset); + bool WaitForOutFile(int Timeout); +public: + cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); + virtual ~cRingBuffer(); + virtual int Read(int Max = -1); + virtual int Write(int Max = -1); + bool EndOfFile(void) { return eof; } + bool Empty(void) { return Available() == 0; } + void Clear(void) { head = tail = 0; } + void Skip(int n); + }; + +cRingBuffer::cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit, int AvailLimit) { - return recording; + inFile = InFile; + outFile = OutFile; + size = Size; + Clear(); + freeLimit = FreeLimit; + availLimit = AvailLimit; + eof = false; + countLimit = countOverflow = 0; + minFree = size - 1; + buffer = new uchar[size]; + if (!buffer) + esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size); } -bool cDvbRecorder::Record(const char *FileName, char Quality) +cRingBuffer::~cRingBuffer() { - isyslog(LOG_INFO, "record %s (%c)", FileName, Quality); - if (MakeDirs(FileName)) { - FILE *f = fopen(FileName, "a"); - if (f) { - fprintf(f, "%s, %c\n", FileName, Quality); - fclose(f); - recording = true; - // TODO - Interface.Error("Recording not yet implemented!"); + dsyslog(LOG_INFO, "buffer stats: %d free, %d overflows, limit exceeded %d times", minFree, countOverflow, countLimit); + delete buffer; +} + +int cRingBuffer::Byte(int Offset) +{ + if (buffer && Offset < Available()) { + Offset += head; + if (Offset >= size) + Offset -= size; + return buffer[Offset]; + } + return -1; +} + +void cRingBuffer::Skip(int n) +{ + if (head < tail) { + head += n; + if (head > tail) + head = tail; + } + else if (head > tail) { + head += n; + if (head >= size) + head -= size; + if (head > tail) + head = tail; + } +} + +bool cRingBuffer::WaitForOutFile(int Timeout) +{ + fd_set set; + FD_ZERO(&set); + FD_SET(*outFile, &set); + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = Timeout; + if (select(FD_SETSIZE, NULL, &set, NULL, &timeout) > 0) { + if (FD_ISSET(*outFile, &set)) return true; + } + esyslog(LOG_ERR, "ERROR: timeout in WaitForOutFile(%d)", Timeout); + return false; +} + +int cRingBuffer::Read(int Max) +{ + if (buffer) { + eof = false; + int free = Free(); + if (free < minFree) + minFree = free; + if (freeLimit) { + if (free == 0) { + esyslog(LOG_ERR, "ERROR: buffer overflow (size=%d)", size); + countOverflow++; + } + else if (free < freeLimit) { + dsyslog(LOG_INFO, "free buffer space dipped into limit (%d < %d)", free, freeLimit); + countLimit++; + } + } + if (free == 0) + return 0; // the buffer is full + int readin = 0; + for (int i = 0; i < 2; i++) { + // If we read in exactly as many bytes as are immediately + // "readable" we have to do it again, because that means we + // were at the very end of the physical buffer and possibly only + // read in very few bytes. + int immediate = Readable(); + int n = immediate; + if (Max > 0 && n > Max) + n = Max; + if (n > 0) { + int r = read(*inFile, buffer + tail, n); + if (r > 0) { + readin += r; + tail += r; + if (tail > size) + esyslog(LOG_ERR, "ERROR: ooops: buffer tail (%d) exceeds size (%d)", tail, size); + if (tail >= size) + tail = 0; + } + else if (r < 0 && errno != EAGAIN) { + LOG_ERROR; + return -1; + } + else + eof = true; + if (r == immediate && Max != immediate && tail == 0) + Max -= immediate; + else + break; + } + } + return readin; + } + return -1; +} + +int cRingBuffer::Write(int Max) +{ + if (buffer) { + int avail = Available(); + if (availLimit) { + //XXX stats??? + if (avail == 0) + //XXX esyslog(LOG_ERR, "ERROR: buffer empty!"); + {//XXX + esyslog(LOG_ERR, "ERROR: buffer empty! %d", Max); + return Max > 0 ? Max : 0; + }//XXX + else if (avail < availLimit) +;//XXX dsyslog(LOG_INFO, "available buffer data dipped into limit (%d < %d)", avail, availLimit); + } + if (avail == 0) + return 0; // the buffer is empty + int n = Writeable(); + if (Max > 0 && n > Max) + n = Max; + int w = write(*outFile, buffer + head, n); + if (w > 0) { + head += w; + if (head > size) + esyslog(LOG_ERR, "ERROR: ooops: buffer head (%d) exceeds size (%d)", head, size); + if (head >= size) + head = 0; + } + else if (w < 0) { + if (errno != EAGAIN) + LOG_ERROR; + else + w = 0; + } + return w; + } + return -1; +} + +// --- cFileBuffer ----------------------------------------------------------- + +class cFileBuffer : public cRingBuffer { +protected: + cIndexFile *index; + uchar fileNumber; + char *fileName, *pFileNumber; + bool stop; + int GetAvPesLength(void) + { + if (Byte(0) == 'A' && Byte(1) == 'V' && Byte(4) == 'U') + return (Byte(6) << 8) + Byte(7) + AV_PES_HEADER_LEN; + return 0; + } + int GetAvPesType(void) { return Byte(2); } + int GetAvPesTag(void) { return Byte(3); } + int FindAvPesBlock(void); + int GetPictureType(int Offset) { return (Byte(Offset + 5) >> 3) & 0x07; } + int FindPictureStartCode(int Length); +public: + cFileBuffer(int *InFile, int *OutFile, const char *FileName, bool Recording, int Size, int FreeLimit = 0, int AvailLimit = 0); + virtual ~cFileBuffer(); + void Stop(void) { stop = true; } + }; + +cFileBuffer::cFileBuffer(int *InFile, int *OutFile, const char *FileName, bool Recording, int Size, int FreeLimit = 0, int AvailLimit = 0) +:cRingBuffer(InFile, OutFile, Size, FreeLimit, AvailLimit) +{ + index = NULL; + fileNumber = 0; + stop = false; + // Prepare the file name: + fileName = new char[strlen(FileName) + RECORDFILESUFFIXLEN]; + if (!fileName) { + esyslog(LOG_ERR, "ERROR: can't copy file name '%s'", fileName); + return; + } + strcpy(fileName, FileName); + pFileNumber = fileName + strlen(fileName); + // Create the index file: + index = new cIndexFile(FileName, Recording); + if (!index) + esyslog(LOG_ERR, "ERROR: can't allocate index"); + // let's continue without index, so we'll at least have the recording +} + +cFileBuffer::~cFileBuffer() +{ + delete index; + delete fileName; +} + +int cFileBuffer::FindAvPesBlock(void) +{ + int Skipped = 0; + + while (Available() > MINVIDEODATA) { + if (GetAvPesLength()) + return Skipped; + Skip(1); + Skipped++; } - else { - Interface.Error("Can't write to file!"); + return -1; +} + +int cFileBuffer::FindPictureStartCode(int Length) +{ + for (int i = AV_PES_HEADER_LEN; i < Length; i++) { + if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1 && Byte(i + 3) == 0) + return i; + } + return -1; +} + +// --- cRecordBuffer --------------------------------------------------------- + +class cRecordBuffer : public cFileBuffer { +private: + uchar pictureType; + int fileSize; + int recordFile; + uchar tagAudio, tagVideo; + bool ok, synced; + int Synchronize(void); + bool NextFile(void); + virtual int Write(int Max = -1); +public: + cRecordBuffer(int *InFile, const char *FileName); + virtual ~cRecordBuffer(); + int WriteWithTimeout(void); + }; + +cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) +:cFileBuffer(InFile, &recordFile, FileName, true, VIDEOBUFSIZE, VIDEOBUFSIZE / 10, 0) +{ + pictureType = NO_PICTURE; + fileSize = 0; + recordFile = -1; + tagAudio = tagVideo = 0; + ok = synced = false; + if (!fileName) + return;//XXX find a better way??? + // Find the highest existing file suffix: + for (;;) { + sprintf(pFileNumber, RECORDFILESUFFIX, ++fileNumber); + if (access(fileName, F_OK) < 0) { + if (errno == ENOENT) + break; // found a non existing file suffix + LOG_ERROR; + return; + } + } + ok = true; + //XXX hack to make the video device go into 'recording' mode: + char dummy; + read(*InFile, &dummy, sizeof(dummy)); +} + +cRecordBuffer::~cRecordBuffer() +{ + if (recordFile >= 0) + close(recordFile); +} + +int cRecordBuffer::Synchronize(void) +{ + int Length = 0; + int Skipped = 0; + int s; + + while ((s = FindAvPesBlock()) >= 0) { + pictureType = NO_PICTURE; + Skipped += s; + Length = GetAvPesLength(); + if (Length <= MINVIDEODATA) { + switch (GetAvPesType()) { + case AV_PES_VIDEO: + { + int PictureOffset = FindPictureStartCode(Length); + if (PictureOffset >= 0) { + pictureType = GetPictureType(PictureOffset); + if (pictureType < I_FRAME || pictureType > B_FRAME) + esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pictureType); + } + } + if (!synced) { + tagVideo = GetAvPesTag(); + if (pictureType == I_FRAME) { + synced = true; + Skipped = 0; + } + else { + Skip(Length - 1); + Length = 0; + } + } + else { + if (++tagVideo != GetAvPesTag()) { + esyslog(LOG_ERR, "ERROR: missed video data block #%d (next block is #%d)", tagVideo, GetAvPesTag()); + tagVideo = GetAvPesTag(); + } + } + break; + case AV_PES_AUDIO: + if (!synced) { + tagAudio = GetAvPesTag(); + Skip(Length - 1); + Length = 0; + } + else { + //XXX might get fooled the first time!!! + if (++tagAudio != GetAvPesTag()) { + esyslog(LOG_ERR, "ERROR: missed audio data block #%d (next block is #%d)", tagAudio, GetAvPesTag()); + tagAudio = GetAvPesTag(); + } + } + break; + default: // unknown data + Length = 0; // don't skip entire block - maybe we're just not in sync with AV_PES yet + if (synced) + esyslog(LOG_ERR, "ERROR: unknown data type '%d'", GetAvPesType()); + } + if (Length > 0) + break; + } + else if (synced) { + esyslog(LOG_ERR, "ERROR: block length too big (%d)", Length); + Length = 0; + } + Skip(1); + Skipped++; + } + if (synced && Skipped) + esyslog(LOG_ERR, "ERROR: skipped %d bytes", Skipped); + return Length; +} + +bool cRecordBuffer::NextFile(void) +{ + if (recordFile >= 0 && fileSize > MAXVIDEOFILESIZE && pictureType == I_FRAME) { + if (close(recordFile) < 0) + LOG_ERROR; + // don't return 'false', maybe we can still record into the next file + recordFile = -1; + fileNumber++; + if (fileNumber == 0) + esyslog(LOG_ERR, "ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); + fileSize = 0; + } + if (recordFile < 0) { + sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); + dsyslog(LOG_INFO, "recording to '%s'", fileName); + recordFile = open(fileName, O_RDWR | O_CREAT | O_NONBLOCK, S_IRUSR | S_IWUSR); + if (recordFile < 0) { + LOG_ERROR; return false; } } - // TODO - return false; + return true; } -bool cDvbRecorder::Play(const char *FileName, int Frame) +int cRecordBuffer::Write(int Max) { - if (!recording) { - isyslog(LOG_INFO, "play %s (%d)", FileName, Frame); - // TODO - Interface.Error("Playback not yet implemented!"); - return true; + // This function ignores the incoming 'Max'! + // It tries to write out exactly *one* block of AV_PES data. + if (!ok) + return -1; + int n = Synchronize(); + if (n) { + if (stop && pictureType == I_FRAME) { + ok = false; + return -1; // finish the recording before the next 'I' frame + } + if (NextFile()) { + if (index && pictureType != NO_PICTURE) + index->Write(pictureType, fileNumber, fileSize); + int written = 0; + for (;;) { + int w = cFileBuffer::Write(n); + if (w >= 0) { + fileSize += w; + written += w; + n -= w; + if (n == 0) + return written; + } + else + return w; + } + } + return -1; } - return false; + return 0; } -bool cDvbRecorder::FastForward(void) +int cRecordBuffer::WriteWithTimeout(void) { - isyslog(LOG_INFO, "fast forward"); - // TODO - return false; + int w, written = 0; + int t0 = time_ms(); + while ((w = Write()) > 0 && time_ms() - t0 < MAXRECORDWRITETIME) + written += w; + return w < 0 ? w : written; +} + +// --- cReplayBuffer --------------------------------------------------------- + +enum eReplayMode { rmPlay, rmFastForward, rmFastRewind }; + +class cReplayBuffer : public cFileBuffer { +private: + int fileOffset; + int replayFile; + eReplayMode mode; + bool skipAudio; + int lastIndex; + void SkipAudioBlocks(void); + bool NextFile(uchar FileNumber = 0, int FileOffset = -1); + void Close(void); +public: + cReplayBuffer(int *OutFile, const char *FileName); + virtual ~cReplayBuffer(); + virtual int Read(int Max = -1); + virtual int Write(int Max = -1); + void SetMode(eReplayMode Mode); + int Resume(void); + bool Save(void); + void SkipSeconds(int Seconds); + }; + +cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName) +:cFileBuffer(&replayFile, OutFile, FileName, false, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) +{ + fileOffset = 0; + replayFile = -1; + mode = rmPlay; + skipAudio = false; + lastIndex = -1; + if (!fileName) + return;//XXX find a better way??? + // All recordings start with '1': + fileNumber = 1; //TODO what if it doesn't start with '1'??? + //XXX hack to make the video device go into 'replaying' mode: + char dummy; + write(*OutFile, &dummy, sizeof(dummy)); +} + +cReplayBuffer::~cReplayBuffer() +{ + Close(); } -bool cDvbRecorder::FastRewind(void) +void cReplayBuffer::Close(void) { - isyslog(LOG_INFO, "fast rewind"); - // TODO + if (replayFile >= 0) { + if (close(replayFile) < 0) + LOG_ERROR; + replayFile = -1; + fileOffset = 0; + } +} + +void cReplayBuffer::SetMode(eReplayMode Mode) +{ + mode = Mode; + skipAudio = Mode != rmPlay; + if (mode != rmPlay) + Clear(); +} + +int cReplayBuffer::Resume(void) +{ + if (index) { + int Index = index->GetResume(); + if (Index >= 0) { + uchar FileNumber; + int FileOffset; + if (index->Get(Index, &FileNumber, &FileOffset) && NextFile(FileNumber, FileOffset)) + return Index; + } + } + return -1; +} + +bool cReplayBuffer::Save(void) +{ + if (index) { + int Index = index->Get(fileNumber, fileOffset); + if (Index >= 0) { + Index -= RESUMEBACKUP; + if (Index > 0) { + uchar FileNumber; + int FileOffset; + Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset); + } + else + Index = 0; + if (Index >= 0) + return index->StoreResume(Index); + } + } return false; } -bool cDvbRecorder::Pause(void) +void cReplayBuffer::SkipSeconds(int Seconds) +{ + if (index && Seconds) { + int Index = index->Get(fileNumber, fileOffset); + if (Index >= 0) { + if (Seconds < 0) { + int sec = index->Last() / FRAMESPERSEC; + if (Seconds < -sec) + Seconds = - sec; + } + Index += Seconds * FRAMESPERSEC; + if (Index < 0) + Index = 1; + uchar FileNumber; + int FileOffset; + if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0) + NextFile(FileNumber, FileOffset); + } + } +} + +void cReplayBuffer::SkipAudioBlocks(void) { - isyslog(LOG_INFO, "pause"); - // TODO + int Length; + + while ((Length = GetAvPesLength()) > 0) { + if (GetAvPesType() == AV_PES_AUDIO) + Skip(Length); + else + break; + } +} + +bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) +{ + if (FileNumber > 0) { + Clear(); + if (FileNumber != fileNumber) { + Close(); + fileNumber = FileNumber; + } + } + if (replayFile >= 0 && EndOfFile()) { + Close(); + fileNumber++; + if (fileNumber == 0) + esyslog(LOG_ERR, "ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); + } + if (replayFile < 0) { + sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); + if (access(fileName, R_OK) == 0) { + dsyslog(LOG_INFO, "playing '%s'", fileName); + replayFile = open(fileName, O_RDONLY | O_NONBLOCK); + if (replayFile < 0) { + LOG_ERROR; + return false; + } + } + else if (errno != ENOENT) + LOG_ERROR; + } + if (replayFile >= 0) { + if (FileOffset >= 0) { + if ((fileOffset = lseek(replayFile, FileOffset, SEEK_SET)) != FileOffset) + LOG_ERROR; + // don't return 'false', maybe we can still replay the file + } + return true; + } return false; } -void cDvbRecorder::Stop(void) +int cReplayBuffer::Read(int Max = -1) { - isyslog(LOG_INFO, "stop"); - recording = false; - // TODO + if (stop) + return -1; + if (mode != rmPlay) { + if (index) { + if (Available()) + return 0; // write out the entire block + int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileNumber, fileOffset); + if (Index >= 0) { + uchar FileNumber; + int FileOffset, Length; + Index = index->GetNextIFrame(Index, mode == rmFastForward, &FileNumber, &FileOffset, &Length); + if (Index >= 0) { + if (!NextFile(FileNumber, FileOffset)) + return -1; + Max = Length; + } + lastIndex = Index; + } + if (Index < 0) { + // This results in normal replay after a fast rewind. + // After a fast forward it will stop. + // TODO Could we cause it to pause at the last frame? + SetMode(rmPlay); + return 0; + } + } + } + else + lastIndex = -1; + //XXX timeout as in recording??? + if (NextFile()) { + int readin = 0; + do { + // If Max is > 0 here we need to make sure we read in the entire block! + int r = cFileBuffer::Read(Max); + if (r >= 0) + readin += r; + else + return -1; + } while (readin < Max && Free() > 0); + return readin; + } + if (Available() > 0) + return 0; + return -1; } -int cDvbRecorder::Frame(void) +int cReplayBuffer::Write(int Max) { - isyslog(LOG_INFO, "frame"); - // TODO - return 0; + int Written = 0; + + do { + if (skipAudio) { + SkipAudioBlocks(); + Max = GetAvPesLength(); + } + while (Max) { + int w = cFileBuffer::Write(Max); + if (w >= 0) { + fileOffset += w; + Written += w; + if (Max < 0) + break; + Max -= w; + } + else + return w; + //XXX??? Why does the buffer get empty here??? + if (Empty() || !WaitForOutFile(1000000)) + return Written; + } + } while (skipAudio && Available()); + return Written; } -// --- cDvbOsd --------------------------------------------------------------- +// --- cDvbApi --------------------------------------------------------------- -cDvbOsd::cDvbOsd(void) +cDvbApi::cDvbApi(void) { + isMainProcess = true; + pidRecord = pidReplay = 0; + fromRecord = toRecord = -1; + fromReplay = toReplay = -1; + videoDev = open(VIDEODEVICE, O_RDWR | O_NONBLOCK); + if (videoDev < 0) + LOG_ERROR; cols = rows = 0; -#ifdef DEBUG_OSD - memset(&colorPairs, 0, sizeof(colorPairs)); +#if defined(DEBUG_OSD) || defined(DEBUG_REMOTE) initscr(); - start_color(); keypad(stdscr, TRUE); nonl(); cbreak(); noecho(); timeout(1000); +#endif +#if defined(DEBUG_OSD) + memset(&colorPairs, 0, sizeof(colorPairs)); + start_color(); leaveok(stdscr, TRUE); window = stdscr; #endif -#ifdef DEBUG_REMOTE - initscr(); - keypad(stdscr, TRUE); - nonl(); - cbreak(); - noecho(); - timeout(1000); -#endif } -cDvbOsd::~cDvbOsd() +cDvbApi::~cDvbApi() { - Close(); + if (isMainProcess) { + if (videoDev >= 0) { + Close(); + StopReplay(); + StopRecord(); + close(videoDev); + } +#if defined(DEBUG_REMOTE) || defined(DEBUG_OSD) + endwin(); +#endif + } } #ifdef DEBUG_OSD -void cDvbOsd::SetColor(eDvbColor colorFg, eDvbColor colorBg) +void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg) { int color = (colorBg << 16) | colorFg | 0x80000000; for (int i = 0; i < MaxColorPairs; i++) { @@ -185,11 +1038,9 @@ void cDvbOsd::SetColor(eDvbColor colorFg, eDvbColor colorBg) } } #else -void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) +void cDvbApi::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) { - int v = open(VIDEODEVICE, O_RDWR); - - if (v >= 0) { + if (videoDev >= 0) { struct drawcmd dc; dc.cmd = cmd; dc.color = color; @@ -198,15 +1049,12 @@ void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co dc.x1 = x1; dc.y1 = y1; dc.data = (void *)data; - ioctl(v, VIDIOCSOSDCOMMAND, &dc); - close(v); + ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc); } - else - Interface.Error("can't open VIDEODEVICE");//XXX } #endif -void cDvbOsd::Open(int w, int h) +void cDvbApi::Open(int w, int h) { cols = w; rows = h; @@ -233,14 +1081,14 @@ void cDvbOsd::Open(int w, int h) SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255); } -void cDvbOsd::Close(void) +void cDvbApi::Close(void) { #ifndef DEBUG_OSD Cmd(OSD_Close); #endif } -void cDvbOsd::Clear(void) +void cDvbApi::Clear(void) { #ifdef DEBUG_OSD SetColor(clrBackground, clrBackground); @@ -250,7 +1098,7 @@ void cDvbOsd::Clear(void) #endif } -void cDvbOsd::Fill(int x, int y, int w, int h, eDvbColor color) +void cDvbApi::Fill(int x, int y, int w, int h, eDvbColor color) { if (x < 0) x = cols + x; if (y < 0) y = rows + y; @@ -265,12 +1113,12 @@ void cDvbOsd::Fill(int x, int y, int w, int h, eDvbColor color) #endif } -void cDvbOsd::ClrEol(int x, int y, eDvbColor color) +void cDvbApi::ClrEol(int x, int y, eDvbColor color) { Fill(x, y, cols - x, 1, color); } -void cDvbOsd::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg) +void cDvbApi::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg) { if (x < 0) x = cols + x; if (y < 0) y = rows + y; @@ -282,3 +1130,343 @@ void cDvbOsd::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor col Cmd(OSD_Text, (int(colorBg) << 16) | colorFg, x * charWidth, y * lineHeight, 1, 0, s); #endif } + +bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr) +{ + if (videoDev >= 0) { + struct frontend front; + ioctl(videoDev, VIDIOCGFRONTEND, &front); + unsigned int freq = FrequencyMHz; + front.ttk = (freq < 11800UL) ? 0 : 1; + if (freq < 11800UL) + freq -= 9750UL; + else + freq -= 10600UL; + front.channel_flags = Ca ? DVB_CHANNEL_CA : DVB_CHANNEL_FTA; + front.pnr = Pnr; + front.freq = freq * 1000000UL; + front.diseqc = Diseqc; + front.srate = Srate * 1000; + front.volt = (Polarization == 'v') ? 0 : 1; + front.video_pid = Vpid; + front.audio_pid = Apid; + front.fec = 8; + front.AFC = 1; + ioctl(videoDev, VIDIOCSFRONTEND, &front); + if (front.sync & 0x1F == 0x1F) + return true; + esyslog(LOG_ERR, "ERROR: channel not sync'ed (front.sync=%X)!", front.sync); + } + return false; +} + +void cDvbApi::KillProcess(pid_t pid) +{ + pid_t Pid2Wait4 = pid; + for (time_t t0 = time(NULL); time(NULL) - t0 < MAXPROCESSTIMEOUT; ) { + int status; + pid_t pid = waitpid(Pid2Wait4, &status, WNOHANG); + if (pid < 0) { + if (errno != ECHILD) + LOG_ERROR; + return; + } + if (pid == Pid2Wait4) + return; + } + esyslog(LOG_ERR, "ERROR: process %d won't end (waited %d seconds) - terminating it...", Pid2Wait4, MAXPROCESSTIMEOUT); + if (kill(Pid2Wait4, SIGTERM) < 0) { + esyslog(LOG_ERR, "ERROR: process %d won't terminate (%s) - killing it...", Pid2Wait4, strerror(errno)); + if (kill(Pid2Wait4, SIGKILL) < 0) + esyslog(LOG_ERR, "ERROR: process %d won't die (%s) - giving up", Pid2Wait4, strerror(errno)); + } +} + +bool cDvbApi::Recording(void) +{ + return pidRecord; +} + +bool cDvbApi::Replaying(void) +{ + return pidReplay; +} + +bool cDvbApi::StartRecord(const char *FileName) +{ + if (Recording()) { + esyslog(LOG_ERR, "ERROR: StartRecord() called while recording - ignored!"); + return false; + } + if (videoDev >= 0) { + + // Check FileName: + + if (!FileName) { + esyslog(LOG_ERR, "ERROR: StartRecord: file name is (null)"); + return false; + } + isyslog(LOG_INFO, "record %s", FileName); + + // Create directories if necessary: + + if (!MakeDirs(FileName, true)) + return false; + + // Open pipes for recording process: + + int fromRecordPipe[2], toRecordPipe[2]; + + if (pipe(fromRecordPipe) != 0) { + LOG_ERROR; + return false; + } + if (pipe(toRecordPipe) != 0) { + LOG_ERROR; + return false; + } + + // Create recording process: + + pidRecord = fork(); + if (pidRecord < 0) { + LOG_ERROR; + return false; + } + if (pidRecord == 0) { + + // This is the actual recording process + + dsyslog(LOG_INFO, "start recording process (pid=%d)", getpid()); + isMainProcess = false; + int fromMain = toRecordPipe[0]; + int toMain = fromRecordPipe[1]; + cRecordBuffer *Buffer = new cRecordBuffer(&videoDev, FileName); + if (Buffer) { + for (;;) { + fd_set set; + FD_ZERO(&set); + FD_SET(videoDev, &set); + FD_SET(fromMain, &set); + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) { + if (FD_ISSET(videoDev, &set)) { + if (Buffer->Read() < 0) + break; + } + if (FD_ISSET(fromMain, &set)) { + switch (readchar(fromMain)) { + case dvbStop: Buffer->Stop(); break; + break; + } + } + } + else + esyslog(LOG_ERR, "ERROR: video data stream broken"); + if (Buffer->WriteWithTimeout() < 0) + break; + } + delete Buffer; + } + else + esyslog(LOG_ERR, "ERROR: can't allocate recording buffer"); + close(fromMain); + close(toMain); + dsyslog(LOG_INFO, "end recording process"); + exit(0); + } + + // Establish communication with the recording process: + + fromRecord = fromRecordPipe[0]; + toRecord = toRecordPipe[1]; + return true; + } + return false; +} + +void cDvbApi::StopRecord(void) +{ + if (pidRecord) { + writechar(toRecord, dvbStop); + close(toRecord); + close(fromRecord); + toRecord = fromRecord = -1; + KillProcess(pidRecord); + pidRecord = 0; + SetReplayMode(VID_PLAY_RESET); //XXX + } +} + +void cDvbApi::SetReplayMode(int Mode) +{ + if (videoDev >= 0) { + struct video_play_mode pmode; + pmode.mode = Mode; + ioctl(videoDev, VIDIOCSPLAYMODE, &pmode); + } +} + +bool cDvbApi::StartReplay(const char *FileName) +{ + if (Recording()) { + esyslog(LOG_ERR, "ERROR: StartReplay() called while recording - ignored!"); + return false; + } + StopReplay(); + if (videoDev >= 0) { + + // Check FileName: + + if (!FileName) { + esyslog(LOG_ERR, "ERROR: StartReplay: file name is (null)"); + return false; + } + isyslog(LOG_INFO, "replay %s", FileName); + + // Open pipes for replay process: + + int fromReplayPipe[2], toReplayPipe[2]; + + if (pipe(fromReplayPipe) != 0) { + LOG_ERROR; + return false; + } + if (pipe(toReplayPipe) != 0) { + LOG_ERROR; + return false; + } + + // Create replay process: + + pidReplay = fork(); + if (pidReplay < 0) { + LOG_ERROR; + return false; + } + if (pidReplay == 0) { + + // This is the actual replaying process + + dsyslog(LOG_INFO, "start replaying process (pid=%d)", getpid()); + isMainProcess = false; + int fromMain = toReplayPipe[0]; + int toMain = fromReplayPipe[1]; + cReplayBuffer *Buffer = new cReplayBuffer(&videoDev, FileName); + if (Buffer) { + bool Paused = false; + bool FastForward = false; + bool FastRewind = false; + int ResumeIndex = Buffer->Resume(); + if (ResumeIndex >= 0) + isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, cIndexFile::Str(ResumeIndex)); + for (;;) { + if (Buffer->Read() < 0) + break; + fd_set setIn, setOut; + FD_ZERO(&setIn); + FD_ZERO(&setOut); + FD_SET(fromMain, &setIn); + FD_SET(videoDev, &setOut); + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + if (select(FD_SETSIZE, &setIn, &setOut, NULL, &timeout) > 0) { + if (FD_ISSET(videoDev, &setOut)) { + if (Buffer->Write() < 0) + break; + } + if (FD_ISSET(fromMain, &setIn)) { + switch (readchar(fromMain)) { + case dvbStop: Buffer->Stop(); break; + case dvbPauseReplay: SetReplayMode(Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); + Paused = !Paused; + FastForward = FastRewind = false; + Buffer->SetMode(rmPlay); + break; + case dvbFastForward: SetReplayMode(VID_PLAY_NORMAL); + FastForward = !FastForward; + FastRewind = Paused = false; + Buffer->SetMode(FastForward ? rmFastForward : rmPlay); + break; + case dvbFastRewind: SetReplayMode(VID_PLAY_NORMAL); + FastRewind = !FastRewind; + FastForward = Paused = false; + Buffer->SetMode(FastRewind ? rmFastRewind : rmPlay); + break; + case dvbSkip: { + int Seconds; + if (readint(fromMain, Seconds)) { + SetReplayMode(VID_PLAY_NORMAL); + FastForward = FastRewind = Paused = false; + Buffer->SetMode(rmPlay); + Buffer->SkipSeconds(Seconds); + } + } + break; + } + } + } + } + Buffer->Save(); + delete Buffer; + } + else + esyslog(LOG_ERR, "ERROR: can't allocate replaying buffer"); + close(fromMain); + close(toMain); + SetReplayMode(VID_PLAY_RESET); //XXX + dsyslog(LOG_INFO, "end replaying process"); + exit(0); + } + + // Establish communication with the replay process: + + fromReplay = fromReplayPipe[0]; + toReplay = toReplayPipe[1]; + return true; + } + return false; +} + +void cDvbApi::StopReplay(void) +{ + if (pidReplay) { + writechar(toReplay, dvbStop); + close(toReplay); + close(fromReplay); + toReplay = fromReplay = -1; + KillProcess(pidReplay); + pidReplay = 0; + SetReplayMode(VID_PLAY_RESET); //XXX + } +} + +void cDvbApi::PauseReplay(void) +{ + if (pidReplay) + writechar(toReplay, dvbPauseReplay); +} + +void cDvbApi::FastForward(void) +{ + if (pidReplay) + writechar(toReplay, dvbFastForward); +} + +void cDvbApi::FastRewind(void) +{ + if (pidReplay) + writechar(toReplay, dvbFastRewind); +} + +void cDvbApi::Skip(int Seconds) +{ + if (pidReplay) { + writechar(toReplay, dvbSkip); + writeint(toReplay, Seconds); + } +} + diff --git a/dvbapi.h b/dvbapi.h index 2e8406ee8..3c447cf1f 100644 --- a/dvbapi.h +++ b/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 #endif +#include #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 @@ class cDvbOsd { 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 diff --git a/interface.c b/interface.c index 6a4b2a4e2..a54651357 100644 --- a/interface.c +++ b/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); } } diff --git a/interface.h b/interface.h index 9322cf39d..1e5329d5d 100644 --- a/interface.h +++ b/interface.h @@ -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 @@ class cInterface { }; extern cInterface Interface; +extern cDvbApi DvbApi; //XXX member of cInterface??? #endif //__INTERFACE_H diff --git a/keys-pc.conf b/keys-pc.conf index cfbe4587144cd511eac35a937b408cb2fc648c1a..744609d5c09e0c95ec545e912d01d81de7cd64ab 100644 GIT binary patch delta 156 zcmbQuw32y(C6k%aMC%9jL8;04MJb#HU|?><6_8k3oC@O_a0Qp-7r=PNTu!O!nR!sI yi4j+DYGP4xhFgA7c_Q2hGc%~LQ(|&9RH+$IX?A7-ib6wEupoZ{LY<+hF&6+hj49#( delta 12 TcmZ3Index()/*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) diff --git a/osm.c b/osm.c index 7031d6893..70305ce88 100644 --- a/osm.c +++ b/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 #include "config.h" #include "interface.h" #include "menu.h" @@ -37,6 +38,13 @@ #define KEYS_CONF "keys.conf" #endif +static int Interrupted = 0; + +void SignalHandler(int signum) +{ + Interrupted = signum; +} + int main(int argc, char *argv[]) { openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); @@ -50,69 +58,93 @@ int main(int argc, char *argv[]) cChannel::SwitchTo(CurrentChannel); + if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN); + if (signal(SIGINT, SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN); + if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN); + cMenuMain *Menu = NULL; cTimer *Timer = NULL; cRecording *Recording = NULL; - for (;;) { - AssertFreeDiskSpace(); - if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) { - DELETENULL(Menu); - // make sure the timer won't be deleted: - Timer->SetRecording(true); - // switch to channel: - cChannel::SwitchTo(Timer->channel - 1); - ChannelLocked = true; - // start recording: - Recording = new cRecording(Timer); - if (!Recording->Record()) - DELETENULL(Recording); - } - if (Timer && !Timer->Matches()) { - // stop recording: - if (Recording) { - Recording->Stop(); - DELETENULL(Recording); - } - // release channel and timer: - ChannelLocked = false; - Timer->SetRecording(false); - // clear single event timer: - if (Timer->IsSingleEvent()) { - DELETENULL(Menu); // must make sure no menu uses it - isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1); - Timers.Del(Timer); - Timers.Save(); - } - Timer = NULL; - } - eKeys key = Interface.GetKey(); - if (Menu) { - switch (Menu->ProcessKey(key)) { - default: if (key != kMenu) - break; - case osBack: - case osEnd: DELETENULL(Menu); - break; + while (!Interrupted) { + AssertFreeDiskSpace(); + if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) { + DELETENULL(Menu); + // make sure the timer won't be deleted: + Timer->SetRecording(true); + // switch to channel: + cChannel::SwitchTo(Timer->channel - 1); + // start recording: + Recording = new cRecording(Timer); + if (!Recording->Record()) + DELETENULL(Recording); + } + if (Timer && !Timer->Matches()) { + // stop recording: + if (Recording) { + Recording->Stop(); + DELETENULL(Recording); + } + // release timer: + Timer->SetRecording(false); + // clear single event timer: + if (Timer->IsSingleEvent()) { + DELETENULL(Menu); // must make sure no menu uses it + isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1); + Timers.Del(Timer); + Timers.Save(); + } + Timer = NULL; + } + eKeys key = Interface.GetKey(); + if (Menu) { + switch (Menu->ProcessKey(key)) { + default: if (key != kMenu) + break; + case osBack: + case osEnd: DELETENULL(Menu); + break; + } } - } - else { - switch (key) { - case kMenu: Menu = new cMenuMain; - Menu->Display(); - break; - case kUp: - case kDown: { - int n = CurrentChannel + (key == kUp ? 1 : -1); - cChannel *channel = Channels.Get(n); - if (channel) - channel->Switch(); - } - break; - default: break; + else { + switch (key) { + // Record/Replay Control: + case kBegin: DvbApi.Skip(-INT_MAX); break; + case kRecord: if (!DvbApi.Recording()) { + cTimer *timer = new cTimer(true); + Timers.Add(timer); + Timers.Save(); + } + else + Interface.Error("Already recording!"); + break; + case kPause: DvbApi.PauseReplay(); break; + case kStop: DvbApi.StopReplay(); break; + case kSearchBack: DvbApi.FastRewind(); break; + case kSearchForward: DvbApi.FastForward(); break; + case kSkipBack: DvbApi.Skip(-60); break; + case kSkipForward: DvbApi.Skip(60); break; + // Menu Control: + case kMenu: Menu = new cMenuMain; + Menu->Display(); + break; + case kUp: + case kDown: { + int n = CurrentChannel + (key == kUp ? 1 : -1); + cChannel *channel = Channels.Get(n); + if (channel) + channel->Switch(); + } + break; + default: break; + } } - } - } + } + isyslog(LOG_INFO, "caught signal %d", Interrupted); + DvbApi.StopRecord(); + DvbApi.StopReplay(); + //TODO kill any remaining sub-processes! + isyslog(LOG_INFO, "exiting", Interrupted); closelog(); - return 1; + return 0; } diff --git a/recording.c b/recording.c index afc2d8b3e..15c716300 100644 --- a/recording.c +++ b/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 #include @@ -16,17 +17,17 @@ #define RECEXT ".rec" #define DELEXT ".del" -#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%c.%02d.%02d" RECEXT +#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT #define NAMEFORMAT "%s/%s/" DATAFORMAT -#define FINDCMD "find %s -type f -name '%s'" +#define FINDCMD "find %s -type d -name '%s'" #define DFCMD "df -m %s" #define MINDISKSPACE 1024 // MB -const char *BaseDir = "/video";//XXX +#define DISKCHECKDELTA 300 // seconds between checks for free disk space -cDvbRecorder *Recorder = NULL; +const char *BaseDir = "/video"; static bool LowDiskSpace(void) { @@ -58,51 +59,54 @@ void AssertFreeDiskSpace(void) // With every call to this function we try to actually remove // a file, or mark a file for removal ("delete" it), so that // it will get removed during the next call. - if (Recorder && Recorder->Recording() && LowDiskSpace()) { - // Remove the oldest file that has been "deleted": - cRecordings Recordings; - if (Recordings.Load(true)) { - cRecording *r = Recordings.First(); - cRecording *r0 = r; - while (r) { - if (r->start < r0->start) - r0 = r; - r = Recordings.Next(r); - } - if (r0 && r0->Remove()) - return; - } - // No "deleted" files to remove, so let's see if we can delete a recording: - if (Recordings.Load(false)) { - cRecording *r = Recordings.First(); - cRecording *r0 = NULL; - while (r) { - if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) { - if (r0) { - if (r->priority < r0->priority) + static time_t LastFreeDiskCheck = 0; + if (time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA) { + LastFreeDiskCheck = time(NULL); + if (DvbApi.Recording() && LowDiskSpace()) { + // Remove the oldest file that has been "deleted": + cRecordings Recordings; + if (Recordings.Load(true)) { + cRecording *r = Recordings.First(); + cRecording *r0 = r; + while (r) { + if (r->start < r0->start) + r0 = r; + r = Recordings.Next(r); + } + if (r0 && r0->Remove()) + return; + } + // No "deleted" files to remove, so let's see if we can delete a recording: + if (Recordings.Load(false)) { + cRecording *r = Recordings.First(); + cRecording *r0 = NULL; + while (r) { + if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) { + if (r0) { + if (r->priority < r0->priority) + r0 = r; + } + else r0 = r; } - else - r0 = r; + r = Recordings.Next(r); } - r = Recordings.Next(r); - } - if (r0 && r0->Delete()) - return; + if (r0 && r0->Delete()) + return; + } + // Unable to free disk space, but there's nothing we can do about that... + esyslog(LOG_ERR, "low disk space, but no recordings to delete"); } - // Unable to free disk space, but there's nothing we can do about that... - //TODO maybe a log entry - but make sure it doesn't come too often } } // --- cRecording ------------------------------------------------------------ -cRecording::cRecording(const char *Name, time_t Start, char Quality, int Priority, int LifeTime) +cRecording::cRecording(const char *Name, time_t Start, int Priority, int LifeTime) { fileName = NULL; name = strdup(Name); start = Start; - quality = Quality; priority = Priority; lifetime = LifeTime; } @@ -112,7 +116,6 @@ cRecording::cRecording(cTimer *Timer) fileName = NULL; name = strdup(Timer->file); start = Timer->StartTime(); - quality = Timer->quality; priority = Timer->priority; lifetime = Timer->lifetime; } @@ -127,7 +130,7 @@ cRecording::cRecording(const char *FileName) if (p) { time_t now = time(NULL); struct tm t = *localtime(&now); // this initializes the time zone in 't' - if (8 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &quality, &priority, &lifetime)) { + if (7 == sscanf(p + 1, DATAFORMAT, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &priority, &lifetime)) { t.tm_year -= 1900; t.tm_mon--; t.tm_sec = 0; @@ -149,7 +152,7 @@ const char *cRecording::FileName(void) { if (!fileName) { struct tm *t = localtime(&start); - asprintf(&fileName, NAMEFORMAT, BaseDir, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, quality, priority, lifetime); + asprintf(&fileName, NAMEFORMAT, BaseDir, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime); } return fileName; } @@ -163,7 +166,7 @@ bool cRecording::Delete(void) strncpy(ext, DELEXT, strlen(ext)); isyslog(LOG_INFO, "deleting recording %s", FileName()); if (rename(FileName(), NewName) == -1) { - esyslog(LOG_ERR, "ERROR: %s", strerror(errno)); + esyslog(LOG_ERR, "ERROR: %s: %s", FileName(), strerror(errno)); result = false; } } @@ -173,40 +176,23 @@ bool cRecording::Delete(void) bool cRecording::Remove(void) { - bool result = true; isyslog(LOG_INFO, "removing recording %s", FileName()); - if (remove(FileName()) == -1) { - esyslog(LOG_ERR, "ERROR: %s", strerror(errno)); - result = false; - } - return result; -} - -bool cRecording::AssertRecorder(void) -{ - if (!Recorder || !Recorder->Recording()) { - if (!Recorder) - Recorder = new cDvbRecorder; - return true; - } - Interface.Error("Recorder is in use!"); - return false; + return RemoveFileOrDir(FileName()); } bool cRecording::Record(void) { - return AssertRecorder() && Recorder->Record(FileName(), quality); + return DvbApi.StartRecord(FileName()); } bool cRecording::Play(void) { - return AssertRecorder() && Recorder->Play(FileName()); + return DvbApi.StartReplay(FileName()); } void cRecording::Stop(void) { - if (Recorder) - Recorder->Stop(); + DvbApi.StopRecord(); } // --- cRecordings ----------------------------------------------------------- diff --git a/recording.h b/recording.h index 5b093a043..5a5e8de48 100644 --- a/recording.h +++ b/recording.h @@ -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(); diff --git a/remote.c b/remote.c index c2fb36f61..bf5b41f84 100644 --- a/remote.c +++ b/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; diff --git a/timers.conf b/timers.conf index de4df9dac..1996be4be 100644 --- a/timers.conf +++ b/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 diff --git a/tools.c b/tools.c index 5a21a9307..e356e0fdb 100644 --- a/tools.c +++ b/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 #include #include #include #include #include +#include #define MaxBuffer 1000 +int SysLogLevel = 3; + +void writechar(int filedes, char c) +{ + write(filedes, &c, sizeof(c)); +} + +void writeint(int filedes, int n) +{ + write(filedes, &n, sizeof(n)); +} + +char readchar(int filedes) +{ + char c; + read(filedes, &c, 1); + return c; +} + +bool readint(int filedes, int &n) +{ + //XXX timeout!! + return read(filedes, &n, sizeof(n)); +} + char *readline(FILE *f) { static char buffer[MaxBuffer]; @@ -30,36 +58,83 @@ char *readline(FILE *f) int time_ms(void) { + static time_t t0 = 0; struct timeval t; - if (gettimeofday(&t, NULL) == 0) - return t.tv_sec * 1000 + t.tv_usec / 1000; + if (gettimeofday(&t, NULL) == 0) { + if (t0 == 0) + t0 = t.tv_sec; // this avoids an overflow (we only work with deltas) + return (t.tv_sec - t0) * 1000 + t.tv_usec / 1000; + } return 0; } -bool MakeDirs(const char *FileName) +void delay_ms(int ms) +{ + int t0 = time_ms(); + while (time_ms() - t0 < ms) + ; +} + +bool MakeDirs(const char *FileName, bool IsDirectory) { bool result = true; char *s = strdup(FileName); char *p = s; if (*p == '/') p++; - while ((p = strchr(p, '/')) != NULL) { - *p = 0; + while ((p = strchr(p, '/')) != NULL || IsDirectory) { + if (p) + *p = 0; struct stat fs; if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) { isyslog(LOG_INFO, "creating directory %s", s); if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) { - esyslog(LOG_ERR, "ERROR while creating directory %s: %s", s, strerror(errno)); + esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno)); result = false; break; } } - *p++ = '/'; + if (p) + *p++ = '/'; + else + break; } delete s; return result; } +bool RemoveFileOrDir(const char *FileName) +{ + struct stat st; + if (stat(FileName, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + DIR *d = opendir(FileName); + if (d) { + struct dirent *e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) { + char *buffer; + asprintf(&buffer, "%s/%s", FileName, e->d_name); + if (remove(buffer) < 0) + esyslog(LOG_ERR, "ERROR: %s: %s", buffer, strerror(errno)); + delete buffer; + } + } + closedir(d); + } + else { + esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno)); + return false; + } + } + if (remove(FileName) == 0) + return true; + } + else + esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno)); + return false; +} + // --- cListObject ----------------------------------------------------------- cListObject::cListObject(void) diff --git a/tools.h b/tools.h index 9f87bbde1..48665a84f 100644 --- a/tools.h +++ b/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 #include -//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 @@ class cListBase { 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); From 85b8e41e8bb16e4e66561768026456ec5f0ee276 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Mon, 24 Apr 2000 18:00:00 +0200 Subject: [PATCH 004/307] Version 0.04 - Changed name from 'osm' to 'vdr' to avoid mixups with the 'oms' program that appears to be in use with DVD replay. - Implemented a channel display in the top menu line. - Implemented replay progress display (press "Ok" when replaying to bring it up). - Implemented direct channel selecting by pressing the numeric keys. - Added several 'const' keywords to please stricter compilers. - The repeat function for the remote control no longer adapts dynamically to the timing of the RCU (this sometimes caused the repeat function to kick in too early). - Channel selection is now blocked when recording or replaying. - Improved process handling. --- BUGS | 7 -- HISTORY | 18 ++++- INSTALL | 96 ++++++++++++++++++++++++++ MANUAL | 53 +++++++++++++-- Makefile | 16 ++--- README | 112 ++----------------------------- TODO | 3 - config.c | 5 +- config.h | 4 +- dvbapi.c | 171 +++++++++++++++++++++++++++++++++++------------ dvbapi.h | 21 ++++-- interface.c | 60 +++++++++++------ interface.h | 15 +++-- menu.c | 52 +++++++++++---- menu.h | 13 +++- osd.c | 6 +- osd.h | 10 +-- osm.c | 150 ----------------------------------------- recording.c | 40 ++++++----- recording.h | 21 +++--- remote.c | 47 +++++++------ remote.h | 7 +- timers.conf | 4 +- tools.c | 60 +++++++++++++++-- tools.h | 12 +++- vdr.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 26 files changed, 748 insertions(+), 444 deletions(-) create mode 100644 INSTALL delete mode 100644 osm.c create mode 100644 vdr.c diff --git a/BUGS b/BUGS index bcb37728a..66755f9f7 100644 --- a/BUGS +++ b/BUGS @@ -14,10 +14,3 @@ Video Disk Recorder - Known Bugs 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? diff --git a/HISTORY b/HISTORY index c013340dd..95cd350b2 100644 --- a/HISTORY +++ b/HISTORY @@ -1,5 +1,5 @@ -Video Disk Recorder OSM Revision History ----------------------------------------- +Video Disk Recorder Revision History +------------------------------------ 2000-02-19: Version 0.01 (Initial revision). @@ -18,3 +18,17 @@ Video Disk Recorder OSM Revision History 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. + +2000-04-24: Version 0.04 + +- Changed name from 'osm' to 'vdr' to avoid mixups with the 'oms' program that + appears to be in use with DVD replay. +- Implemented a channel display in the top menu line. +- Implemented replay progress display (press "Ok" when replaying to bring it up). +- Implemented direct channel selecting by pressing the numeric keys. +- Added several 'const' keywords to please stricter compilers. +- The repeat function for the remote control no longer adapts dynamically + to the timing of the RCU (this sometimes caused the repeat function to + kick in too early). +- Channel selection is now blocked when recording or replaying. +- Improved process handling. diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..d7acfb6d9 --- /dev/null +++ b/INSTALL @@ -0,0 +1,96 @@ +Installation of the Video Disk Recorder +--------------------------------------- + +Compiling and running the program: +---------------------------------- + +Make sure the files from this package are located in a +directory that is "parallel" to the DVB directory of the +driver source for the Siemens DVB-S PCI card (refer to +http://linuxtv.org/dvb/siemens_dvb.html for more information +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/VDR. + +This program requires the card driver version 0.04 or higher +to work properly. + +After extracting the package, change into the VDR directory +and type 'make'. This should produce an executable file +named 'vdr', which can be run after the DVB driver has been +installed. + +There are two macros you can use to customize the 'vdr' program +at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call +will use the PC's keyboard as input device instead of the "Remote +Control Unit" (see http://www.cadsoft.de/people/kls/vdr/remote.htm). +Adding "DEBUG_OSD=1" will use the PC screen (or current window) +to display texts instead of the DVB card's on-screen display +interface. These modes are useful when testing new menus if you +only have a remote connection to the VDR (which, in my case, is +located in the living room and has neither a monitor nor a keyboard). + +The video data directory: +------------------------- + +All recordings are written into directories below "/video". Please +make sure this directory exists, and that the user who runs the 'vdr' +program has read and write access to that directory. +If you prefer a different location for your video files, you can change +the value of 'BaseDir' in recording.c. + +Note that the file system need not be 64-bit proof, since the 'vdr' +program splits video files into chunks of about 1GB. You should use +a disk with several gigabytes of free space. One GB can store roughly +half an hour of video data. + +Configuration files: +-------------------- + +There are three configuration files that hold information about +channels, remote control keys and timers. These files are currrently +assumed to be located in the directory from which the 'vdr' program +was started (this will become configurable later). The configuration +files can be edited with any text editor, or will be written by the +'vdr' program if any changes are made inside the on-screen menus. +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. + +Learning the remote control keys: +--------------------------------- + +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 'vdr' to get into learning mode. + diff --git a/MANUAL b/MANUAL index 9e5036c10..36a62987a 100644 --- a/MANUAL +++ b/MANUAL @@ -1,16 +1,55 @@ Video Disk Recorder User's Manual --------------------------------- +* Navigating through the On Screen Menus + + The "Main" menu can be called up with the "Menu" key of your remote + control unit. The "Up" and "Down" keys are used to select a specific + item. The "Left" and "Right" keys can be used to change options, and + the numeric keys allow direct input of numeric data. The "Ok" key + confirms any changes (or switches to a channel in the "Channels" menu). + The "Back" key goes back one level in the menu structure, discarding + any changes that might have been made in the current menu. + + In the "Timers" menu, the current timer can be enabled or disabled with + the "Right" or "Left" key, respectively (enabled timers are marked with ">"). + "Ok" here opens the "Edit timer" menu. + + Textual options, like channel names or recording file names, can be edited + by pressing the "Right" button (which puts brackets around the current + character as in "[R]TL"), selecting the desired character position with + "Left" and "Right", and changing the character with the "Up" and "Down" + keys. "Ok" then confirms the changes. + + The "Red", "Green", "Yellow" and "Blue" buttons have special meanings + in the various menus and are listed at the bottom of the on-screen-display. + + At any point in the menu system, pressing the "Menu" key again will + immediately leave the menu system. + * 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. + There are three ways to select a channel: + + 1. With no On Screen Menu displayed press the "Up" or "Down" key to switch + to the next higher or lower channel. + 2. Press the "Menu" button to bring up the On Screen Menu, select "Channels" + and browse through the list with the "Up" and "Down" key; to switch to the + selected channel press "Ok". + 2. Directly type in the channel number with the numeric keys ('0'..'9'); + if no key is pressed for about half a second, the digits collected so + far will define the channel number. + + After switching to a different channel the channel number and name, as well + as the current time are displayed at the top of the screen. This line + automatically goes away after about two seconds, or if any key is pressed. + To bring up the channel display without switching channels you can press + the "Ok" button. * Instant Recording You can start recording the current channel by pressing the "Record" - button. This will create a timer event named "instant" that start + button. This will create a timer event named "instant" that starts 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. @@ -23,6 +62,8 @@ Video Disk Recorder User's Manual * Replay Control + The following keys have the listed meaning in Replay mode: + - "Begin" Positions to beginning of the recording and starts playback from there. - "Pause" Halts playback at the current frame. Press again to continue @@ -32,6 +73,10 @@ Video Disk Recorder User's Manual - "Search" Runs playback forward or backward at a higher speed. Press again to resume normal speed. - "Skip" Skips about 60 seconds forward or backward. + - "Ok" Brings up the replay progress display, which shows the date, + time and title of the recording, a progress bar and the + current and total time of the recording. + Press "Ok" again to turn off the progress display. * Programming the Timer diff --git a/Makefile b/Makefile index b5153cfc8..0ed17ca76 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ # # Makefile for the On Screen Menu of the Video Disk Recorder # -# See the main source file 'osm.c' for copyright information and +# See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.2 2000/03/05 13:51:57 kls Exp $ +# $Id: Makefile 1.3 2000/04/24 09:44:10 kls Exp $ -OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o tools.o osm.o +OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o tools.o vdr.o ifdef DEBUG_REMOTE DEFINES += -DDEBUG_REMOTE @@ -19,20 +19,20 @@ endif %.o: %.c g++ -g -O2 -Wall -c $(DEFINES) $< -all: osm +all: vdr config.o : config.c config.h dvbapi.h interface.h tools.h dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h -osm.o : osm.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h +vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h remote.o : remote.c remote.h tools.h tools.o : tools.c tools.h -osm: $(OBJS) - g++ -g -O2 $(OBJS) -lncurses -o osm +vdr: $(OBJS) + g++ -g -O2 $(OBJS) -lncurses -o vdr clean: - -rm $(OBJS) osm + -rm $(OBJS) vdr diff --git a/README b/README index e2b27a4ff..cfc10a765 100644 --- a/README +++ b/README @@ -7,6 +7,12 @@ of the LinuxTV project (http://linuxtv.org). For details about the "Video Disk Recorder" project please refer to http://www.cadsoft.de/people/kls/vdr. +There is also a remote control unit described on those +Web pages, which can be used within this program. + +Please see the INSTALL file for details on how to install +this program on your computer. + The author can be contacted at kls@cadsoft.de. Yet another "set-top-box"? @@ -25,112 +31,6 @@ of commercial set-top-boxes usually are a lot more fancy than the ones in this system, but here we have the full source code and can modify the menus in whatever way desired. -Compiling and running the program: ----------------------------------- - -Make sure the files from this package are located in a -directory that is "parallel" to the DVB directory of the -driver source for the Siemens DVB-S PCI card (refer to -http://linuxtv.org/dvb/siemens_dvb.html for more information -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. - -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 are two macros you can use to customize the 'osm' program -at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call -will use the PC's keyboard as input device instead of the "Remote -Control Unit" (see http://www.cadsoft.de/people/kls/vdr/remote.htm). -Adding "DEBUG_OSD=1" will use the PC screen (or current window) -to display texts instead of the DVB card's on-screen display -interface. These modes are useful when testing new menus if you -only have a remote connection to the VDR (which, in my case, is -located in the living room and has neither a monitor nor a keyboard). - -Configuration files: --------------------- - -There are three configuration files that hold information about -channels, remote control keys and timers. These files are currrently -assumed to be located in the directory from which the 'osm' program -was started (this will become configurable later). The configuration -files can be edited with any text editor, or will be written by the -'osm' program if any changes are made inside the on-screen menus. -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. - -Learning the remote control keys: ---------------------------------- - -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: ---------------------------------------- - -The "Main" menu can be called up with the "Menu" key of your remote -control unit. The "Up" and "Down" keys are used to select a specific -item. The "Left" and "Right" keys can be used to change options, and -the numeric keys allow direct input of numeric data. The "Ok" key -confirms any changes (or switches to a channel in the "Channels" menu). -The "Back" key goes back one level in the menu structure, discarding -any changes that might have been made in the current menu. - -In the "Timers" menu, the current timer can be enabled or disabled with -the "Right" or "Left" key, respectively (enabled timers are marked with ">"). -"Ok" here opens the "Edit timer" menu. - -Textual options, like channel names or recording file names, can be edited -by pressing the "Right" button (which puts brackets around the current -character as in "[R]TL"), selecting the desired character position with -"Left" and "Right", and changing the character with the "Up" and "Down" -keys. "Ok" then confirms the changes. - -The "Red", "Green", "Yellow" and "Blue" buttons have special meanings -in the various menus and are listed at the bottom of the on-screen-display. - -At any point in the menu system, pressing the "Menu" key again will -immediately leave the menu system. - What do you think? ------------------ diff --git a/TODO b/TODO index 8154c01d8..8f5d2f3d9 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ TODO list for the Video Disk Recorder project --------------------------------------------- -* 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,7 +9,5 @@ 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. diff --git a/config.c b/config.c index c29fea8b7..0a39cc503 100644 --- a/config.c +++ b/config.c @@ -1,10 +1,10 @@ /* * config.c: Configuration file handling * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.3 2000/04/15 12:48:00 kls Exp $ + * $Id: config.c 1.5 2000/04/24 09:44:15 kls Exp $ */ #include "config.h" @@ -206,7 +206,6 @@ bool cChannel::Switch(void) 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 (DvbApi.SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) return true; diff --git a/config.h b/config.h index 6184f5628..42af0f858 100644 --- a/config.h +++ b/config.h @@ -1,10 +1,10 @@ /* * config.h: Configuration file handling * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.3 2000/04/15 12:44:23 kls Exp $ + * $Id: config.h 1.4 2000/04/24 09:44:17 kls Exp $ */ #ifndef __CONFIG_H diff --git a/dvbapi.c b/dvbapi.c index ef2f80862..719437d4c 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -1,21 +1,19 @@ /* * dvbapi.c: Interface to the DVB driver * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.3 2000/04/15 14:45:04 kls Exp $ + * $Id: dvbapi.c 1.8 2000/04/24 15:30:35 kls Exp $ */ #include "dvbapi.h" #include #include -#include #include #include #include #include -#include #include #include "interface.h" #include "tools.h" @@ -59,7 +57,6 @@ #define RESUMEFILESUFFIX "/resume.vdr" #define RECORDFILESUFFIX "/%03d.vdr" #define RECORDFILESUFFIXLEN 20 // some additional bytes for safety... -#define MAXPROCESSTIMEOUT 3 // seconds // The number of frames to back up when resuming an interrupted replay session: #define RESUMEBACKUP (10 * FRAMESPERSEC) @@ -85,7 +82,7 @@ class cIndexFile { int Last(void) { return last; } int GetResume(void) { return resume; } bool StoreResume(int Index); - static char *Str(int Index); + static char *Str(int Index, bool WithFrame = false); }; cIndexFile::cIndexFile(const char *FileName, bool Record) @@ -256,7 +253,7 @@ bool cIndexFile::StoreResume(int Index) return false; } -char *cIndexFile::Str(int Index) +char *cIndexFile::Str(int Index, bool WithFrame) { static char buffer[16]; int f = (Index % FRAMESPERSEC) + 1; @@ -264,7 +261,7 @@ char *cIndexFile::Str(int Index) int m = s / 60 % 60; int h = s / 3600; s %= 60; - snprintf(buffer, sizeof(buffer), "%d:%02d:%02d.%02d", h, m, s, f); + snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f); return buffer; } @@ -554,7 +551,7 @@ class cRecordBuffer : public cFileBuffer { public: cRecordBuffer(int *InFile, const char *FileName); virtual ~cRecordBuffer(); - int WriteWithTimeout(void); + int WriteWithTimeout(bool EndIfEmpty = false); }; cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) @@ -720,13 +717,13 @@ int cRecordBuffer::Write(int Max) return 0; } -int cRecordBuffer::WriteWithTimeout(void) +int cRecordBuffer::WriteWithTimeout(bool EndIfEmpty) { int w, written = 0; int t0 = time_ms(); while ((w = Write()) > 0 && time_ms() - t0 < MAXRECORDWRITETIME) written += w; - return w < 0 ? w : written; + return w < 0 ? w : (written == 0 && EndIfEmpty ? -1 : written); } // --- cReplayBuffer --------------------------------------------------------- @@ -752,6 +749,7 @@ class cReplayBuffer : public cFileBuffer { int Resume(void); bool Save(void); void SkipSeconds(int Seconds); + void GetIndex(int &Current, int &Total); }; cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName) @@ -840,7 +838,7 @@ void cReplayBuffer::SkipSeconds(int Seconds) } Index += Seconds * FRAMESPERSEC; if (Index < 0) - Index = 1; + Index = 1; // not '0', to allow GetNextIFrame() below to work! uchar FileNumber; int FileOffset; if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0) @@ -849,6 +847,16 @@ void cReplayBuffer::SkipSeconds(int Seconds) } } +void cReplayBuffer::GetIndex(int &Current, int &Total) +{ + if (index) { + Current = index->Get(fileNumber, fileOffset); + Total = index->Last(); + } + else + Current = Total = -1; +} + void cReplayBuffer::SkipAudioBlocks(void) { int Length; @@ -1001,8 +1009,10 @@ cDvbApi::cDvbApi(void) memset(&colorPairs, 0, sizeof(colorPairs)); start_color(); leaveok(stdscr, TRUE); - window = stdscr; + window = NULL; #endif + lastProgress = -1; + replayTitle = NULL; } cDvbApi::~cDvbApi() @@ -1018,6 +1028,7 @@ cDvbApi::~cDvbApi() endwin(); #endif } + delete replayTitle; } #ifdef DEBUG_OSD @@ -1056,17 +1067,21 @@ void cDvbApi::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co void cDvbApi::Open(int w, int h) { + int d = (h < 0) ? MenuLines + h : 0; + h = abs(h); cols = w; rows = h; #ifdef DEBUG_OSD - //XXX size... + window = subwin(stdscr, h, w, d, 0); + syncok(window, TRUE); #define B2C(b) (((b) * 1000) / 255) #define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b)) #else w *= charWidth; h *= lineHeight; - int x = (720 - w) / 2; //TODO PAL vs. NTSC??? - int y = (576 - h) / 2; + d *= lineHeight; + int x = (720 - MenuColumns * charWidth) / 2; //TODO PAL vs. NTSC??? + int y = (576 - MenuLines * lineHeight) / 2 + d; Cmd(OSD_Open, 4, x, y, x + w - 1, y + h - 1); #define SETCOLOR(n, r, g, b, o) Cmd(OSD_SetColor, n, r, g, b, o) #endif @@ -1079,6 +1094,8 @@ void cDvbApi::Open(int w, int h) SETCOLOR(clrCyan, 0x00, 0xFC, 0xFC, 255); SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255); SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255); + + lastProgress = -1; } void cDvbApi::Close(void) @@ -1086,6 +1103,7 @@ void cDvbApi::Close(void) #ifndef DEBUG_OSD Cmd(OSD_Close); #endif + lastProgress = -1; } void cDvbApi::Clear(void) @@ -1108,6 +1126,7 @@ void cDvbApi::Fill(int x, int y, int w, int h, eDvbColor color) wmove(window, y + r, x); // ncurses wants 'y' before 'x'! whline(window, ' ', w); } + wsyncup(window); // shouldn't be necessary because of 'syncok()', but w/o it doesn't work #else Cmd(OSD_FillBlock, color, x * charWidth, y * lineHeight, (x + w) * charWidth - 1, (y + h) * lineHeight - 1); #endif @@ -1131,6 +1150,52 @@ void cDvbApi::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor col #endif } +bool cDvbApi::ShowProgress(bool Initial) +{ + int Current, Total; + + if (GetIndex(&Current, &Total)) { + if (Initial) { + if (replayTitle) + Text(0, 0, replayTitle); + Text(-7, 2, cIndexFile::Str(Total)); + } +#ifdef DEBUG_OSD + int p = cols * Current / Total; + Fill(0, 1, p, 1, clrGreen); + Fill(p, 1, cols - p, 1, clrWhite); +#else + int w = cols * charWidth; + int p = w * Current / Total; + if (p != lastProgress) { + int y1 = 1 * lineHeight; + int y2 = 2 * lineHeight - 1; + int x1, x2; + eDvbColor color; + if (lastProgress < p) { + x1 = lastProgress + 1; + x2 = p; + if (p >= w) + p = w - 1; + color = clrGreen; + } + else { + x1 = p + 1; + x2 = lastProgress; + color = clrWhite; + } + if (lastProgress < 0) + Cmd(OSD_FillBlock, clrWhite, 0, y1, w - 1, y2); + Cmd(OSD_FillBlock, color, x1, y1, x2, y2); + lastProgress = p; + } +#endif + Text(0, 2, cIndexFile::Str(Current)); + return true; + } + return false; +} + bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr) { if (videoDev >= 0) { @@ -1160,35 +1225,17 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr return false; } -void cDvbApi::KillProcess(pid_t pid) -{ - pid_t Pid2Wait4 = pid; - for (time_t t0 = time(NULL); time(NULL) - t0 < MAXPROCESSTIMEOUT; ) { - int status; - pid_t pid = waitpid(Pid2Wait4, &status, WNOHANG); - if (pid < 0) { - if (errno != ECHILD) - LOG_ERROR; - return; - } - if (pid == Pid2Wait4) - return; - } - esyslog(LOG_ERR, "ERROR: process %d won't end (waited %d seconds) - terminating it...", Pid2Wait4, MAXPROCESSTIMEOUT); - if (kill(Pid2Wait4, SIGTERM) < 0) { - esyslog(LOG_ERR, "ERROR: process %d won't terminate (%s) - killing it...", Pid2Wait4, strerror(errno)); - if (kill(Pid2Wait4, SIGKILL) < 0) - esyslog(LOG_ERR, "ERROR: process %d won't die (%s) - giving up", Pid2Wait4, strerror(errno)); - } -} - bool cDvbApi::Recording(void) { + if (pidRecord && !CheckProcess(pidRecord)) + pidRecord = 0; return pidRecord; } bool cDvbApi::Replaying(void) { + if (pidReplay && !CheckProcess(pidReplay)) + pidReplay = 0; return pidReplay; } @@ -1239,6 +1286,7 @@ bool cDvbApi::StartRecord(const char *FileName) dsyslog(LOG_INFO, "start recording process (pid=%d)", getpid()); isMainProcess = false; + bool DataStreamBroken = false; int fromMain = toRecordPipe[0]; int toMain = fromRecordPipe[1]; cRecordBuffer *Buffer = new cRecordBuffer(&videoDev, FileName); @@ -1251,21 +1299,26 @@ bool cDvbApi::StartRecord(const char *FileName) struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; + bool ForceEnd = false; if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) { if (FD_ISSET(videoDev, &set)) { if (Buffer->Read() < 0) break; + DataStreamBroken = false; } if (FD_ISSET(fromMain, &set)) { switch (readchar(fromMain)) { - case dvbStop: Buffer->Stop(); break; - break; + case dvbStop: Buffer->Stop(); + ForceEnd = DataStreamBroken; + break; } } } - else + else { + DataStreamBroken = true; esyslog(LOG_ERR, "ERROR: video data stream broken"); - if (Buffer->WriteWithTimeout() < 0) + } + if (Buffer->WriteWithTimeout(ForceEnd) < 0) break; } delete Buffer; @@ -1309,7 +1362,7 @@ void cDvbApi::SetReplayMode(int Mode) } } -bool cDvbApi::StartReplay(const char *FileName) +bool cDvbApi::StartReplay(const char *FileName, const char *Title) { if (Recording()) { esyslog(LOG_ERR, "ERROR: StartReplay() called while recording - ignored!"); @@ -1318,6 +1371,13 @@ bool cDvbApi::StartReplay(const char *FileName) StopReplay(); if (videoDev >= 0) { + lastProgress = -1; + delete replayTitle; + if (Title) { + if ((replayTitle = strdup(Title)) == NULL) + esyslog(LOG_ERR, "ERROR: StartReplay: can't copy title '%s'", Title); + } + // Check FileName: if (!FileName) { @@ -1361,7 +1421,7 @@ bool cDvbApi::StartReplay(const char *FileName) bool FastRewind = false; int ResumeIndex = Buffer->Resume(); if (ResumeIndex >= 0) - isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, cIndexFile::Str(ResumeIndex)); + isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, cIndexFile::Str(ResumeIndex, true)); for (;;) { if (Buffer->Read() < 0) break; @@ -1405,6 +1465,12 @@ bool cDvbApi::StartReplay(const char *FileName) Buffer->SkipSeconds(Seconds); } } + case dvbGetIndex: { + int Current, Total; + Buffer->GetIndex(Current, Total); + writeint(toMain, Current); + writeint(toMain, Total); + } break; } } @@ -1470,3 +1536,20 @@ void cDvbApi::Skip(int Seconds) } } +bool cDvbApi::GetIndex(int *Current, int *Total) +{ + if (pidReplay) { + int total; + purge(fromReplay); + writechar(toReplay, dvbGetIndex); + if (readint(fromReplay, *Current) && readint(fromReplay, total)) { + if (Total) + *Total = total; + } + else + *Current = -1; + return *Current >= 0; + } + return false; +} + diff --git a/dvbapi.h b/dvbapi.h index 3c447cf1f..91e554e98 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -1,10 +1,10 @@ /* * dvbapi.h: Interface to the DVB driver * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.3 2000/04/15 13:36:10 kls Exp $ + * $Id: dvbapi.h 1.8 2000/04/24 15:31:07 kls Exp $ */ #ifndef __DVBAPI_H @@ -21,6 +21,9 @@ typedef unsigned char __u8; #include #include "../DVB/driver/dvb.h" +#define MenuLines 15 +#define MenuColumns 40 + enum eDvbColor { clrBackground, #ifndef DEBUG_OSD clrOBSOLETE, //FIXME apparently color '1' can't be used as FgColor with e.g. clrRed as BgColor??? @@ -66,6 +69,14 @@ class cDvbApi { void ClrEol(int x, int y, eDvbColor color = clrBackground); void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground); + // Progress Display facilities + +private: + int lastProgress; + char *replayTitle; +public: + bool ShowProgress(bool Initial = false); + // Channel facilities bool SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr); @@ -78,13 +89,13 @@ class cDvbApi { dvbFastForward, dvbFastRewind, dvbSkip, + dvbGetIndex, }; 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. @@ -102,10 +113,11 @@ class cDvbApi { // returned. void StopRecord(void); // Stops the current recording session (if any). - bool StartReplay(const char *FileName); + bool StartReplay(const char *FileName, const char *Title = NULL); // 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. + // If provided Title will be used in the progress display. void StopReplay(void); // Stops the current replay session (if any). void PauseReplay(void); @@ -119,6 +131,7 @@ class cDvbApi { // 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. + bool GetIndex(int *Current, int *Total = NULL); }; #endif //__DVBAPI_H diff --git a/interface.c b/interface.c index a54651357..446f9c434 100644 --- a/interface.c +++ b/interface.c @@ -1,19 +1,16 @@ /* * interface.c: Abstract user interface layer * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.3 2000/04/15 17:38:11 kls Exp $ + * $Id: interface.c 1.6 2000/04/24 09:44:23 kls Exp $ */ #include "interface.h" #include #include "remote.h" -#define MenuLines 15 -#define MenuColumns 40 - #ifndef DEBUG_REMOTE cRcIo RcIo("/dev/ttyS1"); #endif @@ -26,6 +23,7 @@ cInterface::cInterface(void) { open = 0; cols[0] = 0; + keyFromWait = kNone; } void cInterface::Init(void) @@ -35,10 +33,10 @@ void cInterface::Init(void) #endif } -void cInterface::Open(void) +void cInterface::Open(int NumCols, int NumLines) { if (!open++) - DvbApi.Open(MenuColumns, MenuLines); + DvbApi.Open(NumCols, NumLines); } void cInterface::Close(void) @@ -49,35 +47,45 @@ void cInterface::Close(void) DvbApi.Close(); } -unsigned int cInterface::GetCh(void) +unsigned int cInterface::GetCh(bool Wait) { #ifdef DEBUG_REMOTE + timeout(Wait ? 1000 :10); int c = getch(); return (c > 0) ? c : 0; #else -//XXX #ifdef DEBUG_OSD -//XXX wrefresh(window);//XXX -//XXX #endif - unsigned int Command; - return RcIo.GetCommand(&Command) ? Command : 0; +#ifdef DEBUG_OSD + timeout(0); + getch(); // just to make 'ncurses' display the window: +#endif + if (Wait || RcIo.InputAvailable()) { + unsigned int Command; + return RcIo.GetCommand(&Command, NULL) ? Command : 0; + } + return 0; #endif } -eKeys cInterface::GetKey(void) +eKeys cInterface::GetKey(bool Wait) { - return Keys.Get(GetCh()); + eKeys Key = keyFromWait != kNone ? keyFromWait : Keys.Get(GetCh(Wait)); + keyFromWait = kNone; + return Key; } -eKeys cInterface::Wait(int Seconds) +eKeys cInterface::Wait(int Seconds, bool KeepChar) { int t0 = time_ms(); + eKeys Key = kNone; while (time_ms() - t0 < Seconds * 1000) { - eKeys Key = GetKey(); + Key = GetKey(); if (Key != kNone) - return Key; + break; } - return kNone; + if (KeepChar) + keyFromWait = Key; + return Key; } void cInterface::Clear(void) @@ -312,8 +320,20 @@ void cInterface::LearnKeys(void) void cInterface::DisplayChannel(int Number, const char *Name) { -//TODO #ifndef DEBUG_REMOTE RcIo.Number(Number); #endif + if (Name) { + Open(MenuColumns, 1); + char buffer[MenuColumns + 1]; + snprintf(buffer, sizeof(buffer), "%d %s", Number, Name ? Name : ""); + Write(0, 0, buffer); + time_t t = time(NULL); + struct tm *now = localtime(&t); + snprintf(buffer, sizeof(buffer), "%02d:%02d", now->tm_hour, now->tm_min); + Write(-5, 0, buffer); + if (Wait(2, true) == kOk) + GetKey(); + Close(); + } } diff --git a/interface.h b/interface.h index 1e5329d5d..eb4e76bcd 100644 --- a/interface.h +++ b/interface.h @@ -1,10 +1,10 @@ /* * interface.h: Abstract user interface layer * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.3 2000/03/19 14:03:28 kls Exp $ + * $Id: interface.h 1.7 2000/04/24 09:44:25 kls Exp $ */ #ifndef __INTERFACE_H @@ -19,16 +19,17 @@ class cInterface { private: int open; int cols[MaxCols]; - unsigned int GetCh(void); + eKeys keyFromWait; + unsigned int GetCh(bool Wait = true); void QueryKeys(void); void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor); - eKeys Wait(int Seconds = 1); + eKeys Wait(int Seconds = 1, bool KeepChar = false); public: cInterface(void); void Init(void); - void Open(void); + void Open(int NumCols = MenuColumns, int NumLines = MenuLines); void Close(void); - eKeys GetKey(void); + eKeys GetKey(bool Wait = true); void Clear(void); void ClearEol(int x, int y, eDvbColor Color = clrBackground); void SetCols(int *c); @@ -41,7 +42,7 @@ class cInterface { bool Confirm(const char *s); void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); void LearnKeys(void); - void DisplayChannel(int Number, const char *Name); + void DisplayChannel(int Number, const char *Name = NULL); }; extern cInterface Interface; diff --git a/menu.c b/menu.c index 92c0bd3e1..2a4cfa9fc 100644 --- a/menu.c +++ b/menu.c @@ -1,10 +1,10 @@ /* * menu.c: The actual menu implementations * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.3 2000/04/15 15:07:36 kls Exp $ + * $Id: menu.c 1.8 2000/04/24 15:32:11 kls Exp $ */ #include "menu.h" @@ -428,7 +428,7 @@ void cMenuEditStrItem::Set(void) char buf[1000]; if (pos >= 0) { strncpy(buf, value, pos); - char *s = value[pos] != ' ' ? value + pos + 1 : ""; + const char *s = value[pos] != ' ' ? value + pos + 1 : ""; snprintf(buf + pos, sizeof(buf) - pos - 2, "[%c]%s", *(value + pos), s); SetValue(buf); } @@ -915,16 +915,7 @@ cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording) void cMenuRecordingItem::Set(void) { - char *buffer = NULL; - struct tm *t = localtime(&recording->start); - asprintf(&buffer, "%02d.%02d.%04d\t%02d:%02d\t%s", - t->tm_mday, - t->tm_mon + 1, - t->tm_year + 1900, - t->tm_hour, - t->tm_min, - recording->name); - SetText(buffer, false); + SetText(recording->Title('\t')); } // --- cMenuRecordings ------------------------------------------------------- @@ -957,7 +948,7 @@ eOSState cMenuRecordings::Play(void) cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); if (ri) { //XXX what if this recording's file is currently in use??? - if (ri->recording->Play()) + if (DvbApi.StartReplay(ri->recording->FileName(), ri->recording->Title())) return osEnd; } return osContinue; @@ -1022,3 +1013,36 @@ eOSState cMenuMain::ProcessKey(eKeys Key) return state; } +// --- cReplayDisplay -------------------------------------------------------- + +cReplayDisplay::cReplayDisplay(void) +{ + Interface.Open(MenuColumns, -3); + shown = DvbApi.ShowProgress(true); +} + +cReplayDisplay::~cReplayDisplay() +{ + Interface.Close(); +} + +eKeys cReplayDisplay::ProcessKey(eKeys Key) +{ + if (!DvbApi.Replaying()) + return kOk; // will turn off replay display + shown = DvbApi.ShowProgress(!shown); + switch (Key) { + case kBegin: + case kPause: + case kStop: + case kSearchBack: + case kSearchForward: + case kSkipBack: + case kSkipForward: break; // will be done in main loop + case kMenu: break; // allow direct switching to menu + case kOk: break; // switches off replay display + default: Key = kNone; // ignore anything not explicitly known here + } + return Key; +} + diff --git a/menu.h b/menu.h index 813beecdd..f66579962 100644 --- a/menu.h +++ b/menu.h @@ -1,10 +1,10 @@ /* * menu.h: The actual menu implementations * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.2 2000/03/05 10:57:27 kls Exp $ + * $Id: menu.h 1.5 2000/04/24 15:31:53 kls Exp $ */ #ifndef _MENU_H @@ -18,4 +18,13 @@ class cMenuMain : public cOsdMenu { virtual eOSState ProcessKey(eKeys Key); }; +class cReplayDisplay { +private: + bool shown; +public: + cReplayDisplay(void); + ~cReplayDisplay(); + eKeys ProcessKey(eKeys Key); + }; + #endif //_MENU_H diff --git a/osd.c b/osd.c index 673d075c0..ee9ba287d 100644 --- a/osd.c +++ b/osd.c @@ -1,10 +1,10 @@ /* * osd.c: Abstract On Screen Display layer * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.2 2000/02/27 17:23:07 kls Exp $ + * $Id: osd.c 1.4 2000/04/24 09:44:31 kls Exp $ */ #include "osd.h" @@ -35,7 +35,7 @@ cOsdItem::~cOsdItem() delete text; } -void cOsdItem::SetText(char *Text, bool Copy) +void cOsdItem::SetText(const char *Text, bool Copy) { delete text; text = Copy ? strdup(Text) : Text; diff --git a/osd.h b/osd.h index 5ec13349f..99821b876 100644 --- a/osd.h +++ b/osd.h @@ -1,10 +1,10 @@ /* * osd.h: Abstract On Screen Display layer * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.2 2000/03/05 11:33:11 kls Exp $ + * $Id: osd.h 1.4 2000/04/24 09:44:32 kls Exp $ */ #ifndef __OSD_H @@ -28,7 +28,7 @@ enum eOSState { osUnknown, class cOsdItem : public cListObject { private: - char *text; + const char *text; int offset; eOSState state; protected: @@ -37,8 +37,8 @@ class cOsdItem : public cListObject { cOsdItem(eOSState State = osUnknown); cOsdItem(char *Text, eOSState State = osUnknown); virtual ~cOsdItem(); - void SetText(char *Text, bool Copy = true); - char *Text(void) { return text; } + void SetText(const char *Text, bool Copy = true); + const char *Text(void) { return text; } void Display(int Offset = -1, bool Current = false); virtual void Set(void) {} virtual eOSState ProcessKey(eKeys Key); diff --git a/osm.c b/osm.c deleted file mode 100644 index 70305ce88..000000000 --- a/osm.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * osm.c: On Screen Menu for the Video Disk Recorder - * - * Copyright (C) 2000 Klaus Schmidinger - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * The author can be reached at kls@cadsoft.de - * - * The project's page is at http://www.cadsoft.de/people/kls/vdr - * - * $Id: osm.c 1.3 2000/04/15 14:04:21 kls Exp $ - */ - -#include -#include "config.h" -#include "interface.h" -#include "menu.h" -#include "recording.h" -#include "tools.h" - -#ifdef DEBUG_REMOTE -#define KEYS_CONF "keys-pc.conf" -#else -#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); - isyslog(LOG_INFO, "started"); - - Channels.Load("channels.conf"); - Timers.Load("timers.conf"); - if (!Keys.Load(KEYS_CONF)) - Interface.LearnKeys(); - Interface.Init(); - - 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; - - while (!Interrupted) { - AssertFreeDiskSpace(); - if (!Recording && !Timer && (Timer = cTimer::GetMatch()) != NULL) { - DELETENULL(Menu); - // make sure the timer won't be deleted: - Timer->SetRecording(true); - // switch to channel: - cChannel::SwitchTo(Timer->channel - 1); - // start recording: - Recording = new cRecording(Timer); - if (!Recording->Record()) - DELETENULL(Recording); - } - if (Timer && !Timer->Matches()) { - // stop recording: - if (Recording) { - Recording->Stop(); - DELETENULL(Recording); - } - // release timer: - Timer->SetRecording(false); - // clear single event timer: - if (Timer->IsSingleEvent()) { - DELETENULL(Menu); // must make sure no menu uses it - isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1); - Timers.Del(Timer); - Timers.Save(); - } - Timer = NULL; - } - eKeys key = Interface.GetKey(); - if (Menu) { - switch (Menu->ProcessKey(key)) { - default: if (key != kMenu) - break; - case osBack: - case osEnd: DELETENULL(Menu); - break; - } - } - else { - switch (key) { - // Record/Replay Control: - case kBegin: DvbApi.Skip(-INT_MAX); break; - case kRecord: if (!DvbApi.Recording()) { - cTimer *timer = new cTimer(true); - Timers.Add(timer); - Timers.Save(); - } - else - Interface.Error("Already recording!"); - break; - case kPause: DvbApi.PauseReplay(); break; - case kStop: DvbApi.StopReplay(); break; - case kSearchBack: DvbApi.FastRewind(); break; - case kSearchForward: DvbApi.FastForward(); break; - case kSkipBack: DvbApi.Skip(-60); break; - case kSkipForward: DvbApi.Skip(60); break; - // Menu Control: - case kMenu: Menu = new cMenuMain; - Menu->Display(); - break; - case kUp: - case kDown: { - int n = CurrentChannel + (key == kUp ? 1 : -1); - cChannel *channel = Channels.Get(n); - if (channel) - channel->Switch(); - } - break; - default: break; - } - } - } - isyslog(LOG_INFO, "caught signal %d", Interrupted); - DvbApi.StopRecord(); - DvbApi.StopReplay(); - //TODO kill any remaining sub-processes! - isyslog(LOG_INFO, "exiting", Interrupted); - closelog(); - return 0; -} diff --git a/recording.c b/recording.c index 15c716300..46fe53f44 100644 --- a/recording.c +++ b/recording.c @@ -1,10 +1,10 @@ /* * recording.h: Recording file handling * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.2 2000/04/15 13:29:02 kls Exp $ + * $Id: recording.c 1.6 2000/04/24 09:45:13 kls Exp $ */ #define _GNU_SOURCE @@ -104,6 +104,7 @@ void AssertFreeDiskSpace(void) cRecording::cRecording(const char *Name, time_t Start, int Priority, int LifeTime) { + titleBuffer = NULL; fileName = NULL; name = strdup(Name); start = Start; @@ -113,6 +114,7 @@ cRecording::cRecording(const char *Name, time_t Start, int Priority, int LifeTim cRecording::cRecording(cTimer *Timer) { + titleBuffer = NULL; fileName = NULL; name = strdup(Timer->file); start = Timer->StartTime(); @@ -122,6 +124,7 @@ cRecording::cRecording(cTimer *Timer) cRecording::cRecording(const char *FileName) { + titleBuffer = NULL; fileName = strdup(FileName); FileName += strlen(BaseDir) + 1; char *p = strrchr(FileName, '/'); @@ -144,6 +147,7 @@ cRecording::cRecording(const char *FileName) cRecording::~cRecording() { + delete titleBuffer; delete fileName; delete name; } @@ -157,6 +161,23 @@ const char *cRecording::FileName(void) return fileName; } +const char *cRecording::Title(char Delimiter) +{ + delete titleBuffer; + titleBuffer = NULL; + struct tm *t = localtime(&start); + asprintf(&titleBuffer, "%02d.%02d.%04d%c%02d:%02d%c%s", + t->tm_mday, + t->tm_mon + 1, + t->tm_year + 1900, + Delimiter, + t->tm_hour, + t->tm_min, + Delimiter, + name); + return titleBuffer; +} + bool cRecording::Delete(void) { bool result = true; @@ -180,21 +201,6 @@ bool cRecording::Remove(void) return RemoveFileOrDir(FileName()); } -bool cRecording::Record(void) -{ - return DvbApi.StartRecord(FileName()); -} - -bool cRecording::Play(void) -{ - return DvbApi.StartReplay(FileName()); -} - -void cRecording::Stop(void) -{ - DvbApi.StopRecord(); -} - // --- cRecordings ----------------------------------------------------------- bool cRecordings::Load(bool Deleted) diff --git a/recording.h b/recording.h index 5a5e8de48..eeea5609f 100644 --- a/recording.h +++ b/recording.h @@ -1,10 +1,10 @@ /* * recording.h: Recording file handling * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.2 2000/04/14 15:12:42 kls Exp $ + * $Id: recording.h 1.6 2000/04/24 09:45:49 kls Exp $ */ #ifndef __RECORDING_H @@ -12,15 +12,17 @@ #include #include "config.h" -#include "dvbapi.h" #include "tools.h" void AssertFreeDiskSpace(void); class cRecording : public cListObject { -public: - char *name; + friend class cRecordings; +private: + char *titleBuffer; char *fileName; + char *name; +public: time_t start; int priority; int lifetime; @@ -29,18 +31,13 @@ class cRecording : public cListObject { cRecording(const char *FileName); ~cRecording(); const char *FileName(void); + const char *Title(char Delimiter = ' '); bool Delete(void); - // Changes the file name so that it will no longer be visible in the OSM + // Changes the file name so that it will no longer be visible in the "Recordings" menu // Returns false in case of error bool Remove(void); // Actually removes the file from the disk // Returns false in case of error - bool Record(void); - // Starts recording of the file - bool Play(void); - // Starts playback of the file - void Stop(void); - // Stops recording or playback of the file }; class cRecordings : public cList { diff --git a/remote.c b/remote.c index bf5b41f84..2ba5b22b4 100644 --- a/remote.c +++ b/remote.c @@ -1,10 +1,10 @@ /* * remote.c: Interface to the Remote Control Unit * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.c 1.2 2000/04/15 16:00:51 kls Exp $ + * $Id: remote.c 1.6 2000/04/24 09:45:56 kls Exp $ */ #include "remote.h" @@ -17,6 +17,9 @@ #include #include "tools.h" +#define REPEATLIMIT 100 // ms +#define REPEATDELAY 250 // ms + cRcIo::cRcIo(char *DeviceName) { dp = 0; @@ -25,7 +28,6 @@ cRcIo::cRcIo(char *DeviceName) address = 0xFFFF; t = 0; firstTime = lastTime = 0; - minDelta = 0; lastCommand = 0; if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) { struct termios t; @@ -35,8 +37,11 @@ cRcIo::cRcIo(char *DeviceName) if (tcsetattr(f, TCSAFLUSH, &t) == 0) return; } + LOG_ERROR_STR(DeviceName); close(f); } + else + LOG_ERROR_STR(DeviceName); f = -1; } @@ -46,9 +51,8 @@ cRcIo::~cRcIo() close(f); } -int cRcIo::ReceiveByte(bool Wait) +bool cRcIo::InputAvailable(bool Wait) { - // Returns the byte if one was received within 1 second, -1 otherwise if (f >= 0) { fd_set set; struct timeval timeout; @@ -56,13 +60,19 @@ int cRcIo::ReceiveByte(bool Wait) timeout.tv_usec = Wait ? 0 : 10000; FD_ZERO(&set); FD_SET(f, &set); - if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) { - if (FD_ISSET(f, &set)) { - unsigned char b; - if (read(f, &b, 1) == 1) - return b; - } - } + if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) + return FD_ISSET(f, &set); + } + return false; +} + +int cRcIo::ReceiveByte(bool Wait) +{ + // Returns the byte if one was received within a timeout, -1 otherwise + if (InputAvailable(Wait)) { + unsigned char b; + if (read(f, &b, 1) == 1) + return b; } return -1; } @@ -112,7 +122,6 @@ bool cRcIo::SetCode(unsigned char Code, unsigned short Address) { code = Code; address = Address; - minDelta = 200; return SendCommand(code); } @@ -157,12 +166,10 @@ bool cRcIo::GetCommand(unsigned int *Command, unsigned short *Address) // let's have a timeout to avoid getting overrun by commands int now = time_ms(); int delta = now - lastTime; - if (delta < minDelta) - minDelta = delta; // dynamically adjust to the smallest delta lastTime = now; - if (delta < minDelta * 1.3) { // if commands come in rapidly... - if (now - firstTime < 250) - return false; // ...repeat function kicks in after 250ms + if (delta < REPEATLIMIT) { // if commands come in rapidly... + if (now - firstTime < REPEATDELAY) + return false; // ...repeat function kicks in after a short delay return true; } } @@ -209,12 +216,12 @@ bool cRcIo::Number(int n, bool Hex) bool cRcIo::String(char *s) { - char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP "; + const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP "; int n = 0; for (int i = 0; *s && i < 4; s++, i++) { n <<= 4; - for (char *c = chars; *c; c++) { + for (const char *c = chars; *c; c++) { if (*c == *s) { n |= c - chars; break; diff --git a/remote.h b/remote.h index 682792912..73e50eb78 100644 --- a/remote.h +++ b/remote.h @@ -1,10 +1,10 @@ /* * remote.h: Interface to the Remote Control Unit * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.1 2000/02/19 13:36:48 kls Exp $ + * $Id: remote.h 1.4 2000/04/24 09:46:00 kls Exp $ */ #ifndef __REMOTE_H @@ -19,7 +19,7 @@ class cRcIo { unsigned char dp, code, mode; unsigned short address; time_t t; - int firstTime, lastTime, minDelta; + int firstTime, lastTime; unsigned int lastCommand; bool SendCommand(unsigned char Cmd); int ReceiveByte(bool Wait = true); @@ -29,6 +29,7 @@ class cRcIo { enum { modeH = 'h', modeB = 'b', modeS = 's' }; cRcIo(char *DeviceName); ~cRcIo(); + bool InputAvailable(bool Wait = false); void Flush(int WaitSeconds = 0); bool SetCode(unsigned char Code, unsigned short Address); bool SetMode(unsigned char Mode); diff --git a/timers.conf b/timers.conf index 1996be4be..6fff8d88b 100644 --- a/timers.conf +++ b/timers.conf @@ -1,5 +1,5 @@ -1:15:MTWTF--:1828:1901:10:5:nano -1:3:M------:2110:2230:99:10:SevenDays +0:15:MTWTF--:1828:1901:10:5:nano +0: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 diff --git a/tools.c b/tools.c index e356e0fdb..eb0a14a4f 100644 --- a/tools.c +++ b/tools.c @@ -1,16 +1,17 @@ /* * tools.c: Various tools * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.3 2000/04/15 15:10:05 kls Exp $ + * $Id: tools.c 1.7 2000/04/24 15:01:35 kls Exp $ */ #define _GNU_SOURCE #include "tools.h" #include #include +#include #include #include #include @@ -21,6 +22,17 @@ int SysLogLevel = 3; +bool DataAvailable(int filedes) +{ + fd_set set; + FD_ZERO(&set); + FD_SET(filedes, &set); + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(filedes, &set); +} + void writechar(int filedes, char c) { write(filedes, &c, sizeof(c)); @@ -40,8 +52,13 @@ char readchar(int filedes) bool readint(int filedes, int &n) { - //XXX timeout!! - return read(filedes, &n, sizeof(n)); + return DataAvailable(filedes) && read(filedes, &n, sizeof(n)) == sizeof(n); +} + +void purge(int filedes) +{ + while (DataAvailable(filedes)) + readchar(filedes); } char *readline(FILE *f) @@ -135,6 +152,41 @@ bool RemoveFileOrDir(const char *FileName) return false; } +bool CheckProcess(pid_t pid) +{ + pid_t Pid2Check = pid; + int status; + pid = waitpid(Pid2Check, &status, WNOHANG); + if (pid < 0) { + if (errno != ECHILD) + LOG_ERROR; + return false; + } + return true; +} + +void KillProcess(pid_t pid, int Timeout) +{ + pid_t Pid2Wait4 = pid; + for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) { + int status; + pid_t pid = waitpid(Pid2Wait4, &status, WNOHANG); + if (pid < 0) { + if (errno != ECHILD) + LOG_ERROR; + return; + } + if (pid == Pid2Wait4) + return; + } + esyslog(LOG_ERR, "ERROR: process %d won't end (waited %d seconds) - terminating it...", Pid2Wait4, Timeout); + if (kill(Pid2Wait4, SIGTERM) < 0) { + esyslog(LOG_ERR, "ERROR: process %d won't terminate (%s) - killing it...", Pid2Wait4, strerror(errno)); + if (kill(Pid2Wait4, SIGKILL) < 0) + esyslog(LOG_ERR, "ERROR: process %d won't die (%s) - giving up", Pid2Wait4, strerror(errno)); + } +} + // --- cListObject ----------------------------------------------------------- cListObject::cListObject(void) diff --git a/tools.h b/tools.h index 48665a84f..57b2065db 100644 --- a/tools.h +++ b/tools.h @@ -1,17 +1,20 @@ /* * tools.h: Various tools * - * See the main source file 'osm.c' for copyright information and + * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.3 2000/04/15 15:09:47 kls Exp $ + * $Id: tools.h 1.7 2000/04/24 15:01:49 kls Exp $ */ #ifndef __TOOLS_H #define __TOOLS_H +#include #include #include +#include +#include extern int SysLogLevel; @@ -23,18 +26,23 @@ extern int SysLogLevel; #define LOG_ERROR_STR(s) esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno)); #define SECSINDAY 86400 +#define MAXPROCESSTIMEOUT 3 // seconds #define DELETENULL(p) (delete (p), p = NULL) +bool DataAvailable(int filedes); void writechar(int filedes, char c); void writeint(int filedes, int n); char readchar(int filedes); bool readint(int filedes, int &n); +void purge(int filedes); char *readline(FILE *f); int time_ms(void); void delay_ms(int ms); bool MakeDirs(const char *FileName, bool IsDirectory = false); bool RemoveFileOrDir(const char *FileName); +bool CheckProcess(pid_t pid); +void KillProcess(pid_t pid, int Timeout = MAXPROCESSTIMEOUT); class cListObject { private: diff --git a/vdr.c b/vdr.c new file mode 100644 index 000000000..cbc095049 --- /dev/null +++ b/vdr.c @@ -0,0 +1,189 @@ +/* + * vdr.c: Video Disk Recorder main program + * + * Copyright (C) 2000 Klaus Schmidinger + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * The author can be reached at kls@cadsoft.de + * + * The project's page is at http://www.cadsoft.de/people/kls/vdr + * + * $Id: vdr.c 1.12 2000/04/24 13:36:39 kls Exp $ + */ + +#include +#include "config.h" +#include "interface.h" +#include "menu.h" +#include "recording.h" +#include "tools.h" + +#ifdef DEBUG_REMOTE +#define KEYS_CONF "keys-pc.conf" +#else +#define KEYS_CONF "keys.conf" +#endif + +#define DIRECTCHANNELTIMEOUT 500 //ms + +static int Interrupted = 0; + +void SignalHandler(int signum) +{ + Interrupted = signum; +} + +int main(int argc, char *argv[]) +{ + openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); + isyslog(LOG_INFO, "started"); + + Channels.Load("channels.conf"); + Timers.Load("timers.conf"); + if (!Keys.Load(KEYS_CONF)) + Interface.LearnKeys(); + Interface.Init(); + + 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; + cReplayDisplay *ReplayDisplay = NULL; + cTimer *Timer = NULL; + int dcTime = 0, dcNumber = 0; + int LastChannel = -1; + + while (!Interrupted) { + // Channel display: + if (CurrentChannel != LastChannel) { + if (!Menu && !ReplayDisplay) { + cChannel *channel = Channels.Get(CurrentChannel); + if (channel) + Interface.DisplayChannel(CurrentChannel + 1, channel->name); + } + LastChannel = CurrentChannel; + } + // Direct Channel Select (action): + if (dcNumber) { + Interface.DisplayChannel(dcNumber); + if (time_ms() - dcTime > DIRECTCHANNELTIMEOUT) { + cChannel::SwitchTo(dcNumber - 1); + dcNumber = 0; + LastChannel = -1; // in case an invalid channel number was entered! + } + } + // Timer Processing: + else { + AssertFreeDiskSpace(); + if (!Timer && (Timer = cTimer::GetMatch()) != NULL) { + DELETENULL(Menu); + DELETENULL(ReplayDisplay); + // make sure the timer won't be deleted: + Timer->SetRecording(true); + // switch to channel: + cChannel::SwitchTo(Timer->channel - 1); + // start recording: + cRecording Recording(Timer); + DvbApi.StartRecord(Recording.FileName()); + } + if (Timer && !Timer->Matches()) { + // stop recording: + DvbApi.StopRecord(); + // release timer: + Timer->SetRecording(false); + // clear single event timer: + if (Timer->IsSingleEvent()) { + DELETENULL(Menu); // must make sure no menu uses it + isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1); + Timers.Del(Timer); + Timers.Save(); + } + Timer = NULL; + } + } + // User Input: + eKeys key = Interface.GetKey(!ReplayDisplay); + if (Menu) { + switch (Menu->ProcessKey(key)) { + default: if (key != kMenu) + break; + case osBack: + case osEnd: DELETENULL(Menu); + break; + } + } + else if (!ReplayDisplay || (key = ReplayDisplay->ProcessKey(key)) != kNone) { + switch (key) { + // Direct Channel Select (input): + case k0: case k1: case k2: case k3: case k4: case k5: case k6: case k7: case k8: case k9: + { + if (!(DvbApi.Recording() || DvbApi.Replaying())) { + dcNumber = dcNumber * 10 + key - k0; + dcTime = time_ms(); + } + } + // Record/Replay Control: + case kBegin: DvbApi.Skip(-INT_MAX); break; + case kRecord: if (!(DvbApi.Recording() || DvbApi.Replaying())) { + cTimer *timer = new cTimer(true); + Timers.Add(timer); + Timers.Save(); + } + break; + case kPause: DvbApi.PauseReplay(); break; + case kStop: DELETENULL(ReplayDisplay); + 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: DELETENULL(ReplayDisplay); + Menu = new cMenuMain; + Menu->Display(); + break; + // Up/Down Channel Select: + case kUp: + case kDown: if (!(DvbApi.Recording() || DvbApi.Replaying())) { + int n = CurrentChannel + (key == kUp ? 1 : -1); + cChannel *channel = Channels.Get(n); + if (channel) + channel->Switch(); + } + break; + // Viewing Control: + case kOk: if (ReplayDisplay) + DELETENULL(ReplayDisplay); + else if (DvbApi.Replaying()) + ReplayDisplay = new cReplayDisplay; + else + LastChannel = -1; break; // forces channel display + default: break; + } + } + } + isyslog(LOG_INFO, "caught signal %d", Interrupted); + DvbApi.StopRecord(); + DvbApi.StopReplay(); + isyslog(LOG_INFO, "exiting"); + closelog(); + return 0; +} From 9599a8fd8a6724e55ec4ad2ba2c975c0850073d9 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 27 May 2000 18:00:00 +0200 Subject: [PATCH 005/307] Version 0.05 - Support for more than one DVB card. - Simultaneous record and replay (with two DVB cards). - Instant recordings no longer get the name "instant". They now get the name of the channel, with a prepended '@' character. - Timers that are not given an explicit Name now use the channel name with a prepended '@' character. - If an instant recording is currently active, the Main menu now contains an option to stop that recording. - Timers are now only processed when the Menu is not active. So after editing a timer the effect will take place only after the menu has been closed. In order to avoid missing a timer event by inadvertently leaving the menu open, the menu will be closed automatically after about two minutes of inactivity. - If a recording is currently being replayed, the Main menu now contains an option to stop replaying. - Displaying the recording DVB interface status in the decimal points of the RCU display. - Reduced the number of remote control keys. Modified the key assignments for the PC keyboard to better resemble the "up-down-left-right-ok" layout on menu controlling remote control units. --- BUGS | 6 +- HISTORY | 23 +++++ INSTALL | 26 +++--- MANUAL | 65 ++++++++++---- TODO | 7 +- channels.conf | 14 ++- config.c | 42 ++++----- config.h | 18 ++-- dvbapi.c | 193 +++++++++++++++++++++++++++++++++------- dvbapi.h | 28 ++++-- interface.c | 33 ++++--- interface.h | 5 +- keys-pc.conf | Bin 425 -> 283 bytes menu.c | 238 +++++++++++++++++++++++++++++++++++++++++++------- menu.h | 50 +++++++++-- osd.h | 20 ++++- recording.c | 6 +- remote.c | 13 ++- remote.h | 7 +- timers.conf | 11 +-- vdr.c | 135 ++++++++++++---------------- 21 files changed, 678 insertions(+), 262 deletions(-) diff --git a/BUGS b/BUGS index 66755f9f7..d9e2687bc 100644 --- a/BUGS +++ b/BUGS @@ -1,7 +1,7 @@ Video Disk Recorder - Known Bugs -------------------------------- -* Sometimes picture and sound drift apart. +* Sometimes the picture "jumps" as if a frame is skipped. Presumably this is a problem in the card driver or firmware? * When the on-screen display is activated during recording, @@ -10,7 +10,3 @@ Video Disk Recorder - Known Bugs 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. - diff --git a/HISTORY b/HISTORY index 95cd350b2..9767c3fe7 100644 --- a/HISTORY +++ b/HISTORY @@ -32,3 +32,26 @@ Video Disk Recorder Revision History kick in too early). - Channel selection is now blocked when recording or replaying. - Improved process handling. + +2000-05-27: Version 0.05 + +- Support for more than one DVB card. +- Simultaneous record and replay (with two DVB cards). +- Instant recordings no longer get the name "instant". They now get the name + of the channel, with a prepended '@' character. +- Timers that are not given an explicit Name now use the channel name with + a prepended '@' character. +- If an instant recording is currently active, the Main menu now contains + an option to stop that recording. +- Timers are now only processed when the Menu is not active. So after editing + a timer the effect will take place only after the menu has been closed. + In order to avoid missing a timer event by inadvertently leaving the menu + open, the menu will be closed automatically after about two minutes of + inactivity. +- If a recording is currently being replayed, the Main menu now contains an + option to stop replaying. +- Displaying the recording DVB interface status in the decimal points of the + RCU display. +- Reduced the number of remote control keys. Modified the key assignments for + the PC keyboard to better resemble the "up-down-left-right-ok" layout on + menu controlling remote control units. diff --git a/INSTALL b/INSTALL index d7acfb6d9..bc619d7ca 100644 --- a/INSTALL +++ b/INSTALL @@ -12,7 +12,7 @@ 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/VDR. -This program requires the card driver version 0.04 or higher +This program requires the card driver version 0.05 or higher to work properly. After extracting the package, change into the VDR directory @@ -30,6 +30,10 @@ interface. These modes are useful when testing new menus if you only have a remote connection to the VDR (which, in my case, is located in the living room and has neither a monitor nor a keyboard). +When running, the 'vdr' program writes status information into the +system log file (/var/log/messages). You may want to watch these +messages (tail -f /var/log/mesages) to see if there are any problems. + The video data directory: ------------------------- @@ -69,7 +73,9 @@ 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. +control recording/replaying. The program uses only a very small number +of keys which have multiple meanings in the various modes (see MANUAL +for a detailed description). 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. @@ -77,19 +83,11 @@ 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 + Menu 'Home' in numeric block + Ok '5' in numeric block + Back 'End' in numeric block 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 + 0..9 '0'..'9' in top row If you prefer different key assignments, simply delete the file 'keys-pc.conf' and restart 'vdr' to get into learning mode. diff --git a/MANUAL b/MANUAL index 36a62987a..cea39466e 100644 --- a/MANUAL +++ b/MANUAL @@ -1,6 +1,28 @@ Video Disk Recorder User's Manual --------------------------------- +* Remote Control Keys + + The following remote control keys are used to control the VDR + operation. To keep the number of different keys as small as + possible, several keys have different meanings in the various + modes: + + Key Normal Main Channels Timer Edit/New Recordings Replay + + Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Begin + Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause + Left - - - Disable Decrement - Search back + Right - - - Enable Increment - Search forward + Ok Ch display Select Switch Edit Accept Play Progress disp. + Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on + Back - Menu off Main menu Main menu Discard Main menu - + Red - Record Edit Edit - Play - + Green - - New New - - Skip -60s + Yellow - - Delete Delete - Delete Skip +60s + Blue - - Mark Mark - - Stop + 0..9 Ch select - - - Numeric inp. - - + * Navigating through the On Screen Menus The "Main" menu can be called up with the "Menu" key of your remote @@ -22,10 +44,10 @@ Video Disk Recorder User's Manual keys. "Ok" then confirms the changes. The "Red", "Green", "Yellow" and "Blue" buttons have special meanings - in the various menus and are listed at the bottom of the on-screen-display. + in various menus and are listed at the bottom of the on-screen-display. At any point in the menu system, pressing the "Menu" key again will - immediately leave the menu system. + immediately leave the menu system (discarding any pending changes). * Selecting a Channel @@ -48,35 +70,40 @@ Video Disk Recorder User's Manual * Instant Recording - You can start recording the current channel by pressing the "Record" - button. This will create a timer event named "instant" that starts - at the current time and records for two hours. + You can start recording the current channel by pressing the "Red" button + in the Main menu. This will create a timer event named "@channelname" that + starts 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. + Stop instant recording by pressing the "Menu" button and selecting + "Stop Recording", or by disabling 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. + Playback can be stopped via the Main menu by selecting "Stop replaying", + or by pressing the "Blue" button outside the menu. * Replay Control The following keys have the listed meaning in Replay mode: - - "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. - - "Ok" Brings up the replay progress display, which shows the date, - time and title of the recording, a progress bar and the - current and total time of the recording. - Press "Ok" again to turn off the progress display. + - Up Positions to beginning of the recording and starts playback + from there. + - Down Halts playback at the current position. Press again to continue + playback. + - Blue Stops playback and stores the current position, so that + playback can be resumed later at that point. + - Left + Right Runs playback forward or backward at a higher speed. Press + again to resume normal speed. + - Green + Yellow Skips about 60 seconds back or forward. + - Ok Brings up the replay progress display, which shows the date, + time and title of the recording, a progress bar and the + current and total time of the recording. + Press "Ok" again to turn off the progress display. * Programming the Timer diff --git a/TODO b/TODO index 8f5d2f3d9..64b31b23b 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,8 @@ TODO list for the Video Disk Recorder project --------------------------------------------- -* 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). - Maybe we can do this with only a single card, if the card - driver/firmware allows simultaneuos record/playback? +* Implement simultaneous record/replay with a single DVB card once + the card driver/firmware allows this. * Implement "on-disk editing" to allow "cutting out" of certain scenes in order to archive them (or, reversely, cut out commercial breaks). diff --git a/channels.conf b/channels.conf index c0e191aca..5edd778ef 100644 --- a/channels.conf +++ b/channels.conf @@ -1,14 +1,14 @@ 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 +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 +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 +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 @@ -41,8 +41,14 @@ 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 +Premiere:11798:h:1:27500:511:512:1:10 +Star Kino:11798:h:1:27500:767:768:1:9 +Cine Action:11798:h:1:27500:1023:1024:1:20 +Cine Comedy:11798:h:1:27500:1279:1280:1:29 +Sci Fantasy:11798:h:1:27500:1535:1536:1:41 +Romantic Movies:11798:h:1:27500:1791:1792:1:11 +Studio Universal:11798:h:1:27500:2047:2048:1:21 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 diff --git a/config.c b/config.c index 0a39cc503..7e02c9169 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.5 2000/04/24 09:44:15 kls Exp $ + * $Id: config.c 1.7 2000/05/27 14:44:15 kls Exp $ */ #include "config.h" @@ -23,6 +23,10 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! { kBack, "Back", 0 }, { kLeft, "Left", 0 }, { kRight, "Right", 0 }, + { kRed, "Red", 0 }, + { kGreen, "Green", 0 }, + { kYellow, "Yellow", 0 }, + { kBlue, "Blue", 0 }, { k0, "0", 0 }, { k1, "1", 0 }, { k2, "2", 0 }, @@ -33,18 +37,6 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! { k7, "7", 0 }, { k8, "8", 0 }, { k9, "9", 0 }, - { kRed, "Red", 0 }, - { kGreen, "Green", 0 }, - { kYellow, "Yellow", 0 }, - { kBlue, "Blue", 0 }, - { kRecord, "Record", 0 }, - { kPause, "Pause", 0 }, - { kStop, "Stop", 0 }, - { kBegin, "Begin", 0 }, - { kSearchForward, "SearchForward", 0 }, - { kSearchBack, "SearchBack", 0 }, - { kSkipForward, "SkipForward", 0 }, - { kSkipBack, "SkipBack", 0 }, { kNone, "", 0 }, }; @@ -201,13 +193,15 @@ bool cChannel::Save(FILE *f) 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(cDvbApi *DvbApi) { - if (!DvbApi.Recording()) { + if (!DvbApi) + DvbApi = cDvbApi::PrimaryDvbApi; + if (!DvbApi->Recording()) { isyslog(LOG_INFO, "switching to channel %d", Index() + 1); CurrentChannel = Index(); for (int i = 3; --i;) { - if (DvbApi.SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) + if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) return true; esyslog(LOG_ERR, "retrying"); } @@ -217,10 +211,16 @@ bool cChannel::Switch(void) return false; } -bool cChannel::SwitchTo(int i) +bool cChannel::SwitchTo(int i, cDvbApi *DvbApi) +{ + cChannel *channel = Channels.Get(i); + return channel && channel->Switch(DvbApi); +} + +const char *cChannel::GetChannelName(int i) { cChannel *channel = Channels.Get(i); - return channel && channel->Switch(); + return channel ? channel->name : NULL; } // -- cTimer ----------------------------------------------------------------- @@ -241,7 +241,9 @@ cTimer::cTimer(bool Instant) //TODO VPS??? priority = 99; lifetime = 99; - strcpy(file, Instant ? "instant" : ""); + *file = 0; + if (Instant) + snprintf(file, sizeof(file), "@%s", cChannel::GetChannelName(CurrentChannel)); } int cTimer::TimeToInt(int t) @@ -382,7 +384,7 @@ cTimer *cTimer::GetMatch(void) { cTimer *t = (cTimer *)Timers.First(); while (t) { - if (t->Matches()) + if (!t->recording && t->Matches()) return t; t = (cTimer *)t->Next(); } diff --git a/config.h b/config.h index 42af0f858..1e22b8883 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.4 2000/04/24 09:44:17 kls Exp $ + * $Id: config.h 1.6 2000/05/27 14:43:46 kls Exp $ */ #ifndef __CONFIG_H @@ -14,6 +14,7 @@ #include #include #include +#include "dvbapi.h" #include "tools.h" #define MaxBuffer 1000 @@ -26,19 +27,11 @@ enum eKeys { // "Up" and "Down" must be the first two keys! kBack, kLeft, kRight, - k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, kRed, kGreen, kYellow, kBlue, - kRecord, - kPause, - kStop, - kBegin, - kSearchForward, - kSearchBack, - kSkipForward, - kSkipBack, + k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, kNone }; @@ -79,8 +72,9 @@ class cChannel : public cListObject { cChannel(const cChannel *Channel); bool Parse(char *s); bool Save(FILE *f); - bool Switch(void); - static bool SwitchTo(int i); + bool Switch(cDvbApi *DvbApi = NULL); + static bool SwitchTo(int i, cDvbApi *DvbApi = NULL); + static const char *GetChannelName(int i); }; class cTimer : public cListObject { diff --git a/dvbapi.c b/dvbapi.c index 719437d4c..e652d9971 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.8 2000/04/24 15:30:35 kls Exp $ + * $Id: dvbapi.c 1.10 2000/05/27 14:07:17 kls Exp $ */ #include "dvbapi.h" @@ -70,8 +70,9 @@ class cIndexFile { struct tIndex { int offset; uchar type; uchar number; short reserved; }; int f; char *fileName, *pFileExt; - int last, resume; + int size, last, resume; tIndex *index; + bool CatchUp(void); public: cIndexFile(const char *FileName, bool Record = false); ~cIndexFile(); @@ -89,6 +90,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) { f = -1; fileName = pFileExt = NULL; + size = 0; last = resume = -1; index = NULL; if (FileName) { @@ -108,18 +110,25 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) } last = (buf.st_size + delta) / sizeof(tIndex) - 1; if (!Record && last >= 0) { - index = new tIndex[last + 1]; - int fi = open(fileName, O_RDONLY); - if (fi >= 0) { - if ((int)read(fi, index, buf.st_size) != buf.st_size) { - esyslog(LOG_ERR, "ERROR: can't read from file '%s'", fileName); - delete index; - index = NULL; + size = last + 1; + index = new tIndex[size]; + if (index) { + f = open(fileName, O_RDONLY); + if (f >= 0) { + if ((int)read(f, index, buf.st_size) != buf.st_size) { + esyslog(LOG_ERR, "ERROR: can't read from file '%s'", fileName); + delete index; + index = NULL; + close(f); + f = -1; + } + // we don't close f here, see CatchUp()! } - close(fi); + else + LOG_ERROR_STR(fileName); } else - LOG_ERROR_STR(fileName); + esyslog(LOG_ERR, "ERROR: can't allocate %d bytes for index '%s'", size * sizeof(tIndex), fileName); } } else @@ -164,6 +173,46 @@ cIndexFile::~cIndexFile() delete fileName; } +bool cIndexFile::CatchUp(void) +{ + if (index && f >= 0) { + struct stat buf; + if (fstat(f, &buf) == 0) { + int newLast = buf.st_size / sizeof(tIndex) - 1; + if (newLast > last) { + if (size <= newLast) { + size *= 2; + if (size <= newLast) + size = newLast + 1; + } + index = (tIndex *)realloc(index, size * sizeof(tIndex)); + if (index) { + int offset = (last + 1) * sizeof(tIndex); + int delta = (newLast - last) * sizeof(tIndex); + if (lseek(f, offset, SEEK_SET) == offset) { + if (read(f, &index[last + 1], delta) != delta) { + esyslog(LOG_ERR, "ERROR: can't read from index"); + delete index; + index = NULL; + close(f); + f = -1; + } + last = newLast; + return true; + } + else + LOG_ERROR; + } + else + esyslog(LOG_ERR, "ERROR: can't realloc() index"); + } + } + else + LOG_ERROR; + } + return false; +} + void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) { if (f >= 0) { @@ -181,6 +230,7 @@ void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType) { if (index) { + CatchUp(); if (Index >= 0 && Index <= last) { *FileNumber = index[Index].number; *FileOffset = index[Index].offset; @@ -195,10 +245,12 @@ bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *Pictu int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length) { if (index) { + if (Forward) + CatchUp(); int d = Forward ? 1 : -1; for (;;) { Index += d; - if (Index >= 0 && Index <= last) { + if (Index >= 0 && Index <= last - 100) { // '- 100': need to stay off the end! if (index[Index].type == I_FRAME) { *FileNumber = index[Index].number; *FileOffset = index[Index].offset; @@ -226,6 +278,7 @@ int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *F int cIndexFile::Get(uchar FileNumber, int FileOffset) { if (index) { + CatchUp(); //TODO implement binary search! int i; for (i = 0; i < last; i++) { @@ -842,6 +895,7 @@ void cReplayBuffer::SkipSeconds(int Seconds) uchar FileNumber; int FileOffset; if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0) + if ((Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset)) >= 0) NextFile(FileNumber, FileOffset); } } @@ -987,13 +1041,16 @@ int cReplayBuffer::Write(int Max) // --- cDvbApi --------------------------------------------------------------- -cDvbApi::cDvbApi(void) +int cDvbApi::NumDvbApis = 0; +cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL }; +cDvbApi *cDvbApi::PrimaryDvbApi = NULL; + +cDvbApi::cDvbApi(const char *FileName) { - isMainProcess = true; pidRecord = pidReplay = 0; fromRecord = toRecord = -1; fromReplay = toReplay = -1; - videoDev = open(VIDEODEVICE, O_RDWR | O_NONBLOCK); + videoDev = open(FileName, O_RDWR | O_NONBLOCK); if (videoDev < 0) LOG_ERROR; cols = rows = 0; @@ -1011,26 +1068,90 @@ cDvbApi::cDvbApi(void) leaveok(stdscr, TRUE); window = NULL; #endif - lastProgress = -1; + lastProgress = lastTotal = -1; replayTitle = NULL; } cDvbApi::~cDvbApi() { - if (isMainProcess) { - if (videoDev >= 0) { - Close(); - StopReplay(); - StopRecord(); - close(videoDev); - } + if (videoDev >= 0) { + Close(); + StopReplay(); + StopRecord(); + close(videoDev); + } #if defined(DEBUG_REMOTE) || defined(DEBUG_OSD) - endwin(); + endwin(); #endif - } delete replayTitle; } +cDvbApi *cDvbApi::GetDvbApi(int Ca) +{ + Ca--; + for (int i = MAXDVBAPI; --i >= 0; ) { + if (dvbApi[i]) { + if ((i == Ca || Ca < 0) && !dvbApi[i]->Recording()) + return dvbApi[i]; + } + } + return NULL; +} + +int cDvbApi::Index(void) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + if (dvbApi[i] == this) + return i; + } + return -1; +} + +bool cDvbApi::Init(void) +{ + char fileName[strlen(VIDEODEVICE) + 10]; + int i; + + NumDvbApis = 0; + for (i = 0; i < MAXDVBAPI; i++) { + sprintf(fileName, "%s%d", VIDEODEVICE, i); + if (access(fileName, F_OK | R_OK | W_OK) == 0) { + dsyslog(LOG_INFO, "probing %s", fileName); + int f = open(fileName, O_RDWR); + if (f >= 0) { + close(f); + dvbApi[i] = new cDvbApi(fileName); + NumDvbApis++; + } + else { + if (errno != ENODEV) + LOG_ERROR_STR(fileName); + break; + } + } + else { + if (errno != ENOENT) + LOG_ERROR_STR(fileName); + break; + } + } + PrimaryDvbApi = dvbApi[0]; + if (NumDvbApis > 0) + isyslog(LOG_INFO, "found %d video device%s", NumDvbApis, NumDvbApis > 1 ? "s" : ""); + else + esyslog(LOG_ERR, "ERROR: no video device found, giving up!"); + return NumDvbApis > 0; +} + +void cDvbApi::Cleanup(void) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + delete dvbApi[i]; + dvbApi[i] = NULL; + } + PrimaryDvbApi = NULL; +} + #ifdef DEBUG_OSD void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg) { @@ -1095,15 +1216,17 @@ void cDvbApi::Open(int w, int h) SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255); SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255); - lastProgress = -1; + lastProgress = lastTotal = -1; } void cDvbApi::Close(void) { -#ifndef DEBUG_OSD +#ifdef DEBUG_OSD + delwin(window); +#else Cmd(OSD_Close); #endif - lastProgress = -1; + lastProgress = lastTotal = -1; } void cDvbApi::Clear(void) @@ -1158,8 +1281,9 @@ bool cDvbApi::ShowProgress(bool Initial) if (Initial) { if (replayTitle) Text(0, 0, replayTitle); - Text(-7, 2, cIndexFile::Str(Total)); } + if (Total != lastTotal) + Text(-7, 2, cIndexFile::Str(Total)); #ifdef DEBUG_OSD int p = cols * Current / Total; Fill(0, 1, p, 1, clrGreen); @@ -1191,6 +1315,7 @@ bool cDvbApi::ShowProgress(bool Initial) } #endif Text(0, 2, cIndexFile::Str(Current)); + lastTotal = Total; return true; } return false; @@ -1247,6 +1372,8 @@ bool cDvbApi::StartRecord(const char *FileName) } if (videoDev >= 0) { + StopReplay(); // TODO: remove this if the driver is able to do record and replay at the same time + // Check FileName: if (!FileName) { @@ -1285,7 +1412,6 @@ bool cDvbApi::StartRecord(const char *FileName) // This is the actual recording process dsyslog(LOG_INFO, "start recording process (pid=%d)", getpid()); - isMainProcess = false; bool DataStreamBroken = false; int fromMain = toRecordPipe[0]; int toMain = fromRecordPipe[1]; @@ -1371,7 +1497,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) StopReplay(); if (videoDev >= 0) { - lastProgress = -1; + lastProgress = lastTotal = -1; delete replayTitle; if (Title) { if ((replayTitle = strdup(Title)) == NULL) @@ -1411,7 +1537,6 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) // This is the actual replaying process dsyslog(LOG_INFO, "start replaying process (pid=%d)", getpid()); - isMainProcess = false; int fromMain = toReplayPipe[0]; int toMain = fromReplayPipe[1]; cReplayBuffer *Buffer = new cReplayBuffer(&videoDev, FileName); @@ -1440,7 +1565,8 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) } if (FD_ISSET(fromMain, &setIn)) { switch (readchar(fromMain)) { - case dvbStop: Buffer->Stop(); break; + case dvbStop: SetReplayMode(VID_PLAY_CLEAR_BUFFER); + Buffer->Stop(); break; case dvbPauseReplay: SetReplayMode(Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); Paused = !Paused; FastForward = FastRewind = false; @@ -1459,6 +1585,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) case dvbSkip: { int Seconds; if (readint(fromMain, Seconds)) { + SetReplayMode(VID_PLAY_CLEAR_BUFFER); SetReplayMode(VID_PLAY_NORMAL); FastForward = FastRewind = Paused = false; Buffer->SetMode(rmPlay); diff --git a/dvbapi.h b/dvbapi.h index 91e554e98..e0c74b075 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.8 2000/04/24 15:31:07 kls Exp $ + * $Id: dvbapi.h 1.10 2000/05/20 14:50:43 kls Exp $ */ #ifndef __DVBAPI_H @@ -43,10 +43,29 @@ enum eDvbColor { clrBackground, class cDvbApi { private: int videoDev; + cDvbApi(const char *FileName); public: - cDvbApi(void); ~cDvbApi(); +#define MAXDVBAPI 2 + static int NumDvbApis; +private: + static cDvbApi *dvbApi[MAXDVBAPI]; +public: + static cDvbApi *PrimaryDvbApi; + static cDvbApi *GetDvbApi(int Ca = 0); + // Selects a free DVB device, starting with the highest device number. + // If Ca is nor 0, the device with the given number will be returned + // if it is not currently recording. + int Index(void); + // Returns the index of this DvbApi. + static bool Init(void); + // Initializes the DVB API and probes for existing DVB devices. + // Must be called before accessing any DVB functions. + static void Cleanup(void); + // Closes down all DVB devices. + // Must be called at the end of the program. + // On Screen Display facilities private: @@ -72,7 +91,7 @@ class cDvbApi { // Progress Display facilities private: - int lastProgress; + int lastProgress, lastTotal; char *replayTitle; public: bool ShowProgress(bool Initial = false); @@ -91,7 +110,6 @@ class cDvbApi { dvbSkip, dvbGetIndex, }; - bool isMainProcess; pid_t pidRecord, pidReplay; int fromRecord, toRecord; int fromReplay, toReplay; @@ -133,5 +151,5 @@ class cDvbApi { // beginning of the recording. bool GetIndex(int *Current, int *Total = NULL); }; - + #endif //__DVBAPI_H diff --git a/interface.c b/interface.c index 446f9c434..82f955dc7 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.6 2000/04/24 09:44:23 kls Exp $ + * $Id: interface.c 1.9 2000/05/07 09:28:39 kls Exp $ */ #include "interface.h" @@ -15,8 +15,6 @@ cRcIo RcIo("/dev/ttyS1"); #endif -cDvbApi DvbApi; //XXX member of cInterface??? - cInterface Interface; cInterface::cInterface(void) @@ -36,7 +34,7 @@ void cInterface::Init(void) void cInterface::Open(int NumCols, int NumLines) { if (!open++) - DvbApi.Open(NumCols, NumLines); + cDvbApi::PrimaryDvbApi->Open(NumCols, NumLines); } void cInterface::Close(void) @@ -44,7 +42,7 @@ void cInterface::Close(void) if (open == 1) Clear(); if (!--open) - DvbApi.Close(); + cDvbApi::PrimaryDvbApi->Close(); } unsigned int cInterface::GetCh(bool Wait) @@ -91,13 +89,13 @@ eKeys cInterface::Wait(int Seconds, bool KeepChar) void cInterface::Clear(void) { if (open) - DvbApi.Clear(); + cDvbApi::PrimaryDvbApi->Clear(); } void cInterface::ClearEol(int x, int y, eDvbColor Color) { if (open) - DvbApi.ClrEol(x, y, Color); + cDvbApi::PrimaryDvbApi->ClrEol(x, y, Color); } void cInterface::SetCols(int *c) @@ -112,7 +110,7 @@ void cInterface::SetCols(int *c) void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor) { if (open) - DvbApi.Text(x, y, s, FgColor, BgColor); + cDvbApi::PrimaryDvbApi->Text(x, y, s, FgColor, BgColor); } void cInterface::WriteText(int x, int y, const char *s, bool Current) @@ -198,8 +196,8 @@ void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvb int l = (w - strlen(Text)) / 2; if (l < 0) l = 0; - DvbApi.Fill(Index * w, -1, w, 1, BgColor); - DvbApi.Text(Index * w + l, -1, Text, FgColor, BgColor); + cDvbApi::PrimaryDvbApi->Fill(Index * w, -1, w, 1, BgColor); + cDvbApi::PrimaryDvbApi->Text(Index * w + l, -1, Text, FgColor, BgColor); } } @@ -323,7 +321,7 @@ void cInterface::DisplayChannel(int Number, const char *Name) #ifndef DEBUG_REMOTE RcIo.Number(Number); #endif - if (Name) { + if (Name && !Recording()) { Open(MenuColumns, 1); char buffer[MenuColumns + 1]; snprintf(buffer, sizeof(buffer), "%d %s", Number, Name ? Name : ""); @@ -337,3 +335,16 @@ void cInterface::DisplayChannel(int Number, const char *Name) Close(); } } + +void cInterface::DisplayRecording(int Index, bool On) +{ +#ifndef DEBUG_REMOTE + RcIo.SetPoints(1 << Index, On); +#endif +} + +bool cInterface::Recording(void) +{ + // This is located here because the Interface has to do with the "PrimaryDvbApi" anyway + return cDvbApi::PrimaryDvbApi->Recording(); +} diff --git a/interface.h b/interface.h index eb4e76bcd..2a1c1560f 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.7 2000/04/24 09:44:25 kls Exp $ + * $Id: interface.h 1.9 2000/05/06 15:39:23 kls Exp $ */ #ifndef __INTERFACE_H @@ -43,9 +43,10 @@ class cInterface { void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); void LearnKeys(void); void DisplayChannel(int Number, const char *Name = NULL); + void DisplayRecording(int Index, bool On); + bool Recording(void); }; extern cInterface Interface; -extern cDvbApi DvbApi; //XXX member of cInterface??? #endif //__INTERFACE_H diff --git a/keys-pc.conf b/keys-pc.conf index 744609d5c09e0c95ec545e912d01d81de7cd64ab..cb0192be3fcc6e296bcd6efd69c099dfd7fdf664 100644 GIT binary patch delta 70 zcmZ3}5)a>@5>KTCew(D3R5 zo2H4}_bZwneja~6DKglF@h(c^i|<2HPUCo+nP`Wis*_UW@yX|>xH6pD%XN_!lw5|O z1QoQPh7mN#1T$Dc3n%E{1wGb+Yvh7CPTb5wQI11oUe4Lzm%A>E(k@VR1B=>D&N{?o zCa>{b4Si~pCzQ{Saw2a~@TEHq)$ diff --git a/menu.c b/menu.c index 2a4cfa9fc..aab5fd121 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.8 2000/04/24 15:32:11 kls Exp $ + * $Id: menu.c 1.16 2000/05/27 16:13:39 kls Exp $ */ #include "menu.h" @@ -12,9 +12,10 @@ #include #include #include "config.h" -#include "dvbapi.h" #include "recording.h" +#define MENUTIMEOUT 120 // seconds + const char *FileNameChars = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.# "; // --- cMenuEditItem --------------------------------------------------------- @@ -509,7 +510,7 @@ 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( "CA", &data.ca, 0, cDvbApi::NumDvbApis)); Add(new cMenuEditIntItem( "Pnr", &data.pnr, 0, 10000)); //TODO exact limits??? } } @@ -744,7 +745,7 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key) if (state == osUnknown) { if (Key == kOk) { if (!*data.file) - strcpy(data.file, "unnamed"); + strcpy(data.file, cChannel::GetChannelName(data.channel - 1)); if (timer && memcmp(timer, &data, sizeof(data)) != 0) { *timer = data; Timers.Save(); @@ -947,9 +948,8 @@ eOSState cMenuRecordings::Play(void) { cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); if (ri) { -//XXX what if this recording's file is currently in use??? - if (DvbApi.StartReplay(ri->recording->FileName(), ri->recording->Title())) - return osEnd; + cReplayControl::SetRecording(ri->recording->FileName(), ri->recording->Title()); + return osReplay; } return osContinue; } @@ -992,12 +992,26 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) // --- cMenuMain ------------------------------------------------------------- -cMenuMain::cMenuMain(void) +#define STOP_RECORDING "Stop recording " + +cMenuMain::cMenuMain(bool Replaying) :cOsdMenu("Main") { Add(new cOsdItem("Channels", osChannels)); Add(new cOsdItem("Timer", osTimer)); Add(new cOsdItem("Recordings", osRecordings)); + if (Replaying) + Add(new cOsdItem("Stop replaying", osStopReplay)); + const char *s = NULL; + while ((s = cRecordControls::GetInstantId(s)) != NULL) { + char *buffer = NULL; + asprintf(&buffer, "%s%s", STOP_RECORDING, s); + Add(new cOsdItem(buffer, osStopRecord)); + delete buffer; + } + SetHelp("Record"); + Display(); + lastActivity = time(NULL); } eOSState cMenuMain::ProcessKey(eKeys Key) @@ -1008,41 +1022,205 @@ eOSState cMenuMain::ProcessKey(eKeys Key) case osChannels: return AddSubMenu(new cMenuChannels); case osTimer: return AddSubMenu(new cMenuTimers); case osRecordings: return AddSubMenu(new cMenuRecordings); - default: break; + case osStopRecord: if (Interface.Confirm("Stop Recording?")) { + cOsdItem *item = Get(Current()); + if (item) { + cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING)); + return osEnd; + } + } + default: switch (Key) { + case kMenu: state = osEnd; break; + case kRed: if (!HasSubMenu()) + state = osRecord; + break; + default: break; + } } + if (Key != kNone) + lastActivity = time(NULL); + else if (time(NULL) - lastActivity > MENUTIMEOUT) + state = osEnd; return state; } -// --- cReplayDisplay -------------------------------------------------------- +// --- cRecordControl -------------------------------------------------------- + +cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) +{ + instantId = NULL; + dvbApi = DvbApi; + if (!dvbApi) dvbApi = cDvbApi::PrimaryDvbApi;//XXX + timer = Timer; + if (!timer) { + timer = new cTimer(true); + Timers.Add(timer); + Timers.Save(); + asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s on %d" : "%s", cChannel::GetChannelName(timer->channel - 1), dvbApi->Index() + 1); + } + timer->SetRecording(true); + cChannel::SwitchTo(timer->channel - 1, dvbApi); + cRecording Recording(timer); + dvbApi->StartRecord(Recording.FileName()); + Interface.DisplayRecording(dvbApi->Index(), true); +} + +cRecordControl::~cRecordControl() +{ + Stop(true); + delete instantId; + Interface.DisplayRecording(dvbApi->Index(), false); +} + +void cRecordControl::Stop(bool KeepInstant) +{ + if (timer) { + dvbApi->StopRecord(); + timer->SetRecording(false); + if ((IsInstant() && !KeepInstant) || (timer->IsSingleEvent() && !timer->Matches())) { + // checking timer->Matches() to make sure we don't delete the timer + // if the program was cancelled before the timer's stop time! + isyslog(LOG_INFO, "deleting timer %d", timer->Index() + 1); + Timers.Del(timer); + Timers.Save(); + } + timer = NULL; + } +} + +bool cRecordControl::Process(void) +{ + if (!timer || !timer->Matches()) + return false; + AssertFreeDiskSpace(); + return true; +} + +// --- cRecordControls ------------------------------------------------------- + +cRecordControl *cRecordControls::RecordControls[MAXDVBAPI] = { NULL }; + +bool cRecordControls::Start(cTimer *Timer) +{ + int ch = Timer ? Timer->channel - 1 : CurrentChannel; + cChannel *channel = Channels.Get(ch); + + if (channel) { + cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca); + if (dvbApi) { + for (int i = 0; i < MAXDVBAPI; i++) { + if (!RecordControls[i]) { + RecordControls[i] = new cRecordControl(dvbApi, Timer); + return true; + } + } + } + else + esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch); + } + else + esyslog(LOG_ERR, "ERROR: channel %d not defined!", ch + 1); + return false; +} + +void cRecordControls::Stop(const char *InstantId) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + if (RecordControls[i]) { + const char *id = RecordControls[i]->InstantId(); + if (id && strcmp(id, InstantId) == 0) + RecordControls[i]->Stop(); + } + } +} -cReplayDisplay::cReplayDisplay(void) +const char *cRecordControls::GetInstantId(const char *LastInstantId) { - Interface.Open(MenuColumns, -3); - shown = DvbApi.ShowProgress(true); + for (int i = 0; i < MAXDVBAPI; i++) { + if (RecordControls[i]) { + if (!LastInstantId && RecordControls[i]->InstantId()) + return RecordControls[i]->InstantId(); + if (LastInstantId && LastInstantId == RecordControls[i]->InstantId()) + LastInstantId = NULL; + } + } + return NULL; } -cReplayDisplay::~cReplayDisplay() +void cRecordControls::Process(void) { - Interface.Close(); + for (int i = 0; i < MAXDVBAPI; i++) { + if (RecordControls[i]) { + if (!RecordControls[i]->Process()) + DELETENULL(RecordControls[i]); + } + } } -eKeys cReplayDisplay::ProcessKey(eKeys Key) +// --- cReplayControl -------------------------------------------------------- + +char *cReplayControl::fileName = NULL; +char *cReplayControl::title = NULL; + +cReplayControl::cReplayControl(void) { - if (!DvbApi.Replaying()) - return kOk; // will turn off replay display - shown = DvbApi.ShowProgress(!shown); + dvbApi = cDvbApi::PrimaryDvbApi;//XXX + visible = shown = false; + if (fileName) + dvbApi->StartReplay(fileName, title); +} + +cReplayControl::~cReplayControl() +{ + Hide(); + dvbApi->StopReplay(); +} + +void cReplayControl::SetRecording(const char *FileName, const char *Title) +{ + delete fileName; + delete title; + fileName = FileName ? strdup(FileName) : NULL; + title = Title ? strdup(Title) : NULL; +} + +void cReplayControl::Show(void) +{ + if (!visible) { + Interface.Open(MenuColumns, -3); + needsFastResponse = visible = true; + shown = dvbApi->ShowProgress(true); + } +} + +void cReplayControl::Hide(void) +{ + if (visible) { + Interface.Close(); + needsFastResponse = visible = false; + } +} + +eOSState cReplayControl::ProcessKey(eKeys Key) +{ + if (!dvbApi->Replaying()) + return osEnd; + if (visible) + shown = dvbApi->ShowProgress(!shown) || shown; switch (Key) { - case kBegin: - case kPause: - case kStop: - case kSearchBack: - case kSearchForward: - case kSkipBack: - case kSkipForward: break; // will be done in main loop - case kMenu: break; // allow direct switching to menu - case kOk: break; // switches off replay display - default: Key = kNone; // ignore anything not explicitly known here + case kUp: dvbApi->Skip(-INT_MAX); break; + case kDown: dvbApi->PauseReplay(); break; + case kBlue: Hide(); + dvbApi->StopReplay(); + return osEnd; + case kLeft: dvbApi->FastRewind(); break; + case kRight: dvbApi->FastForward(); break; + case kGreen: dvbApi->Skip(-60); break; + case kYellow: dvbApi->Skip(60); break; + case kMenu: Hide(); return osMenu; // allow direct switching to menu + case kOk: visible ? Hide() : Show(); break; + default: return osUnknown; } - return Key; + return osContinue; } diff --git a/menu.h b/menu.h index f66579962..6ba080cb2 100644 --- a/menu.h +++ b/menu.h @@ -4,27 +4,63 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.5 2000/04/24 15:31:53 kls Exp $ + * $Id: menu.h 1.9 2000/05/01 15:16:23 kls Exp $ */ #ifndef _MENU_H #define _MENU_H +#define _GNU_SOURCE + +#include "dvbapi.h" #include "osd.h" class cMenuMain : public cOsdMenu { +private: + time_t lastActivity; public: - cMenuMain(void); + cMenuMain(bool Replaying); virtual eOSState ProcessKey(eKeys Key); }; -class cReplayDisplay { +class cRecordControl { +private: + cDvbApi *dvbApi; + cTimer *timer; + char *instantId; +public: + cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL); + virtual ~cRecordControl(); + bool Process(void); + void Stop(bool KeepInstant = false); + bool IsInstant(void) { return instantId; } + const char *InstantId(void) { return instantId; } + }; + +class cRecordControls { private: - bool shown; + static cRecordControl *RecordControls[MAXDVBAPI]; public: - cReplayDisplay(void); - ~cReplayDisplay(); - eKeys ProcessKey(eKeys Key); + static bool Start(cTimer *Timer = NULL); + static void Stop(const char *InstantId); + static const char *GetInstantId(const char *LastInstantId); + static void Process(void); + }; + +class cReplayControl : public cOsdBase { +private: + cDvbApi *dvbApi; + bool visible, shown; + void Show(void); + void Hide(void); + static char *fileName; + static char *title; +public: + cReplayControl(void); + virtual ~cReplayControl(); + virtual eOSState ProcessKey(eKeys Key); + bool Visible(void) { return visible; } + static void SetRecording(const char *FileName, const char *Title); }; #endif //_MENU_H diff --git a/osd.h b/osd.h index 99821b876..1d4f4cf0b 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.4 2000/04/24 09:44:32 kls Exp $ + * $Id: osd.h 1.9 2000/05/27 15:35:41 kls Exp $ */ #ifndef __OSD_H @@ -17,11 +17,15 @@ #define MAXOSDITEMS 9 enum eOSState { osUnknown, + osMenu, osContinue, - osProcessed, osChannels, osTimer, osRecordings, + osRecord, + osReplay, + osStopRecord, + osStopReplay, osBack, osEnd, }; @@ -44,7 +48,17 @@ class cOsdItem : public cListObject { virtual eOSState ProcessKey(eKeys Key); }; -class cOsdMenu : public cList { +class cOsdBase { +protected: + bool needsFastResponse; +public: + cOsdBase(bool FastResponse = false) { needsFastResponse = FastResponse; } + virtual ~cOsdBase() {} + virtual eOSState ProcessKey(eKeys Key) = 0; + bool NeedsFastResponse(void) { return needsFastResponse; } + }; + +class cOsdMenu : public cOsdBase, public cList { private: char *title; int cols[cInterface::MaxCols]; diff --git a/recording.c b/recording.c index 46fe53f44..2eba90b41 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.6 2000/04/24 09:45:13 kls Exp $ + * $Id: recording.c 1.8 2000/05/13 16:16:56 kls Exp $ */ #define _GNU_SOURCE @@ -61,8 +61,7 @@ void AssertFreeDiskSpace(void) // it will get removed during the next call. static time_t LastFreeDiskCheck = 0; if (time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA) { - LastFreeDiskCheck = time(NULL); - if (DvbApi.Recording() && LowDiskSpace()) { + if (LowDiskSpace()) { // Remove the oldest file that has been "deleted": cRecordings Recordings; if (Recordings.Load(true)) { @@ -97,6 +96,7 @@ void AssertFreeDiskSpace(void) // Unable to free disk space, but there's nothing we can do about that... esyslog(LOG_ERR, "low disk space, but no recordings to delete"); } + LastFreeDiskCheck = time(NULL); } } diff --git a/remote.c b/remote.c index 2ba5b22b4..eb495e15e 100644 --- a/remote.c +++ b/remote.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.c 1.6 2000/04/24 09:45:56 kls Exp $ + * $Id: remote.c 1.7 2000/05/07 09:28:18 kls Exp $ */ #include "remote.h" @@ -29,6 +29,7 @@ cRcIo::cRcIo(char *DeviceName) t = 0; firstTime = lastTime = 0; lastCommand = 0; + lastNumber = 0; if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) { struct termios t; if (tcgetattr(f, &t) == 0) { @@ -206,6 +207,7 @@ bool cRcIo::Number(int n, bool Hex) n = (n << 4) | ((*d - '0') & 0x0F); } } + lastNumber = n; for (int i = 0; i < 4; i++) { if (!Digit(i, n)) return false; @@ -231,6 +233,15 @@ bool cRcIo::String(char *s) return Number(n, true); } +void cRcIo::SetPoints(unsigned char Dp, bool On) +{ + if (On) + dp |= Dp; + else + dp &= ~Dp; + Number(lastNumber, true); +} + bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address) { // Caller should initialize 'Code' to 0 and call DetectCode() diff --git a/remote.h b/remote.h index 73e50eb78..1d0a1cce0 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.4 2000/04/24 09:46:00 kls Exp $ + * $Id: remote.h 1.5 2000/05/07 09:27:54 kls Exp $ */ #ifndef __REMOTE_H @@ -21,10 +21,12 @@ class cRcIo { time_t t; int firstTime, lastTime; unsigned int lastCommand; + int lastNumber; bool SendCommand(unsigned char Cmd); int ReceiveByte(bool Wait = true); bool SendByteHandshake(unsigned char c); bool SendByte(unsigned char c); + bool Digit(int n, int v); public: enum { modeH = 'h', modeB = 'b', modeS = 's' }; cRcIo(char *DeviceName); @@ -34,9 +36,8 @@ class cRcIo { bool SetCode(unsigned char Code, unsigned short Address); bool SetMode(unsigned char Mode); bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); - bool Digit(int n, int v); bool Number(int n, bool Hex = false); - void Points(unsigned char Dp) { dp = Dp; } + void SetPoints(unsigned char Dp, bool On); bool String(char *s); bool DetectCode(unsigned char *Code, unsigned short *Address); }; diff --git a/timers.conf b/timers.conf index 6fff8d88b..1f9fae0be 100644 --- a/timers.conf +++ b/timers.conf @@ -1,9 +1,10 @@ -0:15:MTWTF--:1828:1901:10:5:nano -0:3:M------:2110:2230:99:10:SevenDays -1:10:-T-----:2058:2150:99:10:Quarks +1:15:MTWTF--:1828:1901:10:5:nano +1:3:M------:2110:2230:99:10:SevenDays +1:10:-T-----:2058:2202: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 +1:2:-----S-:2150:2320:99:10:Wochenshow +1:14:------S:2155:2245:99:10:AprilHailer +1:2:--W----:2110:2325:99:99:BulleVonToelz diff --git a/vdr.c b/vdr.c index cbc095049..bcda47114 100644 --- a/vdr.c +++ b/vdr.c @@ -22,11 +22,12 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.12 2000/04/24 13:36:39 kls Exp $ + * $Id: vdr.c 1.19 2000/05/27 15:38:35 kls Exp $ */ #include #include "config.h" +#include "dvbapi.h" #include "interface.h" #include "menu.h" #include "recording.h" @@ -52,6 +53,9 @@ int main(int argc, char *argv[]) openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); isyslog(LOG_INFO, "started"); + if (!cDvbApi::Init()) + return 1; + Channels.Load("channels.conf"); Timers.Load("timers.conf"); if (!Keys.Load(KEYS_CONF)) @@ -65,15 +69,14 @@ int main(int argc, char *argv[]) if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN); cMenuMain *Menu = NULL; - cReplayDisplay *ReplayDisplay = NULL; - cTimer *Timer = NULL; + cReplayControl *ReplayControl = NULL; int dcTime = 0, dcNumber = 0; int LastChannel = -1; while (!Interrupted) { // Channel display: if (CurrentChannel != LastChannel) { - if (!Menu && !ReplayDisplay) { + if (!Menu) { cChannel *channel = Channels.Get(CurrentChannel); if (channel) Interface.DisplayChannel(CurrentChannel + 1, channel->name); @@ -81,108 +84,80 @@ int main(int argc, char *argv[]) LastChannel = CurrentChannel; } // Direct Channel Select (action): - if (dcNumber) { - Interface.DisplayChannel(dcNumber); - if (time_ms() - dcTime > DIRECTCHANNELTIMEOUT) { - cChannel::SwitchTo(dcNumber - 1); - dcNumber = 0; - LastChannel = -1; // in case an invalid channel number was entered! - } + if (dcNumber && time_ms() - dcTime > DIRECTCHANNELTIMEOUT) { + cChannel::SwitchTo(dcNumber - 1); + dcNumber = 0; + LastChannel = -1; // in case an invalid channel number was entered! } - // Timer Processing: - else { - AssertFreeDiskSpace(); - if (!Timer && (Timer = cTimer::GetMatch()) != NULL) { - DELETENULL(Menu); - DELETENULL(ReplayDisplay); - // make sure the timer won't be deleted: - Timer->SetRecording(true); - // switch to channel: - cChannel::SwitchTo(Timer->channel - 1); - // start recording: - cRecording Recording(Timer); - DvbApi.StartRecord(Recording.FileName()); - } - if (Timer && !Timer->Matches()) { - // stop recording: - DvbApi.StopRecord(); - // release timer: - Timer->SetRecording(false); - // clear single event timer: - if (Timer->IsSingleEvent()) { - DELETENULL(Menu); // must make sure no menu uses it - isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1); - Timers.Del(Timer); - Timers.Save(); + // Timers and Recordings: + if (!Menu) { + cTimer *Timer = cTimer::GetMatch(); + if (Timer) { + if (!cRecordControls::Start(Timer)) { + //TODO need to do something to prevent the timer from hitting over and over again... } - Timer = NULL; } + cRecordControls::Process(); } // User Input: - eKeys key = Interface.GetKey(!ReplayDisplay); - if (Menu) { - switch (Menu->ProcessKey(key)) { - default: if (key != kMenu) - break; + cOsdBase **Interact = Menu ? (cOsdBase **)&Menu : (cOsdBase **)&ReplayControl; + eKeys key = Interface.GetKey(!*Interact || !(*Interact)->NeedsFastResponse()); + if (*Interact) { + switch ((*Interact)->ProcessKey(key)) { + case osMenu: DELETENULL(Menu); + Menu = new cMenuMain(ReplayControl); + break; + case osRecord: DELETENULL(Menu); + if (!cRecordControls::Start()) + Interface.Error("No free DVB device to record!"); + break; + case osReplay: DELETENULL(Menu); + DELETENULL(ReplayControl); + ReplayControl = new cReplayControl; + break; + case osStopReplay: + DELETENULL(*Interact); + DELETENULL(ReplayControl); + break; case osBack: - case osEnd: DELETENULL(Menu); - break; + case osEnd: DELETENULL(*Interact); + break; + default: ; } } - else if (!ReplayDisplay || (key = ReplayDisplay->ProcessKey(key)) != kNone) { + else { switch (key) { // Direct Channel Select (input): case k0: case k1: case k2: case k3: case k4: case k5: case k6: case k7: case k8: case k9: - { - if (!(DvbApi.Recording() || DvbApi.Replaying())) { - dcNumber = dcNumber * 10 + key - k0; - dcTime = time_ms(); + { + if (!Interface.Recording()) { + dcNumber = dcNumber * 10 + key - k0; + dcTime = time_ms(); + Interface.DisplayChannel(dcNumber); + } } - } - // Record/Replay Control: - case kBegin: DvbApi.Skip(-INT_MAX); break; - case kRecord: if (!(DvbApi.Recording() || DvbApi.Replaying())) { - cTimer *timer = new cTimer(true); - Timers.Add(timer); - Timers.Save(); - } - break; - case kPause: DvbApi.PauseReplay(); break; - case kStop: DELETENULL(ReplayDisplay); - 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: DELETENULL(ReplayDisplay); - Menu = new cMenuMain; - Menu->Display(); - break; + break; // Up/Down Channel Select: case kUp: - case kDown: if (!(DvbApi.Recording() || DvbApi.Replaying())) { + case kDown: if (!Interface.Recording()) { int n = CurrentChannel + (key == kUp ? 1 : -1); cChannel *channel = Channels.Get(n); if (channel) channel->Switch(); } break; + // Menu Control: + case kMenu: Menu = new cMenuMain(ReplayControl); break; // Viewing Control: - case kOk: if (ReplayDisplay) - DELETENULL(ReplayDisplay); - else if (DvbApi.Replaying()) - ReplayDisplay = new cReplayDisplay; - else - LastChannel = -1; break; // forces channel display + case kOk: LastChannel = -1; break; // forces channel display default: break; } } } isyslog(LOG_INFO, "caught signal %d", Interrupted); - DvbApi.StopRecord(); - DvbApi.StopReplay(); + delete Menu; + delete ReplayControl; + cDvbApi::Cleanup(); isyslog(LOG_INFO, "exiting"); closelog(); return 0; From 3b78ec8374aac8daa560fa0cd06260fca6eb1500 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 15 Jul 2000 18:00:00 +0200 Subject: [PATCH 006/307] Version 0.06 - Added support for LIRC remote control (thanks to Carsten Koch!). There are now three different remote control modes: KBD (PC-Keyboard), RCU and LIRC. See the INSTALL file for information on how to enable either of these modes. The default mode is now KBD, not RCU as before (to make it work immediately even if there is no actual remote control). --- CONTRIBUTORS | 5 + HISTORY | 9 ++ INSTALL | 30 ++++-- Makefile | 8 +- channels.conf | 6 +- config.c | 13 ++- config.h | 3 +- dvbapi.c | 6 +- dvbapi.h | 4 +- interface.c | 28 ++---- remote.c | 250 +++++++++++++++++++++++++++++++++++++++----------- remote.h | 85 +++++++++++++---- timers.conf | 14 +-- tools.c | 21 +++-- tools.h | 4 +- vdr.c | 6 +- 16 files changed, 360 insertions(+), 132 deletions(-) create mode 100644 CONTRIBUTORS diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 000000000..fbf6e8676 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,5 @@ +Thanks go to the following people for patches and contributions: + +Carsten Koch + for adding LIRC support + diff --git a/HISTORY b/HISTORY index 9767c3fe7..40150c684 100644 --- a/HISTORY +++ b/HISTORY @@ -55,3 +55,12 @@ Video Disk Recorder Revision History - Reduced the number of remote control keys. Modified the key assignments for the PC keyboard to better resemble the "up-down-left-right-ok" layout on menu controlling remote control units. + +2000-07-15: Version 0.06 + +- Added support for LIRC remote control (thanks to Carsten Koch!). + There are now three different remote control modes: KBD (PC-Keyboard), RCU + and LIRC. See the INSTALL file for information on how to enable either of + these modes. The default mode is now KBD, not RCU as before (to make it + work immediately even if there is no actual remote control). + diff --git a/INSTALL b/INSTALL index bc619d7ca..1a6442d9f 100644 --- a/INSTALL +++ b/INSTALL @@ -20,10 +20,16 @@ and type 'make'. This should produce an executable file named 'vdr', which can be run after the DVB driver has been installed. -There are two macros you can use to customize the 'vdr' program -at compile time. Adding "DEBUG_REMOTE=1" to the 'make' call -will use the PC's keyboard as input device instead of the "Remote -Control Unit" (see http://www.cadsoft.de/people/kls/vdr/remote.htm). +The 'vdr' program can be controlled via the PC keyboard or +an infrared remote control unit. Define the REMOTE macro to one of the +following values 'make' call to activate the respective control mode: + + REMOTE=KBD control via the PC keyboard (default) + REMOTE=RCU control via the "Remote Control Unit" receiver + (see http://www.cadsoft.de/people/kls/vdr/remote.htm) + REMOTE=LIRC control via the "Linux Infrared Remote Control" + (see http://fsinfo.cs.uni-sb.de/~columbus/lirc) + Adding "DEBUG_OSD=1" will use the PC screen (or current window) to display texts instead of the DVB card's on-screen display interface. These modes are useful when testing new menus if you @@ -65,7 +71,7 @@ Learning the remote control keys: --------------------------------- 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" +with 'REMOTE=RCU' 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 @@ -76,9 +82,9 @@ you define, the more you will be able to navigate through the menus and control recording/replaying. The program uses only a very small number of keys which have multiple meanings in the various modes (see MANUAL for a detailed description). -If the program has been built with "DEBUG_REMOTE=1", it will use the +If the program has been built with "REMOTE=KBD", it will use the key configuration file 'keys-pc.conf', so that you won't loose data -when switching between normal and debug mode. +when switching between remote control and keyboard mode. The default PC key assignments are: @@ -89,6 +95,12 @@ The default PC key assignments are: Red, Green, Yellow, Blue 'F1'..'F4' 0..9 '0'..'9' in top row -If you prefer different key assignments, simply delete the file -'keys-pc.conf' and restart 'vdr' to get into learning mode. +If you prefer different key assignments, or if the default doesn't work for +your keyboard, simply delete the file 'keys-pc.conf' and restart 'vdr' to get +into learning mode. + +If the program has been compiled with 'REMOTE=LIRC', no 'keys.conf' file +will be used. Instead, the key names as listed in the source file 'config.c' +must be used when setting up LIRC. See http://www2.arnes.si/~mthale1 for +more about LIRC. diff --git a/Makefile b/Makefile index 0ed17ca76..cfa7ef7f5 100644 --- a/Makefile +++ b/Makefile @@ -4,14 +4,16 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.3 2000/04/24 09:44:10 kls Exp $ +# $Id: Makefile 1.4 2000/06/24 15:09:30 kls Exp $ OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o tools.o vdr.o -ifdef DEBUG_REMOTE -DEFINES += -DDEBUG_REMOTE +ifndef REMOTE +REMOTE = KBD endif +DEFINES += -DREMOTE_$(REMOTE) + ifdef DEBUG_OSD DEFINES += -DDEBUG_OSD endif diff --git a/channels.conf b/channels.conf index 5edd778ef..d59b83bb5 100644 --- a/channels.conf +++ b/channels.conf @@ -1,5 +1,5 @@ RTL:12188:h:1:27500:163:104:0:0 -Sat.1:12552:v:1:22000:163:104:0:0 +Sat.1:12480:v:1:27500:1791:1792: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 @@ -41,8 +41,8 @@ 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 -Premiere:11798:h:1:27500:511:512:1:10 -Star Kino:11798:h:1:27500:767:768:1:9 +Premiere:11798:h:1:27500:511:512:2:10 +Star Kino:11798:h:1:27500:767:768:2:9 Cine Action:11798:h:1:27500:1023:1024:1:20 Cine Comedy:11798:h:1:27500:1279:1280:1:29 Sci Fantasy:11798:h:1:27500:1535:1536:1:41 diff --git a/config.c b/config.c index 7e02c9169..ca43ff07f 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.7 2000/05/27 14:44:15 kls Exp $ + * $Id: config.c 1.8 2000/06/24 13:43:14 kls Exp $ */ #include "config.h" @@ -146,6 +146,17 @@ eKeys cKeys::Get(unsigned int Code) return kNone; } +unsigned int cKeys::Encode(const char *Command) +{ + if (Command != NULL) { + const tKey *k = keys; + while ((k->type != kNone) && strncmp(k->name, Command, strlen(k->name)) != 0) //XXX why 'strncmp()'??? + k++; + return k->code; + } + return 0; +} + void cKeys::Set(eKeys Key, unsigned int Code) { for (tKey *k = keys; k->type != kNone; k++) { diff --git a/config.h b/config.h index 1e22b8883..22099b900 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.6 2000/05/27 14:43:46 kls Exp $ + * $Id: config.h 1.7 2000/06/24 13:42:32 kls Exp $ */ #ifndef __CONFIG_H @@ -52,6 +52,7 @@ class cKeys { void Clear(void); bool Load(char *FileName = NULL); bool Save(void); + unsigned int Encode(const char *Command); eKeys Get(unsigned int Code); void Set(eKeys Key, unsigned int Code); }; diff --git a/dvbapi.c b/dvbapi.c index e652d9971..58b2d74f1 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.10 2000/05/27 14:07:17 kls Exp $ + * $Id: dvbapi.c 1.11 2000/06/24 14:03:19 kls Exp $ */ #include "dvbapi.h" @@ -1054,7 +1054,7 @@ cDvbApi::cDvbApi(const char *FileName) if (videoDev < 0) LOG_ERROR; cols = rows = 0; -#if defined(DEBUG_OSD) || defined(DEBUG_REMOTE) +#if defined(DEBUG_OSD) || defined(REMOTE_KBD) initscr(); keypad(stdscr, TRUE); nonl(); @@ -1080,7 +1080,7 @@ cDvbApi::~cDvbApi() StopRecord(); close(videoDev); } -#if defined(DEBUG_REMOTE) || defined(DEBUG_OSD) +#if defined(DEBUG_OSD) || defined(REMOTE_KBD) endwin(); #endif delete replayTitle; diff --git a/dvbapi.h b/dvbapi.h index e0c74b075..a43ba0ee7 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.10 2000/05/20 14:50:43 kls Exp $ + * $Id: dvbapi.h 1.11 2000/06/24 14:03:57 kls Exp $ */ #ifndef __DVBAPI_H @@ -15,7 +15,7 @@ typedef unsigned int __u32; typedef unsigned short __u16; typedef unsigned char __u8; -#if defined(DEBUG_OSD) || defined(DEBUG_REMOTE) +#if defined(DEBUG_OSD) || defined(REMOTE_KBD) #include #endif #include diff --git a/interface.c b/interface.c index 82f955dc7..244488aa7 100644 --- a/interface.c +++ b/interface.c @@ -4,15 +4,19 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.9 2000/05/07 09:28:39 kls Exp $ + * $Id: interface.c 1.10 2000/07/15 12:39:20 kls Exp $ */ #include "interface.h" #include #include "remote.h" -#ifndef DEBUG_REMOTE -cRcIo RcIo("/dev/ttyS1"); +#if defined(REMOTE_RCU) +cRcIoRCU RcIo("/dev/ttyS1"); +#elif defined(REMOTE_LIRC) +cRcIoLIRC RcIo("/dev/lircd"); +#else +cRcIoKBD RcIo; #endif cInterface Interface; @@ -26,9 +30,7 @@ cInterface::cInterface(void) void cInterface::Init(void) { -#ifndef DEBUG_REMOTE RcIo.SetCode(Keys.code, Keys.address); -#endif } void cInterface::Open(int NumCols, int NumLines) @@ -47,21 +49,15 @@ void cInterface::Close(void) unsigned int cInterface::GetCh(bool Wait) { -#ifdef DEBUG_REMOTE - timeout(Wait ? 1000 :10); - int c = getch(); - return (c > 0) ? c : 0; -#else #ifdef DEBUG_OSD timeout(0); getch(); // just to make 'ncurses' display the window: #endif - if (Wait || RcIo.InputAvailable()) { + if (RcIo.InputAvailable(Wait)) { unsigned int Command; return RcIo.GetCommand(&Command, NULL) ? Command : 0; } return 0; -#endif } eKeys cInterface::GetKey(bool Wait) @@ -215,12 +211,12 @@ void cInterface::QueryKeys(void) WriteText(1, 1, "Learning Remote Control Keys"); WriteText(1, 3, "Phase 1: Detecting RC code type"); WriteText(1, 5, "Press any key on the RC unit"); -#ifndef DEBUG_REMOTE +#ifndef REMOTE_KBD unsigned char Code = 0; unsigned short Address; #endif for (;;) { -#ifdef DEBUG_REMOTE +#ifdef REMOTE_KBD if (GetCh()) break; #else @@ -318,9 +314,7 @@ void cInterface::LearnKeys(void) void cInterface::DisplayChannel(int Number, const char *Name) { -#ifndef DEBUG_REMOTE RcIo.Number(Number); -#endif if (Name && !Recording()) { Open(MenuColumns, 1); char buffer[MenuColumns + 1]; @@ -338,9 +332,7 @@ void cInterface::DisplayChannel(int Number, const char *Name) void cInterface::DisplayRecording(int Index, bool On) { -#ifndef DEBUG_REMOTE RcIo.SetPoints(1 << Index, On); -#endif } bool cInterface::Recording(void) diff --git a/remote.c b/remote.c index eb495e15e..e3786c5c4 100644 --- a/remote.c +++ b/remote.c @@ -4,7 +4,9 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.c 1.7 2000/05/07 09:28:18 kls Exp $ + * Ported to LIRC by Carsten Koch 2000-06-16. + * + * $Id: remote.c 1.9 2000/07/15 12:19:50 kls Exp $ */ #include "remote.h" @@ -15,20 +17,82 @@ #include #include #include + +#if defined REMOTE_LIRC +#include +#include +#include +#endif + +#include "config.h" #include "tools.h" #define REPEATLIMIT 100 // ms #define REPEATDELAY 250 // ms -cRcIo::cRcIo(char *DeviceName) +// --- cRcIoBase ------------------------------------------------------------- + +cRcIoBase::cRcIoBase(void) +{ + t = 0; + firstTime = lastTime = 0; + lastCommand = 0; +} + +cRcIoBase::~cRcIoBase() +{ +} + +// --- cRcIoKBD -------------------------------------------------------------- + +#if defined REMOTE_KBD + +cRcIoKBD::cRcIoKBD(void) +{ +} + +cRcIoKBD::~cRcIoKBD() +{ +} + +void cRcIoKBD::Flush(int WaitSeconds) +{ + time_t t0 = time(NULL); + + timeout(10); + for (;;) { + while (getch() > 0) + t0 = time(NULL); + if (time(NULL) - t0 >= WaitSeconds) + break; + } +} + +bool cRcIoKBD::InputAvailable(bool Wait) +{ + timeout(Wait ? 1000 : 10); + return true;//XXX +} + +bool cRcIoKBD::GetCommand(unsigned int *Command, unsigned short *) +{ + if (Command) { + *Command = getch(); + return *Command > 0; + } + return false; +} + +// --- cRcIoRCU -------------------------------------------------------------- + +#elif defined REMOTE_RCU + +cRcIoRCU::cRcIoRCU(char *DeviceName) { dp = 0; mode = modeB; code = 0; address = 0xFFFF; - t = 0; - firstTime = lastTime = 0; - lastCommand = 0; lastNumber = 0; if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) { struct termios t; @@ -46,59 +110,50 @@ cRcIo::cRcIo(char *DeviceName) f = -1; } -cRcIo::~cRcIo() +cRcIoRCU::~cRcIoRCU() { if (f >= 0) close(f); } -bool cRcIo::InputAvailable(bool Wait) -{ - if (f >= 0) { - fd_set set; - struct timeval timeout; - timeout.tv_sec = Wait ? 1 : 0; - timeout.tv_usec = Wait ? 0 : 10000; - FD_ZERO(&set); - FD_SET(f, &set); - if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) - return FD_ISSET(f, &set); - } - return false; -} - -int cRcIo::ReceiveByte(bool Wait) +int cRcIoRCU::ReceiveByte(bool Wait) { // Returns the byte if one was received within a timeout, -1 otherwise if (InputAvailable(Wait)) { unsigned char b; if (read(f, &b, 1) == 1) return b; + else + LOG_ERROR; } return -1; } -bool cRcIo::SendByteHandshake(unsigned char c) +bool cRcIoRCU::SendByteHandshake(unsigned char c) { - if (f >= 0 && write(f, &c, 1) == 1) { - for (int reply = ReceiveByte(); reply >= 0;) { - if (reply == c) - return true; - else if (reply == 'X') { - // skip any incoming RC code - it will come again - for (int i = 6; i--;) { - if (ReceiveByte(false) < 0) - return false; - } + if (f >= 0) { + int w = write(f, &c, 1); + if (w == 1) { + for (int reply = ReceiveByte(); reply >= 0;) { + if (reply == c) + return true; + else if (reply == 'X') { + // skip any incoming RC code - it will come again + for (int i = 6; i--;) { + if (ReceiveByte(false) < 0) + return false; + } + } + else + return false; } - else - return false; - } + } + LOG_ERROR; } return false; } -bool cRcIo::SendByte(unsigned char c) +bool cRcIoRCU::SendByte(unsigned char c) { for (int retry = 5; retry--;) { if (SendByteHandshake(c)) @@ -107,7 +162,20 @@ bool cRcIo::SendByte(unsigned char c) return false; } -void cRcIo::Flush(int WaitSeconds) +bool cRcIoRCU::SetCode(unsigned char Code, unsigned short Address) +{ + code = Code; + address = Address; + return SendCommand(code); +} + +bool cRcIoRCU::SetMode(unsigned char Mode) +{ + mode = Mode; + return SendCommand(mode); +} + +void cRcIoRCU::Flush(int WaitSeconds) { time_t t0 = time(NULL); @@ -119,20 +187,12 @@ void cRcIo::Flush(int WaitSeconds) } } -bool cRcIo::SetCode(unsigned char Code, unsigned short Address) +bool cRcIoRCU::InputAvailable(bool Wait) { - code = Code; - address = Address; - return SendCommand(code); + return DataAvailable(f, Wait); } -bool cRcIo::SetMode(unsigned char Mode) -{ - mode = Mode; - return SendCommand(mode); -} - -bool cRcIo::GetCommand(unsigned int *Command, unsigned short *Address) +bool cRcIoRCU::GetCommand(unsigned int *Command, unsigned short *Address) { #pragma pack(1) union { @@ -185,17 +245,17 @@ bool cRcIo::GetCommand(unsigned int *Command, unsigned short *Address) return false; } -bool cRcIo::SendCommand(unsigned char Cmd) +bool cRcIoRCU::SendCommand(unsigned char Cmd) { return SendByte(Cmd | 0x80); } -bool cRcIo::Digit(int n, int v) +bool cRcIoRCU::Digit(int n, int v) { return SendByte(((n & 0x03) << 5) | (v & 0x0F) | (((dp >> n) & 0x01) << 4)); } -bool cRcIo::Number(int n, bool Hex) +bool cRcIoRCU::Number(int n, bool Hex) { if (!Hex) { char buf[8]; @@ -216,7 +276,7 @@ bool cRcIo::Number(int n, bool Hex) return SendCommand(mode); } -bool cRcIo::String(char *s) +bool cRcIoRCU::String(char *s) { const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP "; int n = 0; @@ -233,7 +293,7 @@ bool cRcIo::String(char *s) return Number(n, true); } -void cRcIo::SetPoints(unsigned char Dp, bool On) +void cRcIoRCU::SetPoints(unsigned char Dp, bool On) { if (On) dp |= Dp; @@ -242,7 +302,7 @@ void cRcIo::SetPoints(unsigned char Dp, bool On) Number(lastNumber, true); } -bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address) +bool cRcIoRCU::DetectCode(unsigned char *Code, unsigned short *Address) { // Caller should initialize 'Code' to 0 and call DetectCode() // until it returns true. Whenever DetectCode() returns false @@ -276,3 +336,83 @@ bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address) return false; } +// --- cRcIoLIRC ------------------------------------------------------------- + +#elif defined REMOTE_LIRC + +cRcIoLIRC::cRcIoLIRC(char *DeviceName) +{ + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, DeviceName); + f = socket(AF_UNIX, SOCK_STREAM, 0); + if (f >= 0) { + if (connect(f, (struct sockaddr *)&addr, sizeof(addr)) >= 0) + return; + LOG_ERROR_STR(DeviceName); + close(f); + } + else + LOG_ERROR_STR(DeviceName); + f = -1; +} + +cRcIoLIRC::~cRcIoLIRC() +{ + if (f >= 0) + close(f); +} + +const char *cRcIoLIRC::ReceiveString(void) +{ + while (InputAvailable(true)) { + if (read(f, buf, sizeof(buf)) > 21) { + const int repeat = 10 * (buf[17] - '0') + (buf[18] - '0'); + const int now = time_ms(); + if (repeat == 0) { + firstTime = lastTime = now; + return buf + 20; + } + else if ((now > firstTime + REPEATDELAY) && (now > lastTime + REPEATLIMIT)) { + lastTime = now; + return buf + 20; + } + } + } + return NULL; +} + +void cRcIoLIRC::Flush(int WaitSeconds) +{ + time_t t0 = time(NULL); + + for (;;) { + while (InputAvailable(false)) { + read(f, buf, sizeof(buf)); + t0 = time(NULL); + } + if (time(NULL) - t0 >= WaitSeconds) + break; + } +} + +bool cRcIoLIRC::InputAvailable(bool Wait) +{ + return DataAvailable(f, Wait); +} + +bool cRcIoLIRC::GetCommand(unsigned int *Command, unsigned short *) +{ + Flush(); + if (Command) { + const char *cmd = ReceiveString(); + if (cmd) { + *Command = Keys.Encode(cmd); + return true; + } + } + return false; +} + +#endif + diff --git a/remote.h b/remote.h index 1d0a1cce0..38961b9ca 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.5 2000/05/07 09:27:54 kls Exp $ + * $Id: remote.h 1.6 2000/06/24 15:52:56 kls Exp $ */ #ifndef __REMOTE_H @@ -13,14 +13,44 @@ #include #include -class cRcIo { +class cRcIoBase { +protected: + time_t t; + int firstTime, lastTime; + unsigned int lastCommand; + cRcIoBase(void); + virtual ~cRcIoBase(); +public: + enum { modeH = 'h', modeB = 'b', modeS = 's' }; + virtual bool SetCode(unsigned char Code, unsigned short Address) { return true; } + virtual bool SetMode(unsigned char Mode) { return true; } + virtual bool Number(int n, bool Hex = false) { return true; } + virtual void SetPoints(unsigned char Dp, bool On) {} + virtual bool String(char *s) { return true; } + virtual bool DetectCode(unsigned char *Code, unsigned short *Address) { return true; } + virtual void Flush(int WaitSeconds = 0) {} + virtual bool InputAvailable(bool Wait = false) = 0; + virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL) = 0; + }; + +#if defined REMOTE_KBD + +class cRcIoKBD : public cRcIoBase { +public: + cRcIoKBD(void); + virtual ~cRcIoKBD(); + virtual void Flush(int WaitSeconds = 0); + virtual bool InputAvailable(bool Wait = false); + virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); + }; + +#elif defined REMOTE_RCU + +class cRcIoRCU : public cRcIoBase { private: int f; unsigned char dp, code, mode; unsigned short address; - time_t t; - int firstTime, lastTime; - unsigned int lastCommand; int lastNumber; bool SendCommand(unsigned char Cmd); int ReceiveByte(bool Wait = true); @@ -28,18 +58,39 @@ class cRcIo { bool SendByte(unsigned char c); bool Digit(int n, int v); public: - enum { modeH = 'h', modeB = 'b', modeS = 's' }; - cRcIo(char *DeviceName); - ~cRcIo(); - bool InputAvailable(bool Wait = false); - void Flush(int WaitSeconds = 0); - bool SetCode(unsigned char Code, unsigned short Address); - bool SetMode(unsigned char Mode); - bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); - bool Number(int n, bool Hex = false); - void SetPoints(unsigned char Dp, bool On); - bool String(char *s); - bool DetectCode(unsigned char *Code, unsigned short *Address); + cRcIoRCU(char *DeviceName); + virtual ~cRcIoRCU(); + virtual bool SetCode(unsigned char Code, unsigned short Address); + virtual bool SetMode(unsigned char Mode); + virtual bool Number(int n, bool Hex = false); + virtual void SetPoints(unsigned char Dp, bool On); + virtual bool String(char *s); + virtual bool DetectCode(unsigned char *Code, unsigned short *Address); + virtual void Flush(int WaitSeconds = 0); + virtual bool InputAvailable(bool Wait = false); + virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); + }; + +#elif defined REMOTE_LIRC + +class cRcIoLIRC : public cRcIoBase { +private: + enum { LIRC_BUFFER_SIZE = 128 }; + int f; + char buf[LIRC_BUFFER_SIZE]; + const char *ReceiveString(void); +public: + cRcIoLIRC(char *DeviceName); + virtual ~cRcIoLIRC(); + virtual void Flush(int WaitSeconds = 0); + virtual bool InputAvailable(bool Wait = false); + virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); }; +#else + +#error Please define a remote control mode! + +#endif + #endif //__REMOTE_H diff --git a/timers.conf b/timers.conf index 1f9fae0be..a5dcb9a03 100644 --- a/timers.conf +++ b/timers.conf @@ -1,10 +1,10 @@ 1:15:MTWTF--:1828:1901:10:5:nano -1:3:M------:2110:2230:99:10:SevenDays 1:10:-T-----:2058:2202:99:10:Quarks -1:3:---T---:2158:2300:99:10:Switch -1:1:----F--:2210:2325:99:10:7Tage7Koepfe +1:5:-T-----:2100:2205:99:10:RudisSuchmaschine +0:3:---T---:2211:2300:99:10:Switch 1:15:-----S-:1358:1435:99:7:Neues -1:1:-----S-:1445:1600:99:10:Hammerman -1:2:-----S-:2150:2320:99:10:Wochenshow -1:14:------S:2155:2245:99:10:AprilHailer -1:2:--W----:2110:2325:99:99:BulleVonToelz +1:1:-----S-:1445:1600:99:30:Hammerman +1:2:-----S-:2200:2350:99:30:Wochenshow +1:11:------S:2058:2120:99:10:Centauri +1:14:20:1920:2035:99:30:SamtUndSeide +1:10:---T---:2158:2250:99:99:DiePlaneten diff --git a/tools.c b/tools.c index eb0a14a4f..c0eb2ec57 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.7 2000/04/24 15:01:35 kls Exp $ + * $Id: tools.c 1.8 2000/06/24 15:26:15 kls Exp $ */ #define _GNU_SOURCE @@ -22,15 +22,18 @@ int SysLogLevel = 3; -bool DataAvailable(int filedes) +bool DataAvailable(int filedes, bool wait) { - fd_set set; - FD_ZERO(&set); - FD_SET(filedes, &set); - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 10000; - return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(filedes, &set); + if (filedes >= 0) { + fd_set set; + FD_ZERO(&set); + FD_SET(filedes, &set); + struct timeval timeout; + timeout.tv_sec = wait ? 1 : 0; + timeout.tv_usec = wait ? 0 : 10000; + return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(filedes, &set); + } + return false; } void writechar(int filedes, char c) diff --git a/tools.h b/tools.h index 57b2065db..db55983fc 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.7 2000/04/24 15:01:49 kls Exp $ + * $Id: tools.h 1.8 2000/06/24 15:25:00 kls Exp $ */ #ifndef __TOOLS_H @@ -30,7 +30,7 @@ extern int SysLogLevel; #define DELETENULL(p) (delete (p), p = NULL) -bool DataAvailable(int filedes); +bool DataAvailable(int filedes, bool wait = false); void writechar(int filedes, char c); void writeint(int filedes, int n); char readchar(int filedes); diff --git a/vdr.c b/vdr.c index bcda47114..4c1dce0ac 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.19 2000/05/27 15:38:35 kls Exp $ + * $Id: vdr.c 1.20 2000/07/15 11:45:05 kls Exp $ */ #include @@ -33,7 +33,7 @@ #include "recording.h" #include "tools.h" -#ifdef DEBUG_REMOTE +#ifdef REMOTE_KBD #define KEYS_CONF "keys-pc.conf" #else #define KEYS_CONF "keys.conf" @@ -58,8 +58,10 @@ int main(int argc, char *argv[]) Channels.Load("channels.conf"); Timers.Load("timers.conf"); +#ifndef REMOTE_LIRC if (!Keys.Load(KEYS_CONF)) Interface.LearnKeys(); +#endif Interface.Init(); cChannel::SwitchTo(CurrentChannel); From 1d22145c423f2524c7766b4ae30ee2c26174113d Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Tue, 25 Jul 2000 18:00:00 +0200 Subject: [PATCH 007/307] Version 0.6 - Added support for LIRC remote control (thanks to Carsten Koch!). There are now three different remote control modes: KBD (PC-Keyboard), RCU and LIRC. See the INSTALL file for information on how to enable either of these modes. The default mode is now KBD, not RCU as before (to make it work immediately even if there is no actual remote control). - Fixed small bug in dvbapi.c that was causing some channels (many on hotbird) not to be correctly tuned (thanks to Plamen Ganev!). - Now clearing the replay buffer in search forward/back, which results in faster reaction. - The 'Recordings' menu is now listed alphabetically (thanks to Carsten Koch!). - The new 'epg2timers' tool (thanks to Carsten Koch!) can be used to convert an EPG "merkliste" page (http://www.tvtv.de) to vdr timer entries. - The new 'xtvrc2vdr' tool (thanks to Plamen Ganev!) can be used to convert 'xtvrc' channel files into 'vdr' format. - When more than one timer matches at the same time, the first one in the list with the highest 'Priority' is selected. - The MANUAL section on "Programming the Timer" has been filled in. - The year in the "Recordings" menu as well as in the progress display during replay has been reduced to 2 digits to allow more space for the recording's title. In the internal file structure the year is still stored with 4 digits, so there will be no problem at the next turn of the century ;-) - Channel names and timer filenames can now contain blanks. To avoid problems with file names that contain blanks, all blanks in recording file names are converted to underscores. - The polarization can now be given in uppercase or lowercase characters in channels.conf. - Fixed buffer initialization to work with DVB driver version 0.6. - Implemented the "Simple Video Disk Recorder Protocol" (SVDRP) to control the VDR over a network connection. - Implemented command line option handling. - The program can now run in full background mode by using the --daemon option. - Added a "summary" field to the timers (thanks to Carsten Koch!). This field can contain a descriptive text of the programme and will be displayed when the "Blue" key is pressed on a recording that was created by this timer. If the text contains the special character '|', a newline will be inserted at that place. When pressing "Ok" on a timer that contains a summary field, the summary will be displayed. To edit such a timer the "Red" key must be pressed. Timers without a summary still go into Edit mode when pressing "Ok". The summary field can only be filled in directly by editing the 'timers.conf' file with a text editor, or by defining/modifying the timer via the SVDRP interface. --- BUGS | 6 - CONTRIBUTORS | 6 + HISTORY | 39 +- INSTALL | 11 + MANUAL | 47 +- Makefile | 9 +- TODO | 1 + Tools/epg2timers/epg2timers.cxx | 242 ++++++ Tools/xtvrc2vdr/Makefile | 16 + Tools/xtvrc2vdr/hotbird.conf | 191 +++++ Tools/xtvrc2vdr/xtvrc.hotbird | 1337 +++++++++++++++++++++++++++++++ Tools/xtvrc2vdr/xtvrc2vdr.c | 146 ++++ channels.conf | 5 +- config.c | 101 ++- config.h | 29 +- dvbapi.c | 25 +- menu.c | 92 ++- recording.c | 81 +- recording.h | 6 +- remote.c | 12 +- remote.h | 6 +- svdrp.c | 620 ++++++++++++++ svdrp.h | 52 ++ timers.conf | 19 +- tools.c | 52 +- tools.h | 6 +- vdr.c | 84 +- 27 files changed, 3138 insertions(+), 103 deletions(-) create mode 100644 Tools/epg2timers/epg2timers.cxx create mode 100644 Tools/xtvrc2vdr/Makefile create mode 100644 Tools/xtvrc2vdr/hotbird.conf create mode 100644 Tools/xtvrc2vdr/xtvrc.hotbird create mode 100644 Tools/xtvrc2vdr/xtvrc2vdr.c create mode 100644 svdrp.c create mode 100644 svdrp.h diff --git a/BUGS b/BUGS index d9e2687bc..cd96197d8 100644 --- a/BUGS +++ b/BUGS @@ -4,9 +4,3 @@ Video Disk Recorder - Known Bugs * Sometimes the picture "jumps" as if a frame is skipped. 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. - diff --git a/CONTRIBUTORS b/CONTRIBUTORS index fbf6e8676..0e2794f08 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2,4 +2,10 @@ Thanks go to the following people for patches and contributions: Carsten Koch for adding LIRC support + for making the 'Recordings' menu be listed alphabetically + for implementing the 'Summary' feature + for adding the 'epg2timers' tool (see Tools/epg2timers) +Plamen Ganev + for fixing the frequency offset for Hotbird channels + for adding the 'xtvrc2vdr' tool (see Tools/xtvrc2vdr) diff --git a/HISTORY b/HISTORY index 40150c684..765f4d1a3 100644 --- a/HISTORY +++ b/HISTORY @@ -56,11 +56,46 @@ Video Disk Recorder Revision History the PC keyboard to better resemble the "up-down-left-right-ok" layout on menu controlling remote control units. -2000-07-15: Version 0.06 +2000-07-25: Version 0.6 - Added support for LIRC remote control (thanks to Carsten Koch!). There are now three different remote control modes: KBD (PC-Keyboard), RCU and LIRC. See the INSTALL file for information on how to enable either of these modes. The default mode is now KBD, not RCU as before (to make it work immediately even if there is no actual remote control). - +- Fixed small bug in dvbapi.c that was causing some channels (many on hotbird) + not to be correctly tuned (thanks to Plamen Ganev!). +- Now clearing the replay buffer in search forward/back, which results in + faster reaction. +- The 'Recordings' menu is now listed alphabetically (thanks to Carsten Koch!). +- The new 'epg2timers' tool (thanks to Carsten Koch!) can be used to convert + an EPG "merkliste" page (http://www.tvtv.de) to vdr timer entries. +- The new 'xtvrc2vdr' tool (thanks to Plamen Ganev!) can be used to convert + 'xtvrc' channel files into 'vdr' format. +- When more than one timer matches at the same time, the first one in the list + with the highest 'Priority' is selected. +- The MANUAL section on "Programming the Timer" has been filled in. +- The year in the "Recordings" menu as well as in the progress display during + replay has been reduced to 2 digits to allow more space for the recording's + title. In the internal file structure the year is still stored with 4 digits, + so there will be no problem at the next turn of the century ;-) +- Channel names and timer filenames can now contain blanks. To avoid problems + with file names that contain blanks, all blanks in recording file names are + converted to underscores. +- The polarization can now be given in uppercase or lowercase characters in + channels.conf. +- Fixed buffer initialization to work with DVB driver version 0.6. +- Implemented the "Simple Video Disk Recorder Protocol" (SVDRP) to control + the VDR over a network connection. +- Implemented command line option handling. +- The program can now run in full background mode by using the --daemon option. +- Added a "summary" field to the timers (thanks to Carsten Koch!). + This field can contain a descriptive text of the programme and will be + displayed when the "Blue" key is pressed on a recording that was created by + this timer. If the text contains the special character '|', a newline will + be inserted at that place. When pressing "Ok" on a timer that contains a + summary field, the summary will be displayed. To edit such a timer the "Red" + key must be pressed. Timers without a summary still go into Edit mode when + pressing "Ok". The summary field can only be filled in directly by editing + the 'timers.conf' file with a text editor, or by defining/modifying the timer + via the SVDRP interface. diff --git a/INSTALL b/INSTALL index 1a6442d9f..3261ef007 100644 --- a/INSTALL +++ b/INSTALL @@ -40,6 +40,17 @@ When running, the 'vdr' program writes status information into the system log file (/var/log/messages). You may want to watch these messages (tail -f /var/log/mesages) to see if there are any problems. +The program can be controlled via a network connection to its SVDRP +port ("Simple Video Disk Recorder Protocol"). By default, it listens +on port 2001 (use the --port=PORT option to change this). For details +about the SVDRP syntax see the source file 'svdrp.c'. + +If the program shall run as a daemon, use the --daemon option. This +will completely detach it from the terminal and will continue as a +background process. + +Use "vdr --help" for a list of available command line options. + The video data directory: ------------------------- diff --git a/MANUAL b/MANUAL index cea39466e..c9b71a377 100644 --- a/MANUAL +++ b/MANUAL @@ -41,7 +41,11 @@ Video Disk Recorder User's Manual by pressing the "Right" button (which puts brackets around the current character as in "[R]TL"), selecting the desired character position with "Left" and "Right", and changing the character with the "Up" and "Down" - keys. "Ok" then confirms the changes. + keys. "Ok" then confirms the changes. The special character '^' can be used + to "cut off" a string at this position. When this character is visible in the + brackets (as in abc[^]), the next press to the "Left" or "Ok" button will + actually cut off the string. Using "Up" and/or "Down" brings back the + original rest of the string (unless you have pressed "Left" or "Ok"). The "Red", "Green", "Yellow" and "Blue" buttons have special meanings in various menus and are listed at the bottom of the on-screen-display. @@ -108,4 +112,43 @@ Video Disk Recorder User's Manual * Programming the Timer Use the "Timer" menu to maintain your list of timer controlled recordings. - + The parameters in the "Edit Timer" menu have the following meanings: + + Active: Defines whether the timer will be processed (set it to 'no' to + temporarily desable a timer). + Channel: The channel to be recorded (as defined in the "Channels" list). + Any changes made in the "Channels" list (like renaming or + reordering channels) will be automatically reflected in the + timers settings. + Day: The day on which this timer shall start. This can be either a + "day of month" (1..31), which allows programming a "single shot" + timer that hits once and is deleted after it ends. Single shot + timers can be programmed up to one month into the future. + Another option here are "repeating timers" which are defined + by listing the days of the week on which they shall record. + For example, a timer that shall record every monday and wednesday + would have a Day setting of "M-W----". + Start: The start time of the timer in hh:mm as 24 hour ("military") time. + Stop: The stop time of the timer. + Priority: The Priority (0..99) is used to decide which timer shall be + started in case there are two or more timers with the exact same + start time. The first timer in the list with the highest Priority + will be used. This value is also stored with the recording and is + later used to decide which recording to remove from disk in order + to free space for a new recording. If the disk is full and a new + recording needs more space, an existing recording with the lowest + Priority (and which has exceeded its guaranteed Lifetime) will be + removed. + Lifetime: The number of days (0..99) a recording made through this timer is + guaranteed to remain on disk before it is automatically removed + to free up space for a new recording. Note that setting this + parameter to very high values for all recordings may soon fill up + the entire disk and cause new recordings to fail due to low disk + space. + File: The name under which a recording created through this timer will + be stored on disk (the actual name will also contain the date and + time, so it is possible to have a "repeating timer" store all its + recordings under the same name; they will be distinguishable by + their date and time). + If this field is left blank, the channel name will be used to form + the name of the recording. diff --git a/Makefile b/Makefile index cfa7ef7f5..8fb678bcd 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ # -# Makefile for the On Screen Menu of the Video Disk Recorder +# Makefile for the Video Disk Recorder # # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.4 2000/06/24 15:09:30 kls Exp $ +# $Id: Makefile 1.5 2000/07/23 11:57:14 kls Exp $ -OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o tools.o vdr.o +OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o ifndef REMOTE REMOTE = KBD @@ -28,9 +28,10 @@ dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h -vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h +vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h remote.o : remote.c remote.h tools.h +svdrp.o : svdrp.c svdrp.h config.h interface.h tools.h tools.o : tools.c tools.h vdr: $(OBJS) diff --git a/TODO b/TODO index 64b31b23b..09e9a10bc 100644 --- a/TODO +++ b/TODO @@ -8,3 +8,4 @@ TODO list for the Video Disk Recorder project commercial breaks). * Implement channel scanning. * Better support for encrypted channels. +* Implement remaining commands in SVDRP. diff --git a/Tools/epg2timers/epg2timers.cxx b/Tools/epg2timers/epg2timers.cxx new file mode 100644 index 000000000..4a8f33336 --- /dev/null +++ b/Tools/epg2timers/epg2timers.cxx @@ -0,0 +1,242 @@ +/* + * epg2timers.cxx: Convert an EPG "merkliste" page (http://www.tvtv.de) to a timers.conf + * file for Klaus Schmidinger's vdr (http://www.cadsoft.de/people/kls/vdr). + * + * Copyright (C) 2000 Carsten Koch + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * The author can be reached at Carsten.Koch@icem.de + */ + + +#include +#include + + +static const char date_line[] = "\t"; +static const char start_time_line[] = " \t\t "; +static const char stop_time_line[] = "\t\t\tbis "; +static const char channel_line[] = "\t\t\t"; +static const char title_line[] = "\t\t\t\t"; +static const char summary_line[] = "\t\t\t"; +static const char * const channel_names[] = +{"RTL", "SAT1", "PRO7", "RTL2", "ARD", "BR3", "HR3", "NDR", "SWF", "WDR", "BR Alpha", "SWR BW", "Phoenix", + "ZDF", "3sat", "Kinderkanal", "ARTE", "phoenix", "ORF Sat", "ZDF.info", "CNN", "Super RTL", "VOX", "DW TV", + "Kabel1", "TM3", "DSF", "HOT", "BloombergTV", "Sky News", "KinderNet", "Alice", "n-tv", "Grand Tour.", "TW1", + "Eins Extra", "Eins Festival", "Eins MuXx", "MDR", "ORB", "B1", "ARD Online-Kanal", "Premiere World Promo", + "Premiere", "Star Kino", "Cine Action", "Cine Comedy", "Sci Fantasy", "Romantic Movies", "Studio Universal", + "TV Niepokalanow", "Mosaico", "Andalucia TV", "TVC Internacional", "Nasza TV", "WishLine test", "Pro 7 Austria", + "Kabel 1 Schweiz", "Kabel 1 Austria", "Pro 7 Schweiz", "Kiosque", "KTO", "TCM", "Cartoon Network France & Spain", + "TVBS Europe", "TVBS Europe", "Travel", "TCM Espania", "MTV Spain", "TCM France", "RTL2 CH", + "La Cinquieme", "ARTE", "Post Filial TV", "Canal Canaris", "Canal Canaris", "Canal Canaris", "Canal Canaris", + "AB Sat Passion promo", "AB Channel 1", "Taquilla 0", "CSAT", "Mosaique", "Mosaique 2", "Mosaique 3", "Le Sesame C+", + "FEED", "RTM 1", "ESC 1", "TV5 Europe", "TV7 Tunisia", "ARTE", "RAI Uno", "RTP International", + "Fashion TV", "VideoService", "Beta Research promo", "Canal Canarias", "TVC International", "Fitur", "Astra Info 1", + "Astra Info 2", "Astra Vision 1", "Astra Vision 1", "Astra Vision 1", "Astra Vision 1", "Astra Vision 1", + "Astra Vision 1", "Astra Vision 1", "RTL Tele Letzebuerg", "Astra Mosaic", "MHP test", "Bloomberg TV Spain", + "Video Italia", "AC 3 promo", "" +}; +static const int month_lengths[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +static const int max_channel = sizeof(channel_names)/sizeof(char *); +static const int max_title = 50; // maximum length of title file name generated +static const int max_line = 1024; // line buffer (not used when parsing summary text) +static const int max_summary = 5000; // Summary can be up to 5000 bytes long +static const int stop_time_safety_margin = 10; // add 10 minutes to stop time in case start was delayed + + + +char map_special_char(const char * const word) + +{ + if (strcmp(word, "auml") == 0) + return ''; + else if (strcmp(word, "ouml") == 0) + return ''; + else if (strcmp(word, "uuml") == 0) + return ''; + else if (strcmp(word, "Auml") == 0) + return ''; + else if (strcmp(word, "Ouml") == 0) + return ''; + else if (strcmp(word, "Uuml") == 0) + return ''; + else if (strcmp(word, "szlig") == 0) + return ''; + return ' '; +} + + + + + +void read_file_name(const char * const line, char * const file_name) + +{ + int line_index = sizeof(title_line) - 1; + int title_index = 0; + char ch = line[line_index++]; + do + { + if (ch == '&') + { + char word[10]; + int i = 0; + while ((line[line_index + i] != ';') && (i < 9)) + word[i++] = line[line_index + i]; + word[i] = 0; + ch = map_special_char(word); + line_index += i; + } + switch (ch) + { + case '': file_name[title_index++] = 'a'; file_name[title_index++] = 'e'; break; + case '': file_name[title_index++] = 'o'; file_name[title_index++] = 'e'; break; + case '': file_name[title_index++] = 'u'; file_name[title_index++] = 'e'; break; + case '': file_name[title_index++] = 'A'; file_name[title_index++] = 'e'; break; + case '': file_name[title_index++] = 'O'; file_name[title_index++] = 'e'; break; + case '': file_name[title_index++] = 'U'; file_name[title_index++] = 'e'; break; + case '': file_name[title_index++] = 's'; file_name[title_index++] = 's'; break; + default: + if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9'))) + file_name[title_index++] = ch; + } + ch = int(line[line_index++]); + } while ((title_index < max_title-1) && (ch != '<') && (ch != 0) && (line_index < max_line-1)); + file_name[title_index] = 0; +} + + + +void read_summary(char * const summary) + +{ + int summary_index = 0; + int ch; + bool need_space = false; + bool done = false; + do + { + ch = getchar(); + switch (ch) + { + case '&': + { + char word[10]; + int i = 0; + ch = getchar(); + while ((ch != ';') && (ch != EOF) && (i < 9)) + { + word[i++] = ch; + ch = getchar(); + } + word[i] = 0; + if (need_space) {summary[summary_index++] = ' '; need_space = false;} + summary[summary_index++] = map_special_char(word); + } + break; + case '<': + { + char word[6]; + int word_index = 0; + do + { + ch = getchar(); + word[word_index++] = ch; + } while ((word_index < 6) && (ch != '>') && (ch != EOF)); + while ((ch != '>') && (ch != EOF)) ch = getchar(); + if (strncmp("/table", word, 6) == 0) + done = true; + } + break; + default: + { + if (ch <= ' ') + { + if (summary_index > 0) need_space = true; + } + else + { + if (need_space) {summary[summary_index++] = ' '; need_space = false;} + summary[summary_index++] = ch; + } + } + } + } while ((summary_index < max_summary - 2) && (!done) && (ch != EOF)); + summary[summary_index] = 0; +} + + + + +main() + +{ + int channel = 0; + int day = -1; + int next_day = -1; + int start_time = -1; + int stop_time = -1; + char summary[max_summary] = {0}; + char file_name[max_title] = {0}; + + while (!feof(stdin)) + { + char line[max_line]; + fgets(line, max_line-1, stdin); + if (strncmp(line, date_line, sizeof(date_line)-1) == 0) + { + const int month = (line[sizeof(date_line) + 6]- '0') * 10 + line[sizeof(date_line) + 7]-'0'; + day = (line[sizeof(date_line) + 3]- '0') * 10 + line[sizeof(date_line) + 4]-'0'; + next_day = day == month_lengths[month]? 1 : day + 1; + } + else if (strncmp(line, start_time_line, sizeof(start_time_line)-1) == 0) + { + start_time = (line[sizeof(start_time_line) - 1] - '0') * 1000 + + (line[sizeof(start_time_line) ] - '0') * 100 + + (line[sizeof(start_time_line) + 2] - '0') * 10 + + (line[sizeof(start_time_line) + 3] - '0'); + } + else if (strncmp(line, stop_time_line, sizeof(stop_time_line)-1) == 0) + { + stop_time = ((line[sizeof(stop_time_line) - 1] - '0') * 1000 + + (line[sizeof(stop_time_line) ] - '0') * 100 + + (line[sizeof(stop_time_line) + 2] - '0') * 10 + + (line[sizeof(stop_time_line) + 3] - '0') + stop_time_safety_margin) % 2400; + if ((day < 0) || (start_time < 0) || (file_name[0] == 0) || (channel == max_channel)) + fprintf(stderr, "Input data error.\n"); + else + printf("1:%03d:%02d:%04d:%04d:2:7:%s:%s\n", channel+1, start_time < 600? next_day : day, start_time, stop_time, file_name, summary); + start_time = -1; stop_time = -1; file_name[0] = 0; summary[0] = 0; channel = max_channel; + } + else if (strncmp(line, title_line, sizeof(title_line)-1) == 0) + read_file_name(line, file_name); + else if (strncmp(line, channel_line, sizeof(channel_line)-1) == 0) + { + int i = sizeof(channel_line); + while ((i < max_line-1) && (line[i] != '<')) i++; + line[i] = 0; // end of string + for (channel = 0; (channel < max_channel) && + (strcmp(line + sizeof(channel_line) - 1, channel_names[channel]) != 0); + channel++); + if (channel == max_channel) + fprintf(stderr, "Error - channel '%s' not recognized.\n", line + sizeof(channel_line) - 1); + } + else if (strncmp(line, summary_line, sizeof(summary_line)-1) == 0) + read_summary(summary); + } +} diff --git a/Tools/xtvrc2vdr/Makefile b/Tools/xtvrc2vdr/Makefile new file mode 100644 index 000000000..be5054152 --- /dev/null +++ b/Tools/xtvrc2vdr/Makefile @@ -0,0 +1,16 @@ +# +# Makefile for xtvrc2vdr utility +# + +OBJS = xtvrc2vdr.o + +%.o: %.c + gcc -g -O2 -Wall -c $(DEFINES) $< + +all: xtvrc2vdr + +xtvrc2vdr: $(OBJS) + gcc -g -O2 $(OBJS) -o xtvrc2vdr + +clean: + -rm -f $(OBJS) xtvrc2vdr diff --git a/Tools/xtvrc2vdr/hotbird.conf b/Tools/xtvrc2vdr/hotbird.conf new file mode 100644 index 000000000..3431d5c4d --- /dev/null +++ b/Tools/xtvrc2vdr/hotbird.conf @@ -0,0 +1,191 @@ +TV Polonia:10719:v:1:27500:163:92:0:0 +Credit Agricole:10834:v:1:27500:5321:5333:0:0 +La Chaine Parlementaire:10873:v:1:27500:1020:1030:0:0 +TMT:10892:v:1:27500:163:92:0:0 +Multivision Accueil:10911:v:1:27500:320:330:0:0 +RTL:11054:v:1:27500:160:80:0:0 +VOX:11054:v:1:27500:500:501:0:0 +Sat 1 A:11054:v:1:27500:511:512:0:0 +RTL II Austria:11054:v:1:27500:520:521:0:0 +NBC Europe:11054:v:1:27500:550:551:0:0 +ZDF:11054:v:1:27500:570:571:0:0 +K-T9:11054:v:1:27500:580:581:0:0 +Sat 1 Schweiz:11604:v:1:27500:101:102:0:0 +MKT9:11623:v:1:27500:222:242:0:0 +Olisat TV Promo:11623:v:1:27500:226:246:0:0 +Bloomberg TV Germany:11642:v:1:27500:1460:1420:0:0 +Bloomberg TV UK:11642:v:1:27500:1560:1520:0:0 +SAT 7:11642:v:1:27500:1660:1620:0:0 +Multivision 1:11662:v:1:27500:120:130:0:0 +Dubai EDT9:11746:v:1:27500:4130:4131:0:0 +Dubai Sport Channel:11746:v:1:27500:4386:4387:0:0 +Dubai Business Channel:11746:v:1:27500:4642:4643:0:0 +Dubai EDT9:11746:v:1:27500:4898:4899:0:0 +RAI Uno:11766:v:1:27500:160:80:0:0 +RAI Due:11766:v:1:27500:161:84:0:0 +RAI Tre:11766:v:1:27500:162:88:0:0 +RAI Mosaico:11766:v:1:27500:518:8191:0:0 +RAI SportSat:11804:v:1:27500:512:650:0:0 +RAI Nettuno Sat 2:11804:v:1:27500:513:651:0:0 +RAI Educational:11804:v:1:27500:514:652:0:0 +TelePace :11804:v:1:27500:515:653:0:0 +RAI News24:11804:v:1:27500:516:654:0:0 +Camera dei Deputati:11804:v:1:27500:517:655:0:0 +SAT 2000:11804:v:1:27500:518:656:0:0 +RAI NettunoSat 1:11804:v:1:27500:519:657:0:0 +ERT Sat:11823:v:1:27500:521:740:0:0 +INT9:11843:v:1:27500:2324:2325:0:0 +TVL:11843:v:1:27500:2441:2442:0:0 +Team TV :11881:v:1:27500:2305:2306:0:0 +Ante Prima:11881:v:1:27500:2435:2436:0:0 +SNAI:11881:v:1:27500:2561:2562:0:0 +Italia 1 :11919:v:1:27500:512:650:0:0 +Canale 5:11919:v:1:27500:513:660:0:0 +Rete 4 :11919:v:1:27500:514:670:0:0 +ART Europe:12015:v:1:27500:164:96:0:0 +ESC 2:12015:v:1:27500:166:104:0:0 +ART Iqra:12015:v:1:27500:168:112:0:0 +Vetrina D+:12034:v:1:27500:166:105:0:0 +D+ Info:12073:v:1:27500:160:80:0:0 +Palco Promo:12073:v:1:27500:161:84:0:0 +Vacaciones T9:12092:v:1:27500:4112:4113:0:0 +TvL - TV Locale:12092:v:1:27500:4160:4161:0:0 +Satisfaction T9:12092:v:1:27500:4192:4193:0:0 +TVE Internacional:12092:v:1:27500:4208:4209:0:0 +TVG - TV de Galicia :12092:v:1:27500:4224:4225:0:0 +La Cadena Del Milagro:12092:v:1:27500:4368:4369:0:0 +Fiesta:12092:v:1:27500:4432:4433:0:0 +Visions Europe:12092:v:1:27500:4416:4417:0:0 +SateliTV/TV Sex Channel:12092:v:1:27500:4480:4481:0:0 +Krisma:12111:v:1:27500:200:201:0:0 +NT9:12111:v:1:27500:210:211:0:0 +Armenia TV 1:12111:v:1:27500:240:241:0:0 +SMAU Channel :12111:v:1:27500:260:261:0:0 +JSC - Al Jazeera Satellite Ch :12111:v:1:27500:270:271:0:0 +Il Tirreno Sat:12111:v:1:27500:280:301:0:0 +Coming Soon T9:12111:v:1:27500:310:311:0:0 +Alice:12149:v:1:27500:160:161:0:0 +Nuvolari Promo:12149:v:1:27500:176:177:0:0 +CCTV 4:12169:v:1:27500:516:690:0:0 +Kanali Vuolis:12169:v:1:27500:517:700:0:0 +Nova Promo:12169:v:1:27500:521:740:0:0 +ERT Sat :12188:v:1:27500:514:652:0:0 +Kanali Voulis:12188:v:1:27500:515:653:0:0 +OTE Promo:12188:v:1:27500:517:655:0:0 +TV 5 Europe:12245:v:1:27500:121:131:0:0 +Fashion T9:12245:v:1:27500:123:133:0:0 +TV Ajara:12245:v:1:27500:127:137:0:0 +Telekom T9:12265:v:1:27500:1460:1420:0:0 +SLO-TV1:12303:v:1:27500:200:201:0:0 +Polonia 1:12303:v:1:27500:205:206:0:0 +Super 1:12303:v:1:27500:207:208:0:0 +Sicilia Internacional:12303:v:1:27500:210:211:0:0 +SicilSat:12303:v:1:27500:225:226:0:0 +TBNE Italy:12303:v:1:27500:230:231:0:0 +Countdown T9:12303:v:1:27500:235:236:0:0 +Napoli International:12303:v:1:27500:240:241:0:0 +Magic T9:12303:v:1:27500:245:246:0:0 +TEST:12341:v:1:27500:165:108:0:0 +Colour Bars:12380:v:1:27500:3022:3032:0:0 +Tele 24 :12380:v:1:27500:3023:3033:0:0 +Abu Dhabi TV :12380:v:1:27500:3024:3034:0:0 +LCA:12380:v:1:27500:3025:3035:0:0 +RTV Montenegro:12380:v:1:27500:3026:3036:0:0 +SRG SSR Sat Access :12399:v:1:27500:165:98:0:0 +Jam-e-Jam Network 1 (IRIB 1):12437:v:1:27500:160:80:0:0 +Jam-e-Jam Network 2 (IRIB 2):12437:v:1:27500:161:82:0:0 +Sahar University Network:12437:v:1:27500:162:84:0:0 +Maharishi Open University:12476:v:1:27500:42:43:0:0 +Europe by Satellite:12476:v:1:27500:101:201:0:0 +Pink Backup:12476:v:1:27500:308:256:0:0 +Mizik Tropical:12476:v:1:27500:435:436:0:0 +TLI info card:12476:v:1:27500:771:768:0:0 +Liberty T9:12476:v:1:27500:941:942:0:0 +HRT TV 1:12520:v:1:27500:100:101:0:0 +HRT National:12520:v:1:27500:107:108:0:0 +BVN TV:12520:v:1:27500:210:211:0:0 +Sicilia International:12520:v:1:27500:501:502:0:0 +Sardegna Uno:12520:v:1:27500:503:504:0:0 +TGRT:12520:v:1:27500:505:506:0:0 +Euro Mediterraneo:12520:v:1:27500:510:511:0:0 +WWWTravel T9:12540:v:1:27500:1180:1183:0:0 +WWWTravel T9:12540:v:1:27500:1180:1184:0:0 +WWWTravel T9:12540:v:1:27500:1180:1185:0:0 +Bulgaria T9:12540:v:1:27500:4612:4613:0:0 +MC Sat Monte Carlo:12540:v:1:27500:5126:5122:0:0 +MBC:12597:v:1:27500:160:80:0:0 +SIMA-YEH-MOGHAVEMENT:12597:v:1:27500:161:84:0:0 +NITV (National Iran TV ):12597:v:1:27500:163:92:0:0 +BET International:12597:v:1:27500:167:108:0:0 +JSTV 2 Info Card:12597:v:1:27500:2011:2012:0:0 +EuroNews:12597:v:1:27500:2221:2231:0:0 +EuroNews:12597:v:1:27500:2221:2232:0:0 +EuroNews:12597:v:1:27500:2221:2233:0:0 +EuroNews:12597:v:1:27500:2221:2234:0:0 +EuroNews:12597:v:1:27500:2221:2235:0:0 +EuroNews:12597:v:1:27500:2221:2236:0:0 +EuroNews:12597:v:1:27500:2221:2237:0:0 +Canal Agro Rual:12597:v:1:27500:2321:2331:0:0 +MMO9:12616:v:1:27500:2561:2562:0:0 +Dubai Sport Channel:12654:v:1:27500:1060:1020:0:0 +Sharjah TV :12654:v:1:27500:1160:1120:0:0 +Qatar T9:12654:v:1:27500:1260:1220:0:0 +Saudi Channel 1 :12654:v:1:27500:1360:1320:0:0 +Kuwait Space Channel :12654:v:1:27500:1460:1420:0:0 +Libya T9:12654:v:1:27500:1560:1520:0:0 +Sudan T9:12654:v:1:27500:1660:1620:0:0 +Oman T9:12654:v:1:27500:1760:1720:0:0 +Jordan Satellite Channel:12654:v:1:27500:1860:1820:0:0 +Iraq Satellite Channel:12654:v:1:27500:1960:1920:0:0 +Thai TV 5 Global Network :12673:v:1:27500:200:201:0:0 +DigItaly:12673:v:1:27500:220:221:0:0 +Studio Europa:12673:v:1:27500:230:231:0:0 +Game Network:12673:v:1:27500:291:292:0:0 +Video Italia :12673:v:1:27500:340:341:0:0 +Telemarket:12673:v:1:27500:350:351:0:0 +Evision:12673:v:1:27500:360:361:0:0 +AB Passion:12692:v:1:27500:160:80:0:0 +Onyx T9:12692:v:1:27500:161:84:0:0 +EWTN:10723:v:1:29900:1001:1201:0:0 +Test (Newslynx):10723:v:1:29900:1002:1202:0:0 +MTA International:10723:v:1:29900:1004:1204:0:0 +J TV Test:10992:v:1:27500:2436:2437:0:0 +Bloomberg UK Test Card:11242:v:1:27500:162:88:0:0 +Channel SUN Test (KBT):11604:v:1:27500:111:112:0:0 +Racing Channel Test:11623:v:1:27500:223:243:0:0 +Test Card (pgm 4):11623:v:1:27500:224:244:0:0 +Olisat TLC test card:11623:v:1:27500:225:245:0:0 +Channel SUN Test (KBT):11623:v:1:27500:229:249:0:0 +Rai way 3 test card:11766:v:1:27500:164:96:0:0 +Rai way 1 test card:11766:v:1:27500:515:653:0:0 +Rai way 2 test card:11766:v:1:27500:516:654:0:0 +Test (Local Satellite):12092:v:1:27500:4176:4177:0:0 +Retelsat Test:12092:v:1:27500:4464:4465:0:0 +AIT Test Card:12111:v:1:27500:220:221:0:0 +Fucino Test Card:12111:v:1:27500:230:231:0:0 +Espresso(Antenna Hungaria Test Card):12149:v:1:27500:36:37:0:0 +Antenna Hungaria Test Card:12149:v:1:27500:96:97:0:0 +Antenna Hungaria Test Card:12149:v:1:27500:112:113:0:0 +Leonardo (Antenna Hungaria Test):12149:v:1:27500:128:129:0:0 +Test (Sahar):12437:v:1:27500:163:86:0:0 +Test 1:12437:v:1:27500:164:88:0:0 +Test 2:12437:v:1:27500:165:90:0:0 +CNES-Toulouse test:12558:v:1:27500:6143:6142:0:0 +Test Card:12597:v:1:27500:161:84:0:0 +FEED:11242:v:1:27500:167:108:0:0 +Feed :11623:v:1:27500:221:241:0:0 +Quantum 24 :10913:v:1:3998:1160:1120:0:0 +Quantum 24:10913:v:1:3998:1160:1220:0:0 +VIVA Polska:11131:v:1:4340:98:99:0:0 +Deutsche Welle T9:11196:v:1:9096:101:102:0:0 +Canal 24 Horas :11205:v:1:4000:4130:4131:0:0 +TV 5 Asie :11338:v:1:5632:512:640:0:0 +RAI4IFA:11548:v:1:4398:512:650:0:0 +Pro TV International:12201:v:1:5632:1160:1120:0:0 +TVN Polnoc:12211:v:1:5632:4194:4195:0:0 +WorldNet Europe:12484:v:1:8298:4260:4220:0:0 +WorldNet Europe:12484:v:1:8298:4360:4320:0:0 +WorldNet Europe:12484:v:1:8298:4460:4420:0:0 +WorldNet Europe:12484:v:1:8298:4560:4520:0:0 +TVN Polnoc:12573:v:1:5632:4194:4195:0:0 +APTN:12582:v:1:5632:308:256:0:0 diff --git a/Tools/xtvrc2vdr/xtvrc.hotbird b/Tools/xtvrc2vdr/xtvrc.hotbird new file mode 100644 index 000000000..c809eeef5 --- /dev/null +++ b/Tools/xtvrc2vdr/xtvrc.hotbird @@ -0,0 +1,1337 @@ +* +Channel: TV Polonia +Frequency: 10719 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 163 92 0 10 + +* +Channel: Credit Agricole +Frequency: 10834 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 5321 5333 0 10 + +* +Channel: La Chaine Parlementaire +Frequency: 10873 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 1020 1030 0 10 + +* +Channel: TMT +Frequency: 10892 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 163 92 0 10 + +* +Channel: Multivision Accueil +Frequency: 10911 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 320 330 0 10 + +* +Channel: RTL +Frequency: 11054 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 4 160 80 0 10 + +* +Channel: VOX +Frequency: 11054 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 4 500 501 0 10 + +* +Channel: Sat 1 A +Frequency: 11054 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 4 511 512 0 10 + +* +Channel: RTL II Austria +Frequency: 11054 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 4 520 521 0 10 + +* +Channel: NBC Europe +Frequency: 11054 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 4 550 551 0 10 + +* +Channel: ZDF +Frequency: 11054 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 4 570 571 0 10 + +* +Channel: K-T9 +Frequency: 11054 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 4 580 581 0 10 + +* +Channel: Sat 1 Schweiz +Frequency: 11604 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 4 101 102 0 10 + +* +Channel: MKT9 +Frequency: 11623 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 222 242 0 10 + +* +Channel: Olisat TV Promo +Frequency: 11623 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 226 246 0 10 + +* +Channel: Bloomberg TV Germany +Frequency: 11642 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1460 1420 0 10 + +* +Channel: Bloomberg TV UK +Frequency: 11642 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1560 1520 0 10 + +* +Channel: SAT 7 +Frequency: 11642 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1660 1620 0 10 + +* +Channel: Multivision 1 +Frequency: 11662 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 120 130 0 10 + +* +Channel: Dubai EDT9 +Frequency: 11746 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4130 4131 0 10 + +* +Channel: Dubai Sport Channel +Frequency: 11746 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4386 4387 0 10 + +* +Channel: Dubai Business Channel +Frequency: 11746 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4642 4643 0 10 + +* +Channel: Dubai EDT9 +Frequency: 11746 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4898 4899 0 10 + +* +Channel: RAI Uno +Frequency: 11766 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 160 80 0 10 + +* +Channel: RAI Due +Frequency: 11766 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 161 84 0 10 + +* +Channel: RAI Tre +Frequency: 11766 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 162 88 0 10 + +* +Channel: RAI Mosaico +Frequency: 11766 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 518 8191 0 10 + +* +Channel: RAI SportSat +Frequency: 11804 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 512 650 0 10 + +* +Channel: RAI Nettuno Sat 2 +Frequency: 11804 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 513 651 0 10 + +* +Channel: RAI Educational +Frequency: 11804 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 514 652 0 10 + +* +Channel: TelePace +Frequency: 11804 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 515 653 0 10 + +* +Channel: RAI News24 +Frequency: 11804 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 516 654 0 10 + +* +Channel: Camera dei Deputati +Frequency: 11804 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 517 655 0 10 + +* +Channel: SAT 2000 +Frequency: 11804 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 518 656 0 10 + +* +Channel: RAI NettunoSat 1 +Frequency: 11804 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 519 657 0 10 + +* +Channel: ERT Sat +Frequency: 11823 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 521 740 0 10 + +* +Channel: INT9 +Frequency: 11843 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2324 2325 0 10 + +* +Channel: TVL +Frequency: 11843 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2441 2442 0 10 + +* +Channel: Team TV +Frequency: 11881 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2305 2306 0 10 + +* +Channel: Ante Prima +Frequency: 11881 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2435 2436 0 10 + +* +Channel: SNAI +Frequency: 11881 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2561 2562 0 10 + +* +Channel: Italia 1 +Frequency: 11919 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 512 650 0 10 + +* +Channel: Canale 5 +Frequency: 11919 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 513 660 0 10 + +* +Channel: Rete 4 +Frequency: 11919 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 514 670 0 10 + +* +Channel: ART Europe +Frequency: 12015 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 164 96 0 10 + +* +Channel: ESC 2 +Frequency: 12015 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 166 104 0 10 + +* +Channel: ART Iqra +Frequency: 12015 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 168 112 0 10 + +* +Channel: Vetrina D+ +Frequency: 12034 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 166 105 0 10 + +* +Channel: D+ Info +Frequency: 12073 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 160 80 0 10 + +* +Channel: Palco Promo +Frequency: 12073 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 161 84 0 10 + +* +Channel: Vacaciones T9 +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4112 4113 0 10 + +* +Channel: TvL - TV Locale +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4160 4161 0 10 + +* +Channel: Satisfaction T9 +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4192 4193 0 10 + +* +Channel: TVE Internacional +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4208 4209 0 10 + +* +Channel: TVG - TV de Galicia +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4224 4225 0 10 + +* +Channel: La Cadena Del Milagro +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4368 4369 0 10 + +* +Channel: Fiesta +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4432 4433 0 10 + +* +Channel: Visions Europe +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4416 4417 0 10 + +* +Channel: SateliTV/TV Sex Channel +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4480 4481 0 10 + +* +Channel: Krisma +Frequency: 12111 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 200 201 0 10 + +* +Channel: NT9 +Frequency: 12111 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 210 211 0 10 + +* +Channel: Armenia TV 1 +Frequency: 12111 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 240 241 0 10 + +* +Channel: SMAU Channel +Frequency: 12111 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 260 261 0 10 + +* +Channel: JSC - Al Jazeera Satellite Ch +Frequency: 12111 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 270 271 0 10 + +* +Channel: Il Tirreno Sat +Frequency: 12111 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 280 301 0 10 + +* +Channel: Coming Soon T9 +Frequency: 12111 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 310 311 0 10 + +* +Channel: Alice +Frequency: 12149 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 160 161 0 10 + +* +Channel: Nuvolari Promo +Frequency: 12149 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 176 177 0 10 + +* +Channel: CCTV 4 +Frequency: 12169 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 516 690 0 10 + +* +Channel: Kanali Vuolis +Frequency: 12169 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 517 700 0 10 + +* +Channel: Nova Promo +Frequency: 12169 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 521 740 0 10 + +* +Channel: ERT Sat +Frequency: 12188 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 514 652 0 10 + +* +Channel: Kanali Voulis +Frequency: 12188 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 515 653 0 10 + +* +Channel: OTE Promo +Frequency: 12188 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 517 655 0 10 + +* +Channel: TV 5 Europe +Frequency: 12245 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 121 131 0 10 + +* +Channel: Fashion T9 +Frequency: 12245 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 123 133 0 10 + +* +Channel: TV Ajara +Frequency: 12245 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 127 137 0 10 + +* +Channel: Telekom T9 +Frequency: 12265 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 1460 1420 0 10 + +* +Channel: SLO-TV1 +Frequency: 12303 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 200 201 0 10 + +* +Channel: Polonia 1 +Frequency: 12303 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 205 206 0 10 + +* +Channel: Super 1 +Frequency: 12303 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 207 208 0 10 + +* +Channel: Sicilia Internacional +Frequency: 12303 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 210 211 0 10 + +* +Channel: SicilSat +Frequency: 12303 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 225 226 0 10 + +* +Channel: TBNE Italy +Frequency: 12303 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 230 231 0 10 + +* +Channel: Countdown T9 +Frequency: 12303 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 235 236 0 10 + +* +Channel: Napoli International +Frequency: 12303 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 240 241 0 10 + +* +Channel: Magic T9 +Frequency: 12303 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 245 246 0 10 + +* +Channel: TEST +Frequency: 12341 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 165 108 0 10 + +* +Channel: Colour Bars +Frequency: 12380 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 3022 3032 0 10 + +* +Channel: Tele 24 +Frequency: 12380 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 3023 3033 0 10 + +* +Channel: Abu Dhabi TV +Frequency: 12380 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 3024 3034 0 10 + +* +Channel: LCA +Frequency: 12380 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 3025 3035 0 10 + +* +Channel: RTV Montenegro +Frequency: 12380 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 3026 3036 0 10 + +* +Channel: SRG SSR Sat Access +Frequency: 12399 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 165 98 0 10 + +* +Channel: Jam-e-Jam Network 1 (IRIB 1) +Frequency: 12437 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 160 80 0 10 + +* +Channel: Jam-e-Jam Network 2 (IRIB 2) +Frequency: 12437 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 161 82 0 10 + +* +Channel: Sahar University Network +Frequency: 12437 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 162 84 0 10 + +* +Channel: Maharishi Open University +Frequency: 12476 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 42 43 0 10 + +* +Channel: Europe by Satellite +Frequency: 12476 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 101 201 0 10 + +* +Channel: Pink Backup +Frequency: 12476 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 308 256 0 10 + +* +Channel: Mizik Tropical +Frequency: 12476 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 435 436 0 10 + +* +Channel: TLI info card +Frequency: 12476 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 771 768 0 10 + +* +Channel: Liberty T9 +Frequency: 12476 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 941 942 0 10 + +* +Channel: HRT TV 1 +Frequency: 12520 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 100 101 0 10 + +* +Channel: HRT National +Frequency: 12520 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 107 108 0 10 + +* +Channel: BVN TV +Frequency: 12520 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 210 211 0 10 + +* +Channel: Sicilia International +Frequency: 12520 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 501 502 0 10 + +* +Channel: Sardegna Uno +Frequency: 12520 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 503 504 0 10 + +* +Channel: TGRT +Frequency: 12520 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 505 506 0 10 + +* +Channel: Euro Mediterraneo +Frequency: 12520 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 510 511 0 10 + +* +Channel: WWWTravel T9 +Frequency: 12540 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1180 1183 0 10 + +* +Channel: WWWTravel T9 +Frequency: 12540 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1180 1184 0 10 + +* +Channel: WWWTravel T9 +Frequency: 12540 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1180 1185 0 10 + +* +Channel: Bulgaria T9 +Frequency: 12540 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4612 4613 0 10 + +* +Channel: MC Sat Monte Carlo +Frequency: 12540 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 5126 5122 0 10 + +* +Channel: MBC +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 160 80 0 10 + +* +Channel: SIMA-YEH-MOGHAVEMENT +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 161 84 0 10 + +* +Channel: NITV (National Iran TV ) +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 163 92 0 10 + +* +Channel: BET International +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 167 108 0 10 + +* +Channel: JSTV 2 Info Card +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2011 2012 0 10 + +* +Channel: EuroNews +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2221 2231 0 10 + +* +Channel: EuroNews +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2221 2232 0 10 + +* +Channel: EuroNews +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2221 2233 0 10 + +* +Channel: EuroNews +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2221 2234 0 10 + +* +Channel: EuroNews +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2221 2235 0 10 + +* +Channel: EuroNews +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2221 2236 0 10 + +* +Channel: EuroNews +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2221 2237 0 10 + +* +Channel: Canal Agro Rual +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2321 2331 0 10 + +* +Channel: MMO9 +Frequency: 12616 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 2561 2562 0 10 + +* +Channel: Dubai Sport Channel +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1060 1020 0 10 + +* +Channel: Sharjah TV +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1160 1120 0 10 + +* +Channel: Qatar T9 +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1260 1220 0 10 + +* +Channel: Saudi Channel 1 +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1360 1320 0 10 + +* +Channel: Kuwait Space Channel +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1460 1420 0 10 + +* +Channel: Libya T9 +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1560 1520 0 10 + +* +Channel: Sudan T9 +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1660 1620 0 10 + +* +Channel: Oman T9 +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1760 1720 0 10 + +* +Channel: Jordan Satellite Channel +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1860 1820 0 10 + +* +Channel: Iraq Satellite Channel +Frequency: 12654 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 1960 1920 0 10 + +* +Channel: Thai TV 5 Global Network +Frequency: 12673 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 200 201 0 10 + +* +Channel: DigItaly +Frequency: 12673 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 220 221 0 10 + +* +Channel: Studio Europa +Frequency: 12673 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 230 231 0 10 + +* +Channel: Game Network +Frequency: 12673 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 291 292 0 10 + +* +Channel: Video Italia +Frequency: 12673 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 340 341 0 10 + +* +Channel: Telemarket +Frequency: 12673 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 350 351 0 10 + +* +Channel: Evision +Frequency: 12673 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 360 361 0 10 + +* +Channel: AB Passion +Frequency: 12692 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 160 80 0 10 + +* +Channel: Onyx T9 +Frequency: 12692 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 161 84 0 10 + +* +Channel: EWTN +Frequency: 10723 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 29900 2 1001 1201 0 10 + +* +Channel: Test (Newslynx) +Frequency: 10723 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 29900 2 1002 1202 0 10 + +* +Channel: MTA International +Frequency: 10723 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 29900 2 1004 1204 0 10 + +* +Channel: J TV Test +Frequency: 10992 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 2436 2437 0 10 + +* +Channel: Bloomberg UK Test Card +Frequency: 11242 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 162 88 0 10 + +* +Channel: Channel SUN Test (KBT) +Frequency: 11604 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 4 111 112 0 10 + +* +Channel: Racing Channel Test +Frequency: 11623 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 223 243 0 10 + +* +Channel: Test Card (pgm 4) +Frequency: 11623 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 224 244 0 10 + +* +Channel: Olisat TLC test card +Frequency: 11623 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 225 245 0 10 + +* +Channel: Channel SUN Test (KBT) +Frequency: 11623 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 229 249 0 10 + +* +Channel: Rai way 3 test card +Frequency: 11766 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 164 96 0 10 + +* +Channel: Rai way 1 test card +Frequency: 11766 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 515 653 0 10 + +* +Channel: Rai way 2 test card +Frequency: 11766 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 1 516 654 0 10 + +* +Channel: Test (Local Satellite) +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4176 4177 0 10 + +* +Channel: Retelsat Test +Frequency: 12092 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 4464 4465 0 10 + +* +Channel: AIT Test Card +Frequency: 12111 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 220 221 0 10 + +* +Channel: Fucino Test Card +Frequency: 12111 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 230 231 0 10 + +* +Channel: Espresso(Antenna Hungaria Test Card) +Frequency: 12149 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 36 37 0 10 + +* +Channel: Antenna Hungaria Test Card +Frequency: 12149 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 96 97 0 10 + +* +Channel: Antenna Hungaria Test Card +Frequency: 12149 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 112 113 0 10 + +* +Channel: Leonardo (Antenna Hungaria Test) +Frequency: 12149 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 128 129 0 10 + +* +Channel: Test (Sahar) +Frequency: 12437 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 163 86 0 10 + +* +Channel: Test 1 +Frequency: 12437 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 164 88 0 10 + +* +Channel: Test 2 +Frequency: 12437 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 27500 2 165 90 0 10 + +* +Channel: CNES-Toulouse test +Frequency: 12558 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 6143 6142 0 10 + +* +Channel: Test Card +Frequency: 12597 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 161 84 0 10 + +* +Channel: FEED +Frequency: 11242 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 167 108 0 10 + +* +Channel: Feed +Frequency: 11623 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 27500 2 221 241 0 10 + +* +Channel: Quantum 24 +Frequency: 10913 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 3998 0 1160 1120 0 10 + +* +Channel: Quantum 24 +Frequency: 10913 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 3998 0 1160 1220 0 10 + +* +Channel: VIVA Polska +Frequency: 11131 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 4340 2 98 99 0 10 + +* +Channel: Deutsche Welle T9 +Frequency: 11196 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 9096 0 101 102 0 10 + +* +Channel: Canal 24 Horas +Frequency: 11205 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 4000 2 4130 4131 0 10 + +* +Channel: TV 5 Asie +Frequency: 11338 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 5632 2 512 640 0 10 + +* +Channel: RAI4IFA +Frequency: 11548 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 4398 6 512 650 0 10 + +* +Channel: Pro TV International +Frequency: 12201 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 5632 6 1160 1120 0 10 + +* +Channel: TVN Polnoc +Frequency: 12211 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 5632 2 4194 4195 0 10 + +* +Channel: WorldNet Europe +Frequency: 12484 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 8298 2 4260 4220 0 10 + +* +Channel: WorldNet Europe +Frequency: 12484 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 8298 2 4360 4320 0 10 + +* +Channel: WorldNet Europe +Frequency: 12484 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 8298 2 4460 4420 0 10 + +* +Channel: WorldNet Europe +Frequency: 12484 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 9 8298 2 4560 4520 0 10 + +* +Channel: TVN Polnoc +Frequency: 12573 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 5632 2 4194 4195 0 10 + +* +Channel: APTN +Frequency: 12582 +CBHC: 255 0 0 255 +NI: -1 0 +SAT: 10 5632 2 308 256 0 10 + diff --git a/Tools/xtvrc2vdr/xtvrc2vdr.c b/Tools/xtvrc2vdr/xtvrc2vdr.c new file mode 100644 index 000000000..772db66a9 --- /dev/null +++ b/Tools/xtvrc2vdr/xtvrc2vdr.c @@ -0,0 +1,146 @@ +/* + * * xtvrc2vdr.c: Converts 'xtvrc' files to 'vdr' channel format + * * + * * Copyright (C) 2000 Plamen Ganev + * * + * * This program is free software; you can redistribute it and/or + * * modify it under the terms of the GNU General Public License + * * as published by the Free Software Foundation; either version 2 + * * of the License, or (at your option) any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * * + * * The author can be reached at pganev@comm.it + * * + * */ + + +#include +#include +#include +#include + +#define MAX_LINE_LEN 1024 +#define MAX_NAME 100 +#define TOKS ": \n\r" +#define NAMETOKS ":\n\r" + +typedef struct { + char Name[MAX_NAME+1]; + int freq; + int color, hue, bright, saturation ; + int nitv, input ; + int pol, srate, fec, vpid, apid, lnbnum, type; +} CHANNEL_DATA ; + +void strlwr( char *s ){ + while ( s && *s ){ + *s = tolower(*s); + s++; + } +} + +int ReadChannel( FILE *f, CHANNEL_DATA *channel ) { + static char s[MAX_LINE_LEN+1]; + char *p; + + memset( channel, sizeof( CHANNEL_DATA ), 0 ) ; + + while ((p=fgets( s, MAX_LINE_LEN, f ))!=NULL){ +// printf("%s", s ) ; + if (s[0] == '*') + break ; + } + + if ( !p ) { /* EOF? */ +// printf("EOF\n"); + return 0 ; + } + + while (fgets( s, MAX_LINE_LEN, f )){ + if ( s[0] == '\n' ) + return channel->freq ? 1 : 0; + p = strtok( s, TOKS ) ; + if ( !p ) { + return 0; + } + strlwr( p ) ; + if ( !strcmp( p, "channel" )){ + p=strtok( NULL, NAMETOKS ); + while ( p && *p==' ') + p++; + strcpy( channel->Name, p ); +// printf("%d ", channel->freq ) ; + } else if ( !strcmp( p, "frequency")) { + channel->freq = atoi( p=strtok( NULL, TOKS )); +// printf("%d ", channel->freq ) ; + } else if ( !strcmp( p, "cbhc")) { + channel->color = atoi(p=strtok(NULL,TOKS)); + channel->hue = atoi(p=strtok(NULL,TOKS)); + channel->bright = atoi(p=strtok(NULL,TOKS)); + channel->saturation = atoi(p=strtok(NULL,TOKS)); + } else if ( !strcmp( p, "ni")) { + channel->nitv = atoi(p=strtok(NULL,TOKS)); + channel->input = atoi(p=strtok(NULL,TOKS)); + } else if ( !strcmp( p, "sat")) { + channel->pol = atoi(p=strtok(NULL,TOKS)); + channel->srate = atoi(p=strtok(NULL,TOKS)); + channel->fec = atoi(p=strtok(NULL,TOKS)); + channel->vpid = atoi(p=strtok(NULL,TOKS)); + channel->apid = atoi(p=strtok(NULL,TOKS)); + channel->lnbnum = atoi(p=strtok(NULL,TOKS)); + channel->type = atoi(p=strtok(NULL,TOKS)); + } else + printf("Unknown token %s\n", p ) ; + } + return 1 ; +} + +int main ( int argc, char *argv[] ){ + FILE *f, *fo ; + int cnt = 0; + CHANNEL_DATA channel ; + + if ( argc != 3 ){ + printf("USAGE: %s \n\n", argv[0] ) ; + return 0; + } + + if ( !(f=fopen(argv[1], "rt"))){ + printf("Can't open %s for reading\n\n", argv[1]); + return 0; + } + + if ( !(fo=fopen(argv[2], "wt"))){ + printf("Can't open %s for writing\n\n", argv[2]); + return 0; + } + + while ( ReadChannel( f, &channel ) ) { + cnt++; + fprintf(fo, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", + channel.Name , + channel.freq , + channel.pol ? 'v' : 'h' , + 1, //channel.lnbnum , + channel.srate , + channel.vpid , + channel.apid , + 0, //channel.type , + 0 ); //channel.fec ) ; + } + + printf( "%d channels read.\n\n", cnt ) ; + + fclose(f); + fclose(fo); + return 1; +} diff --git a/channels.conf b/channels.conf index d59b83bb5..870a6d67d 100644 --- a/channels.conf +++ b/channels.conf @@ -31,12 +31,12 @@ 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 +Grand Tourisme: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 +MDR:12110:h:1:27500: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 @@ -113,3 +113,4 @@ 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 +Rtlneu:12188:h:1:27500:163:104:0:0 diff --git a/config.c b/config.c index ca43ff07f..6b5e04936 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.8 2000/06/24 13:43:14 kls Exp $ + * $Id: config.c 1.15 2000/07/25 16:21:20 kls Exp $ */ #include "config.h" @@ -54,7 +54,13 @@ void cKeys::Clear(void) k->code = 0; } -bool cKeys::Load(char *FileName) +void cKeys::SetDummyValues(void) +{ + for (tKey *k = keys; k->type != kNone; k++) + k->code = k->type + 1; // '+1' to avoid 0 +} + +bool cKeys::Load(const char *FileName) { isyslog(LOG_INFO, "loading %s", FileName); bool result = false; @@ -150,7 +156,7 @@ unsigned int cKeys::Encode(const char *Command) { if (Command != NULL) { const tKey *k = keys; - while ((k->type != kNone) && strncmp(k->name, Command, strlen(k->name)) != 0) //XXX why 'strncmp()'??? + while ((k->type != kNone) && strcmp(k->name, Command) != 0) k++; return k->code; } @@ -169,6 +175,8 @@ void cKeys::Set(eKeys Key, unsigned int Code) // -- cChannel --------------------------------------------------------------- +char *cChannel::buffer = NULL; + cChannel::cChannel(void) { *name = 0; @@ -187,7 +195,18 @@ cChannel::cChannel(const cChannel *Channel) pnr = Channel ? Channel->pnr : 0; } -bool cChannel::Parse(char *s) +const char *cChannel::ToText(cChannel *Channel) +{ + asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", Channel->name, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->ca, Channel->pnr); + return buffer; +} + +const char *cChannel::ToText(void) +{ + return ToText(this); +} + +bool cChannel::Parse(const char *s) { char *buffer = NULL; if (9 == sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &ca, &pnr)) { @@ -201,7 +220,7 @@ bool cChannel::Parse(char *s) bool cChannel::Save(FILE *f) { - return fprintf(f, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid, ca, pnr) > 0; + return fprintf(f, ToText()) > 0; } bool cChannel::Switch(cDvbApi *DvbApi) @@ -211,7 +230,7 @@ bool cChannel::Switch(cDvbApi *DvbApi) if (!DvbApi->Recording()) { isyslog(LOG_INFO, "switching to channel %d", Index() + 1); CurrentChannel = Index(); - for (int i = 3; --i;) { + for (int i = 3; i--;) { if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) return true; esyslog(LOG_ERR, "retrying"); @@ -236,6 +255,8 @@ const char *cChannel::GetChannelName(int i) // -- cTimer ----------------------------------------------------------------- +char *cTimer::buffer = NULL; + cTimer::cTimer(bool Instant) { startTime = stopTime = 0; @@ -253,10 +274,35 @@ cTimer::cTimer(bool Instant) priority = 99; lifetime = 99; *file = 0; + summary = NULL; if (Instant) snprintf(file, sizeof(file), "@%s", cChannel::GetChannelName(CurrentChannel)); } +cTimer::~cTimer() +{ + delete summary; +} + +cTimer& cTimer::operator= (const cTimer &Timer) +{ + memcpy(this, &Timer, sizeof(*this)); + if (summary) + summary = strdup(summary); + return *this; +} + +const char *cTimer::ToText(cTimer *Timer) +{ + asprintf(&buffer, "%d:%d:%s:%d:%d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); + return buffer; +} + +const char *cTimer::ToText(void) +{ + return ToText(this); +} + int cTimer::TimeToInt(int t) { return (t / 100 * 60 + t % 100) * 60; @@ -269,7 +315,7 @@ time_t cTimer::Day(time_t t) return mktime(&d); } -int cTimer::ParseDay(char *s) +int cTimer::ParseDay(const char *s) { char *tail; int d = strtol(s, &tail, 10); @@ -277,7 +323,7 @@ int cTimer::ParseDay(char *s) d = 0; if (tail == s) { if (strlen(s) == 7) { - for (char *p = s + 6; p >= s; p--) { + for (const char *p = s + 6; p >= s; p--) { d <<= 1; d |= (*p != '-'); } @@ -290,7 +336,7 @@ int cTimer::ParseDay(char *s) return d; } -char *cTimer::PrintDay(int d) +const char *cTimer::PrintDay(int d) { static char buffer[8]; if ((d & 0x80000000) != 0) { @@ -308,14 +354,20 @@ char *cTimer::PrintDay(int d) return buffer; } -bool cTimer::Parse(char *s) +bool cTimer::Parse(const char *s) { char *buffer1 = NULL; char *buffer2 = NULL; - if (8 == sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%as", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2)) { + delete summary; + summary = NULL; + if (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) { + //TODO add more plausibility checks day = ParseDay(buffer1); - strncpy(file, buffer2, MaxFileName - 1); - file[strlen(buffer2)] = 0; + int l = strlen(buffer2); + if (l >= MaxFileName) + l = MaxFileName - 1; + strncpy(file, buffer2, l); + file[l] = 0; delete buffer1; delete buffer2; return day != 0; @@ -325,7 +377,7 @@ bool cTimer::Parse(char *s) bool cTimer::Save(FILE *f) { - return fprintf(f, "%d:%d:%s:%d:%d:%d:%d:%s\n", active, channel, PrintDay(day), start, stop, priority, lifetime, file) > 0; + return fprintf(f, ToText()) > 0; } bool cTimer::IsSingleEvent(void) @@ -333,10 +385,11 @@ bool cTimer::IsSingleEvent(void) return (day & 0x80000000) == 0; } -bool cTimer::Matches(void) +bool cTimer::Matches(time_t t) { if (active) { - time_t t = time(NULL); + if (t == 0) + t = time(NULL); struct tm now = *localtime(&t); int weekday = now.tm_wday == 0 ? 6 : now.tm_wday - 1; // we start with monday==0! int begin = TimeToInt(start); @@ -393,13 +446,17 @@ void cTimer::SetRecording(bool Recording) cTimer *cTimer::GetMatch(void) { - cTimer *t = (cTimer *)Timers.First(); - while (t) { - if (!t->recording && t->Matches()) - return t; - t = (cTimer *)t->Next(); + time_t t = time(NULL); // all timers must be checked against the exact same time to correctly handle Priority! + cTimer *t0 = NULL; + cTimer *ti = (cTimer *)Timers.First(); + while (ti) { + if (!ti->recording && ti->Matches(t)) { + if (!t0 || ti->priority > t0->priority) + t0 = ti; + } + ti = (cTimer *)ti->Next(); } - return NULL; + return t0; } // -- cKeys ------------------------------------------------------------------ diff --git a/config.h b/config.h index 22099b900..be1c7ec70 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.7 2000/06/24 13:42:32 kls Exp $ + * $Id: config.h 1.11 2000/07/23 17:17:10 kls Exp $ */ #ifndef __CONFIG_H @@ -17,7 +17,7 @@ #include "dvbapi.h" #include "tools.h" -#define MaxBuffer 1000 +#define MaxBuffer 10000 enum eKeys { // "Up" and "Down" must be the first two keys! kUp, @@ -50,7 +50,8 @@ class cKeys { tKey *keys; cKeys(void); void Clear(void); - bool Load(char *FileName = NULL); + void SetDummyValues(void); + bool Load(const char *FileName = NULL); bool Save(void); unsigned int Encode(const char *Command); eKeys Get(unsigned int Code); @@ -58,6 +59,9 @@ class cKeys { }; class cChannel : public cListObject { +private: + static char *buffer; + static const char *ToText(cChannel *Channel); public: enum { MaxChannelName = 32 }; // 31 chars + terminating 0! char name[MaxChannelName]; @@ -71,7 +75,8 @@ class cChannel : public cListObject { int pnr; cChannel(void); cChannel(const cChannel *Channel); - bool Parse(char *s); + const char *ToText(void); + bool Parse(const char *s); bool Save(FILE *f); bool Switch(cDvbApi *DvbApi = NULL); static bool SwitchTo(int i, cDvbApi *DvbApi = NULL); @@ -81,6 +86,8 @@ class cChannel : public cListObject { class cTimer : public cListObject { private: time_t startTime, stopTime; + static char *buffer; + static const char *ToText(cTimer *Timer); public: enum { MaxFileName = 256 }; bool recording; @@ -93,19 +100,23 @@ class cTimer : public cListObject { int priority; int lifetime; char file[MaxFileName]; + char *summary; cTimer(bool Instant = false); - bool Parse(char *s); + ~cTimer(); + cTimer& operator= (const cTimer &Timer); + const char *ToText(void); + bool Parse(const char *s); bool Save(FILE *f); bool IsSingleEvent(void); - bool Matches(void); + bool Matches(time_t t = 0); time_t StartTime(void); time_t StopTime(void); void SetRecording(bool Recording); static cTimer *GetMatch(void); static int TimeToInt(int t); static time_t Day(time_t t); - static int ParseDay(char *s); - static char *PrintDay(int d); + static int ParseDay(const char *s); + static const char *PrintDay(int d); }; template class cConfig : public cList { @@ -117,7 +128,7 @@ template class cConfig : public cList { cList::Clear(); } public: - bool Load(char *FileName) + bool Load(const char *FileName) { isyslog(LOG_INFO, "loading %s", FileName); bool result = true; diff --git a/dvbapi.c b/dvbapi.c index 58b2d74f1..a9673a7ac 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.11 2000/06/24 14:03:19 kls Exp $ + * $Id: dvbapi.c 1.15 2000/07/21 13:18:02 kls Exp $ */ #include "dvbapi.h" @@ -818,8 +818,8 @@ cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName) // All recordings start with '1': fileNumber = 1; //TODO what if it doesn't start with '1'??? //XXX hack to make the video device go into 'replaying' mode: - char dummy; - write(*OutFile, &dummy, sizeof(dummy)); + char *dummy = "AV"; // must be "AV" to make the driver go into AV_PES mode! + write(*OutFile, dummy, strlen(dummy)); } cReplayBuffer::~cReplayBuffer() @@ -1327,8 +1327,8 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr struct frontend front; ioctl(videoDev, VIDIOCGFRONTEND, &front); unsigned int freq = FrequencyMHz; - front.ttk = (freq < 11800UL) ? 0 : 1; - if (freq < 11800UL) + front.ttk = (freq < 11700UL) ? 0 : 1; + if (freq < 11700UL) freq -= 9750UL; else freq -= 10600UL; @@ -1337,7 +1337,7 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr front.freq = freq * 1000000UL; front.diseqc = Diseqc; front.srate = Srate * 1000; - front.volt = (Polarization == 'v') ? 0 : 1; + front.volt = (Polarization == 'v' || Polarization == 'V') ? 0 : 1; front.video_pid = Vpid; front.audio_pid = Apid; front.fec = 8; @@ -1569,17 +1569,25 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) Buffer->Stop(); break; case dvbPauseReplay: SetReplayMode(Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); Paused = !Paused; + if (FastForward || FastRewind) { + SetReplayMode(VID_PLAY_CLEAR_BUFFER); + Buffer->Clear(); + } FastForward = FastRewind = false; Buffer->SetMode(rmPlay); break; - case dvbFastForward: SetReplayMode(VID_PLAY_NORMAL); + case dvbFastForward: SetReplayMode(VID_PLAY_CLEAR_BUFFER); + SetReplayMode(VID_PLAY_NORMAL); FastForward = !FastForward; FastRewind = Paused = false; + Buffer->Clear(); Buffer->SetMode(FastForward ? rmFastForward : rmPlay); break; - case dvbFastRewind: SetReplayMode(VID_PLAY_NORMAL); + case dvbFastRewind: SetReplayMode(VID_PLAY_CLEAR_BUFFER); + SetReplayMode(VID_PLAY_NORMAL); FastRewind = !FastRewind; FastForward = Paused = false; + Buffer->Clear(); Buffer->SetMode(FastRewind ? rmFastRewind : rmPlay); break; case dvbSkip: { @@ -1592,6 +1600,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) Buffer->SkipSeconds(Seconds); } } + break; case dvbGetIndex: { int Current, Total; Buffer->GetIndex(Current, Total); diff --git a/menu.c b/menu.c index aab5fd121..17a9b0b5c 100644 --- a/menu.c +++ b/menu.c @@ -4,10 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.16 2000/05/27 16:13:39 kls Exp $ + * $Id: menu.c 1.20 2000/07/24 16:25:53 kls Exp $ */ #include "menu.h" +#include #include #include #include @@ -16,7 +17,7 @@ #define MENUTIMEOUT 120 // seconds -const char *FileNameChars = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.# "; +const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#^"; // --- cMenuEditItem --------------------------------------------------------- @@ -429,7 +430,7 @@ void cMenuEditStrItem::Set(void) char buf[1000]; if (pos >= 0) { strncpy(buf, value, pos); - const char *s = value[pos] != ' ' ? value + pos + 1 : ""; + const char *s = value[pos] != '^' ? value + pos + 1 : ""; snprintf(buf + pos, sizeof(buf) - pos - 2, "[%c]%s", *(value + pos), s); SetValue(buf); } @@ -455,12 +456,12 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key) { switch (Key) { case kLeft: if (pos > 0) { - if (value[pos] == ' ') + if (value[pos] == '^') value[pos] = 0; pos--; } break; - case kRight: if (pos < length && value[pos] != ' ') { + case kRight: if (pos < length && value[pos] != '^' && (pos < int(strlen(value) - 1) || value[pos] != ' ')) { if (++pos >= int(strlen(value))) { value[pos] = ' '; value[pos + 1] = 0; @@ -474,7 +475,7 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key) return cMenuEditItem::ProcessKey(Key); break; case kOk: if (pos >= 0) { - if (value[pos] == ' ') + if (value[pos] == '^') value[pos] = 0; pos = -1; break; @@ -707,6 +708,51 @@ eOSState cMenuChannels::ProcessKey(eKeys Key) return state; } +// --- cMenuSummary -------------------------------------------------------- + +class cMenuSummary : public cOsdMenu { +public: + cMenuSummary(const char *Text); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuSummary::cMenuSummary(const char *Text) +:cOsdMenu("Summary") +{ + while (*Text) { + char line[MenuColumns + 1]; + char *p = line; + const char *b = NULL; + *p++ = ' '; + while (*Text && p - line < MenuColumns - 2) { + if (isspace(*Text)) + b = Text; // remember the blank + if (*Text == '\n') + break; + *p++ = *Text++; + } + if (*Text) { + if (b && Text - b > 0) { + p -= Text - b; + Text = b + 1; + } + else + Text++; + } + *p = 0; + Add(new cOsdItem(line, osBack)); + } +} + +eOSState cMenuSummary::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) + state = osContinue; + return state; +} + // --- cMenuEditTimer -------------------------------------------------------- class cMenuEditTimer : public cOsdMenu { @@ -799,6 +845,7 @@ class cMenuTimers : public cOsdMenu { eOSState New(void); eOSState Del(void); virtual void Move(int From, int To); + eOSState Summary(void); public: cMenuTimers(void); virtual eOSState ProcessKey(eKeys Key); @@ -880,6 +927,16 @@ void cMenuTimers::Move(int From, int To) isyslog(LOG_INFO, "timer %d moved to %d", From + 1, To + 1); } +eOSState cMenuTimers::Summary(void) +{ + if (HasSubMenu() || Count() == 0) + return osContinue; + cTimer *ti = Timers.Get(Current()); + if (ti && ti->summary && *ti->summary) + return AddSubMenu(new cMenuSummary(ti->summary)); + return Edit(); // convenience for people not using the Summary feature ;-) +} + eOSState cMenuTimers::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); @@ -888,7 +945,7 @@ eOSState cMenuTimers::ProcessKey(eKeys Key) switch (Key) { case kLeft: case kRight: return Activate(Key == kRight); - case kOk: + case kOk: return Summary(); case kRed: return Edit(); case kGreen: return New(); case kYellow: return Del(); @@ -926,13 +983,14 @@ class cMenuRecordings : public cOsdMenu { cRecordings Recordings; eOSState Play(void); eOSState Del(void); + eOSState Summary(void); public: cMenuRecordings(void); virtual eOSState ProcessKey(eKeys Key); }; cMenuRecordings::cMenuRecordings(void) -:cOsdMenu("Recordings", 11, 6) +:cOsdMenu("Recordings", 9, 6) { if (Recordings.Load()) { cRecording *recording = Recordings.First(); @@ -941,7 +999,7 @@ cMenuRecordings::cMenuRecordings(void) recording = Recordings.Next(recording); } } - SetHelp("Play", NULL/*XXX"Resume"*/, "Delete"); + SetHelp("Play", NULL/*XXX"Resume"*/, "Delete", "Summary"); } eOSState cMenuRecordings::Play(void) @@ -975,6 +1033,16 @@ eOSState cMenuRecordings::Del(void) return osContinue; } +eOSState cMenuRecordings::Summary(void) +{ + if (HasSubMenu() || Count() == 0) + return osContinue; + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri && ri->recording->Summary() && *ri->recording->Summary()) + return AddSubMenu(new cMenuSummary(ri->recording->Summary())); + return osContinue; +} + eOSState cMenuRecordings::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); @@ -984,6 +1052,7 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) case kOk: case kRed: return Play(); case kYellow: return Del(); + case kBlue: return Summary(); default: break; } } @@ -1061,7 +1130,8 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer->SetRecording(true); cChannel::SwitchTo(timer->channel - 1, dvbApi); cRecording Recording(timer); - dvbApi->StartRecord(Recording.FileName()); + if (dvbApi->StartRecord(Recording.FileName())) + Recording.WriteSummary(); Interface.DisplayRecording(dvbApi->Index(), true); } @@ -1116,7 +1186,7 @@ bool cRecordControls::Start(cTimer *Timer) } } else - esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch); + esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch + 1); } else esyslog(LOG_ERR, "ERROR: channel %d not defined!", ch + 1); diff --git a/recording.c b/recording.c index 2eba90b41..e37ccd85e 100644 --- a/recording.c +++ b/recording.c @@ -4,14 +4,16 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.8 2000/05/13 16:16:56 kls Exp $ + * $Id: recording.c 1.12 2000/07/24 16:31:07 kls Exp $ */ #define _GNU_SOURCE #include "recording.h" #include +#include #include #include +#include #include "interface.h" #include "tools.h" @@ -20,7 +22,9 @@ #define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT #define NAMEFORMAT "%s/%s/" DATAFORMAT -#define FINDCMD "find %s -type d -name '%s'" +#define SUMMARYFILESUFFIX "/summary.vdr" + +#define FINDCMD "find %s -type d -name '%s' | sort -df" #define DFCMD "df -m %s" #define MINDISKSPACE 1024 // MB @@ -102,21 +106,14 @@ void AssertFreeDiskSpace(void) // --- cRecording ------------------------------------------------------------ -cRecording::cRecording(const char *Name, time_t Start, int Priority, int LifeTime) -{ - titleBuffer = NULL; - fileName = NULL; - name = strdup(Name); - start = Start; - priority = Priority; - lifetime = LifeTime; -} - cRecording::cRecording(cTimer *Timer) { titleBuffer = NULL; fileName = NULL; name = strdup(Timer->file); + summary = Timer->summary ? strdup(Timer->summary) : NULL; + if (summary) + strreplace(summary, '|', '\n'); start = Timer->StartTime(); priority = Timer->priority; lifetime = Timer->lifetime; @@ -130,6 +127,7 @@ cRecording::cRecording(const char *FileName) char *p = strrchr(FileName, '/'); name = NULL; + summary = NULL; if (p) { time_t now = time(NULL); struct tm t = *localtime(&now); // this initializes the time zone in 't' @@ -141,7 +139,41 @@ cRecording::cRecording(const char *FileName) name = new char[p - FileName + 1]; strncpy(name, FileName, p - FileName); name[p - FileName] = 0; + strreplace(name, '_', ' '); } + // read an optional summary file: + char *SummaryFileName = NULL; + asprintf(&SummaryFileName, "%s%s", fileName, SUMMARYFILESUFFIX); + int f = open(SummaryFileName, O_RDONLY); + if (f >= 0) { + struct stat buf; + if (fstat(f, &buf) == 0) { + int size = buf.st_size; + summary = new char[size + 1]; // +1 for terminating 0 + if (summary) { + int rbytes = read(f, summary, size); + if (rbytes >= 0) { + summary[rbytes] = 0; + if (rbytes != size) + esyslog(LOG_ERR, "%s: expected %d bytes but read %d", SummaryFileName, size, rbytes); + } + else { + LOG_ERROR_STR(SummaryFileName); + delete summary; + summary = NULL; + } + + } + else + esyslog(LOG_ERR, "can't allocate %d byte of memory for summary file '%s'", size + 1, SummaryFileName); + close(f); + } + else + LOG_ERROR_STR(SummaryFileName); + } + else if (errno != ENOENT) + LOG_ERROR_STR(SummaryFileName); + delete SummaryFileName; } } @@ -150,6 +182,7 @@ cRecording::~cRecording() delete titleBuffer; delete fileName; delete name; + delete summary; } const char *cRecording::FileName(void) @@ -157,6 +190,8 @@ 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, priority, lifetime); + if (fileName) + strreplace(fileName, ' ', '_'); } return fileName; } @@ -166,10 +201,10 @@ const char *cRecording::Title(char Delimiter) delete titleBuffer; titleBuffer = NULL; struct tm *t = localtime(&start); - asprintf(&titleBuffer, "%02d.%02d.%04d%c%02d:%02d%c%s", + asprintf(&titleBuffer, "%02d.%02d.%02d%c%02d:%02d%c%s", t->tm_mday, t->tm_mon + 1, - t->tm_year + 1900, + t->tm_year % 100, Delimiter, t->tm_hour, t->tm_min, @@ -178,6 +213,24 @@ const char *cRecording::Title(char Delimiter) return titleBuffer; } +bool cRecording::WriteSummary(void) +{ + if (summary) { + char *SummaryFileName = NULL; + asprintf(&SummaryFileName, "%s%s", fileName, SUMMARYFILESUFFIX); + FILE *f = fopen(SummaryFileName, "w"); + if (f) { + if (fputs(summary, f) < 0) + LOG_ERROR_STR(SummaryFileName); + fclose(f); + } + else + LOG_ERROR_STR(SummaryFileName); + delete SummaryFileName; + } + return true; +} + bool cRecording::Delete(void) { bool result = true; diff --git a/recording.h b/recording.h index eeea5609f..e501af822 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.6 2000/04/24 09:45:49 kls Exp $ + * $Id: recording.h 1.7 2000/07/23 19:06:14 kls Exp $ */ #ifndef __RECORDING_H @@ -22,16 +22,18 @@ class cRecording : public cListObject { char *titleBuffer; char *fileName; char *name; + char *summary; public: time_t start; int priority; int lifetime; - cRecording(const char *Name, time_t Start, int Priority, int LifeTime); cRecording(cTimer *Timer); cRecording(const char *FileName); ~cRecording(); const char *FileName(void); const char *Title(char Delimiter = ' '); + const char *Summary(void) { return summary; } + bool WriteSummary(void); bool Delete(void); // Changes the file name so that it will no longer be visible in the "Recordings" menu // Returns false in case of error diff --git a/remote.c b/remote.c index e3786c5c4..931cfd33c 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.9 2000/07/15 12:19:50 kls Exp $ + * $Id: remote.c 1.10 2000/07/15 16:34:35 kls Exp $ */ #include "remote.h" @@ -365,17 +365,20 @@ cRcIoLIRC::~cRcIoLIRC() const char *cRcIoLIRC::ReceiveString(void) { + char buf[LIRC_BUFFER_SIZE]; + while (InputAvailable(true)) { if (read(f, buf, sizeof(buf)) > 21) { - const int repeat = 10 * (buf[17] - '0') + (buf[18] - '0'); const int now = time_ms(); + int repeat; + sscanf(buf, "%*s %x %7s", &repeat, keyName); // '7' in '%7s' is LIRC_KEY_BUF-1! if (repeat == 0) { firstTime = lastTime = now; - return buf + 20; + return keyName; } else if ((now > firstTime + REPEATDELAY) && (now > lastTime + REPEATLIMIT)) { lastTime = now; - return buf + 20; + return keyName; } } } @@ -384,6 +387,7 @@ const char *cRcIoLIRC::ReceiveString(void) void cRcIoLIRC::Flush(int WaitSeconds) { + char buf[LIRC_BUFFER_SIZE]; time_t t0 = time(NULL); for (;;) { diff --git a/remote.h b/remote.h index 38961b9ca..7b94ac782 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.6 2000/06/24 15:52:56 kls Exp $ + * $Id: remote.h 1.7 2000/07/15 16:32:43 kls Exp $ */ #ifndef __REMOTE_H @@ -75,9 +75,9 @@ class cRcIoRCU : public cRcIoBase { class cRcIoLIRC : public cRcIoBase { private: - enum { LIRC_BUFFER_SIZE = 128 }; + enum { LIRC_KEY_BUF = 8, LIRC_BUFFER_SIZE = 128 }; int f; - char buf[LIRC_BUFFER_SIZE]; + char keyName[LIRC_KEY_BUF]; const char *ReceiveString(void); public: cRcIoLIRC(char *DeviceName); diff --git a/svdrp.c b/svdrp.c new file mode 100644 index 000000000..6873d166e --- /dev/null +++ b/svdrp.c @@ -0,0 +1,620 @@ +/* + * svdrp.c: Simple Video Disk Recorder Protocol + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * The "Simple Video Disk Recorder Protocol" (SVDRP) was inspired + * by the "Simple Mail Transfer Protocol" (SMTP) and is fully ASCII + * text based. Therefore you can simply 'telnet' to your VDR port + * and interact with the Video Disk Recorder - or write a full featured + * graphical interface that sits on top of an SVDRP connection. + * + * $Id: svdrp.c 1.2 2000/07/24 16:43:51 kls Exp $ + */ + +#define _GNU_SOURCE + +#include "svdrp.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "interface.h" +#include "tools.h" + +// --- cSocket --------------------------------------------------------------- + +cSocket::cSocket(int Port, int Queue) +{ + port = Port; + sock = -1; +} + +cSocket::~cSocket() +{ + Close(); +} + +void cSocket::Close(void) +{ + if (sock >= 0) { + close(sock); + sock = -1; + } +} + +bool cSocket::Open(void) +{ + if (sock < 0) { + // create socket: + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + LOG_ERROR; + port = 0; + return false; + } + struct sockaddr_in name; + name.sin_family = AF_INET; + name.sin_port = htons(port); + name.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) { + LOG_ERROR; + Close(); + return false; + } + // make it non-blocking: + int oldflags = fcntl(sock, F_GETFL, 0); + if (oldflags < 0) { + LOG_ERROR; + return false; + } + oldflags |= O_NONBLOCK; + if (fcntl(sock, F_SETFL, oldflags) < 0) { + LOG_ERROR; + return false; + } + // listen to the socket: + if (listen(sock, queue) < 0) { + LOG_ERROR; + return false; + } + } + return true; +} + +int cSocket::Accept(void) +{ + if (Open()) { + struct sockaddr_in clientname; + uint size = sizeof(clientname); + int newsock = accept(sock, (struct sockaddr *)&clientname, &size); + if (newsock > 0) + isyslog(LOG_INFO, "connect from %s, port %hd", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port)); + else if (errno != EINTR) + LOG_ERROR; + return newsock; + } + return -1; +} + +// --- cSVDRP ---------------------------------------------------------------- + +#define MAXCMDBUFFER 10000 +#define MAXHELPTOPIC 10 + +const char *HelpPages[] = { + "CHAN [ + | - | | ]\n" + " Switch channel up, down or to the given channel number or name.\n" + " Without option (or after successfully switching to the channel)\n" + " it returns the current channel number and name.", + "DELC \n" + " Delete channel.", + "DELT \n" + " Delete timer.", + "HELP [ ]\n" + " The HELP command gives help info.", + "LSTC [ | ]\n" + " List channels. Without option, all channels are listed. Otherwise\n" + " only the given channel is listed. If a name is given, all channels\n" + " containing the given string as part of their name are listed.", + "LSTT [ ]\n" + " List timers. Without option, all timers are listed. Otherwise\n" + " only the given timer is listed.", + "MODC \n" + " Modify a channel. Settings must be in the same format as returned\n" + " by the LSTC command.", + "MODT on | off | \n" + " Modify a timer. Settings must be in the same format as returned\n" + " by the LSTT command. The special keywords 'on' and 'off' can be\n" + " used to easily activate or deactivate a timer.", + "MOVC \n" + " Move a channel to a new position.", + "MOVT \n" + " Move a timer to a new position.", + "NEWC \n" + " Create a new channel. Settings must be in the same format as returned\n" + " by the LSTC command.", + "NEWT \n" + " Create a new timer. Settings must be in the same format as returned\n" + " by the LSTT command.", + "QUIT\n" + " Exit vdr (SVDRP).\n" + " You can also hit Ctrl-D to exit.", + NULL + }; + +/* SVDRP Reply Codes: + + 214 Help message + 220 VDR service ready + 221 VDR service closing transmission channel + 250 Requested VDR action okay, completed + 451 Requested action aborted: local error in processing + 500 Syntax error, command unrecognized + 501 Syntax error in parameters or arguments + 502 Command not implemented + 504 Command parameter not implemented + 550 Requested action not taken + 554 Transaction failed + +*/ + +const char *GetHelpTopic(const char *HelpPage) +{ + static char topic[MAXHELPTOPIC]; + const char *q = HelpPage; + while (*q) { + if (isspace(*q)) { + uint n = q - HelpPage; + if (n >= sizeof(topic)) + n = sizeof(topic) - 1; + strncpy(topic, HelpPage, n); + topic[n] = 0; + return topic; + } + q++; + } + return NULL; +} + +const char *GetHelpPage(const char *Cmd) +{ + const char **p = HelpPages; + while (*p) { + const char *t = GetHelpTopic(*p); + if (strcasecmp(Cmd, t) == 0) + return *p; + p++; + } + return NULL; +} + +cSVDRP::cSVDRP(int Port) +:socket(Port) +{ + filedes = -1; + isyslog(LOG_INFO, "SVDRP listening on port %d", Port); +} + +cSVDRP::~cSVDRP() +{ + Close(); +} + +void cSVDRP::Close(void) +{ + if (filedes >= 0) { + //TODO how can we get the *full* hostname? + char buffer[MAXCMDBUFFER]; + gethostname(buffer, sizeof(buffer)); + Reply(221, "%s closing connection", buffer); + isyslog(LOG_INFO, "closing connection"); //TODO store IP#??? + close(filedes); + filedes = -1; + } +} + +bool cSVDRP::Send(const char *s, int length) +{ + if (length < 0) + length = strlen(s); + int wbytes = write(filedes, s, length); + if (wbytes == length) + return true; + if (wbytes < 0) + LOG_ERROR; + else //XXX while...??? + esyslog(LOG_ERR, "Wrote %d bytes to client while expecting %d\n", wbytes, length); + return false; +} + +void cSVDRP::Reply(int Code, const char *fmt, ...) +{ + if (filedes >= 0) { + if (Code != 0) { + va_list ap; + va_start(ap, fmt); + char *buffer; + vasprintf(&buffer, fmt, ap); + char *nl = strchr(buffer, '\n'); + if (Code > 0 && nl && *(nl + 1)) // trailing newlines don't count! + Code = -Code; + char number[16]; + sprintf(number, "%03d%c", abs(Code), Code < 0 ? '-' : ' '); + const char *s = buffer; + while (s && *s) { + const char *n = strchr(s, '\n'); + if (!(Send(number) && Send(s, n ? n - s : -1) && Send("\r\n"))) { + Close(); + break; + } + s = n ? n + 1 : NULL; + } + delete buffer; + va_end(ap); + } + else { + Reply(451, "Zero return code - looks like a programming error!"); + esyslog(LOG_ERR, "SVDRP: zero return code!"); + } + } +} + +void cSVDRP::CmdChan(const char *Option) +{ + if (*Option) { + int n = -1; + if (isnumber(Option)) { + int o = strtol(Option, NULL, 10) - 1; + if (o >= 0 && o < Channels.Count()) + n = o; + } + else if (strcmp(Option, "-") == 0) { + n = CurrentChannel; + if (CurrentChannel > 0) + n--; + } + else if (strcmp(Option, "+") == 0) { + n = CurrentChannel; + if (CurrentChannel < Channels.Count() - 1) + n++; + } + else { + int i = 0; + cChannel *channel; + while ((channel = Channels.Get(i)) != NULL) { + if (strcasecmp(channel->name, Option) == 0) { + n = i; + break; + } + i++; + } + } + if (n < 0) { + Reply(501, "Undefined channel \"%s\"", Option); + return; + } + if (Interface.Recording()) { + Reply(550, "Can't switch channel, interface is recording"); + return; + } + cChannel *channel = Channels.Get(n); + if (channel) { + if (!channel->Switch()) { + Reply(554, "Error switching to channel \"%d\"", channel->Index() + 1); + return; + } + } + else { + Reply(550, "Unable to find channel \"%s\"", Option); + return; + } + } + cChannel *channel = Channels.Get(CurrentChannel); + if (channel) + Reply(250, "%d %s", CurrentChannel + 1, channel->name); + else + Reply(550, "Unable to find channel \"%d\"", CurrentChannel); +} + +void cSVDRP::CmdDelc(const char *Option) +{ + //TODO combine this with menu action (timers must be updated) + Reply(502, "DELC not yet implemented"); +} + +void cSVDRP::CmdDelt(const char *Option) +{ + if (*Option) { + if (isnumber(Option)) { + cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1); + if (timer) { + if (!timer->recording) { + Timers.Del(timer); + Timers.Save(); + isyslog(LOG_INFO, "timer %s deleted", Option); + Reply(250, "Timer \"%s\" deleted", Option); + } + else + Reply(550, "Timer \"%s\" is recording", Option); + } + else + Reply(501, "Timer \"%s\" not defined", Option); + } + else + Reply(501, "Error in timer number \"%s\"", Option); + } + else + Reply(501, "Missing timer number"); +} + +void cSVDRP::CmdHelp(const char *Option) +{ + if (*Option) { + const char *hp = GetHelpPage(Option); + if (hp) + Reply(214, hp); + else { + Reply(504, "HELP topic \"%s\" unknown", Option); + return; + } + } + else { + Reply(-214, "This is VDR version 0.6"); //XXX dynamically insert version number + Reply(-214, "Topics:"); + const char **hp = HelpPages; + while (*hp) { + //TODO multi-column??? + const char *topic = GetHelpTopic(*hp); + if (topic) + Reply(-214, " %s", topic); + hp++; + } + Reply(-214, "To report bugs in the implementation send email to"); + Reply(-214, " vdr-bugs@cadsoft.de"); + } + Reply(214, "End of HELP info"); +} + +void cSVDRP::CmdLstc(const char *Option) +{ + if (*Option) { + if (isnumber(Option)) { + cChannel *channel = Channels.Get(strtol(Option, NULL, 10) - 1); + if (channel) + Reply(250, "%d %s", channel->Index() + 1, channel->ToText()); + else + Reply(501, "Channel \"%s\" not defined", Option); + } + else { + int i = 0; + cChannel *next = NULL; + while (i < Channels.Count()) { + cChannel *channel = Channels.Get(i); + if (channel) { + if (strcasestr(channel->name, Option)) { + if (next) + Reply(-250, "%d %s", next->Index() + 1, next->ToText()); + next = channel; + } + } + else { + Reply(501, "Channel \"%d\" not found", i + 1); + return; + } + i++; + } + if (next) + Reply(250, "%d %s", next->Index() + 1, next->ToText()); + } + } + else { + for (int i = 0; i < Channels.Count(); i++) { + cChannel *channel = Channels.Get(i); + if (channel) + Reply(i < Channels.Count() - 1 ? -250 : 250, "%d %s", channel->Index() + 1, channel->ToText()); + else + Reply(501, "Channel \"%d\" not found", i + 1); + } + } +} + +void cSVDRP::CmdLstt(const char *Option) +{ + if (*Option) { + if (isnumber(Option)) { + cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1); + if (timer) + Reply(250, "%d %s", timer->Index() + 1, timer->ToText()); + else + Reply(501, "Timer \"%s\" not defined", Option); + } + else + Reply(501, "Error in timer number \"%s\"", Option); + } + else { + for (int i = 0; i < Timers.Count(); i++) { + cTimer *timer = Timers.Get(i); + if (timer) + Reply(i < Timers.Count() - 1 ? -250 : 250, "%d %s", timer->Index() + 1, timer->ToText()); + else + Reply(501, "Timer \"%d\" not found", i + 1); + } + } +} + +void cSVDRP::CmdModc(const char *Option) +{ + if (*Option) { + char *tail; + int n = strtol(Option, &tail, 10); + if (tail && tail != Option) { + tail = skipspace(tail); + cChannel *channel = Channels.Get(n - 1); + if (channel) { + cChannel c = *channel; + if (!c.Parse(tail)) { + Reply(501, "Error in channel settings"); + return; + } + *channel = c; + Channels.Save(); + isyslog(LOG_INFO, "channel %d modified", channel->Index() + 1); + Reply(250, "%d %s", channel->Index() + 1, channel->ToText()); + } + else + Reply(501, "Channel \"%d\" not defined", n); + } + else + Reply(501, "Error in channel number"); + } + else + Reply(501, "Missing channel settings"); +} + +void cSVDRP::CmdModt(const char *Option) +{ + if (*Option) { + char *tail; + int n = strtol(Option, &tail, 10); + if (tail && tail != Option) { + tail = skipspace(tail); + cTimer *timer = Timers.Get(n - 1); + if (timer) { + cTimer t = *timer; + if (strcasecmp(tail, "ON") == 0) + t.active = 1; + else if (strcasecmp(tail, "OFF") == 0) + t.active = 0; + else if (!t.Parse(tail)) { + Reply(501, "Error in timer settings"); + return; + } + *timer = t; + Timers.Save(); + isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); + Reply(250, "%d %s", timer->Index() + 1, timer->ToText()); + } + else + Reply(501, "Timer \"%d\" not defined", n); + } + else + Reply(501, "Error in timer number"); + } + else + Reply(501, "Missing timer settings"); +} + +void cSVDRP::CmdMovc(const char *Option) +{ + //TODO combine this with menu action (timers must be updated) + Reply(502, "MOVC not yet implemented"); +} + +void cSVDRP::CmdMovt(const char *Option) +{ + //TODO combine this with menu action + Reply(502, "MOVT not yet implemented"); +} + +void cSVDRP::CmdNewc(const char *Option) +{ + if (*Option) { + cChannel *channel = new cChannel; + if (channel->Parse(Option)) { + Channels.Add(channel); + Channels.Save(); + isyslog(LOG_INFO, "channel %d added", channel->Index() + 1); + Reply(250, "%d %s", channel->Index() + 1, channel->ToText()); + } + else + Reply(501, "Error in channel settings"); + } + else + Reply(501, "Missing channel settings"); +} + +void cSVDRP::CmdNewt(const char *Option) +{ + if (*Option) { + cTimer *timer = new cTimer; + if (timer->Parse(Option)) { + Timers.Add(timer); + Timers.Save(); + isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + Reply(250, "%d %s", timer->Index() + 1, timer->ToText()); + } + else + Reply(501, "Error in timer settings"); + } + else + Reply(501, "Missing timer settings"); +} + +#define CMD(c) (strcasecmp(Cmd, c) == 0) + +void cSVDRP::Execute(char *Cmd) +{ + // skip leading whitespace: + Cmd = skipspace(Cmd); + // find the end of the command word: + char *s = Cmd; + while (*s && !isspace(*s)) + s++; + *s++ = 0; + if (CMD("CHAN")) CmdChan(s); + else if (CMD("DELC")) CmdDelc(s); + else if (CMD("DELT")) CmdDelt(s); + else if (CMD("HELP")) CmdHelp(s); + else if (CMD("LSTC")) CmdLstc(s); + else if (CMD("LSTT")) CmdLstt(s); + else if (CMD("MODC")) CmdModc(s); + else if (CMD("MODT")) CmdModt(s); + else if (CMD("MOVC")) CmdMovc(s); + else if (CMD("MOVT")) CmdMovt(s); + else if (CMD("NEWC")) CmdNewc(s); + else if (CMD("NEWT")) CmdNewt(s); + else if (CMD("QUIT") + || CMD("\x04")) Close(); + else Reply(500, "Command unrecognized: \"%s\"", Cmd); +} + +void cSVDRP::Process(void) +{ + bool SendGreeting = filedes < 0; + + if (filedes >= 0 || (filedes = socket.Accept()) >= 0) { + char buffer[MAXCMDBUFFER]; + if (SendGreeting) { + //TODO how can we get the *full* hostname? + gethostname(buffer, sizeof(buffer)); + time_t now = time(NULL); + Reply(220, "%s SVDRP VideoDiskRecorder 0.6; %s", buffer, ctime(&now));//XXX dynamically insert version number + } + int rbytes = readstring(filedes, buffer, sizeof(buffer) - 1); + if (rbytes > 0) { + //XXX overflow check??? + // strip trailing whitespace: + while (rbytes > 0 && strchr(" \t\r\n", buffer[rbytes - 1])) + buffer[--rbytes] = 0; + // make sure the string is terminated: + buffer[rbytes] = 0; + // showtime! + Execute(buffer); + } + else if (rbytes < 0) + Close(); + } +} + +//TODO timeout??? +//TODO more than one connection??? diff --git a/svdrp.h b/svdrp.h new file mode 100644 index 000000000..c63854240 --- /dev/null +++ b/svdrp.h @@ -0,0 +1,52 @@ +/* + * svdrp.h: Simple Video Disk Recorder Protocol + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: svdrp.h 1.1 2000/07/23 14:49:30 kls Exp $ + */ + +#ifndef __SVDRP_H +#define __SVDRP_H + +class cSocket { +private: + int port; + int sock; + int queue; + void Close(void); +public: + cSocket(int Port, int Queue = 1); + ~cSocket(); + bool Open(void); + int Accept(void); + }; + +class cSVDRP { +private: + cSocket socket; + int filedes; + void Close(void); + bool Send(const char *s, int length = -1); + void Reply(int Code, const char *fmt, ...); + void CmdChan(const char *Option); + void CmdDelc(const char *Option); + void CmdDelt(const char *Option); + void CmdHelp(const char *Option); + void CmdLstc(const char *Option); + void CmdLstt(const char *Option); + void CmdModc(const char *Option); + void CmdModt(const char *Option); + void CmdMovc(const char *Option); + void CmdMovt(const char *Option); + void CmdNewc(const char *Option); + void CmdNewt(const char *Option); + void Execute(char *Cmd); +public: + cSVDRP(int Port); + ~cSVDRP(); + void Process(void); + }; + +#endif //__SVDRP_H diff --git a/timers.conf b/timers.conf index a5dcb9a03..659faaaff 100644 --- a/timers.conf +++ b/timers.conf @@ -1,10 +1,9 @@ -1:15:MTWTF--:1828:1901:10:5:nano -1:10:-T-----:2058:2202:99:10:Quarks -1:5:-T-----:2100:2205:99:10:RudisSuchmaschine -0:3:---T---:2211:2300:99:10:Switch -1:15:-----S-:1358:1435:99:7:Neues -1:1:-----S-:1445:1600:99:30:Hammerman -1:2:-----S-:2200:2350:99:30:Wochenshow -1:11:------S:2058:2120:99:10:Centauri -1:14:20:1920:2035:99:30:SamtUndSeide -1:10:---T---:2158:2250:99:99:DiePlaneten +1:10:-T-----:2058:2202:99:10:Quarks: +1:5:-T-----:2100:2205:99:10:RudisSuchmaschine: +1:10:---T---:2158:2250:99:99:DiePlaneten: +1:3:---T---:2211:2300:99:10:Switch: +1:15:-----S-:1358:1435:99:7:Neues: +1:1:-----S-:1445:1600:99:30:Hammerman: +0:2:-----S-:2200:2350:99:30:Wochenshow: +1:11:------S:2058:2120:99:10:Centauri: +0:15:MTWTF--:1828:1901:10:5:nano: diff --git a/tools.c b/tools.c index c0eb2ec57..998d91b3a 100644 --- a/tools.c +++ b/tools.c @@ -4,11 +4,12 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.8 2000/06/24 15:26:15 kls Exp $ + * $Id: tools.c 1.10 2000/07/23 13:16:54 kls Exp $ */ #define _GNU_SOURCE #include "tools.h" +#include #include #include #include @@ -58,6 +59,26 @@ bool readint(int filedes, int &n) return DataAvailable(filedes) && read(filedes, &n, sizeof(n)) == sizeof(n); } +int readstring(int filedes, char *buffer, int size, bool wait = false) +{ + int rbytes = 0; + + while (DataAvailable(filedes, wait)) { + int n = read(filedes, buffer + rbytes, size - rbytes); + if (n == 0) + break; // EOF + if (n < 0) { + LOG_ERROR; + break; + } + rbytes += n; + if (rbytes == size) + break; + wait = false; + } + return rbytes; +} + void purge(int filedes) { while (DataAvailable(filedes)) @@ -76,6 +97,25 @@ char *readline(FILE *f) return NULL; } +char *strreplace(char *s, char c1, char c2) +{ + char *p = s; + + while (*p) { + if (*p == c1) + *p = c2; + p++; + } + return s; +} + +char *skipspace(char *s) +{ + while (*s && isspace(*s)) + s++; + return s; +} + int time_ms(void) { static time_t t0 = 0; @@ -95,6 +135,16 @@ void delay_ms(int ms) ; } +bool isnumber(const char *s) +{ + while (*s) { + if (!isdigit(*s)) + return false; + s++; + } + return true; +} + bool MakeDirs(const char *FileName, bool IsDirectory) { bool result = true; diff --git a/tools.h b/tools.h index db55983fc..ecf42be62 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.8 2000/06/24 15:25:00 kls Exp $ + * $Id: tools.h 1.10 2000/07/23 13:16:37 kls Exp $ */ #ifndef __TOOLS_H @@ -35,10 +35,14 @@ void writechar(int filedes, char c); void writeint(int filedes, int n); char readchar(int filedes); bool readint(int filedes, int &n); +int readstring(int filedes, char *buffer, int size, bool wait = false); void purge(int filedes); char *readline(FILE *f); +char *strreplace(char *s, char c1, char c2); +char *skipspace(char *s); int time_ms(void); void delay_ms(int ms); +bool isnumber(const char *s); bool MakeDirs(const char *FileName, bool IsDirectory = false); bool RemoveFileOrDir(const char *FileName); bool CheckProcess(pid_t pid); diff --git a/vdr.c b/vdr.c index 4c1dce0ac..626e6dc04 100644 --- a/vdr.c +++ b/vdr.c @@ -22,15 +22,19 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.20 2000/07/15 11:45:05 kls Exp $ + * $Id: vdr.c 1.23 2000/07/23 15:36:43 kls Exp $ */ +#include #include +#include +#include #include "config.h" #include "dvbapi.h" #include "interface.h" #include "menu.h" #include "recording.h" +#include "svdrp.h" #include "tools.h" #ifdef REMOTE_KBD @@ -50,15 +54,83 @@ void SignalHandler(int signum) int main(int argc, char *argv[]) { + // Command line options: + +#define DEFAULTSVDRPPORT 2001 + + int SVDRPport = DEFAULTSVDRPPORT; + bool DaemonMode = false; + + static struct option long_options[] = { + { "daemon", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "port", required_argument, NULL, 'p' }, + { 0 } + }; + + int c; + int option_index = 0; + while ((c = getopt_long(argc, argv, "dhp:", long_options, &option_index)) != -1) { + switch (c) { + case 'd': DaemonMode = true; break; + case 'h': printf("Usage: vdr [OPTION]\n\n" + " -h, --help display this help and exit\n" + " -d, --daemon run in daemon mode\n" + " -p PORT, --port=PORT use PORT for SVDRP ('0' turns off SVDRP)\n" + "\n" + "Report bugs to \n" + ); + return 0; + break; + case 'p': if (isnumber(optarg)) + SVDRPport = strtol(optarg, NULL, 10); + else { + fprintf(stderr, "vdr: invalid port number: %s\n", optarg); + return 1; + } + break; + default: abort(); + } + } + + // Log file: + openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); + + // Daemon mode: + + if (DaemonMode) { +#ifndef DEBUG_OSD + pid_t pid = fork(); + if (pid < 0) { + fprintf(stderr, "%s\n", strerror(errno)); + esyslog(LOG_ERR, strerror(errno)); + return 1; + } + if (pid != 0) + return 0; // initial program immediately returns + fclose(stdin); + fclose(stdout); + fclose(stderr); +#else + fprintf(stderr, "vdr: can't run in daemon mode with DEBUG_OSD on!\n"); + abort(); +#endif + } isyslog(LOG_INFO, "started"); + // DVB interfaces: + if (!cDvbApi::Init()) return 1; + // Configuration data: + Channels.Load("channels.conf"); Timers.Load("timers.conf"); -#ifndef REMOTE_LIRC +#ifdef REMOTE_LIRC + Keys.SetDummyValues(); +#else if (!Keys.Load(KEYS_CONF)) Interface.LearnKeys(); #endif @@ -66,10 +138,15 @@ int main(int argc, char *argv[]) cChannel::SwitchTo(CurrentChannel); + // Signal handlers: + 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); + // Main program loop: + + cSVDRP *SVDRP = SVDRPport ? new cSVDRP(SVDRPport) : NULL; cMenuMain *Menu = NULL; cReplayControl *ReplayControl = NULL; int dcTime = 0, dcNumber = 0; @@ -155,10 +232,13 @@ int main(int argc, char *argv[]) default: break; } } + if (SVDRP) + SVDRP->Process();//TODO lock menu vs. SVDRP? } isyslog(LOG_INFO, "caught signal %d", Interrupted); delete Menu; delete ReplayControl; + delete SVDRP; cDvbApi::Cleanup(); isyslog(LOG_INFO, "exiting"); closelog(); From 9b405778674d5325b225b32ab694d9216b099527 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 6 Aug 2000 18:00:00 +0200 Subject: [PATCH 008/307] Version 0.61 - When scrolling through a list it now moves a full page up or down when the cursor reaches the top or bottom of the menu (thanks to Heino Goldenstein!). - Added missing '#include ' to recording.c. - The video directory can now be defined with the command line option -v. - There can now be more than one video directory (in case you have several disks). - Fixed learning key codes for PC keyboard. - New command line option '-l' to set the log level. - Times in timers.conf are now always printed with 4 digits (leading '0'). - Slow forward/back mode (thanks to Guido Fiala!). - The "Up" key in replay mode no longer restarts replay at the very beginning, but rather resumes normal replay mode after a "pause", "forward" or "backward" operation. Use the "Skip -60s" function repeatedly to go back to the beginning of the recording. - Improved reaction on user input in fast/slow forward/back modes. - No more upper limit for the value of 'Pnr'. - Checking if the video card is really a DVB card. - New SVDRP command UPDT to update an existing timer (or add a new one if it doesn't yet exist). - New version of the 'epg2timers' tool (with a modified channel list). - Bugfix in closing window in DEBUG_OSD mode. --- CONTRIBUTORS | 7 + HISTORY | 24 +++ INSTALL | 40 ++++- MANUAL | 11 +- Makefile | 11 +- Tools/epg2timers/epg2timers.cxx | 56 +++++-- channels.conf | 1 - config.c | 15 +- config.h | 10 +- dvbapi.c | 256 +++++++++++++++++++------------- dvbapi.h | 19 ++- menu.c | 16 +- osd.c | 22 ++- recording.c | 49 ++---- recording.h | 2 +- remote.c | 8 +- svdrp.c | 53 ++++++- svdrp.h | 3 +- timers.conf | 12 +- tools.c | 77 +++++++++- tools.h | 6 +- vdr.c | 59 ++++++-- videodir.c | 182 +++++++++++++++++++++++ videodir.h | 21 +++ 24 files changed, 727 insertions(+), 233 deletions(-) create mode 100644 videodir.c create mode 100644 videodir.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 0e2794f08..74390cf90 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -5,7 +5,14 @@ Carsten Koch for making the 'Recordings' menu be listed alphabetically for implementing the 'Summary' feature for adding the 'epg2timers' tool (see Tools/epg2timers) + for his idea of using multiple disks (and for testing this feature) Plamen Ganev for fixing the frequency offset for Hotbird channels for adding the 'xtvrc2vdr' tool (see Tools/xtvrc2vdr) + +Heino Goldenstein + for modifying scrolling through lists to make it page up and down + +Guido Fiala + for implementing slow forward/back diff --git a/HISTORY b/HISTORY index 765f4d1a3..04cc2d59c 100644 --- a/HISTORY +++ b/HISTORY @@ -99,3 +99,27 @@ Video Disk Recorder Revision History pressing "Ok". The summary field can only be filled in directly by editing the 'timers.conf' file with a text editor, or by defining/modifying the timer via the SVDRP interface. + +2000-08-06: Version 0.61 + +- When scrolling through a list it now moves a full page up or down when the + cursor reaches the top or bottom of the menu (thanks to Heino Goldenstein!). +- Added missing '#include ' to recording.c. +- The video directory can now be defined with the command line option -v. +- There can now be more than one video directory (in case you have several + disks). +- Fixed learning key codes for PC keyboard. +- New command line option '-l' to set the log level. +- Times in timers.conf are now always printed with 4 digits (leading '0'). +- Slow forward/back mode (thanks to Guido Fiala!). +- The "Up" key in replay mode no longer restarts replay at the very beginning, + but rather resumes normal replay mode after a "pause", "forward" or "backward" + operation. Use the "Skip -60s" function repeatedly to go back to the beginning + of the recording. +- Improved reaction on user input in fast/slow forward/back modes. +- No more upper limit for the value of 'Pnr'. +- Checking if the video card is really a DVB card. +- New SVDRP command UPDT to update an existing timer (or add a new one if it + doesn't yet exist). +- New version of the 'epg2timers' tool (with a modified channel list). +- Bugfix in closing window in DEBUG_OSD mode. diff --git a/INSTALL b/INSTALL index 3261ef007..938487c31 100644 --- a/INSTALL +++ b/INSTALL @@ -49,6 +49,9 @@ If the program shall run as a daemon, use the --daemon option. This will completely detach it from the terminal and will continue as a background process. +Command line options: +--------------------- + Use "vdr --help" for a list of available command line options. The video data directory: @@ -57,14 +60,41 @@ The video data directory: All recordings are written into directories below "/video". Please make sure this directory exists, and that the user who runs the 'vdr' program has read and write access to that directory. -If you prefer a different location for your video files, you can change -the value of 'BaseDir' in recording.c. +If you prefer a different location for your video files, you can use +the '-v' option to change that. Note that the file system need not be 64-bit proof, since the 'vdr' program splits video files into chunks of about 1GB. You should use a disk with several gigabytes of free space. One GB can store roughly half an hour of video data. +If you have more than one disk and don't want to combine them to form +one large logical volume, you can set up several video directories as +mount points for these disks. All of these directories must have the +same basic name and must end with a numeric part, which starts at 0 for +the main directory and has increasing values for the rest of the +directories. For example + + /video0 + /video1 + /video2 + +would be a setup with three directories. You can use more than one +numeric digit, and the directories need not be directly under '/': + + /mnt/MyVideos/vdr.00 + /mnt/MyVideos/vdr.01 + /mnt/MyVideos/vdr.02 + ... + /mnt/MyVideos/vdr.11 + +would set up twelve disks (wow, what a machine that would be!). + +To use such a multi directory setup, you need to add the '-v' option +with the name of the basic directory when running 'vdr': + + vdr -v /video0 + Configuration files: -------------------- @@ -78,6 +108,12 @@ 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. +The files that come with this package contain the author's selections, +so please make sure you adapt these to your personal taste. Also make sure +that the channels defined in 'channels.conf' are correct before attempting +to record anything. Channel parameters may vary and not all of the channels +listed in the default 'channels.conf' file have been verified by the author. + Learning the remote control keys: --------------------------------- diff --git a/MANUAL b/MANUAL index c9b71a377..b05c35088 100644 --- a/MANUAL +++ b/MANUAL @@ -10,7 +10,7 @@ Video Disk Recorder User's Manual Key Normal Main Channels Timer Edit/New Recordings Replay - Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Begin + Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause Left - - - Disable Decrement - Search back Right - - - Enable Increment - Search forward @@ -93,15 +93,16 @@ Video Disk Recorder User's Manual The following keys have the listed meaning in Replay mode: - - Up Positions to beginning of the recording and starts playback - from there. + - Up Resumes normal replay from any "pause", "forward" or "backward" + mode. - Down Halts playback at the current position. Press again to continue playback. - Blue Stops playback and stores the current position, so that playback can be resumed later at that point. - Left - Right Runs playback forward or backward at a higher speed. Press - again to resume normal speed. + Right Runs playback forward or backward at a higher speed; press + again to resume normal speed. If in Pause mode, runs forward or + backward at a slower speed; press again to return to pause mode. - Green Yellow Skips about 60 seconds back or forward. - Ok Brings up the replay progress display, which shows the date, diff --git a/Makefile b/Makefile index 8fb678bcd..f71236b78 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,9 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.5 2000/07/23 11:57:14 kls Exp $ +# $Id: Makefile 1.6 2000/07/28 14:37:44 kls Exp $ -OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o +OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o videodir.o ifndef REMOTE REMOTE = KBD @@ -24,15 +24,16 @@ endif all: vdr config.o : config.c config.h dvbapi.h interface.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h +dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h videodir.h interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h -vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h -recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h +vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h +recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h videodir.h remote.o : remote.c remote.h tools.h svdrp.o : svdrp.c svdrp.h config.h interface.h tools.h tools.o : tools.c tools.h +videodir.o : videodir.c tools.h videodir.h vdr: $(OBJS) g++ -g -O2 $(OBJS) -lncurses -o vdr diff --git a/Tools/epg2timers/epg2timers.cxx b/Tools/epg2timers/epg2timers.cxx index 4a8f33336..07e8182d7 100644 --- a/Tools/epg2timers/epg2timers.cxx +++ b/Tools/epg2timers/epg2timers.cxx @@ -34,21 +34,46 @@ static const char channel_line[] = "\t\t\t
"; static const char summary_line[] = "\t\t\t"; static const char * const channel_names[] = -{"RTL", "SAT1", "PRO7", "RTL2", "ARD", "BR3", "HR3", "NDR", "SWF", "WDR", "BR Alpha", "SWR BW", "Phoenix", - "ZDF", "3sat", "Kinderkanal", "ARTE", "phoenix", "ORF Sat", "ZDF.info", "CNN", "Super RTL", "VOX", "DW TV", - "Kabel1", "TM3", "DSF", "HOT", "BloombergTV", "Sky News", "KinderNet", "Alice", "n-tv", "Grand Tour.", "TW1", - "Eins Extra", "Eins Festival", "Eins MuXx", "MDR", "ORB", "B1", "ARD Online-Kanal", "Premiere World Promo", - "Premiere", "Star Kino", "Cine Action", "Cine Comedy", "Sci Fantasy", "Romantic Movies", "Studio Universal", - "TV Niepokalanow", "Mosaico", "Andalucia TV", "TVC Internacional", "Nasza TV", "WishLine test", "Pro 7 Austria", - "Kabel 1 Schweiz", "Kabel 1 Austria", "Pro 7 Schweiz", "Kiosque", "KTO", "TCM", "Cartoon Network France & Spain", - "TVBS Europe", "TVBS Europe", "Travel", "TCM Espania", "MTV Spain", "TCM France", "RTL2 CH", - "La Cinquieme", "ARTE", "Post Filial TV", "Canal Canaris", "Canal Canaris", "Canal Canaris", "Canal Canaris", - "AB Sat Passion promo", "AB Channel 1", "Taquilla 0", "CSAT", "Mosaique", "Mosaique 2", "Mosaique 3", "Le Sesame C+", - "FEED", "RTM 1", "ESC 1", "TV5 Europe", "TV7 Tunisia", "ARTE", "RAI Uno", "RTP International", - "Fashion TV", "VideoService", "Beta Research promo", "Canal Canarias", "TVC International", "Fitur", "Astra Info 1", - "Astra Info 2", "Astra Vision 1", "Astra Vision 1", "Astra Vision 1", "Astra Vision 1", "Astra Vision 1", - "Astra Vision 1", "Astra Vision 1", "RTL Tele Letzebuerg", "Astra Mosaic", "MHP test", "Bloomberg TV Spain", - "Video Italia", "AC 3 promo", "" +{ +"3sat", +"ARTE", +"*B1 Berlin", +"BR3", +"Bloomberg TV", +"BR Alpha", +"CNN", +"ARD", +"*DW-tv", +"Eins Extra", +"Eins Festival", +"Eins MuXx", +"euroNEWS", +"HR3", +"Kabel1", +"Kinderkanal", +"MDR", +"MTV", +"NDR", +"NTV", +"ORB", +"*ORF1", +"Phoenix", +"PRO7", +"RTL", +"RTL2", +"SAT1", +"skynews", +"SWF", +"Super RTL", +"TM3", +"TW1", +"VOX", +"WDR", +"Theaterkanal", +"ZDF", +"ZDF.doku", +"ZDF.info", +"" }; static const int month_lengths[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; @@ -240,3 +265,4 @@ main() read_summary(summary); } } + diff --git a/channels.conf b/channels.conf index 870a6d67d..eefaf52da 100644 --- a/channels.conf +++ b/channels.conf @@ -113,4 +113,3 @@ 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 -Rtlneu:12188:h:1:27500:163:104:0:0 diff --git a/config.c b/config.c index 6b5e04936..c144d6c02 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.15 2000/07/25 16:21:20 kls Exp $ + * $Id: config.c 1.17 2000/08/06 12:27:38 kls Exp $ */ #include "config.h" @@ -294,7 +294,7 @@ cTimer& cTimer::operator= (const cTimer &Timer) const char *cTimer::ToText(cTimer *Timer) { - asprintf(&buffer, "%d:%d:%s:%d:%d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); + asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); return buffer; } @@ -473,3 +473,14 @@ cChannels Channels; cTimers Timers; +cTimer *cTimers::GetTimer(cTimer *Timer) +{ + cTimer *ti = (cTimer *)First(); + while (ti) { + if (ti->channel == Timer->channel && ti->day == Timer->day && ti->start == Timer->start && ti->stop == Timer->stop) + return ti; + ti = (cTimer *)ti->Next(); + } + return NULL; +} + diff --git a/config.h b/config.h index be1c7ec70..1b21d3417 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.11 2000/07/23 17:17:10 kls Exp $ + * $Id: config.h 1.14 2000/08/06 12:22:52 kls Exp $ */ #ifndef __CONFIG_H @@ -17,6 +17,8 @@ #include "dvbapi.h" #include "tools.h" +#define VDRVERSION "0.61" + #define MaxBuffer 10000 enum eKeys { // "Up" and "Down" must be the first two keys! @@ -181,7 +183,11 @@ template class cConfig : public cList { }; class cChannels : public cConfig {}; -class cTimers : public cConfig {}; + +class cTimers : public cConfig { +public: + cTimer *GetTimer(cTimer *Timer); + }; extern int CurrentChannel; diff --git a/dvbapi.c b/dvbapi.c index a9673a7ac..0562a4f58 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.15 2000/07/21 13:18:02 kls Exp $ + * $Id: dvbapi.c 1.22 2000/08/06 14:06:14 kls Exp $ */ #include "dvbapi.h" @@ -17,6 +17,7 @@ #include #include "interface.h" #include "tools.h" +#include "videodir.h" #define VIDEODEVICE "/dev/video" @@ -50,9 +51,12 @@ // 'signed'), so let's use 1GB for absolute safety (the actual file size // may be slightly higher because we stop recording only before the next // 'I' frame, to have a complete Group Of Pictures): -#define MAXVIDEOFILESIZE (1024*1024*1024) +#define MAXVIDEOFILESIZE (1024*1024*1024) // Byte #define MAXFILESPERRECORDING 255 +#define MINFREEDISKSPACE (512) // MB +#define DISKCHECKINTERVAL 100 // seconds + #define INDEXFILESUFFIX "/index.vdr" #define RESUMEFILESUFFIX "/resume.vdr" #define RECORDFILESUFFIX "/%03d.vdr" @@ -341,9 +345,8 @@ class cRingBuffer { int Free(void) { return ((tail >= head) ? size + head - tail : head - tail) - 1; } int Available(void) { return (tail >= head) ? tail - head : size - head + tail; } int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap! - int Writeable(void) { return (tail > head) ? tail - head : size - head; } + int Writeable(void) { return (tail >= head) ? tail - head : size - head; } int Byte(int Offset); - bool WaitForOutFile(int Timeout); public: cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); virtual ~cRingBuffer(); @@ -404,22 +407,6 @@ void cRingBuffer::Skip(int n) } } -bool cRingBuffer::WaitForOutFile(int Timeout) -{ - fd_set set; - FD_ZERO(&set); - FD_SET(*outFile, &set); - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = Timeout; - if (select(FD_SETSIZE, NULL, &set, NULL, &timeout) > 0) { - if (FD_ISSET(*outFile, &set)) - return true; - } - esyslog(LOG_ERR, "ERROR: timeout in WaitForOutFile(%d)", Timeout); - return false; -} - int cRingBuffer::Read(int Max) { if (buffer) { @@ -598,6 +585,8 @@ class cRecordBuffer : public cFileBuffer { int recordFile; uchar tagAudio, tagVideo; bool ok, synced; + time_t lastDiskSpaceCheck; + bool RunningLowOnDiskSpace(void); int Synchronize(void); bool NextFile(void); virtual int Write(int Max = -1); @@ -615,6 +604,7 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) recordFile = -1; tagAudio = tagVideo = 0; ok = synced = false; + lastDiskSpaceCheck = time(NULL); if (!fileName) return;//XXX find a better way??? // Find the highest existing file suffix: @@ -636,7 +626,20 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) cRecordBuffer::~cRecordBuffer() { if (recordFile >= 0) - close(recordFile); + CloseVideoFile(recordFile); +} + +bool cRecordBuffer::RunningLowOnDiskSpace(void) +{ + if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) { + uint Free = FreeDiskSpaceMB(fileName); + lastDiskSpaceCheck = time(NULL); + if (Free < MINFREEDISKSPACE) { + dsyslog(LOG_INFO, "low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE); + return true; + } + } + return false; } int cRecordBuffer::Synchronize(void) @@ -714,20 +717,22 @@ int cRecordBuffer::Synchronize(void) bool cRecordBuffer::NextFile(void) { - if (recordFile >= 0 && fileSize > MAXVIDEOFILESIZE && pictureType == I_FRAME) { - if (close(recordFile) < 0) - LOG_ERROR; - // don't return 'false', maybe we can still record into the next file - recordFile = -1; - fileNumber++; - if (fileNumber == 0) - esyslog(LOG_ERR, "ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); - fileSize = 0; + if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME + if (fileSize > MAXVIDEOFILESIZE || RunningLowOnDiskSpace()) { + if (CloseVideoFile(recordFile) < 0) + LOG_ERROR; + // don't return 'false', maybe we can still record into the next file + recordFile = -1; + fileNumber++; + if (fileNumber == 0) + esyslog(LOG_ERR, "ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); + fileSize = 0; + } } if (recordFile < 0) { sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); dsyslog(LOG_INFO, "recording to '%s'", fileName); - recordFile = open(fileName, O_RDWR | O_CREAT | O_NONBLOCK, S_IRUSR | S_IWUSR); + recordFile = OpenVideoFile(fileName, O_RDWR | O_CREAT | O_NONBLOCK); if (recordFile < 0) { LOG_ERROR; return false; @@ -781,7 +786,7 @@ int cRecordBuffer::WriteWithTimeout(bool EndIfEmpty) // --- cReplayBuffer --------------------------------------------------------- -enum eReplayMode { rmPlay, rmFastForward, rmFastRewind }; +enum eReplayMode { rmPlay, rmFastForward, rmFastRewind, rmSlowRewind }; class cReplayBuffer : public cFileBuffer { private: @@ -790,6 +795,7 @@ class cReplayBuffer : public cFileBuffer { eReplayMode mode; bool skipAudio; int lastIndex; + int brakeCounter; void SkipAudioBlocks(void); bool NextFile(uchar FileNumber = 0, int FileOffset = -1); void Close(void); @@ -811,6 +817,7 @@ cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName) fileOffset = 0; replayFile = -1; mode = rmPlay; + brakeCounter = 0; skipAudio = false; lastIndex = -1; if (!fileName) @@ -841,6 +848,7 @@ void cReplayBuffer::SetMode(eReplayMode Mode) { mode = Mode; skipAudio = Mode != rmPlay; + brakeCounter = 0; if (mode != rmPlay) Clear(); } @@ -974,6 +982,10 @@ int cReplayBuffer::Read(int Max = -1) if (Index >= 0) { uchar FileNumber; int FileOffset, Length; + if (mode == rmSlowRewind && (brakeCounter++ % 24) != 0) { + // show every I_FRAME 24 times in rmSlowRewind mode to achieve roughly the same speed as in slow forward mode + Index = index->GetNextIFrame(Index, true, &FileNumber, &FileOffset, &Length); // jump ahead one frame + } Index = index->GetNextIFrame(Index, mode == rmFastForward, &FileNumber, &FileOffset, &Length); if (Index >= 0) { if (!NextFile(FileNumber, FileOffset)) @@ -1014,28 +1026,27 @@ int cReplayBuffer::Read(int Max = -1) int cReplayBuffer::Write(int Max) { int Written = 0; - - do { - if (skipAudio) { - SkipAudioBlocks(); - Max = GetAvPesLength(); - } - while (Max) { - int w = cFileBuffer::Write(Max); - if (w >= 0) { - fileOffset += w; - Written += w; - if (Max < 0) - break; - Max -= w; - } - else - return w; - //XXX??? Why does the buffer get empty here??? - if (Empty() || !WaitForOutFile(1000000)) - return Written; + int Av = Available(); + if (skipAudio) { + SkipAudioBlocks(); + Max = GetAvPesLength(); + fileOffset += Av - Available(); + } + if (Max) { + int w; + do { + w = cFileBuffer::Write(Max); + if (w >= 0) { + fileOffset += w; + Written += w; + if (Max < 0) + break; + Max -= w; } - } while (skipAudio && Available()); + else + return w; + } while (Max > 0); // we MUST write this entire AV_PES block + } return Written; } @@ -1076,7 +1087,7 @@ cDvbApi::~cDvbApi() { if (videoDev >= 0) { Close(); - StopReplay(); + Stop(); StopRecord(); close(videoDev); } @@ -1119,9 +1130,13 @@ bool cDvbApi::Init(void) dsyslog(LOG_INFO, "probing %s", fileName); int f = open(fileName, O_RDWR); if (f >= 0) { + struct video_capability cap; + int r = ioctl(f, VIDIOCGCAP, &cap); close(f); - dvbApi[i] = new cDvbApi(fileName); - NumDvbApis++; + if (r == 0 && (cap.type & VID_TYPE_DVB)) { + dvbApi[i] = new cDvbApi(fileName); + NumDvbApis++; + } } else { if (errno != ENODEV) @@ -1136,10 +1151,12 @@ bool cDvbApi::Init(void) } } PrimaryDvbApi = dvbApi[0]; - if (NumDvbApis > 0) + if (NumDvbApis > 0) { isyslog(LOG_INFO, "found %d video device%s", NumDvbApis, NumDvbApis > 1 ? "s" : ""); - else + } // need braces because of isyslog-macro + else { esyslog(LOG_ERR, "ERROR: no video device found, giving up!"); + } return NumDvbApis > 0; } @@ -1222,7 +1239,10 @@ void cDvbApi::Open(int w, int h) void cDvbApi::Close(void) { #ifdef DEBUG_OSD - delwin(window); + if (window) { + delwin(window); + window = 0; + } #else Cmd(OSD_Close); #endif @@ -1372,7 +1392,7 @@ bool cDvbApi::StartRecord(const char *FileName) } if (videoDev >= 0) { - StopReplay(); // TODO: remove this if the driver is able to do record and replay at the same time + Stop(); // TODO: remove this if the driver is able to do record and replay at the same time // Check FileName: @@ -1494,7 +1514,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) esyslog(LOG_ERR, "ERROR: StartReplay() called while recording - ignored!"); return false; } - StopReplay(); + Stop(); if (videoDev >= 0) { lastProgress = lastTotal = -1; @@ -1565,49 +1585,69 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) } if (FD_ISSET(fromMain, &setIn)) { switch (readchar(fromMain)) { - case dvbStop: SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Stop(); break; - case dvbPauseReplay: SetReplayMode(Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); - Paused = !Paused; - if (FastForward || FastRewind) { - SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Clear(); - } - FastForward = FastRewind = false; + case dvbStop: SetReplayMode(VID_PLAY_CLEAR_BUFFER); + Buffer->Stop(); + break; + case dvbPause: SetReplayMode(Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); + Paused = !Paused; + if (FastForward || FastRewind) { + SetReplayMode(VID_PLAY_CLEAR_BUFFER); + Buffer->Clear(); + } + FastForward = FastRewind = false; + Buffer->SetMode(rmPlay); + break; + case dvbPlay: if (FastForward || FastRewind || Paused) { + SetReplayMode(VID_PLAY_CLEAR_BUFFER); + SetReplayMode(VID_PLAY_NORMAL); + FastForward = FastRewind = Paused = false; Buffer->SetMode(rmPlay); - break; - case dvbFastForward: SetReplayMode(VID_PLAY_CLEAR_BUFFER); + } + break; + case dvbForward: SetReplayMode(VID_PLAY_CLEAR_BUFFER); + Buffer->Clear(); + FastForward = !FastForward; + FastRewind = false; + if (Paused) { + Buffer->SetMode(rmPlay); + SetReplayMode(FastForward ? VID_PLAY_SLOW_MOTION : VID_PLAY_PAUSE); + } + else { SetReplayMode(VID_PLAY_NORMAL); - FastForward = !FastForward; - FastRewind = Paused = false; - Buffer->Clear(); Buffer->SetMode(FastForward ? rmFastForward : rmPlay); - break; - case dvbFastRewind: SetReplayMode(VID_PLAY_CLEAR_BUFFER); + } + break; + case dvbBackward: SetReplayMode(VID_PLAY_CLEAR_BUFFER); + Buffer->Clear(); + FastRewind = !FastRewind; + FastForward = false; + if (Paused) { + Buffer->SetMode(FastRewind ? rmSlowRewind : rmPlay); + SetReplayMode(FastRewind ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); + } + else { SetReplayMode(VID_PLAY_NORMAL); - FastRewind = !FastRewind; - FastForward = Paused = false; - Buffer->Clear(); Buffer->SetMode(FastRewind ? rmFastRewind : rmPlay); - break; - case dvbSkip: { - int Seconds; - if (readint(fromMain, Seconds)) { - SetReplayMode(VID_PLAY_CLEAR_BUFFER); - SetReplayMode(VID_PLAY_NORMAL); - FastForward = FastRewind = Paused = false; - Buffer->SetMode(rmPlay); - Buffer->SkipSeconds(Seconds); - } - } - break; - case dvbGetIndex: { - int Current, Total; - Buffer->GetIndex(Current, Total); - writeint(toMain, Current); - writeint(toMain, Total); } - break; + break; + case dvbSkip: { + int Seconds; + if (readint(fromMain, Seconds)) { + SetReplayMode(VID_PLAY_CLEAR_BUFFER); + SetReplayMode(VID_PLAY_NORMAL); + FastForward = FastRewind = Paused = false; + Buffer->SetMode(rmPlay); + Buffer->SkipSeconds(Seconds); + } + } + break; + case dvbGetIndex: { + int Current, Total; + Buffer->GetIndex(Current, Total); + writeint(toMain, Current); + writeint(toMain, Total); + } + break; } } } @@ -1633,7 +1673,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) return false; } -void cDvbApi::StopReplay(void) +void cDvbApi::Stop(void) { if (pidReplay) { writechar(toReplay, dvbStop); @@ -1646,22 +1686,28 @@ void cDvbApi::StopReplay(void) } } -void cDvbApi::PauseReplay(void) +void cDvbApi::Pause(void) +{ + if (pidReplay) + writechar(toReplay, dvbPause); +} + +void cDvbApi::Play(void) { if (pidReplay) - writechar(toReplay, dvbPauseReplay); + writechar(toReplay, dvbPlay); } -void cDvbApi::FastForward(void) +void cDvbApi::Forward(void) { if (pidReplay) - writechar(toReplay, dvbFastForward); + writechar(toReplay, dvbForward); } -void cDvbApi::FastRewind(void) +void cDvbApi::Backward(void) { if (pidReplay) - writechar(toReplay, dvbFastRewind); + writechar(toReplay, dvbBackward); } void cDvbApi::Skip(int Seconds) diff --git a/dvbapi.h b/dvbapi.h index a43ba0ee7..25452cfa7 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.11 2000/06/24 14:03:57 kls Exp $ + * $Id: dvbapi.h 1.12 2000/07/30 15:01:01 kls Exp $ */ #ifndef __DVBAPI_H @@ -104,9 +104,10 @@ class cDvbApi { private: enum { dvbStop = 1, // let's not have 0 as a command - dvbPauseReplay, - dvbFastForward, - dvbFastRewind, + dvbPause, + dvbPlay, + dvbForward, + dvbBackward, dvbSkip, dvbGetIndex, }; @@ -136,13 +137,15 @@ class cDvbApi { // If there is already a replay session active, it will be stopped // and the new file will be played back. // If provided Title will be used in the progress display. - void StopReplay(void); + void Stop(void); // Stops the current replay session (if any). - void PauseReplay(void); + void Pause(void); // Pauses the current replay session, or resumes a paused session. - void FastForward(void); + void Play(void); + // Resumes normal replay mode. + void Forward(void); // Runs the current replay session forward at a higher speed. - void FastRewind(void); + void Backward(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. diff --git a/menu.c b/menu.c index 17a9b0b5c..15c8379a0 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.20 2000/07/24 16:25:53 kls Exp $ + * $Id: menu.c 1.22 2000/08/06 07:02:52 kls Exp $ */ #include "menu.h" @@ -512,7 +512,7 @@ cMenuEditChannel::cMenuEditChannel(int Index) 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( "CA", &data.ca, 0, cDvbApi::NumDvbApis)); - Add(new cMenuEditIntItem( "Pnr", &data.pnr, 0, 10000)); //TODO exact limits??? + Add(new cMenuEditIntItem( "Pnr", &data.pnr, 0)); } } @@ -1243,7 +1243,7 @@ cReplayControl::cReplayControl(void) cReplayControl::~cReplayControl() { Hide(); - dvbApi->StopReplay(); + dvbApi->Stop(); } void cReplayControl::SetRecording(const char *FileName, const char *Title) @@ -1278,13 +1278,13 @@ eOSState cReplayControl::ProcessKey(eKeys Key) if (visible) shown = dvbApi->ShowProgress(!shown) || shown; switch (Key) { - case kUp: dvbApi->Skip(-INT_MAX); break; - case kDown: dvbApi->PauseReplay(); break; + case kUp: dvbApi->Play(); break; + case kDown: dvbApi->Pause(); break; case kBlue: Hide(); - dvbApi->StopReplay(); + dvbApi->Stop(); return osEnd; - case kLeft: dvbApi->FastRewind(); break; - case kRight: dvbApi->FastForward(); break; + case kLeft: dvbApi->Backward(); break; + case kRight: dvbApi->Forward(); break; case kGreen: dvbApi->Skip(-60); break; case kYellow: dvbApi->Skip(60); break; case kMenu: Hide(); return osMenu; // allow direct switching to menu diff --git a/osd.c b/osd.c index ee9ba287d..3c323738b 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.4 2000/04/24 09:44:31 kls Exp $ + * $Id: osd.c 1.5 2000/07/26 17:35:09 kls Exp $ */ #include "osd.h" @@ -166,14 +166,20 @@ void cOsdMenu::CursorUp(void) { if (current > 0) { DisplayCurrent(false); - if (--current < first) { + if (current == first) { first -= MAXOSDITEMS; if (first < 0) first = 0; + if (current - MAXOSDITEMS > 0) + current -= MAXOSDITEMS; + else + current--; Display(); } - else + else { + current--; DisplayCurrent(true); + } } } @@ -182,14 +188,20 @@ void cOsdMenu::CursorDown(void) int count = Count(); if (current < count - 1) { DisplayCurrent(false); - if (++current >= first + MAXOSDITEMS) { + if (current == first + MAXOSDITEMS - 1) { first += MAXOSDITEMS; if (first > count - MAXOSDITEMS) first = count - MAXOSDITEMS; + if (current + MAXOSDITEMS < count) + current += MAXOSDITEMS; + else + current++; Display(); } - else + else { + current++; DisplayCurrent(true); + } } } diff --git a/recording.c b/recording.c index e37ccd85e..9f3b38858 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.12 2000/07/24 16:31:07 kls Exp $ + * $Id: recording.c 1.15 2000/07/29 14:08:17 kls Exp $ */ #define _GNU_SOURCE @@ -13,9 +13,11 @@ #include #include #include +#include #include #include "interface.h" #include "tools.h" +#include "videodir.h" #define RECEXT ".rec" #define DELEXT ".del" @@ -24,40 +26,12 @@ #define SUMMARYFILESUFFIX "/summary.vdr" -#define FINDCMD "find %s -type d -name '%s' | sort -df" +#define FINDCMD "find %s -follow -type d -name '%s' 2> /dev/null | sort -df" -#define DFCMD "df -m %s" #define MINDISKSPACE 1024 // MB #define DISKCHECKDELTA 300 // seconds between checks for free disk space -const char *BaseDir = "/video"; - -static bool LowDiskSpace(void) -{ - //TODO Find a simpler way to determine the amount of free disk space! - bool result = true; - char *cmd = NULL; - asprintf(&cmd, DFCMD, BaseDir); - FILE *p = popen(cmd, "r"); - if (p) { - char *s; - while ((s = readline(p)) != NULL) { - if (*s == '/') { - int available; - sscanf(s, "%*s %*d %*d %d", &available); - result = available < MINDISKSPACE; - break; - } - } - pclose(p); - } - else - esyslog(LOG_ERR, "ERROR: can't open pipe for cmd '%s'", cmd); - delete cmd; - return result; -} - void AssertFreeDiskSpace(void) { // With every call to this function we try to actually remove @@ -65,7 +39,7 @@ void AssertFreeDiskSpace(void) // it will get removed during the next call. static time_t LastFreeDiskCheck = 0; if (time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA) { - if (LowDiskSpace()) { + if (!VideoFileSpaceAvailable(MINDISKSPACE)) { // Remove the oldest file that has been "deleted": cRecordings Recordings; if (Recordings.Load(true)) { @@ -123,7 +97,7 @@ cRecording::cRecording(const char *FileName) { titleBuffer = NULL; fileName = strdup(FileName); - FileName += strlen(BaseDir) + 1; + FileName += strlen(VideoDirectory) + 1; char *p = strrchr(FileName, '/'); name = NULL; @@ -189,7 +163,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, priority, lifetime); + asprintf(&fileName, NAMEFORMAT, VideoDirectory, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime); if (fileName) strreplace(fileName, ' ', '_'); } @@ -239,10 +213,7 @@ bool cRecording::Delete(void) if (strcmp(ext, RECEXT) == 0) { strncpy(ext, DELEXT, strlen(ext)); isyslog(LOG_INFO, "deleting recording %s", FileName()); - if (rename(FileName(), NewName) == -1) { - esyslog(LOG_ERR, "ERROR: %s: %s", FileName(), strerror(errno)); - result = false; - } + result = RenameVideoFile(FileName(), NewName); } delete NewName; return result; @@ -251,7 +222,7 @@ bool cRecording::Delete(void) bool cRecording::Remove(void) { isyslog(LOG_INFO, "removing recording %s", FileName()); - return RemoveFileOrDir(FileName()); + return RemoveVideoFile(FileName()); } // --- cRecordings ----------------------------------------------------------- @@ -261,7 +232,7 @@ bool cRecordings::Load(bool Deleted) Clear(); bool result = false; char *cmd = NULL; - asprintf(&cmd, FINDCMD, BaseDir, Deleted ? "*" DELEXT : "*" RECEXT); + asprintf(&cmd, FINDCMD, VideoDirectory, Deleted ? "*" DELEXT : "*" RECEXT); FILE *p = popen(cmd, "r"); if (p) { char *s; diff --git a/recording.h b/recording.h index e501af822..dc3b3d748 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.7 2000/07/23 19:06:14 kls Exp $ + * $Id: recording.h 1.9 2000/07/28 13:53:54 kls Exp $ */ #ifndef __RECORDING_H diff --git a/remote.c b/remote.c index 931cfd33c..0476962cc 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.10 2000/07/15 16:34:35 kls Exp $ + * $Id: remote.c 1.11 2000/07/29 16:23:47 kls Exp $ */ #include "remote.h" @@ -71,7 +71,11 @@ void cRcIoKBD::Flush(int WaitSeconds) bool cRcIoKBD::InputAvailable(bool Wait) { timeout(Wait ? 1000 : 10); - return true;//XXX + int ch = getch(); + if (ch == ERR) + return false; + ungetch(ch); + return true; } bool cRcIoKBD::GetCommand(unsigned int *Command, unsigned short *) diff --git a/svdrp.c b/svdrp.c index 6873d166e..9fef18484 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.2 2000/07/24 16:43:51 kls Exp $ + * $Id: svdrp.c 1.4 2000/08/06 12:52:04 kls Exp $ */ #define _GNU_SOURCE @@ -145,7 +145,12 @@ const char *HelpPages[] = { " by the LSTC command.", "NEWT \n" " Create a new timer. Settings must be in the same format as returned\n" - " by the LSTT command.", + " by the LSTT command. It is an error if a timer with the same channel,\n" + " day, start and stop time already exists.", + "UPDT \n" + " Updates a timer. Settings must be in the same format as returned\n" + " by the LSTT command. If a timer with the same channel, day, start\n" + " and stop time does not yet exists, it will be created.", "QUIT\n" " Exit vdr (SVDRP).\n" " You can also hit Ctrl-D to exit.", @@ -369,7 +374,7 @@ void cSVDRP::CmdHelp(const char *Option) } } else { - Reply(-214, "This is VDR version 0.6"); //XXX dynamically insert version number + Reply(-214, "This is VDR version %s", VDRVERSION); Reply(-214, "Topics:"); const char **hp = HelpPages; while (*hp) { @@ -548,13 +553,48 @@ void cSVDRP::CmdNewt(const char *Option) if (*Option) { cTimer *timer = new cTimer; if (timer->Parse(Option)) { - Timers.Add(timer); + cTimer *t = Timers.GetTimer(timer); + if (!t) { + Timers.Add(timer); + Timers.Save(); + isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + Reply(250, "%d %s", timer->Index() + 1, timer->ToText()); + return; + } + else + Reply(550, "Timer already defined: %d %s", t->Index() + 1, t->ToText()); + } + else + Reply(501, "Error in timer settings"); + delete timer; + } + else + Reply(501, "Missing timer settings"); +} + +void cSVDRP::CmdUpdt(const char *Option) +{ + if (*Option) { + cTimer *timer = new cTimer; + if (timer->Parse(Option)) { + cTimer *t = Timers.GetTimer(timer); + if (t) { + t->Parse(Option); + delete timer; + timer = t; + isyslog(LOG_INFO, "timer %d updated", timer->Index() + 1); + } + else { + Timers.Add(timer); + isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + } Timers.Save(); - isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); Reply(250, "%d %s", timer->Index() + 1, timer->ToText()); + return; } else Reply(501, "Error in timer settings"); + delete timer; } else Reply(501, "Missing timer settings"); @@ -583,6 +623,7 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("MOVT")) CmdMovt(s); else if (CMD("NEWC")) CmdNewc(s); else if (CMD("NEWT")) CmdNewt(s); + else if (CMD("UPDT")) CmdUpdt(s); else if (CMD("QUIT") || CMD("\x04")) Close(); else Reply(500, "Command unrecognized: \"%s\"", Cmd); @@ -598,7 +639,7 @@ void cSVDRP::Process(void) //TODO how can we get the *full* hostname? gethostname(buffer, sizeof(buffer)); time_t now = time(NULL); - Reply(220, "%s SVDRP VideoDiskRecorder 0.6; %s", buffer, ctime(&now));//XXX dynamically insert version number + Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", VDRVERSION, buffer, ctime(&now)); } int rbytes = readstring(filedes, buffer, sizeof(buffer) - 1); if (rbytes > 0) { diff --git a/svdrp.h b/svdrp.h index c63854240..3c1cafa8f 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.1 2000/07/23 14:49:30 kls Exp $ + * $Id: svdrp.h 1.2 2000/08/06 12:45:28 kls Exp $ */ #ifndef __SVDRP_H @@ -42,6 +42,7 @@ class cSVDRP { void CmdMovt(const char *Option); void CmdNewc(const char *Option); void CmdNewt(const char *Option); + void CmdUpdt(const char *Option); void Execute(char *Cmd); public: cSVDRP(int Port); diff --git a/timers.conf b/timers.conf index 659faaaff..47b40674a 100644 --- a/timers.conf +++ b/timers.conf @@ -1,9 +1,13 @@ -1:10:-T-----:2058:2202:99:10:Quarks: -1:5:-T-----:2100:2205:99:10:RudisSuchmaschine: +0:10:-T-----:2058:2202:99:10:Quarks: +0:5:-T-----:2100:2205:99:10:RudisSuchmaschine: 1:10:---T---:2158:2250:99:99:DiePlaneten: -1:3:---T---:2211:2300:99:10:Switch: +0:3:---T---:2211:2300:99:10:Switch: 1:15:-----S-:1358:1435:99:7:Neues: -1:1:-----S-:1445:1600:99:30:Hammerman: +1:1:-----S-:1445:1610:99:30:Hammerman: 0:2:-----S-:2200:2350:99:30:Wochenshow: 1:11:------S:2058:2120:99:10:Centauri: 0:15:MTWTF--:1828:1901:10:5:nano: +1:1:-TWTF--:0858:0940:99:99:Ellen: +1:2:----F--:2140:2225:10:10:WWW: +1:11:-----S-:2158:2235:99:99:Computer: +1:23:-----S-:2200:0020:99:99:BBC special: diff --git a/tools.c b/tools.c index 998d91b3a..0dca69ee3 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.10 2000/07/23 13:16:54 kls Exp $ + * $Id: tools.c 1.13 2000/07/29 18:41:45 kls Exp $ */ #define _GNU_SOURCE @@ -145,6 +145,51 @@ bool isnumber(const char *s) return true; } +#define DFCMD "df -m %s" + +uint FreeDiskSpaceMB(const char *Directory) +{ + //TODO Find a simpler way to determine the amount of free disk space! + uint Free = 0; + char *cmd = NULL; + asprintf(&cmd, DFCMD, Directory); + FILE *p = popen(cmd, "r"); + if (p) { + char *s; + while ((s = readline(p)) != NULL) { + if (*s == '/') { + uint available; + sscanf(s, "%*s %*d %*d %u", &available); + Free = available; + break; + } + } + pclose(p); + } + else + esyslog(LOG_ERR, "ERROR: can't open pipe for cmd '%s'", cmd); + delete cmd; + return Free; +} + +bool DirectoryOk(const char *DirName, bool LogErrors) +{ + struct stat ds; + if (stat(DirName, &ds) == 0) { + if (S_ISDIR(ds.st_mode)) { + if (access(DirName, R_OK | W_OK | X_OK) == 0) + return true; + else if (LogErrors) + esyslog(LOG_ERR, "ERROR: can't access %s", DirName); + } + else if (LogErrors) + esyslog(LOG_ERR, "ERROR: %s is not a directory", DirName); + } + else if (LogErrors) + LOG_ERROR_STR(DirName); + return false; +} + bool MakeDirs(const char *FileName, bool IsDirectory) { bool result = true; @@ -157,7 +202,7 @@ bool MakeDirs(const char *FileName, bool IsDirectory) *p = 0; struct stat fs; if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) { - isyslog(LOG_INFO, "creating directory %s", s); + dsyslog(LOG_INFO, "creating directory %s", s); if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) { esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno)); result = false; @@ -173,7 +218,7 @@ bool MakeDirs(const char *FileName, bool IsDirectory) return result; } -bool RemoveFileOrDir(const char *FileName) +bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks) { struct stat st; if (stat(FileName, &st) == 0) { @@ -185,23 +230,43 @@ bool RemoveFileOrDir(const char *FileName) if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) { char *buffer; asprintf(&buffer, "%s/%s", FileName, e->d_name); + if (FollowSymlinks) { + int size = strlen(buffer) * 2; // should be large enough + char *l = new char[size]; + int n = readlink(buffer, l, size); + if (n < 0) { + if (errno != EINVAL) + LOG_ERROR_STR(buffer); + } + else if (n < size) { + l[n] = 0; + dsyslog(LOG_INFO, "removing %s", l); + if (remove(l) < 0) + LOG_ERROR_STR(l); + } + else + esyslog(LOG_ERR, "ERROR: symlink name length (%d) exceeded anticipated buffer size (%d)", n, size); + delete l; + } + dsyslog(LOG_INFO, "removing %s", buffer); if (remove(buffer) < 0) - esyslog(LOG_ERR, "ERROR: %s: %s", buffer, strerror(errno)); + LOG_ERROR_STR(buffer); delete buffer; } } closedir(d); } else { - esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno)); + LOG_ERROR_STR(FileName); return false; } } + dsyslog(LOG_INFO, "removing %s", FileName); if (remove(FileName) == 0) return true; } else - esyslog(LOG_ERR, "ERROR: %s: %s", FileName, strerror(errno)); + LOG_ERROR_STR(FileName); return false; } diff --git a/tools.h b/tools.h index ecf42be62..563f3d065 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.10 2000/07/23 13:16:37 kls Exp $ + * $Id: tools.h 1.12 2000/07/29 10:56:00 kls Exp $ */ #ifndef __TOOLS_H @@ -43,8 +43,10 @@ char *skipspace(char *s); int time_ms(void); void delay_ms(int ms); bool isnumber(const char *s); +uint FreeDiskSpaceMB(const char *Directory); +bool DirectoryOk(const char *DirName, bool LogErrors = false); bool MakeDirs(const char *FileName, bool IsDirectory = false); -bool RemoveFileOrDir(const char *FileName); +bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); bool CheckProcess(pid_t pid); void KillProcess(pid_t pid, int Timeout = MAXPROCESSTIMEOUT); diff --git a/vdr.c b/vdr.c index 626e6dc04..69eceedb2 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.23 2000/07/23 15:36:43 kls Exp $ + * $Id: vdr.c 1.27 2000/07/29 19:01:57 kls Exp $ */ #include @@ -36,6 +36,7 @@ #include "recording.h" #include "svdrp.h" #include "tools.h" +#include "videodir.h" #ifdef REMOTE_KBD #define KEYS_CONF "keys-pc.conf" @@ -64,38 +65,67 @@ int main(int argc, char *argv[]) static struct option long_options[] = { { "daemon", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, + { "log", required_argument, NULL, 'l' }, { "port", required_argument, NULL, 'p' }, + { "video", required_argument, NULL, 'v' }, { 0 } }; int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "dhp:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "dhl:p:v:", long_options, &option_index)) != -1) { switch (c) { case 'd': DaemonMode = true; break; case 'h': printf("Usage: vdr [OPTION]\n\n" - " -h, --help display this help and exit\n" - " -d, --daemon run in daemon mode\n" - " -p PORT, --port=PORT use PORT for SVDRP ('0' turns off SVDRP)\n" + " -h, --help display this help and exit\n" + " -d, --daemon run in daemon mode\n" + " -l LEVEL, --log=LEVEL set log level (default: 3)\n" + " 0 = no logging, 1 = errors only,\n" + " 2 = errors and info, 3 = errors, info and debug\n" + " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" + " 0 turns off SVDRP\n" + " -v DIR, --video=DIR use DIR as video directory (default is %s)\n" "\n" - "Report bugs to \n" + "Report bugs to \n", + DEFAULTSVDRPPORT, + VideoDirectory ); return 0; break; + case 'l': if (isnumber(optarg)) { + int l = atoi(optarg); + if (0 <= l && l <= 3) { + SysLogLevel = l; + break; + } + } + fprintf(stderr, "vdr: invalid log level: %s\n", optarg); + abort(); + break; case 'p': if (isnumber(optarg)) - SVDRPport = strtol(optarg, NULL, 10); + SVDRPport = atoi(optarg); else { fprintf(stderr, "vdr: invalid port number: %s\n", optarg); - return 1; + abort(); } break; + case 'v': VideoDirectory = optarg; + break; default: abort(); } } // Log file: - openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); + if (SysLogLevel > 0) + openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); + + // Check the video directory: + + if (!DirectoryOk(VideoDirectory, true)) { + fprintf(stderr, "vdr: can't access video directory %s\n", VideoDirectory); + abort(); + } // Daemon mode: @@ -104,8 +134,8 @@ int main(int argc, char *argv[]) pid_t pid = fork(); if (pid < 0) { fprintf(stderr, "%s\n", strerror(errno)); - esyslog(LOG_ERR, strerror(errno)); - return 1; + esyslog(LOG_ERR, "ERROR: %s", strerror(errno)); + abort(); } if (pid != 0) return 0; // initial program immediately returns @@ -117,12 +147,12 @@ int main(int argc, char *argv[]) abort(); #endif } - isyslog(LOG_INFO, "started"); + isyslog(LOG_INFO, "VDR version %s started", VDRVERSION); // DVB interfaces: if (!cDvbApi::Init()) - return 1; + abort(); // Configuration data: @@ -241,6 +271,7 @@ int main(int argc, char *argv[]) delete SVDRP; cDvbApi::Cleanup(); isyslog(LOG_INFO, "exiting"); - closelog(); + if (SysLogLevel > 0) + closelog(); return 0; } diff --git a/videodir.c b/videodir.c new file mode 100644 index 000000000..7bd6299a6 --- /dev/null +++ b/videodir.c @@ -0,0 +1,182 @@ +/* + * videodir.c: Functions to maintain a distributed video directory + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: videodir.c 1.1 2000/07/29 15:21:42 kls Exp $ + */ + +#include "videodir.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "tools.h" + +const char *VideoDirectory = "/video"; + +class cVideoDirectory { +private: + char *name, *stored, *adjusted; + int length, number, digits; +public: + cVideoDirectory(void); + ~cVideoDirectory(); + uint FreeMB(void); + const char *Name(void) { return name; } + const char *Stored(void) { return stored; } + int Length(void) { return length; } + bool IsDistributed(void) { return name != NULL; } + bool Next(void); + void Store(void); + const char *Adjust(const char *FileName); + }; + +cVideoDirectory::cVideoDirectory(void) +{ + length = strlen(VideoDirectory); + name = (VideoDirectory[length - 1] == '0') ? strdup(VideoDirectory) : NULL; + stored = adjusted = NULL; + number = -1; + digits = 0; +} + +cVideoDirectory::~cVideoDirectory() +{ + delete name; + delete stored; + delete adjusted; +} + +uint cVideoDirectory::FreeMB(void) +{ + return FreeDiskSpaceMB(name ? name : VideoDirectory); +} + +bool cVideoDirectory::Next(void) +{ + if (name) { + if (number < 0) { + int l = length; + while (l-- > 0 && isdigit(name[l])) + ; + l++; + digits = length - l; + int n = atoi(&name[l]); + if (n == 0) + number = n; + else + return false; // base video directory must end with zero + } + if (++number > 0) { + char buf[16]; + if (sprintf(buf, "%0*d", digits, number) == digits) { + strcpy(&name[length - digits], buf); + return DirectoryOk(name); + } + } + } + return false; +} + +void cVideoDirectory::Store(void) +{ + if (name) { + delete stored; + stored = strdup(name); + } +} + +const char *cVideoDirectory::Adjust(const char *FileName) +{ + if (stored) { + delete adjusted; + adjusted = strdup(FileName); + return strncpy(adjusted, stored, length); + } + return NULL; +} + +int OpenVideoFile(const char *FileName, int Flags) +{ + const char *ActualFileName = FileName; + + // Incoming name must be in base video directory: + if (strstr(FileName, VideoDirectory) != FileName) { + esyslog(LOG_ERR, "ERROR: %s not in %s", FileName, VideoDirectory); + errno = ENOENT; // must set 'errno' - any ideas for a better value? + return -1; + } + // Are we going to create a new file? + if ((Flags & O_CREAT) != 0) { + cVideoDirectory Dir; + if (Dir.IsDistributed()) { + // Find the directory with the most free space: + uint MaxFree = Dir.FreeMB(); + while (Dir.Next()) { + uint Free = FreeDiskSpaceMB(Dir.Name()); + if (Free > MaxFree) { + Dir.Store(); + MaxFree = Free; + } + } + if (Dir.Stored()) { + ActualFileName = Dir.Adjust(FileName); + if (!MakeDirs(ActualFileName, false)) + return -1; // errno has been set by MakeDirs() + if (symlink(ActualFileName, FileName) < 0) { + LOG_ERROR_STR(FileName); + return -1; + } + ActualFileName = strdup(ActualFileName); // must survive Dir! + } + } + } + int Result = open(ActualFileName, Flags, S_IRUSR | S_IWUSR); + if (ActualFileName != FileName) + delete ActualFileName; + return Result; +} + +int CloseVideoFile(int FileHandle) +{ + // just in case we ever decide to do something special when closing the file! + return close(FileHandle); +} + +bool RenameVideoFile(const char *OldName, const char *NewName) +{ + // Only the base video directory entry will be renamed, leaving the + // possible symlinks untouched. Going through all the symlinks and disks + // would be unnecessary work - maybe later... + if (rename(OldName, NewName) == -1) { + LOG_ERROR_STR(OldName); + return false; + } + return true; +} + +bool RemoveVideoFile(const char *FileName) +{ + return RemoveFileOrDir(FileName, true); +} + +bool VideoFileSpaceAvailable(unsigned int SizeMB) +{ + cVideoDirectory Dir; + if (Dir.IsDistributed()) { + if (Dir.FreeMB() >= SizeMB * 2) // base directory needs additional space + return true; + while (Dir.Next()) { + if (Dir.FreeMB() >= SizeMB) + return true; + } + return false; + } + return Dir.FreeMB() >= SizeMB; +} diff --git a/videodir.h b/videodir.h new file mode 100644 index 000000000..7ce15314d --- /dev/null +++ b/videodir.h @@ -0,0 +1,21 @@ +/* + * videodir.h: Functions to maintain a distributed video directory + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: videodir.h 1.1 2000/07/29 14:08:27 kls Exp $ + */ + +#ifndef __VIDEODIR_H +#define __VIDEODIR_H + +extern const char *VideoDirectory; + +int OpenVideoFile(const char *FileName, int Flags); +int CloseVideoFile(int FileHandle); +bool RenameVideoFile(const char *OldName, const char *NewName); +bool RemoveVideoFile(const char *FileName); +bool VideoFileSpaceAvailable(unsigned int SizeMB); + +#endif //__VIDEODIR_H From 48fea259ae5ed3ac19bcc4152341252b9df39128 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 3 Sep 2000 18:00:00 +0200 Subject: [PATCH 009/307] Version 0.62 - The Makefile now defines DVBDIR to easily point to where the DVB driver source is located. - When switching channels the current/next information is now displayed if available (thanks to Robert Schneider). Since there is now more information to read when switching channels, the timeout for displaying it has been increased from 2 to 5 seconds (remember that this info can always be recalled by pressing the "Ok" button). For this feature to work it is necessary that the 'Pnr' parameter in the channel setup ('channels.conf') is set to the proper value. This has been done for some of the channels in the default 'channels.conf'. Some other parameters in the default 'channels.conf' have also been updated, so please make sure your timers still use the correct channels! --- CONTRIBUTORS | 3 + HISTORY | 15 ++ INSTALL | 3 + Makefile | 14 +- channels.conf | 79 ++++---- config.c | 9 +- config.h | 4 +- dvbapi.h | 4 +- eit.c | 530 ++++++++++++++++++++++++++++++++++++++++++++++++++ eit.h | 92 +++++++++ interface.c | 23 ++- svdrp.c | 4 +- timers.conf | 16 +- 13 files changed, 733 insertions(+), 63 deletions(-) create mode 100644 eit.c create mode 100644 eit.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 74390cf90..07f9d16df 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -16,3 +16,6 @@ Heino Goldenstein Guido Fiala for implementing slow forward/back + +Robert Schneider + for implementing EIT support for displaying the current/next info diff --git a/HISTORY b/HISTORY index 04cc2d59c..f5c3cb93b 100644 --- a/HISTORY +++ b/HISTORY @@ -123,3 +123,18 @@ Video Disk Recorder Revision History doesn't yet exist). - New version of the 'epg2timers' tool (with a modified channel list). - Bugfix in closing window in DEBUG_OSD mode. + +2000-09-03: Version 0.62 + +- The Makefile now defines DVBDIR to easily point to where the DVB driver + source is located. +- When switching channels the current/next information is now displayed if + available (thanks to Robert Schneider). Since there is now more information + to read when switching channels, the timeout for displaying it has been + increased from 2 to 5 seconds (remember that this info can always be recalled + by pressing the "Ok" button). + For this feature to work it is necessary that the 'Pnr' parameter in the + channel setup ('channels.conf') is set to the proper value. This has been + done for some of the channels in the default 'channels.conf'. Some other + parameters in the default 'channels.conf' have also been updated, so please + make sure your timers still use the correct channels! diff --git a/INSTALL b/INSTALL index 938487c31..1ebffa1b3 100644 --- a/INSTALL +++ b/INSTALL @@ -11,6 +11,9 @@ http://linuxtv.org/dvb/siemens_dvb.html for more information 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/VDR. +If you have the DVB driver source in a different location +you will have to change the definition of DVBDIR in the +Makefile. This program requires the card driver version 0.05 or higher to work properly. diff --git a/Makefile b/Makefile index f71236b78..9868ddb89 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,12 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.6 2000/07/28 14:37:44 kls Exp $ +# $Id: Makefile 1.7 2000/09/03 09:26:24 kls Exp $ -OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o videodir.o +DVBDIR = ../DVB + +INCLUDES = -I$(DVBDIR)/driver +OBJS = config.o dvbapi.o eit.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o videodir.o ifndef REMOTE REMOTE = KBD @@ -19,13 +22,14 @@ DEFINES += -DDEBUG_OSD endif %.o: %.c - g++ -g -O2 -Wall -c $(DEFINES) $< + g++ -g -O2 -Wall -c $(DEFINES) $(INCLUDES) $< all: vdr -config.o : config.c config.h dvbapi.h interface.h tools.h +config.o : config.c config.h dvbapi.h eit.h interface.h tools.h dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h videodir.h -interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h +eit.o : eit.c eit.h +interface.o: interface.c config.h dvbapi.h eit.h interface.h remote.h tools.h menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h diff --git a/channels.conf b/channels.conf index eefaf52da..6e6d0168d 100644 --- a/channels.conf +++ b/channels.conf @@ -1,53 +1,56 @@ -RTL:12188:h:1:27500:163:104:0:0 -Sat.1:12480:v:1:27500:1791:1792: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 +RTL:12188:h:1:27500:163:104:0:12003 +Sat.1:12480:v:1:27500:1791:1792:0:46 +Pro-7:12480:v:1:27500:255:256:0:898 +RTL2:12188:h:1:27500:166:128:0:12020 +ARD:11837:h:1:27500:101:102:0:28106 +BR3:11837:h:1:27500:201:202:0:28107 +Hessen-3:11837:h:1:27500:301:302:0:28108 +N3:12110:h:1:27500:2401:2402:0:28224 +SR3:11837:h:1:27500:501:502:0:28110 +WDR:11837:h:1:27500:601:602:0:28111 +BR-alpha:11837:h:1:27500:701:702:0:28112 +SWR BW:11837:h:1:27500:801:802:0:28110 +Phoenix:11837:h:1:27500:901:902:0:28114 +ZDF:11954:h:1:27500:110:120:0:28006 +3sat:11954:h:1:27500:210:220:0:28007 +KiKa:11954:h:1:27500:310:320:0:28008 +arte:11836:h:1:27500:401:402:0:28109 +Eurosport:11954:h:1:27500:410:420:0:28009 +ORF Sat:11954:h:1:27500:506:507:0:28010 +ZDF.info:11954:h:1:27500:610:620:0:28011 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 +Super RTL:12188:h:1:27500:165:120:0:12040 +VOX:12188:h:1:27500:167:136:0:12060 +DW TV:12363:v:1:27500:305:306:0:8905 +Kabel 1:12480:v:1:27500:511:512:0:899 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 +Sky News:12552:v:1:22000:305:306:0:3995 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 Tourisme: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:12110:h:1:27500:401:402:0:0 -ORB:12722:h:1:22000:501:502:0:0 -B1:12722:h:1:22000:601:602:0:0 +TW1:12692:h:1:22000:166:167:0:13013 +Eurosport:11954:h:1:27500:410:420:0:28009 +EinsExtra:12110:H:1:27500:101:102:0:28201 +EinsFestival:12110:H:1:27500:201:202:0:28202 +EinsMuXx:12110:H:1:27500:301:302:0:28203 +ZDF Theaterkanal:11954:H:1:27500:1110:1120:0:28016 +ZDF.doku:11954:H:1:27500:660:670:0:28014 +MDR:12110:h:1:27500:401:402:0:28204 +ORB:12110:h:1:27500:501:502:0:28205 +B1:12110:h:1:27500:601:602:0:28206 ARD Online-Kanal:12722:h:1:22000:8191:701:0:0 Premiere World Promo:11798:h:1:27500:255:256:0:0 Premiere:11798:h:1:27500:511:512:2:10 Star Kino:11798:h:1:27500:767:768:2:9 -Cine Action:11798:h:1:27500:1023:1024:1:20 -Cine Comedy:11798:h:1:27500:1279:1280:1:29 -Sci Fantasy:11798:h:1:27500:1535:1536:1:41 -Romantic Movies:11798:h:1:27500:1791:1792:1:11 -Studio Universal:11798:h:1:27500:2047:2048:1:21 +Cine Action:11798:h:1:27500:1023:1024:2:20 +Cine Comedy:11798:h:1:27500:1279:1280:2:29 +Sci Fantasy:11798:h:1:27500:1535:1536:2:41 +Romantic Movies:11798:h:1:27500:1791:1792:2:11 +Studio Universal:11798:h:1:27500:2047:2048:2:21 TV Niepokalanow:11876:h:1:27500:305:321:0:0 Mosaico:11934:v:1:27500:165:100:0:0 Andalucia TV:11934:v:1:27500:166:104:0:0 @@ -110,6 +113,6 @@ 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 +Bloomberg TV Germany:12552:v:1:22000:162:99:0:12160 Video Italia:12610:v:1:22000:121:122:0:0 AC 3 promo:12670:v:1:22000:308:256:0:0 diff --git a/config.c b/config.c index c144d6c02..af5be871f 100644 --- a/config.c +++ b/config.c @@ -4,15 +4,18 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.17 2000/08/06 12:27:38 kls Exp $ + * $Id: config.c 1.18 2000/09/03 09:20:22 kls Exp $ */ #include "config.h" #include #include #include "dvbapi.h" +#include "eit.h" #include "interface.h" +extern cEIT EIT; + // -- cKeys ------------------------------------------------------------------ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! @@ -231,8 +234,10 @@ bool cChannel::Switch(cDvbApi *DvbApi) isyslog(LOG_INFO, "switching to channel %d", Index() + 1); CurrentChannel = Index(); for (int i = 3; i--;) { - if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) + if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) { + EIT.SetProgramNumber(pnr); return true; + } esyslog(LOG_ERR, "retrying"); } return false; diff --git a/config.h b/config.h index 1b21d3417..15e905011 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.14 2000/08/06 12:22:52 kls Exp $ + * $Id: config.h 1.15 2000/09/03 09:37:30 kls Exp $ */ #ifndef __CONFIG_H @@ -17,7 +17,7 @@ #include "dvbapi.h" #include "tools.h" -#define VDRVERSION "0.61" +#define VDRVERSION "0.62" #define MaxBuffer 10000 diff --git a/dvbapi.h b/dvbapi.h index 25452cfa7..9f9543020 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.12 2000/07/30 15:01:01 kls Exp $ + * $Id: dvbapi.h 1.13 2000/09/03 09:25:53 kls Exp $ */ #ifndef __DVBAPI_H @@ -19,7 +19,7 @@ typedef unsigned char __u8; #include #endif #include -#include "../DVB/driver/dvb.h" +#include #define MenuLines 15 #define MenuColumns 40 diff --git a/eit.c b/eit.c new file mode 100644 index 000000000..c4c12003c --- /dev/null +++ b/eit.c @@ -0,0 +1,530 @@ +/*************************************************************************** + eit.c - description + ------------------- + begin : Fri Aug 25 2000 + copyright : (C) 2000 by Robert Schneider + email : Robert.Schneider@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * $Id: eit.c 1.1 2000/09/03 10:22:25 kls Exp $ + ***************************************************************************/ + +#include "eit.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "tools.h" + +typedef struct { + u_char table_id : 8; + +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator : 1; + u_char : 3; + u_char section_length_hi : 4; +#else + u_char section_length_hi : 4; + u_char : 3; + u_char section_syntax_indicator : 1; +#endif + + u_char section_length_lo : 8; + + u_char service_id_hi : 8; + u_char service_id_lo : 8; + +#if BYTE_ORDER == BIG_ENDIAN + u_char : 2; + u_char version_number : 5; + u_char current_next_indicator : 1; +#else + u_char current_next_indicator : 1; + u_char version_number : 5; + u_char : 2; +#endif + + u_char section_number : 8; + u_char last_section_number : 8; + u_char transport_stream_id_hi : 8; + u_char transport_stream_id_lo : 8; + u_char original_network_id_hi : 8; + u_char original_network_id_lo : 8; + u_char segment_last_section_number : 8; + u_char segment_last_table_id : 8; +} eit_t; + +#define EIT_SIZE 14 + +struct eit_loop_struct1 { + u_char event_id_hi : 8; + u_char event_id_lo : 8; + + u_char date_hi : 8; + u_char date_lo : 8; + u_char time_hour : 4; + u_char time_hour_ten : 4; + u_char time_minute : 4; + u_char time_minute_ten : 4; + u_char time_second : 4; + u_char time_second_ten : 4; + + u_char dur_hour_ten : 4; + u_char dur_hour : 4; + u_char dur_minute_ten : 4; + u_char dur_minute : 4; + u_char dur_second_ten : 4; + u_char dur_second : 4; + +#if BYTE_ORDER == BIG_ENDIAN + u_char running_status : 3; + u_char free_ca_mode : 1; + u_char descriptors_loop_length_hi : 4; +#else + u_char descriptors_loop_length_hi : 4; + u_char free_ca_mode : 1; + u_char running_status : 3; +#endif + + u_char descriptors_loop_length_lo : 8; +}; + +#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d +#define EIT_SHORT_EVENT_DESCRIPTOR_SIZE 6 + +struct eit_short_event_descriptor_struct { + u_char descriptor_tag : 8; + u_char descriptor_length : 8; + + u_char language_code_1 : 8; + u_char language_code_2 : 8; + u_char language_code_3 : 8; + + u_char event_name_length : 8; +}; + +#define EIT_EXTENDED_EVENT_DESCRIPOR 0x4e + +#define EIT_DESCRIPTOR_SIZE + +typedef struct eit_event_struct { + u_char event_id_hi : 8; + u_char event_id_lo : 8; + + u_char start_time_1 : 8; + u_char start_time_2 : 8; + u_char start_time_3 : 8; + u_char start_time_4 : 8; + u_char start_time_5 : 8; + + u_char duration_1 : 8; + u_char duration_2 : 8; + u_char duration_3 : 8; + +#if BYTE_ORDER == BIG_ENDIAN + u_char running_status : 3; + u_char free_CA_mode : 1; + u_char descriptors_loop_length_hi : 4; +#else + u_char descriptors_loop_length_hi : 4; + u_char free_CA_mode : 1; + u_char running_status : 3; +#endif + + u_char descriptors_loop_length_lo : 8; + +} eit_event_t; +#define EIT_LOOP_SIZE 12 + + +typedef struct tot_t { + u_char table_id : 8; + +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator : 1; + u_char : 3; + u_char section_length_hi : 4; +#else + u_char section_length_hi : 4; + u_char : 3; + u_char section_syntax_indicator : 1; +#endif + + u_char date_hi : 8; + u_char date_lo : 8; + u_char time_hour : 4; + u_char time_hour_ten : 4; + u_char time_minute : 4; + u_char time_minute_ten : 4; + u_char time_second : 4; + u_char time_second_ten : 4; + +#if BYTE_ORDER == BIG_ENDIAN + u_char : 4; + u_char descriptor_loop_length_hi : 4; +#else + u_char descriptor_loop_length_hi : 4; + u_char : 4; +#endif + + u_char descriptor_loop_length_lo : 8; +} tot_t; + +typedef struct local_time_offset { + + u_char descriptor_tag : 8; + u_char descriptor_length : 8; + + u_char language_code_1 : 8; + u_char language_code_2 : 8; + u_char language_code_3 : 8; + + u_char : 8; + + u_char offset_hour : 4; + u_char offset_hour_ten : 4; + u_char offset_minute : 4; + u_char offset_minute_ten : 4; + + u_char change_date_hi : 8; + u_char change_date_lo : 8; + u_char change_time_hour : 4; + u_char change_time_hour_ten : 4; + u_char change_time_minute : 4; + u_char change_time_minute_ten : 4; + u_char change_time_second : 4; + u_char change_time_second_ten : 4; + + u_char next_offset_hour : 4; + u_char next_offset_hour_ten : 4; + u_char next_offset_minute : 4; + u_char next_offset_minute_ten : 4; +} local_time_offset; + +cEIT::cEIT() +{ + cszBitFilter = "/dev/vbi"; + if((fsvbi = open(cszBitFilter, O_RDWR))<0) + { + fsvbi = 0; + esyslog(LOG_ERR, "Failed to open DVB bitfilter device: %s", cszBitFilter); + return; + } +} + +cEIT::~cEIT() +{ + if (fsvbi != 0) + close(fsvbi); + fsvbi = 0; +} + +/** Set the bitfilter in vbi device to return +correct tables */ +int cEIT::SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode) +{ + struct bitfilter filt = { + pid, + { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + mode,0, + FILTER_MEM, + {}, + }; + + if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0) + return 0xffff; + return 0; +} +/** */ +int cEIT::GetSection(unsigned char *buf, ushort PID, unsigned char sec) +{ + int seclen=0; + unsigned short handle, pid; + unsigned char section, sectionnum=0xff, maxsec=0; + struct pollfd pfd; + + if ((handle = SetBitFilter(PID, (sec<<8)|0x00ff, SECTION_CONTINUOS))==0xffff) + return -1; + + seclen=0; + pfd.fd=fsvbi; + pfd.events=POLLIN; + if (poll(&pfd, 1, 20000)==0) + { + //cerr << "Timeout\n"; + return -1; + } + + read(fsvbi, buf, 8); + seclen=(buf[6]<<8)|buf[7]; + pid=(buf[4]<<8)|buf[5]; + + read(fsvbi, buf, seclen); + section=buf[0]; + sectionnum=buf[6]; + maxsec=buf[7]; + + //cerr << "secnum: " << HEX(2) << (int)sectionnum + // << ", secmax: " << HEX(2) << (int) msecnum << "\n"; + + CloseFilter(handle); + + return seclen; +} + +/** */ +int cEIT::CloseFilter(unsigned short handle) +{ + if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &handle)<0) + return -1; + return 0; +} + +/** */ +char * cEIT::mjd2string(unsigned short mjd) +{ + int y, m, d, k; + static char buf[20]; + + y = (int) ((mjd - 15078.2) / 365.25); + m = (int) ((mjd - 14956.1 - (int)(y * 365.25)) / 30.6001); + d = (int) (mjd - 14956 - (int)(y * 365.25) - (int)(m * 30.6001)); + k = (m == 14 || m == 15) ? 1 : 0; + y = y + k; + m = m - 1 - k * 12; + sprintf(buf, "%d.%d.%4d", d, m, y + 1900); + + return(buf); +} + +/** */ +int cEIT::GetEIT() +{ + unsigned char buf[1024]; + eit_t *eit; + struct eit_loop_struct1 *eitloop; + struct eit_short_event_descriptor_struct *eitevt; + int seclen; + unsigned short handle, pid; + struct pollfd pfd; + eit_event * pevt = (eit_event *)0; + time_t tstart; + + if ((handle = SetBitFilter(0x12, (0x4e << 8) | 0x00ff, SECTION_CONTINUOS))==0xffff) + { + return -1; + } +/* + pid_t process = fork(); + if (process < 0) + { + cerr << "GetEIT -1" << endl; + return -1; + } + + if (process != 0) + { + cerr << "GetEIT 0" << endl; + return 0; + } +*/ + int nReceivedEITs = 0; + tstart = time(NULL); + while ((!evtRunning.bIsValid || !evtNext.bIsValid) && nReceivedEITs < 20 && difftime(time(NULL), tstart) < 4) + { + pfd.fd=fsvbi; + pfd.events=POLLIN; + if (poll(&pfd, 1, 5000)==0) + { + //cerr << "Timeout\n"; + CloseFilter(handle); + return -1; + } + + read(fsvbi, buf, 8); + seclen=(buf[6]<<8)|buf[7]; + pid=(buf[4]<<8)|buf[5]; + + read(fsvbi, buf, seclen); + + if (seclen < (int)(sizeof(eit_t) + + sizeof(struct eit_loop_struct1) + + sizeof(struct eit_short_event_descriptor_struct))) + continue; + + eit = (eit_t *)buf; + eitloop = (struct eit_loop_struct1 *)&eit[1]; + eitevt = (struct eit_short_event_descriptor_struct *)&eitloop[1]; + + if (eitevt->descriptor_tag != EIT_SHORT_EVENT_DESCRIPTOR) + { + // printf("Tag = '%c'\n", eitevt->descriptor_tag); + continue; + } + + if (((eit->service_id_hi << 8) | eit->service_id_lo) != uProgramNumber) + { + // printf("Wrong program %04x need %04x\n", (eit->service_id_hi << 8) | eit->service_id_lo, uProgramNumber); + continue; + } + + nReceivedEITs++; + + pevt = (eit_event *)0; + if (eitloop->running_status == 4 | eitloop->running_status == 3) + pevt = (eit_event *)&evtRunning; + else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0) + pevt = (eit_event *)&evtNext; + + if (pevt) + { + unsigned char *p = (unsigned char *)&eitevt[1]; + strdvbcpy((unsigned char *)pevt->szTitle, p, eitevt->event_name_length); + pevt->szSubTitle[0] = 0; + strdvbcpy((unsigned char *)pevt->szSubTitle, &p[eitevt->event_name_length+1], (int)p[eitevt->event_name_length]); + strcpy(pevt->szDate, mjd2string((eitloop->date_hi << 8) + eitloop->date_lo)); + int hr = eitloop->time_hour + (eitloop->time_hour_ten * 10); + hr += 2; + if (hr >=24) + { + hr -= 24; + // need to switch date one day ahead here + } + sprintf(pevt->szTime, "%d:%c%c", hr, + eitloop->time_minute_ten + '0', + eitloop->time_minute + '0'); + pevt->bIsValid = true; + } + } + + CloseFilter(handle); + + return 1; +} + +/** */ +int cEIT::SetProgramNumber(unsigned short pnr) +{ + if (pnr == 0) + { + evtRunning.bIsValid = false; + evtNext.bIsValid = false; + return -1; + } + + if (pnr != uProgramNumber) + { + evtRunning.bIsValid = false; + evtNext.bIsValid = false; + uProgramNumber = pnr; + return GetEIT(); + } + return (IsValid() ? 1 : -1); +} + +/** retrieves the string for the running title */ +char * cEIT::GetRunningTitle() +{ + if (evtRunning.bIsValid) + return evtRunning.szTitle; + else + return "---"; +} +/** Retrieves the string for the running subtitle */ +char * cEIT::GetRunningSubtitle() +{ + if (evtRunning.bIsValid) + return evtRunning.szSubTitle; + else + return "---"; +} +/** Retrieves the string representing the +date of the current event + */ +char * cEIT::GetRunningDate() +{ + if (evtRunning.bIsValid) + return evtRunning.szDate; + else + return "---"; +} +/** Retrieves the string representing the +time of the current event */ +char * cEIT::GetRunningTime() +{ + if (evtRunning.bIsValid) + return evtRunning.szTime; + else + return "---"; +} +/** retrieves the string for the running title */ +char * cEIT::GetNextTitle() +{ + if (evtNext.bIsValid) + return evtNext.szTitle; + else + return "---"; +} +/** Retrieves the string for the running subtitle */ +char * cEIT::GetNextSubtitle() +{ + if (evtNext.bIsValid) + return evtNext.szSubTitle; + else + return "---"; +} +/** Retrieves the string representing the +date of the current event + */ +char * cEIT::GetNextDate() +{ + if (evtNext.bIsValid) + return evtNext.szDate; + else + return "---"; +} +/** Retrieves the string representing the +time of the current event */ +char * cEIT::GetNextTime() +{ + if (evtNext.bIsValid) + return evtNext.szTime; + else + return "---"; +} + +/** */ +bool cEIT::IsValid() +{ + return (evtRunning.bIsValid && evtNext.bIsValid); +} + +/** */ +int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) +{ + int a; + for (a = 0; a < max; a++) + { + if (*src == 0) + break; + + if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff)) + *dst++ = *src++; + else + src++; + } + *dst = 0; + return a; +} diff --git a/eit.h b/eit.h new file mode 100644 index 000000000..28329f427 --- /dev/null +++ b/eit.h @@ -0,0 +1,92 @@ +/*************************************************************************** + eit.h - description + ------------------- + begin : Fri Aug 25 2000 + copyright : (C) 2000 by Robert Schneider + email : Robert.Schneider@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * $Id: eit.h 1.1 2000/09/03 10:23:24 kls Exp $ + ***************************************************************************/ + +#ifndef __EIT_H +#define __EIT_H + +#include + +typedef struct eit_event { + + bool bIsValid; + char szTitle[512]; + char szSubTitle[512]; + char szDate[12]; + char szTime[12]; + +}eit_event; + +/** + *@author Robert Schneider + */ + +class cEIT { +public: + cEIT(); + ~cEIT(); + /** */ + int GetEIT(); + /** */ + int SetProgramNumber(unsigned short pnr); + /** Retrieves the string representing the time of the current event */ + char * GetRunningTime(); + /** Retrieves the string representing the date of the current event */ + char * GetRunningDate(); + /** Retrieves the string for the running subtitle */ + char * GetRunningSubtitle(); + /** retrieves the string for the running title */ + char * GetRunningTitle(); + /** Retrieves the string representing the time of the next event */ + char * GetNextTime(); + /** Retrieves the string representing the date of the next event */ + char * GetNextDate(); + /** Retrieves the string for the next subtitle */ + char * GetNextSubtitle(); + /** retrieves the string for the next title */ + char * GetNextTitle(); + /** */ + bool IsValid(); + +protected: // Protected attributes + /** Device name of VBI device */ + const char * cszBitFilter; +protected: // Protected attributes + /** handle to VBI device (usually /dev/vbi) */ + int fsvbi; + /** Describes the event next on */ + eit_event evtNext; + /** Describes the running event */ + eit_event evtRunning; +protected: // Protected methods + /** Set the bitfilter in vbi device to return +correct tables */ + int SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode); + /** */ + int GetSection(unsigned char *buf, ushort PID, unsigned char sec); + /** */ + int CloseFilter(unsigned short handle); + /** */ + char * mjd2string(unsigned short mjd); + /** */ + int strdvbcpy(unsigned char *dst, unsigned char *src, int max); +public: // Public attributes + /** */ + unsigned short uProgramNumber; +}; + +#endif diff --git a/interface.c b/interface.c index 244488aa7..2ae49c330 100644 --- a/interface.c +++ b/interface.c @@ -4,13 +4,16 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.10 2000/07/15 12:39:20 kls Exp $ + * $Id: interface.c 1.11 2000/09/03 10:17:21 kls Exp $ */ #include "interface.h" #include +#include "eit.h" #include "remote.h" +cEIT EIT; + #if defined(REMOTE_RCU) cRcIoRCU RcIo("/dev/ttyS1"); #elif defined(REMOTE_LIRC) @@ -316,7 +319,7 @@ void cInterface::DisplayChannel(int Number, const char *Name) { RcIo.Number(Number); if (Name && !Recording()) { - Open(MenuColumns, 1); + Open(MenuColumns, EIT.IsValid() ? 5 : 1); char buffer[MenuColumns + 1]; snprintf(buffer, sizeof(buffer), "%d %s", Number, Name ? Name : ""); Write(0, 0, buffer); @@ -324,7 +327,21 @@ void cInterface::DisplayChannel(int Number, const char *Name) struct tm *now = localtime(&t); snprintf(buffer, sizeof(buffer), "%02d:%02d", now->tm_hour, now->tm_min); Write(-5, 0, buffer); - if (Wait(2, true) == kOk) + if (EIT.IsValid()) { + const int t = 7; + int w = MenuColumns - t; + Write(0, 1, EIT.GetRunningTime(), clrYellow, clrBackground); + snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningTitle()); + Write(t, 1, buffer, clrCyan, clrBackground); + snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningSubtitle()); + Write(t, 2, buffer, clrCyan, clrBackground); + Write(0, 3, EIT.GetNextTime(), clrYellow, clrBackground); + snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextTitle()); + Write(t, 3, buffer, clrCyan, clrBackground); + snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextSubtitle()); + Write(t, 4, buffer, clrCyan, clrBackground); + } + if (Wait(5, true) == kOk) GetKey(); Close(); } diff --git a/svdrp.c b/svdrp.c index 9fef18484..01e9fb7bf 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.4 2000/08/06 12:52:04 kls Exp $ + * $Id: svdrp.c 1.5 2000/08/26 12:51:51 kls Exp $ */ #define _GNU_SOURCE @@ -639,7 +639,7 @@ void cSVDRP::Process(void) //TODO how can we get the *full* hostname? gethostname(buffer, sizeof(buffer)); time_t now = time(NULL); - Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", VDRVERSION, buffer, ctime(&now)); + Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now)); } int rbytes = readstring(filedes, buffer, sizeof(buffer) - 1); if (rbytes > 0) { diff --git a/timers.conf b/timers.conf index 47b40674a..733fb9c28 100644 --- a/timers.conf +++ b/timers.conf @@ -1,13 +1,11 @@ -0:10:-T-----:2058:2202:99:10:Quarks: -0:5:-T-----:2100:2205:99:10:RudisSuchmaschine: -1:10:---T---:2158:2250:99:99:DiePlaneten: +1:10:-T-----:2058:2202:99:10:Quarks: +1:26:-T-----:2203:0015:99:99:UFO: 0:3:---T---:2211:2300:99:10:Switch: +1:2:----F--:2140:2225:10:10:WWW: 1:15:-----S-:1358:1435:99:7:Neues: 1:1:-----S-:1445:1610:99:30:Hammerman: -0:2:-----S-:2200:2350:99:30:Wochenshow: +0:11:-----S-:2158:2235:99:99:Computer: +1:2:-----S-:2213:2320:99:30:Wochenshow: 1:11:------S:2058:2120:99:10:Centauri: -0:15:MTWTF--:1828:1901:10:5:nano: -1:1:-TWTF--:0858:0940:99:99:Ellen: -1:2:----F--:2140:2225:10:10:WWW: -1:11:-----S-:2158:2235:99:99:Computer: -1:23:-----S-:2200:0020:99:99:BBC special: +1:15:MTWTF--:1828:1901:10:5:nano: +1:1:-TWTF--:0855:0945:99:99:Ellen: From 76c331181a23f97d5e3f2b55c4741ef4e521242d Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 10 Sep 2000 18:00:00 +0200 Subject: [PATCH 010/307] Version 0.63 - The new "Setup" menu allows the user to configure several parameters to his/her personal taste (see MANUAL for details). - Workaround for a driver timing problem in cDvbApi::Cmd(), which sometimes caused the OSD to no longer be displayed (thanks to Niels de Carpentier). - Added the '-m486' option to the compiler call. - If a channel name contains a colon (':') it is now replaced with a '|' in channels.conf. - Not everybody appears to like the "page scrolling" mechanism introduced by Heino Goldenstein in version 0.61, so this is now configurable via the "Setup" menu. - The new 'dvbrc2vdr' tool (thanks to Plamen Ganev!) can be used to convert 'dvbrc' channel files into 'vdr' format. - Channels can now be "grouped" (thanks to Plamen Ganev!). See MANUAL for details. There is currently no mechanism to define and maintain "Channel groups" via the menu, so you'll have to insert "Channel group" control lines into your 'channels.conf' file manually (for example with a text editor). - Started a new file named FORMATS with a description of the various file formats used by VDR. - The "Primary DVB interface" can now be chosen via the "Setup" menu. - Display of the "current/next" information when switching channels can now be disabled via the "Setup" menu. - The "current/next" display now only shows those lines that actually contain information. - When directly selecting a channel by entering the channel number, the digits entered so far together with the name of that channel are displayed on the OSD (suggested by Martin Hammerschmid). --- CONTRIBUTORS | 8 + FORMATS | 35 ++ HISTORY | 30 ++ MANUAL | 45 +- Makefile | 4 +- Tools/dvbrc2vdr/Makefile | 16 + Tools/dvbrc2vdr/channels.conf | 282 +++++++++++ Tools/dvbrc2vdr/dvbrc.hotbird | 63 +++ Tools/dvbrc2vdr/dvbrc2vdr.c | 183 +++++++ Tools/dvbrc2vdr/hotbird2 | 878 ++++++++++++++++++++++++++++++++++ Tools/dvbrc2vdr/test.conf | 799 +++++++++++++++++++++++++++++++ channels.conf | 2 +- config.c | 232 +++++++-- config.h | 52 +- dvbapi.c | 30 +- dvbapi.h | 10 +- interface.c | 73 ++- interface.h | 6 +- menu.c | 149 +++++- menu.h | 13 +- osd.c | 98 ++-- osd.h | 11 +- setup.conf | 4 + svdrp.c | 57 +-- timers.conf | 11 +- tools.c | 12 +- tools.h | 3 +- vdr.c | 59 +-- 28 files changed, 2962 insertions(+), 203 deletions(-) create mode 100644 FORMATS create mode 100644 Tools/dvbrc2vdr/Makefile create mode 100644 Tools/dvbrc2vdr/channels.conf create mode 100644 Tools/dvbrc2vdr/dvbrc.hotbird create mode 100644 Tools/dvbrc2vdr/dvbrc2vdr.c create mode 100644 Tools/dvbrc2vdr/hotbird2 create mode 100644 Tools/dvbrc2vdr/test.conf create mode 100644 setup.conf diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 07f9d16df..9f6aa1b55 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -10,6 +10,8 @@ Carsten Koch Plamen Ganev for fixing the frequency offset for Hotbird channels for adding the 'xtvrc2vdr' tool (see Tools/xtvrc2vdr) + for adding the 'dvbrc2vdr' tool (see Tools/dvbrc2vdr) + for implementing "channel grouping" Heino Goldenstein for modifying scrolling through lists to make it page up and down @@ -19,3 +21,9 @@ Guido Fiala Robert Schneider for implementing EIT support for displaying the current/next info + +Niels de Carpentier + for adding a workaround for a driver timing problem in cDvbApi::Cmd() + +Martin Hammerschmid + for suggesting to display the direct channel select input on the OSD diff --git a/FORMATS b/FORMATS new file mode 100644 index 000000000..776fb4fc2 --- /dev/null +++ b/FORMATS @@ -0,0 +1,35 @@ +Video Disk Recorder File Formats +-------------------------------- + +* channels.conf + + This file contains the channel setup. + It consists of two types of lines: "group delimiters" and "channel + definitions". + + A "group delimiter" is a line starting with a ':' as the very first + character, followed by arbitrary text. + Example: ":First group" + + A "channel definition" is a line with channel data, where the fields + are separated by ':' characters: + Example: "RTL:12188:h:1:27500:163:104:0:12003" + + The fields in a channel definition have the following meaning (from left + to right): + + - Name: the channel's name (if the name originally contains a ':' character + it has to be replaced by '|') + - Frequency in MHz (as an integer) + - Polarization (one of 'h', 'H', 'v', 'V') + - Diseqc number + - Symbol rate + - Video PID + - Audio PID + - Conditional Access (0 = Free To Air, 1 = can be decrypted by the first + DVB card, 2 = can be decrypted by the second DVB card) + - Program Number + +* timers.conf + + TODO diff --git a/HISTORY b/HISTORY index f5c3cb93b..dafab3b7c 100644 --- a/HISTORY +++ b/HISTORY @@ -138,3 +138,33 @@ Video Disk Recorder Revision History done for some of the channels in the default 'channels.conf'. Some other parameters in the default 'channels.conf' have also been updated, so please make sure your timers still use the correct channels! + +2000-09-10: Version 0.63 + +- The new "Setup" menu allows the user to configure several parameters to his/her + personal taste (see MANUAL for details). +- Workaround for a driver timing problem in cDvbApi::Cmd(), which sometimes caused + the OSD to no longer be displayed (thanks to Niels de Carpentier). +- Added the '-m486' option to the compiler call. +- If a channel name contains a colon (':') it is now replaced with a '|' in + channels.conf. +- Not everybody appears to like the "page scrolling" mechanism introduced by + Heino Goldenstein in version 0.61, so this is now configurable via the "Setup" + menu. +- The new 'dvbrc2vdr' tool (thanks to Plamen Ganev!) can be used to convert + 'dvbrc' channel files into 'vdr' format. +- Channels can now be "grouped" (thanks to Plamen Ganev!). See MANUAL for details. + There is currently no mechanism to define and maintain "Channel groups" via + the menu, so you'll have to insert "Channel group" control lines into your + 'channels.conf' file manually (for example with a text editor). +- Started a new file named FORMATS with a description of the various file + formats used by VDR. +- The "Primary DVB interface" can now be chosen via the "Setup" menu. +- Display of the "current/next" information when switching channels can now + be disabled via the "Setup" menu. +- The "current/next" display now only shows those lines that actually contain + information. +- When directly selecting a channel by entering the channel number, the digits + entered so far together with the name of that channel are displayed on the + OSD (suggested by Martin Hammerschmid). + diff --git a/MANUAL b/MANUAL index b05c35088..91c9bffd3 100644 --- a/MANUAL +++ b/MANUAL @@ -12,8 +12,8 @@ Video Disk Recorder User's Manual Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause - Left - - - Disable Decrement - Search back - Right - - - Enable Increment - Search forward + Left Prev group - - Disable Decrement - Search back + Right Next group - - Enable Increment - Search forward Ok Ch display Select Switch Edit Accept Play Progress disp. Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on Back - Menu off Main menu Main menu Discard Main menu - @@ -72,6 +72,18 @@ Video Disk Recorder User's Manual To bring up the channel display without switching channels you can press the "Ok" button. +* Switching through channel groups + + If the 'channels.conf' file contains "group separators" you can switch + through these groups by pressing the "Left" and "Right" key while no + menu is being displayed. The channel display will show the name of the + group, and if you press the "Ok" button while the group name is being + displayed, you will switch to the first channel of that group. + + Channel groups can be whatever you decide them to be. You can either + group your channels by "Bouquet", by language, genre or whatever your + preferences may be. + * Instant Recording You can start recording the current channel by pressing the "Red" button @@ -153,3 +165,32 @@ Video Disk Recorder User's Manual their date and time). If this field is left blank, the channel name will be used to form the name of the recording. + +* Parameters in the "Setup" menu + + Select "Setup" from the main menu to enter the setup menu. From there you can + modify the following system parameters (note that "boolean" values will be + displayed as "no" and "yes" in the "Setup" menu, while in the setup file they + are stored as '0' and '1', respectively): + + PrimaryDVB = 1 Defines the primary DVB interface (i.e. the one that + will display the menus and will react on input through + the remote control). Valid values range from '1' to the + number of installed DVB cards. If more than one DVB card + is installed and a recording is to be started, the + program will try to use a free DVB card that is different + from the primary DVB interface, so that the viewer will + be disturbed as little as possible. + + ShowInfoOnChSwitch = 1 Turns the display of the current/next information on + or off when switching the channel. The information is + always displayed when pressing the "Ok" button in + normal viewing mode. + + MenuScrollPage = 1 0 = when pressing the "Down" ("Up") key while the cursor + is on the last (first) line of a list page, the + list is advanced by a full page and the cursor will + be at the top (bottom) of that page + 1 = dto., but the cursor remains at the bottom (top) of + the page (this mode allows for faster scrolling + through long lists). diff --git a/Makefile b/Makefile index 9868ddb89..2f00459b5 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.7 2000/09/03 09:26:24 kls Exp $ +# $Id: Makefile 1.9 2000/09/10 08:55:45 kls Exp $ DVBDIR = ../DVB @@ -22,7 +22,7 @@ DEFINES += -DDEBUG_OSD endif %.o: %.c - g++ -g -O2 -Wall -c $(DEFINES) $(INCLUDES) $< + g++ -g -O2 -Wall -m486 -c $(DEFINES) $(INCLUDES) $< all: vdr diff --git a/Tools/dvbrc2vdr/Makefile b/Tools/dvbrc2vdr/Makefile new file mode 100644 index 000000000..196f50bef --- /dev/null +++ b/Tools/dvbrc2vdr/Makefile @@ -0,0 +1,16 @@ +# +# Makefile for dvbrc2vdr utility +# + +OBJS = dvbrc2vdr.o + +%.o: %.c + gcc -g -O2 -Wall -c $(DEFINES) $< + +all: dvbrc2vdr + +dvbrc2vdr: $(OBJS) + gcc -g -O2 $(OBJS) -o dvbrc2vdr + +clean: + -rm -f $(OBJS) dvbrc2vdr diff --git a/Tools/dvbrc2vdr/channels.conf b/Tools/dvbrc2vdr/channels.conf new file mode 100644 index 000000000..d26699c1d --- /dev/null +++ b/Tools/dvbrc2vdr/channels.conf @@ -0,0 +1,282 @@ +RAI Uno:11766:v:1:27500:160:80:0:0 +RAI Due:11766:v:1:27500:161:84:0:0 +RAI Tre:11766:v:1:27500:162:88:0:0 +Rete 4:11919:v:1:27500:514:670:0:0 +Canale 5:11919:v:1:27500:513:660:0:0 +Italia 1 :11919:v:1:27500:512:650:0:0 +Video Italia:12610:v:0:22000:121:122:0:0 +Grand Tour.:12670:v:0:22000:289:290:0:0 +AB Sat Passion promo:12266:h:0:27500:160:80:0:0 +Nuvolari Promo:12149:v:1:27500:176:177:0:0 +DigItaly:12673:v:1:27500:220:221:0:0 +NBC Europe:11054:h:1:27500:550:551:0:0 +Bloomberg TV UK:11642:h:1:27500:1560:1520:0:0 +Game Network:12673:v:1:27500:291:292:0:0 +Bulgaria TV:12540:h:1:27500:4612:4613:0:0 +Video Italia :12673:v:1:27500:340:341:0:0 +Racing Channel Test:11623:v:1:27500:223:243:0:0 +Fashion TV:12402:v:0:27500:163:92:0:0 +Palco Promo:12073:v:1:27500:161:84:0:0 +Coming Soon TV:12111:v:1:27500:310:311:0:0 +Alice:12149:v:1:27500:160:161:0:0 +RAI Mosaico:11766:v:1:27500:518:8191:0:0 +RAI SportSat:11804:v:1:27500:512:650:0:0 +Satisfaction TV:12092:h:1:27500:4192:4193:0:0 +RAI Nettuno Sat 2:11804:v:1:27500:513:651:0:0 +RAI Educational:11804:v:1:27500:514:652:0:0 +TelePace :11804:v:1:27500:515:653:0:0 +RAI News24:11804:v:1:27500:516:654:0:0 +AB Channel 1:12266:h:0:27500:161:84:0:0 +Studio Europa:12673:v:1:27500:230:231:0:0 +AB Passion:12692:h:1:27500:160:80:0:0 +Camera dei Deputati:11804:v:1:27500:517:655:0:0 +SAT 2000:11804:v:1:27500:518:656:0:0 +RAI NettunoSat 1:11804:v:1:27500:519:657:0:0 +Ante Prima:11881:v:1:27500:2435:2436:0:0 +Vetrina D+:12034:v:1:27500:166:105:0:0 +D+ Info:12073:v:1:27500:160:80:0:0 +SNAI:11881:v:1:27500:2561:2562:0:0 +RTL:12188:h:0:27500:163:104:0:0 +Sat.1:12480:v:0:27500:1791:1792:0:0 +Pro-7:12480:v:0:27500:255:256:0:0 +RTL2:12188:h:0:27500:166:128:0:0 +VOX:12188:h:0:27500:167:136:0:0 +ARD:11837:h:0:27500:101:102:0:0 +BR3:11837:h:0:27500:201:202:0:0 +INTV:11843:v:1:27500:2324:2325:0:0 +MC Sat Monte Carlo:12540:h:1:27500:5126:5122:0:0 +Hessen-3:11837:h:0:27500:301:302:0:0 +N3:11837:h:0:27500:401:402:0:0 +SR3:11837:h:0:27500:501:502:0:0 +WDR:11837:h:0:27500:601:602:0:0 +BR-alpha:11837:h:0:27500:701:702:0:0 +SWR BW:11837:h:0:27500:801:802:0:0 +Phoenix:11837:h:0:27500:901:902:0:0 +ZDF:11954:h:0:27500:110:120:0:0 +Test 3sat:11954:h:0:27500:210:220:0:0 +Kinderkanal:11954:h:0:27500:310:320:0:0 +arte:11954:h:0:27500:360:370:0:0 +Eurosport:11954:h:0:27500:410:420:0:0 +ZDF Infobox:11954:h:0:27500:610:620:0:0 +CNN:12168:v:0:27500:165:100:0:0 +Super RTL:12188:h:0:27500:165:120:0:0 +VOX:12188:h:0:27500:167:136:0:0 +ORF Sat:11954:h:0:27500:506:507:0:0 +DW TV:12363:v:0:27500:305:306:0:0 +Kabel 1:12480:v:0:27500:511:512:0:0 +TM3:12480:v:0:27500:767:768:0:0 +DSF:12480:v:0:27500:1023:1024:0:0 +HOT:12480:v:0:27500:1279:1280:0:0 +BloombergTV:12552:v:0:22000:162:99:0:0 +Sky News:12552:v:0:22000:305:306:0:0 +KinderNet:12574:h:0:22000:163:92:0:0 +Alice:12610:v:0:22000:162:96:0:0 +n-tv:12670:v:0:22000:162:96:0:0 +RAI Uno:12363:v:0:27500:289:290:0:0 +TW1:12692:h:0:22000:166:167:0:0 +Eins Extra:12722:h:0:22000:101:102:0:0 +Eins Festival:12722:h:0:22000:201:202:0:0 +Eins MuXx:12722:h:0:22000:301:302:0:0 +MDR:12722:h:0:22000:401:402:0:0 +ORB:12722:h:0:22000:501:502:0:0 +B1:12722:h:0:22000:601:602:0:0 +ARD Online-Kanal:12722:h:0:22000:8191:701:0:0 +Premiere World Promo:11798:h:0:27500:255:256:0:0 +Premiere:11798:h:0:27500:511:512:1:10 +Star Kino:11798:h:0:27500:767:768:1:9 +Cine Action:11798:h:0:27500:1023:1024:1:20 +Cine Comedy:11798:h:0:27500:1279:1280:1:29 +Sci Fantasy:11798:h:0:27500:1535:1536:1:41 +Romantic Movies:11798:h:0:27500:1791:1792:1:11 +Studio Universal:11798:h:0:27500:2047:2048:1:21 +TV Niepokalanow:11876:h:0:27500:305:321:0:0 +Mosaico:11934:v:0:27500:165:100:0:0 +Andalucia TV:11934:v:0:27500:166:104:0:0 +TVC Internacional:11934:v:0:27500:167:108:0:0 +Nasza TV:11992:h:0:27500:165:98:0:0 +WishLine test:12012:v:0:27500:163:92:0:0 +Pro 7 Austria:12051:v:0:27500:161:84:0:0 +Kabel 1 Schweiz:12051:v:0:27500:162:163:0:0 +Kabel 1 Austria:12051:v:0:27500:166:167:0:0 +Pro 7 Schweiz:12051:v:0:27500:289:290:0:0 +Kiosque:12129:v:0:27500:160:80:0:0 +KTO:12129:v:0:27500:170:120:0:0 +TCM:12168:v:0:27500:160:80:0:0 +Cartoon Network France & Spain:12168:v:0:27500:161:84:0:0 +TVBS Europe:12168:v:0:27500:162:88:0:0 +TVBS Europe:12168:v:0:27500:162:89:0:0 +Travel:12168:v:0:27500:163:92:0:0 +TCM Espania:12168:v:0:27500:164:96:0:0 +MTV Spain:12168:v:0:27500:167:112:0:0 +TCM France:12168:v:0:27500:169:64:0:0 +RTL2 CH:12188:h:0:27500:164:112:0:0 +La Cinquieme:12207:v:0:27500:160:80:0:0 +ARTE:12207:v:0:27500:165:100:0:0 +Post Filial TV:12226:h:0:27500:255:256:0:0 +Canal Canaris:12246:v:0:27500:160:80:0:0 +Canal Canaris:12246:v:0:27500:160:81:0:0 +Canal Canaris:12246:v:0:27500:160:82:0:0 +Canal Canaris:12246:v:0:27500:160:83:0:0 +Taquilla 0:12285:v:0:27500:165:100:0:0 +CSAT:12324:v:0:27500:160:80:0:0 +Mosaique:12324:v:0:27500:162:88:0:0 +Mosaique 2:12324:v:0:27500:163:92:0:0 +Mosaique 3:12324:v:0:27500:164:96:0:0 +Le Sesame C+:12324:v:0:27500:165:1965:0:0 +FEED:12344:h:0:27500:163:92:0:0 +RTM 1:12363:v:0:27500:162:96:0:0 +ESC 1:12363:v:0:27500:163:104:0:0 +TV5 Europe:12363:v:0:27500:164:112:0:0 +TV7 Tunisia:12363:v:0:27500:166:128:0:0 +ARTE:12363:v:0:27500:167:137:0:0 +RTP International:12363:v:0:27500:300:301:0:0 +VideoService:12422:h:0:27500:255:256:0:0 +Beta Research promo:12422:h:0:27500:1023:1024:0:0 +Canal Canarias:12441:v:0:27500:160:80:0:0 +TVC International:12441:v:0:27500:512:660:0:0 +Fitur:12441:v:0:27500:514:662:0:0 +Astra Info 1:12552:v:0:22000:164:112:0:0 +Astra Info 2:12552:v:0:22000:165:120:0:0 +Astra Vision 1:12552:v:0:22000:168:144:0:0 +Astra Vision 1:12552:v:0:22000:168:145:0:0 +Astra Vision 1:12552:v:0:22000:168:146:0:0 +Astra Vision 1:12552:v:0:22000:168:147:0:0 +Astra Vision 1:12552:v:0:22000:168:148:0:0 +Astra Vision 1:12552:v:0:22000:168:149:0:0 +Astra Vision 1:12552:v:0:22000:168:150:0:0 +RTL Tele Letzebuerg:12552:v:0:22000:168:144:0:0 +Astra Mosaic:12552:v:0:22000:175:176:0:0 +MHP test:12604:h:0:22000:5632:8191:0:0 +Bloomberg TV Spain:12610:v:0:22000:45:49:0:0 +AC 3 promo:12670:v:0:22000:308:256:0:0 +TV Polonia:10719:v:1:27500:163:92:0:0 +Credit Agricole:10834:v:1:27500:5321:5333:0:0 +La Chaine Parlementaire:10873:v:1:27500:1020:1030:0:0 +TMT:10892:v:1:27500:163:92:0:0 +Multivision Accueil:10911:v:1:27500:320:330:0:0 +RTL:11054:h:1:27500:160:80:0:0 +VOX:11054:h:1:27500:500:501:0:0 +Sat 1 A:11054:h:1:27500:511:512:0:0 +RTL II Austria:11054:h:1:27500:520:521:0:0 +ZDF:11054:h:1:27500:570:571:0:0 +K-TV:11054:h:1:27500:580:581:0:0 +Sat 1 Schweiz:11604:v:1:27500:101:102:0:0 +MKTV:11623:v:1:27500:222:242:0:0 +Olisat TV Promo:11623:v:1:27500:226:246:0:0 +Bloomberg TV Germany:11642:v:1:27500:1460:1420:0:0 +Bloomberg TV UK:11642:v:1:27500:1560:1520:0:0 +SAT 7:11642:v:1:27500:1660:1620:0:0 +Multivision 1:11662:v:1:27500:120:130:0:0 +Dubai EDTV:11746:v:1:27500:4130:4131:0:0 +Dubai Sport Channel:11746:v:1:27500:4386:4387:0:0 +Dubai Business Channel:11746:v:1:27500:4642:4643:0:0 +Dubai EDTV:11746:v:1:27500:4898:4899:0:0 +ERT Sat:11823:v:1:27500:521:740:0:0 +TVL:11843:v:1:27500:2441:2442:0:0 +Team TV :11881:v:1:27500:2305:2306:0:0 +ART Europe:12015:v:1:27500:164:96:0:0 +ESC 2:12015:v:1:27500:166:104:0:0 +ART Iqra:12015:v:1:27500:168:112:0:0 +Vacaciones TV:12092:v:1:27500:4112:4113:0:0 +TvL - TV Locale:12092:v:1:27500:4160:4161:0:0 +TVE Internacional:12092:v:1:27500:4208:4209:0:0 +TVG - TV de Galicia :12092:v:1:27500:4224:4225:0:0 +La Cadena Del Milagro:12092:v:1:27500:4368:4369:0:0 +Fiesta:12092:v:1:27500:4432:4433:0:0 +Visions Europe:12092:v:1:27500:4416:4417:0:0 +SateliTV/TV Sex Channel:12092:v:1:27500:4480:4481:0:0 +Krisma:12111:v:1:27500:200:201:0:0 +NTV:12111:v:1:27500:210:211:0:0 +Armenia TV 1:12111:v:1:27500:240:241:0:0 +SMAU Channel :12111:v:1:27500:260:261:0:0 +JSC - Al Jazeera Satellite Ch :12111:v:1:27500:270:271:0:0 +Il Tirreno Sat:12111:v:1:27500:280:301:0:0 +CCTV 4:12169:h:1:27500:516:690:0:0 +Kanali Vuolis:12169:v:1:27500:517:700:0:0 +Nova Promo:12169:v:1:27500:521:740:0:0 +ERT Sat :12188:v:1:27500:514:652:0:0 +Kanali Voulis:12188:v:1:27500:515:653:0:0 +OTE Promo:12188:v:1:27500:517:655:0:0 +TV 5 Europe:12245:v:1:27500:121:131:0:0 +Fashion TV:12245:h:1:27500:123:133:0:0 +TV Ajara:12245:v:1:27500:127:137:0:0 +Telekom TV:12265:v:1:27500:1460:1420:0:0 +SLO-TV1:12303:v:1:27500:200:201:0:0 +Polonia 1:12303:v:1:27500:205:206:0:0 +Super 1:12303:v:1:27500:207:208:0:0 +Sicilia Internacional:12303:v:1:27500:210:211:0:0 +SicilSat:12303:v:1:27500:225:226:0:0 +TBNE Italy:12303:v:1:27500:230:231:0:0 +Countdown TV:12303:v:1:27500:235:236:0:0 +Napoli International:12303:v:1:27500:240:241:0:0 +Magic TV:12303:v:1:27500:245:246:0:0 +TEST:12341:v:1:27500:165:108:0:0 +Colour Bars:12380:v:1:27500:3022:3032:0:0 +Tele 24 :12380:v:1:27500:3023:3033:0:0 +Abu Dhabi TV :12380:v:1:27500:3024:3034:0:0 +LCA:12380:v:1:27500:3025:3035:0:0 +RTV Montenegro:12380:v:1:27500:3026:3036:0:0 +SRG SSR Sat Access :12399:v:1:27500:165:98:0:0 +Jam-e-Jam Network 1 (IRIB 1):12437:v:1:27500:160:80:0:0 +Jam-e-Jam Network 2 (IRIB 2):12437:v:1:27500:161:82:0:0 +Sahar University Network:12437:v:1:27500:162:84:0:0 +Maharishi Open University:12476:v:1:27500:42:43:0:0 +Europe by Satellite:12476:h:1:27500:101:201:0:0 +Pink Backup:12476:v:1:27500:308:256:0:0 +Mizik Tropical:12476:h:1:27500:435:436:0:0 +TLI info card:12476:h:1:27500:771:768:0:0 +Liberty TV:12476:h:1:27500:941:942:0:0 +HRT TV 1:12520:v:1:27500:100:101:0:0 +HRT National:12520:v:1:27500:107:108:0:0 +BVN TV:12520:v:1:27500:210:211:0:0 +Sicilia International:12520:v:1:27500:501:502:0:0 +Sardegna Uno:12520:v:1:27500:503:504:0:0 +TGRT:12520:v:1:27500:505:506:0:0 +Euro Mediterraneo:12520:v:1:27500:510:511:0:0 +WWWTravel TV:12540:v:1:27500:1180:1183:0:0 +WWWTravel TV:12540:v:1:27500:1180:1184:0:0 +WWWTravel TV:12540:v:1:27500:1180:1185:0:0 +MBC:12597:v:1:27500:160:80:0:0 +SIMA-YEH-MOGHAVEMENT:12597:v:1:27500:161:84:0:0 +NITV (National Iran TV ):12597:v:1:27500:163:92:0:0 +BET International:12597:v:1:27500:167:108:0:0 +JSTV 2 Info Card:12597:v:1:27500:2011:2012:0:0 +EuroNews French:12597:v:1:27500:2221:2231:0:0 +EuroNews English:12597:v:1:27500:2221:2232:0:0 +EuroNews German:12597:v:1:27500:2221:2233:0:0 +EuroNews Italian:12597:v:1:27500:2221:2234:0:0 +EuroNews Spanish:12597:v:1:27500:2221:2235:0:0 +EuroNews Portuguese:12597:v:1:27500:2221:2236:0:0 +EuroNews English:12597:v:1:27500:2221:2237:0:0 +Canal Agro Rual:12597:v:1:27500:2321:2331:0:0 +MMO9:12616:v:1:27500:2561:2562:0:0 +Dubai Sport Channel:12654:v:1:27500:1060:1020:0:0 +Sharjah TV :12654:v:1:27500:1160:1120:0:0 +Qatar TV:12654:v:1:27500:1260:1220:0:0 +Saudi Channel 1 :12654:v:1:27500:1360:1320:0:0 +Kuwait Space Channel :12654:v:1:27500:1460:1420:0:0 +Libya TV:12654:v:1:27500:1560:1520:0:0 +Sudan TV:12654:v:1:27500:1660:1620:0:0 +Oman TV:12654:v:1:27500:1760:1720:0:0 +Jordan Satellite Channel:12654:v:1:27500:1860:1820:0:0 +Iraq Satellite Channel:12654:v:1:27500:1960:1920:0:0 +Thai TV 5 Global Network :12673:v:1:27500:200:201:0:0 +Telemarket:12673:v:1:27500:350:351:0:0 +Evision:12673:v:1:27500:360:361:0:0 +Onyx TV:12692:v:1:27500:161:84:0:0 +EWTN:10723:v:1:29900:1001:1201:0:0 +Test (Newslynx):10723:v:1:29900:1002:1202:0:0 +MTA International:10723:v:1:29900:1004:1204:0:0 +J TV Test:10992:v:1:27500:2436:2437:0:0 +Bloomberg UK Test Card:11242:v:1:27500:162:88:0:0 +Channel SUN TV:11604:h:1:27500:111:112:0:0 +Olisat TLC test card:11623:v:1:27500:225:245:0:0 +Channel SUN Test (KBT):11623:v:1:27500:229:249:0:0 +Rai way 3 test card:11766:v:1:27500:164:96:0:0 +Rai way 1 test card:11766:v:1:27500:515:653:0:0 +Rai way 2 test card:11766:v:1:27500:516:654:0:0 +Test (Local Satellite):12092:v:1:27500:4176:4177:0:0 +Retelsat Test:12092:v:1:27500:4464:4465:0:0 +AIT Test Card:12111:v:1:27500:220:221:0:0 +Fucino Test Card:12111:v:1:27500:230:231:0:0 +PGM1:12230:v:1:13396:1160:1121:0:0 diff --git a/Tools/dvbrc2vdr/dvbrc.hotbird b/Tools/dvbrc2vdr/dvbrc.hotbird new file mode 100644 index 000000000..8717fdbcc --- /dev/null +++ b/Tools/dvbrc2vdr/dvbrc.hotbird @@ -0,0 +1,63 @@ +LNB ID 1 TYPE 1 LOF1 9750000 LOF2 10600000 SLOF 11800000 DISEQCNR 1 + SAT ID 1 NAME "Hotbird" LNBID 1 FMIN 12015000 FMAX 12100000 + TRANSPONDER ID 119c8 SATID 0001 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 + CHANNEL ID 0 NAME "T+ BIANCO" SATID ffffff TPID 119c8 SID 2b5d TYPE 1 VPID a0 APID 50 APID 51 TTPID 2c PCRPID a0 + CHANNEL ID 1 NAME "T+ NERO" SATID ffffff TPID 119c8 SID 2b5f TYPE 1 VPID a1 APID 54 APID 55 TTPID 2d PCRPID a1 + CHANNEL ID 2 NAME "T+ GRIGIO" SATID ffffff TPID 119c8 SID 2b61 TYPE 1 VPID a2 APID 58 APID 59 PCRPID a2 + CHANNEL ID 3 NAME "R4" SATID ffffff TPID 119c8 SID 18 TYPE 1 VPID a3 PCRPID a3 + CHANNEL ID 4 NAME "16:9 TELE+" SATID ffffff TPID 119c8 SID 2b63 TYPE 1 VPID a4 APID 60 APID 61 PCRPID a4 + CHANNEL ID 5 NAME "VETRINA D+" SATID ffffff TPID 119c8 SID 2b65 TYPE 1 PCRPID a5 + CHANNEL ID 6 NAME "R/RAGAZZI RAISAT" SATID ffffff TPID 119c8 SID 2b67 TYPE 1 PCRPID a6 + TRANSPONDER ID 11a90 SATID 0001 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 + CHANNEL ID 7 NAME "PALCO" SATID ffffff TPID 11a90 SID 2bc1 TYPE 1 PCRPID af + CHANNEL ID 8 NAME "INFO" SATID ffffff TPID 11a90 SID 2bc3 TYPE 1 VPID a1 PCRPID af + CHANNEL ID 9 NAME "P1" SATID ffffff TPID 11a90 SID 2bc5 TYPE 1 VPID a2 APID 58 APID 59 PCRPID af + CHANNEL ID a NAME "P2" SATID ffffff TPID 11a90 SID 2bc7 TYPE 1 VPID a3 APID 5c APID 5d PCRPID af + CHANNEL ID b NAME "P3" SATID ffffff TPID 11a90 SID 2bc9 TYPE 1 VPID a4 APID 60 APID 61 PCRPID af + CHANNEL ID c NAME "P4" SATID ffffff TPID 11a90 SID 2bcb TYPE 1 VPID a5 APID 64 APID 65 PCRPID af + CHANNEL ID d NAME "P5" SATID ffffff TPID 11a90 SID 2bcd TYPE 1 VPID a6 APID 68 APID 69 PCRPID af + CHANNEL ID e NAME "P6" SATID ffffff TPID 11a90 SID 2bcf TYPE 1 VPID a7 APID 6c APID 6d PCRPID af + TRANSPONDER ID 11964 SATID 0001 TYPE 1 FREQ 12015000 POL H SRATE 27500000 FEC 8 + CHANNEL ID f NAME "ART VARIETY" SATID ffffff TPID 11964 SID 19a TYPE 1 VPID a0 PCRPID a0 + CHANNEL ID 10 NAME "ART CHILDREN" SATID ffffff TPID 11964 SID 1a4 TYPE 1 VPID a1 PCRPID a1 + CHANNEL ID 11 NAME "ART MOVIES" SATID ffffff TPID 11964 SID 1ae TYPE 1 VPID a2 PCRPID a2 + CHANNEL ID 12 NAME "ART MUSIC" SATID ffffff TPID 11964 SID 1b8 TYPE 1 VPID a3 PCRPID a3 + CHANNEL ID 13 NAME "ART EUROPE" SATID ffffff TPID 11964 SID 1c2 TYPE 0 VPID a4 PCRPID a4 + CHANNEL ID 14 NAME "LBC EUROPE" SATID ffffff TPID 11964 SID 1cc TYPE 1 VPID a5 PCRPID a5 + CHANNEL ID 15 NAME "EGYPT SAT. CH. 2" SATID ffffff TPID 11964 SID 1d6 TYPE 1 VPID a6 PCRPID a6 + CHANNEL ID 16 NAME "ART SPORT" SATID ffffff TPID 11964 SID 1d8 TYPE 1 VPID a7 PCRPID a7 + CHANNEL ID 17 NAME "IQRA" SATID ffffff TPID 11964 SID 1da TYPE 1 VPID a8 PCRPID a8 + TRANSPONDER ID 11a2c SATID 0001 TYPE 1 FREQ 12341001 POL H SRATE 27500000 FEC 8 + CHANNEL ID ffffffff NAME "CNN" SATID ffffff TPID 11a2c SID 2ced TYPE 1 PCRPID af + CHANNEL ID ffffffff NAME "BBC" SATID ffffff TPID 11a2c SID 2cef TYPE 1 PCRPID af + CHANNEL ID ffffffff NAME "BLOOMBERG" SATID ffffff TPID 11a2c SID 2cf1 TYPE 1 PCRPID af + CHANNEL ID ffffffff NAME "CNBC" SATID ffffff TPID 11a2c SID 2cf3 TYPE 1 PCRPID af + CHANNEL ID ffffffff NAME "SKYNews" SATID ffffff TPID 11a2c SID 2cf5 TYPE 1 PCRPID af + CHANNEL ID ffffffff NAME "TST2" SATID ffffff TPID 11a2c SID 2cf7 TYPE 1 PCRPID af + CHANNEL ID ffffffff NAME "TV5" SATID ffffff TPID 11a2c SID 2cf9 TYPE 1 PCRPID af + CHANNEL ID ffffffff NAME "EPG" SATID ffffff TPID 11a2c SID 2cfb TYPE 1 PCRPID af + CHANNEL ID ffffffff NAME "CNN" SATID ffffff TPID 11a2c SID 2cfd TYPE 1 VPID a0 APID 50 PCRPID af + CHANNEL ID ffffffff NAME "CNBC" SATID ffffff TPID 11a2c SID 2cff TYPE 1 VPID a3 APID 5c PCRPID af + CHANNEL ID ffffffff NAME "TV5" SATID ffffff TPID 11a2c SID 2d01 TYPE 1 VPID a6 APID 68 PCRPID af + CHANNEL ID ffffffff NAME "BBC WORLD" SATID ffffff TPID 11a2c SID 2d03 TYPE 1 VPID a1 APID 54 PCRPID af + CHANNEL ID ffffffff SATID ffffff TPID 11a2c SID 2d4b TYPE 0 PCRPID 1ffe + CHANNEL ID ffffffff SATID ffffff TPID 11a2c SID 26fc TYPE 0 PCRPID 1ffe + CHANNEL ID ffffffff SATID ffffff TPID 11a2c SID 26fd TYPE 0 PCRPID 1ffe + TRANSPONDER ID 11af4 SATID 0001 TYPE 1 FREQ 12091901 POL H SRATE 27500000 FEC 8 + CHANNEL ID 27 NAME "Bolsa" SATID ffffff TPID 11af4 SID 222e TYPE 0 + CHANNEL ID 28 NAME "Testw" SATID ffffff TPID 11af4 SID 222f TYPE 0 + CHANNEL ID 29 NAME "SIRE" SATID ffffff TPID 11af4 SID 2230 TYPE 0 PCRPID 102 + CHANNEL ID 2a NAME "Telesierra" SATID ffffff TPID 11af4 SID 2200 TYPE 0 VPID 1040 APID 1041 PCRPID 1040 + CHANNEL ID 2b NAME "vtv" SATID ffffff TPID 11af4 SID 21fd TYPE 0 VPID 1010 APID 1012 APID 1011 APID 1013 PCRPID 1010 + CHANNEL ID 2c NAME "Satisfaction" SATID ffffff TPID 11af4 SID 2202 TYPE 0 VPID 1060 APID 1061 PCRPID 1060 + CHANNEL ID 2d NAME "C. Milagro" SATID ffffff TPID 11af4 SID 2207 TYPE 0 VPID 1110 APID 1111 PCRPID 1110 + CHANNEL ID 2e NAME "Fiesta" SATID ffffff TPID 11af4 SID 2210 TYPE 0 VPID 1150 APID 1151 APID 1152 PCRPID 1150 + CHANNEL ID 2f NAME "TVE Internacional" SATID ffffff TPID 11af4 SID 2203 TYPE 0 VPID 1070 APID 1071 PCRPID 1070 + CHANNEL ID 30 NAME "TV Galicia" SATID ffffff TPID 11af4 SID 2204 TYPE 0 APID 1090 PCRPID 1090 + CHANNEL ID 31 NAME "Radio Gallega" SATID ffffff TPID 11af4 SID 2205 TYPE 0 APID 1090 PCRPID 1090 + CHANNEL ID 32 NAME "Retelsat" SATID ffffff TPID 11af4 SID 2212 TYPE 1 VPID 1170 APID 1171 PCRPID 1170 + CHANNEL ID 33 NAME "Musicam 1" SATID ffffff TPID 11af4 SID 2209 TYPE 1 APID 1136 PCRPID 1136 + CHANNEL ID 34 NAME "Musicam 2" SATID ffffff TPID 11af4 SID 220a TYPE 1 APID 1131 PCRPID 1131 + CHANNEL ID 35 NAME "Musicam 3" SATID ffffff TPID 11af4 SID 220b TYPE 1 APID 1136 PCRPID 1136 + CHANNEL ID 36 NAME "Musicam 4" SATID ffffff TPID 11af4 SID 220c TYPE 1 APID 1136 PCRPID 1136 + CHANNEL ID 37 NAME "Musicam 5" SATID ffffff TPID 11af4 SID 220d TYPE 1 APID 1136 PCRPID 1136 diff --git a/Tools/dvbrc2vdr/dvbrc2vdr.c b/Tools/dvbrc2vdr/dvbrc2vdr.c new file mode 100644 index 000000000..243ddc02d --- /dev/null +++ b/Tools/dvbrc2vdr/dvbrc2vdr.c @@ -0,0 +1,183 @@ +/* + * * dvbrc2vdr.c: Converts 'xtvrc' files to 'vdr' channel format + * * + * * Copyright (C) 2000 Plamen Ganev + * * + * * This program is free software; you can redistribute it and/or + * * modify it under the terms of the GNU General Public License + * * as published by the Free Software Foundation; either version 2 + * * of the License, or (at your option) any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * * + * * The author can be reached at pganev@comm.it + * * + * */ + + +#include +#include +#include +#include + +#define MAX_LINE_LEN 1024 +#define MAX_NAME 100 +#define TOKS ": \n\r" +#define NAMETOKS ":\n\r" + +typedef struct { + char Name[MAX_NAME+1]; + int freq; + int color, hue, bright, saturation ; + int nitv, input ; + int pol, srate, fec, vpid, apid, lnbnum, type; + int sid, pcrpid ; +} CHANNEL_DATA ; + +void strupr( char *s ){ + while ( s && *s ){ + *s = toupper(*s); + s++; + } +} + +/* Warning: This function uses the last strtol string! */ +int GetTpInfo( CHANNEL_DATA *channel ) +{ + // s is: ID x SATID x TYPE x FREQ x POL H/V SRATE x FEC x + char *p ; + + p = strtok( NULL, TOKS ) ; /* Skip ID */ + p = strtok( NULL, TOKS ) ; /* Skip x */ + p = strtok( NULL, TOKS ) ; /* Skip SatId */ + p = strtok( NULL, TOKS ) ; /* Skip x */ + p = strtok( NULL, TOKS ) ; /* Skip Type */ + p = strtok( NULL, TOKS ) ; /* Skip x */ + p = strtok( NULL, TOKS ) ; /* Skip Freq */ + p = strtok( NULL, TOKS ) ; /* Get Freq */ + channel->freq = atol( p ) / 1000 ; + p = strtok( NULL, TOKS ) ; /* Skip Pol */ + p = strtok( NULL, TOKS ) ; /* Get H/V */ + channel->pol = (*p=='V') ? 1 : 0 ; + p = strtok( NULL, TOKS ) ; /* Skip SRATE */ + p = strtok( NULL, TOKS ) ; /* Get srate */ + channel->srate = atol(p) / 1000 ; /* Convert SRATE */ + return 0; +} + +/* Warning: This function uses the last strtol string! */ +int GetChInfo( CHANNEL_DATA *channel ) +{ + /* s is: ID x NAME "name" SATID x TPID x SID x TYPE x VPID x APID x */ + char *p, *q ; + + p = strtok( NULL, TOKS ) ; + while ( p ) { + if ( !strcmp( p, "ID" )) { + p = strtok( NULL, TOKS ) ; + } else if ( !strcmp( p, "NAME")) { + while ( *p++ ); /* Jump to end of "NAME" */ + p++ ; /* One More */ + while ( *p == '"' ) p++ ; /* Skip the " */ + q = channel->Name ; + while ( *p != '"' ) + if ( *p == ':' ) + *q++ = '|', p++ ; + else + *q++ = *p++ ; /* Copy the name */ + *q = 0 ; + p++ ; + p = strtok( p, TOKS ) ; + channel->apid = 8190; + channel->vpid = 8190; + channel->pcrpid = 0 ; + channel->sid = 0; + } else if ( !strcmp( p, "VPID")) { + p = strtok( NULL, TOKS ) ; + channel->vpid = strtol( p, NULL, 16 ) ; + p = strtok( NULL, TOKS ) ; + } else if ( !strcmp( p, "APID")) { + p = strtok( NULL, TOKS ) ; + channel->apid = strtol( p, NULL, 16 ) ; + p = strtok( NULL, TOKS ) ; + } else if ( !strcmp( p, "SID")) { + p = strtok( NULL, TOKS ) ; + channel->sid = strtol( p, NULL, 16 ) ; + p = strtok( NULL, TOKS ) ; + } else if ( !strcmp( p, "PCRPID")) { + p = strtok( NULL, TOKS ) ; + channel->pcrpid = strtol( p, NULL, 16 ) ; + p = strtok( NULL, TOKS ) ; + } else { + p = strtok( NULL, TOKS ) ; + } + } + return 1; +} + +int ReadChannel( FILE *f, CHANNEL_DATA *channel ) { + static char s[MAX_LINE_LEN+1]; + char *p; + + while (fgets( s, MAX_LINE_LEN, f )){ + p = strtok( s, TOKS ) ; + strupr( p ) ; + + if ( !strcmp( p, "TRANSPONDER" )){ + GetTpInfo( channel ) ; + } else if ( !strcmp( p, "CHANNEL" ) ) { + GetChInfo( channel ) ; + return 1 ; + } + } + return 0 ; +} + +int main ( int argc, char *argv[] ){ + FILE *f, *fo ; + int cnt = 0; + CHANNEL_DATA channel ; + + if ( argc != 3 ){ + printf("USAGE: %s \n\n", argv[0] ) ; + return 0; + } + + if ( !(f=fopen(argv[1], "rt"))){ + printf("Can't open %s for reading\n\n", argv[1]); + return 0; + } + + if ( !(fo=fopen(argv[2], "wt"))){ + printf("Can't open %s for writing\n\n", argv[2]); + return 0; + } + + while ( ReadChannel( f, &channel ) ) { + cnt++; + fprintf(fo, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", + channel.Name , + channel.freq , + channel.pol ? 'v' : 'h' , + 1, //channel.lnbnum , + channel.srate , + channel.vpid , + channel.apid , + 0, //channel.type , + channel.sid ) ; + } + + printf( "%d channels read.\n\n", cnt ) ; + + fclose(f); + fclose(fo); + return 1; +} diff --git a/Tools/dvbrc2vdr/hotbird2 b/Tools/dvbrc2vdr/hotbird2 new file mode 100644 index 000000000..39c7b8779 --- /dev/null +++ b/Tools/dvbrc2vdr/hotbird2 @@ -0,0 +1,878 @@ +LNB ID 0 TYPE 1 LOF1 9750000 LOF2 10600000 SLOF 11800000 DISEQCNR 0 + SAT ID 0 NAME "HotBird" LNBID 0 FMIN 10700000 FMAX 12800000 + TRANSPONDER ID 2af8 SATID 0000 TYPE 1 FREQ 10719000 POL V SRATE 27500000 FEC 8 + CHANNEL ID 0 NAME "DISCOVERY" SATID ffffff TPID 2af8 SID 1132 TYPE 1 PCRPID a1 + CHANNEL ID 1 NAME "RTL7" SATID ffffff TPID 2af8 SID 1133 TYPE 1 PCRPID a2 + CHANNEL ID 2 NAME "TV POLONIA" SATID ffffff TPID 2af8 SID 1134 TYPE 1 PCRPID a3 + CHANNEL ID 3 NAME "EUROSPORT" SATID ffffff TPID 2af8 SID 1135 TYPE 1 PCRPID a4 + CHANNEL ID 4 NAME "PLANETE" SATID ffffff TPID 2af8 SID 1136 TYPE 1 PCRPID a5 + CHANNEL ID 5 NAME "SEASONS" SATID ffffff TPID 2af8 SID 1137 TYPE 1 PCRPID a6 + CHANNEL ID 6 NAME "VIVA Polska" SATID ffffff TPID 2af8 SID 1138 TYPE 1 PCRPID a7 + CHANNEL ID 7 NAME "MULTIMUSIC 4" SATID ffffff TPID 2af8 SID 1158 TYPE 1 APID 79 APID 7a APID 7b PCRPID 79 + CHANNEL ID 8 NAME "EPG" SATID ffffff TPID 2af8 SID 1162 TYPE 1 PCRPID a1 + CHANNEL ID 9 NAME "CYFRA+ GRY" SATID ffffff TPID 2af8 SID 116c TYPE 1 + TRANSPONDER ID 0101 SATID 0000 TYPE 1 FREQ 10722000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 2bc0 SATID 0000 TYPE 1 FREQ 0 POL V SRATE 27500000 FEC 8 + CHANNEL ID a NAME "Guide LC" SATID ffffff TPID 2bc0 SID 7d0 TYPE 0 APID 1f5e PCRPID 1f5e + CHANNEL ID b NAME "Cinestar 1" SATID ffffff TPID 2bc0 SID 4b1 TYPE 1 VPID 78 APID 82 PCRPID 78 + CHANNEL ID c NAME "Cinestar 2" SATID ffffff TPID 2bc0 SID 4b2 TYPE 1 VPID dc APID e6 PCRPID dc + CHANNEL ID d NAME "Cinetoile" SATID ffffff TPID 2bc0 SID 4b3 TYPE 1 VPID 140 APID 14a PCRPID 140 + CHANNEL ID e NAME "Shopping Avenue" SATID ffffff TPID 2bc0 SID 4b4 TYPE 1 VPID 1a4 APID 1ae PCRPID 1a4 + CHANNEL ID f NAME "Srie Club " SATID ffffff TPID 2bc0 SID 4b5 TYPE 1 VPID 208 APID 212 PCRPID 208 + CHANNEL ID 10 NAME "FUN TV" SATID ffffff TPID 2bc0 SID 4b6 TYPE 1 VPID 26c APID 276 PCRPID 26c + CHANNEL ID 11 NAME "Teva" SATID ffffff TPID 2bc0 SID 4b7 TYPE 1 VPID 2d0 APID 2da PCRPID 2d0 + CHANNEL ID 12 NAME "M6 Music" SATID ffffff TPID 2bc0 SID 4b8 TYPE 1 VPID 334 APID 33e PCRPID 334 + CHANNEL ID 13 NAME "Club Tlachat" SATID ffffff TPID 2bc0 SID 4b9 TYPE 1 VPID 398 APID 3a2 PCRPID 398 + TRANSPONDER ID 0103 SATID 0000 TYPE 1 FREQ 10775000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 2c88 SATID 0000 TYPE 1 FREQ 0 POL V SRATE 27500000 FEC 8 + CHANNEL ID 14 NAME "INFOSPORT" SATID ffffff TPID 2c88 SID 579 TYPE 1 VPID 78 APID 82 PCRPID 78 + CHANNEL ID 15 NAME "Rgions" SATID ffffff TPID 2c88 SID 57a TYPE 1 VPID dc APID e6 PCRPID dc + CHANNEL ID 16 NAME "Mezzo" SATID ffffff TPID 2c88 SID 57b TYPE 1 VPID 140 APID 14a PCRPID 140 + CHANNEL ID 17 NAME "01 01 15 97" SATID ffffff TPID 2c88 SID 5cb TYPE 0 + CHANNEL ID 18 NAME "01 01 17 97" SATID ffffff TPID 2c88 SID 5cd TYPE 0 + CHANNEL ID 19 NAME "01 02 17 97" SATID ffffff TPID 2c88 SID 5ce TYPE 0 + CHANNEL ID 1a NAME "01 02 15 97" SATID ffffff TPID 2c88 SID 5d0 TYPE 0 + CHANNEL ID 1b NAME "01 02 15 96" SATID ffffff TPID 2c88 SID 5d1 TYPE 0 + CHANNEL ID 1c NAME "01 03 17 10" SATID ffffff TPID 2c88 SID 5d2 TYPE 0 + CHANNEL ID 1d NAME "01 03 15 10" SATID ffffff TPID 2c88 SID 5d3 TYPE 0 + CHANNEL ID 1e NAME "Festival" SATID ffffff TPID 2c88 SID 57c TYPE 1 VPID 1a4 APID 1ae PCRPID 1a4 + CHANNEL ID 1f NAME "HISTOIRE " SATID ffffff TPID 2c88 SID 57d TYPE 1 VPID 208 APID 212 PCRPID 208 + CHANNEL ID 20 NAME "Tltoon" SATID ffffff TPID 2c88 SID 57e TYPE 1 VPID 26c APID 276 PCRPID 26c + CHANNEL ID 21 NAME "Odysse " SATID ffffff TPID 2c88 SID 57f TYPE 1 VPID 2d0 APID 2da PCRPID 2d0 + CHANNEL ID 22 NAME "France Musiques" SATID ffffff TPID 2c88 SID 58a TYPE 0 APID 33e PCRPID 33e + CHANNEL ID 23 NAME "Hector" SATID ffffff TPID 2c88 SID 58b TYPE 0 APID 33f PCRPID 33f + CHANNEL ID 24 NAME "FIP" SATID ffffff TPID 2c88 SID 58c TYPE 0 APID 340 PCRPID 340 + CHANNEL ID 25 NAME "France Inter" SATID ffffff TPID 2c88 SID 58d TYPE 0 APID 341 PCRPID 341 + CHANNEL ID 26 NAME "France Info" SATID ffffff TPID 2c88 SID 58e TYPE 0 APID 342 PCRPID 342 + CHANNEL ID 27 NAME "Elisa" SATID ffffff TPID 2c88 SID 58f TYPE 0 APID 343 PCRPID 343 + CHANNEL ID 28 NAME "France Culture" SATID ffffff TPID 2c88 SID 590 TYPE 0 APID 344 PCRPID 344 + CHANNEL ID 29 NAME "Radio Bleue" SATID ffffff TPID 2c88 SID 591 TYPE 0 APID 345 PCRPID 345 + CHANNEL ID 2a NAME "Le Mouv" SATID ffffff TPID 2c88 SID 592 TYPE 0 APID 346 PCRPID 346 + CHANNEL ID 2b NAME "TV5" SATID ffffff TPID 2c88 SID 581 TYPE 1 VPID 398 APID 3a2 PCRPID 398 + TRANSPONDER ID 2d50 SATID 0000 TYPE 1 FREQ 0 POL V SRATE 27500000 FEC 8 + CHANNEL ID 2c NAME "CENTRONICS" SATID ffffff TPID 2d50 SID 7d0 TYPE 0 + CHANNEL ID 2d NAME "FRANCE 2 " SATID ffffff TPID 2d50 SID 450 TYPE 1 VPID 140 PCRPID 140 + CHANNEL ID 2e NAME "FRANCE 3" SATID ffffff TPID 2d50 SID 452 TYPE 1 VPID 208 PCRPID 208 + CHANNEL ID 2f NAME "Crdit Agricole" SATID ffffff TPID 2d50 SID 14b5 TYPE 0 APID 14d5 PCRPID 14c9 + CHANNEL ID 30 NAME "tps foot" SATID ffffff TPID 2d50 SID 1450 TYPE 0 APID 146e PCRPID 146e + CHANNEL ID 31 NAME "LCI" SATID ffffff TPID 2d50 SID 44d TYPE 1 VPID 78 APID 82 PCRPID 78 + CHANNEL ID 32 NAME "EUROSPORT" SATID ffffff TPID 2d50 SID 44e TYPE 1 VPID dc APID e6 PCRPID dc + CHANNEL ID 33 NAME "FRANCE 2" SATID ffffff TPID 2d50 SID 44f TYPE 1 VPID 140 PCRPID 140 + CHANNEL ID 34 NAME "FRANCE 3" SATID ffffff TPID 2d50 SID 451 TYPE 1 VPID 208 PCRPID 208 + CHANNEL ID 35 NAME "I TELEVISION" SATID ffffff TPID 2d50 SID 454 TYPE 1 VPID 334 APID 33e PCRPID 334 + CHANNEL ID 36 NAME "TV Mail alphatest" SATID ffffff TPID 2d50 SID 1645 TYPE 0 + CHANNEL ID 37 NAME "CHAINE FI" SATID ffffff TPID 2d50 SID 14b4 TYPE 0 APID 14d2 APID 14d3 PCRPID 14d2 + CHANNEL ID 38 NAME "caisse d'pargne" SATID ffffff TPID 2d50 SID 14b7 TYPE 0 + CHANNEL ID 39 NAME "TV Mail" SATID ffffff TPID 2d50 SID 1644 TYPE 0 + TRANSPONDER ID 2e7c SATID 0000 TYPE 1 FREQ 10892000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 3a NAME "CANAL+" SATID ffffff TPID 2e7c SID 12c1 TYPE 1 PCRPID a0 + CHANNEL ID 3b NAME "CANAL+ ӣTY" SATID ffffff TPID 2e7c SID 12c2 TYPE 1 PCRPID a1 + CHANNEL ID 3c NAME "TMT" SATID ffffff TPID 2e7c SID 12c4 TYPE 1 PCRPID a3 + CHANNEL ID 3d NAME "ALE KINO!" SATID ffffff TPID 2e7c SID 12c5 TYPE 1 PCRPID a4 + CHANNEL ID 3e NAME "MINIMAX" SATID ffffff TPID 2e7c SID 12c6 TYPE 1 PCRPID a5 + CHANNEL ID 3f NAME "TVP 1" SATID ffffff TPID 2e7c SID 12c7 TYPE 1 PCRPID a6 + CHANNEL ID 40 NAME "TVP 2" SATID ffffff TPID 2e7c SID 12c8 TYPE 1 PCRPID a7 + CHANNEL ID 41 NAME "CANAL+ NIEBIESKI" SATID ffffff TPID 2e7c SID 12c9 TYPE 1 PCRPID a8 + CHANNEL ID 42 NAME "EPG" SATID ffffff TPID 2e7c SID 12f2 TYPE 1 TTPID 1f4 PCRPID a0 + TRANSPONDER ID 2ee0 SATID 0000 TYPE 1 FREQ 0 POL V SRATE 27500000 FEC 8 + CHANNEL ID 43 NAME "Multivision" SATID ffffff TPID 2ee0 SID 643 TYPE 0 VPID 140 PCRPID 140 + CHANNEL ID 44 NAME "Grand Classique" SATID ffffff TPID 2ee0 SID 672 TYPE 1 APID 33e PCRPID 33e + CHANNEL ID 45 NAME "Symphonies" SATID ffffff TPID 2ee0 SID 673 TYPE 1 APID 33f PCRPID 33f + CHANNEL ID 46 NAME "Baroque" SATID ffffff TPID 2ee0 SID 674 TYPE 1 APID 340 PCRPID 340 + CHANNEL ID 47 NAME "Opra" SATID ffffff TPID 2ee0 SID 675 TYPE 1 APID 341 PCRPID 341 + CHANNEL ID 48 NAME "Contemporain" SATID ffffff TPID 2ee0 SID 676 TYPE 1 APID 342 PCRPID 342 + CHANNEL ID 49 NAME "Relaxation" SATID ffffff TPID 2ee0 SID 677 TYPE 1 APID 343 PCRPID 343 + CHANNEL ID 4a NAME "Blues" SATID ffffff TPID 2ee0 SID 678 TYPE 1 APID 344 PCRPID 344 + CHANNEL ID 4b NAME "Jazz" SATID ffffff TPID 2ee0 SID 679 TYPE 1 APID 345 PCRPID 345 + CHANNEL ID 4c NAME "Big Band" SATID ffffff TPID 2ee0 SID 67a TYPE 1 APID 346 PCRPID 346 + CHANNEL ID 4d NAME "Jazz Moderne" SATID ffffff TPID 2ee0 SID 67b TYPE 1 APID 347 PCRPID 347 + CHANNEL ID 4e NAME "Les Tubes Franais" SATID ffffff TPID 2ee0 SID 67c TYPE 1 APID 348 PCRPID 348 + CHANNEL ID 4f NAME "RFO SAT" SATID ffffff TPID 2ee0 SID 641 TYPE 0 VPID 78 APID 82 PCRPID 78 + CHANNEL ID 50 NAME "Appli D1 LC" SATID ffffff TPID 2ee0 SID 690 TYPE 0 + CHANNEL ID 51 NAME "Cinefaz" SATID ffffff TPID 2ee0 SID 642 TYPE 1 VPID dc APID e6 PCRPID dc + CHANNEL ID 52 NAME "TurboPC" SATID ffffff TPID 2ee0 SID af1 TYPE 0 + CHANNEL ID 53 NAME "MTV2" SATID ffffff TPID 2ee0 SID 647 TYPE 1 VPID 2d0 APID 2da PCRPID 2d0 + CHANNEL ID 54 NAME "Rire et chansons" SATID ffffff TPID 2ee0 SID 65e TYPE 0 APID 3a2 PCRPID 3a2 + CHANNEL ID 55 NAME "Radio J" SATID ffffff TPID 2ee0 SID 65f TYPE 1 APID 3a3 PCRPID 3a3 + CHANNEL ID 56 NAME "Mosqueteiros" SATID ffffff TPID 2ee0 SID 660 TYPE 0 APID 3a4 PCRPID 3a4 + CHANNEL ID 57 NAME "Abysse" SATID ffffff TPID 2ee0 SID 661 TYPE 1 APID 3a5 PCRPID 3a5 + CHANNEL ID 58 NAME "RMC" SATID ffffff TPID 2ee0 SID 663 TYPE 1 APID 3a7 PCRPID 3a7 + CHANNEL ID 59 NAME "Radio Junior" SATID ffffff TPID 2ee0 SID 664 TYPE 0 APID 3a8 PCRPID 3a8 + CHANNEL ID 5a NAME "NETRADIO" SATID ffffff TPID 2ee0 SID 665 TYPE 0 APID 3a9 PCRPID 3a9 + CHANNEL ID 5b NAME "Nostalgie" SATID ffffff TPID 2ee0 SID 666 TYPE 0 APID 3aa PCRPID 3aa + CHANNEL ID 5c NAME "Skyrock" SATID ffffff TPID 2ee0 SID 667 TYPE 1 APID 3ab PCRPID 3ab + CHANNEL ID 5d NAME "Radio Coutoisie" SATID ffffff TPID 2ee0 SID 668 TYPE 0 APID 3ac PCRPID 3ac + CHANNEL ID 5e NAME "La Voix des Pays" SATID ffffff TPID 2ee0 SID 669 TYPE 0 APID 3ad PCRPID 3ad + CHANNEL ID 5f NAME "INFO EXPRESS" SATID ffffff TPID 2ee0 SID 157c TYPE 0 APID 159a PCRPID 159a + CHANNEL ID 60 NAME "METEO" SATID ffffff TPID 2ee0 SID 16a8 TYPE 0 APID 16c6 PCRPID 16c6 + CHANNEL ID 61 NAME "X X L" SATID ffffff TPID 2ee0 SID 1518 TYPE 1 + CHANNEL ID 62 NAME "Multivision Cinma" SATID ffffff TPID 2ee0 SID 1c20 TYPE 0 + CHANNEL ID 63 NAME "Multivision Sport" SATID ffffff TPID 2ee0 SID 1c84 TYPE 0 TTPID 18fb + CHANNEL ID 64 NAME "Multivision Spectacle" SATID ffffff TPID 2ee0 SID 1ce8 TYPE 0 + TRANSPONDER ID 2f44 SATID 0000 TYPE 1 FREQ 12673000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 65 NAME "Test OTV8" SATID ffffff TPID 2f44 SID 1d67 TYPE 1 PCRPID e80 + CHANNEL ID 66 NAME "Test OTV9" SATID ffffff TPID 2f44 SID 1d68 TYPE 1 PCRPID e80 + CHANNEL ID 67 NAME "Test OTV10" SATID ffffff TPID 2f44 SID 1d69 TYPE 1 PCRPID e80 + CHANNEL ID 68 NAME "Test OTV11" SATID ffffff TPID 2f44 SID 1d6a TYPE 1 VPID 201 PCRPID 1ffe + CHANNEL ID 69 NAME "Test31" SATID ffffff TPID 2f44 SID 1d4d TYPE 1 VPID 200 APID 28a PCRPID 1ffe + CHANNEL ID 6a NAME "CNN" SATID ffffff TPID 2f44 SID 1d4e TYPE 1 VPID 201 APID 294 PCRPID 1ffe + CHANNEL ID 6b NAME "Q24" SATID ffffff TPID 2f44 SID 1d4f TYPE 0 VPID 202 APID 29e APID 29f APID 2a9 APID 2b3 PCRPID 1ffe + CHANNEL ID 6c NAME "Test34" SATID ffffff TPID 2f44 SID 1d50 TYPE 1 VPID 203 APID 2a8 PCRPID 1ffe + CHANNEL ID 6d NAME "Test35" SATID ffffff TPID 2f44 SID 1d51 TYPE 1 VPID 204 APID 2b2 PCRPID 1ffe + CHANNEL ID 6e NAME "Test OTV1" SATID ffffff TPID 2f44 SID 1d60 TYPE 1 PCRPID e80 + CHANNEL ID 6f NAME "Test OTV2" SATID ffffff TPID 2f44 SID 1d61 TYPE 1 PCRPID e80 + CHANNEL ID 70 NAME "Test OTV3" SATID ffffff TPID 2f44 SID 1d62 TYPE 1 PCRPID e80 + CHANNEL ID 71 NAME "Test OTV4" SATID ffffff TPID 2f44 SID 1d63 TYPE 1 PCRPID e80 + CHANNEL ID 72 NAME "Test OTV5" SATID ffffff TPID 2f44 SID 1d64 TYPE 1 PCRPID e80 + CHANNEL ID 73 NAME "Test OTV6" SATID ffffff TPID 2f44 SID 1d65 TYPE 1 PCRPID e80 + CHANNEL ID 74 NAME "Test OTV7" SATID ffffff TPID 2f44 SID 1d66 TYPE 1 PCRPID e80 + CHANNEL ID 75 SATID ffffff TPID 2f44 SID 1d74 TYPE 0 + CHANNEL ID 76 SATID ffffff TPID 2f44 SID 1d75 TYPE 0 + TRANSPONDER ID 0109 SATID 0000 TYPE 1 FREQ 11033000 POL V SRATE 27500000 FEC 8 + TRANSPONDER ID 010a SATID 0000 TYPE 1 FREQ 11054000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 3264 SATID 0000 TYPE 1 FREQ 11095910 POL H SRATE 27500000 FEC 8 + CHANNEL ID ffffffff NAME "Telekom TV" SATID ffffff TPID 3264 SID e7f TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "FantasticOverOpal" SATID ffffff TPID 3264 SID e80 TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "Gilat" SATID ffffff TPID 3264 SID e81 TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "Siemens TV" SATID ffffff TPID 3264 SID e84 TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "S-TV" SATID ffffff TPID 3264 SID e85 TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "Optibase Encoder" SATID ffffff TPID 3264 SID e86 TYPE 0 VPID 20 PCRPID 20 + TRANSPONDER ID 010c SATID 0000 TYPE 1 FREQ 11130000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 010d SATID 0000 TYPE 1 FREQ 11131000 POL V SRATE 27500000 FEC 8 + TRANSPONDER ID 010e SATID 0000 TYPE 1 FREQ 11196000 POL V SRATE 27500000 FEC 8 + TRANSPONDER ID 010f SATID 0000 TYPE 1 FREQ 11205000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 0110 SATID 0000 TYPE 1 FREQ 11242000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 012c SATID 0000 TYPE 1 FREQ 11095910 POL H SRATE 27500000 FEC 8 + CHANNEL ID 7d NAME "FantasticOverOpal" SATID ffffff TPID 12c SID e76 TYPE 0 PCRPID 201 + TRANSPONDER ID 004d SATID 0000 TYPE 1 FREQ 11303750 POL H SRATE 27500000 FEC 8 + CHANNEL ID ffffffff NAME "Deutsche Bank / T1" SATID ffffff TPID 4d SID 1 TYPE 1 VPID 488 PCRPID 488 + CHANNEL ID 7f NAME "Animal Planet" SATID ffffff TPID 4d SID a TYPE 1 VPID 488 PCRPID 488 + CHANNEL ID 80 NAME "Discovery E Europe-English" SATID ffffff TPID 4d SID 14 TYPE 1 VPID 4ec PCRPID 4ec + CHANNEL ID ffffffff NAME "Wuerth KG / T21" SATID ffffff TPID 4d SID 15 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 82 NAME "Discovery Italy" SATID ffffff TPID 4d SID 1e TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID ffffffff NAME "BTI / T31" SATID ffffff TPID 4d SID 1f TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 84 NAME "Discovery Russia" SATID ffffff TPID 4d SID 28 TYPE 1 VPID 5b4 PCRPID 5b4 + CHANNEL ID ffffffff NAME "K-TV (MetroMux) / T41" SATID ffffff TPID 4d SID 29 TYPE 1 VPID 7a8 PCRPID 7a8 + CHANNEL ID 86 NAME "Animal Planet EE" SATID ffffff TPID 4d SID 32 TYPE 1 VPID 618 PCRPID 618 + CHANNEL ID 87 NAME "Animal Planet - Russian" SATID ffffff TPID 4d SID 33 TYPE 1 VPID 618 PCRPID 618 + CHANNEL ID 88 NAME "Discovery Netherlands" SATID ffffff TPID 4d SID 3c TYPE 1 VPID 67c PCRPID 67c + CHANNEL ID ffffffff NAME "Q English" SATID ffffff TPID 4d SID 46 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 8a NAME "Travel and Adventure" SATID ffffff TPID 4d SID 50 TYPE 1 VPID 744 PCRPID 744 + CHANNEL ID 8b NAME "Travel and Adventure- Russian" SATID ffffff TPID 4d SID 51 TYPE 1 VPID 744 PCRPID 744 + CHANNEL ID 8c NAME "New DCP" SATID ffffff TPID 4d SID 12c TYPE 1 APID 4c4 PCRPID 4c4 + CHANNEL ID 8d NAME "CCP" SATID ffffff TPID 4d SID 12d TYPE 1 VPID 4ec PCRPID 4ec + CHANNEL ID ffffffff NAME "Deutsche Bank / T2" SATID ffffff TPID 4d SID 2 TYPE 1 VPID 4ec PCRPID 4ec + CHANNEL ID 93 NAME "Channel Three" SATID ffffff TPID 4d SID 3 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 94 NAME "Channel Four" SATID ffffff TPID 4d SID 4 TYPE 0 VPID 5b4 PCRPID 5b4 + CHANNEL ID 95 NAME "Channel Five" SATID ffffff TPID 4d SID 5 TYPE 0 VPID 618 PCRPID 618 + CHANNEL ID 96 NAME "Channel 6 = Sat 7 Arabic" SATID ffffff TPID 4d SID 6 TYPE 0 VPID 67c PCRPID 67c + CHANNEL ID 97 NAME "Channel Seven" SATID ffffff TPID 4d SID 7 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 98 NAME "Q German" SATID ffffff TPID 4d SID 47 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 99 NAME "Q French" SATID ffffff TPID 4d SID 48 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 9a NAME "Q Dutch" SATID ffffff TPID 4d SID 49 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 1b8 NAME "DTAG / T11" SATID ffffff TPID 4d SID b TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1b9 NAME "DTAG 50 / T12" SATID ffffff TPID 4d SID c TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1ba NAME "Telekom TV" SATID ffffff TPID 4d SID d TYPE 1 VPID 5b4 PCRPID 5b4 + CHANNEL ID 1bb NAME "Gerling / T26" SATID ffffff TPID 4d SID 1a TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1bc NAME "Hornbach-D / T36" SATID ffffff TPID 4d SID 24 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1bd NAME "Hornbach-NL / T38" SATID ffffff TPID 4d SID 26 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1be NAME "Hornbach-CZ / T39" SATID ffffff TPID 4d SID 27 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1bf NAME "Testkanal" SATID ffffff TPID 4d SID 63 TYPE 0 VPID 67c PCRPID 67c + CHANNEL ID 1c0 NAME "KENCAST" SATID ffffff TPID 4d SID 6f TYPE 0 PCRPID 42e + TRANSPONDER ID 0113 SATID 0000 TYPE 1 FREQ 11338000 POL V SRATE 27500000 FEC 8 + TRANSPONDER ID 0114 SATID 0000 TYPE 1 FREQ 11371000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 0115 SATID 0000 TYPE 1 FREQ 11457000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 0116 SATID 0000 TYPE 1 FREQ 11464000 POL V SRATE 27500000 FEC 8 + TRANSPONDER ID 3c8c SATID 0000 TYPE 1 FREQ 11604100 POL H SRATE 27500000 FEC 8 + CHANNEL ID 8e NAME "SAT.1 CH" SATID ffffff TPID 3c8c SID 259 TYPE 0 VPID 65 APID 66 TTPID 69 PCRPID 69 + CHANNEL ID 8f NAME "KBT Channel SUN" SATID ffffff TPID 3c8c SID 25b TYPE 0 VPID 6f APID 70 PCRPID 6f + CHANNEL ID 90 NAME "big FM" SATID ffffff TPID 3c8c SID 25c TYPE 0 APID 71 PCRPID 71 + CHANNEL ID 91 NAME "Event" SATID ffffff TPID 3c8c SID 25a TYPE 0 VPID a0 APID a1 PCRPID a0 + TRANSPONDER ID 0118 SATID 0000 TYPE 1 FREQ 11623000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 004d SATID 0000 TYPE 1 FREQ 11642500 POL H SRATE 27500000 FEC 8 + CHANNEL ID ffffffff NAME "Deutsche Bank / T1" SATID ffffff TPID 4d SID 1 TYPE 1 VPID 488 PCRPID 488 + CHANNEL ID 7f NAME "Animal Planet" SATID ffffff TPID 4d SID a TYPE 1 VPID 488 PCRPID 488 + CHANNEL ID 80 NAME "Discovery E Europe-English" SATID ffffff TPID 4d SID 14 TYPE 1 VPID 4ec PCRPID 4ec + CHANNEL ID ffffffff NAME "Wuerth KG / T21" SATID ffffff TPID 4d SID 15 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 82 NAME "Discovery Italy" SATID ffffff TPID 4d SID 1e TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID ffffffff NAME "BTI / T31" SATID ffffff TPID 4d SID 1f TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 84 NAME "Discovery Russia" SATID ffffff TPID 4d SID 28 TYPE 1 VPID 5b4 PCRPID 5b4 + CHANNEL ID ffffffff NAME "K-TV (MetroMux) / T41" SATID ffffff TPID 4d SID 29 TYPE 1 VPID 7a8 PCRPID 7a8 + CHANNEL ID 86 NAME "Animal Planet EE" SATID ffffff TPID 4d SID 32 TYPE 1 VPID 618 PCRPID 618 + CHANNEL ID 87 NAME "Animal Planet - Russian" SATID ffffff TPID 4d SID 33 TYPE 1 VPID 618 PCRPID 618 + CHANNEL ID 88 NAME "Discovery Netherlands" SATID ffffff TPID 4d SID 3c TYPE 1 VPID 67c PCRPID 67c + CHANNEL ID ffffffff NAME "Q English" SATID ffffff TPID 4d SID 46 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 8a NAME "Travel and Adventure" SATID ffffff TPID 4d SID 50 TYPE 1 VPID 744 PCRPID 744 + CHANNEL ID 8b NAME "Travel and Adventure- Russian" SATID ffffff TPID 4d SID 51 TYPE 1 VPID 744 PCRPID 744 + CHANNEL ID 8c NAME "New DCP" SATID ffffff TPID 4d SID 12c TYPE 1 APID 4c4 PCRPID 4c4 + CHANNEL ID 8d NAME "CCP" SATID ffffff TPID 4d SID 12d TYPE 1 VPID 4ec PCRPID 4ec + CHANNEL ID ffffffff NAME "Deutsche Bank / T2" SATID ffffff TPID 4d SID 2 TYPE 1 VPID 4ec PCRPID 4ec + CHANNEL ID 93 NAME "Channel Three" SATID ffffff TPID 4d SID 3 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 94 NAME "Channel Four" SATID ffffff TPID 4d SID 4 TYPE 0 VPID 5b4 PCRPID 5b4 + CHANNEL ID 95 NAME "Channel Five" SATID ffffff TPID 4d SID 5 TYPE 0 VPID 618 PCRPID 618 + CHANNEL ID 96 NAME "Channel 6 = Sat 7 Arabic" SATID ffffff TPID 4d SID 6 TYPE 0 VPID 67c PCRPID 67c + CHANNEL ID 97 NAME "Channel Seven" SATID ffffff TPID 4d SID 7 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 98 NAME "Q German" SATID ffffff TPID 4d SID 47 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 99 NAME "Q French" SATID ffffff TPID 4d SID 48 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 9a NAME "Q Dutch" SATID ffffff TPID 4d SID 49 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 1b8 NAME "DTAG / T11" SATID ffffff TPID 4d SID b TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1b9 NAME "DTAG 50 / T12" SATID ffffff TPID 4d SID c TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1ba NAME "Telekom TV" SATID ffffff TPID 4d SID d TYPE 1 VPID 5b4 PCRPID 5b4 + CHANNEL ID 1bb NAME "Gerling / T26" SATID ffffff TPID 4d SID 1a TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1bc NAME "Hornbach-D / T36" SATID ffffff TPID 4d SID 24 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1bd NAME "Hornbach-NL / T38" SATID ffffff TPID 4d SID 26 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1be NAME "Hornbach-CZ / T39" SATID ffffff TPID 4d SID 27 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1bf NAME "Testkanal" SATID ffffff TPID 4d SID 63 TYPE 0 VPID 67c PCRPID 67c + CHANNEL ID 1c0 NAME "KENCAST" SATID ffffff TPID 4d SID 6f TYPE 0 PCRPID 42e + TRANSPONDER ID 011a SATID 0000 TYPE 1 FREQ 11662000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 3e1c SATID 0000 TYPE 1 FREQ 11681001 POL H SRATE 27500000 FEC 8 + CHANNEL ID 9b NAME "AB 1" SATID ffffff TPID 3e1c SID c9 TYPE 1 VPID a0 APID 50 TTPID 20 PCRPID a0 + CHANNEL ID 9c NAME "AB MOTEURS" SATID ffffff TPID 3e1c SID ca TYPE 1 VPID a1 APID 54 TTPID 23 PCRPID a1 + CHANNEL ID 9d NAME "ANIMAUX" SATID ffffff TPID 3e1c SID cb TYPE 1 VPID a2 APID 58 TTPID 26 PCRPID a2 + CHANNEL ID 9e NAME "CHASSE ET PECHE" SATID ffffff TPID 3e1c SID cc TYPE 1 VPID a3 APID 5c TTPID 29 PCRPID a3 + CHANNEL ID 9f NAME "XXL" SATID ffffff TPID 3e1c SID cd TYPE 1 VPID a4 APID 60 TTPID 2c PCRPID a4 + CHANNEL ID a0 NAME "MUSIQUE CLASSIQUE" SATID ffffff TPID 3e1c SID ce TYPE 1 VPID a5 APID 64 TTPID 2f PCRPID a5 + CHANNEL ID a1 NAME "ESCALES" SATID ffffff TPID 3e1c SID cf TYPE 1 VPID a6 APID 68 TTPID 32 PCRPID a6 + CHANNEL ID a2 NAME "FIT/chane HISTOIRE" SATID ffffff TPID 3e1c SID d0 TYPE 1 VPID a7 APID 6c TTPID 35 PCRPID a7 + CHANNEL ID a3 NAME "RFM TV" SATID ffffff TPID 3e1c SID d1 TYPE 1 VPID a8 APID 70 TTPID 38 PCRPID a8 + TRANSPONDER ID 13ec SATID 0000 TYPE 1 FREQ 11744599 POL H SRATE 27500000 FEC 8 + CHANNEL ID a4 NAME "EDTV DRAMA" SATID ffffff TPID 13ec SID 2520 TYPE 0 VPID 1322 PCRPID 1322 + CHANNEL ID a5 NAME "EDTV RADIO 02" SATID ffffff TPID 13ec SID 2534 TYPE 0 VPID 1322 PCRPID 1322 + CHANNEL ID a6 NAME "EDTV RADIO 01" SATID ffffff TPID 13ec SID 2533 TYPE 0 VPID 1322 PCRPID 1322 + CHANNEL ID a7 NAME "EDTV SPORT" SATID ffffff TPID 13ec SID 251e TYPE 0 VPID 1322 PCRPID 1322 + CHANNEL ID a8 NAME "EDTV BUSINESS" SATID ffffff TPID 13ec SID 251f TYPE 0 VPID 1322 PCRPID 1322 + TRANSPONDER ID 1450 SATID 0000 TYPE 1 FREQ 11765841 POL V SRATE 27500000 FEC 8 + CHANNEL ID a9 NAME "RAI1" SATID ffffff TPID 1450 SID d49 TYPE 0 VPID a0 PCRPID 1ffe + CHANNEL ID aa NAME "RAI2" SATID ffffff TPID 1450 SID d4a TYPE 0 VPID a1 PCRPID 1ffe + CHANNEL ID ab NAME "RAI3" SATID ffffff TPID 1450 SID d4b TYPE 0 VPID a2 PCRPID 1ffe + CHANNEL ID ac NAME "Rai Way TEST1" SATID ffffff TPID 1450 SID d4c TYPE 0 VPID 203 PCRPID 1ffe + CHANNEL ID ad NAME "Rai Way TEST2" SATID ffffff TPID 1450 SID d4d TYPE 0 VPID 204 PCRPID 1ffe + CHANNEL ID ae NAME "Rai Way TEST3" SATID ffffff TPID 1450 SID d4e TYPE 0 VPID a4 PCRPID 1ffe + CHANNEL ID af NAME "RAIMOSAICO" SATID ffffff TPID 1450 SID d4f TYPE 0 VPID 206 PCRPID 1ffe + CHANNEL ID b0 SATID ffffff TPID 1450 SID da2 TYPE 0 + TRANSPONDER ID 1518 SATID 0000 TYPE 1 FREQ 11765841 POL V SRATE 27500000 FEC 8 + CHANNEL ID b1 NAME "RAINews24" SATID ffffff TPID 1518 SID ce5 TYPE 0 VPID 204 PCRPID 1ffe + CHANNEL ID b2 NAME "CAMERA DEPUTATI" SATID ffffff TPID 1518 SID ce6 TYPE 0 VPID 205 PCRPID 1ffe + CHANNEL ID b3 NAME "TELEPACE" SATID ffffff TPID 1518 SID ce8 TYPE 0 VPID 203 PCRPID 1ffe + CHANNEL ID b4 NAME "RAISPORTSAT" SATID ffffff TPID 1518 SID ce9 TYPE 0 VPID 200 PCRPID 1ffe + CHANNEL ID b5 NAME "RAINettunoSAT2" SATID ffffff TPID 1518 SID cea TYPE 0 VPID 201 PCRPID 1ffe + CHANNEL ID b6 NAME "RAIeducational" SATID ffffff TPID 1518 SID ceb TYPE 0 VPID 202 PCRPID 1ffe + CHANNEL ID b7 NAME "RAINettunoSAT1" SATID ffffff TPID 1518 SID cec TYPE 0 VPID 207 PCRPID 1ffe + CHANNEL ID b8 NAME "SAT2000" SATID ffffff TPID 1518 SID ced TYPE 0 VPID 206 PCRPID 1ffe + CHANNEL ID b9 NAME "RADIOUNO" SATID ffffff TPID 1518 SID cef TYPE 0 APID 29e PCRPID 1ffe + CHANNEL ID ba NAME "RADIODUE" SATID ffffff TPID 1518 SID cf0 TYPE 0 APID 29f PCRPID 1ffe + CHANNEL ID bb NAME "RADIOTRE" SATID ffffff TPID 1518 SID cf1 TYPE 0 APID 2a0 PCRPID 1ffe + CHANNEL ID bc NAME "FDleggera" SATID ffffff TPID 1518 SID cf2 TYPE 0 APID 2a1 PCRPID 1ffe + CHANNEL ID bd NAME "FDauditorium" SATID ffffff TPID 1518 SID cf3 TYPE 0 APID 299 PCRPID 1ffe + CHANNEL ID be NAME "BLUSAT 2000" SATID ffffff TPID 1518 SID cf4 TYPE 0 APID 2a5 PCRPID 1ffe + CHANNEL ID bf NAME "GR PARLAMENTO" SATID ffffff TPID 1518 SID cf5 TYPE 0 APID 298 PCRPID 1ffe + CHANNEL ID c0 NAME "ISORADIO" SATID ffffff TPID 1518 SID cf6 TYPE 0 APID 295 PCRPID 1ffe + TRANSPONDER ID 157c SATID 0000 TYPE 1 FREQ 11823000 POL H SRATE 27500000 FEC 8 + CHANNEL ID c1 NAME "R1" SATID ffffff TPID 157c SID 12d TYPE 1 VPID 200 APID 28a PCRPID 1ffe + CHANNEL ID c2 NAME "R2" SATID ffffff TPID 157c SID 12e TYPE 1 VPID 201 APID 294 APID 295 PCRPID 1ffe + CHANNEL ID c3 NAME "R3" SATID ffffff TPID 157c SID 12f TYPE 1 VPID 202 APID 29e TTPID 242 PCRPID 1ffe + CHANNEL ID c4 NAME "R4" SATID ffffff TPID 157c SID 130 TYPE 1 VPID 203 APID 2a8 TTPID 243 PCRPID 1ffe + CHANNEL ID c5 NAME "R5" SATID ffffff TPID 157c SID 132 TYPE 1 VPID 124a APID 2bc TTPID 245 PCRPID 1ffe + CHANNEL ID c6 NAME "R6" SATID ffffff TPID 157c SID 133 TYPE 1 VPID 206 APID 2c6 PCRPID 1ffe + CHANNEL ID c7 NAME "R7" SATID ffffff TPID 157c SID 134 TYPE 1 VPID 207 APID 2d0 PCRPID 1ffe + CHANNEL ID c8 NAME "Love Radio" SATID ffffff TPID 157c SID 135 TYPE 1 APID 2c7 PCRPID 1ffe + CHANNEL ID c9 NAME "Greek Church" SATID ffffff TPID 157c SID 136 TYPE 1 APID 29f PCRPID 1ffe + CHANNEL ID ca NAME "Skai Radio" SATID ffffff TPID 157c SID 137 TYPE 1 APID 2e5 PCRPID 1ffe + CHANNEL ID cb NAME "MelodiRadio" SATID ffffff TPID 157c SID 138 TYPE 1 APID 2bd PCRPID 1ffe + CHANNEL ID cc NAME "ERA 3" SATID ffffff TPID 157c SID 139 TYPE 1 APID 28b PCRPID 1ffe + CHANNEL ID cd NAME "RR1" SATID ffffff TPID 157c SID 13a TYPE 1 APID 2a9 PCRPID 1ffe + CHANNEL ID ce NAME "RR2" SATID ffffff TPID 157c SID 13b TYPE 1 APID 2d1 PCRPID 1ffe + CHANNEL ID cf NAME "NOVA CINE" SATID ffffff TPID 157c SID 13c TYPE 1 VPID 209 APID 2e4 PCRPID 1ffe + CHANNEL ID d0 NAME "FILM NET" SATID ffffff TPID 157c SID 13d TYPE 1 VPID 200 APID 28a PCRPID 1ffe + CHANNEL ID d1 NAME "SSportK-T.V" SATID ffffff TPID 157c SID 13e TYPE 1 VPID 201 APID 294 APID 295 PCRPID 1ffe + CHANNEL ID d2 NAME "MEGA" SATID ffffff TPID 157c SID 13f TYPE 1 VPID 202 APID 29e TTPID 242 PCRPID 1ffe + CHANNEL ID d3 NAME "ANT-1" SATID ffffff TPID 157c SID 140 TYPE 1 VPID 203 APID 2a8 TTPID 243 PCRPID 1ffe + CHANNEL ID d4 NAME "STAR" SATID ffffff TPID 157c SID 141 TYPE 1 VPID 205 APID 2bc TTPID 245 PCRPID 1ffe + CHANNEL ID d5 NAME "Alter 5" SATID ffffff TPID 157c SID 142 TYPE 1 VPID 206 APID 2c6 PCRPID 1ffe + CHANNEL ID d6 NAME "NEW Tempo" SATID ffffff TPID 157c SID 143 TYPE 1 VPID 207 APID 2d0 PCRPID 1ffe + CHANNEL ID d7 NAME "Super Sport2" SATID ffffff TPID 157c SID 144 TYPE 1 VPID 204 APID 2b2 APID 2b3 PCRPID 1ffe + TRANSPONDER ID 15e0 SATID 0000 TYPE 1 FREQ 11843000 POL V SRATE 27500000 FEC 8 + CHANNEL ID d8 SATID ffffff TPID 15e0 SID fffe TYPE 0 + CHANNEL ID d9 NAME "INTV" SATID ffffff TPID 15e0 SID db0 TYPE 1 VPID 914 PCRPID 900 + CHANNEL ID da NAME "UNIV" SATID ffffff TPID 15e0 SID db3 TYPE 1 VPID 901 PCRPID 900 + CHANNEL ID db NAME "CULT" SATID ffffff TPID 15e0 SID db6 TYPE 1 VPID 903 PCRPID 900 + CHANNEL ID dc NAME "ERSP" SATID ffffff TPID 15e0 SID db9 TYPE 1 VPID 905 PCRPID 900 + CHANNEL ID dd NAME "SINT" SATID ffffff TPID 15e0 SID dbb TYPE 1 + CHANNEL ID de NAME "CART" SATID ffffff TPID 15e0 SID dbc TYPE 1 VPID 981 PCRPID 980 + CHANNEL ID df NAME "SINT" SATID ffffff TPID 15e0 SID dbf TYPE 1 + CHANNEL ID e0 NAME "DISC" SATID ffffff TPID 15e0 SID dc2 TYPE 1 VPID 985 PCRPID 980 + CHANNEL ID e1 NAME "SINT" SATID ffffff TPID 15e0 SID dc5 TYPE 1 + CHANNEL ID e2 NAME "TVL" SATID ffffff TPID 15e0 SID dc8 TYPE 1 VPID 989 PCRPID 980 + CHANNEL ID e3 NAME "SINT" SATID ffffff TPID 15e0 SID dca TYPE 1 + CHANNEL ID e4 NAME "ROCK" SATID ffffff TPID 15e0 SID dde TYPE 1 APID 910 PCRPID 900 + CHANNEL ID e5 NAME "RDS" SATID ffffff TPID 15e0 SID de1 TYPE 1 APID 911 PCRPID 900 + CHANNEL ID e6 NAME "RTL" SATID ffffff TPID 15e0 SID de4 TYPE 1 APID 912 PCRPID 900 + CHANNEL ID e7 NAME "101" SATID ffffff TPID 15e0 SID de7 TYPE 1 APID 913 PCRPID 900 + CHANNEL ID e8 NAME "RVOY" SATID ffffff TPID 15e0 SID dea TYPE 1 APID 90b PCRPID 900 + CHANNEL ID e9 NAME "RKFM" SATID ffffff TPID 15e0 SID deb TYPE 1 APID 90d PCRPID 900 + CHANNEL ID ea NAME "GLOB" SATID ffffff TPID 15e0 SID dec TYPE 1 APID 90c PCRPID 900 + CHANNEL ID eb NAME "ANT1" SATID ffffff TPID 15e0 SID ded TYPE 1 APID 90e PCRPID 900 + CHANNEL ID ec NAME "RRAD" SATID ffffff TPID 15e0 SID dee TYPE 1 APID 90f PCRPID 900 + CHANNEL ID ed NAME "MC01" SATID ffffff TPID 15e0 SID df0 TYPE 1 APID 908 PCRPID 908 + CHANNEL ID ee NAME "MC02" SATID ffffff TPID 15e0 SID df3 TYPE 1 APID 909 PCRPID 909 + CHANNEL ID ef NAME "MC03" SATID ffffff TPID 15e0 SID df6 TYPE 1 APID 90a PCRPID 90a + TRANSPONDER ID 1644 SATID 0000 TYPE 1 FREQ 12341001 POL H SRATE 27500000 FEC 8 + CHANNEL ID f0 NAME "P7" SATID ffffff TPID 1644 SID 2c25 TYPE 1 VPID a0 APID 50 APID 51 PCRPID af + CHANNEL ID f1 NAME "P8" SATID ffffff TPID 1644 SID 2c27 TYPE 1 VPID a1 APID 54 APID 55 PCRPID af + CHANNEL ID f2 NAME "P9" SATID ffffff TPID 1644 SID 2c29 TYPE 1 VPID a2 APID 58 APID 59 PCRPID af + CHANNEL ID f3 NAME "+GIOCHI" SATID ffffff TPID 1644 SID 2c2e TYPE 1 PCRPID af + CHANNEL ID f4 NAME "MM01" SATID ffffff TPID 1644 SID 2c2f TYPE 1 APID 259 PCRPID b0 + CHANNEL ID f5 NAME "MM02" SATID ffffff TPID 1644 SID 2c30 TYPE 0 APID 25a PCRPID b0 + CHANNEL ID f6 NAME "MM03" SATID ffffff TPID 1644 SID 2c31 TYPE 0 APID 25b PCRPID b0 + CHANNEL ID f7 NAME "MM04" SATID ffffff TPID 1644 SID 2c32 TYPE 0 APID 25c PCRPID b0 + CHANNEL ID f8 NAME "MM05" SATID ffffff TPID 1644 SID 2c33 TYPE 0 APID 25d PCRPID b0 + CHANNEL ID f9 NAME "MM06" SATID ffffff TPID 1644 SID 2c34 TYPE 0 APID 25e PCRPID b0 + CHANNEL ID fa NAME "MM07" SATID ffffff TPID 1644 SID 2c35 TYPE 0 APID 25f PCRPID b0 + CHANNEL ID fb NAME "MM08" SATID ffffff TPID 1644 SID 2c36 TYPE 0 APID 260 PCRPID b0 + CHANNEL ID fc NAME "MM09" SATID ffffff TPID 1644 SID 2c37 TYPE 0 APID 261 PCRPID b0 + CHANNEL ID fd NAME "MM10" SATID ffffff TPID 1644 SID 2c38 TYPE 0 APID 262 PCRPID b0 + CHANNEL ID fe NAME "MM11" SATID ffffff TPID 1644 SID 2c39 TYPE 1 APID 263 PCRPID b0 + CHANNEL ID ff NAME "MM12" SATID ffffff TPID 1644 SID 2c3a TYPE 0 APID 264 PCRPID b0 + CHANNEL ID 100 NAME "MM13" SATID ffffff TPID 1644 SID 2c3b TYPE 0 APID 265 PCRPID b0 + CHANNEL ID 101 NAME "MM14" SATID ffffff TPID 1644 SID 2c3c TYPE 0 APID 266 PCRPID b0 + CHANNEL ID 102 NAME "MM15" SATID ffffff TPID 1644 SID 2c3d TYPE 0 APID 267 PCRPID b0 + CHANNEL ID 103 NAME "MM16" SATID ffffff TPID 1644 SID 2c3e TYPE 0 APID 268 PCRPID b0 + CHANNEL ID 104 NAME "MM17" SATID ffffff TPID 1644 SID 2c3f TYPE 0 APID 269 PCRPID b0 + CHANNEL ID 105 NAME "MM18" SATID ffffff TPID 1644 SID 2c40 TYPE 0 APID 26a PCRPID b0 + CHANNEL ID 106 NAME "MM19" SATID ffffff TPID 1644 SID 2c41 TYPE 0 APID 26b PCRPID b0 + CHANNEL ID 107 NAME "MM20" SATID ffffff TPID 1644 SID 2c42 TYPE 0 APID 26c PCRPID b0 + CHANNEL ID 108 NAME "MM21" SATID ffffff TPID 1644 SID 2c43 TYPE 1 APID 26d PCRPID b0 + CHANNEL ID 109 NAME "MM22" SATID ffffff TPID 1644 SID 2c44 TYPE 0 APID 26e PCRPID b0 + CHANNEL ID 10a NAME "MM23" SATID ffffff TPID 1644 SID 2c45 TYPE 0 APID 26f PCRPID b0 + CHANNEL ID 10b NAME "MM24" SATID ffffff TPID 1644 SID 2c46 TYPE 0 APID 270 PCRPID b0 + CHANNEL ID 10c NAME "MM25" SATID ffffff TPID 1644 SID 2c47 TYPE 0 APID 271 PCRPID b0 + CHANNEL ID 10d NAME "MM26" SATID ffffff TPID 1644 SID 2c48 TYPE 0 APID 272 PCRPID b0 + CHANNEL ID 10e NAME "MM27" SATID ffffff TPID 1644 SID 2c49 TYPE 0 APID 273 PCRPID b0 + CHANNEL ID 10f NAME "MM28" SATID ffffff TPID 1644 SID 2c4a TYPE 0 APID 274 PCRPID b0 + CHANNEL ID 110 NAME "MM29" SATID ffffff TPID 1644 SID 2c4b TYPE 0 APID 275 PCRPID b0 + CHANNEL ID 111 NAME "MM30" SATID ffffff TPID 1644 SID 2c4c TYPE 0 APID 276 PCRPID b0 + CHANNEL ID 112 NAME "RCAP" SATID ffffff TPID 1644 SID 2c4d TYPE 1 APID 277 PCRPID b0 + CHANNEL ID 113 NAME "R105" SATID ffffff TPID 1644 SID 2c4e TYPE 0 APID 278 PCRPID b0 + CHANNEL ID 114 NAME "RDJ" SATID ffffff TPID 1644 SID 2c4f TYPE 0 APID 279 PCRPID b0 + CHANNEL ID 115 NAME "RITA" SATID ffffff TPID 1644 SID 2c50 TYPE 0 APID 27a PCRPID b0 + CHANNEL ID 116 NAME "RMC" SATID ffffff TPID 1644 SID 2c51 TYPE 0 APID 27b PCRPID b0 + CHANNEL ID 117 NAME "R101" SATID ffffff TPID 1644 SID 2c52 TYPE 0 APID 27c PCRPID b0 + CHANNEL ID 118 NAME "RRAD" SATID ffffff TPID 1644 SID 2c53 TYPE 0 APID 27d PCRPID b0 + CHANNEL ID 119 NAME "RR" SATID ffffff TPID 1644 SID 2c54 TYPE 0 APID 27e PCRPID b0 + CHANNEL ID 11a SATID ffffff TPID 1644 SID 2c61 TYPE 0 APID 259 APID 25a APID 25b APID 25c APID 25d APID 25e APID 25f APID 260 APID 261 APID 262 PCRPID b0 + CHANNEL ID 11b SATID ffffff TPID 1644 SID 2c62 TYPE 0 APID 263 APID 264 APID 265 APID 266 APID 267 APID 268 APID 269 APID 26a APID 26b APID 26c PCRPID b0 + CHANNEL ID 11c SATID ffffff TPID 1644 SID 2c63 TYPE 0 APID 26d APID 26e APID 26f APID 270 APID 271 APID 272 APID 273 APID 274 APID 275 APID 276 PCRPID b0 + CHANNEL ID 11d SATID ffffff TPID 1644 SID 2c64 TYPE 0 APID 277 APID 278 APID 279 APID 27a APID 27b APID 27c APID 27d APID 27e PCRPID b0 + CHANNEL ID 11e NAME "MULTIMUSICA" SATID ffffff TPID 1644 SID 2c58 TYPE 1 PCRPID b0 + CHANNEL ID 11f NAME "RADIO" SATID ffffff TPID 1644 SID 2c59 TYPE 1 PCRPID b0 + CHANNEL ID 120 NAME "MULTIMUSIC 1" SATID ffffff TPID 1644 SID 2c65 TYPE 1 APID 262 APID 259 APID 25a APID 25b APID 25c APID 25d APID 25e APID 25f APID 260 APID 261 PCRPID b0 + CHANNEL ID 121 NAME "MULTIMUSIC 2" SATID ffffff TPID 1644 SID 2c66 TYPE 1 APID 265 APID 266 APID 267 APID 263 APID 264 APID 268 APID 269 APID 26a APID 26b APID 26c PCRPID b0 + TRANSPONDER ID 16a8 SATID 0000 TYPE 1 FREQ 12713000 POL V SRATE 27500000 FEC 8 + CHANNEL ID 122 SATID ffffff TPID 16a8 SID fffe TYPE 0 + CHANNEL ID 123 NAME "TEAM" SATID ffffff TPID 16a8 SID e1a TYPE 1 VPID 901 PCRPID 900 + CHANNEL ID 124 NAME "SINT" SATID ffffff TPID 16a8 SID e1d TYPE 1 + CHANNEL ID 125 NAME "VIAG" SATID ffffff TPID 16a8 SID e20 TYPE 1 VPID 904 PCRPID 900 + CHANNEL ID 126 NAME "SINT" SATID ffffff TPID 16a8 SID e23 TYPE 1 + CHANNEL ID 127 NAME "EURO" SATID ffffff TPID 16a8 SID e26 TYPE 1 VPID 907 PCRPID 900 + CHANNEL ID 128 NAME "SINT" SATID ffffff TPID 16a8 SID e27 TYPE 1 + CHANNEL ID 129 NAME "CNN" SATID ffffff TPID 16a8 SID e29 TYPE 1 VPID 981 PCRPID 980 + CHANNEL ID 12a NAME "ante prima" SATID ffffff TPID 16a8 SID e2c TYPE 1 VPID 983 PCRPID 980 + CHANNEL ID 12b NAME "SNAI" SATID ffffff TPID 16a8 SID e2e TYPE 1 VPID a01 PCRPID a00 + CHANNEL ID 12c NAME "MPPV" SATID ffffff TPID 16a8 SID e30 TYPE 1 VPID a03 PCRPID a00 + CHANNEL ID 12d NAME "MC04" SATID ffffff TPID 16a8 SID e34 TYPE 1 APID a80 PCRPID a80 + CHANNEL ID 12e NAME "MC05" SATID ffffff TPID 16a8 SID e35 TYPE 1 APID a81 PCRPID a81 + CHANNEL ID 12f NAME "MC06" SATID ffffff TPID 16a8 SID e36 TYPE 1 APID a82 PCRPID a82 + CHANNEL ID 130 NAME "MC07" SATID ffffff TPID 16a8 SID e39 TYPE 1 APID a83 PCRPID a83 + CHANNEL ID 131 NAME "MC08" SATID ffffff TPID 16a8 SID e3c TYPE 1 APID a84 PCRPID a84 + CHANNEL ID 132 NAME "MC09" SATID ffffff TPID 16a8 SID e3f TYPE 1 APID a85 PCRPID a85 + CHANNEL ID 133 NAME "MC10" SATID ffffff TPID 16a8 SID e42 TYPE 1 APID a86 PCRPID a86 + CHANNEL ID 134 NAME "MC11" SATID ffffff TPID 16a8 SID e45 TYPE 1 APID a87 PCRPID a87 + CHANNEL ID 135 NAME "MC12" SATID ffffff TPID 16a8 SID e48 TYPE 1 APID a88 PCRPID a88 + CHANNEL ID 136 NAME "MC13" SATID ffffff TPID 16a8 SID e4b TYPE 1 APID a89 PCRPID a89 + CHANNEL ID 137 NAME "MC14" SATID ffffff TPID 16a8 SID e4e TYPE 1 APID a8a PCRPID a8a + CHANNEL ID 138 NAME "MC15" SATID ffffff TPID 16a8 SID e51 TYPE 1 APID a8b PCRPID a8b + CHANNEL ID 139 NAME "MC16" SATID ffffff TPID 16a8 SID e54 TYPE 1 APID a8c PCRPID a8c + CHANNEL ID 13a NAME "MC17" SATID ffffff TPID 16a8 SID e57 TYPE 1 APID a8d PCRPID a8d + CHANNEL ID 13b NAME "MC18" SATID ffffff TPID 16a8 SID e5a TYPE 1 APID a8e PCRPID a8e + TRANSPONDER ID 170c SATID 0000 TYPE 1 FREQ 12341001 POL H SRATE 27500000 FEC 8 + CHANNEL ID 13c NAME "MOSAICO D+" SATID ffffff TPID 170c SID 2c89 TYPE 1 VPID a1 APID 55 APID 51 APID 50 APID 54 PCRPID af + CHANNEL ID 13d NAME " MILAN CH." SATID ffffff TPID 170c SID 2c8b TYPE 1 VPID a2 APID 58 APID 59 PCRPID af + CHANNEL ID 13e NAME " INTER CH." SATID ffffff TPID 170c SID 2c8d TYPE 1 VPID a3 APID 5c APID 5d PCRPID af + CHANNEL ID 13f NAME "TST3" SATID ffffff TPID 170c SID 2c8f TYPE 1 PCRPID af + TRANSPONDER ID 1770 SATID 0000 TYPE 1 FREQ 11919280 POL V SRATE 27500000 FEC 8 + CHANNEL ID 140 NAME " I1" SATID ffffff TPID 1770 SID 1 TYPE 1 VPID 200 APID 28a TTPID 240 PCRPID 1ffe + CHANNEL ID 141 NAME " C5" SATID ffffff TPID 1770 SID 2 TYPE 1 VPID 201 APID 294 TTPID 241 PCRPID 1ffe + CHANNEL ID 142 NAME " R4" SATID ffffff TPID 1770 SID 3 TYPE 1 VPID 202 APID 29e TTPID 242 PCRPID 1ffe + CHANNEL ID 143 NAME "Test" SATID ffffff TPID 1770 SID 4 TYPE 1 VPID 203 APID 2a8 TTPID 243 PCRPID 1ffe + TRANSPONDER ID 003d SATID 0000 TYPE 1 FREQ 11938000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 144 NAME "NTV" SATID ffffff TPID 3d SID 1bc1 TYPE 1 VPID a4 APID 58 APID 59 PCRPID a4 + CHANNEL ID 145 NAME "NTV-PLUS" SATID ffffff TPID 3d SID 1bc2 TYPE 1 VPID a5 APID 5a APID 5b PCRPID a5 + CHANNEL ID 146 NAME "NTV Int.-HTB" SATID ffffff TPID 3d SID 1bbd TYPE 1 VPID a0 APID 50 PCRPID a0 + CHANNEL ID 147 NAME "NTV Int.-Nashe Kino" SATID ffffff TPID 3d SID 1bbe TYPE 1 VPID a1 APID 52 PCRPID a1 + CHANNEL ID 148 NAME "NTV Int.-Detsk. Mir" SATID ffffff TPID 3d SID 1bbf TYPE 1 VPID a2 APID 54 PCRPID a2 + TRANSPONDER ID 1838 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 + CHANNEL ID 149 NAME "DISNEY CHANNEL" SATID ffffff TPID 1838 SID 2a95 TYPE 1 PCRPID a0 + CHANNEL ID 14a NAME "DISCOVERY" SATID ffffff TPID 1838 SID 2a97 TYPE 1 VPID a1 PCRPID a1 + CHANNEL ID 14b NAME "EUSP" SATID ffffff TPID 1838 SID 2a99 TYPE 1 VPID a2 APID 58 APID 59 PCRPID a2 + CHANNEL ID 14c NAME "HAPPY CHANNEL" SATID ffffff TPID 1838 SID 2a9b TYPE 1 PCRPID a3 + CHANNEL ID 14d NAME "MATCH MUSIC" SATID ffffff TPID 1838 SID 2a9d TYPE 1 PCRPID a4 + CHANNEL ID 14e NAME "MTV" SATID ffffff TPID 1838 SID 2a9f TYPE 1 PCRPID a5 + CHANNEL ID 14f NAME "R/CINEMA RAISAT" SATID ffffff TPID 1838 SID 2aa1 TYPE 1 PCRPID a6 + TRANSPONDER ID 189c SATID 0000 TYPE 1 FREQ 12713000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 150 SATID ffffff TPID 189c SID fffe TYPE 0 + CHANNEL ID 151 NAME "cine stream" SATID ffffff TPID 189c SID 1e18 TYPE 1 VPID 200 APID 28a PCRPID 1ffe + CHANNEL ID 152 NAME "cine movie" SATID ffffff TPID 189c SID 1e1b TYPE 1 VPID 202 APID 29e PCRPID 1ffe + TRANSPONDER ID 1900 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 + CHANNEL ID 153 NAME "CLASSICA" SATID ffffff TPID 1900 SID 2af9 TYPE 1 PCRPID a0 + CHANNEL ID 154 NAME "R/GAM ROS RAISAT" SATID ffffff TPID 1900 SID 2afb TYPE 1 PCRPID a1 + CHANNEL ID 155 NAME "R/ALBUM RAISAT" SATID ffffff TPID 1900 SID 2afd TYPE 1 PCRPID a2 + CHANNEL ID 156 NAME "HALLMARK" SATID ffffff TPID 1900 SID 2aff TYPE 1 VPID a3 PCRPID a3 + CHANNEL ID 157 NAME "R/ART RAISAT" SATID ffffff TPID 1900 SID 2b01 TYPE 1 PCRPID a4 + CHANNEL ID 158 NAME "TST1" SATID ffffff TPID 1900 SID 2b03 TYPE 1 PCRPID a5 + CHANNEL ID 159 NAME "TMC" SATID ffffff TPID 1900 SID 2b05 TYPE 1 VPID a6 PCRPID a6 + CHANNEL ID 15a NAME "TMC2" SATID ffffff TPID 1900 SID 2b07 TYPE 1 VPID a7 PCRPID a7 + TRANSPONDER ID 1964 SATID 0000 TYPE 1 FREQ 12015000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 15b NAME "ART VARIETY" SATID ffffff TPID 1964 SID 19a TYPE 1 VPID a0 PCRPID a0 + CHANNEL ID 15c NAME "ART CHILDREN" SATID ffffff TPID 1964 SID 1a4 TYPE 1 VPID a1 PCRPID a1 + CHANNEL ID 15d NAME "ART MOVIES" SATID ffffff TPID 1964 SID 1ae TYPE 1 VPID a2 PCRPID a2 + CHANNEL ID 15e NAME "ART MUSIC" SATID ffffff TPID 1964 SID 1b8 TYPE 1 VPID a3 PCRPID a3 + CHANNEL ID 15f NAME "ART EUROPE" SATID ffffff TPID 1964 SID 1c2 TYPE 0 VPID a4 PCRPID a4 + CHANNEL ID 160 NAME "LBC EUROPE" SATID ffffff TPID 1964 SID 1cc TYPE 1 VPID a5 PCRPID a5 + CHANNEL ID 161 NAME "EGYPT SAT. CH. 2" SATID ffffff TPID 1964 SID 1d6 TYPE 1 VPID a6 PCRPID a6 + CHANNEL ID 162 NAME "ART SPORT" SATID ffffff TPID 1964 SID 1d8 TYPE 1 VPID a7 PCRPID a7 + CHANNEL ID 163 NAME "IQRA" SATID ffffff TPID 1964 SID 1da TYPE 1 VPID a8 PCRPID a8 + TRANSPONDER ID 19c8 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 + CHANNEL ID 164 NAME "T+ BIANCO" SATID ffffff TPID 19c8 SID 2b5d TYPE 1 VPID a0 APID 50 APID 51 TTPID 2c PCRPID a0 + CHANNEL ID 165 NAME "T+ NERO" SATID ffffff TPID 19c8 SID 2b5f TYPE 1 VPID a1 APID 54 APID 55 TTPID 2d PCRPID a1 + CHANNEL ID 166 NAME "T+ GRIGIO" SATID ffffff TPID 19c8 SID 2b61 TYPE 1 VPID a2 APID 58 APID 59 PCRPID a2 + CHANNEL ID 167 NAME "R4" SATID ffffff TPID 19c8 SID 18 TYPE 1 VPID a3 PCRPID a3 + CHANNEL ID 168 NAME "16:9 TELE+" SATID ffffff TPID 19c8 SID 2b63 TYPE 1 VPID a4 APID 60 APID 61 PCRPID a4 + CHANNEL ID 169 NAME "VETRINA D+" SATID ffffff TPID 19c8 SID 2b65 TYPE 1 PCRPID a5 + CHANNEL ID 16a NAME "R/RAGAZZI RAISAT" SATID ffffff TPID 19c8 SID 2b67 TYPE 1 PCRPID a6 + TRANSPONDER ID 1a2c SATID 0000 TYPE 1 FREQ 12341001 POL H SRATE 27500000 FEC 8 + CHANNEL ID 16b NAME "CNN" SATID ffffff TPID 1a2c SID 2ced TYPE 1 PCRPID af + CHANNEL ID 16c NAME "BBC" SATID ffffff TPID 1a2c SID 2cef TYPE 1 PCRPID af + CHANNEL ID 16d NAME "BLOOMBERG" SATID ffffff TPID 1a2c SID 2cf1 TYPE 1 PCRPID af + CHANNEL ID 16e NAME "CNBC" SATID ffffff TPID 1a2c SID 2cf3 TYPE 1 PCRPID af + CHANNEL ID 16f NAME "SKYNews" SATID ffffff TPID 1a2c SID 2cf5 TYPE 1 PCRPID af + CHANNEL ID 170 NAME "TST2" SATID ffffff TPID 1a2c SID 2cf7 TYPE 1 PCRPID af + CHANNEL ID 171 NAME "TV5" SATID ffffff TPID 1a2c SID 2cf9 TYPE 1 PCRPID af + CHANNEL ID 172 NAME "EPG" SATID ffffff TPID 1a2c SID 2cfb TYPE 1 PCRPID af + CHANNEL ID 173 NAME "CNN" SATID ffffff TPID 1a2c SID 2cfd TYPE 1 VPID a0 APID 50 PCRPID af + CHANNEL ID 174 NAME "CNBC" SATID ffffff TPID 1a2c SID 2cff TYPE 1 VPID a3 APID 5c PCRPID af + CHANNEL ID 175 NAME "TV5" SATID ffffff TPID 1a2c SID 2d01 TYPE 1 VPID a6 APID 68 PCRPID af + CHANNEL ID 176 NAME "BBC WORLD" SATID ffffff TPID 1a2c SID 2d03 TYPE 1 VPID a1 APID 54 PCRPID af + CHANNEL ID 177 SATID ffffff TPID 1a2c SID 2d4b TYPE 0 PCRPID 1ffe + CHANNEL ID 178 SATID ffffff TPID 1a2c SID 26fc TYPE 0 PCRPID 1ffe + CHANNEL ID 179 SATID ffffff TPID 1a2c SID 26fd TYPE 0 PCRPID 1ffe + TRANSPONDER ID 3264 SATID 0000 TYPE 1 FREQ 11095910 POL V SRATE 27500000 FEC 8 + CHANNEL ID ffffffff NAME "Telekom TV" SATID ffffff TPID 3264 SID e7f TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "FantasticOverOpal" SATID ffffff TPID 3264 SID e80 TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "Gilat" SATID ffffff TPID 3264 SID e81 TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "Siemens TV" SATID ffffff TPID 3264 SID e84 TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "S-TV" SATID ffffff TPID 3264 SID e85 TYPE 0 VPID 20 PCRPID 20 + CHANNEL ID ffffffff NAME "Optibase Encoder" SATID ffffff TPID 3264 SID e86 TYPE 0 VPID 20 PCRPID 20 + TRANSPONDER ID 1af4 SATID 0000 TYPE 1 FREQ 12091901 POL H SRATE 27500000 FEC 8 + CHANNEL ID 17a NAME "Bolsa" SATID ffffff TPID 1af4 SID 222e TYPE 0 + CHANNEL ID 17b NAME "Testw" SATID ffffff TPID 1af4 SID 222f TYPE 0 + CHANNEL ID 17c NAME "SIRE" SATID ffffff TPID 1af4 SID 2230 TYPE 0 PCRPID 102 + CHANNEL ID 17d NAME "Telesierra" SATID ffffff TPID 1af4 SID 2200 TYPE 0 VPID 1040 APID 1041 PCRPID 1040 + CHANNEL ID 17e NAME "vtv" SATID ffffff TPID 1af4 SID 21fd TYPE 0 VPID 1010 APID 1012 APID 1011 APID 1013 PCRPID 1010 + CHANNEL ID 17f NAME "Satisfaction" SATID ffffff TPID 1af4 SID 2202 TYPE 0 VPID 1060 APID 1061 PCRPID 1060 + CHANNEL ID 180 NAME "C. Milagro" SATID ffffff TPID 1af4 SID 2207 TYPE 0 VPID 1110 APID 1111 PCRPID 1110 + CHANNEL ID 181 NAME "Fiesta" SATID ffffff TPID 1af4 SID 2210 TYPE 0 VPID 1150 APID 1151 APID 1152 PCRPID 1150 + CHANNEL ID 182 NAME "TVE Internacional" SATID ffffff TPID 1af4 SID 2203 TYPE 0 VPID 1070 APID 1071 PCRPID 1070 + CHANNEL ID 183 NAME "TV Galicia" SATID ffffff TPID 1af4 SID 2204 TYPE 0 APID 1090 PCRPID 1090 + CHANNEL ID 184 NAME "Radio Gallega" SATID ffffff TPID 1af4 SID 2205 TYPE 0 APID 1090 PCRPID 1090 + CHANNEL ID 185 NAME "Retelsat" SATID ffffff TPID 1af4 SID 2212 TYPE 1 VPID 1170 APID 1171 PCRPID 1170 + CHANNEL ID 186 NAME "Musicam 1" SATID ffffff TPID 1af4 SID 2209 TYPE 1 APID 1136 PCRPID 1136 + CHANNEL ID 187 NAME "Musicam 2" SATID ffffff TPID 1af4 SID 220a TYPE 1 APID 1133 PCRPID 1133 + CHANNEL ID 188 NAME "Musicam 3" SATID ffffff TPID 1af4 SID 220b TYPE 1 APID 1136 PCRPID 1136 + CHANNEL ID 189 NAME "Musicam 4" SATID ffffff TPID 1af4 SID 220c TYPE 1 APID 1132 PCRPID 1132 + CHANNEL ID 18a NAME "Musicam 5" SATID ffffff TPID 1af4 SID 220d TYPE 1 APID 1136 PCRPID 1136 + TRANSPONDER ID 1b58 SATID 0000 TYPE 1 FREQ 12673000 POL V SRATE 27500000 FEC 8 + CHANNEL ID 18b NAME "HBCH FUCINO" SATID ffffff TPID 1b58 SID 2bd TYPE 0 VPID c8 APID c9 PCRPID c8 + CHANNEL ID 18c NAME "NTVi" SATID ffffff TPID 1b58 SID 2be TYPE 0 VPID d2 APID d3 APID d4 PCRPID d2 + CHANNEL ID 18d NAME "Test Telespazio" SATID ffffff TPID 1b58 SID 2bf TYPE 0 VPID dc APID dd PCRPID dc + CHANNEL ID 18e NAME "Test Telespazio" SATID ffffff TPID 1b58 SID 2c0 TYPE 0 VPID e6 APID e7 PCRPID e6 + CHANNEL ID 18f NAME "ARMENIA TV" SATID ffffff TPID 1b58 SID 2c1 TYPE 0 VPID f0 APID f1 APID f2 PCRPID f0 + CHANNEL ID 190 NAME "MEDNET" SATID ffffff TPID 1b58 SID 2c3 TYPE 0 VPID 104 APID 105 PCRPID 104 + CHANNEL ID 191 NAME "AL JAZEERA" SATID ffffff TPID 1b58 SID 2c4 TYPE 0 VPID 10e APID 10f PCRPID 10e + CHANNEL ID 192 NAME "TIRRENO SAT" SATID ffffff TPID 1b58 SID 2c5 TYPE 0 VPID 118 APID 12d TTPID 139 PCRPID 118 + CHANNEL ID 193 NAME "RADIO ROCK" SATID ffffff TPID 1b58 SID 2c7 TYPE 0 APID d4 PCRPID d2 + CHANNEL ID 194 NAME "RADIO ARMENIA" SATID ffffff TPID 1b58 SID 2c8 TYPE 0 APID f2 PCRPID f0 + CHANNEL ID 195 NAME "Coming Soon TV" SATID ffffff TPID 1b58 SID 2cd TYPE 0 APID 28 PCRPID 28 + TRANSPONDER ID 1c20 SATID 0000 TYPE 1 FREQ 12149000 POL V SRATE 27500000 FEC 8 + CHANNEL ID 196 NAME "AH-EDP1" SATID ffffff TPID 1c20 SID 1c21 TYPE 0 VPID 60 APID 61 PCRPID 60 + CHANNEL ID 197 NAME "AH-EDP2" SATID ffffff TPID 1c20 SID 1c22 TYPE 0 VPID 70 APID 71 PCRPID 70 + CHANNEL ID 198 NAME "AH-EDP3" SATID ffffff TPID 1c20 SID 1c23 TYPE 0 VPID 24 APID 25 PCRPID 24 + CHANNEL ID 199 NAME "AH-EMP4-DATA" SATID ffffff TPID 1c20 SID 1c24 TYPE 0 PCRPID 92 + CHANNEL ID 19a NAME "Alice" SATID ffffff TPID 1c20 SID 1c34 TYPE 0 VPID a0 APID a1 PCRPID a0 + CHANNEL ID 19b NAME "Nuvolari" SATID ffffff TPID 1c20 SID 1c35 TYPE 0 VPID b0 APID b1 PCRPID b0 + CHANNEL ID 19c NAME "Leonardo" SATID ffffff TPID 1c20 SID 1c36 TYPE 0 VPID 80 APID 81 PCRPID 80 + TRANSPONDER ID 1c84 SATID 0000 TYPE 1 FREQ 12169000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 19d NAME "Discovery" SATID ffffff TPID 1c84 SID 15f TYPE 1 VPID 200 PCRPID 1ffe + CHANNEL ID 19e NAME "R9" SATID ffffff TPID 1c84 SID 160 TYPE 1 VPID 201 PCRPID 1ffe + CHANNEL ID 19f NAME "BBC World" SATID ffffff TPID 1c84 SID 161 TYPE 1 VPID 202 PCRPID 1ffe + CHANNEL ID 1a0 NAME "CNN" SATID ffffff TPID 1c84 SID 162 TYPE 1 VPID 203 PCRPID 1ffe + CHANNEL ID 1a1 NAME "CCTV" SATID ffffff TPID 1c84 SID 163 TYPE 0 VPID 204 PCRPID 1ffe + CHANNEL ID 1a2 NAME "R10" SATID ffffff TPID 1c84 SID 165 TYPE 1 VPID 206 PCRPID 1ffe + CHANNEL ID 1a3 NAME "R8" SATID ffffff TPID 1c84 SID 166 TYPE 1 VPID 207 PCRPID 1ffe + CHANNEL ID 1a4 NAME "FILM SAT" SATID ffffff TPID 1c84 SID 167 TYPE 1 VPID 208 PCRPID 1ffe + CHANNEL ID 1a5 NAME "Cartoon" SATID ffffff TPID 1c84 SID 168 TYPE 1 VPID 203 PCRPID 1ffe + CHANNEL ID 1a6 NAME "Promo" SATID ffffff TPID 1c84 SID 169 TYPE 0 VPID 209 PCRPID 1ffe + CHANNEL ID 1a7 NAME "Tempo" SATID ffffff TPID 1c84 SID 16a TYPE 1 VPID 5a0 APID 28b PCRPID f80 + CHANNEL ID 1a8 NAME "Tempo" SATID ffffff TPID 1c84 SID 16b TYPE 1 APID 295 PCRPID f80 + CHANNEL ID 1a9 NAME "Tempo" SATID ffffff TPID 1c84 SID 16c TYPE 1 APID 29f PCRPID f80 + CHANNEL ID 1aa NAME "Tempo" SATID ffffff TPID 1c84 SID 16d TYPE 1 APID 2a9 PCRPID f80 + CHANNEL ID 1ab NAME "Tempo" SATID ffffff TPID 1c84 SID 16e TYPE 1 APID 2b3 PCRPID f80 + CHANNEL ID 1ac NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 16f TYPE 1 PCRPID 1080 + CHANNEL ID 1ad NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 171 TYPE 1 PCRPID 1080 + CHANNEL ID 1ae NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 172 TYPE 1 PCRPID 1080 + CHANNEL ID 1af NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 173 TYPE 1 VPID 42b PCRPID 1080 + CHANNEL ID 1b0 NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 174 TYPE 1 PCRPID 1080 + CHANNEL ID 1b1 NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 175 TYPE 1 PCRPID 1080 + CHANNEL ID 1b2 NAME "NOVA Cinema" SATID ffffff TPID 1c84 SID 176 TYPE 1 PCRPID 1080 + CHANNEL ID 1b3 NAME "NET" SATID ffffff TPID 1c84 SID 178 TYPE 1 VPID 201 PCRPID 1ffe + CHANNEL ID 1b4 NAME "MAD T.V" SATID ffffff TPID 1c84 SID 179 TYPE 1 VPID 206 PCRPID 1ffe + CHANNEL ID 1b5 NAME "ET-1" SATID ffffff TPID 1c84 SID 17a TYPE 1 VPID 207 PCRPID 1ffe + CHANNEL ID 1b6 SATID ffffff TPID 1c84 SID 17b TYPE 0 PCRPID 1000 + CHANNEL ID 1b7 NAME "" SATID ffffff TPID 1c84 SID 180 TYPE 0 VPID 205 PCRPID 1ffe + TRANSPONDER ID 0131 SATID 0000 TYPE 1 FREQ 12188000 POL V SRATE 27500000 FEC 8 + TRANSPONDER ID 0132 SATID 0000 TYPE 1 FREQ 12203000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 0133 SATID 0000 TYPE 1 FREQ 12211000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 004d SATID 0000 TYPE 1 FREQ 12264500 POL V SRATE 27500000 FEC 8 + CHANNEL ID ffffffff NAME "Deutsche Bank / T1" SATID ffffff TPID 4d SID 1 TYPE 1 VPID 488 PCRPID 488 + CHANNEL ID 7f NAME "Animal Planet" SATID ffffff TPID 4d SID a TYPE 1 VPID 488 PCRPID 488 + CHANNEL ID 80 NAME "Discovery E Europe-English" SATID ffffff TPID 4d SID 14 TYPE 1 VPID 4ec PCRPID 4ec + CHANNEL ID ffffffff NAME "Wuerth KG / T21" SATID ffffff TPID 4d SID 15 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 82 NAME "Discovery Italy" SATID ffffff TPID 4d SID 1e TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID ffffffff NAME "BTI / T31" SATID ffffff TPID 4d SID 1f TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 84 NAME "Discovery Russia" SATID ffffff TPID 4d SID 28 TYPE 1 VPID 5b4 PCRPID 5b4 + CHANNEL ID ffffffff NAME "K-TV (MetroMux) / T41" SATID ffffff TPID 4d SID 29 TYPE 1 VPID 7a8 PCRPID 7a8 + CHANNEL ID 86 NAME "Animal Planet EE" SATID ffffff TPID 4d SID 32 TYPE 1 VPID 618 PCRPID 618 + CHANNEL ID 87 NAME "Animal Planet - Russian" SATID ffffff TPID 4d SID 33 TYPE 1 VPID 618 PCRPID 618 + CHANNEL ID 88 NAME "Discovery Netherlands" SATID ffffff TPID 4d SID 3c TYPE 1 VPID 67c PCRPID 67c + CHANNEL ID ffffffff NAME "Q English" SATID ffffff TPID 4d SID 46 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 8a NAME "Travel and Adventure" SATID ffffff TPID 4d SID 50 TYPE 1 VPID 744 PCRPID 744 + CHANNEL ID 8b NAME "Travel and Adventure- Russian" SATID ffffff TPID 4d SID 51 TYPE 1 VPID 744 PCRPID 744 + CHANNEL ID 8c NAME "New DCP" SATID ffffff TPID 4d SID 12c TYPE 1 APID 4c4 PCRPID 4c4 + CHANNEL ID 8d NAME "CCP" SATID ffffff TPID 4d SID 12d TYPE 1 VPID 4ec PCRPID 4ec + CHANNEL ID ffffffff NAME "Deutsche Bank / T2" SATID ffffff TPID 4d SID 2 TYPE 1 VPID 4ec PCRPID 4ec + CHANNEL ID 93 NAME "Channel Three" SATID ffffff TPID 4d SID 3 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 94 NAME "Channel Four" SATID ffffff TPID 4d SID 4 TYPE 0 VPID 5b4 PCRPID 5b4 + CHANNEL ID 95 NAME "Channel Five" SATID ffffff TPID 4d SID 5 TYPE 0 VPID 618 PCRPID 618 + CHANNEL ID 96 NAME "Channel 6 = Sat 7 Arabic" SATID ffffff TPID 4d SID 6 TYPE 0 VPID 67c PCRPID 67c + CHANNEL ID 97 NAME "Channel Seven" SATID ffffff TPID 4d SID 7 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 98 NAME "Q German" SATID ffffff TPID 4d SID 47 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 99 NAME "Q French" SATID ffffff TPID 4d SID 48 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 9a NAME "Q Dutch" SATID ffffff TPID 4d SID 49 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 1b8 NAME "DTAG / T11" SATID ffffff TPID 4d SID b TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1b9 NAME "DTAG 50 / T12" SATID ffffff TPID 4d SID c TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1ba NAME "Telekom TV" SATID ffffff TPID 4d SID d TYPE 1 VPID 5b4 PCRPID 5b4 + CHANNEL ID 1bb NAME "Gerling / T26" SATID ffffff TPID 4d SID 1a TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1bc NAME "Hornbach-D / T36" SATID ffffff TPID 4d SID 24 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1bd NAME "Hornbach-NL / T38" SATID ffffff TPID 4d SID 26 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1be NAME "Hornbach-CZ / T39" SATID ffffff TPID 4d SID 27 TYPE 1 VPID 550 PCRPID 550 + CHANNEL ID 1bf NAME "Testkanal" SATID ffffff TPID 4d SID 63 TYPE 0 VPID 67c PCRPID 67c + CHANNEL ID 1c0 NAME "KENCAST" SATID ffffff TPID 4d SID 6f TYPE 0 PCRPID 42e + TRANSPONDER ID 1f40 SATID 0000 TYPE 1 FREQ 12302880 POL V SRATE 27500000 FEC 8 + CHANNEL ID 1c1 NAME "SLO-TV1" SATID ffffff TPID 1f40 SID c81 TYPE 1 VPID c8 PCRPID c8 + CHANNEL ID 1c2 NAME "SLO-TV2" SATID ffffff TPID 1f40 SID c82 TYPE 1 VPID cb PCRPID cb + CHANNEL ID 1c3 NAME "POLONIA 1" SATID ffffff TPID 1f40 SID c83 TYPE 0 VPID cd PCRPID cd + CHANNEL ID 1c4 NAME "SLO-RA1-INF" SATID ffffff TPID 1f40 SID c84 TYPE 0 APID fa PCRPID fa + CHANNEL ID 1c5 NAME "SLO-RA2" SATID ffffff TPID 1f40 SID c85 TYPE 0 APID fb PCRPID fb + CHANNEL ID 1c6 NAME "SLO-RA3" SATID ffffff TPID 1f40 SID c86 TYPE 0 APID fc PCRPID fc + CHANNEL ID 1c7 NAME "SUPER 1" SATID ffffff TPID 1f40 SID c87 TYPE 0 VPID cf PCRPID cf + CHANNEL ID 1c8 NAME "NAPOLI INT." SATID ffffff TPID 1f40 SID c8a TYPE 0 VPID f0 PCRPID f0 + CHANNEL ID 1c9 NAME "MAGIC" SATID ffffff TPID 1f40 SID c8b TYPE 0 VPID f5 PCRPID f5 + CHANNEL ID 1ca NAME "COUNTDOWN" SATID ffffff TPID 1f40 SID c8c TYPE 0 VPID eb PCRPID eb + CHANNEL ID 1cb NAME "TBNE" SATID ffffff TPID 1f40 SID c8d TYPE 0 VPID e6 PCRPID e6 + CHANNEL ID 1cc NAME "SICILSAT" SATID ffffff TPID 1f40 SID c8e TYPE 0 VPID e1 PCRPID e1 + TRANSPONDER ID 1fa4 SATID 0000 TYPE 1 FREQ 10892000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 1cd NAME "TVP1" SATID ffffff TPID 1fa4 SID 1 TYPE 1 VPID 101 APID 102 APID 17df TTPID 103 PCRPID 101 + CHANNEL ID 1ce NAME "TVP2" SATID ffffff TPID 1fa4 SID 2 TYPE 1 VPID 141 APID 142 PCRPID 141 + CHANNEL ID 1cf NAME "POLSAT1" SATID ffffff TPID 1fa4 SID 3 TYPE 1 + CHANNEL ID 1d0 NAME "TV4" SATID ffffff TPID 1fa4 SID 4 TYPE 1 VPID 101 APID 102 APID 17df TTPID 103 PCRPID 101 + CHANNEL ID 1d1 NAME "POLSAT2" SATID ffffff TPID 1fa4 SID 5 TYPE 1 VPID 141 APID 142 PCRPID 141 + CHANNEL ID 1d2 NAME "WOT" SATID ffffff TPID 1fa4 SID 6 TYPE 1 + CHANNEL ID 1d3 NAME "DISCOVERY" SATID ffffff TPID 1fa4 SID f TYPE 1 VPID 101 APID 102 APID 17df TTPID 103 PCRPID 101 + CHANNEL ID 1d4 NAME "ANIMAL PLANET" SATID ffffff TPID 1fa4 SID 10 TYPE 1 VPID 141 APID 142 PCRPID 141 + CHANNEL ID 1d5 NAME "EpgOpenTV" SATID ffffff TPID 1fa4 SID e66 TYPE 0 + TRANSPONDER ID 2008 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 + CHANNEL ID 1d6 NAME "P10" SATID ffffff TPID 2008 SID 2d51 TYPE 1 VPID a0 APID 50 APID 51 PCRPID b0 + CHANNEL ID 1d7 NAME "P11" SATID ffffff TPID 2008 SID 2d53 TYPE 1 VPID a1 APID 54 APID 55 PCRPID b0 + CHANNEL ID 1d8 NAME "P12" SATID ffffff TPID 2008 SID 2d55 TYPE 1 VPID a2 APID 58 APID 59 PCRPID b0 + CHANNEL ID 1d9 NAME "P13" SATID ffffff TPID 2008 SID 2d57 TYPE 1 VPID a3 APID 5c APID 5d PCRPID b0 + CHANNEL ID 1da NAME "P14" SATID ffffff TPID 2008 SID 2d59 TYPE 1 VPID a4 APID 60 APID 61 PCRPID b0 + CHANNEL ID 1db NAME "P15" SATID ffffff TPID 2008 SID 2d5b TYPE 1 VPID a5 APID 64 APID 65 PCRPID b0 + CHANNEL ID 1dc NAME "P16" SATID ffffff TPID 2008 SID 2d5d TYPE 1 VPID a6 APID 68 APID 69 PCRPID b0 + CHANNEL ID 1dd NAME "PREMIUM" SATID ffffff TPID 2008 SID 2d5f TYPE 1 PCRPID af + CHANNEL ID 1de NAME "+F1" SATID ffffff TPID 2008 SID 2d61 TYPE 1 VPID a0 APID 51 APID 298 PCRPID b0 + CHANNEL ID 1df NAME "+F1" SATID ffffff TPID 2008 SID 2d63 TYPE 1 VPID a1 APID 29a APID 55 PCRPID b0 + CHANNEL ID 1e0 NAME "+F1" SATID ffffff TPID 2008 SID 2d65 TYPE 1 VPID a2 APID 59 APID 29b PCRPID b0 + CHANNEL ID 1e1 NAME "+F1" SATID ffffff TPID 2008 SID 2d67 TYPE 1 VPID a3 APID 5d APID 2a2 PCRPID b0 + CHANNEL ID 1e2 NAME "+F1" SATID ffffff TPID 2008 SID 2d69 TYPE 1 VPID a4 APID 61 APID 60 PCRPID b0 + CHANNEL ID 1e3 NAME "+F1" SATID ffffff TPID 2008 SID 2d6b TYPE 1 VPID a5 APID 65 APID 2a4 PCRPID b0 + CHANNEL ID 1e4 NAME "+F1" SATID ffffff TPID 2008 SID 2d6d TYPE 1 VPID a6 APID 69 APID 29a PCRPID b0 + CHANNEL ID 1e5 NAME "RMC" SATID ffffff TPID 2008 SID 2d6f TYPE 1 PCRPID b8 + CHANNEL ID 1e6 NAME "R101" SATID ffffff TPID 2008 SID 2d70 TYPE 1 PCRPID b8 + CHANNEL ID 1e7 NAME "RRAD" SATID ffffff TPID 2008 SID 2d71 TYPE 1 PCRPID b8 + TRANSPONDER ID 206c SATID 0000 TYPE 1 FREQ 10892000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 1e8 NAME "ON" SATID ffffff TPID 206c SID 7 TYPE 1 VPID 161 APID 162 PCRPID 161 + CHANNEL ID 1e9 NAME "DLA-CIEBIE" SATID ffffff TPID 206c SID 8 TYPE 1 VPID 211 APID 212 PCRPID 211 + CHANNEL ID 1ea NAME "KOMEDIA" SATID ffffff TPID 206c SID 9 TYPE 1 VPID 161 APID 162 PCRPID 161 + CHANNEL ID 1eb NAME "SMYK" SATID ffffff TPID 206c SID a TYPE 1 VPID 211 APID 212 PCRPID 211 + CHANNEL ID 1ec NAME "RELAKS" SATID ffffff TPID 206c SID b TYPE 1 VPID 161 APID 162 PCRPID 161 + CHANNEL ID 1ed NAME "INFO" SATID ffffff TPID 206c SID c TYPE 1 VPID 211 APID 212 PCRPID 211 + CHANNEL ID 1ee NAME "POLSAT SPORT" SATID ffffff TPID 206c SID d TYPE 1 VPID 161 APID 162 PCRPID 161 + TRANSPONDER ID 20d0 SATID 0000 TYPE 1 FREQ 12379000 POL V SRATE 27500000 FEC 8 + CHANNEL ID 1ef NAME "Paris Premire" SATID ffffff TPID 20d0 SID bb9 TYPE 1 VPID bcd APID bd7 PCRPID bcd + CHANNEL ID 1f0 NAME "OCC HB3" SATID ffffff TPID 20d0 SID bba TYPE 0 VPID bce APID bd8 PCRPID bce + CHANNEL ID 1f1 NAME "TELE 24 Switzerland" SATID ffffff TPID 20d0 SID bbb TYPE 0 VPID bcf APID bd9 PCRPID bcf + CHANNEL ID 1f2 NAME "AIR MEDIA" SATID ffffff TPID 20d0 SID c0f TYPE 0 APID dd1 PCRPID dd1 + CHANNEL ID 1f3 NAME "Abu Dhabi TV" SATID ffffff TPID 20d0 SID bbc TYPE 0 VPID bd0 APID bda PCRPID bd0 + CHANNEL ID 1f4 NAME "EMIRAT FM 1" SATID ffffff TPID 20d0 SID c0b TYPE 0 APID dcd PCRPID dcd + CHANNEL ID 1f5 NAME "EMIRAT FM2" SATID ffffff TPID 20d0 SID c0c TYPE 0 APID dce PCRPID dce + CHANNEL ID 1f6 NAME "Radio Italia " SATID ffffff TPID 20d0 SID c09 TYPE 0 APID dcb PCRPID dcb + CHANNEL ID 1f7 NAME "EQUIDIA INTER." SATID ffffff TPID 20d0 SID beb TYPE 1 VPID cf9 APID d03 APID d0d APID d17 PCRPID cf9 + CHANNEL ID 1f8 NAME "RTV MONTENEGRO" SATID ffffff TPID 20d0 SID bbe TYPE 0 VPID bd2 APID bdc PCRPID bd2 + CHANNEL ID 1f9 NAME "Radio Montenegro" SATID ffffff TPID 20d0 SID c10 TYPE 0 APID dd2 PCRPID dd2 + CHANNEL ID 1fa NAME "SERTE TEST" SATID ffffff TPID 20d0 SID bbd TYPE 0 VPID bd1 PCRPID bd1 + CHANNEL ID 1fb NAME "GAME 1" SATID ffffff TPID 20d0 SID bbf TYPE 1 VPID bd3 APID bdd PCRPID bd3 + TRANSPONDER ID 0055 SATID 0000 TYPE 1 FREQ 12398781 POL H SRATE 27500000 FEC 8 + CHANNEL ID 1fc NAME "SF 2" SATID ffffff TPID 55 SID 38b TYPE 1 VPID a3 APID 5c APID 5d TTPID 29 PCRPID a3 + CHANNEL ID 1fd NAME "SRG SSR Sat Access" SATID ffffff TPID 55 SID 38e TYPE 0 VPID a5 APID 62 APID 63 TTPID 2f PCRPID a5 + CHANNEL ID 1fe NAME "SF 1" SATID ffffff TPID 55 SID 385 TYPE 1 VPID a0 APID 50 APID 51 TTPID 20 PCRPID a0 + CHANNEL ID 1ff NAME "TSR 1" SATID ffffff TPID 55 SID 386 TYPE 1 VPID a1 APID 54 APID 55 TTPID 23 PCRPID a1 + CHANNEL ID 200 NAME "TSI 1" SATID ffffff TPID 55 SID 387 TYPE 1 VPID a2 APID 58 APID 59 TTPID 26 PCRPID a2 + CHANNEL ID 201 NAME "TSR 2" SATID ffffff TPID 55 SID 38c TYPE 1 VPID a4 APID 60 APID 61 TTPID 2c PCRPID a4 + CHANNEL ID 202 NAME "TSI 2" SATID ffffff TPID 55 SID 38d TYPE 1 VPID a6 APID 64 APID 65 TTPID 32 PCRPID a6 + CHANNEL ID 203 NAME "OPTION MUSIQUE" SATID ffffff TPID 55 SID 3bd TYPE 0 APID cc PCRPID cc + CHANNEL ID 204 NAME "ESPACE 2" SATID ffffff TPID 55 SID 3be TYPE 0 APID cd PCRPID cd + CHANNEL ID 205 NAME "SRI-F-I" SATID ffffff TPID 55 SID 3b7 TYPE 0 APID c7 PCRPID c7 + CHANNEL ID 206 NAME "SRI-EUROPA" SATID ffffff TPID 55 SID 3b9 TYPE 0 VPID 230 APID c8 PCRPID c8 + TRANSPONDER ID 2198 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 + CHANNEL ID 207 NAME "POLO" SATID ffffff TPID 2198 SID 2db5 TYPE 1 VPID a0 APID 50 PCRPID a0 + CHANNEL ID 208 NAME "PLANETE" SATID ffffff TPID 2198 SID 2db7 TYPE 1 VPID a1 APID 54 PCRPID a1 + CHANNEL ID 209 NAME "JIMMY" SATID ffffff TPID 2198 SID 2db9 TYPE 1 VPID a2 APID 58 PCRPID a2 + CHANNEL ID 20a NAME "INN" SATID ffffff TPID 2198 SID 2dbb TYPE 1 VPID a3 APID 5c PCRPID a3 + CHANNEL ID 20b NAME "CIN1" SATID ffffff TPID 2198 SID 2dbd TYPE 1 VPID a4 APID 60 PCRPID a4 + CHANNEL ID 20c NAME "CIN2" SATID ffffff TPID 2198 SID 2dbf TYPE 1 VPID a5 APID 64 PCRPID a5 + CHANNEL ID 20d NAME "CINC" SATID ffffff TPID 2198 SID 2dc1 TYPE 1 VPID a6 APID 68 PCRPID a6 + CHANNEL ID 20e NAME "SEASONS" SATID ffffff TPID 2198 SID 2dc3 TYPE 1 VPID a7 APID 6c PCRPID a7 + CHANNEL ID 20f NAME "WISHLINE" SATID ffffff TPID 2198 SID 2dc5 TYPE 1 VPID a8 APID 55 APID 5d APID 59 PCRPID a8 + CHANNEL ID 210 NAME "MARCOPOLO" SATID ffffff TPID 2198 SID 2dc7 TYPE 1 VPID a0 APID 50 APID 51 PCRPID a0 + TRANSPONDER ID 0049 SATID 0000 TYPE 1 FREQ 12436999 POL H SRATE 27500000 FEC 8 + CHANNEL ID 211 NAME "JAAM-E-JAM 1" SATID ffffff TPID 49 SID 1 TYPE 0 VPID a0 APID 50 APID 51 PCRPID a0 + CHANNEL ID 212 NAME "JAAM-E-JAM 2" SATID ffffff TPID 49 SID 2 TYPE 0 VPID a1 APID 52 APID 53 TTPID 21 PCRPID a1 + CHANNEL ID 213 NAME "SAHAR" SATID ffffff TPID 49 SID 3 TYPE 0 VPID a2 APID 54 APID 55 PCRPID a2 + CHANNEL ID 214 NAME "TEST(SAHAR)" SATID ffffff TPID 49 SID 4 TYPE 0 VPID a3 APID 56 APID 57 PCRPID a3 + CHANNEL ID 215 NAME "IRINN" SATID ffffff TPID 49 SID 5 TYPE 0 VPID a4 APID 58 APID 59 PCRPID a4 + CHANNEL ID 216 NAME "TEST 2" SATID ffffff TPID 49 SID 6 TYPE 0 VPID a5 APID 5a PCRPID a5 + CHANNEL ID 217 NAME "IRIB1 RADIO" SATID ffffff TPID 49 SID 7 TYPE 0 APID 51 PCRPID a0 + CHANNEL ID 218 NAME "IRIB ARABIC /International 1 Radio" SATID ffffff TPID 49 SID 8 TYPE 0 APID 53 PCRPID a1 + TRANSPONDER ID 013d SATID 0000 TYPE 1 FREQ 12460000 POL V SRATE 27500000 FEC 8 + TRANSPONDER ID 013e SATID 0000 TYPE 1 FREQ 12484000 POL V SRATE 27500000 FEC 8 + TRANSPONDER ID 22c4 SATID 0000 TYPE 1 FREQ 12475499 POL H SRATE 27500000 FEC 8 + CHANNEL ID 219 NAME "INT1 FAMILY RADIO" SATID ffffff TPID 22c4 SID 2977 TYPE 0 APID 3c1 PCRPID 3c1 + CHANNEL ID 21a NAME "RADIO 74" SATID ffffff TPID 22c4 SID 2974 TYPE 0 APID 399 PCRPID 399 + CHANNEL ID 21b NAME "R 74 INT." SATID ffffff TPID 22c4 SID 2975 TYPE 0 APID 3a3 PCRPID 3a3 + CHANNEL ID 21c NAME "FAMILY Radio" SATID ffffff TPID 22c4 SID 2976 TYPE 0 APID 3b7 PCRPID 3b7 + CHANNEL ID 21d NAME "Temp" SATID ffffff TPID 22c4 SID 296f TYPE 0 VPID 303 PCRPID 300 + CHANNEL ID 21e NAME "SPREE Radio" SATID ffffff TPID 22c4 SID 299c TYPE 0 APID 1f5 PCRPID 1f5 + CHANNEL ID 21f NAME " RVI ( VRT ) " SATID ffffff TPID 22c4 SID 2972 TYPE 0 APID 385 PCRPID 385 + CHANNEL ID 220 NAME "EbS" SATID ffffff TPID 22c4 SID 2969 TYPE 0 VPID 65 APID c9 APID ca APID cb APID cc APID cd APID ce APID cf APID d0 APID d1 APID d2 APID d3 APID d4 APID d5 APID d6 APID d7 APID d8 TTPID 12d PCRPID 65 + CHANNEL ID 221 NAME "MOU.2" SATID ffffff TPID 22c4 SID 296a TYPE 0 VPID 2a PCRPID 2a + CHANNEL ID 222 NAME "MIZIK TROPICAL" SATID ffffff TPID 22c4 SID 296e TYPE 0 VPID 1b3 APID 1b4 PCRPID 1b3 + CHANNEL ID 223 NAME "MIZIK TROPICAL Radio" SATID ffffff TPID 22c4 SID 2970 TYPE 0 APID 321 PCRPID 321 + CHANNEL ID 224 NAME "Framboise Nord (CH)" SATID ffffff TPID 22c4 SID 2978 TYPE 0 APID 3cb PCRPID 3cb + CHANNEL ID 225 NAME "Framboise Sud (CH)" SATID ffffff TPID 22c4 SID 2979 TYPE 0 APID 3d5 PCRPID 3d5 + CHANNEL ID 226 NAME "PINK PLUS" SATID ffffff TPID 22c4 SID 296d TYPE 1 VPID 134 APID 100 APID 101 PCRPID 24 + CHANNEL ID 227 NAME "LIBERTYTV.COM" SATID ffffff TPID 22c4 SID 296b TYPE 0 VPID 3ad APID 3ae PCRPID 3ad + CHANNEL ID 228 NAME "KURDSAT" SATID ffffff TPID 22c4 SID 297a TYPE 0 VPID 258 APID 259 PCRPID 1ffe + CHANNEL ID 229 NAME "test2" SATID ffffff TPID 22c4 SID 297c TYPE 0 VPID bb8 APID bb9 TTPID bba PCRPID bb8 + TRANSPONDER ID 2328 SATID 0000 TYPE 1 FREQ 12519840 POL V SRATE 27500000 FEC 8 + CHANNEL ID 22a NAME "HRT-TV1" SATID ffffff TPID 2328 SID 206d TYPE 1 VPID 64 APID 65 TTPID 66 PCRPID 64 + CHANNEL ID 22b NAME "HRT-TV2" SATID ffffff TPID 2328 SID 206e TYPE 1 VPID 67 APID 68 TTPID 66 PCRPID 67 + CHANNEL ID 22c NAME "HRT-TV3" SATID ffffff TPID 2328 SID 206f TYPE 1 VPID 69 APID 6a TTPID 66 PCRPID 69 + CHANNEL ID 22d NAME "HRT-HR1" SATID ffffff TPID 2328 SID 2071 TYPE 0 APID 96 PCRPID 96 + CHANNEL ID 22e NAME "HRT-HR2" SATID ffffff TPID 2328 SID 2072 TYPE 0 APID 97 PCRPID 97 + CHANNEL ID 22f NAME "HRT-HR3" SATID ffffff TPID 2328 SID 2073 TYPE 0 APID 98 PCRPID 98 + CHANNEL ID 230 NAME "SICILIA INTERNATIONAL" SATID ffffff TPID 2328 SID 2075 TYPE 0 VPID 1f5 PCRPID 1f5 + CHANNEL ID 231 NAME "HRT-NATIONAL" SATID ffffff TPID 2328 SID 2070 TYPE 1 VPID 6b APID 6c TTPID 66 PCRPID 6b + CHANNEL ID 232 NAME "HRT-TEST" SATID ffffff TPID 2328 SID 2074 TYPE 1 VPID 6d APID 6e TTPID 66 PCRPID 6d + CHANNEL ID 233 NAME "SARDEGNA UNO" SATID ffffff TPID 2328 SID 2076 TYPE 0 VPID 1f7 PCRPID 1f7 + CHANNEL ID 234 NAME "R-HRVATSKA" SATID ffffff TPID 2328 SID 2077 TYPE 0 APID 99 PCRPID 99 + CHANNEL ID 235 NAME "EuroMed" SATID ffffff TPID 2328 SID 2078 TYPE 0 VPID 1fe PCRPID 1fe + CHANNEL ID 236 NAME "TGRT" SATID ffffff TPID 2328 SID 2079 TYPE 0 VPID 1f9 PCRPID 1f9 + CHANNEL ID 237 NAME "HR-TEST" SATID ffffff TPID 2328 SID 207a TYPE 0 APID 9a PCRPID 9a + CHANNEL ID 238 NAME "MINI-BVN" SATID ffffff TPID 2328 SID 207b TYPE 0 VPID d2 PCRPID d6 + TRANSPONDER ID 238c SATID 0000 TYPE 1 FREQ 12713000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 239 NAME "SIMS 91 LARIO" SATID ffffff TPID 238c SID 2262 TYPE 0 + CHANNEL ID 23a NAME "SKYPLEX TXP91" SATID ffffff TPID 238c SID 2261 TYPE 0 + CHANNEL ID 23b NAME "Skygate 18" SATID ffffff TPID 238c SID 2 TYPE 0 + CHANNEL ID 23c NAME "MA12_2905" SATID ffffff TPID 238c SID 226a TYPE 0 PCRPID 1113 + CHANNEL ID 23d NAME "ES13_1107" SATID ffffff TPID 238c SID 226b TYPE 0 PCRPID 1114 + CHANNEL ID 23e NAME "ASTONv0107" SATID ffffff TPID 238c SID 226f TYPE 0 PCRPID 1112 + CHANNEL ID 23f NAME "sisal" SATID ffffff TPID 238c SID 1 TYPE 1 VPID 1104 PCRPID 1104 + CHANNEL ID 240 NAME "service" SATID ffffff TPID 238c SID 3 TYPE 1 VPID 1104 PCRPID 1104 + CHANNEL ID 241 NAME "Skyplex 19" SATID ffffff TPID 238c SID 231f TYPE 0 + CHANNEL ID 242 NAME "Network" SATID ffffff TPID 238c SID 2320 TYPE 0 + CHANNEL ID 243 NAME "www.travel" SATID ffffff TPID 238c SID 2321 TYPE 0 VPID 49c APID 49f APID 4a0 TTPID 49d PCRPID 49c + CHANNEL ID 244 NAME "MagicStar" SATID ffffff TPID 238c SID 2322 TYPE 0 APID 4a4 PCRPID 4a4 + CHANNEL ID 245 NAME "Skygate 8" SATID ffffff TPID 238c SID 22de TYPE 0 + CHANNEL ID 246 NAME "UDLR" SATID ffffff TPID 238c SID 22df TYPE 0 APID 19fd + CHANNEL ID 247 NAME "UDLR UDcast" SATID ffffff TPID 238c SID 22e0 TYPE 0 + CHANNEL ID 248 NAME "Skygate 17" SATID ffffff TPID 238c SID 2264 TYPE 0 + CHANNEL ID 249 NAME "Netshow" SATID ffffff TPID 238c SID 226d TYPE 0 + CHANNEL ID 24a NAME "MEDIOLANUM" SATID ffffff TPID 238c SID 226e TYPE 0 VPID 1006 PCRPID 1006 + CHANNEL ID 24b NAME "Skygate 10" SATID ffffff TPID 238c SID 22c5 TYPE 0 + CHANNEL ID 24c NAME "HitCast Data 1" SATID ffffff TPID 238c SID 22c6 TYPE 0 + CHANNEL ID 24d NAME "HitCast S.Amer." SATID ffffff TPID 238c SID 22c7 TYPE 0 + CHANNEL ID 24e NAME "Skygate 1" SATID ffffff TPID 238c SID 22ac TYPE 0 + CHANNEL ID 24f NAME "MonteCarloSat" SATID ffffff TPID 238c SID 22ad TYPE 0 VPID 1407 APID 1402 PCRPID 1407 + CHANNEL ID 250 NAME "Bulgaria Radio" SATID ffffff TPID 238c SID 227c TYPE 0 APID 1207 + CHANNEL ID 251 NAME "skygate 600" SATID ffffff TPID 238c SID 227a TYPE 0 + TRANSPONDER ID 23f0 SATID 0000 TYPE 1 FREQ 12558201 POL V SRATE 27500000 FEC 8 + CHANNEL ID 252 NAME "SKYPLEX TXP92" SATID ffffff TPID 23f0 SID 238d TYPE 0 + CHANNEL ID 253 SATID ffffff TPID 23f0 SID 2491 TYPE 0 + CHANNEL ID 254 SATID ffffff TPID 23f0 SID 2492 TYPE 0 VPID b09 APID b02 TTPID b0a PCRPID b09 + CHANNEL ID 255 SATID ffffff TPID 23f0 SID 2493 TYPE 0 VPID b09 TTPID b0a PCRPID b0d + CHANNEL ID 256 SATID ffffff TPID 23f0 SID 2494 TYPE 0 VPID b09 TTPID b0a PCRPID b04 + CHANNEL ID 257 NAME "SKY_4" SATID ffffff TPID 23f0 SID 2487 TYPE 0 + CHANNEL ID 258 NAME "ESP Int'l" SATID ffffff TPID 23f0 SID 2488 TYPE 1 VPID a0f APID a02 APID a03 TTPID a10 PCRPID a0f + CHANNEL ID 259 NAME "ESP Romanian" SATID ffffff TPID 23f0 SID 2489 TYPE 1 APID a09 PCRPID a2c + CHANNEL ID 25a NAME "ESP Dutch" SATID ffffff TPID 23f0 SID 248a TYPE 1 VPID a0f APID a04 TTPID a10 PCRPID a2c + CHANNEL ID 25b NAME "ESP PolisI" SATID ffffff TPID 23f0 SID 248b TYPE 1 APID a05 PCRPID a2c + CHANNEL ID 25c SATID ffffff TPID 23f0 SID 248c TYPE 0 VPID a0f APID a06 TTPID a10 PCRPID a2c + CHANNEL ID 25d SATID ffffff TPID 23f0 SID 248d TYPE 0 VPID a0f APID a04 TTPID a10 PCRPID a2c + CHANNEL ID 25e SATID ffffff TPID 23f0 SID 248e TYPE 0 VPID a0f APID a08 TTPID a10 PCRPID a2c + CHANNEL ID 25f SATID ffffff TPID 23f0 SID 248f TYPE 0 APID a02 APID a03 APID a04 APID a05 PCRPID a0f + CHANNEL ID 260 SATID ffffff TPID 23f0 SID 2423 TYPE 0 + TRANSPONDER ID 0143 SATID 0000 TYPE 1 FREQ 12573000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 0144 SATID 0000 TYPE 1 FREQ 12590000 POL H SRATE 27500000 FEC 8 + TRANSPONDER ID 24b8 SATID 0000 TYPE 1 FREQ 12596560 POL V SRATE 27500000 FEC 8 + CHANNEL ID 261 NAME "JSTV 1" SATID ffffff TPID 24b8 SID 2015 TYPE 0 VPID 7d0 APID 7d2 APID 7d3 APID 7d2 PCRPID 7d0 + CHANNEL ID 262 NAME "JSTV 2" SATID ffffff TPID 24b8 SID 2016 TYPE 0 VPID 7db APID 7dc APID 7dd APID 7dd PCRPID 7db + CHANNEL ID 263 NAME "MBC" SATID ffffff TPID 24b8 SID 2009 TYPE 0 VPID a0 APID 50 APID 51 TTPID 20 PCRPID a0 + CHANNEL ID 264 NAME "Service 2" SATID ffffff TPID 24b8 SID 200a TYPE 0 VPID a1 APID 54 PCRPID a1 + CHANNEL ID 265 NAME "NITV" SATID ffffff TPID 24b8 SID 200c TYPE 0 VPID a3 APID 5c PCRPID a3 + CHANNEL ID 266 NAME "SIMAYE AZADI" SATID ffffff TPID 24b8 SID 200f TYPE 0 VPID a6 APID 6a PCRPID a6 + CHANNEL ID 267 NAME "BET" SATID ffffff TPID 24b8 SID 2010 TYPE 0 VPID a7 APID 6c APID 6d PCRPID a7 + CHANNEL ID 268 NAME "CNNI" SATID ffffff TPID 24b8 SID 2011 TYPE 1 VPID a8 APID 70 APID 71 TTPID 38 PCRPID a8 + CHANNEL ID 269 NAME "EuroNews" SATID ffffff TPID 24b8 SID 2013 TYPE 0 VPID 8ad APID 8b7 APID 8b8 APID 8b9 APID 8ba APID 8bb APID 8bc APID 8bd APID 8be TTPID 300 PCRPID 8ad + CHANNEL ID 26a NAME "Canal Rural" SATID ffffff TPID 24b8 SID 2014 TYPE 0 VPID 911 APID 91b APID 91c PCRPID 911 + CHANNEL ID 26b NAME "MediaHW" SATID ffffff TPID 24b8 SID 2063 TYPE 0 PCRPID fa0 + TRANSPONDER ID 251c SATID 0000 TYPE 1 FREQ 12615000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 26c SATID ffffff TPID 251c SID fffe TYPE 0 + CHANNEL ID 26d NAME "MMOV" SATID ffffff TPID 251c SID f46 TYPE 1 VPID a10 PCRPID a00 + CHANNEL ID 26e NAME "MMOV" SATID ffffff TPID 251c SID f49 TYPE 1 VPID a12 PCRPID a01 + CHANNEL ID 26f NAME "MMOV" SATID ffffff TPID 251c SID f4d TYPE 1 VPID a14 PCRPID a02 + CHANNEL ID 270 NAME "MMOV" SATID ffffff TPID 251c SID f4e TYPE 1 VPID a16 PCRPID a03 + CHANNEL ID 271 NAME "MMOV" SATID ffffff TPID 251c SID f4f TYPE 1 VPID a18 PCRPID a04 + CHANNEL ID 272 NAME "MMOV" SATID ffffff TPID 251c SID f50 TYPE 1 VPID a1a PCRPID a05 + CHANNEL ID 273 NAME "SC 1" SATID ffffff TPID 251c SID f51 TYPE 1 VPID a07 PCRPID a06 + CHANNEL ID 274 NAME "SC 2" SATID ffffff TPID 251c SID f54 TYPE 1 VPID a0a PCRPID a06 + CHANNEL ID 275 NAME "SC 3" SATID ffffff TPID 251c SID f57 TYPE 1 VPID a0d PCRPID a06 + CHANNEL ID 276 NAME "MC20" SATID ffffff TPID 251c SID f5f TYPE 1 APID 900 PCRPID 900 + CHANNEL ID 277 NAME "MC21" SATID ffffff TPID 251c SID f62 TYPE 1 APID 901 PCRPID 901 + CHANNEL ID 278 NAME "MC22" SATID ffffff TPID 251c SID f65 TYPE 1 APID 902 PCRPID 902 + CHANNEL ID 279 NAME "MC23" SATID ffffff TPID 251c SID f68 TYPE 1 APID 903 PCRPID 903 + CHANNEL ID 27a NAME "MC24" SATID ffffff TPID 251c SID f6b TYPE 1 APID 904 PCRPID 904 + CHANNEL ID 27b NAME "MC25" SATID ffffff TPID 251c SID f6e TYPE 1 APID 905 PCRPID 905 + CHANNEL ID 27c NAME "MC26" SATID ffffff TPID 251c SID f71 TYPE 1 APID 906 PCRPID 906 + CHANNEL ID 27d NAME "MC27" SATID ffffff TPID 251c SID f74 TYPE 1 APID 907 PCRPID 907 + CHANNEL ID 27e NAME "MC28" SATID ffffff TPID 251c SID f77 TYPE 1 APID 908 PCRPID 908 + CHANNEL ID 27f NAME "MC29" SATID ffffff TPID 251c SID f7a TYPE 1 APID 909 PCRPID 909 + CHANNEL ID 280 NAME "MC30" SATID ffffff TPID 251c SID f7d TYPE 1 APID 90a PCRPID 90a + CHANNEL ID 281 NAME "MC31" SATID ffffff TPID 251c SID f80 TYPE 1 APID 90b PCRPID 90b + CHANNEL ID 282 NAME "MC32" SATID ffffff TPID 251c SID f83 TYPE 1 APID 90c PCRPID 90c + CHANNEL ID 283 NAME "MC33" SATID ffffff TPID 251c SID f86 TYPE 1 APID 90d PCRPID 90d + CHANNEL ID 284 NAME "MC34" SATID ffffff TPID 251c SID f89 TYPE 1 APID 90e PCRPID 90e + CHANNEL ID 285 NAME "MC35" SATID ffffff TPID 251c SID f8c TYPE 1 APID 90f PCRPID 90f + CHANNEL ID 286 NAME "MC36" SATID ffffff TPID 251c SID f8f TYPE 1 APID 910 PCRPID 910 + CHANNEL ID 287 NAME "MC37" SATID ffffff TPID 251c SID f92 TYPE 1 APID 911 PCRPID 911 + CHANNEL ID 288 NAME "MC38" SATID ffffff TPID 251c SID f95 TYPE 1 APID 912 PCRPID 912 + CHANNEL ID 289 NAME "MC39" SATID ffffff TPID 251c SID f98 TYPE 1 APID 913 PCRPID 913 + TRANSPONDER ID 2580 SATID 0000 TYPE 1 FREQ 12635000 POL V SRATE 27500000 FEC 8 + CHANNEL ID 28a SATID ffffff TPID 2580 SID fffe TYPE 0 + CHANNEL ID 28b NAME "SC 4" SATID ffffff TPID 2580 SID fa1 TYPE 1 VPID a90 PCRPID a83 + CHANNEL ID 28c NAME "SC 5" SATID ffffff TPID 2580 SID fa2 TYPE 1 VPID a88 PCRPID a83 + CHANNEL ID 28d NAME "SC 6" SATID ffffff TPID 2580 SID fa3 TYPE 1 VPID a8d PCRPID a83 + CHANNEL ID 28e NAME "MMOV" SATID ffffff TPID 2580 SID fa7 TYPE 1 VPID a84 PCRPID a80 + CHANNEL ID 28f NAME "MMOV" SATID ffffff TPID 2580 SID faa TYPE 1 VPID a86 PCRPID a81 + CHANNEL ID 290 NAME "MMOV" SATID ffffff TPID 2580 SID fb0 TYPE 1 VPID a93 PCRPID a82 + CHANNEL ID 291 NAME "MMOV" SATID ffffff TPID 2580 SID fb3 TYPE 1 VPID a95 PCRPID a8b + CHANNEL ID 292 NAME "MMOV" SATID ffffff TPID 2580 SID fb6 TYPE 1 VPID a97 PCRPID a8c + CHANNEL ID 293 NAME "MMOV" SATID ffffff TPID 2580 SID fb9 TYPE 1 VPID b03 PCRPID b00 + CHANNEL ID 294 NAME "MMOV" SATID ffffff TPID 2580 SID fbc TYPE 1 VPID b05 PCRPID b01 + TRANSPONDER ID 25e4 SATID 0000 TYPE 1 FREQ 12654000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 295 NAME "Sharjah Arabsat Bouquet" SATID ffffff TPID 25e4 SID 1 TYPE 0 VPID 488 PCRPID 488 + CHANNEL ID 296 NAME "Qatar Arabsat Bouquet" SATID ffffff TPID 25e4 SID 2 TYPE 0 VPID 4ec PCRPID 4ec + CHANNEL ID 297 NAME "Saudi 1 Arabsat Bouquet" SATID ffffff TPID 25e4 SID 3 TYPE 0 VPID 550 PCRPID 550 + CHANNEL ID 298 NAME "Kuwait Arabsat Bouquet" SATID ffffff TPID 25e4 SID 4 TYPE 0 VPID 5b4 PCRPID 5b4 + CHANNEL ID 299 NAME "Libya Arabsat Bouquet" SATID ffffff TPID 25e4 SID 5 TYPE 0 VPID 618 PCRPID 618 + CHANNEL ID 29a NAME "Sudan Arabsat Bouquet" SATID ffffff TPID 25e4 SID 6 TYPE 0 VPID 67c PCRPID 67c + CHANNEL ID 29b NAME "Oman Arabsat Bouquet" SATID ffffff TPID 25e4 SID 7 TYPE 0 VPID 6e0 PCRPID 6e0 + CHANNEL ID 29c NAME "Jordan Arabsat Bouquet" SATID ffffff TPID 25e4 SID 8 TYPE 0 VPID 744 PCRPID 744 + CHANNEL ID 29d NAME "IRAQ TV" SATID ffffff TPID 25e4 SID 9 TYPE 0 VPID 7a8 PCRPID 7a8 + CHANNEL ID 29e NAME "Dubai Sport" SATID ffffff TPID 25e4 SID a TYPE 0 VPID 424 PCRPID 424 + CHANNEL ID 29f NAME "Qatar A2 Arabsat Bouquet" SATID ffffff TPID 25e4 SID c TYPE 0 APID 4c5 PCRPID 4c5 + CHANNEL ID 2a0 NAME "Saudi1 A2 Arabsat Bouquet" SATID ffffff TPID 25e4 SID d TYPE 0 APID 529 PCRPID 529 + CHANNEL ID 2a1 NAME "Kuwait A2 Arabsat Bouquet" SATID ffffff TPID 25e4 SID e TYPE 0 APID 58d PCRPID 58d + CHANNEL ID 2a2 NAME "Jordan A2 Arabsat Bouquet" SATID ffffff TPID 25e4 SID 12 TYPE 0 APID 71d PCRPID 71d + CHANNEL ID 2a3 NAME "Radio dubai sport" SATID ffffff TPID 25e4 SID 13 TYPE 0 APID 3fd PCRPID 3fd + TRANSPONDER ID 2648 SATID 0000 TYPE 1 FREQ 12673000 POL V SRATE 27500000 FEC 8 + CHANNEL ID 2a4 NAME "Digitaly" SATID ffffff TPID 2648 SID 106b TYPE 0 VPID dc APID dd APID de PCRPID dc + CHANNEL ID 2a5 NAME "Telemarket" SATID ffffff TPID 2648 SID 1073 TYPE 0 VPID 15e APID 15f PCRPID 15e + CHANNEL ID 2a6 NAME "Internet data 1" SATID ffffff TPID 2648 SID 1074 TYPE 0 TTPID 11f + CHANNEL ID 2a7 NAME "eVision" SATID ffffff TPID 2648 SID 1076 TYPE 0 VPID 168 APID 169 APID 16a APID 1be6 PCRPID 168 + CHANNEL ID 2a8 NAME "ANNI 60" SATID ffffff TPID 2648 SID 1086 TYPE 0 APID fa PCRPID fa + CHANNEL ID 2a9 NAME "R. Reporter" SATID ffffff TPID 2648 SID 1087 TYPE 0 APID fb PCRPID fb + CHANNEL ID 2aa NAME "Radio Italia S.M.I." SATID ffffff TPID 2648 SID 1088 TYPE 0 APID fc PCRPID fc + CHANNEL ID 2ab NAME "R. Tour" SATID ffffff TPID 2648 SID 1089 TYPE 0 APID fd PCRPID fd + CHANNEL ID 2ac NAME "R.Rinascente" SATID ffffff TPID 2648 SID 108a TYPE 0 APID fe PCRPID fe + CHANNEL ID 2ad NAME "R. Cooky" SATID ffffff TPID 2648 SID 108b TYPE 0 APID ff PCRPID ff + CHANNEL ID 2ae NAME "RadioBaby" SATID ffffff TPID 2648 SID 108c TYPE 0 APID 100 PCRPID 100 + CHANNEL ID 2af NAME "McDonalds" SATID ffffff TPID 2648 SID 108d TYPE 0 APID 101 PCRPID 101 + CHANNEL ID 2b0 NAME "TRBuonconsiglio" SATID ffffff TPID 2648 SID 108e TYPE 0 APID 191 PCRPID 191 + CHANNEL ID 2b1 NAME "R-Radio" SATID ffffff TPID 2648 SID 108f TYPE 0 APID 192 PCRPID 192 + CHANNEL ID 2b2 NAME "R. Donna" SATID ffffff TPID 2648 SID 1090 TYPE 0 APID 193 PCRPID 193 + CHANNEL ID 2b3 NAME "R. Reporter 2" SATID ffffff TPID 2648 SID 1091 TYPE 0 APID 194 PCRPID 194 + CHANNEL ID 2b4 NAME "R. West" SATID ffffff TPID 2648 SID 1092 TYPE 0 APID 195 PCRPID 195 + CHANNEL ID 2b5 NAME "Melodia Russia" SATID ffffff TPID 2648 SID 1093 TYPE 0 VPID 19f6 APID 196 PCRPID 196 + CHANNEL ID 2b6 NAME "Padre Pio" SATID ffffff TPID 2648 SID 1094 TYPE 0 APID 197 PCRPID 197 + CHANNEL ID 2b7 NAME "Thai TV5" SATID ffffff TPID 2648 SID 1069 TYPE 0 VPID c8 APID c9 APID ca PCRPID c8 + CHANNEL ID 2b8 NAME "Studio Europa" SATID ffffff TPID 2648 SID 106c TYPE 0 VPID e6 APID e7 PCRPID e6 + CHANNEL ID 2b9 NAME "Video Italia" SATID ffffff TPID 2648 SID 1072 TYPE 0 VPID 154 APID 155 APID 156 PCRPID 154 + TRANSPONDER ID 26ac SATID 0000 TYPE 1 FREQ 12692000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 2ba NAME "PASSIONS" SATID ffffff TPID 26ac SID 1f5 TYPE 0 VPID a0 PCRPID a0 + CHANNEL ID 2bb NAME "ONYX" SATID ffffff TPID 26ac SID 1f6 TYPE 0 VPID a1 PCRPID a1 + CHANNEL ID 2bc NAME "MANGAS" SATID ffffff TPID 26ac SID 1f7 TYPE 1 VPID a2 APID 58 TTPID 26 PCRPID a2 + CHANNEL ID 2bd NAME "ENCYCLOPEDIA" SATID ffffff TPID 26ac SID 1f8 TYPE 1 VPID a3 APID 5c TTPID 29 PCRPID a3 + CHANNEL ID 2be NAME "POLAR" SATID ffffff TPID 26ac SID 1f9 TYPE 1 VPID a4 APID 60 TTPID 2c PCRPID a4 + CHANNEL ID 2bf NAME "CINE PALACE" SATID ffffff TPID 26ac SID 1fa TYPE 1 VPID a5 APID 64 TTPID 2f PCRPID a5 + CHANNEL ID 2c0 NAME "ROMANCE" SATID ffffff TPID 26ac SID 1fb TYPE 1 VPID a6 APID 68 TTPID 32 PCRPID a6 + CHANNEL ID 2c1 NAME "RIRE" SATID ffffff TPID 26ac SID 1fc TYPE 1 VPID a7 APID 6c TTPID 35 PCRPID a7 + CHANNEL ID 2c2 NAME "ACTION" SATID ffffff TPID 26ac SID 1fd TYPE 1 VPID a8 APID 70 TTPID 38 PCRPID a8 + CHANNEL ID 2c3 NAME "ABsat test RADIO" SATID ffffff TPID 26ac SID 1fe TYPE 1 APID 65 PCRPID a5 + TRANSPONDER ID 2710 SATID 0000 TYPE 1 FREQ 12713000 POL V SRATE 27500000 FEC 8 + CHANNEL ID 2c4 SATID ffffff TPID 2710 SID fffe TYPE 0 + CHANNEL ID 2c5 NAME "MMOV" SATID ffffff TPID 2710 SID 10d0 TYPE 1 VPID a03 PCRPID a00 + CHANNEL ID 2c6 NAME "MMOV" SATID ffffff TPID 2710 SID 10d3 TYPE 1 VPID a05 PCRPID a01 + CHANNEL ID 2c7 NAME "MMOV" SATID ffffff TPID 2710 SID 10d6 TYPE 1 VPID a07 PCRPID a02 + CHANNEL ID 2c8 NAME "MMOV" SATID ffffff TPID 2710 SID 10d9 TYPE 1 VPID 904 PCRPID 900 + CHANNEL ID 2c9 NAME "MMOV" SATID ffffff TPID 2710 SID 10dc TYPE 1 VPID 90a PCRPID 901 + CHANNEL ID 2ca NAME "MMOV" SATID ffffff TPID 2710 SID 10e4 TYPE 1 VPID 906 PCRPID 902 + CHANNEL ID 2cb NAME "MMOV" SATID ffffff TPID 2710 SID 10e7 TYPE 1 VPID 908 PCRPID 903 + TRANSPONDER ID 2774 SATID 0000 TYPE 1 FREQ 12713000 POL H SRATE 27500000 FEC 8 + CHANNEL ID 2cc SATID ffffff TPID 2774 SID fffe TYPE 0 + CHANNEL ID 2cd NAME "SINT" SATID ffffff TPID 2774 SID 2262 TYPE 1 + CHANNEL ID 2ce NAME "info" SATID ffffff TPID 2774 SID 2264 TYPE 1 VPID 205 PCRPID 1ffe + CHANNEL ID 2cf NAME "SINT" SATID ffffff TPID 2774 SID 2266 TYPE 1 + CHANNEL ID 2d0 NAME "CFN" SATID ffffff TPID 2774 SID 2269 TYPE 1 VPID 20b PCRPID 1ffe + CHANNEL ID 2d1 NAME "SINT" SATID ffffff TPID 2774 SID 226c TYPE 1 + CHANNEL ID 2d2 NAME "duel" SATID ffffff TPID 2774 SID 226f TYPE 1 VPID 206 PCRPID 1ffe + CHANNEL ID 2d3 NAME "comedy" SATID ffffff TPID 2774 SID 2272 TYPE 1 VPID 203 PCRPID 1ffe + CHANNEL ID 2d4 NAME "fox kids" SATID ffffff TPID 2774 SID 2275 TYPE 1 VPID 201 PCRPID 1ffe diff --git a/Tools/dvbrc2vdr/test.conf b/Tools/dvbrc2vdr/test.conf new file mode 100644 index 000000000..31dddb777 --- /dev/null +++ b/Tools/dvbrc2vdr/test.conf @@ -0,0 +1,799 @@ +DISCOVERY:10719:v:1:27500:8190:8190:0:4402 +RTL7:10719:v:1:27500:8190:8190:0:4403 +TV POLONIA:10719:v:1:27500:8190:8190:0:4404 +EUROSPORT:10719:v:1:27500:8190:8190:0:4405 +PLANETE:10719:v:1:27500:8190:8190:0:4406 +SEASONS:10719:v:1:27500:8190:8190:0:4407 +VIVA Polska:10719:v:1:27500:8190:8190:0:4408 +MULTIMUSIC 4:10719:v:1:27500:8190:123:0:4440 +EPG:10719:v:1:27500:8190:8190:0:4450 +CYFRA+ GRY:10719:v:1:27500:8190:8190:0:4460 +Guide LC:0:v:1:27500:8190:8030:0:2000 +Cinestar 1:0:v:1:27500:120:130:0:1201 +Cinestar 2:0:v:1:27500:220:230:0:1202 +Cinetoile:0:v:1:27500:320:330:0:1203 +Shopping Avenue:0:v:1:27500:420:430:0:1204 +Srie Club :0:v:1:27500:520:530:0:1205 +FUN TV:0:v:1:27500:620:630:0:1206 +Teva:0:v:1:27500:720:730:0:1207 +M6 Music:0:v:1:27500:820:830:0:1208 +Club Tlachat:0:v:1:27500:920:930:0:1209 +INFOSPORT:0:v:1:27500:120:130:0:1401 +Rgions:0:v:1:27500:220:230:0:1402 +Mezzo:0:v:1:27500:320:330:0:1403 +01 01 15 97:0:v:1:27500:8190:8190:0:1483 +01 01 17 97:0:v:1:27500:8190:8190:0:1485 +01 02 17 97:0:v:1:27500:8190:8190:0:1486 +01 02 15 97:0:v:1:27500:8190:8190:0:1488 +01 02 15 96:0:v:1:27500:8190:8190:0:1489 +01 03 17 10:0:v:1:27500:8190:8190:0:1490 +01 03 15 10:0:v:1:27500:8190:8190:0:1491 +Festival:0:v:1:27500:420:430:0:1404 +HISTOIRE :0:v:1:27500:520:530:0:1405 +Tltoon:0:v:1:27500:620:630:0:1406 +Odysse :0:v:1:27500:720:730:0:1407 +France Musiques:0:v:1:27500:8190:830:0:1418 +Hector:0:v:1:27500:8190:831:0:1419 +FIP:0:v:1:27500:8190:832:0:1420 +France Inter:0:v:1:27500:8190:833:0:1421 +France Info:0:v:1:27500:8190:834:0:1422 +Elisa:0:v:1:27500:8190:835:0:1423 +France Culture:0:v:1:27500:8190:836:0:1424 +Radio Bleue:0:v:1:27500:8190:837:0:1425 +Le Mouv:0:v:1:27500:8190:838:0:1426 +TV5:0:v:1:27500:920:930:0:1409 +CENTRONICS:0:v:1:27500:8190:8190:0:2000 +FRANCE 2 :0:v:1:27500:320:8190:0:1104 +FRANCE 3:0:v:1:27500:520:8190:0:1106 +Crdit Agricole:0:v:1:27500:8190:5333:0:5301 +tps foot:0:v:1:27500:8190:5230:0:5200 +LCI:0:v:1:27500:120:130:0:1101 +EUROSPORT:0:v:1:27500:220:230:0:1102 +FRANCE 2:0:v:1:27500:320:8190:0:1103 +FRANCE 3:0:v:1:27500:520:8190:0:1105 +I TELEVISION:0:v:1:27500:820:830:0:1108 +TV Mail alphatest:0:v:1:27500:8190:8190:0:5701 +CHAINE FI:0:v:1:27500:8190:5331:0:5300 +caisse d'pargne:0:v:1:27500:8190:8190:0:5303 +TV Mail:0:v:1:27500:8190:8190:0:5700 +CANAL+:10892:h:1:27500:8190:8190:0:4801 +CANAL+ ӣTY:10892:h:1:27500:8190:8190:0:4802 +TMT:10892:h:1:27500:8190:8190:0:4804 +ALE KINO!:10892:h:1:27500:8190:8190:0:4805 +MINIMAX:10892:h:1:27500:8190:8190:0:4806 +TVP 1:10892:h:1:27500:8190:8190:0:4807 +TVP 2:10892:h:1:27500:8190:8190:0:4808 +CANAL+ NIEBIESKI:10892:h:1:27500:8190:8190:0:4809 +EPG:10892:h:1:27500:8190:8190:0:4850 +Multivision:0:v:1:27500:320:8190:0:1603 +Grand Classique:0:v:1:27500:8190:830:0:1650 +Symphonies:0:v:1:27500:8190:831:0:1651 +Baroque:0:v:1:27500:8190:832:0:1652 +Opra:0:v:1:27500:8190:833:0:1653 +Contemporain:0:v:1:27500:8190:834:0:1654 +Relaxation:0:v:1:27500:8190:835:0:1655 +Blues:0:v:1:27500:8190:836:0:1656 +Jazz:0:v:1:27500:8190:837:0:1657 +Big Band:0:v:1:27500:8190:838:0:1658 +Jazz Moderne:0:v:1:27500:8190:839:0:1659 +Les Tubes Franais:0:v:1:27500:8190:840:0:1660 +RFO SAT:0:v:1:27500:120:130:0:1601 +Appli D1 LC:0:v:1:27500:8190:8190:0:1680 +Cinefaz:0:v:1:27500:220:230:0:1602 +TurboPC:0:v:1:27500:8190:8190:0:2801 +MTV2:0:v:1:27500:720:730:0:1607 +Rire et chansons:0:v:1:27500:8190:930:0:1630 +Radio J:0:v:1:27500:8190:931:0:1631 +Mosqueteiros:0:v:1:27500:8190:932:0:1632 +Abysse:0:v:1:27500:8190:933:0:1633 +RMC:0:v:1:27500:8190:935:0:1635 +Radio Junior:0:v:1:27500:8190:936:0:1636 +NETRADIO:0:v:1:27500:8190:937:0:1637 +Nostalgie:0:v:1:27500:8190:938:0:1638 +Skyrock:0:v:1:27500:8190:939:0:1639 +Radio Coutoisie:0:v:1:27500:8190:940:0:1640 +La Voix des Pays:0:v:1:27500:8190:941:0:1641 +INFO EXPRESS:0:v:1:27500:8190:5530:0:5500 +METEO:0:v:1:27500:8190:5830:0:5800 +X X L:0:v:1:27500:8190:8190:0:5400 +Multivision Cinma:0:v:1:27500:8190:8190:0:7200 +Multivision Sport:0:v:1:27500:8190:8190:0:7300 +Multivision Spectacle:0:v:1:27500:8190:8190:0:7400 +Test OTV8:12673:h:1:27500:8190:8190:0:7527 +Test OTV9:12673:h:1:27500:8190:8190:0:7528 +Test OTV10:12673:h:1:27500:8190:8190:0:7529 +Test OTV11:12673:h:1:27500:513:8190:0:7530 +Test31:12673:h:1:27500:512:650:0:7501 +CNN:12673:h:1:27500:513:660:0:7502 +Q24:12673:h:1:27500:514:691:0:7503 +Test34:12673:h:1:27500:515:680:0:7504 +Test35:12673:h:1:27500:516:690:0:7505 +Test OTV1:12673:h:1:27500:8190:8190:0:7520 +Test OTV2:12673:h:1:27500:8190:8190:0:7521 +Test OTV3:12673:h:1:27500:8190:8190:0:7522 +Test OTV4:12673:h:1:27500:8190:8190:0:7523 +Test OTV5:12673:h:1:27500:8190:8190:0:7524 +Test OTV6:12673:h:1:27500:8190:8190:0:7525 +Test OTV7:12673:h:1:27500:8190:8190:0:7526 +Test OTV7:12673:h:1:27500:8190:8190:0:7540 +Test OTV7:12673:h:1:27500:8190:8190:0:7541 +Telekom TV:11095:h:1:27500:32:8190:0:3711 +FantasticOverOpal:11095:h:1:27500:32:8190:0:3712 +Gilat:11095:h:1:27500:32:8190:0:3713 +Siemens TV:11095:h:1:27500:32:8190:0:3716 +S-TV:11095:h:1:27500:32:8190:0:3717 +Optibase Encoder:11095:h:1:27500:32:8190:0:3718 +FantasticOverOpal:11095:h:1:27500:8190:8190:0:3702 +Deutsche Bank / T1:11303:h:1:27500:1160:8190:0:1 +Animal Planet:11303:h:1:27500:1160:8190:0:10 +Discovery E Europe-English:11303:h:1:27500:1260:8190:0:20 +Wuerth KG / T21:11303:h:1:27500:1360:8190:0:21 +Discovery Italy:11303:h:1:27500:1360:8190:0:30 +BTI / T31:11303:h:1:27500:1360:8190:0:31 +Discovery Russia:11303:h:1:27500:1460:8190:0:40 +K-TV (MetroMux) / T41:11303:h:1:27500:1960:8190:0:41 +Animal Planet EE:11303:h:1:27500:1560:8190:0:50 +Animal Planet - Russian:11303:h:1:27500:1560:8190:0:51 +Discovery Netherlands:11303:h:1:27500:1660:8190:0:60 +Q English:11303:h:1:27500:1760:8190:0:70 +Travel and Adventure:11303:h:1:27500:1860:8190:0:80 +Travel and Adventure- Russian:11303:h:1:27500:1860:8190:0:81 +New DCP:11303:h:1:27500:8190:1220:0:300 +CCP:11303:h:1:27500:1260:8190:0:301 +Deutsche Bank / T2:11303:h:1:27500:1260:8190:0:2 +Channel Three:11303:h:1:27500:1360:8190:0:3 +Channel Four:11303:h:1:27500:1460:8190:0:4 +Channel Five:11303:h:1:27500:1560:8190:0:5 +Channel 6 = Sat 7 Arabic:11303:h:1:27500:1660:8190:0:6 +Channel Seven:11303:h:1:27500:1760:8190:0:7 +Q German:11303:h:1:27500:1760:8190:0:71 +Q French:11303:h:1:27500:1760:8190:0:72 +Q Dutch:11303:h:1:27500:1760:8190:0:73 +DTAG / T11:11303:h:1:27500:1360:8190:0:11 +DTAG 50 / T12:11303:h:1:27500:1360:8190:0:12 +Telekom TV:11303:h:1:27500:1460:8190:0:13 +Gerling / T26:11303:h:1:27500:1360:8190:0:26 +Hornbach-D / T36:11303:h:1:27500:1360:8190:0:36 +Hornbach-NL / T38:11303:h:1:27500:1360:8190:0:38 +Hornbach-CZ / T39:11303:h:1:27500:1360:8190:0:39 +Testkanal:11303:h:1:27500:1660:8190:0:99 +KENCAST:11303:h:1:27500:8190:8190:0:111 +SAT.1 CH:11604:h:1:27500:101:102:0:601 +KBT Channel SUN:11604:h:1:27500:111:112:0:603 +big FM:11604:h:1:27500:8190:113:0:604 +Event:11604:h:1:27500:160:161:0:602 +Deutsche Bank / T1:11642:h:1:27500:1160:8190:0:1 +Animal Planet:11642:h:1:27500:1160:8190:0:10 +Discovery E Europe-English:11642:h:1:27500:1260:8190:0:20 +Wuerth KG / T21:11642:h:1:27500:1360:8190:0:21 +Discovery Italy:11642:h:1:27500:1360:8190:0:30 +BTI / T31:11642:h:1:27500:1360:8190:0:31 +Discovery Russia:11642:h:1:27500:1460:8190:0:40 +K-TV (MetroMux) / T41:11642:h:1:27500:1960:8190:0:41 +Animal Planet EE:11642:h:1:27500:1560:8190:0:50 +Animal Planet - Russian:11642:h:1:27500:1560:8190:0:51 +Discovery Netherlands:11642:h:1:27500:1660:8190:0:60 +Q English:11642:h:1:27500:1760:8190:0:70 +Travel and Adventure:11642:h:1:27500:1860:8190:0:80 +Travel and Adventure- Russian:11642:h:1:27500:1860:8190:0:81 +New DCP:11642:h:1:27500:8190:1220:0:300 +CCP:11642:h:1:27500:1260:8190:0:301 +Deutsche Bank / T2:11642:h:1:27500:1260:8190:0:2 +Channel Three:11642:h:1:27500:1360:8190:0:3 +Channel Four:11642:h:1:27500:1460:8190:0:4 +Channel Five:11642:h:1:27500:1560:8190:0:5 +Channel 6 = Sat 7 Arabic:11642:h:1:27500:1660:8190:0:6 +Channel Seven:11642:h:1:27500:1760:8190:0:7 +Q German:11642:h:1:27500:1760:8190:0:71 +Q French:11642:h:1:27500:1760:8190:0:72 +Q Dutch:11642:h:1:27500:1760:8190:0:73 +DTAG / T11:11642:h:1:27500:1360:8190:0:11 +DTAG 50 / T12:11642:h:1:27500:1360:8190:0:12 +Telekom TV:11642:h:1:27500:1460:8190:0:13 +Gerling / T26:11642:h:1:27500:1360:8190:0:26 +Hornbach-D / T36:11642:h:1:27500:1360:8190:0:36 +Hornbach-NL / T38:11642:h:1:27500:1360:8190:0:38 +Hornbach-CZ / T39:11642:h:1:27500:1360:8190:0:39 +Testkanal:11642:h:1:27500:1660:8190:0:99 +KENCAST:11642:h:1:27500:8190:8190:0:111 +AB 1:11681:h:1:27500:160:80:0:201 +AB MOTEURS:11681:h:1:27500:161:84:0:202 +ANIMAUX:11681:h:1:27500:162:88:0:203 +CHASSE ET PECHE:11681:h:1:27500:163:92:0:204 +XXL:11681:h:1:27500:164:96:0:205 +MUSIQUE CLASSIQUE:11681:h:1:27500:165:100:0:206 +ESCALES:11681:h:1:27500:166:104:0:207 +FIT/chane HISTOIRE:11681:h:1:27500:167:108:0:208 +RFM TV:11681:h:1:27500:168:112:0:209 +EDTV DRAMA:11744:h:1:27500:4898:8190:0:9504 +EDTV RADIO 02:11744:h:1:27500:4898:8190:0:9524 +EDTV RADIO 01:11744:h:1:27500:4898:8190:0:9523 +EDTV SPORT:11744:h:1:27500:4898:8190:0:9502 +EDTV BUSINESS:11744:h:1:27500:4898:8190:0:9503 +RAI1:11765:v:1:27500:160:8190:0:3401 +RAI2:11765:v:1:27500:161:8190:0:3402 +RAI3:11765:v:1:27500:162:8190:0:3403 +Rai Way TEST1:11765:v:1:27500:515:8190:0:3404 +Rai Way TEST2:11765:v:1:27500:516:8190:0:3405 +Rai Way TEST3:11765:v:1:27500:164:8190:0:3406 +RAIMOSAICO:11765:v:1:27500:518:8190:0:3407 +RAIMOSAICO:11765:v:1:27500:518:8190:0:3490 +RAINews24:11765:v:1:27500:516:8190:0:3301 +CAMERA DEPUTATI:11765:v:1:27500:517:8190:0:3302 +TELEPACE:11765:v:1:27500:515:8190:0:3304 +RAISPORTSAT:11765:v:1:27500:512:8190:0:3305 +RAINettunoSAT2:11765:v:1:27500:513:8190:0:3306 +RAIeducational:11765:v:1:27500:514:8190:0:3307 +RAINettunoSAT1:11765:v:1:27500:519:8190:0:3308 +SAT2000:11765:v:1:27500:518:8190:0:3309 +RADIOUNO:11765:v:1:27500:8190:670:0:3311 +RADIODUE:11765:v:1:27500:8190:671:0:3312 +RADIOTRE:11765:v:1:27500:8190:672:0:3313 +FDleggera:11765:v:1:27500:8190:673:0:3314 +FDauditorium:11765:v:1:27500:8190:665:0:3315 +BLUSAT 2000:11765:v:1:27500:8190:677:0:3316 +GR PARLAMENTO:11765:v:1:27500:8190:664:0:3317 +ISORADIO:11765:v:1:27500:8190:661:0:3318 +R1:11823:h:1:27500:512:650:0:301 +R2:11823:h:1:27500:513:661:0:302 +R3:11823:h:1:27500:514:670:0:303 +R4:11823:h:1:27500:515:680:0:304 +R5:11823:h:1:27500:4682:700:0:306 +R6:11823:h:1:27500:518:710:0:307 +R7:11823:h:1:27500:519:720:0:308 +Love Radio:11823:h:1:27500:8190:711:0:309 +Greek Church:11823:h:1:27500:8190:671:0:310 +Skai Radio:11823:h:1:27500:8190:741:0:311 +MelodiRadio:11823:h:1:27500:8190:701:0:312 +ERA 3:11823:h:1:27500:8190:651:0:313 +RR1:11823:h:1:27500:8190:681:0:314 +RR2:11823:h:1:27500:8190:721:0:315 +NOVA CINE:11823:h:1:27500:521:740:0:316 +FILM NET:11823:h:1:27500:512:650:0:317 +SSportK-T.V:11823:h:1:27500:513:661:0:318 +MEGA:11823:h:1:27500:514:670:0:319 +ANT-1:11823:h:1:27500:515:680:0:320 +STAR:11823:h:1:27500:517:700:0:321 +Alter 5:11823:h:1:27500:518:710:0:322 +NEW Tempo:11823:h:1:27500:519:720:0:323 +Super Sport2:11823:h:1:27500:516:691:0:324 +Super Sport2:11843:v:1:27500:516:691:0:65534 +INTV:11843:v:1:27500:2324:8190:0:3504 +UNIV:11843:v:1:27500:2305:8190:0:3507 +CULT:11843:v:1:27500:2307:8190:0:3510 +ERSP:11843:v:1:27500:2309:8190:0:3513 +SINT:11843:v:1:27500:8190:8190:0:3515 +CART:11843:v:1:27500:2433:8190:0:3516 +SINT:11843:v:1:27500:8190:8190:0:3519 +DISC:11843:v:1:27500:2437:8190:0:3522 +SINT:11843:v:1:27500:8190:8190:0:3525 +TVL:11843:v:1:27500:2441:8190:0:3528 +SINT:11843:v:1:27500:8190:8190:0:3530 +ROCK:11843:v:1:27500:8190:2320:0:3550 +RDS:11843:v:1:27500:8190:2321:0:3553 +RTL:11843:v:1:27500:8190:2322:0:3556 +101:11843:v:1:27500:8190:2323:0:3559 +RVOY:11843:v:1:27500:8190:2315:0:3562 +RKFM:11843:v:1:27500:8190:2317:0:3563 +GLOB:11843:v:1:27500:8190:2316:0:3564 +ANT1:11843:v:1:27500:8190:2318:0:3565 +RRAD:11843:v:1:27500:8190:2319:0:3566 +MC01:11843:v:1:27500:8190:2312:0:3568 +MC02:11843:v:1:27500:8190:2313:0:3571 +MC03:11843:v:1:27500:8190:2314:0:3574 +P7:12341:h:1:27500:160:81:0:11301 +P8:12341:h:1:27500:161:85:0:11303 +P9:12341:h:1:27500:162:89:0:11305 ++GIOCHI:12341:h:1:27500:8190:8190:0:11310 +MM01:12341:h:1:27500:8190:601:0:11311 +MM02:12341:h:1:27500:8190:602:0:11312 +MM03:12341:h:1:27500:8190:603:0:11313 +MM04:12341:h:1:27500:8190:604:0:11314 +MM05:12341:h:1:27500:8190:605:0:11315 +MM06:12341:h:1:27500:8190:606:0:11316 +MM07:12341:h:1:27500:8190:607:0:11317 +MM08:12341:h:1:27500:8190:608:0:11318 +MM09:12341:h:1:27500:8190:609:0:11319 +MM10:12341:h:1:27500:8190:610:0:11320 +MM11:12341:h:1:27500:8190:611:0:11321 +MM12:12341:h:1:27500:8190:612:0:11322 +MM13:12341:h:1:27500:8190:613:0:11323 +MM14:12341:h:1:27500:8190:614:0:11324 +MM15:12341:h:1:27500:8190:615:0:11325 +MM16:12341:h:1:27500:8190:616:0:11326 +MM17:12341:h:1:27500:8190:617:0:11327 +MM18:12341:h:1:27500:8190:618:0:11328 +MM19:12341:h:1:27500:8190:619:0:11329 +MM20:12341:h:1:27500:8190:620:0:11330 +MM21:12341:h:1:27500:8190:621:0:11331 +MM22:12341:h:1:27500:8190:622:0:11332 +MM23:12341:h:1:27500:8190:623:0:11333 +MM24:12341:h:1:27500:8190:624:0:11334 +MM25:12341:h:1:27500:8190:625:0:11335 +MM26:12341:h:1:27500:8190:626:0:11336 +MM27:12341:h:1:27500:8190:627:0:11337 +MM28:12341:h:1:27500:8190:628:0:11338 +MM29:12341:h:1:27500:8190:629:0:11339 +MM30:12341:h:1:27500:8190:630:0:11340 +RCAP:12341:h:1:27500:8190:631:0:11341 +R105:12341:h:1:27500:8190:632:0:11342 +RDJ:12341:h:1:27500:8190:633:0:11343 +RITA:12341:h:1:27500:8190:634:0:11344 +RMC:12341:h:1:27500:8190:635:0:11345 +R101:12341:h:1:27500:8190:636:0:11346 +RRAD:12341:h:1:27500:8190:637:0:11347 +RR:12341:h:1:27500:8190:638:0:11348 +RR:12341:h:1:27500:8190:610:0:11361 +RR:12341:h:1:27500:8190:620:0:11362 +RR:12341:h:1:27500:8190:630:0:11363 +RR:12341:h:1:27500:8190:638:0:11364 +MULTIMUSICA:12341:h:1:27500:8190:8190:0:11352 +RADIO:12341:h:1:27500:8190:8190:0:11353 +MULTIMUSIC 1:12341:h:1:27500:8190:609:0:11365 +MULTIMUSIC 2:12341:h:1:27500:8190:620:0:11366 +MULTIMUSIC 2:12713:v:1:27500:8190:620:0:65534 +TEAM:12713:v:1:27500:2305:8190:0:3610 +SINT:12713:v:1:27500:8190:8190:0:3613 +VIAG:12713:v:1:27500:2308:8190:0:3616 +SINT:12713:v:1:27500:8190:8190:0:3619 +EURO:12713:v:1:27500:2311:8190:0:3622 +SINT:12713:v:1:27500:8190:8190:0:3623 +CNN:12713:v:1:27500:2433:8190:0:3625 +ante prima:12713:v:1:27500:2435:8190:0:3628 +SNAI:12713:v:1:27500:2561:8190:0:3630 +MPPV:12713:v:1:27500:2563:8190:0:3632 +MC04:12713:v:1:27500:8190:2688:0:3636 +MC05:12713:v:1:27500:8190:2689:0:3637 +MC06:12713:v:1:27500:8190:2690:0:3638 +MC07:12713:v:1:27500:8190:2691:0:3641 +MC08:12713:v:1:27500:8190:2692:0:3644 +MC09:12713:v:1:27500:8190:2693:0:3647 +MC10:12713:v:1:27500:8190:2694:0:3650 +MC11:12713:v:1:27500:8190:2695:0:3653 +MC12:12713:v:1:27500:8190:2696:0:3656 +MC13:12713:v:1:27500:8190:2697:0:3659 +MC14:12713:v:1:27500:8190:2698:0:3662 +MC15:12713:v:1:27500:8190:2699:0:3665 +MC16:12713:v:1:27500:8190:2700:0:3668 +MC17:12713:v:1:27500:8190:2701:0:3671 +MC18:12713:v:1:27500:8190:2702:0:3674 +MOSAICO D+:12341:h:1:27500:161:84:0:11401 + MILAN CH.:12341:h:1:27500:162:89:0:11403 + INTER CH.:12341:h:1:27500:163:93:0:11405 +TST3:12341:h:1:27500:8190:8190:0:11407 + I1:11919:v:1:27500:512:650:0:1 + C5:11919:v:1:27500:513:660:0:2 + R4:11919:v:1:27500:514:670:0:3 +Test:11919:v:1:27500:515:680:0:4 +NTV:11938:h:1:27500:164:89:0:7105 +NTV-PLUS:11938:h:1:27500:165:91:0:7106 +NTV Int.-HTB:11938:h:1:27500:160:80:0:7101 +NTV Int.-Nashe Kino:11938:h:1:27500:161:82:0:7102 +NTV Int.-Detsk. Mir:11938:h:1:27500:162:84:0:7103 +DISNEY CHANNEL:12341:v:1:27500:8190:8190:0:10901 +DISCOVERY:12341:v:1:27500:161:8190:0:10903 +EUSP:12341:v:1:27500:162:89:0:10905 +HAPPY CHANNEL:12341:v:1:27500:8190:8190:0:10907 +MATCH MUSIC:12341:v:1:27500:8190:8190:0:10909 +MTV:12341:v:1:27500:8190:8190:0:10911 +R/CINEMA RAISAT:12341:v:1:27500:8190:8190:0:10913 +R/CINEMA RAISAT:12713:h:1:27500:8190:8190:0:65534 +cine stream:12713:h:1:27500:512:650:0:7704 +cine movie:12713:h:1:27500:514:670:0:7707 +CLASSICA:12341:v:1:27500:8190:8190:0:11001 +R/GAM ROS RAISAT:12341:v:1:27500:8190:8190:0:11003 +R/ALBUM RAISAT:12341:v:1:27500:8190:8190:0:11005 +HALLMARK:12341:v:1:27500:163:8190:0:11007 +R/ART RAISAT:12341:v:1:27500:8190:8190:0:11009 +TST1:12341:v:1:27500:8190:8190:0:11011 +TMC:12341:v:1:27500:166:8190:0:11013 +TMC2:12341:v:1:27500:167:8190:0:11015 +ART VARIETY:12015:h:1:27500:160:8190:0:410 +ART CHILDREN:12015:h:1:27500:161:8190:0:420 +ART MOVIES:12015:h:1:27500:162:8190:0:430 +ART MUSIC:12015:h:1:27500:163:8190:0:440 +ART EUROPE:12015:h:1:27500:164:8190:0:450 +LBC EUROPE:12015:h:1:27500:165:8190:0:460 +EGYPT SAT. CH. 2:12015:h:1:27500:166:8190:0:470 +ART SPORT:12015:h:1:27500:167:8190:0:472 +IQRA:12015:h:1:27500:168:8190:0:474 +T+ BIANCO:12341:v:1:27500:160:81:0:11101 +T+ NERO:12341:v:1:27500:161:85:0:11103 +T+ GRIGIO:12341:v:1:27500:162:89:0:11105 +R4:12341:v:1:27500:163:8190:0:24 +16|9 TELE+:12341:v:1:27500:164:97:0:11107 +VETRINA D+:12341:v:1:27500:8190:8190:0:11109 +R/RAGAZZI RAISAT:12341:v:1:27500:8190:8190:0:11111 +CNN:12341:h:1:27500:8190:8190:0:11501 +BBC:12341:h:1:27500:8190:8190:0:11503 +BLOOMBERG:12341:h:1:27500:8190:8190:0:11505 +CNBC:12341:h:1:27500:8190:8190:0:11507 +SKYNews:12341:h:1:27500:8190:8190:0:11509 +TST2:12341:h:1:27500:8190:8190:0:11511 +TV5:12341:h:1:27500:8190:8190:0:11513 +EPG:12341:h:1:27500:8190:8190:0:11515 +CNN:12341:h:1:27500:160:80:0:11517 +CNBC:12341:h:1:27500:163:92:0:11519 +TV5:12341:h:1:27500:166:104:0:11521 +BBC WORLD:12341:h:1:27500:161:84:0:11523 +BBC WORLD:12341:h:1:27500:161:84:0:11595 +BBC WORLD:12341:h:1:27500:161:84:0:9980 +BBC WORLD:12341:h:1:27500:161:84:0:9981 +Telekom TV:11095:v:1:27500:32:8190:0:3711 +FantasticOverOpal:11095:v:1:27500:32:8190:0:3712 +Gilat:11095:v:1:27500:32:8190:0:3713 +Siemens TV:11095:v:1:27500:32:8190:0:3716 +S-TV:11095:v:1:27500:32:8190:0:3717 +Optibase Encoder:11095:v:1:27500:32:8190:0:3718 +Bolsa:12091:h:1:27500:8190:8190:0:8750 +Testw:12091:h:1:27500:8190:8190:0:8751 +SIRE:12091:h:1:27500:8190:8190:0:8752 +Telesierra:12091:h:1:27500:4160:4161:0:8704 +vtv:12091:h:1:27500:4112:4115:0:8701 +Satisfaction:12091:h:1:27500:4192:4193:0:8706 +C. Milagro:12091:h:1:27500:4368:4369:0:8711 +Fiesta:12091:h:1:27500:4432:4434:0:8720 +TVE Internacional:12091:h:1:27500:4208:4209:0:8707 +TV Galicia:12091:h:1:27500:8190:4240:0:8708 +Radio Gallega:12091:h:1:27500:8190:4240:0:8709 +Retelsat:12091:h:1:27500:4464:4465:0:8722 +Musicam 1:12091:h:1:27500:8190:4406:0:8713 +Musicam 2:12091:h:1:27500:8190:4403:0:8714 +Musicam 3:12091:h:1:27500:8190:4406:0:8715 +Musicam 4:12091:h:1:27500:8190:4402:0:8716 +Musicam 5:12091:h:1:27500:8190:4406:0:8717 +HBCH FUCINO:12673:v:1:27500:200:201:0:701 +NTVi:12673:v:1:27500:210:212:0:702 +Test Telespazio:12673:v:1:27500:220:221:0:703 +Test Telespazio:12673:v:1:27500:230:231:0:704 +ARMENIA TV:12673:v:1:27500:240:242:0:705 +MEDNET:12673:v:1:27500:260:261:0:707 +AL JAZEERA:12673:v:1:27500:270:271:0:708 +TIRRENO SAT:12673:v:1:27500:280:301:0:709 +RADIO ROCK:12673:v:1:27500:8190:212:0:711 +RADIO ARMENIA:12673:v:1:27500:8190:242:0:712 +Coming Soon TV:12673:v:1:27500:8190:40:0:717 +AH-EDP1:12149:v:1:27500:96:97:0:7201 +AH-EDP2:12149:v:1:27500:112:113:0:7202 +AH-EDP3:12149:v:1:27500:36:37:0:7203 +AH-EMP4-DATA:12149:v:1:27500:8190:8190:0:7204 +Alice:12149:v:1:27500:160:161:0:7220 +Nuvolari:12149:v:1:27500:176:177:0:7221 +Leonardo:12149:v:1:27500:128:129:0:7222 +Discovery:12169:h:1:27500:512:8190:0:351 +R9:12169:h:1:27500:513:8190:0:352 +BBC World:12169:h:1:27500:514:8190:0:353 +CNN:12169:h:1:27500:515:8190:0:354 +CCTV:12169:h:1:27500:516:8190:0:355 +R10:12169:h:1:27500:518:8190:0:357 +R8:12169:h:1:27500:519:8190:0:358 +FILM SAT:12169:h:1:27500:520:8190:0:359 +Cartoon:12169:h:1:27500:515:8190:0:360 +Promo:12169:h:1:27500:521:8190:0:361 +Tempo:12169:h:1:27500:1440:651:0:362 +Tempo:12169:h:1:27500:8190:661:0:363 +Tempo:12169:h:1:27500:8190:671:0:364 +Tempo:12169:h:1:27500:8190:681:0:365 +Tempo:12169:h:1:27500:8190:691:0:366 +NOVA INFO:12169:h:1:27500:8190:8190:0:367 +NOVA INFO:12169:h:1:27500:8190:8190:0:369 +NOVA INFO:12169:h:1:27500:8190:8190:0:370 +NOVA INFO:12169:h:1:27500:1067:8190:0:371 +NOVA INFO:12169:h:1:27500:8190:8190:0:372 +NOVA INFO:12169:h:1:27500:8190:8190:0:373 +NOVA Cinema:12169:h:1:27500:8190:8190:0:374 +NET:12169:h:1:27500:513:8190:0:376 +MAD T.V:12169:h:1:27500:518:8190:0:377 +ET-1:12169:h:1:27500:519:8190:0:378 +ET-1:12169:h:1:27500:519:8190:0:379 +:12169:h:1:27500:517:8190:0:384 +Deutsche Bank / T1:12264:v:1:27500:1160:8190:0:1 +Animal Planet:12264:v:1:27500:1160:8190:0:10 +Discovery E Europe-English:12264:v:1:27500:1260:8190:0:20 +Wuerth KG / T21:12264:v:1:27500:1360:8190:0:21 +Discovery Italy:12264:v:1:27500:1360:8190:0:30 +BTI / T31:12264:v:1:27500:1360:8190:0:31 +Discovery Russia:12264:v:1:27500:1460:8190:0:40 +K-TV (MetroMux) / T41:12264:v:1:27500:1960:8190:0:41 +Animal Planet EE:12264:v:1:27500:1560:8190:0:50 +Animal Planet - Russian:12264:v:1:27500:1560:8190:0:51 +Discovery Netherlands:12264:v:1:27500:1660:8190:0:60 +Q English:12264:v:1:27500:1760:8190:0:70 +Travel and Adventure:12264:v:1:27500:1860:8190:0:80 +Travel and Adventure- Russian:12264:v:1:27500:1860:8190:0:81 +New DCP:12264:v:1:27500:8190:1220:0:300 +CCP:12264:v:1:27500:1260:8190:0:301 +Deutsche Bank / T2:12264:v:1:27500:1260:8190:0:2 +Channel Three:12264:v:1:27500:1360:8190:0:3 +Channel Four:12264:v:1:27500:1460:8190:0:4 +Channel Five:12264:v:1:27500:1560:8190:0:5 +Channel 6 = Sat 7 Arabic:12264:v:1:27500:1660:8190:0:6 +Channel Seven:12264:v:1:27500:1760:8190:0:7 +Q German:12264:v:1:27500:1760:8190:0:71 +Q French:12264:v:1:27500:1760:8190:0:72 +Q Dutch:12264:v:1:27500:1760:8190:0:73 +DTAG / T11:12264:v:1:27500:1360:8190:0:11 +DTAG 50 / T12:12264:v:1:27500:1360:8190:0:12 +Telekom TV:12264:v:1:27500:1460:8190:0:13 +Gerling / T26:12264:v:1:27500:1360:8190:0:26 +Hornbach-D / T36:12264:v:1:27500:1360:8190:0:36 +Hornbach-NL / T38:12264:v:1:27500:1360:8190:0:38 +Hornbach-CZ / T39:12264:v:1:27500:1360:8190:0:39 +Testkanal:12264:v:1:27500:1660:8190:0:99 +KENCAST:12264:v:1:27500:8190:8190:0:111 +SLO-TV1:12302:v:1:27500:200:8190:0:3201 +SLO-TV2:12302:v:1:27500:203:8190:0:3202 +POLONIA 1:12302:v:1:27500:205:8190:0:3203 +SLO-RA1-INF:12302:v:1:27500:8190:250:0:3204 +SLO-RA2:12302:v:1:27500:8190:251:0:3205 +SLO-RA3:12302:v:1:27500:8190:252:0:3206 +SUPER 1:12302:v:1:27500:207:8190:0:3207 +NAPOLI INT.:12302:v:1:27500:240:8190:0:3210 +MAGIC:12302:v:1:27500:245:8190:0:3211 +COUNTDOWN:12302:v:1:27500:235:8190:0:3212 +TBNE:12302:v:1:27500:230:8190:0:3213 +SICILSAT:12302:v:1:27500:225:8190:0:3214 +TVP1:10892:h:1:27500:257:6111:0:1 +TVP2:10892:h:1:27500:321:322:0:2 +POLSAT1:10892:h:1:27500:8190:8190:0:3 +TV4:10892:h:1:27500:257:6111:0:4 +POLSAT2:10892:h:1:27500:321:322:0:5 +WOT:10892:h:1:27500:8190:8190:0:6 +DISCOVERY:10892:h:1:27500:257:6111:0:15 +ANIMAL PLANET:10892:h:1:27500:321:322:0:16 +EpgOpenTV:10892:h:1:27500:8190:8190:0:3686 +P10:12341:v:1:27500:160:81:0:11601 +P11:12341:v:1:27500:161:85:0:11603 +P12:12341:v:1:27500:162:89:0:11605 +P13:12341:v:1:27500:163:93:0:11607 +P14:12341:v:1:27500:164:97:0:11609 +P15:12341:v:1:27500:165:101:0:11611 +P16:12341:v:1:27500:166:105:0:11613 +PREMIUM:12341:v:1:27500:8190:8190:0:11615 ++F1:12341:v:1:27500:160:664:0:11617 ++F1:12341:v:1:27500:161:85:0:11619 ++F1:12341:v:1:27500:162:667:0:11621 ++F1:12341:v:1:27500:163:674:0:11623 ++F1:12341:v:1:27500:164:96:0:11625 ++F1:12341:v:1:27500:165:676:0:11627 ++F1:12341:v:1:27500:166:666:0:11629 +RMC:12341:v:1:27500:8190:8190:0:11631 +R101:12341:v:1:27500:8190:8190:0:11632 +RRAD:12341:v:1:27500:8190:8190:0:11633 +ON:10892:h:1:27500:353:354:0:7 +DLA-CIEBIE:10892:h:1:27500:529:530:0:8 +KOMEDIA:10892:h:1:27500:353:354:0:9 +SMYK:10892:h:1:27500:529:530:0:10 +RELAKS:10892:h:1:27500:353:354:0:11 +INFO:10892:h:1:27500:529:530:0:12 +POLSAT SPORT:10892:h:1:27500:353:354:0:13 +Paris Premire:12379:v:1:27500:3021:3031:0:3001 +OCC HB3:12379:v:1:27500:3022:3032:0:3002 +TELE 24 Switzerland:12379:v:1:27500:3023:3033:0:3003 +AIR MEDIA:12379:v:1:27500:8190:3537:0:3087 +Abu Dhabi TV:12379:v:1:27500:3024:3034:0:3004 +EMIRAT FM 1:12379:v:1:27500:8190:3533:0:3083 +EMIRAT FM2:12379:v:1:27500:8190:3534:0:3084 +Radio Italia :12379:v:1:27500:8190:3531:0:3081 +EQUIDIA INTER.:12379:v:1:27500:3321:3351:0:3051 +RTV MONTENEGRO:12379:v:1:27500:3026:3036:0:3006 +Radio Montenegro:12379:v:1:27500:8190:3538:0:3088 +SERTE TEST:12379:v:1:27500:3025:8190:0:3005 +GAME 1:12379:v:1:27500:3027:3037:0:3007 +SF 2:12398:h:1:27500:163:93:0:907 +SRG SSR Sat Access:12398:h:1:27500:165:99:0:910 +SF 1:12398:h:1:27500:160:81:0:901 +TSR 1:12398:h:1:27500:161:85:0:902 +TSI 1:12398:h:1:27500:162:89:0:903 +TSR 2:12398:h:1:27500:164:97:0:908 +TSI 2:12398:h:1:27500:166:101:0:909 +OPTION MUSIQUE:12398:h:1:27500:8190:204:0:957 +ESPACE 2:12398:h:1:27500:8190:205:0:958 +SRI-F-I:12398:h:1:27500:8190:199:0:951 +SRI-EUROPA:12398:h:1:27500:560:200:0:953 +POLO:12341:v:1:27500:160:80:0:11701 +PLANETE:12341:v:1:27500:161:84:0:11703 +JIMMY:12341:v:1:27500:162:88:0:11705 +INN:12341:v:1:27500:163:92:0:11707 +CIN1:12341:v:1:27500:164:96:0:11709 +CIN2:12341:v:1:27500:165:100:0:11711 +CINC:12341:v:1:27500:166:104:0:11713 +SEASONS:12341:v:1:27500:167:108:0:11715 +WISHLINE:12341:v:1:27500:168:89:0:11717 +MARCOPOLO:12341:v:1:27500:160:81:0:11719 +JAAM-E-JAM 1:12436:h:1:27500:160:81:0:1 +JAAM-E-JAM 2:12436:h:1:27500:161:83:0:2 +SAHAR:12436:h:1:27500:162:85:0:3 +TEST(SAHAR):12436:h:1:27500:163:87:0:4 +IRINN:12436:h:1:27500:164:89:0:5 +TEST 2:12436:h:1:27500:165:90:0:6 +IRIB1 RADIO:12436:h:1:27500:8190:81:0:7 +IRIB ARABIC /International 1 Radio:12436:h:1:27500:8190:83:0:8 +INT1 FAMILY RADIO:12475:h:1:27500:8190:961:0:10615 +RADIO 74:12475:h:1:27500:8190:921:0:10612 +R 74 INT.:12475:h:1:27500:8190:931:0:10613 +FAMILY Radio:12475:h:1:27500:8190:951:0:10614 +Temp:12475:h:1:27500:771:8190:0:10607 +SPREE Radio:12475:h:1:27500:8190:501:0:10652 + RVI ( VRT ) :12475:h:1:27500:8190:901:0:10610 +EbS:12475:h:1:27500:101:216:0:10601 +MOU.2:12475:h:1:27500:42:8190:0:10602 +MIZIK TROPICAL:12475:h:1:27500:435:436:0:10606 +MIZIK TROPICAL Radio:12475:h:1:27500:8190:801:0:10608 +Framboise Nord (CH):12475:h:1:27500:8190:971:0:10616 +Framboise Sud (CH):12475:h:1:27500:8190:981:0:10617 +PINK PLUS:12475:h:1:27500:308:257:0:10605 +LIBERTYTV.COM:12475:h:1:27500:941:942:0:10603 +KURDSAT:12475:h:1:27500:600:601:0:10618 +test2:12475:h:1:27500:3000:3001:0:10620 +HRT-TV1:12519:v:1:27500:100:101:0:8301 +HRT-TV2:12519:v:1:27500:103:104:0:8302 +HRT-TV3:12519:v:1:27500:105:106:0:8303 +HRT-HR1:12519:v:1:27500:8190:150:0:8305 +HRT-HR2:12519:v:1:27500:8190:151:0:8306 +HRT-HR3:12519:v:1:27500:8190:152:0:8307 +SICILIA INTERNATIONAL:12519:v:1:27500:501:8190:0:8309 +HRT-NATIONAL:12519:v:1:27500:107:108:0:8304 +HRT-TEST:12519:v:1:27500:109:110:0:8308 +SARDEGNA UNO:12519:v:1:27500:503:8190:0:8310 +R-HRVATSKA:12519:v:1:27500:8190:153:0:8311 +EuroMed:12519:v:1:27500:510:8190:0:8312 +TGRT:12519:v:1:27500:505:8190:0:8313 +HR-TEST:12519:v:1:27500:8190:154:0:8314 +MINI-BVN:12519:v:1:27500:210:8190:0:8315 +SIMS 91 LARIO:12713:h:1:27500:8190:8190:0:8802 +SKYPLEX TXP91:12713:h:1:27500:8190:8190:0:8801 +Skygate 18:12713:h:1:27500:8190:8190:0:2 +MA12_2905:12713:h:1:27500:8190:8190:0:8810 +ES13_1107:12713:h:1:27500:8190:8190:0:8811 +ASTONv0107:12713:h:1:27500:8190:8190:0:8815 +sisal:12713:h:1:27500:4356:8190:0:1 +service:12713:h:1:27500:4356:8190:0:3 +Skyplex 19:12713:h:1:27500:8190:8190:0:8991 +Network:12713:h:1:27500:8190:8190:0:8992 +www.travel:12713:h:1:27500:1180:1184:0:8993 +MagicStar:12713:h:1:27500:8190:1188:0:8994 +Skygate 8:12713:h:1:27500:8190:8190:0:8926 +UDLR:12713:h:1:27500:8190:6653:0:8927 +UDLR UDcast:12713:h:1:27500:8190:8190:0:8928 +Skygate 17:12713:h:1:27500:8190:8190:0:8804 +Netshow:12713:h:1:27500:8190:8190:0:8813 +MEDIOLANUM:12713:h:1:27500:4102:8190:0:8814 +Skygate 10:12713:h:1:27500:8190:8190:0:8901 +HitCast Data 1:12713:h:1:27500:8190:8190:0:8902 +HitCast S.Amer.:12713:h:1:27500:8190:8190:0:8903 +Skygate 1:12713:h:1:27500:8190:8190:0:8876 +MonteCarloSat:12713:h:1:27500:5127:5122:0:8877 +Bulgaria Radio:12713:h:1:27500:8190:4615:0:8828 +skygate 600:12713:h:1:27500:8190:8190:0:8826 +SKYPLEX TXP92:12558:v:1:27500:8190:8190:0:9101 +SKYPLEX TXP92:12558:v:1:27500:8190:8190:0:9361 +SKYPLEX TXP92:12558:v:1:27500:2825:2818:0:9362 +SKYPLEX TXP92:12558:v:1:27500:2825:2818:0:9363 +SKYPLEX TXP92:12558:v:1:27500:2825:2818:0:9364 +SKY_4:12558:v:1:27500:8190:8190:0:9351 +ESP Int'l:12558:v:1:27500:2575:2563:0:9352 +ESP Romanian:12558:v:1:27500:8190:2569:0:9353 +ESP Dutch:12558:v:1:27500:2575:2564:0:9354 +ESP PolisI:12558:v:1:27500:8190:2565:0:9355 +ESP PolisI:12558:v:1:27500:2575:2566:0:9356 +ESP PolisI:12558:v:1:27500:2575:2564:0:9357 +ESP PolisI:12558:v:1:27500:2575:2568:0:9358 +ESP PolisI:12558:v:1:27500:2575:2565:0:9359 +ESP PolisI:12558:v:1:27500:2575:2565:0:9251 +JSTV 1:12596:v:1:27500:2000:2002:0:8213 +JSTV 2:12596:v:1:27500:2011:2013:0:8214 +MBC:12596:v:1:27500:160:81:0:8201 +Service 2:12596:v:1:27500:161:84:0:8202 +NITV:12596:v:1:27500:163:92:0:8204 +SIMAYE AZADI:12596:v:1:27500:166:106:0:8207 +BET:12596:v:1:27500:167:109:0:8208 +CNNI:12596:v:1:27500:168:113:0:8209 +EuroNews:12596:v:1:27500:2221:2238:0:8211 +Canal Rural:12596:v:1:27500:2321:2332:0:8212 +MediaHW:12596:v:1:27500:8190:8190:0:8291 +MediaHW:12615:h:1:27500:8190:8190:0:65534 +MMOV:12615:h:1:27500:2576:8190:0:3910 +MMOV:12615:h:1:27500:2578:8190:0:3913 +MMOV:12615:h:1:27500:2580:8190:0:3917 +MMOV:12615:h:1:27500:2582:8190:0:3918 +MMOV:12615:h:1:27500:2584:8190:0:3919 +MMOV:12615:h:1:27500:2586:8190:0:3920 +SC 1:12615:h:1:27500:2567:8190:0:3921 +SC 2:12615:h:1:27500:2570:8190:0:3924 +SC 3:12615:h:1:27500:2573:8190:0:3927 +MC20:12615:h:1:27500:8190:2304:0:3935 +MC21:12615:h:1:27500:8190:2305:0:3938 +MC22:12615:h:1:27500:8190:2306:0:3941 +MC23:12615:h:1:27500:8190:2307:0:3944 +MC24:12615:h:1:27500:8190:2308:0:3947 +MC25:12615:h:1:27500:8190:2309:0:3950 +MC26:12615:h:1:27500:8190:2310:0:3953 +MC27:12615:h:1:27500:8190:2311:0:3956 +MC28:12615:h:1:27500:8190:2312:0:3959 +MC29:12615:h:1:27500:8190:2313:0:3962 +MC30:12615:h:1:27500:8190:2314:0:3965 +MC31:12615:h:1:27500:8190:2315:0:3968 +MC32:12615:h:1:27500:8190:2316:0:3971 +MC33:12615:h:1:27500:8190:2317:0:3974 +MC34:12615:h:1:27500:8190:2318:0:3977 +MC35:12615:h:1:27500:8190:2319:0:3980 +MC36:12615:h:1:27500:8190:2320:0:3983 +MC37:12615:h:1:27500:8190:2321:0:3986 +MC38:12615:h:1:27500:8190:2322:0:3989 +MC39:12615:h:1:27500:8190:2323:0:3992 +MC39:12635:v:1:27500:8190:2323:0:65534 +SC 4:12635:v:1:27500:2704:8190:0:4001 +SC 5:12635:v:1:27500:2696:8190:0:4002 +SC 6:12635:v:1:27500:2701:8190:0:4003 +MMOV:12635:v:1:27500:2692:8190:0:4007 +MMOV:12635:v:1:27500:2694:8190:0:4010 +MMOV:12635:v:1:27500:2707:8190:0:4016 +MMOV:12635:v:1:27500:2709:8190:0:4019 +MMOV:12635:v:1:27500:2711:8190:0:4022 +MMOV:12635:v:1:27500:2819:8190:0:4025 +MMOV:12635:v:1:27500:2821:8190:0:4028 +Sharjah Arabsat Bouquet:12654:h:1:27500:1160:8190:0:1 +Qatar Arabsat Bouquet:12654:h:1:27500:1260:8190:0:2 +Saudi 1 Arabsat Bouquet:12654:h:1:27500:1360:8190:0:3 +Kuwait Arabsat Bouquet:12654:h:1:27500:1460:8190:0:4 +Libya Arabsat Bouquet:12654:h:1:27500:1560:8190:0:5 +Sudan Arabsat Bouquet:12654:h:1:27500:1660:8190:0:6 +Oman Arabsat Bouquet:12654:h:1:27500:1760:8190:0:7 +Jordan Arabsat Bouquet:12654:h:1:27500:1860:8190:0:8 +IRAQ TV:12654:h:1:27500:1960:8190:0:9 +Dubai Sport:12654:h:1:27500:1060:8190:0:10 +Qatar A2 Arabsat Bouquet:12654:h:1:27500:8190:1221:0:12 +Saudi1 A2 Arabsat Bouquet:12654:h:1:27500:8190:1321:0:13 +Kuwait A2 Arabsat Bouquet:12654:h:1:27500:8190:1421:0:14 +Jordan A2 Arabsat Bouquet:12654:h:1:27500:8190:1821:0:18 +Radio dubai sport:12654:h:1:27500:8190:1021:0:19 +Digitaly:12673:v:1:27500:220:222:0:4203 +Telemarket:12673:v:1:27500:350:351:0:4211 +Internet data 1:12673:v:1:27500:8190:8190:0:4212 +eVision:12673:v:1:27500:360:7142:0:4214 +ANNI 60:12673:v:1:27500:8190:250:0:4230 +R. Reporter:12673:v:1:27500:8190:251:0:4231 +Radio Italia S.M.I.:12673:v:1:27500:8190:252:0:4232 +R. Tour:12673:v:1:27500:8190:253:0:4233 +R.Rinascente:12673:v:1:27500:8190:254:0:4234 +R. Cooky:12673:v:1:27500:8190:255:0:4235 +RadioBaby:12673:v:1:27500:8190:256:0:4236 +McDonalds:12673:v:1:27500:8190:257:0:4237 +TRBuonconsiglio:12673:v:1:27500:8190:401:0:4238 +R-Radio:12673:v:1:27500:8190:402:0:4239 +R. Donna:12673:v:1:27500:8190:403:0:4240 +R. Reporter 2:12673:v:1:27500:8190:404:0:4241 +R. West:12673:v:1:27500:8190:405:0:4242 +Melodia Russia:12673:v:1:27500:6646:406:0:4243 +Padre Pio:12673:v:1:27500:8190:407:0:4244 +Thai TV5:12673:v:1:27500:200:202:0:4201 +Studio Europa:12673:v:1:27500:230:231:0:4204 +Video Italia:12673:v:1:27500:340:342:0:4210 +PASSIONS:12692:h:1:27500:160:8190:0:501 +ONYX:12692:h:1:27500:161:8190:0:502 +MANGAS:12692:h:1:27500:162:88:0:503 +ENCYCLOPEDIA:12692:h:1:27500:163:92:0:504 +POLAR:12692:h:1:27500:164:96:0:505 +CINE PALACE:12692:h:1:27500:165:100:0:506 +ROMANCE:12692:h:1:27500:166:104:0:507 +RIRE:12692:h:1:27500:167:108:0:508 +ACTION:12692:h:1:27500:168:112:0:509 +ABsat test RADIO:12692:h:1:27500:8190:101:0:510 +ABsat test RADIO:12713:v:1:27500:8190:101:0:65534 +MMOV:12713:v:1:27500:2563:8190:0:4304 +MMOV:12713:v:1:27500:2565:8190:0:4307 +MMOV:12713:v:1:27500:2567:8190:0:4310 +MMOV:12713:v:1:27500:2308:8190:0:4313 +MMOV:12713:v:1:27500:2314:8190:0:4316 +MMOV:12713:v:1:27500:2310:8190:0:4324 +MMOV:12713:v:1:27500:2312:8190:0:4327 +MMOV:12713:h:1:27500:2312:8190:0:65534 +SINT:12713:h:1:27500:8190:8190:0:8802 +info:12713:h:1:27500:517:8190:0:8804 +SINT:12713:h:1:27500:8190:8190:0:8806 +CFN:12713:h:1:27500:523:8190:0:8809 +SINT:12713:h:1:27500:8190:8190:0:8812 +duel:12713:h:1:27500:518:8190:0:8815 +comedy:12713:h:1:27500:515:8190:0:8818 +fox kids:12713:h:1:27500:513:8190:0:8821 diff --git a/channels.conf b/channels.conf index 6e6d0168d..4a6cb0b34 100644 --- a/channels.conf +++ b/channels.conf @@ -9,7 +9,7 @@ N3:12110:h:1:27500:2401:2402:0:28224 SR3:11837:h:1:27500:501:502:0:28110 WDR:11837:h:1:27500:601:602:0:28111 BR-alpha:11837:h:1:27500:701:702:0:28112 -SWR BW:11837:h:1:27500:801:802:0:28110 +SWR BW:11837:h:1:27500:801:802:0:28113 Phoenix:11837:h:1:27500:901:902:0:28114 ZDF:11954:h:1:27500:110:120:0:28006 3sat:11954:h:1:27500:210:220:0:28007 diff --git a/config.c b/config.c index af5be871f..0a965ee54 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.18 2000/09/03 09:20:22 kls Exp $ + * $Id: config.c 1.22 2000/09/10 15:07:15 kls Exp $ */ #include "config.h" @@ -196,11 +196,22 @@ cChannel::cChannel(const cChannel *Channel) apid = Channel ? Channel->apid : 256; ca = Channel ? Channel->ca : 0; pnr = Channel ? Channel->pnr : 0; + groupSep = Channel ? Channel->groupSep : false; } const char *cChannel::ToText(cChannel *Channel) { - asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", Channel->name, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->ca, Channel->pnr); + char buf[MaxChannelName * 2]; + char *s = Channel->name; + if (strchr(s, ':')) { + s = strcpy(buf, s); + strreplace(s, ':', '|'); + } + delete buffer; + if (Channel->groupSep) + asprintf(&buffer, ":%s\n", s); + else + asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->ca, Channel->pnr); return buffer; } @@ -212,13 +223,27 @@ const char *cChannel::ToText(void) bool cChannel::Parse(const char *s) { char *buffer = NULL; - 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; - return true; + if (*s == ':') { + if (*++s) { + strn0cpy(name, s, MaxChannelName); + name[strlen(name) - 1] = 0; // strip the '\n' + groupSep = true; + } + else + return false; } - return false; + else { + groupSep = false; + int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &ca, &pnr); + if (fields == 9) { + strn0cpy(name, buffer, MaxChannelName); + delete buffer; + } + else + return false; + } + strreplace(name, '|', ':'); + return true; } bool cChannel::Save(FILE *f) @@ -230,9 +255,9 @@ bool cChannel::Switch(cDvbApi *DvbApi) { if (!DvbApi) DvbApi = cDvbApi::PrimaryDvbApi; - if (!DvbApi->Recording()) { - isyslog(LOG_INFO, "switching to channel %d", Index() + 1); - CurrentChannel = Index(); + if (!DvbApi->Recording() && !groupSep) { + isyslog(LOG_INFO, "switching to channel %d", number); + CurrentChannel = number; for (int i = 3; i--;) { if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) { EIT.SetProgramNumber(pnr); @@ -242,22 +267,10 @@ bool cChannel::Switch(cDvbApi *DvbApi) } return false; } - Interface.Info("Channel locked (recording)!"); + Interface.Info(DvbApi->Recording() ? "Channel locked (recording)!" : name); return false; } -bool cChannel::SwitchTo(int i, cDvbApi *DvbApi) -{ - cChannel *channel = Channels.Get(i); - return channel && channel->Switch(DvbApi); -} - -const char *cChannel::GetChannelName(int i) -{ - cChannel *channel = Channels.Get(i); - return channel ? channel->name : NULL; -} - // -- cTimer ----------------------------------------------------------------- char *cTimer::buffer = NULL; @@ -267,7 +280,8 @@ cTimer::cTimer(bool Instant) startTime = stopTime = 0; recording = false; active = Instant; - channel = CurrentChannel + 1; + cChannel *ch = Channels.GetByNumber(CurrentChannel); + channel = ch ? ch->number : 0; time_t t = time(NULL); struct tm *now = localtime(&t); day = now->tm_mday; @@ -280,8 +294,8 @@ cTimer::cTimer(bool Instant) lifetime = 99; *file = 0; summary = NULL; - if (Instant) - snprintf(file, sizeof(file), "@%s", cChannel::GetChannelName(CurrentChannel)); + if (Instant && ch) + snprintf(file, sizeof(file), "@%s", ch->name); } cTimer::~cTimer() @@ -299,6 +313,7 @@ cTimer& cTimer::operator= (const cTimer &Timer) const char *cTimer::ToText(cTimer *Timer) { + delete buffer; asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); return buffer; } @@ -368,11 +383,7 @@ bool cTimer::Parse(const char *s) if (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) { //TODO add more plausibility checks day = ParseDay(buffer1); - int l = strlen(buffer2); - if (l >= MaxFileName) - l = MaxFileName - 1; - strncpy(file, buffer2, l); - file[l] = 0; + strn0cpy(file, buffer2, MaxFileName); delete buffer1; delete buffer2; return day != 0; @@ -470,10 +481,87 @@ cKeys Keys; // -- cChannels -------------------------------------------------------------- -int CurrentChannel = 0; +int CurrentChannel = 1; +int CurrentGroup = -1; cChannels Channels; +bool cChannels::Load(const char *FileName) +{ + if (cConfig::Load(FileName)) { + ReNumber(); + return true; + } + return false; +} + +int cChannels::GetNextGroup(int Idx) +{ + cChannel *channel = Get(++Idx); + while (channel && !channel->groupSep) + channel = Get(++Idx); + return channel ? Idx : -1; +} + +int cChannels::GetPrevGroup(int Idx) +{ + cChannel *channel = Get(--Idx); + while (channel && !channel->groupSep) + channel = Get(--Idx); + return channel ? Idx : -1; +} + +int cChannels::GetNextNormal(int Idx) +{ + cChannel *channel = Get(++Idx); + while (channel && channel->groupSep) + channel = Get(++Idx); + return channel ? Idx : -1; +} + +void cChannels::ReNumber( void ) +{ + int Number = 0; + cChannel *ch = (cChannel *)First(); + while (ch) { + if (!ch->groupSep) + ch->number = ++Number; + ch = (cChannel *)ch->Next(); + } + maxNumber = Number; +} + +cChannel *cChannels::GetByNumber(int Number) +{ + cChannel *channel = (cChannel *)First(); + while (channel) { + if (channel->number == Number) + return channel; + channel = (cChannel *)channel->Next(); + } + return NULL; +} + +bool cChannels::SwitchTo(int Number, cDvbApi *DvbApi) +{ + cChannel *channel = GetByNumber(Number); + return channel && channel->Switch(DvbApi); +} + +const char *cChannels::GetChannelNameByNumber(int Number) +{ + cChannel *channel = GetByNumber(Number); + return channel ? channel->name : NULL; +} + +eKeys cChannels::ShowChannel(int Number, bool Switched, bool Group) +{ + cChannel *channel = Group ? Get(Number) : GetByNumber(Number); + if (channel) + return Interface.DisplayChannel(channel->number, channel->name, !Switched || Setup.ShowInfoOnChSwitch); + return kNone; +} + // -- cTimers ---------------------------------------------------------------- cTimers Timers; @@ -489,3 +577,81 @@ cTimer *cTimers::GetTimer(cTimer *Timer) return NULL; } +// -- cSetup ----------------------------------------------------------------- + +cSetup Setup; + +char *cSetup::fileName = NULL; + +cSetup::cSetup(void) +{ + PrimaryDVB = 1; + ShowInfoOnChSwitch = 1; + MenuScrollPage = 1; +} + +bool cSetup::Parse(char *s) +{ + const char *Delimiters = " \t\n="; + char *Name = strtok(s, Delimiters); + char *Value = strtok(NULL, Delimiters); + if (Name && Value) { + if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); + else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); + else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); + else + return false; + return true; + } + return false; +} + +bool cSetup::Load(const char *FileName) +{ + isyslog(LOG_INFO, "loading %s", FileName); + delete fileName; + fileName = strdup(FileName); + FILE *f = fopen(fileName, "r"); + if (f) { + int line = 0; + char buffer[MaxBuffer]; + bool result = true; + while (fgets(buffer, sizeof(buffer), f) > 0) { + line++; + if (*buffer != '#' && !Parse(buffer)) { + esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); + result = false; + break; + } + } + fclose(f); + return result; + } + else + LOG_ERROR_STR(FileName); + return false; +} + +bool cSetup::Save(const char *FileName) +{ + if (!FileName) + FileName = fileName; + if (FileName) { + FILE *f = fopen(FileName, "w"); + if (f) { + fprintf(f, "# VDR Setup\n"); + fprintf(f, "PrimaryDVB = %d\n", PrimaryDVB); + fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch); + fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage); + fclose(f); + isyslog(LOG_INFO, "saved setup to %s", FileName); + return true; + } + else + LOG_ERROR_STR(FileName); + } + else + esyslog(LOG_ERR, "attempt to save setup without file name"); + return false; +} + diff --git a/config.h b/config.h index 15e905011..30dd9bac2 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.15 2000/09/03 09:37:30 kls Exp $ + * $Id: config.h 1.19 2000/09/10 15:05:08 kls Exp $ */ #ifndef __CONFIG_H @@ -17,7 +17,7 @@ #include "dvbapi.h" #include "tools.h" -#define VDRVERSION "0.62" +#define VDRVERSION "0.63" #define MaxBuffer 10000 @@ -75,14 +75,14 @@ class cChannel : public cListObject { int apid; int ca; int pnr; + int number; // Sequence number assigned on load + bool groupSep; cChannel(void); cChannel(const cChannel *Channel); const char *ToText(void); bool Parse(const char *s); bool Save(FILE *f); bool Switch(cDvbApi *DvbApi = NULL); - static bool SwitchTo(int i, cDvbApi *DvbApi = NULL); - static const char *GetChannelName(int i); }; class cTimer : public cListObject { @@ -130,7 +130,7 @@ template class cConfig : public cList { cList::Clear(); } public: - bool Load(const char *FileName) + virtual bool Load(const char *FileName) { isyslog(LOG_INFO, "loading %s", FileName); bool result = true; @@ -155,7 +155,7 @@ template class cConfig : public cList { fclose(f); } else { - esyslog(LOG_ERR, "can't open '%s'\n", fileName); + LOG_ERROR_STR(fileName); result = false; } return result; @@ -176,23 +176,57 @@ template class cConfig : public cList { } fclose(f); } - else + else { + LOG_ERROR_STR(fileName); result = false; + } return result; } }; -class cChannels : public cConfig {}; - +class cChannels : public cConfig { +protected: + int maxNumber; +public: + cChannels(void) { maxNumber = 0; } + virtual bool Load(const char *FileName); + int GetNextGroup(int Idx); // Get next channel group + int GetPrevGroup(int Idx); // Get previous channel group + int GetNextNormal(int Idx); // Get next normal channel (not group) + void ReNumber(void); // Recalculate 'number' based on channel type + cChannel *GetByNumber(int Number); + const char *GetChannelNameByNumber(int Number); + bool SwitchTo(int Number, cDvbApi *DvbApi = NULL); + int MaxNumber(void) { return maxNumber; } + eKeys ShowChannel(int Number, bool Switched, bool Group = false); + }; + class cTimers : public cConfig { public: cTimer *GetTimer(cTimer *Timer); }; extern int CurrentChannel; +extern int CurrentGroup; extern cChannels Channels; extern cTimers Timers; extern cKeys Keys; +class cSetup { +private: + static char *fileName; + bool Parse(char *s); +public: + // Also adjust cMenuSetup (menu.c) when adding parameters here! + int PrimaryDVB; + int ShowInfoOnChSwitch; + int MenuScrollPage; + cSetup(void); + bool Load(const char *FileName); + bool Save(const char *FileName = NULL); + }; + +extern cSetup Setup; + #endif //__CONFIG_H diff --git a/dvbapi.c b/dvbapi.c index 0562a4f58..9f9cbab42 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.22 2000/08/06 14:06:14 kls Exp $ + * $Id: dvbapi.c 1.24 2000/09/10 10:25:09 kls Exp $ */ #include "dvbapi.h" @@ -1097,16 +1097,34 @@ cDvbApi::~cDvbApi() delete replayTitle; } +bool cDvbApi::SetPrimaryDvbApi(int n) +{ + n--; + if (0 <= n && n < NumDvbApis && dvbApi[n]) { + isyslog(LOG_INFO, "setting primary DVB to %d", n + 1); + PrimaryDvbApi = dvbApi[n]; + return true; + } + esyslog(LOG_ERR, "invalid DVB interface: %d", n + 1); + return false; +} + cDvbApi *cDvbApi::GetDvbApi(int Ca) { + cDvbApi *d = NULL; Ca--; for (int i = MAXDVBAPI; --i >= 0; ) { - if (dvbApi[i]) { - if ((i == Ca || Ca < 0) && !dvbApi[i]->Recording()) + if (dvbApi[i] && !dvbApi[i]->Recording()) { + if (i == Ca) return dvbApi[i]; + if (Ca < 0) { + d = dvbApi[i]; + if (d != PrimaryDvbApi) + break; + } } } - return NULL; + return d; } int cDvbApi::Index(void) @@ -1199,6 +1217,10 @@ void cDvbApi::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co dc.y1 = y1; dc.data = (void *)data; ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc); + usleep(10); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places + // XXX and sometimes the OSD was no longer displayed). + // XXX Increase the value if the problem still persists on your particular system. + // TODO Check if this is still necessary with driver versions after 0.6. } } #endif diff --git a/dvbapi.h b/dvbapi.h index 9f9543020..a43e7075c 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.13 2000/09/03 09:25:53 kls Exp $ + * $Id: dvbapi.h 1.14 2000/09/10 10:03:29 kls Exp $ */ #ifndef __DVBAPI_H @@ -53,9 +53,13 @@ class cDvbApi { static cDvbApi *dvbApi[MAXDVBAPI]; public: static cDvbApi *PrimaryDvbApi; + static bool SetPrimaryDvbApi(int n); + // Sets the primary DVB device to 'n' (which must be in the range + // 1...NumDvbApis) and returns true if this was possible. static cDvbApi *GetDvbApi(int Ca = 0); - // Selects a free DVB device, starting with the highest device number. - // If Ca is nor 0, the device with the given number will be returned + // Selects a free DVB device, starting with the highest device number + // (but avoiding, if possible, the PrimaryDvbApi). + // If Ca is not 0, the device with the given number will be returned // if it is not currently recording. int Index(void); // Returns the index of this DvbApi. diff --git a/interface.c b/interface.c index 2ae49c330..5633f864e 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.11 2000/09/03 10:17:21 kls Exp $ + * $Id: interface.c 1.15 2000/09/10 16:04:14 kls Exp $ */ #include "interface.h" @@ -72,10 +72,10 @@ eKeys cInterface::GetKey(bool Wait) eKeys cInterface::Wait(int Seconds, bool KeepChar) { - int t0 = time_ms(); + int t0 = time_ms() + Seconds * 1000; eKeys Key = kNone; - while (time_ms() - t0 < Seconds * 1000) { + while (time_ms() < t0) { Key = GetKey(); if (Key != kNone) break; @@ -112,11 +112,9 @@ void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor cDvbApi::PrimaryDvbApi->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, eDvbColor FgColor, eDvbColor BgColor) { if (open) { - eDvbColor FgColor = Current ? clrBlack : clrWhite; - eDvbColor BgColor = Current ? clrCyan : clrBackground; ClearEol(x, y, BgColor); int col = 0; for (;;) { @@ -315,36 +313,61 @@ void cInterface::LearnKeys(void) } } -void cInterface::DisplayChannel(int Number, const char *Name) +eKeys cInterface::DisplayChannel(int Number, const char *Name, bool WithInfo) { - RcIo.Number(Number); + // Number = 0 is used for channel group display and no EIT + if (Number) + RcIo.Number(Number); if (Name && !Recording()) { - Open(MenuColumns, EIT.IsValid() ? 5 : 1); - char buffer[MenuColumns + 1]; - snprintf(buffer, sizeof(buffer), "%d %s", Number, Name ? Name : ""); + char *RunningTitle = "", *RunningSubtitle = "", *NextTitle = "", *NextSubtitle = ""; + int Lines = 0; + if (Number && WithInfo && EIT.IsValid()) { + if (*(RunningTitle = EIT.GetRunningTitle())) Lines++; + if (*(RunningSubtitle = EIT.GetRunningSubtitle())) Lines++; + if (*(NextTitle = EIT.GetNextTitle())) Lines++; + if (*(NextSubtitle = EIT.GetNextSubtitle())) Lines++; + } + Open(MenuColumns, Lines + 1); + int BufSize = MenuColumns + 1; + char buffer[BufSize]; + if (Number) + snprintf(buffer, BufSize, "%d %s", Number, Name ? Name : ""); + else + snprintf(buffer, BufSize, "%s", Name ? Name : ""); Write(0, 0, buffer); time_t t = time(NULL); struct tm *now = localtime(&t); - snprintf(buffer, sizeof(buffer), "%02d:%02d", now->tm_hour, now->tm_min); + snprintf(buffer, BufSize, "%02d:%02d", now->tm_hour, now->tm_min); Write(-5, 0, buffer); - if (EIT.IsValid()) { - const int t = 7; + if (Lines > 0) { + const int t = 6; int w = MenuColumns - t; - Write(0, 1, EIT.GetRunningTime(), clrYellow, clrBackground); - snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningTitle()); - Write(t, 1, buffer, clrCyan, clrBackground); - snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningSubtitle()); - Write(t, 2, buffer, clrCyan, clrBackground); - Write(0, 3, EIT.GetNextTime(), clrYellow, clrBackground); - snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextTitle()); - Write(t, 3, buffer, clrCyan, clrBackground); - snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextSubtitle()); - Write(t, 4, buffer, clrCyan, clrBackground); + int l = 1; + if (*RunningTitle) { + Write(0, l, EIT.GetRunningTime(), clrYellow, clrBackground); + snprintf(buffer, BufSize, "%.*s", w, RunningTitle); Write(t, l, buffer, clrCyan, clrBackground); + l++; + } + if (*RunningSubtitle) { + snprintf(buffer, BufSize, "%.*s", w, RunningSubtitle); Write(t, l, buffer, clrCyan, clrBackground); + l++; + } + if (*NextTitle) { + Write(0, l, EIT.GetNextTime(), clrYellow, clrBackground); + snprintf(buffer, BufSize, "%.*s", w, NextTitle); Write(t, l, buffer, clrCyan, clrBackground); + l++; + } + if (*NextSubtitle) { + snprintf(buffer, BufSize, "%.*s", w, NextSubtitle); Write(t, l, buffer, clrCyan, clrBackground); + } } - if (Wait(5, true) == kOk) + eKeys Key = Wait(5, true); + if (Key == kOk) GetKey(); Close(); + return Key; } + return kNone; } void cInterface::DisplayRecording(int Index, bool On) diff --git a/interface.h b/interface.h index 2a1c1560f..4503dc65c 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.9 2000/05/06 15:39:23 kls Exp $ + * $Id: interface.h 1.11 2000/09/10 10:35:46 kls Exp $ */ #ifndef __INTERFACE_H @@ -34,7 +34,7 @@ class cInterface { void ClearEol(int x, int y, eDvbColor Color = clrBackground); void SetCols(int *c); void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); - void WriteText(int x, int y, const char *s, bool Current = false); + void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBlack); void Title(const char *s); void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan); void Info(const char *s); @@ -42,7 +42,7 @@ class cInterface { bool Confirm(const char *s); void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); void LearnKeys(void); - void DisplayChannel(int Number, const char *Name = NULL); + eKeys DisplayChannel(int Number, const char *Name = NULL, bool WithInfo = false); void DisplayRecording(int Index, bool On); bool Recording(void); }; diff --git a/menu.c b/menu.c index 15c8379a0..ad803cf42 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.22 2000/08/06 07:02:52 kls Exp $ + * $Id: menu.c 1.26 2000/09/10 15:06:15 kls Exp $ */ #include "menu.h" @@ -145,7 +145,7 @@ class cMenuEditChanItem : public cMenuEditIntItem { }; cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value) -:cMenuEditIntItem(Name, Value, 1, Channels.Count()) +:cMenuEditIntItem(Name, Value, 1, Channels.MaxNumber()) { Set(); } @@ -153,7 +153,7 @@ cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value) void cMenuEditChanItem::Set(void) { char buf[255]; - cChannel *channel = Channels.Get(*value - 1); + cChannel *channel = Channels.GetByNumber(*value); if (channel) snprintf(buf, sizeof(buf), "%d %s", *value, channel->name); else @@ -547,13 +547,18 @@ cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel) { index = Index; channel = Channel; + if (channel->groupSep) + SetColor(clrWhite, clrBlue); Set(); } void cMenuChannelItem::Set(void) { char *buffer = NULL; - asprintf(&buffer, "%d\t%s", index + 1, channel->name); // user visible channel numbers start with '1' + if (!channel->groupSep) + asprintf(&buffer, "%d\t%s", channel->number, channel->name ); + else + asprintf(&buffer, "\t%s", channel->name); SetText(buffer, false); } @@ -583,9 +588,10 @@ cMenuChannels::cMenuChannels(void) //TODO int i = 0; cChannel *channel; + int curr = ((channel = Channels.GetByNumber(CurrentChannel)) != NULL) ? channel->Index() : -1; while ((channel = Channels.Get(i)) != NULL) { - Add(new cMenuChannelItem(i, channel), i == CurrentChannel); + Add(new cMenuChannelItem(i, channel), i == curr); i++; } SetHelp("Edit", "New", "Delete", "Mark"); @@ -613,9 +619,10 @@ eOSState cMenuChannels::New(void) return osContinue; cChannel *channel = new cChannel(Channels.Get(Current())); Channels.Add(channel); + Channels.ReNumber(); Add(new cMenuChannelItem(channel->Index()/*XXX*/, channel), true); Channels.Save(); - isyslog(LOG_INFO, "channel %d added", channel->Index() + 1); + isyslog(LOG_INFO, "channel %d added", channel->number); return AddSubMenu(new cMenuEditChannel(Current())); } @@ -623,28 +630,30 @@ eOSState cMenuChannels::Del(void) { if (Count() > 0) { int Index = Current(); + cChannel *channel = Channels.Get(Index); + int DeletedChannel = channel->number; // Check if there is a timer using this channel: for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { - if (ti->channel == Index + 1) { + if (ti->channel == DeletedChannel) { Interface.Error("Channel is being used by a timer!"); return osContinue; } } if (Interface.Confirm("Delete Channel?")) { // Move and renumber the channels: - Channels.Del(Channels.Get(Index)); + Channels.Del(channel); + Channels.ReNumber(); cOsdMenu::Del(Index); int i = 0; for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) ci->SetIndex(i++); Channels.Save(); - isyslog(LOG_INFO, "channel %d deleted", Index + 1); + isyslog(LOG_INFO, "channel %d deleted", DeletedChannel); // Fix the timers: bool TimersModified = false; - Index++; // user visible channel numbers start with '1' for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { int OldChannel = ti->channel; - if (ti->channel > Index) + if (ti->channel > DeletedChannel) ti->channel--; if (ti->channel != OldChannel) { TimersModified = true; @@ -661,25 +670,28 @@ eOSState cMenuChannels::Del(void) void cMenuChannels::Move(int From, int To) { + int FromNumber = Channels.Get(From)->number; + int ToNumber = Channels.Get(To)->number; // Move and renumber the channels: Channels.Move(From, To); + Channels.ReNumber(); cOsdMenu::Move(From, To); int i = 0; for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) ci->SetIndex(i++); Channels.Save(); - isyslog(LOG_INFO, "channel %d moved to %d", From + 1, To + 1); + isyslog(LOG_INFO, "channel %d moved to %d", FromNumber, ToNumber); // Fix the timers: bool TimersModified = false; From++; // user visible channel numbers start with '1' To++; for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { int OldChannel = ti->channel; - if (ti->channel == From) - ti->channel = To; - else if (ti->channel > From && ti->channel <= To) + if (ti->channel == FromNumber) + ti->channel = ToNumber; + else if (ti->channel > FromNumber && ti->channel <= ToNumber) ti->channel--; - else if (ti->channel < From && ti->channel >= To) + else if (ti->channel < FromNumber && ti->channel >= ToNumber) ti->channel++; if (ti->channel != OldChannel) { TimersModified = true; @@ -791,7 +803,7 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key) if (state == osUnknown) { if (Key == kOk) { if (!*data.file) - strcpy(data.file, cChannel::GetChannelName(data.channel - 1)); + strcpy(data.file, Channels.GetChannelNameByNumber(data.channel)); if (timer && memcmp(timer, &data, sizeof(data)) != 0) { *timer = data; Timers.Save(); @@ -1059,6 +1071,41 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) return state; } +// --- cMenuSetup ------------------------------------------------------------ + +class cMenuSetup : public cOsdMenu { +private: + cSetup data; +public: + cMenuSetup(void); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuSetup::cMenuSetup(void) +:cOsdMenu("Setup", 20) +{ + data = Setup; + Add(new cMenuEditIntItem( "PrimaryDVB", &data.PrimaryDVB, 1, cDvbApi::NumDvbApis)); + Add(new cMenuEditBoolItem("ShowInfoOnChSwitch", &data.ShowInfoOnChSwitch)); + Add(new cMenuEditBoolItem("MenuScrollPage", &data.MenuScrollPage)); +} + +eOSState cMenuSetup::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack; + Setup = data; + Setup.Save(); + break; + default: break; + } + } + return state; +} + // --- cMenuMain ------------------------------------------------------------- #define STOP_RECORDING "Stop recording " @@ -1069,6 +1116,7 @@ cMenuMain::cMenuMain(bool Replaying) Add(new cOsdItem("Channels", osChannels)); Add(new cOsdItem("Timer", osTimer)); Add(new cOsdItem("Recordings", osRecordings)); + Add(new cOsdItem("Setup", osSetup)); if (Replaying) Add(new cOsdItem("Stop replaying", osStopReplay)); const char *s = NULL; @@ -1091,6 +1139,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key) case osChannels: return AddSubMenu(new cMenuChannels); case osTimer: return AddSubMenu(new cMenuTimers); case osRecordings: return AddSubMenu(new cMenuRecordings); + case osSetup: return AddSubMenu(new cMenuSetup); case osStopRecord: if (Interface.Confirm("Stop Recording?")) { cOsdItem *item = Get(Current()); if (item) { @@ -1113,6 +1162,60 @@ eOSState cMenuMain::ProcessKey(eKeys Key) return state; } +// --- cDirectChannelSelect -------------------------------------------------- + +#define DIRECTCHANNELTIMEOUT 500 //ms + +cDirectChannelSelect::cDirectChannelSelect(eKeys FirstKey) +:cOsdBase(true) +{ + oldNumber = CurrentChannel; + number = 0; + lastTime = time_ms(); + Interface.Open(MenuColumns, 1); + ProcessKey(FirstKey); +} + +cDirectChannelSelect::~cDirectChannelSelect() +{ + if (number < 0) + Interface.DisplayChannel(oldNumber); + Interface.Close(); +} + +eOSState cDirectChannelSelect::ProcessKey(eKeys Key) +{ + switch (Key) { + case k0: case k1: case k2: case k3: case k4: case k5: case k6: case k7: case k8: case k9: + if (number >= 0) { + number = number * 10 + Key - k0; + cChannel *channel = Channels.GetByNumber(number); + char *Name = channel ? channel->name : "*** Invalid Channel ***"; + int BufSize = MenuColumns + 1; + char buffer[BufSize]; + snprintf(buffer, BufSize, "%d %s", number, Name); + Interface.DisplayChannel(number); + Interface.Clear(); + Interface.Write(0, 0, buffer); + lastTime = time_ms(); + if (!channel) { + number = -1; + lastTime += 1000; + } + } + break; + case kNone: + if (time_ms() - lastTime > DIRECTCHANNELTIMEOUT) { + if (number > 0 && !Channels.SwitchTo(number)) + number = -1; + } + else + break; + default: return osEnd; + }; + return osContinue; +} + // --- cRecordControl -------------------------------------------------------- cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) @@ -1125,10 +1228,10 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer = new cTimer(true); Timers.Add(timer); Timers.Save(); - asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s on %d" : "%s", cChannel::GetChannelName(timer->channel - 1), dvbApi->Index() + 1); + asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s on %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), dvbApi->Index() + 1); } timer->SetRecording(true); - cChannel::SwitchTo(timer->channel - 1, dvbApi); + Channels.SwitchTo(timer->channel, dvbApi); cRecording Recording(timer); if (dvbApi->StartRecord(Recording.FileName())) Recording.WriteSummary(); @@ -1172,8 +1275,8 @@ cRecordControl *cRecordControls::RecordControls[MAXDVBAPI] = { NULL }; bool cRecordControls::Start(cTimer *Timer) { - int ch = Timer ? Timer->channel - 1 : CurrentChannel; - cChannel *channel = Channels.Get(ch); + int ch = Timer ? Timer->channel : CurrentChannel; + cChannel *channel = Channels.GetByNumber(ch); if (channel) { cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca); @@ -1186,10 +1289,10 @@ bool cRecordControls::Start(cTimer *Timer) } } else - esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch + 1); + esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch); } else - esyslog(LOG_ERR, "ERROR: channel %d not defined!", ch + 1); + esyslog(LOG_ERR, "ERROR: channel %d not defined!", ch); return false; } diff --git a/menu.h b/menu.h index 6ba080cb2..8b4f82efe 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.9 2000/05/01 15:16:23 kls Exp $ + * $Id: menu.h 1.10 2000/09/10 14:42:20 kls Exp $ */ #ifndef _MENU_H @@ -23,6 +23,17 @@ class cMenuMain : public cOsdMenu { virtual eOSState ProcessKey(eKeys Key); }; +class cDirectChannelSelect : public cOsdBase { +private: + int oldNumber; + int number; + int lastTime; +public: + cDirectChannelSelect(eKeys FirstKey); + virtual ~cDirectChannelSelect(); + virtual eOSState ProcessKey(eKeys Key); + }; + class cRecordControl { private: cDvbApi *dvbApi; diff --git a/osd.c b/osd.c index 3c323738b..e1c99b44b 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.5 2000/07/26 17:35:09 kls Exp $ + * $Id: osd.c 1.7 2000/09/10 08:24:50 kls Exp $ */ #include "osd.h" @@ -19,6 +19,9 @@ cOsdItem::cOsdItem(eOSState State) offset = -1; state = State; fresh = false; + userColor = false; + fgColor = clrWhite; + bgColor = clrBackground; } cOsdItem::cOsdItem(char *Text, eOSState State) @@ -27,6 +30,9 @@ cOsdItem::cOsdItem(char *Text, eOSState State) offset = -1; state = State; fresh = false; + userColor = false; + fgColor = clrWhite; + bgColor = clrBackground; SetText(Text); } @@ -41,15 +47,24 @@ void cOsdItem::SetText(const char *Text, bool Copy) text = Copy ? strdup(Text) : Text; } -void cOsdItem::Display(int Offset, bool Current) +void cOsdItem::SetColor(eDvbColor FgColor, eDvbColor BgColor) { + userColor = true; + fgColor = FgColor; + bgColor = BgColor; +} + +void cOsdItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) +{ + if (Offset < 0) { + FgColor = clrBlack; + BgColor = clrCyan; + } fresh |= Offset >= 0; - Current |= Offset < 0; if (Offset >= 0) offset = Offset; - //TODO current if Offset == -1 ??? if (offset >= 0) - Interface.WriteText(0, offset + 2, text, Current); + Interface.WriteText(0, offset + 2, text, userColor ? fgColor : FgColor, userColor ? bgColor : BgColor); } eOSState cOsdItem::ProcessKey(eKeys Key) @@ -100,6 +115,10 @@ void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, c helpGreen = Green; helpYellow = Yellow; helpBlue = Blue; + if (visible) + Display(); + //XXX Interface.Help(helpRed, helpGreen, helpYellow, helpBlue); + //XXX must clear unused button areas! } void cOsdMenu::Del(int Index) @@ -140,7 +159,7 @@ void cOsdMenu::Display(void) for (int i = first; i < count; i++) { cOsdItem *item = Get(i); if (item) - item->Display(i - first, i == current); + item->Display(i - first, i == current ? clrBlack : clrWhite, i == current ? clrCyan : clrBackground); if (++n == MAXOSDITEMS) //TODO get this from Interface!!! break; } @@ -159,49 +178,62 @@ void cOsdMenu::DisplayCurrent(bool Current) { cOsdItem *item = Get(current); if (item) - item->Display(current - first, Current); + item->Display(current - first, Current ? clrBlack : clrWhite, Current ? clrCyan : clrBackground); +} + +bool cOsdMenu::SpecialItem(int idx) +{ + cOsdItem *item = Get(idx); + return item && item->HasUserColor(); } void cOsdMenu::CursorUp(void) { if (current > 0) { - DisplayCurrent(false); - if (current == first) { - first -= MAXOSDITEMS; - if (first < 0) - first = 0; - if (current - MAXOSDITEMS > 0) - current -= MAXOSDITEMS; - else - current--; + int tmpCurrent = current; + while (--tmpCurrent >= 0 && SpecialItem(tmpCurrent)); + if (tmpCurrent < 0) + return; + if (tmpCurrent >= first) + DisplayCurrent(false); + current = tmpCurrent; + if (current < first) { + first = first > MAXOSDITEMS - 1 ? first - (MAXOSDITEMS - 1) : 0; + if (Setup.MenuScrollPage) + current = SpecialItem(first) ? first + 1 : first; Display(); } - else { - current--; + else DisplayCurrent(true); - } } } void cOsdMenu::CursorDown(void) { - int count = Count(); - if (current < count - 1) { - DisplayCurrent(false); - if (current == first + MAXOSDITEMS - 1) { - first += MAXOSDITEMS; - if (first > count - MAXOSDITEMS) - first = count - MAXOSDITEMS; - if (current + MAXOSDITEMS < count) - current += MAXOSDITEMS; - else - current++; + int last = Count() - 1; + int lastOnScreen = first + MAXOSDITEMS - 1; + + if (current < last) { + int tmpCurrent = current; + while (++tmpCurrent <= last && SpecialItem(tmpCurrent)); + if (tmpCurrent > last) + return; + if (tmpCurrent <= lastOnScreen) + DisplayCurrent(false); + current = tmpCurrent; + if (current > lastOnScreen) { + first += MAXOSDITEMS - 1; + lastOnScreen = first + MAXOSDITEMS - 1; + if (lastOnScreen > last) { + first = last - (MAXOSDITEMS - 1); + lastOnScreen = last; + } + if (Setup.MenuScrollPage) + current = SpecialItem(lastOnScreen) ? lastOnScreen - 1 : lastOnScreen; Display(); } - else { - current++; + else DisplayCurrent(true); - } } } diff --git a/osd.h b/osd.h index 1d4f4cf0b..876c87cfc 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.9 2000/05/27 15:35:41 kls Exp $ + * $Id: osd.h 1.11 2000/09/10 09:50:38 kls Exp $ */ #ifndef __OSD_H @@ -22,10 +22,12 @@ enum eOSState { osUnknown, osChannels, osTimer, osRecordings, + osSetup, osRecord, osReplay, osStopRecord, osStopReplay, + osSwitchDvb, osBack, osEnd, }; @@ -37,13 +39,17 @@ class cOsdItem : public cListObject { eOSState state; protected: bool fresh; + bool userColor; + eDvbColor fgColor, bgColor; public: cOsdItem(eOSState State = osUnknown); cOsdItem(char *Text, eOSState State = osUnknown); virtual ~cOsdItem(); + bool HasUserColor(void) { return userColor; } void SetText(const char *Text, bool Copy = true); + void SetColor(eDvbColor FgColor, eDvbColor BgColor = clrBackground); const char *Text(void) { return text; } - void Display(int Offset = -1, bool Current = false); + void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); virtual void Set(void) {} virtual eOSState ProcessKey(eKeys Key); }; @@ -68,6 +74,7 @@ class cOsdMenu : public cOsdBase, public cList { const char *status; protected: bool visible; + bool SpecialItem(int idx); void RefreshCurrent(void); void DisplayCurrent(bool Current); void CursorUp(void); diff --git a/setup.conf b/setup.conf new file mode 100644 index 000000000..e80c2e0c2 --- /dev/null +++ b/setup.conf @@ -0,0 +1,4 @@ +# VDR Setup +PrimaryDVB = 1 +ShowInfoOnChSwitch = 1 +MenuScrollPage = 1 diff --git a/svdrp.c b/svdrp.c index 01e9fb7bf..2af3ee537 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.5 2000/08/26 12:51:51 kls Exp $ + * $Id: svdrp.c 1.6 2000/09/09 10:51:21 kls Exp $ */ #define _GNU_SOURCE @@ -279,24 +279,24 @@ void cSVDRP::CmdChan(const char *Option) if (*Option) { int n = -1; if (isnumber(Option)) { - int o = strtol(Option, NULL, 10) - 1; - if (o >= 0 && o < Channels.Count()) + int o = strtol(Option, NULL, 10); + if (o >= 1 && o <= Channels.MaxNumber()) n = o; } else if (strcmp(Option, "-") == 0) { n = CurrentChannel; - if (CurrentChannel > 0) + if (CurrentChannel > 1) n--; } else if (strcmp(Option, "+") == 0) { n = CurrentChannel; - if (CurrentChannel < Channels.Count() - 1) + if (CurrentChannel < Channels.MaxNumber()) n++; } else { - int i = 0; + int i = 1; cChannel *channel; - while ((channel = Channels.Get(i)) != NULL) { + while ((channel = Channels.GetByNumber(i)) != NULL) { if (strcasecmp(channel->name, Option) == 0) { n = i; break; @@ -312,10 +312,10 @@ void cSVDRP::CmdChan(const char *Option) Reply(550, "Can't switch channel, interface is recording"); return; } - cChannel *channel = Channels.Get(n); + cChannel *channel = Channels.GetByNumber(n); if (channel) { if (!channel->Switch()) { - Reply(554, "Error switching to channel \"%d\"", channel->Index() + 1); + Reply(554, "Error switching to channel \"%d\"", channel->number); return; } } @@ -324,9 +324,9 @@ void cSVDRP::CmdChan(const char *Option) return; } } - cChannel *channel = Channels.Get(CurrentChannel); + cChannel *channel = Channels.GetByNumber(CurrentChannel); if (channel) - Reply(250, "%d %s", CurrentChannel + 1, channel->name); + Reply(250, "%d %s", CurrentChannel, channel->name); else Reply(550, "Unable to find channel \"%d\"", CurrentChannel); } @@ -394,41 +394,41 @@ void cSVDRP::CmdLstc(const char *Option) { if (*Option) { if (isnumber(Option)) { - cChannel *channel = Channels.Get(strtol(Option, NULL, 10) - 1); + cChannel *channel = Channels.GetByNumber(strtol(Option, NULL, 10)); if (channel) - Reply(250, "%d %s", channel->Index() + 1, channel->ToText()); + Reply(250, "%d %s", channel->number, channel->ToText()); else Reply(501, "Channel \"%s\" not defined", Option); } else { - int i = 0; + int i = 1; cChannel *next = NULL; - while (i < Channels.Count()) { - cChannel *channel = Channels.Get(i); + while (i <= Channels.MaxNumber()) { + cChannel *channel = Channels.GetByNumber(i); if (channel) { if (strcasestr(channel->name, Option)) { if (next) - Reply(-250, "%d %s", next->Index() + 1, next->ToText()); + Reply(-250, "%d %s", next->number, next->ToText()); next = channel; } } else { - Reply(501, "Channel \"%d\" not found", i + 1); + Reply(501, "Channel \"%d\" not found", i); return; } i++; } if (next) - Reply(250, "%d %s", next->Index() + 1, next->ToText()); + Reply(250, "%d %s", next->number, next->ToText()); } } else { - for (int i = 0; i < Channels.Count(); i++) { - cChannel *channel = Channels.Get(i); + for (int i = 1; i <= Channels.MaxNumber(); i++) { + cChannel *channel = Channels.GetByNumber(i); if (channel) - Reply(i < Channels.Count() - 1 ? -250 : 250, "%d %s", channel->Index() + 1, channel->ToText()); + Reply(i < Channels.MaxNumber() ? -250 : 250, "%d %s", channel->number, channel->ToText()); else - Reply(501, "Channel \"%d\" not found", i + 1); + Reply(501, "Channel \"%d\" not found", i); } } } @@ -464,7 +464,7 @@ void cSVDRP::CmdModc(const char *Option) int n = strtol(Option, &tail, 10); if (tail && tail != Option) { tail = skipspace(tail); - cChannel *channel = Channels.Get(n - 1); + cChannel *channel = Channels.GetByNumber(n); if (channel) { cChannel c = *channel; if (!c.Parse(tail)) { @@ -473,8 +473,8 @@ void cSVDRP::CmdModc(const char *Option) } *channel = c; Channels.Save(); - isyslog(LOG_INFO, "channel %d modified", channel->Index() + 1); - Reply(250, "%d %s", channel->Index() + 1, channel->ToText()); + isyslog(LOG_INFO, "channel %d modified", channel->number); + Reply(250, "%d %s", channel->number, channel->ToText()); } else Reply(501, "Channel \"%d\" not defined", n); @@ -537,9 +537,10 @@ void cSVDRP::CmdNewc(const char *Option) cChannel *channel = new cChannel; if (channel->Parse(Option)) { Channels.Add(channel); + Channels.ReNumber(); Channels.Save(); - isyslog(LOG_INFO, "channel %d added", channel->Index() + 1); - Reply(250, "%d %s", channel->Index() + 1, channel->ToText()); + isyslog(LOG_INFO, "channel %d added", channel->number); + Reply(250, "%d %s", channel->number, channel->ToText()); } else Reply(501, "Error in channel settings"); diff --git a/timers.conf b/timers.conf index 733fb9c28..9031d35db 100644 --- a/timers.conf +++ b/timers.conf @@ -1,11 +1,12 @@ +1:15:M------:2128:2205:99:7:Neues: +1:3:-T-----:2013:2125:99:99:SevenDays 1:10:-T-----:2058:2202:99:10:Quarks: -1:26:-T-----:2203:0015:99:99:UFO: +1:26:-T-----:2255:0005:99:99:UFO: 0:3:---T---:2211:2300:99:10:Switch: 1:2:----F--:2140:2225:10:10:WWW: -1:15:-----S-:1358:1435:99:7:Neues: -1:1:-----S-:1445:1610:99:30:Hammerman: -0:11:-----S-:2158:2235:99:99:Computer: +1:11:-----S-:2158:2235:99:99:Computer: 1:2:-----S-:2213:2320:99:30:Wochenshow: 1:11:------S:2058:2120:99:10:Centauri: 1:15:MTWTF--:1828:1901:10:5:nano: -1:1:-TWTF--:0855:0945:99:99:Ellen: +1:1:-TWTF--:0955:1040:99:99:Ellen: +1:1:MTWTF--:1553:1710:99:99:Hammerman: diff --git a/tools.c b/tools.c index 0dca69ee3..e081ee793 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.13 2000/07/29 18:41:45 kls Exp $ + * $Id: tools.c 1.14 2000/09/09 12:53:34 kls Exp $ */ #define _GNU_SOURCE @@ -97,6 +97,14 @@ char *readline(FILE *f) return NULL; } +char *strn0cpy(char *dest, const char *src, size_t n) +{ + char *s = dest; + for ( ; --n && (*dest = *src) != 0; dest++, src++) ; + *dest = 0; + return s; +} + char *strreplace(char *s, char c1, char c2) { char *p = s; @@ -418,6 +426,8 @@ void cListBase::Clear(void) cListObject *cListBase::Get(int Index) { + if (Index < 0) + return NULL; cListObject *object = objects; while (object && Index-- > 0) object = object->Next(); diff --git a/tools.h b/tools.h index 563f3d065..1ef955c55 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.12 2000/07/29 10:56:00 kls Exp $ + * $Id: tools.h 1.13 2000/09/09 12:53:10 kls Exp $ */ #ifndef __TOOLS_H @@ -38,6 +38,7 @@ bool readint(int filedes, int &n); int readstring(int filedes, char *buffer, int size, bool wait = false); void purge(int filedes); char *readline(FILE *f); +char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); char *skipspace(char *s); int time_ms(void); diff --git a/vdr.c b/vdr.c index 69eceedb2..4932bf23c 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.27 2000/07/29 19:01:57 kls Exp $ + * $Id: vdr.c 1.30 2000/09/10 14:33:09 kls Exp $ */ #include @@ -44,8 +44,6 @@ #define KEYS_CONF "keys.conf" #endif -#define DIRECTCHANNELTIMEOUT 500 //ms - static int Interrupted = 0; void SignalHandler(int signum) @@ -156,6 +154,7 @@ int main(int argc, char *argv[]) // Configuration data: + Setup.Load("setup.conf"); Channels.Load("channels.conf"); Timers.Load("timers.conf"); #ifdef REMOTE_LIRC @@ -166,7 +165,9 @@ int main(int argc, char *argv[]) #endif Interface.Init(); - cChannel::SwitchTo(CurrentChannel); + cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); + + Channels.SwitchTo(CurrentChannel); // Signal handlers: @@ -177,27 +178,17 @@ int main(int argc, char *argv[]) // Main program loop: cSVDRP *SVDRP = SVDRPport ? new cSVDRP(SVDRPport) : NULL; - cMenuMain *Menu = NULL; + cOsdBase *Menu = NULL; cReplayControl *ReplayControl = NULL; - int dcTime = 0, dcNumber = 0; int LastChannel = -1; while (!Interrupted) { // Channel display: if (CurrentChannel != LastChannel) { - if (!Menu) { - cChannel *channel = Channels.Get(CurrentChannel); - if (channel) - Interface.DisplayChannel(CurrentChannel + 1, channel->name); - } + if (!Menu) + Channels.ShowChannel(CurrentChannel, LastChannel > 0); LastChannel = CurrentChannel; } - // Direct Channel Select (action): - if (dcNumber && time_ms() - dcTime > DIRECTCHANNELTIMEOUT) { - cChannel::SwitchTo(dcNumber - 1); - dcNumber = 0; - LastChannel = -1; // in case an invalid channel number was entered! - } // Timers and Recordings: if (!Menu) { cTimer *Timer = cTimer::GetMatch(); @@ -209,7 +200,7 @@ int main(int argc, char *argv[]) cRecordControls::Process(); } // User Input: - cOsdBase **Interact = Menu ? (cOsdBase **)&Menu : (cOsdBase **)&ReplayControl; + cOsdBase **Interact = Menu ? &Menu : (cOsdBase **)&ReplayControl; eKeys key = Interface.GetKey(!*Interact || !(*Interact)->NeedsFastResponse()); if (*Interact) { switch ((*Interact)->ProcessKey(key)) { @@ -228,6 +219,11 @@ int main(int argc, char *argv[]) DELETENULL(*Interact); DELETENULL(ReplayControl); break; + case osSwitchDvb: + DELETENULL(*Interact); + Interface.Info("Switching primary DVB..."); + cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); + break; case osBack: case osEnd: DELETENULL(*Interact); break; @@ -236,21 +232,30 @@ int main(int argc, char *argv[]) } else { switch (key) { - // Direct Channel Select (input): + // Direct Channel Select: case k0: case k1: case k2: case k3: case k4: case k5: case k6: case k7: case k8: case k9: - { - if (!Interface.Recording()) { - dcNumber = dcNumber * 10 + key - k0; - dcTime = time_ms(); - Interface.DisplayChannel(dcNumber); - } - } + if (!Interface.Recording()) + Menu = new cDirectChannelSelect(key); break; + // Left/Right rotates trough channel groups: + case kLeft: + case kRight: if (!Interface.Recording()) { + int SaveGroup = CurrentGroup; + if (key == kRight) + CurrentGroup = Channels.GetNextGroup(CurrentGroup) ; + else + CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup); + if (CurrentGroup < 0) + CurrentGroup = SaveGroup; + if (Channels.ShowChannel(CurrentGroup, false, true) == kOk) + Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(CurrentGroup))->number); + } + break; // Up/Down Channel Select: case kUp: case kDown: if (!Interface.Recording()) { int n = CurrentChannel + (key == kUp ? 1 : -1); - cChannel *channel = Channels.Get(n); + cChannel *channel = Channels.GetByNumber(n); if (channel) channel->Switch(); } From 7e4b4d290570aee1d24241b0e0ac10e7c8148a36 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Wed, 20 Sep 2000 18:00:00 +0200 Subject: [PATCH 011/307] Version 0.64 - NOTE: If you are using DVB driver version 0.7 you need to load the dvb.o module with option outstream=0, so your insmod statement should read 'insmod dvb.o outstream=0'. This is currently necessary because 'vdr' still works with AV_PES data. - Video files now have the 'group read' bit set. - Fixed handling errors in 'readstring()'. - Handling SIGPIPE and re-establishing handler after intercepting a signal. - The configuration files are now by default read from the video directory. This can be changed by using the new '-c' option. Make sure you copy your current '*.conf' files to your video directory ('/video' by default), or use "-c ." to get the old behaviour of loading the configuration files from the current directory. - Waiting for input is now handled by a common function, which improves response time on user actions. As a consequence the EIT data may sometimes not be displayed, but this will change later when cEIT runs as a separate thread. - The new SVDRP command 'HITK' (thanks to Guido Fiala!) can be used to 'hit' a remote control key. Establish an SVDRP connection and enter HITK without a parameter for a list of all valid key names. - The new SVDRP command 'GRAB' (thanks to Guido Fiala!) can be used to grab the current frame and save it to a file. - The new SVDRP commands 'OVL*' can be used to control video overlays (thanks to Guido Fiala!). This is mainly for use in the 'kvdr' tool (see the 'kvdr' page at http://www.s.netic.de/gfiala). - If the name of the video directory used with the '-v' option had trailing slashes, the recording file names have been damaged. Trailing slashes are now silently removed. - Fixed a buffer overflow in EIT parsing. - Added a security warning regarding SVDRP to the INSTALL file. - Fixed 'confirm' dialog. - The daemon mode (option '-d') now no longer works with REMOTE=KBD (there is no stdin in daemon mode, so KBD makes no sense - plus it sometimes crashed). --- CONTRIBUTORS | 3 + HISTORY | 37 ++++++- INSTALL | 32 ++++-- Makefile | 24 ++--- TODO | 1 - config.c | 18 +++- config.h | 5 +- dvbapi.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++-- dvbapi.h | 27 ++++- eit.c | 19 ++-- interface.c | 35 ++++--- interface.h | 8 +- menu.c | 4 +- remote.c | 60 +++++------ remote.h | 17 ++-- svdrp.c | 280 ++++++++++++++++++++++++++++++++++++++++++++------- svdrp.h | 41 +++++--- timers.conf | 12 ++- tools.c | 157 ++++++++++++++++++++++------- tools.h | 26 ++++- vdr.c | 44 ++++---- videodir.c | 4 +- 22 files changed, 890 insertions(+), 232 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9f6aa1b55..03fd4bc0f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -18,6 +18,9 @@ Heino Goldenstein Guido Fiala for implementing slow forward/back + for implementing the SVDRP command 'HITK' + for implementing image grabbing + for implementing overlay capabilities (see his 'kvdr' tool at http://www.s.netic.de/gfiala) Robert Schneider for implementing EIT support for displaying the current/next info diff --git a/HISTORY b/HISTORY index dafab3b7c..f8a10078a 100644 --- a/HISTORY +++ b/HISTORY @@ -167,4 +167,39 @@ Video Disk Recorder Revision History - When directly selecting a channel by entering the channel number, the digits entered so far together with the name of that channel are displayed on the OSD (suggested by Martin Hammerschmid). - + +2000-09-20: Version 0.64 + +- NOTE: If you are using DVB driver version 0.7 you need to load the dvb.o + module with option outstream=0, so your insmod statement should read + 'insmod dvb.o outstream=0'. This is currently necessary because 'vdr' + still works with AV_PES data. +- Video files now have the 'group read' bit set. +- Fixed handling errors in 'readstring()'. +- Handling SIGPIPE and re-establishing handler after intercepting a signal. +- The configuration files are now by default read from the video directory. + This can be changed by using the new '-c' option. Make sure you copy your + current '*.conf' files to your video directory ('/video' by default), or + use "-c ." to get the old behaviour of loading the configuration files + from the current directory. +- Waiting for input is now handled by a common function, which improves + response time on user actions. As a consequence the EIT data may sometimes + not be displayed, but this will change later when cEIT runs as a separate + thread. +- The new SVDRP command 'HITK' (thanks to Guido Fiala!) can be used to 'hit' + a remote control key. Establish an SVDRP connection and enter HITK without + a parameter for a list of all valid key names. +- The new SVDRP command 'GRAB' (thanks to Guido Fiala!) can be used to grab + the current frame and save it to a file. +- The new SVDRP commands 'OVL*' can be used to control video overlays (thanks + to Guido Fiala!). This is mainly for use in the 'kvdr' tool (see the 'kvdr' + page at http://www.s.netic.de/gfiala). +- If the name of the video directory used with the '-v' option had trailing + slashes, the recording file names have been damaged. Trailing slashes are + now silently removed. +- Fixed a buffer overflow in EIT parsing. +- Added a security warning regarding SVDRP to the INSTALL file. +- Fixed 'confirm' dialog. +- The daemon mode (option '-d') now no longer works with REMOTE=KBD (there + is no stdin in daemon mode, so KBD makes no sense - plus it sometimes + crashed). diff --git a/INSTALL b/INSTALL index 1ebffa1b3..7b953be5d 100644 --- a/INSTALL +++ b/INSTALL @@ -16,7 +16,11 @@ you will have to change the definition of DVBDIR in the Makefile. This program requires the card driver version 0.05 or higher -to work properly. +to work properly. If you are using driver version 0.7 you need +to load the dvb.o module with option outstream=0, so your insmod +statement should read 'insmod dvb.o outstream=0'. This is currently +necessary because 'vdr' works with AV_PES data and will change +once it has been modified to work directly with MPEG2. After extracting the package, change into the VDR directory and type 'make'. This should produce an executable file @@ -48,6 +52,11 @@ port ("Simple Video Disk Recorder Protocol"). By default, it listens on port 2001 (use the --port=PORT option to change this). For details about the SVDRP syntax see the source file 'svdrp.c'. +WARNING: DUE TO THE OPEN SVDRP PORT THIS PROGRAM MAY CONSTITUTE A +======= POTENTIAL SECURITY HAZARD! IF YOU ARE NOT RUNNING VDR IN + A CONTROLLED ENVIRONMENT, YOU MAY WANT TO DISABLE SVDRP + BY USING '--port=0'! + If the program shall run as a daemon, use the --daemon option. This will completely detach it from the terminal and will continue as a background process. @@ -64,7 +73,9 @@ All recordings are written into directories below "/video". Please make sure this directory exists, and that the user who runs the 'vdr' program has read and write access to that directory. If you prefer a different location for your video files, you can use -the '-v' option to change that. +the '-v' option to change that. Please make sure that the directory +name you use with '-v' is a clean and absolute path name (no '..' or +multiple slashes). Note that the file system need not be 64-bit proof, since the 'vdr' program splits video files into chunks of about 1GB. You should use @@ -102,14 +113,15 @@ Configuration files: -------------------- There are three configuration files that hold information about -channels, remote control keys and timers. These files are currrently -assumed to be located in the directory from which the 'vdr' program -was started (this will become configurable later). The configuration -files can be edited with any text editor, or will be written by the -'vdr' program if any changes are made inside the on-screen menus. -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. +channels, remote control keys and timers. By default these files are +assumed to be located in the video directory, but a different directory +can be used with the '-c' option. + +The configuration files can be edited with any text editor, or will be written +by the 'vdr' program if any changes are made inside the on-screen menus. +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. The files that come with this package contain the author's selections, so please make sure you adapt these to your personal taste. Also make sure diff --git a/Makefile b/Makefile index 2f00459b5..fef7a6f12 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.9 2000/09/10 08:55:45 kls Exp $ +# $Id: Makefile 1.11 2000/09/20 17:01:57 kls Exp $ DVBDIR = ../DVB @@ -26,21 +26,21 @@ endif all: vdr -config.o : config.c config.h dvbapi.h eit.h interface.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h videodir.h -eit.o : eit.c eit.h -interface.o: interface.c config.h dvbapi.h eit.h interface.h remote.h tools.h -menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h -osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h -vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h -recording.o: recording.c config.h dvbapi.h interface.h recording.h tools.h videodir.h -remote.o : remote.c remote.h tools.h -svdrp.o : svdrp.c svdrp.h config.h interface.h tools.h +config.o : config.c config.h dvbapi.h eit.h interface.h svdrp.h tools.h +dvbapi.o : dvbapi.c config.h dvbapi.h interface.h svdrp.h tools.h videodir.h +eit.o : eit.c eit.h tools.h +interface.o: interface.c config.h dvbapi.h eit.h interface.h remote.h svdrp.h tools.h +menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h +osd.o : osd.c config.h dvbapi.h interface.h osd.h svdrp.h tools.h +recording.o: recording.c config.h dvbapi.h interface.h recording.h svdrp.h tools.h videodir.h +remote.o : remote.c config.h dvbapi.h remote.h tools.h +svdrp.o : svdrp.c config.h dvbapi.h interface.h svdrp.h tools.h tools.o : tools.c tools.h +vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h videodir.o : videodir.c tools.h videodir.h vdr: $(OBJS) - g++ -g -O2 $(OBJS) -lncurses -o vdr + g++ -g -O2 $(OBJS) -lncurses -ljpeg -o vdr clean: -rm $(OBJS) vdr diff --git a/TODO b/TODO index 09e9a10bc..f2fb5ead2 100644 --- a/TODO +++ b/TODO @@ -7,5 +7,4 @@ TODO list for the Video Disk Recorder project scenes in order to archive them (or, reversely, cut out commercial breaks). * Implement channel scanning. -* Better support for encrypted channels. * Implement remaining commands in SVDRP. diff --git a/config.c b/config.c index 0a965ee54..e161efd76 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.22 2000/09/10 15:07:15 kls Exp $ + * $Id: config.c 1.23 2000/09/17 09:11:59 kls Exp $ */ #include "config.h" @@ -155,14 +155,22 @@ eKeys cKeys::Get(unsigned int Code) return kNone; } -unsigned int cKeys::Encode(const char *Command) +eKeys cKeys::Translate(const char *Command) { - if (Command != NULL) { + if (Command) { const tKey *k = keys; - while ((k->type != kNone) && strcmp(k->name, Command) != 0) + while ((k->type != kNone) && strcasecmp(k->name, Command) != 0) k++; - return k->code; + return k->type; } + return kNone; +} + +unsigned int cKeys::Encode(const char *Command) +{ + eKeys k = Translate(Command); + if (k != kNone) + return keys[k].code; return 0; } diff --git a/config.h b/config.h index 30dd9bac2..418fa6303 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.19 2000/09/10 15:05:08 kls Exp $ + * $Id: config.h 1.21 2000/09/17 09:08:13 kls Exp $ */ #ifndef __CONFIG_H @@ -17,7 +17,7 @@ #include "dvbapi.h" #include "tools.h" -#define VDRVERSION "0.63" +#define VDRVERSION "0.64" #define MaxBuffer 10000 @@ -55,6 +55,7 @@ class cKeys { void SetDummyValues(void); bool Load(const char *FileName = NULL); bool Save(void); + eKeys Translate(const char *Command); unsigned int Encode(const char *Command); eKeys Get(unsigned int Code); void Set(eKeys Key, unsigned int Code); diff --git a/dvbapi.c b/dvbapi.c index 9f9cbab42..1468de60e 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,14 +4,18 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.24 2000/09/10 10:25:09 kls Exp $ + * $Id: dvbapi.c 1.27 2000/09/17 12:45:55 kls Exp $ */ #include "dvbapi.h" #include #include +extern "C" { +#include +} #include #include +#include #include #include #include @@ -139,7 +143,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) LOG_ERROR; } if (Record) { - if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) >= 0) { + if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP)) >= 0) { if (delta) { esyslog(LOG_ERR, "ERROR: padding index file with %d '0' bytes", delta); while (delta--) @@ -297,7 +301,7 @@ int cIndexFile::Get(uchar FileNumber, int FileOffset) bool cIndexFile::StoreResume(int Index) { if (fileName) { - int resumeFile = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + int resumeFile = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); if (resumeFile >= 0) { if (write(resumeFile, &Index, sizeof(Index)) != sizeof(Index)) LOG_ERROR_STR(fileName); @@ -315,8 +319,8 @@ char *cIndexFile::Str(int Index, bool WithFrame) static char buffer[16]; int f = (Index % FRAMESPERSEC) + 1; int s = (Index / FRAMESPERSEC); - int m = s / 60 % 60; - int h = s / 3600; + int m = s / 60 % 60; + int h = s / 3600; s %= 60; snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f); return buffer; @@ -511,7 +515,7 @@ class cFileBuffer : public cRingBuffer { char *fileName, *pFileNumber; bool stop; int GetAvPesLength(void) - { + { if (Byte(0) == 'A' && Byte(1) == 'V' && Byte(4) == 'U') return (Byte(6) << 8) + Byte(7) + AV_PES_HEADER_LEN; return 0; @@ -751,7 +755,7 @@ int cRecordBuffer::Write(int Max) if (n) { if (stop && pictureType == I_FRAME) { ok = false; - return -1; // finish the recording before the next 'I' frame + return -1; // finish the recording before the next 'I' frame } if (NextFile()) { if (index && pictureType != NO_PICTURE) @@ -801,7 +805,7 @@ class cReplayBuffer : public cFileBuffer { void Close(void); public: cReplayBuffer(int *OutFile, const char *FileName); - virtual ~cReplayBuffer(); + virtual ~cReplayBuffer(); virtual int Read(int Max = -1); virtual int Write(int Max = -1); void SetMode(eReplayMode Mode); @@ -1065,9 +1069,14 @@ cDvbApi::cDvbApi(const char *FileName) if (videoDev < 0) LOG_ERROR; cols = rows = 0; + + ovlGeoSet = ovlStat = ovlFbSet = false; + ovlBrightness = ovlColour = ovlHue = ovlContrast = 32768; + ovlClipCount = 0; + #if defined(DEBUG_OSD) || defined(REMOTE_KBD) initscr(); - keypad(stdscr, TRUE); + keypad(stdscr, true); nonl(); cbreak(); noecho(); @@ -1076,7 +1085,7 @@ cDvbApi::cDvbApi(const char *FileName) #if defined(DEBUG_OSD) memset(&colorPairs, 0, sizeof(colorPairs)); start_color(); - leaveok(stdscr, TRUE); + leaveok(stdscr, true); window = NULL; #endif lastProgress = lastTotal = -1; @@ -1089,6 +1098,7 @@ cDvbApi::~cDvbApi() Close(); Stop(); StopRecord(); + OvlO(false); //Overlay off! close(videoDev); } #if defined(DEBUG_OSD) || defined(REMOTE_KBD) @@ -1187,6 +1197,242 @@ void cDvbApi::Cleanup(void) PrimaryDvbApi = NULL; } +bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) +{ + int result = 0; + // just do this once? + struct video_mbuf mbuf; + result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf); + int msize = mbuf.size; + // gf: this needs to be a protected member of cDvbApi! //XXX kls: WHY??? + unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); + if (!mem || mem == (unsigned char *)-1) + return false; + // set up the size and RGB + struct video_capability vc; + result |= ioctl(videoDev, VIDIOCGCAP, &vc); + struct video_mmap vm; + vm.frame = 0; + if ((SizeX > 0) && (SizeX <= vc.maxwidth) && + (SizeY > 0) && (SizeY <= vc.maxheight)) { + vm.width = SizeX; + vm.height = SizeY; + } + else { + vm.width = vc.maxwidth; + vm.height = vc.maxheight; + } + vm.format = VIDEO_PALETTE_RGB24; + // this needs to be done every time: + result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm); + result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame); + // make RGB out of BGR: + int memsize = vm.width * vm.height; + unsigned char *mem1 = mem; + for (int i = 0; i < memsize; i++) { + unsigned char tmp = mem1[2]; + mem1[2] = mem1[0]; + mem1[0] = tmp; + mem1 += 3; + } + + if (Quality < 0) + Quality = 255; //XXX is this 'best'??? + + isyslog(LOG_INFO, "grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height); + FILE *f = fopen(FileName, "wb"); + if (f) { + if (Jpeg) { + // write JPEG file: + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, f); + cinfo.image_width = vm.width; + cinfo.image_height = vm.height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, Quality, true); + jpeg_start_compress(&cinfo, true); + + int rs = vm.width * 3; + JSAMPROW rp[vm.height]; + for (int k = 0; k < vm.height; k++) + rp[k] = &mem[rs * k]; + jpeg_write_scanlines(&cinfo, rp, vm.height); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + } + else { + // write PNM file: + if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 || + fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) { + LOG_ERROR_STR(FileName); + result |= 1; + } + } + fclose(f); + } + else { + LOG_ERROR_STR(FileName); + result |= 1; + } + + if (ovlStat && ovlGeoSet) { + // switch the Overlay on again (gf: why have i to do anything again?) + OvlG(ovlSizeX, ovlSizeY, ovlPosX, ovlPosY); + } + if (ovlFbSet) + OvlP(ovlBrightness, ovlColour, ovlHue, ovlContrast); + + munmap(mem, msize); + return result == 0; +} + +bool cDvbApi::OvlF(int SizeX, int SizeY, int FbAddr, int Bpp, int Palette) +{ + int result = 0; + // get the actual X-Server settings??? + // plausibility-check problem: can't be verified w/o X-server!!! + if (SizeX <= 0 || SizeY <= 0 || FbAddr == 0 || Bpp / 8 > 4 || + Bpp / 8 <= 0 || Palette <= 0 || Palette > 13 || ovlClipCount < 0 || + SizeX > 4096 || SizeY > 4096) { + ovlFbSet = ovlGeoSet = false; + OvlO(false); + return false; + } + else { + dsyslog(LOG_INFO, "OvlF: %d %d %x %d %d", SizeX, SizeY, FbAddr, Bpp, Palette); + // this is the problematic part! + struct video_buffer vb; + result |= ioctl(videoDev, VIDIOCGFBUF, &vb); + vb.base = (void*)FbAddr; + vb.depth = Bpp; + vb.height = SizeY; + vb.width = SizeX; + vb.bytesperline = ((vb.depth + 1) / 8) * vb.width; + //now the real thing: setting the framebuffer + result |= ioctl(videoDev, VIDIOCSFBUF, &vb); + if (result) { + ovlFbSet = ovlGeoSet = false; + ovlClipCount = 0; + OvlO(false); + return false; + } + else { + ovlFbSizeX = SizeX; + ovlFbSizeY = SizeY; + ovlBpp = Bpp; + ovlPalette = Palette; + ovlFbSet = true; + return true; + } + } +} + +bool cDvbApi::OvlG(int SizeX, int SizeY, int PosX, int PosY) +{ + int result = 0; + // get the actual X-Server settings??? + struct video_capability vc; + result |= ioctl(videoDev, VIDIOCGCAP, &vc); + if (!ovlFbSet) + return false; + if (SizeX < vc.minwidth || SizeY < vc.minheight || + SizeX > vc.maxwidth || SizeY>vc.maxheight +// || PosX > FbSizeX || PosY > FbSizeY +// PosX < -SizeX || PosY < -SizeY || + ) { + ovlGeoSet = false; + OvlO(false); + return false; + } + else { + struct video_window vw; + result |= ioctl(videoDev, VIDIOCGWIN, &vw); + vw.x = PosX; + vw.y = PosY; + vw.width = SizeX; + vw.height = SizeY; + vw.chromakey = ovlPalette; + vw.flags = VIDEO_WINDOW_CHROMAKEY; // VIDEO_WINDOW_INTERLACE; //VIDEO_CLIP_BITMAP; + vw.clips = ovlClipRects; + vw.clipcount = ovlClipCount; + result |= ioctl(videoDev, VIDIOCSWIN, &vw); + if (result) { + ovlGeoSet = false; + ovlClipCount = 0; + return false; + } + else { + ovlSizeX = SizeX; + ovlSizeY = SizeY; + ovlPosX = PosX; + ovlPosY = PosY; + ovlGeoSet = true; + ovlStat = true; + return true; + } + } +} + +bool cDvbApi::OvlC(int ClipCount, CRect *cr) +{ + if (ovlGeoSet && ovlFbSet) { + for (int i = 0; i < ClipCount; i++) { + ovlClipRects[i].x = cr[i].x; + ovlClipRects[i].y = cr[i].y; + ovlClipRects[i].width = cr[i].width; + ovlClipRects[i].height = cr[i].height; + ovlClipRects[i].next = &(ovlClipRects[i + 1]); + } + ovlClipCount = ClipCount; + //use it: + return OvlG(ovlSizeX, ovlSizeY, ovlPosX, ovlPosY); + } + return false; +} + +bool cDvbApi::OvlP(__u16 Brightness, __u16 Colour, __u16 Hue, __u16 Contrast) +{ + int result = 0; + ovlBrightness = Brightness; + ovlColour = Colour; + ovlHue = Hue; + ovlContrast = Contrast; + struct video_picture vp; + if (!ovlFbSet) + return false; + result |= ioctl(videoDev, VIDIOCGPICT, &vp); + vp.brightness = Brightness; + vp.colour = Colour; + vp.hue = Hue; + vp.contrast = Contrast; + vp.depth = ovlBpp; + vp.palette = ovlPalette; // gf: is this always ok? VIDEO_PALETTE_RGB565; + result |= ioctl(videoDev, VIDIOCSPICT, &vp); + return result == 0; +} + +bool cDvbApi::OvlO(bool Value) +{ + int result = 0; + if (!ovlGeoSet && Value) + return false; + int one = 1; + int zero = 0; + result |= ioctl(videoDev, VIDIOCCAPTURE, Value ? &one : &zero); + ovlStat = Value; + if (result) { + ovlStat = false; + return false; + } + return true; +} + #ifdef DEBUG_OSD void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg) { @@ -1233,7 +1479,7 @@ void cDvbApi::Open(int w, int h) rows = h; #ifdef DEBUG_OSD window = subwin(stdscr, h, w, d, 0); - syncok(window, TRUE); + syncok(window, true); #define B2C(b) (((b) * 1000) / 255) #define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b)) #else diff --git a/dvbapi.h b/dvbapi.h index a43e7075c..08ba4bfc6 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.14 2000/09/10 10:03:29 kls Exp $ + * $Id: dvbapi.h 1.16 2000/09/17 12:15:05 kls Exp $ */ #ifndef __DVBAPI_H @@ -21,6 +21,12 @@ typedef unsigned char __u8; #include #include +// Overlay facilities +#define MAXCLIPRECTS 100 +typedef struct CRect { + signed short x, y, width, height; + }; + #define MenuLines 15 #define MenuColumns 40 @@ -70,6 +76,25 @@ class cDvbApi { // Closes down all DVB devices. // Must be called at the end of the program. + // Image Grab facilities + + bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); + + // Overlay facilities + +private: + bool ovlStat, ovlGeoSet, ovlFbSet; + int ovlSizeX, ovlSizeY, ovlPosX, ovlPosY, ovlBpp, ovlPalette, ovlClips, ovlClipCount; + int ovlFbSizeX, ovlFbSizeY; + __u16 ovlBrightness, ovlColour, ovlHue, ovlContrast; + struct video_clip ovlClipRects[MAXCLIPRECTS]; +public: + bool OvlF(int SizeX, int SizeY, int FbAddr, int Bpp, int Palette); + bool OvlG(int SizeX, int SizeY, int PosX, int PosY); + bool OvlC(int ClipCount, CRect *Cr); + bool OvlP(__u16 Brightness, __u16 Color, __u16 Hue, __u16 Contrast); + bool OvlO(bool Value); + // On Screen Display facilities private: diff --git a/eit.c b/eit.c index c4c12003c..d62c90252 100644 --- a/eit.c +++ b/eit.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.1 2000/09/03 10:22:25 kls Exp $ + * $Id: eit.c 1.3 2000/09/17 15:23:05 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include "tools.h" @@ -253,15 +252,12 @@ int cEIT::GetSection(unsigned char *buf, ushort PID, unsigned char sec) int seclen=0; unsigned short handle, pid; unsigned char section, sectionnum=0xff, maxsec=0; - struct pollfd pfd; if ((handle = SetBitFilter(PID, (sec<<8)|0x00ff, SECTION_CONTINUOS))==0xffff) return -1; seclen=0; - pfd.fd=fsvbi; - pfd.events=POLLIN; - if (poll(&pfd, 1, 20000)==0) + if (!cFile::AnyFileReady(fsvbi, 20000)) { //cerr << "Timeout\n"; return -1; @@ -312,13 +308,12 @@ char * cEIT::mjd2string(unsigned short mjd) /** */ int cEIT::GetEIT() { - unsigned char buf[1024]; + unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) eit_t *eit; struct eit_loop_struct1 *eitloop; struct eit_short_event_descriptor_struct *eitevt; - int seclen; + unsigned int seclen; unsigned short handle, pid; - struct pollfd pfd; eit_event * pevt = (eit_event *)0; time_t tstart; @@ -344,9 +339,7 @@ int cEIT::GetEIT() tstart = time(NULL); while ((!evtRunning.bIsValid || !evtNext.bIsValid) && nReceivedEITs < 20 && difftime(time(NULL), tstart) < 4) { - pfd.fd=fsvbi; - pfd.events=POLLIN; - if (poll(&pfd, 1, 5000)==0) + if (!cFile::AnyFileReady(fsvbi, 5000)) { //cerr << "Timeout\n"; CloseFilter(handle); @@ -357,6 +350,8 @@ int cEIT::GetEIT() seclen=(buf[6]<<8)|buf[7]; pid=(buf[4]<<8)|buf[5]; + if (seclen >= sizeof(buf)) + seclen = sizeof(buf) - 1; read(fsvbi, buf, seclen); if (seclen < (int)(sizeof(eit_t) diff --git a/interface.c b/interface.c index 5633f864e..3d01238b8 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.15 2000/09/10 16:04:14 kls Exp $ + * $Id: interface.c 1.19 2000/09/19 17:41:23 kls Exp $ */ #include "interface.h" @@ -29,11 +29,19 @@ cInterface::cInterface(void) open = 0; cols[0] = 0; keyFromWait = kNone; + SVDRP = NULL; } -void cInterface::Init(void) +void cInterface::Init(int SVDRPport) { RcIo.SetCode(Keys.code, Keys.address); + if (SVDRPport) + SVDRP = new cSVDRP(SVDRPport); +} + +void cInterface::Cleanup(void) +{ + delete SVDRP; } void cInterface::Open(int NumCols, int NumLines) @@ -52,10 +60,6 @@ void cInterface::Close(void) unsigned int cInterface::GetCh(bool Wait) { -#ifdef DEBUG_OSD - timeout(0); - getch(); // just to make 'ncurses' display the window: -#endif if (RcIo.InputAvailable(Wait)) { unsigned int Command; return RcIo.GetCommand(&Command, NULL) ? Command : 0; @@ -65,21 +69,24 @@ unsigned int cInterface::GetCh(bool Wait) eKeys cInterface::GetKey(bool Wait) { + if (SVDRP) + SVDRP->Process(); eKeys Key = keyFromWait != kNone ? keyFromWait : Keys.Get(GetCh(Wait)); keyFromWait = kNone; return Key; } +void cInterface::PutKey(eKeys Key) +{ + keyFromWait = Key; +} + eKeys cInterface::Wait(int Seconds, bool KeepChar) { - int t0 = time_ms() + Seconds * 1000; eKeys Key = kNone; - - while (time_ms() < t0) { - Key = GetKey(); - if (Key != kNone) - break; - } + RcIo.Flush(500); + if (cFile::AnyFileReady(-1, Seconds * 1000)) + Key = GetKey(); if (KeepChar) keyFromWait = Key; return Key; @@ -227,7 +234,7 @@ void cInterface::QueryKeys(void) Keys.address = Address; WriteText(1, 5, "RC code detected!"); WriteText(1, 6, "Do not press any key..."); - RcIo.Flush(3); + RcIo.Flush(3000); ClearEol(0, 5); ClearEol(0, 6); break; diff --git a/interface.h b/interface.h index 4503dc65c..8f7f1b8d7 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.11 2000/09/10 10:35:46 kls Exp $ + * $Id: interface.h 1.13 2000/09/18 22:29:31 kls Exp $ */ #ifndef __INTERFACE_H @@ -12,6 +12,7 @@ #include "config.h" #include "dvbapi.h" +#include "svdrp.h" class cInterface { public: @@ -20,16 +21,19 @@ class cInterface { int open; int cols[MaxCols]; eKeys keyFromWait; + cSVDRP *SVDRP; unsigned int GetCh(bool Wait = true); void QueryKeys(void); void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor); eKeys Wait(int Seconds = 1, bool KeepChar = false); public: cInterface(void); - void Init(void); + void Init(int SVDRPport = 0); + void Cleanup(void); void Open(int NumCols = MenuColumns, int NumLines = MenuLines); void Close(void); eKeys GetKey(bool Wait = true); + void PutKey(eKeys Key); void Clear(void); void ClearEol(int x, int y, eDvbColor Color = clrBackground); void SetCols(int *c); diff --git a/menu.c b/menu.c index ad803cf42..114ea7ef7 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.26 2000/09/10 15:06:15 kls Exp $ + * $Id: menu.c 1.27 2000/09/11 21:13:46 kls Exp $ */ #include "menu.h" @@ -1190,7 +1190,7 @@ eOSState cDirectChannelSelect::ProcessKey(eKeys Key) if (number >= 0) { number = number * 10 + Key - k0; cChannel *channel = Channels.GetByNumber(number); - char *Name = channel ? channel->name : "*** Invalid Channel ***"; + const char *Name = channel ? channel->name : "*** Invalid Channel ***"; int BufSize = MenuColumns + 1; char buffer[BufSize]; snprintf(buffer, BufSize, "%d %s", number, Name); diff --git a/remote.c b/remote.c index 0476962cc..46565a804 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.11 2000/07/29 16:23:47 kls Exp $ + * $Id: remote.c 1.13 2000/09/19 17:40:52 kls Exp $ */ #include "remote.h" @@ -49,33 +49,29 @@ cRcIoBase::~cRcIoBase() cRcIoKBD::cRcIoKBD(void) { + f.Open(0); // stdin } cRcIoKBD::~cRcIoKBD() { } -void cRcIoKBD::Flush(int WaitSeconds) +void cRcIoKBD::Flush(int WaitMs) { - time_t t0 = time(NULL); + int t0 = time_ms(); timeout(10); for (;;) { while (getch() > 0) - t0 = time(NULL); - if (time(NULL) - t0 >= WaitSeconds) + t0 = time_ms(); + if (time_ms() - t0 >= WaitMs) break; } } bool cRcIoKBD::InputAvailable(bool Wait) { - timeout(Wait ? 1000 : 10); - int ch = getch(); - if (ch == ERR) - return false; - ungetch(ch); - return true; + return f.Ready(Wait); } bool cRcIoKBD::GetCommand(unsigned int *Command, unsigned short *) @@ -98,7 +94,7 @@ cRcIoRCU::cRcIoRCU(char *DeviceName) code = 0; address = 0xFFFF; lastNumber = 0; - if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) { + if (f.Open(DeviceName, O_RDWR | O_NONBLOCK)) { struct termios t; if (tcgetattr(f, &t) == 0) { cfsetspeed(&t, B9600); @@ -107,17 +103,14 @@ cRcIoRCU::cRcIoRCU(char *DeviceName) return; } LOG_ERROR_STR(DeviceName); - close(f); + f.Close(); } else LOG_ERROR_STR(DeviceName); - f = -1; } cRcIoRCU::~cRcIoRCU() { - if (f >= 0) - close(f); } int cRcIoRCU::ReceiveByte(bool Wait) @@ -135,7 +128,7 @@ int cRcIoRCU::ReceiveByte(bool Wait) bool cRcIoRCU::SendByteHandshake(unsigned char c) { - if (f >= 0) { + if (f.IsOpen()) { int w = write(f, &c, 1); if (w == 1) { for (int reply = ReceiveByte(); reply >= 0;) { @@ -179,21 +172,21 @@ bool cRcIoRCU::SetMode(unsigned char Mode) return SendCommand(mode); } -void cRcIoRCU::Flush(int WaitSeconds) +void cRcIoRCU::Flush(int WaitMs) { - time_t t0 = time(NULL); + int t0 = time_ms(); for (;;) { while (ReceiveByte(false) >= 0) - t0 = time(NULL); - if (time(NULL) - t0 >= WaitSeconds) + t0 = time_ms(); + if (time_ms() - t0 >= WaitMs) break; } } bool cRcIoRCU::InputAvailable(bool Wait) { - return DataAvailable(f, Wait); + return f.Ready(Wait); } bool cRcIoRCU::GetCommand(unsigned int *Command, unsigned short *Address) @@ -349,22 +342,21 @@ cRcIoLIRC::cRcIoLIRC(char *DeviceName) struct sockaddr_un addr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, DeviceName); - f = socket(AF_UNIX, SOCK_STREAM, 0); - if (f >= 0) { - if (connect(f, (struct sockaddr *)&addr, sizeof(addr)) >= 0) + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock >= 0) { + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) >= 0) { + f.Open(sock); return; + } LOG_ERROR_STR(DeviceName); - close(f); + close(sock); } else LOG_ERROR_STR(DeviceName); - f = -1; } cRcIoLIRC::~cRcIoLIRC() { - if (f >= 0) - close(f); } const char *cRcIoLIRC::ReceiveString(void) @@ -389,24 +381,24 @@ const char *cRcIoLIRC::ReceiveString(void) return NULL; } -void cRcIoLIRC::Flush(int WaitSeconds) +void cRcIoLIRC::Flush(int WaitMs) { char buf[LIRC_BUFFER_SIZE]; - time_t t0 = time(NULL); + int t0 = time_ms(); for (;;) { while (InputAvailable(false)) { read(f, buf, sizeof(buf)); - t0 = time(NULL); + t0 = time_ms(); } - if (time(NULL) - t0 >= WaitSeconds) + if (time_ms() - t0 >= WaitMs) break; } } bool cRcIoLIRC::InputAvailable(bool Wait) { - return DataAvailable(f, Wait); + return f.Ready(Wait); } bool cRcIoLIRC::GetCommand(unsigned int *Command, unsigned short *) diff --git a/remote.h b/remote.h index 7b94ac782..03f915550 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.7 2000/07/15 16:32:43 kls Exp $ + * $Id: remote.h 1.9 2000/09/19 17:39:36 kls Exp $ */ #ifndef __REMOTE_H @@ -12,6 +12,7 @@ #include #include +#include "tools.h" class cRcIoBase { protected: @@ -28,7 +29,7 @@ class cRcIoBase { virtual void SetPoints(unsigned char Dp, bool On) {} virtual bool String(char *s) { return true; } virtual bool DetectCode(unsigned char *Code, unsigned short *Address) { return true; } - virtual void Flush(int WaitSeconds = 0) {} + virtual void Flush(int WaitMs = 0) {} virtual bool InputAvailable(bool Wait = false) = 0; virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL) = 0; }; @@ -36,10 +37,12 @@ class cRcIoBase { #if defined REMOTE_KBD class cRcIoKBD : public cRcIoBase { +private: + cFile f; public: cRcIoKBD(void); virtual ~cRcIoKBD(); - virtual void Flush(int WaitSeconds = 0); + virtual void Flush(int WaitMs = 0); virtual bool InputAvailable(bool Wait = false); virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); }; @@ -48,7 +51,7 @@ class cRcIoKBD : public cRcIoBase { class cRcIoRCU : public cRcIoBase { private: - int f; + cFile f; unsigned char dp, code, mode; unsigned short address; int lastNumber; @@ -66,7 +69,7 @@ class cRcIoRCU : public cRcIoBase { virtual void SetPoints(unsigned char Dp, bool On); virtual bool String(char *s); virtual bool DetectCode(unsigned char *Code, unsigned short *Address); - virtual void Flush(int WaitSeconds = 0); + virtual void Flush(int WaitMs = 0); virtual bool InputAvailable(bool Wait = false); virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); }; @@ -76,13 +79,13 @@ class cRcIoRCU : public cRcIoBase { class cRcIoLIRC : public cRcIoBase { private: enum { LIRC_KEY_BUF = 8, LIRC_BUFFER_SIZE = 128 }; - int f; + cFile f; char keyName[LIRC_KEY_BUF]; const char *ReceiveString(void); public: cRcIoLIRC(char *DeviceName); virtual ~cRcIoLIRC(); - virtual void Flush(int WaitSeconds = 0); + virtual void Flush(int WaitMs = 0); virtual bool InputAvailable(bool Wait = false); virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); }; diff --git a/svdrp.c b/svdrp.c index 2af3ee537..c9ea7c387 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.6 2000/09/09 10:51:21 kls Exp $ + * $Id: svdrp.c 1.10 2000/09/17 13:39:37 kls Exp $ */ #define _GNU_SOURCE @@ -120,8 +120,15 @@ const char *HelpPages[] = { " Delete channel.", "DELT \n" " Delete timer.", + "GRAB [ jpeg | pnm [ [ ] ] ]\n" + " Grab the current frame and save it to the given file. Images can\n" + " be stored as JPEG (default) or PNM, at the given quality (default\n" + " is 'maximum', only applies to JPEG) and size (default is full screen).", "HELP [ ]\n" " The HELP command gives help info.", + "HITK [ ]\n" + " Hit the given remote control key. Without option a list of all\n" + " valid key names is given.", "LSTC [ | ]\n" " List channels. Without option, all channels are listed. Otherwise\n" " only the given channel is listed. If a name is given, all channels\n" @@ -147,6 +154,16 @@ const char *HelpPages[] = { " Create a new timer. Settings must be in the same format as returned\n" " by the LSTT command. It is an error if a timer with the same channel,\n" " day, start and stop time already exists.", + "OVLF \n" + " Set the size, address depth and palette of the overlay.", + "OVLG \n" + " Set the size and position of the overlay.", + "OVLC \n" + " Set the overlay clipping rectangles.", + "OVLP \n" + " Set the picture parameters for the overlay.", + "OVLO 0 | 1\n" + " Switch the overlay on or off.", "UPDT \n" " Updates a timer. Settings must be in the same format as returned\n" " by the LSTT command. If a timer with the same channel, day, start\n" @@ -206,7 +223,6 @@ const char *GetHelpPage(const char *Cmd) cSVDRP::cSVDRP(int Port) :socket(Port) { - filedes = -1; isyslog(LOG_INFO, "SVDRP listening on port %d", Port); } @@ -217,14 +233,13 @@ cSVDRP::~cSVDRP() void cSVDRP::Close(void) { - if (filedes >= 0) { + if (file.IsOpen()) { //TODO how can we get the *full* hostname? char buffer[MAXCMDBUFFER]; gethostname(buffer, sizeof(buffer)); Reply(221, "%s closing connection", buffer); isyslog(LOG_INFO, "closing connection"); //TODO store IP#??? - close(filedes); - filedes = -1; + file.Close(); } } @@ -232,11 +247,14 @@ bool cSVDRP::Send(const char *s, int length) { if (length < 0) length = strlen(s); - int wbytes = write(filedes, s, length); + int wbytes = write(file, s, length); if (wbytes == length) return true; - if (wbytes < 0) + if (wbytes < 0) { LOG_ERROR; + file.Close(); + cDvbApi::PrimaryDvbApi->OvlO(false); + } else //XXX while...??? esyslog(LOG_ERR, "Wrote %d bytes to client while expecting %d\n", wbytes, length); return false; @@ -244,7 +262,7 @@ bool cSVDRP::Send(const char *s, int length) void cSVDRP::Reply(int Code, const char *fmt, ...) { - if (filedes >= 0) { + if (file.IsOpen()) { if (Code != 0) { va_list ap; va_start(ap, fmt); @@ -274,7 +292,7 @@ void cSVDRP::Reply(int Code, const char *fmt, ...) } } -void cSVDRP::CmdChan(const char *Option) +void cSVDRP::CmdCHAN(const char *Option) { if (*Option) { int n = -1; @@ -331,13 +349,13 @@ void cSVDRP::CmdChan(const char *Option) Reply(550, "Unable to find channel \"%d\"", CurrentChannel); } -void cSVDRP::CmdDelc(const char *Option) +void cSVDRP::CmdDELC(const char *Option) { //TODO combine this with menu action (timers must be updated) Reply(502, "DELC not yet implemented"); } -void cSVDRP::CmdDelt(const char *Option) +void cSVDRP::CmdDELT(const char *Option) { if (*Option) { if (isnumber(Option)) { @@ -362,7 +380,68 @@ void cSVDRP::CmdDelt(const char *Option) Reply(501, "Missing timer number"); } -void cSVDRP::CmdHelp(const char *Option) +void cSVDRP::CmdGRAB(const char *Option) +{ + char *FileName = NULL; + bool Jpeg = true; + int Quality = -1, SizeX = -1, SizeY = -1; + if (*Option) { + char buf[strlen(Option) + 1]; + char *p = strcpy(buf, Option); + const char *delim = " \t"; + FileName = strtok(p, delim); + if ((p = strtok(NULL, delim)) != NULL) { + if (strcasecmp(p, "JPEG") == 0) + Jpeg = true; + else if (strcasecmp(p, "PNM") == 0) + Jpeg = false; + else { + Reply(501, "Unknown image type \"%s\"", p); + return; + } + } + if ((p = strtok(NULL, delim)) != NULL) { + if (isnumber(p)) + Quality = atoi(p); + else { + Reply(501, "Illegal quality \"%s\"", p); + return; + } + } + if ((p = strtok(NULL, delim)) != NULL) { + if (isnumber(p)) + SizeX = atoi(p); + else { + Reply(501, "Illegal sizex \"%s\"", p); + return; + } + if ((p = strtok(NULL, delim)) != NULL) { + if (isnumber(p)) + SizeY = atoi(p); + else { + Reply(501, "Illegal sizey \"%s\"", p); + return; + } + } + else { + Reply(501, "Missing sizey"); + return; + } + } + if ((p = strtok(NULL, delim)) != NULL) { + Reply(501, "Unexpected parameter \"%s\"", p); + return; + } + if (cDvbApi::PrimaryDvbApi->GrabImage(FileName, Jpeg, Quality, SizeX, SizeY)) + Reply(250, "Grabbed image %s", Option); + else + Reply(451, "Grab image failed"); + } + else + Reply(501, "Missing filename"); +} + +void cSVDRP::CmdHELP(const char *Option) { if (*Option) { const char *hp = GetHelpPage(Option); @@ -390,7 +469,27 @@ void cSVDRP::CmdHelp(const char *Option) Reply(214, "End of HELP info"); } -void cSVDRP::CmdLstc(const char *Option) +void cSVDRP::CmdHITK(const char *Option) +{ + if (*Option) { + eKeys k = Keys.Translate(Option); + if (k != kNone) { + Interface.PutKey(k); + Reply(250, "Key \"%s\" accepted", Option); + } + else + Reply(504, "Unknown key: \"%s\"", Option); + } + else { + Reply(-214, "Valid names for the HITK command:"); + for (int i = 0; i < kNone; i++) { + Reply(-214, " %s", Keys.keys[i].name); + } + Reply(214, "End of key list"); + } +} + +void cSVDRP::CmdLSTC(const char *Option) { if (*Option) { if (isnumber(Option)) { @@ -433,7 +532,7 @@ void cSVDRP::CmdLstc(const char *Option) } } -void cSVDRP::CmdLstt(const char *Option) +void cSVDRP::CmdLSTT(const char *Option) { if (*Option) { if (isnumber(Option)) { @@ -457,7 +556,7 @@ void cSVDRP::CmdLstt(const char *Option) } } -void cSVDRP::CmdModc(const char *Option) +void cSVDRP::CmdMODC(const char *Option) { if (*Option) { char *tail; @@ -486,7 +585,7 @@ void cSVDRP::CmdModc(const char *Option) Reply(501, "Missing channel settings"); } -void cSVDRP::CmdModt(const char *Option) +void cSVDRP::CmdMODT(const char *Option) { if (*Option) { char *tail; @@ -519,19 +618,19 @@ void cSVDRP::CmdModt(const char *Option) Reply(501, "Missing timer settings"); } -void cSVDRP::CmdMovc(const char *Option) +void cSVDRP::CmdMOVC(const char *Option) { //TODO combine this with menu action (timers must be updated) Reply(502, "MOVC not yet implemented"); } -void cSVDRP::CmdMovt(const char *Option) +void cSVDRP::CmdMOVT(const char *Option) { //TODO combine this with menu action Reply(502, "MOVT not yet implemented"); } -void cSVDRP::CmdNewc(const char *Option) +void cSVDRP::CmdNEWC(const char *Option) { if (*Option) { cChannel *channel = new cChannel; @@ -549,7 +648,7 @@ void cSVDRP::CmdNewc(const char *Option) Reply(501, "Missing channel settings"); } -void cSVDRP::CmdNewt(const char *Option) +void cSVDRP::CmdNEWT(const char *Option) { if (*Option) { cTimer *timer = new cTimer; @@ -573,7 +672,107 @@ void cSVDRP::CmdNewt(const char *Option) Reply(501, "Missing timer settings"); } -void cSVDRP::CmdUpdt(const char *Option) +void cSVDRP::CmdOVLF(const char *Option) +{ + if (*Option) { + int SizeX = 0, SizeY = 0, Bpp = 0, Palette = 0, FbAddr = 0; + if (5 == sscanf(Option, "%d %d %x %d %d", &SizeX, &SizeY, &FbAddr, &Bpp, &Palette)) { + //somehow_set_overlay_geometry; + if (cDvbApi::PrimaryDvbApi->OvlF(SizeX, SizeY, FbAddr, Bpp, Palette)) + Reply(250, "Overlay framebuffer set"); + else + Reply(451, "Illegal overlay framebuffer settings"); + } + else + Reply(501, "Could not parse overlay framebuffer settings"); + } + else + Reply(501, "Missing overlay framebuffer settings"); +} + +void cSVDRP::CmdOVLG(const char *Option) +{ + if (*Option) { + int SizeX = 0, SizeY = 0, PosX = 0, PosY = 0; + if (4 == sscanf(Option, "%d %d %d %d", &SizeX, &SizeY, &PosX, &PosY)) { + //somehow_set_overlay_geometry; + if (cDvbApi::PrimaryDvbApi->OvlG(SizeX, SizeY, PosX, PosY)) + Reply(250, "Overlay geometry set"); + else + Reply(451, "Illegal overlay geometry settings"); + } + else + Reply(501, "Could not parse overlay geometry settings"); + } + else + Reply(501, "Missing overlay geometry settings"); +} + +void cSVDRP::CmdOVLC(const char *Option) +{ + if (*Option) { + int ClipCount = 0; + unsigned char s[2 * MAXCLIPRECTS * sizeof(CRect) + 2]; + if (2 == sscanf(Option, "%d %s", &ClipCount, s)) { + // Base16-decoding of CRect-array: + unsigned char *p = (unsigned char*)ovlClipRects; + int i = 0, size = sizeof(CRect)*ClipCount; + for (int j = 0; i < size; i++) { + p[i] = (s[j++] - 65); + p[i] += (s[j++] - 65) << 4; + } + if (((unsigned)ClipCount == (i / sizeof(CRect))) && (ClipCount >= 0)) { + // apply it: + if (cDvbApi::PrimaryDvbApi->OvlC(ClipCount, ovlClipRects)) + Reply(250, "Overlay-Clipping set"); + else + Reply(451, "Illegal overlay clipping settings"); + return; + } + } + Reply(501, "Error parsing Overlay-Clipping settings"); + } + else + Reply(501, "Missing Clipping settings"); +} + +void cSVDRP::CmdOVLP(const char *Option) +{ + if (*Option) { + int Brightness = 0, Colour = 0, Hue = 0, Contrast = 0; + if (4 == sscanf(Option, "%d %d %d %d", &Brightness, &Colour, &Hue, &Contrast)) { + //somehow_set_overlay_picture_settings; + if (cDvbApi::PrimaryDvbApi->OvlP(Brightness, Colour, Hue, Contrast)) + Reply(250, "Overlay picture settings set"); + else + Reply(451, "Illegal overlay picture settings"); + } + else + Reply(501, "Could not parse overlay picture settings"); + } + else + Reply(501, "Missing overlay picture settings"); +} + +void cSVDRP::CmdOVLO(const char *Option) +{ + if (*Option) { + int Value; + if (1 == sscanf(Option, "%d", &Value)) { + //somehow_set_overlay_picture_settings; + if (cDvbApi::PrimaryDvbApi->OvlO(Value)) + Reply(250, "Overlay capture set"); + else + Reply(451, "Error setting overlay capture"); + } + else + Reply(501, "Could not parse status"); + } + else + Reply(501, "Missing overlay capture status"); +} + +void cSVDRP::CmdUPDT(const char *Option) { if (*Option) { cTimer *timer = new cTimer; @@ -612,19 +811,26 @@ void cSVDRP::Execute(char *Cmd) while (*s && !isspace(*s)) s++; *s++ = 0; - if (CMD("CHAN")) CmdChan(s); - else if (CMD("DELC")) CmdDelc(s); - else if (CMD("DELT")) CmdDelt(s); - else if (CMD("HELP")) CmdHelp(s); - else if (CMD("LSTC")) CmdLstc(s); - else if (CMD("LSTT")) CmdLstt(s); - else if (CMD("MODC")) CmdModc(s); - else if (CMD("MODT")) CmdModt(s); - else if (CMD("MOVC")) CmdMovc(s); - else if (CMD("MOVT")) CmdMovt(s); - else if (CMD("NEWC")) CmdNewc(s); - else if (CMD("NEWT")) CmdNewt(s); - else if (CMD("UPDT")) CmdUpdt(s); + if (CMD("CHAN")) CmdCHAN(s); + else if (CMD("DELC")) CmdDELC(s); + else if (CMD("DELT")) CmdDELT(s); + else if (CMD("GRAB")) CmdGRAB(s); + else if (CMD("HELP")) CmdHELP(s); + else if (CMD("HITK")) CmdHITK(s); + else if (CMD("LSTC")) CmdLSTC(s); + else if (CMD("LSTT")) CmdLSTT(s); + else if (CMD("MODC")) CmdMODC(s); + else if (CMD("MODT")) CmdMODT(s); + else if (CMD("MOVC")) CmdMOVC(s); + else if (CMD("MOVT")) CmdMOVT(s); + else if (CMD("NEWC")) CmdNEWC(s); + else if (CMD("NEWT")) CmdNEWT(s); + else if (CMD("OVLF")) CmdOVLF(s); + else if (CMD("OVLG")) CmdOVLG(s); + else if (CMD("OVLC")) CmdOVLC(s); + else if (CMD("OVLP")) CmdOVLP(s); + else if (CMD("OVLO")) CmdOVLO(s); + else if (CMD("UPDT")) CmdUPDT(s); else if (CMD("QUIT") || CMD("\x04")) Close(); else Reply(500, "Command unrecognized: \"%s\"", Cmd); @@ -632,9 +838,9 @@ void cSVDRP::Execute(char *Cmd) void cSVDRP::Process(void) { - bool SendGreeting = filedes < 0; + bool SendGreeting = !file.IsOpen(); - if (filedes >= 0 || (filedes = socket.Accept()) >= 0) { + if (file.IsOpen() || file.Open(socket.Accept())) { char buffer[MAXCMDBUFFER]; if (SendGreeting) { //TODO how can we get the *full* hostname? @@ -642,7 +848,7 @@ void cSVDRP::Process(void) time_t now = time(NULL); Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now)); } - int rbytes = readstring(filedes, buffer, sizeof(buffer) - 1); + int rbytes = file.ReadString(buffer, sizeof(buffer) - 1); if (rbytes > 0) { //XXX overflow check??? // strip trailing whitespace: diff --git a/svdrp.h b/svdrp.h index 3c1cafa8f..12eb11e3e 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,12 +4,15 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.2 2000/08/06 12:45:28 kls Exp $ + * $Id: svdrp.h 1.6 2000/09/17 13:22:04 kls Exp $ */ #ifndef __SVDRP_H #define __SVDRP_H +#include "dvbapi.h" +#include "tools.h" + class cSocket { private: int port; @@ -26,23 +29,31 @@ class cSocket { class cSVDRP { private: cSocket socket; - int filedes; + cFile file; + CRect ovlClipRects[MAXCLIPRECTS]; void Close(void); bool Send(const char *s, int length = -1); void Reply(int Code, const char *fmt, ...); - void CmdChan(const char *Option); - void CmdDelc(const char *Option); - void CmdDelt(const char *Option); - void CmdHelp(const char *Option); - void CmdLstc(const char *Option); - void CmdLstt(const char *Option); - void CmdModc(const char *Option); - void CmdModt(const char *Option); - void CmdMovc(const char *Option); - void CmdMovt(const char *Option); - void CmdNewc(const char *Option); - void CmdNewt(const char *Option); - void CmdUpdt(const char *Option); + void CmdCHAN(const char *Option); + void CmdDELC(const char *Option); + void CmdDELT(const char *Option); + void CmdGRAB(const char *Option); + void CmdHELP(const char *Option); + void CmdHITK(const char *Option); + void CmdLSTC(const char *Option); + void CmdLSTT(const char *Option); + void CmdMODC(const char *Option); + void CmdMODT(const char *Option); + void CmdMOVC(const char *Option); + void CmdMOVT(const char *Option); + void CmdNEWC(const char *Option); + void CmdNEWT(const char *Option); + void CmdOVLF(const char *Option); + void CmdOVLG(const char *Option); + void CmdOVLC(const char *Option); + void CmdOVLP(const char *Option); + void CmdOVLO(const char *Option); + void CmdUPDT(const char *Option); void Execute(char *Cmd); public: cSVDRP(int Port); diff --git a/timers.conf b/timers.conf index 9031d35db..a625527fc 100644 --- a/timers.conf +++ b/timers.conf @@ -1,12 +1,14 @@ 1:15:M------:2128:2205:99:7:Neues: -1:3:-T-----:2013:2125:99:99:SevenDays -1:10:-T-----:2058:2202:99:10:Quarks: -1:26:-T-----:2255:0005:99:99:UFO: -0:3:---T---:2211:2300:99:10:Switch: +1:3:-T-----:2013:2125:99:99:SevenDays: +0:10:-T-----:2058:2202:99:10:Quarks: +1:26:-T-----:2255:0015:99:99:UFO: +1:3:---T---:2215:2315:99:10:IngoAppelt: 1:2:----F--:2140:2225:10:10:WWW: +1:1:----F--:2212:2325:99:99:7Tage7Koepfe: 1:11:-----S-:2158:2235:99:99:Computer: 1:2:-----S-:2213:2320:99:30:Wochenshow: -1:11:------S:2058:2120:99:10:Centauri: +1:11:------S:2013:2035:99:10:Centauri: +1:14:------S:2158:2235:99:14:MaxUndLisa: 1:15:MTWTF--:1828:1901:10:5:nano: 1:1:-TWTF--:0955:1040:99:99:Ellen: 1:1:MTWTF--:1553:1710:99:99:Hammerman: diff --git a/tools.c b/tools.c index e081ee793..79d2ee6ca 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.14 2000/09/09 12:53:34 kls Exp $ + * $Id: tools.c 1.19 2000/09/19 17:55:09 kls Exp $ */ #define _GNU_SOURCE @@ -12,31 +12,20 @@ #include #include #include +#if defined(DEBUG_OSD) +#include +#endif #include #include #include -#include #include +#include #include #define MaxBuffer 1000 int SysLogLevel = 3; -bool DataAvailable(int filedes, bool wait) -{ - if (filedes >= 0) { - fd_set set; - FD_ZERO(&set); - FD_SET(filedes, &set); - struct timeval timeout; - timeout.tv_sec = wait ? 1 : 0; - timeout.tv_usec = wait ? 0 : 10000; - return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(filedes, &set); - } - return false; -} - void writechar(int filedes, char c) { write(filedes, &c, sizeof(c)); @@ -56,32 +45,12 @@ char readchar(int filedes) bool readint(int filedes, int &n) { - return DataAvailable(filedes) && read(filedes, &n, sizeof(n)) == sizeof(n); -} - -int readstring(int filedes, char *buffer, int size, bool wait = false) -{ - int rbytes = 0; - - while (DataAvailable(filedes, wait)) { - int n = read(filedes, buffer + rbytes, size - rbytes); - if (n == 0) - break; // EOF - if (n < 0) { - LOG_ERROR; - break; - } - rbytes += n; - if (rbytes == size) - break; - wait = false; - } - return rbytes; + return cFile::AnyFileReady(filedes, 0) && read(filedes, &n, sizeof(n)) == sizeof(n); } void purge(int filedes) { - while (DataAvailable(filedes)) + while (cFile::AnyFileReady(filedes, 0)) readchar(filedes); } @@ -153,6 +122,14 @@ bool isnumber(const char *s) return true; } +const char *AddDirectory(const char *DirName, const char *FileName) +{ + static char *buf = NULL; + delete buf; + asprintf(&buf, "%s/%s", DirName && *DirName ? DirName : ".", FileName); + return buf; +} + #define DFCMD "df -m %s" uint FreeDiskSpaceMB(const char *Directory) @@ -313,6 +290,110 @@ void KillProcess(pid_t pid, int Timeout) } } +// --- cFile ----------------------------------------------------------------- + +bool cFile::files[FD_SETSIZE] = { false }; +int cFile::maxFiles = 0; + +cFile::cFile(void) +{ + f = -1; +} + +cFile::~cFile() +{ + Close(); +} + +bool cFile::Open(const char *FileName, int Flags, mode_t Mode) +{ + if (!IsOpen()) + return Open(open(FileName, Flags, Mode)); + esyslog(LOG_ERR, "ERROR: attempt to re-open %s", FileName); + return false; +} + +bool cFile::Open(int FileDes) +{ + if (FileDes >= 0) { + if (!IsOpen()) { + f = FileDes; + if (f >= 0) { + if (f < FD_SETSIZE) { + if (f >= maxFiles) + maxFiles = f + 1; + if (!files[f]) + files[f] = true; + else + esyslog(LOG_ERR, "ERROR: file descriptor %d already in files[]", f); + return true; + } + else + esyslog(LOG_ERR, "ERROR: file descriptor %d is larger than FD_SETSIZE (%d)", f, FD_SETSIZE); + } + } + else + esyslog(LOG_ERR, "ERROR: attempt to re-open file descriptor %d", FileDes); + } + return false; +} + +void cFile::Close(void) +{ + if (f >= 0) { + close(f); + files[f] = false; + f = -1; + } +} + +int cFile::ReadString(char *Buffer, int Size) +{ + int rbytes = 0; + bool wait = true; + + while (Ready(wait)) { + int n = read(f, Buffer + rbytes, 1); + if (n == 0) + break; // EOF + if (n < 0) { + LOG_ERROR; + return -1; + } + rbytes += n; + if (rbytes == Size || Buffer[rbytes - 1] == '\n') + break; + wait = false; + } + return rbytes; +} + +bool cFile::Ready(bool Wait) +{ + return f >= 0 && AnyFileReady(f, Wait ? 1000 : 0); +} + +bool cFile::AnyFileReady(int FileDes, int TimeoutMs) +{ +#ifdef DEBUG_OSD + refresh(); +#endif + fd_set set; + FD_ZERO(&set); + for (int i = 0; i < maxFiles; i++) { + if (files[i]) + FD_SET(i, &set); + } + if (0 <= FileDes && FileDes < FD_SETSIZE && !files[FileDes]) + FD_SET(FileDes, &set); // in case we come in with an arbitrary descriptor + if (TimeoutMs == 0) + TimeoutMs = 10; // load gets too heavy with 0 + struct timeval timeout; + timeout.tv_sec = TimeoutMs / 1000; + timeout.tv_usec = (TimeoutMs % 1000) * 1000; + return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && (FileDes < 0 || FD_ISSET(FileDes, &set)); +} + // --- cListObject ----------------------------------------------------------- cListObject::cListObject(void) diff --git a/tools.h b/tools.h index 1ef955c55..5c749a7c2 100644 --- a/tools.h +++ b/tools.h @@ -4,16 +4,17 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.13 2000/09/09 12:53:10 kls Exp $ + * $Id: tools.h 1.15 2000/09/17 07:58:19 kls Exp $ */ #ifndef __TOOLS_H #define __TOOLS_H #include +#include #include #include -#include +#include #include extern int SysLogLevel; @@ -30,12 +31,10 @@ extern int SysLogLevel; #define DELETENULL(p) (delete (p), p = NULL) -bool DataAvailable(int filedes, bool wait = false); void writechar(int filedes, char c); void writeint(int filedes, int n); char readchar(int filedes); bool readint(int filedes, int &n); -int readstring(int filedes, char *buffer, int size, bool wait = false); void purge(int filedes); char *readline(FILE *f); char *strn0cpy(char *dest, const char *src, size_t n); @@ -44,6 +43,7 @@ char *skipspace(char *s); int time_ms(void); void delay_ms(int ms); bool isnumber(const char *s); +const char *AddDirectory(const char *DirName, const char *FileName); uint FreeDiskSpaceMB(const char *Directory); bool DirectoryOk(const char *DirName, bool LogErrors = false); bool MakeDirs(const char *FileName, bool IsDirectory = false); @@ -51,6 +51,24 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); bool CheckProcess(pid_t pid); void KillProcess(pid_t pid, int Timeout = MAXPROCESSTIMEOUT); +class cFile { +private: + static bool files[]; + static int maxFiles; + int f; +public: + cFile(void); + ~cFile(); + operator int () { return f; } + bool Open(const char *FileName, int Flags, mode_t Mode = S_IRUSR | S_IWUSR | S_IRGRP); + bool Open(int FileDes); + void Close(void); + bool IsOpen(void) { return f >= 0; } + int ReadString(char *Buffer, int Size); + bool Ready(bool Wait = true); + static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000); + }; + class cListObject { private: cListObject *prev, *next; diff --git a/vdr.c b/vdr.c index 4932bf23c..91643c2f3 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.30 2000/09/10 14:33:09 kls Exp $ + * $Id: vdr.c 1.35 2000/09/20 16:45:01 kls Exp $ */ #include @@ -34,7 +34,6 @@ #include "interface.h" #include "menu.h" #include "recording.h" -#include "svdrp.h" #include "tools.h" #include "videodir.h" @@ -46,9 +45,11 @@ static int Interrupted = 0; -void SignalHandler(int signum) +static void SignalHandler(int signum) { - Interrupted = signum; + if (signum != SIGPIPE) + Interrupted = signum; + signal(signum, SignalHandler); } int main(int argc, char *argv[]) @@ -58,9 +59,11 @@ int main(int argc, char *argv[]) #define DEFAULTSVDRPPORT 2001 int SVDRPport = DEFAULTSVDRPPORT; + const char *ConfigDirectory = NULL; bool DaemonMode = false; static struct option long_options[] = { + { "config", required_argument, NULL, 'c' }, { "daemon", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "log", required_argument, NULL, 'l' }, @@ -71,10 +74,14 @@ int main(int argc, char *argv[]) int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "dhl:p:v:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "c:dhl:p:v:", long_options, &option_index)) != -1) { switch (c) { + case 'c': ConfigDirectory = optarg; + break; case 'd': DaemonMode = true; break; - case 'h': printf("Usage: vdr [OPTION]\n\n" + case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80| + " -c DIR, --config=DIR read config files from DIR (default is to read them\n" + " from the video directory)\n" " -h, --help display this help and exit\n" " -d, --daemon run in daemon mode\n" " -l LEVEL, --log=LEVEL set log level (default: 3)\n" @@ -108,6 +115,8 @@ int main(int argc, char *argv[]) } break; case 'v': VideoDirectory = optarg; + while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') + optarg[strlen(optarg) - 1] = 0; break; default: abort(); } @@ -128,7 +137,7 @@ int main(int argc, char *argv[]) // Daemon mode: if (DaemonMode) { -#ifndef DEBUG_OSD +#if !defined(DEBUG_OSD) && !defined(REMOTE_KBD) pid_t pid = fork(); if (pid < 0) { fprintf(stderr, "%s\n", strerror(errno)); @@ -141,7 +150,7 @@ int main(int argc, char *argv[]) fclose(stdout); fclose(stderr); #else - fprintf(stderr, "vdr: can't run in daemon mode with DEBUG_OSD on!\n"); + fprintf(stderr, "vdr: can't run in daemon mode with DEBUG_OSD or REMOTE_KBD on!\n"); abort(); #endif } @@ -154,16 +163,19 @@ int main(int argc, char *argv[]) // Configuration data: - Setup.Load("setup.conf"); - Channels.Load("channels.conf"); - Timers.Load("timers.conf"); + if (!ConfigDirectory) + ConfigDirectory = VideoDirectory; + + Setup.Load(AddDirectory(ConfigDirectory, "setup.conf")); + Channels.Load(AddDirectory(ConfigDirectory, "channels.conf")); + Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); #ifdef REMOTE_LIRC Keys.SetDummyValues(); #else - if (!Keys.Load(KEYS_CONF)) + if (!Keys.Load(AddDirectory(ConfigDirectory, KEYS_CONF))) Interface.LearnKeys(); #endif - Interface.Init(); + Interface.Init(SVDRPport); cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); @@ -174,10 +186,10 @@ int main(int argc, char *argv[]) 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); + if (signal(SIGPIPE, SignalHandler) == SIG_IGN) signal(SIGPIPE, SIG_IGN); // Main program loop: - cSVDRP *SVDRP = SVDRPport ? new cSVDRP(SVDRPport) : NULL; cOsdBase *Menu = NULL; cReplayControl *ReplayControl = NULL; int LastChannel = -1; @@ -267,13 +279,11 @@ int main(int argc, char *argv[]) default: break; } } - if (SVDRP) - SVDRP->Process();//TODO lock menu vs. SVDRP? } isyslog(LOG_INFO, "caught signal %d", Interrupted); delete Menu; delete ReplayControl; - delete SVDRP; + Interface.Cleanup(); cDvbApi::Cleanup(); isyslog(LOG_INFO, "exiting"); if (SysLogLevel > 0) diff --git a/videodir.c b/videodir.c index 7bd6299a6..91d362dbf 100644 --- a/videodir.c +++ b/videodir.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: videodir.c 1.1 2000/07/29 15:21:42 kls Exp $ + * $Id: videodir.c 1.2 2000/09/15 13:23:47 kls Exp $ */ #include "videodir.h" @@ -137,7 +137,7 @@ int OpenVideoFile(const char *FileName, int Flags) } } } - int Result = open(ActualFileName, Flags, S_IRUSR | S_IWUSR); + int Result = open(ActualFileName, Flags, S_IRUSR | S_IWUSR | S_IRGRP); if (ActualFileName != FileName) delete ActualFileName; return Result; From ef8fe3f04c30caedeb17b11ac275581539f039c7 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Tue, 3 Oct 2000 18:00:00 +0200 Subject: [PATCH 012/307] Version 0.65 - Modified LIRC interface to better handle repeat function. - Faster OSD by first writing into a bitmap and then sending the entire bitmap to the DVB driver at once (requires the patch 'dvb.c.071.diff' to be applied against the version 0.71 DVB driver file 'dvb.c'). - When switching channels the channel is now immediately displayed, and the current/next information is shown as soon as it becomes available. - No longer displaying the year in the 'Recordings' menu to saves space for the title. - The 'Recordings' menu now displays a '*' to indicate new recordings. - Added the description of the timers.conf file to the FORMATS file (thanks to Bastian Guse). - Displaying as much as possible of the current/next info (dropping characters that would display only partially). - In normal viewing mode the '0' key now toggles between the current and the previous channel. --- CONTRIBUTORS | 4 + FORMATS | 24 +- HISTORY | 18 + INSTALL | 19 +- MANUAL | 9 +- Makefile | 55 +- config.h | 4 +- dvb.c.071.diff | 100 + dvbapi.c | 146 +- dvbapi.h | 32 +- dvbosd.c | 177 ++ dvbosd.h | 74 + eit.c | 6 +- font.c | 41 + font.h | 40 + fontosd.c | 6722 ++++++++++++++++++++++++++++++++++++++++++++++++ genfontfile.c | 378 +++ interface.c | 38 +- menu.c | 8 +- recording.c | 17 +- recording.h | 4 +- remote.c | 50 +- remote.h | 5 +- timers.conf | 16 +- tools.c | 3 +- tools.h | 3 +- vdr.c | 11 +- 27 files changed, 7840 insertions(+), 164 deletions(-) create mode 100644 dvb.c.071.diff create mode 100644 dvbosd.c create mode 100644 dvbosd.h create mode 100644 font.c create mode 100644 font.h create mode 100644 fontosd.c create mode 100644 genfontfile.c diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 03fd4bc0f..2eefd64be 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -6,6 +6,7 @@ Carsten Koch for implementing the 'Summary' feature for adding the 'epg2timers' tool (see Tools/epg2timers) for his idea of using multiple disks (and for testing this feature) + for implementing the 'new recording' indicator Plamen Ganev for fixing the frequency offset for Hotbird channels @@ -30,3 +31,6 @@ Niels de Carpentier Martin Hammerschmid for suggesting to display the direct channel select input on the OSD + +Bastian Guse + for writing the FORMATS entry for timers.conf diff --git a/FORMATS b/FORMATS index 776fb4fc2..eb9de0f5c 100644 --- a/FORMATS +++ b/FORMATS @@ -32,4 +32,26 @@ Video Disk Recorder File Formats * timers.conf - TODO + This file contains the timer setup. + + The fields in a timer definition have the following meaning (from left + to right): + + - Timer active (0 = inaactive, 1 = active) + - Program number of the channel to record + - Day of recording, either one or more of + M------ = Monday + -T----- = Tuesday + --W---- = Wednesday + ---T--- = Thrusday + ----F-- = Friday + -----S- = Saturday + ------S = Sunday + (any combination is possible, for example MTWTF--) or the "day of month" (1..31) + - Star time (first two digits for the hour, second two digits for the minutes) + - End time (first two digits for the hour, second two digits for the minutes) + - Priority (from 00 to 99, 00 = lowest prioity, 99 = highest priority) + - Guaranteed lifetime of recording (in days) + - Name of timer (will be used to name the recording) + - Summary + diff --git a/HISTORY b/HISTORY index f8a10078a..481e83ede 100644 --- a/HISTORY +++ b/HISTORY @@ -203,3 +203,21 @@ Video Disk Recorder Revision History - The daemon mode (option '-d') now no longer works with REMOTE=KBD (there is no stdin in daemon mode, so KBD makes no sense - plus it sometimes crashed). + +2000-10-03: Version 0.65 + +- Modified LIRC interface to better handle repeat function. +- Faster OSD by first writing into a bitmap and then sending the entire bitmap + to the DVB driver at once (requires the patch 'dvb.c.071.diff' to be applied + against the version 0.71 DVB driver file 'dvb.c'). +- When switching channels the channel is now immediately displayed, and the + current/next information is shown as soon as it becomes available. +- No longer displaying the year in the 'Recordings' menu to saves space for the + title. +- The 'Recordings' menu now displays a '*' to indicate new recordings. +- Added the description of the timers.conf file to the FORMATS file (thanks to + Bastian Guse). +- Displaying as much as possible of the current/next info (dropping characters + that would display only partially). +- In normal viewing mode the '0' key now toggles between the current and the + previous channel. diff --git a/INSTALL b/INSTALL index 7b953be5d..7def1687e 100644 --- a/INSTALL +++ b/INSTALL @@ -15,18 +15,22 @@ If you have the DVB driver source in a different location you will have to change the definition of DVBDIR in the Makefile. -This program requires the card driver version 0.05 or higher -to work properly. If you are using driver version 0.7 you need -to load the dvb.o module with option outstream=0, so your insmod -statement should read 'insmod dvb.o outstream=0'. This is currently -necessary because 'vdr' works with AV_PES data and will change -once it has been modified to work directly with MPEG2. +This program requires the card driver version 0.71 or higher +to work properly. Currently you need to load the dvb.o module with +option outstream=0, so your insmod statement should read +'insmod dvb.o outstream=0'. This is necessary because 'vdr' works +with AV_PES data and will change once it has been modified to work +directly with MPEG2. You also need to apply the patch 'dvb.c.071.diff' +for the On Screen Display to work properly. After extracting the package, change into the VDR directory and type 'make'. This should produce an executable file named 'vdr', which can be run after the DVB driver has been installed. +IMPORTANT: See "Configuration files" below for information on how +========= to set up the configuration files at the proper location! + The 'vdr' program can be controlled via the PC keyboard or an infrared remote control unit. Define the REMOTE macro to one of the following values 'make' call to activate the respective control mode: @@ -115,7 +119,8 @@ Configuration files: There are three configuration files that hold information about channels, remote control keys and timers. By default these files are assumed to be located in the video directory, but a different directory -can be used with the '-c' option. +can be used with the '-c' option. For starters just copy all *.conf files from +the VDR directory into your video directory. The configuration files can be edited with any text editor, or will be written by the 'vdr' program if any changes are made inside the on-screen menus. diff --git a/MANUAL b/MANUAL index 91c9bffd3..24ee3ff5a 100644 --- a/MANUAL +++ b/MANUAL @@ -66,9 +66,12 @@ Video Disk Recorder User's Manual if no key is pressed for about half a second, the digits collected so far will define the channel number. + Pressing the '0' key toggles between the current and the previous channel. + After switching to a different channel the channel number and name, as well - as the current time are displayed at the top of the screen. This line - automatically goes away after about two seconds, or if any key is pressed. + as the current time are displayed at the top of the screen. If available, the + 'current/next' information will be displayed below this line. This display + automatically goes away after about five seconds, or if any key is pressed. To bring up the channel display without switching channels you can press the "Ok" button. @@ -97,7 +100,7 @@ Video Disk Recorder User's Manual 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. + to start playback. New recordings are marked with an '*'. Playback can be stopped via the Main menu by selecting "Stop replaying", or by pressing the "Blue" button outside the menu. diff --git a/Makefile b/Makefile index fef7a6f12..15757744b 100644 --- a/Makefile +++ b/Makefile @@ -4,12 +4,15 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.11 2000/09/20 17:01:57 kls Exp $ +# $Id: Makefile 1.12 2000/10/01 14:27:12 kls Exp $ DVBDIR = ../DVB INCLUDES = -I$(DVBDIR)/driver -OBJS = config.o dvbapi.o eit.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o videodir.o +OBJS = config.o dvbapi.o dvbosd.o eit.o font.o interface.o menu.o osd.o\ + recording.o remote.o svdrp.o tools.o vdr.o videodir.o + +OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 ifndef REMOTE REMOTE = KBD @@ -21,26 +24,52 @@ ifdef DEBUG_OSD DEFINES += -DDEBUG_OSD endif +all: vdr +font: genfontfile fontosd.c + @echo "font file created." + +# Implicit rules: + %.o: %.c g++ -g -O2 -Wall -m486 -c $(DEFINES) $(INCLUDES) $< -all: vdr +# Dependencies: -config.o : config.c config.h dvbapi.h eit.h interface.h svdrp.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h interface.h svdrp.h tools.h videodir.h +config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h svdrp.h tools.h +dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h videodir.h +dvbosd.o : dvbosd.c dvbosd.h font.h tools.h eit.o : eit.c eit.h tools.h -interface.o: interface.c config.h dvbapi.h eit.h interface.h remote.h svdrp.h tools.h -menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h -osd.o : osd.c config.h dvbapi.h interface.h osd.h svdrp.h tools.h -recording.o: recording.c config.h dvbapi.h interface.h recording.h svdrp.h tools.h videodir.h -remote.o : remote.c config.h dvbapi.h remote.h tools.h -svdrp.o : svdrp.c config.h dvbapi.h interface.h svdrp.h tools.h +font.o : font.c font.h fontosd.c tools.h +interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h tools.h +menu.o : menu.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h +osd.o : osd.c config.h dvbapi.h dvbosd.h font.h interface.h osd.h svdrp.h tools.h +recording.o: recording.c config.h dvbapi.h dvbosd.h font.h interface.h recording.h svdrp.h tools.h videodir.h +remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h tools.h +svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h tools.o : tools.c tools.h -vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h +vdr.o : vdr.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h videodir.o : videodir.c tools.h videodir.h +# The main program: + vdr: $(OBJS) g++ -g -O2 $(OBJS) -lncurses -ljpeg -o vdr +# The font file: + +fontosd.c: + genfontfile "cFont::tPixelData FontOsd" $(OSDFONT) > $@ + +# The font file generator: + +genfontfile.o: genfontfile.c + gcc -O2 -c $< +genfontfile: genfontfile.o + gcc -o $@ -L/usr/X11R6/lib $< -lX11 + +# Housekeeping: + clean: - -rm $(OBJS) vdr + -rm -f $(OBJS) vdr genfontfile genfontfile.o +CLEAN: clean + -rm -f fontosd.c diff --git a/config.h b/config.h index 418fa6303..224a7b3bc 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.21 2000/09/17 09:08:13 kls Exp $ + * $Id: config.h 1.22 2000/10/01 14:14:18 kls Exp $ */ #ifndef __CONFIG_H @@ -17,7 +17,7 @@ #include "dvbapi.h" #include "tools.h" -#define VDRVERSION "0.64" +#define VDRVERSION "0.65" #define MaxBuffer 10000 diff --git a/dvb.c.071.diff b/dvb.c.071.diff new file mode 100644 index 000000000..647b0de1b --- /dev/null +++ b/dvb.c.071.diff @@ -0,0 +1,100 @@ +--- dvb.c.001 Sun Sep 17 22:02:37 2000 ++++ dvb.c Tue Oct 3 12:11:46 2000 +@@ -1143,6 +1143,8 @@ + { + int bpp; + int i; ++ int d, delta; //XXX kls: additional variables for data compression ++ u8 c; //XXX kls: additional variables for data compression + DECLARE_WAITQUEUE(wait, current); + + if (dvb->bmp_state==BMP_LOADING) { +@@ -1160,27 +1162,38 @@ + if (dvb->bmp_state==BMP_LOADING) + return -1; + dvb->bmp_state=BMP_LOADING; +- if (format==BITMAP8) bpp=8; +- else if (format==BITMAP4) bpp=4; +- else if (format==BITMAP2) bpp=2; +- else if (format==BITMAP1) bpp=1; ++ if (format==BITMAP8) { bpp=8; delta = 1; } //XXX kls: initialize 'delta', too ++ else if (format==BITMAP4) { bpp=4; delta = 2; } ++ else if (format==BITMAP2) { bpp=2; delta = 4; } ++ else if (format==BITMAP1) { bpp=1; delta = 8; } + else { + dvb->bmp_state=BMP_NONE; + return -1; + } +- dvb->bmplen= (dx*dy*bpp)/8; ++ dvb->bmplen= ((dx*dy*bpp+7)&~7)/8; //XXX kls: need to round up to include partial bytes + dvb->bmpp=0; + if (dvb->bmplen>32768) { + dvb->bmp_state=BMP_NONE; + return -1; + } + for (i=0; ibmpbuf+1024+i*dx, data+i*inc, (dx*bpp)/8)) { ++ if (copy_from_user(dvb->bmpbuf+1024+i*dx, data+i*inc, dx)) { //XXX kls: incoming data is "1 byte per pixel" + dvb->bmp_state=BMP_NONE; + return -1; + } + + } ++ // XXX kls: Incoming data is always "one byte per pixel", so we need to compress ++ // the data in case we have a lower resolution than 8 bpp: ++ if (format != BITMAP8) { ++ for (i=0; ibmpbuf)[1024+i*delta+delta-1]; ++ for (d=delta-2; d>=0; d--) { ++ c |= (((u8 *)dvb->bmpbuf)[1024+i*delta+d] << ((delta-d-1)*bpp)); ++ ((u8 *)dvb->bmpbuf)[1024+i] = c; ++ } ++ } ++ } + dvb->bmplen+=1024; + return outcom(dvb, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); + } +@@ -1256,24 +1269,25 @@ + int i; + + w=x1-x0+1; h=y1-y0+1; +- if (inc>0) +- w=inc; +- if (w>720 || h>576) ++ if (inc<=0) ++ inc=w; //XXX kls: see dvb_4l.h: "inc<=0 uses blockwidth as linewidth" ++ if (w<=0 || w>720 || h<=0 || h>576) //XXX kls: checking lower bounds, too + return -1; +- bpp=8; //dvb->osdbpp[dvb->osdwin]; +- bpl=w*bpp/8; ++ bpp=dvb->osdbpp[dvb->osdwin]+1; //XXX kls: 'bpp' needs to be taken from the window ++ bpl=((w*bpp+7)&~7)/8; //XXX kls: need to round up to include partial bytes + size=h*bpl; +- lpb=(64*1024)/bpl; ++ lpb=(32*1024)/bpl; //XXX kls: apparently 32K is the maximum possible value + bnum=size/(lpb*bpl); + brest=size-bnum*lpb*bpl; + + for (i=0; iosdbpp[dvb->osdwin]], w, lpb, inc, data); //XXX kls: need to take the format from the actual window + BlitBitmap(dvb, dvb->osdwin, x0, y0+i*lpb, 1); +- data+=bpl; ++ data+=lpb*inc; //XXX kls: incrementing must be done in "one byte per pixel" ++ ddelay(2); //XXX kls: without this the block is sometimes not fully displayed - firmware bug? + } + if (brest) { +- LoadBitmap(dvb, BITMAP8, w, brest/bpl, inc, data); ++ LoadBitmap(dvb, bpp2bit[dvb->osdbpp[dvb->osdwin]], w, brest/bpl, inc, data); //XXX kls: need to take the format from the actual window + BlitBitmap(dvb, dvb->osdwin, x0, y0+bnum*lpb, 1); + } + ReleaseBitmap(dvb); +@@ -6141,7 +6155,7 @@ + init_waitqueue_head(&dvb->bmpq); + spin_lock_init (&(dvb->bmplock)); + dvb->bmpp=dvb->bmplen=0; +- dvb->bmpbuf=vmalloc(32768+1024); ++ dvb->bmpbuf=vmalloc(8*32768+1024); //XXX kls: '8*' to be prepared for the maximum possible incoming data at 1 bpp + + init_waitqueue_head(&dvb->debiq); + dvb->debilock=SPIN_LOCK_UNLOCKED; diff --git a/dvbapi.c b/dvbapi.c index 1468de60e..04873fcc0 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.27 2000/09/17 12:45:55 kls Exp $ + * $Id: dvbapi.c 1.30 2000/10/03 13:26:16 kls Exp $ */ #include "dvbapi.h" @@ -19,6 +19,7 @@ extern "C" { #include #include #include +#include "dvbapi.h" #include "interface.h" #include "tools.h" #include "videodir.h" @@ -71,6 +72,56 @@ extern "C" { typedef unsigned char uchar; +// --- cResumeFile ------------------------------------------------------------ + +cResumeFile::cResumeFile(const char *FileName) +{ + fileName = new char[strlen(FileName) + strlen(RESUMEFILESUFFIX) + 1]; + if (fileName) { + strcpy(fileName, FileName); + strcat(fileName, RESUMEFILESUFFIX); + } + else + esyslog(LOG_ERR, "ERROR: can't allocate memory for resume file name"); +} + +cResumeFile::~cResumeFile() +{ + delete fileName; +} + +int cResumeFile::Read(void) +{ + int resume = -1; + if (fileName) { + int f = open(fileName, O_RDONLY); + if (f >= 0) { + if (read(f, &resume, sizeof(resume)) != sizeof(resume)) { + resume = -1; + LOG_ERROR_STR(fileName); + } + close(f); + } + else if (errno != ENOENT) + LOG_ERROR_STR(fileName); + } + return resume; +} + +bool cResumeFile::Save(int Index) +{ + if (fileName) { + int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); + if (f >= 0) { + if (write(f, &Index, sizeof(Index)) != sizeof(Index)) + LOG_ERROR_STR(fileName); + close(f); + return true; + } + } + return false; +} + // --- cIndexFile ------------------------------------------------------------ class cIndexFile { @@ -78,8 +129,9 @@ class cIndexFile { struct tIndex { int offset; uchar type; uchar number; short reserved; }; int f; char *fileName, *pFileExt; - int size, last, resume; + int size, last; tIndex *index; + cResumeFile resumeFile; bool CatchUp(void); public: cIndexFile(const char *FileName, bool Record = false); @@ -89,21 +141,22 @@ class cIndexFile { int GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length = NULL); int Get(uchar FileNumber, int FileOffset); int Last(void) { return last; } - int GetResume(void) { return resume; } - bool StoreResume(int Index); + int GetResume(void) { return resumeFile.Read(); } + bool StoreResume(int Index) { return resumeFile.Save(Index); } static char *Str(int Index, bool WithFrame = false); }; cIndexFile::cIndexFile(const char *FileName, bool Record) +:resumeFile(FileName) { f = -1; fileName = pFileExt = NULL; size = 0; - last = resume = -1; + last = -1; index = NULL; if (FileName) { - fileName = new char[strlen(FileName) + strlen(INDEXFILESUFFIX) + strlen(RESUMEFILESUFFIX) + 1]; - if (fileName) { // no max() function at hand... + fileName = new char[strlen(FileName) + strlen(INDEXFILESUFFIX) + 1]; + if (fileName) { strcpy(fileName, FileName); pFileExt = fileName + strlen(fileName); strcpy(pFileExt, INDEXFILESUFFIX); @@ -155,19 +208,6 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) delete fileName; fileName = pFileExt = NULL; } - else { - strcpy(pFileExt, RESUMEFILESUFFIX); - int resumeFile = open(fileName, O_RDONLY); - if (resumeFile >= 0) { - if (read(resumeFile, &resume, sizeof(resume)) != sizeof(resume)) { - resume = -1; - LOG_ERROR_STR(fileName); - } - close(resumeFile); - } - else if (errno != ENOENT) - LOG_ERROR_STR(fileName); - } } else esyslog(LOG_ERR, "ERROR: can't copy file name '%s'", FileName); @@ -298,22 +338,6 @@ int cIndexFile::Get(uchar FileNumber, int FileOffset) return -1; } -bool cIndexFile::StoreResume(int Index) -{ - if (fileName) { - int resumeFile = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); - if (resumeFile >= 0) { - if (write(resumeFile, &Index, sizeof(Index)) != sizeof(Index)) - LOG_ERROR_STR(fileName); - close(resumeFile); - return true; - } - else if (errno != ENOENT) - LOG_ERROR_STR(fileName); - } - return false; -} - char *cIndexFile::Str(int Index, bool WithFrame) { static char buffer[16]; @@ -1087,6 +1111,8 @@ cDvbApi::cDvbApi(const char *FileName) start_color(); leaveok(stdscr, true); window = NULL; +#else + osd = NULL; #endif lastProgress = lastTotal = -1; replayTitle = NULL; @@ -1488,18 +1514,19 @@ void cDvbApi::Open(int w, int h) d *= lineHeight; int x = (720 - MenuColumns * charWidth) / 2; //TODO PAL vs. NTSC??? int y = (576 - MenuLines * lineHeight) / 2 + d; - Cmd(OSD_Open, 4, x, y, x + w - 1, y + h - 1); + osd = new cDvbOsd(videoDev, x, y, x + w - 1, y + h - 1, 4); #define SETCOLOR(n, r, g, b, o) Cmd(OSD_SetColor, n, r, g, b, o) + SETCOLOR(clrTransparent, 0x00, 0x00, 0x00, 0); #endif - SETCOLOR(clrBackground, 0x00, 0x00, 0x00, 127); // background 50% gray - SETCOLOR(clrBlack, 0x00, 0x00, 0x00, 255); - SETCOLOR(clrRed, 0xFC, 0x14, 0x14, 255); - SETCOLOR(clrGreen, 0x24, 0xFC, 0x24, 255); - SETCOLOR(clrYellow, 0xFC, 0xC0, 0x24, 255); - SETCOLOR(clrBlue, 0x00, 0x00, 0xFC, 255); - SETCOLOR(clrCyan, 0x00, 0xFC, 0xFC, 255); - SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255); - SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255); + SETCOLOR(clrBackground, 0x00, 0x00, 0x00, 127); // background 50% gray + SETCOLOR(clrBlack, 0x00, 0x00, 0x00, 255); + SETCOLOR(clrRed, 0xFC, 0x14, 0x14, 255); + SETCOLOR(clrGreen, 0x24, 0xFC, 0x24, 255); + SETCOLOR(clrYellow, 0xFC, 0xC0, 0x24, 255); + SETCOLOR(clrBlue, 0x00, 0x00, 0xFC, 255); + SETCOLOR(clrCyan, 0x00, 0xFC, 0xFC, 255); + SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255); + SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255); lastProgress = lastTotal = -1; } @@ -1512,7 +1539,8 @@ void cDvbApi::Close(void) window = 0; } #else - Cmd(OSD_Close); + delete osd; + osd = NULL; #endif lastProgress = lastTotal = -1; } @@ -1523,7 +1551,7 @@ void cDvbApi::Clear(void) SetColor(clrBackground, clrBackground); Fill(0, 0, cols, rows, clrBackground); #else - Cmd(OSD_Clear); + osd->Clear(); #endif } @@ -1539,7 +1567,7 @@ void cDvbApi::Fill(int x, int y, int w, int h, eDvbColor color) } wsyncup(window); // shouldn't be necessary because of 'syncok()', but w/o it doesn't work #else - Cmd(OSD_FillBlock, color, x * charWidth, y * lineHeight, (x + w) * charWidth - 1, (y + h) * lineHeight - 1); + osd->Fill(x * charWidth, y * lineHeight, (x + w) * charWidth - 1, (y + h) * lineHeight - 1, color); #endif } @@ -1555,9 +1583,17 @@ void cDvbApi::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor col #ifdef DEBUG_OSD SetColor(colorFg, colorBg); wmove(window, y, x); // ncurses wants 'y' before 'x'! - waddstr(window, s); + waddnstr(window, s, cols - x); #else - Cmd(OSD_Text, (int(colorBg) << 16) | colorFg, x * charWidth, y * lineHeight, 1, 0, s); + osd->Text(x * charWidth, y * lineHeight, s, colorFg, colorBg); +#endif +} + +void cDvbApi::Flush(void) +{ +#ifndef DEBUG_OSD + if (osd) + osd->Flush(); #endif } @@ -1567,11 +1603,13 @@ bool cDvbApi::ShowProgress(bool Initial) if (GetIndex(&Current, &Total)) { if (Initial) { + Clear(); if (replayTitle) Text(0, 0, replayTitle); } if (Total != lastTotal) Text(-7, 2, cIndexFile::Str(Total)); + Flush(); #ifdef DEBUG_OSD int p = cols * Current / Total; Fill(0, 1, p, 1, clrGreen); @@ -1597,12 +1635,14 @@ bool cDvbApi::ShowProgress(bool Initial) color = clrWhite; } if (lastProgress < 0) - Cmd(OSD_FillBlock, clrWhite, 0, y1, w - 1, y2); - Cmd(OSD_FillBlock, color, x1, y1, x2, y2); + osd->Fill(0, y1, w - 1, y2, clrWhite); + osd->Fill(x1, y1, x2, y2, color); lastProgress = p; } + Flush(); #endif Text(0, 2, cIndexFile::Str(Current)); + Flush(); lastTotal = Total; return true; } diff --git a/dvbapi.h b/dvbapi.h index 08ba4bfc6..b35f3fb80 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.16 2000/09/17 12:15:05 kls Exp $ + * $Id: dvbapi.h 1.18 2000/10/03 11:26:10 kls Exp $ */ #ifndef __DVBAPI_H @@ -20,6 +20,7 @@ typedef unsigned char __u8; #endif #include #include +#include "dvbosd.h" // Overlay facilities #define MAXCLIPRECTS 100 @@ -30,22 +31,16 @@ typedef struct CRect { #define MenuLines 15 #define MenuColumns 40 -enum eDvbColor { clrBackground, -#ifndef DEBUG_OSD - clrOBSOLETE, //FIXME apparently color '1' can't be used as FgColor with e.g. clrRed as BgColor??? - clrBlack, -#else - clrBlack = clrBackground, -#endif - clrRed, - clrGreen, - clrYellow, - clrBlue, - clrMagenta, - clrCyan, - clrWhite, - }; - +class cResumeFile { +private: + char *fileName; +public: + cResumeFile(const char *FileName); + ~cResumeFile(); + int Read(void); + bool Save(int Index); + }; + class cDvbApi { private: int videoDev; @@ -106,6 +101,8 @@ class cDvbApi { enum { MaxColorPairs = 16 }; int colorPairs[MaxColorPairs]; void SetColor(eDvbColor colorFg, eDvbColor colorBg = clrBackground); +#else + cDvbOsd *osd; #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); @@ -116,6 +113,7 @@ class cDvbApi { 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); + void Flush(void); // Progress Display facilities diff --git a/dvbosd.c b/dvbosd.c new file mode 100644 index 000000000..1e2c354ea --- /dev/null +++ b/dvbosd.c @@ -0,0 +1,177 @@ +/* + * dvbosd.c: Interface to the DVB On Screen Display + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: dvbosd.c 1.2 2000/10/03 13:34:13 kls Exp $ + */ + +#include "dvbosd.h" +#include +#include +#include +#include "tools.h" + +// --- cBitmap --------------------------------------------------------------- + +cBitmap::cBitmap(int Width, int Height) +{ + width = Width; + height = Height; + bitmap = NULL; + font = NULL; + if (width > 0 && height > 0) { + bitmap = new char[width * height]; + if (bitmap) { + Clean(); + memset(bitmap, clrTransparent, width * height); + SetFont(fontOsd); + } + else + esyslog(LOG_ERR, "ERROR: can't allocate bitmap!"); + } + else + esyslog(LOG_ERR, "ERROR: illegal bitmap parameters (%d, %d)!", width, height); +} + +cBitmap::~cBitmap() +{ + delete font; + delete bitmap; +} + +void cBitmap::SetFont(eDvbFont Font) +{ + delete font; + font = new cFont(Font); +} + +bool cBitmap::Dirty(void) +{ + return dirtyX2 >= 0; +} + +void cBitmap::Clean(void) +{ + dirtyX1 = width; + dirtyY1 = height; + dirtyX2 = -1; + dirtyY2 = -1; +} + +void cBitmap::SetPixel(int x, int y, eDvbColor Color) +{ + if (bitmap) { + if (0 <= x && x < width && 0 <= y && y < height) { + if (bitmap[width * y + x] != Color) { + bitmap[width * y + x] = Color; + if (dirtyX1 > x) dirtyX1 = x; + if (dirtyY1 > y) dirtyY1 = y; + if (dirtyX2 < x) dirtyX2 = x; + if (dirtyY2 < y) dirtyY2 = y; + } + } + } +} + +void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) +{ + if (bitmap) { + int h = font->Height(s); + while (s && *s) { + const cFont::tCharData *CharData = font->CharData(*s++); + if (int(x + CharData->width) > width) + break; + for (int row = 0; row < h; row++) { + cFont::tPixelData PixelData = CharData->lines[row]; + for (int col = CharData->width; col-- > 0; ) { + SetPixel(x + col, y + row, (PixelData & 1) ? ColorFg : ColorBg); + PixelData >>= 1; + } + } + x += CharData->width; + } + } +} + +void cBitmap::Fill(int x1, int y1, int x2, int y2, eDvbColor Color) +{ + if (bitmap) { + for (int y = y1; y <= y2; y++) + for (int x = x1; x <= x2; x++) + SetPixel(x, y, Color); + } +} + +void cBitmap::Clear(void) +{ + Fill(0, 0, width - 1, height - 1, clrBackground); +} + +// --- cDvbOsd --------------------------------------------------------------- + +cDvbOsd::cDvbOsd(int VideoDev, int x1, int y1, int x2, int y2, int Bpp) +:cBitmap(x2 - x1 + 1, y2 - y1 + 1) +{ + videoDev = VideoDev; + if (videoDev >= 0) + Cmd(OSD_Open, Bpp, x1, y1, x2, y2); + else + esyslog(LOG_ERR, "ERROR: illegal video device handle (%d)!", videoDev); +} + +cDvbOsd::~cDvbOsd() +{ + if (videoDev >= 0) + Cmd(OSD_Close); +} + +void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) +{ + if (videoDev >= 0) { + struct drawcmd dc; + dc.cmd = cmd; + dc.color = color; + dc.x0 = x0; + dc.y0 = y0; + dc.x1 = x1; + dc.y1 = y1; + dc.data = (void *)data; + ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc); + usleep(10); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places + // XXX and sometimes the OSD was no longer displayed). + // XXX Increase the value if the problem still persists on your particular system. + // TODO Check if this is still necessary with driver versions after 0.7. + } +} + +void cDvbOsd::Flush(void) +{ + if (Dirty()) { + //XXX Workaround: apparently the bitmap sent to the driver always has to be a multiple + //XXX of 8 bits wide, and (dx * dy) also has to be a multiple of 8. + //TODO Fix driver (should be able to handle any size bitmaps!) + while ((dirtyX1 > 0 || dirtyX2 < width - 1) && ((dirtyX2 - dirtyX1) & 7) != 7) { + if (dirtyX2 < width - 1) + dirtyX2++; + else if (dirtyX1 > 0) + dirtyX1--; + } + while ((dirtyY1 > 0 || dirtyY2 < height - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { + if (dirtyY2 < height - 1) + dirtyY2++; + else if (dirtyY1 > 0) + dirtyY1--; + } + while ((dirtyX1 > 0 || dirtyX2 < width - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { + if (dirtyX2 < width - 1) + dirtyX2++; + else if (dirtyX1 > 0) + dirtyX1--; + } + Cmd(OSD_SetBlock, width, dirtyX1, dirtyY1, dirtyX2, dirtyY2, &bitmap[dirtyY1 * width + dirtyX1]); + Clean(); + } +} + diff --git a/dvbosd.h b/dvbosd.h new file mode 100644 index 000000000..f7a536350 --- /dev/null +++ b/dvbosd.h @@ -0,0 +1,74 @@ +/* + * dvbosd.h: Interface to the DVB On Screen Display + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: dvbosd.h 1.1 2000/10/01 15:00:00 kls Exp $ + */ + +#ifndef __DVBOSD_H +#define __DVBOSD_H + +// FIXME: these should be defined in ../DVB/driver/dvb.h!!! +typedef unsigned int __u32; +typedef unsigned short __u16; +typedef unsigned char __u8; + +#if defined(DEBUG_OSD) || defined(REMOTE_KBD) +#include +#endif +#include +#include +#include "font.h" + +enum eDvbColor { +#ifndef DEBUG_OSD + clrTransparent, +#endif + clrBackground, +#ifdef DEBUG_OSD + clrTransparent = clrBackground, + clrBlack = clrBackground, +#else + clrBlack, +#endif + clrRed, + clrGreen, + clrYellow, + clrBlue, + clrMagenta, + clrCyan, + clrWhite, + }; + +class cBitmap { +private: + cFont *font; +protected: + int width, height; + char *bitmap; + int dirtyX1, dirtyY1, dirtyX2, dirtyY2; + void Clean(void); +public: + cBitmap(int Width, int Height); + virtual ~cBitmap(); + void SetFont(eDvbFont Font); + bool Dirty(void); + void SetPixel(int x, int y, eDvbColor Color); + void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); + void Fill(int x1, int y1, int x2, int y2, eDvbColor Color); + void Clear(void); + }; + +class cDvbOsd : public cBitmap { +private: + int videoDev; + 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(int VideoDev, int x1, int y1, int x2, int y2, int Bpp); + ~cDvbOsd(); + void Flush(void); + }; + +#endif //__DVBOSD_H diff --git a/eit.c b/eit.c index d62c90252..44c873b17 100644 --- a/eit.c +++ b/eit.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.3 2000/09/17 15:23:05 kls Exp $ + * $Id: eit.c 1.4 2000/10/01 14:09:05 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -424,9 +424,8 @@ int cEIT::SetProgramNumber(unsigned short pnr) evtRunning.bIsValid = false; evtNext.bIsValid = false; uProgramNumber = pnr; - return GetEIT(); } - return (IsValid() ? 1 : -1); + return 1; } /** retrieves the string for the running title */ @@ -503,6 +502,7 @@ char * cEIT::GetNextTime() /** */ bool cEIT::IsValid() { + GetEIT(); return (evtRunning.bIsValid && evtNext.bIsValid); } diff --git a/font.c b/font.c new file mode 100644 index 000000000..3ef40835b --- /dev/null +++ b/font.c @@ -0,0 +1,41 @@ +/* + * font.c: Font handling for the DVB On Screen Display + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: font.c 1.1 2000/10/01 15:01:49 kls Exp $ + */ + +#include "font.h" +#include "tools.h" + +#include "fontosd.c" + +cFont::cFont(eDvbFont Font)//XXX +{ + switch (Font) { + default: + case fontOsd: for (int i = 0; i < NUMCHARS; i++) + data[i] = (tCharData *)&FontOsd[i < 32 ? 0 : i - 32]; + break; + // TODO others... + } +} + +int cFont::Width(const char *s) +{ + int w = 0; + while (s && *s) + w += Width(*s++); + return w; +} + +int cFont::Height(const char *s) +{ + int h = 0; + if (s && *s) + h = Height(*s); // all characters have the same height! + return h; +} + diff --git a/font.h b/font.h new file mode 100644 index 000000000..f31c6b599 --- /dev/null +++ b/font.h @@ -0,0 +1,40 @@ +/* + * font.h: Font handling for the DVB On Screen Display + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: font.h 1.1 2000/10/01 15:00:35 kls Exp $ + */ + +#ifndef __FONT_H +#define __FONT_H + +enum eDvbFont { + fontOsd, +/* TODO as soon as we have the font files... + fontTtxSmall, + fontTtxLarge, +*/ + }; + +class cFont { +public: + enum { NUMCHARS = 256 }; + typedef unsigned long tPixelData; + struct tCharData { + tPixelData width, height; + tPixelData lines[1]; + }; +private: + const tCharData *data[NUMCHARS]; +public: + cFont(eDvbFont Font); + int Width(unsigned char c) { return data[c]->width; } + int Width(const char *s); + int Height(unsigned char c) { return data[c]->height; } + int Height(const char *s); + const tCharData *CharData(unsigned char c) { return data[c]; } + }; + +#endif //__FONT_H diff --git a/fontosd.c b/fontosd.c new file mode 100644 index 000000000..17d1be5a9 --- /dev/null +++ b/fontosd.c @@ -0,0 +1,6722 @@ +cFont::tPixelData FontOsd[][29] = { + { // 32 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 33 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 34 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x000000CC, // .**..**. + 0x000000CC, // .**..**. + 0x000000CC, // .**..**. + 0x000000CC, // .**..**. + 0x000000CC, // .**..**. + 0x00000044, // ..*...*. + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 35 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000118, // .....*...**.. + 0x00000318, // ....**...**.. + 0x00000318, // ....**...**.. + 0x00000310, // ....**...*... + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00000230, // ....*...**... + 0x00000630, // ...**...**... + 0x00000630, // ...**...**... + 0x00000620, // ...**...*.... + 0x00003FFC, // ************. + 0x00003FFC, // ************. + 0x00000460, // ...*...**.... + 0x00000C60, // ..**...**.... + 0x00000C40, // ..**...*..... + 0x00000C40, // ..**...*..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 36 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000180, // .....**...... + 0x00000180, // .....**...... + 0x00000FF0, // ..********... + 0x00000CB8, // ..**..*.***.. + 0x00001998, // .**..**..**.. + 0x00001998, // .**..**..**.. + 0x00001980, // .**..**...... + 0x00001980, // .**..**...... + 0x00000F80, // ..*****...... + 0x000007E0, // ...******.... + 0x000003F8, // ....*******.. + 0x0000019C, // .....**..***. + 0x0000018C, // .....**...**. + 0x0000198C, // .**..**...**. + 0x0000198C, // .**..**...**. + 0x0000199C, // .**..**..***. + 0x00001D38, // .***.*..***.. + 0x00000FF0, // ..********... + 0x00000180, // .....**...... + 0x00000180, // .....**...... + 0x00000180, // .....**...... + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 37 + 20, 27, + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00038040, // ...***........*..... + 0x000FE0C0, // .*******.....**..... + 0x001C7180, // ***...***...**...... + 0x00183100, // **.....**...*....... + 0x00183300, // **.....**..**....... + 0x001C7200, // ***...***..*........ + 0x000FE600, // .*******..**........ + 0x0007C400, // ..*****...*......... + 0x00000C78, // .........**...****.. + 0x000018FC, // ........**...******. + 0x000019CC, // ........**..***..**. + 0x00003186, // .......**...**....** + 0x00002186, // .......*....**....** + 0x00006186, // ......**....**....** + 0x0000C0FC, // .....**......******. + 0x0000C078, // .....**.......****.. + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + }, + { // 38 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00000FC0, // ....******..... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00000DC0, // ....**.***..... + 0x00000F80, // ....*****...... + 0x00000F00, // ....****....... + 0x00001F98, // ...******..**.. + 0x00003198, // ..**...**..**.. + 0x000060D8, // .**.....**.**.. + 0x00006070, // .**......***... + 0x00006070, // .**......***... + 0x00007078, // .***.....****.. + 0x00003FDC, // ..********.***. + 0x00001F00, // ...*****....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 39 + 5, 27, + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x00000004, // ...*. + 0x00000004, // ...*. + 0x00000008, // ..*.. + 0x00000008, // ..*.. + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + }, + { // 40 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x0000000C, // .....**. + 0x00000018, // ....**.. + 0x00000018, // ....**.. + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000020, // ...*.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000020, // ...*.... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000010, // ....*... + 0x00000018, // ....**.. + 0x00000008, // .....*.. + 0x00000008, // .....*.. + }, + { // 41 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000080, // .*...... + 0x00000040, // ..*..... + 0x00000060, // ..**.... + 0x00000020, // ...*.... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000018, // ....**.. + 0x00000018, // ....**.. + 0x00000018, // ....**.. + 0x00000018, // ....**.. + 0x00000018, // ....**.. + 0x00000018, // ....**.. + 0x00000018, // ....**.. + 0x00000018, // ....**.. + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000020, // ...*.... + 0x00000060, // ..**.... + 0x00000040, // ..*..... + 0x00000080, // .*...... + }, + { // 42 + 9, 27, + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000020, // ....*.... + 0x00000020, // ....*.... + 0x000001AC, // .**.*.**. + 0x000000F8, // ..*****.. + 0x00000070, // ...***... + 0x000000D8, // ..**.**.. + 0x00000088, // ..*...*.. + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + }, + { // 43 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 44 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 45 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001FFE, // .************ + 0x00001FFE, // .************ + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 46 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 47 + 6, 27, + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000004, // .....*. + 0x00000004, // .....*. + 0x0000000C, // ....**. + 0x0000000C, // ....**. + 0x00000008, // ....*.. + 0x00000018, // ...**.. + 0x00000018, // ...**.. + 0x00000010, // ...*... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000020, // ..*.... + 0x00000060, // .**.... + 0x00000060, // .**.... + 0x00000040, // .*..... + 0x000000C0, // **..... + 0x000000C0, // **..... + 0x00000080, // *...... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + }, + { // 48 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x000007F0, // ...*******... + 0x00000E38, // ..***...***.. + 0x00000C18, // ..**.....**.. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x00000C18, // ..**.....**.. + 0x00000E38, // ..***...***.. + 0x000007F0, // ...*******... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 49 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000003C0, // ....****..... + 0x00000FC0, // ..******..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 50 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF8, // ..*********.. + 0x00000C1C, // ..**.....***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000000C, // ..........**. + 0x00000018, // .........**.. + 0x00000038, // ........***.. + 0x000000F0, // ......****... + 0x000003C0, // ....****..... + 0x00000700, // ...***....... + 0x00000E00, // ..***........ + 0x00000C00, // ..**......... + 0x00001800, // .**.......... + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 51 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000007E0, // ...******.... + 0x00000FF0, // ..********... + 0x00000C38, // ..**....***.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00000018, // .........**.. + 0x00000030, // ........**... + 0x000001E0, // .....****.... + 0x000001F8, // .....******.. + 0x00000018, // .........**.. + 0x0000000C, // ..........**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x00001C1C, // .***.....***. + 0x00000FF8, // ..*********.. + 0x000007E0, // ...******.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 52 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000030, // ........**... + 0x00000070, // .......***... + 0x000000F0, // ......****... + 0x000000F0, // ......****... + 0x000001B0, // .....**.**... + 0x00000330, // ....**..**... + 0x00000630, // ...**...**... + 0x00000430, // ...*....**... + 0x00000C30, // ..**....**... + 0x00001830, // .**.....**... + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00000030, // ........**... + 0x00000030, // ........**... + 0x00000030, // ........**... + 0x00000030, // ........**... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 53 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000FF8, // ..*********.. + 0x00000FF8, // ..*********.. + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000FE0, // ..*******.... + 0x00000FF0, // ..********... + 0x00001C38, // .***....***.. + 0x0000181C, // .**......***. + 0x0000000C, // ..........**. + 0x0000000C, // ..........**. + 0x0000000C, // ..........**. + 0x0000180C, // .**.......**. + 0x00001C18, // .***.....**.. + 0x00000FF0, // ..********... + 0x000007E0, // ...******.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 54 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x000007F0, // ...*******... + 0x00000E18, // ..***....**.. + 0x00000C1C, // ..**.....***. + 0x00001C00, // .***......... + 0x00001800, // .**.......... + 0x00001BE0, // .**.*****.... + 0x00001FF8, // .**********.. + 0x00001E38, // .****...***.. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x00000C18, // ..**.....**.. + 0x00000FF8, // ..*********.. + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 55 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00000008, // ..........*.. + 0x00000018, // .........**.. + 0x00000030, // ........**... + 0x00000060, // .......**.... + 0x00000060, // .......**.... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00000180, // .....**...... + 0x00000180, // .....**...... + 0x00000300, // ....**....... + 0x00000300, // ....**....... + 0x00000300, // ....**....... + 0x00000700, // ...***....... + 0x00000600, // ...**........ + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 56 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF0, // ..********... + 0x00001C38, // .***....***.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00000C38, // ..**....***.. + 0x000007E0, // ...******.... + 0x000007F0, // ...*******... + 0x00000E38, // ..***...***.. + 0x00001C1C, // .***.....***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x00001C1C, // .***.....***. + 0x00000FF8, // ..*********.. + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 57 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF0, // ..********... + 0x00000C38, // ..**....***.. + 0x00001818, // .**......**.. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x00001C3C, // .***....****. + 0x00000FFC, // ..**********. + 0x000003EC, // ....*****.**. + 0x0000000C, // ..........**. + 0x0000001C, // .........***. + 0x00001818, // .**......**.. + 0x00000C38, // ..**....***.. + 0x00000FF0, // ..********... + 0x000007E0, // ...******.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 58 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 59 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x00000004, // ....*. + 0x00000004, // ....*. + 0x0000000C, // ...**. + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 60 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000004, // ...........*. + 0x0000001C, // .........***. + 0x00000078, // .......****.. + 0x000003C0, // ....****..... + 0x00000F00, // ..****....... + 0x00001C00, // .***......... + 0x00001E00, // .****........ + 0x000003C0, // ....****..... + 0x000000F0, // ......****... + 0x0000001C, // .........***. + 0x00000004, // ...........*. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 61 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 62 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001000, // .*........... + 0x00001C00, // .***......... + 0x00000780, // ...****...... + 0x000001E0, // .....****.... + 0x0000007C, // .......*****. + 0x0000000C, // ..........**. + 0x0000003C, // ........****. + 0x000000F0, // ......****... + 0x00000780, // ...****...... + 0x00001E00, // .****........ + 0x00001000, // .*........... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 63 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000001F0, // .....*****... + 0x000007F8, // ...********.. + 0x00000E1C, // ..***....***. + 0x00000C0C, // ..**......**. + 0x00000C0C, // ..**......**. + 0x0000000C, // ..........**. + 0x00000018, // .........**.. + 0x00000030, // ........**... + 0x00000060, // .......**.... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 64 + 23, 27, + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00007E00, // .........******........ + 0x0003FFC0, // ......************..... + 0x000781E0, // .....****......****.... + 0x000E0070, // ....***..........***... + 0x001C0038, // ...***............***.. + 0x00383D18, // ..***.....****.*...**.. + 0x0030FF9C, // ..**....*********..***. + 0x0031C38C, // ..**...***....***...**. + 0x0061830C, // .**....**.....**....**. + 0x0063030C, // .**...**......**....**. + 0x0063030C, // .**...**......**....**. + 0x00630618, // .**...**.....**....**.. + 0x00630618, // .**...**.....**....**.. + 0x00738E30, // .***..***...***...**... + 0x0031FFE0, // ..**...************.... + 0x0038E3C0, // ..***...***...****..... + 0x001C0000, // ...***................. + 0x000F0000, // ....****............... + 0x0007FF00, // .....***********....... + 0x0000FE00, // ........*******........ + 0x00000000, // ....................... + 0x00000000, // ....................... + }, + { // 65 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x000003C0, // ......****..... + 0x000007C0, // .....*****..... + 0x000006C0, // .....**.**..... + 0x000006E0, // .....**.***.... + 0x00000E60, // ....***..**.... + 0x00000C60, // ....**...**.... + 0x00000C70, // ....**...***... + 0x00001C30, // ...***....**... + 0x00001830, // ...**.....**... + 0x00001FF8, // ...**********.. + 0x00003FF8, // ..***********.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000700C, // .***........**. + 0x0000600C, // .**.........**. + 0x0000600E, // .**.........*** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 66 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FE0, // ..*********.... + 0x00003FF8, // ..***********.. + 0x00003038, // ..**......***.. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x00003018, // ..**.......**.. + 0x00003FF0, // ..**********... + 0x00003FF8, // ..***********.. + 0x00003018, // ..**.......**.. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x00003018, // ..**.......**.. + 0x00003FF8, // ..***********.. + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 67 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000FC0, // ......******..... + 0x00003FE0, // ....*********.... + 0x00007070, // ...***.....***... + 0x0000E038, // ..***.......***.. + 0x0000C018, // ..**.........**.. + 0x0000C000, // ..**............. + 0x00018000, // .**.............. + 0x00018000, // .**.............. + 0x00018000, // .**.............. + 0x00018000, // .**.............. + 0x00018000, // .**.............. + 0x00018018, // .**..........**.. + 0x0000C018, // ..**.........**.. + 0x0000E018, // ..***........**.. + 0x00007030, // ...***......**... + 0x00007FF0, // ...***********... + 0x00001FC0, // .....*******..... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 68 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x0000FF80, // ..*********...... + 0x0000FFE0, // ..***********.... + 0x0000C0E0, // ..**......***.... + 0x0000C030, // ..**........**... + 0x0000C030, // ..**........**... + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C030, // ..**........**... + 0x0000C030, // ..**........**... + 0x0000C0E0, // ..**......***.... + 0x0000FFE0, // ..***********.... + 0x0000FF80, // ..*********...... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 69 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FF8, // ..***********.. + 0x00003FF8, // ..***********.. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 70 + 14, 27, + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00001FFC, // ..***********. + 0x00001FFC, // ..***********. + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001FF8, // ..**********.. + 0x00001FF8, // ..**********.. + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00001800, // ..**.......... + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + }, + { // 71 + 18, 27, + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000E070, // ...***......***... + 0x0001C030, // ..***........**... + 0x00018018, // ..**..........**.. + 0x00038000, // .***.............. + 0x00030000, // .**............... + 0x00030000, // .**............... + 0x000303F8, // .**......*******.. + 0x000303F8, // .**......*******.. + 0x00030018, // .**...........**.. + 0x00038018, // .***..........**.. + 0x00018018, // ..**..........**.. + 0x0001C038, // ..***........***.. + 0x0000E078, // ...***......****.. + 0x00007FD8, // ....*********.**.. + 0x00001F88, // ......******...*.. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + }, + { // 72 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000FFF8, // ..*************.. + 0x0000FFF8, // ..*************.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 73 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 74 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00000018, // ........**.. + 0x00001818, // **......**.. + 0x00001818, // **......**.. + 0x00001C38, // ***....***.. + 0x00000FF0, // .********... + 0x000007E0, // ..******.... + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + }, + { // 75 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000300E, // ..**........*** + 0x0000301C, // ..**.......***. + 0x00003038, // ..**......***.. + 0x00003070, // ..**.....***... + 0x000030E0, // ..**....***.... + 0x000031C0, // ..**...***..... + 0x00003380, // ..**..***...... + 0x00003780, // ..**.****...... + 0x00003F80, // ..*******...... + 0x00003DC0, // ..****.***..... + 0x000038E0, // ..***...***.... + 0x00003060, // ..**.....**.... + 0x00003030, // ..**......**... + 0x00003038, // ..**......***.. + 0x00003018, // ..**.......**.. + 0x0000300C, // ..**........**. + 0x0000300E, // ..**........*** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 76 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000FFC, // ..**********. + 0x00000FFC, // ..**********. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 77 + 19, 27, + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00038038, // ..***.........***.. + 0x00038038, // ..***.........***.. + 0x0003C038, // ..****........***.. + 0x0003C078, // ..****.......****.. + 0x0003C078, // ..****.......****.. + 0x00036058, // ..**.**......*.**.. + 0x000360D8, // ..**.**.....**.**.. + 0x000360D8, // ..**.**.....**.**.. + 0x00033098, // ..**..**....*..**.. + 0x00033198, // ..**..**...**..**.. + 0x00033198, // ..**..**...**..**.. + 0x00031918, // ..**...**..*...**.. + 0x00031B18, // ..**...**.**...**.. + 0x00031B18, // ..**...**.**...**.. + 0x00030F18, // ..**....****...**.. + 0x00030E18, // ..**....***....**.. + 0x00030E18, // ..**....***....**.. + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + }, + { // 78 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x0000C018, // ..**.........**.. + 0x0000E018, // ..***........**.. + 0x0000F018, // ..****.......**.. + 0x0000F018, // ..****.......**.. + 0x0000D818, // ..**.**......**.. + 0x0000DC18, // ..**.***.....**.. + 0x0000CC18, // ..**..**.....**.. + 0x0000C618, // ..**...**....**.. + 0x0000C718, // ..**...***...**.. + 0x0000C318, // ..**....**...**.. + 0x0000C398, // ..**....***..**.. + 0x0000C198, // ..**.....**..**.. + 0x0000C0D8, // ..**......**.**.. + 0x0000C0F8, // ..**......*****.. + 0x0000C078, // ..**.......****.. + 0x0000C038, // ..**........***.. + 0x0000C038, // ..**........***.. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 79 + 18, 27, + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000E0F0, // ...***.....****... + 0x0001C038, // ..***........***.. + 0x00018018, // ..**..........**.. + 0x0003801C, // .***..........***. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x00018018, // ..**..........**.. + 0x0001C038, // ..***........***.. + 0x0000E070, // ...***......***... + 0x00007FE0, // ....**********.... + 0x00001F80, // ......******...... + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + }, + { // 80 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FE0, // ..*********.... + 0x00003FF8, // ..***********.. + 0x00003018, // ..**.......**.. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000301C, // ..**.......***. + 0x00003FF8, // ..***********.. + 0x00003FE0, // ..*********.... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 81 + 18, 27, + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000E0F0, // ...***.....****... + 0x0001C038, // ..***........***.. + 0x00018018, // ..**..........**.. + 0x0003801C, // .***..........***. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x00018098, // ..**.......*..**.. + 0x0001C1F8, // ..***.....******.. + 0x0000E0F0, // ...***.....****... + 0x00007FF0, // ....***********... + 0x00001F9C, // ......******..***. + 0x00000008, // ...............*.. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + }, + { // 82 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x0000FFC0, // ..**********..... + 0x0000FFF0, // ..************... + 0x0000C038, // ..**........***.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C030, // ..**........**... + 0x0000FFE0, // ..***********.... + 0x0000FFF0, // ..************... + 0x0000C030, // ..**........**... + 0x0000C038, // ..**........***.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C01C, // ..**.........***. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 83 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00001FF0, // ...*********... + 0x00001838, // ...**.....***.. + 0x00003018, // ..**.......**.. + 0x00003008, // ..**........*.. + 0x00003000, // ..**........... + 0x00003800, // ..***.......... + 0x00001F00, // ...*****....... + 0x00000FF0, // ....********... + 0x000000F8, // ........*****.. + 0x0000001C, // ...........***. + 0x0000000C, // ............**. + 0x0000600C, // .**.........**. + 0x0000300C, // ..**........**. + 0x00003018, // ..**.......**.. + 0x00001FF0, // ...*********... + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 84 + 14, 27, + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00007FFE, // ************** + 0x00007FFE, // ************** + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + }, + { // 85 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x00006070, // ...**......***... + 0x00007FE0, // ...**********.... + 0x00001FC0, // .....*******..... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 86 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000600E, // .**.........*** + 0x0000700C, // .***........**. + 0x0000300C, // ..**........**. + 0x0000301C, // ..**.......***. + 0x00003818, // ..***......**.. + 0x00001818, // ...**......**.. + 0x00001838, // ...**.....***.. + 0x00001C30, // ...***....**... + 0x00000C30, // ....**....**... + 0x00000C70, // ....**...***... + 0x00000E60, // ....***..**.... + 0x00000660, // .....**..**.... + 0x00000660, // .....**..**.... + 0x000007C0, // .....*****..... + 0x000003C0, // ......****..... + 0x000003C0, // ......****..... + 0x00000180, // .......**...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 87 + 22, 27, + 0x00000000, // ...................... + 0x00000000, // ...................... + 0x00000000, // ...................... + 0x00000000, // ...................... + 0x00000000, // ...................... + 0x0030180C, // .**.......**.......**. + 0x0030380C, // .**......***.......**. + 0x00303C1C, // .**......****.....***. + 0x00383C1C, // .***.....****.....***. + 0x00183C18, // ..**.....****.....**.. + 0x00186618, // ..**....**..**....**.. + 0x00186618, // ..**....**..**....**.. + 0x001C6638, // ..***...**..**...***.. + 0x000CC630, // ...**..**...**...**... + 0x000CC330, // ...**..**....**..**... + 0x000CC330, // ...**..**....**..**... + 0x000EC370, // ...***.**....**.***... + 0x000781E0, // ....****......****.... + 0x000781E0, // ....****......****.... + 0x000781E0, // ....****......****.... + 0x000781C0, // ....****......***..... + 0x000300C0, // .....**........**..... + 0x00000000, // ...................... + 0x00000000, // ...................... + 0x00000000, // ...................... + 0x00000000, // ...................... + 0x00000000, // ...................... + }, + { // 88 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000700C, // .***........**. + 0x0000301C, // ..**.......***. + 0x00001818, // ...**......**.. + 0x00001C38, // ...***....***.. + 0x00000C70, // ....**...***... + 0x00000660, // .....**..**.... + 0x000007C0, // .....*****..... + 0x000003C0, // ......****..... + 0x00000380, // ......***...... + 0x000003C0, // ......****..... + 0x000006C0, // .....**.**..... + 0x00000E60, // ....***..**.... + 0x00001C70, // ...***...***... + 0x00001838, // ...**.....***.. + 0x00003818, // ..***......**.. + 0x0000701C, // .***.......***. + 0x0000600E, // .**.........*** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 89 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000600E, // .**.........*** + 0x0000700E, // .***........*** + 0x0000301C, // ..**.......***. + 0x00001818, // ...**......**.. + 0x00001C38, // ...***....***.. + 0x00000C30, // ....**....**... + 0x00000E60, // ....***..**.... + 0x00000760, // .....***.**.... + 0x000003C0, // ......****..... + 0x000003C0, // ......****..... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 90 + 14, 27, + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00003FFC, // .************. + 0x00003FFC, // .************. + 0x0000001C, // ..........***. + 0x00000018, // ..........**.. + 0x00000038, // .........***.. + 0x00000070, // ........***... + 0x000000E0, // .......***.... + 0x000001C0, // ......***..... + 0x00000180, // ......**...... + 0x00000380, // .....***...... + 0x00000700, // ....***....... + 0x00000E00, // ...***........ + 0x00000C00, // ...**......... + 0x00001C00, // ..***......... + 0x00003800, // .***.......... + 0x00003FFC, // .************. + 0x00003FFC, // .************. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + }, + { // 91 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000003E, // .***** + 0x0000003E, // .***** + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x00000030, // .**... + 0x0000003E, // .***** + 0x0000003E, // .***** + }, + { // 92 + 6, 27, + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000080, // *...... + 0x000000C0, // **..... + 0x00000040, // .*..... + 0x00000040, // .*..... + 0x00000060, // .**.... + 0x00000020, // ..*.... + 0x00000020, // ..*.... + 0x00000020, // ..*.... + 0x00000010, // ...*... + 0x00000010, // ...*... + 0x00000010, // ...*... + 0x00000008, // ....*.. + 0x00000008, // ....*.. + 0x00000008, // ....*.. + 0x0000000C, // ....**. + 0x00000004, // .....*. + 0x00000004, // .....*. + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + }, + { // 93 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000003C, // .****. + 0x0000003C, // .****. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000000C, // ...**. + 0x0000003C, // .****. + 0x0000003C, // .****. + }, + { // 94 + 11, 27, + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x000000E0, // ....***.... + 0x000000E0, // ....***.... + 0x000001A0, // ...**.*.... + 0x000001B0, // ...**.**... + 0x00000110, // ...*...*... + 0x00000318, // ..**...**.. + 0x00000218, // ..*....**.. + 0x00000608, // .**.....*.. + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + 0x00000000, // ........... + }, + { // 95 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00007FFE, // ************** + 0x00007FFE, // ************** + 0x00000000, // ............. + }, + { // 96 + 5, 27, + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000004, // ...*. + 0x00000008, // ..*.. + 0x00000008, // ..*.. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + }, + { // 97 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF8, // ..*********.. + 0x00000C18, // ..**.....**.. + 0x00000818, // ..*......**.. + 0x00000018, // .........**.. + 0x000003F8, // ....*******.. + 0x00000F98, // ..*****..**.. + 0x00001C18, // .***.....**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FFC, // .***********. + 0x000007DC, // ...*****.***. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 98 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001BE0, // .**.*****.... + 0x00001FF8, // .**********.. + 0x00001E38, // .****...***.. + 0x00001C1C, // .***.....***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x00001C1C, // .***.....***. + 0x00001E38, // .****...***.. + 0x00001FF8, // .**********.. + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 99 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x000001F0, // ....*****... + 0x000007F8, // ..********.. + 0x0000061C, // ..**....***. + 0x00000C0C, // .**......**. + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C0C, // .**......**. + 0x0000061C, // ..**....***. + 0x000007F8, // ..********.. + 0x000001F0, // ....*****... + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + }, + { // 100 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000018, // .........**.. + 0x00000018, // .........**.. + 0x00000018, // .........**.. + 0x00000018, // .........**.. + 0x00000018, // .........**.. + 0x000003D8, // ....****.**.. + 0x00000FF8, // ..*********.. + 0x00000C38, // ..**....***.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00000C38, // ..**....***.. + 0x00000FF8, // ..*********.. + 0x000007C0, // ...*****..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 101 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x000007F0, // ...*******... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00001800, // .**.......... + 0x00001808, // .**.......*.. + 0x00000C18, // ..**.....**.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 102 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000000E, // ...*** + 0x0000001E, // ..**** + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x0000007E, // ****** + 0x0000007E, // ****** + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 103 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003D8, // ....****.**.. + 0x00000FF8, // ..*********.. + 0x00000C38, // ..**....***.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00000C38, // ..**....***.. + 0x000007F8, // ...********.. + 0x000003D8, // ....****.**.. + 0x00000018, // .........**.. + 0x00001818, // .**......**.. + 0x00000C30, // ..**....**... + 0x00000FF0, // ..********... + 0x000007C0, // ...*****..... + }, + { // 104 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000C00, // ..**......... + 0x00000DF0, // ..**.*****... + 0x00000FF8, // ..*********.. + 0x00000E18, // ..***....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 105 + 5, 27, + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000018, // .**.. + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + }, + { // 106 + 5, 27, + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000003C, // ****. + 0x00000038, // ***.. + }, + { // 107 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C18, // .**.....**.. + 0x00000C30, // .**....**... + 0x00000C60, // .**...**.... + 0x00000CC0, // .**..**..... + 0x00000FC0, // .******..... + 0x00000FC0, // .******..... + 0x00000E60, // .***..**.... + 0x00000C70, // .**...***... + 0x00000C30, // .**....**... + 0x00000C18, // .**.....**.. + 0x00000C1C, // .**.....***. + 0x00000C0C, // .**......**. + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + }, + { // 108 + 5, 27, + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x0000000C, // ..**. + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + 0x00000000, // ..... + }, + { // 109 + 19, 27, + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00037CF8, // ..**.*****..*****.. + 0x0003FFFC, // ..****************. + 0x0003870C, // ..***....***....**. + 0x0003060C, // ..**.....**.....**. + 0x0003060C, // ..**.....**.....**. + 0x0003060C, // ..**.....**.....**. + 0x0003060C, // ..**.....**.....**. + 0x0003060C, // ..**.....**.....**. + 0x0003060C, // ..**.....**.....**. + 0x0003060C, // ..**.....**.....**. + 0x0003060C, // ..**.....**.....**. + 0x0003060C, // ..**.....**.....**. + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + 0x00000000, // ................... + }, + { // 110 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000009F0, // ..*..*****... + 0x00000FF8, // ..*********.. + 0x00000E18, // ..***....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 111 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF0, // ..********... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000181C, // .**......***. + 0x00000C38, // ..**....***.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 112 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001BE0, // .**.*****.... + 0x00001FF8, // .**********.. + 0x00001E38, // .****...***.. + 0x00001C1C, // .***.....***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x00001C1C, // .***.....***. + 0x00001E38, // .****...***.. + 0x00001FF8, // .**********.. + 0x000019E0, // .**..****.... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + }, + { // 113 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003D8, // ....****.**.. + 0x00000FF8, // ..*********.. + 0x00000C38, // ..**....***.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00000C38, // ..**....***.. + 0x00000FF8, // ..*********.. + 0x000007D8, // ...*****.**.. + 0x00000018, // .........**.. + 0x00000018, // .........**.. + 0x00000018, // .........**.. + 0x00000018, // .........**.. + 0x00000018, // .........**.. + }, + { // 114 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x0000001C, // ....***. + 0x0000007C, // ..*****. + 0x00000070, // ..***... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 115 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x000003F0, // ...******... + 0x000007F8, // ..********.. + 0x00000C18, // .**.....**.. + 0x00000C00, // .**......... + 0x00000E00, // .***........ + 0x000007E0, // ..******.... + 0x000001F8, // ....******.. + 0x0000001C, // ........***. + 0x00000C0C, // .**......**. + 0x00000C0C, // .**......**. + 0x00000FF8, // .*********.. + 0x000003F0, // ...******... + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + }, + { // 116 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x0000007E, // ****** + 0x0000007E, // ****** + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x0000001E, // ..**** + 0x0000001E, // ..**** + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 117 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FF8, // .**********.. + 0x000007C0, // ...*****..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 118 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00001C0C, // ***......**. + 0x00000C1C, // .**.....***. + 0x00000C18, // .**.....**.. + 0x00000E18, // .***....**.. + 0x00000638, // ..**...***.. + 0x00000630, // ..**...**... + 0x00000330, // ...**..**... + 0x00000360, // ...**.**.... + 0x00000360, // ...**.**.... + 0x000001E0, // ....****.... + 0x000001C0, // ....***..... + 0x000001C0, // ....***..... + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + }, + { // 119 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x0003060C, // **.....**.....**. + 0x0001870C, // .**....***....**. + 0x00018F1C, // .**...****...***. + 0x00018F18, // .**...****...**.. + 0x00018D98, // .**...**.**..**.. + 0x0000C998, // ..**..*..**..**.. + 0x0000D9B0, // ..**.**..**.**... + 0x0000D9B0, // ..**.**..**.**... + 0x000058F0, // ...*.**...****... + 0x000070F0, // ...***....****... + 0x000070E0, // ...***....***.... + 0x000070E0, // ...***....***.... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 120 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000C1C, // .**.....***. + 0x00000618, // ..**....**.. + 0x00000630, // ..**...**... + 0x00000360, // ...**.**.... + 0x000001E0, // ....****.... + 0x000001C0, // ....***..... + 0x000001C0, // ....***..... + 0x000003E0, // ...*****.... + 0x00000370, // ...**.***... + 0x00000630, // ..**...**... + 0x00000E18, // .***....**.. + 0x00000C1C, // .**.....***. + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + }, + { // 121 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000C0C, // .**......**. + 0x00000C1C, // .**.....***. + 0x00000C18, // .**.....**.. + 0x00000618, // ..**....**.. + 0x00000630, // ..**...**... + 0x00000630, // ..**...**... + 0x00000330, // ...**..**... + 0x00000360, // ...**.**.... + 0x00000360, // ...**.**.... + 0x000001E0, // ....****.... + 0x000001C0, // ....***..... + 0x000001C0, // ....***..... + 0x00000180, // ....**...... + 0x00000180, // ....**...... + 0x00000380, // ...***...... + 0x00000F00, // .****....... + 0x00000E00, // .***........ + }, + { // 122 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000FF8, // .*********.. + 0x00000FF8, // .*********.. + 0x00000030, // .......**... + 0x00000030, // .......**... + 0x00000060, // ......**.... + 0x000000C0, // .....**..... + 0x00000180, // ....**...... + 0x00000300, // ...**....... + 0x00000600, // ..**........ + 0x00000C00, // .**......... + 0x00000FFC, // .**********. + 0x00000FFC, // .**********. + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + }, + { // 123 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000018, // ....**.. + 0x00000038, // ...***.. + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000070, // ..***... + 0x000000E0, // .***.... + 0x000000C0, // .**..... + 0x00000060, // ..**.... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000038, // ...***.. + 0x00000018, // ....**.. + }, + { // 124 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + }, + { // 125 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x000000C0, // .**..... + 0x000000E0, // .***.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000030, // ...**... + 0x00000038, // ...***.. + 0x00000018, // ....**.. + 0x00000030, // ...**... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x00000060, // ..**.... + 0x000000E0, // .***.... + 0x000000C0, // .**..... + }, + { // 126 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000700, // ...***....... + 0x00000F8C, // ..*****...**. + 0x000008FC, // ..*...******. + 0x00000038, // ........***.. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 127 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 128 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 129 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 130 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 131 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 132 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 133 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 134 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 135 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 136 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 137 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 138 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 139 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 140 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 141 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 142 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 143 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 144 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 145 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 146 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 147 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 148 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 149 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 150 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 151 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 152 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 153 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 154 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 155 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 156 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 157 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 158 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 159 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 160 + 0, 27, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 161 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + }, + { // 162 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000003F0, // ....******... + 0x00000FF8, // ..*********.. + 0x00000E58, // ..***..*.**.. + 0x00001C4C, // .***...*..**. + 0x00001840, // .**....*..... + 0x00001840, // .**....*..... + 0x00001880, // .**...*...... + 0x00001880, // .**...*...... + 0x0000188C, // .**...*...**. + 0x00000C9C, // ..**..*..***. + 0x00000EB8, // ..***.*.***.. + 0x000007F0, // ...*******... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 163 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x000007F0, // ...*******... + 0x00000E38, // ..***...***.. + 0x00001818, // .**......**.. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x00001C00, // .***......... + 0x00000E00, // ..***........ + 0x00001FC0, // .*******..... + 0x00001F40, // .*****.*..... + 0x00000700, // ...***....... + 0x00000300, // ....**....... + 0x00000300, // ....**....... + 0x00000600, // ...**........ + 0x00000C00, // ..**......... + 0x00001FFC, // .***********. + 0x00001FF8, // .**********.. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 164 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000408, // ...*......*.. + 0x00000FD8, // ..******.**.. + 0x00000FF8, // ..*********.. + 0x00000E38, // ..***...***.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000E38, // ..***...***.. + 0x000007F0, // ...*******... + 0x00000FD8, // ..******.**.. + 0x00000408, // ...*......*.. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 165 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x0000180C, // .**.......**. + 0x00001818, // .**......**.. + 0x00000C18, // ..**.....**.. + 0x00000C30, // ..**....**... + 0x00000620, // ...**...*.... + 0x00000260, // ....*..**.... + 0x000003C0, // ....****..... + 0x00001DF8, // .***.******.. + 0x00001FF8, // .**********.. + 0x00000180, // .....**...... + 0x00001FF8, // .**********.. + 0x00001FF8, // .**********.. + 0x00000180, // .....**...... + 0x00000180, // .....**...... + 0x00000180, // .....**...... + 0x00000180, // .....**...... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 166 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + }, + { // 167 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000001E0, // .....****.... + 0x000007F0, // ...*******... + 0x00000E38, // ..***...***.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000E00, // ..***........ + 0x00000780, // ...****...... + 0x00000DE0, // ..**.****.... + 0x000018F0, // .**...****... + 0x00001838, // .**.....***.. + 0x0000181C, // .**......***. + 0x00001C0C, // .***......**. + 0x00000E0C, // ..***.....**. + 0x00000798, // ...****..**.. + 0x000001F0, // .....*****... + 0x000000E0, // ......***.... + 0x00000070, // .......***... + 0x00000C30, // ..**....**... + 0x00000C30, // ..**....**... + 0x00000E30, // ..***...**... + 0x000007E0, // ...******.... + 0x000003C0, // ....****..... + }, + { // 168 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x000000CC, // .**..**. + 0x000000CC, // .**..**. + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 169 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000F078, // ...****.....****.. + 0x0001C718, // ..***...***...**.. + 0x00038F8C, // .***...*****...**. + 0x000318CC, // .**...**...**..**. + 0x00063046, // **...**.....*...** + 0x00063006, // **...**.........** + 0x00063006, // **...**.........** + 0x00063006, // **...**.........** + 0x00063066, // **...**.....**..** + 0x000318C6, // .**...**...**...** + 0x00031FCC, // .**...*******..**. + 0x0001879C, // ..**....****..***. + 0x0000E078, // ...***......****.. + 0x00007FF0, // ....***********... + 0x00001F80, // ......******...... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 170 + 9, 27, + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x000000F0, // ..****... + 0x000001F8, // .******.. + 0x00000018, // .....**.. + 0x00000078, // ...****.. + 0x00000198, // .**..**.. + 0x00000198, // .**..**.. + 0x000001FC, // .*******. + 0x000000EC, // ..***.**. + 0x000001F8, // .******.. + 0x000001F8, // .******.. + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + 0x00000000, // ......... + }, + { // 171 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000110, // .....*...*... + 0x00000310, // ....**...*... + 0x00000670, // ...**..***... + 0x00000C40, // ..**...*..... + 0x00000C60, // ..**...**.... + 0x00000730, // ...***..**... + 0x00000310, // ....**...*... + 0x00000110, // .....*...*... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 172 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001FFE, // .************ + 0x00001FFE, // .************ + 0x00000006, // ...........** + 0x00000006, // ...........** + 0x00000006, // ...........** + 0x00000006, // ...........** + 0x00000006, // ...........** + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 173 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x000000F8, // .*****.. + 0x000000F8, // .*****.. + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 174 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000F078, // ...****.....****.. + 0x0001FF98, // ..**********..**.. + 0x0003BFCC, // .***.********..**. + 0x0003306C, // .**..**.....**.**. + 0x00063066, // **...**.....**..** + 0x00063066, // **...**.....**..** + 0x00063FC6, // **...********...** + 0x00063FE6, // **...*********..** + 0x00063066, // **...**.....**..** + 0x0003306E, // .**..**.....**.*** + 0x0003306C, // .**..**.....**.**. + 0x0001F07C, // ..*****.....*****. + 0x0000E078, // ...***......****.. + 0x00007FE0, // ....**********.... + 0x00001F80, // ......******...... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 175 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x000000FC, // .******. + 0x000000FC, // .******. + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 176 + 14, 27, + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x000003C0, // .....****..... + 0x000007E0, // ....******.... + 0x00000C30, // ...**....**... + 0x00000C30, // ...**....**... + 0x00000C30, // ...**....**... + 0x00000660, // ....**..**.... + 0x000007E0, // ....******.... + 0x000003C0, // .....****..... + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + }, + { // 177 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00000000, // ............. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 178 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000078, // ..****.. + 0x000000FE, // .******* + 0x00000086, // .*....** + 0x00000006, // ......** + 0x0000000C, // .....**. + 0x00000030, // ...**... + 0x000000E0, // .***.... + 0x00000080, // .*...... + 0x000000FE, // .******* + 0x0000007E, // ..****** + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 179 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000078, // ..****.. + 0x000000FC, // .******. + 0x0000008C, // .*...**. + 0x0000000C, // .....**. + 0x00000038, // ...***.. + 0x0000000C, // .....**. + 0x00000006, // ......** + 0x00000186, // **....** + 0x000000FC, // .******. + 0x00000078, // ..****.. + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 180 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x0000001C, // ....***. + 0x00000038, // ...***.. + 0x00000030, // ...**... + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 181 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FFC, // .***********. + 0x00001FDE, // .*******.**** + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + }, + { // 182 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x000001FE, // ....******** + 0x000003FE, // ...********* + 0x000007EC, // ..******.**. + 0x000007EC, // ..******.**. + 0x00000FEC, // .*******.**. + 0x00000FEC, // .*******.**. + 0x00000FEC, // .*******.**. + 0x00000FEC, // .*******.**. + 0x000007EC, // ..******.**. + 0x000007EC, // ..******.**. + 0x000001EC, // ....****.**. + 0x0000006C, // ......**.**. + 0x0000006C, // ......**.**. + 0x0000006C, // ......**.**. + 0x0000006C, // ......**.**. + 0x0000006C, // ......**.**. + 0x0000006C, // ......**.**. + 0x0000006C, // ......**.**. + 0x0000006C, // ......**.**. + 0x0000006C, // ......**.**. + 0x0000006C, // ......**.**. + 0x00000000, // ............ + }, + { // 183 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 184 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000010, // ....*... + 0x00000038, // ...***.. + 0x0000003C, // ...****. + 0x000000FC, // .******. + 0x00000038, // ...***.. + }, + { // 185 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000010, // ....*... + 0x00000070, // ..***... + 0x000000F0, // .****... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000030, // ...**... + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 186 + 8, 27, + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000078, // ..****.. + 0x0000007C, // ..*****. + 0x000000C6, // .**...** + 0x000000C6, // .**...** + 0x000000C6, // .**...** + 0x000000C6, // .**...** + 0x0000007C, // ..*****. + 0x00000038, // ...***.. + 0x000000FC, // .******. + 0x000000FC, // .******. + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + 0x00000000, // ........ + }, + { // 187 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000840, // ..*....*..... + 0x00000C60, // ..**...**.... + 0x00000730, // ...***..**... + 0x00000310, // ....**...*... + 0x00000330, // ....**..**... + 0x00000E60, // ..***..**.... + 0x00000C40, // ..**...*..... + 0x00000840, // ..*....*..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 188 + 20, 27, + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00030060, // ...**.........**.... + 0x00070040, // ..***.........*..... + 0x000F0080, // .****........*...... + 0x00030180, // ...**.......**...... + 0x00030300, // ...**......**....... + 0x00030200, // ...**......*........ + 0x00030618, // ...**.....**....**.. + 0x00030C18, // ...**....**.....**.. + 0x00030C38, // ...**....**....***.. + 0x00001878, // ........**....****.. + 0x000030D8, // .......**....**.**.. + 0x00007098, // ......***....*..**.. + 0x000061FE, // ......**....******** + 0x0000C1FE, // .....**.....******** + 0x0001C018, // ....***.........**.. + 0x00018008, // ....**...........*.. + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + }, + { // 189 + 20, 27, + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00030040, // ...**.........*..... + 0x00070080, // ..***........*...... + 0x000F0180, // .****.......**...... + 0x00030100, // ...**.......*....... + 0x00030300, // ...**......**....... + 0x00030600, // ...**.....**........ + 0x00030C78, // ...**....**...****.. + 0x00030CFC, // ...**....**..******. + 0x00031886, // ...**...**...*....** + 0x00003086, // .......**....*....** + 0x0000300C, // .......**........**. + 0x00006018, // ......**........**.. + 0x0000C060, // .....**.......**.... + 0x0000C080, // .....**......*...... + 0x000181FE, // ....**......******** + 0x0003007E, // ...**.........****** + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + }, + { // 190 + 20, 27, + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00078020, // ..****.........*.... + 0x000FC060, // .******.......**.... + 0x0008C0C0, // .*...**......**..... + 0x0000C080, // .....**......*...... + 0x00038180, // ...***......**...... + 0x0000C300, // .....**....**....... + 0x00006218, // ......**...*....**.. + 0x00186418, // **....**..*.....**.. + 0x000FCC38, // .******..**....***.. + 0x00078878, // ..****...*....****.. + 0x000010D8, // ........*....**.**.. + 0x00003098, // .......**....*..**.. + 0x000021FE, // .......*....******** + 0x000041FE, // ......*.....******** + 0x00008018, // .....*..........**.. + 0x00008008, // .....*...........*.. + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + }, + { // 191 + 14, 27, + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000180, // ......**...... + 0x00000180, // ......**...... + 0x00000380, // .....***...... + 0x00000700, // ....***....... + 0x00000E00, // ...***........ + 0x00000C00, // ...**......... + 0x00001800, // ..**.......... + 0x00001818, // ..**......**.. + 0x00001818, // ..**......**.. + 0x00001C38, // ..***....***.. + 0x00000FF0, // ...********... + 0x000007C0, // ....*****..... + }, + { // 192 + 15, 27, + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000100, // .......*....... + 0x00000080, // ........*...... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x000003C0, // ......****..... + 0x000007C0, // .....*****..... + 0x000006C0, // .....**.**..... + 0x000006E0, // .....**.***.... + 0x00000E60, // ....***..**.... + 0x00000C60, // ....**...**.... + 0x00000C70, // ....**...***... + 0x00001C30, // ...***....**... + 0x00001830, // ...**.....**... + 0x00001FF8, // ...**********.. + 0x00003FF8, // ..***********.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000700C, // .***........**. + 0x0000600C, // .**.........**. + 0x0000600E, // .**.........*** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 193 + 15, 27, + 0x000000E0, // ........***.... + 0x000000C0, // ........**..... + 0x00000180, // .......**...... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x000003C0, // ......****..... + 0x000007C0, // .....*****..... + 0x000006C0, // .....**.**..... + 0x000006E0, // .....**.***.... + 0x00000E60, // ....***..**.... + 0x00000C60, // ....**...**.... + 0x00000C70, // ....**...***... + 0x00001C30, // ...***....**... + 0x00001830, // ...**.....**... + 0x00001FF8, // ...**********.. + 0x00003FF8, // ..***********.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000700C, // .***........**. + 0x0000600C, // .**.........**. + 0x0000600E, // .**.........*** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 194 + 15, 27, + 0x00000180, // .......**...... + 0x000003C0, // ......****..... + 0x000006C0, // .....**.**..... + 0x00000460, // .....*...**.... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x000003C0, // ......****..... + 0x000007C0, // .....*****..... + 0x000006C0, // .....**.**..... + 0x000006E0, // .....**.***.... + 0x00000E60, // ....***..**.... + 0x00000C60, // ....**...**.... + 0x00000C70, // ....**...***... + 0x00001C30, // ...***....**... + 0x00001830, // ...**.....**... + 0x00001FF8, // ...**********.. + 0x00003FF8, // ..***********.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000700C, // .***........**. + 0x0000600C, // .**.........**. + 0x0000600E, // .**.........*** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 195 + 15, 27, + 0x00000000, // ............... + 0x00000720, // .....***..*.... + 0x00000FE0, // ....*******.... + 0x00000040, // .........*..... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x000003C0, // ......****..... + 0x000007C0, // .....*****..... + 0x000006C0, // .....**.**..... + 0x000006E0, // .....**.***.... + 0x00000E60, // ....***..**.... + 0x00000C60, // ....**...**.... + 0x00000C70, // ....**...***... + 0x00001C30, // ...***....**... + 0x00001830, // ...**.....**... + 0x00001FF8, // ...**********.. + 0x00003FF8, // ..***********.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000700C, // .***........**. + 0x0000600C, // .**.........**. + 0x0000600E, // .**.........*** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 196 + 15, 27, + 0x00000000, // ............... + 0x000006E0, // .....**.***.... + 0x000006E0, // .....**.***.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x000003C0, // ......****..... + 0x000007C0, // .....*****..... + 0x000006C0, // .....**.**..... + 0x000006E0, // .....**.***.... + 0x00000E60, // ....***..**.... + 0x00000C60, // ....**...**.... + 0x00000C70, // ....**...***... + 0x00001C30, // ...***....**... + 0x00001830, // ...**.....**... + 0x00001FF8, // ...**********.. + 0x00003FF8, // ..***********.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000700C, // .***........**. + 0x0000600C, // .**.........**. + 0x0000600E, // .**.........*** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 197 + 15, 27, + 0x00000380, // ......***...... + 0x000003C0, // ......****..... + 0x00000240, // ......*..*..... + 0x00000380, // ......***...... + 0x00000180, // .......**...... + 0x00000380, // ......***...... + 0x000003C0, // ......****..... + 0x000007C0, // .....*****..... + 0x000006C0, // .....**.**..... + 0x000006E0, // .....**.***.... + 0x00000E60, // ....***..**.... + 0x00000C60, // ....**...**.... + 0x00000C70, // ....**...***... + 0x00001C30, // ...***....**... + 0x00001830, // ...**.....**... + 0x00001FF8, // ...**********.. + 0x00003FF8, // ..***********.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000700C, // .***........**. + 0x0000600C, // .**.........**. + 0x0000600E, // .**.........*** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 198 + 23, 27, + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x0001FFF8, // .......**************.. + 0x0001FFF8, // .......**************.. + 0x00031800, // ......**...**.......... + 0x00031800, // ......**...**.......... + 0x00061800, // .....**....**.......... + 0x00061800, // .....**....**.......... + 0x000E1800, // ....***....**.......... + 0x000C1FF8, // ....**.....**********.. + 0x000C1FF8, // ....**.....**********.. + 0x00181800, // ...**......**.......... + 0x001FF800, // ...**********.......... + 0x003FF800, // ..***********.......... + 0x00301800, // ..**.......**.......... + 0x00301800, // ..**.......**.......... + 0x00701800, // .***.......**.......... + 0x00601FFC, // .**........***********. + 0x00E01FFC, // ***........***********. + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00000000, // ....................... + 0x00000000, // ....................... + }, + { // 199 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000FC0, // ......******..... + 0x00003FE0, // ....*********.... + 0x00007070, // ...***.....***... + 0x0000E038, // ..***.......***.. + 0x0000C018, // ..**.........**.. + 0x0000C000, // ..**............. + 0x00018000, // .**.............. + 0x00018000, // .**.............. + 0x00018000, // .**.............. + 0x00018000, // .**.............. + 0x00018000, // .**.............. + 0x00018018, // .**..........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x00006030, // ...**.......**... + 0x000078F0, // ...****...****... + 0x00001FE0, // .....********.... + 0x00000200, // ........*........ + 0x00000700, // .......***....... + 0x00000380, // ........***...... + 0x00000F80, // ......*****...... + 0x00000700, // .......***....... + }, + { // 200 + 15, 27, + 0x00000600, // .....**........ + 0x00000300, // ......**....... + 0x00000180, // .......**...... + 0x00000080, // ........*...... + 0x00000000, // ............... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FF8, // ..***********.. + 0x00003FF8, // ..***********.. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 201 + 15, 27, + 0x000000E0, // ........***.... + 0x000000C0, // ........**..... + 0x00000180, // .......**...... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FF8, // ..***********.. + 0x00003FF8, // ..***********.. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 202 + 15, 27, + 0x00000180, // .......**...... + 0x000003C0, // ......****..... + 0x00000640, // .....**..*..... + 0x00000460, // .....*...**.... + 0x00000000, // ............... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FF8, // ..***********.. + 0x00003FF8, // ..***********.. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 203 + 15, 27, + 0x00000000, // ............... + 0x00000660, // .....**..**.... + 0x00000660, // .....**..**.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FF8, // ..***********.. + 0x00003FF8, // ..***********.. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FFC, // ..************. + 0x00003FFC, // ..************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 204 + 6, 27, + 0x00000070, // ***... + 0x00000030, // .**... + 0x00000018, // ..**.. + 0x0000000C, // ...**. + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 205 + 6, 27, + 0x00000006, // ....** + 0x0000000C, // ...**. + 0x00000008, // ...*.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000008, // ...*.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 206 + 6, 27, + 0x00000030, // ..**... + 0x00000078, // .****.. + 0x0000004C, // .*..**. + 0x000000C4, // **...*. + 0x00000000, // ....... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000030, // ..**... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + 0x00000000, // ....... + }, + { // 207 + 6, 27, + 0x00000000, // ...... + 0x00000066, // **..** + 0x00000066, // **..** + 0x00000066, // **..** + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 208 + 17, 27, + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x0000FF80, // ..*********...... + 0x0000FFE0, // ..***********.... + 0x0000C0F0, // ..**......****... + 0x0000C030, // ..**........**... + 0x0000C030, // ..**........**... + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0003FC18, // ********.....**.. + 0x0003FC18, // ********.....**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C030, // ..**........**... + 0x0000C030, // ..**........**... + 0x0000C0E0, // ..**......***.... + 0x0000FFE0, // ..***********.... + 0x0000FF80, // ..*********...... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 209 + 17, 27, + 0x00000000, // ................. + 0x00000EC0, // ......***.**..... + 0x00001FC0, // .....*******..... + 0x00000180, // .........**...... + 0x00000000, // ................. + 0x0000C018, // ..**.........**.. + 0x0000E018, // ..***........**.. + 0x0000F018, // ..****.......**.. + 0x0000F018, // ..****.......**.. + 0x0000D818, // ..**.**......**.. + 0x0000DC18, // ..**.***.....**.. + 0x0000CC18, // ..**..**.....**.. + 0x0000C618, // ..**...**....**.. + 0x0000C718, // ..**...***...**.. + 0x0000C318, // ..**....**...**.. + 0x0000C398, // ..**....***..**.. + 0x0000C198, // ..**.....**..**.. + 0x0000C0D8, // ..**......**.**.. + 0x0000C0F8, // ..**......*****.. + 0x0000C078, // ..**.......****.. + 0x0000C038, // ..**........***.. + 0x0000C038, // ..**........***.. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 210 + 18, 27, + 0x00001800, // ......**.......... + 0x00000C00, // .......**......... + 0x00000600, // ........**........ + 0x00000200, // .........*........ + 0x00000000, // .................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000E0F0, // ...***.....****... + 0x0001C038, // ..***........***.. + 0x00018018, // ..**..........**.. + 0x0003801C, // .***..........***. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x00018018, // ..**..........**.. + 0x0001C038, // ..***........***.. + 0x0000E070, // ...***......***... + 0x00007FE0, // ....**********.... + 0x00001F80, // ......******...... + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + }, + { // 211 + 18, 27, + 0x00000180, // ..........**...... + 0x00000300, // .........**....... + 0x00000600, // ........**........ + 0x00000400, // ........*......... + 0x00000000, // .................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000E0F0, // ...***.....****... + 0x0001C038, // ..***........***.. + 0x00018018, // ..**..........**.. + 0x0003801C, // .***..........***. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x00018018, // ..**..........**.. + 0x0001C038, // ..***........***.. + 0x0000E070, // ...***......***... + 0x00007FE0, // ....**********.... + 0x00001F80, // ......******...... + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + }, + { // 212 + 18, 27, + 0x00000600, // ........**........ + 0x00000F00, // .......****....... + 0x00000900, // .......*..*....... + 0x00001080, // ......*....*...... + 0x00000000, // .................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000E0F0, // ...***.....****... + 0x0001C038, // ..***........***.. + 0x00018018, // ..**..........**.. + 0x0003801C, // .***..........***. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x00018018, // ..**..........**.. + 0x0001C038, // ..***........***.. + 0x0000E070, // ...***......***... + 0x00007FE0, // ....**********.... + 0x00001F80, // ......******...... + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + }, + { // 213 + 18, 27, + 0x00000000, // .................. + 0x00001CC0, // ......***..**..... + 0x00001F80, // ......******...... + 0x00000180, // ..........**...... + 0x00000000, // .................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000E0F0, // ...***.....****... + 0x0001C038, // ..***........***.. + 0x00018018, // ..**..........**.. + 0x0003801C, // .***..........***. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x00018018, // ..**..........**.. + 0x0001C038, // ..***........***.. + 0x0000E070, // ...***......***... + 0x00007FE0, // ....**********.... + 0x00001F80, // ......******...... + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + }, + { // 214 + 18, 27, + 0x00000000, // .................. + 0x00001980, // ......**..**...... + 0x00001980, // ......**..**...... + 0x00000000, // .................. + 0x00000000, // .................. + 0x00001F80, // ......******...... + 0x00007FE0, // ....**********.... + 0x0000E0F0, // ...***.....****... + 0x0001C038, // ..***........***.. + 0x00018018, // ..**..........**.. + 0x0003801C, // .***..........***. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x0003000C, // .**............**. + 0x00018018, // ..**..........**.. + 0x0001C038, // ..***........***.. + 0x0000E070, // ...***......***... + 0x00007FE0, // ....**********.... + 0x00001F80, // ......******...... + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + }, + { // 215 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000408, // ...*......*.. + 0x00000E18, // ..***....**.. + 0x00000730, // ...***..**... + 0x000003E0, // ....*****.... + 0x000001C0, // .....***..... + 0x000001E0, // .....****.... + 0x00000370, // ....**.***... + 0x00000638, // ...**...***.. + 0x00000418, // ...*.....**.. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 216 + 18, 27, + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00001F8C, // ......******...**. + 0x00007FE8, // ....**********.*.. + 0x0000E070, // ...***......***... + 0x0001C038, // ..***........***.. + 0x00018058, // ..**........*.**.. + 0x0003809C, // .***.......*..***. + 0x0003018C, // .**.......**...**. + 0x0003030C, // .**......**....**. + 0x0003060C, // .**.....**.....**. + 0x00030C0C, // .**....**......**. + 0x0003180C, // .**...**.......**. + 0x0003300C, // .**..**........**. + 0x0001E018, // ..****........**.. + 0x0001C038, // ..***........***.. + 0x0000E070, // ...***......***... + 0x0003FFE0, // .*************.... + 0x00023F80, // .*...*******...... + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + 0x00000000, // .................. + }, + { // 217 + 17, 27, + 0x00001C00, // .....***......... + 0x00000C00, // ......**......... + 0x00000600, // .......**........ + 0x00000300, // ........**....... + 0x00000000, // ................. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x00006070, // ...**......***... + 0x00007FE0, // ...**********.... + 0x00001FC0, // .....*******..... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 218 + 17, 27, + 0x00000180, // .........**...... + 0x00000300, // ........**....... + 0x00000200, // ........*........ + 0x00000400, // .......*......... + 0x00000000, // ................. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x00006070, // ...**......***... + 0x00007FE0, // ...**********.... + 0x00001FC0, // .....*******..... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 219 + 17, 27, + 0x00000700, // .......***....... + 0x00000700, // .......***....... + 0x00000D80, // ......**.**...... + 0x00001880, // .....**...*...... + 0x00000000, // ................. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x00006070, // ...**......***... + 0x00007FE0, // ...**********.... + 0x00001FC0, // .....*******..... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 220 + 17, 27, + 0x00000000, // ................. + 0x00001D80, // .....***.**...... + 0x00001D80, // .....***.**...... + 0x00000000, // ................. + 0x00000000, // ................. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x0000C018, // ..**.........**.. + 0x00006070, // ...**......***... + 0x00007FE0, // ...**********.... + 0x00001FC0, // .....*******..... + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + 0x00000000, // ................. + }, + { // 221 + 15, 27, + 0x000000E0, // ........***.... + 0x000000C0, // ........**..... + 0x00000180, // .......**...... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x0000600E, // .**.........*** + 0x0000700E, // .***........*** + 0x0000301C, // ..**.......***. + 0x00001818, // ...**......**.. + 0x00001C38, // ...***....***.. + 0x00000C30, // ....**....**... + 0x00000E60, // ....***..**.... + 0x00000760, // .....***.**.... + 0x000003C0, // ......****..... + 0x000003C0, // ......****..... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 222 + 15, 27, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003FF0, // ..**********... + 0x00003FF8, // ..***********.. + 0x0000301C, // ..**.......***. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x00003038, // ..**......***.. + 0x00003FF8, // ..***********.. + 0x00003FF0, // ..**********... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 223 + 14, 27, + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x000003E0, // .....*****.... + 0x000007F0, // ....*******... + 0x00000E38, // ...***...***.. + 0x00000C18, // ...**.....**.. + 0x00000C18, // ...**.....**.. + 0x00000C18, // ...**.....**.. + 0x00000C38, // ...**....***.. + 0x00000CE0, // ...**..***.... + 0x00000CF0, // ...**..****... + 0x00000C18, // ...**.....**.. + 0x00000C0C, // ...**......**. + 0x00000C0C, // ...**......**. + 0x00000C0C, // ...**......**. + 0x00000C0C, // ...**......**. + 0x00000C18, // ...**.....**.. + 0x00000CF8, // ...**..*****.. + 0x00000CE0, // ...**..***.... + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + }, + { // 224 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000300, // ....**....... + 0x00000180, // .....**...... + 0x00000080, // ......*...... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF8, // ..*********.. + 0x00000C18, // ..**.....**.. + 0x00000818, // ..*......**.. + 0x00000018, // .........**.. + 0x000003F8, // ....*******.. + 0x00000F98, // ..*****..**.. + 0x00001C18, // .***.....**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FFC, // .***********. + 0x000007DC, // ...*****.***. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 225 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000060, // .......**.... + 0x000000C0, // ......**..... + 0x00000180, // .....**...... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF8, // ..*********.. + 0x00000C18, // ..**.....**.. + 0x00000818, // ..*......**.. + 0x00000018, // .........**.. + 0x000003F8, // ....*******.. + 0x00000F98, // ..*****..**.. + 0x00001C18, // .***.....**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FFC, // .***********. + 0x000007DC, // ...*****.***. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 226 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000001C0, // .....***..... + 0x00000340, // ....**.*..... + 0x00000260, // ....*..**.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF8, // ..*********.. + 0x00000C18, // ..**.....**.. + 0x00000818, // ..*......**.. + 0x00000018, // .........**.. + 0x000003F8, // ....*******.. + 0x00000F98, // ..*****..**.. + 0x00001C18, // .***.....**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FFC, // .***********. + 0x000007DC, // ...*****.***. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 227 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000300, // ....**....... + 0x000007F0, // ...*******... + 0x000004E0, // ...*..***.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF8, // ..*********.. + 0x00000C18, // ..**.....**.. + 0x00000818, // ..*......**.. + 0x00000018, // .........**.. + 0x000003F8, // ....*******.. + 0x00000F98, // ..*****..**.. + 0x00001C18, // .***.....**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FFC, // .***********. + 0x000007DC, // ...*****.***. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 228 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000760, // ...***.**.... + 0x00000760, // ...***.**.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF8, // ..*********.. + 0x00000C18, // ..**.....**.. + 0x00000818, // ..*......**.. + 0x00000018, // .........**.. + 0x000003F8, // ....*******.. + 0x00000F98, // ..*****..**.. + 0x00001C18, // .***.....**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FFC, // .***********. + 0x000007DC, // ...*****.***. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 229 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000180, // .....**...... + 0x000001C0, // .....***..... + 0x00000240, // ....*..*..... + 0x000003C0, // ....****..... + 0x00000180, // .....**...... + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF8, // ..*********.. + 0x00000C18, // ..**.....**.. + 0x00000818, // ..*......**.. + 0x00000018, // .........**.. + 0x000003F8, // ....*******.. + 0x00000F98, // ..*****..**.. + 0x00001C18, // .***.....**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FFC, // .***********. + 0x000007DC, // ...*****.***. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 230 + 20, 27, + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x0001F3F0, // ....*****..******... + 0x0007FFF8, // ..****************.. + 0x00060E1C, // ..**.....***....***. + 0x00040C0C, // ..*......**......**. + 0x00001C0C, // ........***......**. + 0x0003FFFC, // ...****************. + 0x0007EFFC, // ..******.**********. + 0x000E0C00, // .***.....**......... + 0x000C0C0C, // .**......**......**. + 0x000C1E1C, // .**.....****....***. + 0x000FF7F8, // .********.********.. + 0x0007C3F0, // ..*****....******... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + 0x00000000, // .................... + }, + { // 231 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x000001F0, // ....*****... + 0x000007F8, // ..********.. + 0x0000061C, // ..**....***. + 0x00000C0C, // .**......**. + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C00, // .**......... + 0x00000C0C, // .**......**. + 0x0000061C, // ..**....***. + 0x00000738, // ..***..***.. + 0x000003F0, // ...******... + 0x00000080, // .....*...... + 0x000000E0, // .....***.... + 0x000000E0, // .....***.... + 0x000003E0, // ...*****.... + 0x000000C0, // .....**..... + }, + { // 232 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000300, // ....**....... + 0x00000180, // .....**...... + 0x00000080, // ......*...... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x000007F0, // ...*******... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00001800, // .**.......... + 0x00001808, // .**.......*.. + 0x00000C18, // ..**.....**.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 233 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000070, // .......***... + 0x000000E0, // ......***.... + 0x00000180, // .....**...... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x000007F0, // ...*******... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00001800, // .**.......... + 0x00001808, // .**.......*.. + 0x00000C18, // ..**.....**.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 234 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000001C0, // .....***..... + 0x00000160, // .....*.**.... + 0x00000320, // ....**..*.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x000007F0, // ...*******... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00001800, // .**.......... + 0x00001808, // .**.......*.. + 0x00000C18, // ..**.....**.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 235 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000370, // ....**.***... + 0x00000370, // ....**.***... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x000007F0, // ...*******... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00001800, // .**.......... + 0x00001808, // .**.......*.. + 0x00000C18, // ..**.....**.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 236 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000070, // ***... + 0x00000030, // .**... + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 237 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000000E, // ...*** + 0x0000000C, // ...**. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 238 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x0000001C, // ..***. + 0x0000003C, // .****. + 0x00000066, // **..** + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 239 + 6, 27, + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000066, // **..** + 0x00000066, // **..** + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000018, // ..**.. + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + 0x00000000, // ...... + }, + { // 240 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000420, // ...*....*.... + 0x000007C0, // ...*****..... + 0x00000780, // ...****...... + 0x000004C0, // ...*..**..... + 0x000000E0, // ......***.... + 0x000003F0, // ....******... + 0x00000FF8, // ..*********.. + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000181C, // .**......***. + 0x00000C38, // ..**....***.. + 0x00000FF8, // ..*********.. + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 241 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000300, // ....**....... + 0x000007F0, // ...*******... + 0x000004E0, // ...*..***.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000009F0, // ..*..*****... + 0x00000FF8, // ..*********.. + 0x00000E18, // ..***....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000C18, // ..**.....**.. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 242 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000300, // ....**....... + 0x00000180, // .....**...... + 0x00000080, // ......*...... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF0, // ..********... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000181C, // .**......***. + 0x00000C38, // ..**....***.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 243 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000060, // .......**.... + 0x000000C0, // ......**..... + 0x00000180, // .....**...... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF0, // ..********... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000181C, // .**......***. + 0x00000C38, // ..**....***.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 244 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000001C0, // .....***..... + 0x00000340, // ....**.*..... + 0x00000260, // ....*..**.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF0, // ..********... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000181C, // .**......***. + 0x00000C38, // ..**....***.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 245 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000300, // ....**....... + 0x000007F0, // ...*******... + 0x000004E0, // ...*..***.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF0, // ..********... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000181C, // .**......***. + 0x00000C38, // ..**....***.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 246 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000760, // ...***.**.... + 0x00000760, // ...***.**.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x000003E0, // ....*****.... + 0x00000FF0, // ..********... + 0x00000C38, // ..**....***.. + 0x0000181C, // .**......***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000181C, // .**......***. + 0x00000C38, // ..**....***.. + 0x00000FF0, // ..********... + 0x000003E0, // ....*****.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 247 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001FFC, // .***********. + 0x00001FFC, // .***********. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000000C0, // ......**..... + 0x000000C0, // ......**..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 248 + 14, 27, + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x000007C8, // ....*****..*.. + 0x00001FF0, // ..*********... + 0x00001830, // ..**.....**... + 0x00003078, // .**.....****.. + 0x00003098, // .**....*..**.. + 0x00003198, // .**...**..**.. + 0x00003318, // .**..**...**.. + 0x00003618, // .**.**....**.. + 0x00003438, // .**.*....***.. + 0x00001870, // ..**....***... + 0x00001FE0, // ..********.... + 0x000027C0, // .*..*****..... + 0x00002000, // .*............ + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + 0x00000000, // .............. + }, + { // 249 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000700, // ...***....... + 0x00000180, // .....**...... + 0x00000080, // ......*...... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FF8, // .**********.. + 0x000007C0, // ...*****..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 250 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000000E0, // ......***.... + 0x000000C0, // ......**..... + 0x00000180, // .....**...... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FF8, // .**********.. + 0x000007C0, // ...*****..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 251 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000001C0, // .....***..... + 0x00000340, // ....**.*..... + 0x00000260, // ....*..**.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FF8, // .**********.. + 0x000007C0, // ...*****..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 252 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x000006E0, // ...**.***.... + 0x00000260, // ....*..**.... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001818, // .**......**.. + 0x00001838, // .**.....***.. + 0x00001FF8, // .**********.. + 0x000007C0, // ...*****..... + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + }, + { // 253 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000070, // ......***... + 0x000000E0, // .....***.... + 0x00000080, // .....*...... + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000C0C, // .**......**. + 0x00000C1C, // .**.....***. + 0x00000C18, // .**.....**.. + 0x00000618, // ..**....**.. + 0x00000630, // ..**...**... + 0x00000630, // ..**...**... + 0x00000330, // ...**..**... + 0x00000360, // ...**.**.... + 0x00000360, // ...**.**.... + 0x000001E0, // ....****.... + 0x000001C0, // ....***..... + 0x000001C0, // ....***..... + 0x00000180, // ....**...... + 0x00000180, // ....**...... + 0x00000380, // ...***...... + 0x00000F00, // .****....... + 0x00000E00, // .***........ + }, + { // 254 + 13, 27, + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00000000, // ............. + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001BE0, // .**.*****.... + 0x00001FF8, // .**********.. + 0x00001E38, // .****...***.. + 0x00001C1C, // .***.....***. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x0000180C, // .**.......**. + 0x00001C1C, // .***.....***. + 0x00001E38, // .****...***.. + 0x00001FF8, // .**********.. + 0x000019E0, // .**..****.... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + 0x00001800, // .**.......... + }, + { // 255 + 12, 27, + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000370, // ...**.***... + 0x00000370, // ...**.***... + 0x00000000, // ............ + 0x00000000, // ............ + 0x00000C0C, // .**......**. + 0x00000C1C, // .**.....***. + 0x00000C18, // .**.....**.. + 0x00000618, // ..**....**.. + 0x00000630, // ..**...**... + 0x00000630, // ..**...**... + 0x00000330, // ...**..**... + 0x00000360, // ...**.**.... + 0x00000360, // ...**.**.... + 0x000001E0, // ....****.... + 0x000001C0, // ....***..... + 0x000001C0, // ....***..... + 0x00000180, // ....**...... + 0x00000180, // ....**...... + 0x00000380, // ...***...... + 0x00000F00, // .****....... + 0x00000E00, // .***........ + }, + }; diff --git a/genfontfile.c b/genfontfile.c new file mode 100644 index 000000000..a98f80124 --- /dev/null +++ b/genfontfile.c @@ -0,0 +1,378 @@ +/* Copyright (c) Mark J. Kilgard, 1997. */ + +/* This program is freely distributable without licensing fees and is + provided without guarantee or warrantee expressed or implied. This + program is -not- in the public domain. */ + +/* X compile line: cc -o gentexfont gentexfont.c -lX11 */ + +/* 2000-10-01: Stripped down the original code to get a simple bitmap C-code generator */ +/* for use with the VDR project (see http://www.cadsoft.de/people/kls/vdr) */ +/* Renamed the file 'genfontfile.c' since it no longer generates 'tex' data */ +/* Klaus Schmidinger (kls@cadsoft.de) */ + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + unsigned short c; /* Potentially support 16-bit glyphs. */ + unsigned char width; + unsigned char height; + signed char xoffset; + signed char yoffset; + signed char advance; + char dummy; /* Space holder for alignment reasons. */ + short x; + short y; +} TexGlyphInfo; + +typedef struct { + short width; + short height; + short xoffset; + short yoffset; + short advance; + unsigned char *bitmap; +} PerGlyphInfo, *PerGlyphInfoPtr; + +typedef struct { + int min_char; + int max_char; + int max_ascent; + int max_descent; + PerGlyphInfo glyph[1]; +} FontInfo, *FontInfoPtr; + +Display *dpy; +FontInfoPtr fontinfo; + +/* #define REPORT_GLYPHS */ +#ifdef REPORT_GLYPHS +#define DEBUG_GLYPH4(msg,a,b,c,d) printf(msg,a,b,c,d) +#define DEBUG_GLYPH(msg) printf(msg) +#else +#define DEBUG_GLYPH4(msg,a,b,c,d) { /* nothing */ } +#define DEBUG_GLYPH(msg) { /* nothing */ } +#endif + +#define MAX_GLYPHS_PER_GRAB 512 /* this is big enough for 2^9 glyph + character sets */ + +FontInfoPtr +SuckGlyphsFromServer(Display * dpy, Font font) +{ + Pixmap offscreen; + XFontStruct *fontinfo; + XImage *image; + GC xgc; + XGCValues values; + int numchars; + int width, height, pixwidth; + int i, j; + XCharStruct *charinfo; + XChar2b character; + unsigned char *bitmapData; + int x, y; + int spanLength; + int charWidth, charHeight, maxSpanLength; + int grabList[MAX_GLYPHS_PER_GRAB]; + int glyphsPerGrab = MAX_GLYPHS_PER_GRAB; + int numToGrab, thisglyph; + FontInfoPtr myfontinfo; + + fontinfo = XQueryFont(dpy, font); + if (!fontinfo) + return NULL; + + numchars = fontinfo->max_char_or_byte2 - fontinfo->min_char_or_byte2 + 1; + if (numchars < 1) + return NULL; + + myfontinfo = (FontInfoPtr) malloc(sizeof(FontInfo) + (numchars - 1) * sizeof(PerGlyphInfo)); + if (!myfontinfo) + return NULL; + + myfontinfo->min_char = fontinfo->min_char_or_byte2; + myfontinfo->max_char = fontinfo->max_char_or_byte2; + myfontinfo->max_ascent = fontinfo->max_bounds.ascent; + myfontinfo->max_descent = fontinfo->max_bounds.descent; + + width = fontinfo->max_bounds.rbearing - fontinfo->min_bounds.lbearing; + height = fontinfo->max_bounds.ascent + fontinfo->max_bounds.descent; + + maxSpanLength = (width + 7) / 8; + /* Be careful determining the width of the pixmap; the X protocol allows + pixmaps of width 2^16-1 (unsigned short size) but drawing coordinates + max out at 2^15-1 (signed short size). If the width is too large, we + need to limit the glyphs per grab. */ + if ((glyphsPerGrab * 8 * maxSpanLength) >= (1 << 15)) { + glyphsPerGrab = (1 << 15) / (8 * maxSpanLength); + } + pixwidth = glyphsPerGrab * 8 * maxSpanLength; + offscreen = XCreatePixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)), + pixwidth, height, 1); + + values.font = font; + values.background = 0; + values.foreground = 0; + xgc = XCreateGC(dpy, offscreen, GCFont | GCBackground | GCForeground, &values); + + XFillRectangle(dpy, offscreen, xgc, 0, 0, 8 * maxSpanLength * glyphsPerGrab, height); + XSetForeground(dpy, xgc, 1); + + numToGrab = 0; + if (fontinfo->per_char == NULL) { + charinfo = &(fontinfo->min_bounds); + charWidth = charinfo->rbearing - charinfo->lbearing; + charHeight = charinfo->ascent + charinfo->descent; + spanLength = (charWidth + 7) / 8; + } + for (i = 0; i < numchars; i++) { + if (fontinfo->per_char != NULL) { + charinfo = &(fontinfo->per_char[i]); + charWidth = charinfo->rbearing - charinfo->lbearing; + charHeight = charinfo->ascent + charinfo->descent; + if (charWidth == 0 || charHeight == 0) { + /* Still must move raster pos even if empty character */ + myfontinfo->glyph[i].width = 0; + myfontinfo->glyph[i].height = 0; + myfontinfo->glyph[i].xoffset = 0; + myfontinfo->glyph[i].yoffset = 0; + myfontinfo->glyph[i].advance = charinfo->width; + myfontinfo->glyph[i].bitmap = NULL; + goto PossiblyDoGrab; + } + } + grabList[numToGrab] = i; + + /* XXX is this right for large fonts? */ + character.byte2 = (i + fontinfo->min_char_or_byte2) & 255; + character.byte1 = (i + fontinfo->min_char_or_byte2) >> 8; + + /* XXX we could use XDrawImageString16 which would also paint the backing + + rectangle but X server bugs in some scalable font rasterizers makes it + + more effective to do XFillRectangles to clear the pixmap and + XDrawImage16 for the text. */ + XDrawString16(dpy, offscreen, xgc, + -charinfo->lbearing + 8 * maxSpanLength * numToGrab, + charinfo->ascent, &character, 1); + + numToGrab++; + + PossiblyDoGrab: + + if (numToGrab >= glyphsPerGrab || i == numchars - 1) { + image = XGetImage(dpy, offscreen, + 0, 0, pixwidth, height, 1, XYPixmap); + for (j = 0; j < numToGrab; j++) { + thisglyph = grabList[j]; + if (fontinfo->per_char != NULL) { + charinfo = &(fontinfo->per_char[thisglyph]); + charWidth = charinfo->rbearing - charinfo->lbearing; + charHeight = charinfo->ascent + charinfo->descent; + spanLength = (charWidth + 7) / 8; + } + bitmapData = calloc(height * spanLength, sizeof(char)); + if (!bitmapData) + goto FreeFontAndReturn; + DEBUG_GLYPH4("index %d, glyph %d (%d by %d)\n", + j, thisglyph + fontinfo->min_char_or_byte2, charWidth, charHeight); + for (y = 0; y < charHeight; y++) { + for (x = 0; x < charWidth; x++) { + /* XXX The algorithm used to suck across the font ensures that + each glyph begins on a byte boundary. In theory this would + make it convienent to copy the glyph into a byte oriented + bitmap. We actually use the XGetPixel function to extract + each pixel from the image which is not that efficient. We + could either do tighter packing in the pixmap or more + efficient extraction from the image. Oh well. */ + if (XGetPixel(image, j * maxSpanLength * 8 + x, charHeight - 1 - y)) { + DEBUG_GLYPH("x"); + bitmapData[y * spanLength + x / 8] |= (1 << (x & 7)); + } else { + DEBUG_GLYPH(" "); + } + } + DEBUG_GLYPH("\n"); + } + myfontinfo->glyph[thisglyph].width = charWidth; + myfontinfo->glyph[thisglyph].height = charHeight; + myfontinfo->glyph[thisglyph].xoffset = charinfo->lbearing; + myfontinfo->glyph[thisglyph].yoffset = -charinfo->descent; + myfontinfo->glyph[thisglyph].advance = charinfo->width; + myfontinfo->glyph[thisglyph].bitmap = bitmapData; + } + XDestroyImage(image); + numToGrab = 0; + /* do we need to clear the offscreen pixmap to get more? */ + if (i < numchars - 1) { + XSetForeground(dpy, xgc, 0); + XFillRectangle(dpy, offscreen, xgc, 0, 0, 8 * maxSpanLength * glyphsPerGrab, height); + XSetForeground(dpy, xgc, 1); + } + } + } + XFreeGC(dpy, xgc); + XFreePixmap(dpy, offscreen); + return myfontinfo; + +FreeFontAndReturn: + XDestroyImage(image); + XFreeGC(dpy, xgc); + XFreePixmap(dpy, offscreen); + for (j = i - 1; j >= 0; j--) { + if (myfontinfo->glyph[j].bitmap) + free(myfontinfo->glyph[j].bitmap); + } + free(myfontinfo); + return NULL; +} + +void +printGlyph(FontInfoPtr font, int c) +{ + PerGlyphInfoPtr glyph; + unsigned char *bitmapData; + int width, height, spanLength; + int x, y, l; + char buf[1000], *b; + + if (c < font->min_char || c > font->max_char) { + fprintf(stderr, "out of range glyph\n"); + exit(1); + } + glyph = &font->glyph[c - font->min_char]; + bitmapData = glyph->bitmap; + width = glyph->width; + spanLength = (width + 7) / 8; + height = glyph->height; + + printf(" { // %d\n", c); + printf(" %d, %d,\n", glyph->advance, font->max_ascent + font->max_descent); + for (y = 0; y < font->max_ascent - glyph->yoffset - height; y++) { + printf(" 0x%08X, // ", 0); + for (x = 0; x < glyph->xoffset + width || x < glyph->advance; x++) + putchar('.'); + putchar('\n'); + } + for (y = height; y-- > 0;) { + l = 0; + b = buf; + for (x = 0; x < glyph->xoffset; x++) + *b++ = '.'; + if (bitmapData) { + for (x = 0; x < width; x++) { + if (bitmapData[y * spanLength + x / 8] & (1 << (x & 7))) { + *b++ = '*'; + l |= 1; + } + else + *b++ = '.'; + l <<= 1; + } + for (x = 0; x < glyph->advance - width - glyph->xoffset; x++) { + *b++ = '.'; + l <<= 1; + } + } + *b = 0; + printf(" 0x%08X, // %s\n", l, buf); + } + for (y = 0; y < font->max_descent + glyph->yoffset; y++) { + printf(" 0x%08X, // ", 0); + for (x = 0; x < glyph->xoffset + width || x < glyph->advance; x++) + putchar('.'); + putchar('\n'); + } + printf(" },\n"); +} + +void +getMetric(FontInfoPtr font, int c, TexGlyphInfo * tgi) +{ + PerGlyphInfoPtr glyph; + unsigned char *bitmapData; + + tgi->c = c; + if (c < font->min_char || c > font->max_char) { + tgi->width = 0; + tgi->height = 0; + tgi->xoffset = 0; + tgi->yoffset = 0; + tgi->dummy = 0; + tgi->advance = 0; + return; + } + glyph = &font->glyph[c - font->min_char]; + bitmapData = glyph->bitmap; + if (bitmapData) { + tgi->width = glyph->width; + tgi->height = glyph->height; + tgi->xoffset = glyph->xoffset; + tgi->yoffset = glyph->yoffset; + } else { + tgi->width = 0; + tgi->height = 0; + tgi->xoffset = 0; + tgi->yoffset = 0; + } + tgi->dummy = 0; + tgi->advance = glyph->advance; +} + +int +main(int argc, char *argv[]) +{ + int c; + TexGlyphInfo tgi; + int usageError = 0; + char *varname, *fontname; + XFontStruct *xfont; + int i; + + if (argc == 3) { + varname = argv[1]; + fontname = argv[2]; + } + else + usageError = 1; + + if (usageError) { + fprintf(stderr, "\n"); + fprintf(stderr, "usage: genfontfile variable_name X_font_name\n"); + fprintf(stderr, "\n"); + exit(1); + } + + dpy = XOpenDisplay(NULL); + if (!dpy) { + fprintf(stderr, "could not open display\n"); + exit(1); + } + /* find an OpenGL-capable RGB visual with depth buffer */ + xfont = XLoadQueryFont(dpy, fontname); + if (!xfont) { + fprintf(stderr, "could not get load X font: %s\n", fontname); + exit(1); + } + fontinfo = SuckGlyphsFromServer(dpy, xfont->fid); + if (!fontinfo) { + fprintf(stderr, "could not get font glyphs\n"); + exit(1); + } + + printf("%s[][%d] = {\n", varname, fontinfo->max_ascent + fontinfo->max_descent + 2); + for (c = 32; c < 256; c++) { + getMetric(fontinfo, c, &tgi); + printGlyph(fontinfo, c); + } + printf(" };\n"); + return 0; +} diff --git a/interface.c b/interface.c index 3d01238b8..a0fca0ea0 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.19 2000/09/19 17:41:23 kls Exp $ + * $Id: interface.c 1.21 2000/10/03 13:28:02 kls Exp $ */ #include "interface.h" @@ -69,6 +69,8 @@ unsigned int cInterface::GetCh(bool Wait) eKeys cInterface::GetKey(bool Wait) { + if (open) + cDvbApi::PrimaryDvbApi->Flush(); if (SVDRP) SVDRP->Process(); eKeys Key = keyFromWait != kNone ? keyFromWait : Keys.Get(GetCh(Wait)); @@ -84,6 +86,8 @@ void cInterface::PutKey(eKeys Key) eKeys cInterface::Wait(int Seconds, bool KeepChar) { eKeys Key = kNone; + if (open) + cDvbApi::PrimaryDvbApi->Flush(); RcIo.Flush(500); if (cFile::AnyFileReady(-1, Seconds * 1000)) Key = GetKey(); @@ -326,15 +330,8 @@ eKeys cInterface::DisplayChannel(int Number, const char *Name, bool WithInfo) if (Number) RcIo.Number(Number); if (Name && !Recording()) { - char *RunningTitle = "", *RunningSubtitle = "", *NextTitle = "", *NextSubtitle = ""; - int Lines = 0; - if (Number && WithInfo && EIT.IsValid()) { - if (*(RunningTitle = EIT.GetRunningTitle())) Lines++; - if (*(RunningSubtitle = EIT.GetRunningSubtitle())) Lines++; - if (*(NextTitle = EIT.GetNextTitle())) Lines++; - if (*(NextSubtitle = EIT.GetNextSubtitle())) Lines++; - } - Open(MenuColumns, Lines + 1); + Open(MenuColumns, 5); + cDvbApi::PrimaryDvbApi->Fill(0, 0, MenuColumns, 1, clrBackground); int BufSize = MenuColumns + 1; char buffer[BufSize]; if (Number) @@ -346,27 +343,38 @@ eKeys cInterface::DisplayChannel(int Number, const char *Name, bool WithInfo) struct tm *now = localtime(&t); snprintf(buffer, BufSize, "%02d:%02d", now->tm_hour, now->tm_min); Write(-5, 0, buffer); + cDvbApi::PrimaryDvbApi->Flush(); + + char *RunningTitle = "", *RunningSubtitle = "", *NextTitle = "", *NextSubtitle = ""; + int Lines = 0; + if (Number && WithInfo && EIT.IsValid()) { + if (*(RunningTitle = EIT.GetRunningTitle())) Lines++; + if (*(RunningSubtitle = EIT.GetRunningSubtitle())) Lines++; + if (*(NextTitle = EIT.GetNextTitle())) Lines++; + if (*(NextSubtitle = EIT.GetNextSubtitle())) Lines++; + } if (Lines > 0) { const int t = 6; - int w = MenuColumns - t; int l = 1; + cDvbApi::PrimaryDvbApi->Fill(0, 1, MenuColumns, Lines, clrBackground); if (*RunningTitle) { Write(0, l, EIT.GetRunningTime(), clrYellow, clrBackground); - snprintf(buffer, BufSize, "%.*s", w, RunningTitle); Write(t, l, buffer, clrCyan, clrBackground); + Write(t, l, RunningTitle, clrCyan, clrBackground); l++; } if (*RunningSubtitle) { - snprintf(buffer, BufSize, "%.*s", w, RunningSubtitle); Write(t, l, buffer, clrCyan, clrBackground); + Write(t, l, RunningSubtitle, clrCyan, clrBackground); l++; } if (*NextTitle) { Write(0, l, EIT.GetNextTime(), clrYellow, clrBackground); - snprintf(buffer, BufSize, "%.*s", w, NextTitle); Write(t, l, buffer, clrCyan, clrBackground); + Write(t, l, NextTitle, clrCyan, clrBackground); l++; } if (*NextSubtitle) { - snprintf(buffer, BufSize, "%.*s", w, NextSubtitle); Write(t, l, buffer, clrCyan, clrBackground); + Write(t, l, NextSubtitle, clrCyan, clrBackground); } + cDvbApi::PrimaryDvbApi->Flush(); } eKeys Key = Wait(5, true); if (Key == kOk) diff --git a/menu.c b/menu.c index 114ea7ef7..1f5fd8885 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.27 2000/09/11 21:13:46 kls Exp $ + * $Id: menu.c 1.30 2000/10/03 14:06:44 kls Exp $ */ #include "menu.h" @@ -985,7 +985,7 @@ cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording) void cMenuRecordingItem::Set(void) { - SetText(recording->Title('\t')); + SetText(recording->Title('\t', true)); } // --- cMenuRecordings ------------------------------------------------------- @@ -1002,7 +1002,7 @@ class cMenuRecordings : public cOsdMenu { }; cMenuRecordings::cMenuRecordings(void) -:cOsdMenu("Recordings", 9, 6) +:cOsdMenu("Recordings", 6, 6) { if (Recordings.Load()) { cRecording *recording = Recordings.First(); @@ -1186,7 +1186,7 @@ cDirectChannelSelect::~cDirectChannelSelect() eOSState cDirectChannelSelect::ProcessKey(eKeys Key) { switch (Key) { - case k0: case k1: case k2: case k3: case k4: case k5: case k6: case k7: case k8: case k9: + case k0 ... k9: if (number >= 0) { number = number * 10 + Key - k0; cChannel *channel = Channels.GetByNumber(number); diff --git a/recording.c b/recording.c index 9f3b38858..60ea4a1c0 100644 --- a/recording.c +++ b/recording.c @@ -1,10 +1,10 @@ /* - * recording.h: Recording file handling + * recording.c: Recording file handling * * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.15 2000/07/29 14:08:17 kls Exp $ + * $Id: recording.c 1.18 2000/10/03 12:39:28 kls Exp $ */ #define _GNU_SOURCE @@ -15,6 +15,7 @@ #include #include #include +#include "dvbapi.h" #include "interface.h" #include "tools.h" #include "videodir.h" @@ -170,18 +171,24 @@ const char *cRecording::FileName(void) return fileName; } -const char *cRecording::Title(char Delimiter) +const char *cRecording::Title(char Delimiter, bool NewIndicator) { + char New = ' '; + if (NewIndicator) { + cResumeFile ResumeFile(FileName()); + if (ResumeFile.Read() <= 0) + New = '*'; + } delete titleBuffer; titleBuffer = NULL; struct tm *t = localtime(&start); - asprintf(&titleBuffer, "%02d.%02d.%02d%c%02d:%02d%c%s", + asprintf(&titleBuffer, "%02d.%02d%c%02d:%02d%c%c%s", t->tm_mday, t->tm_mon + 1, - t->tm_year % 100, Delimiter, t->tm_hour, t->tm_min, + New, Delimiter, name); return titleBuffer; diff --git a/recording.h b/recording.h index dc3b3d748..7511c6591 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.9 2000/07/28 13:53:54 kls Exp $ + * $Id: recording.h 1.10 2000/10/03 12:27:49 kls Exp $ */ #ifndef __RECORDING_H @@ -31,7 +31,7 @@ class cRecording : public cListObject { cRecording(const char *FileName); ~cRecording(); const char *FileName(void); - const char *Title(char Delimiter = ' '); + const char *Title(char Delimiter = ' ', bool NewIndicator = false); const char *Summary(void) { return summary; } bool WriteSummary(void); bool Delete(void); diff --git a/remote.c b/remote.c index 46565a804..1bf810854 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.13 2000/09/19 17:40:52 kls Exp $ + * $Id: remote.c 1.15 2000/10/03 10:49:58 kls Exp $ */ #include "remote.h" @@ -339,6 +339,7 @@ bool cRcIoRCU::DetectCode(unsigned char *Code, unsigned short *Address) cRcIoLIRC::cRcIoLIRC(char *DeviceName) { + repeat = 1; struct sockaddr_un addr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, DeviceName); @@ -361,23 +362,27 @@ cRcIoLIRC::~cRcIoLIRC() const char *cRcIoLIRC::ReceiveString(void) { - char buf[LIRC_BUFFER_SIZE]; + int oldrepeat = 1; - while (InputAvailable(true)) { - if (read(f, buf, sizeof(buf)) > 21) { - const int now = time_ms(); - int repeat; - sscanf(buf, "%*s %x %7s", &repeat, keyName); // '7' in '%7s' is LIRC_KEY_BUF-1! - if (repeat == 0) { - firstTime = lastTime = now; - return keyName; - } - else if ((now > firstTime + REPEATDELAY) && (now > lastTime + REPEATLIMIT)) { - lastTime = now; - return keyName; - } - } + if (repeat != 0) { + Flush(); + if (repeat != 0) { + oldrepeat = repeat; + Flush(REPEATLIMIT); } + } + + if (repeat == 0) { + firstTime = time_ms(); + repeat = 1; + return keyName; + } + + if ((repeat > 1) && (repeat != oldrepeat) && (time_ms() > firstTime + REPEATDELAY)) { + repeat = 1; + return keyName; + } + return NULL; } @@ -386,14 +391,10 @@ void cRcIoLIRC::Flush(int WaitMs) char buf[LIRC_BUFFER_SIZE]; int t0 = time_ms(); - for (;;) { - while (InputAvailable(false)) { - read(f, buf, sizeof(buf)); - t0 = time_ms(); - } - if (time_ms() - t0 >= WaitMs) - break; - } + do { + if (InputAvailable(false) && (read(f, buf, sizeof(buf)) > 21)) + sscanf(buf, "%*x %x %7s", &repeat, keyName); // '7' in '%7s' is LIRC_KEY_BUF-1! + } while ((repeat != 0) && (time_ms() < t0 + WaitMs)); } bool cRcIoLIRC::InputAvailable(bool Wait) @@ -403,7 +404,6 @@ bool cRcIoLIRC::InputAvailable(bool Wait) bool cRcIoLIRC::GetCommand(unsigned int *Command, unsigned short *) { - Flush(); if (Command) { const char *cmd = ReceiveString(); if (cmd) { diff --git a/remote.h b/remote.h index 03f915550..75dc4ac1b 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.9 2000/09/19 17:39:36 kls Exp $ + * $Id: remote.h 1.10 2000/10/03 10:45:35 kls Exp $ */ #ifndef __REMOTE_H @@ -29,7 +29,7 @@ class cRcIoBase { virtual void SetPoints(unsigned char Dp, bool On) {} virtual bool String(char *s) { return true; } virtual bool DetectCode(unsigned char *Code, unsigned short *Address) { return true; } - virtual void Flush(int WaitMs = 0) {} + virtual void Flush(int WaitMs = 0) = 0; virtual bool InputAvailable(bool Wait = false) = 0; virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL) = 0; }; @@ -81,6 +81,7 @@ class cRcIoLIRC : public cRcIoBase { enum { LIRC_KEY_BUF = 8, LIRC_BUFFER_SIZE = 128 }; cFile f; char keyName[LIRC_KEY_BUF]; + int repeat; const char *ReceiveString(void); public: cRcIoLIRC(char *DeviceName); diff --git a/timers.conf b/timers.conf index a625527fc..2a58454b6 100644 --- a/timers.conf +++ b/timers.conf @@ -1,14 +1,16 @@ 1:15:M------:2128:2205:99:7:Neues: 1:3:-T-----:2013:2125:99:99:SevenDays: -0:10:-T-----:2058:2202:99:10:Quarks: -1:26:-T-----:2255:0015:99:99:UFO: -1:3:---T---:2215:2315:99:10:IngoAppelt: +1:10:-T-----:2058:2202:99:10:Quarks: +1:26:-T-----:2235:2345:99:99:UFO: +1:2:--W----:2110:2325:99:99:BulleVonToelz: +1:3:---T---:2210:2315:99:10:IngoAppelt: 1:2:----F--:2140:2225:10:10:WWW: 1:1:----F--:2212:2325:99:99:7Tage7Koepfe: -1:11:-----S-:2158:2235:99:99:Computer: -1:2:-----S-:2213:2320:99:30:Wochenshow: +1:11:-----S-:2058:2135:99:99:Computer: +1:2:-----S-:2211:2340:99:30:Wochenshow: 1:11:------S:2013:2035:99:10:Centauri: 1:14:------S:2158:2235:99:14:MaxUndLisa: -1:15:MTWTF--:1828:1901:10:5:nano: +0:15:MTWTF--:1828:1901:10:5:nano: 1:1:-TWTF--:0955:1040:99:99:Ellen: -1:1:MTWTF--:1553:1710:99:99:Hammerman: +0:1:MTWTF--:1553:1710:99:99:Hammerman: +1:1:4:0755:0910:99:99:Hammerman: diff --git a/tools.c b/tools.c index 79d2ee6ca..5bb56e6df 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.19 2000/09/19 17:55:09 kls Exp $ + * $Id: tools.c 1.20 2000/09/29 16:19:28 kls Exp $ */ #define _GNU_SOURCE @@ -17,7 +17,6 @@ #endif #include #include -#include #include #include #include diff --git a/tools.h b/tools.h index 5c749a7c2..441f5715a 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.15 2000/09/17 07:58:19 kls Exp $ + * $Id: tools.h 1.16 2000/09/29 16:19:31 kls Exp $ */ #ifndef __TOOLS_H @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/vdr.c b/vdr.c index 91643c2f3..042b03ce7 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.35 2000/09/20 16:45:01 kls Exp $ + * $Id: vdr.c 1.36 2000/10/03 13:52:26 kls Exp $ */ #include @@ -193,12 +193,14 @@ int main(int argc, char *argv[]) cOsdBase *Menu = NULL; cReplayControl *ReplayControl = NULL; int LastChannel = -1; + int PreviousChannel = CurrentChannel; while (!Interrupted) { // Channel display: if (CurrentChannel != LastChannel) { if (!Menu) Channels.ShowChannel(CurrentChannel, LastChannel > 0); + PreviousChannel = LastChannel; LastChannel = CurrentChannel; } // Timers and Recordings: @@ -244,8 +246,13 @@ int main(int argc, char *argv[]) } else { switch (key) { + // Toggle channels: + case k0: + if (PreviousChannel != CurrentChannel) + Channels.SwitchTo(PreviousChannel); + break; // Direct Channel Select: - case k0: case k1: case k2: case k3: case k4: case k5: case k6: case k7: case k8: case k9: + case k1 ... k9: if (!Interface.Recording()) Menu = new cDirectChannelSelect(key); break; From a379eb714f7f5ef9a12efbe7588bb3509faba056 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 8 Oct 2000 18:00:00 +0200 Subject: [PATCH 013/307] Version 0.66 - Remote control data is now received in a separate thread, which makes things a lot smoother. - Repeat and release of remote control keys is now explicitly distinguished. - In replay mode the search forward/back and skip functions now have two modes: Pressing the key shortly and releasing it starts the function, and pressing it again stops it. Pressing and holding down the key starts the function and releasing the key stops it. - The '@' character that marks an "instant recording" can now be turned off in the "Setup" menu (thanks to Matthias Schniedermeyer). - Pressing the "Back" button while replaying now stops replaying and brings up the "Recordings" menu (suggested by Carsten Koch). This can be used to easily delete a recording after watching it, or to switch to a different recording. - The "Recordings" menu now places the cursor on the last replayed recording, if that file still exists. - The "Blue" button in the "Main" menu can now be used to "Resume" a previously stopped replay session (suggested by Martin Hammerschmid). - The low and high LNB frequencies can now be changed in the "Setup" menu. --- CONTRIBUTORS | 5 + FORMATS | 8 ++ HISTORY | 22 +++- MANUAL | 29 ++++- Makefile | 11 +- config.c | 17 ++- config.h | 17 ++- dvbapi.c | 8 +- dvbosd.c | 8 +- interface.c | 82 ++++++++------ interface.h | 15 +-- menu.c | 105 ++++++++++------- menu.h | 16 ++- osd.c | 26 +++-- recording.c | 4 +- remote.c | 309 ++++++++++++++++++++++++++++++++------------------- remote.h | 44 ++++---- setup.conf | 3 + svdrp.c | 6 +- thread.c | 105 +++++++++++++++++ thread.h | 57 ++++++++++ timers.conf | 10 +- tools.c | 18 ++- tools.h | 3 +- vdr.c | 36 ++++-- 25 files changed, 682 insertions(+), 282 deletions(-) create mode 100644 thread.c create mode 100644 thread.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 2eefd64be..91c9540ec 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -7,6 +7,7 @@ Carsten Koch for adding the 'epg2timers' tool (see Tools/epg2timers) for his idea of using multiple disks (and for testing this feature) for implementing the 'new recording' indicator + for suggesting that the "Back" button in replay mode should bring up the "Recordings" menu Plamen Ganev for fixing the frequency offset for Hotbird channels @@ -31,6 +32,10 @@ Niels de Carpentier Martin Hammerschmid for suggesting to display the direct channel select input on the OSD + for suggesting to use the "Blue" button in the main menu to resume replay Bastian Guse for writing the FORMATS entry for timers.conf + +Matthias Schniedermeyer + for implementing the 'MarkInstantRecord' setup option. diff --git a/FORMATS b/FORMATS index eb9de0f5c..331fe3d55 100644 --- a/FORMATS +++ b/FORMATS @@ -55,3 +55,11 @@ Video Disk Recorder File Formats - Name of timer (will be used to name the recording) - Summary +* setup.conf + + This file contains the basic configuration options for VDR. + + Each line contains one option in the format "Name = Value". + + See the MANUAL file for a description of the available options. + diff --git a/HISTORY b/HISTORY index 481e83ede..717102a6f 100644 --- a/HISTORY +++ b/HISTORY @@ -212,7 +212,7 @@ Video Disk Recorder Revision History against the version 0.71 DVB driver file 'dvb.c'). - When switching channels the channel is now immediately displayed, and the current/next information is shown as soon as it becomes available. -- No longer displaying the year in the 'Recordings' menu to saves space for the +- No longer displaying the year in the 'Recordings' menu to save space for the title. - The 'Recordings' menu now displays a '*' to indicate new recordings. - Added the description of the timers.conf file to the FORMATS file (thanks to @@ -221,3 +221,23 @@ Video Disk Recorder Revision History that would display only partially). - In normal viewing mode the '0' key now toggles between the current and the previous channel. + +2000-10-08: Version 0.66 + +- Remote control data is now received in a separate thread, which makes things + a lot smoother. +- Repeat and release of remote control keys is now explicitly distinguished. +- In replay mode the search forward/back and skip functions now have two modes: + Pressing the key shortly and releasing it starts the function, and pressing it + again stops it. Pressing and holding down the key starts the function and + releasing the key stops it. +- The '@' character that marks an "instant recording" can now be turned off + in the "Setup" menu (thanks to Matthias Schniedermeyer). +- Pressing the "Back" button while replaying now stops replaying and brings up + the "Recordings" menu (suggested by Carsten Koch). This can be used to easily + delete a recording after watching it, or to switch to a different recording. +- The "Recordings" menu now places the cursor on the last replayed recording, if + that file still exists. +- The "Blue" button in the "Main" menu can now be used to "Resume" a previously + stopped replay session (suggested by Martin Hammerschmid). +- The low and high LNB frequencies can now be changed in the "Setup" menu. diff --git a/MANUAL b/MANUAL index 24ee3ff5a..9b864e367 100644 --- a/MANUAL +++ b/MANUAL @@ -16,11 +16,11 @@ Video Disk Recorder User's Manual Right Next group - - Enable Increment - Search forward Ok Ch display Select Switch Edit Accept Play Progress disp. Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on - Back - Menu off Main menu Main menu Discard Main menu - + Back - Menu off Main menu Main menu Discard Main menu Recordings menu Red - Record Edit Edit - Play - Green - - New New - - Skip -60s Yellow - - Delete Delete - Delete Skip +60s - Blue - - Mark Mark - - Stop + Blue - Resume Mark Mark - - Stop 0..9 Ch select - - - Numeric inp. - - * Navigating through the On Screen Menus @@ -90,7 +90,7 @@ Video Disk Recorder User's Manual * Instant Recording You can start recording the current channel by pressing the "Red" button - in the Main menu. This will create a timer event named "@channelname" that + in the "Main" menu. This will create a timer event named "@channelname" that starts 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 pressing the "Menu" button and selecting @@ -101,8 +101,10 @@ Video Disk Recorder User's Manual 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. New recordings are marked with an '*'. - Playback can be stopped via the Main menu by selecting "Stop replaying", + Playback can be stopped via the "Main" menu by selecting "Stop replaying", or by pressing the "Blue" button outside the menu. + A previously stopped playback session can be resumed by pressing the "Blue" + button in the "Main" menu. * Replay Control @@ -118,12 +120,19 @@ Video Disk Recorder User's Manual Right Runs playback forward or backward at a higher speed; press again to resume normal speed. If in Pause mode, runs forward or backward at a slower speed; press again to return to pause mode. + Pressing and holding down the button performs the function until + the button is released again. - Green Yellow Skips about 60 seconds back or forward. + Pressing and holding down the button performs the function until + the button is released again. - Ok Brings up the replay progress display, which shows the date, time and title of the recording, a progress bar and the current and total time of the recording. Press "Ok" again to turn off the progress display. + - Back Stops replaying and brings up the "Recordings" menu. This can be + used to easily delete a recording after watching it, or to switch + to a different recording. * Programming the Timer @@ -171,7 +180,7 @@ Video Disk Recorder User's Manual * Parameters in the "Setup" menu - Select "Setup" from the main menu to enter the setup menu. From there you can + Select "Setup" from the "Main" menu to enter the setup menu. From there you can modify the following system parameters (note that "boolean" values will be displayed as "no" and "yes" in the "Setup" menu, while in the setup file they are stored as '0' and '1', respectively): @@ -197,3 +206,13 @@ Video Disk Recorder User's Manual 1 = dto., but the cursor remains at the bottom (top) of the page (this mode allows for faster scrolling through long lists). + + MarkInstantRecord = 1 Defines whether an "instant recording" (started by + pressing the "Red" button in the "Main" menu) will be + marked with a '@' character to make it distinguishable + from timer recordings in the "Recordings" menu. + 0 = instant recordings will not be marked + 1 = instant recordings will be marked. + + LnbFrequLo = 9750 The low and high LNB frequencies (in MHz) + LnbFrequHi = 10600 diff --git a/Makefile b/Makefile index 15757744b..8b32be2d8 100644 --- a/Makefile +++ b/Makefile @@ -4,13 +4,13 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.12 2000/10/01 14:27:12 kls Exp $ +# $Id: Makefile 1.13 2000/10/07 16:24:08 kls Exp $ DVBDIR = ../DVB INCLUDES = -I$(DVBDIR)/driver OBJS = config.o dvbapi.o dvbosd.o eit.o font.o interface.o menu.o osd.o\ - recording.o remote.o svdrp.o tools.o vdr.o videodir.o + recording.o remote.o svdrp.o thread.o tools.o vdr.o videodir.o OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 @@ -40,12 +40,13 @@ dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tool dvbosd.o : dvbosd.c dvbosd.h font.h tools.h eit.o : eit.c eit.h tools.h font.o : font.c font.h fontosd.c tools.h -interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h tools.h +interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h menu.o : menu.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h osd.o : osd.c config.h dvbapi.h dvbosd.h font.h interface.h osd.h svdrp.h tools.h recording.o: recording.c config.h dvbapi.h dvbosd.h font.h interface.h recording.h svdrp.h tools.h videodir.h -remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h tools.h +remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h thread.h tools.h svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h +thread.o : thread.c thread.h tools.o : tools.c tools.h vdr.o : vdr.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h videodir.o : videodir.c tools.h videodir.h @@ -53,7 +54,7 @@ videodir.o : videodir.c tools.h videodir.h # The main program: vdr: $(OBJS) - g++ -g -O2 $(OBJS) -lncurses -ljpeg -o vdr + g++ -g -O2 $(OBJS) -lncurses -ljpeg -lpthread -o vdr # The font file: diff --git a/config.c b/config.c index e161efd76..1714651fa 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.23 2000/09/17 09:11:59 kls Exp $ + * $Id: config.c 1.26 2000/10/08 16:10:40 kls Exp $ */ #include "config.h" @@ -275,7 +275,7 @@ bool cChannel::Switch(cDvbApi *DvbApi) } return false; } - Interface.Info(DvbApi->Recording() ? "Channel locked (recording)!" : name); + Interface->Info(DvbApi->Recording() ? "Channel locked (recording)!" : name); return false; } @@ -303,7 +303,7 @@ cTimer::cTimer(bool Instant) *file = 0; summary = NULL; if (Instant && ch) - snprintf(file, sizeof(file), "@%s", ch->name); + snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", ch->name); } cTimer::~cTimer() @@ -566,7 +566,7 @@ eKeys cChannels::ShowChannel(int Number, bool Switched, bool Group) { cChannel *channel = Group ? Get(Number) : GetByNumber(Number); if (channel) - return Interface.DisplayChannel(channel->number, channel->name, !Switched || Setup.ShowInfoOnChSwitch); + return Interface->DisplayChannel(channel->number, channel->name, !Switched || Setup.ShowInfoOnChSwitch); return kNone; } @@ -596,6 +596,9 @@ cSetup::cSetup(void) PrimaryDVB = 1; ShowInfoOnChSwitch = 1; MenuScrollPage = 1; + MarkInstantRecord = 1; + LnbFrequLo = 9750; + LnbFrequHi = 10600; } bool cSetup::Parse(char *s) @@ -607,6 +610,9 @@ bool cSetup::Parse(char *s) if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); + else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); + else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); + else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); else return false; return true; @@ -651,6 +657,9 @@ bool cSetup::Save(const char *FileName) fprintf(f, "PrimaryDVB = %d\n", PrimaryDVB); fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch); fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage); + fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord); + fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo); + fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); fclose(f); isyslog(LOG_INFO, "saved setup to %s", FileName); return true; diff --git a/config.h b/config.h index 224a7b3bc..56f361822 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.22 2000/10/01 14:14:18 kls Exp $ + * $Id: config.h 1.27 2000/10/08 16:33:48 kls Exp $ */ #ifndef __CONFIG_H @@ -17,7 +17,7 @@ #include "dvbapi.h" #include "tools.h" -#define VDRVERSION "0.65" +#define VDRVERSION "0.66" #define MaxBuffer 10000 @@ -34,9 +34,17 @@ enum eKeys { // "Up" and "Down" must be the first two keys! kYellow, kBlue, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, - kNone + kNone, + // The following flags are OR'd with the above codes: + k_Repeat = 0x8000, + k_Release = 0x4000, + k_Flags = k_Repeat | k_Release, }; +#define RAWKEY(k) ((k) & ~k_Flags) +#define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) +#define NORMALKEY(k) ((k) & ~k_Repeat) + struct tKey { eKeys type; char *name; @@ -223,6 +231,9 @@ class cSetup { int PrimaryDVB; int ShowInfoOnChSwitch; int MenuScrollPage; + int MarkInstantRecord; + int LnbFrequLo; + int LnbFrequHi; cSetup(void); bool Load(const char *FileName); bool Save(const char *FileName = NULL); diff --git a/dvbapi.c b/dvbapi.c index 04873fcc0..e5c692cbd 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.30 2000/10/03 13:26:16 kls Exp $ + * $Id: dvbapi.c 1.31 2000/10/08 16:14:45 kls Exp $ */ #include "dvbapi.h" @@ -19,7 +19,7 @@ extern "C" { #include #include #include -#include "dvbapi.h" +#include "config.h" #include "interface.h" #include "tools.h" #include "videodir.h" @@ -1657,9 +1657,9 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr unsigned int freq = FrequencyMHz; front.ttk = (freq < 11700UL) ? 0 : 1; if (freq < 11700UL) - freq -= 9750UL; + freq -= Setup.LnbFrequLo; else - freq -= 10600UL; + freq -= Setup.LnbFrequHi; front.channel_flags = Ca ? DVB_CHANNEL_CA : DVB_CHANNEL_FTA; front.pnr = Pnr; front.freq = freq * 1000000UL; diff --git a/dvbosd.c b/dvbosd.c index 1e2c354ea..97c793228 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,10 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.2 2000/10/03 13:34:13 kls Exp $ + * $Id: dvbosd.c 1.3 2000/10/07 14:42:48 kls Exp $ */ #include "dvbosd.h" +#include #include #include #include @@ -138,11 +139,16 @@ void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co dc.x1 = x1; dc.y1 = y1; dc.data = (void *)data; + // must block all signals, otherwise the command might not be fully executed + sigset_t set, oldset; + sigfillset(&set); + sigprocmask(SIG_BLOCK, &set, &oldset); ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc); usleep(10); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places // XXX and sometimes the OSD was no longer displayed). // XXX Increase the value if the problem still persists on your particular system. // TODO Check if this is still necessary with driver versions after 0.7. + sigprocmask(SIG_SETMASK, &oldset, NULL); } } diff --git a/interface.c b/interface.c index a0fca0ea0..5940195f9 100644 --- a/interface.c +++ b/interface.c @@ -4,43 +4,39 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.21 2000/10/03 13:28:02 kls Exp $ + * $Id: interface.c 1.25 2000/10/08 16:34:17 kls Exp $ */ #include "interface.h" #include #include "eit.h" -#include "remote.h" cEIT EIT; -#if defined(REMOTE_RCU) -cRcIoRCU RcIo("/dev/ttyS1"); -#elif defined(REMOTE_LIRC) -cRcIoLIRC RcIo("/dev/lircd"); -#else -cRcIoKBD RcIo; -#endif - -cInterface Interface; +cInterface *Interface = NULL; -cInterface::cInterface(void) +cInterface::cInterface(int SVDRPport) { open = 0; cols[0] = 0; keyFromWait = kNone; + rcIo = NULL; SVDRP = NULL; -} - -void cInterface::Init(int SVDRPport) -{ - RcIo.SetCode(Keys.code, Keys.address); +#if defined(REMOTE_RCU) + rcIo = new cRcIoRCU("/dev/ttyS1"); +#elif defined(REMOTE_LIRC) + rcIo = new cRcIoLIRC("/dev/lircd"); +#else + rcIo = new cRcIoKBD; +#endif + rcIo->SetCode(Keys.code, Keys.address); if (SVDRPport) SVDRP = new cSVDRP(SVDRPport); } -void cInterface::Cleanup(void) +cInterface::~cInterface() { + delete rcIo; delete SVDRP; } @@ -58,22 +54,29 @@ void cInterface::Close(void) cDvbApi::PrimaryDvbApi->Close(); } -unsigned int cInterface::GetCh(bool Wait) +unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release) { - if (RcIo.InputAvailable(Wait)) { - unsigned int Command; - return RcIo.GetCommand(&Command, NULL) ? Command : 0; - } - return 0; + if (open) + cDvbApi::PrimaryDvbApi->Flush(); + if (!rcIo->InputAvailable()) + cFile::AnyFileReady(-1, Wait ? 1000 : 0); + unsigned int Command; + return rcIo->GetCommand(&Command, Repeat, Release) ? Command : 0; } eKeys cInterface::GetKey(bool Wait) { - if (open) - cDvbApi::PrimaryDvbApi->Flush(); if (SVDRP) SVDRP->Process(); - eKeys Key = keyFromWait != kNone ? keyFromWait : Keys.Get(GetCh(Wait)); + eKeys Key = keyFromWait; + if (Key == kNone) { + bool Repeat = false, Release = false; + Key = Keys.Get(GetCh(Wait, &Repeat, &Release)); + if (Repeat) + Key = eKeys(Key | k_Repeat); + if (Release) + Key = eKeys(Key | k_Release); + } keyFromWait = kNone; return Key; } @@ -85,13 +88,16 @@ void cInterface::PutKey(eKeys Key) eKeys cInterface::Wait(int Seconds, bool KeepChar) { - eKeys Key = kNone; if (open) cDvbApi::PrimaryDvbApi->Flush(); - RcIo.Flush(500); - if (cFile::AnyFileReady(-1, Seconds * 1000)) - Key = GetKey(); - if (KeepChar) + eKeys Key = kNone; + time_t timeout = time(NULL) + Seconds; + for (;;) { + Key = GetKey(); + if ((Key != kNone && (RAWKEY(Key) != kOk || RAWKEY(Key) == Key)) || time(NULL) > timeout) + break; + } + if (KeepChar && ISRAWKEY(Key)) keyFromWait = Key; return Key; } @@ -220,9 +226,11 @@ void cInterface::Help(const char *Red, const char *Green, const char *Yellow, co void cInterface::QueryKeys(void) { Keys.Clear(); + Clear(); WriteText(1, 1, "Learning Remote Control Keys"); WriteText(1, 3, "Phase 1: Detecting RC code type"); WriteText(1, 5, "Press any key on the RC unit"); + cDvbApi::PrimaryDvbApi->Flush(); #ifndef REMOTE_KBD unsigned char Code = 0; unsigned short Address; @@ -233,14 +241,16 @@ void cInterface::QueryKeys(void) break; #else //TODO on screen display... - if (RcIo.DetectCode(&Code, &Address)) { + if (rcIo->DetectCode(&Code, &Address)) { Keys.code = Code; Keys.address = Address; WriteText(1, 5, "RC code detected!"); WriteText(1, 6, "Do not press any key..."); - RcIo.Flush(3000); + cDvbApi::PrimaryDvbApi->Flush(); + rcIo->Flush(3000); ClearEol(0, 5); ClearEol(0, 6); + cDvbApi::PrimaryDvbApi->Flush(); break; } #endif @@ -328,7 +338,7 @@ eKeys cInterface::DisplayChannel(int Number, const char *Name, bool WithInfo) { // Number = 0 is used for channel group display and no EIT if (Number) - RcIo.Number(Number); + rcIo->Number(Number); if (Name && !Recording()) { Open(MenuColumns, 5); cDvbApi::PrimaryDvbApi->Fill(0, 0, MenuColumns, 1, clrBackground); @@ -387,7 +397,7 @@ eKeys cInterface::DisplayChannel(int Number, const char *Name, bool WithInfo) void cInterface::DisplayRecording(int Index, bool On) { - RcIo.SetPoints(1 << Index, On); + rcIo->SetPoints(1 << Index, On); } bool cInterface::Recording(void) diff --git a/interface.h b/interface.h index 8f7f1b8d7..8d0f8f685 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.13 2000/09/18 22:29:31 kls Exp $ + * $Id: interface.h 1.16 2000/10/08 12:15:49 kls Exp $ */ #ifndef __INTERFACE_H @@ -12,6 +12,7 @@ #include "config.h" #include "dvbapi.h" +#include "remote.h" #include "svdrp.h" class cInterface { @@ -22,14 +23,14 @@ class cInterface { int cols[MaxCols]; eKeys keyFromWait; cSVDRP *SVDRP; - unsigned int GetCh(bool Wait = true); + cRcIoBase *rcIo; + unsigned int GetCh(bool Wait = true, bool *Repeat = NULL, bool *Release = NULL); void QueryKeys(void); void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor); eKeys Wait(int Seconds = 1, bool KeepChar = false); public: - cInterface(void); - void Init(int SVDRPport = 0); - void Cleanup(void); + cInterface(int SVDRPport = 0); + ~cInterface(); void Open(int NumCols = MenuColumns, int NumLines = MenuLines); void Close(void); eKeys GetKey(bool Wait = true); @@ -38,7 +39,7 @@ class cInterface { void ClearEol(int x, int y, eDvbColor Color = clrBackground); void SetCols(int *c); void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); - void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBlack); + void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); void Title(const char *s); void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan); void Info(const char *s); @@ -51,6 +52,6 @@ class cInterface { bool Recording(void); }; -extern cInterface Interface; +extern cInterface *Interface; #endif //__INTERFACE_H diff --git a/menu.c b/menu.c index 1f5fd8885..39689c9c7 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.30 2000/10/03 14:06:44 kls Exp $ + * $Id: menu.c 1.36 2000/10/08 16:11:22 kls Exp $ */ #include "menu.h" @@ -13,7 +13,6 @@ #include #include #include "config.h" -#include "recording.h" #define MENUTIMEOUT 120 // seconds @@ -94,11 +93,11 @@ eOSState cMenuEditIntItem::ProcessKey(eKeys Key) } newValue = *value * 10 + (Key - k0); } - else if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly? + else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? newValue = *value - 1; fresh = true; } - else if (Key == kRight) { + else if (NORMALKEY(Key) == kRight) { newValue = *value + 1; fresh = true; } @@ -211,6 +210,7 @@ void cMenuEditDayItem::Set(void) eOSState cMenuEditDayItem::ProcessKey(eKeys Key) { switch (Key) { + case kLeft|k_Repeat: case kLeft: if (d > 0) *value = days[--d]; else if (d == 0) { @@ -225,6 +225,7 @@ eOSState cMenuEditDayItem::ProcessKey(eKeys Key) return cMenuEditIntItem::ProcessKey(Key); Set(); break; + case kRight|k_Repeat: case kRight: if (d >= 0) { *value = days[++d]; if (*value == 0) { @@ -310,7 +311,7 @@ eOSState cMenuEditTimeItem::ProcessKey(eKeys Key) break; } } - else if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly? + else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? if (--mm < 0) { mm = 59; if (--hh < 0) @@ -318,7 +319,7 @@ eOSState cMenuEditTimeItem::ProcessKey(eKeys Key) } fresh = true; } - else if (Key == kRight) { + else if (NORMALKEY(Key) == kRight) { if (++mm > 59) { mm = 0; if (++hh > 23) @@ -377,11 +378,11 @@ eOSState cMenuEditChrItem::ProcessKey(eKeys Key) eOSState state = cMenuEditItem::ProcessKey(Key); if (state == osUnknown) { - if (Key == kLeft) { + if (NORMALKEY(Key) == kLeft) { if (current > allowed) current--; } - else if (Key == kRight) { + else if (NORMALKEY(Key) == kRight) { if (*(current + 1)) current++; } @@ -455,12 +456,14 @@ char cMenuEditStrItem::Inc(char c, bool Up) eOSState cMenuEditStrItem::ProcessKey(eKeys Key) { switch (Key) { + case kLeft|k_Repeat: case kLeft: if (pos > 0) { if (value[pos] == '^') value[pos] = 0; pos--; } break; + case kRight|k_Repeat: case kRight: if (pos < length && value[pos] != '^' && (pos < int(strlen(value) - 1) || value[pos] != ' ')) { if (++pos >= int(strlen(value))) { value[pos] = ' '; @@ -468,9 +471,11 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key) } } break; + case kUp|k_Repeat: case kUp: + case kDown|k_Repeat: case kDown: if (pos >= 0) - value[pos] = Inc(value[pos], Key == kUp); + value[pos] = Inc(value[pos], NORMALKEY(Key) == kUp); else return cMenuEditItem::ProcessKey(Key); break; @@ -635,11 +640,11 @@ eOSState cMenuChannels::Del(void) // Check if there is a timer using this channel: for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { if (ti->channel == DeletedChannel) { - Interface.Error("Channel is being used by a timer!"); + Interface->Error("Channel is being used by a timer!"); return osContinue; } } - if (Interface.Confirm("Delete Channel?")) { + if (Interface->Confirm("Delete Channel?")) { // Move and renumber the channels: Channels.Del(channel); Channels.ReNumber(); @@ -916,7 +921,7 @@ eOSState cMenuTimers::Del(void) cTimer *ti = Timers.Get(Index); if (ti) { if (!ti->recording) { - if (Interface.Confirm("Delete Timer?")) { + if (Interface->Confirm("Delete Timer?")) { Timers.Del(Timers.Get(Index)); cOsdMenu::Del(Index); Timers.Save(); @@ -925,7 +930,7 @@ eOSState cMenuTimers::Del(void) } } else - Interface.Error("Timer is recording!"); + Interface->Error("Timer is recording!"); } return osContinue; } @@ -990,28 +995,19 @@ void cMenuRecordingItem::Set(void) // --- cMenuRecordings ------------------------------------------------------- -class cMenuRecordings : public cOsdMenu { -private: - cRecordings Recordings; - eOSState Play(void); - eOSState Del(void); - eOSState Summary(void); -public: - cMenuRecordings(void); - virtual eOSState ProcessKey(eKeys Key); - }; - cMenuRecordings::cMenuRecordings(void) :cOsdMenu("Recordings", 6, 6) { if (Recordings.Load()) { + const char *lastReplayed = cReplayControl::LastReplayed(); cRecording *recording = Recordings.First(); while (recording) { - Add(new cMenuRecordingItem(recording)); + Add(new cMenuRecordingItem(recording), lastReplayed && strcmp(lastReplayed, recording->FileName()) == 0); recording = Recordings.Next(recording); } } - SetHelp("Play", NULL/*XXX"Resume"*/, "Delete", "Summary"); + SetHelp("Play", NULL, "Delete", "Summary"); + Display(); } eOSState cMenuRecordings::Play(void) @@ -1030,17 +1026,18 @@ eOSState cMenuRecordings::Del(void) if (ri) { //XXX what if this recording's file is currently in use??? //XXX if (!ti->recording) { - if (Interface.Confirm("Delete Recording?")) { + if (Interface->Confirm("Delete Recording?")) { if (ri->recording->Delete()) { + cReplayControl::ClearLastReplayed(ri->recording->FileName()); cOsdMenu::Del(Current()); Display(); } else - Interface.Error("Error while deleting recording!"); + Interface->Error("Error while deleting recording!"); } //XXX } //XXX else -//XXX Interface.Error("Timer is recording!"); +//XXX Interface->Error("Timer is recording!"); } return osContinue; } @@ -1065,6 +1062,7 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) case kRed: return Play(); case kYellow: return Del(); case kBlue: return Summary(); + case kMenu: return osEnd; default: break; } } @@ -1088,6 +1086,9 @@ cMenuSetup::cMenuSetup(void) Add(new cMenuEditIntItem( "PrimaryDVB", &data.PrimaryDVB, 1, cDvbApi::NumDvbApis)); Add(new cMenuEditBoolItem("ShowInfoOnChSwitch", &data.ShowInfoOnChSwitch)); Add(new cMenuEditBoolItem("MenuScrollPage", &data.MenuScrollPage)); + Add(new cMenuEditBoolItem("MarkInstantRecord", &data.MarkInstantRecord)); + Add(new cMenuEditIntItem( "LnbFrequLo", &data.LnbFrequLo)); + Add(new cMenuEditIntItem( "LnbFrequHi", &data.LnbFrequHi)); } eOSState cMenuSetup::ProcessKey(eKeys Key) @@ -1126,7 +1127,7 @@ cMenuMain::cMenuMain(bool Replaying) Add(new cOsdItem(buffer, osStopRecord)); delete buffer; } - SetHelp("Record"); + SetHelp("Record", NULL, NULL, cReplayControl::LastReplayed() ? "Resume" : NULL); Display(); lastActivity = time(NULL); } @@ -1140,7 +1141,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key) case osTimer: return AddSubMenu(new cMenuTimers); case osRecordings: return AddSubMenu(new cMenuRecordings); case osSetup: return AddSubMenu(new cMenuSetup); - case osStopRecord: if (Interface.Confirm("Stop Recording?")) { + case osStopRecord: if (Interface->Confirm("Stop Recording?")) { cOsdItem *item = Get(Current()); if (item) { cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING)); @@ -1152,6 +1153,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key) case kRed: if (!HasSubMenu()) state = osRecord; break; + case kBlue: if (!HasSubMenu()) + state = osReplay; + break; default: break; } } @@ -1172,15 +1176,15 @@ cDirectChannelSelect::cDirectChannelSelect(eKeys FirstKey) oldNumber = CurrentChannel; number = 0; lastTime = time_ms(); - Interface.Open(MenuColumns, 1); + Interface->Open(MenuColumns, 1); ProcessKey(FirstKey); } cDirectChannelSelect::~cDirectChannelSelect() { if (number < 0) - Interface.DisplayChannel(oldNumber); - Interface.Close(); + Interface->DisplayChannel(oldNumber); + Interface->Close(); } eOSState cDirectChannelSelect::ProcessKey(eKeys Key) @@ -1194,9 +1198,9 @@ eOSState cDirectChannelSelect::ProcessKey(eKeys Key) int BufSize = MenuColumns + 1; char buffer[BufSize]; snprintf(buffer, BufSize, "%d %s", number, Name); - Interface.DisplayChannel(number); - Interface.Clear(); - Interface.Write(0, 0, buffer); + Interface->DisplayChannel(number); + Interface->Clear(); + Interface->Write(0, 0, buffer); lastTime = time_ms(); if (!channel) { number = -1; @@ -1235,14 +1239,14 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) cRecording Recording(timer); if (dvbApi->StartRecord(Recording.FileName())) Recording.WriteSummary(); - Interface.DisplayRecording(dvbApi->Index(), true); + Interface->DisplayRecording(dvbApi->Index(), true); } cRecordControl::~cRecordControl() { Stop(true); delete instantId; - Interface.DisplayRecording(dvbApi->Index(), false); + Interface->DisplayRecording(dvbApi->Index(), false); } void cRecordControl::Stop(bool KeepInstant) @@ -1357,10 +1361,23 @@ void cReplayControl::SetRecording(const char *FileName, const char *Title) title = Title ? strdup(Title) : NULL; } +const char *cReplayControl::LastReplayed(void) +{ + return fileName; +} + +void cReplayControl::ClearLastReplayed(const char *FileName) +{ + if (fileName && FileName && strcmp(fileName, FileName) == 0) { + delete fileName; + fileName = NULL; + } +} + void cReplayControl::Show(void) { if (!visible) { - Interface.Open(MenuColumns, -3); + Interface->Open(MenuColumns, -3); needsFastResponse = visible = true; shown = dvbApi->ShowProgress(true); } @@ -1369,7 +1386,7 @@ void cReplayControl::Show(void) void cReplayControl::Hide(void) { if (visible) { - Interface.Close(); + Interface->Close(); needsFastResponse = visible = false; } } @@ -1388,10 +1405,16 @@ eOSState cReplayControl::ProcessKey(eKeys Key) return osEnd; case kLeft: dvbApi->Backward(); break; case kRight: dvbApi->Forward(); break; + case kLeft|k_Release: + case kRight|k_Release: + dvbApi->Play(); break; + case kGreen|k_Repeat: case kGreen: dvbApi->Skip(-60); break; + case kYellow|k_Repeat: case kYellow: dvbApi->Skip(60); break; case kMenu: Hide(); return osMenu; // allow direct switching to menu case kOk: visible ? Hide() : Show(); break; + case kBack: return osRecordings; default: return osUnknown; } return osContinue; diff --git a/menu.h b/menu.h index 8b4f82efe..c36427f12 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.10 2000/09/10 14:42:20 kls Exp $ + * $Id: menu.h 1.12 2000/10/08 15:21:52 kls Exp $ */ #ifndef _MENU_H @@ -14,6 +14,7 @@ #include "dvbapi.h" #include "osd.h" +#include "recording.h" class cMenuMain : public cOsdMenu { private: @@ -34,6 +35,17 @@ class cDirectChannelSelect : public cOsdBase { virtual eOSState ProcessKey(eKeys Key); }; +class cMenuRecordings : public cOsdMenu { +private: + cRecordings Recordings; + eOSState Play(void); + eOSState Del(void); + eOSState Summary(void); +public: + cMenuRecordings(void); + virtual eOSState ProcessKey(eKeys Key); + }; + class cRecordControl { private: cDvbApi *dvbApi; @@ -72,6 +84,8 @@ class cReplayControl : public cOsdBase { virtual eOSState ProcessKey(eKeys Key); bool Visible(void) { return visible; } static void SetRecording(const char *FileName, const char *Title); + static const char *LastReplayed(void); + static void ClearLastReplayed(const char *FileName); }; #endif //_MENU_H diff --git a/osd.c b/osd.c index e1c99b44b..75d9eadeb 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.7 2000/09/10 08:24:50 kls Exp $ + * $Id: osd.c 1.9 2000/10/08 12:20:34 kls Exp $ */ #include "osd.h" @@ -64,7 +64,7 @@ void cOsdItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) if (Offset >= 0) offset = Offset; if (offset >= 0) - Interface.WriteText(0, offset + 2, text, userColor ? fgColor : FgColor, userColor ? bgColor : BgColor); + Interface->WriteText(0, offset + 2, text, userColor ? fgColor : FgColor, userColor ? bgColor : BgColor); } eOSState cOsdItem::ProcessKey(eKeys Key) @@ -88,7 +88,7 @@ cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4) subMenu = NULL; helpRed = helpGreen = helpYellow = helpBlue = NULL; status = NULL; - Interface.Open(); + Interface->Open(); } cOsdMenu::~cOsdMenu() @@ -96,8 +96,8 @@ cOsdMenu::~cOsdMenu() delete title; delete subMenu; delete status; - Interface.Clear(); - Interface.Close(); + Interface->Clear(); + Interface->Close(); } void cOsdMenu::SetStatus(const char *s) @@ -105,7 +105,7 @@ void cOsdMenu::SetStatus(const char *s) delete status; status = s ? strdup(s) : NULL; if (visible) - Interface.Status(status); + Interface->Status(status); } void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue) @@ -117,7 +117,7 @@ void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, c helpBlue = Blue; if (visible) Display(); - //XXX Interface.Help(helpRed, helpGreen, helpYellow, helpBlue); + //XXX Interface->Help(helpRed, helpGreen, helpYellow, helpBlue); //XXX must clear unused button areas! } @@ -140,10 +140,10 @@ void cOsdMenu::Add(cOsdItem *Item, bool Current) void cOsdMenu::Display(void) { visible = true; - Interface.Clear(); - Interface.SetCols(cols); - Interface.Title(title); - Interface.Help(helpRed, helpGreen, helpYellow, helpBlue); + Interface->Clear(); + Interface->SetCols(cols); + Interface->Title(title); + Interface->Help(helpRed, helpGreen, helpYellow, helpBlue); int count = Count(); if (count > 0) { if (current < 0) @@ -164,7 +164,7 @@ void cOsdMenu::Display(void) break; } } - Interface.Status(status); + Interface->Status(status); } void cOsdMenu::RefreshCurrent(void) @@ -274,7 +274,9 @@ eOSState cOsdMenu::ProcessKey(eKeys Key) return state; } switch (Key) { + case kUp|k_Repeat: case kUp: CursorUp(); break; + case kDown|k_Repeat: case kDown: CursorDown(); break; case kBack: return osBack; case kOk: if (marked >= 0) { diff --git a/recording.c b/recording.c index 60ea4a1c0..f9ab01621 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.18 2000/10/03 12:39:28 kls Exp $ + * $Id: recording.c 1.19 2000/10/08 12:20:53 kls Exp $ */ #define _GNU_SOURCE @@ -254,7 +254,7 @@ bool cRecordings::Load(bool Deleted) result = Count() > 0; } else - Interface.Error("Error while opening pipe!"); + Interface->Error("Error while opening pipe!"); delete cmd; return result; } diff --git a/remote.c b/remote.c index 1bf810854..f60d7685c 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.15 2000/10/03 10:49:58 kls Exp $ + * $Id: remote.c 1.18 2000/10/08 16:49:41 kls Exp $ */ #include "remote.h" @@ -27,16 +27,11 @@ #include "config.h" #include "tools.h" -#define REPEATLIMIT 100 // ms -#define REPEATDELAY 250 // ms - // --- cRcIoBase ------------------------------------------------------------- cRcIoBase::cRcIoBase(void) { t = 0; - firstTime = lastTime = 0; - lastCommand = 0; } cRcIoBase::~cRcIoBase() @@ -69,12 +64,12 @@ void cRcIoKBD::Flush(int WaitMs) } } -bool cRcIoKBD::InputAvailable(bool Wait) +bool cRcIoKBD::InputAvailable(void) { - return f.Ready(Wait); + return f.Ready(false); } -bool cRcIoKBD::GetCommand(unsigned int *Command, unsigned short *) +bool cRcIoKBD::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) { if (Command) { *Command = getch(); @@ -87,36 +82,122 @@ bool cRcIoKBD::GetCommand(unsigned int *Command, unsigned short *) #elif defined REMOTE_RCU +#define REPEATLIMIT 20 // ms +#define REPEATDELAY 350 // ms + cRcIoRCU::cRcIoRCU(char *DeviceName) { dp = 0; mode = modeB; code = 0; address = 0xFFFF; + receivedAddress = 0; + receivedCommand = 0; + receivedData = receivedRepeat = receivedRelease = false; lastNumber = 0; - if (f.Open(DeviceName, O_RDWR | O_NONBLOCK)) { + if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) { struct termios t; if (tcgetattr(f, &t) == 0) { cfsetspeed(&t, B9600); cfmakeraw(&t); - if (tcsetattr(f, TCSAFLUSH, &t) == 0) + if (tcsetattr(f, TCSAFLUSH, &t) == 0) { + Start(); return; + } } LOG_ERROR_STR(DeviceName); - f.Close(); + close(f); } else LOG_ERROR_STR(DeviceName); + f = -1; } cRcIoRCU::~cRcIoRCU() { + Stop(); } -int cRcIoRCU::ReceiveByte(bool Wait) +void cRcIoRCU::Action(void) +{ +#pragma pack(1) + union { + struct { + unsigned short address; + unsigned int command; + } data; + unsigned char raw[6]; + } buffer; +#pragma pack() + + dsyslog(LOG_INFO, "RCU remote control thread started (pid=%d)", getpid()); + + int FirstTime = 0; + unsigned int LastCommand = 0; + + for (; f >= 0;) { + + LOCK_THREAD; + + if (ReceiveByte(REPEATLIMIT) == 'X') { + for (int i = 0; i < 6; i++) { + int b = ReceiveByte(); + if (b >= 0) { + buffer.raw[i] = b; + if (i == 5) { + unsigned short Address = ntohs(buffer.data.address); // the PIC sends bytes in "network order" + unsigned int Command = ntohl(buffer.data.command); + if (code == 'B' && address == 0x0000 && Command == 0x00004000) + // Well, well, if it isn't the "d-box"... + // This remote control sends the above command before and after + // each keypress - let's just drop this: + break; + if (!receivedData) { // only accept new data the previous data has been fetched + int Now = time_ms(); + if (Command != LastCommand) { + receivedAddress = Address; + receivedCommand = Command; + receivedData = true; + receivedRepeat = receivedRelease = false; + FirstTime = Now; + } + else { + if (Now - FirstTime < REPEATDELAY) + break; // repeat function kicks in after a short delay + receivedData = receivedRepeat = true; + } + LastCommand = Command; + WakeUp(); + } + } + } + else + break; + } + } + else if (receivedData) { // the last data before releasing the key hasn't been fetched yet + if (receivedRepeat) { // it was a repeat, so let's make it a release + receivedRepeat = false; + receivedRelease = true; + LastCommand = 0; + WakeUp(); + } + } + else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat, so let's generate a release + receivedData = receivedRelease = true; + receivedRepeat = false; + LastCommand = 0; + WakeUp(); + } + else + LastCommand = 0; + } +} + +int cRcIoRCU::ReceiveByte(int TimeoutMs) { // Returns the byte if one was received within a timeout, -1 otherwise - if (InputAvailable(Wait)) { + if (cFile::FileReady(f, TimeoutMs)) { unsigned char b; if (read(f, &b, 1) == 1) return b; @@ -128,16 +209,16 @@ int cRcIoRCU::ReceiveByte(bool Wait) bool cRcIoRCU::SendByteHandshake(unsigned char c) { - if (f.IsOpen()) { + if (f >= 0) { int w = write(f, &c, 1); if (w == 1) { - for (int reply = ReceiveByte(); reply >= 0;) { + for (int reply = ReceiveByte(REPEATLIMIT); reply >= 0;) { if (reply == c) return true; else if (reply == 'X') { // skip any incoming RC code - it will come again for (int i = 6; i--;) { - if (ReceiveByte(false) < 0) + if (ReceiveByte() < 0) return false; } } @@ -152,6 +233,8 @@ bool cRcIoRCU::SendByteHandshake(unsigned char c) bool cRcIoRCU::SendByte(unsigned char c) { + LOCK_THREAD; + for (int retry = 5; retry--;) { if (SendByteHandshake(c)) return true; @@ -174,66 +257,34 @@ bool cRcIoRCU::SetMode(unsigned char Mode) void cRcIoRCU::Flush(int WaitMs) { - int t0 = time_ms(); + LOCK_THREAD; + int t0 = time_ms(); for (;;) { - while (ReceiveByte(false) >= 0) + while (ReceiveByte() >= 0) t0 = time_ms(); if (time_ms() - t0 >= WaitMs) break; } + receivedData = receivedRepeat = false; } -bool cRcIoRCU::InputAvailable(bool Wait) +bool cRcIoRCU::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) { - return f.Ready(Wait); -} - -bool cRcIoRCU::GetCommand(unsigned int *Command, unsigned short *Address) -{ -#pragma pack(1) - union { - struct { - unsigned short address; - unsigned int command; - } data; - unsigned char raw[6]; - } buffer; -#pragma pack() - - Flush(); - if (Command && ReceiveByte() == 'X') { - for (int i = 0; i < 6; i++) { - int b = ReceiveByte(false); - if (b >= 0) - buffer.raw[i] = b; - else - return false; - } - if (Address) - *Address = ntohs(buffer.data.address); // the PIC sends bytes in "network order" - else if (address != ntohs(buffer.data.address)) - return false; - *Command = ntohl(buffer.data.command); - if (code == 'B' && address == 0x0000 && *Command == 0x00004000) - // Well, well, if it isn't the "d-box"... - // This remote control sends the above command before and after - // each keypress - let's just drop this: - return false; - if (*Command == lastCommand) { - // let's have a timeout to avoid getting overrun by commands - int now = time_ms(); - int delta = now - lastTime; - lastTime = now; - if (delta < REPEATLIMIT) { // if commands come in rapidly... - if (now - firstTime < REPEATDELAY) - return false; // ...repeat function kicks in after a short delay - return true; - } + if (receivedData) { // first we check the boolean flag without a lock, to avoid delays + + LOCK_THREAD; + + if (receivedData) { // need to check again, since the status might have changed while waiting for the lock + if (Command) + *Command = receivedCommand; + if (Repeat) + *Repeat = receivedRepeat; + if (Release) + *Release = receivedRelease; + receivedData = false; + return true; } - lastTime = firstTime = time_ms(); - lastCommand = *Command; - return true; } if (time(NULL) - t > 60) { SendCommand(code); // in case the PIC listens to the wrong code @@ -254,6 +305,8 @@ bool cRcIoRCU::Digit(int n, int v) bool cRcIoRCU::Number(int n, bool Hex) { + LOCK_THREAD; + if (!Hex) { char buf[8]; sprintf(buf, "%4d", n & 0xFFFF); @@ -275,6 +328,8 @@ bool cRcIoRCU::Number(int n, bool Hex) bool cRcIoRCU::String(char *s) { + LOCK_THREAD; + const char *chars = mode == modeH ? "0123456789ABCDEF" : "0123456789-EHLP "; int n = 0; @@ -318,8 +373,11 @@ bool cRcIoRCU::DetectCode(unsigned char *Code, unsigned short *Address) sprintf(buf, "C0D%c", *Code); String(buf); SetCode(*Code, 0); - unsigned int Command; - if (GetCommand(&Command, Address)) { + delay_ms(REPEATDELAY); + receivedData = receivedRepeat = 0; + delay_ms(REPEATDELAY); + if (GetCommand()) { + *Address = receivedAddress; SetMode(modeB); String("----"); return true; @@ -337,77 +395,94 @@ bool cRcIoRCU::DetectCode(unsigned char *Code, unsigned short *Address) #elif defined REMOTE_LIRC +#define REPEATLIMIT 20 // ms +#define REPEATDELAY 350 // ms + cRcIoLIRC::cRcIoLIRC(char *DeviceName) { - repeat = 1; + *keyName = 0; + receivedData = receivedRepeat = false; struct sockaddr_un addr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, DeviceName); - int sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock >= 0) { - if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) >= 0) { - f.Open(sock); + if ((f = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) { + if (connect(f, (struct sockaddr *)&addr, sizeof(addr)) >= 0) { + Start(); return; } LOG_ERROR_STR(DeviceName); - close(sock); + close(f); } else LOG_ERROR_STR(DeviceName); + f = -1; } cRcIoLIRC::~cRcIoLIRC() { + Stop(); } -const char *cRcIoLIRC::ReceiveString(void) +void cRcIoLIRC::Action(void) { - int oldrepeat = 1; - - if (repeat != 0) { - Flush(); - if (repeat != 0) { - oldrepeat = repeat; - Flush(REPEATLIMIT); - } - } - - if (repeat == 0) { - firstTime = time_ms(); - repeat = 1; - return keyName; - } - - if ((repeat > 1) && (repeat != oldrepeat) && (time_ms() > firstTime + REPEATDELAY)) { - repeat = 1; - return keyName; - } + dsyslog(LOG_INFO, "LIRC remote control thread started (pid=%d)", getpid()); - return NULL; -} - -void cRcIoLIRC::Flush(int WaitMs) -{ + int FirstTime = 0; char buf[LIRC_BUFFER_SIZE]; - int t0 = time_ms(); - - do { - if (InputAvailable(false) && (read(f, buf, sizeof(buf)) > 21)) - sscanf(buf, "%*x %x %7s", &repeat, keyName); // '7' in '%7s' is LIRC_KEY_BUF-1! - } while ((repeat != 0) && (time_ms() < t0 + WaitMs)); -} - -bool cRcIoLIRC::InputAvailable(bool Wait) -{ - return f.Ready(Wait); + char LastKeyName[LIRC_KEY_BUF]; + + for (; f >= 0;) { + + LOCK_THREAD; + + if (cFile::FileReady(f, REPEATLIMIT) && read(f, buf, sizeof(buf)) > 21) { + if (!receivedData) { // only accept new data the previous data has been fetched + int count; + sscanf(buf, "%*x %x %7s", &count, LastKeyName); // '7' in '%7s' is LIRC_KEY_BUF-1! + int Now = time_ms(); + if (count == 0) { + strcpy(keyName, LastKeyName); + receivedData = true; + receivedRepeat = receivedRelease = false; + FirstTime = Now; + } + else { + if (Now - FirstTime < REPEATDELAY) + continue; // repeat function kicks in after a short delay + receivedData = receivedRepeat = true; + } + WakeUp(); + } + } + else if (receivedData) { // the last data before releasing the key hasn't been fetched yet + if (receivedRepeat) { // it was a repeat, so let's make it a release + receivedRepeat = false; + receivedRelease = true; + WakeUp(); + } + } + else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat, so let's generate a release + receivedData = receivedRelease = true; + receivedRepeat = false; + WakeUp(); + } + } } -bool cRcIoLIRC::GetCommand(unsigned int *Command, unsigned short *) +bool cRcIoLIRC::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) { - if (Command) { - const char *cmd = ReceiveString(); - if (cmd) { - *Command = Keys.Encode(cmd); + if (receivedData) { // first we check the boolean flag without a lock, to avoid delays + + LOCK_THREAD; + + if (receivedData) { // need to check again, since the status might have changed while waiting for the lock + if (Command) + *Command = Keys.Encode(keyName); + if (Repeat) + *Repeat = receivedRepeat; + if (Release) + *Release = receivedRelease; + receivedData = false; return true; } } diff --git a/remote.h b/remote.h index 75dc4ac1b..0ea4442ae 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.10 2000/10/03 10:45:35 kls Exp $ + * $Id: remote.h 1.13 2000/10/08 12:11:34 kls Exp $ */ #ifndef __REMOTE_H @@ -12,26 +12,25 @@ #include #include +#include "thread.h" #include "tools.h" class cRcIoBase { protected: time_t t; - int firstTime, lastTime; - unsigned int lastCommand; cRcIoBase(void); - virtual ~cRcIoBase(); public: enum { modeH = 'h', modeB = 'b', modeS = 's' }; + virtual ~cRcIoBase(); virtual bool SetCode(unsigned char Code, unsigned short Address) { return true; } virtual bool SetMode(unsigned char Mode) { return true; } virtual bool Number(int n, bool Hex = false) { return true; } virtual void SetPoints(unsigned char Dp, bool On) {} virtual bool String(char *s) { return true; } virtual bool DetectCode(unsigned char *Code, unsigned short *Address) { return true; } - virtual void Flush(int WaitMs = 0) = 0; - virtual bool InputAvailable(bool Wait = false) = 0; - virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL) = 0; + virtual void Flush(int WaitMs = 0) {} + virtual bool InputAvailable(void) = 0; + virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL) = 0; }; #if defined REMOTE_KBD @@ -43,23 +42,27 @@ class cRcIoKBD : public cRcIoBase { cRcIoKBD(void); virtual ~cRcIoKBD(); virtual void Flush(int WaitMs = 0); - virtual bool InputAvailable(bool Wait = false); - virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); + virtual bool InputAvailable(void); + virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL); }; #elif defined REMOTE_RCU -class cRcIoRCU : public cRcIoBase { +class cRcIoRCU : public cRcIoBase, private cThread { private: - cFile f; + int f; unsigned char dp, code, mode; unsigned short address; + unsigned short receivedAddress; + unsigned int receivedCommand; + bool receivedData, receivedRepeat, receivedRelease; int lastNumber; bool SendCommand(unsigned char Cmd); - int ReceiveByte(bool Wait = true); + int ReceiveByte(int TimeoutMs = 0); bool SendByteHandshake(unsigned char c); bool SendByte(unsigned char c); bool Digit(int n, int v); + virtual void Action(void); public: cRcIoRCU(char *DeviceName); virtual ~cRcIoRCU(); @@ -70,25 +73,24 @@ class cRcIoRCU : public cRcIoBase { virtual bool String(char *s); virtual bool DetectCode(unsigned char *Code, unsigned short *Address); virtual void Flush(int WaitMs = 0); - virtual bool InputAvailable(bool Wait = false); - virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); + virtual bool InputAvailable(void) { return receivedData; } + virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL); }; #elif defined REMOTE_LIRC -class cRcIoLIRC : public cRcIoBase { +class cRcIoLIRC : public cRcIoBase, private cThread { private: enum { LIRC_KEY_BUF = 8, LIRC_BUFFER_SIZE = 128 }; - cFile f; + int f; char keyName[LIRC_KEY_BUF]; - int repeat; - const char *ReceiveString(void); + bool receivedData, receivedRepeat, receivedRelease; + virtual void Action(void); public: cRcIoLIRC(char *DeviceName); virtual ~cRcIoLIRC(); - virtual void Flush(int WaitMs = 0); - virtual bool InputAvailable(bool Wait = false); - virtual bool GetCommand(unsigned int *Command, unsigned short *Address = NULL); + virtual bool InputAvailable(void) { return receivedData; } + virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL); }; #else diff --git a/setup.conf b/setup.conf index e80c2e0c2..e7ec26747 100644 --- a/setup.conf +++ b/setup.conf @@ -2,3 +2,6 @@ PrimaryDVB = 1 ShowInfoOnChSwitch = 1 MenuScrollPage = 1 +MarkInstantRecord = 1 +LnbFrequLo = 9750 +LnbFrequHi = 10600 diff --git a/svdrp.c b/svdrp.c index c9ea7c387..cf91cafb2 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.10 2000/09/17 13:39:37 kls Exp $ + * $Id: svdrp.c 1.11 2000/10/08 12:21:14 kls Exp $ */ #define _GNU_SOURCE @@ -326,7 +326,7 @@ void cSVDRP::CmdCHAN(const char *Option) Reply(501, "Undefined channel \"%s\"", Option); return; } - if (Interface.Recording()) { + if (Interface->Recording()) { Reply(550, "Can't switch channel, interface is recording"); return; } @@ -474,7 +474,7 @@ void cSVDRP::CmdHITK(const char *Option) if (*Option) { eKeys k = Keys.Translate(Option); if (k != kNone) { - Interface.PutKey(k); + Interface->PutKey(k); Reply(250, "Key \"%s\" accepted", Option); } else diff --git a/thread.c b/thread.c new file mode 100644 index 000000000..7304e682a --- /dev/null +++ b/thread.c @@ -0,0 +1,105 @@ +/* + * thread.c: A simple thread base class + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: thread.c 1.2 2000/10/08 16:45:50 kls Exp $ + */ + +#include "thread.h" +#include +#include + +// --- cThread --------------------------------------------------------------- + +// The signal handler is necessary to be able to use SIGIO to wake up any +// pending 'select()' call. + +bool cThread::signalHandlerInstalled = false; + +cThread::cThread(void) +{ + if (!signalHandlerInstalled) { + signal(SIGIO, SignalHandler); + signalHandlerInstalled = true; + } + pthread_mutex_init(&mutex, NULL); + running = false; + parentPid = lockingPid = 0; + locked = 0; +} + +cThread::~cThread() +{ + pthread_mutex_destroy(&mutex); +} + +void cThread::SignalHandler(int signum) +{ + signal(signum, SignalHandler); +} + +void *cThread::StartThread(cThread *Thread) +{ + Thread->Action(); + return NULL; +} + +bool cThread::Start(void) +{ + if (!running) { + running = true; + parentPid = getpid(); + pthread_create(&thread, NULL, &StartThread, (void *)this); + } + return true; //XXX return value of pthread_create()??? +} + +void cThread::Stop(void) +{ + pthread_cancel(thread); +} + +bool cThread::Lock(void) +{ + if (!lockingPid || lockingPid != getpid()) { + pthread_mutex_lock(&mutex); + lockingPid = getpid(); + } + locked++; + return true; +} + +void cThread::Unlock(void) +{ + if (!--locked) { + lockingPid = 0; + pthread_mutex_unlock(&mutex); + } +} + +void cThread::WakeUp(void) +{ + kill(parentPid, SIGIO); // makes any waiting 'select()' call return immediately +} + +// --- cThreadLock ----------------------------------------------------------- + +cThreadLock::cThreadLock(cThread *Thread) +{ + thread = Thread; + locked = Thread->Lock(); +} + +cThreadLock::~cThreadLock() +{ + if (locked) + thread->Unlock(); +} + +bool cThreadLock::Locked(void) +{ + return locked; +} + diff --git a/thread.h b/thread.h new file mode 100644 index 000000000..86b9e922c --- /dev/null +++ b/thread.h @@ -0,0 +1,57 @@ +/* + * thread.h: A simple thread base class + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: thread.h 1.1 2000/10/08 08:36:21 kls Exp $ + */ + +#ifndef __THREAD_H +#define __THREAD_H + +#include +#include + +class cThread { + friend class cThreadLock; +private: + pthread_t thread; + pthread_mutex_t mutex; + pid_t parentPid, lockingPid; + int locked; + bool running; + static bool signalHandlerInstalled; + static void SignalHandler(int signum); + static void *StartThread(cThread *Thread); + bool Lock(void); + void Unlock(void); +protected: + void WakeUp(void); + virtual void Action(void) = 0; + void Stop(void); +public: + cThread(void); + virtual ~cThread(); + bool Start(void); + }; + +// cThreadLock can be used to easily set a lock in a thread and make absolutely +// sure that it will be unlocked when the block will be left. Several locks can +// be stacked, so a function that makes many calls to another function which uses +// cThreadLock may itself use a cThreadLock to make one longer lock instead of many +// short ones. + +class cThreadLock { +private: + cThread *thread; + bool locked; +public: + cThreadLock(cThread *Thread); + ~cThreadLock(); + bool Locked(void); + }; + +#define LOCK_THREAD cThreadLock ThreadLock(this) + +#endif //__THREAD_H diff --git a/timers.conf b/timers.conf index 2a58454b6..fc0e12a60 100644 --- a/timers.conf +++ b/timers.conf @@ -1,16 +1,16 @@ 1:15:M------:2128:2205:99:7:Neues: 1:3:-T-----:2013:2125:99:99:SevenDays: 1:10:-T-----:2058:2202:99:10:Quarks: -1:26:-T-----:2235:2345:99:99:UFO: +1:26:-T-----:2320:0040:99:99:UFO: +1:14:--W----:1920:2020:99:99:Rettungsflieger: 1:2:--W----:2110:2325:99:99:BulleVonToelz: 1:3:---T---:2210:2315:99:10:IngoAppelt: -1:2:----F--:2140:2225:10:10:WWW: +0:2:----F--:2140:2225:10:10:WWW: 1:1:----F--:2212:2325:99:99:7Tage7Koepfe: 1:11:-----S-:2058:2135:99:99:Computer: 1:2:-----S-:2211:2340:99:30:Wochenshow: 1:11:------S:2013:2035:99:10:Centauri: 1:14:------S:2158:2235:99:14:MaxUndLisa: -0:15:MTWTF--:1828:1901:10:5:nano: +1:15:MTWTF--:1828:1901:10:5:nano: 1:1:-TWTF--:0955:1040:99:99:Ellen: -0:1:MTWTF--:1553:1710:99:99:Hammerman: -1:1:4:0755:0910:99:99:Hammerman: +1:1:MTWTF--:1553:1710:99:99:Hammerman: diff --git a/tools.c b/tools.c index 5bb56e6df..fc15a9853 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.20 2000/09/29 16:19:28 kls Exp $ + * $Id: tools.c 1.21 2000/10/07 18:02:24 kls Exp $ */ #define _GNU_SOURCE @@ -393,6 +393,22 @@ bool cFile::AnyFileReady(int FileDes, int TimeoutMs) return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && (FileDes < 0 || FD_ISSET(FileDes, &set)); } +bool cFile::FileReady(int FileDes, int TimeoutMs) +{ +#ifdef DEBUG_OSD + refresh(); +#endif + fd_set set; + struct timeval timeout; + FD_ZERO(&set); + FD_SET(FileDes, &set); + if (TimeoutMs < 100) + TimeoutMs = 100; + timeout.tv_sec = 0; + timeout.tv_usec = TimeoutMs * 1000; + return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set); +} + // --- cListObject ----------------------------------------------------------- cListObject::cListObject(void) diff --git a/tools.h b/tools.h index 441f5715a..17b643ffb 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.16 2000/09/29 16:19:31 kls Exp $ + * $Id: tools.h 1.17 2000/10/07 18:00:21 kls Exp $ */ #ifndef __TOOLS_H @@ -68,6 +68,7 @@ class cFile { int ReadString(char *Buffer, int Size); bool Ready(bool Wait = true); static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000); + static bool FileReady(int FileDes, int TimeoutMs = 1000); }; class cListObject { diff --git a/vdr.c b/vdr.c index 042b03ce7..c8cabb0b5 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.36 2000/10/03 13:52:26 kls Exp $ + * $Id: vdr.c 1.39 2000/10/08 14:49:25 kls Exp $ */ #include @@ -161,6 +161,10 @@ int main(int argc, char *argv[]) if (!cDvbApi::Init()) abort(); + // User interface: + + Interface = new cInterface(SVDRPport); + // Configuration data: if (!ConfigDirectory) @@ -173,9 +177,8 @@ int main(int argc, char *argv[]) Keys.SetDummyValues(); #else if (!Keys.Load(AddDirectory(ConfigDirectory, KEYS_CONF))) - Interface.LearnKeys(); + Interface->LearnKeys(); #endif - Interface.Init(SVDRPport); cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); @@ -215,7 +218,7 @@ int main(int argc, char *argv[]) } // User Input: cOsdBase **Interact = Menu ? &Menu : (cOsdBase **)&ReplayControl; - eKeys key = Interface.GetKey(!*Interact || !(*Interact)->NeedsFastResponse()); + eKeys key = Interface->GetKey(!*Interact || !(*Interact)->NeedsFastResponse()); if (*Interact) { switch ((*Interact)->ProcessKey(key)) { case osMenu: DELETENULL(Menu); @@ -223,7 +226,12 @@ int main(int argc, char *argv[]) break; case osRecord: DELETENULL(Menu); if (!cRecordControls::Start()) - Interface.Error("No free DVB device to record!"); + Interface->Error("No free DVB device to record!"); + break; + case osRecordings: + DELETENULL(Menu); + DELETENULL(ReplayControl); + Menu = new cMenuRecordings; break; case osReplay: DELETENULL(Menu); DELETENULL(ReplayControl); @@ -235,7 +243,7 @@ int main(int argc, char *argv[]) break; case osSwitchDvb: DELETENULL(*Interact); - Interface.Info("Switching primary DVB..."); + Interface->Info("Switching primary DVB..."); cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); break; case osBack: @@ -253,14 +261,16 @@ int main(int argc, char *argv[]) break; // Direct Channel Select: case k1 ... k9: - if (!Interface.Recording()) + if (!Interface->Recording()) Menu = new cDirectChannelSelect(key); break; // Left/Right rotates trough channel groups: + case kLeft|k_Repeat: case kLeft: - case kRight: if (!Interface.Recording()) { + case kRight|k_Repeat: + case kRight: if (!Interface->Recording()) { int SaveGroup = CurrentGroup; - if (key == kRight) + if (NORMALKEY(key) == kRight) CurrentGroup = Channels.GetNextGroup(CurrentGroup) ; else CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup); @@ -271,9 +281,11 @@ int main(int argc, char *argv[]) } break; // Up/Down Channel Select: + case kUp|k_Repeat: case kUp: - case kDown: if (!Interface.Recording()) { - int n = CurrentChannel + (key == kUp ? 1 : -1); + case kDown|k_Repeat: + case kDown: if (!Interface->Recording()) { + int n = CurrentChannel + (NORMALKEY(key) == kUp ? 1 : -1); cChannel *channel = Channels.GetByNumber(n); if (channel) channel->Switch(); @@ -290,7 +302,7 @@ int main(int argc, char *argv[]) isyslog(LOG_INFO, "caught signal %d", Interrupted); delete Menu; delete ReplayControl; - Interface.Cleanup(); + delete Interface; cDvbApi::Cleanup(); isyslog(LOG_INFO, "exiting"); if (SysLogLevel > 0) From a69b3211dc4f9b34eef440067d5ba304fbfbad94 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Wed, 1 Nov 2000 18:00:00 +0100 Subject: [PATCH 014/307] Version 0.67 - The EIT information is now gathered in a separate thread. - The sytem time can now be synchronized to the time broadcast in the DVB data stream. This can be enabled in the "Setup" menu by setting "SetSystemTime" to 1. Note that this works only if VDR is running under a user id that has permisson to set the system time. - The new item "Schedule" in the "Main" menu opens VDR's EPG (thanks to Robert Schneider). See the MANUAL file for a detailed description. - The new setup parameters MarginStart and MarginStop define how long (in minutes) before the official start time of a broadcast VDR shall begin recording, and how long after the official end time it shall stop recording. These are used when a recording is programmed from the "Schedules" menu. - The delay value in the dvb.c.071.diff patch to the driver has been increased to '3', because on some systems the OSD was not displayed correctly. If you are running an already patched version 0.71 driver and encounter problems with the OSD, please make sure the parameter in the ddelay call is '3', not '2'. - Fixed initializing the RCU remote control code (didn't work after switching on the system). - Problematic characters in recording names (which can come from timers that are programmed via the "Schedules" menu) are now replaced by suitable substitutes. --- BUGS | 2 + CONTRIBUTORS | 1 + HISTORY | 24 + MANUAL | 59 +- Makefile | 20 +- channels.conf | 3 + config.c | 100 +++- config.h | 10 +- dvb.c.071.diff | 2 +- dvbapi.c | 67 ++- dvbapi.h | 16 +- dvbosd.c | 7 +- dvbosd.h | 3 +- eit.c | 1443 ++++++++++++++++++++++++++++++++++++------------ eit.h | 173 +++--- interface.c | 157 +++--- interface.h | 10 +- menu.c | 567 +++++++++++++++++-- menu.h | 16 +- osd.c | 15 +- osd.h | 16 +- recording.c | 9 +- setup.conf | 7 - thread.c | 19 +- thread.h | 5 +- timers.conf | 13 +- tools.c | 15 +- tools.h | 19 +- vdr.c | 24 +- 29 files changed, 2182 insertions(+), 640 deletions(-) delete mode 100644 setup.conf diff --git a/BUGS b/BUGS index cd96197d8..d24d37072 100644 --- a/BUGS +++ b/BUGS @@ -4,3 +4,5 @@ Video Disk Recorder - Known Bugs * Sometimes the picture "jumps" as if a frame is skipped. Presumably this is a problem in the card driver or firmware? +* The first picture captured with the GRAB command in SVDRP + is empty. Also, these pictures appear to be too dark. diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 91c9540ec..db47d8b9e 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -26,6 +26,7 @@ Guido Fiala Robert Schneider for implementing EIT support for displaying the current/next info + for extending EIT support to implement a complete EPG Niels de Carpentier for adding a workaround for a driver timing problem in cDvbApi::Cmd() diff --git a/HISTORY b/HISTORY index 717102a6f..189fd7b32 100644 --- a/HISTORY +++ b/HISTORY @@ -241,3 +241,27 @@ Video Disk Recorder Revision History - The "Blue" button in the "Main" menu can now be used to "Resume" a previously stopped replay session (suggested by Martin Hammerschmid). - The low and high LNB frequencies can now be changed in the "Setup" menu. + +2000-11-01: Version 0.67 + +- The EIT information is now gathered in a separate thread. +- The sytem time can now be synchronized to the time broadcast in the DVB data + stream. This can be enabled in the "Setup" menu by setting "SetSystemTime" to + 1. Note that this works only if VDR is running under a user id that has + permisson to set the system time. +- The new item "Schedule" in the "Main" menu opens VDR's EPG (thanks to Robert + Schneider). See the MANUAL file for a detailed description. +- The new setup parameters MarginStart and MarginStop define how long (in + minutes) before the official start time of a broadcast VDR shall begin + recording, and how long after the official end time it shall stop recording. + These are used when a recording is programmed from the "Schedules" menu. +- The delay value in the dvb.c.071.diff patch to the driver has been increased + to '3', because on some systems the OSD was not displayed correctly. If you + are running an already patched version 0.71 driver and encounter problems + with the OSD, please make sure the parameter in the ddelay call is '3', not + '2'. +- Fixed initializing the RCU remote control code (didn't work after switching + on the system). +- Problematic characters in recording names (which can come from timers that + are programmed via the "Schedules" menu) are now replaced by suitable + substitutes. diff --git a/MANUAL b/MANUAL index 9b864e367..ffcc10b86 100644 --- a/MANUAL +++ b/MANUAL @@ -53,20 +53,60 @@ Video Disk Recorder User's Manual At any point in the menu system, pressing the "Menu" key again will immediately leave the menu system (discarding any pending changes). +* The "Schedule" Menu + + The "Schedule" menu implements VDR's "Electronic Program Guide" (EPG). + + Select "Schedule" from the "Main" menu and you get a list of all upcoming + broadcasts on the current channel. + + "Up" and "Down" can be used to scroll through this list, and pressing "Ok" + displays detailed information about the selected programme. Pressing "Ok" + again (or pressing "Back") gets you back into the "Schedule" menu. + + From the "Schedule" menu, the "Green" button opens the "What's on now?" + menu, which displays all programmes that are currently running on all + channels that broadcast their programme information on the current + transponder, or from channels that have been current lately (VDR stores + all information it gathers in an internal list). The more channels you + have been switching through lately, the longer this list will be. + The "Yellow" button opens the "What's on next?" menu, which lists all + programmes that will start next on all channels. + + Inside the "What's on now/next?" menus the "Green" button toggles between + the "Now" and "Next" display, and the "Yellow" button gets you back to the + "Schedule" menu of the current channel. + + The "Red" button allows you to instantly program a timer to record the + selected programme. You will get into the "Edit Timer" menu in which + everything has already been filled in, and you can make any modifications + you may want to apply. Note that the Start and Stop time are offset by the + MarginStart and MarginStop parameters (see Setup) in order to make sure the + entire programme is recorded in case it doesn't exactly adhere to its + published start/stop times. Of course, no guarantee can be given that the + default margin values will be sufficient, so in case this recording is + really important you may want to add an extra margin ;-) + + The "Blue" button can be pressed to switch to the channel with the selected + programme. + * Selecting a Channel - There are three ways to select a channel: + There are four ways to select a channel: 1. With no On Screen Menu displayed press the "Up" or "Down" key to switch to the next higher or lower channel. 2. Press the "Menu" button to bring up the On Screen Menu, select "Channels" and browse through the list with the "Up" and "Down" key; to switch to the selected channel press "Ok". - 2. Directly type in the channel number with the numeric keys ('0'..'9'); + 3. Directly type in the channel number with the numeric keys ('0'..'9'); if no key is pressed for about half a second, the digits collected so far will define the channel number. + 4. From the "Now", "Next" and "Event" menus (accessible through the "Schedule" + menu) by pressing the "Blue" button. - Pressing the '0' key toggles between the current and the previous channel. + Pressing the '0' key in normal viewing mode toggles between the current and + the previous channel. After switching to a different channel the channel number and name, as well as the current time are displayed at the top of the screen. If available, the @@ -178,6 +218,9 @@ Video Disk Recorder User's Manual If this field is left blank, the channel name will be used to form the name of the recording. + A timer can also be programmed by pressing the "Red" button on the "Schedule", + "Now", "Next" or "Event" menus. + * Parameters in the "Setup" menu Select "Setup" from the "Main" menu to enter the setup menu. From there you can @@ -216,3 +259,13 @@ Video Disk Recorder User's Manual LnbFrequLo = 9750 The low and high LNB frequencies (in MHz) LnbFrequHi = 10600 + + SetSystemTime = 0 Defines whether the system time will be set according to + the time received from the DVB data stream. + 0 = system time will not be set + 1 = system time wil be set + Note that this works only if VDR is running under a user + id that has permisson to set the system time. + MarginStart = 2 Defines how many minutes before the official start time + MarginStop = 10 of a broadcast VDR shall start recording, and how long + after the official end time it shall stop recording. diff --git a/Makefile b/Makefile index 8b32be2d8..9db79f395 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.13 2000/10/07 16:24:08 kls Exp $ +# $Id: Makefile 1.14 2000/10/28 16:24:16 kls Exp $ DVBDIR = ../DVB @@ -35,20 +35,20 @@ font: genfontfile fontosd.c # Dependencies: -config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h svdrp.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h videodir.h +config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h +dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h videodir.h dvbosd.o : dvbosd.c dvbosd.h font.h tools.h -eit.o : eit.c eit.h tools.h +eit.o : eit.c eit.h thread.h tools.h font.o : font.c font.h fontosd.c tools.h interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h -menu.o : menu.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h -osd.o : osd.c config.h dvbapi.h dvbosd.h font.h interface.h osd.h svdrp.h tools.h -recording.o: recording.c config.h dvbapi.h dvbosd.h font.h interface.h recording.h svdrp.h tools.h videodir.h -remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h thread.h tools.h -svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h +menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h +osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h osd.h remote.h svdrp.h thread.h tools.h +recording.o: recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h +remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h +svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h thread.o : thread.c thread.h tools.o : tools.c tools.h -vdr.o : vdr.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h +vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h videodir.o : videodir.c tools.h videodir.h # The main program: diff --git a/channels.conf b/channels.conf index 4a6cb0b34..c61669cab 100644 --- a/channels.conf +++ b/channels.conf @@ -6,6 +6,7 @@ ARD:11837:h:1:27500:101:102:0:28106 BR3:11837:h:1:27500:201:202:0:28107 Hessen-3:11837:h:1:27500:301:302:0:28108 N3:12110:h:1:27500:2401:2402:0:28224 +:Group 1 SR3:11837:h:1:27500:501:502:0:28110 WDR:11837:h:1:27500:601:602:0:28111 BR-alpha:11837:h:1:27500:701:702:0:28112 @@ -15,9 +16,11 @@ ZDF:11954:h:1:27500:110:120:0:28006 3sat:11954:h:1:27500:210:220:0:28007 KiKa:11954:h:1:27500:310:320:0:28008 arte:11836:h:1:27500:401:402:0:28109 +:Group 2 Eurosport:11954:h:1:27500:410:420:0:28009 ORF Sat:11954:h:1:27500:506:507:0:28010 ZDF.info:11954:h:1:27500:610:620:0:28011 +:Group 3 CNN:12168:v:1:27500:165:100:0:0 Super RTL:12188:h:1:27500:165:120:0:12040 VOX:12188:h:1:27500:167:136:0:12060 diff --git a/config.c b/config.c index 1714651fa..5b485f663 100644 --- a/config.c +++ b/config.c @@ -4,18 +4,15 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.26 2000/10/08 16:10:40 kls Exp $ + * $Id: config.c 1.29 2000/11/01 18:22:43 kls Exp $ */ #include "config.h" #include #include #include "dvbapi.h" -#include "eit.h" #include "interface.h" -extern cEIT EIT; - // -- cKeys ------------------------------------------------------------------ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! @@ -267,15 +264,14 @@ bool cChannel::Switch(cDvbApi *DvbApi) isyslog(LOG_INFO, "switching to channel %d", number); CurrentChannel = number; for (int i = 3; i--;) { - if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) { - EIT.SetProgramNumber(pnr); + if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) return true; - } esyslog(LOG_ERR, "retrying"); } return false; } - Interface->Info(DvbApi->Recording() ? "Channel locked (recording)!" : name); + if (DvbApi->Recording()) + Interface->Info("Channel locked (recording)!"); return false; } @@ -306,6 +302,47 @@ cTimer::cTimer(bool Instant) snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", ch->name); } +cTimer::cTimer(const cEventInfo *EventInfo) +{ + startTime = stopTime = 0; + recording = false; + active = true; + cChannel *ch = Channels.GetByServiceID(EventInfo->GetServiceID()); + channel = ch ? ch->number : 0; + time_t tstart = EventInfo->GetTime(); + time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60; + tstart -= Setup.MarginStart * 60; + struct tm *time = localtime(&tstart); + day = time->tm_mday; + start = time->tm_hour * 100 + time->tm_min; + time = localtime(&tstop); + stop = time->tm_hour * 100 + time->tm_min; + if (stop >= 2400) + stop -= 2400; + priority = 99; + lifetime = 99; + *file = 0; + const char *Title = EventInfo->GetTitle(); + if (!isempty(Title)) + strn0cpy(file, EventInfo->GetTitle(), sizeof(file)); + summary = NULL; + const char *Subtitle = EventInfo->GetSubtitle(); + if (isempty(Subtitle)) + Subtitle = ""; + const char *Summary = EventInfo->GetExtendedDescription(); + if (isempty(Summary)) + Summary = ""; + if (*Subtitle || *Summary) { + asprintf(&summary, "%s%s%s", Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary); + char *p = summary; + while (*p) { + if (*p == '\n') + *p = '|'; + p++; + } + } +} + cTimer::~cTimer() { delete summary; @@ -388,14 +425,33 @@ bool cTimer::Parse(const char *s) char *buffer2 = NULL; delete summary; summary = NULL; + //XXX Apparently sscanf() doesn't work correctly if the last %a argument + //XXX results in an empty string (this firt occured when the EIT gathering + //XXX was put into a separate thread - don't know why this happens... + //XXX As a cure we copy the original string and add a blank. + //XXX If anybody can shed some light on why sscanf() failes here, I'd love + //XXX to hear about that! + char *s2 = NULL; + int l2 = strlen(s); + if (s[l2 - 2] == ':') { // note that 's' has a trailing '\n' + s2 = (char *)malloc(l2 + 2); + strcat(strn0cpy(s2, s, l2), " \n"); + s = s2; + } if (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) { + if (summary && !*skipspace(summary)) { + delete summary; + summary = NULL; + } //TODO add more plausibility checks day = ParseDay(buffer1); strn0cpy(file, buffer2, MaxFileName); delete buffer1; delete buffer2; + delete s2; return day != 0; } + delete s2; return false; } @@ -550,6 +606,17 @@ cChannel *cChannels::GetByNumber(int Number) return NULL; } +cChannel *cChannels::GetByServiceID(unsigned short ServiceId) +{ + cChannel *channel = (cChannel *)First(); + while (channel) { + if (channel->pnr == ServiceId) + return channel; + channel = (cChannel *)channel->Next(); + } + return NULL; +} + bool cChannels::SwitchTo(int Number, cDvbApi *DvbApi) { cChannel *channel = GetByNumber(Number); @@ -562,14 +629,6 @@ const char *cChannels::GetChannelNameByNumber(int Number) return channel ? channel->name : NULL; } -eKeys cChannels::ShowChannel(int Number, bool Switched, bool Group) -{ - cChannel *channel = Group ? Get(Number) : GetByNumber(Number); - if (channel) - return Interface->DisplayChannel(channel->number, channel->name, !Switched || Setup.ShowInfoOnChSwitch); - return kNone; -} - // -- cTimers ---------------------------------------------------------------- cTimers Timers; @@ -599,6 +658,9 @@ cSetup::cSetup(void) MarkInstantRecord = 1; LnbFrequLo = 9750; LnbFrequHi = 10600; + SetSystemTime = 0; + MarginStart = 2; + MarginStop = 10; } bool cSetup::Parse(char *s) @@ -613,6 +675,9 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); + else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); + else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); + else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); else return false; return true; @@ -660,6 +725,9 @@ bool cSetup::Save(const char *FileName) fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord); fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo); fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); + fprintf(f, "SetSystemTime = %d\n", SetSystemTime); + fprintf(f, "MarginStart = %d\n", MarginStart); + fprintf(f, "MarginStop = %d\n", MarginStop); fclose(f); isyslog(LOG_INFO, "saved setup to %s", FileName); return true; diff --git a/config.h b/config.h index 56f361822..f9bd579e7 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.27 2000/10/08 16:33:48 kls Exp $ + * $Id: config.h 1.29 2000/11/01 13:42:29 kls Exp $ */ #ifndef __CONFIG_H @@ -15,9 +15,10 @@ #include #include #include "dvbapi.h" +#include "eit.h" #include "tools.h" -#define VDRVERSION "0.66" +#define VDRVERSION "0.67" #define MaxBuffer 10000 @@ -113,6 +114,7 @@ class cTimer : public cListObject { char file[MaxFileName]; char *summary; cTimer(bool Instant = false); + cTimer(const cEventInfo *EventInfo); ~cTimer(); cTimer& operator= (const cTimer &Timer); const char *ToText(void); @@ -204,10 +206,10 @@ class cChannels : public cConfig { int GetNextNormal(int Idx); // Get next normal channel (not group) void ReNumber(void); // Recalculate 'number' based on channel type cChannel *GetByNumber(int Number); + cChannel *GetByServiceID(unsigned short ServiceId); const char *GetChannelNameByNumber(int Number); bool SwitchTo(int Number, cDvbApi *DvbApi = NULL); int MaxNumber(void) { return maxNumber; } - eKeys ShowChannel(int Number, bool Switched, bool Group = false); }; class cTimers : public cConfig { @@ -234,6 +236,8 @@ class cSetup { int MarkInstantRecord; int LnbFrequLo; int LnbFrequHi; + int SetSystemTime; + int MarginStart, MarginStop; cSetup(void); bool Load(const char *FileName); bool Save(const char *FileName = NULL); diff --git a/dvb.c.071.diff b/dvb.c.071.diff index 647b0de1b..ac7ba3a4a 100644 --- a/dvb.c.071.diff +++ b/dvb.c.071.diff @@ -81,7 +81,7 @@ BlitBitmap(dvb, dvb->osdwin, x0, y0+i*lpb, 1); - data+=bpl; + data+=lpb*inc; //XXX kls: incrementing must be done in "one byte per pixel" -+ ddelay(2); //XXX kls: without this the block is sometimes not fully displayed - firmware bug? ++ ddelay(3); //XXX kls: without this the block is sometimes not fully displayed - firmware bug? } if (brest) { - LoadBitmap(dvb, BITMAP8, w, brest/bpl, inc, data); diff --git a/dvbapi.c b/dvbapi.c index e5c692cbd..cc246d2f0 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.31 2000/10/08 16:14:45 kls Exp $ + * $Id: dvbapi.c 1.34 2000/11/01 09:19:27 kls Exp $ */ #include "dvbapi.h" @@ -25,6 +25,7 @@ extern "C" { #include "videodir.h" #define VIDEODEVICE "/dev/video" +#define VBIDEVICE "/dev/vbi" // The size of the array used to buffer video data: #define VIDEOBUFSIZE (1024*1024) @@ -1084,14 +1085,27 @@ int cDvbApi::NumDvbApis = 0; cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL }; cDvbApi *cDvbApi::PrimaryDvbApi = NULL; -cDvbApi::cDvbApi(const char *FileName) +cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) { + siProcessor = NULL; pidRecord = pidReplay = 0; fromRecord = toRecord = -1; fromReplay = toReplay = -1; - videoDev = open(FileName, O_RDWR | O_NONBLOCK); - if (videoDev < 0) - LOG_ERROR; + videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK); + if (videoDev >= 0) { + siProcessor = new cSIProcessor(VbiFileName); + if (!NumDvbApis) // only the first one shall set the system time + siProcessor->SetUseTSTime(Setup.SetSystemTime); + siProcessor->AddFilter(0x14, 0x70); // TDT + siProcessor->AddFilter(0x14, 0x73); // TOT + siProcessor->AddFilter(0x12, 0x4e); // event info, actual TS, present/following + siProcessor->AddFilter(0x12, 0x4f); // event info, other TS, present/following + siProcessor->AddFilter(0x12, 0x50); // event info, actual TS, schedule + siProcessor->AddFilter(0x12, 0x60); // event info, other TS, schedule + siProcessor->Start(); + } + else + LOG_ERROR_STR(VideoFileName); cols = rows = 0; ovlGeoSet = ovlStat = ovlFbSet = false; @@ -1104,7 +1118,7 @@ cDvbApi::cDvbApi(const char *FileName) nonl(); cbreak(); noecho(); - timeout(1000); + timeout(10); #endif #if defined(DEBUG_OSD) memset(&colorPairs, 0, sizeof(colorPairs)); @@ -1121,6 +1135,7 @@ cDvbApi::cDvbApi(const char *FileName) cDvbApi::~cDvbApi() { if (videoDev >= 0) { + delete siProcessor; Close(); Stop(); StopRecord(); @@ -1174,11 +1189,9 @@ int cDvbApi::Index(void) bool cDvbApi::Init(void) { - char fileName[strlen(VIDEODEVICE) + 10]; - int i; - NumDvbApis = 0; - for (i = 0; i < MAXDVBAPI; i++) { + for (int i = 0; i < MAXDVBAPI; i++) { + char fileName[strlen(VIDEODEVICE) + 10]; sprintf(fileName, "%s%d", VIDEODEVICE, i); if (access(fileName, F_OK | R_OK | W_OK) == 0) { dsyslog(LOG_INFO, "probing %s", fileName); @@ -1188,7 +1201,9 @@ bool cDvbApi::Init(void) int r = ioctl(f, VIDIOCGCAP, &cap); close(f); if (r == 0 && (cap.type & VID_TYPE_DVB)) { - dvbApi[i] = new cDvbApi(fileName); + char vbiFileName[strlen(VBIDEVICE) + 10]; + sprintf(vbiFileName, "%s%d", VBIDEVICE, i); + dvbApi[i] = new cDvbApi(fileName, vbiFileName); NumDvbApis++; } } @@ -1223,6 +1238,13 @@ void cDvbApi::Cleanup(void) PrimaryDvbApi = NULL; } +const cSchedules *cDvbApi::Schedules(cThreadLock *ThreadLock) const +{ + if (siProcessor && ThreadLock->Lock(siProcessor)) + return siProcessor->Schedules(); + return NULL; +} + bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) { int result = 0; @@ -1576,6 +1598,24 @@ void cDvbApi::ClrEol(int x, int y, eDvbColor color) Fill(x, y, cols - x, 1, color); } +int cDvbApi::CellWidth(void) +{ +#ifdef DEBUG_OSD + return 1; +#else + return charWidth; +#endif +} + +int cDvbApi::Width(unsigned char c) +{ +#ifdef DEBUG_OSD + return 1; +#else + return osd->Width(c); +#endif +} + void cDvbApi::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg) { if (x < 0) x = cols + x; @@ -1671,8 +1711,11 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr front.fec = 8; front.AFC = 1; ioctl(videoDev, VIDIOCSFRONTEND, &front); - if (front.sync & 0x1F == 0x1F) + if (front.sync & 0x1F == 0x1F) { + if (siProcessor) + siProcessor->SetCurrentServiceID(Pnr); return true; + } esyslog(LOG_ERR, "ERROR: channel not sync'ed (front.sync=%X)!", front.sync); } return false; diff --git a/dvbapi.h b/dvbapi.h index b35f3fb80..16a2b7a71 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.18 2000/10/03 11:26:10 kls Exp $ + * $Id: dvbapi.h 1.20 2000/11/01 09:18:50 kls Exp $ */ #ifndef __DVBAPI_H @@ -21,6 +21,7 @@ typedef unsigned char __u8; #include #include #include "dvbosd.h" +#include "eit.h" // Overlay facilities #define MAXCLIPRECTS 100 @@ -44,7 +45,8 @@ class cResumeFile { class cDvbApi { private: int videoDev; - cDvbApi(const char *FileName); + cSIProcessor *siProcessor; + cDvbApi(const char *VideoFileName, const char *VbiFileName); public: ~cDvbApi(); @@ -71,6 +73,14 @@ class cDvbApi { // Closes down all DVB devices. // Must be called at the end of the program. + // EIT facilities + + const cSchedules *Schedules(cThreadLock *ThreadLock) const; + // Caller must provide a cThreadLock which has to survive the entire + // time the returned cSchedules is accessed. Once the cSchedules is no + // longer used, the cThreadLock must be destroyed. + void SetUseTSTime(bool On) { if (siProcessor) siProcessor->SetUseTSTime(On); } + // Image Grab facilities bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); @@ -112,6 +122,8 @@ class cDvbApi { 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); + int CellWidth(void); + int Width(unsigned char c); void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground); void Flush(void); diff --git a/dvbosd.c b/dvbosd.c index 97c793228..c0150e269 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.3 2000/10/07 14:42:48 kls Exp $ + * $Id: dvbosd.c 1.4 2000/11/01 09:13:32 kls Exp $ */ #include "dvbosd.h" @@ -76,6 +76,11 @@ void cBitmap::SetPixel(int x, int y, eDvbColor Color) } } +int cBitmap::Width(unsigned char c) +{ + return font ? font->Width(c) : -1; +} + void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) { if (bitmap) { diff --git a/dvbosd.h b/dvbosd.h index f7a536350..149dc6cb1 100644 --- a/dvbosd.h +++ b/dvbosd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.h 1.1 2000/10/01 15:00:00 kls Exp $ + * $Id: dvbosd.h 1.2 2000/11/01 09:13:44 kls Exp $ */ #ifndef __DVBOSD_H @@ -56,6 +56,7 @@ class cBitmap { void SetFont(eDvbFont Font); bool Dirty(void); void SetPixel(int x, int y, eDvbColor Color); + int Width(unsigned char c); void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); void Fill(int x1, int y1, int x2, int y2, eDvbColor Color); void Clear(void); diff --git a/eit.c b/eit.c index 44c873b17..65856e6c3 100644 --- a/eit.c +++ b/eit.c @@ -13,20 +13,606 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.4 2000/10/01 14:09:05 kls Exp $ + * $Id: eit.c 1.7 2000/11/02 17:06:19 kls Exp $ ***************************************************************************/ #include "eit.h" +#include +#include +#include +#include +#include +#include #include +#include #include -#include -#include -#include +#include +#include #include -#include -#include "tools.h" +#include +#include +#include +#include +#include + +// --- cMJD ------------------------------------------------------------------ + +class cMJD { +public: + cMJD(); + cMJD(u_char date_hi, u_char date_lo); + cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese); + ~cMJD(); + /** */ + void ConvertToTime(); + /** */ + bool SetSystemTime(); + /** */ + time_t GetTime_t(); +protected: // Protected attributes + /** */ + time_t mjdtime; +protected: // Protected attributes + /** */ + u_char time_second; +protected: // Protected attributes + /** */ + u_char time_minute; +protected: // Protected attributes + /** */ + u_char time_hour; +protected: // Protected attributes + /** */ + u_short mjd; +}; + +cMJD::cMJD() +{ +} + +cMJD::cMJD(u_char date_hi, u_char date_lo) +{ + mjd = date_hi << 8 | date_lo; + time_hour = time_minute = time_second = 0; + ConvertToTime(); +} + +cMJD::cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese) +{ + mjd = date_hi << 8 | date_lo; + time_hour = timehr; + time_minute = timemi; + time_second = timese; + ConvertToTime(); +} + +cMJD::~cMJD() +{ +} + +/** */ +void cMJD::ConvertToTime() +{ + struct tm t; + + t.tm_sec = time_second; + t.tm_min = time_minute; + t.tm_hour = time_hour; + int k; + + t.tm_year = (int) ((mjd - 15078.2) / 365.25); + t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001); + t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001)); + k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0; + t.tm_year = t.tm_year + k; + t.tm_mon = t.tm_mon - 1 - k * 12; + t.tm_mon--; + + t.tm_isdst = -1; + t.tm_gmtoff = 0; + + mjdtime = timegm(&t); + + //isyslog(LOG_INFO, "Time parsed = %s\n", ctime(&mjdtime)); +} + +/** */ +bool cMJD::SetSystemTime() +{ + struct tm *ptm; + time_t loctim; + + ptm = localtime(&mjdtime); + loctim = time(NULL); + + if (abs(mjdtime - loctim) > 2) + { + isyslog(LOG_INFO, "System Time = %s (%ld)\n", ctime(&loctim), loctim); + isyslog(LOG_INFO, "Local Time = %s (%ld)\n", ctime(&mjdtime), mjdtime); + if (stime(&mjdtime) < 0) + esyslog(LOG_ERR, "ERROR while setting system time: %s", strerror(errno)); + return true; + } + + return false; +} +/** */ +time_t cMJD::GetTime_t() +{ + return mjdtime; +} + +// --- cTDT ------------------------------------------------------------------ typedef struct { + u_char table_id : 8; + +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator : 1; + u_char : 3; + u_char section_length_hi : 4; +#else + u_char section_length_hi : 4; + u_char : 3; + u_char section_syntax_indicator : 1; +#endif + + u_char section_length_lo : 8; + + + u_char utc_date_hi : 8; + u_char utc_date_lo : 8; + u_char utc_hour : 4; + u_char utc_hour_ten : 4; + u_char utc_min : 4; + u_char utc_min_ten : 4; + u_char utc_sec : 4; + u_char utc_sec_ten : 4; +} tdt_t; + +class cTDT { +public: + cTDT(tdt_t *ptdt); + ~cTDT(); + /** */ + bool SetSystemTime(); +protected: // Protected attributes + /** */ + tdt_t tdt; + /** */ + cMJD * mjd; +}; + +cTDT::cTDT(tdt_t *ptdt) +{ + tdt = *ptdt; + mjd = new cMJD(tdt.utc_date_hi, tdt.utc_date_lo, + tdt.utc_hour_ten * 10 + tdt.utc_hour, + tdt.utc_min_ten * 10 + tdt.utc_min, + tdt.utc_sec_ten * 10 + tdt.utc_sec); +} + +cTDT::~cTDT() +{ +} +/** */ +bool cTDT::SetSystemTime() +{ + return mjd->SetSystemTime(); +} + +// --- cEventInfo ------------------------------------------------------------ + +cEventInfo::cEventInfo(unsigned short serviceid, unsigned short eventid) +{ + pTitle = NULL; + pSubtitle = NULL; + pExtendedDescription = NULL; + bIsPresent = bIsFollowing = false; + lDuration = 0; + tTime = 0; + uEventID = eventid; + uServiceID = serviceid; + cExtendedDescriptorNumber = 0; + nChannelNumber = 0; +} + +cEventInfo::~cEventInfo() +{ + delete pTitle; + delete pSubtitle; + delete pExtendedDescription; +} + +/** */ +const char * cEventInfo::GetTitle() const +{ + return pTitle; +} +/** */ +const char * cEventInfo::GetSubtitle() const +{ + return pSubtitle; +} +/** */ +const char * cEventInfo::GetExtendedDescription() const +{ + return pExtendedDescription; +} +/** */ +bool cEventInfo::IsPresent() const +{ + return bIsPresent; +} +/** */ +void cEventInfo::SetPresent(bool pres) +{ + bIsPresent = pres; +} +/** */ +bool cEventInfo::IsFollowing() const +{ + return bIsFollowing; +} +/** */ +void cEventInfo::SetFollowing(bool foll) +{ + bIsFollowing = foll; +} +/** */ +const char * cEventInfo::GetDate() const +{ + static char szDate[25]; + + strftime(szDate, sizeof(szDate), "%d.%m.%Y", localtime(&tTime)); + + return szDate; +} +/** */ +const char * cEventInfo::GetTimeString() const +{ + static char szTime[25]; + + strftime(szTime, sizeof(szTime), "%R", localtime(&tTime)); + + return szTime; +} +/** */ +const char * cEventInfo::GetEndTimeString() const +{ + static char szEndTime[25]; + time_t tEndTime = tTime + lDuration; + + strftime(szEndTime, sizeof(szEndTime), "%R", localtime(&tEndTime)); + + return szEndTime; +} +/** */ +time_t cEventInfo::GetTime() const +{ + return tTime; +} +/** */ +long cEventInfo::GetDuration() const +{ + return lDuration; +} +/** */ +unsigned short cEventInfo::GetEventID() const +{ + return uEventID; +} +/** */ +bool cEventInfo::SetTitle(char *string) +{ + if (string == NULL) + return false; + + pTitle = strdup(string); + if (pTitle == NULL) + return false; + + return true; +} +/** */ +bool cEventInfo::SetSubtitle(char *string) +{ + if (string == NULL) + return false; + + pSubtitle = strdup(string); + if (pSubtitle == NULL) + return false; + + return true; +} +/** */ +bool cEventInfo::AddExtendedDescription(char *string) +{ + int size = 0; + bool first = true; + char *p; + + if (string == NULL) + return false; + + if (pExtendedDescription) + { + first = false; + size += strlen(pExtendedDescription); + } + + size += (strlen(string) + 1); + + p = (char *)realloc(pExtendedDescription, size); + if (p == NULL) + return false; + + if (first) + *p = 0; + + strcat(p, string); + + pExtendedDescription = p; + + return true; +} +/** */ +void cEventInfo::SetTime(time_t t) +{ + tTime = t; +} +/** */ +void cEventInfo::SetDuration(long l) +{ + lDuration = l; +} +/** */ +void cEventInfo::SetEventID(unsigned short evid) +{ + uEventID = evid; +} +/** */ +void cEventInfo::SetServiceID(unsigned short servid) +{ + uServiceID = servid; +} +/** */ +u_char cEventInfo::GetExtendedDescriptorNumber() const +{ + return cExtendedDescriptorNumber; +} +/** */ +void cEventInfo::IncreaseExtendedDescriptorNumber() +{ + cExtendedDescriptorNumber++; +} + +/** */ +unsigned short cEventInfo::GetServiceID() const +{ + return uServiceID; +} + +// --- cSchedule ------------------------------------------------------------- + +cSchedule::cSchedule(unsigned short servid) +{ + pPresent = pFollowing = NULL; + uServiceID = servid; +} + + +cSchedule::~cSchedule() +{ +} +/** */ +const cEventInfo * cSchedule::GetPresentEvent() const +{ + // checking temporal sanity of present event (kls 2000-11-01) + time_t now = time(NULL); + if (pPresent && !(pPresent->GetTime() <= now && now <= pPresent->GetTime() + pPresent->GetDuration())) + { + cEventInfo *pe = Events.First(); + while (pe != NULL) + { + if (pe->GetTime() <= now && now <= pe->GetTime() + pe->GetDuration()) + return pe; + pe = Events.Next(pe); + } + } + return pPresent; +} +/** */ +const cEventInfo * cSchedule::GetFollowingEvent() const +{ + // checking temporal sanity of following event (kls 2000-11-01) + time_t now = time(NULL); + const cEventInfo *pr = GetPresentEvent(); // must have it verified! + if (pFollowing && !(pr && pr->GetTime() + pr->GetDuration() <= pFollowing->GetTime())) + { + int minDt = INT_MAX; + cEventInfo *pe = Events.First(), *pf = NULL; + while (pe != NULL) + { + int dt = pe->GetTime() - now; + if (dt > 0 && dt < minDt) + { + minDt = dt; + pf = pe; + } + pe = Events.Next(pe); + } + return pf; + } + return pFollowing; +} +/** */ +void cSchedule::SetServiceID(unsigned short servid) +{ + uServiceID = servid; +} +/** */ +unsigned short cSchedule::GetServiceID() const +{ + return uServiceID; +} +/** */ +const cEventInfo * cSchedule::GetEvent(unsigned short uEventID) const +{ + cEventInfo *pe = Events.First(); + while (pe != NULL) + { + if (pe->GetEventID() == uEventID) + return pe; + + pe = Events.Next(pe); + } + + return NULL; +} +/** */ +const cEventInfo * cSchedule::GetEvent(time_t tTime) const +{ + cEventInfo *pe = Events.First(); + while (pe != NULL) + { + if (pe->GetTime() == tTime) + return pe; + + pe = Events.Next(pe); + } + + return NULL; +} +/** */ +bool cSchedule::SetPresentEvent(cEventInfo *pEvent) +{ + if (pPresent != NULL) + pPresent->SetPresent(false); + pPresent = pEvent; + pPresent->SetPresent(true); + + return true; +} + +/** */ +bool cSchedule::SetFollowingEvent(cEventInfo *pEvent) +{ + if (pFollowing != NULL) + pFollowing->SetFollowing(false); + pFollowing = pEvent; + pFollowing->SetFollowing(true); + + return true; +} + +/** */ +void cSchedule::Cleanup() +{ + Cleanup(time(NULL)); +} + +/** */ +void cSchedule::Cleanup(time_t tTime) +{ + cEventInfo *pEvent; + for (int a = 0; true ; a++) + { + pEvent = Events.Get(a); + if (pEvent == NULL) + break; + if (pEvent->GetTime() + pEvent->GetDuration() < tTime) + { + Events.Del(pEvent); + a--; + } + } +} + +// --- cSchedules ------------------------------------------------------------ + +cSchedules::cSchedules() +{ + pCurrentSchedule = NULL; + uCurrentServiceID = 0; +} + +cSchedules::~cSchedules() +{ +} +/** */ +bool cSchedules::SetCurrentServiceID(unsigned short servid) +{ + pCurrentSchedule = GetSchedule(servid); + if (pCurrentSchedule == NULL) + { + Add(new cSchedule(servid)); + pCurrentSchedule = GetSchedule(servid); + if (pCurrentSchedule == NULL) + return false; + } + + uCurrentServiceID = servid; + + return true; +} +/** */ +const cSchedule * cSchedules::GetSchedule() const +{ + return pCurrentSchedule; +} +/** */ +const cSchedule * cSchedules::GetSchedule(unsigned short servid) const +{ + cSchedule *p; + + p = First(); + while (p != NULL) + { + if (p->GetServiceID() == servid) + return p; + p = Next(p); + } + + return NULL; +} + +/** */ +void cSchedules::Cleanup() +{ + cSchedule *p; + + p = First(); + while (p != NULL) + { + p->Cleanup(time(NULL)); + p = Next(p); + } +} + +// --- cEIT ------------------------------------------------------------------ + +#define DEC(N) dec << setw(N) << setfill(int('0')) +#define HEX(N) hex << setw(N) << setfill(int('0')) + +#define EIT_STUFFING_DESCRIPTOR 0x42 +#define EIT_LINKAGE_DESCRIPTOR 0x4a +#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d +#define EIT_EXTENDED_EVENT_DESCRIPTOR 0x4e +#define EIT_TIME_SHIFTED_EVENT_DESCRIPTOR 0x4f +#define EIT_COMPONENT_DESCRIPTOR 0x50 +#define EIT_CA_IDENTIFIER_DESCRIPTOR 0x53 +#define EIT_CONTENT_DESCRIPTOR 0x54 +#define EIT_PARENTAL_RATING_DESCRIPTOR 0x55 +#define EIT_TELEPHONE_DESCRIPTOR 0x57 +#define EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR 0x5e +#define EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR 0x5f +#define EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR 0x61 +#define EIT_DATA_BROADCAST_DESCRIPTOR 0x64 +#define EIT_PDC_DESCRIPTOR 0x69 + +typedef struct eit_struct { u_char table_id : 8; #if BYTE_ORDER == BIG_ENDIAN @@ -64,9 +650,7 @@ typedef struct { u_char segment_last_table_id : 8; } eit_t; -#define EIT_SIZE 14 - -struct eit_loop_struct1 { +typedef struct eit_loop_struct { u_char event_id_hi : 8; u_char event_id_lo : 8; @@ -79,12 +663,12 @@ struct eit_loop_struct1 { u_char time_second : 4; u_char time_second_ten : 4; - u_char dur_hour_ten : 4; u_char dur_hour : 4; - u_char dur_minute_ten : 4; + u_char dur_hour_ten : 4; u_char dur_minute : 4; - u_char dur_second_ten : 4; + u_char dur_minute_ten : 4; u_char dur_second : 4; + u_char dur_second_ten : 4; #if BYTE_ORDER == BIG_ENDIAN u_char running_status : 3; @@ -97,12 +681,9 @@ struct eit_loop_struct1 { #endif u_char descriptors_loop_length_lo : 8; -}; +} eit_loop_t; -#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d -#define EIT_SHORT_EVENT_DESCRIPTOR_SIZE 6 - -struct eit_short_event_descriptor_struct { +typedef struct eit_short_event_struct { u_char descriptor_tag : 8; u_char descriptor_length : 8; @@ -111,415 +692,583 @@ struct eit_short_event_descriptor_struct { u_char language_code_3 : 8; u_char event_name_length : 8; -}; - -#define EIT_EXTENDED_EVENT_DESCRIPOR 0x4e - -#define EIT_DESCRIPTOR_SIZE - -typedef struct eit_event_struct { - u_char event_id_hi : 8; - u_char event_id_lo : 8; - - u_char start_time_1 : 8; - u_char start_time_2 : 8; - u_char start_time_3 : 8; - u_char start_time_4 : 8; - u_char start_time_5 : 8; - - u_char duration_1 : 8; - u_char duration_2 : 8; - u_char duration_3 : 8; - -#if BYTE_ORDER == BIG_ENDIAN - u_char running_status : 3; - u_char free_CA_mode : 1; - u_char descriptors_loop_length_hi : 4; -#else - u_char descriptors_loop_length_hi : 4; - u_char free_CA_mode : 1; - u_char running_status : 3; -#endif - - u_char descriptors_loop_length_lo : 8; - -} eit_event_t; -#define EIT_LOOP_SIZE 12 - - -typedef struct tot_t { - u_char table_id : 8; - -#if BYTE_ORDER == BIG_ENDIAN - u_char section_syntax_indicator : 1; - u_char : 3; - u_char section_length_hi : 4; -#else - u_char section_length_hi : 4; - u_char : 3; - u_char section_syntax_indicator : 1; -#endif - - u_char date_hi : 8; - u_char date_lo : 8; - u_char time_hour : 4; - u_char time_hour_ten : 4; - u_char time_minute : 4; - u_char time_minute_ten : 4; - u_char time_second : 4; - u_char time_second_ten : 4; - -#if BYTE_ORDER == BIG_ENDIAN - u_char : 4; - u_char descriptor_loop_length_hi : 4; -#else - u_char descriptor_loop_length_hi : 4; - u_char : 4; -#endif - - u_char descriptor_loop_length_lo : 8; -} tot_t; - -typedef struct local_time_offset { +} eit_short_event_t; +typedef struct eit_extended_event_struct { u_char descriptor_tag : 8; u_char descriptor_length : 8; + u_char last_descriptor_number : 4; + u_char descriptor_number : 4; + u_char language_code_1 : 8; u_char language_code_2 : 8; u_char language_code_3 : 8; - u_char : 8; - - u_char offset_hour : 4; - u_char offset_hour_ten : 4; - u_char offset_minute : 4; - u_char offset_minute_ten : 4; + u_char length_of_items : 8; +} eit_extended_event_t; + +typedef struct eit_content_descriptor { + u_char descriptor_tag : 8; + u_char descriptor_length : 8; +} eit_content_descriptor_t; - u_char change_date_hi : 8; - u_char change_date_lo : 8; - u_char change_time_hour : 4; - u_char change_time_hour_ten : 4; - u_char change_time_minute : 4; - u_char change_time_minute_ten : 4; - u_char change_time_second : 4; - u_char change_time_second_ten : 4; +typedef struct eit_content_loop { + u_char content_nibble_level_2 : 4; + u_char content_nibble_level_1 : 4; + u_char user_nibble_2 : 4; + u_char user_nibble_1 : 4; +} eit_content_loop_t; - u_char next_offset_hour : 4; - u_char next_offset_hour_ten : 4; - u_char next_offset_minute : 4; - u_char next_offset_minute_ten : 4; -} local_time_offset; +class cEIT { +private: + cSchedules *schedules; +public: + cEIT(void *buf, int length, cSchedules *Schedules); + ~cEIT(); + /** */ + int ProcessEIT(); -cEIT::cEIT() +protected: // Protected methods + /** */ + int strdvbcpy(unsigned char *dst, unsigned char *src, int max); + /** returns true if this EIT covers a +present/following information, false if it's +schedule information */ + bool IsPresentFollowing(); + /** */ + bool WriteShortEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf); + /** */ + bool WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf); +protected: // Protected attributes + int buflen; +protected: // Protected attributes + /** */ + u_char buffer[4097]; + /** Table ID of this EIT struct */ + u_char tid; + /** EITs service id (program number) */ + u_short pid; +}; + +cEIT::cEIT(void * buf, int length, cSchedules *Schedules) { - cszBitFilter = "/dev/vbi"; - if((fsvbi = open(cszBitFilter, O_RDWR))<0) - { - fsvbi = 0; - esyslog(LOG_ERR, "Failed to open DVB bitfilter device: %s", cszBitFilter); - return; - } + buflen = min((unsigned int)length, sizeof(buffer)); + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, buf, buflen); + tid = buffer[0]; + schedules = Schedules; } cEIT::~cEIT() { - if (fsvbi != 0) - close(fsvbi); - fsvbi = 0; } -/** Set the bitfilter in vbi device to return -correct tables */ -int cEIT::SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode) -{ - struct bitfilter filt = { - pid, - { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - mode,0, - FILTER_MEM, - {}, - }; - - if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0) - return 0xffff; - return 0; -} /** */ -int cEIT::GetSection(unsigned char *buf, ushort PID, unsigned char sec) +int cEIT::ProcessEIT() { - int seclen=0; - unsigned short handle, pid; - unsigned char section, sectionnum=0xff, maxsec=0; - - if ((handle = SetBitFilter(PID, (sec<<8)|0x00ff, SECTION_CONTINUOS))==0xffff) - return -1; + int bufact = 0; + eit_t *eit; + eit_loop_t *eitloop; + u_char tmp[256]; + + if (bufact + (int)sizeof(eit_t) > buflen) + return 0; + eit = (eit_t *)buffer; + bufact += sizeof(eit_t); + + unsigned int service = (eit->service_id_hi << 8) | eit->service_id_lo; + + while(bufact + (int)sizeof(eit_loop_t) <= buflen) + { + eitloop = (eit_loop_t *)&buffer[bufact]; + bufact += sizeof(eit_loop_t); + + int descdatalen = (eitloop->descriptors_loop_length_hi << 8) + eitloop->descriptors_loop_length_lo; + int descdataact = 0; + + while (descdataact < descdatalen && bufact < buflen) + { + switch (buffer[bufact]) + { + eit_content_descriptor_t *cont; + eit_content_loop_t *contloop; + + case EIT_STUFFING_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_STUFFING_DESCRIPTOR"); + break; + + case EIT_LINKAGE_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_LINKAGE_DESCRIPTOR"); + break; + + case EIT_SHORT_EVENT_DESCRIPTOR: + WriteShortEventDescriptor(service, eitloop, &buffer[bufact]); + break; - seclen=0; - if (!cFile::AnyFileReady(fsvbi, 20000)) - { - //cerr << "Timeout\n"; - return -1; - } + case EIT_EXTENDED_EVENT_DESCRIPTOR: + WriteExtEventDescriptor(service, eitloop, &buffer[bufact]); + break; + + case EIT_TIME_SHIFTED_EVENT_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_TIME_SHIFTED_EVENT_DESCRIPTOR"); + break; - read(fsvbi, buf, 8); - seclen=(buf[6]<<8)|buf[7]; - pid=(buf[4]<<8)|buf[5]; + case EIT_COMPONENT_DESCRIPTOR : + strdvbcpy(tmp, &buffer[bufact + 8], buffer[bufact + 1] - 6); + //dsyslog(LOG_INFO, "Found EIT_COMPONENT_DESCRIPTOR %c%c%c 0x%02x/0x%02x/0x%02x '%s'\n", buffer[bufact + 5], buffer[bufact + 6], buffer[bufact + 7], buffer[2], buffer[3], buffer[4], tmp); + break; - read(fsvbi, buf, seclen); - section=buf[0]; - sectionnum=buf[6]; - maxsec=buf[7]; + case EIT_CA_IDENTIFIER_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_CA_IDENTIFIER_DESCRIPTOR"); + break; - //cerr << "secnum: " << HEX(2) << (int)sectionnum - // << ", secmax: " << HEX(2) << (int) msecnum << "\n"; + case EIT_CONTENT_DESCRIPTOR : + cont = (eit_content_descriptor_t *)buffer; + contloop = (eit_content_loop_t *)&buffer[sizeof(eit_content_descriptor_t)]; + //dsyslog(LOG_INFO, "Found EIT_CONTENT_DESCRIPTOR 0x%02x/0x%02x\n", contloop->content_nibble_level_1, contloop->content_nibble_level_2); + break; - CloseFilter(handle); + case EIT_PARENTAL_RATING_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_PARENTAL_RATING_DESCRIPTOR"); + break; - return seclen; -} + case EIT_TELEPHONE_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_TELEPHONE_DESCRIPTOR"); + break; + + case EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR"); + break; + + case EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR"); + break; + + case EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR"); + break; + + case EIT_DATA_BROADCAST_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_DATA_BROADCAST_DESCRIPTOR"); + break; + + case EIT_PDC_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_PDC_DESCRIPTOR"); + break; + + default: + //dsyslog(LOG_INFO, "Found unhandled descriptor 0x%02x with length of %04d\n", (int)buffer[bufact], (int)buffer[bufact + 1]); + break; + } + descdataact += (buffer[bufact + 1] + 2); + bufact += (buffer[bufact + 1] + 2); + } + } -/** */ -int cEIT::CloseFilter(unsigned short handle) -{ - if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &handle)<0) - return -1; return 0; } /** */ -char * cEIT::mjd2string(unsigned short mjd) +int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) { - int y, m, d, k; - static char buf[20]; + int a = 0; - y = (int) ((mjd - 15078.2) / 365.25); - m = (int) ((mjd - 14956.1 - (int)(y * 365.25)) / 30.6001); - d = (int) (mjd - 14956 - (int)(y * 365.25) - (int)(m * 30.6001)); - k = (m == 14 || m == 15) ? 1 : 0; - y = y + k; - m = m - 1 - k * 12; - sprintf(buf, "%d.%d.%4d", d, m, y + 1900); + if (*src == 0x05 || (*src >= 0x20 && *src <= 0xff)) + { + for (a = 0; a < max; a++) + { + if (*src == 0) + break; + + if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff)) + *dst++ = *src++; + else + { + // if ((*src > '~' && *src < 0xa0) || *src == 0xff) + // cerr << "found special character 0x" << HEX(2) << (int)*src << endl; + src++; + } + } + *dst = 0; + } + else + { + const char *ret; + + switch (*src) + { + case 0x01: ret = "Coding according to character table 1"; break; + case 0x02: ret = "Coding according to character table 2"; break; + case 0x03: ret = "Coding according to character table 3"; break; + case 0x04: ret = "Coding according to character table 4"; break; + case 0x10: ret = "Coding according to ISO/IEC 8859"; break; + case 0x11: ret = "Coding according to ISO/IEC 10646"; break; + case 0x12: ret = "Coding according to KSC 5601"; break; + default: ret = "Unknown coding"; break; + } + strncpy((char *)dst, ret, max); + } + return a; +} + +/** returns true if this EIT covers a +present/following information, false if it's +schedule information */ +bool cEIT::IsPresentFollowing() +{ + if (tid == 0x4e || tid == 0x4f) + return true; - return(buf); + return false; } /** */ -int cEIT::GetEIT() +bool cEIT::WriteShortEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf) { - unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) - eit_t *eit; - struct eit_loop_struct1 *eitloop; - struct eit_short_event_descriptor_struct *eitevt; - unsigned int seclen; - unsigned short handle, pid; - eit_event * pevt = (eit_event *)0; - time_t tstart; + u_char tmp[256]; + eit_short_event_t *evt = (eit_short_event_t *)buf; + unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); + cEventInfo *pEvent; + + //isyslog(LOG_INFO, "Found Short Event Descriptor"); - if ((handle = SetBitFilter(0x12, (0x4e << 8) | 0x00ff, SECTION_CONTINUOS))==0xffff) + cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) { - return -1; + schedules->Add(new cSchedule(service)); + pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + return false; } -/* - pid_t process = fork(); - if (process < 0) + + /* cSchedule::GetPresentEvent() and cSchedule::GetFollowingEvent() verify + the temporal sanity of these events, so calling them here appears to + be a bad idea... (kls 2000-11-01) + // + // if we are working on a present/following info, let's see whether + // we already have present/following info for this service and if yes + // check whether it's the same eventid, if yes, just return, nothing + // left to do. + // + if (IsPresentFollowing()) { - cerr << "GetEIT -1" << endl; - return -1; + if (eitloop->running_status == 4 || eitloop->running_status == 3) + pEvent = (cEventInfo *)pSchedule->GetPresentEvent(); + else + pEvent = (cEventInfo *)pSchedule->GetFollowingEvent(); + + if (pEvent != NULL) + if (pEvent->GetEventID() == eventid) + return true; } - - if (process != 0) + */ + + // + // let's see whether we have that eventid already + // in case not, we have to create a new cEventInfo for it + // + pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); + if (pEvent == NULL) { - cerr << "GetEIT 0" << endl; - return 0; + pSchedule->Events.Add(new cEventInfo(service, eventid)); + pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); + if (pEvent == NULL) + return false; + + strdvbcpy(tmp, &buf[sizeof(eit_short_event_t)], evt->event_name_length); + pEvent->SetTitle((char *)tmp); + strdvbcpy(tmp, &buf[sizeof(eit_short_event_t) + evt->event_name_length + 1], + (int)buf[sizeof(eit_short_event_t) + evt->event_name_length]); + pEvent->SetSubtitle((char *)tmp); + cMJD mjd(eitloop->date_hi, eitloop->date_lo, + eitloop->time_hour_ten * 10 + eitloop->time_hour, + eitloop->time_minute_ten * 10 + eitloop->time_minute, + eitloop->time_second_ten * 10 + eitloop->time_second); + pEvent->SetTime(mjd.GetTime_t()); + pEvent->SetDuration((long)((long)((eitloop->dur_hour_ten * 10 + eitloop->dur_hour) * 60l * 60l) + + (long)((eitloop->dur_minute_ten * 10 + eitloop->dur_minute) * 60l) + + (long)(eitloop->dur_second_ten * 10 + eitloop->dur_second))); } -*/ - int nReceivedEITs = 0; - tstart = time(NULL); - while ((!evtRunning.bIsValid || !evtNext.bIsValid) && nReceivedEITs < 20 && difftime(time(NULL), tstart) < 4) + + if (IsPresentFollowing()) { - if (!cFile::AnyFileReady(fsvbi, 5000)) - { - //cerr << "Timeout\n"; - CloseFilter(handle); - return -1; - } + if (eitloop->running_status == 4 || eitloop->running_status == 3) + pSchedule->SetPresentEvent(pEvent); + else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0) + pSchedule->SetFollowingEvent(pEvent); + } + + return true; +} + +/** */ +bool cEIT::WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf) +{ + u_char tmp[256]; + eit_extended_event_t *evt = (eit_extended_event_t *)buf; + int bufact, buflen; + unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); + cEventInfo *pEvent; - read(fsvbi, buf, 8); - seclen=(buf[6]<<8)|buf[7]; - pid=(buf[4]<<8)|buf[5]; + //isyslog(LOG_INFO, "Found Extended Event Descriptor"); - if (seclen >= sizeof(buf)) - seclen = sizeof(buf) - 1; - read(fsvbi, buf, seclen); + cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + { + schedules->Add(new cSchedule(service)); + pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + return false; + } + + pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); + if (pEvent == NULL) + return false; - if (seclen < (int)(sizeof(eit_t) - + sizeof(struct eit_loop_struct1) - + sizeof(struct eit_short_event_descriptor_struct))) - continue; + if (evt->descriptor_number != pEvent->GetExtendedDescriptorNumber()) + return false; - eit = (eit_t *)buf; - eitloop = (struct eit_loop_struct1 *)&eit[1]; - eitevt = (struct eit_short_event_descriptor_struct *)&eitloop[1]; + bufact = sizeof(eit_extended_event_t); + buflen = buf[1] + 2; - if (eitevt->descriptor_tag != EIT_SHORT_EVENT_DESCRIPTOR) + if (evt->length_of_items > 0) + { + while (bufact - sizeof(eit_extended_event_t) < evt->length_of_items) { - // printf("Tag = '%c'\n", eitevt->descriptor_tag); - continue; + strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); + // could use value in tmp now to do something, + // haven't seen any items as of yet transmitted from satellite + bufact += (buf[bufact] + 1); } + } - if (((eit->service_id_hi << 8) | eit->service_id_lo) != uProgramNumber) - { - // printf("Wrong program %04x need %04x\n", (eit->service_id_hi << 8) | eit->service_id_lo, uProgramNumber); - continue; - } - - nReceivedEITs++; + strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); + if (pEvent->AddExtendedDescription((char *)tmp)) + { + pEvent->IncreaseExtendedDescriptorNumber(); + return true; + } - pevt = (eit_event *)0; - if (eitloop->running_status == 4 | eitloop->running_status == 3) - pevt = (eit_event *)&evtRunning; - else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0) - pevt = (eit_event *)&evtNext; + return false; +} + +// --- cSIProcessor ---------------------------------------------------------- + +#define MAX_FILTERS 20 + +/** */ +cSIProcessor::cSIProcessor(const char *FileName) +{ + useTStime = false; + filters = NULL; + schedules = NULL; + if ((fsvbi = open(FileName, O_RDONLY)) >= 0) + { + schedules = new cSchedules; + filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER)); + } + else + LOG_ERROR_STR(FileName); +} + +cSIProcessor::~cSIProcessor() +{ + if (fsvbi >= 0) + { + Stop(); + ShutDownFilters(); + delete filters; + delete schedules; + close(fsvbi); + } +} + +/** use the vbi device to parse all relevant SI +information and let the classes corresponding +to the tables write their information to the disk */ +void cSIProcessor::Action() +{ + if (fsvbi < 0) { + esyslog(LOG_ERR, "cSIProcessor::Action() called without open file - returning"); + return; + } + + dsyslog(LOG_INFO, "EIT processing thread started (pid=%d)", getpid()); + + unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) + unsigned int seclen; + unsigned int pid; + time_t lastCleanup = time(NULL); + struct pollfd pfd; + + while(true) + { + time_t now = time(NULL); + struct tm *ptm = localtime(&now); + if (now - lastCleanup > 3600 && ptm->tm_hour == 5) + { + LOCK_THREAD; - if (pevt) + isyslog(LOG_INFO, "Now cleaning up things"); + schedules->Cleanup(); + lastCleanup = now; + } + + /* wait data become ready from the bitfilter */ + pfd.fd = fsvbi; + pfd.events = POLLIN; + if(poll(&pfd, 1, 1000) != 0) /* timeout is 5 secs */ { - unsigned char *p = (unsigned char *)&eitevt[1]; - strdvbcpy((unsigned char *)pevt->szTitle, p, eitevt->event_name_length); - pevt->szSubTitle[0] = 0; - strdvbcpy((unsigned char *)pevt->szSubTitle, &p[eitevt->event_name_length+1], (int)p[eitevt->event_name_length]); - strcpy(pevt->szDate, mjd2string((eitloop->date_hi << 8) + eitloop->date_lo)); - int hr = eitloop->time_hour + (eitloop->time_hour_ten * 10); - hr += 2; - if (hr >=24) + // fprintf(stderr, "\n"); + /* read section */ + read(fsvbi, buf, 8); + seclen = (buf[6] << 8) | buf[7]; + pid = (buf[4] << 8) | buf[5]; + read(fsvbi, buf, seclen); + + //dsyslog(LOG_INFO, "Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen); + + switch (pid) { - hr -= 24; - // need to switch date one day ahead here + case 0x14: + if (buf[0] == 0x70) + { + if (useTStime) + { + cTDT ctdt((tdt_t *)buf); + ctdt.SetSystemTime(); + } + } + /*XXX this comes pretty often: + else + dsyslog(LOG_INFO, "Time packet was not 0x70 but 0x%02x\n", (int)buf[0]); + XXX*/ + break; + + case 0x12: + if (buf[0] != 0x72) + { + LOCK_THREAD; + + cEIT ceit(buf, seclen, schedules); + ceit.ProcessEIT(); + } + else + dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); + break; + + default: + break; } - sprintf(pevt->szTime, "%d:%c%c", hr, - eitloop->time_minute_ten + '0', - eitloop->time_minute + '0'); - pevt->bIsValid = true; } - } - - CloseFilter(handle); + else + { + LOCK_THREAD; - return 1; + //XXX this comes pretty often + //isyslog(LOG_INFO, "Received timeout from poll, refreshing filters\n"); + RefreshFilters(); + } +// WakeUp(); + } } -/** */ -int cEIT::SetProgramNumber(unsigned short pnr) +/** Add a filter with packet identifier pid and +table identifer tid */ +bool cSIProcessor::AddFilter(u_char pid, u_char tid) { - if (pnr == 0) - { - evtRunning.bIsValid = false; - evtNext.bIsValid = false; - return -1; - } + if (fsvbi < 0) + return false; + + int section = ((int)tid << 8) | 0x00ff; + + struct bitfilter filt = { + pid, + { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + SECTION_CONTINUOS, 0, + FILTER_MEM, + {}, + }; - if (pnr != uProgramNumber) + if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0) + return false; + + for (int a = 0; a < MAX_FILTERS; a++) { - evtRunning.bIsValid = false; - evtNext.bIsValid = false; - uProgramNumber = pnr; + if (filters[a].inuse == false) + { + filters[a].pid = pid; + filters[a].tid = tid; + filters[a].handle = filt.handle; + filters[a].inuse = true; + // dsyslog(LOG_INFO, " Registered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); + return true; + } } - return 1; + + return false; } -/** retrieves the string for the running title */ -char * cEIT::GetRunningTitle() -{ - if (evtRunning.bIsValid) - return evtRunning.szTitle; - else - return "---"; -} -/** Retrieves the string for the running subtitle */ -char * cEIT::GetRunningSubtitle() -{ - if (evtRunning.bIsValid) - return evtRunning.szSubTitle; - else - return "---"; -} -/** Retrieves the string representing the -date of the current event - */ -char * cEIT::GetRunningDate() +/** set whether local systems time should be +set by the received TDT or TOT packets */ +bool cSIProcessor::SetUseTSTime(bool use) { - if (evtRunning.bIsValid) - return evtRunning.szDate; - else - return "---"; -} -/** Retrieves the string representing the -time of the current event */ -char * cEIT::GetRunningTime() -{ - if (evtRunning.bIsValid) - return evtRunning.szTime; - else - return "---"; -} -/** retrieves the string for the running title */ -char * cEIT::GetNextTitle() -{ - if (evtNext.bIsValid) - return evtNext.szTitle; - else - return "---"; + useTStime = use; + return useTStime; } -/** Retrieves the string for the running subtitle */ -char * cEIT::GetNextSubtitle() -{ - if (evtNext.bIsValid) - return evtNext.szSubTitle; - else - return "---"; -} -/** Retrieves the string representing the -date of the current event - */ -char * cEIT::GetNextDate() -{ - if (evtNext.bIsValid) - return evtNext.szDate; - else - return "---"; -} -/** Retrieves the string representing the -time of the current event */ -char * cEIT::GetNextTime() + +/** */ +bool cSIProcessor::ShutDownFilters() { - if (evtNext.bIsValid) - return evtNext.szTime; - else - return "---"; + if (fsvbi < 0) + return false; + + bool ret = true; + + for (int a = 0; a < MAX_FILTERS; a++) + { + if (filters[a].inuse == true) + { + if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &filters[a].handle) < 0) + ret = false; + + // dsyslog(LOG_INFO, "Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); + + filters[a].inuse = false; + } + } + + return ret; } -/** */ -bool cEIT::IsValid() +/** */ +bool cSIProcessor::SetCurrentServiceID(unsigned short servid) { - GetEIT(); - return (evtRunning.bIsValid && evtNext.bIsValid); + LOCK_THREAD; + return schedules ? schedules->SetCurrentServiceID(servid) : false; } /** */ -int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) +bool cSIProcessor::RefreshFilters() { - int a; - for (a = 0; a < max; a++) + if (fsvbi < 0) + return false; + + bool ret = true; + + ret = ShutDownFilters(); + + for (int a = 0; a < MAX_FILTERS; a++) { - if (*src == 0) - break; - - if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff)) - *dst++ = *src++; - else - src++; + if (filters[a].inuse == false && filters[a].pid != 0 && filters[a].tid != 0) + { + if (!AddFilter(filters[a].pid, filters[a].tid)) + ret = false; + } } - *dst = 0; - return a; + + return ret; } + diff --git a/eit.h b/eit.h index 28329f427..fec498baf 100644 --- a/eit.h +++ b/eit.h @@ -13,80 +13,127 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.1 2000/09/03 10:23:24 kls Exp $ + * $Id: eit.h 1.2 2000/10/29 10:21:56 kls Exp $ ***************************************************************************/ #ifndef __EIT_H #define __EIT_H -#include +#include "thread.h" +#include "tools.h" -typedef struct eit_event { +class cEventInfo : public cListObject { + friend class cSchedule; + friend class cEIT; +private: + unsigned short uServiceID; // Service ID of program for that event + bool bIsFollowing; // true if this is the next event on this channel + bool bIsPresent; // true if this is the present event running + char *pExtendedDescription; // Extended description of this event + char *pSubtitle; // Subtitle of event + char *pTitle; // Title of event + unsigned short uEventID; // Event ID of this event + long lDuration; // duration of event in seconds + time_t tTime; // Start time + u_char cExtendedDescriptorNumber; // current extended descriptor number that has to be inserted + int nChannelNumber; // the actual channel number from VDR's channel list (used in cMenuSchedule for sorting by channel number) +protected: + void SetFollowing(bool foll); + void SetPresent(bool pres); + bool SetTitle(char *string); + void SetServiceID(unsigned short servid); + void SetEventID(unsigned short evid); + void SetDuration(long l); + void SetTime(time_t t); + bool AddExtendedDescription(char *string); + bool SetSubtitle(char *string); + void IncreaseExtendedDescriptorNumber(void); + cEventInfo(unsigned short serviceid, unsigned short eventid); +public: + ~cEventInfo(); + const char *GetTimeString(void) const; + const char *GetEndTimeString(void) const; + const char *GetDate(void) const; + bool IsFollowing(void) const; + bool IsPresent(void) const; + const char *GetExtendedDescription(void) const; + const char *GetSubtitle(void) const; + const char *GetTitle(void) const; + unsigned short GetEventID(void) const; + long GetDuration(void) const; + time_t GetTime(void) const; + u_char GetExtendedDescriptorNumber(void) const; + unsigned short GetServiceID(void) const; + int GetChannelNumber(void) const { return nChannelNumber; } + void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' + }; + +class cSchedule : public cListObject { + friend class cSchedules; + friend class cEIT; +private: + cEventInfo *pPresent; + cEventInfo *pFollowing; + unsigned short uServiceID; + cList Events; +protected: + void SetServiceID(unsigned short servid); + bool SetFollowingEvent(cEventInfo *pEvent); + bool SetPresentEvent(cEventInfo *pEvent); + void Cleanup(time_t tTime); + void Cleanup(void); + cSchedule(unsigned short servid = 0); +public: + ~cSchedule(); + const cEventInfo *GetPresentEvent(void) const; + const cEventInfo *GetFollowingEvent(void) const; + unsigned short GetServiceID(void) const; + const cEventInfo *GetEvent(unsigned short uEventID) const; + const cEventInfo *GetEvent(time_t tTime) const; + const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); } + int NumEvents(void) const { return Events.Count(); } + }; - bool bIsValid; - char szTitle[512]; - char szSubTitle[512]; - char szDate[12]; - char szTime[12]; +class cSchedules : public cList { + friend class cSIProcessor; +private: + const cSchedule *pCurrentSchedule; + unsigned short uCurrentServiceID; +protected: + bool SetCurrentServiceID(unsigned short servid); + void Cleanup(); +public: + cSchedules(void); + ~cSchedules(); + const cSchedule *GetSchedule(unsigned short servid) const; + const cSchedule *GetSchedule(void) const; +}; -}eit_event; +typedef struct sip_filter { -/** - *@author Robert Schneider - */ + u_char pid; + u_char tid; + int handle; + bool inuse; -class cEIT { -public: - cEIT(); - ~cEIT(); - /** */ - int GetEIT(); - /** */ - int SetProgramNumber(unsigned short pnr); - /** Retrieves the string representing the time of the current event */ - char * GetRunningTime(); - /** Retrieves the string representing the date of the current event */ - char * GetRunningDate(); - /** Retrieves the string for the running subtitle */ - char * GetRunningSubtitle(); - /** retrieves the string for the running title */ - char * GetRunningTitle(); - /** Retrieves the string representing the time of the next event */ - char * GetNextTime(); - /** Retrieves the string representing the date of the next event */ - char * GetNextDate(); - /** Retrieves the string for the next subtitle */ - char * GetNextSubtitle(); - /** retrieves the string for the next title */ - char * GetNextTitle(); - /** */ - bool IsValid(); +}SIP_FILTER; -protected: // Protected attributes - /** Device name of VBI device */ - const char * cszBitFilter; -protected: // Protected attributes - /** handle to VBI device (usually /dev/vbi) */ +class cSIProcessor : public cThread { +private: + cSchedules *schedules; + bool useTStime; + SIP_FILTER *filters; int fsvbi; - /** Describes the event next on */ - eit_event evtNext; - /** Describes the running event */ - eit_event evtRunning; -protected: // Protected methods - /** Set the bitfilter in vbi device to return -correct tables */ - int SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode); - /** */ - int GetSection(unsigned char *buf, ushort PID, unsigned char sec); - /** */ - int CloseFilter(unsigned short handle); - /** */ - char * mjd2string(unsigned short mjd); - /** */ - int strdvbcpy(unsigned char *dst, unsigned char *src, int max); -public: // Public attributes - /** */ - unsigned short uProgramNumber; -}; + bool RefreshFilters(void); + void Action(void); +public: + cSIProcessor(const char *FileName); + ~cSIProcessor(); + bool SetUseTSTime(bool use); + bool AddFilter(u_char pid, u_char tid); + bool ShutDownFilters(void); + bool SetCurrentServiceID(unsigned short servid); + const cSchedules *Schedules(void) { return schedules; } + }; #endif diff --git a/interface.c b/interface.c index 5940195f9..810270fed 100644 --- a/interface.c +++ b/interface.c @@ -4,14 +4,12 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.25 2000/10/08 16:34:17 kls Exp $ + * $Id: interface.c 1.28 2000/11/01 15:27:52 kls Exp $ */ #include "interface.h" +#include #include -#include "eit.h" - -cEIT EIT; cInterface *Interface = NULL; @@ -19,6 +17,7 @@ cInterface::cInterface(int SVDRPport) { open = 0; cols[0] = 0; + width = height = 0; keyFromWait = kNone; rcIo = NULL; SVDRP = NULL; @@ -43,15 +42,17 @@ cInterface::~cInterface() void cInterface::Open(int NumCols, int NumLines) { if (!open++) - cDvbApi::PrimaryDvbApi->Open(NumCols, NumLines); + cDvbApi::PrimaryDvbApi->Open(width = NumCols, height = NumLines); } void cInterface::Close(void) { if (open == 1) Clear(); - if (!--open) + if (!--open) { cDvbApi::PrimaryDvbApi->Close(); + width = height = 0; + } } unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release) @@ -114,6 +115,18 @@ void cInterface::ClearEol(int x, int y, eDvbColor Color) cDvbApi::PrimaryDvbApi->ClrEol(x, y, Color); } +void cInterface::Fill(int x, int y, int w, int h, eDvbColor Color) +{ + if (open) + cDvbApi::PrimaryDvbApi->Fill(x, y, w, h, Color); +} + +void cInterface::Flush(void) +{ + if (open) + cDvbApi::PrimaryDvbApi->Flush(); +} + void cInterface::SetCols(int *c) { for (int i = 0; i < MaxCols; i++) { @@ -123,6 +136,74 @@ void cInterface::SetCols(int *c) } } +char *cInterface::WrapText(const char *Text, int Width, int *Height) +{ + // Wraps the Text to make it fit into the area defined by the given Width + // (which is given in character cells). + // The actual number of lines resulting from this operation is returned in + // Height. + // The returned string is newly created on the heap and the caller + // is responsible for deleting it once it is no longer used. + // Wrapping is done by inserting the necessary number of newline + // characters into the string. + + int Lines = 1; + char *t = strdup(Text); + char *Blank = NULL; + char *Delim = NULL; + int w = 0; + + Width *= cDvbApi::PrimaryDvbApi->CellWidth(); + + while (*t && t[strlen(t) - 1] == '\n') + t[strlen(t) - 1] = 0; // skips trailing newlines + + for (char *p = t; *p; ) { + if (*p == '\n') { + Lines++; + w = 0; + Blank = Delim = NULL; + p++; + continue; + } + else if (isspace(*p)) + Blank = p; + int cw = cDvbApi::PrimaryDvbApi->Width(*p); + if (w + cw > Width) { + if (Blank) { + *Blank = '\n'; + p = Blank; + continue; + } + else { + // Here's the ugly part, where we don't have any whitespace to + // punch in a newline, so we need to make room for it: + if (Delim) + p = Delim + 1; // let's fall back to the most recent delimiter + char *s = new char[strlen(t) + 2]; // The additional '\n' plus the terminating '\0' + int l = p - t; + strncpy(s, t, l); + s[l] = '\n'; + strcpy(s + l + 1, p); + delete t; + t = s; + p = t + l; + continue; + } + } + else + w += cw; + if (strchr("-.,:;!?_", *p)) { + Delim = p; + Blank = NULL; + } + p++; + } + + *Height = Lines; + return t; +} + void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor) { if (open) @@ -157,7 +238,7 @@ void cInterface::WriteText(int x, int y, const char *s, eDvbColor FgColor, eDvbC void cInterface::Title(const char *s) { - int x = (MenuColumns - strlen(s)) / 2; + int x = (Width() - strlen(s)) / 2; if (x < 0) x = 0; ClearEol(0, 0, clrCyan); @@ -206,7 +287,7 @@ bool cInterface::Confirm(const char *s) void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor) { if (open && Text) { - const int w = MenuColumns / 4; + const int w = Width() / 4; int l = (w - strlen(Text)) / 2; if (l < 0) l = 0; @@ -334,65 +415,9 @@ void cInterface::LearnKeys(void) } } -eKeys cInterface::DisplayChannel(int Number, const char *Name, bool WithInfo) +void cInterface::DisplayChannelNumber(int Number) { - // Number = 0 is used for channel group display and no EIT - if (Number) - rcIo->Number(Number); - if (Name && !Recording()) { - Open(MenuColumns, 5); - cDvbApi::PrimaryDvbApi->Fill(0, 0, MenuColumns, 1, clrBackground); - int BufSize = MenuColumns + 1; - char buffer[BufSize]; - if (Number) - snprintf(buffer, BufSize, "%d %s", Number, Name ? Name : ""); - else - snprintf(buffer, BufSize, "%s", Name ? Name : ""); - Write(0, 0, buffer); - time_t t = time(NULL); - struct tm *now = localtime(&t); - snprintf(buffer, BufSize, "%02d:%02d", now->tm_hour, now->tm_min); - Write(-5, 0, buffer); - cDvbApi::PrimaryDvbApi->Flush(); - - char *RunningTitle = "", *RunningSubtitle = "", *NextTitle = "", *NextSubtitle = ""; - int Lines = 0; - if (Number && WithInfo && EIT.IsValid()) { - if (*(RunningTitle = EIT.GetRunningTitle())) Lines++; - if (*(RunningSubtitle = EIT.GetRunningSubtitle())) Lines++; - if (*(NextTitle = EIT.GetNextTitle())) Lines++; - if (*(NextSubtitle = EIT.GetNextSubtitle())) Lines++; - } - if (Lines > 0) { - const int t = 6; - int l = 1; - cDvbApi::PrimaryDvbApi->Fill(0, 1, MenuColumns, Lines, clrBackground); - if (*RunningTitle) { - Write(0, l, EIT.GetRunningTime(), clrYellow, clrBackground); - Write(t, l, RunningTitle, clrCyan, clrBackground); - l++; - } - if (*RunningSubtitle) { - Write(t, l, RunningSubtitle, clrCyan, clrBackground); - l++; - } - if (*NextTitle) { - Write(0, l, EIT.GetNextTime(), clrYellow, clrBackground); - Write(t, l, NextTitle, clrCyan, clrBackground); - l++; - } - if (*NextSubtitle) { - Write(t, l, NextSubtitle, clrCyan, clrBackground); - } - cDvbApi::PrimaryDvbApi->Flush(); - } - eKeys Key = Wait(5, true); - if (Key == kOk) - GetKey(); - Close(); - return Key; - } - return kNone; + rcIo->Number(Number); } void cInterface::DisplayRecording(int Index, bool On) diff --git a/interface.h b/interface.h index 8d0f8f685..5dd8ee3ad 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.16 2000/10/08 12:15:49 kls Exp $ + * $Id: interface.h 1.19 2000/11/01 15:27:23 kls Exp $ */ #ifndef __INTERFACE_H @@ -19,6 +19,7 @@ class cInterface { public: enum { MaxCols = 5 }; private: + int width, height; int open; int cols[MaxCols]; eKeys keyFromWait; @@ -33,11 +34,16 @@ class cInterface { ~cInterface(); void Open(int NumCols = MenuColumns, int NumLines = MenuLines); void Close(void); + int Width(void) { return width; } + int Height(void) { return height; } eKeys GetKey(bool Wait = true); void PutKey(eKeys Key); void Clear(void); void ClearEol(int x, int y, eDvbColor Color = clrBackground); + void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground); + void Flush(void); void SetCols(int *c); + char *WrapText(const char *Text, int Width, int *Height); void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); void Title(const char *s); @@ -47,7 +53,7 @@ class cInterface { bool Confirm(const char *s); void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); void LearnKeys(void); - eKeys DisplayChannel(int Number, const char *Name = NULL, bool WithInfo = false); + void DisplayChannelNumber(int Number); void DisplayRecording(int Index, bool On); bool Recording(void); }; diff --git a/menu.c b/menu.c index 39689c9c7..c3611ccd3 100644 --- a/menu.c +++ b/menu.c @@ -4,15 +4,16 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.36 2000/10/08 16:11:22 kls Exp $ + * $Id: menu.c 1.40 2000/11/01 16:14:48 kls Exp $ */ #include "menu.h" -#include #include #include +#include #include #include "config.h" +#include "eit.h" #define MENUTIMEOUT 120 // seconds @@ -725,7 +726,107 @@ eOSState cMenuChannels::ProcessKey(eKeys Key) return state; } -// --- cMenuSummary -------------------------------------------------------- +// --- cMenuTextItem --------------------------------------------------------- + +class cMenuTextItem : public cOsdItem { +private: + char *text; + int x, y, w, h, lines, offset; + eDvbColor fgColor, bgColor; +public: + cMenuTextItem(const char *Text, int X, int Y, int W, int H = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); + ~cMenuTextItem(); + int Height(void) { return h; } + void Clear(void); + virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); + bool CanScrollUp(void) { return offset > 0; } + bool CanScrollDown(void) { return h + offset < lines; } + void ScrollUp(void); + void ScrollDown(void); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbColor FgColor, eDvbColor BgColor) +{ + x = X; + y = Y; + w = W; + h = H; + fgColor = FgColor; + bgColor = BgColor; + offset = 0; + text = Interface->WrapText(Text, w - 1, &lines); + if (h < 0) + h = lines; +} + +cMenuTextItem::~cMenuTextItem() +{ + delete text; +} + +void cMenuTextItem::Clear(void) +{ + Interface->Fill(x, y, w, h, bgColor); +} + +void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) +{ + int l = 0; + char *t = text; + while (*t) { + char *n = strchr(t, '\n'); + if (l >= offset) { + if (n) + *n = 0; + Interface->Write(x, y + l - offset, t, fgColor, bgColor); + if (n) + *n = '\n'; + else + break; + } + if (!n) + break; + t = n + 1; + if (++l >= h + offset) + break; + } + // scroll indicators use inverted color scheme! + if (CanScrollUp()) Interface->Write(x + w - 1, y, "^", bgColor, fgColor); + if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor); +} + +void cMenuTextItem::ScrollUp(void) +{ + if (CanScrollUp()) { + Clear(); + offset--; + Display(); + } +} + +void cMenuTextItem::ScrollDown(void) +{ + if (CanScrollDown()) { + Clear(); + offset++; + Display(); + } +} + +eOSState cMenuTextItem::ProcessKey(eKeys Key) +{ + switch (Key) { + case kUp|k_Repeat: + case kUp: ScrollUp(); break; + case kDown|k_Repeat: + case kDown: ScrollDown(); break; + default: return osUnknown; + } + return osContinue; +} + +// --- cMenuSummary ---------------------------------------------------------- class cMenuSummary : public cOsdMenu { public: @@ -736,29 +837,7 @@ class cMenuSummary : public cOsdMenu { cMenuSummary::cMenuSummary(const char *Text) :cOsdMenu("Summary") { - while (*Text) { - char line[MenuColumns + 1]; - char *p = line; - const char *b = NULL; - *p++ = ' '; - while (*Text && p - line < MenuColumns - 2) { - if (isspace(*Text)) - b = Text; // remember the blank - if (*Text == '\n') - break; - *p++ = *Text++; - } - if (*Text) { - if (b && Text - b > 0) { - p -= Text - b; - Text = b + 1; - } - else - Text++; - } - *p = 0; - Add(new cOsdItem(line, osBack)); - } + Add(new cMenuTextItem(Text, 1, 2, MenuColumns - 2, MAXOSDITEMS)); } eOSState cMenuSummary::ProcessKey(eKeys Key) @@ -973,6 +1052,278 @@ eOSState cMenuTimers::ProcessKey(eKeys Key) return state; } +// --- cMenuEvent ------------------------------------------------------------ + +class cMenuEvent : public cOsdMenu { +private: + const cEventInfo *eventInfo; +public: + cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch = false); + cMenuEvent(bool Now); + virtual eOSState ProcessKey(eKeys Key); +}; + +cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch) +:cOsdMenu("Event") +{ + eventInfo = EventInfo; + if (eventInfo) { + cChannel *channel = Channels.GetByServiceID(eventInfo->GetServiceID()); + if (channel) { + const char *p; + char *buffer; + asprintf(&buffer, "%-17.*s %.*s %s - %s", 17, channel->name, 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString()); + SetTitle(buffer, false); + int Line = 2; + cMenuTextItem *item; + if (!isempty(p = eventInfo->GetTitle())) { + Add(item = new cMenuTextItem(p, 1, Line, MenuColumns - 2, -1, clrCyan)); + Line += item->Height() + 1; + } + if (!isempty(p = eventInfo->GetSubtitle())) { + Add(item = new cMenuTextItem(p, 1, Line, MenuColumns - 2, -1, clrYellow)); + Line += item->Height() + 1; + } + if (!isempty(p = eventInfo->GetExtendedDescription())) + Add(new cMenuTextItem(p, 1, Line, MenuColumns - 2, Height() - Line - 2, clrCyan), true); + SetHelp("Record", NULL, NULL, CanSwitch ? "Switch" : NULL); + } + } +} + +eOSState cMenuEvent::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case kOk: return osBack; + default: break; + } + } + return state; +} + +// --- cMenuWhatsOnItem ------------------------------------------------------ + +class cMenuWhatsOnItem : public cOsdItem { +public: + const cEventInfo *eventInfo; + cMenuWhatsOnItem(const cEventInfo *EventInfo); +}; + +cMenuWhatsOnItem::cMenuWhatsOnItem(const cEventInfo *EventInfo) +{ + eventInfo = EventInfo; + char *buffer = NULL; + cChannel *channel = Channels.GetByNumber(eventInfo->GetChannelNumber()); + asprintf(&buffer, "%d\t%.*s\t%.*s\t%s", eventInfo->GetChannelNumber(), 6, channel ? channel->name : "???", 5, eventInfo->GetTimeString(), eventInfo->GetTitle()); + SetText(buffer, false); +} + +// --- cMenuWhatsOn ---------------------------------------------------------- + +class cMenuWhatsOn : public cOsdMenu { +private: + eOSState Record(void); + eOSState Switch(void); +public: + cMenuWhatsOn(const cSchedules *Schedules, bool Now); + virtual eOSState ProcessKey(eKeys Key); + }; + +static int CompareEventChannel(const void *p1, const void *p2) +{ + return (int)( (*(const cEventInfo **)p1)->GetChannelNumber() - (*(const cEventInfo **)p2)->GetChannelNumber()); +} + +cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now) +:cOsdMenu(Now ? "What's on now?" : "What's on next?", 4, 7, 6) +{ + const cSchedule *Schedule = Schedules->First(); + const cEventInfo **pArray = NULL; + int num = 0; + + while (Schedule) { + pArray = (const cEventInfo **)realloc(pArray, (num + 1) * sizeof(cEventInfo *)); + + pArray[num] = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent(); + if (pArray[num]) { + cChannel *channel = Channels.GetByServiceID(pArray[num]->GetServiceID()); + if (channel) { + pArray[num]->SetChannelNumber(channel->number); + num++; + } + } + Schedule = (const cSchedule *)Schedules->Next(Schedule); + } + + qsort(pArray, num, sizeof(cEventInfo *), CompareEventChannel); + + for (int a = 0; a < num; a++) + Add(new cMenuWhatsOnItem(pArray[a])); + + delete pArray; + SetHelp("Record", Now ? "Next" : "Now", "Schedule", "Switch"); +} + +eOSState cMenuWhatsOn::Switch(void) +{ + cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current()); + if (item) { + cChannel *channel = Channels.GetByServiceID(item->eventInfo->GetServiceID()); + if (channel && channel->Switch()) + return osEnd; + } + Interface->Error("Can't switch channel!"); + return osContinue; +} + +eOSState cMenuWhatsOn::Record(void) +{ + cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current()); + if (item) { + cTimer *timer = new cTimer(item->eventInfo); + Timers.Add(timer); + Timers.Save(); + isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + return AddSubMenu(new cMenuEditTimer(timer->Index(), true)); + } + return osContinue; +} + +eOSState cMenuWhatsOn::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case kRed: return Record(); + case kYellow: return osBack; + case kBlue: return Switch(); + case kOk: if (Count()) + return AddSubMenu(new cMenuEvent(((cMenuWhatsOnItem *)Get(Current()))->eventInfo, true)); + break; + default: break; + } + } + return state; +} + +// --- cMenuScheduleItem ----------------------------------------------------- + +class cMenuScheduleItem : public cOsdItem { +public: + const cEventInfo *eventInfo; + cMenuScheduleItem(const cEventInfo *EventInfo); +}; + +cMenuScheduleItem::cMenuScheduleItem(const cEventInfo *EventInfo) +{ + eventInfo = EventInfo; + char *buffer = NULL; + asprintf(&buffer, "%.*s\t%.*s\t%s", 5, eventInfo->GetDate(), 5, eventInfo->GetTimeString(), eventInfo->GetTitle()); + SetText(buffer, false); +} + +// --- cMenuSchedule --------------------------------------------------------- + +class cMenuSchedule : public cOsdMenu { +private: + cThreadLock threadLock; + const cSchedules *schedules; + bool now, next; + eOSState Record(void); + void PrepareSchedule(void); + void PrepareWhatsOnNext(bool On); +public: + cMenuSchedule(void); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuSchedule::cMenuSchedule(void) +:cOsdMenu("Schedule", 6, 6) +{ + now = next = false; + cChannel *channel = Channels.GetByNumber(CurrentChannel); + if (channel) { + char *buffer = NULL; + asprintf(&buffer, "Schedule - %s", channel->name); + SetTitle(buffer, false); + } + PrepareSchedule(); + SetHelp("Record", "Now", "Next"); +} + +static int CompareEventTime(const void *p1, const void *p2) +{ + return (int)((*(cEventInfo **)p1)->GetTime() - (*(cEventInfo **)p2)->GetTime()); +} + +void cMenuSchedule::PrepareSchedule(void) +{ + schedules = cDvbApi::PrimaryDvbApi->Schedules(&threadLock); + if (schedules) { + const cSchedule *Schedule = schedules->GetSchedule(); + int num = Schedule->NumEvents(); + const cEventInfo **pArray = (const cEventInfo **)malloc(num * sizeof(cEventInfo *)); + if (pArray) { + time_t now = time(NULL); + int numreal = 0; + for (int a = 0; a < num; a++) { + const cEventInfo *EventInfo = Schedule->GetEventNumber(a); + if (EventInfo->GetTime() + EventInfo->GetDuration() > now) + pArray[numreal++] = EventInfo; + } + + qsort(pArray, numreal, sizeof(cEventInfo *), CompareEventTime); + + for (int a = 0; a < numreal; a++) + Add(new cMenuScheduleItem(pArray[a])); + delete pArray; + } + } +} + +eOSState cMenuSchedule::Record(void) +{ + cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current()); + if (item) { + cTimer *timer = new cTimer(item->eventInfo); + Timers.Add(timer); + Timers.Save(); + isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + return AddSubMenu(new cMenuEditTimer(timer->Index(), true)); + } + return osContinue; +} + +eOSState cMenuSchedule::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case kRed: return Record(); + case kGreen: if (!now && !next) { + now = true; + return AddSubMenu(new cMenuWhatsOn(schedules, true)); + } + now = !now; + next = !next; + return AddSubMenu(new cMenuWhatsOn(schedules, now)); + case kYellow: return AddSubMenu(new cMenuWhatsOn(schedules, false)); + case kOk: if (Count()) + return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo)); + break; + default: break; + } + } + else if (!HasSubMenu()) + now = next = false; + return state; +} + // --- cMenuRecordingItem ---------------------------------------------------- class cMenuRecordingItem : public cOsdItem { @@ -1089,6 +1440,9 @@ cMenuSetup::cMenuSetup(void) Add(new cMenuEditBoolItem("MarkInstantRecord", &data.MarkInstantRecord)); Add(new cMenuEditIntItem( "LnbFrequLo", &data.LnbFrequLo)); Add(new cMenuEditIntItem( "LnbFrequHi", &data.LnbFrequHi)); + Add(new cMenuEditIntItem( "SetSystemTime", &data.SetSystemTime)); + Add(new cMenuEditIntItem( "MarginStart", &data.MarginStart)); + Add(new cMenuEditIntItem( "MarginStop", &data.MarginStop)); } eOSState cMenuSetup::ProcessKey(eKeys Key) @@ -1098,6 +1452,7 @@ eOSState cMenuSetup::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack; + cDvbApi::PrimaryDvbApi->SetUseTSTime(data.SetSystemTime); Setup = data; Setup.Save(); break; @@ -1114,6 +1469,7 @@ eOSState cMenuSetup::ProcessKey(eKeys Key) cMenuMain::cMenuMain(bool Replaying) :cOsdMenu("Main") { + Add(new cOsdItem("Schedule", osSchedule)); Add(new cOsdItem("Channels", osChannels)); Add(new cOsdItem("Timer", osTimer)); Add(new cOsdItem("Recordings", osRecordings)); @@ -1137,6 +1493,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key) eOSState state = cOsdMenu::ProcessKey(Key); switch (state) { + case osSchedule: return AddSubMenu(new cMenuSchedule); case osChannels: return AddSubMenu(new cMenuChannels); case osTimer: return AddSubMenu(new cMenuTimers); case osRecordings: return AddSubMenu(new cMenuRecordings); @@ -1166,58 +1523,166 @@ eOSState cMenuMain::ProcessKey(eKeys Key) return state; } -// --- cDirectChannelSelect -------------------------------------------------- +// --- cDisplayChannel ------------------------------------------------------- -#define DIRECTCHANNELTIMEOUT 500 //ms +#define DIRECTCHANNELTIMEOUT 500 //ms +#define INFOTIMEOUT 5000 //ms -cDirectChannelSelect::cDirectChannelSelect(eKeys FirstKey) +cDisplayChannel::cDisplayChannel(int Number, bool Switched, bool Group) +:cOsdBase(true) +{ + group = Group; + withInfo = !group && (!Switched || Setup.ShowInfoOnChSwitch); + lines = 0; + oldNumber = number = 0; + cChannel *channel = Group ? Channels.Get(Number) : Channels.GetByNumber(Number); + Interface->Open(MenuColumns, 5); + if (channel) { + DisplayChannel(channel); + DisplayInfo(); + } + lastTime = time_ms(); +} + +cDisplayChannel::cDisplayChannel(eKeys FirstKey) :cOsdBase(true) { oldNumber = CurrentChannel; number = 0; lastTime = time_ms(); - Interface->Open(MenuColumns, 1); + Interface->Open(MenuColumns, 5); ProcessKey(FirstKey); } -cDirectChannelSelect::~cDirectChannelSelect() +cDisplayChannel::~cDisplayChannel() { if (number < 0) - Interface->DisplayChannel(oldNumber); + Interface->DisplayChannelNumber(oldNumber); Interface->Close(); } -eOSState cDirectChannelSelect::ProcessKey(eKeys Key) +void cDisplayChannel::DisplayChannel(const cChannel *Channel) +{ + if (!Interface->Recording()) { + if (Channel && Channel->number) + Interface->DisplayChannelNumber(Channel->number); + int BufSize = Width() + 1; + char buffer[BufSize]; + if (Channel && Channel->number) + snprintf(buffer, BufSize, "%d %s", Channel->number, Channel->name); + else + snprintf(buffer, BufSize, "%s", Channel ? Channel->name : "*** Invalid Channel ***"); + Interface->Fill(0, 0, MenuColumns, 1, clrBackground); + Interface->Write(0, 0, buffer); + time_t t = time(NULL); + struct tm *now = localtime(&t); + snprintf(buffer, BufSize, "%02d:%02d", now->tm_hour, now->tm_min); + Interface->Write(-5, 0, buffer); + Interface->Flush(); + } +} + +void cDisplayChannel::DisplayInfo(void) +{ + if (withInfo) { + const cEventInfo *Present = NULL, *Following = NULL; + cThreadLock ThreadLock; + const cSchedules *Schedules = cDvbApi::PrimaryDvbApi->Schedules(&ThreadLock); + if (Schedules) { + const cSchedule *Schedule = Schedules->GetSchedule(); + if (Schedule) { + const char *PresentTitle = NULL, *PresentSubtitle = NULL, *FollowingTitle = NULL, *FollowingSubtitle = NULL; + int Lines = 0; + if ((Present = Schedule->GetPresentEvent()) != NULL) { + PresentTitle = Present->GetTitle(); + if (!isempty(PresentTitle)) + Lines++; + PresentSubtitle = Present->GetSubtitle(); + if (!isempty(PresentSubtitle)) + Lines++; + } + if ((Following = Schedule->GetFollowingEvent()) != NULL) { + FollowingTitle = Following->GetTitle(); + if (!isempty(FollowingTitle)) + Lines++; + FollowingSubtitle = Following->GetSubtitle(); + if (!isempty(FollowingSubtitle)) + Lines++; + } + if (Lines > lines) { + const int t = 6; + int l = 1; + Interface->Fill(0, 1, MenuColumns, Lines, clrBackground); + if (!isempty(PresentTitle)) { + Interface->Write(0, l, Present->GetTimeString(), clrYellow, clrBackground); + Interface->Write(t, l, PresentTitle, clrCyan, clrBackground); + l++; + } + if (!isempty(PresentSubtitle)) { + Interface->Write(t, l, PresentSubtitle, clrCyan, clrBackground); + l++; + } + if (!isempty(FollowingTitle)) { + Interface->Write(0, l, Following->GetTimeString(), clrYellow, clrBackground); + Interface->Write(t, l, FollowingTitle, clrCyan, clrBackground); + l++; + } + if (!isempty(FollowingSubtitle)) { + Interface->Write(t, l, FollowingSubtitle, clrCyan, clrBackground); + } + Interface->Flush(); + lines = Lines; + lastTime = time_ms(); + } + } + } + } +} + +eOSState cDisplayChannel::ProcessKey(eKeys Key) { switch (Key) { - case k0 ... k9: + case k0: + if (number == 0) { + // keep the "Toggle channels" function working + Interface->PutKey(Key); + return osEnd; + } + case k1 ... k9: if (number >= 0) { number = number * 10 + Key - k0; - cChannel *channel = Channels.GetByNumber(number); - const char *Name = channel ? channel->name : "*** Invalid Channel ***"; - int BufSize = MenuColumns + 1; - char buffer[BufSize]; - snprintf(buffer, BufSize, "%d %s", number, Name); - Interface->DisplayChannel(number); - Interface->Clear(); - Interface->Write(0, 0, buffer); - lastTime = time_ms(); - if (!channel) { - number = -1; - lastTime += 1000; + if (number > 0) { + cChannel *channel = Channels.GetByNumber(number); + DisplayChannel(channel); + lastTime = time_ms(); + if (!channel) { + number = -1; + lastTime += 1000; + } } } break; case kNone: - if (time_ms() - lastTime > DIRECTCHANNELTIMEOUT) { + if (number && time_ms() - lastTime > DIRECTCHANNELTIMEOUT) { if (number > 0 && !Channels.SwitchTo(number)) number = -1; + return osEnd; } - else - break; - default: return osEnd; + break; + //TODO + //XXX case kGreen: return osEventNow; + //XXX case kYellow: return osEventNext; + case kOk: if (group) + Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(CurrentGroup))->number); + return osEnd; + default: Interface->PutKey(Key); + return osEnd; }; - return osContinue; + if (time_ms() - lastTime < INFOTIMEOUT) { + DisplayInfo(); + return osContinue; + } + return osEnd; } // --- cRecordControl -------------------------------------------------------- diff --git a/menu.h b/menu.h index c36427f12..d979069e4 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.12 2000/10/08 15:21:52 kls Exp $ + * $Id: menu.h 1.13 2000/11/01 14:03:09 kls Exp $ */ #ifndef _MENU_H @@ -24,14 +24,18 @@ class cMenuMain : public cOsdMenu { virtual eOSState ProcessKey(eKeys Key); }; -class cDirectChannelSelect : public cOsdBase { +class cDisplayChannel : public cOsdBase { private: - int oldNumber; - int number; + bool withInfo, group; + int lines; int lastTime; + int oldNumber, number; + void DisplayChannel(const cChannel *Channel); + void DisplayInfo(void); public: - cDirectChannelSelect(eKeys FirstKey); - virtual ~cDirectChannelSelect(); + cDisplayChannel(int Number, bool Switched, bool Group = false); + cDisplayChannel(eKeys FirstKey); + virtual ~cDisplayChannel(); virtual eOSState ProcessKey(eKeys Key); }; diff --git a/osd.c b/osd.c index 75d9eadeb..f3458274b 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.9 2000/10/08 12:20:34 kls Exp $ + * $Id: osd.c 1.11 2000/11/01 11:21:51 kls Exp $ */ #include "osd.h" @@ -24,7 +24,7 @@ cOsdItem::cOsdItem(eOSState State) bgColor = clrBackground; } -cOsdItem::cOsdItem(char *Text, eOSState State) +cOsdItem::cOsdItem(const char *Text, eOSState State) { text = NULL; offset = -1; @@ -74,7 +74,7 @@ eOSState cOsdItem::ProcessKey(eKeys Key) // --- cOsdMenu -------------------------------------------------------------- -cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4) +cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4) { visible = false; title = strdup(Title); @@ -108,6 +108,12 @@ void cOsdMenu::SetStatus(const char *s) Interface->Status(status); } +void cOsdMenu::SetTitle(const char *Title, bool Copy) +{ + delete title; + title = Copy ? strdup(Title) : Title; +} + void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue) { // strings are NOT copied - must be constants!!! @@ -164,7 +170,8 @@ void cOsdMenu::Display(void) break; } } - Interface->Status(status); + if (!isempty(status)) + Interface->Status(status); } void cOsdMenu::RefreshCurrent(void) diff --git a/osd.h b/osd.h index 876c87cfc..473e87de4 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.11 2000/09/10 09:50:38 kls Exp $ + * $Id: osd.h 1.14 2000/11/01 14:29:07 kls Exp $ */ #ifndef __OSD_H @@ -19,6 +19,7 @@ enum eOSState { osUnknown, osMenu, osContinue, + osSchedule, osChannels, osTimer, osRecordings, @@ -43,13 +44,13 @@ class cOsdItem : public cListObject { eDvbColor fgColor, bgColor; public: cOsdItem(eOSState State = osUnknown); - cOsdItem(char *Text, eOSState State = osUnknown); + cOsdItem(const char *Text, eOSState State = osUnknown); virtual ~cOsdItem(); bool HasUserColor(void) { return userColor; } void SetText(const char *Text, bool Copy = true); void SetColor(eDvbColor FgColor, eDvbColor BgColor = clrBackground); const char *Text(void) { return text; } - void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); + virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); virtual void Set(void) {} virtual eOSState ProcessKey(eKeys Key); }; @@ -60,13 +61,15 @@ class cOsdBase { public: cOsdBase(bool FastResponse = false) { needsFastResponse = FastResponse; } virtual ~cOsdBase() {} - virtual eOSState ProcessKey(eKeys Key) = 0; + int Width(void) { return Interface->Width(); } + int Height(void) { return Interface->Height(); } bool NeedsFastResponse(void) { return needsFastResponse; } + virtual eOSState ProcessKey(eKeys Key) = 0; }; class cOsdMenu : public cOsdBase, public cList { private: - char *title; + const char *title; int cols[cInterface::MaxCols]; int first, current, marked; cOsdMenu *subMenu; @@ -83,10 +86,11 @@ class cOsdMenu : public cOsdBase, public cList { eOSState AddSubMenu(cOsdMenu *SubMenu); bool HasSubMenu(void) { return subMenu; } void SetStatus(const char *s); + void SetTitle(const char *Title, bool Copy = true); void SetHelp(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); virtual void Del(int Index); public: - cOsdMenu(char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0); + cOsdMenu(const char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0); virtual ~cOsdMenu(); int Current(void) { return current; } void Add(cOsdItem *Item, bool Current = false); diff --git a/recording.c b/recording.c index f9ab01621..3ddf8d350 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.19 2000/10/08 12:20:53 kls Exp $ + * $Id: recording.c 1.20 2000/11/01 16:00:36 kls Exp $ */ #define _GNU_SOURCE @@ -86,6 +86,13 @@ cRecording::cRecording(cTimer *Timer) titleBuffer = NULL; fileName = NULL; name = strdup(Timer->file); + // substitute characters that would cause problems in file names: + for (char *p = name; *p; p++) { + switch (*p) { + case '\n': *p = ' '; break; + case '/': *p = '-'; break; + } + } summary = Timer->summary ? strdup(Timer->summary) : NULL; if (summary) strreplace(summary, '|', '\n'); diff --git a/setup.conf b/setup.conf deleted file mode 100644 index e7ec26747..000000000 --- a/setup.conf +++ /dev/null @@ -1,7 +0,0 @@ -# VDR Setup -PrimaryDVB = 1 -ShowInfoOnChSwitch = 1 -MenuScrollPage = 1 -MarkInstantRecord = 1 -LnbFrequLo = 9750 -LnbFrequHi = 10600 diff --git a/thread.c b/thread.c index 7304e682a..b124581fc 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.2 2000/10/08 16:45:50 kls Exp $ + * $Id: thread.c 1.3 2000/10/28 15:26:02 kls Exp $ */ #include "thread.h" @@ -88,16 +88,27 @@ void cThread::WakeUp(void) cThreadLock::cThreadLock(cThread *Thread) { - thread = Thread; - locked = Thread->Lock(); + thread = NULL; + locked = false; + Lock(Thread); } cThreadLock::~cThreadLock() { - if (locked) + if (thread && locked) thread->Unlock(); } +bool cThreadLock::Lock(cThread *Thread) +{ + if (Thread && !thread) { + thread = Thread; + locked = Thread->Lock(); + return locked; + } + return false; +} + bool cThreadLock::Locked(void) { return locked; diff --git a/thread.h b/thread.h index 86b9e922c..b47f6d715 100644 --- a/thread.h +++ b/thread.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.1 2000/10/08 08:36:21 kls Exp $ + * $Id: thread.h 1.2 2000/10/28 15:08:09 kls Exp $ */ #ifndef __THREAD_H @@ -47,8 +47,9 @@ class cThreadLock { cThread *thread; bool locked; public: - cThreadLock(cThread *Thread); + cThreadLock(cThread *Thread = NULL); ~cThreadLock(); + bool Lock(cThread *Thread); bool Locked(void); }; diff --git a/timers.conf b/timers.conf index fc0e12a60..8f6bcf2fb 100644 --- a/timers.conf +++ b/timers.conf @@ -1,16 +1,15 @@ 1:15:M------:2128:2205:99:7:Neues: 1:3:-T-----:2013:2125:99:99:SevenDays: 1:10:-T-----:2058:2202:99:10:Quarks: -1:26:-T-----:2320:0040:99:99:UFO: +1:26:-T-----:2250:0005:99:99:UFO: 1:14:--W----:1920:2020:99:99:Rettungsflieger: -1:2:--W----:2110:2325:99:99:BulleVonToelz: +0:2:--W----:2110:2325:99:99:BulleVonToelz: 1:3:---T---:2210:2315:99:10:IngoAppelt: -0:2:----F--:2140:2225:10:10:WWW: -1:1:----F--:2212:2325:99:99:7Tage7Koepfe: +1:2:----F--:2013:2125:99:99:Farscape: +1:1:----F--:2215:2325:99:99:7Tage7Koepfe: 1:11:-----S-:2058:2135:99:99:Computer: -1:2:-----S-:2211:2340:99:30:Wochenshow: +1:2:-----S-:2250:0005:99:30:Wochenshow: 1:11:------S:2013:2035:99:10:Centauri: -1:14:------S:2158:2235:99:14:MaxUndLisa: 1:15:MTWTF--:1828:1901:10:5:nano: -1:1:-TWTF--:0955:1040:99:99:Ellen: 1:1:MTWTF--:1553:1710:99:99:Hammerman: +1:3:3:0220:0350:99:99:Seven Days - Das Tor zur Zeit:Die Rache des Alien||Als das Zeitsprung-Team die Leiche eines bei Roswell gefundenen Aliens obduziert, entdecken sie einen Chip in seiner Wirbelsule. Dr. Ballard, der hnliche Rckenprobleme wie der Alien hat, lsst sich den Chip einsetzen. Tatschlich regeneriert Ballard vollstndig. Doch dann ndert sich sein Verhalten: Er wird dem Alien immer hnlicher. Schlielich gelingt es ihm, mit einer Superwaffe Millionen Menschen zu tten - einschlielich des Zeitsprung-Teams. Nur Parker berlebt. diff --git a/tools.c b/tools.c index fc15a9853..4acea0b3d 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.21 2000/10/07 18:02:24 kls Exp $ + * $Id: tools.c 1.22 2000/10/29 11:21:55 kls Exp $ */ #define _GNU_SOURCE @@ -85,11 +85,16 @@ char *strreplace(char *s, char c1, char c2) return s; } -char *skipspace(char *s) +char *skipspace(const char *s) { while (*s && isspace(*s)) s++; - return s; + return (char *)s; +} + +bool isempty(const char *s) +{ + return !(s && *skipspace(s)); } int time_ms(void) @@ -520,7 +525,7 @@ void cListBase::Clear(void) objects = lastObject = NULL; } -cListObject *cListBase::Get(int Index) +cListObject *cListBase::Get(int Index) const { if (Index < 0) return NULL; @@ -530,7 +535,7 @@ cListObject *cListBase::Get(int Index) return object; } -int cListBase::Count(void) +int cListBase::Count(void) const { int n = 0; cListObject *object = objects; diff --git a/tools.h b/tools.h index 17b643ffb..b5bdd278d 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.17 2000/10/07 18:00:21 kls Exp $ + * $Id: tools.h 1.18 2000/10/29 11:19:20 kls Exp $ */ #ifndef __TOOLS_H @@ -40,7 +40,8 @@ void purge(int filedes); char *readline(FILE *f); char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); -char *skipspace(char *s); +char *skipspace(const char *s); +bool isempty(const char *s); int time_ms(void); void delay_ms(int ms); bool isnumber(const char *s); @@ -80,8 +81,8 @@ class cListObject { void Append(cListObject *Object); void Unlink(void); int Index(void); - cListObject *Prev(void) { return prev; } - cListObject *Next(void) { return next; } + cListObject *Prev(void) const { return prev; } + cListObject *Next(void) const { return next; } }; class cListBase { @@ -95,15 +96,15 @@ class cListBase { virtual void Move(int From, int To); void Move(cListObject *From, cListObject *To); void Clear(void); - cListObject *Get(int Index); - int Count(void); + cListObject *Get(int Index) const; + int Count(void) const; }; template class cList : public cListBase { public: - T *Get(int Index) { return (T *)cListBase::Get(Index); } - T *First(void) { return (T *)objects; } - T *Next(T *object) { return (T *)object->Next(); } + T *Get(int Index) const { return (T *)cListBase::Get(Index); } + T *First(void) const { return (T *)objects; } + T *Next(const T *object) const { return (T *)object->Next(); } }; #endif //__TOOLS_H diff --git a/vdr.c b/vdr.c index c8cabb0b5..b1321aef2 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.39 2000/10/08 14:49:25 kls Exp $ + * $Id: vdr.c 1.41 2000/11/01 14:31:32 kls Exp $ */ #include @@ -161,10 +161,6 @@ int main(int argc, char *argv[]) if (!cDvbApi::Init()) abort(); - // User interface: - - Interface = new cInterface(SVDRPport); - // Configuration data: if (!ConfigDirectory) @@ -176,14 +172,21 @@ int main(int argc, char *argv[]) #ifdef REMOTE_LIRC Keys.SetDummyValues(); #else - if (!Keys.Load(AddDirectory(ConfigDirectory, KEYS_CONF))) - Interface->LearnKeys(); + bool KeysLoaded = Keys.Load(AddDirectory(ConfigDirectory, KEYS_CONF)); #endif cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); Channels.SwitchTo(CurrentChannel); + // User interface: + + Interface = new cInterface(SVDRPport); +#ifndef REMOTE_LIRC + if (!KeysLoaded) + Interface->LearnKeys(); +#endif + // Signal handlers: if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN); @@ -202,7 +205,7 @@ int main(int argc, char *argv[]) // Channel display: if (CurrentChannel != LastChannel) { if (!Menu) - Channels.ShowChannel(CurrentChannel, LastChannel > 0); + Menu = new cDisplayChannel(CurrentChannel, LastChannel > 0); PreviousChannel = LastChannel; LastChannel = CurrentChannel; } @@ -262,7 +265,7 @@ int main(int argc, char *argv[]) // Direct Channel Select: case k1 ... k9: if (!Interface->Recording()) - Menu = new cDirectChannelSelect(key); + Menu = new cDisplayChannel(key); break; // Left/Right rotates trough channel groups: case kLeft|k_Repeat: @@ -276,8 +279,7 @@ int main(int argc, char *argv[]) CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup); if (CurrentGroup < 0) CurrentGroup = SaveGroup; - if (Channels.ShowChannel(CurrentGroup, false, true) == kOk) - Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(CurrentGroup))->number); + Menu = new cDisplayChannel(CurrentGroup, false, true); } break; // Up/Down Channel Select: From 9aa2cda494d7af2733362de78234441a25959e86 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 19 Nov 2000 18:00:00 +0100 Subject: [PATCH 015/307] Version 0.68 - Date and time in the title of an event info page are now always right adjusted. - The 'current channel' is now handled device specific (in case there is more than one DVB card). - The 'SetSystemTime' option in the "Setup" menu is now shown as "yes/no". - Implemented "internationalization" (see 'i18n.c' for information on how to add new languages). Thanks to Miha Setina for translating the OSD texts to the Slovenian language. - Fixed learning keys on the PC keyboard (display oscillated). - Fixed a timing problem with OSD refresh and SVDRP. - Avoiding multiple definitions of the same timer in the "Schedule" menu (this could happen when pressing the "Red" button while editing the timer). - There can now be a configuration file named 'commands.conf' that defines commands that can be executed through the "Main" menu's "Commands" option (see FORMATS for details on how to define these commands). - Added a 'fixed' font for use with the output of system commands. - The 'Priority' parameter of the timers is now also used to interrupt a low priority timer recording if a higher priority timer wants to record. - A timer recording on a DVB card with a CAM module will now be interrupted by a timer that needs to use this specific DVB card to record an encrypted channel, if the timer currently occupying this DVB card doesn't need the CAM module (and thus can continue recording on a different DVB card). - The "Yellow" button in the "What's on now/next?" menus now displays the schedule of the current channel from that menu. - All DVB cards in a multi-card system now write their EIT information into the same data structure. - If there is more than one DVB card in the system, the non-primary cards are now used to periodically scan through the channels in order to keep the EPG info up-to-date. Scanning kicks in after 60 seconds of user inactivity (timeout in order to keep user interactions instantaneously) and each channel that has the 'pnr' parameter defined in 'channels.conf' is switched to for 20 seconds. If there is only one DVB card in the system, that card will start scanning after 5 hours (configurable through the "Setup" menu) of user inactivity and will switch back to the channel it originally displayed at the first sign of user activity. Any scanning will only occur if that particular card is not currently recording or replaying. - Now shifting the 'Subtitle' info into the 'ExtendedDescription' on stations that don't send the EIT information correctly (like, e.g., 'VOX'). - Implemented a 10 seconds latency when removing files. - Fixed unwanted reaction on the "Green" and "Yellow" button in the "Event" display. - Implemented 'Transfer Mode' to display video data from the DVB card that actually can receive a certain channel on the primary interface. This is currently in an early state and may still cause some problems, but it appears to work nice already. --- BUGS | 4 +- CONTRIBUTORS | 3 + FORMATS | 31 +- HISTORY | 46 + MANUAL | 43 +- Makefile | 28 +- README | 11 +- channels.conf | 66 +- config.c | 97 +- config.h | 30 +- dvbapi.c | 210 +- dvbapi.h | 68 +- dvbosd.c | 19 +- dvbosd.h | 6 +- eit.c | 40 +- eit.h | 7 +- font.c | 16 +- font.h | 3 +- fontfix.c | 6498 +++++++++++++++++++++++++++++++++++++++++++++++++ i18n.c | 478 ++++ i18n.h | 19 + interface.c | 70 +- interface.h | 3 +- menu.c | 414 +++- menu.h | 4 +- osd.c | 12 +- osd.h | 6 +- recording.c | 7 +- remote.c | 4 +- svdrp.c | 16 +- thread.c | 8 +- thread.h | 14 +- timers.conf | 15 +- tools.c | 14 +- tools.h | 5 +- vdr.c | 38 +- 36 files changed, 8044 insertions(+), 309 deletions(-) create mode 100644 fontfix.c create mode 100644 i18n.c create mode 100644 i18n.h diff --git a/BUGS b/BUGS index d24d37072..506316a50 100644 --- a/BUGS +++ b/BUGS @@ -4,5 +4,5 @@ Video Disk Recorder - Known Bugs * Sometimes the picture "jumps" as if a frame is skipped. Presumably this is a problem in the card driver or firmware? -* The first picture captured with the GRAB command in SVDRP - is empty. Also, these pictures appear to be too dark. +* The pictures captured with the GRAB command in SVDRP + appear to be too dark. diff --git a/CONTRIBUTORS b/CONTRIBUTORS index db47d8b9e..279706da6 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -40,3 +40,6 @@ Bastian Guse Matthias Schniedermeyer for implementing the 'MarkInstantRecord' setup option. + +Miha Setina + for translating the OSD texts to the Slovenian language. diff --git a/FORMATS b/FORMATS index 331fe3d55..3eee494f6 100644 --- a/FORMATS +++ b/FORMATS @@ -47,8 +47,11 @@ Video Disk Recorder File Formats ----F-- = Friday -----S- = Saturday ------S = Sunday - (any combination is possible, for example MTWTF--) or the "day of month" (1..31) - - Star time (first two digits for the hour, second two digits for the minutes) + (any combination is possible, for example MTWTF--, and the days may be + indicated by any characters except '-', so for example ABC---- would set + a timer that records on monday, tuesday and wednesday) or the "day of month" + (1..31) + - Start time (first two digits for the hour, second two digits for the minutes) - End time (first two digits for the hour, second two digits for the minutes) - Priority (from 00 to 99, 00 = lowest prioity, 99 = highest priority) - Guaranteed lifetime of recording (in days) @@ -63,3 +66,27 @@ Video Disk Recorder File Formats See the MANUAL file for a description of the available options. +* commands.conf + + This file contains the definitions of commands that can be executed from + the "Main" menus "Commands" option. + + Each line contains one command definition in the following format: + + title : command + + where 'title' is the string the will be displayed in the "Commands" menu, + and 'command' is the actual command string that will be executed when this + option is selected. The delimiting ':' may be surrounded by any number of + white space characters. + + In order to avoid error messages to stderr, every command should have + stderr redirected to stdout. Everything the command prints to stdout will + be displayed in a result window, with 'title' as its title. + + Examples: + + Check for new mail: /usr/local/bin/checkmail 2>&1 + CPU status : /usr/loval/bin/cpustatus 2>&1 + Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' + diff --git a/HISTORY b/HISTORY index 189fd7b32..485f24a2c 100644 --- a/HISTORY +++ b/HISTORY @@ -265,3 +265,49 @@ Video Disk Recorder Revision History - Problematic characters in recording names (which can come from timers that are programmed via the "Schedules" menu) are now replaced by suitable substitutes. + +2000-11-19: Version 0.68 + +- Date and time in the title of an event info page are now always right adjusted. +- The 'current channel' is now handled device specific (in case there is more + than one DVB card). +- The 'SetSystemTime' option in the "Setup" menu is now shown as "yes/no". +- Implemented "internationalization" (see 'i18n.c' for information on how to + add new languages). Thanks to Miha Setina for translating the OSD texts to + the Slovenian language. +- Fixed learning keys on the PC keyboard (display oscillated). +- Fixed a timing problem with OSD refresh and SVDRP. +- Avoiding multiple definitions of the same timer in the "Schedule" menu (this + could happen when pressing the "Red" button while editing the timer). +- There can now be a configuration file named 'commands.conf' that defines + commands that can be executed through the "Main" menu's "Commands" option + (see FORMATS for details on how to define these commands). +- Added a 'fixed' font for use with the output of system commands. +- The 'Priority' parameter of the timers is now also used to interrupt a low + priority timer recording if a higher priority timer wants to record. +- A timer recording on a DVB card with a CAM module will now be interrupted + by a timer that needs to use this specific DVB card to record an encrypted + channel, if the timer currently occupying this DVB card doesn't need the + CAM module (and thus can continue recording on a different DVB card). +- The "Yellow" button in the "What's on now/next?" menus now displays the + schedule of the current channel from that menu. +- All DVB cards in a multi-card system now write their EIT information into the + same data structure. +- If there is more than one DVB card in the system, the non-primary cards are + now used to periodically scan through the channels in order to keep the + EPG info up-to-date. Scanning kicks in after 60 seconds of user inactivity + (timeout in order to keep user interactions instantaneously) and each channel + that has the 'pnr' parameter defined in 'channels.conf' is switched to for + 20 seconds. If there is only one DVB card in the system, that card will start + scanning after 5 hours (configurable through the "Setup" menu) of user inactivity + and will switch back to the channel it originally displayed at the first sign of + user activity. Any scanning will only occur if that particular card is not + currently recording or replaying. +- Now shifting the 'Subtitle' info into the 'ExtendedDescription' on stations + that don't send the EIT information correctly (like, e.g., 'VOX'). +- Implemented a 10 seconds latency when removing files. +- Fixed unwanted reaction on the "Green" and "Yellow" button in the "Event" display. +- Implemented 'Transfer Mode' to display video data from the DVB card that actually + can receive a certain channel on the primary interface. This is currently in + an early state and may still cause some problems, but it appears to work nice + already. diff --git a/MANUAL b/MANUAL index ffcc10b86..46466bf8b 100644 --- a/MANUAL +++ b/MANUAL @@ -74,8 +74,8 @@ Video Disk Recorder User's Manual programmes that will start next on all channels. Inside the "What's on now/next?" menus the "Green" button toggles between - the "Now" and "Next" display, and the "Yellow" button gets you back to the - "Schedule" menu of the current channel. + the "Now" and "Next" display, and the "Yellow" button takes you to the + "Schedule" menu of the current channel in the list. The "Red" button allows you to instantly program a timer to record the selected programme. You will get into the "Edit Timer" menu in which @@ -203,7 +203,9 @@ Video Disk Recorder User's Manual to free space for a new recording. If the disk is full and a new recording needs more space, an existing recording with the lowest Priority (and which has exceeded its guaranteed Lifetime) will be - removed. + removed. If all available DVB cards are currently occupied, a + timer with a higher priority will interrupt the timer with the + lowest priority in order to start recording. Lifetime: The number of days (0..99) a recording made through this timer is guaranteed to remain on disk before it is automatically removed to free up space for a new recording. Note that setting this @@ -228,6 +230,10 @@ Video Disk Recorder User's Manual displayed as "no" and "yes" in the "Setup" menu, while in the setup file they are stored as '0' and '1', respectively): + OSDLanguage = 0 Defines the language used to display the OSD texts. + 0 = Englisch + 1 = Deutsch + PrimaryDVB = 1 Defines the primary DVB interface (i.e. the one that will display the menus and will react on input through the remote control). Valid values range from '1' to the @@ -266,6 +272,37 @@ Video Disk Recorder User's Manual 1 = system time wil be set Note that this works only if VDR is running under a user id that has permisson to set the system time. + MarginStart = 2 Defines how many minutes before the official start time MarginStop = 10 of a broadcast VDR shall start recording, and how long after the official end time it shall stop recording. + + EPGScanTimeout = 5 The time (in hours) of user inactivity after which the + DVB card in a single card system starts scanning channels + to keep the EPG up-to-date. + A value of '0' turns off scanning on a single card system. + +* Executing system commands + + The "Main" menu option "Commands" allows you to execute any system commands + defined in the configuration file 'commands.conf' (see FORMATS for details). + The "Commands" option will only be present in the "Main" menu if a valid + 'commands.conf' file containing at least one command definition has been + found at program start. + + This feature can be used to do virtually anything, like checking for new + mail, displaying the CPU temperature - you name it! All you need to do is + enter the necessary command definition into 'commands.conf' and implement + the actual command that will be called. Such a command can typically be a + shell script or a Perl program. Anything that command writes to stdout will + be displayed on a result screen after executing the command. This screen will + use a 'fixed' font so that you can generate formatted output. In order to + avoid error messages going to stderr, command definitions should redirect + stderr to stdout (see FORMATS). + + WARNING: THE COMMANDS DEFINED IN 'commands.conf' WILL BE EXECUTED UNDER THE + ======= SAME USER ID THAT VDR IS RUNNING WITH. BE VERY CAREFUL WHEN + DEFINING THESE COMMANDS AND MAKE SURE THEY DON'T HARM YOUR SYSTEM, + ESPECIALLY IF YOU ARE RUNNING VDR UNDER A HIGH PRIVILEGED USER ID + (LIKE 'root'). + diff --git a/Makefile b/Makefile index 9db79f395..739d3942b 100644 --- a/Makefile +++ b/Makefile @@ -4,15 +4,16 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.14 2000/10/28 16:24:16 kls Exp $ +# $Id: Makefile 1.16 2000/11/18 14:58:10 kls Exp $ DVBDIR = ../DVB INCLUDES = -I$(DVBDIR)/driver -OBJS = config.o dvbapi.o dvbosd.o eit.o font.o interface.o menu.o osd.o\ +OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o osd.o\ recording.o remote.o svdrp.o thread.o tools.o vdr.o videodir.o OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 +FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1 ifndef REMOTE REMOTE = KBD @@ -25,8 +26,8 @@ DEFINES += -DDEBUG_OSD endif all: vdr -font: genfontfile fontosd.c - @echo "font file created." +font: genfontfile fontfix.c fontosd.c + @echo "font files created." # Implicit rules: @@ -35,20 +36,21 @@ font: genfontfile fontosd.c # Dependencies: -config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h +config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h videodir.h dvbosd.o : dvbosd.c dvbosd.h font.h tools.h eit.o : eit.c eit.h thread.h tools.h -font.o : font.c font.h fontosd.c tools.h -interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h -menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h -osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h osd.h remote.h svdrp.h thread.h tools.h +font.o : font.c font.h fontfix.c fontosd.c tools.h +i18n.o : i18n.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h thread.h tools.h +interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h +menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h +osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h recording.o: recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h thread.o : thread.c thread.h tools.o : tools.c tools.h -vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h +vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h videodir.o : videodir.c tools.h videodir.h # The main program: @@ -56,8 +58,10 @@ videodir.o : videodir.c tools.h videodir.h vdr: $(OBJS) g++ -g -O2 $(OBJS) -lncurses -ljpeg -lpthread -o vdr -# The font file: +# The font files: +fontfix.c: + genfontfile "cFont::tPixelData FontFix" $(FIXFONT) > $@ fontosd.c: genfontfile "cFont::tPixelData FontOsd" $(OSDFONT) > $@ @@ -73,4 +77,4 @@ genfontfile: genfontfile.o clean: -rm -f $(OBJS) vdr genfontfile genfontfile.o CLEAN: clean - -rm -f fontosd.c + -rm -f fontfix.c fontosd.c diff --git a/README b/README index cfc10a765..b1e071ee0 100644 --- a/README +++ b/README @@ -1,9 +1,8 @@ -On Screen Menu for the Video Disk Recorder ------------------------------------------- +Video Disk Recorder ('VDR') +--------------------------- -These files contain the source code of an on screen -menu for a video disk recorder based on the DVB driver -of the LinuxTV project (http://linuxtv.org). +These files contain the source code of the "Video Disk Recorder", +which is based on the DVB driver of the LinuxTV project (http://linuxtv.org). For details about the "Video Disk Recorder" project please refer to http://www.cadsoft.de/people/kls/vdr. @@ -13,6 +12,8 @@ Web pages, which can be used within this program. Please see the INSTALL file for details on how to install this program on your computer. +The MANUAL file describes how to operate the VDR. + The author can be contacted at kls@cadsoft.de. Yet another "set-top-box"? diff --git a/channels.conf b/channels.conf index c61669cab..ce30919e9 100644 --- a/channels.conf +++ b/channels.conf @@ -6,7 +6,6 @@ ARD:11837:h:1:27500:101:102:0:28106 BR3:11837:h:1:27500:201:202:0:28107 Hessen-3:11837:h:1:27500:301:302:0:28108 N3:12110:h:1:27500:2401:2402:0:28224 -:Group 1 SR3:11837:h:1:27500:501:502:0:28110 WDR:11837:h:1:27500:601:602:0:28111 BR-alpha:11837:h:1:27500:701:702:0:28112 @@ -16,25 +15,24 @@ ZDF:11954:h:1:27500:110:120:0:28006 3sat:11954:h:1:27500:210:220:0:28007 KiKa:11954:h:1:27500:310:320:0:28008 arte:11836:h:1:27500:401:402:0:28109 -:Group 2 -Eurosport:11954:h:1:27500:410:420:0:28009 ORF Sat:11954:h:1:27500:506:507:0:28010 ZDF.info:11954:h:1:27500:610:620:0:28011 -:Group 3 -CNN:12168:v:1:27500:165:100:0:0 +CNN:12168:v:1:27500:165:100:0:28512 Super RTL:12188:h:1:27500:165:120:0:12040 VOX:12188:h:1:27500:167:136:0:12060 DW TV:12363:v:1:27500:305:306:0:8905 Kabel 1:12480:v:1:27500:511:512:0:899 -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 +tm3:12480:v:1:27500:767:768:0:897 +DSF:12480:v:1:27500:1023:1024:0:900 +HOT:12480:v:1:27500:1279:1280:0:40 +Bloomberg TV Germany:12551:v:1:22000:162:99:0:12160 +BLOOMBERG TV:11817:v:1:27500:163:92:0:8004 +Bloomberg:12168:v:1:27500:167:112:0:12721 Sky News:12552:v:1:22000:305:306:0:3995 -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 Tourisme:12670:v:1:22000:289:290:0:0 +KinderNet:12574:h:1:22000:163:92:0:5020 +Alice:12610:v:1:22000:162:96:0:12200 +n-tv:12669:v:1:22000:162:96:0:12730 +Grand Tourisme:12670:v:1:22000:289:290:0:17300 TW1:12692:h:1:22000:166:167:0:13013 Eurosport:11954:h:1:27500:410:420:0:28009 EinsExtra:12110:H:1:27500:101:102:0:28201 @@ -43,10 +41,12 @@ EinsMuXx:12110:H:1:27500:301:302:0:28203 ZDF Theaterkanal:11954:H:1:27500:1110:1120:0:28016 ZDF.doku:11954:H:1:27500:660:670:0:28014 MDR:12110:h:1:27500:401:402:0:28204 +NICK-PARAMOUNT:12246:v:1:27500:167:108:0:29312 ORB:12110:h:1:27500:501:502:0:28205 B1:12110:h:1:27500:601:602:0:28206 ARD Online-Kanal:12722:h:1:22000:8191:701:0:0 -Premiere World Promo:11798:h:1:27500:255:256:0:0 +:Premiere World +Premiere World Promo:11798:h:1:27500:255:256:0:8 Premiere:11798:h:1:27500:511:512:2:10 Star Kino:11798:h:1:27500:767:768:2:9 Cine Action:11798:h:1:27500:1023:1024:2:20 @@ -54,9 +54,31 @@ Cine Comedy:11798:h:1:27500:1279:1280:2:29 Sci Fantasy:11798:h:1:27500:1535:1536:2:41 Romantic Movies:11798:h:1:27500:1791:1792:2:11 Studio Universal:11798:h:1:27500:2047:2048:2:21 -TV Niepokalanow:11876:h:1:27500:305:321:0:0 -Mosaico:11934:v:1:27500:165:100:0:0 -Andalucia TV:11934:v:1:27500:166:104:0:0 +13th Street:11797:h:1:27500:2303:2304:2:43 +Junior:12031:h:1:27500:255:256:2:19 +K-Toon:12032:h:1:27500:511:512:2:12 +Disney Channel:12031:h:1:27500:767:768:2:15 +Fox Kids:11798:h:1:27500:255:256:2:0 +Sunset:12031:h:1:27500:1023:1024:2:16 +Comedy:12031:h:1:27500:1279:1280:2:28 +Planet:12031:h:1:27500:2047:2048:2:13 +Discovery Channel:12031:h:1:27500:1791:1792:2:14 +Krimi&Co:12031:h:1:27500:1535:1536:2:23 +Filmpalast:12090:v:1:27500:255:256:2:36 +Heimatkanal:11758:h:1:27500:2815:2816:2:517 +Goldstar:11758:h:1:27500:3839:3840:2:518 +Classica:12090:v:1:27500:767:768:2:34 +Seasons:12090:v:1:27500:511:512:2:33 +Blue Channel:11758:h:1:27500:2559:2560:2:516 +Feed (F1 Boxengasse):11720:h:1:27500:2559:2560:2:242 +Feed (F1 Data):11720:h:1:27500:3071:3072:2:244 +Feed (F1 Multi):11720:h:1:27500:2815:2816:2:243 +Feed (F1 On Board):11720:h:1:27500:2303:2304:2:241 +Feed (F1 Verfolger):11720:h:1:27500:2047:2048:2:240 +: +TV Niepokalanow:11876:h:1:27500:305:321:0:20601 +Mosaico:11934:v:1:27500:165:100:0:29010 +Andalucia TV:11934:v:1:27500:166:104:0:29011 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 @@ -96,7 +118,7 @@ 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 +RAI Uno:12363:v:1:27500:289:290:0:8904 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 @@ -116,6 +138,10 @@ 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 Germany:12552:v:1:22000:162:99:0:12160 -Video Italia:12610:v:1:22000:121:122:0:0 +VERONICA:12574:h:1:22000:161:84:0:5010 +VH1 Classic:12699:v:1:22000:3071:3072:0:28647 +VH-1 Germany:12699:v:1:22000:3081:3082:0:28648 +Via 1 - Schner Reisen:12148:h:1:27500:511:512:0:44 +Video Italia:12610:v:1:22000:121:122:0:12220 AC 3 promo:12670:v:1:22000:308:256:0:0 +ORF/ZDF:12699:h:1:22000:506:507:0:13012 diff --git a/config.c b/config.c index 5b485f663..8964e5a04 100644 --- a/config.c +++ b/config.c @@ -4,13 +4,14 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.29 2000/11/01 18:22:43 kls Exp $ + * $Id: config.c 1.34 2000/11/18 13:26:36 kls Exp $ */ #include "config.h" #include #include #include "dvbapi.h" +#include "i18n.h" #include "interface.h" // -- cKeys ------------------------------------------------------------------ @@ -256,22 +257,23 @@ bool cChannel::Save(FILE *f) return fprintf(f, ToText()) > 0; } -bool cChannel::Switch(cDvbApi *DvbApi) +bool cChannel::Switch(cDvbApi *DvbApi, bool Log) { if (!DvbApi) DvbApi = cDvbApi::PrimaryDvbApi; if (!DvbApi->Recording() && !groupSep) { - isyslog(LOG_INFO, "switching to channel %d", number); - CurrentChannel = number; + if (Log) { + isyslog(LOG_INFO, "switching to channel %d", number); + } for (int i = 3; i--;) { - if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) + if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) return true; esyslog(LOG_ERR, "retrying"); } return false; } if (DvbApi->Recording()) - Interface->Info("Channel locked (recording)!"); + Interface->Info(tr("Channel locked (recording)!")); return false; } @@ -284,7 +286,7 @@ cTimer::cTimer(bool Instant) startTime = stopTime = 0; recording = false; active = Instant; - cChannel *ch = Channels.GetByNumber(CurrentChannel); + cChannel *ch = Channels.GetByNumber(cDvbApi::CurrentChannel()); channel = ch ? ch->number : 0; time_t t = time(NULL); struct tm *now = localtime(&t); @@ -294,8 +296,8 @@ cTimer::cTimer(bool Instant) if (stop >= 2400) stop -= 2400; //TODO VPS??? - priority = 99; - lifetime = 99; + priority = DEFAULTPRIORITY; + lifetime = DEFAULTLIFETIME; *file = 0; summary = NULL; if (Instant && ch) @@ -319,8 +321,8 @@ cTimer::cTimer(const cEventInfo *EventInfo) stop = time->tm_hour * 100 + time->tm_min; if (stop >= 2400) stop -= 2400; - priority = 99; - lifetime = 99; + priority = DEFAULTPRIORITY; + lifetime = DEFAULTLIFETIME; *file = 0; const char *Title = EventInfo->GetTitle(); if (!isempty(Title)) @@ -406,7 +408,7 @@ const char *cTimer::PrintDay(int d) static char buffer[8]; if ((d & 0x80000000) != 0) { char *b = buffer; - char *w = "MTWTFSS"; + const char *w = tr("MTWTFSS"); *b = 0; while (*w) { *b++ = (d & 1) ? *w : '-'; @@ -426,7 +428,7 @@ bool cTimer::Parse(const char *s) delete summary; summary = NULL; //XXX Apparently sscanf() doesn't work correctly if the last %a argument - //XXX results in an empty string (this firt occured when the EIT gathering + //XXX results in an empty string (this first occured when the EIT gathering //XXX was put into a separate thread - don't know why this happens... //XXX As a cure we copy the original string and add a blank. //XXX If anybody can shed some light on why sscanf() failes here, I'd love @@ -539,13 +541,71 @@ cTimer *cTimer::GetMatch(void) return t0; } +// --- cCommand ------------------------------------------------------------- + +char *cCommand::result = NULL; + +cCommand::cCommand(void) +{ + title = command = NULL; +} + +cCommand::~cCommand() +{ + delete title; + delete command; +} + +bool cCommand::Parse(const char *s) +{ + const char *p = strchr(s, ':'); + if (p) { + int l = p - s; + if (l > 0) { + title = new char[l + 1]; + strn0cpy(title, s, l + 1); + if (!isempty(title)) { + command = stripspace(strdup(skipspace(p + 1))); + return !isempty(command); + } + } + } + return false; +} + +const char *cCommand::Execute(void) +{ + dsyslog(LOG_INFO, "executing command '%s'", command); + delete result; + result = NULL; + FILE *p = popen(command, "r"); + if (p) { + int l = 0; + int c; + while ((c = fgetc(p)) != EOF) { + if (l % 20 == 0) + result = (char *)realloc(result, l + 21); + result[l++] = c; + } + if (result) + result[l] = 0; + pclose(p); + } + else + esyslog(LOG_ERR, "ERROR: can't open pipe for command '%s'", command); + return result; +} + // -- cKeys ------------------------------------------------------------------ cKeys Keys; +// -- cCommands -------------------------------------------------------------- + +cCommands Commands; + // -- cChannels -------------------------------------------------------------- -int CurrentChannel = 1; int CurrentGroup = -1; cChannels Channels; @@ -652,6 +712,7 @@ char *cSetup::fileName = NULL; cSetup::cSetup(void) { + OSDLanguage = 0; PrimaryDVB = 1; ShowInfoOnChSwitch = 1; MenuScrollPage = 1; @@ -661,6 +722,7 @@ cSetup::cSetup(void) SetSystemTime = 0; MarginStart = 2; MarginStop = 10; + EPGScanTimeout = 5; } bool cSetup::Parse(char *s) @@ -669,7 +731,8 @@ bool cSetup::Parse(char *s) char *Name = strtok(s, Delimiters); char *Value = strtok(NULL, Delimiters); if (Name && Value) { - if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); + if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value); + else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); @@ -678,6 +741,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); + else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); else return false; return true; @@ -719,6 +783,7 @@ bool cSetup::Save(const char *FileName) FILE *f = fopen(FileName, "w"); if (f) { fprintf(f, "# VDR Setup\n"); + fprintf(f, "OSDLanguage = %d\n", OSDLanguage); fprintf(f, "PrimaryDVB = %d\n", PrimaryDVB); fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch); fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage); @@ -727,7 +792,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); fprintf(f, "SetSystemTime = %d\n", SetSystemTime); fprintf(f, "MarginStart = %d\n", MarginStart); - fprintf(f, "MarginStop = %d\n", MarginStop); + fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout); fclose(f); isyslog(LOG_INFO, "saved setup to %s", FileName); return true; diff --git a/config.h b/config.h index f9bd579e7..db3f1edc9 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.29 2000/11/01 13:42:29 kls Exp $ + * $Id: config.h 1.34 2000/11/18 13:25:53 kls Exp $ */ #ifndef __CONFIG_H @@ -18,7 +18,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.67" +#define VDRVERSION "0.68" #define MaxBuffer 10000 @@ -92,9 +92,12 @@ class cChannel : public cListObject { const char *ToText(void); bool Parse(const char *s); bool Save(FILE *f); - bool Switch(cDvbApi *DvbApi = NULL); + bool Switch(cDvbApi *DvbApi = NULL, bool Log = true); }; +#define DEFAULTPRIORITY 99 +#define DEFAULTLIFETIME 99 + class cTimer : public cListObject { private: time_t startTime, stopTime; @@ -115,7 +118,7 @@ class cTimer : public cListObject { char *summary; cTimer(bool Instant = false); cTimer(const cEventInfo *EventInfo); - ~cTimer(); + virtual ~cTimer(); cTimer& operator= (const cTimer &Timer); const char *ToText(void); bool Parse(const char *s); @@ -132,6 +135,19 @@ class cTimer : public cListObject { static const char *PrintDay(int d); }; +class cCommand : public cListObject { +private: + char *title; + char *command; + static char *result; +public: + cCommand(void); + virtual ~cCommand(); + bool Parse(const char *s); + const char *Title(void) { return title; } + const char *Execute(void); + }; + template class cConfig : public cList { private: char *fileName; @@ -217,12 +233,14 @@ class cTimers : public cConfig { cTimer *GetTimer(cTimer *Timer); }; -extern int CurrentChannel; +class cCommands : public cConfig {}; + extern int CurrentGroup; extern cChannels Channels; extern cTimers Timers; extern cKeys Keys; +extern cCommands Commands; class cSetup { private: @@ -230,6 +248,7 @@ class cSetup { bool Parse(char *s); public: // Also adjust cMenuSetup (menu.c) when adding parameters here! + int OSDLanguage; int PrimaryDVB; int ShowInfoOnChSwitch; int MenuScrollPage; @@ -238,6 +257,7 @@ class cSetup { int LnbFrequHi; int SetSystemTime; int MarginStart, MarginStop; + int EPGScanTimeout; cSetup(void); bool Load(const char *FileName); bool Save(const char *FileName = NULL); diff --git a/dvbapi.c b/dvbapi.c index cc246d2f0..5e4f2e647 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.34 2000/11/01 09:19:27 kls Exp $ + * $Id: dvbapi.c 1.40 2000/11/19 16:46:37 kls Exp $ */ #include "dvbapi.h" @@ -372,7 +372,9 @@ class cRingBuffer { int *inFile, *outFile; protected: int Free(void) { return ((tail >= head) ? size + head - tail : head - tail) - 1; } +public: int Available(void) { return (tail >= head) ? tail - head : size - head + tail; } +protected: int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap! int Writeable(void) { return (tail >= head) ? tail - head : size - head; } int Byte(int Offset); @@ -1079,6 +1081,63 @@ int cReplayBuffer::Write(int Max) return Written; } +// --- cTransferBuffer ------------------------------------------------------- + +class cTransferBuffer : public cThread { +private: + bool active; + int fromDevice, toDevice; +protected: + virtual void Action(void); +public: + cTransferBuffer(int FromDevice, int ToDevice); + virtual ~cTransferBuffer(); + }; + +cTransferBuffer::cTransferBuffer(int FromDevice, int ToDevice) +{ + fromDevice = FromDevice; + toDevice = ToDevice; + active = true; + Start(); +} + +cTransferBuffer::~cTransferBuffer() +{ + { + LOCK_THREAD; + active = false; + } + for (time_t t0 = time(NULL); time(NULL) - t0 < 3; ) { + LOCK_THREAD; + if (active) + break; + } +} + +void cTransferBuffer::Action(void) +{ + dsyslog(LOG_INFO, "data transfer thread started (pid=%d)", getpid()); + //XXX hack to make the video device go into 'replaying' mode: + char *dummy = "AV"; // must be "AV" to make the driver go into AV_PES mode! + write(toDevice, dummy, strlen(dummy)); + { + cRingBuffer Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); + while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start + Buffer.Read(); // initializes fromDevice for reading + usleep(1); // this keeps the CPU load low + } + for (; active;) { + if (Buffer.Read() < 0 || Buffer.Write() < 0) + break; + usleep(1); // this keeps the CPU load low + } + } + dsyslog(LOG_INFO, "data transfer thread stopped (pid=%d)", getpid()); + LOCK_THREAD; + active = true; +} + // --- cDvbApi --------------------------------------------------------------- int cDvbApi::NumDvbApis = 0; @@ -1091,6 +1150,10 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) pidRecord = pidReplay = 0; fromRecord = toRecord = -1; fromReplay = toReplay = -1; + ca = 0; + priority = -1; + transferBuffer = NULL; + transferringFromDvbApi = NULL; videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK); if (videoDev >= 0) { siProcessor = new cSIProcessor(VbiFileName); @@ -1130,6 +1193,7 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) #endif lastProgress = lastTotal = -1; replayTitle = NULL; + currentChannel = 1; } cDvbApi::~cDvbApi() @@ -1139,7 +1203,9 @@ cDvbApi::~cDvbApi() Close(); Stop(); StopRecord(); + StopTransfer(); OvlO(false); //Overlay off! + //XXX the following call sometimes causes a segfault - driver problem? close(videoDev); } #if defined(DEBUG_OSD) || defined(REMOTE_KBD) @@ -1160,22 +1226,25 @@ bool cDvbApi::SetPrimaryDvbApi(int n) return false; } -cDvbApi *cDvbApi::GetDvbApi(int Ca) +cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) { cDvbApi *d = NULL; - Ca--; + int index = Ca - 1; for (int i = MAXDVBAPI; --i >= 0; ) { - if (dvbApi[i] && !dvbApi[i]->Recording()) { - if (i == Ca) - return dvbApi[i]; - if (Ca < 0) { + if (dvbApi[i]) { + if (i == index) { // means we need exactly _this_ device d = dvbApi[i]; - if (d != PrimaryDvbApi) + break; + } + else if (Ca == 0) { // means any device would be acceptable + if (!d || !dvbApi[i]->Recording() || (d->Recording() && d->Priority() > dvbApi[i]->Priority())) + d = dvbApi[i]; + if (d && d != PrimaryDvbApi && !d->Recording()) // avoids the PrimaryDvbApi if possible break; } } } - return d; + return (d && (!d->Recording() || d->Priority() < Priority || (!d->Ca() && Ca))) ? d : NULL; } int cDvbApi::Index(void) @@ -1616,6 +1685,24 @@ int cDvbApi::Width(unsigned char c) #endif } +int cDvbApi::WidthInCells(const char *s) +{ +#ifdef DEBUG_OSD + return strlen(s); +#else + return (osd->Width(s) + charWidth - 1) / charWidth; +#endif +} + +eDvbFont cDvbApi::SetFont(eDvbFont Font) +{ +#ifdef DEBUG_OSD + return Font; +#else + return osd->SetFont(Font); +#endif +} + void cDvbApi::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg) { if (x < 0) x = cols + x; @@ -1689,9 +1776,15 @@ bool cDvbApi::ShowProgress(bool Initial) return false; } -bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr) +bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr) { if (videoDev >= 0) { + StopTransfer(); + if (transferringFromDvbApi) { + transferringFromDvbApi->StopTransfer(); + transferringFromDvbApi = NULL; + } + SetReplayMode(VID_PLAY_RESET); struct frontend front; ioctl(videoDev, VIDIOCGFRONTEND, &front); unsigned int freq = FrequencyMHz; @@ -1712,8 +1805,20 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr front.AFC = 1; ioctl(videoDev, VIDIOCSFRONTEND, &front); if (front.sync & 0x1F == 0x1F) { - if (siProcessor) + if (this == PrimaryDvbApi && siProcessor) siProcessor->SetCurrentServiceID(Pnr); + currentChannel = ChannelNumber; + // If this DVB card can't receive this channel, let's see if we can + // use the card that actually can receive it and transfer data from there: + if (Ca && Ca != Index() + 1) { + cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); + if (CaDvbApi) { + if (!CaDvbApi->Recording()) { + if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Ca, Pnr)) + transferringFromDvbApi = CaDvbApi->StartTransfer(videoDev); + } + } + } return true; } esyslog(LOG_ERR, "ERROR: channel not sync'ed (front.sync=%X)!", front.sync); @@ -1721,6 +1826,27 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr return false; } +bool cDvbApi::Transferring(void) +{ + return transferBuffer; +} + +cDvbApi *cDvbApi::StartTransfer(int TransferToVideoDev) +{ + StopTransfer(); + transferBuffer = new cTransferBuffer(videoDev, TransferToVideoDev); + return this; +} + +void cDvbApi::StopTransfer(void) +{ + if (transferBuffer) { + delete transferBuffer; + transferBuffer = NULL; + SetReplayMode(VID_PLAY_RESET); + } +} + bool cDvbApi::Recording(void) { if (pidRecord && !CheckProcess(pidRecord)) @@ -1735,7 +1861,7 @@ bool cDvbApi::Replaying(void) return pidReplay; } -bool cDvbApi::StartRecord(const char *FileName) +bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) { if (Recording()) { esyslog(LOG_ERR, "ERROR: StartRecord() called while recording - ignored!"); @@ -1743,6 +1869,8 @@ bool cDvbApi::StartRecord(const char *FileName) } if (videoDev >= 0) { + StopTransfer(); + Stop(); // TODO: remove this if the driver is able to do record and replay at the same time // Check FileName: @@ -1832,6 +1960,9 @@ bool cDvbApi::StartRecord(const char *FileName) fromRecord = fromRecordPipe[0]; toRecord = toRecordPipe[1]; + + ca = Ca; + priority = Priority; return true; } return false; @@ -1846,6 +1977,8 @@ void cDvbApi::StopRecord(void) toRecord = fromRecord = -1; KillProcess(pidRecord); pidRecord = 0; + ca = 0; + priority = -1; SetReplayMode(VID_PLAY_RESET); //XXX } } @@ -1865,6 +1998,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) esyslog(LOG_ERR, "ERROR: StartReplay() called while recording - ignored!"); return false; } + StopTransfer(); Stop(); if (videoDev >= 0) { @@ -2086,3 +2220,55 @@ bool cDvbApi::GetIndex(int *Current, int *Total) return false; } +// --- cEITScanner ----------------------------------------------------------- + +cEITScanner::cEITScanner(void) +{ + lastScan = lastActivity = time(NULL); + currentChannel = 0; + lastChannel = 1; +} + +void cEITScanner::Activity(void) +{ + if (currentChannel) { + Channels.SwitchTo(currentChannel); + currentChannel = 0; + } + lastActivity = time(NULL); +} + +void cEITScanner::Process(void) +{ + if (Channels.MaxNumber() > 1) { + time_t now = time(NULL); + if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) { + for (int i = 0; i < cDvbApi::NumDvbApis; i++) { + cDvbApi *DvbApi = cDvbApi::GetDvbApi(i, 0); + if (DvbApi) { + if (DvbApi != cDvbApi::PrimaryDvbApi || (cDvbApi::NumDvbApis == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) { + if (!(DvbApi->Recording() || DvbApi->Replaying() || DvbApi->Transferring())) { + int oldCh = lastChannel; + int ch = oldCh + 1; + while (ch != oldCh) { + if (ch > Channels.MaxNumber()) + ch = 1; + cChannel *Channel = Channels.GetByNumber(ch); + if (Channel && Channel->pnr) { + if (DvbApi == cDvbApi::PrimaryDvbApi && !currentChannel) + currentChannel = DvbApi->Channel(); + Channel->Switch(DvbApi, false); + lastChannel = ch; + break; + } + ch++; + } + } + } + } + } + lastScan = time(NULL); + } + } +} + diff --git a/dvbapi.h b/dvbapi.h index 16a2b7a71..f6640ff5d 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.20 2000/11/01 09:18:50 kls Exp $ + * $Id: dvbapi.h 1.26 2000/11/19 14:09:41 kls Exp $ */ #ifndef __DVBAPI_H @@ -42,10 +42,11 @@ class cResumeFile { bool Save(int Index); }; +class cTransferBuffer; + class cDvbApi { private: int videoDev; - cSIProcessor *siProcessor; cDvbApi(const char *VideoFileName, const char *VbiFileName); public: ~cDvbApi(); @@ -59,11 +60,15 @@ class cDvbApi { static bool SetPrimaryDvbApi(int n); // Sets the primary DVB device to 'n' (which must be in the range // 1...NumDvbApis) and returns true if this was possible. - static cDvbApi *GetDvbApi(int Ca = 0); + static cDvbApi *GetDvbApi(int Ca, int Priority); // Selects a free DVB device, starting with the highest device number // (but avoiding, if possible, the PrimaryDvbApi). - // If Ca is not 0, the device with the given number will be returned - // if it is not currently recording. + // If Ca is not 0, the device with the given number will be returned. + // If all DVB devices are currently recording, the one recording the + // lowest priority timer (if any) that is lower than the given Priority + // will be returned. + // The caller must check whether the returned DVB device is actually + // recording and stop recording if necessary. int Index(void); // Returns the index of this DvbApi. static bool Init(void); @@ -75,6 +80,9 @@ class cDvbApi { // EIT facilities +private: + cSIProcessor *siProcessor; +public: const cSchedules *Schedules(cThreadLock *ThreadLock) const; // Caller must provide a cThreadLock which has to survive the entire // time the returned cSchedules is accessed. Once the cSchedules is no @@ -124,6 +132,8 @@ class cDvbApi { void ClrEol(int x, int y, eDvbColor color = clrBackground); int CellWidth(void); int Width(unsigned char c); + int WidthInCells(const char *s); + eDvbFont SetFont(eDvbFont Font); void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground); void Flush(void); @@ -137,7 +147,26 @@ class cDvbApi { // Channel facilities - bool SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr); +private: + int currentChannel; +public: + bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr); + static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } + int Channel(void) { return currentChannel; } + + // Transfer facilities + +private: + cTransferBuffer *transferBuffer; + cDvbApi *transferringFromDvbApi; +public: + bool Transferring(void); + // Returns true if we are currently transferring video data. +private: + cDvbApi *StartTransfer(int TransferToVideoDev); + // Starts transferring video data from this DVB device to TransferToVideoDev. + void StopTransfer(void); + // Stops transferring video data (in case a transfer is currently active). // Record/Replay facilities @@ -153,14 +182,23 @@ class cDvbApi { pid_t pidRecord, pidReplay; int fromRecord, toRecord; int fromReplay, toReplay; + int ca; + int priority; void SetReplayMode(int Mode); +protected: + int Ca(void) { return ca; } + // Returns the ca of the current recording session (0..MAXDVBAPI). + int Priority(void) { return priority; } + // Returns the priority of the current recording session (0..99), + // or -1 if no recording is currently active. 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. + bool StartRecord(const char *FileName, int Ca, int Priority); + // Starts recording the current channel into the given file, with + // the given ca and priority. // 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 @@ -194,4 +232,18 @@ class cDvbApi { bool GetIndex(int *Current, int *Total = NULL); }; +class cEITScanner { +private: + enum { ActivityTimeout = 60, + ScanTimeout = 20 + }; + time_t lastScan, lastActivity; + int currentChannel, lastChannel; +public: + cEITScanner(void); + bool Active(void) { return currentChannel; } + void Activity(void); + void Process(void); + }; + #endif //__DVBAPI_H diff --git a/dvbosd.c b/dvbosd.c index c0150e269..457175d8b 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.4 2000/11/01 09:13:32 kls Exp $ + * $Id: dvbosd.c 1.6 2000/11/18 15:36:51 kls Exp $ */ #include "dvbosd.h" @@ -21,6 +21,7 @@ cBitmap::cBitmap(int Width, int Height) width = Width; height = Height; bitmap = NULL; + fontType = fontOsd; font = NULL; if (width > 0 && height > 0) { bitmap = new char[width * height]; @@ -42,10 +43,15 @@ cBitmap::~cBitmap() delete bitmap; } -void cBitmap::SetFont(eDvbFont Font) +eDvbFont cBitmap::SetFont(eDvbFont Font) { - delete font; - font = new cFont(Font); + eDvbFont oldFont = fontType; + if (fontType != Font || !font) { + delete font; + font = new cFont(Font); + fontType = Font; + } + return oldFont; } bool cBitmap::Dirty(void) @@ -81,6 +87,11 @@ int cBitmap::Width(unsigned char c) return font ? font->Width(c) : -1; } +int cBitmap::Width(const char *s) +{ + return font ? font->Width(s) : -1; +} + void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) { if (bitmap) { diff --git a/dvbosd.h b/dvbosd.h index 149dc6cb1..e2a424a8d 100644 --- a/dvbosd.h +++ b/dvbosd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.h 1.2 2000/11/01 09:13:44 kls Exp $ + * $Id: dvbosd.h 1.4 2000/11/18 15:25:25 kls Exp $ */ #ifndef __DVBOSD_H @@ -45,6 +45,7 @@ enum eDvbColor { class cBitmap { private: cFont *font; + eDvbFont fontType; protected: int width, height; char *bitmap; @@ -53,10 +54,11 @@ class cBitmap { public: cBitmap(int Width, int Height); virtual ~cBitmap(); - void SetFont(eDvbFont Font); + eDvbFont SetFont(eDvbFont Font); bool Dirty(void); void SetPixel(int x, int y, eDvbColor Color); int Width(unsigned char c); + int Width(const char *s); void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); void Fill(int x1, int y1, int x2, int y2, eDvbColor Color); void Clear(void); diff --git a/eit.c b/eit.c index 65856e6c3..79855282f 100644 --- a/eit.c +++ b/eit.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.7 2000/11/02 17:06:19 kls Exp $ + * $Id: eit.c 1.9 2000/11/18 13:42:28 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -753,7 +752,7 @@ schedule information */ cEIT::cEIT(void * buf, int length, cSchedules *Schedules) { - buflen = min((unsigned int)length, sizeof(buffer)); + buflen = length < int(sizeof(buffer)) ? length : sizeof(buffer); memset(buffer, 0, sizeof(buffer)); memcpy(buffer, buf, buflen); tid = buffer[0]; @@ -1057,15 +1056,20 @@ bool cEIT::WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, #define MAX_FILTERS 20 +int cSIProcessor::numSIProcessors = 0; +cSchedules *cSIProcessor::schedules = NULL; +cMutex cSIProcessor::schedulesMutex; + /** */ cSIProcessor::cSIProcessor(const char *FileName) { + masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master' useTStime = false; filters = NULL; - schedules = NULL; if ((fsvbi = open(FileName, O_RDONLY)) >= 0) { - schedules = new cSchedules; + if (!numSIProcessors++) // the first one creates it + schedules = new cSchedules; filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER)); } else @@ -1079,7 +1083,8 @@ cSIProcessor::~cSIProcessor() Stop(); ShutDownFilters(); delete filters; - delete schedules; + if (!--numSIProcessors) // the last one deletes it + delete schedules; close(fsvbi); } } @@ -1094,7 +1099,7 @@ void cSIProcessor::Action() return; } - dsyslog(LOG_INFO, "EIT processing thread started (pid=%d)", getpid()); + dsyslog(LOG_INFO, "EIT processing thread started (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : ""); unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) unsigned int seclen; @@ -1104,15 +1109,20 @@ void cSIProcessor::Action() while(true) { - time_t now = time(NULL); - struct tm *ptm = localtime(&now); - if (now - lastCleanup > 3600 && ptm->tm_hour == 5) + if (masterSIProcessor) { - LOCK_THREAD; + time_t now = time(NULL); + struct tm *ptm = localtime(&now); + if (now - lastCleanup > 3600 && ptm->tm_hour == 5) + { + LOCK_THREAD; - isyslog(LOG_INFO, "Now cleaning up things"); - schedules->Cleanup(); - lastCleanup = now; + schedulesMutex.Lock(); + isyslog(LOG_INFO, "cleaning up schedules data"); + schedules->Cleanup(); + schedulesMutex.Unlock(); + lastCleanup = now; + } } /* wait data become ready from the bitfilter */ @@ -1151,8 +1161,10 @@ void cSIProcessor::Action() { LOCK_THREAD; + schedulesMutex.Lock(); cEIT ceit(buf, seclen, schedules); ceit.ProcessEIT(); + schedulesMutex.Unlock(); } else dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); diff --git a/eit.h b/eit.h index fec498baf..d5c4ebdcf 100644 --- a/eit.h +++ b/eit.h @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.2 2000/10/29 10:21:56 kls Exp $ + * $Id: eit.h 1.3 2000/11/17 16:14:27 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -120,7 +120,10 @@ typedef struct sip_filter { class cSIProcessor : public cThread { private: - cSchedules *schedules; + static int numSIProcessors; + static cSchedules *schedules; + static cMutex schedulesMutex; + bool masterSIProcessor; bool useTStime; SIP_FILTER *filters; int fsvbi; diff --git a/font.c b/font.c index 3ef40835b..22c92be00 100644 --- a/font.c +++ b/font.c @@ -4,21 +4,27 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: font.c 1.1 2000/10/01 15:01:49 kls Exp $ + * $Id: font.c 1.2 2000/11/18 15:16:08 kls Exp $ */ #include "font.h" #include "tools.h" +#include "fontfix.c" #include "fontosd.c" -cFont::cFont(eDvbFont Font)//XXX +cFont::cFont(eDvbFont Font) { + +#define FONTINDEX(Name)\ + case font##Name: for (int i = 0; i < NUMCHARS; i++)\ + data[i] = (tCharData *)&Font##Name[i < 32 ? 0 : i - 32];\ + break; + switch (Font) { default: - case fontOsd: for (int i = 0; i < NUMCHARS; i++) - data[i] = (tCharData *)&FontOsd[i < 32 ? 0 : i - 32]; - break; + FONTINDEX(Osd); + FONTINDEX(Fix); // TODO others... } } diff --git a/font.h b/font.h index f31c6b599..414eaa8b7 100644 --- a/font.h +++ b/font.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: font.h 1.1 2000/10/01 15:00:35 kls Exp $ + * $Id: font.h 1.2 2000/11/18 14:51:45 kls Exp $ */ #ifndef __FONT_H @@ -12,6 +12,7 @@ enum eDvbFont { fontOsd, + fontFix, /* TODO as soon as we have the font files... fontTtxSmall, fontTtxLarge, diff --git a/fontfix.c b/fontfix.c new file mode 100644 index 000000000..67eb1621f --- /dev/null +++ b/fontfix.c @@ -0,0 +1,6498 @@ +cFont::tPixelData FontFix[][28] = { + { // 32 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 33 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 34 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001DC0, // ...***.***..... + 0x00001DC0, // ...***.***..... + 0x00001DC0, // ...***.***..... + 0x00001DC0, // ...***.***..... + 0x00000880, // ....*...*...... + 0x00000880, // ....*...*...... + 0x00000880, // ....*...*...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 35 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000660, // .....**..**.... + 0x00000660, // .....**..**.... + 0x00000660, // .....**..**.... + 0x00000660, // .....**..**.... + 0x00000660, // .....**..**.... + 0x00000660, // .....**..**.... + 0x00003FF8, // ..***********.. + 0x00003FF8, // ..***********.. + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00007FF0, // .***********... + 0x00007FF0, // .***********... + 0x00001980, // ...**..**...... + 0x00001980, // ...**..**...... + 0x00001980, // ...**..**...... + 0x00001980, // ...**..**...... + 0x00001980, // ...**..**...... + 0x00001980, // ...**..**...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 36 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000F60, // ....****.**.... + 0x00001FE0, // ...********.... + 0x000030E0, // ..**....***.... + 0x00003060, // ..**.....**.... + 0x00003000, // ..**........... + 0x00003800, // ..***.......... + 0x00001F80, // ...******...... + 0x000007E0, // .....******.... + 0x00000070, // .........***... + 0x00000030, // ..........**... + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00003FE0, // ..*********.... + 0x000037C0, // ..**.*****..... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 37 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000F00, // ....****....... + 0x00001980, // ...**..**...... + 0x000030C0, // ..**....**..... + 0x000030C0, // ..**....**..... + 0x00001980, // ...**..**...... + 0x00000F00, // ....****....... + 0x00000070, // .........***... + 0x000003C0, // ......****..... + 0x00000E00, // ....***........ + 0x000039E0, // ..***..****.... + 0x00000330, // ......**..**... + 0x00000618, // .....**....**.. + 0x00000618, // .....**....**.. + 0x00000330, // ......**..**... + 0x000001E0, // .......****.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 38 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00000FC0, // ....******..... + 0x000018C0, // ...**...**..... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00000C00, // ....**......... + 0x00000E00, // ....***........ + 0x00001F30, // ...*****..**... + 0x00001BF0, // ...**.******... + 0x000031E0, // ..**...****.... + 0x000030C0, // ..**....**..... + 0x000031E0, // ..**...****.... + 0x00003FF8, // ..***********.. + 0x00001F38, // ...*****..***.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 39 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000600, // .....**........ + 0x00000C00, // ....**......... + 0x00000800, // ....*.......... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 40 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000060, // .........**.... + 0x000000E0, // ........***.... + 0x000000C0, // ........**..... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x000000C0, // ........**..... + 0x000000E0, // ........***.... + 0x00000060, // .........**.... + 0x00000000, // ............... + }, + { // 41 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001800, // ...**.......... + 0x00001C00, // ...***......... + 0x00000C00, // ....**......... + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000C00, // ....**......... + 0x00001C00, // ...***......... + 0x00001800, // ...**.......... + 0x00000000, // ............... + }, + { // 42 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003330, // ..**..**..**... + 0x00003FF0, // ..**********... + 0x00000FC0, // ....******..... + 0x00000300, // ......**....... + 0x00000FC0, // ....******..... + 0x00000CC0, // ....**..**..... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 43 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 44 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000600, // .....**........ + 0x00000C00, // ....**......... + 0x00000800, // ....*.......... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 45 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 46 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 47 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000018, // ...........**.. + 0x00000018, // ...........**.. + 0x00000030, // ..........**... + 0x00000030, // ..........**... + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 48 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00001FE0, // ...********.... + 0x00001860, // ...**....**.... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00001860, // ...**....**.... + 0x00001FE0, // ...********.... + 0x00000780, // .....****...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 49 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00003F00, // ..******....... + 0x00003F00, // ..******....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 50 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00001FE0, // ...********.... + 0x00003870, // ..***....***... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00000030, // ..........**... + 0x00000070, // .........***... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000E00, // ....***........ + 0x00001C00, // ...***......... + 0x00003800, // ..***.......... + 0x00007FF0, // .***********... + 0x00007FF0, // .***********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 51 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00001FE0, // ...********.... + 0x00003870, // ..***....***... + 0x00003030, // ..**......**... + 0x00000030, // ..........**... + 0x00000070, // .........***... + 0x000000E0, // ........***.... + 0x000007C0, // .....*****..... + 0x000007E0, // .....******.... + 0x00000070, // .........***... + 0x00000030, // ..........**... + 0x00000030, // ..........**... + 0x00006030, // .**.......**... + 0x00007070, // .***.....***... + 0x00003FE0, // ..*********.... + 0x00001FC0, // ...*******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 52 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000001C0, // .......***..... + 0x000003C0, // ......****..... + 0x000007C0, // .....*****..... + 0x000006C0, // .....**.**..... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000030C0, // ..**....**..... + 0x000030C0, // ..**....**..... + 0x00007FF0, // .***********... + 0x00007FF0, // .***********... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000007F0, // .....*******... + 0x000007F0, // .....*******... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 53 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001FF0, // ...*********... + 0x00001FF0, // ...*********... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001BC0, // ...**.****..... + 0x00001FF0, // ...*********... + 0x00001C70, // ...***...***... + 0x00000038, // ..........***.. + 0x00000018, // ...........**.. + 0x00000018, // ...........**.. + 0x00000018, // ...........**.. + 0x00003038, // ..**......***.. + 0x00003870, // ..***....***... + 0x00001FF0, // ...*********... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 54 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000001F0, // .......*****... + 0x000007F0, // .....*******... + 0x00000F00, // ....****....... + 0x00001C00, // ...***......... + 0x00001800, // ...**.......... + 0x00003800, // ..***.......... + 0x000037C0, // ..**.*****..... + 0x00003FE0, // ..*********.... + 0x00003870, // ..***....***... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003830, // ..***.....**... + 0x00001C70, // ...***...***... + 0x00001FE0, // ...********.... + 0x000007C0, // .....*****..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 55 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00003030, // ..**......**... + 0x00000030, // ..........**... + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 56 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00001FE0, // ...********.... + 0x00003870, // ..***....***... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00001860, // ...**....**.... + 0x00000FC0, // ....******..... + 0x00001FE0, // ...********.... + 0x00003870, // ..***....***... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001FE0, // ...********.... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 57 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000003C0, // ......****..... + 0x00000FF0, // ....********... + 0x00000C30, // ....**....**... + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x00001838, // ...**.....***.. + 0x00001C78, // ...***...****.. + 0x00000FD8, // ....******.**.. + 0x00000798, // .....****..**.. + 0x00000018, // ...........**.. + 0x00000030, // ..........**... + 0x00000070, // .........***... + 0x00001FE0, // ...********.... + 0x00001F80, // ...******...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 58 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 59 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000E00, // ....***........ + 0x00000C00, // ....**......... + 0x00001800, // ...**.......... + 0x00001000, // ...*........... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 60 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000001C, // ...........***. + 0x00000078, // .........****.. + 0x000001E0, // .......****.... + 0x00000780, // .....****...... + 0x00001E00, // ...****........ + 0x00007800, // .****.......... + 0x00007800, // .****.......... + 0x00001E00, // ...****........ + 0x00000780, // .....****...... + 0x000001E0, // .......****.... + 0x00000078, // .........****.. + 0x0000001C, // ...........***. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 61 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 62 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007000, // .***........... + 0x00003C00, // ..****......... + 0x00000F00, // ....****....... + 0x000003C0, // ......****..... + 0x000000F0, // ........****... + 0x0000003C, // ..........****. + 0x0000003C, // ..........****. + 0x000000F0, // ........****... + 0x000003C0, // ......****..... + 0x00000F00, // ....****....... + 0x00003C00, // ..****......... + 0x00007000, // .***........... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 63 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00001FE0, // ...********.... + 0x00001870, // ...**....***... + 0x00001830, // ...**.....**... + 0x00001830, // ...**.....**... + 0x00000030, // ..........**... + 0x00000070, // .........***... + 0x000001E0, // .......****.... + 0x00000380, // ......***...... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 64 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00001FC0, // ...*******..... + 0x000018C0, // ...**...**..... + 0x00003060, // ..**.....**.... + 0x00003060, // ..**.....**.... + 0x000031E0, // ..**...****.... + 0x000033E0, // ..**..*****.... + 0x00003760, // ..**.***.**.... + 0x00003660, // ..**.**..**.... + 0x00003660, // ..**.**..**.... + 0x00003760, // ..**.***.**.... + 0x000033F0, // ..**..******... + 0x000031F0, // ..**...*****... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00001860, // ...**....**.... + 0x00001FE0, // ...********.... + 0x00000780, // .....****...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 65 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003F00, // ..******....... + 0x00003F00, // ..******....... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 66 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FE0, // .**********.... + 0x00007FF0, // .***********... + 0x00001838, // ...**.....***.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x00001838, // ...**.....***.. + 0x00001FF0, // ...*********... + 0x00001FF8, // ...**********.. + 0x0000181C, // ...**......***. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000181C, // ...**......***. + 0x00007FF8, // .************.. + 0x00007FF0, // .***********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 67 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007D8, // .....*****.**.. + 0x00001FF8, // ...**********.. + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x00007018, // .***.......**.. + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00007000, // .***........... + 0x00003000, // ..**........... + 0x00003818, // ..***......**.. + 0x00001FF8, // ...**********.. + 0x000007E0, // .....******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 68 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FFC0, // **********..... + 0x0000FFF0, // ************... + 0x00003038, // ..**......***.. + 0x00003018, // ..**.......**.. + 0x0000301C, // ..**.......***. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x00003018, // ..**.......**.. + 0x00003038, // ..**......***.. + 0x0000FFF0, // ************... + 0x0000FFE0, // ***********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 69 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x000018D8, // ...**...**.**.. + 0x000018C0, // ...**...**..... + 0x00001FC0, // ...*******..... + 0x00001FC0, // ...*******..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x00007FFC, // .*************. + 0x00007FFC, // .*************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 70 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FFC, // .*************. + 0x00007FFC, // .*************. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x000018CC, // ...**...**..**. + 0x000018C0, // ...**...**..... + 0x00001FC0, // ...*******..... + 0x00001FC0, // ...*******..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00007F80, // .********...... + 0x00007F80, // .********...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 71 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007EC, // .....******.**. + 0x00001FFC, // ...***********. + 0x0000381C, // ..***......***. + 0x0000300C, // ..**........**. + 0x0000700C, // .***........**. + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x000060FC, // .**.....******. + 0x000060FC, // .**.....******. + 0x0000700C, // .***........**. + 0x0000300C, // ..**........**. + 0x0000381C, // ..***......***. + 0x00001FF8, // ...**********.. + 0x000007E0, // .....******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 72 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 73 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 74 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FFC, // ....**********. + 0x00000FFC, // ....**********. + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x00006060, // .**......**.... + 0x00006060, // .**......**.... + 0x00006060, // .**......**.... + 0x000070E0, // .***....***.... + 0x00003FC0, // ..********..... + 0x00001F80, // ...******...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 75 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FCF8, // ******..*****.. + 0x0000FCF8, // ******..*****.. + 0x000030E0, // ..**....***.... + 0x000031C0, // ..**...***..... + 0x00003380, // ..**..***...... + 0x00003700, // ..**.***....... + 0x00003E00, // ..*****........ + 0x00003F00, // ..******....... + 0x00003B80, // ..***.***...... + 0x000031C0, // ..**...***..... + 0x000030E0, // ..**....***.... + 0x00003060, // ..**.....**.... + 0x00003070, // ..**.....***... + 0x0000FC3C, // ******....****. + 0x0000FC3C, // ******....****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 76 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007F80, // .********...... + 0x00007F80, // .********...... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C18, // ....**.....**.. + 0x00000C18, // ....**.....**.. + 0x00000C18, // ....**.....**.. + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 77 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F03C, // ****......****. + 0x0000F03C, // ****......****. + 0x00007878, // .****....****.. + 0x00007878, // .****....****.. + 0x00006CD8, // .**.**..**.**.. + 0x00006CD8, // .**.**..**.**.. + 0x00006CD8, // .**.**..**.**.. + 0x00006798, // .**..****..**.. + 0x00006318, // .**...**...**.. + 0x00006318, // .**...**...**.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x0000F87C, // *****....*****. + 0x0000F87C, // *****....*****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 78 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000787C, // .****....*****. + 0x0000787C, // .****....*****. + 0x00003C18, // ..****.....**.. + 0x00003C18, // ..****.....**.. + 0x00003618, // ..**.**....**.. + 0x00003618, // ..**.**....**.. + 0x00003318, // ..**..**...**.. + 0x00003318, // ..**..**...**.. + 0x00003198, // ..**...**..**.. + 0x00003198, // ..**...**..**.. + 0x000030D8, // ..**....**.**.. + 0x000030D8, // ..**....**.**.. + 0x00003078, // ..**.....****.. + 0x00007C78, // .*****...****.. + 0x00007C38, // .*****....***.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 79 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00001FF0, // ...*********... + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000701C, // .***.......***. + 0x00003018, // ..**.......**.. + 0x00003838, // ..***.....***.. + 0x00001FF0, // ...*********... + 0x000007C0, // .....*****..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 80 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FE0, // .**********.... + 0x00007FF8, // .************.. + 0x0000181C, // ...**......***. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000181C, // ...**......***. + 0x00001FF8, // ...**********.. + 0x00001FE0, // ...********.... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00007F80, // .********...... + 0x00007F80, // .********...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 81 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00001FF0, // ...*********... + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000701C, // .***.......***. + 0x00003018, // ..**.......**.. + 0x00003838, // ..***.....***.. + 0x00001FF0, // ...*********... + 0x000007C0, // .....*****..... + 0x0000070C, // .....***....**. + 0x00001FFC, // ...***********. + 0x00001CF0, // ...***..****... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 82 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FF80, // *********...... + 0x0000FFE0, // ***********.... + 0x00003070, // ..**.....***... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003070, // ..**.....***... + 0x00003FE0, // ..*********.... + 0x00003F80, // ..*******...... + 0x000031C0, // ..**...***..... + 0x000030E0, // ..**....***.... + 0x00003060, // ..**.....**.... + 0x00003070, // ..**.....***... + 0x0000FC3C, // ******....****. + 0x0000FC3C, // ******....****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 83 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FD8, // ....******.**.. + 0x00001FF8, // ...**********.. + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003800, // ..***.......... + 0x00001F00, // ...*****....... + 0x00000FE0, // ....*******.... + 0x000001F0, // .......*****... + 0x00000038, // ..........***.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00007038, // .***......***.. + 0x00007FF0, // .***********... + 0x00006FE0, // .**.*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 84 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00006318, // .**...**...**.. + 0x00006318, // .**...**...**.. + 0x00006318, // .**...**...**.. + 0x00006318, // .**...**...**.. + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00001FE0, // ...********.... + 0x00001FE0, // ...********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 85 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007C7C, // .*****...*****. + 0x00007C7C, // .*****...*****. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00001830, // ...**.....**... + 0x00001FF0, // ...*********... + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 86 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F87C, // *****....*****. + 0x0000F87C, // *****....*****. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 87 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F87C, // *****....*****. + 0x0000F87C, // *****....*****. + 0x00006018, // .**........**.. + 0x00006318, // .**...**...**.. + 0x00006318, // .**...**...**.. + 0x00006798, // .**..****..**.. + 0x00006798, // .**..****..**.. + 0x00006FD8, // .**.******.**.. + 0x00006CD8, // .**.**..**.**.. + 0x00006CD8, // .**.**..**.**.. + 0x00003CF0, // ..****..****... + 0x00003870, // ..***....***... + 0x00003870, // ..***....***... + 0x00003870, // ..***....***... + 0x00003870, // ..***....***... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 88 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00001CE0, // ...***..***.... + 0x00000FC0, // ....******..... + 0x00000780, // .....****...... + 0x00000300, // ......**....... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00001CE0, // ...***..***.... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 89 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00001860, // ...**....**.... + 0x00000CC0, // ....**..**..... + 0x00000FC0, // ....******..... + 0x00000780, // .....****...... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00001FE0, // ...********.... + 0x00001FE0, // ...********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 90 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FF8, // ..***********.. + 0x00003FF8, // ..***********.. + 0x00003038, // ..**......***.. + 0x00003070, // ..**.....***... + 0x000030E0, // ..**....***.... + 0x000000C0, // ........**..... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000600, // .....**........ + 0x00000E18, // ....***....**.. + 0x00001C18, // ...***.....**.. + 0x00003818, // ..***......**.. + 0x00003FF8, // ..***********.. + 0x00003FF8, // ..***********.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 91 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000003E0, // ......*****.... + 0x000003E0, // ......*****.... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x000003E0, // ......*****.... + 0x000003E0, // ......*****.... + 0x00000000, // ............... + }, + { // 92 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000180, // .......**...... + 0x00000180, // .......**...... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x00000060, // .........**.... + 0x00000060, // .........**.... + 0x00000030, // ..........**... + 0x00000030, // ..........**... + 0x00000018, // ...........**.. + 0x00000018, // ...........**.. + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 93 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001F00, // ...*****....... + 0x00001F00, // ...*****....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00001F00, // ...*****....... + 0x00001F00, // ...*****....... + 0x00000000, // ............... + }, + { // 94 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 95 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FFFE, // *************** + 0x0000FFFE, // *************** + 0x00000000, // ............... + }, + { // 96 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000380, // ......***...... + 0x00000180, // .......**...... + 0x000000C0, // ........**..... + 0x00000040, // .........*..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 97 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001F80, // ...******...... + 0x00003FC0, // ..********..... + 0x000030E0, // ..**....***.... + 0x00000060, // .........**.... + 0x00000FE0, // ....*******.... + 0x00003FE0, // ..*********.... + 0x00007060, // .***.....**.... + 0x00006060, // .**......**.... + 0x000060E0, // .**.....***.... + 0x00007FF8, // .************.. + 0x00003F78, // ..******.****.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 98 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007800, // .****.......... + 0x00007800, // .****.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001BE0, // ...**.*****.... + 0x00001FF8, // ...**********.. + 0x00001E38, // ...****...***.. + 0x00001C1C, // ...***.....***. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x00001C1C, // ...***.....***. + 0x00001E38, // ...****...***.. + 0x00007FF8, // .************.. + 0x00007BE0, // .****.*****.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 99 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FD8, // ....******.**.. + 0x00003FF8, // ..***********.. + 0x00003878, // ..***....****.. + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00007000, // .***........... + 0x00003838, // ..***.....***.. + 0x00003FF8, // ..***********.. + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 100 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000000F0, // ........****... + 0x000000F0, // ........****... + 0x00000030, // ..........**... + 0x00000030, // ..........**... + 0x00000030, // ..........**... + 0x00000FB0, // ....*****.**... + 0x00003FF0, // ..**********... + 0x000038F0, // ..***...****... + 0x00007070, // .***.....***... + 0x00006030, // .**.......**... + 0x00006030, // .**.......**... + 0x00006030, // .**.......**... + 0x00007070, // .***.....***... + 0x000038F0, // ..***...****... + 0x00003FFC, // ..************. + 0x00000FBC, // ....*****.****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 101 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00007000, // .***........... + 0x00003838, // ..***.....***.. + 0x00003FF8, // ..***********.. + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 102 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000001F8, // .......******.. + 0x000003F8, // ......*******.. + 0x00000700, // .....***....... + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 103 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FBC, // ....*****.****. + 0x00003FFC, // ..************. + 0x000038F0, // ..***...****... + 0x00007070, // .***.....***... + 0x00006030, // .**.......**... + 0x00006030, // .**.......**... + 0x00006030, // .**.......**... + 0x00007070, // .***.....***... + 0x000038F0, // ..***...****... + 0x00003FF0, // ..**********... + 0x00000FB0, // ....*****.**... + 0x00000030, // ..........**... + 0x00000030, // ..........**... + 0x00000070, // .........***... + 0x00001FE0, // ...********.... + 0x00001FC0, // ...*******..... + }, + { // 104 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F000, // ****........... + 0x0000F000, // ****........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x000037C0, // ..**.*****..... + 0x00003FE0, // ..*********.... + 0x00003C70, // ..****...***... + 0x00003830, // ..***.....**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 105 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001F00, // ...*****....... + 0x00001F00, // ...*****....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 106 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x00000380, // ......***...... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FC0, // ..********..... + 0x00003FC0, // ..********..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000000C0, // ........**..... + 0x000001C0, // .......***..... + 0x00003F80, // ..*******...... + 0x00003F00, // ..******....... + }, + { // 107 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007800, // .****.......... + 0x00007800, // .****.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x000018F0, // ...**...****... + 0x000018F0, // ...**...****... + 0x000019C0, // ...**..***..... + 0x00001B80, // ...**.***...... + 0x00001F00, // ...*****....... + 0x00001F00, // ...*****....... + 0x00001B80, // ...**.***...... + 0x000019C0, // ...**..***..... + 0x000018E0, // ...**...***.... + 0x000078FC, // .****...******. + 0x000078FC, // .****...******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 108 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001F00, // ...*****....... + 0x00001F00, // ...*****....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 109 + 15, 26, + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x0001DEF0, // ***.****.****... + 0x0001FFF8, // **************.. + 0x00007398, // ..***..***..**.. + 0x00006318, // ..**...**...**.. + 0x00006318, // ..**...**...**.. + 0x00006318, // ..**...**...**.. + 0x00006318, // ..**...**...**.. + 0x00006318, // ..**...**...**.. + 0x00006318, // ..**...**...**.. + 0x0001F3DE, // *****..****.**** + 0x0001F3DE, // *****..****.**** + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + 0x00000000, // ................ + }, + { // 110 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F3C0, // ****..****..... + 0x0000F7E0, // ****.******.... + 0x00003C70, // ..****...***... + 0x00003830, // ..***.....**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 111 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00003FF0, // ..**********... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 112 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F7C0, // ****.*****..... + 0x0000FFF0, // ************... + 0x00003C70, // ..****...***... + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003838, // ..***.....***.. + 0x00003C70, // ..****...***... + 0x00003FF0, // ..**********... + 0x000037C0, // ..**.*****..... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x0000FE00, // *******........ + 0x0000FE00, // *******........ + }, + { // 113 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FBC, // ....*****.****. + 0x00003FFC, // ..************. + 0x000038F0, // ..***...****... + 0x00007070, // .***.....***... + 0x00006030, // .**.......**... + 0x00006030, // .**.......**... + 0x00006030, // .**.......**... + 0x00007070, // .***.....***... + 0x000038F0, // ..***...****... + 0x00003FF0, // ..**********... + 0x00000FB0, // ....*****.**... + 0x00000030, // ..........**... + 0x00000030, // ..........**... + 0x00000030, // ..........**... + 0x000001FC, // .......*******. + 0x000001FC, // .......*******. + }, + { // 114 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003CF0, // ..****..****... + 0x00003FF8, // ..***********.. + 0x00000F18, // ....****...**.. + 0x00000E00, // ....***........ + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00007FE0, // .**********.... + 0x00007FE0, // .**********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 115 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FB0, // ....*****.**... + 0x00001FF0, // ...*********... + 0x00003870, // ..***....***... + 0x00003830, // ..***.....**... + 0x00001F00, // ...*****....... + 0x000007C0, // .....*****..... + 0x000001F0, // .......*****... + 0x00003038, // ..**......***.. + 0x00003838, // ..***.....***.. + 0x00003FF0, // ..**********... + 0x000037E0, // ..**.******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 116 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00007FE0, // .**********.... + 0x00007FE0, // .**********.... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001C70, // ...***...***... + 0x00000FF0, // ....********... + 0x000007C0, // .....*****..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 117 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F0F0, // ****....****... + 0x0000F0F0, // ****....****... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001FFC, // ...***********. + 0x00000FBC, // ....*****.****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 118 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 119 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F87C, // *****....*****. + 0x0000F87C, // *****....*****. + 0x00006318, // .**...**...**.. + 0x00006318, // .**...**...**.. + 0x00003330, // ..**..**..**... + 0x000037B0, // ..**.****.**... + 0x000037B0, // ..**.****.**... + 0x00003CF0, // ..****..****... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 120 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007CF8, // .*****..*****.. + 0x00007CF8, // .*****..*****.. + 0x00001860, // ...**....**.... + 0x00000CC0, // ....**..**..... + 0x00000780, // .....****...... + 0x00000300, // ......**....... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00001860, // ...**....**.... + 0x00007CF8, // .*****..*****.. + 0x00007CF8, // .*****..*****.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 121 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007CF8, // .*****..*****.. + 0x00007CF8, // .*****..*****.. + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001860, // ...**....**.... + 0x00001CE0, // ...***..***.... + 0x00000CC0, // ....**..**..... + 0x00000DC0, // ....**.***..... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000300, // ......**....... + 0x00000700, // .....***....... + 0x00000600, // .....**........ + 0x00000E00, // ....***........ + 0x00007F00, // .*******....... + 0x00007F00, // .*******....... + }, + { // 122 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x000030E0, // ..**....***.... + 0x000031C0, // ..**...***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000E00, // ....***........ + 0x00001C30, // ...***....**... + 0x00003830, // ..***.....**... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 123 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000000E0, // ........***.... + 0x00000180, // .......**...... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000700, // .....***....... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000180, // .......**...... + 0x000000E0, // ........***.... + 0x00000000, // ............... + }, + { // 124 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 125 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001C00, // ...***......... + 0x00000600, // .....**........ + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000380, // ......***...... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000600, // .....**........ + 0x00001C00, // ...***......... + 0x00000000, // ............... + }, + { // 126 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001E18, // ...****....**.. + 0x00003F38, // ..******..***.. + 0x000073F0, // .***..******... + 0x000061E0, // .**....****.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 127 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 128 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 129 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 130 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 131 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 132 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 133 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 134 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 135 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 136 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 137 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 138 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 139 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 140 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 141 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 142 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 143 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 144 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 145 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 146 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 147 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 148 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 149 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 150 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 151 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 152 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 153 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 154 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 155 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 156 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 157 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 158 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 159 + 0, 26, + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + 0x00000000, // + }, + { // 160 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 161 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000000, // ............... + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000600, // .....**........ + 0x00000F00, // ....****....... + 0x00000F00, // ....****....... + 0x00000F00, // ....****....... + 0x00000F00, // ....****....... + 0x00000F00, // ....****....... + 0x00000F00, // ....****....... + 0x00000600, // .....**........ + }, + { // 162 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000F60, // ....****.**.... + 0x00001FE0, // ...********.... + 0x000038E0, // ..***...***.... + 0x00003060, // ..**.....**.... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003860, // ..***....**.... + 0x00001FE0, // ...********.... + 0x00000FC0, // ....******..... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 163 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00000FE0, // ....*******.... + 0x00001C60, // ...***...**.... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00007F80, // .********...... + 0x00007F80, // .********...... + 0x00000C00, // ....**......... + 0x00000C00, // ....**......... + 0x00001C00, // ...***......... + 0x00003818, // ..***......**.. + 0x00007FF8, // .************.. + 0x00007FF0, // .***********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 164 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003030, // ..**......**... + 0x00003FF0, // ..**********... + 0x00001FE0, // ...********.... + 0x00003870, // ..***....***... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001FE0, // ...********.... + 0x00003FF0, // ..**********... + 0x00003030, // ..**......**... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 165 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007CF8, // .*****..*****.. + 0x00007CF8, // .*****..*****.. + 0x00003870, // ..***....***... + 0x00001860, // ...**....**.... + 0x00001CE0, // ...***..***.... + 0x00000CC0, // ....**..**..... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00001FE0, // ...********.... + 0x00000300, // ......**....... + 0x00001FE0, // ...********.... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00001FE0, // ...********.... + 0x00001FE0, // ...********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 166 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 167 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007F0, // .....*******... + 0x00000FF0, // ....********... + 0x00001C30, // ...***....**... + 0x00001830, // ...**.....**... + 0x00001C00, // ...***......... + 0x00003F00, // ..******....... + 0x000067C0, // .**..*****..... + 0x000061F0, // .**....*****... + 0x00007878, // .****....****.. + 0x00003E18, // ..*****....**.. + 0x00000F98, // ....*****..**.. + 0x000003F8, // ......*******.. + 0x000000F0, // ........****... + 0x00000060, // .........**.... + 0x00003060, // ..**.....**.... + 0x000030E0, // ..**....***.... + 0x00003FC0, // ..********..... + 0x00003F80, // ..*******...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 168 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 169 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00001FE0, // ...********.... + 0x00003870, // ..***....***... + 0x00006798, // .**..****..**.. + 0x00006FD8, // .**.******.**.. + 0x0000DCCC, // **.***..**..**. + 0x0000D80C, // **.**.......**. + 0x0000D80C, // **.**.......**. + 0x0000DCCC, // **.***..**..**. + 0x00006FD8, // .**.******.**.. + 0x00006798, // .**..****..**.. + 0x00003870, // ..***....***... + 0x00001FE0, // ...********.... + 0x00000780, // .....****...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 170 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x000000C0, // ........**..... + 0x00000FC0, // ....******..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000019E0, // ...**..****.... + 0x00000F60, // ....****.**.... + 0x00000000, // ............... + 0x00001FE0, // ...********.... + 0x00001FE0, // ...********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 171 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000071C, // .....***...***. + 0x00000E38, // ....***...***.. + 0x00001C70, // ...***...***... + 0x000038E0, // ..***...***.... + 0x000071C0, // .***...***..... + 0x000038E0, // ..***...***.... + 0x00001C70, // ...***...***... + 0x00000E38, // ....***...***.. + 0x0000071C, // .....***...***. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 172 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00000018, // ...........**.. + 0x00000018, // ...........**.. + 0x00000018, // ...........**.. + 0x00000018, // ...........**.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 173 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003FF8, // ..***********.. + 0x00003FF8, // ..***********.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 174 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00001FE0, // ...********.... + 0x00003870, // ..***....***... + 0x00006F98, // .**.*****..**.. + 0x00006FD8, // .**.******.**.. + 0x0000CCCC, // **..**..**..**. + 0x0000CCCC, // **..**..**..**. + 0x0000CF8C, // **..*****...**. + 0x0000CD8C, // **..**.**...**. + 0x00006CD8, // .**.**..**.**.. + 0x00006CD8, // .**.**..**.**.. + 0x00003870, // ..***....***... + 0x00001FE0, // ...********.... + 0x00000780, // .....****...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 175 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001FC0, // ...*******..... + 0x00001FC0, // ...*******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 176 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00000CC0, // ....**..**..... + 0x00000780, // .....****...... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 177 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 178 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00000C60, // ....**...**.... + 0x00000C60, // ....**...**.... + 0x000000C0, // ........**..... + 0x00000180, // .......**...... + 0x00000300, // ......**....... + 0x00000600, // .....**........ + 0x00000C60, // ....**...**.... + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 179 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00000C60, // ....**...**.... + 0x00000C60, // ....**...**.... + 0x000000C0, // ........**..... + 0x000003C0, // ......****..... + 0x00000060, // .........**.... + 0x00000C60, // ....**...**.... + 0x00000C60, // ....**...**.... + 0x000007C0, // .....*****..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 180 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000E00, // ....***........ + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 181 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F0F0, // ****....****... + 0x0000F0F0, // ****....****... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00003FFC, // ..************. + 0x00003FBC, // ..*******.****. + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + 0x00003000, // ..**........... + }, + { // 182 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FF8, // ....*********.. + 0x00003FF8, // ..***********.. + 0x00007360, // .***..**.**.... + 0x00007360, // .***..**.**.... + 0x00007360, // .***..**.**.... + 0x00007360, // .***..**.**.... + 0x00007360, // .***..**.**.... + 0x00003F60, // ..******.**.... + 0x00000F60, // ....****.**.... + 0x00000360, // ......**.**.... + 0x00000360, // ......**.**.... + 0x00000360, // ......**.**.... + 0x00000360, // ......**.**.... + 0x00000360, // ......**.**.... + 0x00000360, // ......**.**.... + 0x00000360, // ......**.**.... + 0x00001F78, // ...*****.****.. + 0x00001F78, // ...*****.****.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 183 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 184 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000780, // .....****...... + 0x00000180, // .......**...... + 0x00000F80, // ....*****...... + 0x00000700, // .....***....... + }, + { // 185 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00001F00, // ...*****....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00001FE0, // ...********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 186 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00000FC0, // ....******..... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00000FC0, // ....******..... + 0x00000780, // .....****...... + 0x00000000, // ............... + 0x00001FE0, // ...********.... + 0x00001FE0, // ...********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 187 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000071C0, // .***...***..... + 0x000038E0, // ..***...***.... + 0x00001C70, // ...***...***... + 0x00000E38, // ....***...***.. + 0x0000071C, // .....***...***. + 0x00000E38, // ....***...***.. + 0x00001C70, // ...***...***... + 0x000038E0, // ..***...***.... + 0x000071C0, // .***...***..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 188 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003000, // ...**........... + 0x0001F002, // *****..........* + 0x00003006, // ...**.........** + 0x0000300C, // ...**........**. + 0x00003018, // ...**.......**.. + 0x00003030, // ...**......**... + 0x00003060, // ...**.....**.... + 0x000030C8, // ...**....**..*.. + 0x0001FF98, // **********..**.. + 0x00000338, // .......**..***.. + 0x00000658, // ......**..*.**.. + 0x00000C98, // .....**..*..**.. + 0x00001918, // ....**..*...**.. + 0x000031FC, // ...**...*******. + 0x00006018, // ..**........**.. + 0x0000403C, // ..*........****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 189 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003000, // ...**........... + 0x0001F002, // *****..........* + 0x00003006, // ...**.........** + 0x0000300C, // ...**........**. + 0x00003018, // ...**.......**.. + 0x00003030, // ...**......**... + 0x00003060, // ...**.....**.... + 0x000030FC, // ...**....******. + 0x0001FFE6, // ************..** + 0x00000346, // .......**.*...** + 0x0000060C, // ......**.....**. + 0x00000C18, // .....**.....**.. + 0x00001830, // ....**.....**... + 0x00003060, // ...**.....**.... + 0x000060C6, // ..**.....**...** + 0x000040FE, // ..*......******* + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 190 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007C00, // .*****......... + 0x0000C602, // **...**.......* + 0x0000C606, // **...**......** + 0x00000C0C, // ....**......**. + 0x00003C18, // ..****.....**.. + 0x00000630, // .....**...**... + 0x0000C660, // **...**..**.... + 0x0000C6C8, // **...**.**..*.. + 0x00007D98, // .*****.**..**.. + 0x00000338, // ......**..***.. + 0x00000658, // .....**..*.**.. + 0x00000C98, // ....**..*..**.. + 0x00001918, // ...**..*...**.. + 0x000031FC, // ..**...*******. + 0x00006018, // .**........**.. + 0x0000403C, // .*........****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 191 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000000, // ............... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000700, // .....***....... + 0x00001E00, // ...****........ + 0x00003800, // ..***.......... + 0x00003000, // ..**........... + 0x00003060, // ..**.....**.... + 0x00003060, // ..**.....**.... + 0x00003860, // ..***....**.... + 0x00001FE0, // ...********.... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + }, + { // 192 + 15, 26, + 0x00000000, // ............... + 0x00003800, // ..***.......... + 0x00001C00, // ...***......... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00003F00, // ..******....... + 0x00003F00, // ..******....... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 193 + 15, 26, + 0x00000000, // ............... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00003F00, // ..******....... + 0x00003F00, // ..******....... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 194 + 15, 26, + 0x00000600, // .....**........ + 0x00000F00, // ....****....... + 0x00001F80, // ...******...... + 0x000039C0, // ..***..***..... + 0x000070E0, // .***....***.... + 0x00000000, // ............... + 0x00003F00, // ..******....... + 0x00003F00, // ..******....... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 195 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000E60, // ....***..**.... + 0x00001FC0, // ...*******..... + 0x00003380, // ..**..***...... + 0x00000000, // ............... + 0x00003F00, // ..******....... + 0x00003F00, // ..******....... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 196 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x00000000, // ............... + 0x00003F00, // ..******....... + 0x00003F00, // ..******....... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 197 + 15, 26, + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000D80, // ....**.**...... + 0x00000880, // ....*...*...... + 0x00000D80, // ....**.**...... + 0x00000700, // .....***....... + 0x00003F00, // ..******....... + 0x00003F00, // ..******....... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 198 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FFE, // ....*********** + 0x00000FFE, // ....*********** + 0x00000386, // ......***....** + 0x00000786, // .....****....** + 0x00000780, // .....****...... + 0x00000D98, // ....**.**..**.. + 0x000009F8, // ....*..******.. + 0x000019F8, // ...**..******.. + 0x00001F98, // ...******..**.. + 0x00003F80, // ..*******...... + 0x00003180, // ..**...**...... + 0x00006186, // .**....**....** + 0x00006186, // .**....**....** + 0x0000F7FE, // ****.********** + 0x0000F7FE, // ****.********** + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 199 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000007D8, // .....*****.**.. + 0x00001FF8, // ...**********.. + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x00007018, // .***.......**.. + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00007000, // .***........... + 0x00003008, // ..**........*.. + 0x00003818, // ..***......**.. + 0x00001FF0, // ...*********... + 0x000007E0, // .....******.... + 0x00000300, // ......**....... + 0x00000780, // .....****...... + 0x00000180, // .......**...... + 0x00000F80, // ....*****...... + 0x00000700, // .....***....... + }, + { // 200 + 15, 26, + 0x00000000, // ............... + 0x00001C00, // ...***......... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x000018D8, // ...**...**.**.. + 0x000018C0, // ...**...**..... + 0x00001FC0, // ...*******..... + 0x00001FC0, // ...*******..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x00007FFC, // .*************. + 0x00007FFC, // .*************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 201 + 15, 26, + 0x00000000, // ............... + 0x00000070, // .........***... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x000018D8, // ...**...**.**.. + 0x000018C0, // ...**...**..... + 0x00001FC0, // ...*******..... + 0x00001FC0, // ...*******..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x00007FFC, // .*************. + 0x00007FFC, // .*************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 202 + 15, 26, + 0x00000180, // .......**...... + 0x000003C0, // ......****..... + 0x000007E0, // .....******.... + 0x00000E70, // ....***..***... + 0x00001C38, // ...***....***.. + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x000018D8, // ...**...**.**.. + 0x000018C0, // ...**...**..... + 0x00001FC0, // ...*******..... + 0x00001FC0, // ...*******..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x00007FFC, // .*************. + 0x00007FFC, // .*************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 203 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000C60, // ....**...**.... + 0x00000C60, // ....**...**.... + 0x00000C60, // ....**...**.... + 0x00000000, // ............... + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x000018D8, // ...**...**.**.. + 0x000018C0, // ...**...**..... + 0x00001FC0, // ...*******..... + 0x00001FC0, // ...*******..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x00007FFC, // .*************. + 0x00007FFC, // .*************. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 204 + 15, 26, + 0x00000000, // ............... + 0x00001C00, // ...***......... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 205 + 15, 26, + 0x00000000, // ............... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 206 + 15, 26, + 0x00000300, // ......**....... + 0x00000780, // .....****...... + 0x00000FC0, // ....******..... + 0x00001CE0, // ...***..***.... + 0x00003870, // ..***....***... + 0x00000000, // ............... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 207 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00000CC0, // ....**..**..... + 0x00000000, // ............... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 208 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FFC0, // **********..... + 0x0000FFF0, // ************... + 0x00003038, // ..**......***.. + 0x00003018, // ..**.......**.. + 0x0000301C, // ..**.......***. + 0x0000300C, // ..**........**. + 0x0000FE0C, // *******.....**. + 0x0000FE0C, // *******.....**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x0000300C, // ..**........**. + 0x00003018, // ..**.......**.. + 0x00003038, // ..**......***.. + 0x0000FFF0, // ************... + 0x0000FFE0, // ***********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 209 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000730, // .....***..**... + 0x00000FE0, // ....*******.... + 0x000019C0, // ...**..***..... + 0x00000000, // ............... + 0x0000787C, // .****....*****. + 0x0000787C, // .****....*****. + 0x00003C18, // ..****.....**.. + 0x00003C18, // ..****.....**.. + 0x00003618, // ..**.**....**.. + 0x00003618, // ..**.**....**.. + 0x00003318, // ..**..**...**.. + 0x00003318, // ..**..**...**.. + 0x00003198, // ..**...**..**.. + 0x00003198, // ..**...**..**.. + 0x000030D8, // ..**....**.**.. + 0x000030D8, // ..**....**.**.. + 0x00003078, // ..**.....****.. + 0x00007C78, // .*****...****.. + 0x00007C38, // .*****....***.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 210 + 15, 26, + 0x00000000, // ............... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000380, // ......***...... + 0x000001C0, // .......***..... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00001FF0, // ...*********... + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000701C, // .***.......***. + 0x00003018, // ..**.......**.. + 0x00003838, // ..***.....***.. + 0x00001FF0, // ...*********... + 0x000007C0, // .....*****..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 211 + 15, 26, + 0x00000000, // ............... + 0x00000070, // .........***... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00001FF0, // ...*********... + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000701C, // .***.......***. + 0x00003018, // ..**.......**.. + 0x00003838, // ..***.....***.. + 0x00001FF0, // ...*********... + 0x000007C0, // .....*****..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 212 + 15, 26, + 0x00000180, // .......**...... + 0x000003C0, // ......****..... + 0x000007E0, // .....******.... + 0x00000E70, // ....***..***... + 0x00001C38, // ...***....***.. + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00001FF0, // ...*********... + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000701C, // .***.......***. + 0x00003018, // ..**.......**.. + 0x00003838, // ..***.....***.. + 0x00001FF0, // ...*********... + 0x000007C0, // .....*****..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 213 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000730, // .....***..**... + 0x00000FE0, // ....*******.... + 0x000019C0, // ...**..***..... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00001FF0, // ...*********... + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000701C, // .***.......***. + 0x00003018, // ..**.......**.. + 0x00003838, // ..***.....***.. + 0x00001FF0, // ...*********... + 0x000007C0, // .....*****..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 214 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000C60, // ....**...**.... + 0x00000C60, // ....**...**.... + 0x00000C60, // ....**...**.... + 0x00000000, // ............... + 0x000007C0, // .....*****..... + 0x00001FF0, // ...*********... + 0x00003838, // ..***.....***.. + 0x00003018, // ..**.......**.. + 0x0000701C, // .***.......***. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000600C, // .**.........**. + 0x0000701C, // .***.......***. + 0x00003018, // ..**.......**.. + 0x00003838, // ..***.....***.. + 0x00001FF0, // ...*********... + 0x000007C0, // .....*****..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 215 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00002010, // ..*........*... + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00001CE0, // ...***..***.... + 0x00000FC0, // ....******..... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000FC0, // ....******..... + 0x00001CE0, // ...***..***.... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00002010, // ..*........*... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 216 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000000C, // ............**. + 0x00000018, // ...........**.. + 0x000007F0, // .....*******... + 0x00001FF0, // ...*********... + 0x00003838, // ..***.....***.. + 0x00003078, // ..**.....****.. + 0x000070DC, // .***....**.***. + 0x0000608C, // .**.....*...**. + 0x0000618C, // .**....**...**. + 0x0000630C, // .**...**....**. + 0x0000620C, // .**...*.....**. + 0x0000660C, // .**..**.....**. + 0x0000741C, // .***.*.....***. + 0x00003C18, // ..****.....**.. + 0x00003838, // ..***.....***.. + 0x00001FF0, // ...*********... + 0x000037C0, // ..**.*****..... + 0x00006000, // .**............ + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 217 + 15, 26, + 0x00000000, // ............... + 0x00001C00, // ...***......... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x00007C7C, // .*****...*****. + 0x00007C7C, // .*****...*****. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00001830, // ...**.....**... + 0x00001FF0, // ...*********... + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 218 + 15, 26, + 0x00000000, // ............... + 0x00000070, // .........***... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x00007C7C, // .*****...*****. + 0x00007C7C, // .*****...*****. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00001830, // ...**.....**... + 0x00001FF0, // ...*********... + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 219 + 15, 26, + 0x00000180, // .......**...... + 0x000003C0, // ......****..... + 0x000007E0, // .....******.... + 0x00000E70, // ....***..***... + 0x00001C38, // ...***....***.. + 0x00000000, // ............... + 0x00007C7C, // .*****...*****. + 0x00007C7C, // .*****...*****. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00001830, // ...**.....**... + 0x00001FF0, // ...*********... + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 220 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000C60, // ....**...**.... + 0x00000C60, // ....**...**.... + 0x00000C60, // ....**...**.... + 0x00000000, // ............... + 0x00007C7C, // .*****...*****. + 0x00007C7C, // .*****...*****. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00003018, // ..**.......**.. + 0x00001830, // ...**.....**... + 0x00001FF0, // ...*********... + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 221 + 15, 26, + 0x00000000, // ............... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00001860, // ...**....**.... + 0x00000CC0, // ....**..**..... + 0x00000FC0, // ....******..... + 0x00000780, // .....****...... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00001FE0, // ...********.... + 0x00001FE0, // ...********.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 222 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007E00, // .******........ + 0x00007E00, // .******........ + 0x00001800, // ...**.......... + 0x00001FE0, // ...********.... + 0x00001FF8, // ...**********.. + 0x0000181C, // ...**......***. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000181C, // ...**......***. + 0x00001FF8, // ...**********.. + 0x00001FE0, // ...********.... + 0x00001800, // ...**.......... + 0x00007E00, // .******........ + 0x00007E00, // .******........ + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 223 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000780, // .....****...... + 0x00000FC0, // ....******..... + 0x00001CE0, // ...***..***.... + 0x00001860, // ...**....**.... + 0x00001860, // ...**....**.... + 0x000018E0, // ...**...***.... + 0x00001BC0, // ...**.****..... + 0x00001BE0, // ...**.*****.... + 0x00001870, // ...**....***... + 0x00001838, // ...**.....***.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x00001818, // ...**......**.. + 0x000019B8, // ...**..**.***.. + 0x00007DF0, // .*****.*****... + 0x00007CE0, // .*****..***.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 224 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003800, // ..***.......... + 0x00001C00, // ...***......... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00001F80, // ...******...... + 0x00003FC0, // ..********..... + 0x000030E0, // ..**....***.... + 0x00000060, // .........**.... + 0x00000FE0, // ....*******.... + 0x00003FE0, // ..*********.... + 0x00007060, // .***.....**.... + 0x00006060, // .**......**.... + 0x000060E0, // .**.....***.... + 0x00007FF8, // .************.. + 0x00003F78, // ..******.****.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 225 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00001F80, // ...******...... + 0x00003FC0, // ..********..... + 0x000030E0, // ..**....***.... + 0x00000060, // .........**.... + 0x00000FE0, // ....*******.... + 0x00003FE0, // ..*********.... + 0x00007060, // .***.....**.... + 0x00006060, // .**......**.... + 0x000060E0, // .**.....***.... + 0x00007FF8, // .************.. + 0x00003F78, // ..******.****.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 226 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000F80, // ....*****...... + 0x00001DC0, // ...***.***..... + 0x000038E0, // ..***...***.... + 0x00000000, // ............... + 0x00001F80, // ...******...... + 0x00003FC0, // ..********..... + 0x000030E0, // ..**....***.... + 0x00000060, // .........**.... + 0x00000FE0, // ....*******.... + 0x00003FE0, // ..*********.... + 0x00007060, // .***.....**.... + 0x00006060, // .**......**.... + 0x000060E0, // .**.....***.... + 0x00007FF8, // .************.. + 0x00003F78, // ..******.****.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 227 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000E60, // ....***..**.... + 0x00001FC0, // ...*******..... + 0x00003380, // ..**..***...... + 0x00000000, // ............... + 0x00001F80, // ...******...... + 0x00003FC0, // ..********..... + 0x000030E0, // ..**....***.... + 0x00000060, // .........**.... + 0x00000FE0, // ....*******.... + 0x00003FE0, // ..*********.... + 0x00007060, // .***.....**.... + 0x00006060, // .**......**.... + 0x000060E0, // .**.....***.... + 0x00007FF8, // .************.. + 0x00003F78, // ..******.****.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 228 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x00000000, // ............... + 0x00001F80, // ...******...... + 0x00003FC0, // ..********..... + 0x000030E0, // ..**....***.... + 0x00000060, // .........**.... + 0x00000FE0, // ....*******.... + 0x00003FE0, // ..*********.... + 0x00007060, // .***.....**.... + 0x00006060, // .**......**.... + 0x000060E0, // .**.....***.... + 0x00007FF8, // .************.. + 0x00003F78, // ..******.****.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 229 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000D80, // ....**.**...... + 0x00000880, // ....*...*...... + 0x00000D80, // ....**.**...... + 0x00000700, // .....***....... + 0x00001F80, // ...******...... + 0x00003FC0, // ..********..... + 0x000030E0, // ..**....***.... + 0x00000060, // .........**.... + 0x00000FE0, // ....*******.... + 0x00003FE0, // ..*********.... + 0x00007060, // .***.....**.... + 0x00006060, // .**......**.... + 0x000060E0, // .**.....***.... + 0x00007FF8, // .************.. + 0x00003F78, // ..******.****.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 230 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003CF0, // ..****..****... + 0x00007FF8, // .************.. + 0x0000679C, // .**..****..***. + 0x0000030C, // ......**....**. + 0x00001F0C, // ...*****....**. + 0x00007FFC, // .*************. + 0x0000E3FC, // ***...********. + 0x0000C300, // **....**....... + 0x0000C78C, // **...****...**. + 0x0000FFFC, // **************. + 0x00007CF0, // .*****..****... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 231 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000FB0, // ....*****.**... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007030, // .***......**... + 0x00006030, // .**.......**... + 0x00006000, // .**............ + 0x00006000, // .**............ + 0x00007000, // .***........... + 0x00003830, // ..***.....**... + 0x00003FF0, // ..**********... + 0x00000FE0, // ....*******.... + 0x00000300, // ......**....... + 0x00000780, // .....****...... + 0x00000180, // .......**...... + 0x00000F80, // ....*****...... + 0x00000700, // .....***....... + }, + { // 232 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001C00, // ...***......... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00007000, // .***........... + 0x00003838, // ..***.....***.. + 0x00003FF8, // ..***********.. + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 233 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00007000, // .***........... + 0x00003838, // ..***.....***.. + 0x00003FF8, // ..***********.. + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 234 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000380, // ......***...... + 0x000007C0, // .....*****..... + 0x00000EE0, // ....***.***.... + 0x00001C70, // ...***...***... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00007000, // .***........... + 0x00003838, // ..***.....***.. + 0x00003FF8, // ..***********.. + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 235 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00007FF8, // .************.. + 0x00007FF8, // .************.. + 0x00007000, // .***........... + 0x00003838, // ..***.....***.. + 0x00003FF8, // ..***********.. + 0x00000FE0, // ....*******.... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 236 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003800, // ..***.......... + 0x00001C00, // ...***......... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00001F00, // ...*****....... + 0x00001F00, // ...*****....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 237 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00001F00, // ...*****....... + 0x00001F00, // ...*****....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 238 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000F80, // ....*****...... + 0x00001DC0, // ...***.***..... + 0x000038E0, // ..***...***.... + 0x00000000, // ............... + 0x00001F00, // ...*****....... + 0x00001F00, // ...*****....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 239 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x00000000, // ............... + 0x00001F00, // ...*****....... + 0x00001F00, // ...*****....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00000300, // ......**....... + 0x00003FF0, // ..**********... + 0x00003FF0, // ..**********... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 240 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000F000, // ****........... + 0x0000FC70, // ******...***... + 0x00000FF0, // ....********... + 0x00001F80, // ...******...... + 0x00007DC0, // .*****.***..... + 0x000070E0, // .***....***.... + 0x00000FF0, // ....********... + 0x00003FF0, // ..**********... + 0x00003878, // ..***....****.. + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00003FF0, // ..**********... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 241 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000E60, // ....***..**.... + 0x00001FC0, // ...*******..... + 0x00003380, // ..**..***...... + 0x00000000, // ............... + 0x0000F3C0, // ****..****..... + 0x0000F7E0, // ****.******.... + 0x00003C70, // ..****...***... + 0x00003830, // ..***.....**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x0000FCFC, // ******..******. + 0x0000FCFC, // ******..******. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 242 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00001C00, // ...***......... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00003FF0, // ..**********... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 243 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00003FF0, // ..**********... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 244 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000F80, // ....*****...... + 0x00001DC0, // ...***.***..... + 0x000038E0, // ..***...***.... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00003FF0, // ..**********... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 245 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000E60, // ....***..**.... + 0x00001FC0, // ...*******..... + 0x00003380, // ..**..***...... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00003FF0, // ..**********... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 246 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x00000000, // ............... + 0x00000FC0, // ....******..... + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x00007038, // .***......***.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00006018, // .**........**.. + 0x00007038, // .***......***.. + 0x00003870, // ..***....***... + 0x00003FF0, // ..**********... + 0x00000FC0, // ....******..... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 247 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000FFF8, // *************.. + 0x0000FFF8, // *************.. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 248 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x0000000C, // ............**. + 0x00000FD8, // ....******.**.. + 0x00003FF0, // ..**********... + 0x00003870, // ..***....***... + 0x000070D8, // .***....**.**.. + 0x00006198, // .**....**..**.. + 0x00006318, // .**...**...**.. + 0x00006618, // .**..**....**.. + 0x00006C38, // .**.**....***.. + 0x00003870, // ..***....***... + 0x00003FF0, // ..**********... + 0x00003FC0, // ..********..... + 0x00006000, // .**............ + 0x0000C000, // **............. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 249 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00003800, // ..***.......... + 0x00001C00, // ...***......... + 0x00000E00, // ....***........ + 0x00000700, // .....***....... + 0x00000000, // ............... + 0x0000F0F0, // ****....****... + 0x0000F0F0, // ****....****... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001FFC, // ...***********. + 0x00000FBC, // ....*****.****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 250 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000700, // .....***....... + 0x00000E00, // ....***........ + 0x00000000, // ............... + 0x0000F0F0, // ****....****... + 0x0000F0F0, // ****....****... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001FFC, // ...***********. + 0x00000FBC, // ....*****.****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 251 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000700, // .....***....... + 0x00000F80, // ....*****...... + 0x00001DC0, // ...***.***..... + 0x000038E0, // ..***...***.... + 0x00000000, // ............... + 0x0000F0F0, // ****....****... + 0x0000F0F0, // ****....****... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001FFC, // ...***********. + 0x00000FBC, // ....*****.****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 252 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x00000000, // ............... + 0x0000F0F0, // ****....****... + 0x0000F0F0, // ****....****... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001FFC, // ...***********. + 0x00000FBC, // ....*****.****. + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + }, + { // 253 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000070, // .........***... + 0x000000E0, // ........***.... + 0x000001C0, // .......***..... + 0x00000380, // ......***...... + 0x00000000, // ............... + 0x00007CF8, // .*****..*****.. + 0x00007CF8, // .*****..*****.. + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001860, // ...**....**.... + 0x00001CE0, // ...***..***.... + 0x00000CC0, // ....**..**..... + 0x00000DC0, // ....**.***..... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000300, // ......**....... + 0x00000700, // .....***....... + 0x00000600, // .....**........ + 0x00000E00, // ....***........ + 0x00007F00, // .*******....... + 0x00007F00, // .*******....... + }, + { // 254 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00007800, // .****.......... + 0x00007800, // .****.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001BE0, // ...**.*****.... + 0x00001FF8, // ...**********.. + 0x00001E38, // ...****...***.. + 0x00001C1C, // ...***.....***. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x0000180C, // ...**.......**. + 0x00001C1C, // ...***.....***. + 0x00001E38, // ...****...***.. + 0x00001FF8, // ...**********.. + 0x00001BE0, // ...**.*****.... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00001800, // ...**.......... + 0x00007F00, // .*******....... + 0x00007F00, // .*******....... + }, + { // 255 + 15, 26, + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x00000000, // ............... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x000018C0, // ...**...**..... + 0x00000000, // ............... + 0x00007CF8, // .*****..*****.. + 0x00007CF8, // .*****..*****.. + 0x00003030, // ..**......**... + 0x00003870, // ..***....***... + 0x00001860, // ...**....**.... + 0x00001CE0, // ...***..***.... + 0x00000CC0, // ....**..**..... + 0x00000DC0, // ....**.***..... + 0x00000780, // .....****...... + 0x00000780, // .....****...... + 0x00000300, // ......**....... + 0x00000700, // .....***....... + 0x00000600, // .....**........ + 0x00000E00, // ....***........ + 0x00007F00, // .*******....... + 0x00007F00, // .*******....... + }, + }; diff --git a/i18n.c b/i18n.c new file mode 100644 index 000000000..7b93062d3 --- /dev/null +++ b/i18n.c @@ -0,0 +1,478 @@ +/* + * i18n.c: Internationalization + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: i18n.c 1.6 2000/11/19 12:12:53 kls Exp $ + * + * Slovenian translations provided by Miha Setina + * + */ + +/* + * How to add a new language: + * + * 1. Announce your translation action on the Linux-DVB mailing + * list to avoid duplicate work. + * 2. Increase the value of 'NumLanguages'. + * 3. Insert a new line in every member of the 'Phrases[]' array, + * containing the translated text for the new language. + * For example, assuming you want to add the Italian language, + * + * { "English", + * "Deutsch", + * }, + * + * would become + * + * { "English", + * "Deutsch", + * "Italiano", + * }, + * + * and so on. Insert your language so that all the entries + * following 'English' will be sorted alphabetically, and write + * the name of your language in your language (not in English, + * which means that it should be 'Italiano', not 'Italian'). + * Note that only the characters defined in 'fontosd.c' will + * be available! + * 4. Compile VDR and test the new language by switching to it + * in the "Setup" menu. + * 5. Send the modified 'i18n.c' file to to have + * it included in the next version of VDR. + */ + +#include "i18n.h" +#include +#include "config.h" +#include "tools.h" + +const int NumLanguages = 3; + +typedef const char *tPhrase[NumLanguages]; + +const tPhrase Phrases[] = { + // The name of the language (this MUST be the first phrase!): + { "English", + "Deutsch", + "Slovenski", + }, + // Menu titles: + { "Main", + "Hauptmen", + "Glavni meni", + }, + { "Schedule", + "Programm", + "Urnik", + }, + { "Channels", + "Kanle", + "Kanali", + }, + { "Timers", + "Timer", + "Termini", + }, + { "Recordings", + "Aufzeichnungen", + "Posnetki", + }, + { "Setup", + "Einstellungen", + "Nastavitve", + }, + { "Commands", + "Befehle", + "Ukazi", + }, + { "Edit Channel", + "Kanal Editieren", + "Uredi kanal", + }, + { "Edit Timer", + "Timer Editieren", + "Uredi termin", + }, + { "Event", + "Sendung", + "Oddaja", + }, + { "Summary", + "Inhalt", + "Vsebina", + }, + { "Schedule - %s", + "Programm - %s", + "Urnik - %s", + }, + { "What's on now?", + "Was luft jetzt?", + "Kaj je na sporedu?", + }, + { "What's on next?", + "Was luft als nchstes?", + "Kaj sledi?", + }, + // Button texts (must not be more than 10 characters!): + { "Edit", + "Editieren", + "Uredi", + }, + { "New", + "Neu", + "Novo", + }, + { "Delete", + "Lschen", + "Odstrani", + }, + { "Mark", + "Markieren", + "Oznaci", + }, + { "Record", + "Aufnehmen", + "Posnemi", + }, + { "Play", + "Wiedergabe", + "Predavajaj", + }, + { "Resume", + "Weiter", + "Nadaljuj", + }, + { "Summary", + "Inhalt", + "Vsebina", + }, + { "Switch", + "Umschalten", + "Preklopi", + }, + { "Now", + "Jetzt", + "Sedaj", + }, + { "Next", + "Nchste", + "Naslednji", + }, + { "Schedule", + "Programm", + "Urnik", + }, + // Confirmations: + { "Delete Channel?", + "Kanal lschen?", + "Odstrani kanal?", + }, + { "Delete Timer?", + "Timer lschen?", + "Odstani termin?", + }, + { "Delete Recording?", + "Aufzeichnung lschen?", + "Odstrani posnetek?", + }, + { "Stop Recording?", + "Aufzeichnung beenden?", + "Koncaj snemanje?", + }, + // Channel parameters: + { "Name", + "Name", + "Naziv", + }, + { "Frequency", + "Frequenz", + "Frekvenca", + }, + { "Polarization", + "Polarisation", + "Polarizacija", + }, + { "Diseqc", + "Diseqc", + "Diseqc", + }, + { "Srate", + "Srate", + "Srate", + }, + { "Vpid", + "Vpid", + "Vpid", + }, + { "Apid", + "Apid", + "Apid", + }, + { "CA", + "CA", + "CA", + }, + { "Pnr", + "Pnr", + "Pnr", + }, + // Timer parameters: + { "Active", + "Aktiv", + "Aktivno", + }, + { "Channel", + "Kanal", + "Kanal", + }, + { "Day", + "Tag", + "Dan", + }, + { "Start", + "Anfang", + "Zacetek", + }, + { "Stop", + "Ende", + "Konec", + }, + { "Priority", + "Prioritt", + "Prioriteta", + }, + { "Lifetime", + "Lebensdauer", + "Veljavnost", + }, + { "File", + "Datei", + "Datoteka", + }, + // Error messages: + { "Channel is being used by a timer!", + "Kanal wird von einem Timer benutzt!", + "Urnik zaseda kanal!", + }, + { "Can't switch channel!", + "Kanal kann nicht umgeschaltet werden!", + "Ne morem preklopiti kanala!", + }, + { "Timer is recording!", + "Timer zeichnet gerade auf!", + "Snemanje po urniku!", + }, + { "Error while deleting recording!", + "Fehler beim Lschen der Aufzeichnung!", + "Napaka pri odstranjevanju posnetka!", + }, + { "*** Invalid Channel ***", + "*** Ungltiger Kanal ***", + "*** Neznan kanal ***", + }, + { "No free DVB device to record!", + "Keine freie DVB-Karte zum Aufnehmen!", + "Ni proste DVB naprave za snemanje!", + }, + { "Channel locked (recording)!", + "Kanal blockiert (zeichnet auf)!", + "Zaklenjen kanal (snemanje)!", + }, + // Setup parameters: + { "OSD-Language", + "OSD-Sprache", + "OSD-jezik", + }, + { "PrimaryDVB", + "Primres Interface", + "Primarna naprava", + }, + { "ShowInfoOnChSwitch", + "Info zeigen", + "Pokazi naziv kanala", + }, + { "MenuScrollPage", + "Seitenweise scrollen", + "Drsni meni", + }, + { "MarkInstantRecord", + "Direktaufz. markieren", + "Oznaci direktno snemanje", + }, + { "LnbFrequLo", + "Untere LNB-Frequenz", + "Spodnja LNB-frek.", + }, + { "LnbFrequHi", + "Obere LNB-Frequenz", + "Zgornja LNB-frek.", + }, + { "SetSystemTime", + "Systemzeit stellen", + "Sistemski cas", + }, + { "MarginStart", + "Zeitpuffer bei Anfang", + "Premor pred zacetkom", + }, + { "MarginStop", + "Zeitpuffer bei Ende", + "Premor za koncem", + }, + { "EPGScanTimeout", + "Zeit bis EPG Scan", + "Cas do EPG pregleda", + }, + // The days of the week: + { "MTWTFSS", + "MDMDFSS", + "PTSCPSN", + }, + // Learning keys: + { "Learning Remote Control Keys", + "Fernbedienungs-Codes lernen", + "Ucim se kod upravljalca", + }, + { "Phase 1: Detecting RC code type", + "Phase 1: FB Code feststellen", + "Faza 1: Sprejemanje IR kode", + }, + { "Press any key on the RC unit", + "Eine Taste auf der FB drcken", + "Pritisnite tipko na upravljalcu", + }, + { "RC code detected!", + "FB Code erkannt!", + "IR koda sprejeta!", + }, + { "Do not press any key...", + "Keine Taste drcken...", + "Ne pritiskajte tipk...", + }, + { "Phase 2: Learning specific key codes", + "Phase 2: Einzelne Tastencodes lernen", + "Faza 2: Ucenje posebnih kod", + }, + { "Press key for '%s'", + "Taste fr '%s' drcken", + "Pritisnite tipko za '%s'", + }, + { "Press 'Up' to confirm", + "'Auf' drcken zum Besttigen", + "Pritisnite tipko 'Gor' za potrditev", + }, + { "Press 'Down' to continue", + "'Ab' drcken zum Weitermachen", + "Pritisnite tipko 'Dol' za nadaljevanje", + }, + { "(press 'Up' to go back)", + "('Auf' drcken um zurckzugehen)", + "(pritisnite 'Gor' za nazaj)", + }, + { "(press 'Down' to end key definition)", + "('Ab' drcken zum Beenden", + "(pritisnite 'Dol' za konec)", + }, + { "Phase 3: Saving key codes", + "Phase 3: Codes abspeichern", + "Faza 3: Shranjujem kodo", + }, + { "Press 'Up' to save, 'Down' to cancel", + "'Auf' speichert, 'Ab' bricht ab", + "'Gor' za potrditev, 'Dol' za prekinitev", + }, + // Key names: + { "Up", + "Auf", + "Gor", + }, + { "Down", + "Ab", + "Dol", + }, + { "Menu", + "Men", + "Meni", + }, + { "Ok", + "Ok", + "Ok", + }, + { "Back", + "Zurck", + "Nazaj", + }, + { "Left", + "Links", + "Levo", + }, + { "Right", + "Rechts", + "Desno", + }, + { "Red", + "Rot", + "Rdeca", + }, + { "Green", + "Grn", + "Zelena", + }, + { "Yellow", + "Gelb", + "Rumena", + }, + { "Blue", + "Blau", + "Modra", + }, + // Miscellaneous: + { "yes", + "ja", + "da", + }, + { "no", + "nein", + "ne", + }, + { "Stop replaying", + "Wiedergabe beenden", + "Prekini ponavljanje", + }, + { "Stop recording ", // note the trailing blank! + "Aufzeichnung beenden ", + "Prekini shranjevanje ", + }, + { "Switching primary DVB...", + "Primres Interface wird umgeschaltet...", + "Preklapljanje primarne naprave...", + }, + { "Up/Dn for new location - OK to move", + "Auf/Ab fr neue Position - dann OK", + "Gor/Dol za novo poz. - Ok za premik", + }, + { NULL } + }; + +const char *tr(const char *s) +{ + if (Setup.OSDLanguage) { + for (const tPhrase *p = Phrases; **p; p++) { + if (strcmp(s, **p) == 0) { + const char *t = (*p)[Setup.OSDLanguage]; + if (t && *t) + return t; + } + } + esyslog(LOG_ERR, "no translation found for '%s' in language %d (%s)\n", s, Setup.OSDLanguage, Phrases[0][Setup.OSDLanguage]); + } + return s; +} + +const char * const * Languages(void) +{ + return &Phrases[0][0]; +} + diff --git a/i18n.h b/i18n.h new file mode 100644 index 000000000..c94241a54 --- /dev/null +++ b/i18n.h @@ -0,0 +1,19 @@ +/* + * i18n.h: Internationalization + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: i18n.h 1.1 2000/11/11 09:27:25 kls Exp $ + */ + +#ifndef __I18N_H +#define __I18N_H + +extern const int NumLanguages; + +const char *tr(const char *s); + +const char * const * Languages(void); + +#endif //__I18N_H diff --git a/interface.c b/interface.c index 810270fed..e5cc1d25c 100644 --- a/interface.c +++ b/interface.c @@ -4,12 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.28 2000/11/01 15:27:52 kls Exp $ + * $Id: interface.c 1.32 2000/11/18 15:28:50 kls Exp $ */ #include "interface.h" #include #include +#include "i18n.h" cInterface *Interface = NULL; @@ -57,8 +58,7 @@ void cInterface::Close(void) unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release) { - if (open) - cDvbApi::PrimaryDvbApi->Flush(); + Flush(); if (!rcIo->InputAvailable()) cFile::AnyFileReady(-1, Wait ? 1000 : 0); unsigned int Command; @@ -67,6 +67,7 @@ unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release) eKeys cInterface::GetKey(bool Wait) { + Flush(); if (SVDRP) SVDRP->Process(); eKeys Key = keyFromWait; @@ -89,8 +90,7 @@ void cInterface::PutKey(eKeys Key) eKeys cInterface::Wait(int Seconds, bool KeepChar) { - if (open) - cDvbApi::PrimaryDvbApi->Flush(); + Flush(); eKeys Key = kNone; time_t timeout = time(NULL) + Seconds; for (;;) { @@ -136,6 +136,11 @@ void cInterface::SetCols(int *c) } } +eDvbFont cInterface::SetFont(eDvbFont Font) +{ + return cDvbApi::PrimaryDvbApi->SetFont(Font); +} + char *cInterface::WrapText(const char *Text, int Width, int *Height) { // Wraps the Text to make it fit into the area defined by the given Width @@ -238,11 +243,24 @@ void cInterface::WriteText(int x, int y, const char *s, eDvbColor FgColor, eDvbC void cInterface::Title(const char *s) { - int x = (Width() - strlen(s)) / 2; - if (x < 0) - x = 0; ClearEol(0, 0, clrCyan); - Write(x, 0, s, clrBlack, clrCyan); + const char *t = strchr(s, '\t'); + if (t) { + char buffer[Width() + 1]; + unsigned int n = t - s; + if (n >= sizeof(buffer)) + n = sizeof(buffer) - 1; + strn0cpy(buffer, s, n); + Write(1, 0, buffer, clrBlack, clrCyan); + t++; + Write(-(cDvbApi::PrimaryDvbApi->WidthInCells(t) + 1), 0, t, clrBlack, clrCyan); + } + else { + int x = (Width() - strlen(s)) / 2; + if (x < 0) + x = 0; + Write(x, 0, s, clrBlack, clrCyan); + } } void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor) @@ -308,10 +326,10 @@ void cInterface::QueryKeys(void) { Keys.Clear(); Clear(); - WriteText(1, 1, "Learning Remote Control Keys"); - WriteText(1, 3, "Phase 1: Detecting RC code type"); - WriteText(1, 5, "Press any key on the RC unit"); - cDvbApi::PrimaryDvbApi->Flush(); + WriteText(1, 1, tr("Learning Remote Control Keys")); + WriteText(1, 3, tr("Phase 1: Detecting RC code type")); + WriteText(1, 5, tr("Press any key on the RC unit")); + Flush(); #ifndef REMOTE_KBD unsigned char Code = 0; unsigned short Address; @@ -325,22 +343,22 @@ void cInterface::QueryKeys(void) if (rcIo->DetectCode(&Code, &Address)) { Keys.code = Code; Keys.address = Address; - WriteText(1, 5, "RC code detected!"); - WriteText(1, 6, "Do not press any key..."); - cDvbApi::PrimaryDvbApi->Flush(); + WriteText(1, 5, tr("RC code detected!")); + WriteText(1, 6, tr("Do not press any key...")); + Flush(); rcIo->Flush(3000); ClearEol(0, 5); ClearEol(0, 6); - cDvbApi::PrimaryDvbApi->Flush(); + Flush(); break; } #endif } - WriteText(1, 3, "Phase 2: Learning specific key codes"); + WriteText(1, 3, tr("Phase 2: Learning specific key codes")); tKey *k = Keys.keys; while (k->type != kNone) { char *Prompt; - asprintf(&Prompt, "Press key for '%s'", k->name); + asprintf(&Prompt, tr("Press key for '%s'"), tr(k->name)); WriteText(1, 5, Prompt); delete Prompt; for (;;) { @@ -352,8 +370,8 @@ void cInterface::QueryKeys(void) break; } case kDown: if (k > Keys.keys + 1) { - WriteText(1, 5, "Press 'Up' to confirm"); - WriteText(1, 6, "Press 'Down' to continue"); + WriteText(1, 5, tr("Press 'Up' to confirm")); + WriteText(1, 6, tr("Press 'Down' to continue")); ClearEol(0, 7); ClearEol(0, 8); for (;;) { @@ -378,11 +396,11 @@ void cInterface::QueryKeys(void) } } if (k > Keys.keys) - WriteText(1, 7, "(press 'Up' to go back)"); + WriteText(1, 7, tr("(press 'Up' to go back)")); else ClearEol(0, 7); if (k > Keys.keys + 1) - WriteText(1, 8, "(press 'Down' to end key definition)"); + WriteText(1, 8, tr("(press 'Down' to end key definition)")); else ClearEol(0, 8); } @@ -396,9 +414,9 @@ void cInterface::LearnKeys(void) Clear(); QueryKeys(); Clear(); - WriteText(1, 1, "Learning Remote Control Keys"); - WriteText(1, 3, "Phase 3: Saving key codes"); - WriteText(1, 5, "Press 'Up' to save, 'Down' to cancel"); + WriteText(1, 1, tr("Learning Remote Control Keys")); + WriteText(1, 3, tr("Phase 3: Saving key codes")); + WriteText(1, 5, tr("Press 'Up' to save, 'Down' to cancel")); for (;;) { eKeys key = GetKey(); if (key == kUp) { diff --git a/interface.h b/interface.h index 5dd8ee3ad..cd46fbaa7 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.19 2000/11/01 15:27:23 kls Exp $ + * $Id: interface.h 1.20 2000/11/18 15:27:59 kls Exp $ */ #ifndef __INTERFACE_H @@ -43,6 +43,7 @@ class cInterface { void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground); void Flush(void); void SetCols(int *c); + eDvbFont SetFont(eDvbFont Font); char *WrapText(const char *Text, int Width, int *Height); void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); diff --git a/menu.c b/menu.c index c3611ccd3..3cf832819 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.40 2000/11/01 16:14:48 kls Exp $ + * $Id: menu.c 1.52 2000/11/18 16:30:13 kls Exp $ */ #include "menu.h" @@ -14,6 +14,7 @@ #include #include "config.h" #include "eit.h" +#include "i18n.h" #define MENUTIMEOUT 120 // seconds @@ -131,7 +132,7 @@ cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value) void cMenuEditBoolItem::Set(void) { char buf[16]; - snprintf(buf, sizeof(buf), "%s", *value ? "yes" : "no"); + snprintf(buf, sizeof(buf), "%s", *value ? tr("yes") : tr("no")); SetValue(buf); } @@ -493,6 +494,29 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key) return osContinue; } +// --- cMenuEditStraItem ----------------------------------------------------- + +class cMenuEditStraItem : public cMenuEditIntItem { +private: + const char * const *strings; +protected: + virtual void Set(void); +public: + cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings); + }; + +cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings) +:cMenuEditIntItem(Name, Value, 0, NumStrings - 1) +{ + strings = Strings; + Set(); +} + +void cMenuEditStraItem::Set(void) +{ + SetValue(strings[*value]); +} + // --- cMenuEditChannel ------------------------------------------------------ class cMenuEditChannel : public cOsdMenu { @@ -505,20 +529,20 @@ class cMenuEditChannel : public cOsdMenu { }; cMenuEditChannel::cMenuEditChannel(int Index) -:cOsdMenu("Edit Channel", 14) +:cOsdMenu(tr("Edit Channel"), 14) { channel = Channels.Get(Index); if (channel) { data = *channel; - Add(new cMenuEditStrItem( "Name", data.name, sizeof(data.name), FileNameChars)); - Add(new cMenuEditIntItem( "Frequency", &data.frequency, 10000, 13000)); //TODO exact limits??? - Add(new cMenuEditChrItem( "Polarization", &data.polarization, "hv")); - Add(new cMenuEditIntItem( "Diseqc", &data.diseqc, 0, 10)); //TODO exact limits??? - Add(new cMenuEditIntItem( "Srate", &data.srate, 22000, 27500)); //TODO exact limits - toggle??? - Add(new cMenuEditIntItem( "Vpid", &data.vpid, 0, 10000)); //TODO exact limits??? - Add(new cMenuEditIntItem( "Apid", &data.apid, 0, 10000)); //TODO exact limits??? - Add(new cMenuEditIntItem( "CA", &data.ca, 0, cDvbApi::NumDvbApis)); - Add(new cMenuEditIntItem( "Pnr", &data.pnr, 0)); + Add(new cMenuEditStrItem( tr("Name"), data.name, sizeof(data.name), FileNameChars)); + Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency, 10000, 13000)); //TODO exact limits??? + Add(new cMenuEditChrItem( tr("Polarization"), &data.polarization, "hv")); + Add(new cMenuEditIntItem( tr("Diseqc"), &data.diseqc, 0, 10)); //TODO exact limits??? + Add(new cMenuEditIntItem( tr("Srate"), &data.srate, 22000, 27500)); //TODO exact limits - toggle??? + Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 10000)); //TODO exact limits??? + Add(new cMenuEditIntItem( tr("Apid"), &data.apid, 0, 10000)); //TODO exact limits??? + Add(new cMenuEditIntItem( tr("CA"), &data.ca, 0, cDvbApi::NumDvbApis)); + Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0)); } } @@ -589,18 +613,18 @@ class cMenuChannels : public cOsdMenu { }; cMenuChannels::cMenuChannels(void) -:cOsdMenu("Channels", 4) +:cOsdMenu(tr("Channels"), 4) { //TODO int i = 0; cChannel *channel; - int curr = ((channel = Channels.GetByNumber(CurrentChannel)) != NULL) ? channel->Index() : -1; + int curr = ((channel = Channels.GetByNumber(cDvbApi::CurrentChannel())) != NULL) ? channel->Index() : -1; while ((channel = Channels.Get(i)) != NULL) { Add(new cMenuChannelItem(i, channel), i == curr); i++; } - SetHelp("Edit", "New", "Delete", "Mark"); + SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark")); } eOSState cMenuChannels::Switch(void) @@ -641,11 +665,11 @@ eOSState cMenuChannels::Del(void) // Check if there is a timer using this channel: for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { if (ti->channel == DeletedChannel) { - Interface->Error("Channel is being used by a timer!"); + Interface->Error(tr("Channel is being used by a timer!")); return osContinue; } } - if (Interface->Confirm("Delete Channel?")) { + if (Interface->Confirm(tr("Delete Channel?"))) { // Move and renumber the channels: Channels.Del(channel); Channels.ReNumber(); @@ -733,8 +757,9 @@ class cMenuTextItem : public cOsdItem { char *text; int x, y, w, h, lines, offset; eDvbColor fgColor, bgColor; + eDvbFont font; public: - cMenuTextItem(const char *Text, int X, int Y, int W, int H = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); + cMenuTextItem(const char *Text, int X, int Y, int W, int H = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground, eDvbFont Font = fontOsd); ~cMenuTextItem(); int Height(void) { return h; } void Clear(void); @@ -746,7 +771,7 @@ class cMenuTextItem : public cOsdItem { virtual eOSState ProcessKey(eKeys Key); }; -cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbColor FgColor, eDvbColor BgColor) +cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbColor FgColor, eDvbColor BgColor, eDvbFont Font) { x = X; y = Y; @@ -754,8 +779,11 @@ cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbC h = H; fgColor = FgColor; bgColor = BgColor; + font = Font; offset = 0; + eDvbFont oldFont = Interface->SetFont(font); text = Interface->WrapText(Text, w - 1, &lines); + Interface->SetFont(oldFont); if (h < 0) h = lines; } @@ -774,6 +802,7 @@ void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) { int l = 0; char *t = text; + eDvbFont oldFont = Interface->SetFont(font); while (*t) { char *n = strchr(t, '\n'); if (l >= offset) { @@ -791,6 +820,7 @@ void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) if (++l >= h + offset) break; } + Interface->SetFont(oldFont); // scroll indicators use inverted color scheme! if (CanScrollUp()) Interface->Write(x + w - 1, y, "^", bgColor, fgColor); if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor); @@ -826,26 +856,30 @@ eOSState cMenuTextItem::ProcessKey(eKeys Key) return osContinue; } -// --- cMenuSummary ---------------------------------------------------------- +// --- cMenuText ------------------------------------------------------------- -class cMenuSummary : public cOsdMenu { +class cMenuText : public cOsdMenu { public: - cMenuSummary(const char *Text); + cMenuText(const char *Title, const char *Text, eDvbFont Font = fontOsd); virtual eOSState ProcessKey(eKeys Key); }; -cMenuSummary::cMenuSummary(const char *Text) -:cOsdMenu("Summary") +cMenuText::cMenuText(const char *Title, const char *Text, eDvbFont Font) +:cOsdMenu(Title) { - Add(new cMenuTextItem(Text, 1, 2, MenuColumns - 2, MAXOSDITEMS)); + Add(new cMenuTextItem(Text, 1, 2, MenuColumns - 2, MAXOSDITEMS, clrWhite, clrBackground, Font)); } -eOSState cMenuSummary::ProcessKey(eKeys Key) +eOSState cMenuText::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); - if (state == osUnknown) - state = osContinue; + if (state == osUnknown) { + switch (Key) { + case kOk: return osBack; + default: state = osContinue; + } + } return state; } @@ -861,22 +895,22 @@ class cMenuEditTimer : public cOsdMenu { }; cMenuEditTimer::cMenuEditTimer(int Index, bool New) -:cOsdMenu("Edit Timer", 10) +:cOsdMenu(tr("Edit Timer"), 12) { 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)); + Add(new cMenuEditBoolItem(tr("Active"), &data.active)); + Add(new cMenuEditChanItem(tr("Channel"), &data.channel)); + Add(new cMenuEditDayItem( tr("Day"), &data.day)); + Add(new cMenuEditTimeItem(tr("Start"), &data.start)); + Add(new cMenuEditTimeItem(tr("Stop"), &data.stop)); //TODO VPS??? - 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)); + Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, 99)); + Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, 99)); + Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), FileNameChars)); } } @@ -885,16 +919,21 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key) eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { - if (Key == kOk) { - if (!*data.file) - strcpy(data.file, Channels.GetChannelNameByNumber(data.channel)); - if (timer && memcmp(timer, &data, sizeof(data)) != 0) { - *timer = data; - Timers.Save(); - isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); - } - state = osBack; - } + switch (Key) { + case kOk: if (!*data.file) + strcpy(data.file, Channels.GetChannelNameByNumber(data.channel)); + if (timer && memcmp(timer, &data, sizeof(data)) != 0) { + *timer = data; + Timers.Save(); + isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); + } + return osBack; + case kRed: + case kGreen: + case kYellow: + case kBlue: return osContinue; + default: break; + } } return state; } @@ -948,7 +987,7 @@ class cMenuTimers : public cOsdMenu { }; cMenuTimers::cMenuTimers(void) -:cOsdMenu("Timer", 2, 4, 10, 6, 6) +:cOsdMenu(tr("Timers"), 2, 4, 10, 6, 6) { int i = 0; cTimer *timer; @@ -957,7 +996,7 @@ cMenuTimers::cMenuTimers(void) Add(new cMenuTimerItem(i, timer)); i++; } - SetHelp("Edit", "New", "Delete", "Mark"); + SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark")); } eOSState cMenuTimers::Activate(bool On) @@ -1000,7 +1039,7 @@ eOSState cMenuTimers::Del(void) cTimer *ti = Timers.Get(Index); if (ti) { if (!ti->recording) { - if (Interface->Confirm("Delete Timer?")) { + if (Interface->Confirm(tr("Delete Timer?"))) { Timers.Del(Timers.Get(Index)); cOsdMenu::Del(Index); Timers.Save(); @@ -1009,7 +1048,7 @@ eOSState cMenuTimers::Del(void) } } else - Interface->Error("Timer is recording!"); + Interface->Error(tr("Timer is recording!")); } return osContinue; } @@ -1029,7 +1068,7 @@ eOSState cMenuTimers::Summary(void) return osContinue; cTimer *ti = Timers.Get(Current()); if (ti && ti->summary && *ti->summary) - return AddSubMenu(new cMenuSummary(ti->summary)); + return AddSubMenu(new cMenuText(tr("Summary"), ti->summary)); return Edit(); // convenience for people not using the Summary feature ;-) } @@ -1064,29 +1103,42 @@ class cMenuEvent : public cOsdMenu { }; cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch) -:cOsdMenu("Event") +:cOsdMenu(tr("Event")) { eventInfo = EventInfo; if (eventInfo) { cChannel *channel = Channels.GetByServiceID(eventInfo->GetServiceID()); if (channel) { - const char *p; char *buffer; - asprintf(&buffer, "%-17.*s %.*s %s - %s", 17, channel->name, 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString()); + asprintf(&buffer, "%-17.*s\t%.*s %s - %s", 17, channel->name, 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString()); SetTitle(buffer, false); int Line = 2; cMenuTextItem *item; - if (!isempty(p = eventInfo->GetTitle())) { - Add(item = new cMenuTextItem(p, 1, Line, MenuColumns - 2, -1, clrCyan)); + const char *Title = eventInfo->GetTitle(); + const char *Subtitle = eventInfo->GetSubtitle(); + const char *ExtendedDescription = eventInfo->GetExtendedDescription(); + // Some channels send a 'Subtitle' that should actually be the 'ExtendedDescription' + // (their 'ExtendedDescription' is then empty). In order to handle this correctly + // we silently shift that text to where it belongs. + // The German TV station 'VOX' is notorious for this - why can't they do it correctly + // like all the others? Well, at least like those who actually send the full range + // of information (like, e.g., 'Sat.1'). Some stations (like 'RTL') don't even + // bother sending anything but the 'Title'... + if (isempty(ExtendedDescription) && !isempty(Subtitle) && strlen(Subtitle) > 2 * MenuColumns) { + ExtendedDescription = Subtitle; + Subtitle = NULL; + } + if (!isempty(Title)) { + Add(item = new cMenuTextItem(Title, 1, Line, MenuColumns - 2, -1, clrCyan)); Line += item->Height() + 1; } - if (!isempty(p = eventInfo->GetSubtitle())) { - Add(item = new cMenuTextItem(p, 1, Line, MenuColumns - 2, -1, clrYellow)); + if (!isempty(Subtitle)) { + Add(item = new cMenuTextItem(Subtitle, 1, Line, MenuColumns - 2, -1, clrYellow)); Line += item->Height() + 1; } - if (!isempty(p = eventInfo->GetExtendedDescription())) - Add(new cMenuTextItem(p, 1, Line, MenuColumns - 2, Height() - Line - 2, clrCyan), true); - SetHelp("Record", NULL, NULL, CanSwitch ? "Switch" : NULL); + if (!isempty(ExtendedDescription)) + Add(new cMenuTextItem(ExtendedDescription, 1, Line, MenuColumns - 2, Height() - Line - 2, clrCyan), true); + SetHelp(tr("Record"), NULL, NULL, CanSwitch ? tr("Switch") : NULL); } } } @@ -1097,6 +1149,8 @@ eOSState cMenuEvent::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { + case kGreen: + case kYellow: return osContinue; case kOk: return osBack; default: break; } @@ -1127,18 +1181,22 @@ class cMenuWhatsOn : public cOsdMenu { private: eOSState Record(void); eOSState Switch(void); + static const cEventInfo *scheduleEventInfo; public: cMenuWhatsOn(const cSchedules *Schedules, bool Now); + static const cEventInfo *ScheduleEventInfo(void); virtual eOSState ProcessKey(eKeys Key); }; +const cEventInfo *cMenuWhatsOn::scheduleEventInfo = NULL; + static int CompareEventChannel(const void *p1, const void *p2) { return (int)( (*(const cEventInfo **)p1)->GetChannelNumber() - (*(const cEventInfo **)p2)->GetChannelNumber()); } cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now) -:cOsdMenu(Now ? "What's on now?" : "What's on next?", 4, 7, 6) +:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), 4, 7, 6) { const cSchedule *Schedule = Schedules->First(); const cEventInfo **pArray = NULL; @@ -1164,7 +1222,14 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now) Add(new cMenuWhatsOnItem(pArray[a])); delete pArray; - SetHelp("Record", Now ? "Next" : "Now", "Schedule", "Switch"); + SetHelp(tr("Record"), Now ? tr("Next") : tr("Now"), tr("Schedule"), tr("Switch")); +} + +const cEventInfo *cMenuWhatsOn::ScheduleEventInfo(void) +{ + const cEventInfo *ei = scheduleEventInfo; + scheduleEventInfo = NULL; + return ei; } eOSState cMenuWhatsOn::Switch(void) @@ -1175,7 +1240,7 @@ eOSState cMenuWhatsOn::Switch(void) if (channel && channel->Switch()) return osEnd; } - Interface->Error("Can't switch channel!"); + Interface->Error(tr("Can't switch channel!")); return osContinue; } @@ -1184,9 +1249,16 @@ eOSState cMenuWhatsOn::Record(void) cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current()); if (item) { cTimer *timer = new cTimer(item->eventInfo); - Timers.Add(timer); - Timers.Save(); - isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + cTimer *t = Timers.GetTimer(timer); + if (!t) { + Timers.Add(timer); + Timers.Save(); + isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + } + else { + delete timer; + timer = t; + } return AddSubMenu(new cMenuEditTimer(timer->Index(), true)); } return osContinue; @@ -1199,7 +1271,12 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { case kRed: return Record(); - case kYellow: return osBack; + case kYellow: { + cMenuWhatsOnItem *mi = (cMenuWhatsOnItem *)Get(Current()); + if (mi) + scheduleEventInfo = mi->eventInfo; + } + return osBack; case kBlue: return Switch(); case kOk: if (Count()) return AddSubMenu(new cMenuEvent(((cMenuWhatsOnItem *)Get(Current()))->eventInfo, true)); @@ -1234,7 +1311,7 @@ class cMenuSchedule : public cOsdMenu { const cSchedules *schedules; bool now, next; eOSState Record(void); - void PrepareSchedule(void); + void PrepareSchedule(cChannel *Channel); void PrepareWhatsOnNext(bool On); public: cMenuSchedule(void); @@ -1242,17 +1319,15 @@ class cMenuSchedule : public cOsdMenu { }; cMenuSchedule::cMenuSchedule(void) -:cOsdMenu("Schedule", 6, 6) +:cOsdMenu("", 6, 6) { now = next = false; - cChannel *channel = Channels.GetByNumber(CurrentChannel); + cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel()); if (channel) { - char *buffer = NULL; - asprintf(&buffer, "Schedule - %s", channel->name); - SetTitle(buffer, false); + schedules = cDvbApi::PrimaryDvbApi->Schedules(&threadLock); + PrepareSchedule(channel); + SetHelp(tr("Record"), tr("Now"), tr("Next")); } - PrepareSchedule(); - SetHelp("Record", "Now", "Next"); } static int CompareEventTime(const void *p1, const void *p2) @@ -1260,11 +1335,14 @@ static int CompareEventTime(const void *p1, const void *p2) return (int)((*(cEventInfo **)p1)->GetTime() - (*(cEventInfo **)p2)->GetTime()); } -void cMenuSchedule::PrepareSchedule(void) +void cMenuSchedule::PrepareSchedule(cChannel *Channel) { - schedules = cDvbApi::PrimaryDvbApi->Schedules(&threadLock); + Clear(); + char *buffer = NULL; + asprintf(&buffer, tr("Schedule - %s"), Channel->name); + SetTitle(buffer, false); if (schedules) { - const cSchedule *Schedule = schedules->GetSchedule(); + const cSchedule *Schedule = Channel->pnr ? schedules->GetSchedule(Channel->pnr) : schedules->GetSchedule(); int num = Schedule->NumEvents(); const cEventInfo **pArray = (const cEventInfo **)malloc(num * sizeof(cEventInfo *)); if (pArray) { @@ -1290,9 +1368,16 @@ eOSState cMenuSchedule::Record(void) cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current()); if (item) { cTimer *timer = new cTimer(item->eventInfo); - Timers.Add(timer); - Timers.Save(); - isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + cTimer *t = Timers.GetTimer(timer); + if (!t) { + Timers.Add(timer); + Timers.Save(); + isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); + } + else { + delete timer; + timer = t; + } return AddSubMenu(new cMenuEditTimer(timer->Index(), true)); } return osContinue; @@ -1319,8 +1404,17 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) default: break; } } - else if (!HasSubMenu()) + else if (!HasSubMenu()) { now = next = false; + const cEventInfo *ei = cMenuWhatsOn::ScheduleEventInfo(); + if (ei) { + cChannel *channel = Channels.GetByServiceID(ei->GetServiceID()); + if (channel) { + PrepareSchedule(channel); + Display(); + } + } + } return state; } @@ -1347,7 +1441,7 @@ void cMenuRecordingItem::Set(void) // --- cMenuRecordings ------------------------------------------------------- cMenuRecordings::cMenuRecordings(void) -:cOsdMenu("Recordings", 6, 6) +:cOsdMenu(tr("Recordings"), 6, 6) { if (Recordings.Load()) { const char *lastReplayed = cReplayControl::LastReplayed(); @@ -1357,7 +1451,7 @@ cMenuRecordings::cMenuRecordings(void) recording = Recordings.Next(recording); } } - SetHelp("Play", NULL, "Delete", "Summary"); + SetHelp(tr("Play"), NULL, tr("Delete"), tr("Summary")); Display(); } @@ -1377,18 +1471,18 @@ eOSState cMenuRecordings::Del(void) if (ri) { //XXX what if this recording's file is currently in use??? //XXX if (!ti->recording) { - if (Interface->Confirm("Delete Recording?")) { + if (Interface->Confirm(tr("Delete Recording?"))) { if (ri->recording->Delete()) { cReplayControl::ClearLastReplayed(ri->recording->FileName()); cOsdMenu::Del(Current()); Display(); } else - Interface->Error("Error while deleting recording!"); + Interface->Error(tr("Error while deleting recording!")); } //XXX } //XXX else -//XXX Interface->Error("Timer is recording!"); +//XXX Interface->Error(tr("Timer is recording!")); } return osContinue; } @@ -1399,7 +1493,7 @@ eOSState cMenuRecordings::Summary(void) return osContinue; cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); if (ri && ri->recording->Summary() && *ri->recording->Summary()) - return AddSubMenu(new cMenuSummary(ri->recording->Summary())); + return AddSubMenu(new cMenuText(tr("Summary"), ri->recording->Summary())); return osContinue; } @@ -1425,24 +1519,36 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) class cMenuSetup : public cOsdMenu { private: cSetup data; + int osdLanguage; + void Set(void); public: cMenuSetup(void); virtual eOSState ProcessKey(eKeys Key); }; cMenuSetup::cMenuSetup(void) -:cOsdMenu("Setup", 20) +:cOsdMenu("", 25) { data = Setup; - Add(new cMenuEditIntItem( "PrimaryDVB", &data.PrimaryDVB, 1, cDvbApi::NumDvbApis)); - Add(new cMenuEditBoolItem("ShowInfoOnChSwitch", &data.ShowInfoOnChSwitch)); - Add(new cMenuEditBoolItem("MenuScrollPage", &data.MenuScrollPage)); - Add(new cMenuEditBoolItem("MarkInstantRecord", &data.MarkInstantRecord)); - Add(new cMenuEditIntItem( "LnbFrequLo", &data.LnbFrequLo)); - Add(new cMenuEditIntItem( "LnbFrequHi", &data.LnbFrequHi)); - Add(new cMenuEditIntItem( "SetSystemTime", &data.SetSystemTime)); - Add(new cMenuEditIntItem( "MarginStart", &data.MarginStart)); - Add(new cMenuEditIntItem( "MarginStop", &data.MarginStop)); + osdLanguage = Setup.OSDLanguage; + Set(); +} + +void cMenuSetup::Set(void) +{ + Clear(); + SetTitle(tr("Setup")); + Add(new cMenuEditStraItem(tr("OSD-Language"), &data.OSDLanguage, NumLanguages, Languages())); + Add(new cMenuEditIntItem( tr("PrimaryDVB"), &data.PrimaryDVB, 1, cDvbApi::NumDvbApis)); + Add(new cMenuEditBoolItem(tr("ShowInfoOnChSwitch"), &data.ShowInfoOnChSwitch)); + Add(new cMenuEditBoolItem(tr("MenuScrollPage"), &data.MenuScrollPage)); + Add(new cMenuEditBoolItem(tr("MarkInstantRecord"), &data.MarkInstantRecord)); + Add(new cMenuEditIntItem( tr("LnbFrequLo"), &data.LnbFrequLo)); + Add(new cMenuEditIntItem( tr("LnbFrequHi"), &data.LnbFrequHi)); + Add(new cMenuEditBoolItem(tr("SetSystemTime"), &data.SetSystemTime)); + Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart)); + Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop)); + Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout)); } eOSState cMenuSetup::ProcessKey(eKeys Key) @@ -1451,7 +1557,7 @@ eOSState cMenuSetup::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { - case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack; + case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osEnd; cDvbApi::PrimaryDvbApi->SetUseTSTime(data.SetSystemTime); Setup = data; Setup.Save(); @@ -1459,23 +1565,79 @@ eOSState cMenuSetup::ProcessKey(eKeys Key) default: break; } } + if (data.OSDLanguage != osdLanguage) { + int OriginalOSDLanguage = Setup.OSDLanguage; + Setup.OSDLanguage = data.OSDLanguage; + Set(); + Display(); + osdLanguage = data.OSDLanguage; + Setup.OSDLanguage = OriginalOSDLanguage; + } + return state; +} + +// --- cMenuCommands --------------------------------------------------------- + +class cMenuCommands : public cOsdMenu { +private: + eOSState Execute(void); +public: + cMenuCommands(void); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuCommands::cMenuCommands(void) +:cOsdMenu(tr("Commands")) +{ + int i = 0; + cCommand *command; + + while ((command = Commands.Get(i)) != NULL) { + Add(new cOsdItem(command->Title())); + i++; + } +} + +eOSState cMenuCommands::Execute(void) +{ + cCommand *command = Commands.Get(Current()); + if (command) { + const char *Result = command->Execute(); + if (Result) + return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); + } + return osContinue; +} + +eOSState cMenuCommands::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case kOk: return Execute(); + default: break; + } + } return state; } // --- cMenuMain ------------------------------------------------------------- -#define STOP_RECORDING "Stop recording " +#define STOP_RECORDING tr("Stop recording ") cMenuMain::cMenuMain(bool Replaying) -:cOsdMenu("Main") -{ - Add(new cOsdItem("Schedule", osSchedule)); - Add(new cOsdItem("Channels", osChannels)); - Add(new cOsdItem("Timer", osTimer)); - Add(new cOsdItem("Recordings", osRecordings)); - Add(new cOsdItem("Setup", osSetup)); +:cOsdMenu(tr("Main")) +{ + Add(new cOsdItem(tr("Schedule"), osSchedule)); + Add(new cOsdItem(tr("Channels"), osChannels)); + Add(new cOsdItem(tr("Timers"), osTimers)); + Add(new cOsdItem(tr("Recordings"), osRecordings)); + Add(new cOsdItem(tr("Setup"), osSetup)); + if (Commands.Count()) + Add(new cOsdItem(tr("Commands"), osCommands)); if (Replaying) - Add(new cOsdItem("Stop replaying", osStopReplay)); + Add(new cOsdItem(tr("Stop replaying"), osStopReplay)); const char *s = NULL; while ((s = cRecordControls::GetInstantId(s)) != NULL) { char *buffer = NULL; @@ -1483,7 +1645,7 @@ cMenuMain::cMenuMain(bool Replaying) Add(new cOsdItem(buffer, osStopRecord)); delete buffer; } - SetHelp("Record", NULL, NULL, cReplayControl::LastReplayed() ? "Resume" : NULL); + SetHelp(tr("Record"), NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); Display(); lastActivity = time(NULL); } @@ -1495,10 +1657,11 @@ eOSState cMenuMain::ProcessKey(eKeys Key) switch (state) { case osSchedule: return AddSubMenu(new cMenuSchedule); case osChannels: return AddSubMenu(new cMenuChannels); - case osTimer: return AddSubMenu(new cMenuTimers); + case osTimers: return AddSubMenu(new cMenuTimers); case osRecordings: return AddSubMenu(new cMenuRecordings); case osSetup: return AddSubMenu(new cMenuSetup); - case osStopRecord: if (Interface->Confirm("Stop Recording?")) { + case osCommands: return AddSubMenu(new cMenuCommands); + case osStopRecord: if (Interface->Confirm(tr("Stop Recording?"))) { cOsdItem *item = Get(Current()); if (item) { cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING)); @@ -1547,7 +1710,7 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched, bool Group) cDisplayChannel::cDisplayChannel(eKeys FirstKey) :cOsdBase(true) { - oldNumber = CurrentChannel; + oldNumber = cDvbApi::CurrentChannel(); number = 0; lastTime = time_ms(); Interface->Open(MenuColumns, 5); @@ -1571,7 +1734,7 @@ void cDisplayChannel::DisplayChannel(const cChannel *Channel) if (Channel && Channel->number) snprintf(buffer, BufSize, "%d %s", Channel->number, Channel->name); else - snprintf(buffer, BufSize, "%s", Channel ? Channel->name : "*** Invalid Channel ***"); + snprintf(buffer, BufSize, "%s", Channel ? Channel->name : tr("*** Invalid Channel ***")); Interface->Fill(0, 0, MenuColumns, 1, clrBackground); Interface->Write(0, 0, buffer); time_t t = time(NULL); @@ -1697,12 +1860,12 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer = new cTimer(true); Timers.Add(timer); Timers.Save(); - asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s on %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), dvbApi->Index() + 1); + asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), dvbApi->Index() + 1); } timer->SetRecording(true); Channels.SwitchTo(timer->channel, dvbApi); cRecording Recording(timer); - if (dvbApi->StartRecord(Recording.FileName())) + if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority)) Recording.WriteSummary(); Interface->DisplayRecording(dvbApi->Index(), true); } @@ -1744,12 +1907,13 @@ cRecordControl *cRecordControls::RecordControls[MAXDVBAPI] = { NULL }; bool cRecordControls::Start(cTimer *Timer) { - int ch = Timer ? Timer->channel : CurrentChannel; + int ch = Timer ? Timer->channel : cDvbApi::CurrentChannel(); cChannel *channel = Channels.GetByNumber(ch); if (channel) { - cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca); + cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca, Timer ? Timer->priority : DEFAULTPRIORITY); if (dvbApi) { + Stop(dvbApi); for (int i = 0; i < MAXDVBAPI; i++) { if (!RecordControls[i]) { RecordControls[i] = new cRecordControl(dvbApi, Timer); @@ -1776,6 +1940,18 @@ void cRecordControls::Stop(const char *InstantId) } } +void cRecordControls::Stop(cDvbApi *DvbApi) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + if (RecordControls[i]) { + if (RecordControls[i]->Uses(DvbApi)) { + isyslog(LOG_INFO, "stopping recording on DVB device %d due to higher priority", DvbApi->Index() + 1); + RecordControls[i]->Stop(); + } + } + } +} + const char *cRecordControls::GetInstantId(const char *LastInstantId) { for (int i = 0; i < MAXDVBAPI; i++) { diff --git a/menu.h b/menu.h index d979069e4..8153f5d78 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.13 2000/11/01 14:03:09 kls Exp $ + * $Id: menu.h 1.14 2000/11/12 12:33:00 kls Exp $ */ #ifndef _MENU_H @@ -59,6 +59,7 @@ class cRecordControl { cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL); virtual ~cRecordControl(); bool Process(void); + bool Uses(cDvbApi *DvbApi) { return DvbApi == dvbApi; } void Stop(bool KeepInstant = false); bool IsInstant(void) { return instantId; } const char *InstantId(void) { return instantId; } @@ -70,6 +71,7 @@ class cRecordControls { public: static bool Start(cTimer *Timer = NULL); static void Stop(const char *InstantId); + static void Stop(cDvbApi *DvbApi); static const char *GetInstantId(const char *LastInstantId); static void Process(void); }; diff --git a/osd.c b/osd.c index f3458274b..bc9c94850 100644 --- a/osd.c +++ b/osd.c @@ -4,12 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.11 2000/11/01 11:21:51 kls Exp $ + * $Id: osd.c 1.13 2000/11/12 15:29:25 kls Exp $ */ #include "osd.h" #include #include +#include "i18n.h" // --- cOsdItem -------------------------------------------------------------- @@ -188,6 +189,13 @@ void cOsdMenu::DisplayCurrent(bool Current) item->Display(current - first, Current ? clrBlack : clrWhite, Current ? clrCyan : clrBackground); } +void cOsdMenu::Clear(void) +{ + first = 0; + current = marked = -1; + cList::Clear(); +} + bool cOsdMenu::SpecialItem(int idx) { cOsdItem *item = Get(idx); @@ -248,7 +256,7 @@ void cOsdMenu::Mark(void) { if (Count() && marked < 0) { marked = current; - SetStatus("Up/Dn for new location - OK to move"); + SetStatus(tr("Up/Dn for new location - OK to move")); } } diff --git a/osd.h b/osd.h index 473e87de4..0d8085dfd 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.14 2000/11/01 14:29:07 kls Exp $ + * $Id: osd.h 1.17 2000/11/12 15:27:34 kls Exp $ */ #ifndef __OSD_H @@ -21,9 +21,10 @@ enum eOSState { osUnknown, osContinue, osSchedule, osChannels, - osTimer, + osTimers, osRecordings, osSetup, + osCommands, osRecord, osReplay, osStopRecord, @@ -77,6 +78,7 @@ class cOsdMenu : public cOsdBase, public cList { const char *status; protected: bool visible; + virtual void Clear(void); bool SpecialItem(int idx); void RefreshCurrent(void); void DisplayCurrent(bool Current); diff --git a/recording.c b/recording.c index 3ddf8d350..f45be9632 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.20 2000/11/01 16:00:36 kls Exp $ + * $Id: recording.c 1.21 2000/11/18 16:22:29 kls Exp $ */ #define _GNU_SOURCE @@ -32,6 +32,7 @@ #define MINDISKSPACE 1024 // MB #define DISKCHECKDELTA 300 // seconds between checks for free disk space +#define REMOVELATENCY 10 // seconds to wait until next check after removing a file void AssertFreeDiskSpace(void) { @@ -51,8 +52,10 @@ void AssertFreeDiskSpace(void) r0 = r; r = Recordings.Next(r); } - if (r0 && r0->Remove()) + if (r0 && r0->Remove()) { + LastFreeDiskCheck += REMOVELATENCY; return; + } } // No "deleted" files to remove, so let's see if we can delete a recording: if (Recordings.Load(false)) { diff --git a/remote.c b/remote.c index f60d7685c..349a44527 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.18 2000/10/08 16:49:41 kls Exp $ + * $Id: remote.c 1.19 2000/11/11 11:22:22 kls Exp $ */ #include "remote.h" @@ -73,7 +73,7 @@ bool cRcIoKBD::GetCommand(unsigned int *Command, bool *Repeat, bool *Release) { if (Command) { *Command = getch(); - return *Command > 0; + return int(*Command) > 0; } return false; } diff --git a/svdrp.c b/svdrp.c index cf91cafb2..66ae8e9ad 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.11 2000/10/08 12:21:14 kls Exp $ + * $Id: svdrp.c 1.12 2000/11/05 13:44:42 kls Exp $ */ #define _GNU_SOURCE @@ -302,13 +302,13 @@ void cSVDRP::CmdCHAN(const char *Option) n = o; } else if (strcmp(Option, "-") == 0) { - n = CurrentChannel; - if (CurrentChannel > 1) + n = cDvbApi::CurrentChannel(); + if (n > 1) n--; } else if (strcmp(Option, "+") == 0) { - n = CurrentChannel; - if (CurrentChannel < Channels.MaxNumber()) + n = cDvbApi::CurrentChannel(); + if (n < Channels.MaxNumber()) n++; } else { @@ -342,11 +342,11 @@ void cSVDRP::CmdCHAN(const char *Option) return; } } - cChannel *channel = Channels.GetByNumber(CurrentChannel); + cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel()); if (channel) - Reply(250, "%d %s", CurrentChannel, channel->name); + Reply(250, "%d %s", channel->number, channel->name); else - Reply(550, "Unable to find channel \"%d\"", CurrentChannel); + Reply(550, "Unable to find channel \"%d\"", cDvbApi::CurrentChannel()); } void cSVDRP::CmdDELC(const char *Option) diff --git a/thread.c b/thread.c index b124581fc..67b5ab96e 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.3 2000/10/28 15:26:02 kls Exp $ + * $Id: thread.c 1.4 2000/11/14 18:38:25 kls Exp $ */ #include "thread.h" @@ -24,7 +24,6 @@ cThread::cThread(void) signal(SIGIO, SignalHandler); signalHandlerInstalled = true; } - pthread_mutex_init(&mutex, NULL); running = false; parentPid = lockingPid = 0; locked = 0; @@ -32,7 +31,6 @@ cThread::cThread(void) cThread::~cThread() { - pthread_mutex_destroy(&mutex); } void cThread::SignalHandler(int signum) @@ -64,7 +62,7 @@ void cThread::Stop(void) bool cThread::Lock(void) { if (!lockingPid || lockingPid != getpid()) { - pthread_mutex_lock(&mutex); + Mutex.Lock(); lockingPid = getpid(); } locked++; @@ -75,7 +73,7 @@ void cThread::Unlock(void) { if (!--locked) { lockingPid = 0; - pthread_mutex_unlock(&mutex); + Mutex.Unlock(); } } diff --git a/thread.h b/thread.h index b47f6d715..c85c51e2c 100644 --- a/thread.h +++ b/thread.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.2 2000/10/28 15:08:09 kls Exp $ + * $Id: thread.h 1.3 2000/11/14 18:38:11 kls Exp $ */ #ifndef __THREAD_H @@ -13,11 +13,21 @@ #include #include +class cMutex { +private: + pthread_mutex_t mutex; +public: + cMutex(void) { pthread_mutex_init(&mutex, NULL); } + ~cMutex() { pthread_mutex_destroy(&mutex); } + void Lock(void) { pthread_mutex_lock(&mutex); } + void Unlock(void) { pthread_mutex_unlock(&mutex); } + }; + class cThread { friend class cThreadLock; private: pthread_t thread; - pthread_mutex_t mutex; + cMutex Mutex; pid_t parentPid, lockingPid; int locked; bool running; diff --git a/timers.conf b/timers.conf index 8f6bcf2fb..05946a53a 100644 --- a/timers.conf +++ b/timers.conf @@ -1,15 +1,14 @@ -1:15:M------:2128:2205:99:7:Neues: +1:15:M------:2128:2205:80:7:Neues: 1:3:-T-----:2013:2125:99:99:SevenDays: 1:10:-T-----:2058:2202:99:10:Quarks: -1:26:-T-----:2250:0005:99:99:UFO: -1:14:--W----:1920:2020:99:99:Rettungsflieger: +1:25:-T-----:2305:0020:99:99:UFO: +1:14:--W----:1920:2020:70:99:Rettungsflieger: 0:2:--W----:2110:2325:99:99:BulleVonToelz: -1:3:---T---:2210:2315:99:10:IngoAppelt: +1:3:---T---:2210:2315:50:20:IngoAppelt: 1:2:----F--:2013:2125:99:99:Farscape: -1:1:----F--:2215:2325:99:99:7Tage7Koepfe: -1:11:-----S-:2058:2135:99:99:Computer: -1:2:-----S-:2250:0005:99:30:Wochenshow: +1:1:----F--:2215:2325:50:20:7Tage7Koepfe: +0:11:-----S-:2058:2135:99:99:Computer: +0:2:-----S-:2220:2340:99:30:Wochenshow: 1:11:------S:2013:2035:99:10:Centauri: 1:15:MTWTF--:1828:1901:10:5:nano: 1:1:MTWTF--:1553:1710:99:99:Hammerman: -1:3:3:0220:0350:99:99:Seven Days - Das Tor zur Zeit:Die Rache des Alien||Als das Zeitsprung-Team die Leiche eines bei Roswell gefundenen Aliens obduziert, entdecken sie einen Chip in seiner Wirbelsule. Dr. Ballard, der hnliche Rckenprobleme wie der Alien hat, lsst sich den Chip einsetzen. Tatschlich regeneriert Ballard vollstndig. Doch dann ndert sich sein Verhalten: Er wird dem Alien immer hnlicher. Schlielich gelingt es ihm, mit einer Superwaffe Millionen Menschen zu tten - einschlielich des Zeitsprung-Teams. Nur Parker berlebt. diff --git a/tools.c b/tools.c index 4acea0b3d..6d86f1620 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.22 2000/10/29 11:21:55 kls Exp $ + * $Id: tools.c 1.23 2000/11/11 15:17:12 kls Exp $ */ #define _GNU_SOURCE @@ -92,6 +92,18 @@ char *skipspace(const char *s) return (char *)s; } +char *stripspace(char *s) +{ + if (s && *s) { + for (char *p = s + strlen(s) - 1; p >= s; p--) { + if (!isspace(*p)) + break; + *p = 0; + } + } + return s; +} + bool isempty(const char *s) { return !(s && *skipspace(s)); diff --git a/tools.h b/tools.h index b5bdd278d..f83e7da4a 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.18 2000/10/29 11:19:20 kls Exp $ + * $Id: tools.h 1.20 2000/11/12 15:27:06 kls Exp $ */ #ifndef __TOOLS_H @@ -41,6 +41,7 @@ char *readline(FILE *f); char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); char *skipspace(const char *s); +char *stripspace(char *s); bool isempty(const char *s); int time_ms(void); void delay_ms(int ms); @@ -95,7 +96,7 @@ class cListBase { void Del(cListObject *Object); virtual void Move(int From, int To); void Move(cListObject *From, cListObject *To); - void Clear(void); + virtual void Clear(void); cListObject *Get(int Index) const; int Count(void) const; }; diff --git a/vdr.c b/vdr.c index b1321aef2..8a842003a 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.41 2000/11/01 14:31:32 kls Exp $ + * $Id: vdr.c 1.46 2000/11/18 13:46:56 kls Exp $ */ #include @@ -31,6 +31,7 @@ #include #include "config.h" #include "dvbapi.h" +#include "i18n.h" #include "interface.h" #include "menu.h" #include "recording.h" @@ -156,11 +157,6 @@ int main(int argc, char *argv[]) } isyslog(LOG_INFO, "VDR version %s started", VDRVERSION); - // DVB interfaces: - - if (!cDvbApi::Init()) - abort(); - // Configuration data: if (!ConfigDirectory) @@ -169,15 +165,23 @@ int main(int argc, char *argv[]) Setup.Load(AddDirectory(ConfigDirectory, "setup.conf")); Channels.Load(AddDirectory(ConfigDirectory, "channels.conf")); Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); + Commands.Load(AddDirectory(ConfigDirectory, "commands.conf")); #ifdef REMOTE_LIRC Keys.SetDummyValues(); #else bool KeysLoaded = Keys.Load(AddDirectory(ConfigDirectory, KEYS_CONF)); #endif + // DVB interfaces: + + if (!cDvbApi::Init()) + abort(); + cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); - Channels.SwitchTo(CurrentChannel); + Channels.SwitchTo(1); + + cEITScanner EITScanner; // User interface: @@ -199,15 +203,15 @@ int main(int argc, char *argv[]) cOsdBase *Menu = NULL; cReplayControl *ReplayControl = NULL; int LastChannel = -1; - int PreviousChannel = CurrentChannel; + int PreviousChannel = cDvbApi::CurrentChannel(); while (!Interrupted) { // Channel display: - if (CurrentChannel != LastChannel) { + if (!EITScanner.Active() && cDvbApi::CurrentChannel() != LastChannel) { if (!Menu) - Menu = new cDisplayChannel(CurrentChannel, LastChannel > 0); + Menu = new cDisplayChannel(cDvbApi::CurrentChannel(), LastChannel > 0); PreviousChannel = LastChannel; - LastChannel = CurrentChannel; + LastChannel = cDvbApi::CurrentChannel(); } // Timers and Recordings: if (!Menu) { @@ -222,6 +226,8 @@ int main(int argc, char *argv[]) // User Input: cOsdBase **Interact = Menu ? &Menu : (cOsdBase **)&ReplayControl; eKeys key = Interface->GetKey(!*Interact || !(*Interact)->NeedsFastResponse()); + if (NORMALKEY(key) != kNone) + EITScanner.Activity(); if (*Interact) { switch ((*Interact)->ProcessKey(key)) { case osMenu: DELETENULL(Menu); @@ -229,7 +235,7 @@ int main(int argc, char *argv[]) break; case osRecord: DELETENULL(Menu); if (!cRecordControls::Start()) - Interface->Error("No free DVB device to record!"); + Interface->Error(tr("No free DVB device to record!")); break; case osRecordings: DELETENULL(Menu); @@ -246,7 +252,7 @@ int main(int argc, char *argv[]) break; case osSwitchDvb: DELETENULL(*Interact); - Interface->Info("Switching primary DVB..."); + Interface->Info(tr("Switching primary DVB...")); cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); break; case osBack: @@ -259,7 +265,7 @@ int main(int argc, char *argv[]) switch (key) { // Toggle channels: case k0: - if (PreviousChannel != CurrentChannel) + if (PreviousChannel != cDvbApi::CurrentChannel()) Channels.SwitchTo(PreviousChannel); break; // Direct Channel Select: @@ -287,7 +293,7 @@ int main(int argc, char *argv[]) case kUp: case kDown|k_Repeat: case kDown: if (!Interface->Recording()) { - int n = CurrentChannel + (NORMALKEY(key) == kUp ? 1 : -1); + int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1); cChannel *channel = Channels.GetByNumber(n); if (channel) channel->Switch(); @@ -300,6 +306,8 @@ int main(int argc, char *argv[]) default: break; } } + if (!Menu) + EITScanner.Process(); } isyslog(LOG_INFO, "caught signal %d", Interrupted); delete Menu; From 3fe3c15d5db9c1f3982ffe6dac1ae4ad56d1664d Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Thu, 18 Jan 2001 18:00:00 +0100 Subject: [PATCH 016/307] Version 0.70 - VDR now requires driver version 0.8.1 or higher. - Recordings are now saved in PES mode. Note that you now need to install the driver *WITHOUT* 'outstream=0'! This is the default when you 'make insmod' in the DVB/driver directory. Old recordings (in AV_PES mode) can still be replayed (as long as the driver still supports replaying AV_PES files). The only limitation with this is that in fast forward/back mode the picture may be slightly distorted and there may be sound fragments. - The EPG data is now dumped into the file /video/epg.data every ten minutes. Use the Perl script 'epg2html.pl' to convert the raw EPG data into a simple HTML programme listing. - Fixed handling of channel switching with the "Blue" button in the "What's on now/next?" menus. - Fixed saving the MarginStop setup parameter. - Fixed missing initialization in cConfig. - Implemented "On Disk Editing". - There is no more default 'timers.conf' file. - Added Italian language texts (thanks to Alberto Carraro). - Fixed starting a replay session when the program is currently in "transfer mode". - Fixed setting/modifying timers via SVDRP with empty summary fields. - Fixed a problem with recordings that have a single quote character in their name (this is now mapped to 0x01). - Changed the value for Diseqc to '0' in the default 'channels.conf'. - Fixed displaying channels and recording status in the RCU's LED display when a recording is interrupted due to higher priority. - Implemented safe writing of config files (first writes into a temporary file and then renames it). - In case the video data stream is broken the log message will come only every 5 seconds. - The current channel is now saved in the 'setup.conf' file when VDR is cancelled, and will be restored next time it is started (thanks to Deti Fliegl). - The EIT scanning thread is now locked when switching channels to avoid problems. - Encrypted channels can now be selected even without knowing the PNR (however, it is still necessary for the EPG info). --- CONTRIBUTORS | 6 + FORMATS | 23 + HISTORY | 38 ++ INSTALL | 17 +- MANUAL | 46 ++ Makefile | 8 +- README | 2 +- TODO | 3 - channels.conf | 291 ++++----- config.c | 29 +- config.h | 73 ++- dvb.c.071.diff | 100 ---- dvbapi.c | 1533 +++++++++++++++++++++++++++--------------------- dvbapi.h | 64 +- dvbosd.c | 12 +- dvbosd.h | 3 +- eit.c | 58 +- eit.h | 5 +- epg2html.pl | 96 +++ i18n.c | 140 ++++- interface.c | 8 +- interface.h | 3 +- menu.c | 265 +++++++-- menu.h | 11 +- osd.h | 3 +- recording.c | 112 +++- recording.h | 25 +- remote.c | 6 +- svdrp.c | 3 +- thread.c | 36 +- thread.h | 7 +- timers.conf | 14 - tools.c | 119 ++-- tools.h | 33 +- vdr.c | 15 +- videodir.c | 19 +- videodir.h | 3 +- 37 files changed, 2056 insertions(+), 1173 deletions(-) delete mode 100644 dvb.c.071.diff create mode 100644 epg2html.pl delete mode 100644 timers.conf diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 279706da6..ee44ada63 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -43,3 +43,9 @@ Matthias Schniedermeyer Miha Setina for translating the OSD texts to the Slovenian language. + +Alberto Carraro + for translating the OSD texts to the Italian language. + +Deti Fliegl + for implementing the 'CurrentChannel' setup parameter. diff --git a/FORMATS b/FORMATS index 3eee494f6..ed52518d2 100644 --- a/FORMATS +++ b/FORMATS @@ -90,3 +90,26 @@ Video Disk Recorder File Formats CPU status : /usr/loval/bin/cpustatus 2>&1 Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' +* marks.vdr + + This file (if present in a recording directory) contains the editing marks + defined for this recording. + + Each line contains the definition of one mark in the following format: + + hh:mm:ss.ff comment + + where 'hh:mm:ss.ff' is a frame position within the recording, given as "hours, + minutes, seconds and (optional) frame number". 'comment' can be any string + and may be used to describe this mark. If present, 'comment' must be separated + from the frame position by at least one blank. + + The lines in this file need not necessarily appear in the correct temporal + sequence, they will be automatically sorted by time index. + + CURRENT RESTRICTIONS: + + - the 'comment' is currently not used by VDR + - marks must have a frame number, and that frame MUST be an I-frame (this + means that only marks generated by VDR itself can be used, since they + will always be guaranteed to mark I-frames). diff --git a/HISTORY b/HISTORY index 485f24a2c..8d5e88494 100644 --- a/HISTORY +++ b/HISTORY @@ -311,3 +311,41 @@ Video Disk Recorder Revision History can receive a certain channel on the primary interface. This is currently in an early state and may still cause some problems, but it appears to work nice already. + +2001-01-18: Version 0.70 + +- VDR now requires driver version 0.8.1 or higher. +- Recordings are now saved in PES mode. Note that you now need to install the + driver *WITHOUT* 'outstream=0'! This is the default when you 'make insmod' in + the DVB/driver directory. + Old recordings (in AV_PES mode) can still be replayed (as long as the driver + still supports replaying AV_PES files). The only limitation with this is that + in fast forward/back mode the picture may be slightly distorted and there may + be sound fragments. +- The EPG data is now dumped into the file /video/epg.data every ten minutes. + Use the Perl script 'epg2html.pl' to convert the raw EPG data into a simple + HTML programme listing. +- Fixed handling of channel switching with the "Blue" button in the "What's on + now/next?" menus. +- Fixed saving the MarginStop setup parameter. +- Fixed missing initialization in cConfig. +- Implemented "On Disk Editing". +- There is no more default 'timers.conf' file. +- Added Italian language texts (thanks to Alberto Carraro). +- Fixed starting a replay session when the program is currently in "transfer + mode". +- Fixed setting/modifying timers via SVDRP with empty summary fields. +- Fixed a problem with recordings that have a single quote character in their + name (this is now mapped to 0x01). +- Changed the value for Diseqc to '0' in the default 'channels.conf'. +- Fixed displaying channels and recording status in the RCU's LED display when + a recording is interrupted due to higher priority. +- Implemented safe writing of config files (first writes into a temporary file + and then renames it). +- In case the video data stream is broken the log message will come only every + 5 seconds. +- The current channel is now saved in the 'setup.conf' file when VDR is cancelled, + and will be restored next time it is started (thanks to Deti Fliegl). +- The EIT scanning thread is now locked when switching channels to avoid problems. +- Encrypted channels can now be selected even without knowing the PNR (however, it + is still necessary for the EPG info). diff --git a/INSTALL b/INSTALL index 7def1687e..e2a67a0fd 100644 --- a/INSTALL +++ b/INSTALL @@ -15,13 +15,11 @@ If you have the DVB driver source in a different location you will have to change the definition of DVBDIR in the Makefile. -This program requires the card driver version 0.71 or higher -to work properly. Currently you need to load the dvb.o module with -option outstream=0, so your insmod statement should read -'insmod dvb.o outstream=0'. This is necessary because 'vdr' works -with AV_PES data and will change once it has been modified to work -directly with MPEG2. You also need to apply the patch 'dvb.c.071.diff' -for the On Screen Display to work properly. +This program requires the card driver version 0.8.1 or higher +to work properly. You need to load the dvb.o module *without* option +'outstream=0' (previous versions of VDR required this option to have +the driver supply the data in AV_PES format; as of version 0.70 VDR +works with PES format). After extracting the package, change into the VDR directory and type 'make'. This should produce an executable file @@ -39,7 +37,7 @@ following values 'make' call to activate the respective control mode: REMOTE=RCU control via the "Remote Control Unit" receiver (see http://www.cadsoft.de/people/kls/vdr/remote.htm) REMOTE=LIRC control via the "Linux Infrared Remote Control" - (see http://fsinfo.cs.uni-sb.de/~columbus/lirc) + (see http://www.lirc.org) Adding "DEBUG_OSD=1" will use the PC screen (or current window) to display texts instead of the DVB card's on-screen display @@ -168,6 +166,5 @@ into learning mode. If the program has been compiled with 'REMOTE=LIRC', no 'keys.conf' file will be used. Instead, the key names as listed in the source file 'config.c' -must be used when setting up LIRC. See http://www2.arnes.si/~mthale1 for -more about LIRC. +must be used when setting up LIRC. See http://www.lirc.org for more about LIRC. diff --git a/MANUAL b/MANUAL index 46466bf8b..b0e9abe01 100644 --- a/MANUAL +++ b/MANUAL @@ -174,6 +174,52 @@ Video Disk Recorder User's Manual used to easily delete a recording after watching it, or to switch to a different recording. +* Editing a Recording + + While in Replay mode, the following keys can be used to manipulate editing + marks: + + - 0 Toggles an editing mark. If the mark indicator shows a red triangle, + the current mark is deleted. Otherwise a new mark is set at the + current position. + - 4, 6 Move an editing mark back and forward. You need to first jump to + an editing mark for this to work. + - 7, 9 Jump back and forward between editing marks. Replay goes into still + mode after jumping to a mark. + - 8 Positions replay at a point 3 seconds before the current or next + "start" mark and starts replay. + - 2 Start the actual cutting process. + + Editing marks are represented by black, vertical lines in the progress display. + A small black triangle at the top of the mark means that this is a "start" + mark, and a triangle at the bottom means that this is an "end" mark. + The cutting process will save all video data between "start" and "end" marks + into a new file (the original recording remains untouched). The new file will + have the same name as the original recording, preceeded with a '%' character + (imagine the '%' somehow looking like a pair of scissors ;-). Red bars in the + progress display indicate which video sequences will be saved by the cutting + process. + + The video sequences to be saved by the cutting process are determined by an + "even/odd" algorithm. This means that every odd numbered editing mark (i.e. + 1, 3, 5,...) represents a "start" mark, while every even numbered mark (2, 4, + 6,...) is an "end" mark. Inserting or toggling a mark on or off automatically + adjusts the sequence to the right side of that mark. + + Use the keys described under "Replay Control" to position to, e.g., the + beginning and end of commercial breaks and press the '0' key to set the + necessary editing marks. After that you may want to use the '7' and '9' + keys to jump to each mark and maybe use the '4' and '6' keys to fine tune + them. Once all marks are in place, press '2' to start the actual cutting + process, which will run as a background process. When replaying the edited + version of the recording you can use the '8' key to jump to a point just + before the next cut and have a look at the resulting sequence. + + Currently editing marks can only be set at I-frames, which typically is + every 12th frame. So editing can be done with a resolution of roughly half + a second. A "start" mark marks the first frame of a resulting video + sequence, and an "end" mark marks the last frame of that sequence. + * Programming the Timer Use the "Timer" menu to maintain your list of timer controlled recordings. diff --git a/Makefile b/Makefile index 739d3942b..4505c7b56 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.16 2000/11/18 14:58:10 kls Exp $ +# $Id: Makefile 1.18 2001/01/13 12:26:43 kls Exp $ DVBDIR = ../DVB @@ -37,9 +37,9 @@ font: genfontfile fontfix.c fontosd.c # Dependencies: config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h videodir.h +dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h dvbosd.o : dvbosd.c dvbosd.h font.h tools.h -eit.o : eit.c eit.h thread.h tools.h +eit.o : eit.c config.h dvbapi.h dvbosd.h eit.h font.h thread.h tools.h videodir.h font.o : font.c font.h fontfix.c fontosd.c tools.h i18n.o : i18n.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h thread.h tools.h interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h @@ -48,7 +48,7 @@ osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h os recording.o: recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h -thread.o : thread.c thread.h +thread.o : thread.c thread.h tools.h tools.o : tools.c tools.h vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h videodir.o : videodir.c tools.h videodir.h diff --git a/README b/README index b1e071ee0..0dfc875ef 100644 --- a/README +++ b/README @@ -27,7 +27,7 @@ driver software (of course, the hardware still has to be bought). The on screen menu system is simple, but shall provide all the possibilites necessary to perform timer controlled recording, -file management and, maybe, even "on disk editing". The menus +file management and even "on disk editing". The menus of commercial set-top-boxes usually are a lot more fancy than the ones in this system, but here we have the full source code and can modify the menus in whatever way desired. diff --git a/TODO b/TODO index f2fb5ead2..1ae7d7176 100644 --- a/TODO +++ b/TODO @@ -3,8 +3,5 @@ TODO list for the Video Disk Recorder project * Implement simultaneous record/replay with a single DVB card once the card driver/firmware allows this. -* Implement "on-disk editing" to allow "cutting out" of certain - scenes in order to archive them (or, reversely, cut out - commercial breaks). * Implement channel scanning. * Implement remaining commands in SVDRP. diff --git a/channels.conf b/channels.conf index ce30919e9..43e69cd6f 100644 --- a/channels.conf +++ b/channels.conf @@ -1,147 +1,148 @@ -RTL:12188:h:1:27500:163:104:0:12003 -Sat.1:12480:v:1:27500:1791:1792:0:46 -Pro-7:12480:v:1:27500:255:256:0:898 -RTL2:12188:h:1:27500:166:128:0:12020 -ARD:11837:h:1:27500:101:102:0:28106 -BR3:11837:h:1:27500:201:202:0:28107 -Hessen-3:11837:h:1:27500:301:302:0:28108 -N3:12110:h:1:27500:2401:2402:0:28224 -SR3:11837:h:1:27500:501:502:0:28110 -WDR:11837:h:1:27500:601:602:0:28111 -BR-alpha:11837:h:1:27500:701:702:0:28112 -SWR BW:11837:h:1:27500:801:802:0:28113 -Phoenix:11837:h:1:27500:901:902:0:28114 -ZDF:11954:h:1:27500:110:120:0:28006 -3sat:11954:h:1:27500:210:220:0:28007 -KiKa:11954:h:1:27500:310:320:0:28008 -arte:11836:h:1:27500:401:402:0:28109 -ORF Sat:11954:h:1:27500:506:507:0:28010 -ZDF.info:11954:h:1:27500:610:620:0:28011 -CNN:12168:v:1:27500:165:100:0:28512 -Super RTL:12188:h:1:27500:165:120:0:12040 -VOX:12188:h:1:27500:167:136:0:12060 -DW TV:12363:v:1:27500:305:306:0:8905 -Kabel 1:12480:v:1:27500:511:512:0:899 -tm3:12480:v:1:27500:767:768:0:897 -DSF:12480:v:1:27500:1023:1024:0:900 -HOT:12480:v:1:27500:1279:1280:0:40 -Bloomberg TV Germany:12551:v:1:22000:162:99:0:12160 -BLOOMBERG TV:11817:v:1:27500:163:92:0:8004 -Bloomberg:12168:v:1:27500:167:112:0:12721 -Sky News:12552:v:1:22000:305:306:0:3995 -KinderNet:12574:h:1:22000:163:92:0:5020 -Alice:12610:v:1:22000:162:96:0:12200 -n-tv:12669:v:1:22000:162:96:0:12730 -Grand Tourisme:12670:v:1:22000:289:290:0:17300 -TW1:12692:h:1:22000:166:167:0:13013 -Eurosport:11954:h:1:27500:410:420:0:28009 -EinsExtra:12110:H:1:27500:101:102:0:28201 -EinsFestival:12110:H:1:27500:201:202:0:28202 -EinsMuXx:12110:H:1:27500:301:302:0:28203 -ZDF Theaterkanal:11954:H:1:27500:1110:1120:0:28016 -ZDF.doku:11954:H:1:27500:660:670:0:28014 -MDR:12110:h:1:27500:401:402:0:28204 -NICK-PARAMOUNT:12246:v:1:27500:167:108:0:29312 -ORB:12110:h:1:27500:501:502:0:28205 -B1:12110:h:1:27500:601:602:0:28206 -ARD Online-Kanal:12722:h:1:22000:8191:701:0:0 +RTL:12188:h:0:27500:163:104:0:12003 +Sat.1:12480:v:0:27500:1791:1792:0:46 +Pro-7:12480:v:0:27500:255:256:0:898 +RTL2:12188:h:0:27500:166:128:0:12020 +ARD:11837:h:0:27500:101:102:0:28106 +BR3:11837:h:0:27500:201:202:0:28107 +Hessen-3:11837:h:0:27500:301:302:0:28108 +N3:12110:h:0:27500:2401:2402:0:28224 +SR3:11837:h:0:27500:501:502:0:28110 +WDR:11837:h:0:27500:601:602:0:28111 +BR-alpha:11837:h:0:27500:701:702:0:28112 +SWR BW:11837:h:0:27500:801:802:0:28113 +Phoenix:11837:h:0:27500:901:902:0:28114 +ZDF:11954:h:0:27500:110:120:0:28006 +3sat:11954:h:0:27500:210:220:0:28007 +KiKa:11954:h:0:27500:310:320:0:28008 +arte:11836:h:0:27500:401:402:0:28109 +ORF Sat:11954:h:0:27500:506:507:0:28010 +ZDF.info:11954:h:0:27500:610:620:0:28011 +CNN:12168:v:0:27500:165:100:0:28512 +Super RTL:12188:h:0:27500:165:120:0:12040 +VOX:12188:h:0:27500:167:136:0:12060 +DW TV:12363:v:0:27500:305:306:0:8905 +Kabel 1:12480:v:0:27500:511:512:0:899 +tm3:12480:v:0:27500:767:768:0:897 +DSF:12480:v:0:27500:1023:1024:0:900 +HOT:12480:v:0:27500:1279:1280:0:40 +Bloomberg TV Germany:12551:v:0:22000:162:99:0:12160 +BLOOMBERG TV:11817:v:0:27500:163:92:0:8004 +Bloomberg:12168:v:0:27500:167:112:0:12721 +Sky News:12552:v:0:22000:305:306:0:3995 +KinderNet:12574:h:0:22000:163:92:0:5020 +Alice:12610:v:0:22000:162:96:0:12200 +n-tv:12669:v:0:22000:162:96:0:12730 +Grand Tourisme:12670:v:0:22000:289:290:0:17300 +TW1:12692:h:0:22000:166:167:0:13013 +Eurosport:11954:h:0:27500:410:420:0:28009 +EinsExtra:12110:h:0:27500:101:102:0:28201 +EinsFestival:12110:h:0:27500:201:202:0:28202 +EinsMuXx:12110:h:0:27500:301:302:0:28203 +ZDF Theaterkanal:11954:h:0:27500:1110:1120:0:28016 +ZDF.doku:11954:h:0:27500:660:670:0:28014 +MDR:12110:h:0:27500:401:402:0:28204 +NICK-PARAMOUNT:12246:v:0:27500:167:108:0:29312 +ORB:12110:h:0:27500:501:502:0:28205 +B1:12110:h:0:27500:601:602:0:28206 +ARD Online-Kanal:12722:h:0:22000:8191:701:0:0 :Premiere World -Premiere World Promo:11798:h:1:27500:255:256:0:8 -Premiere:11798:h:1:27500:511:512:2:10 -Star Kino:11798:h:1:27500:767:768:2:9 -Cine Action:11798:h:1:27500:1023:1024:2:20 -Cine Comedy:11798:h:1:27500:1279:1280:2:29 -Sci Fantasy:11798:h:1:27500:1535:1536:2:41 -Romantic Movies:11798:h:1:27500:1791:1792:2:11 -Studio Universal:11798:h:1:27500:2047:2048:2:21 -13th Street:11797:h:1:27500:2303:2304:2:43 -Junior:12031:h:1:27500:255:256:2:19 -K-Toon:12032:h:1:27500:511:512:2:12 -Disney Channel:12031:h:1:27500:767:768:2:15 -Fox Kids:11798:h:1:27500:255:256:2:0 -Sunset:12031:h:1:27500:1023:1024:2:16 -Comedy:12031:h:1:27500:1279:1280:2:28 -Planet:12031:h:1:27500:2047:2048:2:13 -Discovery Channel:12031:h:1:27500:1791:1792:2:14 -Krimi&Co:12031:h:1:27500:1535:1536:2:23 -Filmpalast:12090:v:1:27500:255:256:2:36 -Heimatkanal:11758:h:1:27500:2815:2816:2:517 -Goldstar:11758:h:1:27500:3839:3840:2:518 -Classica:12090:v:1:27500:767:768:2:34 -Seasons:12090:v:1:27500:511:512:2:33 -Blue Channel:11758:h:1:27500:2559:2560:2:516 -Feed (F1 Boxengasse):11720:h:1:27500:2559:2560:2:242 -Feed (F1 Data):11720:h:1:27500:3071:3072:2:244 -Feed (F1 Multi):11720:h:1:27500:2815:2816:2:243 -Feed (F1 On Board):11720:h:1:27500:2303:2304:2:241 -Feed (F1 Verfolger):11720:h:1:27500:2047:2048:2:240 +Premiere World Promo:11798:h:0:27500:255:256:0:8 +Premiere:11798:h:0:27500:511:512:2:10 +Star Kino:11798:h:0:27500:767:768:2:9 +Cine Action:11798:h:0:27500:1023:1024:2:20 +Cine Comedy:11798:h:0:27500:1279:1280:2:29 +Sci Fantasy:11798:h:0:27500:1535:1536:2:41 +Romantic Movies:11798:h:0:27500:1791:1792:2:11 +Studio Universal:11798:h:0:27500:2047:2048:2:21 +13th Street:11797:h:0:27500:2303:2304:2:43 +Junior:12031:h:0:27500:255:256:2:19 +K-Toon:12032:h:0:27500:511:512:2:12 +Disney Channel:12031:h:0:27500:767:768:2:15 +Fox Kids:11798:h:0:27500:255:256:2:0 +Sunset:12031:h:0:27500:1023:1024:2:16 +Comedy:12031:h:0:27500:1279:1280:2:28 +Planet:12031:h:0:27500:2047:2048:2:13 +Discovery Channel:12031:h:0:27500:1791:1792:2:14 +Krimi&Co:12031:h:0:27500:1535:1536:2:23 +Filmpalast:12090:v:0:27500:255:256:2:36 +Heimatkanal:11758:h:0:27500:2815:2816:2:517 +Goldstar:11758:h:0:27500:3839:3840:2:518 +Classica:12090:v:0:27500:767:768:2:34 +Seasons:12090:v:0:27500:511:512:2:33 +Blue Channel:11758:h:0:27500:2559:2560:2:516 +Feed (F1 Boxengasse):11720:h:0:27500:2559:2560:2:242 +Feed (F1 Data):11720:h:0:27500:3071:3072:2:244 +Feed (F1 Multi):11720:h:0:27500:2815:2816:2:243 +Feed (F1 On Board):11720:h:0:27500:2303:2304:2:241 +Feed (F1 Verfolger):11720:h:0:27500:2047:2048:2:240 : -TV Niepokalanow:11876:h:1:27500:305:321:0:20601 -Mosaico:11934:v:1:27500:165:100:0:29010 -Andalucia TV:11934:v:1:27500:166:104:0:29011 -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:8904 -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 -VERONICA:12574:h:1:22000:161:84:0:5010 -VH1 Classic:12699:v:1:22000:3071:3072:0:28647 -VH-1 Germany:12699:v:1:22000:3081:3082:0:28648 -Via 1 - Schner Reisen:12148:h:1:27500:511:512:0:44 -Video Italia:12610:v:1:22000:121:122:0:12220 -AC 3 promo:12670:v:1:22000:308:256:0:0 -ORF/ZDF:12699:h:1:22000:506:507:0:13012 +TV Niepokalanow:11876:h:0:27500:305:321:0:20601 +Mosaico:11934:v:0:27500:165:100:0:29010 +Andalucia TV:11934:v:0:27500:166:104:0:29011 +TVC Internacional:11934:v:0:27500:167:108:0:0 +Nasza TV:11992:h:0:27500:165:98:0:0 +WishLine test:12012:v:0:27500:163:90:0:0 +Pro 7 Austria:12051:v:0:27500:161:84:0:0 +Kabel 1 Schweiz:12051:v:0:27500:162:163:0:0 +Kabel 1 Austria:12051:v:0:27500:166:167:0:0 +Pro 7 Schweiz:12051:v:0:27500:289:290:0:0 +Kiosque:12129:v:0:27500:160:80:0:0 +KTO:12129:v:0:27500:170:120:0:0 +TCM:12168:v:0:27500:160:80:0:0 +Cartoon Network France & Spain:12168:v:0:27500:161:84:0:0 +TVBS Europe:12168:v:0:27500:162:88:0:0 +TVBS Europe:12168:v:0:27500:162:89:0:0 +Travel:12168:v:0:27500:163:92:0:0 +TCM Espania:12168:v:0:27500:164:96:0:0 +MTV Spain:12168:v:0:27500:167:112:0:0 +TCM France:12168:v:0:27500:169:64:0:0 +RTL2 CH:12188:h:0:27500:164:112:0:0 +La Cinquieme:12207:v:0:27500:160:80:0:0 +ARTE:12207:v:0:27500:165:100:0:0 +Post Filial TV:12226:h:0:27500:255:256:0:0 +Canal Canaris:12246:v:0:27500:160:80:0:0 +Canal Canaris:12246:v:0:27500:160:81:0:0 +Canal Canaris:12246:v:0:27500:160:82:0:0 +Canal Canaris:12246:v:0:27500:160:83:0:0 +AB Sat Passion promo:12266:h:0:27500:160:80:0:0 +AB Channel 1:12266:h:0:27500:161:84:0:0 +Taquilla 0:12285:v:0:27500:165:100:0:0 +CSAT:12324:v:0:27500:160:80:0:0 +Mosaique:12324:v:0:27500:162:88:0:0 +Mosaique 2:12324:v:0:27500:163:92:0:0 +Mosaique 3:12324:v:0:27500:164:96:0:0 +Le Sesame C+:12324:v:0:27500:165:1965:0:0 +FEED:12344:h:0:27500:163:92:0:0 +RTM 1:12363:v:0:27500:162:96:0:0 +ESC 1:12363:v:0:27500:163:104:0:0 +TV5 Europe:12363:v:0:27500:164:112:0:0 +TV7 Tunisia:12363:v:0:27500:166:128:0:0 +ARTE:12363:v:0:27500:167:137:0:0 +RAI Uno:12363:v:0:27500:289:290:0:8904 +RTP International:12363:v:0:27500:300:301:0:0 +Fashion TV:12402:v:0:27500:163:92:0:0 +VideoService:12422:h:0:27500:255:256:0:0 +Beta Research promo:12422:h:0:27500:1023:1024:0:0 +Canal Canarias:12441:v:0:27500:160:80:0:0 +TVC International:12441:v:0:27500:512:660:0:0 +Fitur:12441:v:0:27500:514:662:0:0 +Astra Info 1:12552:v:0:22000:164:112:0:0 +Astra Info 2:12552:v:0:22000:165:120:0:0 +Astra Vision 1:12552:v:0:22000:168:144:0:0 +Astra Vision 1:12552:v:0:22000:168:145:0:0 +Astra Vision 1:12552:v:0:22000:168:146:0:0 +Astra Vision 1:12552:v:0:22000:168:147:0:0 +Astra Vision 1:12552:v:0:22000:168:148:0:0 +Astra Vision 1:12552:v:0:22000:168:149:0:0 +Astra Vision 1:12552:v:0:22000:168:150:0:0 +RTL Tele Letzebuerg:12552:v:0:22000:168:144:0:0 +Astra Mosaic:12552:v:0:22000:175:176:0:0 +MHP test:12604:h:0:22000:5632:8191:0:0 +VERONICA:12574:h:0:22000:161:84:0:5010 +VH1 Classic:12699:v:0:22000:3071:3072:0:28647 +VH-1 Germany:12699:v:0:22000:3081:3082:0:28648 +Via 1 - Schner Reisen:12148:h:0:27500:511:512:0:44 +Video Italia:12610:v:0:22000:121:122:0:12220 +AC 3 promo:12670:v:0:22000:308:256:0:0 +ORF/ZDF:12699:h:0:22000:506:507:0:13012 +VIVA:12670:v:0:22000:309:310:0:12732 diff --git a/config.c b/config.c index 8964e5a04..5838c68c0 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.34 2000/11/18 13:26:36 kls Exp $ + * $Id: config.c 1.39 2001/01/14 15:29:15 kls Exp $ */ #include "config.h" @@ -119,10 +119,9 @@ bool cKeys::Load(const char *FileName) bool cKeys::Save(void) { - //TODO make backup copies??? bool result = true; - FILE *f = fopen(fileName, "w"); - if (f) { + cSafeFile f(fileName); + if (f.Open()) { if (fprintf(f, "Code\t%c\nAddress\t%04X\n", code, address) > 0) { for (tKey *k = keys; k->type != kNone; k++) { if (fprintf(f, "%s\t%08X\n", k->name, k->code) <= 0) { @@ -133,7 +132,7 @@ bool cKeys::Save(void) } else result = false; - fclose(f); + f.Close(); } else result = false; @@ -196,7 +195,7 @@ cChannel::cChannel(const cChannel *Channel) strcpy(name, Channel ? Channel->name : "Pro7"); frequency = Channel ? Channel->frequency : 12480; polarization = Channel ? Channel->polarization : 'v'; - diseqc = Channel ? Channel->diseqc : 1; + diseqc = Channel ? Channel->diseqc : 0; srate = Channel ? Channel->srate : 27500; vpid = Channel ? Channel->vpid : 255; apid = Channel ? Channel->apid : 256; @@ -435,9 +434,11 @@ bool cTimer::Parse(const char *s) //XXX to hear about that! char *s2 = NULL; int l2 = strlen(s); - if (s[l2 - 2] == ':') { // note that 's' has a trailing '\n' - s2 = (char *)malloc(l2 + 2); - strcat(strn0cpy(s2, s, l2), " \n"); + while (l2 > 0 && isspace(s[l2 - 1])) + l2--; + if (s[l2 - 1] == ':') { + s2 = (char *)malloc(l2 + 3); + strcat(strn0cpy(s2, s, l2 + 1), " \n"); s = s2; } if (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) { @@ -723,6 +724,7 @@ cSetup::cSetup(void) MarginStart = 2; MarginStop = 10; EPGScanTimeout = 5; + CurrentChannel = -1; } bool cSetup::Parse(char *s) @@ -742,6 +744,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); + else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else return false; return true; @@ -780,8 +783,8 @@ bool cSetup::Save(const char *FileName) if (!FileName) FileName = fileName; if (FileName) { - FILE *f = fopen(FileName, "w"); - if (f) { + cSafeFile f(FileName); + if (f.Open()) { fprintf(f, "# VDR Setup\n"); fprintf(f, "OSDLanguage = %d\n", OSDLanguage); fprintf(f, "PrimaryDVB = %d\n", PrimaryDVB); @@ -792,8 +795,10 @@ bool cSetup::Save(const char *FileName) fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); fprintf(f, "SetSystemTime = %d\n", SetSystemTime); fprintf(f, "MarginStart = %d\n", MarginStart); + fprintf(f, "MarginStop = %d\n", MarginStop); fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout); - fclose(f); + fprintf(f, "CurrentChannel = %d\n", CurrentChannel); + f.Close(); isyslog(LOG_INFO, "saved setup to %s", FileName); return true; } diff --git a/config.h b/config.h index db3f1edc9..277e957e2 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.34 2000/11/18 13:25:53 kls Exp $ + * $Id: config.h 1.38 2001/01/14 15:29:27 kls Exp $ */ #ifndef __CONFIG_H @@ -14,11 +14,12 @@ #include #include #include +#include #include "dvbapi.h" #include "eit.h" #include "tools.h" -#define VDRVERSION "0.68" +#define VDRVERSION "0.70" #define MaxBuffer 10000 @@ -42,6 +43,15 @@ enum eKeys { // "Up" and "Down" must be the first two keys! k_Flags = k_Repeat | k_Release, }; +// This is in preparation for having more key codes: +#define kMarkToggle k0 +#define kMarkMoveBack k4 +#define kMarkMoveForward k6 +#define kMarkJumpBack k7 +#define kMarkJumpForward k9 +#define kEditCut k2 +#define kEditTest k8 + #define RAWKEY(k) ((k) & ~k_Flags) #define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) #define NORMALKEY(k) ((k) & ~k_Repeat) @@ -157,43 +167,45 @@ template class cConfig : public cList { cList::Clear(); } public: + cConfig(void) { fileName = NULL; } + virtual ~cConfig() { delete fileName; } virtual bool Load(const char *FileName) { - isyslog(LOG_INFO, "loading %s", FileName); - bool result = true; Clear(); fileName = strdup(FileName); - FILE *f = fopen(fileName, "r"); - if (f) { - int line = 0; - char buffer[MaxBuffer]; - while (fgets(buffer, sizeof(buffer), f) > 0) { - line++; - T *l = new T; - if (l->Parse(buffer)) - Add(l); - else { - esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); - delete l; - result = false; - break; + bool result = false; + if (access(FileName, F_OK) == 0) { + isyslog(LOG_INFO, "loading %s", FileName); + FILE *f = fopen(fileName, "r"); + if (f) { + int line = 0; + char buffer[MaxBuffer]; + result = true; + while (fgets(buffer, sizeof(buffer), f) > 0) { + line++; + T *l = new T; + if (l->Parse(buffer)) + Add(l); + else { + esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); + delete l; + result = false; + break; + } } - } - fclose(f); - } - else { - LOG_ERROR_STR(fileName); - result = false; + fclose(f); + } + else + LOG_ERROR_STR(fileName); } return result; } bool Save(void) { - //TODO make backup copies??? bool result = true; T *l = (T *)First(); - FILE *f = fopen(fileName, "w"); - if (f) { + cSafeFile f(fileName); + if (f.Open()) { while (l) { if (!l->Save(f)) { result = false; @@ -201,12 +213,10 @@ template class cConfig : public cList { } l = (T *)l->Next(); } - fclose(f); + f.Close(); } - else { - LOG_ERROR_STR(fileName); + else result = false; - } return result; } }; @@ -258,6 +268,7 @@ class cSetup { int SetSystemTime; int MarginStart, MarginStop; int EPGScanTimeout; + int CurrentChannel; cSetup(void); bool Load(const char *FileName); bool Save(const char *FileName = NULL); diff --git a/dvb.c.071.diff b/dvb.c.071.diff deleted file mode 100644 index ac7ba3a4a..000000000 --- a/dvb.c.071.diff +++ /dev/null @@ -1,100 +0,0 @@ ---- dvb.c.001 Sun Sep 17 22:02:37 2000 -+++ dvb.c Tue Oct 3 12:11:46 2000 -@@ -1143,6 +1143,8 @@ - { - int bpp; - int i; -+ int d, delta; //XXX kls: additional variables for data compression -+ u8 c; //XXX kls: additional variables for data compression - DECLARE_WAITQUEUE(wait, current); - - if (dvb->bmp_state==BMP_LOADING) { -@@ -1160,27 +1162,38 @@ - if (dvb->bmp_state==BMP_LOADING) - return -1; - dvb->bmp_state=BMP_LOADING; -- if (format==BITMAP8) bpp=8; -- else if (format==BITMAP4) bpp=4; -- else if (format==BITMAP2) bpp=2; -- else if (format==BITMAP1) bpp=1; -+ if (format==BITMAP8) { bpp=8; delta = 1; } //XXX kls: initialize 'delta', too -+ else if (format==BITMAP4) { bpp=4; delta = 2; } -+ else if (format==BITMAP2) { bpp=2; delta = 4; } -+ else if (format==BITMAP1) { bpp=1; delta = 8; } - else { - dvb->bmp_state=BMP_NONE; - return -1; - } -- dvb->bmplen= (dx*dy*bpp)/8; -+ dvb->bmplen= ((dx*dy*bpp+7)&~7)/8; //XXX kls: need to round up to include partial bytes - dvb->bmpp=0; - if (dvb->bmplen>32768) { - dvb->bmp_state=BMP_NONE; - return -1; - } - for (i=0; ibmpbuf+1024+i*dx, data+i*inc, (dx*bpp)/8)) { -+ if (copy_from_user(dvb->bmpbuf+1024+i*dx, data+i*inc, dx)) { //XXX kls: incoming data is "1 byte per pixel" - dvb->bmp_state=BMP_NONE; - return -1; - } - - } -+ // XXX kls: Incoming data is always "one byte per pixel", so we need to compress -+ // the data in case we have a lower resolution than 8 bpp: -+ if (format != BITMAP8) { -+ for (i=0; ibmpbuf)[1024+i*delta+delta-1]; -+ for (d=delta-2; d>=0; d--) { -+ c |= (((u8 *)dvb->bmpbuf)[1024+i*delta+d] << ((delta-d-1)*bpp)); -+ ((u8 *)dvb->bmpbuf)[1024+i] = c; -+ } -+ } -+ } - dvb->bmplen+=1024; - return outcom(dvb, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); - } -@@ -1256,24 +1269,25 @@ - int i; - - w=x1-x0+1; h=y1-y0+1; -- if (inc>0) -- w=inc; -- if (w>720 || h>576) -+ if (inc<=0) -+ inc=w; //XXX kls: see dvb_4l.h: "inc<=0 uses blockwidth as linewidth" -+ if (w<=0 || w>720 || h<=0 || h>576) //XXX kls: checking lower bounds, too - return -1; -- bpp=8; //dvb->osdbpp[dvb->osdwin]; -- bpl=w*bpp/8; -+ bpp=dvb->osdbpp[dvb->osdwin]+1; //XXX kls: 'bpp' needs to be taken from the window -+ bpl=((w*bpp+7)&~7)/8; //XXX kls: need to round up to include partial bytes - size=h*bpl; -- lpb=(64*1024)/bpl; -+ lpb=(32*1024)/bpl; //XXX kls: apparently 32K is the maximum possible value - bnum=size/(lpb*bpl); - brest=size-bnum*lpb*bpl; - - for (i=0; iosdbpp[dvb->osdwin]], w, lpb, inc, data); //XXX kls: need to take the format from the actual window - BlitBitmap(dvb, dvb->osdwin, x0, y0+i*lpb, 1); -- data+=bpl; -+ data+=lpb*inc; //XXX kls: incrementing must be done in "one byte per pixel" -+ ddelay(3); //XXX kls: without this the block is sometimes not fully displayed - firmware bug? - } - if (brest) { -- LoadBitmap(dvb, BITMAP8, w, brest/bpl, inc, data); -+ LoadBitmap(dvb, bpp2bit[dvb->osdbpp[dvb->osdwin]], w, brest/bpl, inc, data); //XXX kls: need to take the format from the actual window - BlitBitmap(dvb, dvb->osdwin, x0, y0+bnum*lpb, 1); - } - ReleaseBitmap(dvb); -@@ -6141,7 +6155,7 @@ - init_waitqueue_head(&dvb->bmpq); - spin_lock_init (&(dvb->bmplock)); - dvb->bmpp=dvb->bmplen=0; -- dvb->bmpbuf=vmalloc(32768+1024); -+ dvb->bmpbuf=vmalloc(8*32768+1024); //XXX kls: '8*' to be prepared for the maximum possible incoming data at 1 bpp - - init_waitqueue_head(&dvb->debiq); - dvb->debilock=SPIN_LOCK_UNLOCKED; diff --git a/dvbapi.c b/dvbapi.c index 5e4f2e647..e583baf94 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.40 2000/11/19 16:46:37 kls Exp $ + * $Id: dvbapi.c 1.50 2001/01/18 19:53:54 kls Exp $ */ #include "dvbapi.h" @@ -21,6 +21,7 @@ extern "C" { #include #include "config.h" #include "interface.h" +#include "recording.h" #include "tools.h" #include "videodir.h" @@ -32,23 +33,25 @@ extern "C" { // The minimum amount of video data necessary to identify frames // (must be smaller than VIDEOBUFSIZE!): -#define MINVIDEODATA (20*1024) // just a safe guess (max. size of any AV_PES block, plus some safety) +#define MINVIDEODATA (256*1024) // just a safe guess (max. size of any frame block, plus some safety) // The maximum time the buffer is allowed to write data to disk when recording: #define MAXRECORDWRITETIME 50 // ms -#define AV_PES_HEADER_LEN 8 - -// AV_PES block types: -#define AV_PES_VIDEO 1 -#define AV_PES_AUDIO 2 - // Picture types: #define NO_PICTURE 0 #define I_FRAME 1 #define P_FRAME 2 #define B_FRAME 3 +// Start codes: +#define SC_PICTURE 0x00 // "picture header" +#define SC_SEQU 0xB3 // "sequence header" +#define SC_PHEAD 0xBA // "pack header" +#define SC_SHEAD 0xBB // "system header" +#define SC_AUDIO 0xC0 +#define SC_VIDEO 0xE0 + #define FRAMESPERSEC 25 // The maximum file size is limited by the range that can be covered @@ -73,6 +76,35 @@ extern "C" { typedef unsigned char uchar; +static void SetPlayMode(int VideoDev, int Mode) +{ + if (VideoDev >= 0) { + struct video_play_mode pmode; + pmode.mode = Mode; + ioctl(VideoDev, VIDIOCSPLAYMODE, &pmode); + } +} + +const char *IndexToHMSF(int Index, bool WithFrame) +{ + static char buffer[16]; + int f = (Index % FRAMESPERSEC) + 1; + int s = (Index / FRAMESPERSEC); + int m = s / 60 % 60; + int h = s / 3600; + s %= 60; + snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f); + return buffer; +} + +int HMSFToIndex(const char *HMSF) +{ + int h, m, s, f = 0; + if (3 <= sscanf(HMSF, "%d:%d:%d.%d", &h, &m, &s, &f)) + return (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1; + return 0; +} + // --- cResumeFile ------------------------------------------------------------ cResumeFile::cResumeFile(const char *FileName) @@ -135,16 +167,15 @@ class cIndexFile { cResumeFile resumeFile; bool CatchUp(void); public: - cIndexFile(const char *FileName, bool Record = false); + cIndexFile(const char *FileName, bool Record); ~cIndexFile(); void Write(uchar PictureType, uchar FileNumber, int FileOffset); - bool Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType = NULL); - int GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length = NULL); + bool Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType = NULL, int *Length = NULL); + int GetNextIFrame(int Index, bool Forward, uchar *FileNumber = NULL, int *FileOffset = NULL, int *Length = NULL); int Get(uchar FileNumber, int FileOffset); - int Last(void) { return last; } + int Last(void) { CatchUp(); return last; } int GetResume(void) { return resumeFile.Read(); } bool StoreResume(int Index) { return resumeFile.Save(Index); } - static char *Str(int Index, bool WithFrame = false); }; cIndexFile::cIndexFile(const char *FileName, bool Record) @@ -276,7 +307,7 @@ void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) } } -bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType) +bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType, int *Length) { if (index) { CatchUp(); @@ -285,6 +316,14 @@ bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *Pictu *FileOffset = index[Index].offset; if (PictureType) *PictureType = index[Index].type; + if (Length) { + int fn = index[Index + 1].number; + int fo = index[Index + 1].offset; + if (fn == *FileNumber) + *Length = fo - *FileOffset; + else + *Length = -1; // this means "everything up to EOF" (the buffer's Read function will act accordingly) + } return true; } } @@ -301,8 +340,14 @@ int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *F Index += d; if (Index >= 0 && Index <= last - 100) { // '- 100': need to stay off the end! if (index[Index].type == I_FRAME) { - *FileNumber = index[Index].number; - *FileOffset = index[Index].offset; + if (FileNumber) + *FileNumber = index[Index].number; + else + FileNumber = &index[Index].number; + if (FileOffset) + *FileOffset = index[Index].offset; + else + FileOffset = &index[Index].offset; if (Length) { // all recordings end with a non-I_FRAME, so the following should be safe: int fn = index[Index + 1].number; @@ -339,18 +384,6 @@ int cIndexFile::Get(uchar FileNumber, int FileOffset) return -1; } -char *cIndexFile::Str(int Index, bool WithFrame) -{ - static char buffer[16]; - int f = (Index % FRAMESPERSEC) + 1; - int s = (Index / FRAMESPERSEC); - int m = s / 60 % 60; - int h = s / 3600; - s %= 60; - snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f); - return buffer; -} - // --- cRingBuffer ----------------------------------------------------------- /* cRingBuffer reads data from an input file, stores it in a buffer and writes @@ -378,6 +411,12 @@ class cRingBuffer { int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap! int Writeable(void) { return (tail >= head) ? tail - head : size - head; } int Byte(int Offset); + bool Set(int Offset, int Length, int Value); +protected: + int GetStartCode(int Offset) { return (Byte(Offset) == 0x00 && Byte(Offset + 1) == 0x00 && Byte(Offset + 2) == 0x01) ? Byte(Offset + 3) : -1; } + int GetPictureType(int Offset) { return (Byte(Offset + 5) >> 3) & 0x07; } + int FindStartCode(uchar Code, int Offset = 0); + int GetPacketLength(int Offset = 0); public: cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); virtual ~cRingBuffer(); @@ -422,19 +461,36 @@ int cRingBuffer::Byte(int Offset) return -1; } -void cRingBuffer::Skip(int n) +bool cRingBuffer::Set(int Offset, int Length, int Value) { - if (head < tail) { - head += n; - if (head > tail) - head = tail; + if (buffer && Offset + Length <= Available() ) { + Offset += head; + while (Length--) { + if (Offset >= size) + Offset -= size; + buffer[Offset] = Value; + Offset++; + } + return true; } - else if (head > tail) { - head += n; - if (head >= size) - head -= size; - if (head > tail) - head = tail; + return false; +} + +void cRingBuffer::Skip(int n) +{ + if (n > 0) { + if (head < tail) { + head += n; + if (head > tail) + head = tail; + } + else if (head > tail) { + head += n; + if (head >= size) + head -= size; + if (head > tail) + head = tail; + } } } @@ -477,9 +533,11 @@ int cRingBuffer::Read(int Max) if (tail >= size) tail = 0; } - else if (r < 0 && errno != EAGAIN) { - LOG_ERROR; - return -1; + else if (r < 0) { + if (errno != EAGAIN) { + LOG_ERROR; + return -1; + } } else eof = true; @@ -533,37 +591,53 @@ int cRingBuffer::Write(int Max) return -1; } -// --- cFileBuffer ----------------------------------------------------------- +int cRingBuffer::FindStartCode(uchar Code, int Offset) +{ + // Searches for a start code (beginning at Offset) and returns the number + // of bytes from Offset to the start code. -class cFileBuffer : public cRingBuffer { -protected: - cIndexFile *index; - uchar fileNumber; + int n = Available() - Offset; + + for (int i = 0; i < n; i++) { + int c = GetStartCode(Offset + i); + if (c == Code) + return i; + if (i > 0 && c == SC_PHEAD) + break; // found another block start while looking for a different code + } + return -1; +} + +int cRingBuffer::GetPacketLength(int Offset) +{ + // Returns the entire length of the packet starting at offset. + return (Byte(Offset + 4) << 8) + Byte(Offset + 5) + 6; +} + +// --- cFileName ------------------------------------------------------------- + +class cFileName { +private: + int file; + int fileNumber; char *fileName, *pFileNumber; - bool stop; - int GetAvPesLength(void) - { - if (Byte(0) == 'A' && Byte(1) == 'V' && Byte(4) == 'U') - return (Byte(6) << 8) + Byte(7) + AV_PES_HEADER_LEN; - return 0; - } - int GetAvPesType(void) { return Byte(2); } - int GetAvPesTag(void) { return Byte(3); } - int FindAvPesBlock(void); - int GetPictureType(int Offset) { return (Byte(Offset + 5) >> 3) & 0x07; } - int FindPictureStartCode(int Length); + bool record; public: - cFileBuffer(int *InFile, int *OutFile, const char *FileName, bool Recording, int Size, int FreeLimit = 0, int AvailLimit = 0); - virtual ~cFileBuffer(); - void Stop(void) { stop = true; } + cFileName(const char *FileName, bool Record); + ~cFileName(); + const char *Name(void) { return fileName; } + int Number(void) { return fileNumber; } + int Open(void); + void Close(void); + int SetOffset(int Number, int Offset = 0); + int NextFile(void); }; -cFileBuffer::cFileBuffer(int *InFile, int *OutFile, const char *FileName, bool Recording, int Size, int FreeLimit = 0, int AvailLimit = 0) -:cRingBuffer(InFile, OutFile, Size, FreeLimit, AvailLimit) +cFileName::cFileName(const char *FileName, bool Record) { - index = NULL; + file = -1; fileNumber = 0; - stop = false; + record = Record; // Prepare the file name: fileName = new char[strlen(FileName) + RECORDFILESUFFIXLEN]; if (!fileName) { @@ -572,98 +646,165 @@ cFileBuffer::cFileBuffer(int *InFile, int *OutFile, const char *FileName, bool R } strcpy(fileName, FileName); pFileNumber = fileName + strlen(fileName); - // Create the index file: - index = new cIndexFile(FileName, Recording); - if (!index) - esyslog(LOG_ERR, "ERROR: can't allocate index"); - // let's continue without index, so we'll at least have the recording + SetOffset(1); } -cFileBuffer::~cFileBuffer() +cFileName::~cFileName() { - delete index; + Close(); delete fileName; } -int cFileBuffer::FindAvPesBlock(void) +int cFileName::Open(void) +{ + if (file < 0) { + if (record) { + dsyslog(LOG_INFO, "recording to '%s'", fileName); + file = OpenVideoFile(fileName, O_RDWR | O_CREAT | O_NONBLOCK); + if (file < 0) + LOG_ERROR_STR(fileName); + } + else { + if (access(fileName, R_OK) == 0) { + dsyslog(LOG_INFO, "playing '%s'", fileName); + file = open(fileName, O_RDONLY | O_NONBLOCK); + if (file < 0) + LOG_ERROR_STR(fileName); + } + else if (errno != ENOENT) + LOG_ERROR_STR(fileName); + } + } + return file; +} + +void cFileName::Close(void) { - int Skipped = 0; + if (file >= 0) { + if ((record && CloseVideoFile(file) < 0) || (!record && close(file) < 0)) + LOG_ERROR_STR(fileName); + file = -1; + } +} - while (Available() > MINVIDEODATA) { - if (GetAvPesLength()) - return Skipped; - Skip(1); - Skipped++; +int cFileName::SetOffset(int Number, int Offset) +{ + if (fileNumber != Number) + Close(); + if (0 < Number && Number <= MAXFILESPERRECORDING) { + fileNumber = Number; + sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); + if (record) { + if (access(fileName, F_OK) == 0) // file exists, let's try next suffix + return SetOffset(Number + 1); + else if (errno != ENOENT) { // something serious has happened + LOG_ERROR_STR(fileName); + return -1; + } + // found a non existing file suffix } + if (Open() >= 0) { + if (!record && Offset >= 0 && lseek(file, Offset, SEEK_SET) != Offset) { + LOG_ERROR_STR(fileName); + return -1; + } + } + return file; + } + esyslog(LOG_ERR, "ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); return -1; } -int cFileBuffer::FindPictureStartCode(int Length) +int cFileName::NextFile(void) { - for (int i = AV_PES_HEADER_LEN; i < Length; i++) { - if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1 && Byte(i + 3) == 0) - return i; - } - return -1; + return SetOffset(fileNumber + 1); } // --- cRecordBuffer --------------------------------------------------------- -class cRecordBuffer : public cFileBuffer { +class cRecordBuffer : public cRingBuffer, public cThread { private: + cFileName fileName; + cIndexFile *index; uchar pictureType; int fileSize; + int videoDev; int recordFile; - uchar tagAudio, tagVideo; - bool ok, synced; + bool ok, synced, stop; time_t lastDiskSpaceCheck; bool RunningLowOnDiskSpace(void); + int ScanVideoPacket(int *PictureType, int Offset); int Synchronize(void); bool NextFile(void); virtual int Write(int Max = -1); + bool WriteWithTimeout(void); +protected: + virtual void Action(void); public: cRecordBuffer(int *InFile, const char *FileName); virtual ~cRecordBuffer(); - int WriteWithTimeout(bool EndIfEmpty = false); }; cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) -:cFileBuffer(InFile, &recordFile, FileName, true, VIDEOBUFSIZE, VIDEOBUFSIZE / 10, 0) +:cRingBuffer(InFile, &recordFile, VIDEOBUFSIZE, VIDEOBUFSIZE / 10, 0) +,fileName(FileName, true) { + index = NULL; pictureType = NO_PICTURE; fileSize = 0; - recordFile = -1; - tagAudio = tagVideo = 0; - ok = synced = false; + videoDev = *InFile; + recordFile = fileName.Open(); + ok = synced = stop = false; lastDiskSpaceCheck = time(NULL); - if (!fileName) - return;//XXX find a better way??? - // Find the highest existing file suffix: - for (;;) { - sprintf(pFileNumber, RECORDFILESUFFIX, ++fileNumber); - if (access(fileName, F_OK) < 0) { - if (errno == ENOENT) - break; // found a non existing file suffix - LOG_ERROR; - return; - } - } + if (!fileName.Name()) + return; + // Create the index file: + index = new cIndexFile(FileName, true); + if (!index) + esyslog(LOG_ERR, "ERROR: can't allocate index"); + // let's continue without index, so we'll at least have the recording ok = true; - //XXX hack to make the video device go into 'recording' mode: - char dummy; - read(*InFile, &dummy, sizeof(dummy)); + Start(); } cRecordBuffer::~cRecordBuffer() { - if (recordFile >= 0) - CloseVideoFile(recordFile); + stop = true; + Cancel(3); + delete index; +} + +void cRecordBuffer::Action(void) +{ + dsyslog(LOG_INFO, "recording thread started (pid=%d)", getpid()); + + time_t t = time(NULL); + for (;;) { + usleep(1); // this keeps the CPU load low + + LOCK_THREAD; + + int r = Read(); + if (r >= 0) { + if (r > 0) + t = time(NULL); + if (!WriteWithTimeout()) + break; + } + if (r < 0 || (r == 0 && time(NULL) - t > 5)) { + esyslog(LOG_ERR, "ERROR: video data stream broken"); + t = time(NULL); + } + } + SetPlayMode(videoDev, VID_PLAY_RESET); + + dsyslog(LOG_INFO, "end recording thread"); } bool cRecordBuffer::RunningLowOnDiskSpace(void) { if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) { - uint Free = FreeDiskSpaceMB(fileName); + uint Free = FreeDiskSpaceMB(fileName.Name()); lastDiskSpaceCheck = time(NULL); if (Free < MINFREEDISKSPACE) { dsyslog(LOG_INFO, "low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE); @@ -673,109 +814,109 @@ bool cRecordBuffer::RunningLowOnDiskSpace(void) return false; } +int cRecordBuffer::ScanVideoPacket(int *PictureType, int Offset) +{ + // Scans the video packet starting at Offset and returns its length. + // If the return value is -1 the packet was not completely in the buffer. + + int Length = GetPacketLength(Offset); + if (Length <= Available()) { + for (int i = Offset; i < Offset + Length; i++) { + if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { + switch (Byte(i + 3)) { + case SC_PICTURE: *PictureType = GetPictureType(i); + return Length; + } + } + } + *PictureType = NO_PICTURE; + return Length; + } + return -1; +} + int cRecordBuffer::Synchronize(void) { - int Length = 0; - int Skipped = 0; - int s; - - while ((s = FindAvPesBlock()) >= 0) { - pictureType = NO_PICTURE; - Skipped += s; - Length = GetAvPesLength(); - if (Length <= MINVIDEODATA) { - switch (GetAvPesType()) { - case AV_PES_VIDEO: - { - int PictureOffset = FindPictureStartCode(Length); - if (PictureOffset >= 0) { - pictureType = GetPictureType(PictureOffset); - if (pictureType < I_FRAME || pictureType > B_FRAME) - esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pictureType); - } - } - if (!synced) { - tagVideo = GetAvPesTag(); - if (pictureType == I_FRAME) { - synced = true; - Skipped = 0; - } - else { - Skip(Length - 1); - Length = 0; - } - } - else { - if (++tagVideo != GetAvPesTag()) { - esyslog(LOG_ERR, "ERROR: missed video data block #%d (next block is #%d)", tagVideo, GetAvPesTag()); - tagVideo = GetAvPesTag(); - } - } - break; - case AV_PES_AUDIO: - if (!synced) { - tagAudio = GetAvPesTag(); - Skip(Length - 1); - Length = 0; - } - else { - //XXX might get fooled the first time!!! - if (++tagAudio != GetAvPesTag()) { - esyslog(LOG_ERR, "ERROR: missed audio data block #%d (next block is #%d)", tagAudio, GetAvPesTag()); - tagAudio = GetAvPesTag(); - } - } - break; - default: // unknown data - Length = 0; // don't skip entire block - maybe we're just not in sync with AV_PES yet - if (synced) - esyslog(LOG_ERR, "ERROR: unknown data type '%d'", GetAvPesType()); - } - if (Length > 0) - break; - } - else if (synced) { - esyslog(LOG_ERR, "ERROR: block length too big (%d)", Length); - Length = 0; + // Positions to the start of a data block (skipping everything up to + // an I-frame if not synced) and returns the block length. + + int LastPackHeader = -1; + + pictureType = NO_PICTURE; + + //XXX remove this once the buffer is handled with two separate threads: + if (!synced && Free() < 100000) { + dsyslog(LOG_INFO, "unable to synchronize, dropped %d bytes", Available()); + Clear(); + return 0; + } + for (int i = 0; Available() > MINVIDEODATA && i < MINVIDEODATA; i++) { + if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { + switch (Byte(i + 3)) { + case SC_PHEAD: LastPackHeader = i; + break; + case SC_VIDEO: { + int pt = NO_PICTURE; + int l = ScanVideoPacket(&pt, i); + if (l < 0) + return 0; // no useful data found, wait for more + if (pt != NO_PICTURE) { + if (pt < I_FRAME || B_FRAME < pt) { + esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); + } + else if (pictureType == NO_PICTURE) { + if (!synced) { + if (LastPackHeader == 0) { + if (pt == I_FRAME) + synced = true; + } + else if (LastPackHeader > 0) { + Skip(LastPackHeader); + LastPackHeader = -1; + i = 0; + break; + } + else { // LastPackHeader < 0 + Skip(i + l); + i = 0; + break; + } + } + if (synced) + pictureType = pt; + } + else if (LastPackHeader > 0) + return LastPackHeader; + else + return i; + } + i += l - 1; // -1 to compensate for i++ in the loop! + LastPackHeader = -1; + } + break; + case SC_AUDIO: i += GetPacketLength(i) - 1; // -1 to compensate for i++ in the loop! + break; } - Skip(1); - Skipped++; - } - if (synced && Skipped) - esyslog(LOG_ERR, "ERROR: skipped %d bytes", Skipped); - return Length; + } + } + return 0; // no useful data found, wait for more } bool cRecordBuffer::NextFile(void) { if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME if (fileSize > MAXVIDEOFILESIZE || RunningLowOnDiskSpace()) { - if (CloseVideoFile(recordFile) < 0) - LOG_ERROR; - // don't return 'false', maybe we can still record into the next file - recordFile = -1; - fileNumber++; - if (fileNumber == 0) - esyslog(LOG_ERR, "ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); + recordFile = fileName.NextFile(); fileSize = 0; } } - if (recordFile < 0) { - sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); - dsyslog(LOG_INFO, "recording to '%s'", fileName); - recordFile = OpenVideoFile(fileName, O_RDWR | O_CREAT | O_NONBLOCK); - if (recordFile < 0) { - LOG_ERROR; - return false; - } - } - return true; + return recordFile >= 0; } int cRecordBuffer::Write(int Max) { // This function ignores the incoming 'Max'! - // It tries to write out exactly *one* block of AV_PES data. + // It tries to write out exactly *one* frame block. if (!ok) return -1; int n = Synchronize(); @@ -786,10 +927,10 @@ int cRecordBuffer::Write(int Max) } if (NextFile()) { if (index && pictureType != NO_PICTURE) - index->Write(pictureType, fileNumber, fileSize); + index->Write(pictureType, fileName.Number(), fileSize); int written = 0; for (;;) { - int w = cFileBuffer::Write(n); + int w = cRingBuffer::Write(n); if (w >= 0) { fileSize += w; written += w; @@ -806,30 +947,41 @@ int cRecordBuffer::Write(int Max) return 0; } -int cRecordBuffer::WriteWithTimeout(bool EndIfEmpty) +bool cRecordBuffer::WriteWithTimeout(void) { - int w, written = 0; int t0 = time_ms(); - while ((w = Write()) > 0 && time_ms() - t0 < MAXRECORDWRITETIME) - written += w; - return w < 0 ? w : (written == 0 && EndIfEmpty ? -1 : written); + do { + int w = Write(); + if (w < 0) + return false; + if (w == 0) + break; + } while (time_ms() - t0 < MAXRECORDWRITETIME); + return true; } // --- cReplayBuffer --------------------------------------------------------- -enum eReplayMode { rmPlay, rmFastForward, rmFastRewind, rmSlowRewind }; - -class cReplayBuffer : public cFileBuffer { +class cReplayBuffer : public cRingBuffer, public cThread { private: + enum eReplayCmd { rcNone, rcStill, rcPause, rcPlay, rcForward, rcBackward }; + enum eReplayMode { rmStill, rmPlay, rmFastForward, rmFastRewind, rmSlowRewind }; + cIndexFile *index; + cFileName fileName; int fileOffset; + int videoDev; int replayFile; eReplayMode mode; - bool skipAudio; - int lastIndex; + int lastIndex, stillIndex; int brakeCounter; - void SkipAudioBlocks(void); + eReplayCmd command; + bool active; bool NextFile(uchar FileNumber = 0, int FileOffset = -1); void Close(void); + void SetCmd(eReplayCmd Cmd) { LOCK_THREAD; command = Cmd; } + void SetTemporalReference(void); +protected: + virtual void Action(void); public: cReplayBuffer(int *OutFile, const char *FileName); virtual ~cReplayBuffer(); @@ -838,38 +990,136 @@ class cReplayBuffer : public cFileBuffer { void SetMode(eReplayMode Mode); int Resume(void); bool Save(void); + void Pause(void) { SetCmd(rcPause); } + void Play(void) { SetCmd(rcPlay); } + void Forward(void) { SetCmd(rcForward); } + void Backward(void) { SetCmd(rcBackward); } + int SkipFrames(int Frames); void SkipSeconds(int Seconds); - void GetIndex(int &Current, int &Total); + void Goto(int Position, bool Still = false); + void GetIndex(int &Current, int &Total, bool SnapToIFrame = false); }; cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName) -:cFileBuffer(&replayFile, OutFile, FileName, false, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) +:cRingBuffer(&replayFile, OutFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) +,fileName(FileName, false) { + index = NULL; fileOffset = 0; - replayFile = -1; + videoDev = *OutFile; + replayFile = fileName.Open(); mode = rmPlay; brakeCounter = 0; - skipAudio = false; - lastIndex = -1; - if (!fileName) - return;//XXX find a better way??? - // All recordings start with '1': - fileNumber = 1; //TODO what if it doesn't start with '1'??? - //XXX hack to make the video device go into 'replaying' mode: - char *dummy = "AV"; // must be "AV" to make the driver go into AV_PES mode! - write(*OutFile, dummy, strlen(dummy)); + command = rcNone; + lastIndex = stillIndex = -1; + active = false; + if (!fileName.Name()) + return; + // Create the index file: + index = new cIndexFile(FileName, false); + if (!index) + esyslog(LOG_ERR, "ERROR: can't allocate index"); + // let's continue without index, so we'll at least have the recording + Start(); } cReplayBuffer::~cReplayBuffer() { + active = false; + Cancel(3); Close(); + SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + SetPlayMode(videoDev, VID_PLAY_RESET); + delete index; +} + +void cReplayBuffer::Action(void) +{ + dsyslog(LOG_INFO, "replay thread started (pid=%d)", getpid()); + + bool Paused = false; + bool FastForward = false; + bool FastRewind = false; + + int ResumeIndex = Resume(); + if (ResumeIndex >= 0) + isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, IndexToHMSF(ResumeIndex, true)); + active = true; + while (active) { + usleep(1); // this keeps the CPU load low + + LOCK_THREAD; + + if (command != rcNone) { + switch (command) { + case rcStill: SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + SetPlayMode(videoDev, VID_PLAY_NORMAL); + SetMode(rmStill); + Paused = FastForward = FastRewind = false; + break; + case rcPause: SetPlayMode(videoDev, Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); + Paused = !Paused; + if (FastForward || FastRewind) { + SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + Clear(); + } + FastForward = FastRewind = false; + SetMode(rmPlay); + if (!Paused) + stillIndex = -1; + break; + case rcPlay: if (FastForward || FastRewind || Paused) { + SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + SetPlayMode(videoDev, VID_PLAY_NORMAL); + FastForward = FastRewind = Paused = false; + SetMode(rmPlay); + } + stillIndex = -1; + break; + case rcForward: SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + Clear(); + FastForward = !FastForward; + FastRewind = false; + if (Paused) { + SetMode(rmPlay); + SetPlayMode(videoDev, FastForward ? VID_PLAY_SLOW_MOTION : VID_PLAY_PAUSE); + } + else { + SetPlayMode(videoDev, VID_PLAY_NORMAL); + SetMode(FastForward ? rmFastForward : rmPlay); + } + stillIndex = -1; + break; + case rcBackward: SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + Clear(); + FastRewind = !FastRewind; + FastForward = false; + if (Paused) { + SetMode(FastRewind ? rmSlowRewind : rmPlay); + SetPlayMode(videoDev, FastRewind ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); + } + else { + SetPlayMode(videoDev, VID_PLAY_NORMAL); + SetMode(FastRewind ? rmFastRewind : rmPlay); + } + stillIndex = -1; + break; + default: break; + } + command = rcNone; + } + if (Read() < 0 || Write() < 0) + break; + } + Save(); + + dsyslog(LOG_INFO, "end replaying thread"); } void cReplayBuffer::Close(void) { if (replayFile >= 0) { - if (close(replayFile) < 0) - LOG_ERROR; + fileName.Close(); replayFile = -1; fileOffset = 0; } @@ -878,7 +1128,6 @@ void cReplayBuffer::Close(void) void cReplayBuffer::SetMode(eReplayMode Mode) { mode = Mode; - skipAudio = Mode != rmPlay; brakeCounter = 0; if (mode != rmPlay) Clear(); @@ -901,14 +1150,11 @@ int cReplayBuffer::Resume(void) bool cReplayBuffer::Save(void) { if (index) { - int Index = index->Get(fileNumber, fileOffset); + int Index = index->Get(fileName.Number(), fileOffset); if (Index >= 0) { Index -= RESUMEBACKUP; - if (Index > 0) { - uchar FileNumber; - int FileOffset; - Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset); - } + if (Index > 0) + Index = index->GetNextIFrame(Index, false); else Index = 0; if (Index >= 0) @@ -918,15 +1164,39 @@ bool cReplayBuffer::Save(void) return false; } +int cReplayBuffer::SkipFrames(int Frames) +{ + if (index && Frames) { + + LOCK_THREAD; + + int Current, Total; + GetIndex(Current, Total, true); + int OldCurrent = Current; + Current = index->GetNextIFrame(Current + Frames, Frames > 0); + return Current >= 0 ? Current : OldCurrent; + } + return -1; +} + void cReplayBuffer::SkipSeconds(int Seconds) { + LOCK_THREAD; + + SetPlayMode(videoDev, VID_PLAY_PAUSE); + SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + SetPlayMode(videoDev, VID_PLAY_NORMAL); + command = rcPlay; + SetMode(rmPlay); + Clear(); + if (index && Seconds) { - int Index = index->Get(fileNumber, fileOffset); + int Index = index->Get(fileName.Number(), fileOffset); if (Index >= 0) { if (Seconds < 0) { int sec = index->Last() / FRAMESPERSEC; if (Seconds < -sec) - Seconds = - sec; + Seconds = -sec; } Index += Seconds * FRAMESPERSEC; if (Index < 0) @@ -934,103 +1204,120 @@ void cReplayBuffer::SkipSeconds(int Seconds) uchar FileNumber; int FileOffset; if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0) - if ((Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset)) >= 0) NextFile(FileNumber, FileOffset); } } } -void cReplayBuffer::GetIndex(int &Current, int &Total) +void cReplayBuffer::Goto(int Index, bool Still) { - if (index) { - Current = index->Get(fileNumber, fileOffset); - Total = index->Last(); - } - else - Current = Total = -1; + LOCK_THREAD; + + if (Still) + command = rcStill; + if (++Index <= 0) + Index = 1; // not '0', to allow GetNextIFrame() below to work! + uchar FileNumber; + int FileOffset; + if ((stillIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset)) >= 0) + NextFile(FileNumber, FileOffset); + SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); + Clear(); } -void cReplayBuffer::SkipAudioBlocks(void) +void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) { - int Length; + if (index) { - while ((Length = GetAvPesLength()) > 0) { - if (GetAvPesType() == AV_PES_AUDIO) - Skip(Length); - else - break; + LOCK_THREAD; + + if (stillIndex >= 0) + Current = stillIndex; + else { + Current = index->Get(fileName.Number(), fileOffset); + if (SnapToIFrame) { + int i1 = index->GetNextIFrame(Current + 1, false); + int i2 = index->GetNextIFrame(Current, true); + Current = (abs(Current - i1) <= abs(Current - i2)) ? i1 : i2; + } } + Total = index->Last(); + } + else + Current = Total = -1; } bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) { if (FileNumber > 0) { Clear(); - if (FileNumber != fileNumber) { - Close(); - fileNumber = FileNumber; - } + fileOffset = FileOffset; + replayFile = fileName.SetOffset(FileNumber, FileOffset); } - if (replayFile >= 0 && EndOfFile()) { + else if (replayFile >= 0 && EndOfFile()) { Close(); - fileNumber++; - if (fileNumber == 0) - esyslog(LOG_ERR, "ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING); + replayFile = fileName.NextFile(); } - if (replayFile < 0) { - sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); - if (access(fileName, R_OK) == 0) { - dsyslog(LOG_INFO, "playing '%s'", fileName); - replayFile = open(fileName, O_RDONLY | O_NONBLOCK); - if (replayFile < 0) { - LOG_ERROR; - return false; + return replayFile >= 0; +} + +void cReplayBuffer::SetTemporalReference(void) +{ + for (int i = 0; i < Available(); i++) { + if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { + switch (Byte(i + 3)) { + case SC_PICTURE: { + unsigned short m = (Byte(i + 4) << 8) | Byte(i + 5); + m &= 0x003F; + Set(i + 4, 1, m >> 8); + Set(i + 5, 1, m & 0xFF); + } + return; } - } - else if (errno != ENOENT) - LOG_ERROR; - } - if (replayFile >= 0) { - if (FileOffset >= 0) { - if ((fileOffset = lseek(replayFile, FileOffset, SEEK_SET)) != FileOffset) - LOG_ERROR; - // don't return 'false', maybe we can still replay the file - } - return true; - } - return false; + } + } } int cReplayBuffer::Read(int Max = -1) { - if (stop) - return -1; if (mode != rmPlay) { if (index) { if (Available()) return 0; // write out the entire block - int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileNumber, fileOffset); - if (Index >= 0) { + if (mode == rmStill) { uchar FileNumber; int FileOffset, Length; - if (mode == rmSlowRewind && (brakeCounter++ % 24) != 0) { - // show every I_FRAME 24 times in rmSlowRewind mode to achieve roughly the same speed as in slow forward mode - Index = index->GetNextIFrame(Index, true, &FileNumber, &FileOffset, &Length); // jump ahead one frame - } - Index = index->GetNextIFrame(Index, mode == rmFastForward, &FileNumber, &FileOffset, &Length); - if (Index >= 0) { + if (index->GetNextIFrame(stillIndex + 1, false, &FileNumber, &FileOffset, &Length) >= 0) { if (!NextFile(FileNumber, FileOffset)) return -1; Max = Length; } - lastIndex = Index; + command = rcPause; } - if (Index < 0) { - // This results in normal replay after a fast rewind. - // After a fast forward it will stop. - // TODO Could we cause it to pause at the last frame? - SetMode(rmPlay); - return 0; + else { + int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset); + if (Index >= 0) { + if (mode == rmSlowRewind && (brakeCounter++ % 24) != 0) { + // show every I_FRAME 24 times in rmSlowRewind mode to achieve roughly the same speed as in slow forward mode + Index = index->GetNextIFrame(Index, true); // jump ahead one frame + } + uchar FileNumber; + int FileOffset, Length; + Index = index->GetNextIFrame(Index, mode == rmFastForward, &FileNumber, &FileOffset, &Length); + if (Index >= 0) { + if (!NextFile(FileNumber, FileOffset)) + return -1; + Max = Length; + } + lastIndex = Index; + } + if (Index < 0) { + // This results in normal replay after a fast rewind. + // After a fast forward it will stop. + // TODO Could we cause it to pause at the last frame? + SetMode(rmPlay); + return 0; + } } } } @@ -1041,12 +1328,22 @@ int cReplayBuffer::Read(int Max = -1) int readin = 0; do { // If Max is > 0 here we need to make sure we read in the entire block! - int r = cFileBuffer::Read(Max); + int r = cRingBuffer::Read(Max); if (r >= 0) readin += r; else return -1; } while (readin < Max && Free() > 0); + if (mode != rmPlay) { + // delete the audio data in modes other than rmPlay: + int AudioOffset, StartOffset = 0; + while ((AudioOffset = FindStartCode(SC_AUDIO, StartOffset)) >= 0) { + if (!Set(StartOffset + AudioOffset, GetPacketLength(StartOffset + AudioOffset), 0)) + break; // to be able to replay old AV_PES recordings! + StartOffset += AudioOffset; + } + SetTemporalReference(); + } return readin; } if (Available() > 0) @@ -1057,16 +1354,10 @@ int cReplayBuffer::Read(int Max = -1) int cReplayBuffer::Write(int Max) { int Written = 0; - int Av = Available(); - if (skipAudio) { - SkipAudioBlocks(); - Max = GetAvPesLength(); - fileOffset += Av - Available(); - } if (Max) { int w; do { - w = cFileBuffer::Write(Max); + w = cRingBuffer::Write(Max); if (w >= 0) { fileOffset += w; Written += w; @@ -1076,7 +1367,7 @@ int cReplayBuffer::Write(int Max) } else return w; - } while (Max > 0); // we MUST write this entire AV_PES block + } while (Max > 0); // we MUST write this entire frame block } return Written; } @@ -1098,44 +1389,188 @@ cTransferBuffer::cTransferBuffer(int FromDevice, int ToDevice) { fromDevice = FromDevice; toDevice = ToDevice; - active = true; + active = false; Start(); } cTransferBuffer::~cTransferBuffer() { - { - LOCK_THREAD; - active = false; - } - for (time_t t0 = time(NULL); time(NULL) - t0 < 3; ) { - LOCK_THREAD; - if (active) - break; - } + active = false; + Cancel(3); + SetPlayMode(fromDevice, VID_PLAY_RESET); + SetPlayMode(toDevice, VID_PLAY_RESET); } void cTransferBuffer::Action(void) { dsyslog(LOG_INFO, "data transfer thread started (pid=%d)", getpid()); - //XXX hack to make the video device go into 'replaying' mode: - char *dummy = "AV"; // must be "AV" to make the driver go into AV_PES mode! - write(toDevice, dummy, strlen(dummy)); - { - cRingBuffer Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); - while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start - Buffer.Read(); // initializes fromDevice for reading - usleep(1); // this keeps the CPU load low - } - for (; active;) { + + cRingBuffer Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); + active = true; + while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start + Buffer.Read(); // initializes fromDevice for reading + usleep(1); // this keeps the CPU load low + } + while (active) { if (Buffer.Read() < 0 || Buffer.Write() < 0) break; usleep(1); // this keeps the CPU load low } - } dsyslog(LOG_INFO, "data transfer thread stopped (pid=%d)", getpid()); - LOCK_THREAD; - active = true; +} + +// --- cCuttingBuffer -------------------------------------------------------- + +class cCuttingBuffer : public cRingBuffer, public cThread { +private: + bool active; + int fromFile, toFile; + cFileName *fromFileName, *toFileName; + cIndexFile *fromIndex, *toIndex; + cMarks fromMarks, toMarks; +protected: + virtual void Action(void); +public: + cCuttingBuffer(const char *FromFileName, const char *ToFileName); + virtual ~cCuttingBuffer(); + }; + +cCuttingBuffer::cCuttingBuffer(const char *FromFileName, const char *ToFileName) +:cRingBuffer(&fromFile, &toFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) +{ + active = false; + fromFile = toFile = -1; + fromFileName = toFileName = NULL; + fromIndex = toIndex = NULL; + if (fromMarks.Load(FromFileName) && fromMarks.Count()) { + fromFileName = new cFileName(FromFileName, false); + toFileName = new cFileName(ToFileName, true); + fromIndex = new cIndexFile(FromFileName, false); + toIndex = new cIndexFile(ToFileName, true); + toMarks.Load(ToFileName); // doesn't actually load marks, just sets the file name + Start(); + } + else + esyslog(LOG_ERR, "no editing marks found for %s", FromFileName); +} + +cCuttingBuffer::~cCuttingBuffer() +{ + active = false; + Cancel(3); + delete fromFileName; + delete toFileName; + delete fromIndex; + delete toIndex; +} + +void cCuttingBuffer::Action(void) +{ + dsyslog(LOG_INFO, "video cutting thread started (pid=%d)", getpid()); + + cMark *Mark = fromMarks.First(); + if (Mark) { + fromFile = fromFileName->Open(); + toFile = toFileName->Open(); + active = fromFile >= 0 && toFile >= 0; + int Index = Mark->position; + Mark = fromMarks.Next(Mark); + int FileSize = 0; + int CurrentFileNumber = 0; + int LastIFrame = 0; + toMarks.Add(0); + toMarks.Save(); + while (active) { + uchar FileNumber; + int FileOffset, Length; + uchar PictureType; + + Clear(); // makes sure one frame is completely read and written + + // Read one frame: + + if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { + if (FileNumber != CurrentFileNumber) { + fromFile = fromFileName->SetOffset(FileNumber, FileOffset); + CurrentFileNumber = FileNumber; + } + if (fromFile >= 0) + Length = cRingBuffer::Read(Length); + else + break; + } + else + break; + + // Write one frame: + + if (PictureType == I_FRAME) { // every file shall start with an I_FRAME + if (FileSize > MAXVIDEOFILESIZE) { + toFile = toFileName->NextFile(); + if (toFile < 0) + break; + FileSize = 0; + } + LastIFrame = 0; + } + cRingBuffer::Write(Length); + toIndex->Write(PictureType, toFileName->Number(), FileSize); + FileSize += Length; + if (!LastIFrame) + LastIFrame = toIndex->Last(); + + // Check editing marks: + + if (Mark && Index >= Mark->position) { + Mark = fromMarks.Next(Mark); + if (Mark) { + Index = Mark->position; + Mark = fromMarks.Next(Mark); + CurrentFileNumber = 0; // triggers SetOffset before reading next frame + toMarks.Add(LastIFrame); + toMarks.Add(toIndex->Last() + 1); + toMarks.Save(); + } + else + break; // final end mark reached + } + } + } + else + esyslog(LOG_ERR, "no editing marks found!"); + dsyslog(LOG_INFO, "end video cutting thread"); +} + +// --- cVideoCutter ---------------------------------------------------------- + +cCuttingBuffer *cVideoCutter::cuttingBuffer = NULL; + +bool cVideoCutter::Start(const char *FileName) +{ + if (!cuttingBuffer) { + const char *EditedVersionName = PrefixVideoFileName(FileName, '%'); + if (EditedVersionName && RemoveVideoFile(EditedVersionName) && MakeDirs(EditedVersionName, true)) { + cuttingBuffer = new cCuttingBuffer(FileName, EditedVersionName); + return true; + } + } + return false; +} + +void cVideoCutter::Stop(void) +{ + delete cuttingBuffer; + cuttingBuffer = NULL; +} + +bool cVideoCutter::Active(void) +{ + if (cuttingBuffer) { + if (cuttingBuffer->Active()) + return true; + Stop(); + } + return false; } // --- cDvbApi --------------------------------------------------------------- @@ -1147,13 +1582,12 @@ cDvbApi *cDvbApi::PrimaryDvbApi = NULL; cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) { siProcessor = NULL; - pidRecord = pidReplay = 0; - fromRecord = toRecord = -1; - fromReplay = toReplay = -1; - ca = 0; - priority = -1; + recordBuffer = NULL; + replayBuffer = NULL; transferBuffer = NULL; transferringFromDvbApi = NULL; + ca = 0; + priority = -1; videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK); if (videoDev >= 0) { siProcessor = new cSIProcessor(VbiFileName); @@ -1191,8 +1625,6 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) #else osd = NULL; #endif - lastProgress = lastTotal = -1; - replayTitle = NULL; currentChannel = 1; } @@ -1201,7 +1633,7 @@ cDvbApi::~cDvbApi() if (videoDev >= 0) { delete siProcessor; Close(); - Stop(); + StopReplay(); StopRecord(); StopTransfer(); OvlO(false); //Overlay off! @@ -1211,7 +1643,6 @@ cDvbApi::~cDvbApi() #if defined(DEBUG_OSD) || defined(REMOTE_KBD) endwin(); #endif - delete replayTitle; } bool cDvbApi::SetPrimaryDvbApi(int n) @@ -1618,8 +2049,6 @@ void cDvbApi::Open(int w, int h) SETCOLOR(clrCyan, 0x00, 0xFC, 0xFC, 255); SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255); SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255); - - lastProgress = lastTotal = -1; } void cDvbApi::Close(void) @@ -1633,7 +2062,6 @@ void cDvbApi::Close(void) delete osd; osd = NULL; #endif - lastProgress = lastTotal = -1; } void cDvbApi::Clear(void) @@ -1662,6 +2090,13 @@ void cDvbApi::Fill(int x, int y, int w, int h, eDvbColor color) #endif } +void cDvbApi::SetBitmap(int x, int y, const cBitmap &Bitmap) +{ +#ifndef DEBUG_OSD + osd->SetBitmap(x, y, Bitmap); +#endif +} + void cDvbApi::ClrEol(int x, int y, eDvbColor color) { Fill(x, y, cols - x, 1, color); @@ -1676,6 +2111,15 @@ int cDvbApi::CellWidth(void) #endif } +int cDvbApi::LineHeight(void) +{ +#ifdef DEBUG_OSD + return 1; +#else + return lineHeight; +#endif +} + int cDvbApi::Width(unsigned char c) { #ifdef DEBUG_OSD @@ -1724,67 +2168,12 @@ void cDvbApi::Flush(void) #endif } -bool cDvbApi::ShowProgress(bool Initial) -{ - int Current, Total; - - if (GetIndex(&Current, &Total)) { - if (Initial) { - Clear(); - if (replayTitle) - Text(0, 0, replayTitle); - } - if (Total != lastTotal) - Text(-7, 2, cIndexFile::Str(Total)); - Flush(); -#ifdef DEBUG_OSD - int p = cols * Current / Total; - Fill(0, 1, p, 1, clrGreen); - Fill(p, 1, cols - p, 1, clrWhite); -#else - int w = cols * charWidth; - int p = w * Current / Total; - if (p != lastProgress) { - int y1 = 1 * lineHeight; - int y2 = 2 * lineHeight - 1; - int x1, x2; - eDvbColor color; - if (lastProgress < p) { - x1 = lastProgress + 1; - x2 = p; - if (p >= w) - p = w - 1; - color = clrGreen; - } - else { - x1 = p + 1; - x2 = lastProgress; - color = clrWhite; - } - if (lastProgress < 0) - osd->Fill(0, y1, w - 1, y2, clrWhite); - osd->Fill(x1, y1, x2, y2, color); - lastProgress = p; - } - Flush(); -#endif - Text(0, 2, cIndexFile::Str(Current)); - Flush(); - lastTotal = Total; - return true; - } - return false; -} - bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr) { if (videoDev >= 0) { + cThreadLock ThreadLock(siProcessor); // makes sure the siProcessor won't access the vbi-device while switching StopTransfer(); - if (transferringFromDvbApi) { - transferringFromDvbApi->StopTransfer(); - transferringFromDvbApi = NULL; - } - SetReplayMode(VID_PLAY_RESET); + SetPlayMode(videoDev, VID_PLAY_RESET); struct frontend front; ioctl(videoDev, VIDIOCGFRONTEND, &front); unsigned int freq = FrequencyMHz; @@ -1793,8 +2182,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, freq -= Setup.LnbFrequLo; else freq -= Setup.LnbFrequHi; - front.channel_flags = Ca ? DVB_CHANNEL_CA : DVB_CHANNEL_FTA; - front.pnr = Pnr; + front.pnr = 0; front.freq = freq * 1000000UL; front.diseqc = Diseqc; front.srate = Srate * 1000; @@ -1821,7 +2209,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, } return true; } - esyslog(LOG_ERR, "ERROR: channel not sync'ed (front.sync=%X)!", front.sync); + esyslog(LOG_ERR, "ERROR: channel %d not sync'ed (front.sync=%X)!", ChannelNumber, front.sync); } return false; } @@ -1843,22 +2231,31 @@ void cDvbApi::StopTransfer(void) if (transferBuffer) { delete transferBuffer; transferBuffer = NULL; - SetReplayMode(VID_PLAY_RESET); + SetPlayMode(videoDev, VID_PLAY_RESET); + } + if (transferringFromDvbApi) { + transferringFromDvbApi->StopTransfer(); + transferringFromDvbApi = NULL; } } +int cDvbApi::SecondsToFrames(int Seconds) +{ + return Seconds * FRAMESPERSEC; +} + bool cDvbApi::Recording(void) { - if (pidRecord && !CheckProcess(pidRecord)) - pidRecord = 0; - return pidRecord; + if (recordBuffer && !recordBuffer->Active()) + StopRecord(); + return recordBuffer != NULL; } bool cDvbApi::Replaying(void) { - if (pidReplay && !CheckProcess(pidReplay)) - pidReplay = 0; - return pidReplay; + if (replayBuffer && !replayBuffer->Active()) + StopReplay(); + return replayBuffer != NULL; } bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) @@ -1871,7 +2268,7 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) StopTransfer(); - Stop(); // TODO: remove this if the driver is able to do record and replay at the same time + StopReplay(); // TODO: remove this if the driver is able to do record and replay at the same time // Check FileName: @@ -1886,129 +2283,41 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) if (!MakeDirs(FileName, true)) return false; - // Open pipes for recording process: + // Create recording buffer: - int fromRecordPipe[2], toRecordPipe[2]; + recordBuffer = new cRecordBuffer(&videoDev, FileName); - if (pipe(fromRecordPipe) != 0) { - LOG_ERROR; - return false; - } - if (pipe(toRecordPipe) != 0) { - LOG_ERROR; - return false; - } - - // Create recording process: - - pidRecord = fork(); - if (pidRecord < 0) { - LOG_ERROR; - return false; - } - if (pidRecord == 0) { - - // This is the actual recording process - - dsyslog(LOG_INFO, "start recording process (pid=%d)", getpid()); - bool DataStreamBroken = false; - int fromMain = toRecordPipe[0]; - int toMain = fromRecordPipe[1]; - cRecordBuffer *Buffer = new cRecordBuffer(&videoDev, FileName); - if (Buffer) { - for (;;) { - fd_set set; - FD_ZERO(&set); - FD_SET(videoDev, &set); - FD_SET(fromMain, &set); - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - bool ForceEnd = false; - if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) { - if (FD_ISSET(videoDev, &set)) { - if (Buffer->Read() < 0) - break; - DataStreamBroken = false; - } - if (FD_ISSET(fromMain, &set)) { - switch (readchar(fromMain)) { - case dvbStop: Buffer->Stop(); - ForceEnd = DataStreamBroken; - break; - } - } - } - else { - DataStreamBroken = true; - esyslog(LOG_ERR, "ERROR: video data stream broken"); - } - if (Buffer->WriteWithTimeout(ForceEnd) < 0) - break; - } - delete Buffer; - } - else - esyslog(LOG_ERR, "ERROR: can't allocate recording buffer"); - close(fromMain); - close(toMain); - dsyslog(LOG_INFO, "end recording process"); - exit(0); + if (recordBuffer) { + ca = Ca; + priority = Priority; + return true; } - - // Establish communication with the recording process: - - fromRecord = fromRecordPipe[0]; - toRecord = toRecordPipe[1]; - - ca = Ca; - priority = Priority; - return true; + else + esyslog(LOG_ERR, "ERROR: can't allocate recording buffer"); } return false; } void cDvbApi::StopRecord(void) { - if (pidRecord) { - writechar(toRecord, dvbStop); - close(toRecord); - close(fromRecord); - toRecord = fromRecord = -1; - KillProcess(pidRecord); - pidRecord = 0; + if (recordBuffer) { + delete recordBuffer; + recordBuffer = NULL; ca = 0; priority = -1; - SetReplayMode(VID_PLAY_RESET); //XXX } } -void cDvbApi::SetReplayMode(int Mode) -{ - if (videoDev >= 0) { - struct video_play_mode pmode; - pmode.mode = Mode; - ioctl(videoDev, VIDIOCSPLAYMODE, &pmode); - } -} - -bool cDvbApi::StartReplay(const char *FileName, const char *Title) +bool cDvbApi::StartReplay(const char *FileName) { if (Recording()) { esyslog(LOG_ERR, "ERROR: StartReplay() called while recording - ignored!"); return false; } StopTransfer(); - Stop(); + StopReplay(); if (videoDev >= 0) { - lastProgress = lastTotal = -1; - delete replayTitle; - if (Title) { - if ((replayTitle = strdup(Title)) == NULL) - esyslog(LOG_ERR, "ERROR: StartReplay: can't copy title '%s'", Title); - } - // Check FileName: if (!FileName) { @@ -2017,209 +2326,77 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) } isyslog(LOG_INFO, "replay %s", FileName); - // Open pipes for replay process: - - int fromReplayPipe[2], toReplayPipe[2]; - - if (pipe(fromReplayPipe) != 0) { - LOG_ERROR; - return false; - } - if (pipe(toReplayPipe) != 0) { - LOG_ERROR; - return false; - } - - // Create replay process: + // Create replay buffer: - pidReplay = fork(); - if (pidReplay < 0) { - LOG_ERROR; - return false; - } - if (pidReplay == 0) { - - // This is the actual replaying process - - dsyslog(LOG_INFO, "start replaying process (pid=%d)", getpid()); - int fromMain = toReplayPipe[0]; - int toMain = fromReplayPipe[1]; - cReplayBuffer *Buffer = new cReplayBuffer(&videoDev, FileName); - if (Buffer) { - bool Paused = false; - bool FastForward = false; - bool FastRewind = false; - int ResumeIndex = Buffer->Resume(); - if (ResumeIndex >= 0) - isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, cIndexFile::Str(ResumeIndex, true)); - for (;;) { - if (Buffer->Read() < 0) - break; - fd_set setIn, setOut; - FD_ZERO(&setIn); - FD_ZERO(&setOut); - FD_SET(fromMain, &setIn); - FD_SET(videoDev, &setOut); - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - if (select(FD_SETSIZE, &setIn, &setOut, NULL, &timeout) > 0) { - if (FD_ISSET(videoDev, &setOut)) { - if (Buffer->Write() < 0) - break; - } - if (FD_ISSET(fromMain, &setIn)) { - switch (readchar(fromMain)) { - case dvbStop: SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Stop(); - break; - case dvbPause: SetReplayMode(Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); - Paused = !Paused; - if (FastForward || FastRewind) { - SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Clear(); - } - FastForward = FastRewind = false; - Buffer->SetMode(rmPlay); - break; - case dvbPlay: if (FastForward || FastRewind || Paused) { - SetReplayMode(VID_PLAY_CLEAR_BUFFER); - SetReplayMode(VID_PLAY_NORMAL); - FastForward = FastRewind = Paused = false; - Buffer->SetMode(rmPlay); - } - break; - case dvbForward: SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Clear(); - FastForward = !FastForward; - FastRewind = false; - if (Paused) { - Buffer->SetMode(rmPlay); - SetReplayMode(FastForward ? VID_PLAY_SLOW_MOTION : VID_PLAY_PAUSE); - } - else { - SetReplayMode(VID_PLAY_NORMAL); - Buffer->SetMode(FastForward ? rmFastForward : rmPlay); - } - break; - case dvbBackward: SetReplayMode(VID_PLAY_CLEAR_BUFFER); - Buffer->Clear(); - FastRewind = !FastRewind; - FastForward = false; - if (Paused) { - Buffer->SetMode(FastRewind ? rmSlowRewind : rmPlay); - SetReplayMode(FastRewind ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); - } - else { - SetReplayMode(VID_PLAY_NORMAL); - Buffer->SetMode(FastRewind ? rmFastRewind : rmPlay); - } - break; - case dvbSkip: { - int Seconds; - if (readint(fromMain, Seconds)) { - SetReplayMode(VID_PLAY_CLEAR_BUFFER); - SetReplayMode(VID_PLAY_NORMAL); - FastForward = FastRewind = Paused = false; - Buffer->SetMode(rmPlay); - Buffer->SkipSeconds(Seconds); - } - } - break; - case dvbGetIndex: { - int Current, Total; - Buffer->GetIndex(Current, Total); - writeint(toMain, Current); - writeint(toMain, Total); - } - break; - } - } - } - } - Buffer->Save(); - delete Buffer; - } - else - esyslog(LOG_ERR, "ERROR: can't allocate replaying buffer"); - close(fromMain); - close(toMain); - SetReplayMode(VID_PLAY_RESET); //XXX - dsyslog(LOG_INFO, "end replaying process"); - exit(0); - } - - // Establish communication with the replay process: - - fromReplay = fromReplayPipe[0]; - toReplay = toReplayPipe[1]; - return true; + replayBuffer = new cReplayBuffer(&videoDev, FileName); + if (replayBuffer) + return true; + else + esyslog(LOG_ERR, "ERROR: can't allocate replaying buffer"); } return false; } -void cDvbApi::Stop(void) +void cDvbApi::StopReplay(void) { - if (pidReplay) { - writechar(toReplay, dvbStop); - close(toReplay); - close(fromReplay); - toReplay = fromReplay = -1; - KillProcess(pidReplay); - pidReplay = 0; - SetReplayMode(VID_PLAY_RESET); //XXX + if (replayBuffer) { + delete replayBuffer; + replayBuffer = NULL; } } void cDvbApi::Pause(void) { - if (pidReplay) - writechar(toReplay, dvbPause); + if (replayBuffer) + replayBuffer->Pause(); } void cDvbApi::Play(void) { - if (pidReplay) - writechar(toReplay, dvbPlay); + if (replayBuffer) + replayBuffer->Play(); } void cDvbApi::Forward(void) { - if (pidReplay) - writechar(toReplay, dvbForward); + if (replayBuffer) + replayBuffer->Forward(); } void cDvbApi::Backward(void) { - if (pidReplay) - writechar(toReplay, dvbBackward); + if (replayBuffer) + replayBuffer->Backward(); } -void cDvbApi::Skip(int Seconds) +void cDvbApi::SkipSeconds(int Seconds) { - if (pidReplay) { - writechar(toReplay, dvbSkip); - writeint(toReplay, Seconds); - } + if (replayBuffer) + replayBuffer->SkipSeconds(Seconds); } -bool cDvbApi::GetIndex(int *Current, int *Total) +int cDvbApi::SkipFrames(int Frames) { - if (pidReplay) { - int total; - purge(fromReplay); - writechar(toReplay, dvbGetIndex); - if (readint(fromReplay, *Current) && readint(fromReplay, total)) { - if (Total) - *Total = total; - } - else - *Current = -1; - return *Current >= 0; + if (replayBuffer) + return replayBuffer->SkipFrames(Frames); + return -1; +} + +bool cDvbApi::GetIndex(int &Current, int &Total, bool SnapToIFrame) +{ + if (replayBuffer) { + replayBuffer->GetIndex(Current, Total, SnapToIFrame); + return true; } return false; } +void cDvbApi::Goto(int Position, bool Still) +{ + if (replayBuffer) + replayBuffer->Goto(Position, Still); +} + // --- cEITScanner ----------------------------------------------------------- cEITScanner::cEITScanner(void) diff --git a/dvbapi.h b/dvbapi.h index f6640ff5d..cf0584f80 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.26 2000/11/19 14:09:41 kls Exp $ + * $Id: dvbapi.h 1.30 2001/01/07 15:56:10 kls Exp $ */ #ifndef __DVBAPI_H @@ -22,6 +22,7 @@ typedef unsigned char __u8; #include #include "dvbosd.h" #include "eit.h" +#include "thread.h" // Overlay facilities #define MAXCLIPRECTS 100 @@ -42,7 +43,24 @@ class cResumeFile { bool Save(int Index); }; +const char *IndexToHMSF(int Index, bool WithFrame = false); + // Converts the given index to a string, optionally containing the frame number. +int HMSFToIndex(const char *HMSF); + // Converts the given string (format: "hh:mm:ss.ff") to an index. + +class cRecordBuffer; +class cReplayBuffer; class cTransferBuffer; +class cCuttingBuffer; + +class cVideoCutter { +private: + static cCuttingBuffer *cuttingBuffer; +public: + static bool Start(const char *FileName); + static void Stop(void); + static bool Active(void); + }; class cDvbApi { private: @@ -129,22 +147,16 @@ class cDvbApi { void Close(void); void Clear(void); void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground); + void SetBitmap(int x, int y, const cBitmap &Bitmap); void ClrEol(int x, int y, eDvbColor color = clrBackground); int CellWidth(void); + int LineHeight(void); int Width(unsigned char c); int WidthInCells(const char *s); eDvbFont SetFont(eDvbFont Font); void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground); void Flush(void); - // Progress Display facilities - -private: - int lastProgress, lastTotal; - char *replayTitle; -public: - bool ShowProgress(bool Initial = false); - // Channel facilities private: @@ -171,20 +183,10 @@ class cDvbApi { // Record/Replay facilities private: - enum { dvbStop = 1, // let's not have 0 as a command - dvbPause, - dvbPlay, - dvbForward, - dvbBackward, - dvbSkip, - dvbGetIndex, - }; - pid_t pidRecord, pidReplay; - int fromRecord, toRecord; - int fromReplay, toReplay; + cRecordBuffer *recordBuffer; + cReplayBuffer *replayBuffer; int ca; int priority; - void SetReplayMode(int Mode); protected: int Ca(void) { return ca; } // Returns the ca of the current recording session (0..MAXDVBAPI). @@ -192,6 +194,8 @@ class cDvbApi { // Returns the priority of the current recording session (0..99), // or -1 if no recording is currently active. public: + int SecondsToFrames(int Seconds); + // Returns the number of frames corresponding to the given number of seconds. bool Recording(void); // Returns true if we are currently recording. bool Replaying(void); @@ -209,12 +213,11 @@ class cDvbApi { // returned. void StopRecord(void); // Stops the current recording session (if any). - bool StartReplay(const char *FileName, const char *Title = NULL); + 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. - // If provided Title will be used in the progress display. - void Stop(void); + void StopReplay(void); // Stops the current replay session (if any). void Pause(void); // Pauses the current replay session, or resumes a paused session. @@ -224,12 +227,21 @@ class cDvbApi { // Runs the current replay session forward at a higher speed. void Backward(void); // Runs the current replay session backwards at a higher speed. - void Skip(int Seconds); + void SkipSeconds(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. - bool GetIndex(int *Current, int *Total = NULL); + int SkipFrames(int Frames); + // Returns the new index into the current replay session after skipping + // the given number of frames (no actual repositioning is done!). + // The sign of 'Frames' determines the direction in which to skip. + bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); + // Returns the current and total frame index, optionally snapped to the + // nearest I-frame. + void Goto(int Index, bool Still = false); + // Positions to the given index and displays that frame as a still picture + // if Still is true. }; class cEITScanner { diff --git a/dvbosd.c b/dvbosd.c index 457175d8b..395ad32ed 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.6 2000/11/18 15:36:51 kls Exp $ + * $Id: dvbosd.c 1.7 2000/12/09 11:13:00 kls Exp $ */ #include "dvbosd.h" @@ -82,6 +82,16 @@ void cBitmap::SetPixel(int x, int y, eDvbColor Color) } } +void cBitmap::SetBitmap(int x, int y, const cBitmap &Bitmap) +{ + if (bitmap && Bitmap.bitmap) { + for (int ix = 0; ix < Bitmap.width; ix++) { + for (int iy = 0; iy < Bitmap.height; iy++) + SetPixel(x + ix, y + iy, eDvbColor(Bitmap.bitmap[Bitmap.width * iy + ix])); + } + } +} + int cBitmap::Width(unsigned char c) { return font ? font->Width(c) : -1; diff --git a/dvbosd.h b/dvbosd.h index e2a424a8d..eefdb621e 100644 --- a/dvbosd.h +++ b/dvbosd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.h 1.4 2000/11/18 15:25:25 kls Exp $ + * $Id: dvbosd.h 1.5 2000/12/09 10:32:47 kls Exp $ */ #ifndef __DVBOSD_H @@ -57,6 +57,7 @@ class cBitmap { eDvbFont SetFont(eDvbFont Font); bool Dirty(void); void SetPixel(int x, int y, eDvbColor Color); + void SetBitmap(int x, int y, const cBitmap &Bitmap); int Width(unsigned char c); int Width(const char *s); void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); diff --git a/eit.c b/eit.c index 79855282f..e7c60c164 100644 --- a/eit.c +++ b/eit.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.9 2000/11/18 13:42:28 kls Exp $ + * $Id: eit.c 1.11 2000/12/03 15:33:37 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -33,6 +33,8 @@ #include #include #include +#include "config.h" +#include "videodir.h" // --- cMJD ------------------------------------------------------------------ @@ -129,7 +131,7 @@ bool cMJD::SetSystemTime() isyslog(LOG_INFO, "System Time = %s (%ld)\n", ctime(&loctim), loctim); isyslog(LOG_INFO, "Local Time = %s (%ld)\n", ctime(&mjdtime), mjdtime); if (stime(&mjdtime) < 0) - esyslog(LOG_ERR, "ERROR while setting system time: %s", strerror(errno)); + esyslog(LOG_ERR, "ERROR while setting system time: %m"); return true; } @@ -393,6 +395,21 @@ unsigned short cEventInfo::GetServiceID() const return uServiceID; } +/** */ +void cEventInfo::Dump(FILE *f) const +{ + if (tTime + lDuration >= time(NULL)) { + fprintf(f, "E %u %ld %ld\n", uEventID, tTime, lDuration); + if (!isempty(pTitle)) + fprintf(f, "T %s\n", pTitle); + if (!isempty(pSubtitle)) + fprintf(f, "S %s\n", pSubtitle); + if (!isempty(pExtendedDescription)) + fprintf(f, "D %s\n", pExtendedDescription); + fprintf(f, "e\n"); + } +} + // --- cSchedule ------------------------------------------------------------- cSchedule::cSchedule(unsigned short servid) @@ -529,6 +546,19 @@ void cSchedule::Cleanup(time_t tTime) } } +/** */ +void cSchedule::Dump(FILE *f) const +{ + cChannel *channel = Channels.GetByServiceID(uServiceID); + if (channel) + { + fprintf(f, "C %u %s\n", uServiceID, channel->name); + for (cEventInfo *p = Events.First(); p; p = Events.Next(p)) + p->Dump(f); + fprintf(f, "c\n"); + } +} + // --- cSchedules ------------------------------------------------------------ cSchedules::cSchedules() @@ -590,6 +620,13 @@ void cSchedules::Cleanup() } } +/** */ +void cSchedules::Dump(FILE *f) const +{ + for (cSchedule *p = First(); p; p = Next(p)) + p->Dump(f); +} + // --- cEIT ------------------------------------------------------------------ #define DEC(N) dec << setw(N) << setfill(int('0')) @@ -1080,7 +1117,7 @@ cSIProcessor::~cSIProcessor() { if (fsvbi >= 0) { - Stop(); + Cancel(); ShutDownFilters(); delete filters; if (!--numSIProcessors) // the last one deletes it @@ -1105,6 +1142,7 @@ void cSIProcessor::Action() unsigned int seclen; unsigned int pid; time_t lastCleanup = time(NULL); + time_t lastDump = time(NULL); struct pollfd pfd; while(true) @@ -1123,6 +1161,19 @@ void cSIProcessor::Action() schedulesMutex.Unlock(); lastCleanup = now; } + if (now - lastDump > 600) + { + LOCK_THREAD; + + schedulesMutex.Lock(); + FILE *f = fopen(AddDirectory(VideoDirectory, "epg.data"), "w"); + if (f) { + schedules->Dump(f); + fclose(f); + } + lastDump = now; + schedulesMutex.Unlock(); + } } /* wait data become ready from the bitfilter */ @@ -1283,4 +1334,3 @@ bool cSIProcessor::RefreshFilters() return ret; } - diff --git a/eit.h b/eit.h index d5c4ebdcf..bedead755 100644 --- a/eit.h +++ b/eit.h @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.3 2000/11/17 16:14:27 kls Exp $ + * $Id: eit.h 1.4 2000/11/24 14:35:22 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -66,6 +66,7 @@ class cEventInfo : public cListObject { unsigned short GetServiceID(void) const; int GetChannelNumber(void) const { return nChannelNumber; } void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' + void Dump(FILE *f) const; }; class cSchedule : public cListObject { @@ -92,6 +93,7 @@ class cSchedule : public cListObject { const cEventInfo *GetEvent(time_t tTime) const; const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); } int NumEvents(void) const { return Events.Count(); } + void Dump(FILE *f) const; }; class cSchedules : public cList { @@ -107,6 +109,7 @@ class cSchedules : public cList { ~cSchedules(); const cSchedule *GetSchedule(unsigned short servid) const; const cSchedule *GetSchedule(void) const; + void Dump(FILE *f) const; }; typedef struct sip_filter { diff --git a/epg2html.pl b/epg2html.pl new file mode 100644 index 000000000..215eb7356 --- /dev/null +++ b/epg2html.pl @@ -0,0 +1,96 @@ +#!/usr/bin/perl + +# A simple EPG to HTML converter +# +# Converts the EPG data written by 'vdr' into the file /video/epg.data +# into a simple HTML programme listing, consisting of one file per channel +# plus an 'index.htm' file. All output files are written into the current +# directory. +# +# Usage: epg2html.pl < /video/epg.data +# +# See the main source file 'vdr.c' for copyright information and +# how to reach the author. +# +# $Id: epg2html.pl 1.2 2000/12/01 18:37:46 kls Exp $ + +@Index = (); + +sub GetDay +{ + return substr(localtime(shift), 0, 10); +} + +sub GetTime +{ + return substr(localtime(shift), 11, 5); +} + +sub Tags +{ + my $s = shift; + $s =~ s/\&/&/g; + $s =~ s//>/g; + return $s; +} + +while (<>) { + chomp; + if (/^C ([^ ]+) *(.*)/) { + my $Channel = $2; + (my $Page = $Channel) =~ y/\/ /-_/; + $Page .= ".htm"; + $Channel = Tags($Channel); + push(@Index, qq{$Channel
\n}); + my %Events = (); + while (<>) { + if (/^E (.*) (.*) (.*)/) { + (my $Time, $Duration) = ($2, $3); + my $Title = "", $Subtitle = "", $Description = ""; + while (<>) { + if (/^T (.*)/) { $Title = Tags($1); } + elsif (/^S (.*)/) { $Subtitle = Tags($1); } + elsif (/^D (.*)/) { $Description = Tags($1); } + elsif (/^e/) { + $Events{$Time} = [($Duration, $Title, $Subtitle, $Description)]; + last; + } + } + } + elsif (/^c/) { + my @Schedule = (); + my $Day = ""; + for $t (sort keys %Events) { + (my $Duration, $Title, $Subtitle, $Description) = @{$Events{$t}}; + my $d = GetDay($t); + if ($d ne $Day) { + push(@Schedule, "
\n") if ($Day && @Schedule); + push(@Schedule, "

$d

\n"); + push(@Schedule, "\n"); + $Day = $d; + } + my $Entry = $Title; + $Entry .= "
$Subtitle" if $Subtitle; + $Entry .= "
$Description" if $Description; + push(@Schedule, "\n"); + } + push(@Schedule, "
" . GetTime($t) . "$Entry
\n") if (@Schedule); + open(PAGE, ">$Page") or die "$Page: $!\n"; + print PAGE "\n$Channel\n\n"; + print PAGE "

$Channel

\n"; + print PAGE @Schedule; + print PAGE "\n\n"; + close(PAGE); + last; + } + } + } + } + +open(INDEX, ">index.htm") or die "index.htm: $!\n"; +print INDEX "\nEPG Index\n\n"; +print INDEX sort { lc($a) cmp lc($b) } @Index; +print INDEX "\n\n"; +close(INDEX); + diff --git a/i18n.c b/i18n.c index 7b93062d3..cf1785f3a 100644 --- a/i18n.c +++ b/i18n.c @@ -4,9 +4,10 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.6 2000/11/19 12:12:53 kls Exp $ + * $Id: i18n.c 1.8 2001/01/06 16:17:39 kls Exp $ * * Slovenian translations provided by Miha Setina + * Italian translations provided by Alberto Carraro * */ @@ -31,9 +32,8 @@ * "Italiano", * }, * - * and so on. Insert your language so that all the entries - * following 'English' will be sorted alphabetically, and write - * the name of your language in your language (not in English, + * and so on. Append your language after the last existing language + * and write the name of your language in your language (not in English, * which means that it should be 'Italiano', not 'Italian'). * Note that only the characters defined in 'fontosd.c' will * be available! @@ -48,7 +48,7 @@ #include "config.h" #include "tools.h" -const int NumLanguages = 3; +const int NumLanguages = 4; typedef const char *tPhrase[NumLanguages]; @@ -57,401 +57,523 @@ const tPhrase Phrases[] = { { "English", "Deutsch", "Slovenski", + "Italiano", }, // Menu titles: { "Main", "Hauptmen", "Glavni meni", + "Principale", }, { "Schedule", "Programm", "Urnik", + "Programmi", }, { "Channels", "Kanle", "Kanali", + "Canali", }, { "Timers", "Timer", "Termini", + "Timer", }, { "Recordings", "Aufzeichnungen", "Posnetki", + "Registrazioni", }, { "Setup", "Einstellungen", "Nastavitve", + "Opzioni", }, { "Commands", "Befehle", "Ukazi", + "Comandi", }, { "Edit Channel", "Kanal Editieren", "Uredi kanal", + "Modifica canale", }, { "Edit Timer", "Timer Editieren", "Uredi termin", + "Modifica Timer", }, { "Event", "Sendung", "Oddaja", + "Eventi", }, { "Summary", "Inhalt", "Vsebina", + "Sommario", }, { "Schedule - %s", "Programm - %s", "Urnik - %s", + "Programma - %s", }, { "What's on now?", "Was luft jetzt?", "Kaj je na sporedu?", + "In programmazione", }, { "What's on next?", "Was luft als nchstes?", "Kaj sledi?", + "Prossimi programmi", }, // Button texts (must not be more than 10 characters!): { "Edit", "Editieren", "Uredi", + "Modifica", }, { "New", "Neu", "Novo", + "Nuovo", }, { "Delete", "Lschen", "Odstrani", + "Cancella", }, { "Mark", "Markieren", "Oznaci", + "Marca", }, { "Record", "Aufnehmen", "Posnemi", + "Registra", }, { "Play", "Wiedergabe", "Predavajaj", + "Riproduci", }, { "Resume", "Weiter", "Nadaljuj", + "Riprendi", }, { "Summary", "Inhalt", "Vsebina", + "Sommario", }, { "Switch", "Umschalten", "Preklopi", + "Cambia", }, { "Now", "Jetzt", "Sedaj", + "Adesso", }, { "Next", "Nchste", "Naslednji", + "Prossimo", }, { "Schedule", "Programm", "Urnik", + "Programma", }, // Confirmations: - { "Delete Channel?", + { "Delete channel?", "Kanal lschen?", "Odstrani kanal?", + "Cancello il canale?", }, - { "Delete Timer?", + { "Delete timer?", "Timer lschen?", "Odstani termin?", + "Cancello il timer?", }, - { "Delete Recording?", + { "Delete recording?", "Aufzeichnung lschen?", "Odstrani posnetek?", + "Cancello la registrazione?", }, - { "Stop Recording?", + { "Stop recording?", "Aufzeichnung beenden?", "Koncaj snemanje?", + "Fermo la registrazione?", + }, + { "Cancel editing?", + "Schneiden abbrechen?", + "Zelite prekiniti urejanje?", + "Annullo la modifica?", }, // Channel parameters: { "Name", "Name", "Naziv", + "Nome", }, { "Frequency", "Frequenz", "Frekvenca", + "Frequenza", }, { "Polarization", "Polarisation", "Polarizacija", + "Polarizzazione", }, { "Diseqc", "Diseqc", "Diseqc", + "Diseqc", }, { "Srate", "Srate", "Srate", + "Srate", }, { "Vpid", "Vpid", "Vpid", + "Vpid", }, { "Apid", "Apid", "Apid", + "Apid", }, { "CA", "CA", "CA", + "CA", }, { "Pnr", "Pnr", "Pnr", + "Pnr", }, // Timer parameters: { "Active", "Aktiv", "Aktivno", + "Attivo", }, { "Channel", "Kanal", "Kanal", + "Canale", }, { "Day", "Tag", "Dan", + "Giorno", }, { "Start", "Anfang", "Zacetek", + "Inizio", }, { "Stop", "Ende", "Konec", + "Fine", }, { "Priority", "Prioritt", "Prioriteta", + "Priorita", }, { "Lifetime", "Lebensdauer", "Veljavnost", + "Durata", }, { "File", "Datei", "Datoteka", + "Nome", }, // Error messages: { "Channel is being used by a timer!", "Kanal wird von einem Timer benutzt!", "Urnik zaseda kanal!", + "Canale occupato da un timer!", }, { "Can't switch channel!", "Kanal kann nicht umgeschaltet werden!", "Ne morem preklopiti kanala!", + "Impossibile cambiare canale!", }, { "Timer is recording!", "Timer zeichnet gerade auf!", "Snemanje po urniku!", + "Registrazione di un timer in corso!", }, { "Error while deleting recording!", "Fehler beim Lschen der Aufzeichnung!", "Napaka pri odstranjevanju posnetka!", + "Errore durante la canc del filmato!", }, { "*** Invalid Channel ***", "*** Ungltiger Kanal ***", "*** Neznan kanal ***", + "*** CANALE INVALIDO ***", }, { "No free DVB device to record!", "Keine freie DVB-Karte zum Aufnehmen!", "Ni proste DVB naprave za snemanje!", + "Nessuna card DVB disp per registrare!", }, { "Channel locked (recording)!", "Kanal blockiert (zeichnet auf)!", "Zaklenjen kanal (snemanje)!", + "Canale bloccato (in registrazione)!", + }, + { "Can't start editing process!", + "Schnitt kann nicht gestartet werden!", + "Ne morem zaceti urejanja!", + "Imposs iniziare processo di modifica", + }, + { "Editing process already active!", + "Schnitt bereits aktiv!", + "Urejanje je ze aktivno!", + "Processo di modifica gia` attivo", }, // Setup parameters: { "OSD-Language", "OSD-Sprache", "OSD-jezik", + "Linguaggio OSD", }, { "PrimaryDVB", "Primres Interface", "Primarna naprava", + "Scheda DVB primaria", }, { "ShowInfoOnChSwitch", "Info zeigen", "Pokazi naziv kanala", + "Vis info nel cambio canale", }, { "MenuScrollPage", "Seitenweise scrollen", "Drsni meni", + "Scrolla pagina nel menu", }, { "MarkInstantRecord", "Direktaufz. markieren", "Oznaci direktno snemanje", + "Marca la registrazione", }, { "LnbFrequLo", "Untere LNB-Frequenz", "Spodnja LNB-frek.", + "Freq LO LNB", }, { "LnbFrequHi", "Obere LNB-Frequenz", "Zgornja LNB-frek.", + "Freq HI LNB", }, { "SetSystemTime", "Systemzeit stellen", "Sistemski cas", + "Setta orario auto", }, { "MarginStart", "Zeitpuffer bei Anfang", "Premor pred zacetkom", + "Min margine inizio", }, { "MarginStop", "Zeitpuffer bei Ende", "Premor za koncem", + "Min margine fine", }, { "EPGScanTimeout", "Zeit bis EPG Scan", "Cas do EPG pregleda", + "Timeout EPG", }, // The days of the week: { "MTWTFSS", "MDMDFSS", "PTSCPSN", + "DLMMGVS", }, // Learning keys: { "Learning Remote Control Keys", "Fernbedienungs-Codes lernen", "Ucim se kod upravljalca", + "Apprendimento tasti unita` remota", }, { "Phase 1: Detecting RC code type", "Phase 1: FB Code feststellen", "Faza 1: Sprejemanje IR kode", + "Fase 1: tipo ricevitore RC", }, { "Press any key on the RC unit", "Eine Taste auf der FB drcken", "Pritisnite tipko na upravljalcu", + "Premere un tasto nell'unita` RC", }, { "RC code detected!", "FB Code erkannt!", "IR koda sprejeta!", + "Codice RC rilevato!", }, { "Do not press any key...", "Keine Taste drcken...", "Ne pritiskajte tipk...", + "Non premere alcun tasto...", }, { "Phase 2: Learning specific key codes", "Phase 2: Einzelne Tastencodes lernen", "Faza 2: Ucenje posebnih kod", + "Fase 2: Codici specifici dei tasti", }, { "Press key for '%s'", "Taste fr '%s' drcken", "Pritisnite tipko za '%s'", + "Premere il tasto per '%s'", }, { "Press 'Up' to confirm", "'Auf' drcken zum Besttigen", "Pritisnite tipko 'Gor' za potrditev", + "Premere 'Su' per confermare", }, { "Press 'Down' to continue", "'Ab' drcken zum Weitermachen", "Pritisnite tipko 'Dol' za nadaljevanje", + "Premere 'Giu' per confermare", }, { "(press 'Up' to go back)", "('Auf' drcken um zurckzugehen)", "(pritisnite 'Gor' za nazaj)", + "(premere 'Su' per tornare indietro)", }, { "(press 'Down' to end key definition)", "('Ab' drcken zum Beenden", "(pritisnite 'Dol' za konec)", + "('Giu' per finire la definiz tasti)", }, { "Phase 3: Saving key codes", "Phase 3: Codes abspeichern", "Faza 3: Shranjujem kodo", + "Fase 3: Salvataggio key codes", }, { "Press 'Up' to save, 'Down' to cancel", "'Auf' speichert, 'Ab' bricht ab", "'Gor' za potrditev, 'Dol' za prekinitev", + "'Su' per salvare, 'Giu' per annullare", }, // Key names: { "Up", "Auf", "Gor", + "Su", }, { "Down", "Ab", "Dol", + "Giu", }, { "Menu", "Men", "Meni", + "Menu", }, { "Ok", "Ok", "Ok", + "Ok", }, { "Back", "Zurck", "Nazaj", + "Indietro", }, { "Left", "Links", "Levo", + "Sinistra", }, { "Right", "Rechts", "Desno", + "Destra", }, { "Red", "Rot", "Rdeca", + "Rosso", }, { "Green", "Grn", "Zelena", + "Verde", }, { "Yellow", "Gelb", "Rumena", + "Giallo", }, { "Blue", "Blau", "Modra", + "Blu", }, // Miscellaneous: { "yes", "ja", "da", + "si", }, { "no", "nein", "ne", + "no", }, { "Stop replaying", "Wiedergabe beenden", "Prekini ponavljanje", + "Interrompi riproduzione", }, { "Stop recording ", // note the trailing blank! "Aufzeichnung beenden ", "Prekini shranjevanje ", + "Interrompi registrazione ", + }, + { "Cancel editing", + "Schneiden abbrechen", + "Prekini urejanje", + "Annulla modifiche", }, { "Switching primary DVB...", "Primres Interface wird umgeschaltet...", "Preklapljanje primarne naprave...", + "Cambio su card DVB primaria...", }, { "Up/Dn for new location - OK to move", "Auf/Ab fr neue Position - dann OK", "Gor/Dol za novo poz. - Ok za premik", + "Su/Giu per nuova posizione - OK per muovere", + }, + { "Editing process started", + "Schnitt gestartet", + "Urejanje se je zacelo", + "Processo di modifica iniziato", }, { NULL } }; diff --git a/interface.c b/interface.c index e5cc1d25c..ef8368ae9 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.32 2000/11/18 15:28:50 kls Exp $ + * $Id: interface.c 1.33 2000/12/09 11:04:10 kls Exp $ */ #include "interface.h" @@ -121,6 +121,12 @@ void cInterface::Fill(int x, int y, int w, int h, eDvbColor Color) cDvbApi::PrimaryDvbApi->Fill(x, y, w, h, Color); } +void cInterface::SetBitmap(int x, int y, const cBitmap &Bitmap) +{ + if (open) + cDvbApi::PrimaryDvbApi->SetBitmap(x, y, Bitmap); +} + void cInterface::Flush(void) { if (open) diff --git a/interface.h b/interface.h index cd46fbaa7..50c376154 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.20 2000/11/18 15:27:59 kls Exp $ + * $Id: interface.h 1.21 2000/12/09 10:48:41 kls Exp $ */ #ifndef __INTERFACE_H @@ -41,6 +41,7 @@ class cInterface { void Clear(void); void ClearEol(int x, int y, eDvbColor Color = clrBackground); void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground); + void SetBitmap(int x, int y, const cBitmap &Bitmap); void Flush(void); void SetCols(int *c); eDvbFont SetFont(eDvbFont Font); diff --git a/menu.c b/menu.c index 3cf832819..144233fc7 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.52 2000/11/18 16:30:13 kls Exp $ + * $Id: menu.c 1.58 2001/01/13 13:07:43 kls Exp $ */ #include "menu.h" @@ -669,7 +669,7 @@ eOSState cMenuChannels::Del(void) return osContinue; } } - if (Interface->Confirm(tr("Delete Channel?"))) { + if (Interface->Confirm(tr("Delete channel?"))) { // Move and renumber the channels: Channels.Del(channel); Channels.ReNumber(); @@ -1039,7 +1039,7 @@ eOSState cMenuTimers::Del(void) cTimer *ti = Timers.Get(Index); if (ti) { if (!ti->recording) { - if (Interface->Confirm(tr("Delete Timer?"))) { + if (Interface->Confirm(tr("Delete timer?"))) { Timers.Del(Timers.Get(Index)); cOsdMenu::Del(Index); Timers.Save(); @@ -1310,7 +1310,9 @@ class cMenuSchedule : public cOsdMenu { cThreadLock threadLock; const cSchedules *schedules; bool now, next; + int otherChannel; eOSState Record(void); + eOSState Switch(void); void PrepareSchedule(cChannel *Channel); void PrepareWhatsOnNext(bool On); public: @@ -1322,6 +1324,7 @@ cMenuSchedule::cMenuSchedule(void) :cOsdMenu("", 6, 6) { now = next = false; + otherChannel = 0; cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel()); if (channel) { schedules = cDvbApi::PrimaryDvbApi->Schedules(&threadLock); @@ -1383,6 +1386,16 @@ eOSState cMenuSchedule::Record(void) return osContinue; } +eOSState cMenuSchedule::Switch(void) +{ + if (otherChannel) { + if (Channels.SwitchTo(otherChannel)) + return osEnd; + } + Interface->Error(tr("Can't switch channel!")); + return osContinue; +} + eOSState cMenuSchedule::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); @@ -1398,8 +1411,9 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) next = !next; return AddSubMenu(new cMenuWhatsOn(schedules, now)); case kYellow: return AddSubMenu(new cMenuWhatsOn(schedules, false)); + case kBlue: return Switch(); case kOk: if (Count()) - return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo)); + return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo, otherChannel)); break; default: break; } @@ -1411,6 +1425,10 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) cChannel *channel = Channels.GetByServiceID(ei->GetServiceID()); if (channel) { PrepareSchedule(channel); + if (channel->number != cDvbApi::CurrentChannel()) { + otherChannel = channel->number; + SetHelp(tr("Record"), tr("Now"), tr("Next"), tr("Switch")); + } Display(); } } @@ -1471,7 +1489,7 @@ eOSState cMenuRecordings::Del(void) if (ri) { //XXX what if this recording's file is currently in use??? //XXX if (!ti->recording) { - if (Interface->Confirm(tr("Delete Recording?"))) { + if (Interface->Confirm(tr("Delete recording?"))) { if (ri->recording->Delete()) { cReplayControl::ClearLastReplayed(ri->recording->FileName()); cOsdMenu::Del(Current()); @@ -1645,6 +1663,8 @@ cMenuMain::cMenuMain(bool Replaying) Add(new cOsdItem(buffer, osStopRecord)); delete buffer; } + if (cVideoCutter::Active()) + Add(new cOsdItem(tr("Cancel editing"), osCancelEdit)); SetHelp(tr("Record"), NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); Display(); lastActivity = time(NULL); @@ -1661,13 +1681,19 @@ eOSState cMenuMain::ProcessKey(eKeys Key) case osRecordings: return AddSubMenu(new cMenuRecordings); case osSetup: return AddSubMenu(new cMenuSetup); case osCommands: return AddSubMenu(new cMenuCommands); - case osStopRecord: if (Interface->Confirm(tr("Stop Recording?"))) { + case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { cOsdItem *item = Get(Current()); if (item) { cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING)); return osEnd; } } + break; + case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) { + cVideoCutter::Stop(); + return osEnd; + } + break; default: switch (Key) { case kMenu: state = osEnd; break; case kRed: if (!HasSubMenu()) @@ -1726,23 +1752,21 @@ cDisplayChannel::~cDisplayChannel() void cDisplayChannel::DisplayChannel(const cChannel *Channel) { - if (!Interface->Recording()) { - if (Channel && Channel->number) - Interface->DisplayChannelNumber(Channel->number); - int BufSize = Width() + 1; - char buffer[BufSize]; - if (Channel && Channel->number) - snprintf(buffer, BufSize, "%d %s", Channel->number, Channel->name); - else - snprintf(buffer, BufSize, "%s", Channel ? Channel->name : tr("*** Invalid Channel ***")); - Interface->Fill(0, 0, MenuColumns, 1, clrBackground); - Interface->Write(0, 0, buffer); - time_t t = time(NULL); - struct tm *now = localtime(&t); - snprintf(buffer, BufSize, "%02d:%02d", now->tm_hour, now->tm_min); - Interface->Write(-5, 0, buffer); - Interface->Flush(); - } + if (Channel && Channel->number) + Interface->DisplayChannelNumber(Channel->number); + int BufSize = Width() + 1; + char buffer[BufSize]; + if (Channel && Channel->number) + snprintf(buffer, BufSize, "%d %s", Channel->number, Channel->name); + else + snprintf(buffer, BufSize, "%s", Channel ? Channel->name : tr("*** Invalid Channel ***")); + Interface->Fill(0, 0, MenuColumns, 1, clrBackground); + Interface->Write(0, 0, buffer); + time_t t = time(NULL); + struct tm *now = localtime(&t); + snprintf(buffer, BufSize, "%02d:%02d", now->tm_hour, now->tm_min); + Interface->Write(-5, 0, buffer); + Interface->Flush(); } void cDisplayChannel::DisplayInfo(void) @@ -1874,7 +1898,6 @@ cRecordControl::~cRecordControl() { Stop(true); delete instantId; - Interface->DisplayRecording(dvbApi->Index(), false); } void cRecordControl::Stop(bool KeepInstant) @@ -1890,6 +1913,7 @@ void cRecordControl::Stop(bool KeepInstant) Timers.Save(); } timer = NULL; + Interface->DisplayRecording(dvbApi->Index(), false); } } @@ -1946,7 +1970,7 @@ void cRecordControls::Stop(cDvbApi *DvbApi) if (RecordControls[i]) { if (RecordControls[i]->Uses(DvbApi)) { isyslog(LOG_INFO, "stopping recording on DVB device %d due to higher priority", DvbApi->Index() + 1); - RecordControls[i]->Stop(); + RecordControls[i]->Stop(true); } } } @@ -1975,6 +1999,50 @@ void cRecordControls::Process(void) } } +// --- cProgressBar ---------------------------------------------------------- + +class cProgressBar : public cBitmap { +protected: + int total; + int Pos(int p) { return p * width / total; } + void Mark(int x, bool Start, bool Current); +public: + cProgressBar(int Width, int Height, int Current, int Total, const cMarks &Marks); + }; + +cProgressBar::cProgressBar(int Width, int Height, int Current, int Total, const cMarks &Marks) +:cBitmap(Width, Height) +{ + total = Total; + if (total > 0) { + int p = Pos(Current); + Fill(0, 0, p, Height - 1, clrGreen); + Fill(p + 1, 0, Width - 1, Height - 1, clrWhite); + bool Start = true; + for (const cMark *m = Marks.First(); m; m = Marks.Next(m)) { + int p1 = Pos(m->position); + if (Start) { + const cMark *m2 = Marks.Next(m); + int p2 = Pos(m2 ? m2->position : total); + int h = Height / 3; + Fill(p1, h, p2, Height - h, clrRed); + } + Mark(p1, Start, m->position == Current); + Start = !Start; + } + } +} + +void cProgressBar::Mark(int x, bool Start, bool Current) +{ + Fill(x, 0, x, height - 1, clrBlack); + const int d = height / (Current ? 3 : 9); + for (int i = 0; i < d; i++) { + int h = Start ? i : height - 1 - i; + Fill(x - d + i, h, x + d - i, h, Current ? clrRed : clrBlack); + } +} + // --- cReplayControl -------------------------------------------------------- char *cReplayControl::fileName = NULL; @@ -1982,16 +2050,18 @@ char *cReplayControl::title = NULL; cReplayControl::cReplayControl(void) { - dvbApi = cDvbApi::PrimaryDvbApi;//XXX - visible = shown = false; - if (fileName) - dvbApi->StartReplay(fileName, title); + dvbApi = cDvbApi::PrimaryDvbApi; + visible = shown = displayFrames = false; + if (fileName) { + marks.Load(fileName); + dvbApi->StartReplay(fileName); + } } cReplayControl::~cReplayControl() { Hide(); - dvbApi->Stop(); + dvbApi->StopReplay(); } void cReplayControl::SetRecording(const char *FileName, const char *Title) @@ -2020,7 +2090,7 @@ void cReplayControl::Show(void) if (!visible) { Interface->Open(MenuColumns, -3); needsFastResponse = visible = true; - shown = dvbApi->ShowProgress(true); + shown = ShowProgress(true); } } @@ -2032,27 +2102,148 @@ void cReplayControl::Hide(void) } } +bool cReplayControl::ShowProgress(bool Initial) +{ + int Current, Total; + + if (dvbApi->GetIndex(Current, Total) && Total > 0) { + if (Initial) { + Interface->Clear(); + if (title) + Interface->Write(0, 0, title); + displayFrames = marks.Count() > 0; + } + Interface->Write(-7, 2, IndexToHMSF(Total)); + Interface->Flush(); +#ifdef DEBUG_OSD + int p = Width() * Current / Total; + Interface->Fill(0, 1, p, 1, clrGreen); + Interface->Fill(p, 1, Width() - p, 1, clrWhite); +#else + cProgressBar ProgressBar(Width() * dvbApi->CellWidth(), dvbApi->LineHeight(), Current, Total, marks); + Interface->SetBitmap(0, dvbApi->LineHeight(), ProgressBar); + Interface->Flush(); +#endif + Interface->Write(0, 2, IndexToHMSF(Current, displayFrames)); + Interface->Flush(); + return true; + } + return false; +} + +void cReplayControl::MarkToggle(void) +{ + int Current, Total; + if (dvbApi->GetIndex(Current, Total, true)) { + cMark *m = marks.Get(Current); + if (m) + marks.Del(m); + else + marks.Add(Current); + marks.Save(); + } + displayFrames = marks.Count() > 0; + if (!displayFrames) + Interface->Fill(0, 2, Width() / 2, 1, clrBackground); +} + +void cReplayControl::MarkJump(bool Forward) +{ + int Current, Total; + if (dvbApi->GetIndex(Current, Total)) { + cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); + if (m) + dvbApi->Goto(m->position, true); + } +} + +void cReplayControl::MarkMove(bool Forward) +{ + int Current, Total; + if (dvbApi->GetIndex(Current, Total)) { + cMark *m = marks.Get(Current); + if (m) { + int p = dvbApi->SkipFrames(Forward ? 1 : -1); + cMark *m2; + if (Forward) { + if ((m2 = marks.Next(m)) != NULL && m2->position <= p) + return; + } + else { + if ((m2 = marks.Prev(m)) != NULL && m2->position >= p) + return; + } + dvbApi->Goto(m->position = p, true); + marks.Save(); + } + } +} + +void cReplayControl::EditCut(void) +{ + Hide(); + if (!cVideoCutter::Active()) { + if (!cVideoCutter::Start(fileName)) + Interface->Error(tr("Can't start editing process!")); + else + Interface->Info(tr("Editing process started")); + } + else + Interface->Error(tr("Editing process already active!")); +} + +void cReplayControl::EditTest(void) +{ + int Current, Total; + if (dvbApi->GetIndex(Current, Total)) { + cMark *m = marks.Get(Current); + if (!m) + m = marks.GetNext(Current); + if (m) { + if ((m->Index() & 0x01) != 0) + m = marks.Next(m); + if (m) { + dvbApi->Goto(m->position - dvbApi->SecondsToFrames(3)); + dvbApi->Play(); + } + } + } +} + eOSState cReplayControl::ProcessKey(eKeys Key) { if (!dvbApi->Replaying()) return osEnd; if (visible) - shown = dvbApi->ShowProgress(!shown) || shown; + shown = ShowProgress(!shown) || shown; switch (Key) { + // Positioning: case kUp: dvbApi->Play(); break; case kDown: dvbApi->Pause(); break; - case kBlue: Hide(); - dvbApi->Stop(); - return osEnd; case kLeft: dvbApi->Backward(); break; case kRight: dvbApi->Forward(); break; case kLeft|k_Release: case kRight|k_Release: dvbApi->Play(); break; case kGreen|k_Repeat: - case kGreen: dvbApi->Skip(-60); break; + case kGreen: dvbApi->SkipSeconds(-60); break; case kYellow|k_Repeat: - case kYellow: dvbApi->Skip(60); break; + case kYellow: dvbApi->SkipSeconds(60); break; + case kBlue: Hide(); + dvbApi->StopReplay(); + return osEnd; + // Editing: + //XXX should we do this only when the ProgressDisplay is on??? + case kMarkToggle: MarkToggle(); break; + case kMarkJumpBack: MarkJump(false); break; + case kMarkJumpForward: MarkJump(true); break; + case kMarkMoveBack|k_Repeat: + case kMarkMoveBack: MarkMove(false); break; + case kMarkMoveForward|k_Repeat: + case kMarkMoveForward: MarkMove(true); break; + case kEditCut: EditCut(); break; + case kEditTest: EditTest(); break; + // Menu control: case kMenu: Hide(); return osMenu; // allow direct switching to menu case kOk: visible ? Hide() : Show(); break; case kBack: return osRecordings; diff --git a/menu.h b/menu.h index 8153f5d78..923211115 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.14 2000/11/12 12:33:00 kls Exp $ + * $Id: menu.h 1.16 2000/12/25 14:25:29 kls Exp $ */ #ifndef _MENU_H @@ -79,11 +79,18 @@ class cRecordControls { class cReplayControl : public cOsdBase { private: cDvbApi *dvbApi; - bool visible, shown; + cMarks marks; + bool visible, shown, displayFrames; void Show(void); void Hide(void); static char *fileName; static char *title; + bool ShowProgress(bool Initial); + void MarkToggle(void); + void MarkJump(bool Forward); + void MarkMove(bool Forward); + void EditCut(void); + void EditTest(void); public: cReplayControl(void); virtual ~cReplayControl(); diff --git a/osd.h b/osd.h index 0d8085dfd..16d0ec2c3 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.17 2000/11/12 15:27:34 kls Exp $ + * $Id: osd.h 1.18 2000/12/24 10:16:52 kls Exp $ */ #ifndef __OSD_H @@ -29,6 +29,7 @@ enum eOSState { osUnknown, osReplay, osStopRecord, osStopReplay, + osCancelEdit, osSwitchDvb, osBack, osEnd, diff --git a/recording.c b/recording.c index f45be9632..064731dfd 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.21 2000/11/18 16:22:29 kls Exp $ + * $Id: recording.c 1.24 2001/01/13 12:17:15 kls Exp $ */ #define _GNU_SOURCE @@ -26,6 +26,7 @@ #define NAMEFORMAT "%s/%s/" DATAFORMAT #define SUMMARYFILESUFFIX "/summary.vdr" +#define MARKSFILESUFFIX "/marks.vdr" #define FINDCMD "find %s -follow -type d -name '%s' 2> /dev/null | sort -df" @@ -125,6 +126,7 @@ cRecording::cRecording(const char *FileName) strncpy(name, FileName, p - FileName); name[p - FileName] = 0; strreplace(name, '_', ' '); + strreplace(name, '\x01', '\''); } // read an optional summary file: char *SummaryFileName = NULL; @@ -175,8 +177,10 @@ const char *cRecording::FileName(void) if (!fileName) { struct tm *t = localtime(&start); asprintf(&fileName, NAMEFORMAT, VideoDirectory, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime); - if (fileName) + if (fileName) { strreplace(fileName, ' ', '_'); + strreplace(fileName, '\'', '\x01'); + } } return fileName; } @@ -269,3 +273,107 @@ bool cRecordings::Load(bool Deleted) return result; } +// --- cMark ----------------------------------------------------------------- + +char *cMark::buffer = NULL; + +cMark::cMark(int Position, const char *Comment) +{ + position = Position; + comment = Comment ? strdup(Comment) : NULL; +} + +cMark::~cMark() +{ + delete comment; +} + +const char *cMark::ToText(void) +{ + delete buffer; + asprintf(&buffer, "%s%s%s\n", IndexToHMSF(position, true), comment ? " " : "", comment ? comment : ""); + return buffer; +} + +bool cMark::Parse(const char *s) +{ + delete comment; + comment = NULL; + position = HMSFToIndex(s); + const char *p = strchr(s, ' '); + if (p) { + p = skipspace(p); + if (*p) { + comment = strdup(p); + comment[strlen(comment) - 1] = 0; // strips trailing newline + } + } + return true; +} + +bool cMark::Save(FILE *f) +{ + return fprintf(f, ToText()) > 0; +} + +// --- cMarks ---------------------------------------------------------------- + +bool cMarks::Load(const char *RecordingFileName) +{ + const char *MarksFile = AddDirectory(RecordingFileName, MARKSFILESUFFIX); + if (cConfig::Load(MarksFile)) { + Sort(); + return true; + } + return false; +} + +void cMarks::Sort(void) +{ + for (cMark *m1 = First(); m1; m1 = Next(m1)) { + for (cMark *m2 = Next(m1); m2; m2 = Next(m2)) { + if (m2->position < m1->position) { + swap(m1->position, m2->position); + swap(m1->comment, m2->comment); + } + } + } +} + +cMark *cMarks::Add(int Position) +{ + cMark *m = Get(Position); + if (!m) { + cConfig::Add(m = new cMark(Position)); + Sort(); + } + return m; +} + +cMark *cMarks::Get(int Position) +{ + for (cMark *mi = First(); mi; mi = Next(mi)) { + if (mi->position == Position) + return mi; + } + return NULL; +} + +cMark *cMarks::GetPrev(int Position) +{ + for (cMark *mi = Last(); mi; mi = Prev(mi)) { + if (mi->position < Position) + return mi; + } + return NULL; +} + +cMark *cMarks::GetNext(int Position) +{ + for (cMark *mi = First(); mi; mi = Next(mi)) { + if (mi->position > Position) + return mi; + } + return NULL; +} + diff --git a/recording.h b/recording.h index 7511c6591..454c356f7 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.10 2000/10/03 12:27:49 kls Exp $ + * $Id: recording.h 1.11 2000/12/16 14:25:20 kls Exp $ */ #ifndef __RECORDING_H @@ -47,4 +47,27 @@ class cRecordings : public cList { bool Load(bool Deleted = false); }; +class cMark : public cListObject { +private: + static char *buffer; +public: + int position; + char *comment; + cMark(int Position = 0, const char *Comment = NULL); + ~cMark(); + const char *ToText(void); + bool Parse(const char *s); + bool Save(FILE *f); + }; + +class cMarks : public cConfig { +public: + bool Load(const char *RecordingFileName); + void Sort(void); + cMark *Add(int Position); + cMark *Get(int Position); + cMark *GetPrev(int Position); + cMark *GetNext(int Position); + }; + #endif //__RECORDING_H diff --git a/remote.c b/remote.c index 349a44527..691b5e94e 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.19 2000/11/11 11:22:22 kls Exp $ + * $Id: remote.c 1.20 2000/12/03 11:55:06 kls Exp $ */ #include "remote.h" @@ -115,7 +115,7 @@ cRcIoRCU::cRcIoRCU(char *DeviceName) cRcIoRCU::~cRcIoRCU() { - Stop(); + Cancel(); } void cRcIoRCU::Action(void) @@ -420,7 +420,7 @@ cRcIoLIRC::cRcIoLIRC(char *DeviceName) cRcIoLIRC::~cRcIoLIRC() { - Stop(); + Cancel(); } void cRcIoLIRC::Action(void) diff --git a/svdrp.c b/svdrp.c index 66ae8e9ad..0ce30dbae 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.12 2000/11/05 13:44:42 kls Exp $ + * $Id: svdrp.c 1.13 2000/12/03 15:34:35 kls Exp $ */ #define _GNU_SOURCE @@ -18,6 +18,7 @@ #include "svdrp.h" #include #include +#include #include #include #include diff --git a/thread.c b/thread.c index 67b5ab96e..363190d84 100644 --- a/thread.c +++ b/thread.c @@ -4,12 +4,15 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.4 2000/11/14 18:38:25 kls Exp $ + * $Id: thread.c 1.7 2000/12/24 12:27:21 kls Exp $ */ #include "thread.h" +#include #include +#include #include +#include "tools.h" // --- cThread --------------------------------------------------------------- @@ -25,7 +28,7 @@ cThread::cThread(void) signalHandlerInstalled = true; } running = false; - parentPid = lockingPid = 0; + parentPid = threadPid = lockingPid = 0; locked = 0; } @@ -40,6 +43,7 @@ void cThread::SignalHandler(int signum) void *cThread::StartThread(cThread *Thread) { + Thread->threadPid = getpid(); Thread->Action(); return NULL; } @@ -49,13 +53,37 @@ bool cThread::Start(void) if (!running) { running = true; parentPid = getpid(); - pthread_create(&thread, NULL, &StartThread, (void *)this); + pthread_create(&thread, NULL, (void *(*) (void *))&StartThread, (void *)this); + usleep(10000); // otherwise calling Active() immediately after Start() causes a "pure virtual method called" error } return true; //XXX return value of pthread_create()??? } -void cThread::Stop(void) +bool cThread::Active(void) { + if (threadPid) { + if (kill(threadPid, SIGIO) < 0) { // couldn't find another way of checking whether the thread is still running - any ideas? + if (errno == ESRCH) + threadPid = 0; + else + LOG_ERROR; + } + else + return true; + } + return false; +} + +void cThread::Cancel(int WaitSeconds) +{ + if (WaitSeconds > 0) { + for (time_t t0 = time(NULL) + WaitSeconds; time(NULL) < t0; ) { + if (!Active()) + return; + usleep(10000); + } + esyslog(LOG_ERR, "ERROR: thread %d won't end (waited %d seconds) - cancelling it...", threadPid, WaitSeconds); + } pthread_cancel(thread); } diff --git a/thread.h b/thread.h index c85c51e2c..6aaee0b90 100644 --- a/thread.h +++ b/thread.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.3 2000/11/14 18:38:11 kls Exp $ + * $Id: thread.h 1.4 2000/12/03 11:18:37 kls Exp $ */ #ifndef __THREAD_H @@ -28,7 +28,7 @@ class cThread { private: pthread_t thread; cMutex Mutex; - pid_t parentPid, lockingPid; + pid_t parentPid, threadPid, lockingPid; int locked; bool running; static bool signalHandlerInstalled; @@ -39,11 +39,12 @@ class cThread { protected: void WakeUp(void); virtual void Action(void) = 0; - void Stop(void); + void Cancel(int WaitSeconds = 0); public: cThread(void); virtual ~cThread(); bool Start(void); + bool Active(void); }; // cThreadLock can be used to easily set a lock in a thread and make absolutely diff --git a/timers.conf b/timers.conf deleted file mode 100644 index 05946a53a..000000000 --- a/timers.conf +++ /dev/null @@ -1,14 +0,0 @@ -1:15:M------:2128:2205:80:7:Neues: -1:3:-T-----:2013:2125:99:99:SevenDays: -1:10:-T-----:2058:2202:99:10:Quarks: -1:25:-T-----:2305:0020:99:99:UFO: -1:14:--W----:1920:2020:70:99:Rettungsflieger: -0:2:--W----:2110:2325:99:99:BulleVonToelz: -1:3:---T---:2210:2315:50:20:IngoAppelt: -1:2:----F--:2013:2125:99:99:Farscape: -1:1:----F--:2215:2325:50:20:7Tage7Koepfe: -0:11:-----S-:2058:2135:99:99:Computer: -0:2:-----S-:2220:2340:99:30:Wochenshow: -1:11:------S:2013:2035:99:10:Centauri: -1:15:MTWTF--:1828:1901:10:5:nano: -1:1:MTWTF--:1553:1710:99:99:Hammerman: diff --git a/tools.c b/tools.c index 6d86f1620..cd2c60f8a 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.23 2000/11/11 15:17:12 kls Exp $ + * $Id: tools.c 1.27 2001/01/13 15:35:02 kls Exp $ */ #define _GNU_SOURCE @@ -15,10 +15,7 @@ #if defined(DEBUG_OSD) #include #endif -#include -#include #include -#include #include #define MaxBuffer 1000 @@ -30,29 +27,6 @@ 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) -{ - return cFile::AnyFileReady(filedes, 0) && read(filedes, &n, sizeof(n)) == sizeof(n); -} - -void purge(int filedes) -{ - while (cFile::AnyFileReady(filedes, 0)) - readchar(filedes); -} - char *readline(FILE *f) { static char buffer[MaxBuffer]; @@ -146,7 +120,7 @@ const char *AddDirectory(const char *DirName, const char *FileName) return buf; } -#define DFCMD "df -m %s" +#define DFCMD "df -m '%s'" uint FreeDiskSpaceMB(const char *Directory) { @@ -205,7 +179,7 @@ bool MakeDirs(const char *FileName, bool IsDirectory) if (stat(s, &fs) != 0 || !S_ISDIR(fs.st_mode)) { dsyslog(LOG_INFO, "creating directory %s", s); if (mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) { - esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno)); + LOG_ERROR_STR(s); result = false; break; } @@ -266,44 +240,32 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks) if (remove(FileName) == 0) return true; } - else + else if (errno != ENOENT) { LOG_ERROR_STR(FileName); - return false; -} - -bool CheckProcess(pid_t pid) -{ - pid_t Pid2Check = pid; - int status; - pid = waitpid(Pid2Check, &status, WNOHANG); - if (pid < 0) { - if (errno != ECHILD) - LOG_ERROR; return false; } return true; } -void KillProcess(pid_t pid, int Timeout) +char *ReadLink(const char *FileName) { - pid_t Pid2Wait4 = pid; - for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) { - int status; - pid_t pid = waitpid(Pid2Wait4, &status, WNOHANG); - if (pid < 0) { - if (errno != ECHILD) - LOG_ERROR; - return; - } - if (pid == Pid2Wait4) - return; - } - esyslog(LOG_ERR, "ERROR: process %d won't end (waited %d seconds) - terminating it...", Pid2Wait4, Timeout); - if (kill(Pid2Wait4, SIGTERM) < 0) { - esyslog(LOG_ERR, "ERROR: process %d won't terminate (%s) - killing it...", Pid2Wait4, strerror(errno)); - if (kill(Pid2Wait4, SIGKILL) < 0) - esyslog(LOG_ERR, "ERROR: process %d won't die (%s) - giving up", Pid2Wait4, strerror(errno)); + char RealName[_POSIX_PATH_MAX]; + const char *TargetName = NULL; + int n = readlink(FileName, RealName, sizeof(RealName) - 1); + if (n < 0) { + if (errno == ENOENT || errno == EINVAL) // file doesn't exist or is not a symlink + TargetName = FileName; + else { // some other error occurred + LOG_ERROR_STR(FileName); + } + } + else if (n < int(sizeof(RealName))) { // got it! + RealName[n] = 0; + TargetName = RealName; } + else + esyslog(LOG_ERR, "ERROR: symlink's target name too long: %s", FileName); + return TargetName ? strdup(TargetName) : NULL; } // --- cFile ----------------------------------------------------------------- @@ -426,6 +388,45 @@ bool cFile::FileReady(int FileDes, int TimeoutMs) return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set); } +// --- cSafeFile ------------------------------------------------------------- + +cSafeFile::cSafeFile(const char *FileName) +{ + f = NULL; + fileName = ReadLink(FileName); + tempName = fileName ? new char[strlen(fileName) + 5] : NULL; + if (tempName) + strcat(strcpy(tempName, fileName), ".$$$"); +} + +cSafeFile::~cSafeFile() +{ + if (f) + fclose(f); + unlink(tempName); + delete fileName; + delete tempName; +} + +bool cSafeFile::Open(void) +{ + if (!f && fileName && tempName) { + f = fopen(tempName, "w"); + if (!f) + LOG_ERROR_STR(tempName); + } + return f != NULL; +} + +void cSafeFile::Close(void) +{ + if (f) { + fclose(f); + f = NULL; + rename(tempName, fileName); + } +} + // --- cListObject ----------------------------------------------------------- cListObject::cListObject(void) diff --git a/tools.h b/tools.h index f83e7da4a..539dba019 100644 --- a/tools.h +++ b/tools.h @@ -4,13 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.20 2000/11/12 15:27:06 kls Exp $ + * $Id: tools.h 1.23 2001/01/13 15:36:00 kls Exp $ */ #ifndef __TOOLS_H #define __TOOLS_H -#include +//#include #include #include #include @@ -24,19 +24,16 @@ extern int SysLogLevel; #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 LOG_ERROR esyslog(LOG_ERR, "ERROR (%s,%d): %m", __FILE__, __LINE__) +#define LOG_ERROR_STR(s) esyslog(LOG_ERR, "ERROR: %s: %m", s) #define SECSINDAY 86400 -#define MAXPROCESSTIMEOUT 3 // seconds #define DELETENULL(p) (delete (p), p = NULL) +template inline void swap(T &a, T &b) { T t = a; a = b; b = t; }; + void writechar(int filedes, char c); -void writeint(int filedes, int n); -char readchar(int filedes); -bool readint(int filedes, int &n); -void purge(int filedes); char *readline(FILE *f); char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); @@ -51,8 +48,7 @@ uint FreeDiskSpaceMB(const char *Directory); bool DirectoryOk(const char *DirName, bool LogErrors = false); bool MakeDirs(const char *FileName, bool IsDirectory = false); bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); -bool CheckProcess(pid_t pid); -void KillProcess(pid_t pid, int Timeout = MAXPROCESSTIMEOUT); +char *ReadLink(const char *FileName); class cFile { private: @@ -73,6 +69,19 @@ class cFile { static bool FileReady(int FileDes, int TimeoutMs = 1000); }; +class cSafeFile { +private: + FILE *f; + char *fileName; + char *tempName; +public: + cSafeFile(const char *FileName); + ~cSafeFile(); + operator FILE* () { return f; } + bool Open(void); + void Close(void); + }; + class cListObject { private: cListObject *prev, *next; @@ -105,6 +114,8 @@ template class cList : public cListBase { public: T *Get(int Index) const { return (T *)cListBase::Get(Index); } T *First(void) const { return (T *)objects; } + T *Last(void) const { return (T *)lastObject; } + T *Prev(const T *object) const { return (T *)object->Prev(); } T *Next(const T *object) const { return (T *)object->Next(); } }; diff --git a/vdr.c b/vdr.c index 8a842003a..698cc7a61 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.46 2000/11/18 13:46:56 kls Exp $ + * $Id: vdr.c 1.49 2001/01/14 15:29:51 kls Exp $ */ #include @@ -141,8 +141,8 @@ int main(int argc, char *argv[]) #if !defined(DEBUG_OSD) && !defined(REMOTE_KBD) pid_t pid = fork(); if (pid < 0) { - fprintf(stderr, "%s\n", strerror(errno)); - esyslog(LOG_ERR, "ERROR: %s", strerror(errno)); + fprintf(stderr, "%m\n"); + esyslog(LOG_ERR, "ERROR: %m"); abort(); } if (pid != 0) @@ -179,7 +179,7 @@ int main(int argc, char *argv[]) cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); - Channels.SwitchTo(1); + Channels.SwitchTo(Setup.CurrentChannel); cEITScanner EITScanner; @@ -306,10 +306,15 @@ int main(int argc, char *argv[]) default: break; } } - if (!Menu) + if (!Menu) { EITScanner.Process(); + cVideoCutter::Active(); + } } isyslog(LOG_INFO, "caught signal %d", Interrupted); + Setup.CurrentChannel = cDvbApi::CurrentChannel(); + Setup.Save(); + cVideoCutter::Stop(); delete Menu; delete ReplayControl; delete Interface; diff --git a/videodir.c b/videodir.c index 91d362dbf..4d5c2572b 100644 --- a/videodir.c +++ b/videodir.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: videodir.c 1.2 2000/09/15 13:23:47 kls Exp $ + * $Id: videodir.c 1.3 2000/12/24 12:51:41 kls Exp $ */ #include "videodir.h" @@ -180,3 +180,20 @@ bool VideoFileSpaceAvailable(unsigned int SizeMB) } return Dir.FreeMB() >= SizeMB; } + +const char *PrefixVideoFileName(const char *FileName, char Prefix) +{ + static char *PrefixedName = NULL; + + if (!PrefixedName || strlen(PrefixedName) <= strlen(FileName)) + PrefixedName = (char *)realloc(PrefixedName, strlen(FileName) + 2); + if (PrefixedName) { + strcpy(PrefixedName, VideoDirectory); + char *p = PrefixedName + strlen(PrefixedName); + *p++ = '/'; + *p++ = Prefix; + strcpy(p, FileName + strlen(VideoDirectory) + 1); + } + return PrefixedName; +} + diff --git a/videodir.h b/videodir.h index 7ce15314d..0716a284b 100644 --- a/videodir.h +++ b/videodir.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: videodir.h 1.1 2000/07/29 14:08:27 kls Exp $ + * $Id: videodir.h 1.2 2000/12/24 12:41:10 kls Exp $ */ #ifndef __VIDEODIR_H @@ -17,5 +17,6 @@ int CloseVideoFile(int FileHandle); bool RenameVideoFile(const char *OldName, const char *NewName); bool RemoveVideoFile(const char *FileName); bool VideoFileSpaceAvailable(unsigned int SizeMB); +const char *PrefixVideoFileName(const char *FileName, char Prefix); #endif //__VIDEODIR_H From f2937af95ceaf3a52c327e96571367ef5475b3a1 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 24 Feb 2001 18:00:00 +0100 Subject: [PATCH 017/307] Version 0.71 - Fixed 'Transfer Mode' in cases where a non-primary interface was switched to a channel that only the primary interface can receive (which could happen in the EPG scanner). - The EPG scanner now starts with the first channel (it used to start with the second channel). - Reacitvated setting the PNR. - Adapted the frame scanning to the new muxing of the driver. - The new compile time option REMOTE=NONE can be used to compile VDR without any remote control support (for applications where it shall be controlled exclusively via SVDRP). - The new command line option -D can be used to define which DVB interfaces a certain instance of VDR shall use. - The "Left" and "Right" keys are now used to page up and down in lists (thanks to Martin Hammerschmid). Since the "Timers" menu already uses these keys to (de)activate timers, this functionality is not available there. - The "Main" and "Commands" menu now support "hotkeys", which means that if the first non-blank character of a menu item is a digit in the range 1..9, that item can be selected by pressing the respective numeric key on the remote control. - The channel data in 'channels.conf' now contains the teletext PID (thanks to Dave Chapman). Existing files will be read normally (and the teletext PID set to 0), but once they are written back (due to some channel editing) the file will have the new format. - The EPG scanner now scans each transponder only once per cycle. - Deleted recordings are now automatically removed from disk after a while (not only when disk space is being needed for a new recording). - Fixed repeat function in LIRC remote control. - Changed the MAXDVBAPI macro in dvbapi.c to 4 in order to directly support the maximum possible number of DVB cards. - The 'Ca' parameter in the default 'channels.conf' has been changed from '2' to '3' because the VDR prototype now has 3 DVB cards (and currently the CAM module only works if it is inserted into the last DVB card). - The "Now", "Next" and "Schedule" menus now remember the current channel and restore the list when switching between them. - The "Green" button in the "Recordings" menu can now be used to rewind a recording and play it from the very beginning. - Fixed handling ':' in timer filenames and '\n' in timer summaries (see FORMATS). - When removing recordings empty directories are now removed from the video directory. - Added the "schnitt" tools from Matthias Schniedermeyer. - New SVDRP command MESG to display a short message on the OSD. - The Perl script 'svdrpsend.pl' can be used to send SVDRP commands to VDR. - SVDRP can now immediately reuse the same port if VDR is restarted. - SVDRP now has a timeout after which the connection is automatically closed (default is 300 seconds, can be changed in "Setup"). - The compile time switch VFAT can be used to make VDR avoid the ':' character in file names (VFAT can't handle them). Do 'make VFAT=1' to enable this. - Support for DVB-C (thanks to Hans-Peter Raschke and Peter Hofmann). See the INSTALL file for more information about the use of VDR with cable. - Fixed an occasional segfault in the EIT processor. - A value of '0' for the EPGScanTimeout setup parameter now completely turns off scanning for EPG data on both single and multiple card systems. - New setup parameter "PrimaryLimit" that allows to prevent timers from using the primary DVB interface in multi card systems. Default value is 0, which means that every timer may use the primary interface. - The 'active' field of a timer will now be explicitly set to '1' if the user modifies an active timer (see FORMATS for details). - The new command line option -w can be used to activate a watchdog that makes VDR exit in case the main program loop does not respond for more than the given number of seconds. This is mainly useful in combination with the new 'runvdr' script that restarts VDR in case is has exited. --- BUGS | 8 - CONTRIBUTORS | 19 +- FORMATS | 31 +++- HISTORY | 64 +++++++ INSTALL | 32 +++- MANUAL | 28 ++- Makefile | 9 +- TODO | 7 - Tools/schnitt/README | 84 +++++++++ Tools/schnitt/cut.pl | 40 ++++ Tools/schnitt/cut2 | 2 + Tools/schnitt/cutall | 4 + Tools/schnitt/cutall2 | 5 + Tools/schnitt/cutt | 85 +++++++++ Tools/schnitt/getpreviframe.pl | 31 ++++ Tools/schnitt/index.php | 215 +++++++++++++++++++++ Tools/schnitt/lmplex | 51 +++++ Tools/schnitt/mv2 | 23 +++ Tools/schnitt/schnitt.pl | 26 +++ Tools/schnitt/schnitt2.pl | 91 +++++++++ Tools/schnitt/schnitt3.pl | 64 +++++++ Tools/schnitt/schnitt3.pl.new | 77 ++++++++ Tools/schnitt/schnitt4.pl | 13 ++ Tools/schnitt/schnitt5.pl | 16 ++ Tools/schnitt/schnitt6.pl | 30 +++ Tools/schnitt/schnittcommon.pli | 64 +++++++ Tools/schnitt/show | 11 ++ Tools/schnitt/unsort | 25 +++ Tools/schnitt/vdr-remote.pl | 40 ++++ Tools/schnitt/vdr2 | 2 + Tools/schnitt/vmount | 18 ++ channels.conf | 318 +++++++++++++++++--------------- channels.conf.cable | 134 ++++++++++++++ config.c | 30 ++- config.h | 7 +- dvbapi.c | 208 ++++++++++----------- dvbapi.h | 26 +-- eit.c | 13 +- epg2html.pl | 0 i18n.c | 22 ++- interface.c | 20 +- menu.c | 115 +++++++++--- menu.h | 4 +- osd.c | 50 ++++- osd.h | 7 +- recording.c | 97 +++++++++- recording.h | 14 +- remote.c | 12 +- remote.h | 10 +- runvdr | 13 ++ svdrp.c | 54 +++++- svdrp.h | 8 +- svdrpsend.pl | 57 ++++++ tools.c | 52 +++++- tools.h | 3 +- vdr.c | 111 ++++++++--- videodir.c | 12 +- videodir.h | 3 +- 58 files changed, 2214 insertions(+), 401 deletions(-) delete mode 100644 BUGS delete mode 100644 TODO create mode 100644 Tools/schnitt/README create mode 100755 Tools/schnitt/cut.pl create mode 100755 Tools/schnitt/cut2 create mode 100755 Tools/schnitt/cutall create mode 100755 Tools/schnitt/cutall2 create mode 100755 Tools/schnitt/cutt create mode 100755 Tools/schnitt/getpreviframe.pl create mode 100644 Tools/schnitt/index.php create mode 100755 Tools/schnitt/lmplex create mode 100755 Tools/schnitt/mv2 create mode 100755 Tools/schnitt/schnitt.pl create mode 100755 Tools/schnitt/schnitt2.pl create mode 100755 Tools/schnitt/schnitt3.pl create mode 100755 Tools/schnitt/schnitt3.pl.new create mode 100755 Tools/schnitt/schnitt4.pl create mode 100755 Tools/schnitt/schnitt5.pl create mode 100755 Tools/schnitt/schnitt6.pl create mode 100755 Tools/schnitt/schnittcommon.pli create mode 100755 Tools/schnitt/show create mode 100755 Tools/schnitt/unsort create mode 100755 Tools/schnitt/vdr-remote.pl create mode 100755 Tools/schnitt/vdr2 create mode 100755 Tools/schnitt/vmount create mode 100644 channels.conf.cable mode change 100644 => 100755 epg2html.pl create mode 100755 runvdr create mode 100755 svdrpsend.pl diff --git a/BUGS b/BUGS deleted file mode 100644 index 506316a50..000000000 --- a/BUGS +++ /dev/null @@ -1,8 +0,0 @@ -Video Disk Recorder - Known Bugs --------------------------------- - -* Sometimes the picture "jumps" as if a frame is skipped. - Presumably this is a problem in the card driver or firmware? - -* The pictures captured with the GRAB command in SVDRP - appear to be too dark. diff --git a/CONTRIBUTORS b/CONTRIBUTORS index ee44ada63..7a93b33ca 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -34,18 +34,29 @@ Niels de Carpentier Martin Hammerschmid for suggesting to display the direct channel select input on the OSD for suggesting to use the "Blue" button in the main menu to resume replay + for implementing pege up/down with the "Left" and "Right" keys Bastian Guse for writing the FORMATS entry for timers.conf Matthias Schniedermeyer - for implementing the 'MarkInstantRecord' setup option. + for implementing the 'MarkInstantRecord' setup option + for his "schnitt" tools Miha Setina - for translating the OSD texts to the Slovenian language. + for translating the OSD texts to the Slovenian language Alberto Carraro - for translating the OSD texts to the Italian language. + for translating the OSD texts to the Italian language Deti Fliegl - for implementing the 'CurrentChannel' setup parameter. + for implementing the 'CurrentChannel' setup parameter + +Dave Chapman + for implementing support for the teletext PID + +Hans-Peter Raschke + for his support in adapting VDR to DVB-C + +Peter Hofmann + for his support in adapting VDR to DVB-C diff --git a/FORMATS b/FORMATS index ed52518d2..2a357a355 100644 --- a/FORMATS +++ b/FORMATS @@ -13,7 +13,7 @@ Video Disk Recorder File Formats A "channel definition" is a line with channel data, where the fields are separated by ':' characters: - Example: "RTL:12188:h:1:27500:163:104:0:12003" + Example: "RTL:12188:h:1:27500:163:104:0:0:12003" The fields in a channel definition have the following meaning (from left to right): @@ -21,15 +21,19 @@ Video Disk Recorder File Formats - Name: the channel's name (if the name originally contains a ':' character it has to be replaced by '|') - Frequency in MHz (as an integer) - - Polarization (one of 'h', 'H', 'v', 'V') - - Diseqc number + - Polarization (one of 'h', 'H', 'v', 'V') ** + - Diseqc number ** - Symbol rate - Video PID - Audio PID + - Teletext PID - Conditional Access (0 = Free To Air, 1 = can be decrypted by the first DVB card, 2 = can be decrypted by the second DVB card) - Program Number + Fields marked with ** are only meaningful for DVB-S (satellite) receivers. + DVB-C receivers simply ignore these. + * timers.conf This file contains the timer setup. @@ -37,7 +41,10 @@ Video Disk Recorder File Formats The fields in a timer definition have the following meaning (from left to right): - - Timer active (0 = inaactive, 1 = active) + - Timer active (0 = inactive, 1 = active) + Values larger than '1' can be used by external programs to mark active timers + and recognize if the user has modified them. When a user modifes an active + timer the 'active' field will be explicitly set to '1'. - Program number of the channel to record - Day of recording, either one or more of M------ = Monday @@ -55,8 +62,10 @@ Video Disk Recorder File Formats - End time (first two digits for the hour, second two digits for the minutes) - Priority (from 00 to 99, 00 = lowest prioity, 99 = highest priority) - Guaranteed lifetime of recording (in days) - - Name of timer (will be used to name the recording) - - Summary + - Name of timer (will be used to name the recording); if the name contains + any ':' characters, these have to be replaced with '|' + - Summary (any newline characters in the summary have to be replaced with '|'; + the summary may contain ':' characters) * setup.conf @@ -86,9 +95,13 @@ Video Disk Recorder File Formats Examples: - Check for new mail: /usr/local/bin/checkmail 2>&1 - CPU status : /usr/loval/bin/cpustatus 2>&1 - Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' + 1 Check for new mail: /usr/local/bin/checkmail 2>&1 + 2 CPU status : /usr/loval/bin/cpustatus 2>&1 + 3 Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' + + If the first non-blank character of the 'title' is a digit in the range + 1..9, the command can be selected directly by pressing the respective numerical + key on the remote control. * marks.vdr diff --git a/HISTORY b/HISTORY index 8d5e88494..684d2b65c 100644 --- a/HISTORY +++ b/HISTORY @@ -349,3 +349,67 @@ Video Disk Recorder Revision History - The EIT scanning thread is now locked when switching channels to avoid problems. - Encrypted channels can now be selected even without knowing the PNR (however, it is still necessary for the EPG info). + +2001-02-24: Version 0.71 + +- Fixed 'Transfer Mode' in cases where a non-primary interface was switched to + a channel that only the primary interface can receive (which could happen in + the EPG scanner). +- The EPG scanner now starts with the first channel (it used to start with the + second channel). +- Reacitvated setting the PNR. +- Adapted the frame scanning to the new muxing of the driver. +- The new compile time option REMOTE=NONE can be used to compile VDR without + any remote control support (for applications where it shall be controlled + exclusively via SVDRP). +- The new command line option -D can be used to define which DVB interfaces + a certain instance of VDR shall use. +- The "Left" and "Right" keys are now used to page up and down in lists (thanks + to Martin Hammerschmid). Since the "Timers" menu already uses these keys to + (de)activate timers, this functionality is not available there. +- The "Main" and "Commands" menu now support "hotkeys", which means that if the + first non-blank character of a menu item is a digit in the range 1..9, that + item can be selected by pressing the respective numeric key on the remote + control. +- The channel data in 'channels.conf' now contains the teletext PID (thanks to + Dave Chapman). Existing files will be read normally (and the teletext PID set + to 0), but once they are written back (due to some channel editing) the file + will have the new format. +- The EPG scanner now scans each transponder only once per cycle. +- Deleted recordings are now automatically removed from disk after a while (not + only when disk space is being needed for a new recording). +- Fixed repeat function in LIRC remote control. +- Changed the MAXDVBAPI macro in dvbapi.c to 4 in order to directly support the + maximum possible number of DVB cards. +- The 'Ca' parameter in the default 'channels.conf' has been changed from '2' + to '3' because the VDR prototype now has 3 DVB cards (and currently the CAM + module only works if it is inserted into the last DVB card). +- The "Now", "Next" and "Schedule" menus now remember the current channel and + restore the list when switching between them. +- The "Green" button in the "Recordings" menu can now be used to rewind a + recording and play it from the very beginning. +- Fixed handling ':' in timer filenames and '\n' in timer summaries (see FORMATS). +- When removing recordings empty directories are now removed from the video + directory. +- Added the "schnitt" tools from Matthias Schniedermeyer. +- New SVDRP command MESG to display a short message on the OSD. +- The Perl script 'svdrpsend.pl' can be used to send SVDRP commands to VDR. +- SVDRP can now immediately reuse the same port if VDR is restarted. +- SVDRP now has a timeout after which the connection is automatically closed + (default is 300 seconds, can be changed in "Setup"). +- The compile time switch VFAT can be used to make VDR avoid the ':' character + in file names (VFAT can't handle them). Do 'make VFAT=1' to enable this. +- Support for DVB-C (thanks to Hans-Peter Raschke and Peter Hofmann). + See the INSTALL file for more information about the use of VDR with cable. +- Fixed an occasional segfault in the EIT processor. +- A value of '0' for the EPGScanTimeout setup parameter now completely turns off + scanning for EPG data on both single and multiple card systems. +- New setup parameter "PrimaryLimit" that allows to prevent timers from using the + primary DVB interface in multi card systems. Default value is 0, which means + that every timer may use the primary interface. +- The 'active' field of a timer will now be explicitly set to '1' if the user + modifies an active timer (see FORMATS for details). +- The new command line option -w can be used to activate a watchdog that makes + VDR exit in case the main program loop does not respond for more than the + given number of seconds. This is mainly useful in combination with the new + 'runvdr' script that restarts VDR in case is has exited. diff --git a/INSTALL b/INSTALL index e2a67a0fd..c334ed6d5 100644 --- a/INSTALL +++ b/INSTALL @@ -15,7 +15,7 @@ If you have the DVB driver source in a different location you will have to change the definition of DVBDIR in the Makefile. -This program requires the card driver version 0.8.1 or higher +This program requires the card driver version 0.8.2 or higher to work properly. You need to load the dvb.o module *without* option 'outstream=0' (previous versions of VDR required this option to have the driver supply the data in AV_PES format; as of version 0.70 VDR @@ -38,6 +38,7 @@ following values 'make' call to activate the respective control mode: (see http://www.cadsoft.de/people/kls/vdr/remote.htm) REMOTE=LIRC control via the "Linux Infrared Remote Control" (see http://www.lirc.org) + REMOTE=NONE no remote control (in case only SVDRP shall be used) Adding "DEBUG_OSD=1" will use the PC screen (or current window) to display texts instead of the DVB card's on-screen display @@ -45,6 +46,13 @@ interface. These modes are useful when testing new menus if you only have a remote connection to the VDR (which, in my case, is located in the living room and has neither a monitor nor a keyboard). +If your video directory will be on a VFAT partition, add the compile +time switch + + VFAT=1 + +to the 'make' command. + When running, the 'vdr' program writes status information into the system log file (/var/log/messages). You may want to watch these messages (tail -f /var/log/mesages) to see if there are any problems. @@ -63,6 +71,13 @@ If the program shall run as a daemon, use the --daemon option. This will completely detach it from the terminal and will continue as a background process. +Automatic restart in case of hangups: +------------------------------------- + +If you run VDR using the 'runvdr' shell script it will use the built-in +watchdog timer to restart the program in case something happens that +causes a program hangup. + Command line options: --------------------- @@ -132,6 +147,21 @@ that the channels defined in 'channels.conf' are correct before attempting to record anything. Channel parameters may vary and not all of the channels listed in the default 'channels.conf' file have been verified by the author. +As a starting point you can copy the 'channels.conf' file that comes with the +VDR archive into your video directory (or into your config directory, +respectively, in case you have redirected it with the -c option). + +Running VDR with DVB-C (cable): +------------------------------- + +VDR automatically recognizes if the DVB card in use is a cable card. +The only things that needs to be different when using digital cable +is the 'channels.conf' file. The distribution archive contains a default +'channels.conf.cable', which cable users can rename or copy to 'channels.conf' +in order to receive cable channels. The format of this file is exactly the +same as for satellite channels (the fields containing "Polarization" and +"Diseqc" data are ignored in case of DVB-C). + Learning the remote control keys: --------------------------------- diff --git a/MANUAL b/MANUAL index b0e9abe01..f77bd2763 100644 --- a/MANUAL +++ b/MANUAL @@ -12,16 +12,16 @@ Video Disk Recorder User's Manual Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause - Left Prev group - - Disable Decrement - Search back - Right Next group - - Enable Increment - Search forward + Left Prev group - Page up Disable Decrement Page up Search back + Right Next group - Page down Enable Increment Page down Search forward Ok Ch display Select Switch Edit Accept Play Progress disp. Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on Back - Menu off Main menu Main menu Discard Main menu Recordings menu Red - Record Edit Edit - Play - - Green - - New New - - Skip -60s + Green - - New New - Rewind Skip -60s Yellow - - Delete Delete - Delete Skip +60s - Blue - Resume Mark Mark - - Stop - 0..9 Ch select - - - Numeric inp. - - + Blue - Resume Mark Mark - Summary Stop + 0..9 Ch select - - - Numeric inp. - Editing * Navigating through the On Screen Menus @@ -310,7 +310,7 @@ Video Disk Recorder User's Manual 1 = instant recordings will be marked. LnbFrequLo = 9750 The low and high LNB frequencies (in MHz) - LnbFrequHi = 10600 + LnbFrequHi = 10600 (these have no meaning for DVB-C receivers) SetSystemTime = 0 Defines whether the system time will be set according to the time received from the DVB data stream. @@ -326,7 +326,21 @@ Video Disk Recorder User's Manual EPGScanTimeout = 5 The time (in hours) of user inactivity after which the DVB card in a single card system starts scanning channels to keep the EPG up-to-date. - A value of '0' turns off scanning on a single card system. + A value of '0' completely turns off scanning on both single + and multiple card systems. + + SVDRPTimeout = 300 The time (in seconds) of inactivity on an open SVDRP + connection after which the connection is automatically + closed. Default is 300, a value of 0 means no timeout. + + PrimaryLimit = 0 The minimum priority a timer must have to be allowed to + use the primary DVB interface, or to force another timer + with higher priority to use the primary DVB interface. + This is mainly useful for recordings that should take + place only when there is nothing else to do, but should + never keep the user from viewing stuff on the primary + interface. On systems with only one DVB card, timers + with a priority below PrimaryLimit will never execute. * Executing system commands diff --git a/Makefile b/Makefile index 4505c7b56..c1cfabe1a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.18 2001/01/13 12:26:43 kls Exp $ +# $Id: Makefile 1.20 2001/02/24 15:52:58 kls Exp $ DVBDIR = ../DVB @@ -25,6 +25,11 @@ ifdef DEBUG_OSD DEFINES += -DDEBUG_OSD endif +ifdef VFAT +# for people who want their video directory on a VFAT partition +DEFINES += -DVFAT +endif + all: vdr font: genfontfile fontfix.c fontosd.c @echo "font files created." @@ -75,6 +80,6 @@ genfontfile: genfontfile.o # Housekeeping: clean: - -rm -f $(OBJS) vdr genfontfile genfontfile.o + -rm -f $(OBJS) vdr genfontfile genfontfile.o core CLEAN: clean -rm -f fontfix.c fontosd.c diff --git a/TODO b/TODO deleted file mode 100644 index 1ae7d7176..000000000 --- a/TODO +++ /dev/null @@ -1,7 +0,0 @@ -TODO list for the Video Disk Recorder project ---------------------------------------------- - -* Implement simultaneous record/replay with a single DVB card once - the card driver/firmware allows this. -* Implement channel scanning. -* Implement remaining commands in SVDRP. diff --git a/Tools/schnitt/README b/Tools/schnitt/README new file mode 100644 index 000000000..29953e0ee --- /dev/null +++ b/Tools/schnitt/README @@ -0,0 +1,84 @@ + Sammlung von "Hilfs"-Scripten + +Diese Sammlung an "Hilfs"-Scripten habe ich mir zum scheiden und anderen +Zwecken zusammengeschrieben. + +Das ganze unterliegt natuerlich der GPL. + +Ich bin nicht sonderlich gut im "Dokumentieren". Also gilt die Devise +"Hilf dir selbst". + +Ein paar Worte zu den "Hart"-Codierten Pfaden. + +/yele/video (/video/video0) +/yelg/video (/video/video1) + +Sind die 2 Pfade auf meinem DVB-Rechner + +/x1/video + +Ist das Verzeichniss in das die Video zum schneiden verschoben werden. + +/x1/temp +/x2/temp + +Sind die beim schneiden verwendeten Temporaer-Verzeichnisse + + +Enthalten sind folgende Scripte: + +cutall -> "Master"-Script zum starten des Scheide vorgangs. + Ist ein "find" nach "cut" -Dateien +cutt -> Das "eigentliche" Schnitt-Script + Scheidet die Stuecke aus, demultipext, remultipext, + splitted die Dateien und macht am Ende ein + ISO-Image daraus +index.php -> PHP-Script zum finden der Schnitt-Punkte, mit + Testmoeglichkeit ob erfolgreich an diesem Punkt + geschnitten werden kann +mv2 -> Zum Moven der Aufnahmen von meinem DVB-Rechner + auf mein "Arbeitsrechner" +schnitt.pl -> Extraiert ein einzelnes Bild um es anzuzeigen + (Fuer index.php) +schnitt2.pl -> Gibt alles zwischen 2 Schnittpunkten auf STDOUT aus +schnitt3.pl -> Testet ob erfolgreich geschnitten werden kann. +schnitt3.pl.new -> Version fuer PES-Datenstroeme +schnitt4.pl -> "Beschleunigtes" Schnitt-Programm fuer VIVA + aufnahmen. 1 "VIDEO" pro Zeile erzeugt + "a", "b" ... Dateien +schnitt5.pl -> Gibt Datei-Nummern von einer Schnittmarke + +- 15000 Frames aus +schnitt6.pl -> Loescht alle Dateien die nicht von in einer von + schnitt5.pl abgedeckt ist. (Damit mv2 nicht so + lange braucht) +show -> Wird auf einem X-Display gestartet und zeigt das + aktuelle Bild von "schnitt.pl" an +vdr-remote.pl -> "Skeleton" um ueber SVDR-Kommandos zu schicken +vdr2 -> Start-Script +vmount -> Mounten aller zusammengehoeriger ISO-Images zum + abspielen + +Hilsscripte: +------------ +cut.pl -> Entspricht weitestgehend "split" aber mit + "Nummer" anstatt Buchstaben +cut2 -> Entfernt escapende Backslashes +cutall2 -> Springt ins Schnitt-Verzeichniss und ruft das + "eigentliche" Schnitt-Script auf +lmplex -> Multiplexed Datenstrome unter Zurhilfename + saemtlicher CPUs +schnittcommon.pli -> Das "Common" Script fuer schnitt?.pl +getpreviframe.pl -> Findet das vorherige I-Frame. +unsort -> Macht das Gegenteil von sort. + + +Die ganze "Schnittloesung" ist leider etwas "unbrauchbar", weil ich aus +Unachtsamkeit leider die gepatchten Sourcen von 2 wichtigen Programm +geloescht habe. + +dumpfrage -> Extraiert das erste Frage in eine Datei zum + anzeigen (gepatchtes dump aus "libmpeg3" +pvademux -> gepatcht um eine Pfad-Angabe + +Entweder macht jemand/ich patchen "nochmal" oder ich kann auch die +Binaries zur Verfuegung stellen. diff --git a/Tools/schnitt/cut.pl b/Tools/schnitt/cut.pl new file mode 100755 index 000000000..dd62c18ff --- /dev/null +++ b/Tools/schnitt/cut.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w + +use strict; + +my $maxsize = 660 * 1024 * 1024; + +my $read = 1024*1024; +my $size = 1024*1024; + +my $filenum = "1"; +my $count = 0; + +my ($fi,$data); + +$fi = sprintf ("part%d",$filenum); +open (FI,">$fi"); + +while ($read == $size) + { + if ($count < $maxsize) + { + $read = read (STDIN,$data,$size); + print FI $data; + $count += $size; + $a = $count /1024/1024; + if ($a % 10 == 0) { + print STDERR "File: $filenum Size: ${a}MB\n"; + } + } + else + { + close (FI); + $filenum++; + $fi = sprintf ("part%d",$filenum); + open (FI,">$fi"); + $count = 0; + } + } + +close FI; diff --git a/Tools/schnitt/cut2 b/Tools/schnitt/cut2 new file mode 100755 index 000000000..0193ac0c2 --- /dev/null +++ b/Tools/schnitt/cut2 @@ -0,0 +1,2 @@ +#!/bin/sh +cat cut | head -n 1 | tr -d [\\\\] diff --git a/Tools/schnitt/cutall b/Tools/schnitt/cutall new file mode 100755 index 000000000..355935fd3 --- /dev/null +++ b/Tools/schnitt/cutall @@ -0,0 +1,4 @@ +#!/bin/sh +cutdir=/x1/video/ + +find $cutdir -name "cut" -exec cutall2 {} \; diff --git a/Tools/schnitt/cutall2 b/Tools/schnitt/cutall2 new file mode 100755 index 000000000..90b0f46ba --- /dev/null +++ b/Tools/schnitt/cutall2 @@ -0,0 +1,5 @@ +#!/bin/sh +a=`echo $1 | cut -d / -f1-5` +cd $a +cutt +mv cut cut.bak diff --git a/Tools/schnitt/cutt b/Tools/schnitt/cutt new file mode 100755 index 000000000..4e89b7a3d --- /dev/null +++ b/Tools/schnitt/cutt @@ -0,0 +1,85 @@ +#!/bin/sh + +DIRA=/x2/temp +DIRB=/x1/temp + +if [ -f cut ]; then + name="`cut2`" + echo $name + count=`cat cut | wc -l` + let count=count-1 + let test=count%2 + if [ "$test" == "1" ]; then + echo Ungerade Anzahl von Markierungen + exit 1 + fi + + file=1 + + while [ "$count" != "0" ] + do + start=`cat cut | tail -n $count | head -n 1` + let count=count-1 + end=`cat cut | tail -n $count | head -n 1` + let count=count-1 + echo Cutting\&Demuxing from $start to $end + schnitt2.pl $start $end | pvademux $DIRA teil$file +# schnitt2.pl $start $end | pes2av_pes | pvademux $DIRA teil$file + let file=file+1 + done +else + echo Keine Beschreibungsdatei + exit 1 +fi + +# Ab hier mkimg + +sync + +lmplex $DIRA $DIRB `ls -la $DIRA/teil*.m2v | cut -b 30- | sort -n -r | cut -d / -f4` + +echo Multiplexing DONE + +rm -f $DIRA/teil*.m2v $DIRA/teil*.mp2 + +sync + +if [ -f $DIRB/teil1.mpg ]; then + echo Splitting + cd $DIRA +# cat $DIRB/teil*.mpg | split -b 723517440 + cat $DIRB/teil*.mpg | cut.pl + rm $DIRB/teil* +fi + +sync + +cd $DIRA + +if [ -f part2 ]; then + count=1 + cond=0 + + while [ "$cond" != "1" ] + do + mkdir a + mv "part$count" "a/${name} Teil $count" + echo mkisofs Teil $count + mkisofs -r -o $DIRB/image1.raw a + rm -rf a + mv -- $DIRB/image1.raw "$DIRB/${name} Teil $count" + sync + + let count=count+1 + if [ ! -f "part$count" ]; then + cond=1 + fi + done +else + mkdir a + mv part1 "a/${name}" + echo mkisofs + mkisofs -r -o $DIRB/image1.raw a + rm -rf a + mv -- $DIRB/image1.raw "$DIRB/${name}" +fi diff --git a/Tools/schnitt/getpreviframe.pl b/Tools/schnitt/getpreviframe.pl new file mode 100755 index 000000000..6774f3192 --- /dev/null +++ b/Tools/schnitt/getpreviframe.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +use strict; + +my ($index, $oindex); + +require "/usr/local/bin/my/schnittcommon.pli"; + +if (!open (INDEX,"index.vdr")) + { + exit 1; + } + +$index = $oindex = $ARGV[0]; + +if ($index > 0) +{ + &prevI; + if ($oindex != $index) + { + print "$index\n"; + } + else + { + print "$oindex\n"; + } +} +else +{ + print "0\n"; +} diff --git a/Tools/schnitt/index.php b/Tools/schnitt/index.php new file mode 100644 index 000000000..58a288fec --- /dev/null +++ b/Tools/schnitt/index.php @@ -0,0 +1,215 @@ + + + Schneiden + + + +

Sender

+
+ +\n"; + } + } + closedir($handle); +?> +
+ +
+ +

Filme/Serien fuer den Sender $dir

"; + $handle=opendir("/x1/video/$dir"); + while ($file = readdir($handle)) { + if ($file != "." && $file != "..") { + echo "
\n"; + } + } + closedir($handle); +?> +
+=10000) + $index -= 10000; + break; + case "-4000": + if ($index >=4000) + $index -= 4000; + break; + case "-2000": + if ($index >=2000) + $index -= 2000; + break; + case "-1000": + if ($index >=1000) + $index -= 1000; + break; + case "-500": + if ($index >=500) + $index -= 500; + break; + case "-100": + if ($index >=100) + $index -= 100; + break; + case "Vorheriges I-Frame": + $pindex = $index - 1; + $fp = popen ("/usr/local/bin/my/getpreviframe.pl $pindex","r"); + $i = fgets($fp,1000); + $index = chop ($i); + pclose ($fp); + break; + case "Naechstes I-Frame": + $index ++; + break; + case "+100": + $index += 100; + break; + case "+500": + $index += 500; + break; + case "+1000": + $index += 1000; + break; + case "+2000": + $index += 2000; + break; + case "+4000": + $index += 4000; + break; + case "+10000": + $index += 10000; + break; + } + +if ($test) + { + $fp = popen ("/usr/local/bin/my/schnitt3.pl $index","r"); + $i = fgets($fp,1000); + pclose ($fp); + $index = chop ($i); + } + +if ($name) + { + $fp = fopen ("cut","w"); + fputs ($fp,"$name\n"); + fclose ($fp); + } + +if ($cut) + { + $fp = fopen ("cut","a"); + fputs ($fp,"$index\n"); + fclose ($fp); + } + +$fp = popen ("/usr/local/bin/my/schnitt.pl $index","r"); +$i = fgets($fp,1000); +pclose ($fp); +$index = chop ($i); + +system ("/usr/local/bin/my/dumpframe /x2/temp/bild.m2v"); +system ("mv output.ppm /x2/temp"); +system ("touch /x2/temp/newpic"); +system ("killall sleep"); +?> +
+ + +> + + + + + +

Index

Dir:

+ + + + + + + + + + + + + + + + +
+
+ + + + + + + + + +> + + + +
Absoluter Index:
Titel:
+ + + diff --git a/Tools/schnitt/lmplex b/Tools/schnitt/lmplex new file mode 100755 index 000000000..8cbb50f20 --- /dev/null +++ b/Tools/schnitt/lmplex @@ -0,0 +1,51 @@ +#! /usr/bin/perl + +### Calculate the number of CPUs we want to keep busy +open IN, "/proc/cpuinfo"; +$cpus = grep /processor.*:/, ; +close IN; + +### This is a list of files to encode +@names = @ARGV; + +$dira = shift @names; +$dirb = shift @names; + +### This is the name of the encoder to use. +$coder = "/usr/local/bin/mplex "; +### + +### +### +### + +# Encode a single file +sub do_one { + my($m2v) = shift; + # Make mp3 from wav + $m2v =~ s/\.m2v$//; + + # In a subprocess, encode the file + printf "Multiplexing ${m2v}\n"; + unless($pid = fork) { + system ("$coder ${dira}/${m2v}.m2v ${dira}/${m2v}.mp2 ${dirb}/${m2v}.mpg"); + exit; + } +} + +# Go ahead and prefork $cpus encoders +foreach $i (0 .. $cpus-1) { + &do_one($names[0]) if ($names[0] ne ""); + shift @names; +} + +# Wait for the end of each encoder, start a new one... +foreach $i (@names) { + wait; + &do_one($i); +} + +# Wait for everything to close down. +while(wait > 0) { + ; +} diff --git a/Tools/schnitt/mv2 b/Tools/schnitt/mv2 new file mode 100755 index 000000000..a0cefba7f --- /dev/null +++ b/Tools/schnitt/mv2 @@ -0,0 +1,23 @@ +#!/bin/sh + +DIR = /x1/video + +if [ ! "$UID" = 0 ]; then + if [ -d "$1" ]; then + cd $DIR + a=`echo "$1" | cut -d / -f4-` + mkdir -p "$a" + cd "$a" + (echo cd "$1"; echo mget \*)| ftp -i dvb + cd $DIR + ls -Ls $1 > /tmp/yele + ls -Ls $a > /tmp/x1 + a=`echo "$1" | cut -d \/ -f3-` + diff -u /tmp/yele /tmp/x1 &> /dev/null && rm -rfv /yel?/$a + rm /tmp/yele + rm /tmp/x1 + rmdir /yel?/video/* + fi +else + echo Not as root +fi diff --git a/Tools/schnitt/schnitt.pl b/Tools/schnitt/schnitt.pl new file mode 100755 index 000000000..d5521ebbf --- /dev/null +++ b/Tools/schnitt/schnitt.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +require "/usr/local/bin/my/schnittcommon.pli"; + +if (!open (INDEX,"index.vdr")) + { + exit 1; + } +$index = $ARGV[0]; +&nextI; +$offset1 = $offset; +&readnext; +$off = $offset - $offset1; +close (FI); +$fi = sprintf ("%03d.vdr",$file); +open (FI,$fi); +open (FO,">bild"); +sysseek (FI,$offset1,0); +sysread (FI,$temp,200000); +syswrite (FO,$temp,200000); +close (FI); +close (FO); + +`/usr/local/bin/pvademux.old /x2/temp bild`; +#`/usr/local/bin/pes2av_pes bild | /usr/local/bin/pvademux /x2/temp bild`; +print "$index\n"; diff --git a/Tools/schnitt/schnitt2.pl b/Tools/schnitt/schnitt2.pl new file mode 100755 index 000000000..e52b24595 --- /dev/null +++ b/Tools/schnitt/schnitt2.pl @@ -0,0 +1,91 @@ +#!/usr/bin/perl + +require "/usr/local/bin/my/schnittcommon.pli"; + +if (!open (INDEX,"index.vdr")) + { + print "Error opening index.vdr"; + exit 1; + } + +$index = $ARGV[0]; +&nextI; +$file1 = $file; +$offset1 = $offset; +$index = $ARGV[1]; +&nextI; +$file2 = $file; +$offset2 = $offset; + +if ($file1 == $file2) + { + $count = $offset2 - $offset1; + $cond = 0; + $size = 1024*1024; + $fi = sprintf ("%03d.vdr",$file); + open (FI,$fi); + sysseek (FI,$offset1,0); + while ($cond == 0) + { + if ($count > $size) + { + $read = sysread (FI,$data,$size); + print $data; + $count -= $size; + } + else + { + $read = sysread (FI,$data,$count); + print $data; + $cond = 1; + } + } + } +else + { + $count = $offset2; + $cond = 0; + $read = $size = 1024*1024; + $fi = sprintf ("%03d.vdr",$file1); + open (FI,$fi); + sysseek (FI,$offset1,0); + while ($read == $size) + { + $read = sysread (FI,$data,$size); + print $data; + } + close (FI); + + $file1++; + while ($file1 != $file2) + { + $fi = sprintf ("%03d.vdr",$file1); + open (FI,$fi); + $read = 1024*1024; + while ($read == $size) + { + $read = sysread (FI,$data,$size); + print $data; + } + close (FI); + $file1++; + } + + $fi = sprintf ("%03d.vdr",$file2); + open (FI,$fi); + while ($cond == 0) + { + if ($count > $size) + { + $read = sysread (FI,$data,$size); + print $data; + $count -= $size; + } + else + { + $read = sysread (FI,$data,$count); + print $data; + $cond = 1; + } + } + } diff --git a/Tools/schnitt/schnitt3.pl b/Tools/schnitt/schnitt3.pl new file mode 100755 index 000000000..7cc0f7f3e --- /dev/null +++ b/Tools/schnitt/schnitt3.pl @@ -0,0 +1,64 @@ +#!/usr/bin/perl + +require "/usr/local/bin/my/schnittcommon.pli"; + +open (INDEX,"index.vdr"); +$index = $ARGV[0]; +&nextI; + +$oldindex = $index; +$tempindex = $index; + +$add = -1; + +$fi = sprintf ("%03d.vdr",$file); +open (FI2,$fi); +open (FO,">test"); +sysseek (FI2,$offset,0); +sysread (FI2,$temp,3000000); +syswrite (FO,$temp,3000000); +close (FI2); +close (FO); +`/usr/local/bin/pvademux.old . test`; +if ( -s "test.mp2") + { + `rm test*`; + print "$index\n"; + exit 0; + } + +while (1) + { + if ($index == 0) + { + $add = 1; + } + if ($add = -1) + { + $index--; + &prevI; + } + else + { + nextI; + } + $fi = sprintf ("%03d.vdr",$file); + open (FI2,$fi); + open (FO,">test"); + sysseek (FI2,$offset,0); + sysread (FI2,$temp,3000000); + syswrite (FO,$temp,3000000); + close (FI2); + close (FO); + `/usr/local/bin/pvademux.old . test`; + if ( -s "test.mp2") + { + `rm test*`; + if ($index < 0) + { + $index *= -1; + } + print "$index\n"; + exit 0; + } + } diff --git a/Tools/schnitt/schnitt3.pl.new b/Tools/schnitt/schnitt3.pl.new new file mode 100755 index 000000000..04a6239be --- /dev/null +++ b/Tools/schnitt/schnitt3.pl.new @@ -0,0 +1,77 @@ +#!/usr/bin/perl + +require "/usr/local/bin/my/schnittcommon.pli"; + +open (INDEX,"index.vdr"); + +$index = $ARGV[0]; +&nextI; + +$oldindex = $index; +$tempindex = $index; + +$add = -1; + +$fi = sprintf ("%03d.vdr",$file); +open (FI2,$fi); +open (FO,">test2"); +sysseek (FI2,$offset,0); +sysread (FI2,$temp,3000000); +syswrite (FO,$temp,3000000); +close (FI2); +close (FO); + +system ("pes2av_pes test2 > test 2>/dev/null"); +open (PVA,"/usr/local/bin/pvademux.old . test 2>&1 |"); + +@a=; close PVA; +@b=split (/\s/,$a[2]); + +if (!($b[4] =~ /\-/) && $b[4] < 2000) + { + unlink ; + print "$index\n"; + exit 0; + } + +while (1) + { + if ($index == 0) + { + $add = 1; + } + if ($add = -1) + { + $index--; + &prevI; + } + else + { + nextI; + } + $fi = sprintf ("%03d.vdr",$file); + open (FI2,$fi); + open (FO,">test2"); + sysseek (FI2,$offset,0); + sysread (FI2,$temp,3000000); + syswrite (FO,$temp,3000000); + close (FI2); + close (FO); + +system ("/usr/local/bin/pes2av_pes test2 > test 2>/dev/null"); +open (PVA,"/usr/local/bin/pvademux.old . test 2>&1 |"); + +@a=; close PVA; +@b=split (/\s/,$a[2]); + +if (!($b[4] =~ /\-/) && $b[4] < 2000) + { + unlink ; + if ($index < 0) + { + $index *= -1; + } + print "$index\n"; + exit 0; + } +} diff --git a/Tools/schnitt/schnitt4.pl b/Tools/schnitt/schnitt4.pl new file mode 100755 index 000000000..75f2ad178 --- /dev/null +++ b/Tools/schnitt/schnitt4.pl @@ -0,0 +1,13 @@ +#!/usr/bin/perl + +open (FI,$ARGV[0]) or die "Kann Input-Datei nicht oeffnen"; +$count = 1; + +while () + { + chomp; + $char = sprintf ("%c",$count + 96); + print "Cutting from/to $_ into /x2/clips/$char\n"; + system ("/usr/local/bin/my/schnitt2.pl $_ > /x2/clips/$char"); + $count++; + } diff --git a/Tools/schnitt/schnitt5.pl b/Tools/schnitt/schnitt5.pl new file mode 100755 index 000000000..7626ab51f --- /dev/null +++ b/Tools/schnitt/schnitt5.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl +require "/usr/local/bin/my/schnittcommon.pli"; + +open (INDEX,"index.vdr"); +$index = $ARGV[0] - 15000; +&nextI; + +$file1 = $file; + +$index += 30000; +&nextI; + +$file2 = $file; + +print "$file1 $file2\n"; + diff --git a/Tools/schnitt/schnitt6.pl b/Tools/schnitt/schnitt6.pl new file mode 100755 index 000000000..92d9eb49c --- /dev/null +++ b/Tools/schnitt/schnitt6.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl + +open (FI,"a"); + +while () +{ + open (SCH,"/usr/local/bin/my/schnitt5.pl $_|"); + $files = ; + chomp $files; + ($a,$b) = split (/\s/,$files); + $files[$a] = 1; + $files[$b] = 1; + close (SCH); +} + +while (<0*.vdr>) +{ + $_ =~ /\d(\d\d)\.vdr/; + if ($files[$1]) + { + print "Keeping $1\n"; + } + else + { + print "Deleting $_\n"; + unlink $_; + } +} + +close (FI); diff --git a/Tools/schnitt/schnittcommon.pli b/Tools/schnitt/schnittcommon.pli new file mode 100755 index 000000000..f221f41af --- /dev/null +++ b/Tools/schnitt/schnittcommon.pli @@ -0,0 +1,64 @@ +sub nextI + { + if (!$size) + { + $size = -s INDEX; + } + local ($a,$b,$c,$dummy); + $cond = 0; + seek (INDEX,$index * 8,0); + + while ($cond == 0) + { + &readnext; + if ($frame == 1) + { + $cond = 1; + } + else + { + $index++; + if ($index > ($size/8-1)) + { + $index = $size/8-1; + &prevI; + print "$index\n"; + exit 1; + } + } + } + } + +sub readnext + { + read (INDEX,$a,4); + read (INDEX,$b,1); + read (INDEX,$c,1); + read (INDEX,$dummy,2); + $offset = unpack ("L",$a); + $frame = unpack ("C",$b); + $file = unpack ("C",$c); + } + +sub prevI + { + local ($a,$b,$c,$dummy); + $cond = 0; + seek (INDEX,$index * 8,0); + + while ($cond == 0) + { + &readnext; + if ($frame == 1) + { + $cond = 1; + } + else + { + $index--; + seek (INDEX,$index * 8,0); + } + } + } + +1; diff --git a/Tools/schnitt/show b/Tools/schnitt/show new file mode 100755 index 000000000..afed79b3c --- /dev/null +++ b/Tools/schnitt/show @@ -0,0 +1,11 @@ +#!/bin/sh +cd /x2/temp +while true +do + if [ -f newpic ]; then + killall xli + rm -f newpic + xli output.ppm & + fi +sleep 24h +done diff --git a/Tools/schnitt/unsort b/Tools/schnitt/unsort new file mode 100755 index 000000000..83adfb6c6 --- /dev/null +++ b/Tools/schnitt/unsort @@ -0,0 +1,25 @@ +#!/usr/bin/perl + +while (<>) +{ + $h{$_}=1; +} + +foreach $key (sort shuffle keys %h) +{ + print $key; +} + +sub shuffle { + $ran = rand(1); + + if ($ran > 0.5) + { + return -1; + } + else + { + return 1; + } +} + diff --git a/Tools/schnitt/vdr-remote.pl b/Tools/schnitt/vdr-remote.pl new file mode 100755 index 000000000..32d408e0d --- /dev/null +++ b/Tools/schnitt/vdr-remote.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w + +use strict; +use Socket; + +my ($dest, $port, $iaddr, $paddr, $proto, $line); + +$dest = "localhost"; +$port = "2001"; + +$iaddr = inet_aton($dest) || Error("no host: $dest"); +$paddr = sockaddr_in($port, $iaddr); + +$proto = getprotobyname('tcp'); +socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!"); +connect(SOCK, $paddr) || Error("connect: $!"); +select (SOCK); $| = 1; +$a=; + +for (;;) + { + open (FI,"/tmp/vdr-keys"); + while () + { + chomp; + print "$_\r\n"; + $a=; + } + close (FI); + } + +print "quit\r\n"; +$a=; +close (SOCK) || Error("close: $!"); + +sub Error +{ + print STDERR "@_\n"; + exit 0; +} diff --git a/Tools/schnitt/vdr2 b/Tools/schnitt/vdr2 new file mode 100755 index 000000000..96557bf2f --- /dev/null +++ b/Tools/schnitt/vdr2 @@ -0,0 +1,2 @@ +#!/bin/sh +irpty ~/.lircrc-vdr -- vdr -c /home/ms/.vdr -v /video/video0 diff --git a/Tools/schnitt/vmount b/Tools/schnitt/vmount new file mode 100755 index 000000000..6b7906473 --- /dev/null +++ b/Tools/schnitt/vmount @@ -0,0 +1,18 @@ +#!/bin/sh +count=1 +cond=0 + +if [ -f "$1" ]; then + mount "$1" /mnt/1 -o loop + $cond = 1 +else + while [ "$cond" != "1" ] + do + if [ -f "$1$count" ]; then + mount "$1$count" /mnt/$count -o loop + else + cond=1 + fi + let count=count+1 + done +fi diff --git a/channels.conf b/channels.conf index 43e69cd6f..4947f8238 100644 --- a/channels.conf +++ b/channels.conf @@ -1,148 +1,174 @@ -RTL:12188:h:0:27500:163:104:0:12003 -Sat.1:12480:v:0:27500:1791:1792:0:46 -Pro-7:12480:v:0:27500:255:256:0:898 -RTL2:12188:h:0:27500:166:128:0:12020 -ARD:11837:h:0:27500:101:102:0:28106 -BR3:11837:h:0:27500:201:202:0:28107 -Hessen-3:11837:h:0:27500:301:302:0:28108 -N3:12110:h:0:27500:2401:2402:0:28224 -SR3:11837:h:0:27500:501:502:0:28110 -WDR:11837:h:0:27500:601:602:0:28111 -BR-alpha:11837:h:0:27500:701:702:0:28112 -SWR BW:11837:h:0:27500:801:802:0:28113 -Phoenix:11837:h:0:27500:901:902:0:28114 -ZDF:11954:h:0:27500:110:120:0:28006 -3sat:11954:h:0:27500:210:220:0:28007 -KiKa:11954:h:0:27500:310:320:0:28008 -arte:11836:h:0:27500:401:402:0:28109 -ORF Sat:11954:h:0:27500:506:507:0:28010 -ZDF.info:11954:h:0:27500:610:620:0:28011 -CNN:12168:v:0:27500:165:100:0:28512 -Super RTL:12188:h:0:27500:165:120:0:12040 -VOX:12188:h:0:27500:167:136:0:12060 -DW TV:12363:v:0:27500:305:306:0:8905 -Kabel 1:12480:v:0:27500:511:512:0:899 -tm3:12480:v:0:27500:767:768:0:897 -DSF:12480:v:0:27500:1023:1024:0:900 -HOT:12480:v:0:27500:1279:1280:0:40 -Bloomberg TV Germany:12551:v:0:22000:162:99:0:12160 -BLOOMBERG TV:11817:v:0:27500:163:92:0:8004 -Bloomberg:12168:v:0:27500:167:112:0:12721 -Sky News:12552:v:0:22000:305:306:0:3995 -KinderNet:12574:h:0:22000:163:92:0:5020 -Alice:12610:v:0:22000:162:96:0:12200 -n-tv:12669:v:0:22000:162:96:0:12730 -Grand Tourisme:12670:v:0:22000:289:290:0:17300 -TW1:12692:h:0:22000:166:167:0:13013 -Eurosport:11954:h:0:27500:410:420:0:28009 -EinsExtra:12110:h:0:27500:101:102:0:28201 -EinsFestival:12110:h:0:27500:201:202:0:28202 -EinsMuXx:12110:h:0:27500:301:302:0:28203 -ZDF Theaterkanal:11954:h:0:27500:1110:1120:0:28016 -ZDF.doku:11954:h:0:27500:660:670:0:28014 -MDR:12110:h:0:27500:401:402:0:28204 -NICK-PARAMOUNT:12246:v:0:27500:167:108:0:29312 -ORB:12110:h:0:27500:501:502:0:28205 -B1:12110:h:0:27500:601:602:0:28206 -ARD Online-Kanal:12722:h:0:22000:8191:701:0:0 +RTL:12188:h:0:27500:163:104:32:0:12003 +Sat.1:12480:v:0:27500:1791:1792:34:0:46 +Pro-7:12480:v:0:27500:255:256:32:0:898 +RTL2:12188:h:0:27500:166:128:68:0:12020 +ARD:11837:h:0:27500:101:102:0:0:28106 +BR3:11837:h:0:27500:201:202:0:0:28107 +Hessen-3:11837:h:0:27500:301:302:0:0:28108 +N3:12110:h:0:27500:2401:2402:0:0:28224 +SR3:11837:h:0:27500:501:502:0:0:28110 +WDR:11837:h:0:27500:601:602:0:0:28111 +BR-alpha:11837:h:0:27500:701:702:0:0:28112 +SWR BW:11837:h:0:27500:801:802:0:0:28113 +Phoenix:11837:h:0:27500:901:902:0:0:28114 +ZDF:11954:h:0:27500:110:120:130:0:28006 +3sat:11954:h:0:27500:210:220:230:0:28007 +KiKa:11954:h:0:27500:310:320:0:0:28008 +arte:11836:h:0:27500:401:402:0:0:28109 +ORF1:12692:h:0:22000:160:161:165:3:13001 +ORF2:12692:h:0:22000:500:501:505:3:13007 +ORF Sat:11954:h:0:27500:506:507:0:0:28010 +ZDF.info:11954:h:0:27500:610:620:0:0:28011 +CNN:12168:v:0:27500:165:100:0:0:28512 +Super RTL:12188:h:0:27500:165:120:65:0:12040 +VOX:12188:h:0:27500:167:136:0:0:12060 +DW TV:12363:v:0:27500:305:306:0:0:8905 +Kabel 1:12480:v:0:27500:511:512:33:0:899 +tm3:12480:v:0:27500:767:768:0:0:897 +DSF:12480:v:0:27500:1023:1024:0:0:900 +HOT:12480:v:0:27500:1279:1280:0:0:40 +Bloomberg TV Germany:12551:v:0:22000:162:99:0:0:12160 +BLOOMBERG TV:11817:v:0:27500:163:92:0:0:8004 +Bloomberg:12168:v:0:27500:167:112:0:0:12721 +Sky News:12552:v:0:22000:305:306:0:0:3995 +KinderNet:12574:h:0:22000:163:92:0:0:5020 +Alice:12610:v:0:22000:162:96:0:0:12200 +n-tv:12669:v:0:22000:162:96:55:0:12730 +Grand Tourisme:12670:v:0:22000:289:290:0:0:17300 +TW1:12692:h:0:22000:166:167:0:0:13013 +Eurosport:11954:h:0:27500:410:420:0:0:28009 +EinsExtra:12110:h:0:27500:101:102:0:0:28201 +EinsFestival:12110:h:0:27500:201:202:0:0:28202 +EinsMuXx:12110:h:0:27500:301:302:0:0:28203 +ZDF Theaterkanal:11954:h:0:27500:1110:1120:0:0:28016 +ZDF.doku:11954:h:0:27500:660:670:0:0:28014 +MDR:12110:h:0:27500:401:402:0:0:28204 +NICK-PARAMOUNT:12246:v:0:27500:167:108:0:0:29312 +ORB:12110:h:0:27500:501:502:0:0:28205 +B1:12110:h:0:27500:601:602:0:0:28206 +ARD Online-Kanal:12722:h:0:22000:8191:701:0:0:0 :Premiere World -Premiere World Promo:11798:h:0:27500:255:256:0:8 -Premiere:11798:h:0:27500:511:512:2:10 -Star Kino:11798:h:0:27500:767:768:2:9 -Cine Action:11798:h:0:27500:1023:1024:2:20 -Cine Comedy:11798:h:0:27500:1279:1280:2:29 -Sci Fantasy:11798:h:0:27500:1535:1536:2:41 -Romantic Movies:11798:h:0:27500:1791:1792:2:11 -Studio Universal:11798:h:0:27500:2047:2048:2:21 -13th Street:11797:h:0:27500:2303:2304:2:43 -Junior:12031:h:0:27500:255:256:2:19 -K-Toon:12032:h:0:27500:511:512:2:12 -Disney Channel:12031:h:0:27500:767:768:2:15 -Fox Kids:11798:h:0:27500:255:256:2:0 -Sunset:12031:h:0:27500:1023:1024:2:16 -Comedy:12031:h:0:27500:1279:1280:2:28 -Planet:12031:h:0:27500:2047:2048:2:13 -Discovery Channel:12031:h:0:27500:1791:1792:2:14 -Krimi&Co:12031:h:0:27500:1535:1536:2:23 -Filmpalast:12090:v:0:27500:255:256:2:36 -Heimatkanal:11758:h:0:27500:2815:2816:2:517 -Goldstar:11758:h:0:27500:3839:3840:2:518 -Classica:12090:v:0:27500:767:768:2:34 -Seasons:12090:v:0:27500:511:512:2:33 -Blue Channel:11758:h:0:27500:2559:2560:2:516 -Feed (F1 Boxengasse):11720:h:0:27500:2559:2560:2:242 -Feed (F1 Data):11720:h:0:27500:3071:3072:2:244 -Feed (F1 Multi):11720:h:0:27500:2815:2816:2:243 -Feed (F1 On Board):11720:h:0:27500:2303:2304:2:241 -Feed (F1 Verfolger):11720:h:0:27500:2047:2048:2:240 +Premiere World Promo:11798:h:0:27500:255:256:0:0:8 +Premiere:11798:h:0:27500:511:512:0:3:10 +Star Kino:11798:h:0:27500:767:768:0:3:9 +Cine Action:11798:h:0:27500:1023:1024:0:3:20 +Cine Comedy:11798:h:0:27500:1279:1280:0:3:29 +Sci Fantasy:11798:h:0:27500:1535:1536:0:3:41 +Romantic Movies:11798:h:0:27500:1791:1792:0:3:11 +Studio Universal:11798:h:0:27500:2047:2048:0:3:21 +13th Street:11797:h:0:27500:2303:2304:0:3:43 +Junior:12031:h:0:27500:255:256:0:3:19 +K-Toon:12032:h:0:27500:511:512:0:3:12 +Disney Channel:12031:h:0:27500:767:768:0:3:15 +Fox Kids:11798:h:0:27500:255:256:0:3:0 +Sunset:12031:h:0:27500:1023:1024:0:3:16 +Comedy:12031:h:0:27500:1279:1280:0:3:28 +Planet:12031:h:0:27500:2047:2048:0:3:13 +Discovery Channel:12031:h:0:27500:1791:1792:0:3:14 +Krimi&Co:12031:h:0:27500:1535:1536:0:3:23 +Filmpalast:12090:v:0:27500:255:256:0:3:36 +Heimatkanal:11758:h:0:27500:2815:2816:0:3:517 +Goldstar:11758:h:0:27500:3839:3840:0:3:518 +Classica:12090:v:0:27500:767:768:0:3:34 +Seasons:12090:v:0:27500:511:512:0:3:33 +Blue Channel:11758:h:0:27500:2559:2560:0:3:516 +Cinedom 1A de:12070:h:0:27500:1279:1280:0:3:188 +Cinedom 1A en:12070:h:0:27500:1279:1281:0:3:188 +Cinedom 1B:12070:h:0:27500:1791:1792:0:3:191 +Cinedom 1C:12070:h:0:27500:767:768:0:3:185 +Cinedom 1D:11758:h:0:27500:511:512:0:3:178 +Cinedom 1E:11720:h:0:27500:1535:1537:0:3:176 +Cinedom 2A:12070:h:0:27500:1535:1536:0:3:189 +Cinedom 2B:12070:h:0:27500:511:512:0:3:184 +Cinedom 2C:11758:h:0:27500:767:768:0:3:179 +Cinedom 2D:11758:h:0:27500:1023:1024:0:3:193 +Cinedom 2E:11720:h:0:27500:1279:1280:0:3:183 +Cinedom 3A:11758:h:0:27500:255:256:0:3:177 +Cinedom 3B:11758:h:0:27500:1279:1280:0:3:194 +Cinedom 3C:12090:v:0:27500:1279:1280:17689:3:192 +Cinedom 3D:11720:h:0:27500:511:512:0:3:180 +Cinedom 3E:11720:h:0:27500:1023:1024:0:3:182 +Cinedom 4A:11758:h:0:27500:1535:1536:0:3:195 +Cinedom 4B:12032:h:0:27500:2559:2560:0:3:187 +Cinedom 4C:11720:h:0:27500:767:768:0:3:181 +Cinedom 4D:11720:h:0:27500:1791:1792:0:3:190 +Cinedom 4E:12070:h:0:27500:1023:1025:0:3:186 +Blue Movie 1:11758:h:0:27500:1791:1792:0:3:513 +Blue Movie 2:11758:h:0:27500:2047:2048:0:3:514 +Blue Movie 3:11758:h:0:27500:2303:2304:0:3:515 +Feed (F1 Boxengasse):11720:h:0:27500:2559:2560:0:3:242 +Feed (F1 Data):11720:h:0:27500:3071:3072:0:3:244 +Feed (F1 Multi):11720:h:0:27500:2815:2816:0:3:243 +Feed (F1 On Board):11720:h:0:27500:2303:2304:0:3:241 +Feed (F1 Verfolger):11720:h:0:27500:2047:2048:0:3:240 : -TV Niepokalanow:11876:h:0:27500:305:321:0:20601 -Mosaico:11934:v:0:27500:165:100:0:29010 -Andalucia TV:11934:v:0:27500:166:104:0:29011 -TVC Internacional:11934:v:0:27500:167:108:0:0 -Nasza TV:11992:h:0:27500:165:98:0:0 -WishLine test:12012:v:0:27500:163:90:0:0 -Pro 7 Austria:12051:v:0:27500:161:84:0:0 -Kabel 1 Schweiz:12051:v:0:27500:162:163:0:0 -Kabel 1 Austria:12051:v:0:27500:166:167:0:0 -Pro 7 Schweiz:12051:v:0:27500:289:290:0:0 -Kiosque:12129:v:0:27500:160:80:0:0 -KTO:12129:v:0:27500:170:120:0:0 -TCM:12168:v:0:27500:160:80:0:0 -Cartoon Network France & Spain:12168:v:0:27500:161:84:0:0 -TVBS Europe:12168:v:0:27500:162:88:0:0 -TVBS Europe:12168:v:0:27500:162:89:0:0 -Travel:12168:v:0:27500:163:92:0:0 -TCM Espania:12168:v:0:27500:164:96:0:0 -MTV Spain:12168:v:0:27500:167:112:0:0 -TCM France:12168:v:0:27500:169:64:0:0 -RTL2 CH:12188:h:0:27500:164:112:0:0 -La Cinquieme:12207:v:0:27500:160:80:0:0 -ARTE:12207:v:0:27500:165:100:0:0 -Post Filial TV:12226:h:0:27500:255:256:0:0 -Canal Canaris:12246:v:0:27500:160:80:0:0 -Canal Canaris:12246:v:0:27500:160:81:0:0 -Canal Canaris:12246:v:0:27500:160:82:0:0 -Canal Canaris:12246:v:0:27500:160:83:0:0 -AB Sat Passion promo:12266:h:0:27500:160:80:0:0 -AB Channel 1:12266:h:0:27500:161:84:0:0 -Taquilla 0:12285:v:0:27500:165:100:0:0 -CSAT:12324:v:0:27500:160:80:0:0 -Mosaique:12324:v:0:27500:162:88:0:0 -Mosaique 2:12324:v:0:27500:163:92:0:0 -Mosaique 3:12324:v:0:27500:164:96:0:0 -Le Sesame C+:12324:v:0:27500:165:1965:0:0 -FEED:12344:h:0:27500:163:92:0:0 -RTM 1:12363:v:0:27500:162:96:0:0 -ESC 1:12363:v:0:27500:163:104:0:0 -TV5 Europe:12363:v:0:27500:164:112:0:0 -TV7 Tunisia:12363:v:0:27500:166:128:0:0 -ARTE:12363:v:0:27500:167:137:0:0 -RAI Uno:12363:v:0:27500:289:290:0:8904 -RTP International:12363:v:0:27500:300:301:0:0 -Fashion TV:12402:v:0:27500:163:92:0:0 -VideoService:12422:h:0:27500:255:256:0:0 -Beta Research promo:12422:h:0:27500:1023:1024:0:0 -Canal Canarias:12441:v:0:27500:160:80:0:0 -TVC International:12441:v:0:27500:512:660:0:0 -Fitur:12441:v:0:27500:514:662:0:0 -Astra Info 1:12552:v:0:22000:164:112:0:0 -Astra Info 2:12552:v:0:22000:165:120:0:0 -Astra Vision 1:12552:v:0:22000:168:144:0:0 -Astra Vision 1:12552:v:0:22000:168:145:0:0 -Astra Vision 1:12552:v:0:22000:168:146:0:0 -Astra Vision 1:12552:v:0:22000:168:147:0:0 -Astra Vision 1:12552:v:0:22000:168:148:0:0 -Astra Vision 1:12552:v:0:22000:168:149:0:0 -Astra Vision 1:12552:v:0:22000:168:150:0:0 -RTL Tele Letzebuerg:12552:v:0:22000:168:144:0:0 -Astra Mosaic:12552:v:0:22000:175:176:0:0 -MHP test:12604:h:0:22000:5632:8191:0:0 -VERONICA:12574:h:0:22000:161:84:0:5010 -VH1 Classic:12699:v:0:22000:3071:3072:0:28647 -VH-1 Germany:12699:v:0:22000:3081:3082:0:28648 -Via 1 - Schner Reisen:12148:h:0:27500:511:512:0:44 -Video Italia:12610:v:0:22000:121:122:0:12220 -AC 3 promo:12670:v:0:22000:308:256:0:0 -ORF/ZDF:12699:h:0:22000:506:507:0:13012 -VIVA:12670:v:0:22000:309:310:0:12732 +TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601 +Mosaico:11934:v:0:27500:165:100:0:0:29010 +Andalucia TV:11934:v:0:27500:166:104:0:0:29011 +TVC Internacional:11934:v:0:27500:167:108:0:0:0 +Nasza TV:11992:h:0:27500:165:98:0:0:0 +WishLine test:12012:v:0:27500:163:90:0:0:0 +Pro 7 Austria:12051:v:0:27500:161:84:0:0:0 +Kabel 1 Schweiz:12051:v:0:27500:162:163:0:0:0 +Kabel 1 Austria:12051:v:0:27500:166:167:0:0:0 +Pro 7 Schweiz:12051:v:0:27500:289:290:0:0:0 +Kiosque:12129:v:0:27500:160:80:0:0:0 +KTO:12129:v:0:27500:170:120:0:0:0 +TCM:12168:v:0:27500:160:80:0:0:0 +Cartoon Network France & Spain:12168:v:0:27500:161:84:0:0:0 +TVBS Europe:12168:v:0:27500:162:88:0:0:0 +TVBS Europe:12168:v:0:27500:162:89:0:0:0 +Travel:12168:v:0:27500:163:92:0:0:0 +TCM Espania:12168:v:0:27500:164:96:0:0:0 +MTV Spain:12168:v:0:27500:167:112:0:0:0 +TCM France:12168:v:0:27500:169:64:0:0:0 +RTL2 CH:12188:h:0:27500:164:112:0:0:0 +La Cinquieme:12207:v:0:27500:160:80:0:0:0 +ARTE:12207:v:0:27500:165:100:0:0:0 +Post Filial TV:12226:h:0:27500:255:256:0:0:0 +Canal Canaris:12246:v:0:27500:160:80:0:0:0 +Canal Canaris:12246:v:0:27500:160:81:0:0:0 +Canal Canaris:12246:v:0:27500:160:82:0:0:0 +Canal Canaris:12246:v:0:27500:160:83:0:0:0 +AB Sat Passion promo:12266:h:0:27500:160:80:0:0:0 +AB Channel 1:12266:h:0:27500:161:84:0:0:0 +Taquilla 0:12285:v:0:27500:165:100:0:0:0 +CSAT:12324:v:0:27500:160:80:0:0:0 +Mosaique:12324:v:0:27500:162:88:0:0:0 +Mosaique 2:12324:v:0:27500:163:92:0:0:0 +Mosaique 3:12324:v:0:27500:164:96:0:0:0 +Le Sesame C+:12324:v:0:27500:165:1965:0:0:0 +FEED:12344:h:0:27500:163:92:0:0:0 +RTM 1:12363:v:0:27500:162:96:0:0:0 +ESC 1:12363:v:0:27500:163:104:0:0:0 +TV5 Europe:12363:v:0:27500:164:112:0:0:0 +TV7 Tunisia:12363:v:0:27500:166:128:0:0:0 +ARTE:12363:v:0:27500:167:137:0:0:0 +RAI Uno:12363:v:0:27500:289:290:0:0:8904 +RTP International:12363:v:0:27500:300:301:0:0:0 +Fashion TV:12402:v:0:27500:163:92:0:0:0 +VideoService:12422:h:0:27500:255:256:0:0:0 +Beta Research promo:12422:h:0:27500:1023:1024:0:0:0 +Canal Canarias:12441:v:0:27500:160:80:0:0:0 +TVC International:12441:v:0:27500:512:660:0:0:0 +Fitur:12441:v:0:27500:514:662:0:0:0 +Astra Info 1:12552:v:0:22000:164:112:0:0:0 +Astra Info 2:12552:v:0:22000:165:120:0:0:0 +Astra Vision 1:12552:v:0:22000:168:144:0:0:0 +Astra Vision 1:12552:v:0:22000:168:145:0:0:0 +Astra Vision 1:12552:v:0:22000:168:146:0:0:0 +Astra Vision 1:12552:v:0:22000:168:147:0:0:0 +Astra Vision 1:12552:v:0:22000:168:148:0:0:0 +Astra Vision 1:12552:v:0:22000:168:149:0:0:0 +Astra Vision 1:12552:v:0:22000:168:150:0:0:0 +RTL Tele Letzebuerg:12552:v:0:22000:168:144:0:0:0 +Astra Mosaic:12552:v:0:22000:175:176:0:0:0 +MHP test:12604:h:0:22000:5632:8191:0:0:0 +VERONICA:12574:h:0:22000:161:84:0:0:5010 +VH1 Classic:12699:v:0:22000:3071:3072:0:0:28647 +VH-1 Germany:12699:v:0:22000:3081:3082:0:0:28648 +Via 1 - Schner Reisen:12148:h:0:27500:511:512:0:0:44 +Video Italia:12610:v:0:22000:121:122:0:0:12220 +AC 3 promo:12670:v:0:22000:308:256:0:0:0 +ORF/ZDF:12699:h:0:22000:506:507:0:0:13012 +VIVA:12670:v:0:22000:309:310:0:0:12732 diff --git a/channels.conf.cable b/channels.conf.cable new file mode 100644 index 000000000..93fc3761d --- /dev/null +++ b/channels.conf.cable @@ -0,0 +1,134 @@ +Leitseite:346:h:0:6900:2254:0:0:5004 +Extreme Sport:346:h:0:6900:801:802:0:0 +Bloomberg:346:h:0:6900:811:812:0:0 +Fashion TV:346:h:0:6900:821:822:0:0 +LANDSCAPE:346:h:0:6900:831:832:0:0 +BET ON JAZZ:346:h:0:6900:841:842:0:0 +Via 1 - Schner Reisen:346:h:0:6900:611:612:0:50705 +Single TV:346:h:0:6900:621:622:0:0 +HomeNet:346:h:0:6900:0:0:0:0 +Einstein:346:h:0:6900:623:624:0:0 +BLUE CHANNEL:354:h:0:6900:2559:2560:0:0 +GOLDSTAR TV:354:h:0:6900:3839:3840:1:0 +HEIMATKANAL:354:h:0:6900:2815:2816:1:0 +100,6:354:h:0:6900:0:1312:0:0 +SPORT 1:362:h:0:6900:255:256:1:0 +LOVE SONGS:362:h:0:6900:0:320:1:0 +MUSICALS:362:h:0:6900:0:336:1:0 +EASY LISTENING:362:h:0:6900:0:304:1:0 +HITLISTE:362:h:0:6900:0:784:1:0 +ALTERNATIVE ROCK:362:h:0:6900:0:800:1:0 +DANCE:362:h:0:6900:0:816:1:0 +COUNTRY:362:h:0:6900:0:352:1:0 +CLASSIC ROCK:362:h:0:6900:0:544:1:0 +FILMMUSIK:362:h:0:6900:3552:368:1:0 +DEUTSCHE HITS:362:h:0:6900:3552:384:1:0 +SOUL CLASSICS:362:h:0:6900:3439:400:1:0 +TRK MZIGI:362:h:0:6900:0:560:1:0 +GOLD:362:h:0:6900:0:576:1:0 +KLASSIK POPULR:362:h:0:6900:3552:592:1:0 +KLASS. SYMPHONIEN:362:h:0:6900:0:608:1:0 +OPER & VOKALMUSIK:362:h:0:6900:0:624:1:0 +BAROCKMUSIK:362:h:0:6900:0:640:1:0 +JAZZ:362:h:0:6900:0:656:1:0 +Videotext:362:h:0:6900:0:0:0:0 +PREMIERE WORLD:370:h:0:6900:255:256:0:10 +PREMIERE:370:h:0:6900:511:0:1:0 +STAR KINO:370:h:0:6900:767:768:1:0 +CINE ACTION:370:h:0:6900:1023:1024:1:0 +CINE COMEDY:370:h:0:6900:1279:1280:1:0 +SCI-FANTASY:370:h:0:6900:1535:1536:1:0 +ROMANTIC MOVIES:370:h:0:6900:1791:1792:1:0 +STUDIO UNIVERSAL:370:h:0:6900:2047:2048:1:0 +13 TH STREET:370:h:0:6900:2303:2304:1:0 +FOX KIDS:370:h:0:6900:2559:2560:1:0 +DISNEY CHANNEL:378:h:0:6900:767:768:1:0 +SUNSET:378:h:0:6900:1023:1024:1:0 +COMEDY:378:h:0:6900:1279:1280:1:0 +KRIMI &CO:378:h:0:6900:1535:1536:1:0 +DISCOVERY CHANNEL:378:h:0:6900:1791:1792:1:0 +PLANET:378:h:0:6900:2047:2048:1:0 +SUPERDOM:378:h:0:6900:2303:2304:1:0 +VCR-Setup:378:h:0:6900:0:0:0:0 +Modem-Setup:378:h:0:6900:0:0:0:0 +SCHLAGER:378:h:0:6900:0:320:1:0 +VOLKSMUSIK:378:h:0:6900:0:336:1:0 +OLD GOLD:378:h:0:6900:0:304:1:0 +TM V1.0:378:h:0:6900:0:0:1:0 +JUNIOR:378:h:0:6900:255:256:1:0 +KICK 1:386:h:0:6900:255:256:1:0 +KICK 2:386:h:0:6900:2559:2560:1:0 +ZDF.digitext:394:h:0:6900:0:0:0:0 +ZDF:394:h:0:6900:110:120:0:28006 +DLR-Berlin:394:h:0:6900:0:710:0:0 +DLF-Kln:394:h:0:6900:0:810:0:0 +3sat:394:h:0:6900:210:0:0:28007 +KiKa:394:h:0:6900:0:0:0:28008 +Eurosport:394:h:0:6900:410:0:0:28009 +ZDF.info:394:h:0:6900:610:620:0:28011 +EuroNews:394:h:0:6900:2221:2233:0:28015 +ZDF Theaterkanal:394:h:0:6900:1110:0:0:0 +ZDF.doku:394:h:0:6900:660:670:0:28014 +SEASONS:402:h:0:6900:1040:1044:1:0 +CLASSICA:402:h:0:6900:1030:1034:1:0 +FILMPALAST:402:h:0:6900:1050:1054:1:0 +Blockmaster:402:h:0:6900:0:0:1:0 +Test-R:410:h:0:6900:901:0:0:0 +Bayerisches FS:410:h:0:6900:201:202:0:0 +Bayern 4 Klassik:410:h:0:6900:0:3001:0:0 +B5 aktuell:410:h:0:6900:0:3101:0:0 +WDR FERNSEHEN:410:h:0:6900:601:602:0:28111 +Bremen 2:410:h:0:6900:0:3801:0:0 +arte:410:h:0:6900:401:402:0:28109 +Bayern 1:410:h:0:6900:0:3601:0:0 +NDR 4 Info:410:h:0:6900:0:3701:0:0 +SR Fernsehen Suedwest:410:h:0:6900:501:502:0:28110 +SR 1:410:h:0:6900:0:3901:0:0 +Das Erste:410:h:0:6900:101:102:0:28106 +HR2 plus:410:h:0:6900:0:3401:0:0 +HR2:410:h:0:6900:0:3301:0:0 +hessen fernsehen:410:h:0:6900:301:302:0:28108 +hr-chronos:410:h:0:6900:0:3201:0:0 +HR XXL:410:h:0:6900:0:3501:0:0 +hessen:10160:h:1:6900:301:302:0:28108 +BR:10160:h:1:6900:201:202:0:28107 +BR-alpha:410:h:0:6900:701:702:0:28112 +SWR Fernsehen:410:h:0:6900:801:802:0:28113 +Phoenix:410:h:0:6900:901:902:0:0 +ARD-Online-Kanal:426:h:0:6900:0:1805:0:0 +EinsExtra:426:h:0:6900:101:102:0:28201 +EinsFestival:426:h:0:6900:201:202:0:28202 +EinsMuXx:426:h:0:6900:301:302:0:28203 +MDR FERNSEHEN:426:h:0:6900:401:402:0:28204 +ORB-Fernsehen:426:h:0:6900:501:502:0:28205 +B1 Berlin:426:h:0:6900:601:602:0:28206 +Radio 3:426:h:0:6900:0:701:0:0 +MDR KULTUR:426:h:0:6900:0:801:0:0 +Fritz:426:h:0:6900:0:901:0:0 +JUMP:426:h:0:6900:0:1001:0:0 +MDR info:426:h:0:6900:0:1101:0:0 +SPUTNIK:426:h:0:6900:0:1201:0:0 +SFB4 Multikulti:426:h:0:6900:0:1301:0:0 +SWR-2:426:h:0:6900:0:1401:0:0 +WDR3:426:h:0:6900:0:1501:0:0 +WDR 5:426:h:0:6900:0:1601:0:0 +N3:426:h:0:6900:2401:2402:0:0 +ORF:394:h:1:6900:506:507:0:28010 +TV Polonia:434:h:0:6900:641:642:0:0 +Kanal D:434:h:0:6900:651:652:0:0 +RTP international:434:h:0:6900:661:662:0:0 +ATV:434:h:0:6900:631:632:0:0 +ERT-Sat:434:h:0:6900:691:692:0:0 +MV-Test:442:h:0:6900:0:0:0:0 +ZEE TV:442:h:0:6900:517:773:0:0 +NTV i:442:h:0:6900:514:515:0:0 +All Jazz:442:h:0:6900:0:535:0:0 +Cristal New Age:442:h:0:6900:0:536:0:0 +Movie Sounds:442:h:0:6900:0:537:0:0 +Sinfonica:442:h:0:6900:0:538:0:0 +Opernfestival:442:h:0:6900:0:539:0:0 +Barock Fantasie:442:h:0:6900:0:540:0:0 +Musica Camerata:442:h:0:6900:0:541:0:0 +Musica Antica:442:h:0:6900:0:542:0:0 +Adagio:442:h:0:6900:0:543:0:0 +Jazz Legends:442:h:0:6900:0:544:0:0 diff --git a/config.c b/config.c index 5838c68c0..66eb1780e 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.39 2001/01/14 15:29:15 kls Exp $ + * $Id: config.c 1.43 2001/02/24 13:20:18 kls Exp $ */ #include "config.h" @@ -199,6 +199,7 @@ cChannel::cChannel(const cChannel *Channel) srate = Channel ? Channel->srate : 27500; vpid = Channel ? Channel->vpid : 255; apid = Channel ? Channel->apid : 256; + tpid = Channel ? Channel->tpid : 32; ca = Channel ? Channel->ca : 0; pnr = Channel ? Channel->pnr : 0; groupSep = Channel ? Channel->groupSep : false; @@ -216,7 +217,7 @@ const char *cChannel::ToText(cChannel *Channel) if (Channel->groupSep) asprintf(&buffer, ":%s\n", s); else - asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->ca, Channel->pnr); + asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->tpid, Channel->ca, Channel->pnr); return buffer; } @@ -239,8 +240,15 @@ bool cChannel::Parse(const char *s) } else { groupSep = false; - int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &ca, &pnr); - if (fields == 9) { + //XXX + int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &tpid, &ca, &pnr); + if (fields >= 9) { + if (fields == 9) { + // allow reading of old format + pnr = ca; + ca = tpid; + tpid = 0; + } strn0cpy(name, buffer, MaxChannelName); delete buffer; } @@ -265,7 +273,7 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log) isyslog(LOG_INFO, "switching to channel %d", number); } for (int i = 3; i--;) { - if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) + if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid, tpid, ca, pnr)) return true; esyslog(LOG_ERR, "retrying"); } @@ -360,7 +368,11 @@ cTimer& cTimer::operator= (const cTimer &Timer) const char *cTimer::ToText(cTimer *Timer) { delete buffer; + strreplace(Timer->file, ':', '|'); + strreplace(Timer->summary, '\n', '|'); asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); + strreplace(Timer->summary, '|', '\n'); + strreplace(Timer->file, '|', ':'); return buffer; } @@ -449,6 +461,8 @@ bool cTimer::Parse(const char *s) //TODO add more plausibility checks day = ParseDay(buffer1); strn0cpy(file, buffer2, MaxFileName); + strreplace(file, '|', ':'); + strreplace(summary, '|', '\n'); delete buffer1; delete buffer2; delete s2; @@ -724,6 +738,8 @@ cSetup::cSetup(void) MarginStart = 2; MarginStop = 10; EPGScanTimeout = 5; + SVDRPTimeout = 300; + PrimaryLimit = 0; CurrentChannel = -1; } @@ -744,6 +760,8 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); + else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); + else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else return false; @@ -797,6 +815,8 @@ bool cSetup::Save(const char *FileName) fprintf(f, "MarginStart = %d\n", MarginStart); fprintf(f, "MarginStop = %d\n", MarginStop); fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout); + fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout); + fprintf(f, "PrimaryLimit = %d\n", PrimaryLimit); fprintf(f, "CurrentChannel = %d\n", CurrentChannel); f.Close(); isyslog(LOG_INFO, "saved setup to %s", FileName); diff --git a/config.h b/config.h index 277e957e2..60a95c3af 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.38 2001/01/14 15:29:27 kls Exp $ + * $Id: config.h 1.42 2001/02/24 13:19:39 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.70" +#define VDRVERSION "0.71" #define MaxBuffer 10000 @@ -93,6 +93,7 @@ class cChannel : public cListObject { int srate; int vpid; int apid; + int tpid; int ca; int pnr; int number; // Sequence number assigned on load @@ -268,6 +269,8 @@ class cSetup { int SetSystemTime; int MarginStart, MarginStop; int EPGScanTimeout; + int SVDRPTimeout; + int PrimaryLimit; int CurrentChannel; cSetup(void); bool Load(const char *FileName); diff --git a/dvbapi.c b/dvbapi.c index e583baf94..8518d7f99 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.50 2001/01/18 19:53:54 kls Exp $ + * $Id: dvbapi.c 1.61 2001/02/24 13:13:19 kls Exp $ */ #include "dvbapi.h" @@ -67,7 +67,6 @@ extern "C" { #define DISKCHECKINTERVAL 100 // seconds #define INDEXFILESUFFIX "/index.vdr" -#define RESUMEFILESUFFIX "/resume.vdr" #define RECORDFILESUFFIX "/%03d.vdr" #define RECORDFILESUFFIXLEN 20 // some additional bytes for safety... @@ -105,56 +104,6 @@ int HMSFToIndex(const char *HMSF) return 0; } -// --- cResumeFile ------------------------------------------------------------ - -cResumeFile::cResumeFile(const char *FileName) -{ - fileName = new char[strlen(FileName) + strlen(RESUMEFILESUFFIX) + 1]; - if (fileName) { - strcpy(fileName, FileName); - strcat(fileName, RESUMEFILESUFFIX); - } - else - esyslog(LOG_ERR, "ERROR: can't allocate memory for resume file name"); -} - -cResumeFile::~cResumeFile() -{ - delete fileName; -} - -int cResumeFile::Read(void) -{ - int resume = -1; - if (fileName) { - int f = open(fileName, O_RDONLY); - if (f >= 0) { - if (read(f, &resume, sizeof(resume)) != sizeof(resume)) { - resume = -1; - LOG_ERROR_STR(fileName); - } - close(f); - } - else if (errno != ENOENT) - LOG_ERROR_STR(fileName); - } - return resume; -} - -bool cResumeFile::Save(int Index) -{ - if (fileName) { - int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); - if (f >= 0) { - if (write(f, &Index, sizeof(Index)) != sizeof(Index)) - LOG_ERROR_STR(fileName); - close(f); - return true; - } - } - return false; -} - // --- cIndexFile ------------------------------------------------------------ class cIndexFile { @@ -821,7 +770,9 @@ int cRecordBuffer::ScanVideoPacket(int *PictureType, int Offset) int Length = GetPacketLength(Offset); if (Length <= Available()) { - for (int i = Offset; i < Offset + Length; i++) { + int i = Offset + 8; // the minimum length of the video packet header + i += Byte(i) + 1; // possible additional header bytes + for (; i < Offset + Length; i++) { if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { switch (Byte(i + 3)) { case SC_PICTURE: *PictureType = GetPictureType(i); @@ -840,8 +791,6 @@ int cRecordBuffer::Synchronize(void) // Positions to the start of a data block (skipping everything up to // an I-frame if not synced) and returns the block length. - int LastPackHeader = -1; - pictureType = NO_PICTURE; //XXX remove this once the buffer is handled with two separate threads: @@ -853,8 +802,6 @@ int cRecordBuffer::Synchronize(void) for (int i = 0; Available() > MINVIDEODATA && i < MINVIDEODATA; i++) { if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { switch (Byte(i + 3)) { - case SC_PHEAD: LastPackHeader = i; - break; case SC_VIDEO: { int pt = NO_PICTURE; int l = ScanVideoPacket(&pt, i); @@ -862,21 +809,15 @@ int cRecordBuffer::Synchronize(void) return 0; // no useful data found, wait for more if (pt != NO_PICTURE) { if (pt < I_FRAME || B_FRAME < pt) { - esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); - } + esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); + } else if (pictureType == NO_PICTURE) { if (!synced) { - if (LastPackHeader == 0) { - if (pt == I_FRAME) - synced = true; - } - else if (LastPackHeader > 0) { - Skip(LastPackHeader); - LastPackHeader = -1; - i = 0; - break; + if (pt == I_FRAME) { + Skip(i); + synced = true; } - else { // LastPackHeader < 0 + else { Skip(i + l); i = 0; break; @@ -885,13 +826,15 @@ int cRecordBuffer::Synchronize(void) if (synced) pictureType = pt; } - else if (LastPackHeader > 0) - return LastPackHeader; else return i; } + else if (!synced) { + Skip(i + l); + i = 0; + break; + } i += l - 1; // -1 to compensate for i++ in the loop! - LastPackHeader = -1; } break; case SC_AUDIO: i += GetPacketLength(i) - 1; // -1 to compensate for i++ in the loop! @@ -1576,6 +1519,7 @@ bool cVideoCutter::Active(void) // --- cDvbApi --------------------------------------------------------------- int cDvbApi::NumDvbApis = 0; +int cDvbApi::useDvbApi = 0; cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL }; cDvbApi *cDvbApi::PrimaryDvbApi = NULL; @@ -1645,6 +1589,12 @@ cDvbApi::~cDvbApi() #endif } +void cDvbApi::SetUseDvbApi(int n) +{ + if (n < MAXDVBAPI) + useDvbApi |= (1 << n); +} + bool cDvbApi::SetPrimaryDvbApi(int n) { n--; @@ -1659,7 +1609,7 @@ bool cDvbApi::SetPrimaryDvbApi(int n) cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) { - cDvbApi *d = NULL; + cDvbApi *d = NULL, *dMinPriority = NULL; int index = Ca - 1; for (int i = MAXDVBAPI; --i >= 0; ) { if (dvbApi[i]) { @@ -1669,13 +1619,25 @@ cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) } else if (Ca == 0) { // means any device would be acceptable if (!d || !dvbApi[i]->Recording() || (d->Recording() && d->Priority() > dvbApi[i]->Priority())) - d = dvbApi[i]; + d = dvbApi[i]; // this is one that is either not currently recording or has the lowest priority if (d && d != PrimaryDvbApi && !d->Recording()) // avoids the PrimaryDvbApi if possible break; + if (d && d->Recording() && d->Priority() < Setup.PrimaryLimit && (!dMinPriority || d->Priority() < dMinPriority->Priority())) + dMinPriority = d; // this is the one with the lowest priority below Setup.PrimaryLimit } } } - return (d && (!d->Recording() || d->Priority() < Priority || (!d->Ca() && Ca))) ? d : NULL; + if (d == PrimaryDvbApi) { // the PrimaryDvbApi was the only one that was free + if (Priority < Setup.PrimaryLimit) + return NULL; // not enough priority to use the PrimaryDvbApi + if (dMinPriority) // there's one that must not use the PrimaryDvbApi... + d = dMinPriority; // ...so let's kick out that one + } + return (d // we found one... + && (!d->Recording() // ...that's either not currently recording... + || d->Priority() < Priority // ...or has a lower priority... + || (!d->Ca() && Ca))) // ...or doesn't need this card + ? d : NULL; } int cDvbApi::Index(void) @@ -1691,33 +1653,34 @@ bool cDvbApi::Init(void) { NumDvbApis = 0; for (int i = 0; i < MAXDVBAPI; i++) { - char fileName[strlen(VIDEODEVICE) + 10]; - sprintf(fileName, "%s%d", VIDEODEVICE, i); - if (access(fileName, F_OK | R_OK | W_OK) == 0) { - dsyslog(LOG_INFO, "probing %s", fileName); - int f = open(fileName, O_RDWR); - if (f >= 0) { - struct video_capability cap; - int r = ioctl(f, VIDIOCGCAP, &cap); - close(f); - if (r == 0 && (cap.type & VID_TYPE_DVB)) { - char vbiFileName[strlen(VBIDEVICE) + 10]; - sprintf(vbiFileName, "%s%d", VBIDEVICE, i); - dvbApi[i] = new cDvbApi(fileName, vbiFileName); - NumDvbApis++; + if (useDvbApi == 0 || (useDvbApi & (1 << i)) != 0) { + char fileName[strlen(VIDEODEVICE) + 10]; + sprintf(fileName, "%s%d", VIDEODEVICE, i); + if (access(fileName, F_OK | R_OK | W_OK) == 0) { + dsyslog(LOG_INFO, "probing %s", fileName); + int f = open(fileName, O_RDWR); + if (f >= 0) { + struct video_capability cap; + int r = ioctl(f, VIDIOCGCAP, &cap); + close(f); + if (r == 0 && (cap.type & VID_TYPE_DVB)) { + char vbiFileName[strlen(VBIDEVICE) + 10]; + sprintf(vbiFileName, "%s%d", VBIDEVICE, i); + dvbApi[NumDvbApis++] = new cDvbApi(fileName, vbiFileName); + } + } + else { + if (errno != ENODEV) + LOG_ERROR_STR(fileName); + break; } } else { - if (errno != ENODEV) + if (errno != ENOENT) LOG_ERROR_STR(fileName); break; } } - else { - if (errno != ENOENT) - LOG_ERROR_STR(fileName); - break; - } } PrimaryDvbApi = dvbApi[0]; if (NumDvbApis > 0) { @@ -2168,7 +2131,7 @@ void cDvbApi::Flush(void) #endif } -bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr) +bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr) { if (videoDev >= 0) { cThreadLock ThreadLock(siProcessor); // makes sure the siProcessor won't access the vbi-device while switching @@ -2177,20 +2140,29 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, struct frontend front; ioctl(videoDev, VIDIOCGFRONTEND, &front); unsigned int freq = FrequencyMHz; - front.ttk = (freq < 11700UL) ? 0 : 1; - if (freq < 11700UL) - freq -= Setup.LnbFrequLo; - else - freq -= Setup.LnbFrequHi; - front.pnr = 0; + if (front.type == FRONT_DVBS) { + front.ttk = (freq < 11700UL) ? 0 : 1; + if (freq < 11700UL) { + freq -= Setup.LnbFrequLo; + front.ttk = 0; + } + else { + freq -= Setup.LnbFrequHi; + front.ttk = 1; + } + } + front.channel_flags = Ca ? DVB_CHANNEL_CA : DVB_CHANNEL_FTA; + front.pnr = Pnr; front.freq = freq * 1000000UL; front.diseqc = Diseqc; front.srate = Srate * 1000; front.volt = (Polarization == 'v' || Polarization == 'V') ? 0 : 1; front.video_pid = Vpid; front.audio_pid = Apid; + front.tt_pid = Tpid; front.fec = 8; front.AFC = 1; + front.qam = 2; ioctl(videoDev, VIDIOCSFRONTEND, &front); if (front.sync & 0x1F == 0x1F) { if (this == PrimaryDvbApi && siProcessor) @@ -2198,11 +2170,11 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, currentChannel = ChannelNumber; // If this DVB card can't receive this channel, let's see if we can // use the card that actually can receive it and transfer data from there: - if (Ca && Ca != Index() + 1) { + if (this == PrimaryDvbApi && Ca && Ca != Index() + 1) { cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); if (CaDvbApi) { if (!CaDvbApi->Recording()) { - if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Ca, Pnr)) + if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Tpid, Ca, Pnr)) transferringFromDvbApi = CaDvbApi->StartTransfer(videoDev); } } @@ -2403,7 +2375,25 @@ cEITScanner::cEITScanner(void) { lastScan = lastActivity = time(NULL); currentChannel = 0; - lastChannel = 1; + lastChannel = 0; + numTransponders = 0; + transponders = NULL; +} + +cEITScanner::~cEITScanner() +{ + delete transponders; +} + +bool cEITScanner::TransponderScanned(cChannel *Channel) +{ + for (int i = 0; i < numTransponders; i++) { + if (transponders[i] == Channel->frequency) + return true; + } + transponders = (int *)realloc(transponders, ++numTransponders * sizeof(int)); + transponders[numTransponders - 1] = Channel->frequency; + return false; } void cEITScanner::Activity(void) @@ -2417,7 +2407,7 @@ void cEITScanner::Activity(void) void cEITScanner::Process(void) { - if (Channels.MaxNumber() > 1) { + if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) { time_t now = time(NULL); if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) { for (int i = 0; i < cDvbApi::NumDvbApis; i++) { @@ -2428,10 +2418,12 @@ void cEITScanner::Process(void) int oldCh = lastChannel; int ch = oldCh + 1; while (ch != oldCh) { - if (ch > Channels.MaxNumber()) + if (ch > Channels.MaxNumber()) { ch = 1; + numTransponders = 0; + } cChannel *Channel = Channels.GetByNumber(ch); - if (Channel && Channel->pnr) { + if (Channel && Channel->pnr && !TransponderScanned(Channel)) { if (DvbApi == cDvbApi::PrimaryDvbApi && !currentChannel) currentChannel = DvbApi->Channel(); Channel->Switch(DvbApi, false); diff --git a/dvbapi.h b/dvbapi.h index cf0584f80..de646121e 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.30 2001/01/07 15:56:10 kls Exp $ + * $Id: dvbapi.h 1.35 2001/02/11 10:41:10 kls Exp $ */ #ifndef __DVBAPI_H @@ -33,21 +33,13 @@ typedef struct CRect { #define MenuLines 15 #define MenuColumns 40 -class cResumeFile { -private: - char *fileName; -public: - cResumeFile(const char *FileName); - ~cResumeFile(); - int Read(void); - bool Save(int Index); - }; - const char *IndexToHMSF(int Index, bool WithFrame = false); // Converts the given index to a string, optionally containing the frame number. int HMSFToIndex(const char *HMSF); // Converts the given string (format: "hh:mm:ss.ff") to an index. +class cChannel; + class cRecordBuffer; class cReplayBuffer; class cTransferBuffer; @@ -69,12 +61,17 @@ class cDvbApi { public: ~cDvbApi(); -#define MAXDVBAPI 2 +#define MAXDVBAPI 4 static int NumDvbApis; private: static cDvbApi *dvbApi[MAXDVBAPI]; + static int useDvbApi; public: static cDvbApi *PrimaryDvbApi; + static void SetUseDvbApi(int n); + // Sets the 'useDvbApi' flag of the given DVB device. + // If this function is not called before Init(), all DVB devices + // will be used. static bool SetPrimaryDvbApi(int n); // Sets the primary DVB device to 'n' (which must be in the range // 1...NumDvbApis) and returns true if this was possible. @@ -162,7 +159,7 @@ class cDvbApi { private: int currentChannel; public: - bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr); + bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr); static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } int Channel(void) { return currentChannel; } @@ -251,8 +248,11 @@ class cEITScanner { }; time_t lastScan, lastActivity; int currentChannel, lastChannel; + int numTransponders, *transponders; + bool TransponderScanned(cChannel *Channel); public: cEITScanner(void); + ~cEITScanner(); bool Active(void) { return currentChannel; } void Activity(void); void Process(void); diff --git a/eit.c b/eit.c index e7c60c164..08588b06b 100644 --- a/eit.c +++ b/eit.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.11 2000/12/03 15:33:37 kls Exp $ + * $Id: eit.c 1.12 2001/02/24 12:12:58 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -851,7 +851,8 @@ int cEIT::ProcessEIT() break; case EIT_COMPONENT_DESCRIPTOR : - strdvbcpy(tmp, &buffer[bufact + 8], buffer[bufact + 1] - 6); + if (buffer[bufact + 1] > 6) // kls 2001-02-24: otherwise strncpy() causes a segfault in strdvbcpy() + strdvbcpy(tmp, &buffer[bufact + 8], buffer[bufact + 1] - 6); //dsyslog(LOG_INFO, "Found EIT_COMPONENT_DESCRIPTOR %c%c%c 0x%02x/0x%02x/0x%02x '%s'\n", buffer[bufact + 5], buffer[bufact + 6], buffer[bufact + 7], buffer[2], buffer[3], buffer[4], tmp); break; @@ -910,6 +911,14 @@ int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) { int a = 0; + // kls 2001-02-24: if we come in with negative values, the caller must + // have done something wrong and the strncpy() below will cause a segfault + if (max <= 0) + { + *dst = 0; + return 0; + } + if (*src == 0x05 || (*src >= 0x20 && *src <= 0xff)) { for (a = 0; a < max; a++) diff --git a/epg2html.pl b/epg2html.pl old mode 100644 new mode 100755 diff --git a/i18n.c b/i18n.c index cf1785f3a..f81a2029d 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.8 2001/01/06 16:17:39 kls Exp $ + * $Id: i18n.c 1.14 2001/02/24 13:57:14 kls Exp $ * * Slovenian translations provided by Miha Setina * Italian translations provided by Alberto Carraro @@ -161,6 +161,11 @@ const tPhrase Phrases[] = { "Predavajaj", "Riproduci", }, + { "Rewind", + "Anfang", + "Zacetek", + "Da inizio", + }, { "Resume", "Weiter", "Nadaljuj", @@ -253,6 +258,11 @@ const tPhrase Phrases[] = { "Apid", "Apid", }, + { "Tpid", + "Tpid", + "Tpid", + "Tpid", + }, { "CA", "CA", "CA", @@ -406,6 +416,16 @@ const tPhrase Phrases[] = { "Cas do EPG pregleda", "Timeout EPG", }, + { "SVDRPTimeout", + "SVDRP Timeout", + "", // TODO + "Timeout SVDRP", + }, + { "PrimaryLimit", + "Primr-Limit", + "", // TODO + "", // TODO + }, // The days of the week: { "MTWTFSS", "MDMDFSS", diff --git a/interface.c b/interface.c index ef8368ae9..55cdb0b9c 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.33 2000/12/09 11:04:10 kls Exp $ + * $Id: interface.c 1.35 2001/02/18 10:46:13 kls Exp $ */ #include "interface.h" @@ -26,8 +26,10 @@ cInterface::cInterface(int SVDRPport) rcIo = new cRcIoRCU("/dev/ttyS1"); #elif defined(REMOTE_LIRC) rcIo = new cRcIoLIRC("/dev/lircd"); -#else +#elif defined(REMOTE_KBD) rcIo = new cRcIoKBD; +#else + rcIo = new cRcIoBase; // acts as a dummy device #endif rcIo->SetCode(Keys.code, Keys.address); if (SVDRPport) @@ -68,8 +70,16 @@ unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release) eKeys cInterface::GetKey(bool Wait) { Flush(); - if (SVDRP) + if (SVDRP) { SVDRP->Process(); + if (!open) { + char *message = SVDRP->GetMessage(); + if (message) { + Info(message); + delete message; + } + } + } eKeys Key = keyFromWait; if (Key == kNone) { bool Repeat = false, Release = false; @@ -279,7 +289,7 @@ void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor) void cInterface::Info(const char *s) { Open(); - isyslog(LOG_INFO, s); + isyslog(LOG_INFO, "info: %s", s); Status(s, clrWhite, clrGreen); Wait(); Status(NULL); @@ -289,7 +299,7 @@ void cInterface::Info(const char *s) void cInterface::Error(const char *s) { Open(); - esyslog(LOG_ERR, s); + esyslog(LOG_ERR, "ERROR: %s", s); Status(s, clrWhite, clrRed); Wait(); Status(NULL); diff --git a/menu.c b/menu.c index 144233fc7..45be9eb93 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.58 2001/01/13 13:07:43 kls Exp $ + * $Id: menu.c 1.68 2001/02/24 14:53:40 kls Exp $ */ #include "menu.h" @@ -541,6 +541,7 @@ cMenuEditChannel::cMenuEditChannel(int Index) Add(new cMenuEditIntItem( tr("Srate"), &data.srate, 22000, 27500)); //TODO exact limits - toggle??? Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 10000)); //TODO exact limits??? Add(new cMenuEditIntItem( tr("Apid"), &data.apid, 0, 10000)); //TODO exact limits??? + Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 10000)); //TODO exact limits??? Add(new cMenuEditIntItem( tr("CA"), &data.ca, 0, cDvbApi::NumDvbApis)); Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0)); } @@ -924,6 +925,8 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key) strcpy(data.file, Channels.GetChannelNameByNumber(data.channel)); if (timer && memcmp(timer, &data, sizeof(data)) != 0) { *timer = data; + if (timer->active) + timer->active = 1; // allows external programs to mark active timers with values > 1 and recognize if the user has modified them Timers.Save(); isyslog(LOG_INFO, "timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); } @@ -1074,6 +1077,16 @@ eOSState cMenuTimers::Summary(void) eOSState cMenuTimers::ProcessKey(eKeys Key) { + // Must do these before calling cOsdMenu::ProcessKey() because cOsdMenu + // uses them to page up/down: + if (!HasSubMenu()) { + switch (Key) { + case kLeft: + case kRight: return Activate(Key == kRight); + default: break; + } + } + eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { @@ -1181,13 +1194,17 @@ class cMenuWhatsOn : public cOsdMenu { private: eOSState Record(void); eOSState Switch(void); + static int currentChannel; static const cEventInfo *scheduleEventInfo; public: - cMenuWhatsOn(const cSchedules *Schedules, bool Now); + cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr); + static int CurrentChannel(void) { return currentChannel; } + static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; } static const cEventInfo *ScheduleEventInfo(void); virtual eOSState ProcessKey(eKeys Key); }; +int cMenuWhatsOn::currentChannel = 0; const cEventInfo *cMenuWhatsOn::scheduleEventInfo = NULL; static int CompareEventChannel(const void *p1, const void *p2) @@ -1195,7 +1212,7 @@ static int CompareEventChannel(const void *p1, const void *p2) return (int)( (*(const cEventInfo **)p1)->GetChannelNumber() - (*(const cEventInfo **)p2)->GetChannelNumber()); } -cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now) +cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr) :cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), 4, 7, 6) { const cSchedule *Schedule = Schedules->First(); @@ -1219,8 +1236,9 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now) qsort(pArray, num, sizeof(cEventInfo *), CompareEventChannel); for (int a = 0; a < num; a++) - Add(new cMenuWhatsOnItem(pArray[a])); + Add(new cMenuWhatsOnItem(pArray[a]), pArray[a]->GetChannelNumber() == CurrentChannelNr); + currentChannel = CurrentChannelNr; delete pArray; SetHelp(tr("Record"), Now ? tr("Next") : tr("Now"), tr("Schedule"), tr("Switch")); } @@ -1271,12 +1289,16 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { case kRed: return Record(); - case kYellow: { + case kYellow: state = osBack; + // continue with kGreen + case kGreen: { cMenuWhatsOnItem *mi = (cMenuWhatsOnItem *)Get(Current()); - if (mi) + if (mi) { scheduleEventInfo = mi->eventInfo; + currentChannel = mi->eventInfo->GetChannelNumber(); + } } - return osBack; + break; case kBlue: return Switch(); case kOk: if (Count()) return AddSubMenu(new cMenuEvent(((cMenuWhatsOnItem *)Get(Current()))->eventInfo, true)); @@ -1314,7 +1336,6 @@ class cMenuSchedule : public cOsdMenu { eOSState Record(void); eOSState Switch(void); void PrepareSchedule(cChannel *Channel); - void PrepareWhatsOnNext(bool On); public: cMenuSchedule(void); virtual eOSState ProcessKey(eKeys Key); @@ -1327,6 +1348,7 @@ cMenuSchedule::cMenuSchedule(void) otherChannel = 0; cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel()); if (channel) { + cMenuWhatsOn::SetCurrentChannel(channel->number); schedules = cDvbApi::PrimaryDvbApi->Schedules(&threadLock); PrepareSchedule(channel); SetHelp(tr("Record"), tr("Now"), tr("Next")); @@ -1403,14 +1425,22 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { case kRed: return Record(); - case kGreen: if (!now && !next) { - now = true; - return AddSubMenu(new cMenuWhatsOn(schedules, true)); - } - now = !now; - next = !next; - return AddSubMenu(new cMenuWhatsOn(schedules, now)); - case kYellow: return AddSubMenu(new cMenuWhatsOn(schedules, false)); + case kGreen: { + if (!now && !next) { + int ChannelNr = 0; + if (Count()) { + cChannel *channel = Channels.GetByServiceID(((cMenuScheduleItem *)Get(Current()))->eventInfo->GetServiceID()); + if (channel) + ChannelNr = channel->number; + } + now = true; + return AddSubMenu(new cMenuWhatsOn(schedules, true, ChannelNr)); + } + now = !now; + next = !next; + return AddSubMenu(new cMenuWhatsOn(schedules, now, cMenuWhatsOn::CurrentChannel())); + } + case kYellow: return AddSubMenu(new cMenuWhatsOn(schedules, false, cMenuWhatsOn::CurrentChannel())); case kBlue: return Switch(); case kOk: if (Count()) return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo, otherChannel)); @@ -1469,7 +1499,7 @@ cMenuRecordings::cMenuRecordings(void) recording = Recordings.Next(recording); } } - SetHelp(tr("Play"), NULL, tr("Delete"), tr("Summary")); + SetHelp(tr("Play"), tr("Rewind"), tr("Delete"), tr("Summary")); Display(); } @@ -1483,6 +1513,18 @@ eOSState cMenuRecordings::Play(void) return osContinue; } +eOSState cMenuRecordings::Rewind(void) +{ + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri) { + cDvbApi::PrimaryDvbApi->StopReplay(); // must do this first to be able to rewind the currently replayed recording + cResumeFile ResumeFile(ri->recording->FileName()); + ResumeFile.Delete(); + return Play(); + } + return osContinue; +} + eOSState cMenuRecordings::Del(void) { cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); @@ -1523,6 +1565,7 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) switch (Key) { case kOk: case kRed: return Play(); + case kGreen: return Rewind(); case kYellow: return Del(); case kBlue: return Summary(); case kMenu: return osEnd; @@ -1567,6 +1610,8 @@ void cMenuSetup::Set(void) Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart)); Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop)); Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout)); + Add(new cMenuEditIntItem( tr("SVDRPTimeout"), &data.SVDRPTimeout)); + Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit)); } eOSState cMenuSetup::ProcessKey(eKeys Key) @@ -1614,6 +1659,7 @@ cMenuCommands::cMenuCommands(void) Add(new cOsdItem(command->Title())); i++; } + SetHasHotkeys(); } eOSState cMenuCommands::Execute(void) @@ -1644,18 +1690,25 @@ eOSState cMenuCommands::ProcessKey(eKeys Key) #define STOP_RECORDING tr("Stop recording ") +static const char *hk(int n, const char *s) +{ + static char buffer[32]; + snprintf(buffer, sizeof(buffer), " %d %s", n, s); + return buffer; +} + cMenuMain::cMenuMain(bool Replaying) :cOsdMenu(tr("Main")) { - Add(new cOsdItem(tr("Schedule"), osSchedule)); - Add(new cOsdItem(tr("Channels"), osChannels)); - Add(new cOsdItem(tr("Timers"), osTimers)); - Add(new cOsdItem(tr("Recordings"), osRecordings)); - Add(new cOsdItem(tr("Setup"), osSetup)); + Add(new cOsdItem(hk(1, tr("Schedule")), osSchedule)); + Add(new cOsdItem(hk(2, tr("Channels")), osChannels)); + Add(new cOsdItem(hk(3, tr("Timers")), osTimers)); + Add(new cOsdItem(hk(4, tr("Recordings")), osRecordings)); + Add(new cOsdItem(hk(5, tr("Setup")), osSetup)); if (Commands.Count()) - Add(new cOsdItem(tr("Commands"), osCommands)); + Add(new cOsdItem(hk(6, tr("Commands")), osCommands)); if (Replaying) - Add(new cOsdItem(tr("Stop replaying"), osStopReplay)); + Add(new cOsdItem(tr(" Stop replaying"), osStopReplay)); const char *s = NULL; while ((s = cRecordControls::GetInstantId(s)) != NULL) { char *buffer = NULL; @@ -1664,10 +1717,11 @@ cMenuMain::cMenuMain(bool Replaying) delete buffer; } if (cVideoCutter::Active()) - Add(new cOsdItem(tr("Cancel editing"), osCancelEdit)); + Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit)); SetHelp(tr("Record"), NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); Display(); lastActivity = time(NULL); + SetHasHotkeys(); } eOSState cMenuMain::ProcessKey(eKeys Key) @@ -1945,7 +1999,7 @@ bool cRecordControls::Start(cTimer *Timer) } } } - else + else if (!Timer || Timer->priority >= Setup.PrimaryLimit) esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch); } else @@ -1999,6 +2053,15 @@ void cRecordControls::Process(void) } } +bool cRecordControls::Active(void) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + if (RecordControls[i]) + return true; + } + return false; +} + // --- cProgressBar ---------------------------------------------------------- class cProgressBar : public cBitmap { diff --git a/menu.h b/menu.h index 923211115..356122e02 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.16 2000/12/25 14:25:29 kls Exp $ + * $Id: menu.h 1.18 2001/02/11 10:30:35 kls Exp $ */ #ifndef _MENU_H @@ -43,6 +43,7 @@ class cMenuRecordings : public cOsdMenu { private: cRecordings Recordings; eOSState Play(void); + eOSState Rewind(void); eOSState Del(void); eOSState Summary(void); public: @@ -74,6 +75,7 @@ class cRecordControls { static void Stop(cDvbApi *DvbApi); static const char *GetInstantId(const char *LastInstantId); static void Process(void); + static bool Active(void); }; class cReplayControl : public cOsdBase { diff --git a/osd.c b/osd.c index bc9c94850..c29c98316 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.13 2000/11/12 15:29:25 kls Exp $ + * $Id: osd.c 1.16 2001/02/24 16:26:11 kls Exp $ */ #include "osd.h" @@ -77,6 +77,7 @@ eOSState cOsdItem::ProcessKey(eKeys Key) cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4) { + hasHotkeys = false; visible = false; title = strdup(Title); cols[0] = c0; @@ -252,6 +253,32 @@ void cOsdMenu::CursorDown(void) } } +void cOsdMenu::PageUp(void) +{ + if (Count() <= MAXOSDITEMS) + return; + current -= MAXOSDITEMS; + first -= MAXOSDITEMS; + if (first < 0) + first = current = 0; + Display(); + DisplayCurrent(true); +} + +void cOsdMenu::PageDown(void) +{ + if (Count() <= MAXOSDITEMS) + return; + current += MAXOSDITEMS; + first += MAXOSDITEMS; + if (current > Count() - 1) { + current = Count() - 1; + first = Count() - MAXOSDITEMS; + } + Display(); + DisplayCurrent(true); +} + void cOsdMenu::Mark(void) { if (Count() && marked < 0) { @@ -260,6 +287,20 @@ void cOsdMenu::Mark(void) } } +eOSState cOsdMenu::HotKey(eKeys Key) +{ + for (cOsdItem *item = First(); item; item = Next(item)) { + const char *s = item->Text(); + if (s && (s = skipspace(s)) != NULL) { + if (*s == Key - k1 + '1') { + current = item->Index(); + return ProcessKey(kOk); + } + } + } + return osContinue; +} + eOSState cOsdMenu::AddSubMenu(cOsdMenu *SubMenu) { delete subMenu; @@ -289,10 +330,17 @@ eOSState cOsdMenu::ProcessKey(eKeys Key) return state; } switch (Key) { + case k1...k9: if (hasHotkeys) + return HotKey(Key); + break; case kUp|k_Repeat: case kUp: CursorUp(); break; case kDown|k_Repeat: case kDown: CursorDown(); break; + case kLeft|k_Repeat: + case kLeft: PageUp(); break; + case kRight|k_Repeat: + case kRight: PageDown(); break; case kBack: return osBack; case kOk: if (marked >= 0) { SetStatus(NULL); diff --git a/osd.h b/osd.h index 16d0ec2c3..c0fb1a1ef 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.18 2000/12/24 10:16:52 kls Exp $ + * $Id: osd.h 1.20 2001/02/03 15:13:59 kls Exp $ */ #ifndef __OSD_H @@ -77,6 +77,7 @@ class cOsdMenu : public cOsdBase, public cList { cOsdMenu *subMenu; const char *helpRed, *helpGreen, *helpYellow, *helpBlue; const char *status; + bool hasHotkeys; protected: bool visible; virtual void Clear(void); @@ -85,7 +86,10 @@ class cOsdMenu : public cOsdBase, public cList { void DisplayCurrent(bool Current); void CursorUp(void); void CursorDown(void); + void PageUp(void); + void PageDown(void); void Mark(void); + eOSState HotKey(eKeys Key); eOSState AddSubMenu(cOsdMenu *SubMenu); bool HasSubMenu(void) { return subMenu; } void SetStatus(const char *s); @@ -95,6 +99,7 @@ class cOsdMenu : public cOsdBase, public cList { public: cOsdMenu(const char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0); virtual ~cOsdMenu(); + void SetHasHotkeys(void) { hasHotkeys = true; } int Current(void) { return current; } void Add(cOsdItem *Item, bool Current = false); void Display(void); diff --git a/recording.c b/recording.c index 064731dfd..d6e5a333e 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.24 2001/01/13 12:17:15 kls Exp $ + * $Id: recording.c 1.28 2001/02/18 16:14:05 kls Exp $ */ #define _GNU_SOURCE @@ -15,16 +15,20 @@ #include #include #include -#include "dvbapi.h" #include "interface.h" #include "tools.h" #include "videodir.h" #define RECEXT ".rec" #define DELEXT ".del" +#ifdef VFAT +#define DATAFORMAT "%4d-%02d-%02d.%02d.%02d.%02d.%02d" RECEXT +#else #define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT +#endif #define NAMEFORMAT "%s/%s/" DATAFORMAT +#define RESUMEFILESUFFIX "/resume.vdr" #define SUMMARYFILESUFFIX "/summary.vdr" #define MARKSFILESUFFIX "/marks.vdr" @@ -32,8 +36,35 @@ #define MINDISKSPACE 1024 // MB -#define DISKCHECKDELTA 300 // seconds between checks for free disk space -#define REMOVELATENCY 10 // seconds to wait until next check after removing a file +#define DELETEDLIFETIME 1 // hours after which a deleted recording will be actually removed +#define REMOVECHECKDELTA 3600 // seconds between checks for removing deleted files +#define DISKCHECKDELTA 300 // seconds between checks for free disk space +#define REMOVELATENCY 10 // seconds to wait until next check after removing a file + +void RemoveDeletedRecordings(void) +{ + static time_t LastRemoveCheck = 0; + if (time(NULL) - LastRemoveCheck > REMOVECHECKDELTA) { + // Remove the oldest file that has been "deleted": + cRecordings Recordings; + if (Recordings.Load(true)) { + cRecording *r = Recordings.First(); + cRecording *r0 = r; + while (r) { + if (r->start < r0->start) + r0 = r; + r = Recordings.Next(r); + } + if (r0 && time(NULL) - r0->start > DELETEDLIFETIME * 60) { + r0->Remove(); + RemoveEmptyVideoDirectories(); + LastRemoveCheck += REMOVELATENCY; + return; + } + } + LastRemoveCheck = time(NULL); + } +} void AssertFreeDiskSpace(void) { @@ -83,6 +114,64 @@ void AssertFreeDiskSpace(void) } } +// --- cResumeFile ------------------------------------------------------------ + +cResumeFile::cResumeFile(const char *FileName) +{ + fileName = new char[strlen(FileName) + strlen(RESUMEFILESUFFIX) + 1]; + if (fileName) { + strcpy(fileName, FileName); + strcat(fileName, RESUMEFILESUFFIX); + } + else + esyslog(LOG_ERR, "ERROR: can't allocate memory for resume file name"); +} + +cResumeFile::~cResumeFile() +{ + delete fileName; +} + +int cResumeFile::Read(void) +{ + int resume = -1; + if (fileName) { + int f = open(fileName, O_RDONLY); + if (f >= 0) { + if (read(f, &resume, sizeof(resume)) != sizeof(resume)) { + resume = -1; + LOG_ERROR_STR(fileName); + } + close(f); + } + else if (errno != ENOENT) + LOG_ERROR_STR(fileName); + } + return resume; +} + +bool cResumeFile::Save(int Index) +{ + if (fileName) { + int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); + if (f >= 0) { + if (write(f, &Index, sizeof(Index)) != sizeof(Index)) + LOG_ERROR_STR(fileName); + close(f); + return true; + } + } + return false; +} + +void cResumeFile::Delete(void) +{ + if (fileName) { + if (remove(fileName) < 0 && errno != ENOENT) + LOG_ERROR_STR(fileName); + } +} + // --- cRecording ------------------------------------------------------------ cRecording::cRecording(cTimer *Timer) diff --git a/recording.h b/recording.h index 454c356f7..b561fa2f9 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.11 2000/12/16 14:25:20 kls Exp $ + * $Id: recording.h 1.13 2001/02/11 10:45:52 kls Exp $ */ #ifndef __RECORDING_H @@ -14,8 +14,20 @@ #include "config.h" #include "tools.h" +void RemoveDeletedRecordings(void); void AssertFreeDiskSpace(void); +class cResumeFile { +private: + char *fileName; +public: + cResumeFile(const char *FileName); + ~cResumeFile(); + int Read(void); + bool Save(int Index); + void Delete(void); + }; + class cRecording : public cListObject { friend class cRecordings; private: diff --git a/remote.c b/remote.c index 691b5e94e..940243863 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.20 2000/12/03 11:55:06 kls Exp $ + * $Id: remote.c 1.21 2001/02/04 19:17:59 kls Exp $ */ #include "remote.h" @@ -428,6 +428,7 @@ void cRcIoLIRC::Action(void) dsyslog(LOG_INFO, "LIRC remote control thread started (pid=%d)", getpid()); int FirstTime = 0; + int LastTime = 0; char buf[LIRC_BUFFER_SIZE]; char LastKeyName[LIRC_KEY_BUF]; @@ -451,14 +452,17 @@ void cRcIoLIRC::Action(void) continue; // repeat function kicks in after a short delay receivedData = receivedRepeat = true; } + LastTime = Now; WakeUp(); } } else if (receivedData) { // the last data before releasing the key hasn't been fetched yet if (receivedRepeat) { // it was a repeat, so let's make it a release - receivedRepeat = false; - receivedRelease = true; - WakeUp(); + if (time_ms() - LastTime > REPEATDELAY) { + receivedRepeat = false; + receivedRelease = true; + WakeUp(); + } } } else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat, so let's generate a release diff --git a/remote.h b/remote.h index 0ea4442ae..659de1aca 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.13 2000/10/08 12:11:34 kls Exp $ + * $Id: remote.h 1.14 2001/02/02 14:49:10 kls Exp $ */ #ifndef __REMOTE_H @@ -18,9 +18,9 @@ class cRcIoBase { protected: time_t t; - cRcIoBase(void); public: enum { modeH = 'h', modeB = 'b', modeS = 's' }; + cRcIoBase(void); virtual ~cRcIoBase(); virtual bool SetCode(unsigned char Code, unsigned short Address) { return true; } virtual bool SetMode(unsigned char Mode) { return true; } @@ -29,8 +29,8 @@ class cRcIoBase { virtual bool String(char *s) { return true; } virtual bool DetectCode(unsigned char *Code, unsigned short *Address) { return true; } virtual void Flush(int WaitMs = 0) {} - virtual bool InputAvailable(void) = 0; - virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL) = 0; + virtual bool InputAvailable(void) { return false; } + virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL) { return false; } }; #if defined REMOTE_KBD @@ -93,7 +93,7 @@ class cRcIoLIRC : public cRcIoBase, private cThread { virtual bool GetCommand(unsigned int *Command = NULL, bool *Repeat = NULL, bool *Release = NULL); }; -#else +#elif !defined REMOTE_NONE #error Please define a remote control mode! diff --git a/runvdr b/runvdr new file mode 100755 index 000000000..83b2ea62f --- /dev/null +++ b/runvdr @@ -0,0 +1,13 @@ +#!/bin/sh + +DVBDIR='../DVB/driver' +VDRCMD='./vdr -w 60' + +while test 1; do +# (cd $DVBDIR; make reload) +# sleep 3 + if $VDRCMD; then exit; fi + date + echo "restarting VDR" + sleep 10 + done diff --git a/svdrp.c b/svdrp.c index 0ce30dbae..ffdac28b4 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.13 2000/12/03 15:34:35 kls Exp $ + * $Id: svdrp.c 1.14 2001/02/18 14:18:13 kls Exp $ */ #define _GNU_SOURCE @@ -63,6 +63,10 @@ bool cSocket::Open(void) port = 0; return false; } + // allow it to always reuse the same port: + int ReUseAddr = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ReUseAddr, sizeof(ReUseAddr)); + // struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = htons(port); @@ -137,6 +141,12 @@ const char *HelpPages[] = { "LSTT [ ]\n" " List timers. Without option, all timers are listed. Otherwise\n" " only the given timer is listed.", + "MESG [ ]\n" + " Displays the given message on the OSD. If message is omitted, the\n" + " currently pending message (if any) will be returned. The message\n" + " will be displayed for a few seconds as soon as the OSD has become\n" + " idle. If a new MESG command is entered while the previous message\n" + " has not yet been displayed, the old message will be overwritten.", "MODC \n" " Modify a channel. Settings must be in the same format as returned\n" " by the LSTC command.", @@ -224,22 +234,25 @@ const char *GetHelpPage(const char *Cmd) cSVDRP::cSVDRP(int Port) :socket(Port) { + message = NULL; + lastActivity = 0; isyslog(LOG_INFO, "SVDRP listening on port %d", Port); } cSVDRP::~cSVDRP() { Close(); + delete message; } -void cSVDRP::Close(void) +void cSVDRP::Close(bool Timeout) { if (file.IsOpen()) { //TODO how can we get the *full* hostname? char buffer[MAXCMDBUFFER]; gethostname(buffer, sizeof(buffer)); - Reply(221, "%s closing connection", buffer); - isyslog(LOG_INFO, "closing connection"); //TODO store IP#??? + Reply(221, "%s closing connection%s", buffer, Timeout ? " (timeout)" : ""); + isyslog(LOG_INFO, "closing SVDRP connection"); //TODO store IP#??? file.Close(); } } @@ -557,6 +570,20 @@ void cSVDRP::CmdLSTT(const char *Option) } } +void cSVDRP::CmdMESG(const char *Option) +{ + if (*Option) { + delete message; + message = strdup(Option); + isyslog(LOG_INFO, "SVDRP message: '%s'", message); + Reply(250, "Message stored"); + } + else if (message) + Reply(250, "%s", message); + else + Reply(550, "No pending message"); +} + void cSVDRP::CmdMODC(const char *Option) { if (*Option) { @@ -820,6 +847,7 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("HITK")) CmdHITK(s); else if (CMD("LSTC")) CmdLSTC(s); else if (CMD("LSTT")) CmdLSTT(s); + else if (CMD("MESG")) CmdMESG(s); else if (CMD("MODC")) CmdMODC(s); else if (CMD("MODT")) CmdMODT(s); else if (CMD("MOVC")) CmdMOVC(s); @@ -839,7 +867,8 @@ void cSVDRP::Execute(char *Cmd) void cSVDRP::Process(void) { - bool SendGreeting = !file.IsOpen(); + bool NewConnection = !file.IsOpen(); + bool SendGreeting = NewConnection; if (file.IsOpen() || file.Open(socket.Accept())) { char buffer[MAXCMDBUFFER]; @@ -849,6 +878,8 @@ void cSVDRP::Process(void) time_t now = time(NULL); Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now)); } + if (NewConnection) + lastActivity = time(NULL); int rbytes = file.ReadString(buffer, sizeof(buffer) - 1); if (rbytes > 0) { //XXX overflow check??? @@ -859,11 +890,22 @@ void cSVDRP::Process(void) buffer[rbytes] = 0; // showtime! Execute(buffer); + lastActivity = time(NULL); } else if (rbytes < 0) Close(); + else if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) { + isyslog(LOG_INFO, "timeout on SVDRP connection"); + Close(true); + } } } -//TODO timeout??? +char *cSVDRP::GetMessage(void) +{ + char *s = message; + message = NULL; + return s; +} + //TODO more than one connection??? diff --git a/svdrp.h b/svdrp.h index 12eb11e3e..62c1e7537 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.6 2000/09/17 13:22:04 kls Exp $ + * $Id: svdrp.h 1.7 2001/02/18 13:36:47 kls Exp $ */ #ifndef __SVDRP_H @@ -31,7 +31,9 @@ class cSVDRP { cSocket socket; cFile file; CRect ovlClipRects[MAXCLIPRECTS]; - void Close(void); + char *message; + time_t lastActivity; + void Close(bool Timeout = false); bool Send(const char *s, int length = -1); void Reply(int Code, const char *fmt, ...); void CmdCHAN(const char *Option); @@ -42,6 +44,7 @@ class cSVDRP { void CmdHITK(const char *Option); void CmdLSTC(const char *Option); void CmdLSTT(const char *Option); + void CmdMESG(const char *Option); void CmdMODC(const char *Option); void CmdMODT(const char *Option); void CmdMOVC(const char *Option); @@ -59,6 +62,7 @@ class cSVDRP { cSVDRP(int Port); ~cSVDRP(); void Process(void); + char *GetMessage(void); }; #endif //__SVDRP_H diff --git a/svdrpsend.pl b/svdrpsend.pl new file mode 100755 index 000000000..5efd504be --- /dev/null +++ b/svdrpsend.pl @@ -0,0 +1,57 @@ +#!/usr/bin/perl + +use Socket; +use Getopt::Std; + +$Usage = qq{ +Usage: $0 options command... + +Options: -d hostname destination hostname (default: localhost) + -p port SVDRP port number (default: 2001) +}; + +die $Usage if (!$ARGV[0] || !getopts("d:p:")); + +$Dest = $opt_d || "localhost"; +$Port = $opt_p || 2001; +$Cmd = "@ARGV" || Error("missing command"); + +$Timeout = 10; # max. seconds to wait for response + +$SIG{ALRM} = sub { Error("timeout"); }; +alarm($Timeout); + +$iaddr = inet_aton($Dest) || Error("no host: $Dest"); +$paddr = sockaddr_in($Port, $iaddr); + +$proto = getprotobyname('tcp'); +socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!"); +connect(SOCK, $paddr) || Error("connect: $!"); +select(SOCK); $| = 1; +Receive(); +Send($Cmd); +Send("quit"); +close(SOCK) || Error("close: $!"); + +sub Send +{ + my $cmd = shift || Error("no command to send"); + print SOCK "$cmd\r\n"; + Receive(); +} + +sub Receive +{ + while () { + print STDOUT $_; + last if substr($_, 3, 1) ne "-"; + } +} + +sub Error +{ + print STDERR "@_\n"; + close(SOCK); + exit 0; +} + diff --git a/tools.c b/tools.c index cd2c60f8a..a3b27e5a7 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.27 2001/01/13 15:35:02 kls Exp $ + * $Id: tools.c 1.30 2001/02/11 14:44:22 kls Exp $ */ #define _GNU_SOURCE @@ -51,7 +51,7 @@ char *strreplace(char *s, char c1, char c2) { char *p = s; - while (*p) { + while (p && *p) { if (*p == c1) *p = c2; p++; @@ -237,8 +237,10 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks) } } dsyslog(LOG_INFO, "removing %s", FileName); - if (remove(FileName) == 0) - return true; + if (remove(FileName) < 0) { + LOG_ERROR_STR(FileName); + return false; + } } else if (errno != ENOENT) { LOG_ERROR_STR(FileName); @@ -247,6 +249,48 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks) return true; } +bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis) +{ + DIR *d = opendir(DirName); + if (d) { + bool empty = true; + struct dirent *e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..") && strcmp(e->d_name, "lost+found")) { + char *buffer; + asprintf(&buffer, "%s/%s", DirName, e->d_name); + struct stat st; + if (stat(buffer, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + if (!RemoveEmptyDirectories(buffer, true)) + empty = false; + } + else + empty = false; + } + else { + LOG_ERROR_STR(buffer); + delete buffer; + return false; + } + delete buffer; + } + } + closedir(d); + if (RemoveThis && empty) { + dsyslog(LOG_INFO, "removing %s", DirName); + if (remove(DirName) < 0) { + LOG_ERROR_STR(DirName); + return false; + } + } + return empty; + } + else + LOG_ERROR_STR(DirName); + return false; +} + char *ReadLink(const char *FileName) { char RealName[_POSIX_PATH_MAX]; diff --git a/tools.h b/tools.h index 539dba019..96d09826e 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.23 2001/01/13 15:36:00 kls Exp $ + * $Id: tools.h 1.24 2001/02/11 13:39:40 kls Exp $ */ #ifndef __TOOLS_H @@ -48,6 +48,7 @@ uint FreeDiskSpaceMB(const char *Directory); bool DirectoryOk(const char *DirName, bool LogErrors = false); bool MakeDirs(const char *FileName, bool IsDirectory = false); bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); +bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false); char *ReadLink(const char *FileName); class cFile { diff --git a/vdr.c b/vdr.c index 698cc7a61..938afcf09 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.49 2001/01/14 15:29:51 kls Exp $ + * $Id: vdr.c 1.54 2001/02/24 16:18:43 kls Exp $ */ #include @@ -44,6 +44,8 @@ #define KEYS_CONF "keys.conf" #endif +#define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping + static int Interrupted = 0; static void SignalHandler(int signum) @@ -53,48 +55,76 @@ static void SignalHandler(int signum) signal(signum, SignalHandler); } +static void Watchdog(int signum) +{ + // Something terrible must have happened that prevented the 'alarm()' from + // being called in time, so let's get out of here: + esyslog(LOG_ERR, "PANIC: watchdog timer expired - exiting!"); + exit(1); +} + int main(int argc, char *argv[]) { // Command line options: #define DEFAULTSVDRPPORT 2001 +#define DEFAULTWATCHDOG 0 // seconds int SVDRPport = DEFAULTSVDRPPORT; const char *ConfigDirectory = NULL; bool DaemonMode = false; + int WatchdogTimeout = DEFAULTWATCHDOG; static struct option long_options[] = { - { "config", required_argument, NULL, 'c' }, - { "daemon", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "log", required_argument, NULL, 'l' }, - { "port", required_argument, NULL, 'p' }, - { "video", required_argument, NULL, 'v' }, + { "config", required_argument, NULL, 'c' }, + { "daemon", no_argument, NULL, 'd' }, + { "device", required_argument, NULL, 'D' }, + { "help", no_argument, NULL, 'h' }, + { "log", required_argument, NULL, 'l' }, + { "port", required_argument, NULL, 'p' }, + { "video", required_argument, NULL, 'v' }, + { "watchdog", required_argument, NULL, 'w' }, { 0 } }; int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "c:dhl:p:v:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "c:dD:hl:p:v:w:", long_options, &option_index)) != -1) { switch (c) { case 'c': ConfigDirectory = optarg; break; case 'd': DaemonMode = true; break; + case 'D': if (isnumber(optarg)) { + int n = atoi(optarg); + if (0 <= n && n < MAXDVBAPI) { + cDvbApi::SetUseDvbApi(n); + break; + } + } + fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg); + abort(); + break; case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80| - " -c DIR, --config=DIR read config files from DIR (default is to read them\n" - " from the video directory)\n" - " -h, --help display this help and exit\n" - " -d, --daemon run in daemon mode\n" - " -l LEVEL, --log=LEVEL set log level (default: 3)\n" - " 0 = no logging, 1 = errors only,\n" - " 2 = errors and info, 3 = errors, info and debug\n" - " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" - " 0 turns off SVDRP\n" - " -v DIR, --video=DIR use DIR as video directory (default is %s)\n" + " -c DIR, --config=DIR read config files from DIR (default is to read them\n" + " from the video directory)\n" + " -h, --help display this help and exit\n" + " -d, --daemon run in daemon mode\n" + " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n" + " there may be several -D options (default: all DVB\n" + " devices will be used)\n" + " -l LEVEL, --log=LEVEL set log level (default: 3)\n" + " 0 = no logging, 1 = errors only,\n" + " 2 = errors and info, 3 = errors, info and debug\n" + " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" + " 0 turns off SVDRP\n" + " -v DIR, --video=DIR use DIR as video directory (default is %s)\n" + " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n" + " seconds (default: %d); '0' disables the watchdog\n" "\n" "Report bugs to \n", DEFAULTSVDRPPORT, - VideoDirectory + VideoDirectory, + DEFAULTWATCHDOG ); return 0; break; @@ -119,6 +149,16 @@ int main(int argc, char *argv[]) while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') optarg[strlen(optarg) - 1] = 0; break; + case 'w': if (isnumber(optarg)) { + int t = atoi(optarg); + if (t >= 0) { + WatchdogTimeout = t; + break; + } + } + fprintf(stderr, "vdr: invalid watchdog timeout: %s\n", optarg); + abort(); + break; default: abort(); } } @@ -166,9 +206,9 @@ int main(int argc, char *argv[]) Channels.Load(AddDirectory(ConfigDirectory, "channels.conf")); Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); Commands.Load(AddDirectory(ConfigDirectory, "commands.conf")); -#ifdef REMOTE_LIRC +#if defined(REMOTE_LIRC) Keys.SetDummyValues(); -#else +#elif !defined(REMOTE_NONE) bool KeysLoaded = Keys.Load(AddDirectory(ConfigDirectory, KEYS_CONF)); #endif @@ -186,7 +226,7 @@ int main(int argc, char *argv[]) // User interface: Interface = new cInterface(SVDRPport); -#ifndef REMOTE_LIRC +#if !defined(REMOTE_LIRC) && !defined(REMOTE_NONE) if (!KeysLoaded) Interface->LearnKeys(); #endif @@ -197,6 +237,8 @@ int main(int argc, char *argv[]) if (signal(SIGINT, SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN); if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN); if (signal(SIGPIPE, SignalHandler) == SIG_IGN) signal(SIGPIPE, SIG_IGN); + if (WatchdogTimeout > 0) + if (signal(SIGALRM, Watchdog) == SIG_IGN) signal(SIGALRM, SIG_IGN); // Main program loop: @@ -204,8 +246,23 @@ int main(int argc, char *argv[]) cReplayControl *ReplayControl = NULL; int LastChannel = -1; int PreviousChannel = cDvbApi::CurrentChannel(); + time_t LastActivity = time(NULL); + int MaxLatencyTime = 0; + + if (WatchdogTimeout > 0) { + dsyslog(LOG_INFO, "setting watchdog timer to %d seconds", WatchdogTimeout); + alarm(WatchdogTimeout); // Initial watchdog timer start + } while (!Interrupted) { + // Restart the Watchdog timer: + if (WatchdogTimeout > 0) { + int LatencyTime = WatchdogTimeout - alarm(WatchdogTimeout); + if (LatencyTime > MaxLatencyTime) { + MaxLatencyTime = LatencyTime; + dsyslog(LOG_INFO, "max. latency time %d seconds", MaxLatencyTime); + } + } // Channel display: if (!EITScanner.Active() && cDvbApi::CurrentChannel() != LastChannel) { if (!Menu) @@ -310,6 +367,14 @@ int main(int argc, char *argv[]) EITScanner.Process(); cVideoCutter::Active(); } + if (!*Interact && !cRecordControls::Active()) { + if (time(NULL) - LastActivity > ACTIVITYTIMEOUT) { + RemoveDeletedRecordings(); + LastActivity = time(NULL); + } + } + else + LastActivity = time(NULL); } isyslog(LOG_INFO, "caught signal %d", Interrupted); Setup.CurrentChannel = cDvbApi::CurrentChannel(); @@ -319,6 +384,8 @@ int main(int argc, char *argv[]) delete ReplayControl; delete Interface; cDvbApi::Cleanup(); + if (WatchdogTimeout > 0) + dsyslog(LOG_INFO, "max. latency time %d seconds", MaxLatencyTime); isyslog(LOG_INFO, "exiting"); if (SysLogLevel > 0) closelog(); diff --git a/videodir.c b/videodir.c index 4d5c2572b..2824d04e3 100644 --- a/videodir.c +++ b/videodir.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: videodir.c 1.3 2000/12/24 12:51:41 kls Exp $ + * $Id: videodir.c 1.4 2001/02/11 13:48:30 kls Exp $ */ #include "videodir.h" @@ -28,7 +28,7 @@ class cVideoDirectory { cVideoDirectory(void); ~cVideoDirectory(); uint FreeMB(void); - const char *Name(void) { return name; } + const char *Name(void) { return name ? name : VideoDirectory; } const char *Stored(void) { return stored; } int Length(void) { return length; } bool IsDistributed(void) { return name != NULL; } @@ -197,3 +197,11 @@ const char *PrefixVideoFileName(const char *FileName, char Prefix) return PrefixedName; } +void RemoveEmptyVideoDirectories(void) +{ + cVideoDirectory Dir; + do { + RemoveEmptyDirectories(Dir.Name()); + } while (Dir.Next()); +} + diff --git a/videodir.h b/videodir.h index 0716a284b..0197de303 100644 --- a/videodir.h +++ b/videodir.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: videodir.h 1.2 2000/12/24 12:41:10 kls Exp $ + * $Id: videodir.h 1.3 2001/02/11 13:12:50 kls Exp $ */ #ifndef __VIDEODIR_H @@ -18,5 +18,6 @@ bool RenameVideoFile(const char *OldName, const char *NewName); bool RemoveVideoFile(const char *FileName); bool VideoFileSpaceAvailable(unsigned int SizeMB); const char *PrefixVideoFileName(const char *FileName, char Prefix); +void RemoveEmptyVideoDirectories(void); #endif //__VIDEODIR_H From 610c5600df98b35226536ffe92b1fd231128c7d4 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 1 Apr 2001 18:00:00 +0200 Subject: [PATCH 018/307] =?UTF-8?q?Version=200.72=20-=20Fixed=20SVDRP=20co?= =?UTF-8?q?mmands=20LSTC=20and=20LSTT=20to=20make=20them=20return=20an=20e?= =?UTF-8?q?rror=20message=20if=20=20=20no=20channels=20or=20timers=20are?= =?UTF-8?q?=20defined.=20-=20Enhanced=20'channels.conf.cable'=20(thanks=20?= =?UTF-8?q?to=20Hans-Peter=20Raschke).=20-=20Fixed=20switching=20to=20anot?= =?UTF-8?q?her=20channel=20via=20the=20EPG=20while=20a=20recording=20is=20?= =?UTF-8?q?being=20=20=20replayed.=20-=20Fixed=20a=20memory=20leak=20in=20?= =?UTF-8?q?the=20EIT=20processor=20that=20happened=20when=20the=20system?= =?UTF-8?q?=20time=20=20=20was=20set.=20-=20Removed=20some=20redundant=20c?= =?UTF-8?q?ode=20from=20the=20cListBase=20destructor.=20-=20Fixed=20intern?= =?UTF-8?q?ationalization=20of=20some=20Main=20menu=20texts.=20-=20Updated?= =?UTF-8?q?=20'channels.conf'=20after=20the=20recent=20changes=20of=20Prem?= =?UTF-8?q?iere=20World=20(thanks=20=20=20to=20Axel=20Gruber).=20-=20Redes?= =?UTF-8?q?igned=20the=20ring=20buffer=20to=20make=20it=20work=20with=20tw?= =?UTF-8?q?o=20separate=20threads=20for=20=20=20input=20and=20output=20(al?= =?UTF-8?q?so=20prepared=20for=20using=20a=20remultiplexer).=20-=20Fixed?= =?UTF-8?q?=20setting=20system=20time=20from=20transponders.=20-=20Fixed?= =?UTF-8?q?=20a=20segfault=20in=20the=20Schedule=20menu=20in=20case=20ther?= =?UTF-8?q?e=20is=20no=20EPG=20information.=20-=20The=20'runvdr'=20script?= =?UTF-8?q?=20now=20kills=20any=20leftover=20vdr=20threads=20before=20rest?= =?UTF-8?q?arting=20it.=20-=20Fixed=20a=20problem=20with=20Daylight=20Savi?= =?UTF-8?q?ng=20Time=20when=20displaying=20the=20times=20of=20=20=20record?= =?UTF-8?q?ings.=20-=20Added=20Dutch=20language=20texts=20(thanks=20to=20A?= =?UTF-8?q?rnold=20Niessen).=20-=20The=20new=20command=20line=20option=20-?= =?UTF-8?q?t=20can=20be=20used=20to=20set=20the=20controlling=20terminal?= =?UTF-8?q?=20=20=20(thanks=20to=20J=FCrgen=20Sauer).=20This=20is=20especi?= =?UTF-8?q?ally=20useful=20when=20starting=20VDR=20through=20=20=20an=20en?= =?UTF-8?q?try=20in=20/etc/inittab=20(see=20INSTALL).=20-=20Since=20the=20?= =?UTF-8?q?CAM=20module=20only=20works=20if=20it=20is=20installed=20in=20t?= =?UTF-8?q?he=20"highest"=20DVB=20card,=20=20=20recordings=20now=20search?= =?UTF-8?q?=20for=20a=20free=20DVB=20card=20from=20lowest=20to=20highest?= =?UTF-8?q?=20index=20(as=20=20=20opposed=20to=20the=20previous=20"highest?= =?UTF-8?q?=20to=20lowest"=20search)=20in=20order=20to=20not=20use=20the?= =?UTF-8?q?=20=20=20CAM=20card=20for=20FTA=20recordings=20unless=20necessa?= =?UTF-8?q?ry.=20This=20is=20only=20important=20for=20=20=20systems=20with?= =?UTF-8?q?=20three=20or=20more=20DVB=20cards.=20-=20Added=20the=20"statdv?= =?UTF-8?q?b2vdr"=20tool=20from=20Hans-Peter=20Raschke.=20-=20Fixed=20a=20?= =?UTF-8?q?segfault=20that=20sometimes=20happened=20when=20killing=20VDR.?= =?UTF-8?q?=20-=20VDR=20now=20returns=20an=20exit=20status=20of=20'2'=20in?= =?UTF-8?q?=20case=20of=20an=20error=20at=20startup,=20instead=20=20=20of?= =?UTF-8?q?=20terminating=20with=20'abort()'=20(which=20caused=20a=20core?= =?UTF-8?q?=20dump).=20-=20SVDRP=20now=20also=20works=20with=20clients=20t?= =?UTF-8?q?hat=20don't=20do=20line=20buffering=20(like=20the=20=20=20Windo?= =?UTF-8?q?ws=20'telnet').=20-=20Empty=20lines=20in=20config=20files=20no?= =?UTF-8?q?=20longer=20cause=20error=20messages.=20-=20New=20SVDRP=20comma?= =?UTF-8?q?nd=20LSTE=20to=20list=20the=20EPG=20data.=20-=20The=20SVDRP=20H?= =?UTF-8?q?ELP=20command=20now=20prints=20the=20topics=20in=20several=20co?= =?UTF-8?q?lumns.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTORS | 10 + HISTORY | 39 ++ INSTALL | 5 + Makefile | 41 +- Tools/statdvb2vdr/ch.pl | 250 +++++++ channels.conf | 63 +- channels.conf.cable | 301 ++++---- config.c | 66 +- config.h | 22 +- dvbapi.c | 321 +++------ eit.c | 1452 ++++++++++++++++++++------------------- eit.h | 17 +- i18n.c | 143 +++- menu.c | 42 +- recording.c | 3 +- remux.c | 173 +++++ remux.h | 51 ++ ringbuffer.c | 170 +++++ ringbuffer.h | 55 ++ runvdr | 13 +- svdrp.c | 114 ++- svdrp.h | 7 +- tools.c | 28 +- tools.h | 3 +- vdr.c | 36 +- 25 files changed, 2151 insertions(+), 1274 deletions(-) create mode 100644 Tools/statdvb2vdr/ch.pl create mode 100644 remux.c create mode 100644 remux.h create mode 100644 ringbuffer.c create mode 100644 ringbuffer.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 7a93b33ca..8a67f37c9 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -57,6 +57,16 @@ Dave Chapman Hans-Peter Raschke for his support in adapting VDR to DVB-C + for adding the 'statdvb2vdr' tool (see Tools/statdvb2vdr) Peter Hofmann for his support in adapting VDR to DVB-C + +Axel Gruber + for his support in keeping the Premiere World channels up to date in 'channels.conf' + +Arnold Niessen + for translating the OSD texts to the Dutch language + +Jrgen Sauer + for implementing the -t option to set the controlling terminal diff --git a/HISTORY b/HISTORY index 684d2b65c..203377d37 100644 --- a/HISTORY +++ b/HISTORY @@ -413,3 +413,42 @@ Video Disk Recorder Revision History VDR exit in case the main program loop does not respond for more than the given number of seconds. This is mainly useful in combination with the new 'runvdr' script that restarts VDR in case is has exited. + +2001-04-01: Version 0.72 + +- Fixed SVDRP commands LSTC and LSTT to make them return an error message if + no channels or timers are defined. +- Enhanced 'channels.conf.cable' (thanks to Hans-Peter Raschke). +- Fixed switching to another channel via the EPG while a recording is being + replayed. +- Fixed a memory leak in the EIT processor that happened when the system time + was set. +- Removed some redundant code from the cListBase destructor. +- Fixed internationalization of some Main menu texts. +- Updated 'channels.conf' after the recent changes of Premiere World (thanks + to Axel Gruber). +- Redesigned the ring buffer to make it work with two separate threads for + input and output (also prepared for using a remultiplexer). +- Fixed setting system time from transponders. +- Fixed a segfault in the Schedule menu in case there is no EPG information. +- The 'runvdr' script now kills any leftover vdr threads before restarting it. +- Fixed a problem with Daylight Saving Time when displaying the times of + recordings. +- Added Dutch language texts (thanks to Arnold Niessen). +- The new command line option -t can be used to set the controlling terminal + (thanks to Jrgen Sauer). This is especially useful when starting VDR through + an entry in /etc/inittab (see INSTALL). +- Since the CAM module only works if it is installed in the "highest" DVB card, + recordings now search for a free DVB card from lowest to highest index (as + opposed to the previous "highest to lowest" search) in order to not use the + CAM card for FTA recordings unless necessary. This is only important for + systems with three or more DVB cards. +- Added the "statdvb2vdr" tool from Hans-Peter Raschke. +- Fixed a segfault that sometimes happened when killing VDR. +- VDR now returns an exit status of '2' in case of an error at startup, instead + of terminating with 'abort()' (which caused a core dump). +- SVDRP now also works with clients that don't do line buffering (like the + Windows 'telnet'). +- Empty lines in config files no longer cause error messages. +- New SVDRP command LSTE to list the EPG data. +- The SVDRP HELP command now prints the topics in several columns. diff --git a/INSTALL b/INSTALL index c334ed6d5..6910f6b47 100644 --- a/INSTALL +++ b/INSTALL @@ -71,6 +71,11 @@ If the program shall run as a daemon, use the --daemon option. This will completely detach it from the terminal and will continue as a background process. +When starting the program through an entry in /etc/inittab, use the --terminal +option to set the controlling terminal, as in + +vdr:123:respawn:/usr/local/bin/vdr --terminal=/dev/tty8 -w 60 + Automatic restart in case of hangups: ------------------------------------- diff --git a/Makefile b/Makefile index c1cfabe1a..cec04caef 100644 --- a/Makefile +++ b/Makefile @@ -4,13 +4,14 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.20 2001/02/24 15:52:58 kls Exp $ +# $Id: Makefile 1.21 2001/03/11 11:36:15 kls Exp $ DVBDIR = ../DVB INCLUDES = -I$(DVBDIR)/driver OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o osd.o\ - recording.o remote.o svdrp.o thread.o tools.o vdr.o videodir.o + recording.o remote.o remux.o ringbuffer.o svdrp.o thread.o tools.o vdr.o\ + videodir.o OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1 @@ -37,26 +38,28 @@ font: genfontfile fontfix.c fontosd.c # Implicit rules: %.o: %.c - g++ -g -O2 -Wall -m486 -c $(DEFINES) $(INCLUDES) $< + g++ -g -O2 -Wall -Woverloaded-virtual -m486 -c $(DEFINES) $(INCLUDES) $< # Dependencies: -config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h -dvbosd.o : dvbosd.c dvbosd.h font.h tools.h -eit.o : eit.c config.h dvbapi.h dvbosd.h eit.h font.h thread.h tools.h videodir.h -font.o : font.c font.h fontfix.c fontosd.c tools.h -i18n.o : i18n.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h thread.h tools.h -interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h -osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h -recording.o: recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h -remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h -svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h -thread.o : thread.c thread.h tools.h -tools.o : tools.c tools.h -vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h -videodir.o : videodir.c tools.h videodir.h +config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h +dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h remux.h ringbuffer.h svdrp.h thread.h tools.h videodir.h +dvbosd.o : dvbosd.c dvbosd.h font.h tools.h +eit.o : eit.c config.h dvbapi.h dvbosd.h eit.h font.h thread.h tools.h videodir.h +font.o : font.c font.h fontfix.c fontosd.c tools.h +i18n.o : i18n.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h thread.h tools.h +interface.o : interface.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h +menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h +osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h +recording.o : recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h +remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h +remux.o : remux.c remux.h tools.h +ringbuffer.o: ringbuffer.c ringbuffer.h thread.h tools.h +svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h +thread.o : thread.c thread.h tools.h +tools.o : tools.c tools.h +vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h +videodir.o : videodir.c tools.h videodir.h # The main program: diff --git a/Tools/statdvb2vdr/ch.pl b/Tools/statdvb2vdr/ch.pl new file mode 100644 index 000000000..91e918d27 --- /dev/null +++ b/Tools/statdvb2vdr/ch.pl @@ -0,0 +1,250 @@ +#!/usr/bin/perl + +# Reads the file statdvb.dat produced by the Siemens windows +# software (1.50), which contains the scanned channels of an +# DVB-C (-S). The file ist located in the windows directory. +# +# Output is suitable for VDR (channels.conf). Only tested for +# the cable version. Should work with slight modifications for +# the sat version. +# +# 8. Mrz 2001 - Hans-Peter Raschke + + +# file structure derived from "DvbGlobalDef.h" of the Siemens +# DVB kit. + +# typedef int TABLETYPE; +# enum TunStandard +# { +# PAL_BG, //B/G stereo or mono +# PAL_I, //I mono (with Nicam stereo) +# PAL_DK, //D/K mono +# SECAM_L, //L mono (with Nicam stereo) +# SECAM_LI, //Secam L (with Nicam stereo) +# SECAM_DK, +# SECAM_BG, +# NTSC_M, +# DVB_C, +# DVB_S, +# DVB_T +# }; +# +# typedef struct TunProgDataTag //xx bytes+1string +# { +# int nNumber; //logical number of the program +# DWORD dwFrequency; //frequency in khz +# CString csName; //name of the program +# TunStandard eStandard; //standard of the program +# DWORD dwExtraInfo; //specific info, like teletext,reserved data +# //0x8 == external input 1-CVBS +# //0x10 == external input 2-Y/C +# //0x20 == scrambled Program stream +# //0x40 == ASTRA Sattable +# //0x80 == Eutelsat Sattable +# //0xC0 == Sattable from File +# //0x100 == Pulsed switch to other satellite dish +# //0x1000-0xF000 = Other Satellite Nr(if Sattable from File) +# //Digital only params beginning from here +# WORD ProgNr; //DVB Nr for the prog (PAS related) +# WORD wTS_ID; //Transport-Stream ID orig. +# WORD wNW_ID; //Network ID orig. +# WORD wService_ID; //Service /Programm Id +# BYTE nModulation; //Modulation-Type QAM,QPSK,other +# BYTE nFEC_outerinner; //outer(high nibble) and inner(low n.) +# DWORD dwSymbolrate; //in symbol/s +# BOOL b22kHz; //east or west(TRUE) position in Sat +# BOOL bVertical_pos; //horizontal or vertical(TRUE) position in SAT +# BYTE nProgtype; //type of service (e.g. tv, radio) +# WORD wVideo_PID; //video-pid of the channel +# WORD wAudio_PID; //audio-pid of the channel +# WORD wPMT_PID; //PID of the associated PMT +# WORD wTxt_PID; //teletext PID for the program +# WORD wSubtitling_PID; //subtitling PID for the program +# WORD wData_PID; //PID for data broadcast +# BYTE nIPFilter; //filter for different ip's +# DWORD dwReserved1; //Shows some extended Information LOWORD=DataBroadcast_Id, +# //MSB showing Databroadcast, (HIWORD & 0xFF)=ComponentTag from the stream ident desc +# DWORD dwReserved2; //reserved dword +# }DVBTunProgData; +# + +use strict; +use FileHandle; + +# for a full dump +my @varNames = ("nNumber", # logical number of the program + "dwFrequency", # frequency in khz + "csName", # name of the program + "eStandard", # standard of the program + "dwExtraInfo", # specific info, like teletext,reserved data + # 0x8 == external input 1-CVBS + # 0x10 == external input 2-Y/C + # 0x20 == scrambled Program stream + # 0x40 == ASTRA Sattable + # 0x80 == Eutelsat Sattable + # 0xC0 == Sattable from File + # 0x100 == Pulsed switch to other satellite dish + # 0x1000-0xF000 = Other Satellite Nr(if Sattable from File) + "ProgNr", # DVB Nr for the prog (PAS related) + "wTS_ID", # Transport-Stream ID orig. + "wNW_ID", # Network ID orig. + "wService_ID", # Service /Programm Id + "nModulation", # Modulation-Type QAM,QPSK,other + "nFEC_outerinner", # outer(high nibble) and inner(low n.) + "dwSymbolrate", # in symbol/s + "b22kHz", # east or west(TRUE) position in Sat + "bVertical_pos", # horizontal or vertical(TRUE) position in SAT + "nProgtype", # type of service (e.g. tv, radio) + "wVideo_PID", # video-pid of the channel + "wAudio_PID", # audio-pid of the channel + "wPMT_PID", # PID of the associated PMT + "wTxt_PID", # teletext PID for the program + "wSubtitling_PID", # subtitling PID for the program + "wData_PID"); # PID for data broadcast + +my @outVar = ("csName", + "dwFrequency", + "bVertical_pos", + "b22kHz", + "dwSymbolrate", + "wVideo_PID", + "wAudio_PID", + "wTxt_PID", + "dwExtraInfo", + "ProgNr"); + +# channels that need a valid smartcard +my @addCrypted = ("Extreme Sport", + "Bloomberg", + "Fashion TV", + "BET ON JAZZ", + "LANDSCAPE", + "Einstein", + "Single TV"); + +my @chNames = (); # list of scanned channels +my $camNo = 1; # number of CI/CAM to use +my %chData; # all channel data +my $buff; # input buffer +my $fh = new FileHandle("$ARGV[0]") or die "Datei $ARGV[0] nicht gefunden!"; + +binmode($fh); # could be run on windows +$fh->seek(4, 0); # skip id + +my $chCnt = 0; +while (!$fh->eof()) { + $chCnt++; + + last if ($fh->read($buff, 7) != 7); + my ($nNumber, + $dwFrequency, + $sLen + ) = unpack("SLC", $buff); + + last if ($fh->read($buff, $sLen) != $sLen); + my ($csName) = unpack("A$sLen", $buff); + $csName =~ s/:/./g; + $csName =~ s/^\s+//; + $csName =~ s/\s+$//; + + last if ($fh->read($buff, 54) != 54); + my ($eStandard, + $dwExtraInfo, + $ProgNr, + $wTS_ID, + $wNW_ID, + $wService_ID, + $nModulation, + $nFEC_outerinner, + $dwSymbolrate, + $b22kHz, + $bVertical_pos, + $nProgtype, + $wVideo_PID, + $wAudio_PID, + $wPMT_PID, + $wTxt_PID, + $wSubtitling_PID, + $wData_PID + ) = unpack("LLSSSSCCLLLCSSSSSS", $buff); + + # some modifications for VDR + $dwFrequency /= 1000; + $bVertical_pos = $bVertical_pos ? "v" : "h"; + $dwSymbolrate /= 1000; + $dwExtraInfo = ($dwExtraInfo == 32 || grep(($_ cmp $csName) == 0, @addCrypted)) ? $camNo : 0; + + my $x = 1; + my $orgName = $csName; + while (exists($chData{$csName})) { + $csName = "$orgName" . "_$x"; + $x++; + } + push(@chNames, $csName); + + my %tmp = ("nNumber" => $nNumber, + "dwFrequency" => $dwFrequency, + "csName" => $orgName, + "eStandard" => $eStandard, + "dwExtraInfo" => $dwExtraInfo, + "ProgNr" => $ProgNr, + "wTS_ID" => $wTS_ID, + "wNW_ID" => $wNW_ID, + "wService_ID" => $wService_ID, + "nModulation" => $nModulation, + "nFEC_outerinner" => $nFEC_outerinner, + "dwSymbolrate" => $dwSymbolrate, + "b22kHz" => $b22kHz, + "bVertical_pos" => $bVertical_pos, + "nProgtype" => $nProgtype, + "wVideo_PID" => $wVideo_PID, + "wAudio_PID" => $wAudio_PID, + "wPMT_PID" => $wPMT_PID, + "wTxt_PID" => $wTxt_PID, + "wSubtitling_PID" => $wSubtitling_PID, + "wData_PID" => $wData_PID); + $chData{$csName} = {%tmp}; +} + +print STDERR "$chCnt channels found!\n"; + +# now we print the channels.conf +# crypted TV +print ":verschlsselte Fernsehprogramme\n"; +for my $n (@chNames) { + my %tmp = %{$chData{$n}}; + printChannel($chData{$n}) if ($tmp{"nProgtype"} == 1 && $tmp{"dwExtraInfo"}); +} + +# TV +print ":Fernsehprogramme\n"; +for my $n (@chNames) { + my %tmp = %{$chData{$n}}; + printChannel($chData{$n}) if ($tmp{"nProgtype"} == 1 && !$tmp{"dwExtraInfo"}); +} + +# crypted radio +print ":verschlsselte Radioprogramme\n"; +for my $n (@chNames) { + my %tmp = %{$chData{$n}}; + printChannel($chData{$n}) if ($tmp{"nProgtype"} == 2 && $tmp{"dwExtraInfo"}); +} + +# radio +print ":Radioprogramme\n"; +for my $n (@chNames) { + my %tmp = %{$chData{$n}}; + printChannel($chData{$n}) if ($tmp{"nProgtype"} == 2 && !$tmp{"dwExtraInfo"}); +} + +sub printChannel { + my $p = shift; + my @tmp = (); + + for my $n (@outVar) { + push(@tmp, ${$p}{$n}); + } + + print join(":", @tmp), "\n"; +} diff --git a/channels.conf b/channels.conf index 4947f8238..36b5b2843 100644 --- a/channels.conf +++ b/channels.conf @@ -1,4 +1,4 @@ -RTL:12188:h:0:27500:163:104:32:0:12003 +RTL:12188:h:0:27500:163:104:105:0:12003 Sat.1:12480:v:0:27500:1791:1792:34:0:46 Pro-7:12480:v:0:27500:255:256:32:0:898 RTL2:12188:h:0:27500:166:128:68:0:12020 @@ -54,53 +54,54 @@ Star Kino:11798:h:0:27500:767:768:0:3:9 Cine Action:11798:h:0:27500:1023:1024:0:3:20 Cine Comedy:11798:h:0:27500:1279:1280:0:3:29 Sci Fantasy:11798:h:0:27500:1535:1536:0:3:41 -Romantic Movies:11798:h:0:27500:1791:1792:0:3:11 -Studio Universal:11798:h:0:27500:2047:2048:0:3:21 +Romantic Movies:11797:h:0:27500:1791:1792:0:3:11 +Studio Universal:12090:v:0:27500:255:256:0:3:36 13th Street:11797:h:0:27500:2303:2304:0:3:43 Junior:12031:h:0:27500:255:256:0:3:19 K-Toon:12032:h:0:27500:511:512:0:3:12 -Disney Channel:12031:h:0:27500:767:768:0:3:15 -Fox Kids:11798:h:0:27500:255:256:0:3:0 +Disney Channel:12090:v:0:27500:767:768:0:3:34 +Fox Kids:11797:h:0:27500:2559:2560:0:3:22 Sunset:12031:h:0:27500:1023:1024:0:3:16 Comedy:12031:h:0:27500:1279:1280:0:3:28 -Planet:12031:h:0:27500:2047:2048:0:3:13 +Planet:12090:v:0:27500:1279:1280:0:3:13 Discovery Channel:12031:h:0:27500:1791:1792:0:3:14 Krimi&Co:12031:h:0:27500:1535:1536:0:3:23 -Filmpalast:12090:v:0:27500:255:256:0:3:36 +Filmpalast:11758:h:0:27500:2559:2560:0:3:516 Heimatkanal:11758:h:0:27500:2815:2816:0:3:517 Goldstar:11758:h:0:27500:3839:3840:0:3:518 -Classica:12090:v:0:27500:767:768:0:3:34 +Classica:12031:h:0:27500:767:768:0:3:15 Seasons:12090:v:0:27500:511:512:0:3:33 -Blue Channel:11758:h:0:27500:2559:2560:0:3:516 -Cinedom 1A de:12070:h:0:27500:1279:1280:0:3:188 -Cinedom 1A en:12070:h:0:27500:1279:1281:0:3:188 -Cinedom 1B:12070:h:0:27500:1791:1792:0:3:191 -Cinedom 1C:12070:h:0:27500:767:768:0:3:185 -Cinedom 1D:11758:h:0:27500:511:512:0:3:178 -Cinedom 1E:11720:h:0:27500:1535:1537:0:3:176 +Sport 1:11720:h:0:27500:255:256:0:3:17 +Sport 2:12070:h:0:27500:2047:2048:0:3:27 +Sport 3:12070:h:0:27500:2303:2304:0:3:18 +Sport 4:12070:h:0:27500:2559:2560:0:3:24 +Feed (F1 Boxengasse):11720:h:0:27500:2559:2560:0:3:242 +Feed (F1 Data):11720:h:0:27500:3071:3072:0:3:244 +Feed (F1 Multi):11720:h:0:27500:2815:2816:0:3:243 +Feed (F1 On Board):11720:h:0:27500:2303:2304:0:3:241 +Feed (F1 Verfolger):11720:h:0:27500:2047:2048:0:3:240 +Cinedom Deluxe:12070:h:0:27500:1279:1280:0:3:188 +Cinedom 1A de:11758:h:0:27500:511:512:0:3:178 +Cinedom 1A en:11758:h:0:27500:511:513:0:3:178 +Cinedom 1B:12070:h:0:27500:767:768:0:3:185 +Cinedom 1C:12070:h:0:27500:1791:1792:0:3:191 +Cinedom 1E??:11720:h:0:27500:1535:1537:0:3:176 Cinedom 2A:12070:h:0:27500:1535:1536:0:3:189 -Cinedom 2B:12070:h:0:27500:511:512:0:3:184 -Cinedom 2C:11758:h:0:27500:767:768:0:3:179 -Cinedom 2D:11758:h:0:27500:1023:1024:0:3:193 -Cinedom 2E:11720:h:0:27500:1279:1280:0:3:183 +Cinedom 2B:11758:h:0:27500:767:768:0:3:179 +Cinedom 2C:11758:h:0:27500:1023:1024:0:3:193 +Cinedom 2D??:12070:h:0:27500:511:512:0:3:184 Cinedom 3A:11758:h:0:27500:255:256:0:3:177 Cinedom 3B:11758:h:0:27500:1279:1280:0:3:194 -Cinedom 3C:12090:v:0:27500:1279:1280:17689:3:192 -Cinedom 3D:11720:h:0:27500:511:512:0:3:180 -Cinedom 3E:11720:h:0:27500:1023:1024:0:3:182 +Cinedom 3C??:12090:v:0:27500:1279:1280:17689:3:192 Cinedom 4A:11758:h:0:27500:1535:1536:0:3:195 -Cinedom 4B:12032:h:0:27500:2559:2560:0:3:187 -Cinedom 4C:11720:h:0:27500:767:768:0:3:181 -Cinedom 4D:11720:h:0:27500:1791:1792:0:3:190 -Cinedom 4E:12070:h:0:27500:1023:1025:0:3:186 +Cinedom 4B:12070:h:0:27500:1023:1025:0:3:186 +Cinedom 4C??:11720:h:0:27500:767:768:0:3:181 +Cinedom 5A:12032:h:0:27500:2559:2560:0:3:187 +Beate Uhse_TV:11797:h:0:27500:2047:2048:0:3:21 +Blue Channel:11758:h:0:27500:2559:2560:0:3:516 Blue Movie 1:11758:h:0:27500:1791:1792:0:3:513 Blue Movie 2:11758:h:0:27500:2047:2048:0:3:514 Blue Movie 3:11758:h:0:27500:2303:2304:0:3:515 -Feed (F1 Boxengasse):11720:h:0:27500:2559:2560:0:3:242 -Feed (F1 Data):11720:h:0:27500:3071:3072:0:3:244 -Feed (F1 Multi):11720:h:0:27500:2815:2816:0:3:243 -Feed (F1 On Board):11720:h:0:27500:2303:2304:0:3:241 -Feed (F1 Verfolger):11720:h:0:27500:2047:2048:0:3:240 : TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601 Mosaico:11934:v:0:27500:165:100:0:0:29010 diff --git a/channels.conf.cable b/channels.conf.cable index 93fc3761d..c60fb8f6d 100644 --- a/channels.conf.cable +++ b/channels.conf.cable @@ -1,134 +1,167 @@ -Leitseite:346:h:0:6900:2254:0:0:5004 -Extreme Sport:346:h:0:6900:801:802:0:0 -Bloomberg:346:h:0:6900:811:812:0:0 -Fashion TV:346:h:0:6900:821:822:0:0 -LANDSCAPE:346:h:0:6900:831:832:0:0 -BET ON JAZZ:346:h:0:6900:841:842:0:0 -Via 1 - Schner Reisen:346:h:0:6900:611:612:0:50705 -Single TV:346:h:0:6900:621:622:0:0 -HomeNet:346:h:0:6900:0:0:0:0 -Einstein:346:h:0:6900:623:624:0:0 -BLUE CHANNEL:354:h:0:6900:2559:2560:0:0 -GOLDSTAR TV:354:h:0:6900:3839:3840:1:0 -HEIMATKANAL:354:h:0:6900:2815:2816:1:0 -100,6:354:h:0:6900:0:1312:0:0 -SPORT 1:362:h:0:6900:255:256:1:0 -LOVE SONGS:362:h:0:6900:0:320:1:0 -MUSICALS:362:h:0:6900:0:336:1:0 -EASY LISTENING:362:h:0:6900:0:304:1:0 -HITLISTE:362:h:0:6900:0:784:1:0 -ALTERNATIVE ROCK:362:h:0:6900:0:800:1:0 -DANCE:362:h:0:6900:0:816:1:0 -COUNTRY:362:h:0:6900:0:352:1:0 -CLASSIC ROCK:362:h:0:6900:0:544:1:0 -FILMMUSIK:362:h:0:6900:3552:368:1:0 -DEUTSCHE HITS:362:h:0:6900:3552:384:1:0 -SOUL CLASSICS:362:h:0:6900:3439:400:1:0 -TRK MZIGI:362:h:0:6900:0:560:1:0 -GOLD:362:h:0:6900:0:576:1:0 -KLASSIK POPULR:362:h:0:6900:3552:592:1:0 -KLASS. SYMPHONIEN:362:h:0:6900:0:608:1:0 -OPER & VOKALMUSIK:362:h:0:6900:0:624:1:0 -BAROCKMUSIK:362:h:0:6900:0:640:1:0 -JAZZ:362:h:0:6900:0:656:1:0 -Videotext:362:h:0:6900:0:0:0:0 -PREMIERE WORLD:370:h:0:6900:255:256:0:10 -PREMIERE:370:h:0:6900:511:0:1:0 -STAR KINO:370:h:0:6900:767:768:1:0 -CINE ACTION:370:h:0:6900:1023:1024:1:0 -CINE COMEDY:370:h:0:6900:1279:1280:1:0 -SCI-FANTASY:370:h:0:6900:1535:1536:1:0 -ROMANTIC MOVIES:370:h:0:6900:1791:1792:1:0 -STUDIO UNIVERSAL:370:h:0:6900:2047:2048:1:0 -13 TH STREET:370:h:0:6900:2303:2304:1:0 -FOX KIDS:370:h:0:6900:2559:2560:1:0 -DISNEY CHANNEL:378:h:0:6900:767:768:1:0 -SUNSET:378:h:0:6900:1023:1024:1:0 -COMEDY:378:h:0:6900:1279:1280:1:0 -KRIMI &CO:378:h:0:6900:1535:1536:1:0 -DISCOVERY CHANNEL:378:h:0:6900:1791:1792:1:0 -PLANET:378:h:0:6900:2047:2048:1:0 -SUPERDOM:378:h:0:6900:2303:2304:1:0 -VCR-Setup:378:h:0:6900:0:0:0:0 -Modem-Setup:378:h:0:6900:0:0:0:0 -SCHLAGER:378:h:0:6900:0:320:1:0 -VOLKSMUSIK:378:h:0:6900:0:336:1:0 -OLD GOLD:378:h:0:6900:0:304:1:0 -TM V1.0:378:h:0:6900:0:0:1:0 -JUNIOR:378:h:0:6900:255:256:1:0 -KICK 1:386:h:0:6900:255:256:1:0 -KICK 2:386:h:0:6900:2559:2560:1:0 -ZDF.digitext:394:h:0:6900:0:0:0:0 -ZDF:394:h:0:6900:110:120:0:28006 -DLR-Berlin:394:h:0:6900:0:710:0:0 -DLF-Kln:394:h:0:6900:0:810:0:0 -3sat:394:h:0:6900:210:0:0:28007 -KiKa:394:h:0:6900:0:0:0:28008 -Eurosport:394:h:0:6900:410:0:0:28009 -ZDF.info:394:h:0:6900:610:620:0:28011 -EuroNews:394:h:0:6900:2221:2233:0:28015 -ZDF Theaterkanal:394:h:0:6900:1110:0:0:0 -ZDF.doku:394:h:0:6900:660:670:0:28014 -SEASONS:402:h:0:6900:1040:1044:1:0 -CLASSICA:402:h:0:6900:1030:1034:1:0 -FILMPALAST:402:h:0:6900:1050:1054:1:0 -Blockmaster:402:h:0:6900:0:0:1:0 -Test-R:410:h:0:6900:901:0:0:0 -Bayerisches FS:410:h:0:6900:201:202:0:0 -Bayern 4 Klassik:410:h:0:6900:0:3001:0:0 -B5 aktuell:410:h:0:6900:0:3101:0:0 -WDR FERNSEHEN:410:h:0:6900:601:602:0:28111 -Bremen 2:410:h:0:6900:0:3801:0:0 -arte:410:h:0:6900:401:402:0:28109 -Bayern 1:410:h:0:6900:0:3601:0:0 -NDR 4 Info:410:h:0:6900:0:3701:0:0 -SR Fernsehen Suedwest:410:h:0:6900:501:502:0:28110 -SR 1:410:h:0:6900:0:3901:0:0 -Das Erste:410:h:0:6900:101:102:0:28106 -HR2 plus:410:h:0:6900:0:3401:0:0 -HR2:410:h:0:6900:0:3301:0:0 -hessen fernsehen:410:h:0:6900:301:302:0:28108 -hr-chronos:410:h:0:6900:0:3201:0:0 -HR XXL:410:h:0:6900:0:3501:0:0 -hessen:10160:h:1:6900:301:302:0:28108 -BR:10160:h:1:6900:201:202:0:28107 -BR-alpha:410:h:0:6900:701:702:0:28112 -SWR Fernsehen:410:h:0:6900:801:802:0:28113 -Phoenix:410:h:0:6900:901:902:0:0 -ARD-Online-Kanal:426:h:0:6900:0:1805:0:0 -EinsExtra:426:h:0:6900:101:102:0:28201 -EinsFestival:426:h:0:6900:201:202:0:28202 -EinsMuXx:426:h:0:6900:301:302:0:28203 -MDR FERNSEHEN:426:h:0:6900:401:402:0:28204 -ORB-Fernsehen:426:h:0:6900:501:502:0:28205 -B1 Berlin:426:h:0:6900:601:602:0:28206 -Radio 3:426:h:0:6900:0:701:0:0 -MDR KULTUR:426:h:0:6900:0:801:0:0 -Fritz:426:h:0:6900:0:901:0:0 -JUMP:426:h:0:6900:0:1001:0:0 -MDR info:426:h:0:6900:0:1101:0:0 -SPUTNIK:426:h:0:6900:0:1201:0:0 -SFB4 Multikulti:426:h:0:6900:0:1301:0:0 -SWR-2:426:h:0:6900:0:1401:0:0 -WDR3:426:h:0:6900:0:1501:0:0 -WDR 5:426:h:0:6900:0:1601:0:0 -N3:426:h:0:6900:2401:2402:0:0 -ORF:394:h:1:6900:506:507:0:28010 -TV Polonia:434:h:0:6900:641:642:0:0 -Kanal D:434:h:0:6900:651:652:0:0 -RTP international:434:h:0:6900:661:662:0:0 -ATV:434:h:0:6900:631:632:0:0 -ERT-Sat:434:h:0:6900:691:692:0:0 -MV-Test:442:h:0:6900:0:0:0:0 -ZEE TV:442:h:0:6900:517:773:0:0 -NTV i:442:h:0:6900:514:515:0:0 -All Jazz:442:h:0:6900:0:535:0:0 -Cristal New Age:442:h:0:6900:0:536:0:0 -Movie Sounds:442:h:0:6900:0:537:0:0 -Sinfonica:442:h:0:6900:0:538:0:0 -Opernfestival:442:h:0:6900:0:539:0:0 -Barock Fantasie:442:h:0:6900:0:540:0:0 -Musica Camerata:442:h:0:6900:0:541:0:0 -Musica Antica:442:h:0:6900:0:542:0:0 -Adagio:442:h:0:6900:0:543:0:0 -Jazz Legends:442:h:0:6900:0:544:0:0 +:verschlsselte Fernsehprogramme +Extreme Sport:346:h:0:6900:801:802:0:1:50700 +Bloomberg:346:h:0:6900:811:812:0:1:50701 +Fashion TV:346:h:0:6900:821:822:0:1:50702 +BET ON JAZZ:346:h:0:6900:841:842:0:1:50704 +LANDSCAPE:346:h:0:6900:831:832:0:1:50703 +Einstein:346:h:0:6900:623:624:0:1:50719 +Single TV:346:h:0:6900:621:622:0:1:50706 +Einstein:346:h:0:6900:255:256:0:1:40100 +GOLDSTAR TV:354:h:0:6900:3839:3840:0:1:518 +HEIMATKANAL:354:h:0:6900:2815:2816:0:1:517 +FILMPALAST:354:h:0:6900:2559:2560:0:1:516 +FILMPALAST:354:h:0:6900:1535:1536:0:1:195 +FILMPALAST:354:h:0:6900:1279:1280:0:1:194 +FILMPALAST:354:h:0:6900:255:256:0:1:177 +FILMPALAST:354:h:0:6900:767:768:0:1:179 +FILMPALAST:354:h:0:6900:511:513:0:1:178 +FILMPALAST:354:h:0:6900:1023:1024:0:1:193 +BLUE MOVIE 1:354:h:0:6900:255:256:0:1:513 +BLUE MOVIE 2:354:h:0:6900:255:256:0:1:514 +BLUE MOVIE 3:354:h:0:6900:255:256:0:1:515 +SPORT 1:362:h:0:6900:255:256:0:1:17 +F1 Boxenstrasse:362:h:0:6900:2815:2816:0:1:240 +F1 Cockpit:362:h:0:6900:2559:2560:0:1:242 +F1 Multikanal:362:h:0:6900:2047:2048:0:1:243 +SPORT 1:362:h:0:6900:255:256:0:1:180 +SPORT 1:362:h:0:6900:255:256:0:1:181 +SPORT 1:362:h:0:6900:255:256:0:1:182 +SPORT 1:362:h:0:6900:255:256:0:1:183 +SPORT 1:362:h:0:6900:255:256:0:1:176 +SPORT 1:362:h:0:6900:255:256:0:1:190 +PREMIERE:370:h:0:6900:511:512:0:1:10 +STAR KINO:370:h:0:6900:767:768:0:1:9 +CINE ACTION:370:h:0:6900:1023:1024:0:1:20 +CINE COMEDY:370:h:0:6900:1279:1280:0:1:29 +SCI-FANTASY:370:h:0:6900:1535:1536:0:1:41 +ROMANTIC MOVIES:370:h:0:6900:1791:1792:0:1:11 +BEATE-UHSE.TV:370:h:0:6900:2047:2048:0:1:21 +13 TH STREET:370:h:0:6900:2303:2304:0:1:43 +FOX KIDS:370:h:0:6900:255:256:0:1:22 +SUNSET:378:h:0:6900:1023:1024:0:1:16 +COMEDY:378:h:0:6900:1279:1280:0:1:28 +KRIMI &CO:378:h:0:6900:1535:1536:0:1:23 +DISCOVERY CHANNEL:378:h:0:6900:1791:1792:0:1:14 +CLASSICA:378:h:0:6900:767:768:0:1:15 +SUPERDOM:378:h:0:6900:2303:2304:0:1:42 +K-TOON:378:h:0:6900:511:512:0:1:12 +SUPERDOM:378:h:0:6900:2047:2048:0:1:192 +SUPERDOM:378:h:0:6900:2559:2560:0:1:187 +JUNIOR:378:h:0:6900:255:256:0:1:19 +SUPERDOM 5:378:h:0:6900:2815:2816:0:1:213 +KICK 1:386:h:0:6900:255:257:0:1:26 +KICK 4:386:h:0:6900:1279:1281:0:1:188 +KICK 4:386:h:0:6900:1535:1536:0:1:189 +SPORT 2:386:h:0:6900:2047:2048:0:1:27 +KICK 4:386:h:0:6900:1023:1024:0:1:186 +KICK 2:386:h:0:6900:2559:2560:0:1:300 +KICK 4:386:h:0:6900:767:769:0:1:185 +SPORT 3:386:h:0:6900:2303:2304:0:1:18 +SUPERDOM 3:386:h:0:6900:3583:3584:0:1:211 +SPORT 4:386:h:0:6900:255:256:0:1:24 +KICK 3:386:h:0:6900:255:256:0:1:301 +KICK 4:386:h:0:6900:255:256:0:1:302 +KICK 4:386:h:0:6900:255:256:0:1:184 +KICK 4:386:h:0:6900:255:256:0:1:191 +EuroNews:394:h:0:6900:255:256:0:1:65039 +SEASONS:402:h:0:6900:1040:1044:0:1:33 +DISNEY CHANNEL:402:h:0:6900:1030:1034:0:1:34 +STUDIO UNIVERSAL:402:h:0:6900:1050:1054:0:1:36 +PLANET:402:h:0:6900:1100:1104:0:1:13 +BBC PRIME:402:h:0:6900:255:256:0:1:32 +ATV:402:h:0:6900:255:256:0:1:39 +:Fernsehprogramme +Leitseite:346:h:0:6900:2254:0:0:0:5004 +Via 1 - Schner Reisen:346:h:0:6900:611:612:0:0:50705 +PREMIERE WORLD:370:h:0:6900:255:256:32:0:8 +ZDF:394:h:0:6900:110:120:130:0:28006 +3sat:394:h:0:6900:210:220:230:0:28007 +KiKa:394:h:0:6900:255:256:0:0:28008 +Eurosport:394:h:0:6900:410:420:430:0:28009 +ZDF.info:394:h:0:6900:610:620:0:0:28011 +EuroNews:394:h:0:6900:2221:2233:768:0:28015 +ZDF Theaterkanal:394:h:0:6900:1110:1120:0:0:28016 +ZDF.doku:394:h:0:6900:660:670:0:0:28014 +Test-R:410:h:0:6900:901:902:104:0:28130 +Bayerisches FS:410:h:0:6900:201:202:204:0:28107 +WDR FERNSEHEN:410:h:0:6900:601:602:604:0:28111 +arte:410:h:0:6900:401:402:404:0:28109 +SR Fernsehen Suedwest:410:h:0:6900:501:502:504:0:28110 +Das Erste:410:h:0:6900:101:102:104:0:28106 +hessen fernsehen:410:h:0:6900:301:302:304:0:28108 +BR-alpha:410:h:0:6900:701:702:704:0:28112 +SWR Fernsehen:410:h:0:6900:801:802:804:0:28113 +Phoenix:410:h:0:6900:255:256:0:0:28114 +Phoenix:410:h:0:6900:255:256:0:0:61225 +ARD-Online-Kanal:426:h:0:6900:0:1801:0:0:28218 +EinsExtra:426:h:0:6900:101:102:0:0:28201 +EinsFestival:426:h:0:6900:201:202:0:0:28202 +EinsMuXx:426:h:0:6900:301:302:0:0:28203 +MDR FERNSEHEN:426:h:0:6900:401:402:404:0:28204 +ORB-Fernsehen:426:h:0:6900:501:502:504:0:28205 +B1 Berlin:426:h:0:6900:601:602:604:0:28206 +N3:426:h:0:6900:2401:2402:2404:0:28224 +TV Polonia:434:h:0:6900:641:642:0:0:53204 +Kanal D:434:h:0:6900:651:652:0:0:53205 +RTP international:434:h:0:6900:661:662:0:0:53206 +ATV:434:h:0:6900:631:632:0:0:53203 +ERT-Sat:434:h:0:6900:691:692:0:0:53209 +CNE:434:h:0:6900:255:256:0:0:53208 +ERT-Sat:434:h:0:6900:255:256:0:0:48587 +ZEE TV:442:h:0:6900:517:773:0:0:53301 +NTV i:442:h:0:6900:514:515:0:0:53302 +:verschlsselte Radioprogramme +LOVE SONGS:362:h:0:6900:0:320:0:1:163 +MUSICALS:362:h:0:6900:0:336:0:1:164 +EASY LISTENING:362:h:0:6900:0:304:0:1:162 +HITLISTE:362:h:0:6900:0:784:0:1:150 +ALTERNATIVE ROCK:362:h:0:6900:0:800:0:1:151 +DANCE:362:h:0:6900:0:816:0:1:152 +COUNTRY:362:h:0:6900:0:352:0:1:153 +CLASSIC ROCK:362:h:0:6900:0:544:0:1:154 +FILMMUSIK:362:h:0:6900:0:368:0:1:155 +DEUTSCHE HITS:362:h:0:6900:0:384:0:1:156 +SOUL CLASSICS:362:h:0:6900:0:400:0:1:157 +TRK MZIGI:362:h:0:6900:0:560:0:1:158 +GOLD:362:h:0:6900:0:576:0:1:159 +KLASSIK POPULR:362:h:0:6900:0:592:0:1:145 +KLASS. SYMPHONIEN:362:h:0:6900:0:608:0:1:146 +OPER & VOKALMUSIK:362:h:0:6900:0:624:0:1:147 +BAROCKMUSIK:362:h:0:6900:0:640:0:1:148 +SCHLAGER:378:h:0:6900:0:320:0:1:166 +VOLKSMUSIK:378:h:0:6900:0:336:0:1:167 +OLD GOLD:378:h:0:6900:0:304:0:1:165 +:Radioprogramme +100,6:354:h:0:6900:0:1312:0:0:161 +DLR-Berlin:394:h:0:6900:0:710:0:0:28012 +DLF-Kln:394:h:0:6900:0:810:0:0:28013 +sterreich 1:394:h:0:6900:0:169:0:0:28017 +Bayern 4 Klassik:410:h:0:6900:0:3001:0:0:28120 +B5 aktuell:410:h:0:6900:0:3101:0:0:28121 +Bremen 2:410:h:0:6900:0:3801:0:0:28128 +Bayern 1:410:h:0:6900:0:3601:0:0:28126 +NDR 4 Info:410:h:0:6900:0:3701:0:0:28127 +SR 1:410:h:0:6900:0:3901:0:0:28129 +HR2 plus:410:h:0:6900:0:3401:0:0:28124 +HR2:410:h:0:6900:0:3301:0:0:28123 +hr-chronos:410:h:0:6900:0:3201:0:0:28122 +HR XXL:410:h:0:6900:0:3501:0:0:28125 +Radio 3:426:h:0:6900:0:701:0:0:28207 +MDR KULTUR:426:h:0:6900:0:801:0:0:28208 +Fritz:426:h:0:6900:0:901:0:0:28209 +JUMP:426:h:0:6900:0:1001:0:0:28210 +MDR info:426:h:0:6900:0:1101:0:0:28211 +SPUTNIK:426:h:0:6900:0:1201:0:0:28212 +SFB4 Multikulti:426:h:0:6900:0:1301:0:0:28213 +SWR-2:426:h:0:6900:0:1401:0:0:28214 +WDR3:426:h:0:6900:0:1501:0:0:28215 +WDR Radio 5:426:h:0:6900:0:1601:0:0:28216 +All Jazz:442:h:0:6900:0:535:0:0:53350 +Cristal New Age:442:h:0:6900:0:536:0:0:53351 +Movie Sounds:442:h:0:6900:0:537:0:0:53352 +Sinfonica:442:h:0:6900:0:538:0:0:53353 +Opernfestival:442:h:0:6900:0:539:0:0:53354 +Barock Fantasie:442:h:0:6900:0:540:0:0:53355 +Musica Camerata:442:h:0:6900:0:541:0:0:53356 +Musica Antica:442:h:0:6900:0:542:0:0:53357 +Adagio:442:h:0:6900:0:543:0:0:53358 diff --git a/config.c b/config.c index 66eb1780e..acf1996ae 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.43 2001/02/24 13:20:18 kls Exp $ + * $Id: config.c 1.44 2001/04/01 14:32:22 kls Exp $ */ #include "config.h" @@ -75,37 +75,39 @@ bool cKeys::Load(const char *FileName) result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; - char *Name = buffer; - char *p = strpbrk(Name, " \t"); - if (p) { - *p = 0; // terminates 'Name' - while (*++p && isspace(*p)) - ; - if (*p) { - if (strcasecmp(Name, "Code") == 0) - code = *p; - else if (strcasecmp(Name, "Address") == 0) - address = strtol(p, NULL, 16); - else { - for (tKey *k = keys; k->type != kNone; k++) { - if (strcasecmp(Name, k->name) == 0) { - k->code = strtol(p, NULL, 16); - Name = NULL; // to indicate that we found it + if (!isempty(buffer)) { + char *Name = buffer; + char *p = strpbrk(Name, " \t"); + if (p) { + *p = 0; // terminates 'Name' + while (*++p && isspace(*p)) + ; + if (*p) { + if (strcasecmp(Name, "Code") == 0) + code = *p; + else if (strcasecmp(Name, "Address") == 0) + address = strtol(p, NULL, 16); + else { + for (tKey *k = keys; k->type != kNone; k++) { + if (strcasecmp(Name, k->name) == 0) { + k->code = strtol(p, NULL, 16); + Name = NULL; // to indicate that we found it + break; + } + } + if (Name) { + esyslog(LOG_ERR, "unknown key in %s, line %d\n", fileName, line); + result = false; break; } } - if (Name) { - esyslog(LOG_ERR, "unknown key in %s, line %d\n", fileName, line); - result = false; - break; - } - } + } + continue; } - continue; + esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); + result = false; + break; } - esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); - result = false; - break; } fclose(f); } @@ -782,10 +784,12 @@ bool cSetup::Load(const char *FileName) bool result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; - if (*buffer != '#' && !Parse(buffer)) { - esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); - result = false; - break; + if (!isempty(buffer)) { + if (*buffer != '#' && !Parse(buffer)) { + esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); + result = false; + break; + } } } fclose(f); diff --git a/config.h b/config.h index 60a95c3af..6c21fb2f6 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.42 2001/02/24 13:19:39 kls Exp $ + * $Id: config.h 1.44 2001/04/01 14:44:40 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.71" +#define VDRVERSION "0.72" #define MaxBuffer 10000 @@ -184,14 +184,16 @@ template class cConfig : public cList { result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; - T *l = new T; - if (l->Parse(buffer)) - Add(l); - else { - esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); - delete l; - result = false; - break; + if (!isempty(buffer)) { + T *l = new T; + if (l->Parse(buffer)) + Add(l); + else { + esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); + delete l; + result = false; + break; + } } } fclose(f); diff --git a/dvbapi.c b/dvbapi.c index 8518d7f99..a929b5039 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.61 2001/02/24 13:13:19 kls Exp $ + * $Id: dvbapi.c 1.66 2001/03/31 15:01:57 kls Exp $ */ #include "dvbapi.h" @@ -22,6 +22,8 @@ extern "C" { #include "config.h" #include "interface.h" #include "recording.h" +#include "remux.h" +#include "ringbuffer.h" #include "tools.h" #include "videodir.h" @@ -29,29 +31,9 @@ extern "C" { #define VBIDEVICE "/dev/vbi" // The size of the array used to buffer video data: +// (must be larger than MINVIDEODATA - see remux.h) #define VIDEOBUFSIZE (1024*1024) -// The minimum amount of video data necessary to identify frames -// (must be smaller than VIDEOBUFSIZE!): -#define MINVIDEODATA (256*1024) // just a safe guess (max. size of any frame block, plus some safety) - -// The maximum time the buffer is allowed to write data to disk when recording: -#define MAXRECORDWRITETIME 50 // ms - -// Picture types: -#define NO_PICTURE 0 -#define I_FRAME 1 -#define P_FRAME 2 -#define B_FRAME 3 - -// Start codes: -#define SC_PICTURE 0x00 // "picture header" -#define SC_SEQU 0xB3 // "sequence header" -#define SC_PHEAD 0xBA // "pack header" -#define SC_SHEAD 0xBB // "system header" -#define SC_AUDIO 0xC0 -#define SC_VIDEO 0xE0 - #define FRAMESPERSEC 25 // The maximum file size is limited by the range that can be covered @@ -333,7 +315,7 @@ int cIndexFile::Get(uchar FileNumber, int FileOffset) return -1; } -// --- cRingBuffer ----------------------------------------------------------- +// --- cRingBuffer_ ----------------------------------------------------------- /* cRingBuffer reads data from an input file, stores it in a buffer and writes it to an output file upon request. The Read() and Write() functions should @@ -344,7 +326,7 @@ int cIndexFile::Get(uchar FileNumber, int FileOffset) will be made. */ -class cRingBuffer { +class cRingBuffer_ { private: uchar *buffer; int size, head, tail, freeLimit, availLimit; @@ -367,8 +349,8 @@ class cRingBuffer { int FindStartCode(uchar Code, int Offset = 0); int GetPacketLength(int Offset = 0); public: - cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); - virtual ~cRingBuffer(); + cRingBuffer_(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); + virtual ~cRingBuffer_(); virtual int Read(int Max = -1); virtual int Write(int Max = -1); bool EndOfFile(void) { return eof; } @@ -377,7 +359,7 @@ class cRingBuffer { void Skip(int n); }; -cRingBuffer::cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit, int AvailLimit) +cRingBuffer_::cRingBuffer_(int *InFile, int *OutFile, int Size, int FreeLimit, int AvailLimit) { inFile = InFile; outFile = OutFile; @@ -393,13 +375,13 @@ cRingBuffer::cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit, int esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size); } -cRingBuffer::~cRingBuffer() +cRingBuffer_::~cRingBuffer_() { dsyslog(LOG_INFO, "buffer stats: %d free, %d overflows, limit exceeded %d times", minFree, countOverflow, countLimit); delete buffer; } -int cRingBuffer::Byte(int Offset) +int cRingBuffer_::Byte(int Offset) { if (buffer && Offset < Available()) { Offset += head; @@ -410,7 +392,7 @@ int cRingBuffer::Byte(int Offset) return -1; } -bool cRingBuffer::Set(int Offset, int Length, int Value) +bool cRingBuffer_::Set(int Offset, int Length, int Value) { if (buffer && Offset + Length <= Available() ) { Offset += head; @@ -425,7 +407,7 @@ bool cRingBuffer::Set(int Offset, int Length, int Value) return false; } -void cRingBuffer::Skip(int n) +void cRingBuffer_::Skip(int n) { if (n > 0) { if (head < tail) { @@ -443,7 +425,7 @@ void cRingBuffer::Skip(int n) } } -int cRingBuffer::Read(int Max) +int cRingBuffer_::Read(int Max) { if (buffer) { eof = false; @@ -501,7 +483,7 @@ int cRingBuffer::Read(int Max) return -1; } -int cRingBuffer::Write(int Max) +int cRingBuffer_::Write(int Max) { if (buffer) { int avail = Available(); @@ -540,7 +522,7 @@ int cRingBuffer::Write(int Max) return -1; } -int cRingBuffer::FindStartCode(uchar Code, int Offset) +int cRingBuffer_::FindStartCode(uchar Code, int Offset) { // Searches for a start code (beginning at Offset) and returns the number // of bytes from Offset to the start code. @@ -557,7 +539,7 @@ int cRingBuffer::FindStartCode(uchar Code, int Offset) return -1; } -int cRingBuffer::GetPacketLength(int Offset) +int cRingBuffer_::GetPacketLength(int Offset) { // Returns the entire length of the packet starting at offset. return (Byte(Offset + 4) << 8) + Byte(Offset + 5) + 6; @@ -671,31 +653,29 @@ int cFileName::NextFile(void) // --- cRecordBuffer --------------------------------------------------------- -class cRecordBuffer : public cRingBuffer, public cThread { +class cRecordBuffer : public cRingBuffer { private: cFileName fileName; cIndexFile *index; + cRemux remux; uchar pictureType; int fileSize; int videoDev; int recordFile; - bool ok, synced, stop; + bool recording; time_t lastDiskSpaceCheck; bool RunningLowOnDiskSpace(void); - int ScanVideoPacket(int *PictureType, int Offset); - int Synchronize(void); bool NextFile(void); - virtual int Write(int Max = -1); - bool WriteWithTimeout(void); protected: - virtual void Action(void); + virtual void Input(void); + virtual void Output(void); public: cRecordBuffer(int *InFile, const char *FileName); virtual ~cRecordBuffer(); }; cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) -:cRingBuffer(InFile, &recordFile, VIDEOBUFSIZE, VIDEOBUFSIZE / 10, 0) +:cRingBuffer(VIDEOBUFSIZE) ,fileName(FileName, true) { index = NULL; @@ -703,7 +683,7 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) fileSize = 0; videoDev = *InFile; recordFile = fileName.Open(); - ok = synced = stop = false; + recording = false; lastDiskSpaceCheck = time(NULL); if (!fileName.Name()) return; @@ -712,44 +692,15 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) if (!index) esyslog(LOG_ERR, "ERROR: can't allocate index"); // let's continue without index, so we'll at least have the recording - ok = true; Start(); } cRecordBuffer::~cRecordBuffer() { - stop = true; - Cancel(3); + Stop(); delete index; } -void cRecordBuffer::Action(void) -{ - dsyslog(LOG_INFO, "recording thread started (pid=%d)", getpid()); - - time_t t = time(NULL); - for (;;) { - usleep(1); // this keeps the CPU load low - - LOCK_THREAD; - - int r = Read(); - if (r >= 0) { - if (r > 0) - t = time(NULL); - if (!WriteWithTimeout()) - break; - } - if (r < 0 || (r == 0 && time(NULL) - t > 5)) { - esyslog(LOG_ERR, "ERROR: video data stream broken"); - t = time(NULL); - } - } - SetPlayMode(videoDev, VID_PLAY_RESET); - - dsyslog(LOG_INFO, "end recording thread"); -} - bool cRecordBuffer::RunningLowOnDiskSpace(void) { if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) { @@ -763,88 +714,6 @@ bool cRecordBuffer::RunningLowOnDiskSpace(void) return false; } -int cRecordBuffer::ScanVideoPacket(int *PictureType, int Offset) -{ - // Scans the video packet starting at Offset and returns its length. - // If the return value is -1 the packet was not completely in the buffer. - - int Length = GetPacketLength(Offset); - if (Length <= Available()) { - int i = Offset + 8; // the minimum length of the video packet header - i += Byte(i) + 1; // possible additional header bytes - for (; i < Offset + Length; i++) { - if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { - switch (Byte(i + 3)) { - case SC_PICTURE: *PictureType = GetPictureType(i); - return Length; - } - } - } - *PictureType = NO_PICTURE; - return Length; - } - return -1; -} - -int cRecordBuffer::Synchronize(void) -{ - // Positions to the start of a data block (skipping everything up to - // an I-frame if not synced) and returns the block length. - - pictureType = NO_PICTURE; - - //XXX remove this once the buffer is handled with two separate threads: - if (!synced && Free() < 100000) { - dsyslog(LOG_INFO, "unable to synchronize, dropped %d bytes", Available()); - Clear(); - return 0; - } - for (int i = 0; Available() > MINVIDEODATA && i < MINVIDEODATA; i++) { - if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { - switch (Byte(i + 3)) { - case SC_VIDEO: { - int pt = NO_PICTURE; - int l = ScanVideoPacket(&pt, i); - if (l < 0) - return 0; // no useful data found, wait for more - if (pt != NO_PICTURE) { - if (pt < I_FRAME || B_FRAME < pt) { - esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); - } - else if (pictureType == NO_PICTURE) { - if (!synced) { - if (pt == I_FRAME) { - Skip(i); - synced = true; - } - else { - Skip(i + l); - i = 0; - break; - } - } - if (synced) - pictureType = pt; - } - else - return i; - } - else if (!synced) { - Skip(i + l); - i = 0; - break; - } - i += l - 1; // -1 to compensate for i++ in the loop! - } - break; - case SC_AUDIO: i += GetPacketLength(i) - 1; // -1 to compensate for i++ in the loop! - break; - } - } - } - return 0; // no useful data found, wait for more -} - bool cRecordBuffer::NextFile(void) { if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME @@ -856,56 +725,93 @@ bool cRecordBuffer::NextFile(void) return recordFile >= 0; } -int cRecordBuffer::Write(int Max) +void cRecordBuffer::Input(void) { - // This function ignores the incoming 'Max'! - // It tries to write out exactly *one* frame block. - if (!ok) - return -1; - int n = Synchronize(); - if (n) { - if (stop && pictureType == I_FRAME) { - ok = false; - return -1; // finish the recording before the next 'I' frame - } - if (NextFile()) { - if (index && pictureType != NO_PICTURE) - index->Write(pictureType, fileName.Number(), fileSize); - int written = 0; - for (;;) { - int w = cRingBuffer::Write(n); - if (w >= 0) { - fileSize += w; - written += w; - n -= w; - if (n == 0) - return written; + dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid()); + + uchar b[MINVIDEODATA]; + time_t t = time(NULL); + recording = true; + for (;;) { + int r = read(videoDev, b, sizeof(b)); + if (r > 0) { + uchar *p = b; + while (r > 0) { + int w = Put(p, r); + p += w; + r -= w; } - else - return w; + t = time(NULL); + } + else if (r < 0) { + if (errno != EAGAIN) { + LOG_ERROR; + break; } - } - return -1; - } - return 0; + } + else if (time(NULL) - t > 5) { + esyslog(LOG_ERR, "ERROR: video data stream broken"); + t = time(NULL); + } + cFile::FileReady(videoDev, 100); + if (!recording) + break; + } + SetPlayMode(videoDev, VID_PLAY_RESET); + + dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid()); } -bool cRecordBuffer::WriteWithTimeout(void) +void cRecordBuffer::Output(void) { - int t0 = time_ms(); - do { - int w = Write(); - if (w < 0) - return false; - if (w == 0) - break; - } while (time_ms() - t0 < MAXRECORDWRITETIME); - return true; + dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); + + uchar b[MINVIDEODATA * 2]; + int r = 0; + for (;;) { + usleep(1); // this keeps the CPU load low + r += Get(b + r, sizeof(b) - r); + if (r > 0) { + //XXX buffer full??? + int Count = r, Result; + const uchar *p = remux.Process(b, Count, Result, pictureType); + if (p) { + if (!Busy() && pictureType == I_FRAME) // finish the recording before the next 'I' frame + break; + if (NextFile()) { + if (index && pictureType != NO_PICTURE) + index->Write(pictureType, fileName.Number(), fileSize); + while (Result > 0) { + int w = write(recordFile, p, Result); + if (w < 0) { + LOG_ERROR_STR(fileName.Name()); + recording = false; + return; + } + p += w; + Result -= w; + fileSize += w; + } + } + else + break; + } + if (Count > 0) { + r -= Count; + memmove(b, b + Count, r); + } + if (!recording) + break; + } + } + recording = false; + + dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); } // --- cReplayBuffer --------------------------------------------------------- -class cReplayBuffer : public cRingBuffer, public cThread { +class cReplayBuffer : public cRingBuffer_, public cThread { private: enum eReplayCmd { rcNone, rcStill, rcPause, rcPlay, rcForward, rcBackward }; enum eReplayMode { rmStill, rmPlay, rmFastForward, rmFastRewind, rmSlowRewind }; @@ -944,7 +850,7 @@ class cReplayBuffer : public cRingBuffer, public cThread { }; cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName) -:cRingBuffer(&replayFile, OutFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) +:cRingBuffer_(&replayFile, OutFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) ,fileName(FileName, false) { index = NULL; @@ -1271,7 +1177,7 @@ int cReplayBuffer::Read(int Max = -1) int readin = 0; do { // If Max is > 0 here we need to make sure we read in the entire block! - int r = cRingBuffer::Read(Max); + int r = cRingBuffer_::Read(Max); if (r >= 0) readin += r; else @@ -1300,7 +1206,7 @@ int cReplayBuffer::Write(int Max) if (Max) { int w; do { - w = cRingBuffer::Write(Max); + w = cRingBuffer_::Write(Max); if (w >= 0) { fileOffset += w; Written += w; @@ -1348,7 +1254,7 @@ void cTransferBuffer::Action(void) { dsyslog(LOG_INFO, "data transfer thread started (pid=%d)", getpid()); - cRingBuffer Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); + cRingBuffer_ Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); active = true; while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start Buffer.Read(); // initializes fromDevice for reading @@ -1364,7 +1270,7 @@ void cTransferBuffer::Action(void) // --- cCuttingBuffer -------------------------------------------------------- -class cCuttingBuffer : public cRingBuffer, public cThread { +class cCuttingBuffer : public cRingBuffer_, public cThread { private: bool active; int fromFile, toFile; @@ -1379,7 +1285,7 @@ class cCuttingBuffer : public cRingBuffer, public cThread { }; cCuttingBuffer::cCuttingBuffer(const char *FromFileName, const char *ToFileName) -:cRingBuffer(&fromFile, &toFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) +:cRingBuffer_(&fromFile, &toFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) { active = false; fromFile = toFile = -1; @@ -1438,7 +1344,7 @@ void cCuttingBuffer::Action(void) CurrentFileNumber = FileNumber; } if (fromFile >= 0) - Length = cRingBuffer::Read(Length); + Length = cRingBuffer_::Read(Length); else break; } @@ -1456,7 +1362,7 @@ void cCuttingBuffer::Action(void) } LastIFrame = 0; } - cRingBuffer::Write(Length); + cRingBuffer_::Write(Length); toIndex->Write(PictureType, toFileName->Number(), FileSize); FileSize += Length; if (!LastIFrame) @@ -1535,7 +1441,7 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK); if (videoDev >= 0) { siProcessor = new cSIProcessor(VbiFileName); - if (!NumDvbApis) // only the first one shall set the system time + if (!dvbApi[0]) // only the first one shall set the system time siProcessor->SetUseTSTime(Setup.SetSystemTime); siProcessor->AddFilter(0x14, 0x70); // TDT siProcessor->AddFilter(0x14, 0x73); // TOT @@ -1582,7 +1488,7 @@ cDvbApi::~cDvbApi() StopTransfer(); OvlO(false); //Overlay off! //XXX the following call sometimes causes a segfault - driver problem? - close(videoDev); + //XXX close(videoDev); } #if defined(DEBUG_OSD) || defined(REMOTE_KBD) endwin(); @@ -1611,7 +1517,7 @@ cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) { cDvbApi *d = NULL, *dMinPriority = NULL; int index = Ca - 1; - for (int i = MAXDVBAPI; --i >= 0; ) { + for (int i = 0; i < MAXDVBAPI; i++) { if (dvbApi[i]) { if (i == index) { // means we need exactly _this_ device d = dvbApi[i]; @@ -2136,6 +2042,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, if (videoDev >= 0) { cThreadLock ThreadLock(siProcessor); // makes sure the siProcessor won't access the vbi-device while switching StopTransfer(); + StopReplay(); SetPlayMode(videoDev, VID_PLAY_RESET); struct frontend front; ioctl(videoDev, VIDIOCGFRONTEND, &front); diff --git a/eit.c b/eit.c index 08588b06b..6cbe504d3 100644 --- a/eit.c +++ b/eit.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.12 2001/02/24 12:12:58 kls Exp $ + * $Id: eit.c 1.15 2001/04/01 15:36:09 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -39,11 +39,11 @@ // --- cMJD ------------------------------------------------------------------ class cMJD { -public: - cMJD(); - cMJD(u_char date_hi, u_char date_lo); - cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese); - ~cMJD(); +public: + cMJD(); + cMJD(u_char date_hi, u_char date_lo); + cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese); + ~cMJD(); /** */ void ConvertToTime(); /** */ @@ -73,18 +73,18 @@ cMJD::cMJD() cMJD::cMJD(u_char date_hi, u_char date_lo) { - mjd = date_hi << 8 | date_lo; - time_hour = time_minute = time_second = 0; - ConvertToTime(); + mjd = date_hi << 8 | date_lo; + time_hour = time_minute = time_second = 0; + ConvertToTime(); } cMJD::cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese) { - mjd = date_hi << 8 | date_lo; - time_hour = timehr; - time_minute = timemi; - time_second = timese; - ConvertToTime(); + mjd = date_hi << 8 | date_lo; + time_hour = timehr; + time_minute = timemi; + time_second = timese; + ConvertToTime(); } cMJD::~cMJD() @@ -94,103 +94,102 @@ cMJD::~cMJD() /** */ void cMJD::ConvertToTime() { - struct tm t; - - t.tm_sec = time_second; - t.tm_min = time_minute; - t.tm_hour = time_hour; - int k; - - t.tm_year = (int) ((mjd - 15078.2) / 365.25); - t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001); - t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001)); - k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0; - t.tm_year = t.tm_year + k; - t.tm_mon = t.tm_mon - 1 - k * 12; - t.tm_mon--; - - t.tm_isdst = -1; - t.tm_gmtoff = 0; - - mjdtime = timegm(&t); - - //isyslog(LOG_INFO, "Time parsed = %s\n", ctime(&mjdtime)); + struct tm t; + + t.tm_sec = time_second; + t.tm_min = time_minute; + t.tm_hour = time_hour; + int k; + + t.tm_year = (int) ((mjd - 15078.2) / 365.25); + t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001); + t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001)); + k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0; + t.tm_year = t.tm_year + k; + t.tm_mon = t.tm_mon - 1 - k * 12; + t.tm_mon--; + + t.tm_isdst = -1; + t.tm_gmtoff = 0; + + mjdtime = timegm(&t); + + //isyslog(LOG_INFO, "Time parsed = %s\n", ctime(&mjdtime)); } /** */ bool cMJD::SetSystemTime() { - struct tm *ptm; - time_t loctim; - - ptm = localtime(&mjdtime); - loctim = time(NULL); - - if (abs(mjdtime - loctim) > 2) - { - isyslog(LOG_INFO, "System Time = %s (%ld)\n", ctime(&loctim), loctim); - isyslog(LOG_INFO, "Local Time = %s (%ld)\n", ctime(&mjdtime), mjdtime); - if (stime(&mjdtime) < 0) + struct tm *ptm; + time_t loctim; + + ptm = localtime(&mjdtime); + loctim = time(NULL); + + if (abs(mjdtime - loctim) > 2) + { + isyslog(LOG_INFO, "System Time = %s (%ld)\n", ctime(&loctim), loctim); + isyslog(LOG_INFO, "Local Time = %s (%ld)\n", ctime(&mjdtime), mjdtime); + if (stime(&mjdtime) < 0) esyslog(LOG_ERR, "ERROR while setting system time: %m"); - return true; - } - - return false; + return true; + } + + return false; } /** */ time_t cMJD::GetTime_t() { - return mjdtime; + return mjdtime; } // --- cTDT ------------------------------------------------------------------ typedef struct { - u_char table_id : 8; + u_char table_id : 8; #if BYTE_ORDER == BIG_ENDIAN - u_char section_syntax_indicator : 1; - u_char : 3; - u_char section_length_hi : 4; + u_char section_syntax_indicator : 1; + u_char : 3; + u_char section_length_hi : 4; #else - u_char section_length_hi : 4; - u_char : 3; - u_char section_syntax_indicator : 1; + u_char section_length_hi : 4; + u_char : 3; + u_char section_syntax_indicator : 1; #endif - u_char section_length_lo : 8; + u_char section_length_lo : 8; - u_char utc_date_hi : 8; - u_char utc_date_lo : 8; - u_char utc_hour : 4; - u_char utc_hour_ten : 4; - u_char utc_min : 4; - u_char utc_min_ten : 4; - u_char utc_sec : 4; - u_char utc_sec_ten : 4; + u_char utc_date_hi : 8; + u_char utc_date_lo : 8; + u_char utc_hour : 4; + u_char utc_hour_ten : 4; + u_char utc_min : 4; + u_char utc_min_ten : 4; + u_char utc_sec : 4; + u_char utc_sec_ten : 4; } tdt_t; class cTDT { -public: - cTDT(tdt_t *ptdt); - ~cTDT(); +public: + cTDT(tdt_t *ptdt); + ~cTDT(); /** */ bool SetSystemTime(); protected: // Protected attributes /** */ tdt_t tdt; /** */ - cMJD * mjd; + cMJD mjd; // kls 2001-03-02: made this a member instead of a pointer (it wasn't deleted in the destructor!) }; cTDT::cTDT(tdt_t *ptdt) +:tdt(*ptdt) +,mjd(tdt.utc_date_hi, tdt.utc_date_lo, tdt.utc_hour_ten * 10 + tdt.utc_hour, + tdt.utc_min_ten * 10 + tdt.utc_min, + tdt.utc_sec_ten * 10 + tdt.utc_sec) { - tdt = *ptdt; - mjd = new cMJD(tdt.utc_date_hi, tdt.utc_date_lo, - tdt.utc_hour_ten * 10 + tdt.utc_hour, - tdt.utc_min_ten * 10 + tdt.utc_min, - tdt.utc_sec_ten * 10 + tdt.utc_sec); } cTDT::~cTDT() @@ -199,22 +198,22 @@ cTDT::~cTDT() /** */ bool cTDT::SetSystemTime() { - return mjd->SetSystemTime(); + return mjd.SetSystemTime(); } // --- cEventInfo ------------------------------------------------------------ cEventInfo::cEventInfo(unsigned short serviceid, unsigned short eventid) { - pTitle = NULL; - pSubtitle = NULL; - pExtendedDescription = NULL; - bIsPresent = bIsFollowing = false; - lDuration = 0; - tTime = 0; - uEventID = eventid; - uServiceID = serviceid; - cExtendedDescriptorNumber = 0; + pTitle = NULL; + pSubtitle = NULL; + pExtendedDescription = NULL; + bIsPresent = bIsFollowing = false; + lDuration = 0; + tTime = 0; + uEventID = eventid; + uServiceID = serviceid; + cExtendedDescriptorNumber = 0; nChannelNumber = 0; } @@ -228,165 +227,165 @@ cEventInfo::~cEventInfo() /** */ const char * cEventInfo::GetTitle() const { - return pTitle; + return pTitle; } /** */ const char * cEventInfo::GetSubtitle() const { - return pSubtitle; + return pSubtitle; } /** */ const char * cEventInfo::GetExtendedDescription() const { - return pExtendedDescription; + return pExtendedDescription; } /** */ bool cEventInfo::IsPresent() const { - return bIsPresent; + return bIsPresent; } /** */ void cEventInfo::SetPresent(bool pres) { - bIsPresent = pres; + bIsPresent = pres; } /** */ bool cEventInfo::IsFollowing() const { - return bIsFollowing; + return bIsFollowing; } /** */ void cEventInfo::SetFollowing(bool foll) { - bIsFollowing = foll; + bIsFollowing = foll; } /** */ const char * cEventInfo::GetDate() const { - static char szDate[25]; + static char szDate[25]; - strftime(szDate, sizeof(szDate), "%d.%m.%Y", localtime(&tTime)); + strftime(szDate, sizeof(szDate), "%d.%m.%Y", localtime(&tTime)); - return szDate; + return szDate; } /** */ const char * cEventInfo::GetTimeString() const { - static char szTime[25]; - - strftime(szTime, sizeof(szTime), "%R", localtime(&tTime)); - - return szTime; + static char szTime[25]; + + strftime(szTime, sizeof(szTime), "%R", localtime(&tTime)); + + return szTime; } /** */ const char * cEventInfo::GetEndTimeString() const { - static char szEndTime[25]; + static char szEndTime[25]; time_t tEndTime = tTime + lDuration; - - strftime(szEndTime, sizeof(szEndTime), "%R", localtime(&tEndTime)); - - return szEndTime; + + strftime(szEndTime, sizeof(szEndTime), "%R", localtime(&tEndTime)); + + return szEndTime; } /** */ time_t cEventInfo::GetTime() const { - return tTime; + return tTime; } /** */ long cEventInfo::GetDuration() const { - return lDuration; + return lDuration; } /** */ unsigned short cEventInfo::GetEventID() const { - return uEventID; + return uEventID; } /** */ bool cEventInfo::SetTitle(char *string) { - if (string == NULL) - return false; - - pTitle = strdup(string); - if (pTitle == NULL) - return false; - - return true; + if (string == NULL) + return false; + + pTitle = strdup(string); + if (pTitle == NULL) + return false; + + return true; } /** */ bool cEventInfo::SetSubtitle(char *string) { - if (string == NULL) - return false; - - pSubtitle = strdup(string); - if (pSubtitle == NULL) - return false; - - return true; + if (string == NULL) + return false; + + pSubtitle = strdup(string); + if (pSubtitle == NULL) + return false; + + return true; } /** */ bool cEventInfo::AddExtendedDescription(char *string) { - int size = 0; - bool first = true; - char *p; - - if (string == NULL) - return false; - - if (pExtendedDescription) - { - first = false; - size += strlen(pExtendedDescription); - } - - size += (strlen(string) + 1); - - p = (char *)realloc(pExtendedDescription, size); - if (p == NULL) - return false; - - if (first) - *p = 0; - - strcat(p, string); - - pExtendedDescription = p; - - return true; + int size = 0; + bool first = true; + char *p; + + if (string == NULL) + return false; + + if (pExtendedDescription) + { + first = false; + size += strlen(pExtendedDescription); + } + + size += (strlen(string) + 1); + + p = (char *)realloc(pExtendedDescription, size); + if (p == NULL) + return false; + + if (first) + *p = 0; + + strcat(p, string); + + pExtendedDescription = p; + + return true; } /** */ void cEventInfo::SetTime(time_t t) { - tTime = t; + tTime = t; } /** */ void cEventInfo::SetDuration(long l) { - lDuration = l; + lDuration = l; } /** */ void cEventInfo::SetEventID(unsigned short evid) { - uEventID = evid; + uEventID = evid; } /** */ void cEventInfo::SetServiceID(unsigned short servid) { - uServiceID = servid; + uServiceID = servid; } /** */ u_char cEventInfo::GetExtendedDescriptorNumber() const { - return cExtendedDescriptorNumber; + return cExtendedDescriptorNumber; } /** */ void cEventInfo::IncreaseExtendedDescriptorNumber() { - cExtendedDescriptorNumber++; + cExtendedDescriptorNumber++; } /** */ @@ -396,17 +395,17 @@ unsigned short cEventInfo::GetServiceID() const } /** */ -void cEventInfo::Dump(FILE *f) const +void cEventInfo::Dump(FILE *f, const char *Prefix) const { if (tTime + lDuration >= time(NULL)) { - fprintf(f, "E %u %ld %ld\n", uEventID, tTime, lDuration); + fprintf(f, "%sE %u %ld %ld\n", Prefix, uEventID, tTime, lDuration); if (!isempty(pTitle)) - fprintf(f, "T %s\n", pTitle); + fprintf(f, "%sT %s\n", Prefix, pTitle); if (!isempty(pSubtitle)) - fprintf(f, "S %s\n", pSubtitle); + fprintf(f, "%sS %s\n", Prefix, pSubtitle); if (!isempty(pExtendedDescription)) - fprintf(f, "D %s\n", pExtendedDescription); - fprintf(f, "e\n"); + fprintf(f, "%sD %s\n", Prefix, pExtendedDescription); + fprintf(f, "%se\n", Prefix); } } @@ -414,8 +413,8 @@ void cEventInfo::Dump(FILE *f) const cSchedule::cSchedule(unsigned short servid) { - pPresent = pFollowing = NULL; - uServiceID = servid; + pPresent = pFollowing = NULL; + uServiceID = servid; } @@ -429,15 +428,15 @@ const cEventInfo * cSchedule::GetPresentEvent() const time_t now = time(NULL); if (pPresent && !(pPresent->GetTime() <= now && now <= pPresent->GetTime() + pPresent->GetDuration())) { - cEventInfo *pe = Events.First(); - while (pe != NULL) - { - if (pe->GetTime() <= now && now <= pe->GetTime() + pe->GetDuration()) + cEventInfo *pe = Events.First(); + while (pe != NULL) + { + if (pe->GetTime() <= now && now <= pe->GetTime() + pe->GetDuration()) return pe; pe = Events.Next(pe); - } + } } - return pPresent; + return pPresent; } /** */ const cEventInfo * cSchedule::GetFollowingEvent() const @@ -451,111 +450,111 @@ const cEventInfo * cSchedule::GetFollowingEvent() const cEventInfo *pe = Events.First(), *pf = NULL; while (pe != NULL) { - int dt = pe->GetTime() - now; - if (dt > 0 && dt < minDt) + int dt = pe->GetTime() - now; + if (dt > 0 && dt < minDt) { minDt = dt; pf = pe; } - pe = Events.Next(pe); + pe = Events.Next(pe); } return pf; } - return pFollowing; + return pFollowing; } /** */ void cSchedule::SetServiceID(unsigned short servid) { - uServiceID = servid; + uServiceID = servid; } /** */ unsigned short cSchedule::GetServiceID() const { - return uServiceID; + return uServiceID; } /** */ const cEventInfo * cSchedule::GetEvent(unsigned short uEventID) const { - cEventInfo *pe = Events.First(); - while (pe != NULL) - { - if (pe->GetEventID() == uEventID) - return pe; - - pe = Events.Next(pe); - } - - return NULL; + cEventInfo *pe = Events.First(); + while (pe != NULL) + { + if (pe->GetEventID() == uEventID) + return pe; + + pe = Events.Next(pe); + } + + return NULL; } /** */ const cEventInfo * cSchedule::GetEvent(time_t tTime) const { - cEventInfo *pe = Events.First(); - while (pe != NULL) - { - if (pe->GetTime() == tTime) - return pe; - - pe = Events.Next(pe); - } - - return NULL; + cEventInfo *pe = Events.First(); + while (pe != NULL) + { + if (pe->GetTime() == tTime) + return pe; + + pe = Events.Next(pe); + } + + return NULL; } /** */ bool cSchedule::SetPresentEvent(cEventInfo *pEvent) { - if (pPresent != NULL) - pPresent->SetPresent(false); - pPresent = pEvent; - pPresent->SetPresent(true); - - return true; + if (pPresent != NULL) + pPresent->SetPresent(false); + pPresent = pEvent; + pPresent->SetPresent(true); + + return true; } /** */ bool cSchedule::SetFollowingEvent(cEventInfo *pEvent) { - if (pFollowing != NULL) - pFollowing->SetFollowing(false); - pFollowing = pEvent; - pFollowing->SetFollowing(true); - - return true; + if (pFollowing != NULL) + pFollowing->SetFollowing(false); + pFollowing = pEvent; + pFollowing->SetFollowing(true); + + return true; } /** */ void cSchedule::Cleanup() { - Cleanup(time(NULL)); + Cleanup(time(NULL)); } /** */ void cSchedule::Cleanup(time_t tTime) { - cEventInfo *pEvent; - for (int a = 0; true ; a++) - { - pEvent = Events.Get(a); - if (pEvent == NULL) - break; - if (pEvent->GetTime() + pEvent->GetDuration() < tTime) - { - Events.Del(pEvent); - a--; - } - } + cEventInfo *pEvent; + for (int a = 0; true ; a++) + { + pEvent = Events.Get(a); + if (pEvent == NULL) + break; + if (pEvent->GetTime() + pEvent->GetDuration() < tTime) + { + Events.Del(pEvent); + a--; + } + } } /** */ -void cSchedule::Dump(FILE *f) const +void cSchedule::Dump(FILE *f, const char *Prefix) const { cChannel *channel = Channels.GetByServiceID(uServiceID); if (channel) { - fprintf(f, "C %u %s\n", uServiceID, channel->name); + fprintf(f, "%sC %u %s\n", Prefix, uServiceID, channel->name); for (cEventInfo *p = Events.First(); p; p = Events.Next(p)) - p->Dump(f); - fprintf(f, "c\n"); + p->Dump(f, Prefix); + fprintf(f, "%sc\n", Prefix); } } @@ -563,8 +562,8 @@ void cSchedule::Dump(FILE *f) const cSchedules::cSchedules() { - pCurrentSchedule = NULL; - uCurrentServiceID = 0; + pCurrentSchedule = NULL; + uCurrentServiceID = 0; } cSchedules::~cSchedules() @@ -573,58 +572,58 @@ cSchedules::~cSchedules() /** */ bool cSchedules::SetCurrentServiceID(unsigned short servid) { - pCurrentSchedule = GetSchedule(servid); - if (pCurrentSchedule == NULL) - { - Add(new cSchedule(servid)); - pCurrentSchedule = GetSchedule(servid); - if (pCurrentSchedule == NULL) - return false; - } - - uCurrentServiceID = servid; - - return true; + pCurrentSchedule = GetSchedule(servid); + if (pCurrentSchedule == NULL) + { + Add(new cSchedule(servid)); + pCurrentSchedule = GetSchedule(servid); + if (pCurrentSchedule == NULL) + return false; + } + + uCurrentServiceID = servid; + + return true; } /** */ const cSchedule * cSchedules::GetSchedule() const { - return pCurrentSchedule; + return pCurrentSchedule; } /** */ const cSchedule * cSchedules::GetSchedule(unsigned short servid) const { - cSchedule *p; - - p = First(); - while (p != NULL) - { - if (p->GetServiceID() == servid) - return p; - p = Next(p); - } - - return NULL; + cSchedule *p; + + p = First(); + while (p != NULL) + { + if (p->GetServiceID() == servid) + return p; + p = Next(p); + } + + return NULL; } /** */ void cSchedules::Cleanup() { - cSchedule *p; - - p = First(); - while (p != NULL) - { - p->Cleanup(time(NULL)); - p = Next(p); - } + cSchedule *p; + + p = First(); + while (p != NULL) + { + p->Cleanup(time(NULL)); + p = Next(p); + } } /** */ -void cSchedules::Dump(FILE *f) const +void cSchedules::Dump(FILE *f, const char *Prefix) const { for (cSchedule *p = First(); p; p = Next(p)) - p->Dump(f); + p->Dump(f, Prefix); } // --- cEIT ------------------------------------------------------------------ @@ -632,136 +631,136 @@ void cSchedules::Dump(FILE *f) const #define DEC(N) dec << setw(N) << setfill(int('0')) #define HEX(N) hex << setw(N) << setfill(int('0')) -#define EIT_STUFFING_DESCRIPTOR 0x42 -#define EIT_LINKAGE_DESCRIPTOR 0x4a -#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d -#define EIT_EXTENDED_EVENT_DESCRIPTOR 0x4e -#define EIT_TIME_SHIFTED_EVENT_DESCRIPTOR 0x4f -#define EIT_COMPONENT_DESCRIPTOR 0x50 -#define EIT_CA_IDENTIFIER_DESCRIPTOR 0x53 -#define EIT_CONTENT_DESCRIPTOR 0x54 -#define EIT_PARENTAL_RATING_DESCRIPTOR 0x55 -#define EIT_TELEPHONE_DESCRIPTOR 0x57 -#define EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR 0x5e -#define EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR 0x5f -#define EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR 0x61 -#define EIT_DATA_BROADCAST_DESCRIPTOR 0x64 -#define EIT_PDC_DESCRIPTOR 0x69 +#define EIT_STUFFING_DESCRIPTOR 0x42 +#define EIT_LINKAGE_DESCRIPTOR 0x4a +#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d +#define EIT_EXTENDED_EVENT_DESCRIPTOR 0x4e +#define EIT_TIME_SHIFTED_EVENT_DESCRIPTOR 0x4f +#define EIT_COMPONENT_DESCRIPTOR 0x50 +#define EIT_CA_IDENTIFIER_DESCRIPTOR 0x53 +#define EIT_CONTENT_DESCRIPTOR 0x54 +#define EIT_PARENTAL_RATING_DESCRIPTOR 0x55 +#define EIT_TELEPHONE_DESCRIPTOR 0x57 +#define EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR 0x5e +#define EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR 0x5f +#define EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR 0x61 +#define EIT_DATA_BROADCAST_DESCRIPTOR 0x64 +#define EIT_PDC_DESCRIPTOR 0x69 typedef struct eit_struct { - u_char table_id : 8; + u_char table_id : 8; #if BYTE_ORDER == BIG_ENDIAN - u_char section_syntax_indicator : 1; - u_char : 3; - u_char section_length_hi : 4; + u_char section_syntax_indicator : 1; + u_char : 3; + u_char section_length_hi : 4; #else - u_char section_length_hi : 4; - u_char : 3; - u_char section_syntax_indicator : 1; + u_char section_length_hi : 4; + u_char : 3; + u_char section_syntax_indicator : 1; #endif - u_char section_length_lo : 8; + u_char section_length_lo : 8; - u_char service_id_hi : 8; - u_char service_id_lo : 8; + u_char service_id_hi : 8; + u_char service_id_lo : 8; #if BYTE_ORDER == BIG_ENDIAN - u_char : 2; - u_char version_number : 5; - u_char current_next_indicator : 1; + u_char : 2; + u_char version_number : 5; + u_char current_next_indicator : 1; #else - u_char current_next_indicator : 1; - u_char version_number : 5; - u_char : 2; + u_char current_next_indicator : 1; + u_char version_number : 5; + u_char : 2; #endif - u_char section_number : 8; - u_char last_section_number : 8; - u_char transport_stream_id_hi : 8; - u_char transport_stream_id_lo : 8; - u_char original_network_id_hi : 8; - u_char original_network_id_lo : 8; - u_char segment_last_section_number : 8; - u_char segment_last_table_id : 8; + u_char section_number : 8; + u_char last_section_number : 8; + u_char transport_stream_id_hi : 8; + u_char transport_stream_id_lo : 8; + u_char original_network_id_hi : 8; + u_char original_network_id_lo : 8; + u_char segment_last_section_number : 8; + u_char segment_last_table_id : 8; } eit_t; typedef struct eit_loop_struct { - u_char event_id_hi : 8; - u_char event_id_lo : 8; - - u_char date_hi : 8; - u_char date_lo : 8; - u_char time_hour : 4; - u_char time_hour_ten : 4; - u_char time_minute : 4; - u_char time_minute_ten : 4; - u_char time_second : 4; - u_char time_second_ten : 4; - - u_char dur_hour : 4; - u_char dur_hour_ten : 4; - u_char dur_minute : 4; - u_char dur_minute_ten : 4; - u_char dur_second : 4; - u_char dur_second_ten : 4; + u_char event_id_hi : 8; + u_char event_id_lo : 8; + + u_char date_hi : 8; + u_char date_lo : 8; + u_char time_hour : 4; + u_char time_hour_ten : 4; + u_char time_minute : 4; + u_char time_minute_ten : 4; + u_char time_second : 4; + u_char time_second_ten : 4; + + u_char dur_hour : 4; + u_char dur_hour_ten : 4; + u_char dur_minute : 4; + u_char dur_minute_ten : 4; + u_char dur_second : 4; + u_char dur_second_ten : 4; #if BYTE_ORDER == BIG_ENDIAN - u_char running_status : 3; - u_char free_ca_mode : 1; - u_char descriptors_loop_length_hi : 4; + u_char running_status : 3; + u_char free_ca_mode : 1; + u_char descriptors_loop_length_hi : 4; #else - u_char descriptors_loop_length_hi : 4; - u_char free_ca_mode : 1; - u_char running_status : 3; + u_char descriptors_loop_length_hi : 4; + u_char free_ca_mode : 1; + u_char running_status : 3; #endif - u_char descriptors_loop_length_lo : 8; + u_char descriptors_loop_length_lo : 8; } eit_loop_t; typedef struct eit_short_event_struct { - u_char descriptor_tag : 8; - u_char descriptor_length : 8; + u_char descriptor_tag : 8; + u_char descriptor_length : 8; - u_char language_code_1 : 8; - u_char language_code_2 : 8; - u_char language_code_3 : 8; + u_char language_code_1 : 8; + u_char language_code_2 : 8; + u_char language_code_3 : 8; - u_char event_name_length : 8; + u_char event_name_length : 8; } eit_short_event_t; typedef struct eit_extended_event_struct { - u_char descriptor_tag : 8; - u_char descriptor_length : 8; + u_char descriptor_tag : 8; + u_char descriptor_length : 8; - u_char last_descriptor_number : 4; - u_char descriptor_number : 4; + u_char last_descriptor_number : 4; + u_char descriptor_number : 4; - u_char language_code_1 : 8; - u_char language_code_2 : 8; - u_char language_code_3 : 8; + u_char language_code_1 : 8; + u_char language_code_2 : 8; + u_char language_code_3 : 8; - u_char length_of_items : 8; + u_char length_of_items : 8; } eit_extended_event_t; typedef struct eit_content_descriptor { - u_char descriptor_tag : 8; - u_char descriptor_length : 8; + u_char descriptor_tag : 8; + u_char descriptor_length : 8; } eit_content_descriptor_t; typedef struct eit_content_loop { - u_char content_nibble_level_2 : 4; - u_char content_nibble_level_1 : 4; - u_char user_nibble_2 : 4; - u_char user_nibble_1 : 4; + u_char content_nibble_level_2 : 4; + u_char content_nibble_level_1 : 4; + u_char user_nibble_2 : 4; + u_char user_nibble_1 : 4; } eit_content_loop_t; class cEIT { private: cSchedules *schedules; -public: - cEIT(void *buf, int length, cSchedules *Schedules); - ~cEIT(); +public: + cEIT(void *buf, int length, cSchedules *Schedules); + ~cEIT(); /** */ int ProcessEIT(); @@ -789,10 +788,10 @@ schedule information */ cEIT::cEIT(void * buf, int length, cSchedules *Schedules) { - buflen = length < int(sizeof(buffer)) ? length : sizeof(buffer); - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, buf, buflen); - tid = buffer[0]; + buflen = length < int(sizeof(buffer)) ? length : sizeof(buffer); + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, buf, buflen); + tid = buffer[0]; schedules = Schedules; } @@ -803,114 +802,114 @@ cEIT::~cEIT() /** */ int cEIT::ProcessEIT() { - int bufact = 0; - eit_t *eit; - eit_loop_t *eitloop; - u_char tmp[256]; - - if (bufact + (int)sizeof(eit_t) > buflen) - return 0; - eit = (eit_t *)buffer; - bufact += sizeof(eit_t); - - unsigned int service = (eit->service_id_hi << 8) | eit->service_id_lo; - - while(bufact + (int)sizeof(eit_loop_t) <= buflen) - { - eitloop = (eit_loop_t *)&buffer[bufact]; - bufact += sizeof(eit_loop_t); - - int descdatalen = (eitloop->descriptors_loop_length_hi << 8) + eitloop->descriptors_loop_length_lo; - int descdataact = 0; - - while (descdataact < descdatalen && bufact < buflen) - { - switch (buffer[bufact]) - { - eit_content_descriptor_t *cont; - eit_content_loop_t *contloop; - - case EIT_STUFFING_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_STUFFING_DESCRIPTOR"); - break; - - case EIT_LINKAGE_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_LINKAGE_DESCRIPTOR"); - break; - - case EIT_SHORT_EVENT_DESCRIPTOR: - WriteShortEventDescriptor(service, eitloop, &buffer[bufact]); - break; - - case EIT_EXTENDED_EVENT_DESCRIPTOR: - WriteExtEventDescriptor(service, eitloop, &buffer[bufact]); - break; - - case EIT_TIME_SHIFTED_EVENT_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_TIME_SHIFTED_EVENT_DESCRIPTOR"); - break; - - case EIT_COMPONENT_DESCRIPTOR : + int bufact = 0; + eit_t *eit; + eit_loop_t *eitloop; + u_char tmp[256]; + + if (bufact + (int)sizeof(eit_t) > buflen) + return 0; + eit = (eit_t *)buffer; + bufact += sizeof(eit_t); + + unsigned int service = (eit->service_id_hi << 8) | eit->service_id_lo; + + while(bufact + (int)sizeof(eit_loop_t) <= buflen) + { + eitloop = (eit_loop_t *)&buffer[bufact]; + bufact += sizeof(eit_loop_t); + + int descdatalen = (eitloop->descriptors_loop_length_hi << 8) + eitloop->descriptors_loop_length_lo; + int descdataact = 0; + + while (descdataact < descdatalen && bufact < buflen) + { + switch (buffer[bufact]) + { + eit_content_descriptor_t *cont; + eit_content_loop_t *contloop; + + case EIT_STUFFING_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_STUFFING_DESCRIPTOR"); + break; + + case EIT_LINKAGE_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_LINKAGE_DESCRIPTOR"); + break; + + case EIT_SHORT_EVENT_DESCRIPTOR: + WriteShortEventDescriptor(service, eitloop, &buffer[bufact]); + break; + + case EIT_EXTENDED_EVENT_DESCRIPTOR: + WriteExtEventDescriptor(service, eitloop, &buffer[bufact]); + break; + + case EIT_TIME_SHIFTED_EVENT_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_TIME_SHIFTED_EVENT_DESCRIPTOR"); + break; + + case EIT_COMPONENT_DESCRIPTOR : if (buffer[bufact + 1] > 6) // kls 2001-02-24: otherwise strncpy() causes a segfault in strdvbcpy() - strdvbcpy(tmp, &buffer[bufact + 8], buffer[bufact + 1] - 6); - //dsyslog(LOG_INFO, "Found EIT_COMPONENT_DESCRIPTOR %c%c%c 0x%02x/0x%02x/0x%02x '%s'\n", buffer[bufact + 5], buffer[bufact + 6], buffer[bufact + 7], buffer[2], buffer[3], buffer[4], tmp); - break; - - case EIT_CA_IDENTIFIER_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_CA_IDENTIFIER_DESCRIPTOR"); - break; - - case EIT_CONTENT_DESCRIPTOR : - cont = (eit_content_descriptor_t *)buffer; - contloop = (eit_content_loop_t *)&buffer[sizeof(eit_content_descriptor_t)]; - //dsyslog(LOG_INFO, "Found EIT_CONTENT_DESCRIPTOR 0x%02x/0x%02x\n", contloop->content_nibble_level_1, contloop->content_nibble_level_2); - break; - - case EIT_PARENTAL_RATING_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_PARENTAL_RATING_DESCRIPTOR"); - break; - - case EIT_TELEPHONE_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_TELEPHONE_DESCRIPTOR"); - break; - - case EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR"); - break; - - case EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR"); - break; - - case EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR"); - break; - - case EIT_DATA_BROADCAST_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_DATA_BROADCAST_DESCRIPTOR"); - break; - - case EIT_PDC_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_PDC_DESCRIPTOR"); - break; - - default: - //dsyslog(LOG_INFO, "Found unhandled descriptor 0x%02x with length of %04d\n", (int)buffer[bufact], (int)buffer[bufact + 1]); - break; - } - descdataact += (buffer[bufact + 1] + 2); - bufact += (buffer[bufact + 1] + 2); - } - } - - return 0; + strdvbcpy(tmp, &buffer[bufact + 8], buffer[bufact + 1] - 6); + //dsyslog(LOG_INFO, "Found EIT_COMPONENT_DESCRIPTOR %c%c%c 0x%02x/0x%02x/0x%02x '%s'\n", buffer[bufact + 5], buffer[bufact + 6], buffer[bufact + 7], buffer[2], buffer[3], buffer[4], tmp); + break; + + case EIT_CA_IDENTIFIER_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_CA_IDENTIFIER_DESCRIPTOR"); + break; + + case EIT_CONTENT_DESCRIPTOR : + cont = (eit_content_descriptor_t *)buffer; + contloop = (eit_content_loop_t *)&buffer[sizeof(eit_content_descriptor_t)]; + //dsyslog(LOG_INFO, "Found EIT_CONTENT_DESCRIPTOR 0x%02x/0x%02x\n", contloop->content_nibble_level_1, contloop->content_nibble_level_2); + break; + + case EIT_PARENTAL_RATING_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_PARENTAL_RATING_DESCRIPTOR"); + break; + + case EIT_TELEPHONE_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_TELEPHONE_DESCRIPTOR"); + break; + + case EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR"); + break; + + case EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR"); + break; + + case EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR"); + break; + + case EIT_DATA_BROADCAST_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_DATA_BROADCAST_DESCRIPTOR"); + break; + + case EIT_PDC_DESCRIPTOR : + //dsyslog(LOG_INFO, "Found EIT_PDC_DESCRIPTOR"); + break; + + default: + //dsyslog(LOG_INFO, "Found unhandled descriptor 0x%02x with length of %04d\n", (int)buffer[bufact], (int)buffer[bufact + 1]); + break; + } + descdataact += (buffer[bufact + 1] + 2); + bufact += (buffer[bufact + 1] + 2); + } + } + + return 0; } /** */ int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) { - int a = 0; - + int a = 0; + // kls 2001-02-24: if we come in with negative values, the caller must // have done something wrong and the strncpy() below will cause a segfault if (max <= 0) @@ -919,42 +918,42 @@ int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) return 0; } - if (*src == 0x05 || (*src >= 0x20 && *src <= 0xff)) - { - for (a = 0; a < max; a++) - { - if (*src == 0) - break; - - if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff)) - *dst++ = *src++; - else - { - // if ((*src > '~' && *src < 0xa0) || *src == 0xff) - // cerr << "found special character 0x" << HEX(2) << (int)*src << endl; - src++; - } - } - *dst = 0; - } - else - { - const char *ret; - - switch (*src) - { - case 0x01: ret = "Coding according to character table 1"; break; - case 0x02: ret = "Coding according to character table 2"; break; - case 0x03: ret = "Coding according to character table 3"; break; - case 0x04: ret = "Coding according to character table 4"; break; - case 0x10: ret = "Coding according to ISO/IEC 8859"; break; - case 0x11: ret = "Coding according to ISO/IEC 10646"; break; - case 0x12: ret = "Coding according to KSC 5601"; break; - default: ret = "Unknown coding"; break; - } - strncpy((char *)dst, ret, max); - } - return a; + if (*src == 0x05 || (*src >= 0x20 && *src <= 0xff)) + { + for (a = 0; a < max; a++) + { + if (*src == 0) + break; + + if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff)) + *dst++ = *src++; + else + { + // if ((*src > '~' && *src < 0xa0) || *src == 0xff) + // cerr << "found special character 0x" << HEX(2) << (int)*src << endl; + src++; + } + } + *dst = 0; + } + else + { + const char *ret; + + switch (*src) + { + case 0x01: ret = "Coding according to character table 1"; break; + case 0x02: ret = "Coding according to character table 2"; break; + case 0x03: ret = "Coding according to character table 3"; break; + case 0x04: ret = "Coding according to character table 4"; break; + case 0x10: ret = "Coding according to ISO/IEC 8859"; break; + case 0x11: ret = "Coding according to ISO/IEC 10646"; break; + case 0x12: ret = "Coding according to KSC 5601"; break; + default: ret = "Unknown coding"; break; + } + strncpy((char *)dst, ret, max); + } + return a; } /** returns true if this EIT covers a @@ -962,140 +961,140 @@ present/following information, false if it's schedule information */ bool cEIT::IsPresentFollowing() { - if (tid == 0x4e || tid == 0x4f) - return true; + if (tid == 0x4e || tid == 0x4f) + return true; - return false; + return false; } /** */ bool cEIT::WriteShortEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf) { - u_char tmp[256]; - eit_short_event_t *evt = (eit_short_event_t *)buf; - unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); - cEventInfo *pEvent; - - //isyslog(LOG_INFO, "Found Short Event Descriptor"); - - cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - { - schedules->Add(new cSchedule(service)); - pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - return false; - } + u_char tmp[256]; + eit_short_event_t *evt = (eit_short_event_t *)buf; + unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); + cEventInfo *pEvent; + + //isyslog(LOG_INFO, "Found Short Event Descriptor"); + + cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + { + schedules->Add(new cSchedule(service)); + pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + return false; + } /* cSchedule::GetPresentEvent() and cSchedule::GetFollowingEvent() verify the temporal sanity of these events, so calling them here appears to be a bad idea... (kls 2000-11-01) - // - // if we are working on a present/following info, let's see whether - // we already have present/following info for this service and if yes - // check whether it's the same eventid, if yes, just return, nothing - // left to do. - // - if (IsPresentFollowing()) - { - if (eitloop->running_status == 4 || eitloop->running_status == 3) - pEvent = (cEventInfo *)pSchedule->GetPresentEvent(); - else - pEvent = (cEventInfo *)pSchedule->GetFollowingEvent(); - - if (pEvent != NULL) - if (pEvent->GetEventID() == eventid) - return true; - } + // + // if we are working on a present/following info, let's see whether + // we already have present/following info for this service and if yes + // check whether it's the same eventid, if yes, just return, nothing + // left to do. + // + if (IsPresentFollowing()) + { + if (eitloop->running_status == 4 || eitloop->running_status == 3) + pEvent = (cEventInfo *)pSchedule->GetPresentEvent(); + else + pEvent = (cEventInfo *)pSchedule->GetFollowingEvent(); + + if (pEvent != NULL) + if (pEvent->GetEventID() == eventid) + return true; + } */ - // - // let's see whether we have that eventid already - // in case not, we have to create a new cEventInfo for it - // - pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); - if (pEvent == NULL) - { - pSchedule->Events.Add(new cEventInfo(service, eventid)); - pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); - if (pEvent == NULL) - return false; - - strdvbcpy(tmp, &buf[sizeof(eit_short_event_t)], evt->event_name_length); - pEvent->SetTitle((char *)tmp); - strdvbcpy(tmp, &buf[sizeof(eit_short_event_t) + evt->event_name_length + 1], - (int)buf[sizeof(eit_short_event_t) + evt->event_name_length]); - pEvent->SetSubtitle((char *)tmp); - cMJD mjd(eitloop->date_hi, eitloop->date_lo, - eitloop->time_hour_ten * 10 + eitloop->time_hour, - eitloop->time_minute_ten * 10 + eitloop->time_minute, - eitloop->time_second_ten * 10 + eitloop->time_second); - pEvent->SetTime(mjd.GetTime_t()); - pEvent->SetDuration((long)((long)((eitloop->dur_hour_ten * 10 + eitloop->dur_hour) * 60l * 60l) + - (long)((eitloop->dur_minute_ten * 10 + eitloop->dur_minute) * 60l) + - (long)(eitloop->dur_second_ten * 10 + eitloop->dur_second))); - } - - if (IsPresentFollowing()) - { - if (eitloop->running_status == 4 || eitloop->running_status == 3) - pSchedule->SetPresentEvent(pEvent); - else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0) - pSchedule->SetFollowingEvent(pEvent); - } - - return true; + // + // let's see whether we have that eventid already + // in case not, we have to create a new cEventInfo for it + // + pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); + if (pEvent == NULL) + { + pSchedule->Events.Add(new cEventInfo(service, eventid)); + pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); + if (pEvent == NULL) + return false; + + strdvbcpy(tmp, &buf[sizeof(eit_short_event_t)], evt->event_name_length); + pEvent->SetTitle((char *)tmp); + strdvbcpy(tmp, &buf[sizeof(eit_short_event_t) + evt->event_name_length + 1], + (int)buf[sizeof(eit_short_event_t) + evt->event_name_length]); + pEvent->SetSubtitle((char *)tmp); + cMJD mjd(eitloop->date_hi, eitloop->date_lo, + eitloop->time_hour_ten * 10 + eitloop->time_hour, + eitloop->time_minute_ten * 10 + eitloop->time_minute, + eitloop->time_second_ten * 10 + eitloop->time_second); + pEvent->SetTime(mjd.GetTime_t()); + pEvent->SetDuration((long)((long)((eitloop->dur_hour_ten * 10 + eitloop->dur_hour) * 60l * 60l) + + (long)((eitloop->dur_minute_ten * 10 + eitloop->dur_minute) * 60l) + + (long)(eitloop->dur_second_ten * 10 + eitloop->dur_second))); + } + + if (IsPresentFollowing()) + { + if (eitloop->running_status == 4 || eitloop->running_status == 3) + pSchedule->SetPresentEvent(pEvent); + else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0) + pSchedule->SetFollowingEvent(pEvent); + } + + return true; } /** */ bool cEIT::WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf) { - u_char tmp[256]; - eit_extended_event_t *evt = (eit_extended_event_t *)buf; - int bufact, buflen; - unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); - cEventInfo *pEvent; - - //isyslog(LOG_INFO, "Found Extended Event Descriptor"); - - cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - { - schedules->Add(new cSchedule(service)); - pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - return false; - } - - pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); - if (pEvent == NULL) - return false; - - if (evt->descriptor_number != pEvent->GetExtendedDescriptorNumber()) - return false; - - bufact = sizeof(eit_extended_event_t); - buflen = buf[1] + 2; - - if (evt->length_of_items > 0) - { - while (bufact - sizeof(eit_extended_event_t) < evt->length_of_items) - { - strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); - // could use value in tmp now to do something, - // haven't seen any items as of yet transmitted from satellite - bufact += (buf[bufact] + 1); - } - } - - strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); - if (pEvent->AddExtendedDescription((char *)tmp)) - { - pEvent->IncreaseExtendedDescriptorNumber(); - return true; - } - - return false; + u_char tmp[256]; + eit_extended_event_t *evt = (eit_extended_event_t *)buf; + int bufact, buflen; + unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); + cEventInfo *pEvent; + + //isyslog(LOG_INFO, "Found Extended Event Descriptor"); + + cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + { + schedules->Add(new cSchedule(service)); + pSchedule = (cSchedule *)schedules->GetSchedule(service); + if (pSchedule == NULL) + return false; + } + + pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); + if (pEvent == NULL) + return false; + + if (evt->descriptor_number != pEvent->GetExtendedDescriptorNumber()) + return false; + + bufact = sizeof(eit_extended_event_t); + buflen = buf[1] + 2; + + if (evt->length_of_items > 0) + { + while (bufact - sizeof(eit_extended_event_t) < evt->length_of_items) + { + strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); + // could use value in tmp now to do something, + // haven't seen any items as of yet transmitted from satellite + bufact += (buf[bufact] + 1); + } + } + + strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); + if (pEvent->AddExtendedDescription((char *)tmp)) + { + pEvent->IncreaseExtendedDescriptorNumber(); + return true; + } + + return false; } // --- cSIProcessor ---------------------------------------------------------- @@ -1110,13 +1109,13 @@ cMutex cSIProcessor::schedulesMutex; cSIProcessor::cSIProcessor(const char *FileName) { masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master' - useTStime = false; + useTStime = false; filters = NULL; if ((fsvbi = open(FileName, O_RDONLY)) >= 0) { if (!numSIProcessors++) // the first one creates it schedules = new cSchedules; - filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER)); + filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER)); } else LOG_ERROR_STR(FileName); @@ -1126,8 +1125,9 @@ cSIProcessor::~cSIProcessor() { if (fsvbi >= 0) { - Cancel(); - ShutDownFilters(); + active = false; + Cancel(3); + ShutDownFilters(); delete filters; if (!--numSIProcessors) // the last one deletes it delete schedules; @@ -1146,16 +1146,18 @@ void cSIProcessor::Action() } dsyslog(LOG_INFO, "EIT processing thread started (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : ""); - + unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) - unsigned int seclen; - unsigned int pid; + unsigned int seclen; + unsigned int pid; time_t lastCleanup = time(NULL); time_t lastDump = time(NULL); - struct pollfd pfd; - - while(true) - { + struct pollfd pfd; + + active = true; + + while(active) + { if (masterSIProcessor) { time_t now = time(NULL); @@ -1185,65 +1187,65 @@ void cSIProcessor::Action() } } - /* wait data become ready from the bitfilter */ - pfd.fd = fsvbi; - pfd.events = POLLIN; - if(poll(&pfd, 1, 1000) != 0) /* timeout is 5 secs */ - { - // fprintf(stderr, "\n"); - /* read section */ - read(fsvbi, buf, 8); - seclen = (buf[6] << 8) | buf[7]; - pid = (buf[4] << 8) | buf[5]; - read(fsvbi, buf, seclen); - - //dsyslog(LOG_INFO, "Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen); - - switch (pid) - { - case 0x14: - if (buf[0] == 0x70) - { - if (useTStime) + /* wait data become ready from the bitfilter */ + pfd.fd = fsvbi; + pfd.events = POLLIN; + if(poll(&pfd, 1, 1000) != 0) /* timeout is 5 secs */ + { + // fprintf(stderr, "\n"); + /* read section */ + read(fsvbi, buf, 8); + seclen = (buf[6] << 8) | buf[7]; + pid = (buf[4] << 8) | buf[5]; + read(fsvbi, buf, seclen); + + //dsyslog(LOG_INFO, "Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen); + + switch (pid) + { + case 0x14: + if (buf[0] == 0x70) + { + if (useTStime) { cTDT ctdt((tdt_t *)buf); - ctdt.SetSystemTime(); + ctdt.SetSystemTime(); } - } + } /*XXX this comes pretty often: - else - dsyslog(LOG_INFO, "Time packet was not 0x70 but 0x%02x\n", (int)buf[0]); + else + dsyslog(LOG_INFO, "Time packet was not 0x70 but 0x%02x\n", (int)buf[0]); XXX*/ - break; - - case 0x12: - if (buf[0] != 0x72) - { + break; + + case 0x12: + if (buf[0] != 0x72) + { LOCK_THREAD; schedulesMutex.Lock(); - cEIT ceit(buf, seclen, schedules); - ceit.ProcessEIT(); + cEIT ceit(buf, seclen, schedules); + ceit.ProcessEIT(); schedulesMutex.Unlock(); - } - else - dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); - break; - - default: - break; - } - } - else - { + } + else + dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); + break; + + default: + break; + } + } + else + { LOCK_THREAD; //XXX this comes pretty often - //isyslog(LOG_INFO, "Received timeout from poll, refreshing filters\n"); - RefreshFilters(); - } -// WakeUp(); - } + //isyslog(LOG_INFO, "Received timeout from poll, refreshing filters\n"); + RefreshFilters(); + } +// WakeUp(); + } } /** Add a filter with packet identifier pid and @@ -1253,42 +1255,42 @@ bool cSIProcessor::AddFilter(u_char pid, u_char tid) if (fsvbi < 0) return false; - int section = ((int)tid << 8) | 0x00ff; - - struct bitfilter filt = { - pid, - { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - SECTION_CONTINUOS, 0, - FILTER_MEM, - {}, - }; - - if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0) - return false; - - for (int a = 0; a < MAX_FILTERS; a++) - { - if (filters[a].inuse == false) - { - filters[a].pid = pid; - filters[a].tid = tid; - filters[a].handle = filt.handle; - filters[a].inuse = true; - // dsyslog(LOG_INFO, " Registered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); - return true; - } - } - - return false; + int section = ((int)tid << 8) | 0x00ff; + + struct bitfilter filt = { + pid, + { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + SECTION_CONTINUOS, 0, + FILTER_MEM, + {}, + }; + + if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0) + return false; + + for (int a = 0; a < MAX_FILTERS; a++) + { + if (filters[a].inuse == false) + { + filters[a].pid = pid; + filters[a].tid = tid; + filters[a].handle = filt.handle; + filters[a].inuse = true; + // dsyslog(LOG_INFO, " Registered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); + return true; + } + } + + return false; } /** set whether local systems time should be set by the received TDT or TOT packets */ bool cSIProcessor::SetUseTSTime(bool use) { - useTStime = use; - return useTStime; + useTStime = use; + return useTStime; } /** */ @@ -1297,22 +1299,22 @@ bool cSIProcessor::ShutDownFilters() if (fsvbi < 0) return false; - bool ret = true; - - for (int a = 0; a < MAX_FILTERS; a++) - { - if (filters[a].inuse == true) - { - if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &filters[a].handle) < 0) - ret = false; + bool ret = true; + + for (int a = 0; a < MAX_FILTERS; a++) + { + if (filters[a].inuse == true) + { + if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &filters[a].handle) < 0) + ret = false; + + // dsyslog(LOG_INFO, "Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); - // dsyslog(LOG_INFO, "Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); - - filters[a].inuse = false; - } - } + filters[a].inuse = false; + } + } - return ret; + return ret; } /** */ @@ -1328,18 +1330,18 @@ bool cSIProcessor::RefreshFilters() if (fsvbi < 0) return false; - bool ret = true; - - ret = ShutDownFilters(); - - for (int a = 0; a < MAX_FILTERS; a++) - { - if (filters[a].inuse == false && filters[a].pid != 0 && filters[a].tid != 0) - { - if (!AddFilter(filters[a].pid, filters[a].tid)) - ret = false; - } - } - - return ret; + bool ret = true; + + ret = ShutDownFilters(); + + for (int a = 0; a < MAX_FILTERS; a++) + { + if (filters[a].inuse == false && filters[a].pid != 0 && filters[a].tid != 0) + { + if (!AddFilter(filters[a].pid, filters[a].tid)) + ret = false; + } + } + + return ret; } diff --git a/eit.h b/eit.h index bedead755..3d491935c 100644 --- a/eit.h +++ b/eit.h @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.4 2000/11/24 14:35:22 kls Exp $ + * $Id: eit.h 1.6 2001/04/01 15:14:12 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -49,7 +49,7 @@ class cEventInfo : public cListObject { bool SetSubtitle(char *string); void IncreaseExtendedDescriptorNumber(void); cEventInfo(unsigned short serviceid, unsigned short eventid); -public: +public: ~cEventInfo(); const char *GetTimeString(void) const; const char *GetEndTimeString(void) const; @@ -66,7 +66,7 @@ class cEventInfo : public cListObject { unsigned short GetServiceID(void) const; int GetChannelNumber(void) const { return nChannelNumber; } void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' - void Dump(FILE *f) const; + void Dump(FILE *f, const char *Prefix = "") const; }; class cSchedule : public cListObject { @@ -84,7 +84,7 @@ class cSchedule : public cListObject { void Cleanup(time_t tTime); void Cleanup(void); cSchedule(unsigned short servid = 0); -public: +public: ~cSchedule(); const cEventInfo *GetPresentEvent(void) const; const cEventInfo *GetFollowingEvent(void) const; @@ -93,7 +93,7 @@ class cSchedule : public cListObject { const cEventInfo *GetEvent(time_t tTime) const; const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); } int NumEvents(void) const { return Events.Count(); } - void Dump(FILE *f) const; + void Dump(FILE *f, const char *Prefix = "") const; }; class cSchedules : public cList { @@ -104,12 +104,12 @@ class cSchedules : public cList { protected: bool SetCurrentServiceID(unsigned short servid); void Cleanup(); -public: +public: cSchedules(void); ~cSchedules(); const cSchedule *GetSchedule(unsigned short servid) const; const cSchedule *GetSchedule(void) const; - void Dump(FILE *f) const; + void Dump(FILE *f, const char *Prefix = "") const; }; typedef struct sip_filter { @@ -130,9 +130,10 @@ class cSIProcessor : public cThread { bool useTStime; SIP_FILTER *filters; int fsvbi; + bool active; bool RefreshFilters(void); void Action(void); -public: +public: cSIProcessor(const char *FileName); ~cSIProcessor(); bool SetUseTSTime(bool use); diff --git a/i18n.c b/i18n.c index f81a2029d..b2c321aa2 100644 --- a/i18n.c +++ b/i18n.c @@ -4,10 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.14 2001/02/24 13:57:14 kls Exp $ + * $Id: i18n.c 1.16 2001/03/31 09:58:14 kls Exp $ * * Slovenian translations provided by Miha Setina * Italian translations provided by Alberto Carraro + * Dutch translations provided by Arnold Niessen * */ @@ -48,7 +49,7 @@ #include "config.h" #include "tools.h" -const int NumLanguages = 4; +const int NumLanguages = 5; typedef const char *tPhrase[NumLanguages]; @@ -58,542 +59,648 @@ const tPhrase Phrases[] = { "Deutsch", "Slovenski", "Italiano", + "Nederlands", }, // Menu titles: { "Main", "Hauptmen", "Glavni meni", "Principale", + "Hoofdmenu", }, { "Schedule", "Programm", "Urnik", "Programmi", + "Gids", }, { "Channels", "Kanle", "Kanali", "Canali", + "Kanalen", }, { "Timers", "Timer", "Termini", "Timer", + "Timers", }, { "Recordings", "Aufzeichnungen", "Posnetki", "Registrazioni", + "Opnames", }, { "Setup", "Einstellungen", "Nastavitve", "Opzioni", + "Instellingen", }, { "Commands", "Befehle", "Ukazi", "Comandi", + "Commando's", }, { "Edit Channel", "Kanal Editieren", "Uredi kanal", "Modifica canale", + "Kanaal aanpassen", }, { "Edit Timer", "Timer Editieren", "Uredi termin", "Modifica Timer", + "Timer veranderen", }, { "Event", "Sendung", "Oddaja", "Eventi", + "Uitzending", }, { "Summary", "Inhalt", "Vsebina", "Sommario", + "Inhoud", }, { "Schedule - %s", "Programm - %s", "Urnik - %s", "Programma - %s", + "Programma - %s", }, { "What's on now?", "Was luft jetzt?", "Kaj je na sporedu?", "In programmazione", + "Wat is er nu?", }, { "What's on next?", "Was luft als nchstes?", "Kaj sledi?", "Prossimi programmi", + "Wat komt er hierna?", }, // Button texts (must not be more than 10 characters!): { "Edit", "Editieren", "Uredi", "Modifica", + "Verander", }, { "New", "Neu", "Novo", "Nuovo", + "Nieuw", }, { "Delete", "Lschen", "Odstrani", "Cancella", + "Verwijder", }, { "Mark", "Markieren", "Oznaci", "Marca", + "Verplaats", }, { "Record", "Aufnehmen", "Posnemi", "Registra", + "Opnemen", }, { "Play", "Wiedergabe", "Predavajaj", "Riproduci", + "Afspelen", }, { "Rewind", "Anfang", "Zacetek", "Da inizio", + "Spoel terug", }, { "Resume", "Weiter", "Nadaljuj", "Riprendi", + "Verder", }, { "Summary", "Inhalt", "Vsebina", "Sommario", + "Inhoud", }, { "Switch", "Umschalten", "Preklopi", "Cambia", + "Selecteer", }, { "Now", "Jetzt", "Sedaj", "Adesso", + "Nu", }, { "Next", "Nchste", "Naslednji", "Prossimo", + "Hierna", }, { "Schedule", "Programm", "Urnik", "Programma", + "Programma", }, // Confirmations: { "Delete channel?", "Kanal lschen?", "Odstrani kanal?", "Cancello il canale?", + "Kanaal verwijderen?", }, { "Delete timer?", "Timer lschen?", "Odstani termin?", "Cancello il timer?", + "Timer verwijderen?", }, { "Delete recording?", "Aufzeichnung lschen?", "Odstrani posnetek?", "Cancello la registrazione?", + "Opname verwijderen?", }, { "Stop recording?", "Aufzeichnung beenden?", "Koncaj snemanje?", "Fermo la registrazione?", + "Opname stoppen?", }, { "Cancel editing?", "Schneiden abbrechen?", "Zelite prekiniti urejanje?", "Annullo la modifica?", + "Bewerken afbreken?", }, // Channel parameters: { "Name", "Name", "Naziv", "Nome", + "Naam", }, { "Frequency", "Frequenz", "Frekvenca", "Frequenza", + "Frequentie", }, { "Polarization", "Polarisation", "Polarizacija", "Polarizzazione", + "Polarisatie", }, { "Diseqc", "Diseqc", "Diseqc", "Diseqc", + "Diseqc", }, { "Srate", "Srate", "Srate", "Srate", + "Srate", }, { "Vpid", "Vpid", "Vpid", "Vpid", + "Vpid", }, { "Apid", "Apid", "Apid", "Apid", + "Apid", }, { "Tpid", "Tpid", "Tpid", "Tpid", + "Tpid", }, { "CA", "CA", "CA", "CA", + "CA", }, { "Pnr", "Pnr", "Pnr", "Pnr", + "Pnr", }, // Timer parameters: { "Active", "Aktiv", "Aktivno", "Attivo", + "Actief", }, { "Channel", "Kanal", "Kanal", "Canale", + "Kanaal", }, { "Day", "Tag", "Dan", "Giorno", + "Dag", }, { "Start", "Anfang", "Zacetek", "Inizio", + "Begin", }, { "Stop", "Ende", "Konec", "Fine", + "Einde", }, { "Priority", "Prioritt", "Prioriteta", "Priorita", + "Prioriteit", }, { "Lifetime", "Lebensdauer", "Veljavnost", "Durata", + "Bewaarduur", }, { "File", "Datei", "Datoteka", "Nome", + "Filenaam", }, // Error messages: { "Channel is being used by a timer!", "Kanal wird von einem Timer benutzt!", "Urnik zaseda kanal!", "Canale occupato da un timer!", + "Kanaal wordt gebruikt door een timer!", }, { "Can't switch channel!", "Kanal kann nicht umgeschaltet werden!", "Ne morem preklopiti kanala!", "Impossibile cambiare canale!", + "Kan geen kanaal wisselen!", }, { "Timer is recording!", "Timer zeichnet gerade auf!", "Snemanje po urniku!", "Registrazione di un timer in corso!", + "Timer is aan het opnemen!", }, { "Error while deleting recording!", "Fehler beim Lschen der Aufzeichnung!", "Napaka pri odstranjevanju posnetka!", "Errore durante la canc del filmato!", + "Fout bij verwijderen opname!", }, { "*** Invalid Channel ***", "*** Ungltiger Kanal ***", "*** Neznan kanal ***", "*** CANALE INVALIDO ***", + "*** Ongeldig kanaal ***", }, { "No free DVB device to record!", "Keine freie DVB-Karte zum Aufnehmen!", "Ni proste DVB naprave za snemanje!", "Nessuna card DVB disp per registrare!", + "Geen vrije DVB kaart om op te nemen!", }, { "Channel locked (recording)!", "Kanal blockiert (zeichnet auf)!", "Zaklenjen kanal (snemanje)!", "Canale bloccato (in registrazione)!", + "Kanaal geblokkeerd (neemt op)!", }, { "Can't start editing process!", "Schnitt kann nicht gestartet werden!", "Ne morem zaceti urejanja!", "Imposs iniziare processo di modifica", + "Kan niet beginnen met bewerken!", }, { "Editing process already active!", "Schnitt bereits aktiv!", "Urejanje je ze aktivno!", "Processo di modifica gia` attivo", + "Bewerken is al actief!", }, // Setup parameters: { "OSD-Language", "OSD-Sprache", "OSD-jezik", "Linguaggio OSD", + "OSD-taal", }, { "PrimaryDVB", "Primres Interface", "Primarna naprava", "Scheda DVB primaria", + "Eerste DVB kaart", }, { "ShowInfoOnChSwitch", "Info zeigen", "Pokazi naziv kanala", "Vis info nel cambio canale", + "Kanaal info tonen", }, { "MenuScrollPage", "Seitenweise scrollen", "Drsni meni", "Scrolla pagina nel menu", + "Scrollen per pagina", }, { "MarkInstantRecord", "Direktaufz. markieren", "Oznaci direktno snemanje", "Marca la registrazione", + "Direkte opnamen markeren", }, { "LnbFrequLo", "Untere LNB-Frequenz", "Spodnja LNB-frek.", "Freq LO LNB", + "Laagste LNB frequentie", }, { "LnbFrequHi", "Obere LNB-Frequenz", "Zgornja LNB-frek.", "Freq HI LNB", + "Hoogste LNB frequentie", }, { "SetSystemTime", "Systemzeit stellen", "Sistemski cas", "Setta orario auto", + "Systeem klok instellen", }, { "MarginStart", "Zeitpuffer bei Anfang", "Premor pred zacetkom", "Min margine inizio", + "Tijd marge (begin)", }, { "MarginStop", "Zeitpuffer bei Ende", "Premor za koncem", "Min margine fine", + "Tijd marge (eind)", }, { "EPGScanTimeout", "Zeit bis EPG Scan", "Cas do EPG pregleda", "Timeout EPG", + "EPG-scan Timeout", }, { "SVDRPTimeout", "SVDRP Timeout", "", // TODO "Timeout SVDRP", + "SVDRP Timeout", }, { "PrimaryLimit", "Primr-Limit", "", // TODO "", // TODO + "", // TODO }, // The days of the week: { "MTWTFSS", "MDMDFSS", "PTSCPSN", "DLMMGVS", + "MDWDVZZ", }, // Learning keys: { "Learning Remote Control Keys", "Fernbedienungs-Codes lernen", "Ucim se kod upravljalca", "Apprendimento tasti unita` remota", + "Leren toetsen afstandsbediening", }, { "Phase 1: Detecting RC code type", "Phase 1: FB Code feststellen", "Faza 1: Sprejemanje IR kode", "Fase 1: tipo ricevitore RC", + "Fase 1: detecteren type afstandsbediening", }, { "Press any key on the RC unit", "Eine Taste auf der FB drcken", "Pritisnite tipko na upravljalcu", "Premere un tasto nell'unita` RC", + "Druk op een willekeurige knop", }, { "RC code detected!", "FB Code erkannt!", "IR koda sprejeta!", "Codice RC rilevato!", + "Afstandsbediening code herkend!", }, { "Do not press any key...", "Keine Taste drcken...", "Ne pritiskajte tipk...", "Non premere alcun tasto...", + "Druk niet op een knop...", }, { "Phase 2: Learning specific key codes", "Phase 2: Einzelne Tastencodes lernen", "Faza 2: Ucenje posebnih kod", "Fase 2: Codici specifici dei tasti", + "Fase 2: Leren specifieke toets-codes", }, { "Press key for '%s'", "Taste fr '%s' drcken", "Pritisnite tipko za '%s'", "Premere il tasto per '%s'", + "Druk knop voor '%s'", }, { "Press 'Up' to confirm", "'Auf' drcken zum Besttigen", "Pritisnite tipko 'Gor' za potrditev", "Premere 'Su' per confermare", + "Druk 'Omhoog' om te bevestigen", }, { "Press 'Down' to continue", "'Ab' drcken zum Weitermachen", "Pritisnite tipko 'Dol' za nadaljevanje", "Premere 'Giu' per confermare", + "Druk 'Omlaag' om verder te gaan", }, { "(press 'Up' to go back)", "('Auf' drcken um zurckzugehen)", "(pritisnite 'Gor' za nazaj)", "(premere 'Su' per tornare indietro)", + "(druk 'Omhoog' om terug te gaan)", }, { "(press 'Down' to end key definition)", - "('Ab' drcken zum Beenden", + "('Ab' drcken zum Beenden)", "(pritisnite 'Dol' za konec)", "('Giu' per finire la definiz tasti)", + "(Druk 'Omlaag' om te beeindigen)", }, { "Phase 3: Saving key codes", "Phase 3: Codes abspeichern", "Faza 3: Shranjujem kodo", "Fase 3: Salvataggio key codes", + "Fase 3: Opslaan toets codes", }, { "Press 'Up' to save, 'Down' to cancel", "'Auf' speichert, 'Ab' bricht ab", "'Gor' za potrditev, 'Dol' za prekinitev", "'Su' per salvare, 'Giu' per annullare", + "'Omhoog' te bewaren, 'Omlaag' voor annuleren", }, // Key names: { "Up", "Auf", "Gor", "Su", + "Omhoog", }, { "Down", "Ab", "Dol", "Giu", + "Omlaag", }, { "Menu", "Men", "Meni", "Menu", + "Menu", }, { "Ok", "Ok", "Ok", "Ok", + "Ok", }, { "Back", "Zurck", "Nazaj", "Indietro", + "Terug", }, { "Left", "Links", "Levo", "Sinistra", + "Links", }, { "Right", "Rechts", "Desno", "Destra", + "Rechts", }, { "Red", "Rot", "Rdeca", "Rosso", + "Rood", }, { "Green", "Grn", "Zelena", "Verde", + "Groen", }, { "Yellow", "Gelb", "Rumena", "Giallo", + "Geel", }, { "Blue", "Blau", "Modra", "Blu", + "Blauw", }, // Miscellaneous: { "yes", "ja", "da", "si", + "ja", }, { "no", "nein", "ne", "no", - }, - { "Stop replaying", - "Wiedergabe beenden", - "Prekini ponavljanje", - "Interrompi riproduzione", - }, - { "Stop recording ", // note the trailing blank! - "Aufzeichnung beenden ", - "Prekini shranjevanje ", - "Interrompi registrazione ", - }, - { "Cancel editing", - "Schneiden abbrechen", - "Prekini urejanje", - "Annulla modifiche", + "nee", + }, + { " Stop replaying", // note the leading blank! + " Wiedergabe beenden", + " Prekini ponavljanje", + " Interrompi riproduzione", + " Stop afspelen", + }, + { " Stop recording ", // note the leading and trailing blanks! + " Aufzeichnung beenden ", + " Prekini shranjevanje ", + " Interrompi registrazione ", + " Stop opnemen ", + }, + { " Cancel editing", // note the leading blank! + " Schneiden abbrechen", + " Prekini urejanje", + " Annulla modifiche", + " Bewerken afbreken", }, { "Switching primary DVB...", "Primres Interface wird umgeschaltet...", "Preklapljanje primarne naprave...", "Cambio su card DVB primaria...", + "Eerste DVB-kaart wordt omgeschakeld...", }, { "Up/Dn for new location - OK to move", "Auf/Ab fr neue Position - dann OK", "Gor/Dol za novo poz. - Ok za premik", "Su/Giu per nuova posizione - OK per muovere", + "Gebruik Omhoog/Omlaag - daarna Ok", }, { "Editing process started", "Schnitt gestartet", "Urejanje se je zacelo", "Processo di modifica iniziato", + "Bewerken is gestart", }, { NULL } }; diff --git a/menu.c b/menu.c index 45be9eb93..09c180c47 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.68 2001/02/24 14:53:40 kls Exp $ + * $Id: menu.c 1.70 2001/03/18 10:16:56 kls Exp $ */ #include "menu.h" @@ -1425,23 +1425,27 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { case kRed: return Record(); - case kGreen: { - if (!now && !next) { - int ChannelNr = 0; - if (Count()) { - cChannel *channel = Channels.GetByServiceID(((cMenuScheduleItem *)Get(Current()))->eventInfo->GetServiceID()); - if (channel) - ChannelNr = channel->number; - } - now = true; - return AddSubMenu(new cMenuWhatsOn(schedules, true, ChannelNr)); - } - now = !now; - next = !next; - return AddSubMenu(new cMenuWhatsOn(schedules, now, cMenuWhatsOn::CurrentChannel())); - } - case kYellow: return AddSubMenu(new cMenuWhatsOn(schedules, false, cMenuWhatsOn::CurrentChannel())); - case kBlue: return Switch(); + case kGreen: if (schedules) { + if (!now && !next) { + int ChannelNr = 0; + if (Count()) { + cChannel *channel = Channels.GetByServiceID(((cMenuScheduleItem *)Get(Current()))->eventInfo->GetServiceID()); + if (channel) + ChannelNr = channel->number; + } + now = true; + return AddSubMenu(new cMenuWhatsOn(schedules, true, ChannelNr)); + } + now = !now; + next = !next; + return AddSubMenu(new cMenuWhatsOn(schedules, now, cMenuWhatsOn::CurrentChannel())); + } + case kYellow: if (schedules) + return AddSubMenu(new cMenuWhatsOn(schedules, false, cMenuWhatsOn::CurrentChannel())); + break; + case kBlue: if (Count()) + return Switch(); + break; case kOk: if (Count()) return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo, otherChannel)); break; @@ -1688,7 +1692,7 @@ eOSState cMenuCommands::ProcessKey(eKeys Key) // --- cMenuMain ------------------------------------------------------------- -#define STOP_RECORDING tr("Stop recording ") +#define STOP_RECORDING tr(" Stop recording ") static const char *hk(int n, const char *s) { diff --git a/recording.c b/recording.c index d6e5a333e..fc0daa57a 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.28 2001/02/18 16:14:05 kls Exp $ + * $Id: recording.c 1.29 2001/03/31 09:38:30 kls Exp $ */ #define _GNU_SOURCE @@ -206,6 +206,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' + t.tm_isdst = -1; // makes sure mktime() will determine the correct dst setting 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--; diff --git a/remux.c b/remux.c new file mode 100644 index 000000000..e48296d84 --- /dev/null +++ b/remux.c @@ -0,0 +1,173 @@ +/* + * remux.c: A streaming MPEG2 remultiplexer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: remux.c 1.1 2001/03/31 08:42:17 kls Exp $ + */ + +/* The calling interface of the 'cRemux::Process()' function is defined + as follows: + + 'Data' points to a chunk of data that consists of 'Count' bytes. + The 'Process' function shall try to remultiplex as much of the + data as possible and return a pointer to the resulting buffer. + That buffer typically is different from the incoming 'Data', + but in the simplest case (when 'Process' does nothing) might + as well point to the original 'Data'. When returning, 'Count' + shall be set to the number of bytes that have been processed + (i.e. have been taken from 'Data'), while 'Result' indicates + how many bytes the returned buffer contains. 'PictureType' shall + be set to NO_PICTURE if the returned data does not start a new + picture, or one of I_FRAME, P_FRAME or B_FRAME if a new picture + starting point has been found. This also means that the returned + data buffer may contain at most one entire video frame, because + the next frame must be returned with its own value for 'PictureType'. + + 'Process' shall do it's best to keep the latency time as short + as possible in order to allow a quick start of VDR's "Transfer + mode" (displaying the signal of one DVB card on another card). + In order to do that, this function may decide to first pass + through the incoming data (almost) unprocessed, and make + actual processing kick in after a few seconds (if that is at + all possible for the algorithm). This may result in a non- + optimal stream at the beginning, which won't matter for normal + recordings but may make switching through encrypted channels + in "Transfer mode" faster. + + In the resulting data stream, a new packet shall always be started + when a frame border is encountered. VDR needs this in order to + be able to detect and store the frame indexes, and to easily + display single frames in fast forward/back mode. The very first + data block returned shall be the starting point of an I_FRAME. + Everything before that shall be silently dropped. + + If the incoming data is not enough to do remultiplexing, a value + of NULL shall be returned ('Result' has no meaning then). This + will tell the caller to wait for more data to be presented in + the next call. If NULL is returned and 'Count' is not 0, the + caller shall remove 'Count' bytes from the beginning of 'Data' + before the next call. This is the way 'Process' indicates that + it must skip that data. + + Any data that is not used during this call will appear at the + beginning of the incoming 'Data' buffer at the next call, plus + any new data that has become available. + + It is guaranteed that the caller will completely process any + returned data before the next call to 'Process'. That way, 'Process' + can dynamically allocate its return buffer and be sure the caller + doesn't keep any pointers into that buffer. +*/ + +#include "remux.h" +#include "tools.h" + +#if defined(REMUX_NONE) + +cRemux::cRemux(void) +{ + synced = false; +} + +cRemux::~cRemux() +{ +} + +int cRemux::GetPacketLength(const uchar *Data, int Count, int Offset) +{ + // Returns the entire length of the packet starting at offset, or -1 in case of error. + return (Offset + 5 < Count) ? (Data[Offset + 4] << 8) + Data[Offset + 5] + 6 : -1; +} + +int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType) +{ + // Scans the video packet starting at Offset and returns its length. + // If the return value is -1 the packet was not completely in the buffer. + + int Length = GetPacketLength(Data, Count, Offset); + if (Length > 0 && Offset + Length <= Count) { + int i = Offset + 8; // the minimum length of the video packet header + i += Data[i] + 1; // possible additional header bytes + for (; i < Offset + Length; i++) { + if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { + switch (Data[i + 3]) { + case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07; + return Length; + } + } + } + PictureType = NO_PICTURE; + return Length; + } + return -1; +} + +const uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar &PictureType) +{ + int Skip = 0; + + PictureType = NO_PICTURE; + + if (Count >= MINVIDEODATA) { + for (int i = 0; i < Count; i++) { + if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { + switch (Data[i + 3]) { + case SC_VIDEO: + { + uchar pt = NO_PICTURE; + int l = ScanVideoPacket(Data, Count, i, pt); + if (l < 0) { + if (Skip < Count) + Count = Skip; + return NULL; // no useful data found, wait for more + } + if (pt != NO_PICTURE) { + if (pt < I_FRAME || B_FRAME < pt) { + esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); + } + else if (PictureType == NO_PICTURE) { + if (!synced) { + if (pt == I_FRAME) { + Skip = i; + synced = true; + } + else { + i += l; + Skip = i; + break; + } + } + if (synced) + PictureType = pt; + } + else { + Count = i; + Result = i - Skip; + return Data + Skip; + } + } + else if (!synced) { + i += l; + Skip = i; + break; + } + i += l - 1; // -1 to compensate for i++ in the loop! + } + break; + case SC_AUDIO: + i += GetPacketLength(Data, Count, i) - 1; // -1 to compensate for i++ in the loop! + break; + } + } + } + } + if (Skip < Count) + Count = Skip; + return NULL; // no useful data found, wait for more +} + +#elif defined(REMUX_TEST) +#endif + diff --git a/remux.h b/remux.h new file mode 100644 index 000000000..bceb676bf --- /dev/null +++ b/remux.h @@ -0,0 +1,51 @@ +/* + * remux.h: A streaming MPEG2 remultiplexer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: remux.h 1.1 2001/03/31 08:42:27 kls Exp $ + */ + +#ifndef __REMUX_H +#define __REMUX_H + +// There are various experiments with different types of remultiplexers +// going on at the moment. Select the remultiplexer here: +#define REMUX_NONE 1 +//#define REMUX_TEST 1 + +// Picture types: +#define NO_PICTURE 0 +#define I_FRAME 1 +#define P_FRAME 2 +#define B_FRAME 3 + +// Start codes: +#define SC_PICTURE 0x00 // "picture header" +#define SC_SEQU 0xB3 // "sequence header" +#define SC_PHEAD 0xBA // "pack header" +#define SC_SHEAD 0xBB // "system header" +#define SC_AUDIO 0xC0 +#define SC_VIDEO 0xE0 + +// The minimum amount of video data necessary to identify frames: +#define MINVIDEODATA (256*1024) // just a safe guess (max. size of any frame block, plus some safety) + +typedef unsigned char uchar; + +class cRemux { +private: +#if defined(REMUX_NONE) + bool synced; + int GetPacketLength(const uchar *Data, int Count, int Offset); + int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType); +#elif defined(REMUX_TEST) +#endif +public: + cRemux(void); + ~cRemux(); + const uchar *Process(const uchar *Data, int &Count, int &Result, uchar &PictureType); + }; + +#endif // __REMUX_H diff --git a/ringbuffer.c b/ringbuffer.c new file mode 100644 index 000000000..48707133c --- /dev/null +++ b/ringbuffer.c @@ -0,0 +1,170 @@ +/* + * ringbuffer.c: A threaded ring buffer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * Parts of this file were inspired by the 'ringbuffy.c' from the + * LinuxDVB driver (see linuxtv.org). + * + * $Id: ringbuffer.c 1.1 2001/03/10 17:11:34 kls Exp $ + */ + +#include "ringbuffer.h" +#include "tools.h" + +// --- cRingBufferInputThread ------------------------------------------------- + +class cRingBufferInputThread : public cThread { +private: + cRingBuffer *ringBuffer; +protected: + virtual void Action(void) { ringBuffer->Input(); } +public: + cRingBufferInputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; } + }; + +// --- cRingBufferOutputThread ------------------------------------------------ + +class cRingBufferOutputThread : public cThread { +private: + cRingBuffer *ringBuffer; +protected: + virtual void Action(void) { ringBuffer->Output(); } +public: + cRingBufferOutputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; } + }; + +// --- cRingBuffer ------------------------------------------------------------ + +cRingBuffer::cRingBuffer(int Size) +{ + size = Size; + buffer = NULL; + inputThread = NULL; + outputThread = NULL; + maxFill = 0; + busy = false; + if (size > 1) { // 'size - 1' must not be 0! + buffer = new uchar[size]; + if (!buffer) + esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size); + Clear(); + } + else + esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", size); +} + +cRingBuffer::~cRingBuffer() +{ + delete inputThread; + delete outputThread; + delete buffer; + dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1)); +} + +void cRingBuffer::Clear(void) +{ + mutex.Lock(); + head = tail = 0; + mutex.Unlock(); +} + +int cRingBuffer::Put(const uchar *Data, int Count) +{ + if (Count > 0) { + mutex.Lock(); + int rest = size - head; + int diff = tail - head; + mutex.Unlock(); + int free = (diff > 0) ? diff - 1 : size + diff - 1; + // Statistics: + int fill = size - free - 1 + Count; + if (fill >= size) + fill = size - 1; + if (fill > maxFill) { + maxFill = fill; + int percent = maxFill * 100 / (size - 1); + if (percent > 75) + dsyslog(LOG_INFO, "buffer usage: %d%%", percent); + } + // + if (free <= 0) + return 0; + if (free < Count) + Count = free; + if (Count > maxFill) + maxFill = Count; + if (Count >= rest) { + memcpy(buffer + head, Data, rest); + if (Count - rest) + memcpy(buffer, Data + rest, Count - rest); + head = Count - rest; + } + else { + memcpy(buffer + head, Data, Count); + head += Count; + } + } + return Count; +} + +int cRingBuffer::Get(uchar *Data, int Count) +{ + if (Count > 0) { + mutex.Lock(); + int rest = size - tail; + int diff = head - tail; + mutex.Unlock(); + int cont = (diff >= 0) ? diff : size + diff; + if (rest <= 0) + return 0; + if (cont < Count) + Count = cont; + if (Count >= rest) { + memcpy(Data, buffer + tail, rest); + if (Count - rest) + memcpy(Data + rest, buffer, Count - rest); + tail = Count - rest; + } + else { + memcpy(Data, buffer + tail, Count); + tail += Count; + } + } + return Count; +} + +bool cRingBuffer::Start(void) +{ + if (!busy) { + busy = true; + outputThread = new cRingBufferOutputThread(this); + if (!outputThread->Start()) + DELETENULL(outputThread); + inputThread = new cRingBufferInputThread(this); + if (!inputThread->Start()) { + DELETENULL(inputThread); + DELETENULL(outputThread); + } + busy = outputThread && inputThread; + } + return busy; +} + +bool cRingBuffer::Active(void) +{ + return outputThread && outputThread->Active() && inputThread && inputThread->Active(); +} + +void cRingBuffer::Stop(void) +{ + busy = false; + for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) { + if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active()))) + break; + } + DELETENULL(inputThread); + DELETENULL(outputThread); +} + diff --git a/ringbuffer.h b/ringbuffer.h new file mode 100644 index 000000000..1669a4946 --- /dev/null +++ b/ringbuffer.h @@ -0,0 +1,55 @@ +/* + * ringbuffer.h: A threaded ring buffer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: ringbuffer.h 1.1 2001/03/10 14:00:59 kls Exp $ + */ + +#ifndef __RINGBUFFER_H +#define __RINGBUFFER_H + +#include "thread.h" + +typedef unsigned char uchar; + +class cRingBufferInputThread; +class cRingBufferOutputThread; + +class cRingBuffer { + friend class cRingBufferInputThread; + friend class cRingBufferOutputThread; +private: + cRingBufferInputThread *inputThread; + cRingBufferOutputThread *outputThread; + cMutex mutex; + int size, head, tail; + uchar *buffer; + int maxFill; + bool busy; +protected: + bool Busy(void) { return busy; } + void Clear(void); + // Immediately clears the ring buffer. + int Put(const uchar *Data, int Count); + // Puts at most Count bytes of Data into the ring buffer. + // Returns the number of bytes actually stored. + int Get(uchar *Data, int Count); + // Gets at most Count bytes of Data from the ring buffer. + // Returns the number of bytes actually retrieved. + virtual void Input(void) = 0; + // Runs as a separate thread and shall continuously read data from + // a source and call Put() to store the data in the ring buffer. + virtual void Output(void) = 0; + // Runs as a separate thread and shall continuously call Get() to + // retrieve data from the ring buffer and write it to a destination. +public: + cRingBuffer(int Size); + virtual ~cRingBuffer(); + bool Start(void); + bool Active(void); + void Stop(void); + }; + +#endif // __RINGBUFFER_H diff --git a/runvdr b/runvdr index 83b2ea62f..5ec345854 100755 --- a/runvdr +++ b/runvdr @@ -1,13 +1,18 @@ #!/bin/sh -DVBDIR='../DVB/driver' -VDRCMD='./vdr -w 60' +DVBDIR="../DVB/driver" +VDRPRG="./vdr" +VDRCMD="$VDRPRG -w 60" -while test 1; do +KILLPROC="/sbin/killproc -TERM" + +while (true) do # (cd $DVBDIR; make reload) # sleep 3 - if $VDRCMD; then exit; fi + $VDRCMD + if test $? -ne 1; then exit; fi date echo "restarting VDR" + $KILLPROC $VDRPRG sleep 10 done diff --git a/svdrp.c b/svdrp.c index ffdac28b4..df4ffaccb 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.14 2001/02/18 14:18:13 kls Exp $ + * $Id: svdrp.c 1.18 2001/04/01 16:06:54 kls Exp $ */ #define _GNU_SOURCE @@ -113,7 +113,6 @@ int cSocket::Accept(void) // --- cSVDRP ---------------------------------------------------------------- -#define MAXCMDBUFFER 10000 #define MAXHELPTOPIC 10 const char *HelpPages[] = { @@ -138,6 +137,8 @@ const char *HelpPages[] = { " List channels. Without option, all channels are listed. Otherwise\n" " only the given channel is listed. If a name is given, all channels\n" " containing the given string as part of their name are listed.", + "LSTE\n" + " List EPG data.", "LSTT [ ]\n" " List timers. Without option, all timers are listed. Otherwise\n" " only the given timer is listed.", @@ -188,6 +189,7 @@ const char *HelpPages[] = { /* SVDRP Reply Codes: 214 Help message + 215 EPG data record 220 VDR service ready 221 VDR service closing transmission channel 250 Requested VDR action okay, completed @@ -234,6 +236,7 @@ const char *GetHelpPage(const char *Cmd) cSVDRP::cSVDRP(int Port) :socket(Port) { + numChars = 0; message = NULL; lastActivity = 0; isyslog(LOG_INFO, "SVDRP listening on port %d", Port); @@ -470,13 +473,24 @@ void cSVDRP::CmdHELP(const char *Option) Reply(-214, "This is VDR version %s", VDRVERSION); Reply(-214, "Topics:"); const char **hp = HelpPages; + int NumPages = 0; while (*hp) { - //TODO multi-column??? - const char *topic = GetHelpTopic(*hp); - if (topic) - Reply(-214, " %s", topic); + NumPages++; hp++; } + const int TopicsPerLine = 5; + int x = 0; + for (int y = 0; (y * TopicsPerLine + x) < NumPages; y++) { + char buffer[TopicsPerLine * (MAXHELPTOPIC + 5)]; + char *q = buffer; + for (x = 0; x < TopicsPerLine && (y * TopicsPerLine + x) < NumPages; x++) { + const char *topic = GetHelpTopic(HelpPages[(y * TopicsPerLine + x)]); + if (topic) + q += sprintf(q, " %s", topic); + } + x = 0; + Reply(-214, buffer); + } Reply(-214, "To report bugs in the implementation send email to"); Reply(-214, " vdr-bugs@cadsoft.de"); } @@ -535,7 +549,7 @@ void cSVDRP::CmdLSTC(const char *Option) Reply(250, "%d %s", next->number, next->ToText()); } } - else { + else if (Channels.MaxNumber() >= 1) { for (int i = 1; i <= Channels.MaxNumber(); i++) { cChannel *channel = Channels.GetByNumber(i); if (channel) @@ -544,6 +558,27 @@ void cSVDRP::CmdLSTC(const char *Option) Reply(501, "Channel \"%d\" not found", i); } } + else + Reply(550, "No channels defined"); +} + +void cSVDRP::CmdLSTE(const char *Option) +{ + cThreadLock ThreadLock; + const cSchedules *Schedules = cDvbApi::PrimaryDvbApi->Schedules(&ThreadLock); + if (Schedules) { + FILE *f = fdopen(file, "w"); + if (f) { + Schedules->Dump(f, "215-"); + fflush(f); + Reply(215, "End of EPG data"); + // don't 'fclose(f)' here! + } + else + Reply(451, "Can't open file connection"); + } + else + Reply(451, "Can't get EPG data"); } void cSVDRP::CmdLSTT(const char *Option) @@ -559,7 +594,7 @@ void cSVDRP::CmdLSTT(const char *Option) else Reply(501, "Error in timer number \"%s\"", Option); } - else { + else if (Timers.Count()) { for (int i = 0; i < Timers.Count(); i++) { cTimer *timer = Timers.Get(i); if (timer) @@ -568,6 +603,8 @@ void cSVDRP::CmdLSTT(const char *Option) Reply(501, "Timer \"%d\" not found", i + 1); } } + else + Reply(550, "No timers defined"); } void cSVDRP::CmdMESG(const char *Option) @@ -838,7 +875,8 @@ void cSVDRP::Execute(char *Cmd) char *s = Cmd; while (*s && !isspace(*s)) s++; - *s++ = 0; + if (*s) + *s++ = 0; if (CMD("CHAN")) CmdCHAN(s); else if (CMD("DELC")) CmdDELC(s); else if (CMD("DELT")) CmdDELT(s); @@ -846,6 +884,7 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("HELP")) CmdHELP(s); else if (CMD("HITK")) CmdHITK(s); else if (CMD("LSTC")) CmdLSTC(s); + else if (CMD("LSTE")) CmdLSTE(s); else if (CMD("LSTT")) CmdLSTT(s); else if (CMD("MESG")) CmdMESG(s); else if (CMD("MODC")) CmdMODC(s); @@ -860,8 +899,7 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("OVLP")) CmdOVLP(s); else if (CMD("OVLO")) CmdOVLO(s); else if (CMD("UPDT")) CmdUPDT(s); - else if (CMD("QUIT") - || CMD("\x04")) Close(); + else if (CMD("QUIT")) Close(); else Reply(500, "Command unrecognized: \"%s\"", Cmd); } @@ -871,29 +909,55 @@ void cSVDRP::Process(void) bool SendGreeting = NewConnection; if (file.IsOpen() || file.Open(socket.Accept())) { - char buffer[MAXCMDBUFFER]; if (SendGreeting) { //TODO how can we get the *full* hostname? + char buffer[MAXCMDBUFFER]; gethostname(buffer, sizeof(buffer)); time_t now = time(NULL); Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now)); } if (NewConnection) lastActivity = time(NULL); - int rbytes = file.ReadString(buffer, sizeof(buffer) - 1); - if (rbytes > 0) { - //XXX overflow check??? - // strip trailing whitespace: - while (rbytes > 0 && strchr(" \t\r\n", buffer[rbytes - 1])) - buffer[--rbytes] = 0; - // make sure the string is terminated: - buffer[rbytes] = 0; - // showtime! - Execute(buffer); - lastActivity = time(NULL); + if (file.Ready(false)) { + unsigned char c; + int r = read(file, &c, 1); + if (r > 0) { + if (c == '\n' || c == 0x00) { + // strip trailing whitespace: + while (numChars > 0 && strchr(" \t\r\n", cmdLine[numChars - 1])) + cmdLine[--numChars] = 0; + // make sure the string is terminated: + cmdLine[numChars] = 0; + // showtime! + Execute(cmdLine); + numChars = 0; + } + else if (c == 0x04 && numChars == 0) { + // end of file (only at beginning of line) + Close(); + } + else if (c == 0x08 || c == 0x7F) { + // backspace or delete (last character) + if (numChars > 0) + numChars--; + } + else if (c <= 0x03 || c == 0x0D || 0xF0 <= c) { + // ignore control characters + } + else if (numChars < sizeof(cmdLine) - 1) { + cmdLine[numChars++] = c; + cmdLine[numChars] = 0; + } + else { + Reply(501, "Command line too long"); + esyslog(LOG_ERR, "SVDRP: command line too long: '%s'", cmdLine); + numChars = 0; + } + lastActivity = time(NULL); + } + else if (r < 0) + Close(); } - else if (rbytes < 0) - Close(); else if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) { isyslog(LOG_INFO, "timeout on SVDRP connection"); Close(true); diff --git a/svdrp.h b/svdrp.h index 62c1e7537..83827082a 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.7 2001/02/18 13:36:47 kls Exp $ + * $Id: svdrp.h 1.9 2001/04/01 15:05:38 kls Exp $ */ #ifndef __SVDRP_H @@ -26,11 +26,15 @@ class cSocket { int Accept(void); }; +#define MAXCMDBUFFER 1024 + class cSVDRP { private: cSocket socket; cFile file; CRect ovlClipRects[MAXCLIPRECTS]; + uint numChars; + char cmdLine[MAXCMDBUFFER]; char *message; time_t lastActivity; void Close(bool Timeout = false); @@ -43,6 +47,7 @@ class cSVDRP { void CmdHELP(const char *Option); void CmdHITK(const char *Option); void CmdLSTC(const char *Option); + void CmdLSTE(const char *Option); void CmdLSTT(const char *Option); void CmdMESG(const char *Option); void CmdMODC(const char *Option); diff --git a/tools.c b/tools.c index a3b27e5a7..c303a8ab8 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.30 2001/02/11 14:44:22 kls Exp $ + * $Id: tools.c 1.32 2001/04/01 14:13:36 kls Exp $ */ #define _GNU_SOURCE @@ -369,27 +369,6 @@ void cFile::Close(void) } } -int cFile::ReadString(char *Buffer, int Size) -{ - int rbytes = 0; - bool wait = true; - - while (Ready(wait)) { - int n = read(f, Buffer + rbytes, 1); - if (n == 0) - break; // EOF - if (n < 0) { - LOG_ERROR; - return -1; - } - rbytes += n; - if (rbytes == Size || Buffer[rbytes - 1] == '\n') - break; - wait = false; - } - return rbytes; -} - bool cFile::Ready(bool Wait) { return f >= 0 && AnyFileReady(f, Wait ? 1000 : 0); @@ -519,11 +498,6 @@ cListBase::cListBase(void) cListBase::~cListBase() { Clear(); - while (objects) { - cListObject *object = objects->Next(); - delete objects; - objects = object; - } } void cListBase::Add(cListObject *Object) diff --git a/tools.h b/tools.h index 96d09826e..a9d61218f 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.24 2001/02/11 13:39:40 kls Exp $ + * $Id: tools.h 1.25 2001/04/01 14:13:42 kls Exp $ */ #ifndef __TOOLS_H @@ -64,7 +64,6 @@ class cFile { bool Open(int FileDes); void Close(void); bool IsOpen(void) { return f >= 0; } - int ReadString(char *Buffer, int Size); bool Ready(bool Wait = true); static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000); static bool FileReady(int FileDes, int TimeoutMs = 1000); diff --git a/vdr.c b/vdr.c index 938afcf09..8ed209a63 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.54 2001/02/24 16:18:43 kls Exp $ + * $Id: vdr.c 1.56 2001/04/01 11:16:54 kls Exp $ */ #include @@ -74,6 +74,7 @@ int main(int argc, char *argv[]) const char *ConfigDirectory = NULL; bool DaemonMode = false; int WatchdogTimeout = DEFAULTWATCHDOG; + char *Terminal = NULL; static struct option long_options[] = { { "config", required_argument, NULL, 'c' }, @@ -84,12 +85,13 @@ int main(int argc, char *argv[]) { "port", required_argument, NULL, 'p' }, { "video", required_argument, NULL, 'v' }, { "watchdog", required_argument, NULL, 'w' }, + { "terminal", required_argument, NULL, 't' }, { 0 } }; int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "c:dD:hl:p:v:w:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "c:dD:hl:p:v:w:t:", long_options, &option_index)) != -1) { switch (c) { case 'c': ConfigDirectory = optarg; break; @@ -102,7 +104,7 @@ int main(int argc, char *argv[]) } } fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg); - abort(); + return 2; break; case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80| " -c DIR, --config=DIR read config files from DIR (default is to read them\n" @@ -117,9 +119,10 @@ int main(int argc, char *argv[]) " 2 = errors and info, 3 = errors, info and debug\n" " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" " 0 turns off SVDRP\n" - " -v DIR, --video=DIR use DIR as video directory (default is %s)\n" + " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n" " seconds (default: %d); '0' disables the watchdog\n" + " -t TTY, --terminal=TTY controlling tty\n" "\n" "Report bugs to \n", DEFAULTSVDRPPORT, @@ -136,15 +139,17 @@ int main(int argc, char *argv[]) } } fprintf(stderr, "vdr: invalid log level: %s\n", optarg); - abort(); + return 2; break; case 'p': if (isnumber(optarg)) SVDRPport = atoi(optarg); else { fprintf(stderr, "vdr: invalid port number: %s\n", optarg); - abort(); + return 2; } break; + case 't': Terminal = optarg; + break; case 'v': VideoDirectory = optarg; while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') optarg[strlen(optarg) - 1] = 0; @@ -157,9 +162,9 @@ int main(int argc, char *argv[]) } } fprintf(stderr, "vdr: invalid watchdog timeout: %s\n", optarg); - abort(); + return 2; break; - default: abort(); + default: return 2; } } @@ -172,7 +177,7 @@ int main(int argc, char *argv[]) if (!DirectoryOk(VideoDirectory, true)) { fprintf(stderr, "vdr: can't access video directory %s\n", VideoDirectory); - abort(); + return 2; } // Daemon mode: @@ -183,7 +188,7 @@ int main(int argc, char *argv[]) if (pid < 0) { fprintf(stderr, "%m\n"); esyslog(LOG_ERR, "ERROR: %m"); - abort(); + return 2; } if (pid != 0) return 0; // initial program immediately returns @@ -192,9 +197,16 @@ int main(int argc, char *argv[]) fclose(stderr); #else fprintf(stderr, "vdr: can't run in daemon mode with DEBUG_OSD or REMOTE_KBD on!\n"); - abort(); + return 2; #endif } + else if (Terminal) { + // Claim new controlling terminal + stdin = freopen(Terminal, "r", stdin); + stdout = freopen(Terminal, "w", stdout); + stderr = freopen(Terminal, "w", stderr); + } + isyslog(LOG_INFO, "VDR version %s started", VDRVERSION); // Configuration data: @@ -215,7 +227,7 @@ int main(int argc, char *argv[]) // DVB interfaces: if (!cDvbApi::Init()) - abort(); + return 2; cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); From 8f9cc68f76c4fd0960f919a77fb16a6455922deb Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 29 Jul 2001 18:00:00 +0200 Subject: [PATCH 019/307] =?UTF-8?q?Version=200.85=20-=20Added=20Norwegian?= =?UTF-8?q?=20language=20texts=20(thanks=20to=20J=F8rgen=20Tvedt).=20-=20I?= =?UTF-8?q?ncreased=20the=20usleep=20value=20in=20cDvbOsd::Cmd()=20to=2050?= =?UTF-8?q?00=20in=20order=20to=20work=20on=20=20=20systems=20with=20the?= =?UTF-8?q?=20KURT/utime-patch=20(thanks=20to=20Guido=20Fiala).=20-=20Chan?= =?UTF-8?q?ged=20the=20check=20whether=20the=20driver=20is=20loaded=20in?= =?UTF-8?q?=20runvdr=20to=20check=20for=20the=20=20=20'dvb'=20module=20(th?= =?UTF-8?q?e=20last=20one=20loaded).=20-=20Fixed=20repeat=20function=20wit?= =?UTF-8?q?h=20LIRC=20(thanks=20to=20Stefan=20Huelswitt).=20-=20Increased?= =?UTF-8?q?=20the=20upper=20limit=20for=20the=20symbol=20rate=20to=2030000?= =?UTF-8?q?=20(thanks=20to=20Ulrich=20=20=20R=F6der).=20-=20Made=20the=20p?= =?UTF-8?q?osition=20of=20the=20channel=20display=20configurable=20(thanks?= =?UTF-8?q?=20to=20Stefan=20=20=20Huelswitt).=20-=20Made=20the=20width=20a?= =?UTF-8?q?nd=20height=20of=20the=20OSD=20configurable=20(thanks=20to=20St?= =?UTF-8?q?efan=20Huelswitt).=20-=20DiSEqC=20support=20can=20now=20be=20ge?= =?UTF-8?q?nerally=20enabled/disabled=20in=20the=20Setup=20menu.=20This=20?= =?UTF-8?q?=20=20may=20be=20necessary=20if=20your=20multiswitch=20gets=20i?= =?UTF-8?q?rritated=20by=20the=20default=20DiSEqC=20=20=20codes=20'0'=20(t?= =?UTF-8?q?hanks=20to=20Markus=20Lang).=20-=20Fixed=20replaying=20in=20cas?= =?UTF-8?q?e=20there=20is=20no=20index=20file.=20-=20Fixed=20jumping=20to?= =?UTF-8?q?=20an=20editing=20mark=20when=20replay=20has=20been=20paused.?= =?UTF-8?q?=20-=20Avoiding=20unnecessary=20code=20execution=20in=20the=20r?= =?UTF-8?q?eplay=20progress=20display=20(thanks=20=20=20to=20Guido=20Fiala?= =?UTF-8?q?).=20-=20When=20entering=20time=20values=20the=20digits=20that?= =?UTF-8?q?=20still=20have=20to=20be=20entered=20are=20now=20=20=20shown?= =?UTF-8?q?=20as=20'-'=20(as=20in=20"1-:--").=20-=20When=20setting=20an=20?= =?UTF-8?q?editing=20mark=20while=20the=20progress=20display=20is=20not=20?= =?UTF-8?q?active,=20the=20=20=20display=20will=20now=20be=20turned=20on?= =?UTF-8?q?=20for=20a=20short=20while=20to=20indicate=20the=20successful?= =?UTF-8?q?=20=20=20setting=20of=20the=20mark.=20-=20Updated=20'channels.c?= =?UTF-8?q?onf'=20for=20Premiere=20World=20(thanks=20to=20Helmut=20Sch=E4c?= =?UTF-8?q?hner).=20=20=20Check=20your=20timers=20if=20you=20use=20this=20?= =?UTF-8?q?channels.conf=20file,=20since=20the=20sequence=20of=20=20=20sev?= =?UTF-8?q?eral=20PW=20channels=20has=20been=20changed.=20-=20Changed=20th?= =?UTF-8?q?e=20color=20of=20"Info"=20messages=20to=20"black=20on=20green"?= =?UTF-8?q?=20and=20that=20of=20the=20=20=20confirmation=20messages=20(lik?= =?UTF-8?q?e=20"Delete...")=20to=20"black=20on=20yellow".=20-=20Fixed=20di?= =?UTF-8?q?splay=20with=20DEBUG=5FOSD=20(it=20still=20crashes=20sometimes,?= =?UTF-8?q?=20esp.=20when=20replaying,=20=20=20but=20I=20can't=20seem=20to?= =?UTF-8?q?=20find=20what=20causes=20this...=20any=20ideas=20anybody=3F).?= =?UTF-8?q?=20-=20Avoiding=20audio/video=20distortions=20in=20'Transfer=20?= =?UTF-8?q?Mode'=20by=20no=20longer=20actually=20=20=20tuning=20the=20prim?= =?UTF-8?q?ary=20interface=20(which=20can't=20receive=20this=20channel,=20?= =?UTF-8?q?anyway).=20=20=20Apparently=20the=20driver=20gets=20irritated?= =?UTF-8?q?=20when=20the=20channel=20is=20switched=20and=20a=20=20=20repla?= =?UTF-8?q?y=20session=20is=20started=20immediately=20after=20that.=20-=20?= =?UTF-8?q?Increased=20timeout=20until=20reporting=20"video=20data=20strea?= =?UTF-8?q?m=20broken"=20when=20recording.=20-=20Explicitly=20switching=20?= =?UTF-8?q?back=20to=20the=20previously=20active=20channel=20after=20endin?= =?UTF-8?q?g=20a=20=20=20replay=20session=20(to=20have=20it=20shown=20corr?= =?UTF-8?q?ectly=20in=20case=20it=20was=20in=20'Transfer=20Mode').?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTORS | 36 + FORMATS | 22 +- HISTORY | 163 +++- INSTALL | 16 +- MANUAL | 48 +- Makefile | 8 +- Tools/schnitt/README | 63 +- Tools/schnitt/cut.pl | 19 +- Tools/schnitt/cut2 | 2 +- Tools/schnitt/cutall | 4 +- Tools/schnitt/cutall2 | 2 +- Tools/schnitt/cutt | 129 +-- Tools/schnitt/getpreviframe.pl | 6 - Tools/schnitt/mv2 | 35 +- Tools/schnitt/schnitt.pl | 3 +- Tools/schnitt/schnitt2.pl | 2 + Tools/schnitt/show | 2 +- Tools/schnitt/vmount | 2 +- channels.conf | 122 ++- config.c | 81 +- config.h | 26 +- dvbapi.c | 1621 ++++++++++++++++++-------------- dvbapi.h | 75 +- dvbosd.c | 352 ++++++- dvbosd.h | 84 +- eit.c | 257 +++-- eit.h | 10 +- i18n.c | 458 ++++++++- interface.c | 22 +- interface.h | 4 +- menu.c | 250 +++-- menu.h | 6 +- osd.h | 4 +- recording.c | 57 +- recording.h | 4 +- remote.c | 12 +- remote.h | 4 +- remux.c | 539 ++++++++++- remux.h | 37 +- ringbuffer.c | 37 +- ringbuffer.h | 8 +- runvdr | 36 +- svdrp.c | 8 +- thread.c | 60 +- thread.h | 17 +- tools.c | 22 +- tools.h | 3 +- vdr.c | 20 +- videodir.c | 4 +- 49 files changed, 3431 insertions(+), 1371 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 8a67f37c9..676cf8991 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -23,6 +23,7 @@ Guido Fiala for implementing the SVDRP command 'HITK' for implementing image grabbing for implementing overlay capabilities (see his 'kvdr' tool at http://www.s.netic.de/gfiala) + for making the replay progress display avoid unnecessary code execution Robert Schneider for implementing EIT support for displaying the current/next info @@ -42,6 +43,7 @@ Bastian Guse Matthias Schniedermeyer for implementing the 'MarkInstantRecord' setup option for his "schnitt" tools + for his "master-timer" tool Miha Setina for translating the OSD texts to the Slovenian language @@ -54,6 +56,7 @@ Deti Fliegl Dave Chapman for implementing support for the teletext PID + for his great support in switching to the NAPI Hans-Peter Raschke for his support in adapting VDR to DVB-C @@ -70,3 +73,36 @@ Arnold Niessen Jrgen Sauer for implementing the -t option to set the controlling terminal + +Benjamin Reichardt + for his help in debugging the transition to the new API + +Henning Holtschneider + for patching 'runvdr' to check whether the driver is already loaded + +Paulo Manuel Martins Lopes + for translating the OSD texts to the Portugese language + +Markus Lang and Ulrich Rder + for making DiSEqC support configurable + +Jean-Claude Repetto + for translating the OSD texts to the French language + +Andre Valentin + for increasing the key name buffer size for LIRC + +Jrgen Tvedt + for translating the OSD texts to the Norwegian language + +Stefan Huelswitt + for fixing the repeat function with LIRC + for making the position of the channel display configurable + for making the width and height of the OSD configurable + +Ulrich Rder + for pointing out that there are channels that have a symbol rate higher than + 27500. + +Helmut Schchner + for his support in keeping the Premiere World channels up to date in 'channels.conf' diff --git a/FORMATS b/FORMATS index 2a357a355..03739ee50 100644 --- a/FORMATS +++ b/FORMATS @@ -13,7 +13,7 @@ Video Disk Recorder File Formats A "channel definition" is a line with channel data, where the fields are separated by ':' characters: - Example: "RTL:12188:h:1:27500:163:104:0:0:12003" + Example: "RTL:12188:h:1:27500:163:104:105:0:12003" The fields in a channel definition have the following meaning (from left to right): @@ -25,7 +25,9 @@ Video Disk Recorder File Formats - Diseqc number ** - Symbol rate - Video PID - - Audio PID + - Audio PID (either one number, or two, separated by a comma) + If this channel also carries Dolby Digital sound, the Dolby PIDs follow + the audio PIDs, separated by a semicolon, as in "...:101,102;103,104:..." - Teletext PID - Conditional Access (0 = Free To Air, 1 = can be decrypted by the first DVB card, 2 = can be decrypted by the second DVB card) @@ -60,8 +62,10 @@ Video Disk Recorder File Formats (1..31) - Start time (first two digits for the hour, second two digits for the minutes) - End time (first two digits for the hour, second two digits for the minutes) - - Priority (from 00 to 99, 00 = lowest prioity, 99 = highest priority) - - Guaranteed lifetime of recording (in days) + - Priority (from 0 to 99, 0 = lowest prioity, 99 = highest priority) + - Guaranteed lifetime of recording (in days); 0 means that this recording may + be automatically deleted by a new recording with higher priority, 99 means + that this recording will never be automatically deleted - Name of timer (will be used to name the recording); if the name contains any ':' characters, these have to be replaced with '|' - Summary (any newline characters in the summary have to be replaced with '|'; @@ -126,3 +130,13 @@ Video Disk Recorder File Formats - marks must have a frame number, and that frame MUST be an I-frame (this means that only marks generated by VDR itself can be used, since they will always be guaranteed to mark I-frames). + +* 001.vdr ... 255.vdr + + These are the actual recorded MPEG data files. In order to keep the size of + an individual file below a given limit, a recording is split into several + files. The contents of these files is "Packetized Elementary Stream" (PES) + and contains ES packets with ids 0xE0 for video, 0xC0 for audio 1 and 0xC1 + for audio 2 (if available). Dolby Digital data is stored in packets with + ids 0xBD. + diff --git a/HISTORY b/HISTORY index 203377d37..d625b260f 100644 --- a/HISTORY +++ b/HISTORY @@ -290,7 +290,7 @@ Video Disk Recorder Revision History channel, if the timer currently occupying this DVB card doesn't need the CAM module (and thus can continue recording on a different DVB card). - The "Yellow" button in the "What's on now/next?" menus now displays the - schedule of the current channel from that menu. + schedule of the current channel from that menu. - All DVB cards in a multi-card system now write their EIT information into the same data structure. - If there is more than one DVB card in the system, the non-primary cards are @@ -332,8 +332,8 @@ Video Disk Recorder Revision History - Implemented "On Disk Editing". - There is no more default 'timers.conf' file. - Added Italian language texts (thanks to Alberto Carraro). -- Fixed starting a replay session when the program is currently in "transfer - mode". +- Fixed starting a replay session when the program is currently in 'Transfer + Mode'. - Fixed setting/modifying timers via SVDRP with empty summary fields. - Fixed a problem with recordings that have a single quote character in their name (this is now mapped to 0x01). @@ -452,3 +452,160 @@ Video Disk Recorder Revision History - Empty lines in config files no longer cause error messages. - New SVDRP command LSTE to list the EPG data. - The SVDRP HELP command now prints the topics in several columns. + +2001-06-02: Version 0.80 + +- VDR now requires driver version 0.9.0 or higher. +- Switched to the "new API" (thanks to Dave Chapman for his great support in + this task). +- New setup parameter "LnbSLOF" that defines the switching frequency of the LNB. +- Fixed a bug in the EPG scanner with more than one DVB card. +- Fixed checking for free disk space, so that it works with NFS mounted drives. +- Files are now created with mode 644. +- Fixed checking the exit status in the 'runvdr' script. +- Activated loading the driver in 'runvdr'. Please read the comments in 'runvdr' + for details. +- The new "emergency exit" feature automatically triggers a restart of VDR (if + used with 'runvdr', otherwise it simply exists) if + * tuning the channel for a recording fails + * no useful data is received within the first 1MB of a recording + * no data is received within a recording for more than 5 seconds + This should make sure that a recording is successfully restarted after any + problems. +- Processing the EIT data is now disabled during replay and 'Transfer Mode' in + order to avoid video and audio glitches (there appears to be a bandwidth + problem somewhere in the driver/firmware/hardware). +- Due to the reduced amount of OSD memory provided by the driver the number of + lines in the OSD had to be reduced by 2. By rearranging some of the display + items the amount of visible information remained the same as before, though. + If your DVB card has even less memory (which would result in only the + channel switching display and the replay progress display being visible, but + no Main menu), try reducing the constant 'MenuLines' in dvbapi.h (currently + '13') even further. +- There are two new setup parameters to define the "Default Priority" and + "Default Lifetime" when creating a new timer event. +- The meaning of the "Lifetime" parameter has been modified: a value of '99' + now means that the recording will live "forever", and a value of '0' means + that the recording has no guaranteed lifetime and will be deleted whenever + a new recording with higher priority needs disk space. +- Updated version of Matthias Schniedermeyer's 'schnitt' tools. +- New 'master-timer' tool (thanks to Matthias Schniedermeyer). + +2001-06-12: Version 0.81 + +- Fixed handling the case where the driver reports EAGAIN during recording, + but no data comes within 5 seconds. +- Fixed EPG scanning on single DVB card systems. +- There can now be two audio PIDs per channel, which can be toggled via the + "Green" button in the "Main" menu. The "Edit Channel" menu therefore now + has two audio PID fields (Apid1 and Apid2). By default, Apid2 is 0, which + means there is no alternate audio track. +- Fixed replaying in case the driver reports EAGAIN. +- Now 'runvdr' checks if the driver is already loaded (thanks to Henning + Holtschneider). +- Fixed removing recordings with Lifetime = 99. +- Improved channel switching. + +2001-06-16: Version 0.82 + +- Increased timeout until reporting "broken video data stream" when recording. +- Increased amount of non-useful data received by cRemux before assuming the + recording will fail. +- If there are two audio PIDs defined for a channel, both audio tracks will + now be recorded and can be selectively replayed later. See the FORMATS file + for details on how these different audio tracks are stored in the recorded + files. In order for this to work properly you need to use a driver version + dated 2001-06-16 or later, where the default PES filter buffer size has been + reduced. This will create packets for the second audio track that are small + enough to multiplex smoothly with the video data. +- Fixed a bug in the editing mechanism (didn't work with recordings that + consist of more than one data file). +- The compile time switch VFAT has been fixed to recognize the ':' character + in recording names, too. +- Setting all PIDs to 0x1FFF before switching channel. +- New setup parameter "VideoFormat" to define the aspect ratio of the tv set + in use (4:3 or 16:9). + +2001-06-26: Version 0.83 + +- Avoiding "Device or resource busy" error message when setting PIDs. +- Added Portugese language texts (thanks to Paulo Manuel Martins Lopes). +- Recording and replaying Dolby Digital (AC3) sound. +- No longer getting stuck when a channel doesn't sync while switching + with the 'Up' and 'Down' keys. + +2001-07-22: Version 0.84 + +- Fixed video packet scanning to make it recognize the whole range of + allowed video packet ids. +- Added an additional "emergency exit" in case channel switching doesn't + work several times in a row (when will the driver finally become stable + enough to allow rock solid channel switching??). +- No longer sending a Diseqc command if the Diseqc value for a given channel + is '0'. Previously this caused problems with some multi-switches (thanks to + Markus Lang and Ulrich Rder). +- When switching channels by entering the channel number via the numeric keys + on the remote control, the channel number displayed is now followed by the + '-' character to indicate that additional digits can be entered. +- Increased the timeout for numeric channel switching from 500ms to 1s. +- Fixed handling the "Green" button in the "Schedules" menu for channels that + have a second audio PID. +- Fixed high system load when displaying a still picture in replay. +- Fixed a hanging SVDRP connection if the client dies without issuing QUIT. +- Increased the frame buffer size to 192KB. +- Removed a superfluous VIDEO_FREEZE call in the replay buffer. +- Added French language texts (thanks to Jean-Claude Repetto). +- Modified OSD to use 2bpp windows (4 colors) in order to work with less + memory, allow a larger OSD window and be faster. The group separators in the + "Channels" menu had to be given a different color. +- Moved the channel display to the bottom of the screen. +- Displaying the frame counter in the replay progress display only when editing + a mark. +- Fixed handling characters above 0xEF in SVDRP. +- Fixed a possible crash in parsing incorrect lines in 'channels.conf'. +- New channel settings for Premiere World (Dolby Digital PIDs not yet + available). +- Increased the buffer for key names received from LIRC (thanks to Andre + Valentin). +- Fixed handling a channel group separator at the very beginning of the + 'channels.conf' file. + +2001-07-29: Version 0.85 + +- Added Norwegian language texts (thanks to Jrgen Tvedt). +- Increased the usleep value in cDvbOsd::Cmd() to 5000 in order to work on + systems with the KURT/utime-patch (thanks to Guido Fiala). +- Changed the check whether the driver is loaded in runvdr to check for the + 'dvb' module (the last one loaded). +- Fixed repeat function with LIRC (thanks to Stefan Huelswitt). +- Increased the upper limit for the symbol rate to 30000 (thanks to Ulrich + Rder). +- Made the position of the channel display configurable (thanks to Stefan + Huelswitt). +- Made the width and height of the OSD configurable (thanks to Stefan Huelswitt). +- DiSEqC support can now be generally enabled/disabled in the Setup menu. This + may be necessary if your multiswitch gets irritated by the default DiSEqC + codes '0' (thanks to Markus Lang). +- Fixed replaying in case there is no index file. +- Fixed jumping to an editing mark when replay has been paused. +- Avoiding unnecessary code execution in the replay progress display (thanks + to Guido Fiala). +- When entering time values the digits that still have to be entered are now + shown as '-' (as in "1-:--"). +- When setting an editing mark while the progress display is not active, the + display will now be turned on for a short while to indicate the successful + setting of the mark. +- Updated 'channels.conf' for Premiere World (thanks to Helmut Schchner). + Check your timers if you use this channels.conf file, since the sequence of + several PW channels has been changed. +- Changed the color of "Info" messages to "black on green" and that of the + confirmation messages (like "Delete...") to "black on yellow". +- Fixed display with DEBUG_OSD (it still crashes sometimes, esp. when replaying, + but I can't seem to find what causes this... any ideas anybody?). +- Avoiding audio/video distortions in 'Transfer Mode' by no longer actually + tuning the primary interface (which can't receive this channel, anyway). + Apparently the driver gets irritated when the channel is switched and a + replay session is started immediately after that. +- Increased timeout until reporting "video data stream broken" when recording. +- Explicitly switching back to the previously active channel after ending a + replay session (to have it shown correctly in case it was in 'Transfer Mode'). diff --git a/INSTALL b/INSTALL index 6910f6b47..28037eb36 100644 --- a/INSTALL +++ b/INSTALL @@ -15,7 +15,7 @@ If you have the DVB driver source in a different location you will have to change the definition of DVBDIR in the Makefile. -This program requires the card driver version 0.8.2 or higher +This program requires the card driver version 0.9.0 or higher to work properly. You need to load the dvb.o module *without* option 'outstream=0' (previous versions of VDR required this option to have the driver supply the data in AV_PES format; as of version 0.70 VDR @@ -81,13 +81,25 @@ Automatic restart in case of hangups: If you run VDR using the 'runvdr' shell script it will use the built-in watchdog timer to restart the program in case something happens that -causes a program hangup. +causes a program hangup. If you change the command line options for the +call to the VDR program, be sure to NOT use the '-d' option! Otherwise +VDR will go into 'deamon' mode and the initial program call will return +immediately! Command line options: --------------------- Use "vdr --help" for a list of available command line options. +Replaying Dolby Digital audio: +------------------------------ + +To replay Dolby Digital audio you need a program that reads the DD data +from stdin and processes it in a way suitable for your audio hardware. +This program must be given to VDR with the '-a' option, as in + + vdr -a ac3play + The video data directory: ------------------------- diff --git a/MANUAL b/MANUAL index f77bd2763..c59f3fefc 100644 --- a/MANUAL +++ b/MANUAL @@ -18,7 +18,7 @@ Video Disk Recorder User's Manual Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on Back - Menu off Main menu Main menu Discard Main menu Recordings menu Red - Record Edit Edit - Play - - Green - - New New - Rewind Skip -60s + Green - Language New New - Rewind Skip -60s Yellow - - Delete Delete - Delete Skip +60s Blue - Resume Mark Mark - Summary Stop 0..9 Ch select - - - Numeric inp. - Editing @@ -32,11 +32,11 @@ Video Disk Recorder User's Manual confirms any changes (or switches to a channel in the "Channels" menu). The "Back" key goes back one level in the menu structure, discarding any changes that might have been made in the current menu. - + In the "Timers" menu, the current timer can be enabled or disabled with the "Right" or "Left" key, respectively (enabled timers are marked with ">"). "Ok" here opens the "Edit timer" menu. - + Textual options, like channel names or recording file names, can be edited by pressing the "Right" button (which puts brackets around the current character as in "[R]TL"), selecting the desired character position with @@ -46,10 +46,10 @@ Video Disk Recorder User's Manual brackets (as in abc[^]), the next press to the "Left" or "Ok" button will actually cut off the string. Using "Up" and/or "Down" brings back the original rest of the string (unless you have pressed "Left" or "Ok"). - + The "Red", "Green", "Yellow" and "Blue" buttons have special meanings in various menus and are listed at the bottom of the on-screen-display. - + At any point in the menu system, pressing the "Menu" key again will immediately leave the menu system (discarding any pending changes). @@ -100,7 +100,7 @@ Video Disk Recorder User's Manual and browse through the list with the "Up" and "Down" key; to switch to the selected channel press "Ok". 3. Directly type in the channel number with the numeric keys ('0'..'9'); - if no key is pressed for about half a second, the digits collected so + if no key is pressed for about one second, the digits collected so far will define the channel number. 4. From the "Now", "Next" and "Event" menus (accessible through the "Schedule" menu) by pressing the "Blue" button. @@ -115,6 +115,16 @@ Video Disk Recorder User's Manual To bring up the channel display without switching channels you can press the "Ok" button. +* Selecting language specific audio track + + If the current channel provides different audio tracks (typically for + different languages), the "Green" button in the "Main" menu can be pressed + to toggle between these. There can be two different audio PIDs per channel, + assuming that typically a channel broadcasts a country specific language + plus the movie's original soundtrack. + Recordings made form such channels will contain both audio tracks, and when + replaying the desired audio track can be selected the same way. + * Switching through channel groups If the 'channels.conf' file contains "group separators" you can switch @@ -257,6 +267,9 @@ Video Disk Recorder User's Manual to free up space for a new recording. Note that setting this parameter to very high values for all recordings may soon fill up the entire disk and cause new recordings to fail due to low disk + space. The special value 99 means that this recording will live + "forever", and a value of 0 means that this recording can be + deleted any time if a recording with a higher priority needs disk space. File: The name under which a recording created through this timer will be stored on disk (the actual name will also contain the date and @@ -309,9 +322,14 @@ Video Disk Recorder User's Manual 0 = instant recordings will not be marked 1 = instant recordings will be marked. - LnbFrequLo = 9750 The low and high LNB frequencies (in MHz) + LnbSLOF = 11700 The switching frequency (in MHz) between low and high LOF + LnbFrequLo = 9750 The LNB's low and high local oscillator frequencies (in MHz) LnbFrequHi = 10600 (these have no meaning for DVB-C receivers) + DiSEqC = 1 Generally turns DiSEqC support on or off. + 0 = disabled + 1 = enabled + SetSystemTime = 0 Defines whether the system time will be set according to the time received from the DVB data stream. 0 = system time will not be set @@ -341,6 +359,22 @@ Video Disk Recorder User's Manual never keep the user from viewing stuff on the primary interface. On systems with only one DVB card, timers with a priority below PrimaryLimit will never execute. + + DefaultPriority = 50 The default Priority and Lifetime values used when + DefaultLifetime = 50 creating a new timer event. A Lifetime value of 99 + means that this recording will never be deleted + automatically. + + VideoFormat = 0 The video format (or aspect ratio) of the tv set in use. + 0 = 4:3 + 1 = 16:9 + + ChannelInfoPos = 0 The position of the channel info window in the OSD. + 0 = bottom + 1 = top + + OSDwidth = 52 The width and height of the OSD . + OSDheight = 18 The valid ranges are width=40...56, height=12...21. * Executing system commands diff --git a/Makefile b/Makefile index cec04caef..507de2146 100644 --- a/Makefile +++ b/Makefile @@ -4,11 +4,11 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.21 2001/03/11 11:36:15 kls Exp $ +# $Id: Makefile 1.22 2001/06/02 09:15:39 kls Exp $ DVBDIR = ../DVB -INCLUDES = -I$(DVBDIR)/driver +INCLUDES = -I$(DVBDIR)/ost/include OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o osd.o\ recording.o remote.o remux.o ringbuffer.o svdrp.o thread.o tools.o vdr.o\ videodir.o @@ -43,7 +43,7 @@ font: genfontfile fontfix.c fontosd.c # Dependencies: config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h remux.h ringbuffer.h svdrp.h thread.h tools.h videodir.h +dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h recording.h remux.h ringbuffer.h thread.h tools.h videodir.h dvbosd.o : dvbosd.c dvbosd.h font.h tools.h eit.o : eit.c config.h dvbapi.h dvbosd.h eit.h font.h thread.h tools.h videodir.h font.o : font.c font.h fontfix.c fontosd.c tools.h @@ -53,7 +53,7 @@ menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h recording.o : recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h -remux.o : remux.c remux.h tools.h +remux.o : remux.c remux.h thread.h tools.h ringbuffer.o: ringbuffer.c ringbuffer.h thread.h tools.h svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h thread.o : thread.c thread.h tools.h diff --git a/Tools/schnitt/README b/Tools/schnitt/README index 29953e0ee..8e1cacc99 100644 --- a/Tools/schnitt/README +++ b/Tools/schnitt/README @@ -1,4 +1,6 @@ Sammlung von "Hilfs"-Scripten + von Matthias Schniedermeyer + ms@citd.de Diese Sammlung an "Hilfs"-Scripten habe ich mir zum scheiden und anderen Zwecken zusammengeschrieben. @@ -10,10 +12,10 @@ Ich bin nicht sonderlich gut im "Dokumentieren". Also gilt die Devise Ein paar Worte zu den "Hart"-Codierten Pfaden. -/yele/video (/video/video0) -/yelg/video (/video/video1) +/dvb/video +/dvb2/video -Sind die 2 Pfade auf meinem DVB-Rechner +Sind die 2 DVB-Rechner. /x1/video @@ -30,14 +32,23 @@ Enthalten sind folgende Scripte: cutall -> "Master"-Script zum starten des Scheide vorgangs. Ist ein "find" nach "cut" -Dateien cutt -> Das "eigentliche" Schnitt-Script - Scheidet die Stuecke aus, demultipext, remultipext, - splitted die Dateien und macht am Ende ein - ISO-Image daraus + Bei einem einzelnen Block wird diese direkt + gesplitet und dann zu einem ISO-Image verarbeitet + Wenn mehrere Teile (=War mit Werbung) vorhanden + sind, dann werden zuerst die einzelnen Teile, + legt nummerierte Verzeichniss ein und kopiert bzw + splitet die einzelnen Dateien in die Verzeichniss + und macht dann daraus die ISO-Images + (Leider funktioniert das aus irgendwelche Gruenden + (noch) nicht mit Serien die nur eine CD gross sind + aber das wird noch) index.php -> PHP-Script zum finden der Schnitt-Punkte, mit Testmoeglichkeit ob erfolgreich an diesem Punkt geschnitten werden kann -mv2 -> Zum Moven der Aufnahmen von meinem DVB-Rechner +mv2 -> Zum Moven der Aufnahmen von meinen DVB-Rechnern auf mein "Arbeitsrechner" +play -> Zum Abspielen einer Aufnahme von meinem Recher auf + dem "Frontend" DVB-Rechner schnitt.pl -> Extraiert ein einzelnes Bild um es anzuzeigen (Fuer index.php) schnitt2.pl -> Gibt alles zwischen 2 Schnittpunkten auf STDOUT aus @@ -58,27 +69,43 @@ vdr2 -> Start-Script vmount -> Mounten aller zusammengehoeriger ISO-Images zum abspielen -Hilsscripte: +Hilfsscripte: ------------ cut.pl -> Entspricht weitestgehend "split" aber mit "Nummer" anstatt Buchstaben cut2 -> Entfernt escapende Backslashes +cut2.pl/cut3.pl -> Fuer Aufnehmen die aus mehreren Bloecken bestehen + (=Mit Werbung) cutall2 -> Springt ins Schnitt-Verzeichniss und ruft das "eigentliche" Schnitt-Script auf -lmplex -> Multiplexed Datenstrome unter Zurhilfename - saemtlicher CPUs +cutall3.pl -> Wenn in einem Verzeichniss mehrere Aufnahmen sind + splitet dies Programm diese und ruft fuer jede + Aufnahme das "cutt"-Script auf schnittcommon.pli -> Das "Common" Script fuer schnitt?.pl getpreviframe.pl -> Findet das vorherige I-Frame. unsort -> Macht das Gegenteil von sort. +dump.c -> Muss in der "libmpeg3"-Verzeichniss des + "mpeg2-movie"-Packets kopiert werden und dann mit + "make" compilieren + Dieses C-Programm ist dafuer da um fuer das + PHP-Script das Bild anzuzeigen wo man gerade ist. + Da mir der "urspruengliche" Source-Code dafuer + abhanden gekommen ist und ich den Patch neumachen + musste (Wie immer mit "Verbesserungen") ist index.php + nocht nicht auf die neue Version angepasst. Die + Anpassung besteht aber nur darin eine "1" an die + Kommandozeile anzuhaengen. -Die ganze "Schnittloesung" ist leider etwas "unbrauchbar", weil ich aus -Unachtsamkeit leider die gepatchten Sourcen von 2 wichtigen Programm -geloescht habe. -dumpfrage -> Extraiert das erste Frage in eine Datei zum - anzeigen (gepatchtes dump aus "libmpeg3" -pvademux -> gepatcht um eine Pfad-Angabe +Im Gegensatz zur "alten"-Version ist diese Version "vollstaendig" +einsatzfaehig! -Entweder macht jemand/ich patchen "nochmal" oder ich kann auch die -Binaries zur Verfuegung stellen. + +Wenn jemand Fragen zum Einsatz hat dann "loechern Sie mich" + +ms@citd.de + + +Ich kann auch gerne die Einrichtung per "Fernwartung" (=ssh) uebernehmen. +(Wenn noetig compiliere ich auch auch apache mit PHP usw.) diff --git a/Tools/schnitt/cut.pl b/Tools/schnitt/cut.pl index dd62c18ff..e05507692 100755 --- a/Tools/schnitt/cut.pl +++ b/Tools/schnitt/cut.pl @@ -1,30 +1,25 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl -use strict; +chdir ($ARGV[0]) if ($ARGV[0]); -my $maxsize = 660 * 1024 * 1024; +$read = $size = 1024*1024; -my $read = 1024*1024; -my $size = 1024*1024; - -my $filenum = "1"; -my $count = 0; - -my ($fi,$data); +$filenum = "1"; +$count = 0; $fi = sprintf ("part%d",$filenum); open (FI,">$fi"); while ($read == $size) { - if ($count < $maxsize) + if ($count < 660*1024*1024) { $read = read (STDIN,$data,$size); print FI $data; $count += $size; $a = $count /1024/1024; if ($a % 10 == 0) { - print STDERR "File: $filenum Size: ${a}MB\n"; + print stderr "File: $filenum Size: ${a}MB\n"; } } else diff --git a/Tools/schnitt/cut2 b/Tools/schnitt/cut2 index 0193ac0c2..09e9acbcc 100755 --- a/Tools/schnitt/cut2 +++ b/Tools/schnitt/cut2 @@ -1,2 +1,2 @@ #!/bin/sh -cat cut | head -n 1 | tr -d [\\\\] +cat cut2 | head -n 1 | tr -d [\\\\] diff --git a/Tools/schnitt/cutall b/Tools/schnitt/cutall index 355935fd3..a6803e2b7 100755 --- a/Tools/schnitt/cutall +++ b/Tools/schnitt/cutall @@ -1,4 +1,2 @@ #!/bin/sh -cutdir=/x1/video/ - -find $cutdir -name "cut" -exec cutall2 {} \; +find /x1/video/ -name "cut" -exec cutall2 {} \; diff --git a/Tools/schnitt/cutall2 b/Tools/schnitt/cutall2 index 90b0f46ba..962d57722 100755 --- a/Tools/schnitt/cutall2 +++ b/Tools/schnitt/cutall2 @@ -1,5 +1,5 @@ #!/bin/sh a=`echo $1 | cut -d / -f1-5` cd $a -cutt +cutall3.pl mv cut cut.bak diff --git a/Tools/schnitt/cutt b/Tools/schnitt/cutt index 4e89b7a3d..1942437a0 100755 --- a/Tools/schnitt/cutt +++ b/Tools/schnitt/cutt @@ -3,10 +3,13 @@ DIRA=/x2/temp DIRB=/x1/temp -if [ -f cut ]; then +if [ ! -f cut2 ]; then + echo Keine Beschreibungsdatei + exit 1 +else name="`cut2`" echo $name - count=`cat cut | wc -l` + count=`cat cut2 | wc -l` let count=count-1 let test=count%2 if [ "$test" == "1" ]; then @@ -16,70 +19,88 @@ if [ -f cut ]; then file=1 - while [ "$count" != "0" ] - do - start=`cat cut | tail -n $count | head -n 1` + if [ "$count" == "2" ]; then + start=`cat cut2 | tail -n $count | head -n 1` let count=count-1 - end=`cat cut | tail -n $count | head -n 1` - let count=count-1 - echo Cutting\&Demuxing from $start to $end - schnitt2.pl $start $end | pvademux $DIRA teil$file -# schnitt2.pl $start $end | pes2av_pes | pvademux $DIRA teil$file - let file=file+1 - done -else - echo Keine Beschreibungsdatei - exit 1 + end=`cat cut2 | tail -n $count | head -n 1` + schnitt2.pl $start $end | avpes2mpeg | cut.pl $DIRA + secondway=2 + else + while [ "$count" != "0" ] + do + start=`cat cut2 | tail -n $count | head -n 1` + let count=count-1 + end=`cat cut2 | tail -n $count | head -n 1` + let count=count-1 + echo Cutting \& Converting from $start to $end + schnitt2.pl $start $end | avpes2mpeg > $DIRA/teil$file.mpg +# schnitt2.pl $start $end | pvademux $DIRA teil$file + let file=file+1 + done + fi fi # Ab hier mkimg -sync - -lmplex $DIRA $DIRB `ls -la $DIRA/teil*.m2v | cut -b 30- | sort -n -r | cut -d / -f4` - -echo Multiplexing DONE - -rm -f $DIRA/teil*.m2v $DIRA/teil*.mp2 +rm cut2 sync -if [ -f $DIRB/teil1.mpg ]; then - echo Splitting +if [ "$secondway" != "2" ]; then cd $DIRA -# cat $DIRB/teil*.mpg | split -b 723517440 - cat $DIRB/teil*.mpg | cut.pl - rm $DIRB/teil* -fi - -sync - -cd $DIRA + cut2.pl "$name" + if [ -d 2 ]; then + count=1 + cond=0 + + while [ "$cond" != "1" ] + do + echo mkisofs Teil $count + mkisofs -r -o $DIRB/image1.raw $count + rm -rf $count + mv -- $DIRB/image1.raw "$DIRB/${name} CD $count" + sync + let count=count+1 + if [ ! -d $count ]; then + cond=1 + fi + done + else + echo mkisofs + mkisofs -r -o $DIRB/image1.raw $count + rm -rf $count + mv -- $DIRB/image1.raw "$DIRB/${name}" + fi +else -if [ -f part2 ]; then - count=1 - cond=0 + cd $DIRA - while [ "$cond" != "1" ] - do + if [ -f part2 ]; then + count=1 + cond=0 + + while [ "$cond" != "1" ] + do + mkdir a + mv "part$count" "a/${name} CD $count.mpg" + echo mkisofs Teil $count + mkisofs -r -o $DIRB/image1.raw a + rm -rf a + mv -- $DIRB/image1.raw "$DIRB/${name} CD $count" + sync + + let count=count+1 + if [ ! -f "part$count" ]; then + cond=1 + fi + done + else mkdir a - mv "part$count" "a/${name} Teil $count" - echo mkisofs Teil $count + mv part1 "a/${name}.mpg" + echo mkisofs mkisofs -r -o $DIRB/image1.raw a rm -rf a - mv -- $DIRB/image1.raw "$DIRB/${name} Teil $count" - sync - - let count=count+1 - if [ ! -f "part$count" ]; then - cond=1 - fi - done -else - mkdir a - mv part1 "a/${name}" - echo mkisofs - mkisofs -r -o $DIRB/image1.raw a - rm -rf a - mv -- $DIRB/image1.raw "$DIRB/${name}" + mv -- $DIRB/image1.raw "$DIRB/${name}" + fi fi + diff --git a/Tools/schnitt/getpreviframe.pl b/Tools/schnitt/getpreviframe.pl index 6774f3192..4829304c3 100755 --- a/Tools/schnitt/getpreviframe.pl +++ b/Tools/schnitt/getpreviframe.pl @@ -1,18 +1,12 @@ #!/usr/bin/perl -use strict; - -my ($index, $oindex); - require "/usr/local/bin/my/schnittcommon.pli"; if (!open (INDEX,"index.vdr")) { exit 1; } - $index = $oindex = $ARGV[0]; - if ($index > 0) { &prevI; diff --git a/Tools/schnitt/mv2 b/Tools/schnitt/mv2 index a0cefba7f..c27a9ffe6 100755 --- a/Tools/schnitt/mv2 +++ b/Tools/schnitt/mv2 @@ -1,23 +1,30 @@ #!/bin/sh +# +# Move files from DVB-Computer(s) to localmachine into $LOCALDIR +# -DIR = /x1/video +LOCALDIR=/x1/video if [ ! "$UID" = 0 ]; then if [ -d "$1" ]; then - cd $DIR - a=`echo "$1" | cut -d / -f4-` - mkdir -p "$a" - cd "$a" - (echo cd "$1"; echo mget \*)| ftp -i dvb - cd $DIR - ls -Ls $1 > /tmp/yele - ls -Ls $a > /tmp/x1 - a=`echo "$1" | cut -d \/ -f3-` - diff -u /tmp/yele /tmp/x1 &> /dev/null && rm -rfv /yel?/$a - rm /tmp/yele - rm /tmp/x1 - rmdir /yel?/video/* + if [ -f "$1/index.vdr" ]; then + cd $LOCALDIR + recdir=`echo "$1" | cut -d / -f4-` + mkdir -p "$recdir" + cd "$recdir" + dvbcomp=`echo "$1" | cut -d / -f2` + (echo cd "/video/video0/$recdir"; echo mget \*)| ftp -i $dvbcomp + cd $LOCALDIR + ssh $dvbcomp ls -Ls /video/video0/$recdir > /tmp/dvb + ls -Ls $recdir > /tmp/local + diff -u /tmp/dvb /tmp/local &> /dev/null && rm -rfv /$dvbcomp/video?/$recdir + rm /tmp/dvb + rm /tmp/local + rmdir --ignore-fail-on-non-empty `find /$dvbcomp/video?/ -type d -mindepth 1 | cut -d \/ -f-4 | grep -v temp | sort | uniq` + fi fi else echo Not as root fi + +/usr/local/bin/my/process_summary.pl diff --git a/Tools/schnitt/schnitt.pl b/Tools/schnitt/schnitt.pl index d5521ebbf..ac72a144f 100755 --- a/Tools/schnitt/schnitt.pl +++ b/Tools/schnitt/schnitt.pl @@ -21,6 +21,7 @@ close (FI); close (FO); -`/usr/local/bin/pvademux.old /x2/temp bild`; +`cat bild | /usr/local/bin/avpes2mpeg > avpes`; +`/usr/local/bin/my/dumpframe avpes 1`; #`/usr/local/bin/pes2av_pes bild | /usr/local/bin/pvademux /x2/temp bild`; print "$index\n"; diff --git a/Tools/schnitt/schnitt2.pl b/Tools/schnitt/schnitt2.pl index e52b24595..d81b5fd59 100755 --- a/Tools/schnitt/schnitt2.pl +++ b/Tools/schnitt/schnitt2.pl @@ -10,10 +10,12 @@ $index = $ARGV[0]; &nextI; +#&readnext; $file1 = $file; $offset1 = $offset; $index = $ARGV[1]; &nextI; +#&readnext; $file2 = $file; $offset2 = $offset; diff --git a/Tools/schnitt/show b/Tools/schnitt/show index afed79b3c..bfcc58a8f 100755 --- a/Tools/schnitt/show +++ b/Tools/schnitt/show @@ -5,7 +5,7 @@ do if [ -f newpic ]; then killall xli rm -f newpic - xli output.ppm & + xli output000.ppm & fi sleep 24h done diff --git a/Tools/schnitt/vmount b/Tools/schnitt/vmount index 6b7906473..ab16e4579 100755 --- a/Tools/schnitt/vmount +++ b/Tools/schnitt/vmount @@ -4,7 +4,7 @@ cond=0 if [ -f "$1" ]; then mount "$1" /mnt/1 -o loop - $cond = 1 + cond=1 else while [ "$cond" != "1" ] do diff --git a/channels.conf b/channels.conf index 36b5b2843..8fc1a980c 100644 --- a/channels.conf +++ b/channels.conf @@ -1,6 +1,6 @@ RTL:12188:h:0:27500:163:104:105:0:12003 Sat.1:12480:v:0:27500:1791:1792:34:0:46 -Pro-7:12480:v:0:27500:255:256:32:0:898 +Pro-7:12480:v:0:27500:255:256;257:32:0:898 RTL2:12188:h:0:27500:166:128:68:0:12020 ARD:11837:h:0:27500:101:102:0:0:28106 BR3:11837:h:0:27500:201:202:0:0:28107 @@ -16,7 +16,7 @@ ZDF:11954:h:0:27500:110:120:130:0:28006 KiKa:11954:h:0:27500:310:320:0:0:28008 arte:11836:h:0:27500:401:402:0:0:28109 ORF1:12692:h:0:22000:160:161:165:3:13001 -ORF2:12692:h:0:22000:500:501:505:3:13007 +ORF2:12692:h:0:22000:500:501:505:3:13002 ORF Sat:11954:h:0:27500:506:507:0:0:28010 ZDF.info:11954:h:0:27500:610:620:0:0:28011 CNN:12168:v:0:27500:165:100:0:0:28512 @@ -46,62 +46,81 @@ MDR:12110:h:0:27500:401:402:0:0:28204 NICK-PARAMOUNT:12246:v:0:27500:167:108:0:0:29312 ORB:12110:h:0:27500:501:502:0:0:28205 B1:12110:h:0:27500:601:602:0:0:28206 -ARD Online-Kanal:12722:h:0:22000:8191:701:0:0:0 +ARD Online-Kanal:12722:h:0:22000:0:701:0:0:0 :Premiere World -Premiere World Promo:11798:h:0:27500:255:256:0:0:8 -Premiere:11798:h:0:27500:511:512:0:3:10 -Star Kino:11798:h:0:27500:767:768:0:3:9 -Cine Action:11798:h:0:27500:1023:1024:0:3:20 -Cine Comedy:11798:h:0:27500:1279:1280:0:3:29 -Sci Fantasy:11798:h:0:27500:1535:1536:0:3:41 -Romantic Movies:11797:h:0:27500:1791:1792:0:3:11 -Studio Universal:12090:v:0:27500:255:256:0:3:36 -13th Street:11797:h:0:27500:2303:2304:0:3:43 +Premiere World:11797:h:0:27500:255:256:32:0:8 +Premiere 1:11797:h:0:27500:511:512:0:3:10 +Premiere 2:11797:h:0:27500:1791:1792:0:3:11 +Premiere 3:11797:h:0:27500:2303:2304:0:3:43 +Premiere Star:11797:h:0:27500:767:768:0:3:9 +Premiere Sci-Fi:11797:h:0:27500:1535:1536:0:3:41 +Premiere Action:11797:h:0:27500:1023:1024:0:3:20 +Premiere Comedy:11797:h:0:27500:1279:1280:0:3:29 +13th Street:12031:h:0:27500:2303:2304:0:3:42 +Studio Universal:12090:V:0:27500:255:256:0:3:36 +Filmpalast:12031:h:0:27500:2559:2560:0:3:516 +Heimatkanal:12031:h:0:27500:2815:2816:0:3:517 +Discovery Channel:12031:h:0:27500:1791:1792:0:3:14 +Planet:12090:V:0:27500:1279:1280:0:3:13 +Fox Kids:12031:h:0:27500:1279:1280:0:3:28 Junior:12031:h:0:27500:255:256:0:3:19 -K-Toon:12032:h:0:27500:511:512:0:3:12 -Disney Channel:12090:v:0:27500:767:768:0:3:34 -Fox Kids:11797:h:0:27500:2559:2560:0:3:22 +K-Toon:12031:h:0:27500:511:512:0:3:12 +Disney Channel:12090:V:0:27500:767:768:0:3:34 Sunset:12031:h:0:27500:1023:1024:0:3:16 -Comedy:12031:h:0:27500:1279:1280:0:3:28 -Planet:12090:v:0:27500:1279:1280:0:3:13 -Discovery Channel:12031:h:0:27500:1791:1792:0:3:14 Krimi&Co:12031:h:0:27500:1535:1536:0:3:23 -Filmpalast:11758:h:0:27500:2559:2560:0:3:516 -Heimatkanal:11758:h:0:27500:2815:2816:0:3:517 -Goldstar:11758:h:0:27500:3839:3840:0:3:518 +Goldstar TV:12031:h:0:27500:3839:3840:0:3:518 Classica:12031:h:0:27500:767:768:0:3:15 -Seasons:12090:v:0:27500:511:512:0:3:33 -Sport 1:11720:h:0:27500:255:256:0:3:17 -Sport 2:12070:h:0:27500:2047:2048:0:3:27 -Sport 3:12070:h:0:27500:2303:2304:0:3:18 -Sport 4:12070:h:0:27500:2559:2560:0:3:24 -Feed (F1 Boxengasse):11720:h:0:27500:2559:2560:0:3:242 -Feed (F1 Data):11720:h:0:27500:3071:3072:0:3:244 -Feed (F1 Multi):11720:h:0:27500:2815:2816:0:3:243 -Feed (F1 On Board):11720:h:0:27500:2303:2304:0:3:241 -Feed (F1 Verfolger):11720:h:0:27500:2047:2048:0:3:240 -Cinedom Deluxe:12070:h:0:27500:1279:1280:0:3:188 -Cinedom 1A de:11758:h:0:27500:511:512:0:3:178 -Cinedom 1A en:11758:h:0:27500:511:513:0:3:178 -Cinedom 1B:12070:h:0:27500:767:768:0:3:185 -Cinedom 1C:12070:h:0:27500:1791:1792:0:3:191 -Cinedom 1E??:11720:h:0:27500:1535:1537:0:3:176 -Cinedom 2A:12070:h:0:27500:1535:1536:0:3:189 -Cinedom 2B:11758:h:0:27500:767:768:0:3:179 -Cinedom 2C:11758:h:0:27500:1023:1024:0:3:193 -Cinedom 2D??:12070:h:0:27500:511:512:0:3:184 -Cinedom 3A:11758:h:0:27500:255:256:0:3:177 -Cinedom 3B:11758:h:0:27500:1279:1280:0:3:194 -Cinedom 3C??:12090:v:0:27500:1279:1280:17689:3:192 -Cinedom 4A:11758:h:0:27500:1535:1536:0:3:195 -Cinedom 4B:12070:h:0:27500:1023:1025:0:3:186 -Cinedom 4C??:11720:h:0:27500:767:768:0:3:181 -Cinedom 5A:12032:h:0:27500:2559:2560:0:3:187 -Beate Uhse_TV:11797:h:0:27500:2047:2048:0:3:21 -Blue Channel:11758:h:0:27500:2559:2560:0:3:516 +Seasons:12090:V:0:27500:511:512:0:3:33 +:Cinedom +Cinedom Deluxe:11758:h:0:27500:255:256,257;259:0:3:189 +Cinedom 1A:11758:h:0:27500:511:512,513:0:3:190 +Cinedom 1B:12070:h:0:27500:1535:1536,1537:0:3:178 +Cinedom 1C:11720:h:0:27500:511:512,513:0:3:180 +Cinedom 1D:11720:h:0:27500:1535:1536,1537:0:3:176 +Cinedom 2A:11758:h:0:27500:1023:1024:0:3:193 +Cinedom 2B:11720:h:0:27500:1279:1280:0:3:183 +Cinedom 2C:12070:h:0:27500:1791:1792:0:3:179 +Cinedom 2D:12070:h:0:27500:511:512:0:3:184 +Cinedom 2E:12070:h:0:27500:1279:1280:0:3:188 +Cinedom 3A:11758:h:0:27500:2559:2560:0:3:192 +Cinedom 3B:11758:h:0:27500:1535:1536:0:3:195 +Cinedom 3C:12070:h:0:27500:767:768:0:3:185 +Cinedom 3D:11720:h:0:27500:1023:1024:0:3:182 +Cinedom 4A:11758:h:0:27500:767:768:0:3:191 +Cinedom 4B:11720:h:0:27500:767:768:0:3:181 +Cinedom 4C:12070:h:0:27500:2047:2048:0:3:187 +Cinedom 5A:11758:h:0:27500:1279:1280:0:3:194 +Cinedom 5B:11720:h:0:27500:1791:1792:0:3:177 +Cinedom 5C:12070:h:0:27500:1023:1024:0:3:186 +:Beta Digital +CNBC:12148:h:0:27500:255:256:0:3:35 +Liberty TV.com:12610:V:0:22000:941:943:0:0:12199 +:PW Erotic +Beate-Uhse.TV:11758:h:0:27500:3839:3840:0:3:21 Blue Movie 1:11758:h:0:27500:1791:1792:0:3:513 Blue Movie 2:11758:h:0:27500:2047:2048:0:3:514 Blue Movie 3:11758:h:0:27500:2303:2304:0:3:515 +:Sportsworld +Premiere Sport 1:11719:h:0:27500:255:256:0:3:17 +Premiere Sport 2:11719:h:0:27500:3327:3328:0:3:27 +Premiere Sport 3:11758:h:0:27500:2815:2816:0:3:18 +:Formel 1 +Infokanal:11720:h:0:27500:3071:3072:0:3:244 +Multikanal:11720:h:0:27500:2815:2816:0:3:243 +Supersignal:11720:h:0:27500:255:256:0:3:17 +Verfolgerfeld:11720:h:0:27500:2303:2304:0:3:241 +Cockpitkanal:11720:h:0:27500:2559:2560:0:3:242 +Boxengasse:11720:h:0:27500:2047:2048:0:3:240 +:Premiere World Bundesliga +Superdom:12070:h:0:27500:255:256:0:3:26 +Spiel 1:11719:h:0:27500:255:256,257:0:3:17 +Spiel 2:11719:h:0:27500:2047:2048,2049:0:3:240 +BuLi-Konferenz:12070:h:0:27500:3071:3072,3073:0:3:208 +BuLi-Spiel 1:12070:h:0:27500:3327:3328,3329:0:3:209 +BuLi-Spiel 2:12070:h:0:27500:2303:2304,2305:0:3:210 +BuLi-Spiel 3:12070:h:0:27500:3583:3584,3585:0:3:211 +BuLi-Spiel 4:12070:h:0:27500:2559:2560,2561:0:3:212 +BuLi-Spiel 5:12070:h:0:27500:2815:2816,2817:0:3:213 : TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601 Mosaico:11934:v:0:27500:165:100:0:0:29010 @@ -164,7 +183,7 @@ Astra Vision 1:12552:v:0:22000:168:149:0:0:0 Astra Vision 1:12552:v:0:22000:168:150:0:0:0 RTL Tele Letzebuerg:12552:v:0:22000:168:144:0:0:0 Astra Mosaic:12552:v:0:22000:175:176:0:0:0 -MHP test:12604:h:0:22000:5632:8191:0:0:0 +MHP test:12604:h:0:22000:5632:0:0:0:0 VERONICA:12574:h:0:22000:161:84:0:0:5010 VH1 Classic:12699:v:0:22000:3071:3072:0:0:28647 VH-1 Germany:12699:v:0:22000:3081:3082:0:0:28648 @@ -173,3 +192,4 @@ Video Italia:12610:v:0:22000:121:122:0:0:12220 AC 3 promo:12670:v:0:22000:308:256:0:0:0 ORF/ZDF:12699:h:0:22000:506:507:0:0:13012 VIVA:12670:v:0:22000:309:310:0:0:12732 +MTV Central Europe:12699:v:0:22000:3031:3032:0:0:28643 diff --git a/config.c b/config.c index acf1996ae..8e0cce300 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.44 2001/04/01 14:32:22 kls Exp $ + * $Id: config.c 1.52 2001/07/27 13:45:28 kls Exp $ */ #include "config.h" @@ -155,7 +155,7 @@ eKeys cKeys::Get(unsigned int Code) } eKeys cKeys::Translate(const char *Command) -{ +{ if (Command) { const tKey *k = keys; while ((k->type != kNone) && strcasecmp(k->name, Command) != 0) @@ -166,7 +166,7 @@ eKeys cKeys::Translate(const char *Command) } unsigned int cKeys::Encode(const char *Command) -{ +{ eKeys k = Translate(Command); if (k != kNone) return keys[k].code; @@ -200,7 +200,10 @@ cChannel::cChannel(const cChannel *Channel) diseqc = Channel ? Channel->diseqc : 0; srate = Channel ? Channel->srate : 27500; vpid = Channel ? Channel->vpid : 255; - apid = Channel ? Channel->apid : 256; + apid1 = Channel ? Channel->apid1 : 256; + apid2 = Channel ? Channel->apid2 : 0; + dpid1 = Channel ? Channel->dpid1 : 257; + dpid2 = Channel ? Channel->dpid2 : 0; tpid = Channel ? Channel->tpid : 32; ca = Channel ? Channel->ca : 0; pnr = Channel ? Channel->pnr : 0; @@ -218,8 +221,19 @@ const char *cChannel::ToText(cChannel *Channel) delete buffer; if (Channel->groupSep) asprintf(&buffer, ":%s\n", s); - else - asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->tpid, Channel->ca, Channel->pnr); + else { + char apidbuf[32]; + char *q = apidbuf; + q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1); + if (Channel->apid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->apid2); + if (Channel->dpid1 || Channel->dpid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ";%d", Channel->dpid1); + if (Channel->dpid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->dpid2); + *q = 0; + asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%s:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, apidbuf, Channel->tpid, Channel->ca, Channel->pnr); + } return buffer; } @@ -242,8 +256,21 @@ bool cChannel::Parse(const char *s) } else { groupSep = false; - //XXX - int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &tpid, &ca, &pnr); + char *apidbuf = NULL; + int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%a[^:]:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apidbuf, &tpid, &ca, &pnr); + apid1 = apid2 = 0; + dpid1 = dpid2 = 0; + if (apidbuf) { + char *p = strchr(apidbuf, ';'); + if (p) + *p++ = 0; + sscanf(apidbuf, "%d,%d", &apid1, &apid2); + if (p) + sscanf(p, "%d,%d", &dpid1, &dpid2); + delete apidbuf; + } + else + return false; if (fields >= 9) { if (fields == 9) { // allow reading of old format @@ -275,7 +302,7 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log) isyslog(LOG_INFO, "switching to channel %d", number); } for (int i = 3; i--;) { - if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid, tpid, ca, pnr)) + if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr)) return true; esyslog(LOG_ERR, "retrying"); } @@ -305,8 +332,8 @@ cTimer::cTimer(bool Instant) if (stop >= 2400) stop -= 2400; //TODO VPS??? - priority = DEFAULTPRIORITY; - lifetime = DEFAULTLIFETIME; + priority = Setup.DefaultPriority; + lifetime = Setup.DefaultLifetime; *file = 0; summary = NULL; if (Instant && ch) @@ -330,8 +357,8 @@ cTimer::cTimer(const cEventInfo *EventInfo) stop = time->tm_hour * 100 + time->tm_min; if (stop >= 2400) stop -= 2400; - priority = DEFAULTPRIORITY; - lifetime = DEFAULTLIFETIME; + priority = Setup.DefaultPriority; + lifetime = Setup.DefaultLifetime; *file = 0; const char *Title = EventInfo->GetTitle(); if (!isempty(Title)) @@ -524,14 +551,14 @@ bool cTimer::Matches(time_t t) } time_t cTimer::StartTime(void) -{ +{ if (!startTime) Matches(); return startTime; } time_t cTimer::StopTime(void) -{ +{ if (!stopTime) Matches(); return stopTime; @@ -734,14 +761,22 @@ cSetup::cSetup(void) ShowInfoOnChSwitch = 1; MenuScrollPage = 1; MarkInstantRecord = 1; + LnbSLOF = 11700; LnbFrequLo = 9750; LnbFrequHi = 10600; + DiSEqC = 1; SetSystemTime = 0; MarginStart = 2; MarginStop = 10; EPGScanTimeout = 5; SVDRPTimeout = 300; PrimaryLimit = 0; + DefaultPriority = 50; + DefaultLifetime = 50; + VideoFormat = VIDEO_FORMAT_4_3; + ChannelInfoPos = 0; + OSDwidth = 52; + OSDheight = 18; CurrentChannel = -1; } @@ -756,14 +791,22 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); + else if (!strcasecmp(Name, "LnbSLOF")) LnbSLOF = atoi(Value); else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); + else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value); else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); + else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); + else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); + else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); + else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else return false; @@ -813,14 +856,22 @@ bool cSetup::Save(const char *FileName) fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch); fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage); fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord); + fprintf(f, "LnbSLOF = %d\n", LnbSLOF); fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo); fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); + fprintf(f, "DiSEqC = %d\n", DiSEqC); fprintf(f, "SetSystemTime = %d\n", SetSystemTime); fprintf(f, "MarginStart = %d\n", MarginStart); fprintf(f, "MarginStop = %d\n", MarginStop); fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout); fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout); fprintf(f, "PrimaryLimit = %d\n", PrimaryLimit); + fprintf(f, "DefaultPriority = %d\n", DefaultPriority); + fprintf(f, "DefaultLifetime = %d\n", DefaultLifetime); + fprintf(f, "VideoFormat = %d\n", VideoFormat); + fprintf(f, "ChannelInfoPos = %d\n", ChannelInfoPos); + fprintf(f, "OSDwidth = %d\n", OSDwidth); + fprintf(f, "OSDheight = %d\n", OSDheight); fprintf(f, "CurrentChannel = %d\n", CurrentChannel); f.Close(); isyslog(LOG_INFO, "saved setup to %s", FileName); diff --git a/config.h b/config.h index 6c21fb2f6..58d038241 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.44 2001/04/01 14:44:40 kls Exp $ + * $Id: config.h 1.55 2001/07/27 13:32:53 kls Exp $ */ #ifndef __CONFIG_H @@ -19,10 +19,18 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.72" +#define VDRVERSION "0.85" #define MaxBuffer 10000 +#define MAXPRIORITY 99 +#define MAXLIFETIME 99 + +#define MINOSDWIDTH 40 +#define MAXOSDWIDTH 56 +#define MINOSDHEIGHT 12 +#define MAXOSDHEIGHT 21 + enum eKeys { // "Up" and "Down" must be the first two keys! kUp, kDown, @@ -92,7 +100,8 @@ class cChannel : public cListObject { int diseqc; int srate; int vpid; - int apid; + int apid1, apid2; + int dpid1, dpid2; int tpid; int ca; int pnr; @@ -106,9 +115,6 @@ class cChannel : public cListObject { bool Switch(cDvbApi *DvbApi = NULL, bool Log = true); }; -#define DEFAULTPRIORITY 99 -#define DEFAULTLIFETIME 99 - class cTimer : public cListObject { private: time_t startTime, stopTime; @@ -240,7 +246,7 @@ class cChannels : public cConfig { bool SwitchTo(int Number, cDvbApi *DvbApi = NULL); int MaxNumber(void) { return maxNumber; } }; - + class cTimers : public cConfig { public: cTimer *GetTimer(cTimer *Timer); @@ -266,13 +272,19 @@ class cSetup { int ShowInfoOnChSwitch; int MenuScrollPage; int MarkInstantRecord; + int LnbSLOF; int LnbFrequLo; int LnbFrequHi; + int DiSEqC; int SetSystemTime; int MarginStart, MarginStop; int EPGScanTimeout; int SVDRPTimeout; int PrimaryLimit; + int DefaultPriority, DefaultLifetime; + int VideoFormat; + int ChannelInfoPos; + int OSDwidth, OSDheight; int CurrentChannel; cSetup(void); bool Load(const char *FileName); diff --git a/dvbapi.c b/dvbapi.c index a929b5039..07b6f61bc 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,13 +4,15 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.66 2001/03/31 15:01:57 kls Exp $ + * $Id: dvbapi.c 1.96 2001/07/29 10:32:50 kls Exp $ */ #include "dvbapi.h" +#include #include #include extern "C" { +#define HAVE_BOOLEAN #include } #include @@ -20,20 +22,29 @@ extern "C" { #include #include #include "config.h" -#include "interface.h" #include "recording.h" #include "remux.h" #include "ringbuffer.h" #include "tools.h" #include "videodir.h" -#define VIDEODEVICE "/dev/video" -#define VBIDEVICE "/dev/vbi" +#define DEV_VIDEO "/dev/video" +#define DEV_OST_OSD "/dev/ost/osd" +#define DEV_OST_QAMFE "/dev/ost/qamfe" +#define DEV_OST_QPSKFE "/dev/ost/qpskfe" +#define DEV_OST_SEC "/dev/ost/sec" +#define DEV_OST_DVR "/dev/ost/dvr" +#define DEV_OST_DEMUX "/dev/ost/demux" +#define DEV_OST_VIDEO "/dev/ost/video" +#define DEV_OST_AUDIO "/dev/ost/audio" // The size of the array used to buffer video data: // (must be larger than MINVIDEODATA - see remux.h) #define VIDEOBUFSIZE (1024*1024) +// The maximum size of a single frame: +#define MAXFRAMESIZE (192*1024) + #define FRAMESPERSEC 25 // The maximum file size is limited by the range that can be covered @@ -55,16 +66,13 @@ extern "C" { // The number of frames to back up when resuming an interrupted replay session: #define RESUMEBACKUP (10 * FRAMESPERSEC) -typedef unsigned char uchar; +// The maximum time we wait before assuming that a recorded video data stream +// is broken: +#define MAXBROKENTIMEOUT 30 // seconds -static void SetPlayMode(int VideoDev, int Mode) -{ - if (VideoDev >= 0) { - struct video_play_mode pmode; - pmode.mode = Mode; - ioctl(VideoDev, VIDIOCSPLAYMODE, &pmode); - } -} +#define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls + +typedef unsigned char uchar; const char *IndexToHMSF(int Index, bool WithFrame) { @@ -100,6 +108,7 @@ class cIndexFile { public: cIndexFile(const char *FileName, bool Record); ~cIndexFile(); + bool Ok(void) { return index != NULL; } void Write(uchar PictureType, uchar FileNumber, int FileOffset); bool Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType = NULL, int *Length = NULL); int GetNextIFrame(int Index, bool Forward, uchar *FileNumber = NULL, int *FileOffset = NULL, int *Length = NULL); @@ -158,8 +167,10 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) else LOG_ERROR; } + else if (!Record) + isyslog(LOG_INFO, "missing index file %s", fileName); if (Record) { - if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP)) >= 0) { + if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) { if (delta) { esyslog(LOG_ERR, "ERROR: padding index file with %d '0' bytes", delta); while (delta--) @@ -315,236 +326,6 @@ int cIndexFile::Get(uchar FileNumber, int FileOffset) return -1; } -// --- cRingBuffer_ ----------------------------------------------------------- - -/* cRingBuffer reads data from an input file, stores it in a buffer and writes - it to an output file upon request. The Read() and Write() functions should - be called only when the associated file is ready to provide or receive data - (use the 'select()' function to determine that), and the files should be - opened in non-blocking mode. - The '...Limit' parameters define safety limits. If they are exceeded a log entry - will be made. -*/ - -class cRingBuffer_ { -private: - uchar *buffer; - int size, head, tail, freeLimit, availLimit; - int countLimit, countOverflow; - int minFree; - bool eof; - int *inFile, *outFile; -protected: - int Free(void) { return ((tail >= head) ? size + head - tail : head - tail) - 1; } -public: - int Available(void) { return (tail >= head) ? tail - head : size - head + tail; } -protected: - int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap! - int Writeable(void) { return (tail >= head) ? tail - head : size - head; } - int Byte(int Offset); - bool Set(int Offset, int Length, int Value); -protected: - int GetStartCode(int Offset) { return (Byte(Offset) == 0x00 && Byte(Offset + 1) == 0x00 && Byte(Offset + 2) == 0x01) ? Byte(Offset + 3) : -1; } - int GetPictureType(int Offset) { return (Byte(Offset + 5) >> 3) & 0x07; } - int FindStartCode(uchar Code, int Offset = 0); - int GetPacketLength(int Offset = 0); -public: - cRingBuffer_(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); - virtual ~cRingBuffer_(); - virtual int Read(int Max = -1); - virtual int Write(int Max = -1); - bool EndOfFile(void) { return eof; } - bool Empty(void) { return Available() == 0; } - void Clear(void) { head = tail = 0; } - void Skip(int n); - }; - -cRingBuffer_::cRingBuffer_(int *InFile, int *OutFile, int Size, int FreeLimit, int AvailLimit) -{ - inFile = InFile; - outFile = OutFile; - size = Size; - Clear(); - freeLimit = FreeLimit; - availLimit = AvailLimit; - eof = false; - countLimit = countOverflow = 0; - minFree = size - 1; - buffer = new uchar[size]; - if (!buffer) - esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size); -} - -cRingBuffer_::~cRingBuffer_() -{ - dsyslog(LOG_INFO, "buffer stats: %d free, %d overflows, limit exceeded %d times", minFree, countOverflow, countLimit); - delete buffer; -} - -int cRingBuffer_::Byte(int Offset) -{ - if (buffer && Offset < Available()) { - Offset += head; - if (Offset >= size) - Offset -= size; - return buffer[Offset]; - } - return -1; -} - -bool cRingBuffer_::Set(int Offset, int Length, int Value) -{ - if (buffer && Offset + Length <= Available() ) { - Offset += head; - while (Length--) { - if (Offset >= size) - Offset -= size; - buffer[Offset] = Value; - Offset++; - } - return true; - } - return false; -} - -void cRingBuffer_::Skip(int n) -{ - if (n > 0) { - if (head < tail) { - head += n; - if (head > tail) - head = tail; - } - else if (head > tail) { - head += n; - if (head >= size) - head -= size; - if (head > tail) - head = tail; - } - } -} - -int cRingBuffer_::Read(int Max) -{ - if (buffer) { - eof = false; - int free = Free(); - if (free < minFree) - minFree = free; - if (freeLimit) { - if (free == 0) { - esyslog(LOG_ERR, "ERROR: buffer overflow (size=%d)", size); - countOverflow++; - } - else if (free < freeLimit) { - dsyslog(LOG_INFO, "free buffer space dipped into limit (%d < %d)", free, freeLimit); - countLimit++; - } - } - if (free == 0) - return 0; // the buffer is full - int readin = 0; - for (int i = 0; i < 2; i++) { - // If we read in exactly as many bytes as are immediately - // "readable" we have to do it again, because that means we - // were at the very end of the physical buffer and possibly only - // read in very few bytes. - int immediate = Readable(); - int n = immediate; - if (Max > 0 && n > Max) - n = Max; - if (n > 0) { - int r = read(*inFile, buffer + tail, n); - if (r > 0) { - readin += r; - tail += r; - if (tail > size) - esyslog(LOG_ERR, "ERROR: ooops: buffer tail (%d) exceeds size (%d)", tail, size); - if (tail >= size) - tail = 0; - } - else if (r < 0) { - if (errno != EAGAIN) { - LOG_ERROR; - return -1; - } - } - else - eof = true; - if (r == immediate && Max != immediate && tail == 0) - Max -= immediate; - else - break; - } - } - return readin; - } - return -1; -} - -int cRingBuffer_::Write(int Max) -{ - if (buffer) { - int avail = Available(); - if (availLimit) { - //XXX stats??? - if (avail == 0) - //XXX esyslog(LOG_ERR, "ERROR: buffer empty!"); - {//XXX - esyslog(LOG_ERR, "ERROR: buffer empty! %d", Max); - return Max > 0 ? Max : 0; - }//XXX - else if (avail < availLimit) -;//XXX dsyslog(LOG_INFO, "available buffer data dipped into limit (%d < %d)", avail, availLimit); - } - if (avail == 0) - return 0; // the buffer is empty - int n = Writeable(); - if (Max > 0 && n > Max) - n = Max; - int w = write(*outFile, buffer + head, n); - if (w > 0) { - head += w; - if (head > size) - esyslog(LOG_ERR, "ERROR: ooops: buffer head (%d) exceeds size (%d)", head, size); - if (head >= size) - head = 0; - } - else if (w < 0) { - if (errno != EAGAIN) - LOG_ERROR; - else - w = 0; - } - return w; - } - return -1; -} - -int cRingBuffer_::FindStartCode(uchar Code, int Offset) -{ - // Searches for a start code (beginning at Offset) and returns the number - // of bytes from Offset to the start code. - - int n = Available() - Offset; - - for (int i = 0; i < n; i++) { - int c = GetStartCode(Offset + i); - if (c == Code) - return i; - if (i > 0 && c == SC_PHEAD) - break; // found another block start while looking for a different code - } - return -1; -} - -int cRingBuffer_::GetPacketLength(int Offset) -{ - // Returns the entire length of the packet starting at offset. - return (Byte(Offset + 4) << 8) + Byte(Offset + 5) + 6; -} - // --- cFileName ------------------------------------------------------------- class cFileName { @@ -553,8 +334,9 @@ class cFileName { int fileNumber; char *fileName, *pFileNumber; bool record; + bool blocking; public: - cFileName(const char *FileName, bool Record); + cFileName(const char *FileName, bool Record, bool Blocking = false); ~cFileName(); const char *Name(void) { return fileName; } int Number(void) { return fileNumber; } @@ -564,11 +346,12 @@ class cFileName { int NextFile(void); }; -cFileName::cFileName(const char *FileName, bool Record) +cFileName::cFileName(const char *FileName, bool Record, bool Blocking) { file = -1; fileNumber = 0; record = Record; + blocking = Blocking; // Prepare the file name: fileName = new char[strlen(FileName) + RECORDFILESUFFIXLEN]; if (!fileName) { @@ -589,16 +372,17 @@ cFileName::~cFileName() int cFileName::Open(void) { if (file < 0) { + int BlockingFlag = blocking ? 0 : O_NONBLOCK; if (record) { dsyslog(LOG_INFO, "recording to '%s'", fileName); - file = OpenVideoFile(fileName, O_RDWR | O_CREAT | O_NONBLOCK); + file = OpenVideoFile(fileName, O_RDWR | O_CREAT | BlockingFlag); if (file < 0) LOG_ERROR_STR(fileName); } else { if (access(fileName, R_OK) == 0) { dsyslog(LOG_INFO, "playing '%s'", fileName); - file = open(fileName, O_RDONLY | O_NONBLOCK); + file = open(fileName, O_RDONLY | BlockingFlag); if (file < 0) LOG_ERROR_STR(fileName); } @@ -655,6 +439,7 @@ int cFileName::NextFile(void) class cRecordBuffer : public cRingBuffer { private: + cDvbApi *dvbApi; cFileName fileName; cIndexFile *index; cRemux remux; @@ -670,18 +455,19 @@ class cRecordBuffer : public cRingBuffer { virtual void Input(void); virtual void Output(void); public: - cRecordBuffer(int *InFile, const char *FileName); + cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2); virtual ~cRecordBuffer(); }; -cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) -:cRingBuffer(VIDEOBUFSIZE) +cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2) +:cRingBuffer(VIDEOBUFSIZE, true) ,fileName(FileName, true) +,remux(VPid, APid1, APid2, DPid1, DPid2, true) { + dvbApi = DvbApi; index = NULL; pictureType = NO_PICTURE; fileSize = 0; - videoDev = *InFile; recordFile = fileName.Open(); recording = false; lastDiskSpaceCheck = time(NULL); @@ -692,12 +478,14 @@ cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) if (!index) esyslog(LOG_ERR, "ERROR: can't allocate index"); // let's continue without index, so we'll at least have the recording + videoDev = dvbApi->SetModeRecord(); Start(); } cRecordBuffer::~cRecordBuffer() { Stop(); + dvbApi->SetModeNormal(true); delete index; } @@ -746,18 +534,19 @@ void cRecordBuffer::Input(void) else if (r < 0) { if (errno != EAGAIN) { LOG_ERROR; - break; + if (errno != EBUFFEROVERFLOW) + break; } } - else if (time(NULL) - t > 5) { + if (time(NULL) - t > MAXBROKENTIMEOUT) { esyslog(LOG_ERR, "ERROR: video data stream broken"); + cThread::EmergencyExit(true); t = time(NULL); } cFile::FileReady(videoDev, 100); if (!recording) break; } - SetPlayMode(videoDev, VID_PLAY_RESET); dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid()); } @@ -766,15 +555,14 @@ void cRecordBuffer::Output(void) { dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); - uchar b[MINVIDEODATA * 2]; + uchar b[MINVIDEODATA]; int r = 0; for (;;) { - usleep(1); // this keeps the CPU load low - r += Get(b + r, sizeof(b) - r); - if (r > 0) { - //XXX buffer full??? + int g = Get(b + r, sizeof(b) - r); + if (g > 0) { + r += g; int Count = r, Result; - const uchar *p = remux.Process(b, Count, Result, pictureType); + const uchar *p = remux.Process(b, Count, Result, &pictureType); if (p) { if (!Busy() && pictureType == I_FRAME) // finish the recording before the next 'I' frame break; @@ -803,166 +591,353 @@ void cRecordBuffer::Output(void) if (!recording) break; } + else + usleep(1); // this keeps the CPU load low } recording = false; dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); } +// --- ReadFrame ------------------------------------------------------------- + +int ReadFrame(int f, uchar *b, int Length, int Max) +{ + if (Length == -1) + Length = Max; // this means we read up to EOF (see cIndex) + else if (Length > Max) { + esyslog(LOG_ERR, "ERROR: frame larger than buffer (%d > %d)", Length, Max); + Length = Max; + } + int r = read(f, b, Length); + if (r < 0) + LOG_ERROR; + return r; +} + // --- cReplayBuffer --------------------------------------------------------- -class cReplayBuffer : public cRingBuffer_, public cThread { +class cReplayBuffer : public cRingBuffer { private: - enum eReplayCmd { rcNone, rcStill, rcPause, rcPlay, rcForward, rcBackward }; - enum eReplayMode { rmStill, rmPlay, rmFastForward, rmFastRewind, rmSlowRewind }; + cDvbApi *dvbApi; cIndexFile *index; cFileName fileName; int fileOffset; - int videoDev; + int videoDev, audioDev; + FILE *dolbyDev; int replayFile; - eReplayMode mode; - int lastIndex, stillIndex; - int brakeCounter; - eReplayCmd command; - bool active; + bool eof; + int blockInput, blockOutput; + bool paused, fastForward, fastRewind; + int lastIndex, stillIndex, playIndex; + bool canToggleAudioTrack; + uchar audioTrack; bool NextFile(uchar FileNumber = 0, int FileOffset = -1); + void Clear(bool Block = false); void Close(void); - void SetCmd(eReplayCmd Cmd) { LOCK_THREAD; command = Cmd; } - void SetTemporalReference(void); + void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00); + void DisplayFrame(uchar *b, int Length); + int Resume(void); + bool Save(void); protected: - virtual void Action(void); + virtual void Input(void); + virtual void Output(void); public: - cReplayBuffer(int *OutFile, const char *FileName); + cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName); virtual ~cReplayBuffer(); - virtual int Read(int Max = -1); - virtual int Write(int Max = -1); - void SetMode(eReplayMode Mode); - int Resume(void); - bool Save(void); - void Pause(void) { SetCmd(rcPause); } - void Play(void) { SetCmd(rcPlay); } - void Forward(void) { SetCmd(rcForward); } - void Backward(void) { SetCmd(rcBackward); } + void Pause(void); + void Play(void); + void Forward(void); + void Backward(void); int SkipFrames(int Frames); void SkipSeconds(int Seconds); void Goto(int Position, bool Still = false); void GetIndex(int &Current, int &Total, bool SnapToIFrame = false); + bool CanToggleAudioTrack(void) { return canToggleAudioTrack; } + void ToggleAudioTrack(void); }; -cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName) -:cRingBuffer_(&replayFile, OutFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) +cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName) +:cRingBuffer(VIDEOBUFSIZE) ,fileName(FileName, false) { + dvbApi = DvbApi; index = NULL; fileOffset = 0; - videoDev = *OutFile; + videoDev = VideoDev; + audioDev = AudioDev; + dolbyDev = NULL; + if (cDvbApi::AudioCommand()) { + dolbyDev = popen(cDvbApi::AudioCommand(), "w"); + if (!dolbyDev) + esyslog(LOG_ERR, "ERROR: can't open pipe to audio command '%s'", cDvbApi::AudioCommand()); + } replayFile = fileName.Open(); - mode = rmPlay; - brakeCounter = 0; - command = rcNone; - lastIndex = stillIndex = -1; - active = false; + eof = false; + blockInput = blockOutput = false; + paused = fastForward = fastRewind = false; + lastIndex = stillIndex = playIndex = -1; + canToggleAudioTrack = false; + audioTrack = 0xC0; if (!fileName.Name()) return; // Create the index file: index = new cIndexFile(FileName, false); - if (!index) + if (!index) { esyslog(LOG_ERR, "ERROR: can't allocate index"); - // let's continue without index, so we'll at least have the recording + } + else if (!index->Ok()) { + delete index; + index = NULL; + } + dvbApi->SetModeReplay(); Start(); } cReplayBuffer::~cReplayBuffer() { - active = false; - Cancel(3); + Stop(); + Save(); Close(); - SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); - SetPlayMode(videoDev, VID_PLAY_RESET); + if (dolbyDev) + pclose(dolbyDev); + dvbApi->SetModeNormal(false); delete index; } -void cReplayBuffer::Action(void) +void cReplayBuffer::Input(void) { - dsyslog(LOG_INFO, "replay thread started (pid=%d)", getpid()); - - bool Paused = false; - bool FastForward = false; - bool FastRewind = false; + dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid()); int ResumeIndex = Resume(); if (ResumeIndex >= 0) isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, IndexToHMSF(ResumeIndex, true)); - active = true; - while (active) { - usleep(1); // this keeps the CPU load low - - LOCK_THREAD; - - if (command != rcNone) { - switch (command) { - case rcStill: SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); - SetPlayMode(videoDev, VID_PLAY_NORMAL); - SetMode(rmStill); - Paused = FastForward = FastRewind = false; - break; - case rcPause: SetPlayMode(videoDev, Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); - Paused = !Paused; - if (FastForward || FastRewind) { - SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); - Clear(); - } - FastForward = FastRewind = false; - SetMode(rmPlay); - if (!Paused) - stillIndex = -1; - break; - case rcPlay: if (FastForward || FastRewind || Paused) { - SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); - SetPlayMode(videoDev, VID_PLAY_NORMAL); - FastForward = FastRewind = Paused = false; - SetMode(rmPlay); - } - stillIndex = -1; - break; - case rcForward: SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); - Clear(); - FastForward = !FastForward; - FastRewind = false; - if (Paused) { - SetMode(rmPlay); - SetPlayMode(videoDev, FastForward ? VID_PLAY_SLOW_MOTION : VID_PLAY_PAUSE); - } - else { - SetPlayMode(videoDev, VID_PLAY_NORMAL); - SetMode(FastForward ? rmFastForward : rmPlay); - } - stillIndex = -1; - break; - case rcBackward: SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); - Clear(); - FastRewind = !FastRewind; - FastForward = false; - if (Paused) { - SetMode(FastRewind ? rmSlowRewind : rmPlay); - SetPlayMode(videoDev, FastRewind ? VID_PLAY_NORMAL : VID_PLAY_PAUSE); - } - else { - SetPlayMode(videoDev, VID_PLAY_NORMAL); - SetMode(FastRewind ? rmFastRewind : rmPlay); - } - stillIndex = -1; - break; - default: break; - } - command = rcNone; + + int lastIndex = -1; + int brakeCounter = 0; + uchar b[MAXFRAMESIZE]; + while (Busy() && (blockInput || NextFile())) { + if (!blockInput && stillIndex < 0) { + int r = 0; + if (fastForward && !paused || fastRewind) { + int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset); + uchar FileNumber; + int FileOffset, Length; + if (!paused || (brakeCounter++ % 24) == 0) // show every I_FRAME 24 times in rmSlowRewind mode to achieve roughly the same speed as in slow forward mode + Index = index->GetNextIFrame(Index, fastForward, &FileNumber, &FileOffset, &Length); + if (Index >= 0) { + if (!NextFile(FileNumber, FileOffset)) + break; + } + else { + paused = fastForward = fastRewind = false; + Play(); + continue; + } + lastIndex = Index; + playIndex = -1; + r = ReadFrame(replayFile, b, Length, sizeof(b)); + StripAudioPackets(b, r); + } + else if (index) { + lastIndex = -1; + playIndex = (playIndex >= 0) ? playIndex + 1 : index->Get(fileName.Number(), fileOffset); + uchar FileNumber; + int FileOffset, Length; + if (!(index->Get(playIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) + break; + r = ReadFrame(replayFile, b, Length, sizeof(b)); + StripAudioPackets(b, r, audioTrack); + } + else // allows replay even if the index file is missing + r = read(replayFile, b, sizeof(b)); + if (r > 0) { + uchar *p = b; + while (r > 0 && Busy() && !blockInput) { + int w = Put(p, r); + p += w; + r -= w; + usleep(1); // this keeps the CPU load low + } + } + else if (r ==0) + eof = true; + else if (r < 0 && errno != EAGAIN) { + LOG_ERROR; + break; + } } - if (Read() < 0 || Write() < 0) - break; + else + usleep(1); // this keeps the CPU load low + if (blockInput > 1) + blockInput = 1; } - Save(); - dsyslog(LOG_INFO, "end replaying thread"); + dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid()); +} + +void cReplayBuffer::Output(void) +{ + dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); + + uchar b[MINVIDEODATA]; + while (Busy()) { + int r = blockOutput ? 0 : Get(b, sizeof(b)); + if (r > 0) { + uchar *p = b; + while (r > 0 && Busy() && !blockOutput) { + cFile::FileReadyForWriting(videoDev, 100); + int w = write(videoDev, p, r); + if (w > 0) { + p += w; + r -= w; + fileOffset += w; + } + else if (w < 0 && errno != EAGAIN) { + LOG_ERROR; + Stop(); + return; + } + } + } + else + usleep(1); // this keeps the CPU load low + if (blockOutput > 1) + blockOutput = 1; + } + + dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); +} + +void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except) +{ + for (int i = 0; i < Length - 6; i++) { + if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { + uchar c = b[i + 3]; + int l = b[i + 4] * 256 + b[i + 5] + 6; + switch (c) { + case 0xBD: // dolby + if (Except && dolbyDev) { + int written = b[i + 8] + 9; // skips the PES header + int n = l - written; + while (n > 0) { + int w = fwrite(&b[i + written], 1, n, dolbyDev); + if (w < 0) { + LOG_ERROR; + break; + } + n -= w; + written += w; + } + } + // continue with deleting the data - otherwise it disturbs DVB replay + case 0xC0 ... 0xC1: // audio + if (c == 0xC1) + canToggleAudioTrack = true; + if (!Except || c != Except) { + int n = l; + for (int j = i; j < Length && n--; j++) + b[j] = 0x00; + } + break; + case 0xE0 ... 0xEF: // video + break; + default: + //esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c); + l = 0; + } + if (l) + i += l - 1; // the loop increments, too! + } + /*XXX + else + esyslog(LOG_ERR, "ERROR: broken packet header"); + XXX*/ + } +} + +void cReplayBuffer::DisplayFrame(uchar *b, int Length) +{ + StripAudioPackets(b, Length); + videoDisplayStillPicture sp = { (char *)b, Length }; + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); + CHECK(ioctl(audioDev, AUDIO_SET_MUTE, true)); + CHECK(ioctl(videoDev, VIDEO_STILLPICTURE, &sp)); +} + +void cReplayBuffer::Clear(bool Block) +{ + if (!(blockInput || blockOutput)) { + blockInput = blockOutput = 2; + time_t t0 = time(NULL); + while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2) + usleep(1); + Lock(); + cRingBuffer::Clear(); + playIndex = -1; + CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER)); + CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER)); + } + if (!Block) { + blockInput = blockOutput = 0; + Unlock(); + } +} + +void cReplayBuffer::Pause(void) +{ + paused = !paused; + CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE)); + if (fastForward || fastRewind) { + if (paused) + Clear(); + fastForward = fastRewind = false; + } + CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); + stillIndex = -1; +} + +void cReplayBuffer::Play(void) +{ + if (fastForward || fastRewind || paused) { + if (!paused) + Clear(); + stillIndex = -1; + CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY)); + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); + CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); + fastForward = fastRewind = paused = false; + } +} + +void cReplayBuffer::Forward(void) +{ + if (index || paused) { + if (!paused) + Clear(true); + stillIndex = -1; + fastForward = !fastForward; + fastRewind = false; + if (paused) + CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2)); + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward)); + CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused)); + if (!paused) + Clear(false); + } +} + +void cReplayBuffer::Backward(void) +{ + if (index) { + Clear(true); + stillIndex = -1; + fastRewind = !fastRewind; + fastForward = false; + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind)); + CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused)); + Clear(false); + } } void cReplayBuffer::Close(void) @@ -974,14 +949,6 @@ void cReplayBuffer::Close(void) } } -void cReplayBuffer::SetMode(eReplayMode Mode) -{ - mode = Mode; - brakeCounter = 0; - if (mode != rmPlay) - Clear(); -} - int cReplayBuffer::Resume(void) { if (index) { @@ -1016,9 +983,6 @@ bool cReplayBuffer::Save(void) int cReplayBuffer::SkipFrames(int Frames) { if (index && Frames) { - - LOCK_THREAD; - int Current, Total; GetIndex(Current, Total, true); int OldCurrent = Current; @@ -1030,16 +994,8 @@ int cReplayBuffer::SkipFrames(int Frames) void cReplayBuffer::SkipSeconds(int Seconds) { - LOCK_THREAD; - - SetPlayMode(videoDev, VID_PLAY_PAUSE); - SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); - SetPlayMode(videoDev, VID_PLAY_NORMAL); - command = rcPlay; - SetMode(rmPlay); - Clear(); - if (index && Seconds) { + Clear(true); int Index = index->Get(fileName.Number(), fileOffset); if (Index >= 0) { if (Seconds < 0) { @@ -1055,31 +1011,41 @@ void cReplayBuffer::SkipSeconds(int Seconds) if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0) NextFile(FileNumber, FileOffset); } + Clear(false); + Play(); } } void cReplayBuffer::Goto(int Index, bool Still) { - LOCK_THREAD; - - if (Still) - command = rcStill; - if (++Index <= 0) - Index = 1; // not '0', to allow GetNextIFrame() below to work! - uchar FileNumber; - int FileOffset; - if ((stillIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset)) >= 0) - NextFile(FileNumber, FileOffset); - SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); - Clear(); + if (index) { + Clear(true); + if (paused) + CHECK(ioctl(videoDev, VIDEO_CONTINUE)); + if (++Index <= 0) + Index = 1; // not '0', to allow GetNextIFrame() below to work! + uchar FileNumber; + int FileOffset, Length; + Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); + if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { + stillIndex = Index; + playIndex = -1; + uchar b[MAXFRAMESIZE]; + int r = ReadFrame(replayFile, b, Length, sizeof(b)); + if (r > 0) + DisplayFrame(b, r); + fileOffset += Length; + paused = true; + } + else + stillIndex = playIndex = -1; + Clear(false); + } } void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) { if (index) { - - LOCK_THREAD; - if (stillIndex >= 0) Current = stillIndex; else { @@ -1099,178 +1065,145 @@ void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) { if (FileNumber > 0) { - Clear(); fileOffset = FileOffset; replayFile = fileName.SetOffset(FileNumber, FileOffset); } - else if (replayFile >= 0 && EndOfFile()) { + else if (replayFile >= 0 && eof) { Close(); replayFile = fileName.NextFile(); } + eof = false; return replayFile >= 0; } -void cReplayBuffer::SetTemporalReference(void) -{ - for (int i = 0; i < Available(); i++) { - if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { - switch (Byte(i + 3)) { - case SC_PICTURE: { - unsigned short m = (Byte(i + 4) << 8) | Byte(i + 5); - m &= 0x003F; - Set(i + 4, 1, m >> 8); - Set(i + 5, 1, m & 0xFF); - } - return; - } - } - } -} - -int cReplayBuffer::Read(int Max = -1) +void cReplayBuffer::ToggleAudioTrack(void) { - if (mode != rmPlay) { - if (index) { - if (Available()) - return 0; // write out the entire block - if (mode == rmStill) { - uchar FileNumber; - int FileOffset, Length; - if (index->GetNextIFrame(stillIndex + 1, false, &FileNumber, &FileOffset, &Length) >= 0) { - if (!NextFile(FileNumber, FileOffset)) - return -1; - Max = Length; - } - command = rcPause; - } - else { - int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset); - if (Index >= 0) { - if (mode == rmSlowRewind && (brakeCounter++ % 24) != 0) { - // show every I_FRAME 24 times in rmSlowRewind mode to achieve roughly the same speed as in slow forward mode - Index = index->GetNextIFrame(Index, true); // jump ahead one frame - } - uchar FileNumber; - int FileOffset, Length; - Index = index->GetNextIFrame(Index, mode == rmFastForward, &FileNumber, &FileOffset, &Length); - if (Index >= 0) { - if (!NextFile(FileNumber, FileOffset)) - return -1; - Max = Length; - } - lastIndex = Index; - } - if (Index < 0) { - // This results in normal replay after a fast rewind. - // After a fast forward it will stop. - // TODO Could we cause it to pause at the last frame? - SetMode(rmPlay); - return 0; - } - } - } - } - else - lastIndex = -1; - //XXX timeout as in recording??? - if (NextFile()) { - int readin = 0; - do { - // If Max is > 0 here we need to make sure we read in the entire block! - int r = cRingBuffer_::Read(Max); - if (r >= 0) - readin += r; - else - return -1; - } while (readin < Max && Free() > 0); - if (mode != rmPlay) { - // delete the audio data in modes other than rmPlay: - int AudioOffset, StartOffset = 0; - while ((AudioOffset = FindStartCode(SC_AUDIO, StartOffset)) >= 0) { - if (!Set(StartOffset + AudioOffset, GetPacketLength(StartOffset + AudioOffset), 0)) - break; // to be able to replay old AV_PES recordings! - StartOffset += AudioOffset; - } - SetTemporalReference(); - } - return readin; - } - if (Available() > 0) - return 0; - return -1; -} - -int cReplayBuffer::Write(int Max) -{ - int Written = 0; - if (Max) { - int w; - do { - w = cRingBuffer_::Write(Max); - if (w >= 0) { - fileOffset += w; - Written += w; - if (Max < 0) - break; - Max -= w; - } - else - return w; - } while (Max > 0); // we MUST write this entire frame block + if (CanToggleAudioTrack()) { + audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0; + Clear(); } - return Written; } // --- cTransferBuffer ------------------------------------------------------- -class cTransferBuffer : public cThread { +class cTransferBuffer : public cRingBuffer { private: - bool active; + cDvbApi *dvbApi; int fromDevice, toDevice; + bool gotBufferReserve; + cRemux remux; protected: - virtual void Action(void); + virtual void Input(void); + virtual void Output(void); public: - cTransferBuffer(int FromDevice, int ToDevice); + cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid); virtual ~cTransferBuffer(); + void SetAudioPid(int APid); }; -cTransferBuffer::cTransferBuffer(int FromDevice, int ToDevice) +cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid) +:cRingBuffer(VIDEOBUFSIZE, true) +,remux(VPid, APid, 0, 0, 0) { - fromDevice = FromDevice; + dvbApi = DvbApi; + fromDevice = dvbApi->SetModeRecord(); toDevice = ToDevice; - active = false; + gotBufferReserve = false; Start(); } cTransferBuffer::~cTransferBuffer() { - active = false; - Cancel(3); - SetPlayMode(fromDevice, VID_PLAY_RESET); - SetPlayMode(toDevice, VID_PLAY_RESET); + Stop(); + dvbApi->SetModeNormal(true); } -void cTransferBuffer::Action(void) +void cTransferBuffer::SetAudioPid(int APid) { - dsyslog(LOG_INFO, "data transfer thread started (pid=%d)", getpid()); + Clear(); + //XXX we may need to have access to the audio device, too, in order to clear it + CHECK(ioctl(toDevice, VIDEO_CLEAR_BUFFER)); + gotBufferReserve = false; + remux.SetAudioPid(APid); +} + +void cTransferBuffer::Input(void) +{ + dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid()); - cRingBuffer_ Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0); - active = true; - while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start - Buffer.Read(); // initializes fromDevice for reading - usleep(1); // this keeps the CPU load low + uchar b[MINVIDEODATA]; + int n = 0; + while (Busy()) { + cFile::FileReady(fromDevice, 100); + int r = read(fromDevice, b + n, sizeof(b) - n); + if (r > 0) { + n += r; + int Count = n, Result; + const uchar *p = remux.Process(b, Count, Result); + if (p) { + while (Result > 0 && Busy()) { + int w = Put(p, Result); + p += w; + Result -= w; + } + } + if (Count > 0) { + n -= Count; + memmove(b, b + Count, n); + } + } + else if (r < 0) { + if (errno != EAGAIN) { + LOG_ERROR; + if (errno != EBUFFEROVERFLOW) + break; + } + } } - while (active) { - if (Buffer.Read() < 0 || Buffer.Write() < 0) - break; - usleep(1); // this keeps the CPU load low + + dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid()); +} + +void cTransferBuffer::Output(void) +{ + dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); + + uchar b[MINVIDEODATA]; + while (Busy()) { + if (!gotBufferReserve) { + if (Available() < MAXFRAMESIZE) { + usleep(100000); // allow the buffer to collect some reserve + continue; + } + else + gotBufferReserve = true; + } + int r = Get(b, sizeof(b)); + if (r > 0) { + uchar *p = b; + while (r > 0 && Busy()) { + int w = write(toDevice, p, r); + if (w > 0) { + p += w; + r -= w; + } + else if (w < 0 && errno != EAGAIN) { + LOG_ERROR; + Stop(); + return; + } + } + } + else + usleep(1); // this keeps the CPU load low } - dsyslog(LOG_INFO, "data transfer thread stopped (pid=%d)", getpid()); + + dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); } // --- cCuttingBuffer -------------------------------------------------------- -class cCuttingBuffer : public cRingBuffer_, public cThread { +class cCuttingBuffer : public cThread { private: bool active; int fromFile, toFile; @@ -1285,15 +1218,14 @@ class cCuttingBuffer : public cRingBuffer_, public cThread { }; cCuttingBuffer::cCuttingBuffer(const char *FromFileName, const char *ToFileName) -:cRingBuffer_(&fromFile, &toFile, VIDEOBUFSIZE, 0, VIDEOBUFSIZE / 10) { active = false; fromFile = toFile = -1; fromFileName = toFileName = NULL; fromIndex = toIndex = NULL; if (fromMarks.Load(FromFileName) && fromMarks.Count()) { - fromFileName = new cFileName(FromFileName, false); - toFileName = new cFileName(ToFileName, true); + fromFileName = new cFileName(FromFileName, false, true); + toFileName = new cFileName(ToFileName, true, true); fromIndex = new cIndexFile(FromFileName, false); toIndex = new cIndexFile(ToFileName, true); toMarks.Load(ToFileName); // doesn't actually load marks, just sets the file name @@ -1329,22 +1261,24 @@ void cCuttingBuffer::Action(void) int LastIFrame = 0; toMarks.Add(0); toMarks.Save(); + uchar buffer[MAXFRAMESIZE]; while (active) { uchar FileNumber; int FileOffset, Length; uchar PictureType; - - Clear(); // makes sure one frame is completely read and written - + // Read one frame: - + if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { if (FileNumber != CurrentFileNumber) { fromFile = fromFileName->SetOffset(FileNumber, FileOffset); CurrentFileNumber = FileNumber; } - if (fromFile >= 0) - Length = cRingBuffer_::Read(Length); + if (fromFile >= 0) { + Length = ReadFrame(fromFile, buffer, Length, sizeof(buffer)); + if (Length < 0) + break; + } else break; } @@ -1362,7 +1296,7 @@ void cCuttingBuffer::Action(void) } LastIFrame = 0; } - cRingBuffer_::Write(Length); + write(toFile, buffer, Length); toIndex->Write(PictureType, toFileName->Number(), FileSize); FileSize += Length; if (!LastIFrame) @@ -1424,13 +1358,32 @@ bool cVideoCutter::Active(void) // --- cDvbApi --------------------------------------------------------------- + +static const char *OstName(const char *Name, int n) +{ + static char buffer[_POSIX_PATH_MAX]; + snprintf(buffer, sizeof(buffer), "%s%d", Name, n); + return buffer; +} + +static int OstOpen(const char *Name, int n, int Mode, bool ReportError = false) +{ + const char *FileName = OstName(Name, n); + int fd = open(FileName, Mode); + if (fd < 0 && ReportError) + LOG_ERROR_STR(FileName); + return fd; +} + int cDvbApi::NumDvbApis = 0; int cDvbApi::useDvbApi = 0; cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL }; cDvbApi *cDvbApi::PrimaryDvbApi = NULL; +char *cDvbApi::audioCommand = NULL; -cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) +cDvbApi::cDvbApi(int n) { + vPid = aPid1 = aPid2 = dPid1 = dPid2 = 0; siProcessor = NULL; recordBuffer = NULL; replayBuffer = NULL; @@ -1438,21 +1391,49 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) transferringFromDvbApi = NULL; ca = 0; priority = -1; - videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK); - if (videoDev >= 0) { - siProcessor = new cSIProcessor(VbiFileName); + + // Devices that are only present on DVB-C or DVB-S cards: + + fd_qamfe = OstOpen(DEV_OST_QAMFE, n, O_RDWR); + fd_qpskfe = OstOpen(DEV_OST_QPSKFE, n, O_RDWR); + fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR); + + // Devices that all DVB cards must have: + + fd_demuxv = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); + fd_demuxa1 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); + fd_demuxa2 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); + fd_demuxd1 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); + fd_demuxd2 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); + fd_demuxt = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); + + // Devices not present on "budget" cards: + + fd_osd = OstOpen(DEV_OST_OSD, n, O_RDWR); + fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK); + fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK); + + // Devices that may not be available, and are not necessary for normal operation: + + videoDev = OstOpen(DEV_VIDEO, n, O_RDWR); + + // Devices that will be dynamically opened and closed when necessary: + + fd_dvr = -1; + + // Video format: + + SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3); + + // We only check the devices that must be present - the others will be checked before accessing them: + + if (((fd_qpskfe >= 0 && fd_sec >= 0) || fd_qamfe >= 0) && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxd1 >= 0 && fd_demuxd2 >= 0 && fd_demuxt >= 0) { + siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n)); if (!dvbApi[0]) // only the first one shall set the system time siProcessor->SetUseTSTime(Setup.SetSystemTime); - siProcessor->AddFilter(0x14, 0x70); // TDT - siProcessor->AddFilter(0x14, 0x73); // TOT - siProcessor->AddFilter(0x12, 0x4e); // event info, actual TS, present/following - siProcessor->AddFilter(0x12, 0x4f); // event info, other TS, present/following - siProcessor->AddFilter(0x12, 0x50); // event info, actual TS, schedule - siProcessor->AddFilter(0x12, 0x60); // event info, other TS, schedule - siProcessor->Start(); } else - LOG_ERROR_STR(VideoFileName); + esyslog(LOG_ERR, "ERROR: can't open video device %d", n); cols = rows = 0; ovlGeoSet = ovlStat = ovlFbSet = false; @@ -1480,16 +1461,14 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName) cDvbApi::~cDvbApi() { - if (videoDev >= 0) { - delete siProcessor; - Close(); - StopReplay(); - StopRecord(); - StopTransfer(); - OvlO(false); //Overlay off! - //XXX the following call sometimes causes a segfault - driver problem? - //XXX close(videoDev); - } + delete siProcessor; + Close(); + StopReplay(); + StopRecord(); + StopTransfer(); + OvlO(false); //Overlay off! + // We're not explicitly closing any device files here, since this sometimes + // caused segfaults. Besides, the program is about to terminate anyway... #if defined(DEBUG_OSD) || defined(REMOTE_KBD) endwin(); #endif @@ -1555,37 +1534,32 @@ int cDvbApi::Index(void) return -1; } +bool cDvbApi::Probe(const char *FileName) +{ + if (access(FileName, F_OK) == 0) { + dsyslog(LOG_INFO, "probing %s", FileName); + int f = open(FileName, O_RDONLY); + if (f >= 0) { + close(f); + return true; + } + else if (errno != ENODEV && errno != EINVAL) + LOG_ERROR_STR(FileName); + } + else if (errno != ENOENT) + LOG_ERROR_STR(FileName); + return false; +} + bool cDvbApi::Init(void) { NumDvbApis = 0; for (int i = 0; i < MAXDVBAPI; i++) { if (useDvbApi == 0 || (useDvbApi & (1 << i)) != 0) { - char fileName[strlen(VIDEODEVICE) + 10]; - sprintf(fileName, "%s%d", VIDEODEVICE, i); - if (access(fileName, F_OK | R_OK | W_OK) == 0) { - dsyslog(LOG_INFO, "probing %s", fileName); - int f = open(fileName, O_RDWR); - if (f >= 0) { - struct video_capability cap; - int r = ioctl(f, VIDIOCGCAP, &cap); - close(f); - if (r == 0 && (cap.type & VID_TYPE_DVB)) { - char vbiFileName[strlen(VBIDEVICE) + 10]; - sprintf(vbiFileName, "%s%d", VBIDEVICE, i); - dvbApi[NumDvbApis++] = new cDvbApi(fileName, vbiFileName); - } - } - else { - if (errno != ENODEV) - LOG_ERROR_STR(fileName); - break; - } - } - else { - if (errno != ENOENT) - LOG_ERROR_STR(fileName); + if (Probe(OstName(DEV_OST_QPSKFE, i)) || Probe(OstName(DEV_OST_QAMFE, i))) + dvbApi[NumDvbApis++] = new cDvbApi(i); + else break; - } } } PrimaryDvbApi = dvbApi[0]; @@ -1616,6 +1590,8 @@ const cSchedules *cDvbApi::Schedules(cThreadLock *ThreadLock) const bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) { + if (videoDev < 0) + return false; int result = 0; // just do this once? struct video_mbuf mbuf; @@ -1711,6 +1687,8 @@ bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, bool cDvbApi::OvlF(int SizeX, int SizeY, int FbAddr, int Bpp, int Palette) { + if (videoDev < 0) + return false; int result = 0; // get the actual X-Server settings??? // plausibility-check problem: can't be verified w/o X-server!!! @@ -1752,6 +1730,8 @@ bool cDvbApi::OvlF(int SizeX, int SizeY, int FbAddr, int Bpp, int Palette) bool cDvbApi::OvlG(int SizeX, int SizeY, int PosX, int PosY) { + if (videoDev < 0) + return false; int result = 0; // get the actual X-Server settings??? struct video_capability vc; @@ -1798,6 +1778,8 @@ bool cDvbApi::OvlG(int SizeX, int SizeY, int PosX, int PosY) bool cDvbApi::OvlC(int ClipCount, CRect *cr) { + if (videoDev < 0) + return false; if (ovlGeoSet && ovlFbSet) { for (int i = 0; i < ClipCount; i++) { ovlClipRects[i].x = cr[i].x; @@ -1815,6 +1797,8 @@ bool cDvbApi::OvlC(int ClipCount, CRect *cr) bool cDvbApi::OvlP(__u16 Brightness, __u16 Colour, __u16 Hue, __u16 Contrast) { + if (videoDev < 0) + return false; int result = 0; ovlBrightness = Brightness; ovlColour = Colour; @@ -1836,6 +1820,8 @@ bool cDvbApi::OvlP(__u16 Brightness, __u16 Colour, __u16 Hue, __u16 Contrast) bool cDvbApi::OvlO(bool Value) { + if (videoDev < 0) + return false; int result = 0; if (!ovlGeoSet && Value) return false; @@ -1867,30 +1853,11 @@ void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg) } } } -#else -void cDvbApi::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) -{ - if (videoDev >= 0) { - struct drawcmd dc; - dc.cmd = cmd; - dc.color = color; - dc.x0 = x0; - dc.y0 = y0; - dc.x1 = x1; - dc.y1 = y1; - dc.data = (void *)data; - ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc); - usleep(10); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places - // XXX and sometimes the OSD was no longer displayed). - // XXX Increase the value if the problem still persists on your particular system. - // TODO Check if this is still necessary with driver versions after 0.6. - } -} #endif void cDvbApi::Open(int w, int h) { - int d = (h < 0) ? MenuLines + h : 0; + int d = (h < 0) ? Setup.OSDheight + h : 0; h = abs(h); cols = w; rows = h; @@ -1899,16 +1866,7 @@ void cDvbApi::Open(int w, int h) syncok(window, true); #define B2C(b) (((b) * 1000) / 255) #define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b)) -#else - w *= charWidth; - h *= lineHeight; - d *= lineHeight; - int x = (720 - MenuColumns * charWidth) / 2; //TODO PAL vs. NTSC??? - int y = (576 - MenuLines * lineHeight) / 2 + d; - osd = new cDvbOsd(videoDev, x, y, x + w - 1, y + h - 1, 4); - #define SETCOLOR(n, r, g, b, o) Cmd(OSD_SetColor, n, r, g, b, o) - SETCOLOR(clrTransparent, 0x00, 0x00, 0x00, 0); -#endif + //XXX SETCOLOR(clrBackground, 0x00, 0x00, 0x00, 127); // background 50% gray SETCOLOR(clrBlack, 0x00, 0x00, 0x00, 255); SETCOLOR(clrRed, 0xFC, 0x14, 0x14, 255); @@ -1918,6 +1876,35 @@ void cDvbApi::Open(int w, int h) SETCOLOR(clrCyan, 0x00, 0xFC, 0xFC, 255); SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255); SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255); +#else + w *= charWidth; + h *= lineHeight; + d *= lineHeight; + int x = (720 - (Setup.OSDwidth - 1) * charWidth) / 2; //TODO PAL vs. NTSC??? + int y = (576 - Setup.OSDheight * lineHeight) / 2 + d; + //XXX + osd = new cDvbOsd(fd_osd, x, y); + //XXX TODO this should be transferred to the places where the individual windows are requested (there's too much detailed knowledge here!) + if (h / lineHeight == 5) { //XXX channel display + osd->Create(0, 0, w, h, 4); + } + else if (h / lineHeight == 1) { //XXX info display + osd->Create(0, 0, w, h, 4); + } + else if (d == 0) { //XXX full menu + osd->Create(0, 0, w, lineHeight, 2); + osd->Create(0, lineHeight, w, (Setup.OSDheight - 3) * lineHeight, 2, true, clrBackground, clrCyan, clrWhite, clrBlack); + osd->Create(0, (Setup.OSDheight - 2) * lineHeight, w, 2 * lineHeight, 4); + } + else { //XXX progress display + /*XXX + osd->Create(0, 0, w, lineHeight, 1); + osd->Create(0, lineHeight, w, lineHeight, 2, false); + osd->Create(0, 2 * lineHeight, w, lineHeight, 1); + XXX*///XXX some pixels are not drawn correctly with lower bpp values + osd->Create(0, 0, w, 3*lineHeight, 4); + } +#endif } void cDvbApi::Close(void) @@ -2037,60 +2024,270 @@ void cDvbApi::Flush(void) #endif } -bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr) +int cDvbApi::SetModeRecord(void) { - if (videoDev >= 0) { - cThreadLock ThreadLock(siProcessor); // makes sure the siProcessor won't access the vbi-device while switching - StopTransfer(); - StopReplay(); - SetPlayMode(videoDev, VID_PLAY_RESET); - struct frontend front; - ioctl(videoDev, VIDIOCGFRONTEND, &front); - unsigned int freq = FrequencyMHz; - if (front.type == FRONT_DVBS) { - front.ttk = (freq < 11700UL) ? 0 : 1; - if (freq < 11700UL) { + // Sets up the DVB device for recording + + SetPids(true); + if (fd_dvr >= 0) + close(fd_dvr); + fd_dvr = OstOpen(DEV_OST_DVR, Index(), O_RDONLY | O_NONBLOCK); + if (fd_dvr < 0) + LOG_ERROR; + return fd_dvr; +} + +void cDvbApi::SetModeReplay(void) +{ + // Sets up the DVB device for replay + + if (fd_video >= 0 && fd_audio >= 0) { + if (siProcessor) + siProcessor->SetStatus(false); + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); + CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); + CHECK(ioctl(fd_audio, AUDIO_PLAY)); + CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); + CHECK(ioctl(fd_video, VIDEO_PLAY)); + } +} + +void cDvbApi::SetModeNormal(bool FromRecording) +{ + // Puts the DVB device back into "normal" viewing mode (after replay or recording) + + if (FromRecording) { + close(fd_dvr); + fd_dvr = -1; + SetPids(false); + } + else { + if (fd_video >= 0 && fd_audio >= 0) { + CHECK(ioctl(fd_video, VIDEO_STOP, true)); + CHECK(ioctl(fd_audio, AUDIO_STOP, true)); + CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); + CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); + CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX)); + CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); + CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); + if (siProcessor) + siProcessor->SetStatus(true); + } + } +} + +void cDvbApi::SetVideoFormat(videoFormat_t Format) +{ + if (fd_video) + CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, Format)); +} + +bool cDvbApi::SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output) +{ + if (Pid) { + CHECK(ioctl(fd, DMX_STOP)); + dmxPesFilterParams pesFilterParams; + pesFilterParams.pid = Pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = Output; + pesFilterParams.pesType = PesType; + pesFilterParams.flags = DMX_IMMEDIATE_START; + if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { + if (Pid != 0x1FFF) + LOG_ERROR; + return false; + } + } + return true; +} + +bool cDvbApi::SetPids(bool ForRecording) +{ + return SetVpid(vPid, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && + SetApid1(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && + SetApid2(ForRecording ? aPid2 : 0, DMX_OUT_TS_TAP) && + SetDpid1(ForRecording ? dPid1 : 0, DMX_OUT_TS_TAP) && + SetDpid2(ForRecording ? dPid2 : 0, DMX_OUT_TS_TAP); +} + +bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr) +{ + // Make sure the siProcessor won't access the device while switching + cThreadLock ThreadLock(siProcessor); + + StopTransfer(); + StopReplay(); + + // Must set this anyway to avoid getting stuck when switching through + // channels with 'Up' and 'Down' keys: + currentChannel = ChannelNumber; + vPid = Vpid; + aPid1 = Apid1; + aPid2 = Apid2; + dPid1 = Dpid1; + dPid2 = Dpid2; + + // Avoid noise while switching: + + if (fd_video >= 0 && fd_audio >= 0) { + CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); + CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); + CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); + } + + // If this card can't receive this channel, we must not actually switch + // the channel here, because that would irritate the driver when we + // start replaying in Transfer Mode immediately after switching the channel: + bool NeedsTransferMode = (this == PrimaryDvbApi && Ca && Ca != Index() + 1); + + if (!NeedsTransferMode) { + + // Turn off current PIDs: + + SetVpid( 0x1FFF, DMX_OUT_DECODER); + SetApid1(0x1FFF, DMX_OUT_DECODER); + SetApid2(0x1FFF, DMX_OUT_DECODER); + SetDpid1(0x1FFF, DMX_OUT_DECODER); + SetDpid2(0x1FFF, DMX_OUT_DECODER); + SetTpid( 0x1FFF, DMX_OUT_DECODER); + + bool ChannelSynced = false; + + if (fd_qpskfe >= 0 && fd_sec >= 0) { // DVB-S + + // Frequency offsets: + + unsigned int freq = FrequencyMHz; + int tone = SEC_TONE_OFF; + + if (freq < (unsigned int)Setup.LnbSLOF) { freq -= Setup.LnbFrequLo; - front.ttk = 0; + tone = SEC_TONE_OFF; } else { freq -= Setup.LnbFrequHi; - front.ttk = 1; + tone = SEC_TONE_ON; + } + + qpskParameters qpsk; + qpsk.iFrequency = freq * 1000UL; + qpsk.SymbolRate = Srate * 1000UL; + qpsk.FEC_inner = FEC_AUTO; + + int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; + + // DiseqC: + + secCommand scmd; + scmd.type = 0; + scmd.u.diseqc.addr = 0x10; + scmd.u.diseqc.cmd = 0x38; + scmd.u.diseqc.numParams = 1; + scmd.u.diseqc.params[0] = 0xF0 | ((Diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0); + + secCmdSequence scmds; + scmds.voltage = volt; + scmds.miniCommand = SEC_MINI_NONE; + scmds.continuousTone = tone; + scmds.numCommands = Setup.DiSEqC ? 1 : 0; + scmds.commands = &scmd; + + CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); + + // Tuning: + + CHECK(ioctl(fd_qpskfe, QPSK_TUNE, &qpsk)); + + // Wait for channel sync: + + if (cFile::FileReady(fd_qpskfe, 5000)) { + qpskEvent event; + int res = ioctl(fd_qpskfe, QPSK_GET_EVENT, &event); + if (res >= 0) + ChannelSynced = event.type == FE_COMPLETION_EV; + else + esyslog(LOG_ERR, "ERROR %d in qpsk get event", res); } + else + esyslog(LOG_ERR, "ERROR: timeout while tuning\n"); } - front.channel_flags = Ca ? DVB_CHANNEL_CA : DVB_CHANNEL_FTA; - front.pnr = Pnr; - front.freq = freq * 1000000UL; - front.diseqc = Diseqc; - front.srate = Srate * 1000; - front.volt = (Polarization == 'v' || Polarization == 'V') ? 0 : 1; - front.video_pid = Vpid; - front.audio_pid = Apid; - front.tt_pid = Tpid; - front.fec = 8; - front.AFC = 1; - front.qam = 2; - ioctl(videoDev, VIDIOCSFRONTEND, &front); - if (front.sync & 0x1F == 0x1F) { - if (this == PrimaryDvbApi && siProcessor) - siProcessor->SetCurrentServiceID(Pnr); - currentChannel = ChannelNumber; - // If this DVB card can't receive this channel, let's see if we can - // use the card that actually can receive it and transfer data from there: - if (this == PrimaryDvbApi && Ca && Ca != Index() + 1) { - cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); - if (CaDvbApi) { - if (!CaDvbApi->Recording()) { - if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Tpid, Ca, Pnr)) - transferringFromDvbApi = CaDvbApi->StartTransfer(videoDev); - } + else if (fd_qamfe >= 0) { // DVB-C + + // Frequency and symbol rate: + + qamParameters qam; + qam.Frequency = FrequencyMHz * 1000000UL; + qam.SymbolRate = Srate * 1000UL; + qam.FEC_inner = FEC_AUTO; + qam.QAM = QAM_64; + + // Tuning: + + CHECK(ioctl(fd_qamfe, QAM_TUNE, &qam)); + + // Wait for channel sync: + + if (cFile::FileReady(fd_qamfe, 5000)) { + qamEvent event; + int res = ioctl(fd_qamfe, QAM_GET_EVENT, &event); + if (res >= 0) + ChannelSynced = event.type == FE_COMPLETION_EV; + else + esyslog(LOG_ERR, "ERROR %d in qam get event", res); + } + else + esyslog(LOG_ERR, "ERROR: timeout while tuning\n"); + } + else { + esyslog(LOG_ERR, "ERROR: attempt to set channel without DVB-S or DVB-C device"); + return false; + } + + if (!ChannelSynced) { + esyslog(LOG_ERR, "ERROR: channel %d not sync'ed!", ChannelNumber); + if (this == PrimaryDvbApi) + cThread::RaisePanic(); + return false; + } + + // PID settings: + + if (!SetPids(false)) { + esyslog(LOG_ERR, "ERROR: failed to set PIDs for channel %d", ChannelNumber); + return false; + } + SetTpid(Tpid, DMX_OUT_DECODER); + if (fd_audio >= 0) + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); + } + + if (this == PrimaryDvbApi && siProcessor) + siProcessor->SetCurrentServiceID(Pnr); + + // If this DVB card can't receive this channel, let's see if we can + // use the card that actually can receive it and transfer data from there: + + if (NeedsTransferMode) { + cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); + if (CaDvbApi) { + if (!CaDvbApi->Recording()) { + if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) { + SetModeReplay(); + transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video); } } - return true; } - esyslog(LOG_ERR, "ERROR: channel %d not sync'ed (front.sync=%X)!", ChannelNumber, front.sync); } - return false; + + if (fd_video >= 0 && fd_audio >= 0) { + CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); + } + + return true; } bool cDvbApi::Transferring(void) @@ -2101,7 +2298,7 @@ bool cDvbApi::Transferring(void) cDvbApi *cDvbApi::StartTransfer(int TransferToVideoDev) { StopTransfer(); - transferBuffer = new cTransferBuffer(videoDev, TransferToVideoDev); + transferBuffer = new cTransferBuffer(this, TransferToVideoDev, vPid, aPid1); return this; } @@ -2110,7 +2307,6 @@ void cDvbApi::StopTransfer(void) if (transferBuffer) { delete transferBuffer; transferBuffer = NULL; - SetPlayMode(videoDev, VID_PLAY_RESET); } if (transferringFromDvbApi) { transferringFromDvbApi->StopTransfer(); @@ -2143,37 +2339,36 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) esyslog(LOG_ERR, "ERROR: StartRecord() called while recording - ignored!"); return false; } - if (videoDev >= 0) { - StopTransfer(); + StopTransfer(); - StopReplay(); // TODO: remove this if the driver is able to do record and replay at the same time + StopReplay(); // TODO: remove this if the driver is able to do record and replay at the same time - // Check FileName: + // Check FileName: - if (!FileName) { - esyslog(LOG_ERR, "ERROR: StartRecord: file name is (null)"); - return false; - } - isyslog(LOG_INFO, "record %s", FileName); + if (!FileName) { + esyslog(LOG_ERR, "ERROR: StartRecord: file name is (null)"); + return false; + } + isyslog(LOG_INFO, "record %s", FileName); - // Create directories if necessary: + // Create directories if necessary: - if (!MakeDirs(FileName, true)) - return false; + if (!MakeDirs(FileName, true)) + return false; - // Create recording buffer: + // Create recording buffer: - recordBuffer = new cRecordBuffer(&videoDev, FileName); + recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1, aPid2, dPid1, dPid2); - if (recordBuffer) { - ca = Ca; - priority = Priority; - return true; - } - else - esyslog(LOG_ERR, "ERROR: can't allocate recording buffer"); + if (recordBuffer) { + ca = Ca; + priority = Priority; + return true; } + else + esyslog(LOG_ERR, "ERROR: can't allocate recording buffer"); + return false; } @@ -2195,7 +2390,7 @@ bool cDvbApi::StartReplay(const char *FileName) } StopTransfer(); StopReplay(); - if (videoDev >= 0) { + if (fd_video >= 0 && fd_audio >= 0) { // Check FileName: @@ -2207,7 +2402,7 @@ bool cDvbApi::StartReplay(const char *FileName) // Create replay buffer: - replayBuffer = new cReplayBuffer(&videoDev, FileName); + replayBuffer = new cReplayBuffer(this, fd_video, fd_audio, FileName); if (replayBuffer) return true; else @@ -2221,6 +2416,12 @@ void cDvbApi::StopReplay(void) if (replayBuffer) { delete replayBuffer; replayBuffer = NULL; + if (this == PrimaryDvbApi) { + // let's explicitly switch the channel back in case it was in Transfer Mode: + cChannel *Channel = Channels.GetByNumber(currentChannel); + if (Channel) + Channel->Switch(this, false); + } } } @@ -2276,6 +2477,38 @@ void cDvbApi::Goto(int Position, bool Still) replayBuffer->Goto(Position, Still); } +bool cDvbApi::CanToggleAudioTrack(void) +{ + return replayBuffer ? replayBuffer->CanToggleAudioTrack() : (aPid1 && aPid2 && aPid1 != aPid2); +} + +bool cDvbApi::ToggleAudioTrack(void) +{ + if (replayBuffer) { + replayBuffer->ToggleAudioTrack(); + return true; + } + else { + int a = aPid2; + aPid2 = aPid1; + aPid1 = a; + if (transferringFromDvbApi) + return transferringFromDvbApi->ToggleAudioTrack(); + else { + if (transferBuffer) + transferBuffer->SetAudioPid(aPid1); + return SetPids(transferBuffer != NULL); + } + } + return false; +} + +void cDvbApi::SetAudioCommand(const char *Command) +{ + delete audioCommand; + audioCommand = strdup(Command); +} + // --- cEITScanner ----------------------------------------------------------- cEITScanner::cEITScanner(void) @@ -2318,7 +2551,7 @@ void cEITScanner::Process(void) time_t now = time(NULL); if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) { for (int i = 0; i < cDvbApi::NumDvbApis; i++) { - cDvbApi *DvbApi = cDvbApi::GetDvbApi(i, 0); + cDvbApi *DvbApi = cDvbApi::GetDvbApi(i + 1, MAXPRIORITY); if (DvbApi) { if (DvbApi != cDvbApi::PrimaryDvbApi || (cDvbApi::NumDvbApis == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) { if (!(DvbApi->Recording() || DvbApi->Replaying() || DvbApi->Transferring())) { diff --git a/dvbapi.h b/dvbapi.h index de646121e..2203d799e 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,22 +4,28 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.35 2001/02/11 10:41:10 kls Exp $ + * $Id: dvbapi.h 1.42 2001/07/27 11:40:38 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; - #if defined(DEBUG_OSD) || defined(REMOTE_KBD) #include #endif +#include // FIXME: this is apparently necessary for the ost/... header files + // FIXME: shouldn't every header file include ALL the other header + // FIXME: files it depends on? The sequence in which header files + // FIXME: are included here should not matter - and it should NOT + // FIXME: be necessary to include here! +#include +#include +#include +#include +#include +#include +#include #include -#include #include "dvbosd.h" #include "eit.h" #include "thread.h" @@ -30,9 +36,6 @@ typedef struct CRect { signed short x, y, width, height; }; -#define MenuLines 15 -#define MenuColumns 40 - const char *IndexToHMSF(int Index, bool WithFrame = false); // Converts the given index to a string, optionally containing the frame number. int HMSFToIndex(const char *HMSF); @@ -55,9 +58,22 @@ class cVideoCutter { }; class cDvbApi { + friend class cRecordBuffer; + friend class cReplayBuffer; + friend class cTransferBuffer; private: int videoDev; - cDvbApi(const char *VideoFileName, const char *VbiFileName); + int fd_osd, fd_qpskfe, fd_qamfe, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxd1, fd_demuxd2, fd_demuxv, fd_demuxt; + int vPid, aPid1, aPid2, dPid1, dPid2; + bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output); + bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO, Vpid, Output); } + bool SetApid1(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa1, DMX_PES_AUDIO, Apid, Output); } + bool SetApid2(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa2, DMX_PES_OTHER, Apid, Output); } + bool SetDpid1(int Dpid, dmxOutput_t Output) { return SetPid(fd_demuxd1, DMX_PES_OTHER, Dpid, Output); } + bool SetDpid2(int Dpid, dmxOutput_t Output) { return SetPid(fd_demuxd2, DMX_PES_OTHER, Dpid, Output); } + bool SetTpid(int Tpid, dmxOutput_t Output) { return SetPid(fd_demuxt, DMX_PES_TELETEXT, Tpid, Output); } + bool SetPids(bool ForRecording); + cDvbApi(int n); public: ~cDvbApi(); @@ -86,8 +102,10 @@ class cDvbApi { // recording and stop recording if necessary. int Index(void); // Returns the index of this DvbApi. + static bool Probe(const char *FileName); + // Probes for existing DVB devices. static bool Init(void); - // Initializes the DVB API and probes for existing DVB devices. + // Initializes the DVB API. // Must be called before accessing any DVB functions. static void Cleanup(void); // Closes down all DVB devices. @@ -138,7 +156,6 @@ class cDvbApi { cDvbOsd *osd; #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: void Open(int w, int h); void Close(void); @@ -154,12 +171,16 @@ class cDvbApi { void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground); void Flush(void); + // Video format facilities: + + void SetVideoFormat(videoFormat_t Format); + // Channel facilities private: int currentChannel; public: - bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr); + bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr); static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } int Channel(void) { return currentChannel; } @@ -184,12 +205,15 @@ class cDvbApi { cReplayBuffer *replayBuffer; int ca; int priority; -protected: int Ca(void) { return ca; } // Returns the ca of the current recording session (0..MAXDVBAPI). int Priority(void) { return priority; } - // Returns the priority of the current recording session (0..99), + // Returns the priority of the current recording session (0..MAXPRIORITY), // or -1 if no recording is currently active. + int SetModeRecord(void); + // Initiates recording mode and returns the file handle to read from. + void SetModeReplay(void); + void SetModeNormal(bool FromRecording); public: int SecondsToFrames(int Seconds); // Returns the number of frames corresponding to the given number of seconds. @@ -238,7 +262,24 @@ class cDvbApi { // nearest I-frame. void Goto(int Index, bool Still = false); // Positions to the given index and displays that frame as a still picture - // if Still is true. + // if Still is true. + + // Audio track facilities + +public: + bool CanToggleAudioTrack(void); + // Returns true if we are currently replaying and this recording has two + // audio tracks, or if the current channel has two audio PIDs. + bool ToggleAudioTrack(void); + // Toggles the audio track if possible. + + // Dolby Digital audio facilities + +private: + static char *audioCommand; +public: + static void SetAudioCommand(const char *Command); + static const char *AudioCommand(void) { return audioCommand; } }; class cEITScanner { diff --git a/dvbosd.c b/dvbosd.c index 395ad32ed..90ac067dc 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.7 2000/12/09 11:13:00 kls Exp $ + * $Id: dvbosd.c 1.10 2001/07/24 16:25:34 kls Exp $ */ #include "dvbosd.h" @@ -14,12 +14,83 @@ #include #include "tools.h" +// --- cPalette -------------------------------------------------------------- + +cPalette::cPalette(int Bpp) +{ + maxColors = 1 << Bpp; + numColors = 0; + full = false; +} + +int cPalette::Index(eDvbColor Color) +{ + for (int i = 0; i < numColors; i++) { + if (color[i] == Color) { + used[i] = true; + return i; + } + } + if (!full) { + if (numColors < maxColors) { + color[numColors++] = Color; + used[numColors - 1] = true; + fetched[numColors - 1] = false; + return numColors - 1; + } + for (int i = maxColors; --i >= 0; ) { + if (!used[i]) { + color[i] = Color; + used[i] = true; + fetched[i] = false; + return i; + } + } + esyslog(LOG_ERR, "ERROR: too many different colors used in palette"); + full = true; + } + return 0; +} + +void cPalette::Reset(void) +{ + for (int i = 0; i < numColors; i++) + used[i] = false; + full = false; +} + +const eDvbColor *cPalette::Colors(int &FirstColor, int &LastColor) +{ + for (FirstColor = 0; FirstColor < numColors; FirstColor++) { + if (!fetched[FirstColor]) { + for (LastColor = FirstColor; LastColor < numColors && !fetched[LastColor]; LastColor++) + fetched[LastColor] = true; + LastColor--; // the loop ended one past the last one! + return &color[FirstColor]; + } + } + return NULL; +} + +void cPalette::Take(const cPalette &Palette, tIndexes *Indexes) +{ + for (int i = 0; i < Palette.numColors; i++) { + if (Palette.used[i]) { + int n = Index(Palette.color[i]); + if (Indexes) + (*Indexes)[i] = n; + } + } +} + // --- cBitmap --------------------------------------------------------------- -cBitmap::cBitmap(int Width, int Height) +cBitmap::cBitmap(int Width, int Height, int Bpp, bool ClearWithBackground) +:cPalette(Bpp) { width = Width; height = Height; + clearWithBackground = ClearWithBackground; bitmap = NULL; fontType = fontOsd; font = NULL; @@ -27,7 +98,7 @@ cBitmap::cBitmap(int Width, int Height) bitmap = new char[width * height]; if (bitmap) { Clean(); - memset(bitmap, clrTransparent, width * height); + memset(bitmap, 0x00, width * height); SetFont(fontOsd); } else @@ -54,9 +125,38 @@ eDvbFont cBitmap::SetFont(eDvbFont Font) return oldFont; } -bool cBitmap::Dirty(void) +bool cBitmap::Dirty(int &x1, int &y1, int &x2, int &y2) { - return dirtyX2 >= 0; + if (dirtyX2 >= 0) { + //XXX Workaround: apparently the bitmap sent to the driver always has to be a multiple + //XXX of 8 bits wide, and (dx * dy) also has to be a multiple of 8. + //TODO Fix driver (should be able to handle any size bitmaps!) + while ((dirtyX1 > 0 || dirtyX2 < width - 1) && ((dirtyX2 - dirtyX1) & 7) != 7) { + if (dirtyX2 < width - 1) + dirtyX2++; + else if (dirtyX1 > 0) + dirtyX1--; + } + //XXX "... / 2" <==> Bpp??? + while ((dirtyY1 > 0 || dirtyY2 < height - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { + if (dirtyY2 < height - 1) + dirtyY2++; + else if (dirtyY1 > 0) + dirtyY1--; + } + while ((dirtyX1 > 0 || dirtyX2 < width - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { + if (dirtyX2 < width - 1) + dirtyX2++; + else if (dirtyX1 > 0) + dirtyX1--; + } + x1 = dirtyX1; + y1 = dirtyY1; + x2 = dirtyX2; + y2 = dirtyY2; + return true; + } + return false; } void cBitmap::Clean(void) @@ -67,12 +167,12 @@ void cBitmap::Clean(void) dirtyY2 = -1; } -void cBitmap::SetPixel(int x, int y, eDvbColor Color) +void cBitmap::SetIndex(int x, int y, char Index) { if (bitmap) { if (0 <= x && x < width && 0 <= y && y < height) { - if (bitmap[width * y + x] != Color) { - bitmap[width * y + x] = Color; + if (bitmap[width * y + x] != Index) { + bitmap[width * y + x] = Index; if (dirtyX1 > x) dirtyX1 = x; if (dirtyY1 > y) dirtyY1 = y; if (dirtyX2 < x) dirtyX2 = x; @@ -82,12 +182,19 @@ void cBitmap::SetPixel(int x, int y, eDvbColor Color) } } +void cBitmap::SetPixel(int x, int y, eDvbColor Color) +{ + SetIndex(x, y, Index(Color)); +} + void cBitmap::SetBitmap(int x, int y, const cBitmap &Bitmap) { if (bitmap && Bitmap.bitmap) { + tIndexes Indexes; + Take(Bitmap, &Indexes); for (int ix = 0; ix < Bitmap.width; ix++) { for (int iy = 0; iy < Bitmap.height; iy++) - SetPixel(x + ix, y + iy, eDvbColor(Bitmap.bitmap[Bitmap.width * iy + ix])); + SetIndex(x + ix, y + iy, Indexes[Bitmap.bitmap[Bitmap.width * iy + ix]]); } } } @@ -105,6 +212,8 @@ int cBitmap::Width(const char *s) void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) { if (bitmap) { + char fg = Index(ColorFg); + char bg = Index(ColorBg); int h = font->Height(s); while (s && *s) { const cFont::tCharData *CharData = font->CharData(*s++); @@ -113,7 +222,7 @@ void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor Col for (int row = 0; row < h; row++) { cFont::tPixelData PixelData = CharData->lines[row]; for (int col = CharData->width; col-- > 0; ) { - SetPixel(x + col, y + row, (PixelData & 1) ? ColorFg : ColorBg); + SetIndex(x + col, y + row, (PixelData & 1) ? fg : bg); PixelData >>= 1; } } @@ -125,39 +234,109 @@ void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor Col void cBitmap::Fill(int x1, int y1, int x2, int y2, eDvbColor Color) { if (bitmap) { + char c = Index(Color); for (int y = y1; y <= y2; y++) for (int x = x1; x <= x2; x++) - SetPixel(x, y, Color); + SetIndex(x, y, c); } } void cBitmap::Clear(void) { - Fill(0, 0, width - 1, height - 1, clrBackground); + Reset(); + if (clearWithBackground) + Fill(0, 0, width - 1, height - 1, clrBackground); +} + +const char *cBitmap::Data(int x, int y) +{ + return &bitmap[y * width + x]; +} + +// --- cWindow --------------------------------------------------------------- + +class cWindow : public cBitmap { +private: + int x0, y0; + bool shown; +public: + cWindow(int x, int y, int w, int h, int Bpp, bool ClearWithBackground = true); + int X0(void) { return x0; } + int Y0(void) { return y0; } + bool Shown(void) { bool s = shown; shown = true; return s; } + bool Contains(int x, int y); + void Fill(int x1, int y1, int x2, int y2, eDvbColor Color); + void SetBitmap(int x, int y, const cBitmap &Bitmap); + void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); + const char *Data(int x, int y); + }; + +cWindow::cWindow(int x, int y, int w, int h, int Bpp, bool ClearWithBackground) +:cBitmap(w, h, Bpp, ClearWithBackground) +{ + x0 = x; + y0 = y; + shown = false; +} + +bool cWindow::Contains(int x, int y) +{ + x -= x0; + y -= y0; + return x >= 0 && y >= 0 && x < width && y < height; +} + +void cWindow::Fill(int x1, int y1, int x2, int y2, eDvbColor Color) +{ + cBitmap::Fill(x1 - x0, y1 - y0, x2 - x0, y2 - y0, Color); +} + +void cWindow::SetBitmap(int x, int y, const cBitmap &Bitmap) +{ + cBitmap::SetBitmap(x - x0, y - y0, Bitmap); +} + +void cWindow::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) +{ + cBitmap::Text(x - x0, y - y0, s, ColorFg, ColorBg); +} + +const char *cWindow::Data(int x, int y) +{ + return cBitmap::Data(x, y); } // --- cDvbOsd --------------------------------------------------------------- -cDvbOsd::cDvbOsd(int VideoDev, int x1, int y1, int x2, int y2, int Bpp) -:cBitmap(x2 - x1 + 1, y2 - y1 + 1) +cDvbOsd::cDvbOsd(int VideoDev, int x, int y, int w, int h, int Bpp) { videoDev = VideoDev; - if (videoDev >= 0) - Cmd(OSD_Open, Bpp, x1, y1, x2, y2); + numWindows = 0; + x0 = x; + y0 = y; + if (videoDev >= 0) { + if (w > 0 && h > 0) + Create(0, 0, w, h, Bpp); + } else esyslog(LOG_ERR, "ERROR: illegal video device handle (%d)!", videoDev); } cDvbOsd::~cDvbOsd() { - if (videoDev >= 0) - Cmd(OSD_Close); + if (videoDev >= 0) { + while (numWindows > 0) { + Cmd(OSD_SetWindow, 0, numWindows--); + Cmd(OSD_Close); + delete window[numWindows]; + } + } } void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) { if (videoDev >= 0) { - struct drawcmd dc; + osd_cmd_t dc; dc.cmd = cmd; dc.color = color; dc.x0 = x0; @@ -169,41 +348,120 @@ void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co sigset_t set, oldset; sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); - ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc); - usleep(10); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places - // XXX and sometimes the OSD was no longer displayed). - // XXX Increase the value if the problem still persists on your particular system. - // TODO Check if this is still necessary with driver versions after 0.7. + ioctl(videoDev, OSD_SEND_CMD, &dc); + usleep(5000); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places + // XXX and sometimes the OSD was no longer displayed). + // XXX Increase the value if the problem still persists on your particular system. + // TODO Check if this is still necessary with driver versions after 0.7. sigprocmask(SIG_SETMASK, &oldset, NULL); } } -void cDvbOsd::Flush(void) +bool cDvbOsd::Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground, eDvbColor Color0, eDvbColor Color1, eDvbColor Color2, eDvbColor Color3) { - if (Dirty()) { - //XXX Workaround: apparently the bitmap sent to the driver always has to be a multiple - //XXX of 8 bits wide, and (dx * dy) also has to be a multiple of 8. - //TODO Fix driver (should be able to handle any size bitmaps!) - while ((dirtyX1 > 0 || dirtyX2 < width - 1) && ((dirtyX2 - dirtyX1) & 7) != 7) { - if (dirtyX2 < width - 1) - dirtyX2++; - else if (dirtyX1 > 0) - dirtyX1--; - } - while ((dirtyY1 > 0 || dirtyY2 < height - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { - if (dirtyY2 < height - 1) - dirtyY2++; - else if (dirtyY1 > 0) - dirtyY1--; + /* TODO XXX + - check that no two windows overlap + */ + if (numWindows < MAXNUMWINDOWS) { + if (x >= 0 && y >= 0 && w > 0 && h > 0 && (Bpp == 1 || Bpp == 2 || Bpp == 4 || Bpp == 8)) { + if ((w & 0x03) != 0) { + w += 4 - (w & 0x03); + esyslog(LOG_ERR, "ERROR: OSD window width must be a multiple of 4 - increasing to %d", w); } - while ((dirtyX1 > 0 || dirtyX2 < width - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { - if (dirtyX2 < width - 1) - dirtyX2++; - else if (dirtyX1 > 0) - dirtyX1--; + cWindow *win = new cWindow(x, y, w, h, Bpp, ClearWithBackground); + if (Color0 != clrTransparent) { + win->Index(Color0); + win->Index(Color1); + win->Index(Color2); + win->Index(Color3); + win->Reset(); } - Cmd(OSD_SetBlock, width, dirtyX1, dirtyY1, dirtyX2, dirtyY2, &bitmap[dirtyY1 * width + dirtyX1]); - Clean(); + window[numWindows++] = win; + Cmd(OSD_SetWindow, 0, numWindows); + Cmd(OSD_Open, Bpp, x0 + x, y0 + y, x0 + x + w - 1, y0 + y + h - 1, (void *)1); // initially hidden! + } + else + esyslog(LOG_ERR, "ERROR: illegal OSD parameters"); } + else + esyslog(LOG_ERR, "ERROR: too many OSD windows"); + return false; +} + +cWindow *cDvbOsd::GetWindow(int x, int y) +{ + for (int i = 0; i < numWindows; i++) { + if (window[i]->Contains(x, y)) + return window[i]; + } + return NULL; +} + +void cDvbOsd::Flush(void) +{ + for (int i = 0; i < numWindows; i++) { + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; + if (window[i]->Dirty(x1, y1, x2, y2)) { + Cmd(OSD_SetWindow, 0, i + 1); + int FirstColor = 0, LastColor = 0; + const eDvbColor *pal; + while ((pal = window[i]->Colors(FirstColor, LastColor)) != NULL) + Cmd(OSD_SetPalette, FirstColor, LastColor, 0, 0, 0, pal); + Cmd(OSD_SetBlock, window[i]->Width(), x1, y1, x2, y2, window[i]->Data(x1, y1)); + window[i]->Clean(); + } + } + // Showing the windows in a separate loop to avoid seeing them come up one after another + for (int i = 0; i < numWindows; i++) { + if (!window[i]->Shown()) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_MoveWindow, 0, x0 + window[i]->X0(), y0 + window[i]->Y0()); + } + } +} + +void cDvbOsd::Clear(void) +{ + for (int i = 0; i < numWindows; i++) + window[i]->Clear(); +} + +void cDvbOsd::Fill(int x1, int y1, int x2, int y2, eDvbColor Color) +{ + cWindow *w = GetWindow(x1, y1); + if (w) + w->Fill(x1, y1, x2, y2, Color); +} + +void cDvbOsd::SetBitmap(int x, int y, const cBitmap &Bitmap) +{ + cWindow *w = GetWindow(x, y); + if (w) + w->SetBitmap(x, y, Bitmap); +} + +int cDvbOsd::Width(unsigned char c) +{ + return numWindows ? window[0]->Width(c) : 0; +} + +int cDvbOsd::Width(const char *s) +{ + return numWindows ? window[0]->Width(s) : 0; +} + +eDvbFont cDvbOsd::SetFont(eDvbFont Font) +{ + eDvbFont oldFont = Font; + for (int i = 0; i < numWindows; i++) + oldFont = window[i]->SetFont(Font); + return oldFont; +} + +void cDvbOsd::Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground) +{ + cWindow *w = GetWindow(x, y); + if (w) + w->Text(x, y, s, ColorFg, ColorBg); } diff --git a/dvbosd.h b/dvbosd.h index eefdb621e..5039a9159 100644 --- a/dvbosd.h +++ b/dvbosd.h @@ -4,35 +4,26 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.h 1.5 2000/12/09 10:32:47 kls Exp $ + * $Id: dvbosd.h 1.8 2001/07/28 16:22:32 kls Exp $ */ #ifndef __DVBOSD_H #define __DVBOSD_H -// FIXME: these should be defined in ../DVB/driver/dvb.h!!! -typedef unsigned int __u32; -typedef unsigned short __u16; -typedef unsigned char __u8; - #if defined(DEBUG_OSD) || defined(REMOTE_KBD) #include #endif +#include #include -#include #include "font.h" -enum eDvbColor { -#ifndef DEBUG_OSD - clrTransparent, -#endif - clrBackground, +#define MAXNUMCOLORS 16 + +enum eDvbColor { #ifdef DEBUG_OSD + clrBackground, clrTransparent = clrBackground, clrBlack = clrBackground, -#else - clrBlack, -#endif clrRed, clrGreen, clrYellow, @@ -40,39 +31,88 @@ enum eDvbColor { clrMagenta, clrCyan, clrWhite, +#else + clrTransparent = 0x00000000, + clrBackground = 0x7F000000, // 50% gray + clrBlack = 0xFF000000, + clrRed = 0xFF1414FC, + clrGreen = 0xFF24FC24, + clrYellow = 0xFF24C0FC, + clrMagenta = 0xFFFC00B0, + clrBlue = 0xFFFC0000, + clrCyan = 0xFFFCFC00, + clrWhite = 0xFFFCFCFC, +#endif + }; + +class cPalette { +private: + eDvbColor color[MAXNUMCOLORS]; + int maxColors, numColors; + bool used[MAXNUMCOLORS]; + bool fetched[MAXNUMCOLORS]; + bool full; +protected: + typedef unsigned char tIndexes[MAXNUMCOLORS]; +public: + cPalette(int Bpp); + int Index(eDvbColor Color); + void Reset(void); + const eDvbColor *Colors(int &FirstColor, int &LastColor); + void Take(const cPalette &Palette, tIndexes *Indexes = NULL); }; -class cBitmap { +class cBitmap : public cPalette { private: cFont *font; eDvbFont fontType; + void SetIndex(int x, int y, char Index); + char *bitmap; + bool clearWithBackground; protected: int width, height; - char *bitmap; int dirtyX1, dirtyY1, dirtyX2, dirtyY2; - void Clean(void); public: - cBitmap(int Width, int Height); + cBitmap(int Width, int Height, int Bpp, bool ClearWithBackground = true); virtual ~cBitmap(); eDvbFont SetFont(eDvbFont Font); - bool Dirty(void); + bool Dirty(int &x1, int &y1, int &x2, int &y2); void SetPixel(int x, int y, eDvbColor Color); void SetBitmap(int x, int y, const cBitmap &Bitmap); + int Width(void) { return width; } int Width(unsigned char c); int Width(const char *s); void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); void Fill(int x1, int y1, int x2, int y2, eDvbColor Color); + void Clean(void); void Clear(void); + const char *Data(int x, int y); }; -class cDvbOsd : public cBitmap { +#define MAXNUMWINDOWS 7 // OSD windows are counted 1...7 + +class cWindow; + +class cDvbOsd { private: int videoDev; + int numWindows; + int x0, y0; + cWindow *window[MAXNUMWINDOWS]; void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL); + cWindow *GetWindow(int x, int y); public: - cDvbOsd(int VideoDev, int x1, int y1, int x2, int y2, int Bpp); + cDvbOsd(int VideoDev, int x, int y, int w = -1, int h = -1, int Bpp = -1); ~cDvbOsd(); + bool Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground = true, eDvbColor Color0 = clrTransparent, eDvbColor Color1 = clrTransparent, eDvbColor Color2 = clrTransparent, eDvbColor Color3 = clrTransparent); void Flush(void); + void Clear(void); + void Fill(int x1, int y1, int x2, int y2, eDvbColor Color); + void SetBitmap(int x, int y, const cBitmap &Bitmap); + int Width(unsigned char c); + int Width(const char *s); + eDvbFont SetFont(eDvbFont Font); + void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); }; #endif //__DVBOSD_H diff --git a/eit.c b/eit.c index 6cbe504d3..3de610209 100644 --- a/eit.c +++ b/eit.c @@ -13,17 +13,16 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.15 2001/04/01 15:36:09 kls Exp $ + * $Id: eit.c 1.16 2001/05/26 10:58:01 kls Exp $ ***************************************************************************/ #include "eit.h" #include -#include -#include #include #include #include #include +#include #include #include #include @@ -1108,31 +1107,43 @@ cMutex cSIProcessor::schedulesMutex; /** */ cSIProcessor::cSIProcessor(const char *FileName) { + fileName = strdup(FileName); masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master' useTStime = false; filters = NULL; - if ((fsvbi = open(FileName, O_RDONLY)) >= 0) - { - if (!numSIProcessors++) // the first one creates it - schedules = new cSchedules; - filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER)); - } - else - LOG_ERROR_STR(FileName); + if (!numSIProcessors++) // the first one creates it + schedules = new cSchedules; + filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER)); + SetStatus(true); + Start(); } cSIProcessor::~cSIProcessor() { - if (fsvbi >= 0) + active = false; + Cancel(3); + ShutDownFilters(); + delete filters; + if (!--numSIProcessors) // the last one deletes it + delete schedules; + delete fileName; +} + +void cSIProcessor::SetStatus(bool On) +{ + LOCK_THREAD; + schedulesMutex.Lock(); + ShutDownFilters(); + if (On) { - active = false; - Cancel(3); - ShutDownFilters(); - delete filters; - if (!--numSIProcessors) // the last one deletes it - delete schedules; - close(fsvbi); + AddFilter(0x14, 0x70); // TDT + AddFilter(0x14, 0x73); // TOT + AddFilter(0x12, 0x4e); // event info, actual TS, present/following + AddFilter(0x12, 0x4f); // event info, other TS, present/following + AddFilter(0x12, 0x50); // event info, actual TS, schedule + AddFilter(0x12, 0x60); // event info, other TS, schedule } + schedulesMutex.Unlock(); } /** use the vbi device to parse all relevant SI @@ -1140,19 +1151,10 @@ information and let the classes corresponding to the tables write their information to the disk */ void cSIProcessor::Action() { - if (fsvbi < 0) { - esyslog(LOG_ERR, "cSIProcessor::Action() called without open file - returning"); - return; - } - dsyslog(LOG_INFO, "EIT processing thread started (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : ""); - unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) - unsigned int seclen; - unsigned int pid; time_t lastCleanup = time(NULL); time_t lastDump = time(NULL); - struct pollfd pfd; active = true; @@ -1187,100 +1189,123 @@ void cSIProcessor::Action() } } - /* wait data become ready from the bitfilter */ - pfd.fd = fsvbi; - pfd.events = POLLIN; - if(poll(&pfd, 1, 1000) != 0) /* timeout is 5 secs */ + // set up pfd structures for all active filter + pollfd pfd[MAX_FILTERS]; + int NumUsedFilters = 0; + for (int a = 0; a < MAX_FILTERS ; a++) { - // fprintf(stderr, "\n"); - /* read section */ - read(fsvbi, buf, 8); - seclen = (buf[6] << 8) | buf[7]; - pid = (buf[4] << 8) | buf[5]; - read(fsvbi, buf, seclen); - - //dsyslog(LOG_INFO, "Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen); + if (filters[a].inuse) + { + pfd[NumUsedFilters].fd = filters[a].handle; + pfd[NumUsedFilters].events = POLLIN; + NumUsedFilters++; + } + } - switch (pid) + // wait until data becomes ready from the bitfilter + if (poll(pfd, NumUsedFilters, 1000) != 0) + { + for (int a = 0; a < NumUsedFilters ; a++) { - case 0x14: - if (buf[0] == 0x70) + if (pfd[a].revents & POLLIN) + { + /* read section */ + unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) + if (read(filters[a].handle, buf, 3) == 3) { - if (useTStime) + int seclen = ((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF); + int pid = filters[a].pid; + int n = read(filters[a].handle, buf + 3, seclen); + if (n == seclen) { - cTDT ctdt((tdt_t *)buf); - ctdt.SetSystemTime(); + seclen += 3; + //dsyslog(LOG_INFO, "Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen); + switch (pid) + { + case 0x14: + if (buf[0] == 0x70) + { + if (useTStime) + { + cTDT ctdt((tdt_t *)buf); + ctdt.SetSystemTime(); + } + } + /*XXX this comes pretty often: + else + dsyslog(LOG_INFO, "Time packet was not 0x70 but 0x%02x\n", (int)buf[0]); + XXX*/ + break; + + case 0x12: + if (buf[0] != 0x72) + { + LOCK_THREAD; + + schedulesMutex.Lock(); + cEIT ceit(buf, seclen, schedules); + ceit.ProcessEIT(); + schedulesMutex.Unlock(); + } + else + dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); + break; + + default: + break; + } } + else + dsyslog(LOG_INFO, "read incomplete section - seclen = %d, n = %d", seclen, n); } - /*XXX this comes pretty often: - else - dsyslog(LOG_INFO, "Time packet was not 0x70 but 0x%02x\n", (int)buf[0]); - XXX*/ - break; - - case 0x12: - if (buf[0] != 0x72) - { - LOCK_THREAD; - - schedulesMutex.Lock(); - cEIT ceit(buf, seclen, schedules); - ceit.ProcessEIT(); - schedulesMutex.Unlock(); - } - else - dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); - break; - - default: - break; + } } } - else - { - LOCK_THREAD; - - //XXX this comes pretty often - //isyslog(LOG_INFO, "Received timeout from poll, refreshing filters\n"); - RefreshFilters(); - } -// WakeUp(); } + + dsyslog(LOG_INFO, "EIT processing thread ended (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : ""); } /** Add a filter with packet identifier pid and table identifer tid */ bool cSIProcessor::AddFilter(u_char pid, u_char tid) { - if (fsvbi < 0) - return false; - - int section = ((int)tid << 8) | 0x00ff; - - struct bitfilter filt = { - pid, - { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, - SECTION_CONTINUOS, 0, - FILTER_MEM, - {}, - }; - - if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0) - return false; + dmxSctFilterParams sctFilterParams; + sctFilterParams.pid = pid; + memset(&sctFilterParams.filter.filter, 0, DMX_FILTER_SIZE); + memset(&sctFilterParams.filter.mask, 0, DMX_FILTER_SIZE); + sctFilterParams.timeout = 0; + sctFilterParams.flags = DMX_IMMEDIATE_START; + sctFilterParams.filter.filter[0] = tid; + sctFilterParams.filter.mask[0] = 0xFF; for (int a = 0; a < MAX_FILTERS; a++) { - if (filters[a].inuse == false) + if (!filters[a].inuse) { filters[a].pid = pid; filters[a].tid = tid; - filters[a].handle = filt.handle; - filters[a].inuse = true; - // dsyslog(LOG_INFO, " Registered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); + if ((filters[a].handle = open(fileName, O_RDWR | O_NONBLOCK)) >= 0) + { + if (ioctl(filters[a].handle, DMX_SET_FILTER, &sctFilterParams) >= 0) + filters[a].inuse = true; + else + { + esyslog(LOG_ERR, "ERROR: can't set filter"); + close(filters[a].handle); + return false; + } + // dsyslog(LOG_INFO, " Registered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); + } + else + { + esyslog(LOG_ERR, "ERROR: can't open filter handle"); + return false; + } return true; } } + esyslog(LOG_ERR, "ERROR: too many filters"); return false; } @@ -1294,27 +1319,19 @@ bool cSIProcessor::SetUseTSTime(bool use) } /** */ -bool cSIProcessor::ShutDownFilters() +bool cSIProcessor::ShutDownFilters(void) { - if (fsvbi < 0) - return false; - - bool ret = true; - for (int a = 0; a < MAX_FILTERS; a++) { - if (filters[a].inuse == true) + if (filters[a].inuse) { - if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &filters[a].handle) < 0) - ret = false; - + close(filters[a].handle); // dsyslog(LOG_INFO, "Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid); - filters[a].inuse = false; } } - return ret; + return true; // there's no real 'boolean' to return here... } /** */ @@ -1323,25 +1340,3 @@ bool cSIProcessor::SetCurrentServiceID(unsigned short servid) LOCK_THREAD; return schedules ? schedules->SetCurrentServiceID(servid) : false; } - -/** */ -bool cSIProcessor::RefreshFilters() -{ - if (fsvbi < 0) - return false; - - bool ret = true; - - ret = ShutDownFilters(); - - for (int a = 0; a < MAX_FILTERS; a++) - { - if (filters[a].inuse == false && filters[a].pid != 0 && filters[a].tid != 0) - { - if (!AddFilter(filters[a].pid, filters[a].tid)) - ret = false; - } - } - - return ret; -} diff --git a/eit.h b/eit.h index 3d491935c..e6bbd13e6 100644 --- a/eit.h +++ b/eit.h @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.6 2001/04/01 15:14:12 kls Exp $ + * $Id: eit.h 1.7 2001/05/25 12:56:53 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -129,16 +129,16 @@ class cSIProcessor : public cThread { bool masterSIProcessor; bool useTStime; SIP_FILTER *filters; - int fsvbi; + char *fileName; bool active; - bool RefreshFilters(void); void Action(void); + bool AddFilter(u_char pid, u_char tid); + bool ShutDownFilters(void); public: cSIProcessor(const char *FileName); ~cSIProcessor(); + void SetStatus(bool On); bool SetUseTSTime(bool use); - bool AddFilter(u_char pid, u_char tid); - bool ShutDownFilters(void); bool SetCurrentServiceID(unsigned short servid); const cSchedules *Schedules(void) { return schedules; } }; diff --git a/i18n.c b/i18n.c index b2c321aa2..571eea92d 100644 --- a/i18n.c +++ b/i18n.c @@ -4,11 +4,14 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.16 2001/03/31 09:58:14 kls Exp $ + * $Id: i18n.c 1.26 2001/07/27 13:32:43 kls Exp $ * * Slovenian translations provided by Miha Setina * Italian translations provided by Alberto Carraro * Dutch translations provided by Arnold Niessen + * Portugese translations provided by Paulo Manuel Martins Lopes + * French translations provided by Jean-Claude Repetto + * Norwegian translations provided by Jrgen Tvedt * */ @@ -49,7 +52,7 @@ #include "config.h" #include "tools.h" -const int NumLanguages = 5; +const int NumLanguages = 8; typedef const char *tPhrase[NumLanguages]; @@ -60,6 +63,9 @@ const tPhrase Phrases[] = { "Slovenski", "Italiano", "Nederlands", + "Portugues", + "Franais", + "Norsk", }, // Menu titles: { "Main", @@ -67,84 +73,126 @@ const tPhrase Phrases[] = { "Glavni meni", "Principale", "Hoofdmenu", + "Principal", + "Menu", + "Hovedmeny", }, { "Schedule", "Programm", "Urnik", "Programmi", "Gids", + "Programa", + "Programmes", + "Programmer", }, { "Channels", "Kanle", "Kanali", "Canali", "Kanalen", + "Canal", + "Chanes", + "Kanaler", }, { "Timers", "Timer", "Termini", "Timer", "Timers", + "Alarmes", + "Programmation", + "Timer", }, { "Recordings", "Aufzeichnungen", "Posnetki", "Registrazioni", "Opnames", + "Gravacoes", + "Enregistrements", + "Opptak", }, { "Setup", "Einstellungen", "Nastavitve", "Opzioni", "Instellingen", + "Configurar", + "Configuration", + "Konfigurasjon", }, { "Commands", "Befehle", "Ukazi", "Comandi", "Commando's", + "Comandos", + "Commandes", + "Kommandoer", }, { "Edit Channel", "Kanal Editieren", "Uredi kanal", "Modifica canale", "Kanaal aanpassen", + "Modificar Canal", + "Modifier une chane", + "Editer Kanal", }, { "Edit Timer", "Timer Editieren", "Uredi termin", "Modifica Timer", "Timer veranderen", + "Modificar Alarme", + "Changer la programmation", + "Editer Timer", }, { "Event", "Sendung", "Oddaja", "Eventi", "Uitzending", + "Evento", + "Evnement", + "Hendelse" }, { "Summary", "Inhalt", "Vsebina", "Sommario", "Inhoud", + "Resumo", + "Rsum", + "Sammendrag", }, { "Schedule - %s", "Programm - %s", "Urnik - %s", "Programma - %s", "Programma - %s", + "Programa - %s", + "Programmes - %s", + "Program Guide - %s", }, { "What's on now?", "Was luft jetzt?", "Kaj je na sporedu?", "In programmazione", "Wat is er nu?", + "O que ver agora?", + "Programmes en cours", + "Hvilket program sendes n?", }, { "What's on next?", "Was luft als nchstes?", "Kaj sledi?", "Prossimi programmi", "Wat komt er hierna?", + "O que ver depois?", + "Prochains programmes", + "Hvilket program er neste?", }, // Button texts (must not be more than 10 characters!): { "Edit", @@ -152,78 +200,126 @@ const tPhrase Phrases[] = { "Uredi", "Modifica", "Verander", + "Modificar", + "Modifier", + "Editer", }, { "New", "Neu", "Novo", "Nuovo", "Nieuw", + "Novo", + "Nouveau", + "Ny", }, { "Delete", "Lschen", "Odstrani", "Cancella", "Verwijder", + "Apagar", + "Supprimer", + "Slett", }, { "Mark", "Markieren", "Oznaci", "Marca", "Verplaats", + "Marcar", + "Marquer", + "Marker", }, { "Record", "Aufnehmen", "Posnemi", "Registra", "Opnemen", + "Gravar", + "Enregistre", + "Ta opp", }, { "Play", "Wiedergabe", "Predavajaj", "Riproduci", "Afspelen", + "Play", + "Lire", + "Spill av", }, { "Rewind", "Anfang", "Zacetek", "Da inizio", "Spoel terug", + "Rebobinar", + "Retour", + "Spol tilbake", }, { "Resume", "Weiter", "Nadaljuj", "Riprendi", "Verder", + "Continuar", + "Reprendre", + "Fortsett", }, { "Summary", "Inhalt", "Vsebina", "Sommario", "Inhoud", + "Resumo", + "Rsum", + "Sammendrag", }, { "Switch", "Umschalten", "Preklopi", "Cambia", "Selecteer", + "Seleccionar", + "Regarder", + "Skift til", }, { "Now", "Jetzt", "Sedaj", "Adesso", "Nu", + "Agora", + "Maintenant", + "N", }, { "Next", "Nchste", "Naslednji", "Prossimo", "Hierna", + "Proximo", + "Aprs", + "Neste", }, { "Schedule", "Programm", "Urnik", "Programma", "Programma", + "Programa", + "Programme", + "Programmer", + }, + { "Language", + "Sprache", + "Jezik", + "Linguaggio", + "Taal", + "", // TODO + "Langue", + "Sprk", }, // Confirmations: { "Delete channel?", @@ -231,30 +327,45 @@ const tPhrase Phrases[] = { "Odstrani kanal?", "Cancello il canale?", "Kanaal verwijderen?", + "Apagar o Canal?", + "Supprimer la chane?", + "Slette kanal?", }, { "Delete timer?", "Timer lschen?", "Odstani termin?", "Cancello il timer?", "Timer verwijderen?", + "Apagar o Alarme?", + "Supprimer la programmation?", + "Slette timer?", }, { "Delete recording?", "Aufzeichnung lschen?", "Odstrani posnetek?", "Cancello la registrazione?", "Opname verwijderen?", + "Apagar Gravaco?", + "Supprimer l'enregistrement?", + "Slette opptak?", }, { "Stop recording?", "Aufzeichnung beenden?", "Koncaj snemanje?", "Fermo la registrazione?", "Opname stoppen?", + "Parar Gravaco?", + "Arrter l'enregistrement?", + "Stoppe opptak?", }, { "Cancel editing?", "Schneiden abbrechen?", "Zelite prekiniti urejanje?", "Annullo la modifica?", "Bewerken afbreken?", + "Cancelar Modificar?", + "Annuler les modifications?", + "Avbryte redigering", }, // Channel parameters: { "Name", @@ -262,60 +373,117 @@ const tPhrase Phrases[] = { "Naziv", "Nome", "Naam", + "Nome", + "Nom", + "Navn", }, { "Frequency", "Frequenz", "Frekvenca", "Frequenza", "Frequentie", + "Frequencia", + "Frquence", + "Frekvens", }, { "Polarization", "Polarisation", "Polarizacija", "Polarizzazione", "Polarisatie", + "Polarizacao", + "Polarisation", + "Polaritet", }, { "Diseqc", "Diseqc", "Diseqc", "Diseqc", "Diseqc", + "Diseqc", + "Diseqc", + "Diseqc", }, { "Srate", "Srate", "Srate", "Srate", "Srate", + "Srate", + "Srate", + "Symbolrate", }, { "Vpid", "Vpid", "Vpid", "Vpid", "Vpid", - }, - { "Apid", - "Apid", - "Apid", - "Apid", - "Apid", + "Vpid", + "Vpid", + "Video pid", + }, + { "Apid1", + "Apid1", + "Apid1", + "Apid1", + "Apid1", + "Apid1", + "Apid1", + "Audio pid1", + }, + { "Apid2", + "Apid2", + "Apid2", + "Apid2", + "Apid2", + "Apid2", + "Apid2", + "Audio pid2", + }, + { "Dpid1", + "Dpid1", + "Dpid1", + "Dpid1", + "Dpid1", + "Dpid1", + "Dpid1", + "AC3 pid1", + }, + { "Dpid2", + "Dpid2", + "Dpid2", + "Dpid2", + "Dpid2", + "Dpid2", + "Dpid2", + "AC3 pid2", }, { "Tpid", "Tpid", "Tpid", "Tpid", "Tpid", + "Tpid", + "Tpid", + "Teletext pid", }, { "CA", "CA", "CA", "CA", "CA", + "CA", + "CA", + "Kortleser", }, { "Pnr", "Pnr", "Pnr", "Pnr", "Pnr", + "Pnr", + "Pnr", + "Program Id", }, // Timer parameters: { "Active", @@ -323,48 +491,72 @@ const tPhrase Phrases[] = { "Aktivno", "Attivo", "Actief", + "Activo", + "Actif", + "Aktiv", }, { "Channel", "Kanal", "Kanal", "Canale", "Kanaal", + "Canal", + "Chane", + "Kanal", }, { "Day", "Tag", "Dan", "Giorno", "Dag", + "Dia", + "Jour", + "Dag", }, { "Start", "Anfang", "Zacetek", "Inizio", "Begin", + "Inicio", + "Dbut", + "Start", }, { "Stop", "Ende", "Konec", "Fine", "Einde", + "Fim", + "Fin", + "Slutt", }, { "Priority", "Prioritt", "Prioriteta", "Priorita", "Prioriteit", + "Prioridade", + "Priorit", + "Prioritet", }, { "Lifetime", "Lebensdauer", "Veljavnost", "Durata", "Bewaarduur", + "Duracao", + "Dure de vie", + "Levetid", }, { "File", "Datei", "Datoteka", "Nome", "Filenaam", + "Ficheiro", + "Fichier", + "Filnavn", }, // Error messages: { "Channel is being used by a timer!", @@ -372,54 +564,81 @@ const tPhrase Phrases[] = { "Urnik zaseda kanal!", "Canale occupato da un timer!", "Kanaal wordt gebruikt door een timer!", + "Canal a ser utilizador por um alarme!", + "Cette chane est en cours d'utilisation!" + "Kanalen er i bruk av en timer!", }, { "Can't switch channel!", "Kanal kann nicht umgeschaltet werden!", "Ne morem preklopiti kanala!", "Impossibile cambiare canale!", "Kan geen kanaal wisselen!", + "Nao pode mudar de canal!", + "Impossible de changer de chane!", + "Ikke mulig skifte kanal!", }, { "Timer is recording!", "Timer zeichnet gerade auf!", "Snemanje po urniku!", "Registrazione di un timer in corso!", "Timer is aan het opnemen!", + "Alarme a gravar!", + "Enregistrement en cours!", + "Timer gjr opptak!", }, { "Error while deleting recording!", "Fehler beim Lschen der Aufzeichnung!", "Napaka pri odstranjevanju posnetka!", "Errore durante la canc del filmato!", "Fout bij verwijderen opname!", + "Erro enquanto apagava uma gravacao!", + "Erreur de suppression de l'enregistrement!", + "Feil under sletting av opptak!", }, { "*** Invalid Channel ***", "*** Ungltiger Kanal ***", "*** Neznan kanal ***", "*** CANALE INVALIDO ***", "*** Ongeldig kanaal ***", + "*** Canal Invalido! ***", + "*** Chane invalide! ***", + "*** Ugyldig Kanal! ***", }, { "No free DVB device to record!", "Keine freie DVB-Karte zum Aufnehmen!", "Ni proste DVB naprave za snemanje!", "Nessuna card DVB disp per registrare!", "Geen vrije DVB kaart om op te nemen!", + "Nenhuma placa DVB disponivel para gravar!", + "Pas de carte DVB disponible pour l'enregistrement!", + "Ingen ledige DVB enheter for opptak!" }, { "Channel locked (recording)!", "Kanal blockiert (zeichnet auf)!", "Zaklenjen kanal (snemanje)!", "Canale bloccato (in registrazione)!", "Kanaal geblokkeerd (neemt op)!", + "Canal bloqueado (a gravar)!", + "Chane verrouille (enregistrement en cours)!", + "Kanalen er lst (opptak)!", }, { "Can't start editing process!", "Schnitt kann nicht gestartet werden!", "Ne morem zaceti urejanja!", "Imposs iniziare processo di modifica", "Kan niet beginnen met bewerken!", + "Nao pode iniciar a modificacao!", + "Impossible de commencer le montage!", + "Kan ikke starte redigeringsprosessen!", }, { "Editing process already active!", "Schnitt bereits aktiv!", "Urejanje je ze aktivno!", "Processo di modifica gia` attivo", "Bewerken is al actief!", + "Processo de modificacao ja activo!", + "Montage dj en cours!", + "Redigeringsprosessen er allerede aktiv!", }, // Setup parameters: { "OSD-Language", @@ -427,78 +646,186 @@ const tPhrase Phrases[] = { "OSD-jezik", "Linguaggio OSD", "OSD-taal", + "Linguagem OSD", + "Langue OSD", + "OSD Sprk", }, { "PrimaryDVB", "Primres Interface", "Primarna naprava", "Scheda DVB primaria", "Eerste DVB kaart", + "DVB primario", + "Premire carte DVB", + "Hoved DVB-enhet", }, { "ShowInfoOnChSwitch", "Info zeigen", "Pokazi naziv kanala", "Vis info nel cambio canale", "Kanaal info tonen", + "Mostrar info ao mudar de Canal", + "Affichage progr. en cours", + "Info ved kanalskifte", }, { "MenuScrollPage", "Seitenweise scrollen", "Drsni meni", "Scrolla pagina nel menu", "Scrollen per pagina", + "Scroll da pagina no menu", + "Affichage progr. suivant", + "Rask rulling i menyer", }, { "MarkInstantRecord", "Direktaufz. markieren", "Oznaci direktno snemanje", "Marca la registrazione", "Direkte opnamen markeren", + "Marca de gravacao", + "Enregistrement immdiat", + "Markere direkteopptak", + }, + { "LnbSLOF", + "LnbSLOF", + "LnbSLOF", + "LnbSLOF", + "LnbSLOF", + "LnbSLOF", + "LnbSLOF", + "LO-grensefrekvens", }, { "LnbFrequLo", "Untere LNB-Frequenz", "Spodnja LNB-frek.", "Freq LO LNB", "Laagste LNB frequentie", + "Freq LO LNB", + "Frquence basse LNB", + "LO-frekvens i lavbndet", }, { "LnbFrequHi", "Obere LNB-Frequenz", "Zgornja LNB-frek.", "Freq HI LNB", "Hoogste LNB frequentie", + "Freq HI LNB", + "Frquence haute LNB", + "LO-frekvens i hybndet", + }, + { "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", }, { "SetSystemTime", "Systemzeit stellen", "Sistemski cas", "Setta orario auto", "Systeem klok instellen", + "Ajustar relogio do sistema", + "Ajuster l'heure du systme", + "Juster system-klokken", }, { "MarginStart", "Zeitpuffer bei Anfang", "Premor pred zacetkom", "Min margine inizio", "Tijd marge (begin)", + "Margem de inicio", + "Marge antrieure", + "Opptaks margin (start)", }, { "MarginStop", "Zeitpuffer bei Ende", "Premor za koncem", "Min margine fine", "Tijd marge (eind)", + "Margem de fim", + "Marge postrieure", + "Opptaks margin (slutt)", }, { "EPGScanTimeout", "Zeit bis EPG Scan", "Cas do EPG pregleda", "Timeout EPG", "EPG-scan Timeout", + "Timeout EPG", + "Temps maxi EPG", + "Ledig tid fr EPG-sk", }, { "SVDRPTimeout", "SVDRP Timeout", "", // TODO "Timeout SVDRP", "SVDRP Timeout", + "Timeout SVDRP", + "Temps maxi SVDRP", + "Ubrukt SVDRP-levetid", }, { "PrimaryLimit", "Primr-Limit", "", // TODO "", // TODO "", // TODO + "Limite Primario", + "Premire limite", + "Prioritets grense HovedDVB", + }, + { "DefaultPriority", + "Default Prioritt", + "", // TODO + "", // TODO + "", // TODO + "Prioridade por defeito", + "Priorit par dfaut", + "Normal prioritet (Timer)", + }, + { "DefaultLifetime", + "Default Lebensdauer", + "", // TODO + "", // TODO + "", // TODO + "Validade por defeito", + "Dure de vie par dfaut", + "Normal levetid (Timer)", + }, + { "VideoFormat", + "Video Format", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "Format vido", + "TV Format", + }, + { "ChannelInfoPos", + "Kanal Info Position", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "OSDwidth", + "OSD Breite", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "OSDheight", + "OSD Hhe", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO }, // The days of the week: { "MTWTFSS", @@ -506,6 +833,9 @@ const tPhrase Phrases[] = { "PTSCPSN", "DLMMGVS", "MDWDVZZ", + "STQQSSD", + "LMMJVSD", + "MTOTFLS", }, // Learning keys: { "Learning Remote Control Keys", @@ -513,78 +843,117 @@ const tPhrase Phrases[] = { "Ucim se kod upravljalca", "Apprendimento tasti unita` remota", "Leren toetsen afstandsbediening", + "Aprender as teclas do telecomando", + "Apprentissage des codes de tlcommande", + "Lre fjernkontrolltaster", }, { "Phase 1: Detecting RC code type", "Phase 1: FB Code feststellen", "Faza 1: Sprejemanje IR kode", "Fase 1: tipo ricevitore RC", "Fase 1: detecteren type afstandsbediening", + "Fase 1: detectar tipo de receptor", + "Phase 1: Dtection du type de code", + "Fase 1: Finne fjernkontroll-kodetype", }, { "Press any key on the RC unit", "Eine Taste auf der FB drcken", "Pritisnite tipko na upravljalcu", "Premere un tasto nell'unita` RC", "Druk op een willekeurige knop", + "Pressione qualquer tecla do telecomando", + "Appuyer sur une touche de la tlcommande", + "Trykk en av tastene p fjernkontrollen", }, { "RC code detected!", "FB Code erkannt!", "IR koda sprejeta!", "Codice RC rilevato!", "Afstandsbediening code herkend!", + "Codigo do telecomando detectado!", + "Code de la tlcommande dtect!", + "Fjernkontroll-kodetype funnet!", }, { "Do not press any key...", "Keine Taste drcken...", "Ne pritiskajte tipk...", "Non premere alcun tasto...", "Druk niet op een knop...", + "Nao pressione nada...", + "Ne pas appuyer sur une touche ...", + "Ikke trykk p noen av tastene...", }, { "Phase 2: Learning specific key codes", "Phase 2: Einzelne Tastencodes lernen", "Faza 2: Ucenje posebnih kod", "Fase 2: Codici specifici dei tasti", "Fase 2: Leren specifieke toets-codes", + "Fase 2: A aprender codigos especificos", + "Phase 2: Apprentissage des codes des touches", + "Fase 2: Lre spesifikke tastekoder", }, { "Press key for '%s'", "Taste fr '%s' drcken", "Pritisnite tipko za '%s'", "Premere il tasto per '%s'", "Druk knop voor '%s'", + "Pressione tecla para '%s'", + "Appuyer sur la touche '%s'", + "Trykk tasten for '%s'", }, { "Press 'Up' to confirm", "'Auf' drcken zum Besttigen", "Pritisnite tipko 'Gor' za potrditev", "Premere 'Su' per confermare", "Druk 'Omhoog' om te bevestigen", + "Pressione 'Cima' para confirmar", + "Appuyer sur 'Haut' pour confirmer", + "Trykk 'Opp' for bekrefte", }, { "Press 'Down' to continue", "'Ab' drcken zum Weitermachen", "Pritisnite tipko 'Dol' za nadaljevanje", "Premere 'Giu' per confermare", "Druk 'Omlaag' om verder te gaan", + "Pressione 'Baixo' para continuar", + "Appuyer sur 'Bas' pour continuer", + "Trykk Ned' for fortsette", }, { "(press 'Up' to go back)", "('Auf' drcken um zurckzugehen)", "(pritisnite 'Gor' za nazaj)", "(premere 'Su' per tornare indietro)", "(druk 'Omhoog' om terug te gaan)", + "(Pressione 'Cima' para voltar)", + "(Appuyer sur 'Haut' pour revenir en arrire)", + "(trykk 'Opp' for g tilbake)", }, { "(press 'Down' to end key definition)", "('Ab' drcken zum Beenden)", "(pritisnite 'Dol' za konec)", "('Giu' per finire la definiz tasti)", "(Druk 'Omlaag' om te beeindigen)", + "(Pressione 'Baixo' para terminar a definicao)", + "(Appuyer sur 'Bas' pour terminer)", + "(trykk 'Ned' for avslutte innlring)", }, { "Phase 3: Saving key codes", "Phase 3: Codes abspeichern", "Faza 3: Shranjujem kodo", "Fase 3: Salvataggio key codes", "Fase 3: Opslaan toets codes", + "Fase 3: A Salvar os codigos das teclas", + "Phase 3: Sauvegarde des codes des touches", + "Fase 3: Lagre tastekoder", }, { "Press 'Up' to save, 'Down' to cancel", "'Auf' speichert, 'Ab' bricht ab", "'Gor' za potrditev, 'Dol' za prekinitev", "'Su' per salvare, 'Giu' per annullare", "'Omhoog' te bewaren, 'Omlaag' voor annuleren", + "'Cima' para Salvar, 'Baixo' para Cancelar", + "Appuyer sur 'Haut' pour sauvegarder, 'Bas' pour annuler", + "Trykk 'Opp' for lagre, 'Ned' for avbryte", }, // Key names: { "Up", @@ -592,66 +961,99 @@ const tPhrase Phrases[] = { "Gor", "Su", "Omhoog", + "Cima", + "Haut", + "Opp", }, { "Down", "Ab", "Dol", "Giu", "Omlaag", + "Baixo", + "Bas", + "Ned", }, { "Menu", "Men", "Meni", "Menu", "Menu", + "Menu", + "Menu", + "Meny", }, { "Ok", "Ok", "Ok", "Ok", "Ok", + "Ok", + "Ok", + "Ok", }, { "Back", "Zurck", "Nazaj", "Indietro", "Terug", + "Voltar", + "Retour", + "Tilbake", }, { "Left", "Links", "Levo", "Sinistra", "Links", + "Esquerda", + "Gauche", + "Venstre", }, { "Right", "Rechts", "Desno", "Destra", "Rechts", + "Direita", + "Droite", + "Hyre", }, { "Red", "Rot", "Rdeca", "Rosso", "Rood", + "Vermelho", + "Rouge", + "Rd", }, { "Green", "Grn", "Zelena", "Verde", "Groen", + "Verde", + "Vert", + "Grnn", }, { "Yellow", "Gelb", "Rumena", "Giallo", "Geel", + "Amarelo", + "Jaune", + "Gul", }, { "Blue", "Blau", "Modra", "Blu", "Blauw", + "Azul", + "Bleu", + "Bl", }, // Miscellaneous: { "yes", @@ -659,48 +1061,88 @@ const tPhrase Phrases[] = { "da", "si", "ja", + "sim", + "oui", + "ja", }, { "no", "nein", "ne", "no", "nee", + "nao", + "non", + "nei", + }, + { "top", + "oben", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "bottom", + "unten", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO }, { " Stop replaying", // note the leading blank! " Wiedergabe beenden", " Prekini ponavljanje", " Interrompi riproduzione", " Stop afspelen", + " Parar reproducao", + " Arrter la lecture", + " Stopp avspilling", }, { " Stop recording ", // note the leading and trailing blanks! " Aufzeichnung beenden ", " Prekini shranjevanje ", " Interrompi registrazione ", " Stop opnemen ", + " Parar gravacao ", + " Arrter l'enregistrement ", + " Stopp opptak fra ", }, { " Cancel editing", // note the leading blank! " Schneiden abbrechen", " Prekini urejanje", " Annulla modifiche", " Bewerken afbreken", + " Anular modificacao", + " Annuler le montage", + " Avbryt editering", }, { "Switching primary DVB...", "Primres Interface wird umgeschaltet...", "Preklapljanje primarne naprave...", "Cambio su card DVB primaria...", "Eerste DVB-kaart wordt omgeschakeld...", + "A mudar placa DVB primaria...", + "Changement de carte DVB...", + "Bytter hoved DVB-enhet... ", }, { "Up/Dn for new location - OK to move", "Auf/Ab fr neue Position - dann OK", "Gor/Dol za novo poz. - Ok za premik", "Su/Giu per nuova posizione - OK per muovere", "Gebruik Omhoog/Omlaag - daarna Ok", + "Cima/Baixo para nova localizacao - Ok para mudar", + "Haut/Bas -> nouvelle place - OK -> dplacer", + "Opp/Ned for ny plass - OK for flytte", }, { "Editing process started", "Schnitt gestartet", "Urejanje se je zacelo", "Processo di modifica iniziato", "Bewerken is gestart", + "Processo de modificacao iniciado", + "Opration de montage lance", + "Redigeringsprosess startet", }, { NULL } }; diff --git a/interface.c b/interface.c index 55cdb0b9c..03dca06f2 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.35 2001/02/18 10:46:13 kls Exp $ + * $Id: interface.c 1.39 2001/07/28 14:57:52 kls Exp $ */ #include "interface.h" @@ -44,8 +44,13 @@ cInterface::~cInterface() void cInterface::Open(int NumCols, int NumLines) { - if (!open++) + if (!open++) { + if (NumCols == 0) + NumCols = Setup.OSDwidth; + if (NumLines == 0) + NumLines = Setup.OSDheight; cDvbApi::PrimaryDvbApi->Open(width = NumCols, height = NumLines); + } } void cInterface::Close(void) @@ -281,16 +286,17 @@ void cInterface::Title(const char *s) void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor) { - ClearEol(0, -3, s ? BgColor : clrBackground); + int Line = (abs(height) == 1) ? 0 : -2; + ClearEol(0, Line, s ? BgColor : clrBackground); if (s) - Write(0, -3, s, FgColor, BgColor); + Write(0, Line, s, FgColor, BgColor); } void cInterface::Info(const char *s) { - Open(); + Open(Setup.OSDwidth, -1); isyslog(LOG_INFO, "info: %s", s); - Status(s, clrWhite, clrGreen); + Status(s, clrBlack, clrGreen); Wait(); Status(NULL); Close(); @@ -298,7 +304,7 @@ void cInterface::Info(const char *s) void cInterface::Error(const char *s) { - Open(); + Open(Setup.OSDwidth, -1); esyslog(LOG_ERR, "ERROR: %s", s); Status(s, clrWhite, clrRed); Wait(); @@ -310,7 +316,7 @@ bool cInterface::Confirm(const char *s) { Open(); isyslog(LOG_INFO, "confirm: %s", s); - Status(s, clrBlack, clrGreen); + Status(s, clrBlack, clrYellow); bool result = Wait(10) == kOk; Status(NULL); Close(); diff --git a/interface.h b/interface.h index 50c376154..2b0e2f1ae 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.21 2000/12/09 10:48:41 kls Exp $ + * $Id: interface.h 1.22 2001/07/27 11:38:01 kls Exp $ */ #ifndef __INTERFACE_H @@ -32,7 +32,7 @@ class cInterface { public: cInterface(int SVDRPport = 0); ~cInterface(); - void Open(int NumCols = MenuColumns, int NumLines = MenuLines); + void Open(int NumCols = 0, int NumLines = 0); void Close(void); int Width(void) { return width; } int Height(void) { return height; } diff --git a/menu.c b/menu.c index 09c180c47..30532a7d6 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.70 2001/03/18 10:16:56 kls Exp $ + * $Id: menu.c 1.88 2001/07/28 16:17:28 kls Exp $ */ #include "menu.h" @@ -118,21 +118,24 @@ eOSState cMenuEditIntItem::ProcessKey(eKeys Key) class cMenuEditBoolItem : public cMenuEditIntItem { protected: + const char *falseString, *trueString; virtual void Set(void); public: - cMenuEditBoolItem(const char *Name, int *Value); + cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString = NULL, const char *TrueString = NULL); }; -cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value) +cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString) :cMenuEditIntItem(Name, Value, 0, 1) { + falseString = FalseString ? FalseString : tr("no"); + trueString = TrueString ? TrueString : tr("yes"); Set(); } void cMenuEditBoolItem::Set(void) { char buf[16]; - snprintf(buf, sizeof(buf), "%s", *value ? tr("yes") : tr("no")); + snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString); SetValue(buf); } @@ -274,7 +277,12 @@ cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value) void cMenuEditTimeItem::Set(void) { char buf[10]; - snprintf(buf, sizeof(buf), "%02d:%02d", hh, mm); + switch (pos) { + case 1: snprintf(buf, sizeof(buf), "%01d-:--", hh / 10); break; + case 2: snprintf(buf, sizeof(buf), "%02d:--", hh); break; + case 3: snprintf(buf, sizeof(buf), "%02d:%01d-", hh, mm / 10); break; + default: snprintf(buf, sizeof(buf), "%02d:%02d", hh, mm); + } SetValue(buf); } @@ -538,10 +546,13 @@ cMenuEditChannel::cMenuEditChannel(int Index) Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency, 10000, 13000)); //TODO exact limits??? Add(new cMenuEditChrItem( tr("Polarization"), &data.polarization, "hv")); Add(new cMenuEditIntItem( tr("Diseqc"), &data.diseqc, 0, 10)); //TODO exact limits??? - Add(new cMenuEditIntItem( tr("Srate"), &data.srate, 22000, 27500)); //TODO exact limits - toggle??? - Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 10000)); //TODO exact limits??? - Add(new cMenuEditIntItem( tr("Apid"), &data.apid, 0, 10000)); //TODO exact limits??? - Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 10000)); //TODO exact limits??? + Add(new cMenuEditIntItem( tr("Srate"), &data.srate, 22000, 30000)); //TODO exact limits - toggle??? + Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0xFFFE)); + Add(new cMenuEditIntItem( tr("Apid1"), &data.apid1, 0, 0xFFFE)); + Add(new cMenuEditIntItem( tr("Apid2"), &data.apid2, 0, 0xFFFE)); + Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0xFFFE)); + Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0xFFFE)); + Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0xFFFE)); Add(new cMenuEditIntItem( tr("CA"), &data.ca, 0, cDvbApi::NumDvbApis)); Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0)); } @@ -579,7 +590,7 @@ cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel) index = Index; channel = Channel; if (channel->groupSep) - SetColor(clrWhite, clrBlue); + SetColor(clrWhite, clrCyan); Set(); } @@ -589,7 +600,7 @@ void cMenuChannelItem::Set(void) if (!channel->groupSep) asprintf(&buffer, "%d\t%s", channel->number, channel->name ); else - asprintf(&buffer, "\t%s", channel->name); + asprintf(&buffer, "\t%s", channel->name); SetText(buffer, false); } @@ -868,7 +879,7 @@ class cMenuText : public cOsdMenu { cMenuText::cMenuText(const char *Title, const char *Text, eDvbFont Font) :cOsdMenu(Title) { - Add(new cMenuTextItem(Text, 1, 2, MenuColumns - 2, MAXOSDITEMS, clrWhite, clrBackground, Font)); + Add(new cMenuTextItem(Text, 1, 2, Setup.OSDwidth - 2, MAXOSDITEMS, clrWhite, clrBackground, Font)); } eOSState cMenuText::ProcessKey(eKeys Key) @@ -904,13 +915,13 @@ cMenuEditTimer::cMenuEditTimer(int Index, bool New) if (New) data.active = 1; Add(new cMenuEditBoolItem(tr("Active"), &data.active)); - Add(new cMenuEditChanItem(tr("Channel"), &data.channel)); - Add(new cMenuEditDayItem( tr("Day"), &data.day)); - Add(new cMenuEditTimeItem(tr("Start"), &data.start)); - Add(new cMenuEditTimeItem(tr("Stop"), &data.stop)); + Add(new cMenuEditChanItem(tr("Channel"), &data.channel)); + Add(new cMenuEditDayItem( tr("Day"), &data.day)); + Add(new cMenuEditTimeItem(tr("Start"), &data.start)); + Add(new cMenuEditTimeItem(tr("Stop"), &data.stop)); //TODO VPS??? - Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, 99)); - Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, 99)); + Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), FileNameChars)); } } @@ -963,9 +974,9 @@ void cMenuTimerItem::Set(void) { char *buffer = NULL; asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s", - timer->active ? '>' : ' ', - timer->channel, - timer->PrintDay(timer->day), + timer->active ? '>' : ' ', + timer->channel, + timer->PrintDay(timer->day), timer->start / 100, timer->start % 100, timer->stop / 100, @@ -1137,20 +1148,20 @@ cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch) // like all the others? Well, at least like those who actually send the full range // of information (like, e.g., 'Sat.1'). Some stations (like 'RTL') don't even // bother sending anything but the 'Title'... - if (isempty(ExtendedDescription) && !isempty(Subtitle) && strlen(Subtitle) > 2 * MenuColumns) { + if (isempty(ExtendedDescription) && !isempty(Subtitle) && int(strlen(Subtitle)) > 2 * Setup.OSDwidth) { ExtendedDescription = Subtitle; Subtitle = NULL; } if (!isempty(Title)) { - Add(item = new cMenuTextItem(Title, 1, Line, MenuColumns - 2, -1, clrCyan)); + Add(item = new cMenuTextItem(Title, 1, Line, Setup.OSDwidth - 2, -1, clrCyan)); Line += item->Height() + 1; } if (!isempty(Subtitle)) { - Add(item = new cMenuTextItem(Subtitle, 1, Line, MenuColumns - 2, -1, clrYellow)); + Add(item = new cMenuTextItem(Subtitle, 1, Line, Setup.OSDwidth - 2, -1, clrYellow)); Line += item->Height() + 1; } if (!isempty(ExtendedDescription)) - Add(new cMenuTextItem(ExtendedDescription, 1, Line, MenuColumns - 2, Height() - Line - 2, clrCyan), true); + Add(new cMenuTextItem(ExtendedDescription, 1, Line, Setup.OSDwidth - 2, Height() - Line - 2, clrCyan), true); SetHelp(tr("Record"), NULL, NULL, CanSwitch ? tr("Switch") : NULL); } } @@ -1265,7 +1276,7 @@ eOSState cMenuWhatsOn::Switch(void) eOSState cMenuWhatsOn::Record(void) { cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current()); - if (item) { + if (item) { cTimer *timer = new cTimer(item->eventInfo); cTimer *t = Timers.GetTimer(timer); if (!t) { @@ -1391,7 +1402,7 @@ void cMenuSchedule::PrepareSchedule(cChannel *Channel) eOSState cMenuSchedule::Record(void) { cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current()); - if (item) { + if (item) { cTimer *timer = new cTimer(item->eventInfo); cTimer *t = Timers.GetTimer(timer); if (!t) { @@ -1608,14 +1619,22 @@ void cMenuSetup::Set(void) Add(new cMenuEditBoolItem(tr("ShowInfoOnChSwitch"), &data.ShowInfoOnChSwitch)); Add(new cMenuEditBoolItem(tr("MenuScrollPage"), &data.MenuScrollPage)); Add(new cMenuEditBoolItem(tr("MarkInstantRecord"), &data.MarkInstantRecord)); + Add(new cMenuEditIntItem( tr("LnbSLOF"), &data.LnbSLOF)); Add(new cMenuEditIntItem( tr("LnbFrequLo"), &data.LnbFrequLo)); Add(new cMenuEditIntItem( tr("LnbFrequHi"), &data.LnbFrequHi)); + Add(new cMenuEditBoolItem(tr("DiSEqC"), &data.DiSEqC)); Add(new cMenuEditBoolItem(tr("SetSystemTime"), &data.SetSystemTime)); Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart)); Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop)); Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout)); Add(new cMenuEditIntItem( tr("SVDRPTimeout"), &data.SVDRPTimeout)); - Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit)); + Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("DefaultPriority"), &data.DefaultPriority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("DefaultLifetime"), &data.DefaultLifetime, 0, MAXLIFETIME)); + Add(new cMenuEditBoolItem(tr("VideoFormat"), &data.VideoFormat, "4:3", "16:9")); + Add(new cMenuEditBoolItem(tr("ChannelInfoPos"), &data.ChannelInfoPos, tr("bottom"), tr("top"))); + Add(new cMenuEditIntItem( tr("OSDwidth"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); + Add(new cMenuEditIntItem( tr("OSDheight"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); } eOSState cMenuSetup::ProcessKey(eKeys Key) @@ -1626,6 +1645,7 @@ eOSState cMenuSetup::ProcessKey(eKeys Key) switch (Key) { case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osEnd; cDvbApi::PrimaryDvbApi->SetUseTSTime(data.SetSystemTime); + cDvbApi::PrimaryDvbApi->SetVideoFormat(data.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3); Setup = data; Setup.Save(); break; @@ -1722,7 +1742,7 @@ cMenuMain::cMenuMain(bool Replaying) } if (cVideoCutter::Active()) Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit)); - SetHelp(tr("Record"), NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); + SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); Display(); lastActivity = time(NULL); SetHasHotkeys(); @@ -1753,14 +1773,22 @@ eOSState cMenuMain::ProcessKey(eKeys Key) } break; default: switch (Key) { - case kMenu: state = osEnd; break; - case kRed: if (!HasSubMenu()) - state = osRecord; - break; - case kBlue: if (!HasSubMenu()) - state = osReplay; - break; - default: break; + case kMenu: state = osEnd; break; + case kRed: if (!HasSubMenu()) + state = osRecord; + break; + case kGreen: if (!HasSubMenu()) { + if (cDvbApi::PrimaryDvbApi->CanToggleAudioTrack()) { + Interface->Clear(); + cDvbApi::PrimaryDvbApi->ToggleAudioTrack(); + state = osEnd; + } + } + break; + case kBlue: if (!HasSubMenu()) + state = osReplay; + break; + default: break; } } if (Key != kNone) @@ -1772,7 +1800,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key) // --- cDisplayChannel ------------------------------------------------------- -#define DIRECTCHANNELTIMEOUT 500 //ms +#define DIRECTCHANNELTIMEOUT 1000 //ms #define INFOTIMEOUT 5000 //ms cDisplayChannel::cDisplayChannel(int Number, bool Switched, bool Group) @@ -1783,7 +1811,7 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched, bool Group) lines = 0; oldNumber = number = 0; cChannel *channel = Group ? Channels.Get(Number) : Channels.GetByNumber(Number); - Interface->Open(MenuColumns, 5); + Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? 5 : -5); if (channel) { DisplayChannel(channel); DisplayInfo(); @@ -1797,7 +1825,7 @@ cDisplayChannel::cDisplayChannel(eKeys FirstKey) oldNumber = cDvbApi::CurrentChannel(); number = 0; lastTime = time_ms(); - Interface->Open(MenuColumns, 5); + Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? 5 : -5); ProcessKey(FirstKey); } @@ -1810,21 +1838,20 @@ cDisplayChannel::~cDisplayChannel() void cDisplayChannel::DisplayChannel(const cChannel *Channel) { - if (Channel && Channel->number) + if (Channel && Channel->number > 0) Interface->DisplayChannelNumber(Channel->number); int BufSize = Width() + 1; char buffer[BufSize]; - if (Channel && Channel->number) - snprintf(buffer, BufSize, "%d %s", Channel->number, Channel->name); + if (Channel && Channel->number > 0) + snprintf(buffer, BufSize, "%d%s %s", Channel->number, number ? "-" : "", Channel->name); else snprintf(buffer, BufSize, "%s", Channel ? Channel->name : tr("*** Invalid Channel ***")); - Interface->Fill(0, 0, MenuColumns, 1, clrBackground); + Interface->Fill(0, 0, Setup.OSDwidth, 1, clrBackground); Interface->Write(0, 0, buffer); time_t t = time(NULL); struct tm *now = localtime(&t); snprintf(buffer, BufSize, "%02d:%02d", now->tm_hour, now->tm_min); Interface->Write(-5, 0, buffer); - Interface->Flush(); } void cDisplayChannel::DisplayInfo(void) @@ -1857,7 +1884,7 @@ void cDisplayChannel::DisplayInfo(void) if (Lines > lines) { const int t = 6; int l = 1; - Interface->Fill(0, 1, MenuColumns, Lines, clrBackground); + Interface->Fill(0, 1, Setup.OSDwidth, Lines, clrBackground); if (!isempty(PresentTitle)) { Interface->Write(0, l, Present->GetTimeString(), clrYellow, clrBackground); Interface->Write(t, l, PresentTitle, clrCyan, clrBackground); @@ -1945,11 +1972,14 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), dvbApi->Index() + 1); } timer->SetRecording(true); - Channels.SwitchTo(timer->channel, dvbApi); - cRecording Recording(timer); - if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority)) - Recording.WriteSummary(); - Interface->DisplayRecording(dvbApi->Index(), true); + if (Channels.SwitchTo(timer->channel, dvbApi)) { + cRecording Recording(timer); + if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority)) + Recording.WriteSummary(); + Interface->DisplayRecording(dvbApi->Index(), true); + } + else + cThread::EmergencyExit(true); } cRecordControl::~cRecordControl() @@ -1979,7 +2009,7 @@ bool cRecordControl::Process(void) { if (!timer || !timer->Matches()) return false; - AssertFreeDiskSpace(); + AssertFreeDiskSpace(timer->priority); return true; } @@ -1993,7 +2023,7 @@ bool cRecordControls::Start(cTimer *Timer) cChannel *channel = Channels.GetByNumber(ch); if (channel) { - cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca, Timer ? Timer->priority : DEFAULTPRIORITY); + cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca, Timer ? Timer->priority : Setup.DefaultPriority); if (dvbApi) { Stop(dvbApi); for (int i = 0; i < MAXDVBAPI; i++) { @@ -2078,7 +2108,7 @@ class cProgressBar : public cBitmap { }; cProgressBar::cProgressBar(int Width, int Height, int Current, int Total, const cMarks &Marks) -:cBitmap(Width, Height) +:cBitmap(Width, Height, 2) { total = Total; if (total > 0) { @@ -2119,6 +2149,8 @@ cReplayControl::cReplayControl(void) { dvbApi = cDvbApi::PrimaryDvbApi; visible = shown = displayFrames = false; + lastCurrent = lastTotal = -1; + timeoutShow = 0; if (fileName) { marks.Load(fileName); dvbApi->StartReplay(fileName); @@ -2152,12 +2184,14 @@ void cReplayControl::ClearLastReplayed(const char *FileName) } } -void cReplayControl::Show(void) +void cReplayControl::Show(int Seconds) { if (!visible) { - Interface->Open(MenuColumns, -3); + Interface->Open(Setup.OSDwidth, -3); needsFastResponse = visible = true; shown = ShowProgress(true); + if (Seconds > 0) + timeoutShow = time(NULL) + Seconds; } } @@ -2178,21 +2212,27 @@ bool cReplayControl::ShowProgress(bool Initial) Interface->Clear(); if (title) Interface->Write(0, 0, title); - displayFrames = marks.Count() > 0; + lastCurrent = lastTotal = -1; + } + if (Total != lastTotal) { + Interface->Write(-7, 2, IndexToHMSF(Total)); + Interface->Flush(); + lastTotal = Total; } - Interface->Write(-7, 2, IndexToHMSF(Total)); - Interface->Flush(); + if (Current != lastCurrent) { #ifdef DEBUG_OSD - int p = Width() * Current / Total; - Interface->Fill(0, 1, p, 1, clrGreen); - Interface->Fill(p, 1, Width() - p, 1, clrWhite); + int p = Width() * Current / Total; + Interface->Fill(0, 1, p, 1, clrGreen); + Interface->Fill(p, 1, Width() - p, 1, clrWhite); #else - cProgressBar ProgressBar(Width() * dvbApi->CellWidth(), dvbApi->LineHeight(), Current, Total, marks); - Interface->SetBitmap(0, dvbApi->LineHeight(), ProgressBar); - Interface->Flush(); + cProgressBar ProgressBar(Width() * dvbApi->CellWidth(), dvbApi->LineHeight(), Current, Total, marks); + Interface->SetBitmap(0, dvbApi->LineHeight(), ProgressBar); + Interface->Flush(); #endif - Interface->Write(0, 2, IndexToHMSF(Current, displayFrames)); - Interface->Flush(); + Interface->Write(0, 2, IndexToHMSF(Current, displayFrames)); + Interface->Flush(); + lastCurrent = Current; + } return true; } return false; @@ -2205,22 +2245,24 @@ void cReplayControl::MarkToggle(void) cMark *m = marks.Get(Current); if (m) marks.Del(m); - else + else { marks.Add(Current); + Show(2); + } marks.Save(); } - displayFrames = marks.Count() > 0; - if (!displayFrames) - Interface->Fill(0, 2, Width() / 2, 1, clrBackground); } void cReplayControl::MarkJump(bool Forward) { - int Current, Total; - if (dvbApi->GetIndex(Current, Total)) { - cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); - if (m) - dvbApi->Goto(m->position, true); + if (marks.Count()) { + int Current, Total; + if (dvbApi->GetIndex(Current, Total)) { + cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); + if (m) + dvbApi->Goto(m->position, true); + } + displayFrames = true; } } @@ -2230,6 +2272,7 @@ void cReplayControl::MarkMove(bool Forward) if (dvbApi->GetIndex(Current, Total)) { cMark *m = marks.Get(Current); if (m) { + displayFrames = true; int p = dvbApi->SkipFrames(Forward ? 1 : -1); cMark *m2; if (Forward) { @@ -2281,8 +2324,16 @@ eOSState cReplayControl::ProcessKey(eKeys Key) { if (!dvbApi->Replaying()) return osEnd; - if (visible) - shown = ShowProgress(!shown) || shown; + if (visible) { + if (timeoutShow && time(NULL) > timeoutShow) { + Hide(); + timeoutShow = 0; + } + else + shown = ShowProgress(!shown) || shown; + } + bool DisplayedFrames = displayFrames; + displayFrames = false; switch (Key) { // Positioning: case kUp: dvbApi->Play(); break; @@ -2299,23 +2350,34 @@ eOSState cReplayControl::ProcessKey(eKeys Key) case kBlue: Hide(); dvbApi->StopReplay(); return osEnd; - // Editing: - //XXX should we do this only when the ProgressDisplay is on??? - case kMarkToggle: MarkToggle(); break; - case kMarkJumpBack: MarkJump(false); break; - case kMarkJumpForward: MarkJump(true); break; - case kMarkMoveBack|k_Repeat: - case kMarkMoveBack: MarkMove(false); break; - case kMarkMoveForward|k_Repeat: - case kMarkMoveForward: MarkMove(true); break; - case kEditCut: EditCut(); break; - case kEditTest: EditTest(); break; - // Menu control: - case kMenu: Hide(); return osMenu; // allow direct switching to menu - case kOk: visible ? Hide() : Show(); break; - case kBack: return osRecordings; - default: return osUnknown; + default: { + switch (Key) { + // Editing: + //XXX should we do this only when the ProgressDisplay is on??? + case kMarkToggle: MarkToggle(); break; + case kMarkJumpBack: MarkJump(false); break; + case kMarkJumpForward: MarkJump(true); break; + case kMarkMoveBack|k_Repeat: + case kMarkMoveBack: MarkMove(false); break; + case kMarkMoveForward|k_Repeat: + case kMarkMoveForward: MarkMove(true); break; + case kEditCut: EditCut(); break; + case kEditTest: EditTest(); break; + default: { + displayFrames = DisplayedFrames; + switch (Key) { + // Menu control: + case kMenu: Hide(); return osMenu; // allow direct switching to menu + case kOk: visible ? Hide() : Show(); break; + case kBack: return osRecordings; + default: return osUnknown; + } + } + } + } } + if (DisplayedFrames && !displayFrames) + Interface->Fill(0, 2, Width() / 2, 1, clrBackground); return osContinue; } diff --git a/menu.h b/menu.h index 356122e02..adc10b726 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.18 2001/02/11 10:30:35 kls Exp $ + * $Id: menu.h 1.20 2001/07/28 13:59:29 kls Exp $ */ #ifndef _MENU_H @@ -83,7 +83,9 @@ class cReplayControl : public cOsdBase { cDvbApi *dvbApi; cMarks marks; bool visible, shown, displayFrames; - void Show(void); + int lastCurrent, lastTotal; + time_t timeoutShow; + void Show(int Seconds = 0); void Hide(void); static char *fileName; static char *title; diff --git a/osd.h b/osd.h index c0fb1a1ef..a1977be4f 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.20 2001/02/03 15:13:59 kls Exp $ + * $Id: osd.h 1.22 2001/07/27 11:33:30 kls Exp $ */ #ifndef __OSD_H @@ -14,7 +14,7 @@ #include "interface.h" #include "tools.h" -#define MAXOSDITEMS 9 +#define MAXOSDITEMS (Setup.OSDheight - 4) enum eOSState { osUnknown, osMenu, diff --git a/recording.c b/recording.c index fc0daa57a..ddca1a4b2 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.29 2001/03/31 09:38:30 kls Exp $ + * $Id: recording.c 1.32 2001/06/16 10:33:20 kls Exp $ */ #define _GNU_SOURCE @@ -39,7 +39,7 @@ #define DELETEDLIFETIME 1 // hours after which a deleted recording will be actually removed #define REMOVECHECKDELTA 3600 // seconds between checks for removing deleted files #define DISKCHECKDELTA 300 // seconds between checks for free disk space -#define REMOVELATENCY 10 // seconds to wait until next check after removing a file +#define REMOVELATENCY 10 // seconds to wait until next check after removing a file void RemoveDeletedRecordings(void) { @@ -66,7 +66,7 @@ void RemoveDeletedRecordings(void) } } -void AssertFreeDiskSpace(void) +void AssertFreeDiskSpace(int Priority) { // With every call to this function we try to actually remove // a file, or mark a file for removal ("delete" it), so that @@ -94,13 +94,16 @@ void AssertFreeDiskSpace(void) cRecording *r = Recordings.First(); cRecording *r0 = NULL; while (r) { - if ((time(NULL) - r->start) / SECSINDAY > r->lifetime) { - if (r0) { - if (r->priority < r0->priority) + if (r->lifetime < MAXLIFETIME) { // recordings with MAXLIFETIME live forever + if ((r->lifetime == 0 && Priority > r->priority) || // the recording has guaranteed lifetime and the new recording has higher priority + (time(NULL) - r->start) / SECSINDAY > r->lifetime) { // the recording's guaranteed lifetime has expired + if (r0) { + if (r->priority < r0->priority || (r->priority == r0->priority && r->start < r0->start)) + r0 = r; // in any case we delete the one with the lowest priority (or the older one in case of equal priorities) + } + else r0 = r; } - else - r0 = r; } r = Recordings.Next(r); } @@ -153,7 +156,7 @@ int cResumeFile::Read(void) bool cResumeFile::Save(int Index) { if (fileName) { - int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); + int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (f >= 0) { if (write(f, &Index, sizeof(Index)) != sizeof(Index)) LOG_ERROR_STR(fileName); @@ -174,18 +177,31 @@ void cResumeFile::Delete(void) // --- cRecording ------------------------------------------------------------ +struct tCharExchange { char a; char b; }; +tCharExchange CharExchange[] = { + { ' ', '_' }, + { '\'', '\x01' }, + { '/', '\x02' }, +#ifdef VFAT + { ':', '\x03' }, +#endif + { 0, 0 } + }; + +char *ExchangeChars(char *s, bool ToFileSystem) +{ + for (struct tCharExchange *ce = CharExchange; ce->a && ce->b; ce++) + strreplace(s, ToFileSystem ? ce->a : ce->b, ToFileSystem ? ce->b : ce->a); + return s; +} + cRecording::cRecording(cTimer *Timer) { titleBuffer = NULL; fileName = NULL; name = strdup(Timer->file); // substitute characters that would cause problems in file names: - for (char *p = name; *p; p++) { - switch (*p) { - case '\n': *p = ' '; break; - case '/': *p = '-'; break; - } - } + strreplace(name, '\n', ' '); summary = Timer->summary ? strdup(Timer->summary) : NULL; if (summary) strreplace(summary, '|', '\n'); @@ -215,8 +231,7 @@ cRecording::cRecording(const char *FileName) name = new char[p - FileName + 1]; strncpy(name, FileName, p - FileName); name[p - FileName] = 0; - strreplace(name, '_', ' '); - strreplace(name, '\x01', '\''); + ExchangeChars(name, false); } // read an optional summary file: char *SummaryFileName = NULL; @@ -239,7 +254,7 @@ cRecording::cRecording(const char *FileName) delete summary; summary = NULL; } - + } else esyslog(LOG_ERR, "can't allocate %d byte of memory for summary file '%s'", size + 1, SummaryFileName); @@ -266,11 +281,9 @@ const char *cRecording::FileName(void) { if (!fileName) { struct tm *t = localtime(&start); + ExchangeChars(name, true); asprintf(&fileName, NAMEFORMAT, VideoDirectory, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime); - if (fileName) { - strreplace(fileName, ' ', '_'); - strreplace(fileName, '\'', '\x01'); - } + ExchangeChars(name, false); } return fileName; } diff --git a/recording.h b/recording.h index b561fa2f9..059133e72 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.13 2001/02/11 10:45:52 kls Exp $ + * $Id: recording.h 1.14 2001/06/02 10:00:25 kls Exp $ */ #ifndef __RECORDING_H @@ -15,7 +15,7 @@ #include "tools.h" void RemoveDeletedRecordings(void); -void AssertFreeDiskSpace(void); +void AssertFreeDiskSpace(int Priority); class cResumeFile { private: diff --git a/remote.c b/remote.c index 940243863..db8fa870d 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch 2000-06-16. * - * $Id: remote.c 1.21 2001/02/04 19:17:59 kls Exp $ + * $Id: remote.c 1.23 2001/07/27 10:17:19 kls Exp $ */ #include "remote.h" @@ -439,7 +439,7 @@ void cRcIoLIRC::Action(void) if (cFile::FileReady(f, REPEATLIMIT) && read(f, buf, sizeof(buf)) > 21) { if (!receivedData) { // only accept new data the previous data has been fetched int count; - sscanf(buf, "%*x %x %7s", &count, LastKeyName); // '7' in '%7s' is LIRC_KEY_BUF-1! + sscanf(buf, "%*x %x %29s", &count, LastKeyName); // '29' in '%29s' is LIRC_KEY_BUF-1! int Now = time_ms(); if (count == 0) { strcpy(keyName, LastKeyName); @@ -466,9 +466,11 @@ void cRcIoLIRC::Action(void) } } else if (receivedRepeat) { // all data has already been fetched, but the last one was a repeat, so let's generate a release - receivedData = receivedRelease = true; - receivedRepeat = false; - WakeUp(); + if (time_ms() - LastTime > REPEATDELAY) { + receivedData = receivedRelease = true; + receivedRepeat = false; + WakeUp(); + } } } } diff --git a/remote.h b/remote.h index 659de1aca..bbdf2facc 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.14 2001/02/02 14:49:10 kls Exp $ + * $Id: remote.h 1.15 2001/07/22 14:42:59 kls Exp $ */ #ifndef __REMOTE_H @@ -81,7 +81,7 @@ class cRcIoRCU : public cRcIoBase, private cThread { class cRcIoLIRC : public cRcIoBase, private cThread { private: - enum { LIRC_KEY_BUF = 8, LIRC_BUFFER_SIZE = 128 }; + enum { LIRC_KEY_BUF = 30, LIRC_BUFFER_SIZE = 128 }; int f; char keyName[LIRC_KEY_BUF]; bool receivedData, receivedRepeat, receivedRelease; diff --git a/remux.c b/remux.c index e48296d84..3c7ec6e62 100644 --- a/remux.c +++ b/remux.c @@ -4,7 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remux.c 1.1 2001/03/31 08:42:17 kls Exp $ + * The parts of this code that implement cTS2PES have been taken from + * the Linux DVB driver's 'tuxplayer' example and were rewritten to suit + * VDR's needs. + * + * $Id: remux.c 1.5 2001/06/24 16:37:23 kls Exp $ */ /* The calling interface of the 'cRemux::Process()' function is defined @@ -62,17 +66,390 @@ */ #include "remux.h" +#include "thread.h" #include "tools.h" -#if defined(REMUX_NONE) +// --- cTS2PES --------------------------------------------------------------- + +#include + +//XXX TODO: these should really be available in some driver header file! +#define PROG_STREAM_MAP 0xBC +#ifndef PRIVATE_STREAM1 +#define PRIVATE_STREAM1 0xBD +#endif +#define PADDING_STREAM 0xBE +#ifndef PRIVATE_STREAM2 +#define PRIVATE_STREAM2 0xBF +#endif +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +//pts_dts flags +#define PTS_ONLY 0x80 + +#define TS_SIZE 188 +#define PAY_START 0x40 +#define PID_MASK_HI 0x1F +//flags +#define ADAPT_FIELD 0x20 +//XXX TODO + +#define MAX_PLENGTH 0xFFFF +#define MMAX_PLENGTH (4*MAX_PLENGTH) + +#define IPACKS 2048 + +// Start codes: +#define SC_PICTURE 0x00 // "picture header" + +#define MAXNONUSEFULDATA (10*1024*1024) + +class cTS2PES { +private: + int size; + int found; + int count; + uint8_t *buf; + uint8_t cid; + uint8_t audioCid; + int plength; + uint8_t plen[2]; + uint8_t flag1; + uint8_t flag2; + uint8_t hlength; + int mpeg; + uint8_t check; + int which; + bool done; + uint8_t *resultBuffer; + int *resultCount; + static uint8_t headr[]; + void store(uint8_t *Data, int Count); + void reset_ipack(void); + void send_ipack(void); + void write_ipack(const uint8_t *Data, int Count); + void instant_repack(const uint8_t *Buf, int Count); +public: + cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid = 0x00); + ~cTS2PES(); + void ts_to_pes(const uint8_t *Buf); // don't need count (=188) + void Clear(void); + }; + +uint8_t cTS2PES::headr[] = { 0x00, 0x00, 0x01 }; -cRemux::cRemux(void) +cTS2PES::cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid) { + resultBuffer = ResultBuffer; + resultCount = ResultCount; + size = Size; + audioCid = AudioCid; + + if (!(buf = new uint8_t[size])) + esyslog(LOG_ERR, "Not enough memory for ts_transform"); + + reset_ipack(); +} + +cTS2PES::~cTS2PES() +{ + delete buf; +} + +void cTS2PES::Clear(void) +{ + reset_ipack(); +} + +void cTS2PES::store(uint8_t *Data, int Count) +{ + if (*resultCount + Count > RESULTBUFFERSIZE) { + esyslog(LOG_ERR, "ERROR: result buffer overflow (%d + %d > %d)", *resultCount, Count, RESULTBUFFERSIZE); + Count = RESULTBUFFERSIZE - *resultCount; + } + memcpy(resultBuffer + *resultCount, Data, Count); + *resultCount += Count; +} + +void cTS2PES::reset_ipack(void) +{ + found = 0; + cid = 0; + plength = 0; + flag1 = 0; + flag2 = 0; + hlength = 0; + mpeg = 0; + check = 0; + which = 0; + done = false; + count = 0; +} + +void cTS2PES::send_ipack(void) +{ + if (count < 10) + return; + buf[3] = (AUDIO_STREAM_S <= cid && cid <= AUDIO_STREAM_E && audioCid) ? audioCid : cid; + buf[4] = (uint8_t)(((count - 6) & 0xFF00) >> 8); + buf[5] = (uint8_t)((count - 6) & 0x00FF); + store(buf, count); + + switch (mpeg) { + case 2: + buf[6] = 0x80; + buf[7] = 0x00; + buf[8] = 0x00; + count = 9; + break; + case 1: + buf[6] = 0x0F; + count = 7; + break; + } +} + +void cTS2PES::write_ipack(const uint8_t *Data, int Count) +{ + if (count < 6) { + memcpy(buf, headr, 3); + count = 6; + } + + if (count + Count < size) { + memcpy(buf + count, Data, Count); + count += Count; + } + else { + int rest = size - count; + memcpy(buf + count, Data, rest); + count += rest; + send_ipack(); + if (Count - rest > 0) + write_ipack(Data + rest, Count - rest); + } +} + +void cTS2PES::instant_repack(const uint8_t *Buf, int Count) +{ + int c = 0; + + while (c < Count && (mpeg == 0 || (mpeg == 1 && found < 7) || (mpeg == 2 && found < 9)) && (found < 5 || !done)) { + switch (found ) { + case 0: + case 1: + if (Buf[c] == 0x00) + found++; + else + found = 0; + c++; + break; + case 2: + if (Buf[c] == 0x01) + found++; + else if (Buf[c] != 0) + found = 0; + c++; + break; + case 3: + cid = 0; + switch (Buf[c]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + done = true; + case PRIVATE_STREAM1: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + found++; + cid = Buf[c++]; + break; + default: + found = 0; + break; + } + break; + case 4: + if (Count - c > 1) { + unsigned short *pl = (unsigned short *)(Buf + c); + plength = ntohs(*pl); + c += 2; + found += 2; + } + else { + plen[0] = Buf[c]; + found++; + return; + } + break; + case 5: { + plen[1] = Buf[c++]; + unsigned short *pl = (unsigned short *)plen; + plength = ntohs(*pl); + found++; + } + break; + case 6: + if (!done) { + flag1 = Buf[c++]; + found++; + if ((flag1 & 0xC0) == 0x80 ) + mpeg = 2; + else { + esyslog(LOG_INFO, "ERROR: can't record MPEG1!"); + hlength = 0; + which = 0; + mpeg = 1; + flag2 = 0; + } + } + break; + case 7: + if (!done && mpeg == 2) { + flag2 = Buf[c++]; + found++; + } + break; + case 8: + if (!done && mpeg == 2) { + hlength = Buf[c++]; + found++; + } + break; + default: + break; + } + } + + if (!plength) + plength = MMAX_PLENGTH - 6; + + if (done || ((mpeg == 2 && found >= 9) || (mpeg == 1 && found >= 7))) { + switch (cid) { + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case PRIVATE_STREAM1: + + if (mpeg == 2 && found == 9) { + write_ipack(&flag1, 1); + write_ipack(&flag2, 1); + write_ipack(&hlength, 1); + } + + if (mpeg == 2 && (flag2 & PTS_ONLY) && found < 14) { + while (c < Count && found < 14) { + write_ipack(Buf + c, 1); + c++; + found++; + } + if (c == Count) + return; + } + + while (c < Count && found < plength + 6) { + int l = Count - c; + if (l + found > plength + 6) + l = plength + 6 - found; + write_ipack(Buf + c, l); + found += l; + c += l; + } + + break; + } + + if (done) { + if (found + Count - c < plength + 6) { + found += Count - c; + c = Count; + } + else { + c += plength + 6 - found; + found = plength + 6; + } + } + + if (plength && found == plength + 6) { + send_ipack(); + reset_ipack(); + if (c < Count) + instant_repack(Buf + c, Count - c); + } + } + return; +} + +void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188) +{ + if (!Buf) + return; + + if (Buf[1] & PAY_START) { + if (plength == MMAX_PLENGTH - 6 && found > 6) { + plength = found - 6; + found = 0; + send_ipack(); + reset_ipack(); + } + } + + uint8_t off = 0; + + if (Buf[3] & ADAPT_FIELD) { // adaptation field? + off = Buf[4] + 1; + if (off + 4 > 187) + return; + } + + instant_repack(Buf + 4 + off, TS_SIZE - 4 - off); +} + +// --- cRemux ---------------------------------------------------------------- + +cRemux::cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure) +{ + vPid = VPid; + aPid1 = APid1; + aPid2 = APid2; + dPid1 = DPid1; + dPid2 = DPid2; + exitOnFailure = ExitOnFailure; synced = false; + skipped = 0; + resultCount = resultDelivered = 0; + vTS2PES = new cTS2PES(resultBuffer, &resultCount, IPACKS); + aTS2PES1 = new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC0); + aTS2PES2 = aPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC1) : NULL; + dTS2PES1 = dPid1 ? new cTS2PES(resultBuffer, &resultCount, IPACKS) : NULL; + //XXX don't yet know how to tell apart primary and secondary DD data... + dTS2PES2 = /*XXX dPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS) : XXX*/ NULL; } cRemux::~cRemux() { + delete vTS2PES; + delete aTS2PES1; + delete aTS2PES2; + delete dTS2PES1; + delete dTS2PES2; +} + +int cRemux::GetPid(const uchar *Data) +{ + return (((uint16_t)Data[0] & PID_MASK_HI) << 8) | (Data[1] & 0xFF); } int cRemux::GetPacketLength(const uchar *Data, int Count, int Offset) @@ -104,70 +481,140 @@ int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &Pic return -1; } -const uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar &PictureType) +void cRemux::SetAudioPid(int APid) { - int Skip = 0; + aPid1 = APid; + vTS2PES->Clear(); + aTS2PES1->Clear(); + resultCount = resultDelivered = 0; +} - PictureType = NO_PICTURE; +const uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar *PictureType) +{ + uchar dummyPictureType; + if (!PictureType) + PictureType = &dummyPictureType; - if (Count >= MINVIDEODATA) { - for (int i = 0; i < Count; i++) { - if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { - switch (Data[i + 3]) { - case SC_VIDEO: +/*XXX + // test recording the raw TS: + Result = Count; + *PictureType = I_FRAME; + return Data; +XXX*/ + + // Remove any previously delivered data from the result buffer: + + if (resultDelivered) { + if (resultDelivered < resultCount) + memmove(resultBuffer, resultBuffer + resultDelivered, resultCount - resultDelivered); + resultCount -= resultDelivered; + resultDelivered = 0; + } + + // Convert incoming TS data into multiplexed PES: + + int used = 0; + for (int i = 0; i < Count; i += TS_SIZE) { + if (Count - i < TS_SIZE) + break; + int pid = GetPid(Data + i + 1); + if (Data[i + 3] & 0x10) { // got payload + if (pid == vPid) vTS2PES->ts_to_pes(Data + i); + else if (pid == aPid1) aTS2PES1->ts_to_pes(Data + i); + else if (pid == aPid2 && aTS2PES2) aTS2PES2->ts_to_pes(Data + i); + else if (pid == dPid1 && dTS2PES1) dTS2PES1->ts_to_pes(Data + i); + else if (pid == dPid2 && dTS2PES2) dTS2PES2->ts_to_pes(Data + i); + } + used += TS_SIZE; + if (resultCount > (int)sizeof(resultBuffer) / 2) + break; + } + Count = used; + +/*XXX + // test recording without determining the real frame borders: + *PictureType = I_FRAME; + Result = resultDelivered = resultCount; + return Result ? resultBuffer : NULL; +XXX*/ + + // Check if we're getting anywhere here: + + if (!synced && skipped >= 0) { + if (skipped > MAXNONUSEFULDATA) { + esyslog(LOG_ERR, "ERROR: no useful data seen within %d byte of video stream", skipped); + skipped = -1; + if (exitOnFailure) + cThread::EmergencyExit(true); + } + else + skipped += Count; + } + + // Check for frame borders: + + *PictureType = NO_PICTURE; + + if (resultCount >= MINVIDEODATA) { + for (int i = 0; i < resultCount; i++) { + if (resultBuffer[i] == 0 && resultBuffer[i + 1] == 0 && resultBuffer[i + 2] == 1) { + switch (resultBuffer[i + 3]) { + case VIDEO_STREAM_S ... VIDEO_STREAM_E: { uchar pt = NO_PICTURE; - int l = ScanVideoPacket(Data, Count, i, pt); - if (l < 0) { - if (Skip < Count) - Count = Skip; + int l = ScanVideoPacket(resultBuffer, resultCount, i, pt); + if (l < 0) return NULL; // no useful data found, wait for more - } if (pt != NO_PICTURE) { if (pt < I_FRAME || B_FRAME < pt) { esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); } - else if (PictureType == NO_PICTURE) { - if (!synced) { - if (pt == I_FRAME) { - Skip = i; - synced = true; - } - else { - i += l; - Skip = i; - break; - } + else if (!synced) { + if (pt == I_FRAME) { + resultDelivered = i; // will drop everything before this position + synced = true; + } + else { + resultDelivered = i + l; // will drop everything before and including this packet + return NULL; } - if (synced) - PictureType = pt; - } - else { - Count = i; - Result = i - Skip; - return Data + Skip; } } - else if (!synced) { - i += l; - Skip = i; - break; + if (synced) { + *PictureType = pt; + Result = l; + const uchar *p = resultBuffer + resultDelivered; + resultDelivered += l; + return p; + } + else { + resultDelivered = i + l; // will drop everything before and including this packet + return NULL; } - i += l - 1; // -1 to compensate for i++ in the loop! } break; - case SC_AUDIO: - i += GetPacketLength(Data, Count, i) - 1; // -1 to compensate for i++ in the loop! + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + { + int l = GetPacketLength(resultBuffer, resultCount, i); + if (l < 0) + return NULL; // no useful data found, wait for more + if (synced) { + Result = l; + const uchar *p = resultBuffer + resultDelivered; + resultDelivered += l; + return p; + } + else { + resultDelivered = i + l; // will drop everything before and including this packet + return NULL; + } + } break; } } } } - if (Skip < Count) - Count = Skip; return NULL; // no useful data found, wait for more } -#elif defined(REMUX_TEST) -#endif - diff --git a/remux.h b/remux.h index bceb676bf..792469e5c 100644 --- a/remux.h +++ b/remux.h @@ -4,16 +4,14 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remux.h 1.1 2001/03/31 08:42:27 kls Exp $ + * $Id: remux.h 1.5 2001/06/23 14:06:59 kls Exp $ */ #ifndef __REMUX_H #define __REMUX_H -// There are various experiments with different types of remultiplexers -// going on at the moment. Select the remultiplexer here: -#define REMUX_NONE 1 -//#define REMUX_TEST 1 +#include //XXX FIXME: DVB/ost/include/ost/dmx.h should include itself!!! +#include // Picture types: #define NO_PICTURE 0 @@ -21,31 +19,32 @@ #define P_FRAME 2 #define B_FRAME 3 -// Start codes: -#define SC_PICTURE 0x00 // "picture header" -#define SC_SEQU 0xB3 // "sequence header" -#define SC_PHEAD 0xBA // "pack header" -#define SC_SHEAD 0xBB // "system header" -#define SC_AUDIO 0xC0 -#define SC_VIDEO 0xE0 - // The minimum amount of video data necessary to identify frames: -#define MINVIDEODATA (256*1024) // just a safe guess (max. size of any frame block, plus some safety) +#define MINVIDEODATA (16*1024) // just a safe guess (max. size of any frame block, plus some safety) + +#define RESULTBUFFERSIZE (MINVIDEODATA * 4) typedef unsigned char uchar; +class cTS2PES; class cRemux { private: -#if defined(REMUX_NONE) + bool exitOnFailure; bool synced; + int skipped; + int vPid, aPid1, aPid2, dPid1, dPid2; + cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2, *dTS2PES1, *dTS2PES2; + uchar resultBuffer[RESULTBUFFERSIZE]; + int resultCount; + int resultDelivered; + int GetPid(const uchar *Data); int GetPacketLength(const uchar *Data, int Count, int Offset); int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType); -#elif defined(REMUX_TEST) -#endif public: - cRemux(void); + cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure = false); ~cRemux(); - const uchar *Process(const uchar *Data, int &Count, int &Result, uchar &PictureType); + void SetAudioPid(int APid); + const uchar *Process(const uchar *Data, int &Count, int &Result, uchar *PictureType = NULL); }; #endif // __REMUX_H diff --git a/ringbuffer.c b/ringbuffer.c index 48707133c..8511a1c23 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -7,7 +7,7 @@ * Parts of this file were inspired by the 'ringbuffy.c' from the * LinuxDVB driver (see linuxtv.org). * - * $Id: ringbuffer.c 1.1 2001/03/10 17:11:34 kls Exp $ + * $Id: ringbuffer.c 1.2 2001/05/20 11:58:08 kls Exp $ */ #include "ringbuffer.h" @@ -37,9 +37,10 @@ class cRingBufferOutputThread : public cThread { // --- cRingBuffer ------------------------------------------------------------ -cRingBuffer::cRingBuffer(int Size) +cRingBuffer::cRingBuffer(int Size, bool Statistics) { size = Size; + statistics = Statistics; buffer = NULL; inputThread = NULL; outputThread = NULL; @@ -60,7 +61,17 @@ cRingBuffer::~cRingBuffer() delete inputThread; delete outputThread; delete buffer; - dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1)); + if (statistics) + dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1)); +} + +int cRingBuffer::Available(void) +{ + mutex.Lock(); + int diff = head - tail; + int cont = (diff >= 0) ? diff : size + diff; + mutex.Unlock(); + return cont; } void cRingBuffer::Clear(void) @@ -78,17 +89,17 @@ int cRingBuffer::Put(const uchar *Data, int Count) int diff = tail - head; mutex.Unlock(); int free = (diff > 0) ? diff - 1 : size + diff - 1; - // Statistics: - int fill = size - free - 1 + Count; - if (fill >= size) - fill = size - 1; - if (fill > maxFill) { - maxFill = fill; - int percent = maxFill * 100 / (size - 1); - if (percent > 75) - dsyslog(LOG_INFO, "buffer usage: %d%%", percent); + if (statistics) { + int fill = size - free - 1 + Count; + if (fill >= size) + fill = size - 1; + if (fill > maxFill) { + maxFill = fill; + int percent = maxFill * 100 / (size - 1); + if (percent > 75) + dsyslog(LOG_INFO, "buffer usage: %d%%", percent); + } } - // if (free <= 0) return 0; if (free < Count) diff --git a/ringbuffer.h b/ringbuffer.h index 1669a4946..49be769c2 100644 --- a/ringbuffer.h +++ b/ringbuffer.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ringbuffer.h 1.1 2001/03/10 14:00:59 kls Exp $ + * $Id: ringbuffer.h 1.2 2001/05/20 11:56:44 kls Exp $ */ #ifndef __RINGBUFFER_H @@ -28,7 +28,11 @@ class cRingBuffer { uchar *buffer; int maxFill; bool busy; + bool statistics; protected: + void Lock(void) { mutex.Lock(); } + void Unlock(void) { mutex.Unlock(); } + int Available(void); bool Busy(void) { return busy; } void Clear(void); // Immediately clears the ring buffer. @@ -45,7 +49,7 @@ class cRingBuffer { // Runs as a separate thread and shall continuously call Get() to // retrieve data from the ring buffer and write it to a destination. public: - cRingBuffer(int Size); + cRingBuffer(int Size, bool Statistics = false); virtual ~cRingBuffer(); bool Start(void); bool Active(void); diff --git a/runvdr b/runvdr index 5ec345854..afd645fc4 100755 --- a/runvdr +++ b/runvdr @@ -1,18 +1,44 @@ #!/bin/sh +# runvdr: Loads the DVB driver and runs VDR +# +# If VDR exits abnormally, the driver will be reloaded +# and VDR restarted. +# +# Set the environment variable VDRUSR to the user id you +# want VDR to run with. If VDRUSR is not set, VDR will run +# as 'root', which is not necessarily advisable. +# +# Since this script loads the DVB driver, it must be started +# as user 'root'. +# +# Any command line parameters will be passed on to the +# actual 'vdr' program. +# +# See the main source file 'vdr.c' for copyright information and +# how to reach the author. +# +# $Id: runvdr 1.8 2001/07/27 07:35:19 kls Exp $ + DVBDIR="../DVB/driver" VDRPRG="./vdr" -VDRCMD="$VDRPRG -w 60" +VDRCMD="$VDRPRG -w 60 $*" +LSMOD="`/sbin/lsmod | grep -w '^dvb' | wc -l`" KILLPROC="/sbin/killproc -TERM" +# Load driver if it hasn't been loaded already: +if [ $LSMOD -eq 0 ] ; then + (cd $DVBDIR; make insmod) + fi + while (true) do -# (cd $DVBDIR; make reload) -# sleep 3 - $VDRCMD - if test $? -ne 1; then exit; fi + su -c "$VDRCMD" $VDRUSR + if test $? -eq 0; then exit; fi date echo "restarting VDR" $KILLPROC $VDRPRG sleep 10 + (cd $DVBDIR; make rmmod; make insmod) + date done diff --git a/svdrp.c b/svdrp.c index df4ffaccb..a626fdade 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.18 2001/04/01 16:06:54 kls Exp $ + * $Id: svdrp.c 1.20 2001/07/22 13:58:48 kls Exp $ */ #define _GNU_SOURCE @@ -941,7 +941,7 @@ void cSVDRP::Process(void) if (numChars > 0) numChars--; } - else if (c <= 0x03 || c == 0x0D || 0xF0 <= c) { + else if (c <= 0x03 || c == 0x0D) { // ignore control characters } else if (numChars < sizeof(cmdLine) - 1) { @@ -955,8 +955,10 @@ void cSVDRP::Process(void) } lastActivity = time(NULL); } - else if (r < 0) + else if (r <= 0) { + isyslog(LOG_INFO, "lost connection to SVDRP client"); Close(); + } } else if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) { isyslog(LOG_INFO, "timeout on SVDRP connection"); diff --git a/thread.c b/thread.c index 363190d84..e253ea042 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.7 2000/12/24 12:27:21 kls Exp $ + * $Id: thread.c 1.9 2001/06/27 11:34:41 kls Exp $ */ #include "thread.h" @@ -14,12 +14,43 @@ #include #include "tools.h" +// --- cMutex ---------------------------------------------------------------- + +cMutex::cMutex(void) +{ + lockingPid = 0; + locked = 0; + pthread_mutex_init(&mutex, NULL); +} + +cMutex::~cMutex() +{ + pthread_mutex_destroy(&mutex); +} + +void cMutex::Lock(void) +{ + if (getpid() != lockingPid || !locked) + pthread_mutex_lock(&mutex); + lockingPid = getpid(); + locked++; +} + +void cMutex::Unlock(void) +{ + if (!--locked) + pthread_mutex_unlock(&mutex); +} + // --- cThread --------------------------------------------------------------- // The signal handler is necessary to be able to use SIGIO to wake up any // pending 'select()' call. +time_t cThread::lastPanic = 0; +int cThread::panicLevel = 0; bool cThread::signalHandlerInstalled = false; +bool cThread::emergencyExitRequested = false; cThread::cThread(void) { @@ -110,6 +141,33 @@ void cThread::WakeUp(void) kill(parentPid, SIGIO); // makes any waiting 'select()' call return immediately } +#define MAXPANICLEVEL 10 + +void cThread::RaisePanic(void) +{ + if (lastPanic > 0) { + if (time(NULL) - lastPanic < 5) + panicLevel++; + else if (panicLevel > 0) + panicLevel--; + } + lastPanic = time(NULL); + if (panicLevel > MAXPANICLEVEL) { + esyslog(LOG_ERR, "ERROR: max. panic level exceeded"); + EmergencyExit(true); + } + else + dsyslog(LOG_INFO, "panic level: %d", panicLevel); +} + +bool cThread::EmergencyExit(bool Request) +{ + if (!Request) + return emergencyExitRequested; + esyslog(LOG_ERR, "initiating emergency exit"); + return emergencyExitRequested = true; // yes, it's an assignment, not a comparison! +} + // --- cThreadLock ----------------------------------------------------------- cThreadLock::cThreadLock(cThread *Thread) diff --git a/thread.h b/thread.h index 6aaee0b90..bf9804d33 100644 --- a/thread.h +++ b/thread.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.4 2000/12/03 11:18:37 kls Exp $ + * $Id: thread.h 1.6 2001/06/27 11:22:04 kls Exp $ */ #ifndef __THREAD_H @@ -16,11 +16,13 @@ class cMutex { private: pthread_mutex_t mutex; + pid_t lockingPid; + int locked; public: - cMutex(void) { pthread_mutex_init(&mutex, NULL); } - ~cMutex() { pthread_mutex_destroy(&mutex); } - void Lock(void) { pthread_mutex_lock(&mutex); } - void Unlock(void) { pthread_mutex_unlock(&mutex); } + cMutex(void); + ~cMutex(); + void Lock(void); + void Unlock(void); }; class cThread { @@ -31,6 +33,9 @@ class cThread { pid_t parentPid, threadPid, lockingPid; int locked; bool running; + static time_t lastPanic; + static int panicLevel; + static bool emergencyExitRequested; static bool signalHandlerInstalled; static void SignalHandler(int signum); static void *StartThread(cThread *Thread); @@ -45,6 +50,8 @@ class cThread { virtual ~cThread(); bool Start(void); bool Active(void); + static void RaisePanic(void); + static bool EmergencyExit(bool Request = false); }; // cThreadLock can be used to easily set a lock in a thread and make absolutely diff --git a/tools.c b/tools.c index c303a8ab8..de1a52c39 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.32 2001/04/01 14:13:36 kls Exp $ + * $Id: tools.c 1.34 2001/05/20 08:30:54 kls Exp $ */ #define _GNU_SOURCE @@ -120,7 +120,7 @@ const char *AddDirectory(const char *DirName, const char *FileName) return buf; } -#define DFCMD "df -m '%s'" +#define DFCMD "df -m -P '%s'" uint FreeDiskSpaceMB(const char *Directory) { @@ -132,7 +132,7 @@ uint FreeDiskSpaceMB(const char *Directory) if (p) { char *s; while ((s = readline(p)) != NULL) { - if (*s == '/') { + if (strchr(s, '/')) { uint available; sscanf(s, "%*s %*d %*d %u", &available); Free = available; @@ -411,6 +411,22 @@ bool cFile::FileReady(int FileDes, int TimeoutMs) return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set); } +bool cFile::FileReadyForWriting(int FileDes, int TimeoutMs) +{ +#ifdef DEBUG_OSD + refresh(); +#endif + fd_set set; + struct timeval timeout; + FD_ZERO(&set); + FD_SET(FileDes, &set); + if (TimeoutMs < 100) + TimeoutMs = 100; + timeout.tv_sec = 0; + timeout.tv_usec = TimeoutMs * 1000; + return select(FD_SETSIZE, NULL, &set, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set); +} + // --- cSafeFile ------------------------------------------------------------- cSafeFile::cSafeFile(const char *FileName) diff --git a/tools.h b/tools.h index a9d61218f..b4a0cb672 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.25 2001/04/01 14:13:42 kls Exp $ + * $Id: tools.h 1.26 2001/05/20 08:29:45 kls Exp $ */ #ifndef __TOOLS_H @@ -67,6 +67,7 @@ class cFile { bool Ready(bool Wait = true); static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000); static bool FileReady(int FileDes, int TimeoutMs = 1000); + static bool FileReadyForWriting(int FileDes, int TimeoutMs = 1000); }; class cSafeFile { diff --git a/vdr.c b/vdr.c index 8ed209a63..12b1a5381 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.56 2001/04/01 11:16:54 kls Exp $ + * $Id: vdr.c 1.58 2001/06/23 12:29:41 kls Exp $ */ #include @@ -77,6 +77,7 @@ int main(int argc, char *argv[]) char *Terminal = NULL; static struct option long_options[] = { + { "audio", required_argument, NULL, 'a' }, { "config", required_argument, NULL, 'c' }, { "daemon", no_argument, NULL, 'd' }, { "device", required_argument, NULL, 'D' }, @@ -91,8 +92,10 @@ int main(int argc, char *argv[]) int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "c:dD:hl:p:v:w:t:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:hl:p:v:w:t:", long_options, &option_index)) != -1) { switch (c) { + case 'a': cDvbApi::SetAudioCommand(optarg); + break; case 'c': ConfigDirectory = optarg; break; case 'd': DaemonMode = true; break; @@ -107,6 +110,7 @@ int main(int argc, char *argv[]) return 2; break; case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80| + " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n" " -c DIR, --config=DIR read config files from DIR (default is to read them\n" " from the video directory)\n" " -h, --help display this help and exit\n" @@ -267,6 +271,11 @@ int main(int argc, char *argv[]) } while (!Interrupted) { + // Handle emergency exits: + if (cThread::EmergencyExit()) { + esyslog(LOG_ERR, "emergency exit requested - shutting down"); + break; + } // Restart the Watchdog timer: if (WatchdogTimeout > 0) { int LatencyTime = WatchdogTimeout - alarm(WatchdogTimeout); @@ -388,7 +397,8 @@ int main(int argc, char *argv[]) else LastActivity = time(NULL); } - isyslog(LOG_INFO, "caught signal %d", Interrupted); + if (Interrupted) + isyslog(LOG_INFO, "caught signal %d", Interrupted); Setup.CurrentChannel = cDvbApi::CurrentChannel(); Setup.Save(); cVideoCutter::Stop(); @@ -401,5 +411,9 @@ int main(int argc, char *argv[]) isyslog(LOG_INFO, "exiting"); if (SysLogLevel > 0) closelog(); + if (cThread::EmergencyExit()) { + esyslog(LOG_ERR, "emergency exit!"); + return 1; + } return 0; } diff --git a/videodir.c b/videodir.c index 2824d04e3..6f35a3dcc 100644 --- a/videodir.c +++ b/videodir.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: videodir.c 1.4 2001/02/11 13:48:30 kls Exp $ + * $Id: videodir.c 1.5 2001/05/01 09:48:57 kls Exp $ */ #include "videodir.h" @@ -137,7 +137,7 @@ int OpenVideoFile(const char *FileName, int Flags) } } } - int Result = open(ActualFileName, Flags, S_IRUSR | S_IWUSR | S_IRGRP); + int Result = open(ActualFileName, Flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (ActualFileName != FileName) delete ActualFileName; return Result; From f1d1c9849c8e27cccb46cf9c0d0ccb59da3f91f9 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Mon, 6 Aug 2001 18:00:00 +0200 Subject: [PATCH 020/307] Version 0.90 - Modified the display of the channel group separators (thanks to Markus Lang for this suggestion). - Added support for replaying DVDs (thanks to Andreas Schultz). See INSTALL for instructions on how to compile VDR with DVD support. - Fixed replay progress display in case replay is paused while watching an ongoing recording. - Ringbuffer uses semaphores to signal empty/full conditions. - Fixed calculating the timeout value in cFile::FileReady() (thanks to Wolfgang Henselmann-Weiss). --- CONTRIBUTORS | 10 + HISTORY | 12 + INSTALL | 24 +- MANUAL | 2 +- Makefile | 51 +- Tools/master-timer/LIESMICH | 106 ++ Tools/master-timer/README | 52 + Tools/master-timer/Todo | 10 + Tools/master-timer/master-timer.pl | 1169 ++++++++++++++++ Tools/master-timer/process_summary.pl | 79 ++ Tools/master-timer/sample/channels-to-scan | 8 + Tools/master-timer/sample/config | 14 + Tools/master-timer/sample/deepblack | 79 ++ Tools/master-timer/sample/done | 1 + Tools/master-timer/sample/subtitle-movie | 41 + Tools/master-timer/sample/torecord | 32 + Tools/master-timer/scan-channels | 8 + Tools/schnitt/cut2.pl | 39 + Tools/schnitt/cut3.pl | 40 + Tools/schnitt/cutall3.pl | 31 + Tools/schnitt/dump.c | 65 + Tools/schnitt/play | 10 + ac3dec/Makefile | 22 + ac3dec/ac3.h | 60 + ac3dec/ac3_internal.h | 344 +++++ ac3dec/bit_allocate.c | 494 +++++++ ac3dec/bit_allocate.h | 24 + ac3dec/bitstream.c | 76 + ac3dec/bitstream.h | 76 + ac3dec/coeff.c | 353 +++++ ac3dec/coeff.h | 24 + ac3dec/crc.c | 96 ++ ac3dec/crc.h | 27 + ac3dec/debug.c | 58 + ac3dec/debug.h | 37 + ac3dec/decode.c | 269 ++++ ac3dec/decode.h | 22 + ac3dec/dither.c | 115 ++ ac3dec/dither.h | 37 + ac3dec/downmix.c | 428 ++++++ ac3dec/downmix.h | 28 + ac3dec/exponent.c | 135 ++ ac3dec/exponent.h | 28 + ac3dec/imdct.c | 468 +++++++ ac3dec/imdct.h | 26 + ac3dec/parse.c | 597 ++++++++ ac3dec/parse.h | 28 + ac3dec/rematrix.c | 83 ++ ac3dec/rematrix.h | 25 + ac3dec/sanity_check.c | 131 ++ ac3dec/sanity_check.h | 27 + ac3dec/stats.c | 178 +++ ac3dec/stats.h | 27 + channels.conf | 2 +- config.h | 4 +- dvbapi.c | 1451 ++++++++++++++++---- dvbapi.h | 19 +- dvd.c | 148 ++ dvd.h | 53 + i18n.c | 22 +- menu.c | 201 ++- menu.h | 28 +- osd.c | 3 +- osd.h | 9 +- ringbuffer.c | 253 +++- ringbuffer.h | 84 +- thread.c | 39 +- thread.h | 17 +- tools.c | 6 +- vdr.c | 46 +- 70 files changed, 8206 insertions(+), 405 deletions(-) create mode 100644 Tools/master-timer/LIESMICH create mode 100644 Tools/master-timer/README create mode 100644 Tools/master-timer/Todo create mode 100755 Tools/master-timer/master-timer.pl create mode 100755 Tools/master-timer/process_summary.pl create mode 100644 Tools/master-timer/sample/channels-to-scan create mode 100644 Tools/master-timer/sample/config create mode 100644 Tools/master-timer/sample/deepblack create mode 100644 Tools/master-timer/sample/done create mode 100644 Tools/master-timer/sample/subtitle-movie create mode 100644 Tools/master-timer/sample/torecord create mode 100755 Tools/master-timer/scan-channels create mode 100755 Tools/schnitt/cut2.pl create mode 100755 Tools/schnitt/cut3.pl create mode 100755 Tools/schnitt/cutall3.pl create mode 100644 Tools/schnitt/dump.c create mode 100755 Tools/schnitt/play create mode 100644 ac3dec/Makefile create mode 100644 ac3dec/ac3.h create mode 100644 ac3dec/ac3_internal.h create mode 100644 ac3dec/bit_allocate.c create mode 100644 ac3dec/bit_allocate.h create mode 100644 ac3dec/bitstream.c create mode 100644 ac3dec/bitstream.h create mode 100644 ac3dec/coeff.c create mode 100644 ac3dec/coeff.h create mode 100644 ac3dec/crc.c create mode 100644 ac3dec/crc.h create mode 100644 ac3dec/debug.c create mode 100644 ac3dec/debug.h create mode 100644 ac3dec/decode.c create mode 100644 ac3dec/decode.h create mode 100644 ac3dec/dither.c create mode 100644 ac3dec/dither.h create mode 100644 ac3dec/downmix.c create mode 100644 ac3dec/downmix.h create mode 100644 ac3dec/exponent.c create mode 100644 ac3dec/exponent.h create mode 100644 ac3dec/imdct.c create mode 100644 ac3dec/imdct.h create mode 100644 ac3dec/parse.c create mode 100644 ac3dec/parse.h create mode 100644 ac3dec/rematrix.c create mode 100644 ac3dec/rematrix.h create mode 100644 ac3dec/sanity_check.c create mode 100644 ac3dec/sanity_check.h create mode 100644 ac3dec/stats.c create mode 100644 ac3dec/stats.h create mode 100644 dvd.c create mode 100644 dvd.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 676cf8991..46a84101f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -106,3 +106,13 @@ Ulrich R Helmut Schchner for his support in keeping the Premiere World channels up to date in 'channels.conf' + +Andreas Schultz + for adding support for replaying DVDs (much of this was derived from + dvdplayer-0.5 by Matjaz Thaler ) + +Aaron Holtzman + for writing 'ac3dec' + +Wolfgang Henselmann-Weiss + for fixing calculating the timeout value in cFile::FileReady() diff --git a/HISTORY b/HISTORY index d625b260f..041e4423f 100644 --- a/HISTORY +++ b/HISTORY @@ -609,3 +609,15 @@ Video Disk Recorder Revision History - Increased timeout until reporting "video data stream broken" when recording. - Explicitly switching back to the previously active channel after ending a replay session (to have it shown correctly in case it was in 'Transfer Mode'). + +2001-08-06: Version 0.90 + +- Modified the display of the channel group separators (thanks to Markus Lang + for this suggestion). +- Added support for replaying DVDs (thanks to Andreas Schultz). See INSTALL for + instructions on how to compile VDR with DVD support. +- Fixed replay progress display in case replay is paused while watching an + ongoing recording. +- Ringbuffer uses semaphores to signal empty/full conditions. +- Fixed calculating the timeout value in cFile::FileReady() (thanks to + Wolfgang Henselmann-Weiss). diff --git a/INSTALL b/INSTALL index 28037eb36..86b4a1eee 100644 --- a/INSTALL +++ b/INSTALL @@ -15,7 +15,16 @@ If you have the DVB driver source in a different location you will have to change the definition of DVBDIR in the Makefile. -This program requires the card driver version 0.9.0 or higher +If you want to use your DVD drive you will need to compile VDR with + + make DVD=1 + +to activate DVD support. VDR then also needs the package 'libdvdread' +in order to replay DVDs. This package is expected to be located in the +directory ../DVD (seen from the VDR directory). Adjust the definition +of DVDDIR in the Makefile if necessary. + +VDR requires the card driver version 0.9.0 or higher to work properly. You need to load the dvb.o module *without* option 'outstream=0' (previous versions of VDR required this option to have the driver supply the data in AV_PES format; as of version 0.70 VDR @@ -100,6 +109,19 @@ This program must be given to VDR with the '-a' option, as in vdr -a ac3play +Accessing the DVD drive: +------------------------ + +By default VDR expects the DVD drive to be located at /dev/dvd (which +typically is a symbolic link to the actual device, for instance /dev/hdc). +You can use the '-V' option to overwrite this, as in + + vdr -V /media/dvd + +Note that the user id under which VDR runs needs to have write access to +the DVD device in order to replay CSS protected DVDs (which also requires +the presence of the 'libcss' library). + The video data directory: ------------------------- diff --git a/MANUAL b/MANUAL index c59f3fefc..59ff57c93 100644 --- a/MANUAL +++ b/MANUAL @@ -19,7 +19,7 @@ Video Disk Recorder User's Manual Back - Menu off Main menu Main menu Discard Main menu Recordings menu Red - Record Edit Edit - Play - Green - Language New New - Rewind Skip -60s - Yellow - - Delete Delete - Delete Skip +60s + Yellow - Eject DVD Delete Delete - Delete Skip +60s Blue - Resume Mark Mark - Summary Stop 0..9 Ch select - - - Numeric inp. - Editing diff --git a/Makefile b/Makefile index 507de2146..891871741 100644 --- a/Makefile +++ b/Makefile @@ -4,12 +4,24 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.22 2001/06/02 09:15:39 kls Exp $ +# $Id: Makefile 1.24 2001/08/06 16:13:42 kls Exp $ DVBDIR = ../DVB +DVDDIR = ../DVD +AC3DIR = ./ac3dec INCLUDES = -I$(DVBDIR)/ost/include -OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o osd.o\ + +ifdef DVD +INCLUDES += -I$(DVDDIR)/libdvdread +LIBDIRS += -L$(DVDDIR)/libdvdread/dvdread/.libs +DEFINES += -DDVDSUPPORT +DEFINES += -D_LARGEFILE64_SOURCE # needed by libdvdread +AC3LIB = $(AC3DIR)/libac3.a +DVDLIB = -ldvdread +endif + +OBJS = config.o dvbapi.o dvbosd.o dvd.o eit.o font.o i18n.o interface.o menu.o osd.o\ recording.o remote.o remux.o ringbuffer.o svdrp.o thread.o tools.o vdr.o\ videodir.o @@ -42,29 +54,30 @@ font: genfontfile fontfix.c fontosd.c # Dependencies: -config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h recording.h remux.h ringbuffer.h thread.h tools.h videodir.h +config.o : config.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h +dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h recording.h remux.h ringbuffer.h thread.h tools.h videodir.h dvbosd.o : dvbosd.c dvbosd.h font.h tools.h -eit.o : eit.c config.h dvbapi.h dvbosd.h eit.h font.h thread.h tools.h videodir.h +dvd.o : dvd.c dvd.h +eit.o : eit.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h thread.h tools.h videodir.h font.o : font.c font.h fontfix.c fontosd.c tools.h -i18n.o : i18n.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h thread.h tools.h -interface.o : interface.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h -osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h -recording.o : recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h -remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h +i18n.o : i18n.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h thread.h tools.h +interface.o : interface.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h +menu.o : menu.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h +osd.o : osd.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h +recording.o : recording.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h +remote.o : remote.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h remote.h thread.h tools.h remux.o : remux.c remux.h thread.h tools.h ringbuffer.o: ringbuffer.c ringbuffer.h thread.h tools.h -svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h +svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h thread.o : thread.c thread.h tools.h tools.o : tools.c tools.h -vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h +vdr.o : vdr.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h videodir.o : videodir.c tools.h videodir.h # The main program: -vdr: $(OBJS) - g++ -g -O2 $(OBJS) -lncurses -ljpeg -lpthread -o vdr +vdr: $(OBJS) $(AC3LIB) + g++ -g -O2 $(OBJS) -lncurses -ljpeg -lpthread $(LIBDIRS) $(DVDLIB) $(AC3LIB) -o vdr # The font files: @@ -80,9 +93,15 @@ genfontfile.o: genfontfile.c genfontfile: genfontfile.o gcc -o $@ -L/usr/X11R6/lib $< -lX11 +# The ac3dec library: + +$(AC3LIB): + make -C $(AC3DIR) all + # Housekeeping: clean: - -rm -f $(OBJS) vdr genfontfile genfontfile.o core + make -C $(AC3DIR) clean + -rm -f $(OBJS) vdr genfontfile genfontfile.o core *~ CLEAN: clean -rm -f fontfix.c fontosd.c diff --git a/Tools/master-timer/LIESMICH b/Tools/master-timer/LIESMICH new file mode 100644 index 000000000..969487507 --- /dev/null +++ b/Tools/master-timer/LIESMICH @@ -0,0 +1,106 @@ + Master-Timer + ============ + + +1. Einleitung +------------- + +Master-Timer ist ein System zum automatischen Aufnehmen von Serien und Filmen. + +2. Voraussetzungen +------------------ + +VDR liefert die "epg.data". + +3. Konfigurationsdateien +------------------------ + +Alle Konfigurationsdateien liegen unter ".master-timer" + +config: Eine Ansammlung von Key-Value Paaren. Alle sind "optional" und + erhalten dann die angegebenen Default-Werte + +(# = Kommentarzeilen) +marginstart (Default 600) + Anzahl der "Sicherheits" Sekunden die ein Timer frueher beginnen soll + +marginstop (Default 600) + Anzahl der "Sicherheits" Sekunden die ein Timer laenger dauern soll + +defaultprio (Default 50) + Die Prioritaet die fuer Timer verwendet wird wo keine Prioritaet + angegeben ist + +DVBCards (Default 1) + Anzahl der vorhandenen DVB-Karten (Derzeit nicht verwendet) + +Dest-Host (Default "localhost") + Host-name oder IP des Rechners auf dem VDR laeuft + +Dest-Port (Default "2001") + Port der VDR verwendet + +jointimers (Default 0) + Sollen aufeinanderfolgende Timer auf den gleichen Kanal zusammengefasst + werden (0 = "Nein", alles andere "Ja") + +debug (Default 0) + Debug-Level, die einzelnen Debug-Werte muessen aus folgenden Werten + zusammengezaehlt werden + 1 : Dump "torecord" + 2 : Dump all timers + 4 : Show when a timer will be deleted + 8 : Dump the "Done" REs + 16 : Verbose Config-Reading + +deepblack: Eine Liste von Titeln die man NIEMALS NIMMER sehen will + Jede Zeile = 1 Titel + +subtitle-movies: Eine Liste der "Subtitel" die ein Zeichen fuer einen Film sind + (Soweit die von den Sendern richtig ausgefuellt sind.) + Jede Zeile = 1 Subtitel + +torecord: Die Sachen die man Aufnehmen will + Jede Zeile = 1 Timer +# Format: (Every field is "optional". +# [Title RE|Subtitle RE|Description RE|Channel-Name|Timeframe|Prio|Timer-Title] +# +# To record something at least one of the "Title", "Subtitle" or "Description" +# Fields has to be provided. This 3 fields are "include" and the rest are +# "exclude" fields! +# +# More than one channel definition can be provided. The delimiter is ";" +# Additionaly you can make a "blacklist" of Channels when you prepent a "!" to the first Channel Definition +# The "!" is only tested for the FIRST Channel definition. +# You can only have a white or a blacklist (Mixing doesn't make sense!) +# +# ex. Record the series "Deep Space Nine" on Sci-Fantasy in the timeframe 09:00 - 14:00 +# Deep Space Nine|||Sci-Fantasy|0900-1400|99|DS9 +# +# Record all "Actionfilm"s with "Schwarzenegger" +# |Actionfilm|Schwarzenegger +# + + +done: The titles/subtitles which are already recorded/should not be recorded + (Programmed Timers which got inserted into "done" will be deleted + automaticaly) + +4. Notices +---------- + +- Recordings "overlapping" on the same channel, will be joined into one Timer +- Title/Subtitle/Descriptions are "fixed" for Channel that don't fill them + out "correctly" (Currently the "Bugs" from Pro-7/VOX/VIVA) + Pro7: Remove the Title from the Subtitle ' / <Subtitle>' + VOX/VIVA: Subtitle is enclosed into "" and after ". " is the description + VIVA: When the Subtitle beginns with space the subtitle is moved to + description + All (except the second VIVA one) fixes are tried onto ALL Subtitles. + +5. Known-Bugs +------------- + +- It isn't checked if there are enough DVB-Cards +- Overlapping Timers, on the same channel, are always joined +- JOINed timers which are "done" don't get deleted automaticaly diff --git a/Tools/master-timer/README b/Tools/master-timer/README new file mode 100644 index 000000000..c71e6e185 --- /dev/null +++ b/Tools/master-timer/README @@ -0,0 +1,52 @@ + Master-Timer (w) by Matthias Schniedermeyer (ms@citd.de) + ============ + + +1. Introduction +--------------- + +Master-Timer ist a system for recording Films/Series automaticaly + +2. Requierements +---------------- + +epg.data + +3. Config-Files +--------------- + +For all files: One Entry per Line. Each line is a "Regular Expresion" + So you can use all Perl-Style REs you want. + The RE are matched with "i" so they are case insensitive! + (Except for the "done"-list, these must match excatly!) + +deepblack: Blacklist of "Titles" you NEVER EVER want to get to you eyes + +subtitle-movies: A list of "Subtitles" which indicate a movie. + (For Channels that correctly fill out the Subtitle. + e.g. it won't work for *eRTL*) + +torecord: The titles/subtitles/Description you want to record + +done: The titles/subtitles which are already recorded/should not be recorded + (Programmed Timers which got inserted into "done" will be deleted + automaticaly) + +4. Notices +---------- + +- Recordings "overlapping" on the same channel, will be joined into one Timer +- Title/Subtitle/Descriptions are "fixed" for Channel that don't fill them + out "correctly" (Currently the "Bugs" from Pro-7/VOX/VIVA) + Pro7: Remove the Title from the Subtitle '<Title> / <Subtitle>' + VOX/VIVA: Subtitle is enclosed into "" and after ". " is the description + VIVA: When the Subtitle beginns with space the subtitle is moved to + description + All (except the second VIVA one) fixes are tried onto ALL Subtitles. + +5. Known-Bugs +------------- + +- It isn't checked if there are enough DVB-Cards +- Overlapping Timers, on the same channel, are always joined +- JOINed timers which are "done" don't get deleted automaticaly diff --git a/Tools/master-timer/Todo b/Tools/master-timer/Todo new file mode 100644 index 000000000..722ee969c --- /dev/null +++ b/Tools/master-timer/Todo @@ -0,0 +1,10 @@ + +- "Intelligenter" Kanal-Scanner (z.B. nur 1 Kanal fuer ein + Sender-"Gruppe") +- Filtern nach Serie/Film +- "Komfortable" Anzeige, mit Black & Whitelisten, fuer Genres/Titeln usw. +- Unterstueztung von 1xVDR pro Karte +- Abspielen (mit automatischen "killen" des "Frontend"-VDRs) von + Aufzeichnungen +- "View"-Timer d.h. Timer der nicht Aufnimmt sondern nur den Kanal aendert +- "unwichtige" Timer "verdraengen" wenn andere Aufnahmen anstehen. diff --git a/Tools/master-timer/master-timer.pl b/Tools/master-timer/master-timer.pl new file mode 100755 index 000000000..3b98acc8d --- /dev/null +++ b/Tools/master-timer/master-timer.pl @@ -0,0 +1,1169 @@ +#!/usr/bin/perl -w + +use strict; +# For the TCP-Connection to VDR +use Socket; +# For converting the Timers, read from VDR, back to Unix-Timestamps +use Time::Local; + +# Debugmode +# You have to add the following numbers to build the debug-var +# 1 : Dump the "torecord" +# 2 : Dump all timers +# 4 : Show when a timer will be deleted +# 8 : Dump the "Done" REs +# 16 : Verbose Config-Reading +my $debug = 0; + +# The Supervariable Program +# %Program{$title}{$channel}{$time}{duration} +# {subtitle} +# {description} + +# The Supervariable Timer +# %Timer{$time}{$channel}{$title}{duration} +# {subtitle} +# {prio} +# {real_title} +# {VDR} (Already programmed) +# The Value of VDR is ">0" for the position in the Timer-List or "R" for a "Repeating" Timer. +# A Value of >1.000.000 is a Master Timer-Timer which is already programmed into VDR + +# Variable-Definition +my (%Program, @channels, %channels, %Timer); + +# Which Subtitles are Movies +my ($subtitle_movie); + +# Blacklist +my ($title_deepblack); + +# What is already recorded/Should not be recorded +my ($title_done, $subtitle_done); + +# What to record +my ($title_torecord, $subtitle_torecord, $description_torecord, @title_torecord, @subtitle_torecord, @description_torecord, @channel_torecord, @timeframe_torecord, @prio_torecord, @timer_title_torecord, $num_torecord, @marginstart_torecord, @marginstop_torecord, @machine_torecord); + +# Default Priority for Timers (Config: defaultprio) +my $default_prio = 50; + +# How many DVB-S cards are there (Config: DVBCards) +my $DVB_cards = 1; + +# How many seconds to substract from the time and to add to the duration +my $marginstart = 60*10; # Config: Marginstart +my $marginstop = 60*10; # Config: Marginstop + +# Shall Timers, on the same channel, be joined if they overlap +my $jointimers = 0; + +# Hostname/IP of DVB-Computer and the Port of VDR +my @Dest = ("localhost:2001"); # Config: Dest + +# Which VDR-Instance shall be used +my $currentVDR = 1; + +# Working-Variables +my ($title, $duration, $subtitle, $channel, $time, $description, $hit); +my (@time, @date); + +sub sub_die + { + my ($error) = @_; + &closesocket(); + die "$error"; + } + + +if ($ARGV[0]) + { + $currentVDR = $ARGV[0]; + } + +&init(); +&dumpdone() if ($debug & 8); +&dumptorecord() if ($debug & 1); +&fetchVDRTimers(); +&process_torecord(); +print "Timers before joining\n" if ($debug & 2 && $jointimers); +&dumptimers() if ($debug & 2); +if ($jointimers) + { + &jointimers(); + print "Timers after joining\n" if ($debug & 2); + &dumptimers() if ($debug & 2); + } + +&printtimers(); +&transfertimers(); +&closesocket(); + +# +# Subfunctions +# + +sub dumpdone() + { + print "Start Done-dump\n"; + print "Titledone: \"$title_done\"\n"; + print "Subtitledone \"$subtitle_done\"\n"; + print "End Done-dump\n"; + } + +sub dumptorecord() + { + print "Start Torecord-dump\n"; + print "Regex-Title: $title_torecord\n"; + print "Regex-Subtitle: $subtitle_torecord\n"; + print "Regex-Description: $description_torecord\n"; + foreach my $num (0 .. $num_torecord) + { + print "Timer Number $num: "; + + print "Title: \"$title_torecord[$num]\" " if ($title_torecord[$num]); + print "Title: \"\" " unless ($title_torecord[$num]); + + print "Subtitle: \"$subtitle_torecord[$num]\" "if ($subtitle_torecord[$num]); + print "Subtitle: \"\" " unless ($subtitle_torecord[$num]); + + print "Description: \"$description_torecord[$num]\" " if ($description_torecord[$num]); + print "Description: \"\" " unless ($description_torecord[$num]); + + print "Timeframe: \"$timeframe_torecord[$num]\" " if ($timeframe_torecord[$num]); + print "Timeframe: \"\" " unless ($timeframe_torecord[$num]); + + print "Channel: \"". join (";",@{$channel_torecord[$num]})."\" " if ($channel_torecord[$num]); + print "Channel: \"\" " unless ($channel_torecord[$num]); + + print "Prio: \"$prio_torecord[$num]\" " if ($prio_torecord[$num]); + print "Prio: \"\" " unless ($prio_torecord[$num]); + + print "Timertitle: \"$timer_title_torecord[$num]\" " if ($timer_title_torecord[$num]); + print "Timertitle: \"\" " unless ($timer_title_torecord[$num]); + + print "Marginstart: \"$marginstart_torecord[$num]\" " if ($marginstart_torecord[$num]); + print "Marginstart: \"\" " unless ($marginstart_torecord[$num]); + + print "Marginstop: \"$marginstop_torecord[$num]\" " if ($marginstop_torecord[$num]); + print "Marginstop: \"\" " unless ($marginstop_torecord[$num]); + + print "Machine: \"$machine_torecord[$num]\" " if ($machine_torecord[$num]); + print "Machine: \"\" " unless ($machine_torecord[$num]); + + print "\n"; + } + print "End Torecord-dump\n"; + } + +sub dumptimers() + { + print "Start Timers-dump\n"; + foreach $time (sort {$a <=> $b} keys %Timer) + { + foreach $channel (sort keys %{%Timer->{$time}}) + { + foreach $title (sort keys %{%Timer->{$time}->{$channel}}) + { + my ($prio, @time, @date, @time2); + my ($realtitle); + @time = &GetTime ($time); + @date = &GetDay ($time); + @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); + $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; + $prio = $Timer{$time}{$channel}{$title}{prio}; + $realtitle = $Timer{$time}{$channel}{$title}{real_title}; + print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\":$Timer{$time}{$channel}{$title}{VDR}\n"; + } + } + } + print "End Timers-dump\n"; + } + +sub printtimers() + { + foreach $time (sort {$a <=> $b} keys %Timer) + { + foreach $channel (sort keys %{%Timer->{$time}}) + { + foreach $title (sort keys %{%Timer->{$time}->{$channel}}) + { + my ($prio, @time, @date, @time2); + if ($Timer{$time}{$channel}{$title}{VDR} eq 0) + { + my ($realtitle); + @time = &GetTime ($time); + @date = &GetDay ($time); + @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); + $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; + $prio = $Timer{$time}{$channel}{$title}{prio}; + $realtitle = $Timer{$time}{$channel}{$title}{real_title}; + + print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"\n"; + } + } + } + } + } + +sub transfertimers() + { + foreach $time (sort {$a <=> $b} keys %Timer) + { + foreach $channel (sort keys %{%Timer->{$time}}) + { + foreach $title (sort keys %{%Timer->{$time}->{$channel}}) + { + my ($prio, @time, @date, @time2, $realtitle, $result); + if ($Timer{$time}{$channel}{$title}{VDR} eq 0) + { + @time = &GetTime ($time); + @date = &GetDay ($time); + @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); + $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; + $prio = $Timer{$time}{$channel}{$title}{prio}; + $realtitle = $Timer{$time}{$channel}{$title}{real_title}; + + ($result) = GetSend ("newt 2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\""); + print "Timer: $result" if ($debug & 2); + } + } + } + } + } + +# Convert the Unix-Time-Stamp into "month" and "Day of month" +sub GetDay + { + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); + $mon++; + $mon = sprintf ("%02i",$mon); + $mday = sprintf ("%02i",$mday); + return ($mon, $mday); + } + +# Convert the Unix-Time-Stramp into "hour" and "minute" +sub GetTime + { + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); + $hour = sprintf ("%02i",$hour); + $min = sprintf ("%02i",$min); + return ($hour, $min); + } + +# Workaround some EPG-Bugs +sub correct_epg_data + { + if ($subtitle) + { + # For Pro-7. Remove $title from $subtitle + $subtitle =~ s/$title\s\/\s//; + + # For VOX & VIVA. The Format it '"<Subtitle>". <Description>' + if ($subtitle =~ /^\"(.*?)\"\.\s(.*)/) + { + # Lets see if there are Channels that where the VOX/VIVA scheme matches, but also have a description + if ($description) + { + sub_die ("Subtitle: \"$subtitle\"\nDescription\"$description\"\n"); + } + $subtitle = $1; + $description = $2; + } + elsif ($channel eq "VIVA") + { + if ($subtitle =~ /^\s(.*)/) + { + $subtitle = ""; + $description = $1; + } + } + } + + # Workaround for the broken PRO-7/Kabel-1 EPG-Date. If Time is between 00.00 and 05.00 the time is shifted forward by a day + if ($channel eq "Pro-7" || $channel eq "Kabel-1") + { + my (@time); + @time = GetTime ($time); + if ($time[0] >= 0 && ($time[0] <= 4 || ($time[0] == 5 && $time[1] == 0))) + { + $time += 24*60*60; + } + } +} + +# Add a Recording into the "to record"-List +sub addtimer + { + my ($hit, $title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $VDR, $time2, $title2, $channel2, $marginstart, $marginstop); + ($title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $VDR, $marginstart, $marginstop) = @_; +# print "Title: \"$title\" Realtitle: \"$realtitle\" Subtitle: \"$subtitle\" Channel: \"$channel\" Time: \"$time\" Duration: \"$duration\" Prio: \"$prio\" VDR: \"$VDR\"\n"; + + $hit = 1; + + foreach $time2 (sort keys %Timer) + { + foreach $title2 (sort keys %{%Timer->{$time2}->{$channel}}) + { + my ($ctime, $ctime2); + $ctime = $time2; + $ctime2 = $time2 + $Timer{$time2}{$channel}{$title2}{duration}; + + if (($time >= $ctime) && ($time <= $ctime2)) + { + undef $hit; + } + } + } + + + if ($hit) + { + $time -= $marginstart; + $duration += $marginstart + $marginstop; + $Timer{$time}{$channel}{$title}{duration}=$duration; + $Timer{$time}{$channel}{$title}{subtitle}=$subtitle; + $Timer{$time}{$channel}{$title}{prio}=$prio; + $Timer{$time}{$channel}{$title}{VDR}=$VDR; + $Timer{$time}{$channel}{$title}{real_title}=$realtitle; + } + } + +sub deltimer() + { + my ($time, $channel, $title, $delete_from_VDR); + ($time, $channel, $title, $delete_from_VDR) = @_; + +# if ($delete_from_VDR) +# { +# if ($Timer{$time}{$channel}{$title}{VDR}) +# { +# if ($Timer{$time}{$channel}{$title}{VDR} =~ s/ ^R/) +# { +# print "Error: A Repeating-Timer can't be deleted from VDR: \"$title\"\n"; +# } +# elsif ($Timer{$time}{$channel}{$title}{VDR} < 1000000) +# { +# print "A User-Programmed Timer has been deleted from VDR: \"$title\"\n"; +# } +# else +# { +# +# } +# } +# } + + delete $Timer{$time}{$channel}{$title}{duration}; + delete $Timer{$time}{$channel}{$title}{subtitle}; + delete $Timer{$time}{$channel}{$title}{prio}; + delete $Timer{$time}{$channel}{$title}{VDR}; + delete $Timer{$time}{$channel}{$title}{real_title}; + delete $Timer{$time}{$channel}{$title}; + delete $Timer{$time}{$channel} if (keys %{ $Timer{$time}{$channel} } == 1); + delete $Timer{$time} if (keys %{ $Timer{$time} } == 1); + } + +sub jointimers + { + # + # FIXME: 2 Timers on the same channel will always be joined. + # It should be checked if there is another DVB-Card available. + # + # FIXME2: When one timer is already programmed in VDR, delete that timer in VDR. + my ($running, $counter, @times, $channel, $title, $channel2, $title2); + $running = 1; + outer: while ($running) + { + $counter = 0; + @times = sort {$a <=> $b} keys %Timer; + + # We only need to check till the second last timer. The last one can't have a overlapping one. + while ($counter < $#times) + { + foreach $channel (sort keys %{%Timer->{$times[$counter]}}) + { + foreach $title (sort keys %{%Timer->{$times[$counter]}->{$channel}}) + { + if ($times[$counter + 1] < ($times[$counter] + $Timer{$times[$counter]}{$channel}{$title}{duration})) + { + foreach $channel2 (sort keys %{%Timer->{$times[$counter + 1]}}) + { + foreach $title2 (sort keys %{%Timer->{$times[$counter + 1]}->{$channel}}) + { + if ($channel eq $channel2) + { + my ($duration, $subtitle, $prio, $realtitle, $duration2, $subtitle2, $prio2, $realtitle2); + # Values from Lower-Timer + $duration = $Timer{$times[$counter]}{$channel}{$title}{duration}; + $subtitle = $Timer{$times[$counter]}{$channel}{$title}{subtitle}; + $prio = $Timer{$times[$counter]}{$channel}{$title}{prio}; + $realtitle = $Timer{$times[$counter]}{$channel}{$title}{real_title}; + + # Values from Higher-Timer + $duration2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{duration}; + $subtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{subtitle}; + $prio2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{prio}; + $realtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{real_title}; + + # Use the Higher Priority for the new Timer + $prio = ($prio > $prio2) ? $prio : $prio2; + + # Delete the two "Obsolet" Timers + &deltimer ($times[$counter], $channel, $title); + &deltimer ($times[$counter + 1], $channel2, $title2); + + # And set the new one + &addtimer ("$title + $title2", "$realtitle\~$realtitle2", "$subtitle\~$subtitle2", $channel, $times[$counter], $duration2 + ($times[$counter + 1 ] - $times[$counter]),$prio,0,0,0); + + # Now a Value is "missing", so we will redo the whole thing. (This will do three-times JOIN correct) + redo outer; + } + } + } + } + } + } + $counter++; + } + undef $running; + } + } + +sub process_torecord + { + my ($first_hit, $prio, $timer_title); + foreach $title (sort keys %Program) + { + foreach $channel (sort keys %{%Program->{$title}}) + { + foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}}) + { + undef $hit; + + # First look if any of the Title/Subtitle/Description REs match + if ($title =~ /$title_torecord/i) + { + $hit = 1; + } + elsif ($Program{$title}{$channel}{$time}{subtitle} && $Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_torecord/i) + { + $hit = 1; + } + elsif ($Program{$title}{$channel}{$time}{description} && $Program{$title}{$channel}{$time}{description} =~ /$description_torecord/i) + { + $hit = 1; + } + + # Now look if we have a "exact" hit + if ($hit) + { + my ($counter); + undef $hit; + foreach $counter (0 .. $num_torecord) + { + + if ($title_torecord[$counter]) + { + if (!($title =~ /$title_torecord[$counter]/i)) + { + next; + } + } + + if ($subtitle_torecord[$counter]) + { + if (!($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_torecord[$counter]/i)) + { + next; + } + elsif (!$title_torecord[$counter] && !$description_torecord[$counter]) + { + next; + } + } + + if ($description_torecord[$counter]) + { + if ($Program{$title}{$channel}{$time}{description}) + { + if (!($Program{$title}{$channel}{$time}{description} =~ /$description_torecord[$counter]/i)) + { + next; + } + } + elsif (!$title_torecord[$counter] && !$subtitle_torecord[$counter]) + { + next; + } + } + + if ($channel_torecord[$counter]) + { + my ($hit); + # Blacklist-Mode + if ($channel_torecord[$counter][0] =~ /^!/) + { + $hit = 1; + foreach (0 .. $#{$channel_torecord[$counter]}) + { + # Strip a possibel "!" Charactar + $channel_torecord[$counter][$_] =~ /^!?(.*)/; + if ($channel =~ /^$1$/) + { + undef $hit; + last; + } + } + } + # Whitelist-Mode + else + { + undef $hit; + foreach (0 .. $#{$channel_torecord[$counter]}) + { + # Strip a possibel "!" Charactar + $channel_torecord[$counter][$_] =~ /^!?(.*)/; + if ($channel =~ /^$1$/) + { + $hit = 1; + last ; + } + } + } + if (!$hit) + { + next; + } + } + + if ($timeframe_torecord[$counter]) + { + my (@time, $time2, $ctime, $ctime2); + @time = GetTime($time); + $time2 = "$time[0]$time[1]"; + + ($ctime, $ctime2) = split (/\-/,$timeframe_torecord[$counter]); + + if (!$ctime) + { + $ctime = "0"; + } + if (!$ctime2) + { + $ctime2 = "2400"; + } + + if ($ctime < $ctime2) + { + if (!($time2 >= $ctime && $time2 <= $ctime2)) + { + next; + } + } + else + { + if (!(($time2 >= $ctime && $time2 <= "2400") || ($time2 >= "0" && $time2 <= $ctime2))) + { + next; + } + } + } + + if ($prio_torecord[$counter]) + { + $prio = $prio_torecord[$counter]; + } + else + { + $prio = 50; + } + + # What Title to use for the timer + if ($timer_title_torecord[$counter]) + { + $timer_title = $timer_title_torecord[$counter] + } + elsif ($title_torecord[$counter]) + { + $timer_title = $title_torecord[$counter] + } + else + { + $timer_title = $title; + } + + my ($subtitle); + if ($Program{$title}{$channel}{$time}{subtitle}) + { + $subtitle = $Program{$title}{$channel}{$time}{subtitle}; + } + else + { + $subtitle = ""; + } + + &addtimer ($timer_title,$title,$subtitle,$channel,$time,$Program{$title}{$channel}{$time}{duration},$prio,0,$marginstart_torecord[$counter],$marginstop_torecord[$counter]); + last; + } + } + } + } + } + } + +# Open the connection to VDR +sub initsocket + { + my ($Dest, $Port) = split (/\:/,$Dest[$currentVDR - 1],2); + my $iaddr = inet_aton($Dest); + my $paddr = sockaddr_in($Port, $iaddr); + + socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp')); + connect(SOCKET, $paddr) or sub_die ("Can't connect to VDR\n"); + select(SOCKET); $| = 1; + select(STDOUT); + + while (<SOCKET>) { + last if substr($_, 3, 1) ne "-"; + } + } + +# Send a command to VDR and read back the result +sub GetSend + { + my ($command, @retval); + + while ($command = shift) + { + print SOCKET "$command\r\n"; + while (<SOCKET>) { + (@retval) = (@retval, $_); + last if substr($_, 3, 1) ne "-"; + } + } + + foreach my $retval (@retval) + { + $retval =~ s/\x0d//g; + } + return (@retval); + } + +# Close the socket to VDR +sub closesocket + { + print SOCKET "Quit\r\n"; + close(SOCKET); + } + + +# Fetch the timers-List from VDR via SVDR and process it. +sub fetchVDRTimers + { + my (@timers, $timer, $position, $active, $channel, $day, $start, $end, $prio, $ttl, $title, $subtitle, $minute, $duration); + my ($utime, $utime2); + + # First fetch the timers-list from VDR + @timers = GetSend ("lstt"); + + foreach $timer (@timers) + { +# $timer =~ s/\x0d//g; + chomp $timer; + # a Valid Timer-line beginns with "250" + if ($timer =~ s/250-|250\s//) + { + # Extract the Position in front of the line + ($position, $timer) = split (/\s/,$timer,2); + +# print "Position: \"$position\" Timer: \"$timer\"\n"; + # Split the : seperated values + ($active, $channel, $day, $start, $end, $prio, $ttl, $title, $subtitle) = split (/\:/,$timer,9); + + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + + # If the string is exactly 7 char wide, then its a "repeating"-timer + if ($active >= 1) + { + if ($day =~ /(.)(.)(.)(.)(.)(.)(.)/) + { + my (@days); + @days = ($1, $2, $3, $4, $5, $6, $7); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + + $start =~ /(\d\d)(\d\d)/; + $hour = $1; + $minute = $2; + $utime = timelocal 0, $minute, $hour, $mday, $mon, $year; + $end =~ /(\d\d)(\d\d)/; + $hour = $1; + $minute = $2; + $utime2 = timelocal 0, $minute, $hour, $mday, $mon, $year; + if ($end < $start) + { + $utime2 += 24*60*60; + } + $duration = $utime2 - $utime; + + # "Normalize" the timestamp to monday + $utime = $utime - ($wday * 24 * 60 *60); + + foreach my $num (0 .. $#days) + { + if ($days[$num] ne "-") + { + my $utime3; + # Todays before today will be shifted in the next week + if (($num + 1) < $wday) + { + $utime3 = $utime + (($num + 7 + 1) * 24 * 60 * 60); + } + else + { + $utime3 = $utime + (($num + 1) * 24 * 60 * 60); + } + &addtimer ($title,$title,$subtitle,$channels[$channel],$utime3,$duration,$prio,"R$position",0,0); + } + } + } + + # When the Day-Value is between 1 and 31, then its a "One time" Timer + elsif (($day >= 1) && ($day <= 31)) + { + if ($active == "2") + { + $position += 1000000; + } + # When the Day is before the Current-Day, then the Timer is for the next month + if ($day < $mday) + { + $mon++; + if ($mon == 12) + { + $mon = 0; + $year ++; + } + } + $start =~ /(\d\d)(\d\d)/; + $hour = $1; + $minute = $2; + $utime = timelocal 0, $minute, $hour, $day, $mon, $year; + $end =~ /(\d\d)(\d\d)/; + $hour = $1; + $minute = $2; + $utime2 = timelocal 0, $minute, $hour, $day, $mon, $year; + if ($end < $start) + { + $utime2 += 24*60*60; + } + $duration = $utime2 - $utime; + + &addtimer ($title,$title,$subtitle,$channels[$channel],$utime,$duration,$prio,$position,0,0); + } + } + } + } + } + +# Parse file "epg.data" +sub initepgdata + { + open (FI,"epg.data") or sub_die ("Can't open file \"epg.data\"\n"); + + while (<FI>) + { + # Begin Channel + if (/^C\s(\d+)\s+(.+)/) + { + $channel = $2; + while (<FI>) + { + # End Channel + if (/^c$/) + { + last; + } + # Begin Timer + elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/) + { + # Undef this Variables because it is possibel that not every timer uses this values + undef $duration; + undef $subtitle; + undef $description; + + $time=$2; + $duration=$3; + } + # Title + elsif (/^T\s(.*)/) + { + $title = $1; + } + # Subtitle + elsif (/^S\s(.*)/) + { + $subtitle=$1; + } + # Description + elsif (/^D\s(.*)/) + { + $description=$1; + } + # End Timer + elsif (/^e$/) + { + # Only accept timers that are in the future + if ($time < time) + { + next; + } + + # Work around the diffrent Bugs in the data + &correct_epg_data(); + + # Check if the title is in the DEEP-Blacklist + if ($title =~ /$title_deepblack/i) + { + next; + } + + # Check if the Title & Subtitle is in the Done-List + if ($title =~ /$title_done/) + { + if ($subtitle) + { + if ($subtitle =~ /$subtitle_done/) + { + next; + } + } + } + + $Program{$title}{$channel}{$time}{duration}=$duration; + if ($subtitle) + { + $Program{$title}{$channel}{$time}{subtitle}=$subtitle; + } + if ($description) + { + $Program{$title}{$channel}{$time}{description}=$description; + } + } + } + } + } + close (FI); + } + +# What is a Movie (When correctly stored into Subtitle) +sub initmovie + { + my (@list,$list); + open (FI,"$ENV{HOME}/.master-timer/subtitle-movie") or return; + @list = <FI>; + close(FI); + + foreach $list (@list) + { + chomp $list; + } + $subtitle_movie = join ('|',@list); + } + +# What should be blacklistet +sub initblacklist + { + my (@list,$list); + if (open (FI,"$ENV{HOME}/.master-timer/deepblack")) + { + @list = <FI>; + close(FI); + + foreach $list (@list) + { + chomp $list; + } + $title_deepblack = join ('|',@list); + } + else + { + $title_deepblack = "^\$"; + } + } + +# What is already recorded/Should not be recorded +sub initdone + { + my (@list,$list, %title_done, %subtitle_done, $title_temp, $subtitle_temp); + if (open (FI,"$ENV{HOME}/.master-timer/done")) + { + @list = <FI>; + close (FI); + + foreach $list (@list) + { + chomp $list; + ($title_temp,$subtitle_temp) = split (/\|/,$list); + if ($title_temp) + { + $title_done{"^$title_temp\$"} = 1; + } + if ($subtitle_temp) + { + $subtitle_done{"^$subtitle_temp\$"} = 1; + } + } + $title_done = join ('|',sort keys %title_done); + $subtitle_done = join ('|',sort keys %subtitle_done); + + # Ein paar Zeichen Escapen + $title_done =~ s/\?/\\\?/g; + $title_done =~ s/\+/\\\+/g; + $subtitle_done =~ s/\?/\\\?/g; + $subtitle_done =~ s/\+/\\\+/g; + + # Now delete Timers in VDR that are already in the done-List + my ($position, $timer, $active, $g, $title, $subtitle, $counter, @todel); + $counter = 0; + @list = GetSend ("LSTT"); + + foreach $timer (@list) + { +# $timer =~ s/0x0d//g; + chomp $timer; + if ($timer =~ s/250-|250\s//) + { + ($position, $timer) = split (/\s/,$timer,2); + # Split the : seperated values + ($active, $g, $g, $g, $g, $g, $g, $title, $subtitle) = split (/\:/,$timer,9); + if ($active == 2) + { + # Title: "Shakespeare in Love"||Subtitle: "Romanze" + my ($ctitle, $csubtitle); + if ($subtitle && $subtitle =~ /^Title\:\s\"(.*)\"\|\|Subtitle\:\s\"(.*)\"/) + { + $title = $1; + $subtitle = $2; + if ($subtitle) + { + my (@titles, @subtitles, $num, $hit); + undef $hit; + @titles = split (/\~/,$title); + @subtitles = split (/\~/,$subtitle); + foreach $num (0 .. $#titles) + { + if ($titles[$num] =~ /$title_done/ && $subtitles[$num] =~ /$subtitle_done/) + { + $hit = 1; + } + else + { + undef $hit; + last; + } + } + + if ($hit) + { + my ($result); + print "Delete Timer: $title $subtitle\n" if ($debug & 4); + $position -= $counter; + ($result) = GetSend ("DELT $position"); + print "Result: $result" if ($debug & 4); + if ($result =~ /^250/) + { + $counter++; + } + } + } + } + } + } + } + } + } + +# What should be recorded +sub inittorecord + { + my (@list, $list, $title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine, @title_list, @subtitle_list, @description_list); + my $counter = 0; + open (FI,"$ENV{HOME}/.master-timer/torecord") or sub_die ("Can't open file \"torecord\"\n"); + @list = <FI>; + close(FI); + + foreach $list (0 .. $#list) + { + chomp $list[$list]; + if ($list[$list] && !($list[$list] =~ /^\#/)) + { + ($title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine) = split (/\|/,$list[$list]); + + # Accept torecord only if it is for the current machine + if ((!$machine && $currentVDR == 1) || $machine == $currentVDR) + { + if ($title) + { + $title_torecord[$counter] = $title; + $title_list[$#title_list + 1] = $title; + } + if ($subtitle) + { + $subtitle_torecord[$counter] = $subtitle; + $subtitle_list[$#subtitle_list + 1] = $subtitle; + } + if ($description) + { + $description_torecord[$counter] = $description; + $description_list[$#description_list + 1] = $description; + } + if ($channel) + { + my (@temp); + @temp = split (/\;/,$channel); + foreach (0 .. $#temp) + { + $channel_torecord[$counter][$_] = $temp[$_]; + } + } + if ($timeframe) + { + $timeframe_torecord[$counter] = $timeframe; + } + if ($prio) + { + $prio_torecord[$counter] = $prio; + } + else + { + $prio_torecord[$counter] = $default_prio; + } + if ($timer_title) + { + $timer_title_torecord[$counter] = $timer_title; + } + if ($margin) + { + my ($start, $stop); + ($start, $stop) = split (/;/,$margin, 2); + $marginstart_torecord[$counter] = $start if ($start); + $marginstop_torecord[$counter] = $stop if ($stop); + } + # Set Default-Margins if not margins defined + $marginstart_torecord[$counter] = $marginstart if (!$marginstart_torecord[$counter]); + $marginstop_torecord[$counter] = $marginstop if (!$marginstop_torecord[$counter]); + $counter++; + } + } + } + + $num_torecord = $counter - 1; + + $title_torecord = join ('|',@title_list); + $subtitle_torecord = join ('|',@subtitle_list); + $description_torecord = join ('|',@description_list); + + if (!$title_torecord) + { + $title_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; + } + if (!$subtitle_torecord) + { + $subtitle_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; + } + if (!$description_torecord) + { + $description_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; + } + } + +# Parse the "channels.conf" of VDR +sub initchannellist + { + my ($counter, $chan, $garbage, $card, @temp_channels, $temp, $i); + + @temp_channels = GetSend ("LSTC"); + + foreach $i (0 .. $#temp_channels) + { + $temp = $temp_channels[$i]; +# $temp =~ s/\x0d//g; + chomp $temp; + + if ($temp =~ s/250-|250\s//) + { + ($counter, $temp) = split (/\s/,$temp,2); + ($chan, $garbage,$garbage, $garbage, $garbage, $garbage, $garbage, $card, $garbage) = split (/\:/,$temp); + $channels[$counter] = $chan; + $channels{$chan}{number} = $counter; + $channels{$chan}{card} = $card; + $counter++; + } + } + } + +sub initconfigfile + { + open (FI,"$ENV{HOME}/.master-timer/config") or return; + while (<FI>) + { + s/\#.*//; + chomp; + if ($_) + { + my ($key, $value); + ($key, $value) = split (/\s+=\s+/); + if ($key =~ /^debug$/i) + { + $debug = $value; + print "Debug-Level = $value\n" if ($debug & 16); + } + elsif ($key =~ /^marginstart$/i) + { + print "Marginstart = $value\n" if ($debug & 16); + $marginstart = $value; + } + elsif ($key =~ /^marginstop$/i) + { + print "Marginstop = $value\n" if ($debug & 16); + $marginstop = $value; + } + elsif ($key =~ /^DVBCards$/i) + { + print "DVB_Cards = $value\n" if ($debug & 16); + $DVB_cards = $value; + } + elsif ($key =~ /^defaultprio$/i) + { + print "Default Priority = $value\n" if ($debug & 16); + $default_prio = $value; + } + elsif ($key =~ /^Dest$/i) + { + print "Destination Host/IP:Port = $value\n" if ($debug & 16); + @Dest = split (/\s+/,$value); + } + elsif ($key =~ /^jointimers$/i) + { + print "Join Timers = $value\n" if ($debug & 16); + $jointimers = $value; + } + else + { + print "Unkown Key: \"$key\" with Value: \"$value\"\n"; + } + } + } + print "End Config\n" if ($debug & 16); + } + +sub init + { + &initconfigfile(); + &initsocket(); + &initmovie(); + &initblacklist(); + &initdone(); + &initchannellist(); + &initepgdata(); + &inittorecord(); + } diff --git a/Tools/master-timer/process_summary.pl b/Tools/master-timer/process_summary.pl new file mode 100755 index 000000000..ebe63009f --- /dev/null +++ b/Tools/master-timer/process_summary.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl -w + +$dir = "/home/ms/.master-timer"; + +open (FI,"$dir/done") or die "Can't open \"done\"\n"; +while (<FI>) + { + chomp; + if ($_) + { + ($title,$subtitle) = split (/\|/,$_,2); + $Done{$title}{$subtitle}=1; + } + } +close (FI); + +&traverse('/video'); + +if ($hit) + { + rename ("$dir/done","$dir/done.bak"); + open (FO,">$dir/done"); + foreach $title (sort keys %Done) + { + foreach $subtitle (sort keys %{%Done->{$title}}) + { + print FO "$title\|$subtitle\n"; + } + } + } + +sub traverse + { + local($dir) = shift; + local($path); + unless (opendir(DIR, $dir)) + { + warn "Can't open $dir\n"; + closedir(DIR); + return; + } + foreach (readdir(DIR)) + { + next if $_ eq '.' || $_ eq '..'; + $path = "$dir/$_"; + if (-d $path) # a directory + { + &traverse($path); + } + if ($_ eq "summary.vdr") + { + open (FI,"$path") or die "Can't open \"$path\"\n"; + @lines = <FI>; + close (FI); + if ($lines[0] =~ /^Title\:\s\"(.*)\"/) + { + @titles = split (/\~/,$1); + if ($lines[2] && $lines[2] =~ /^Subtitle\:\s\"(.*)\"/) + { + @subtitles = split (/\~/,$1); + foreach $num (0 .. $#titles) + { + if ($titles[$num] && $subtitles[$num]) + { + if (!$Done{$titles[$num]}{$subtitles[$num]}) + { + $Done{$titles[$num]}{$subtitles[$num]}=1; + $hit = 1; + } + } + } + } + } + } + } + closedir(DIR); + } + + diff --git a/Tools/master-timer/sample/channels-to-scan b/Tools/master-timer/sample/channels-to-scan new file mode 100644 index 000000000..6acf15792 --- /dev/null +++ b/Tools/master-timer/sample/channels-to-scan @@ -0,0 +1,8 @@ +1 +2 +3 +4 +5 +13 +18 +21 diff --git a/Tools/master-timer/sample/config b/Tools/master-timer/sample/config new file mode 100644 index 000000000..d01c8a858 --- /dev/null +++ b/Tools/master-timer/sample/config @@ -0,0 +1,14 @@ +# How Many Seconds "too early" should the timer begin +marginstart = 600 +# How Many Seocnds "too long" should the timer end +marginstop = 600 +# When the Prio isn't provied in the config-File use this value +defaultprio = 50 +# How many DVB-Cards are installed in the Computer (Not used yet) +DVBCards = 3 +# IP/Hostname:Port of the Destinations (Space is used for delimiter) +Dest-Host = localhost:2001 +# Should Timers on the same channels be joined when they overlapp (0 = off) +jointimers = 1 +# Debug-Level +debug = 0 diff --git a/Tools/master-timer/sample/deepblack b/Tools/master-timer/sample/deepblack new file mode 100644 index 000000000..63b4f9e94 --- /dev/null +++ b/Tools/master-timer/sample/deepblack @@ -0,0 +1,79 @@ +Fr alle Flle Stefanie +'MAX' - Das ganze Leben! +10 vor 11 +17:30 live +18:30 +24 Stunden +Andreas Trck +Arabella +^BIZZ$ +Big Brother +Britt - Der Talk um Eins +Brbel Schfer +Call TV +Chicago Hope - Endstation Hoffnung +Chicago Hope +DIE REDAKTION +Dauerwerbesendungen +Die Harald Schmidt Show +Die Oliver Geissen Show +Die Quiz Show +Doppelter Einsatz +Dr. Stefan Frank - Der Arzt, dem die Frauen vertrauen +EXCLUSIV +EXTRA +Ehekriege +Ein Bayer auf Rgen +Emergency Room +Explosiv - Das Magazin +GIRLSCAMP +Glcksrad +Gute Zeiten, schlechte Zeiten +Hallo, Onkel Doc! +Hans Meiser +Hercules +Hinter Gittern - Der Frauenknast +Infomercials +Jeder gegen Jeden +K1 DIE REPORTAGE +K1 Das Magazin +K1 Nachrichten +Kickers +Kochduell +Nachrichten +Nicole - Entscheidung am Nachmittag +OP ruft Dr. Bruckner +PREMIERE WORLD - Das Programm +PROSIEBEN REPORTAGE +Peter Imhof +Programm ab +Programm von +Punkt 12 +Punkt 6 +Punkt 9 +RTL II News +RTL SHOP +RTL aktuell +RTL-Nachtjournal +SAT.1-FRHSTCKSFERNSEHEN +Spiegel TV-Reportage +UEFA Champions +fussball +fball +Vera am Mittag +Wolffs Revier +Zapping +alphateam +peep! +s.a.m. +taff. +^blitz$ +SK Klsch +^Becker$ +Kommissar Rex +Fit For Fun TV +Nur die Liebe zhlt +Unsere kleine Farm +Die Waltons +^Die Zwei$ +^Sieben$ diff --git a/Tools/master-timer/sample/done b/Tools/master-timer/sample/done new file mode 100644 index 000000000..76819c7be --- /dev/null +++ b/Tools/master-timer/sample/done @@ -0,0 +1 @@ +Alles Routine|Komdie diff --git a/Tools/master-timer/sample/subtitle-movie b/Tools/master-timer/sample/subtitle-movie new file mode 100644 index 000000000..3b5a0abf5 --- /dev/null +++ b/Tools/master-timer/sample/subtitle-movie @@ -0,0 +1,41 @@ +^Abenteuerfilm$ +^Actionfilm$ +^Actionkomdie$ +^Actionthriller$ +^Agentenfilm$ +^Biografie$ +^Biographie$ +^Computeranimation$ +^Drama$ +^Episodenfilm$ +^Erotikfilm$ +^Familiendrama$ +^Fantasy$ +^Fantasykomdie$ +^Gangsterfilm$ +^Gerichtsfilm$ +^Gesellschaftsdrama$ +^Horrorfilm$ +^Horrorkomdie$ +^Kinderfilm$ +^Komdie$ +^Kriegsfilm$ +^Krimikomdie$ +^Kriminalfilm$ +^Liebesfilm$ +^Melodram$ +^Melodrama$ +^Musical$ +^Politthriller$ +^Psychothriller$ +^Road Movie$ +^Romanze$ +^Satire$ +^Science-Fiction$ +^Spielfilm$ +^TV Movie$ +^TV-Drama$ +^Thriller$ +^Western$ +^Zeichentrick$ +^Zeichentrickkomdie$ diff --git a/Tools/master-timer/sample/torecord b/Tools/master-timer/sample/torecord new file mode 100644 index 000000000..030683068 --- /dev/null +++ b/Tools/master-timer/sample/torecord @@ -0,0 +1,32 @@ +# Format: (Every field is "optional". +# [Title RE|Subtitle RE|Description RE|Channel-Name|Timeframe|Prio|Timer-Title|Marginstart;Marginstop|VDR-Instance] +# +# To record something at least one of the "Title", "Subtitle" or "Description" +# Fields has to be provided. This 3 fields are "include" and the rest are +# "exclude" fields! +# +# More than one channel definition can be provided. The delimiter is ";" +# Additionaly you can make a "blacklist" of Channels when you prepent a "!" to the first Channel Definition +# The "!" is only tested for the FIRST Channel definition. +# You can only have a white or a blacklist (Mixing doesn't make sense!) +# +# ex. Record the series "Deep Space Nine" on Sci-Fantasy in the timeframe 09:00 - 14:00 with 60 Seconds Marginstart and -60 Seconds Marginstop +# Deep Space Nine|||Sci-Fantasy|0900-1400|99|DS9|60;-60 +# +# Record all "Actionfilm"s with "Schwarzenegger" +# |Actionfilm|Schwarzenegger +# +Babylon 5|||!Pro-7||99|60;-60|1 +Deep Space Nine|||||99|DS9|60;-60|2 +Seven Days|||||99| +Stargate|||||99| +Futurama||||2100-2300|50| +Ally McBeal|||||99| +Snoops|||||50| +^Friends$|||||99|Friends| +Pensacola|||||50| +seaQuest|||||50| +||Paltrow|Sci Fantasy;13th Street;Star Kino;Cine Action;Cine Comedy;Romantic Movies;Studio Universal;Premiere||99| +||Aniston|||99| +Matrix + diff --git a/Tools/master-timer/scan-channels b/Tools/master-timer/scan-channels new file mode 100755 index 000000000..324181b98 --- /dev/null +++ b/Tools/master-timer/scan-channels @@ -0,0 +1,8 @@ +#!/bin/sh +old=`svdrpsend.pl chan | grep 250 | cut -d " " -f2` +for dat in `cat $HOME/.master-timer/channels-to-scan` +do + svdrpsend.pl "chan $dat" + sleep 30s +done +svdrpsend.pl "chan $old" diff --git a/Tools/schnitt/cut2.pl b/Tools/schnitt/cut2.pl new file mode 100755 index 000000000..6131e880a --- /dev/null +++ b/Tools/schnitt/cut2.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl + +$titel = $ARGV[0]; + +chdir ("/x2/temp"); + +@files=<teil*.mpg>; +$cd = 1; +mkdir "/x2/temp/$cd"; +open (FF,">/x2/temp/$cd/$titel\ CD\ $cd"); +close (FF); + +foreach $file (@files) + { + $size = -s $file; + $total += $size; + if ($total <= 660*1024*1024) + { + print "Moving $file\n"; + system ("mv /x2/temp/$file /x2/temp/$cd/$file"); + } + else + { + print "Splitting $file\n"; + $file =~ s/\.mpg$//; + $total -= $size; + $size = (660*1024*1024) - $total; + $cd = `cut3.pl /x2/temp $cd $file $size \'$titel\' < $file.mpg`; + chomp $cd; + $total = 0; + @files2=</x2/temp/$cd/teil*>; + foreach $file2 (@files2) + { + $total += -s $file2; + } + print "CD: $cd Total $total\n"; + unlink "$file.mpg"; + } + } diff --git a/Tools/schnitt/cut3.pl b/Tools/schnitt/cut3.pl new file mode 100755 index 000000000..ddaf0d6f1 --- /dev/null +++ b/Tools/schnitt/cut3.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl + +$read = $size = 1024*1024; + +$dir = $ARGV[0]; +$subdir = $ARGV[1]; +$teil = $ARGV[2]; +$count1 = $ARGV[3]; +$title = $ARGV[4]; + +$filenum = "1"; +$count = 0; + +open (FI,">$dir/$subdir/$teil.$filenum.mpg"); + +while ($read == $size) + { + if (($filenum == 1 && $count < $count1) || ($filenum > 1 && $count < 660*1024*1024)) + { + $read = read (STDIN,$data,$size); + print FI $data; + $count += $size; + $a = $count /1024/1024; + } + else + { + close (FI); + $filenum++; + $subdir++; + mkdir ("$dir/$subdir"); + open (FF,">$dir/$subdir/$title\ CD\ $subdir"); + close (FF); + open (FI,">$dir/$subdir/$teil.$filenum.mpg"); + $count = 0; + } + } + +close FI; + +print "$subdir\n"; diff --git a/Tools/schnitt/cutall3.pl b/Tools/schnitt/cutall3.pl new file mode 100755 index 000000000..696166697 --- /dev/null +++ b/Tools/schnitt/cutall3.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +open (FI,"cut") or die "Kann Cut-Datei nicht oeffnen\n"; + +outer: while (<FI>) + { + chomp; + if (! ($_ > 1 || $_ eq "0")) + { + open (FO,">cut2"); + print FO "$_\n"; + while (<FI>) + { + chomp; + if ($_ > 1 || $_ eq "0") + { + print FO "$_\n"; + } + else + { + system ("cutt"); + redo outer; + } + } + } + } +if ( -f "cut2") + { + system ("cutt"); + unlink "cut2"; + } diff --git a/Tools/schnitt/dump.c b/Tools/schnitt/dump.c new file mode 100644 index 000000000..a362f6892 --- /dev/null +++ b/Tools/schnitt/dump.c @@ -0,0 +1,65 @@ +#include "libmpeg3.h" +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> + +int main(int argc, char *argv[]) +{ + mpeg3_t *file; + int x,y,ii,i,j,result,out; + int howmany; + unsigned char *output, **output_rows; + char filename[100]; + char header[100]; + char temp; + + howmany = atoi (argv[2]); + + if ((file = mpeg3_open(argv[1])) == NULL) + { + printf ("Open failed\n"); + return 1; + } + mpeg3_set_cpus(file,1); + mpeg3_set_mmx(file,0); + if (mpeg3_has_video == 0) + { + printf ("Stream has no Video\n"); + return 1; + } + x = mpeg3_video_width(file,0); + y = mpeg3_video_height(file, 0); + output = malloc (x*y*3 + 4); + output_rows = malloc (sizeof(unsigned char*) * y); + for(i = 0; i < y; i++) + output_rows[i] = &output[i * x * 3]; + + for (ii = 0; ii < howmany; ii++) + { + result = mpeg3_read_frame(file,output_rows,0,0,x,y,x,y,0,0); + + sprintf (filename,"/x2/temp/output%03i.ppm",ii); + sprintf (header,"P6\n%i %i\n255\n\r",x,y); + +/* printf ("Opening %s\n",filename); */ + + if ((out = open (filename,O_CREAT|O_WRONLY|O_TRUNC,0755)) == -1) + { + printf ("Can't open %s\n",filename); + return 1; + } + + write (out,header,strlen(header)); + + for (i = 0; i < y; i++) + for (j = 0; j < x; j++) + { + temp = output [(i*x+j)*3 + 1]; + output[(i*x+j)*3 + 1] = output [(i*x+j)*3 + 0]; + output[(i*x+j)*3 + 0] = temp; + } + write (out, output, x*y*3); + close (out); + } +} diff --git a/Tools/schnitt/play b/Tools/schnitt/play new file mode 100755 index 000000000..0c43bff5f --- /dev/null +++ b/Tools/schnitt/play @@ -0,0 +1,10 @@ +#!/bin/sh +if [ "$1" != "" ]; then + vmount "$1" +fi +ssh dvb2 /usr/local/bin/my/novdr +sleep 1s +cat /mnt/*/* | buffer -b 1000 -S 1024 | ssh dvb2 play2 +ssh dvb2 rm /tmp/novdr +umount /mnt/* + diff --git a/ac3dec/Makefile b/ac3dec/Makefile new file mode 100644 index 000000000..a0547e915 --- /dev/null +++ b/ac3dec/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for 'ac3dec' +# +# $Id: Makefile 1.1 2001/08/03 12:58:06 kls Exp $ + +OBJS = coeff.o decode.o exponent.o rematrix.o bit_allocate.o crc.o dither.o\ + imdct.o sanity_check.o bitstream.o debug.o downmix.o parse.o stats.o + +DEFINES += -DDOLBY_SURROUND + +all: libac3.a + +libac3.a: $(OBJS) + ar -rc libac3.a $(OBJS) + +# Implicit rules: + +%.o: %.c + gcc -g -O2 -Wall -m486 -c $(DEFINES) $< + +clean: + rm -f *~ libac3.a $(OBJS) diff --git a/ac3dec/ac3.h b/ac3dec/ac3.h new file mode 100644 index 000000000..4919fc504 --- /dev/null +++ b/ac3dec/ac3.h @@ -0,0 +1,60 @@ +/* + * ac3.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#ifndef AARONS_TYPES +#define AARONS_TYPES +typedef unsigned long long uint_64; +typedef unsigned int uint_32; +typedef unsigned short uint_16; +typedef unsigned char uint_8; + +typedef signed long long sint_64; +typedef signed int sint_32; +typedef signed short sint_16; +typedef signed char sint_8; +#endif + +#define AC3_DOLBY_SURR_ENABLE 0x1 +#define AC3_3DNOW_ENABLE 0x2 +#define AC3_MMX_ENABLE 0x4 +#define AC3_ALTIVEC_ENABLE 0x8 + +typedef struct ac3_config_s +{ + //Bit flags that enable various things + uint_32 flags; + //Callback that points the decoder to new stream data + void (*fill_buffer_callback)(uint_8 **, uint_8 **); + //Number of discrete channels in final output (for downmixing) + uint_16 num_output_ch; + //Which channel of a dual mono stream to select + uint_16 dual_mono_ch_sel; +} ac3_config_t; + +void ac3_init(ac3_config_t *); +uint_32 ac3_decode_data(uint_8 *data_start,uint_8 *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data); + + + + diff --git a/ac3dec/ac3_internal.h b/ac3dec/ac3_internal.h new file mode 100644 index 000000000..235189ede --- /dev/null +++ b/ac3dec/ac3_internal.h @@ -0,0 +1,344 @@ +/* + * ac3_internal.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __GNUC__ +#define inline +#endif + +/* Exponent strategy constants */ +#define EXP_REUSE (0) +#define EXP_D15 (1) +#define EXP_D25 (2) +#define EXP_D45 (3) + +/* Delta bit allocation constants */ +#define DELTA_BIT_REUSE (0) +#define DELTA_BIT_NEW (1) +#define DELTA_BIT_NONE (2) +#define DELTA_BIT_RESERVED (3) + +/* samples work structure */ +typedef float stream_samples_t[6][256]; + +/* global config structure */ +extern ac3_config_t ac3_config; +/* global error flag */ +extern uint_32 error_flag; + +/* Everything you wanted to know about band structure */ +/* + * The entire frequency domain is represented by 256 real + * floating point fourier coefficients. Only the lower 253 + * coefficients are actually utilized however. We use arrays + * of 256 to be efficient in some cases. + * + * The 5 full bandwidth channels (fbw) can have their higher + * frequencies coupled together. These coupled channels then + * share their high frequency components. + * + * This coupling band is broken up into 18 sub-bands starting + * at mantissa number 37. Each sub-band is 12 bins wide. + * + * There are 50 bit allocation sub-bands which cover the entire + * frequency range. The sub-bands are of non-uniform width, and + * approximate a 1/6 octave scale. + */ + +/* The following structures are filled in by their corresponding parse_* + * functions. See http://www.atsc.org/Standards/A52/a_52.pdf for + * full details on each field. Indented fields are used to denote + * conditional fields. + */ + +typedef struct syncinfo_s +{ + uint_32 magic; + /* Sync word == 0x0B77 */ + uint_16 syncword; + /* crc for the first 5/8 of the sync block */ + /* uint_16 crc1; */ + /* Stream Sampling Rate (kHz) 0 = 48, 1 = 44.1, 2 = 32, 3 = reserved */ + uint_16 fscod; + /* Frame size code */ + uint_16 frmsizecod; + + /* Information not in the AC-3 bitstream, but derived */ + /* Frame size in 16 bit words */ + uint_16 frame_size; + /* Bit rate in kilobits */ + uint_16 bit_rate; + /* sampling rate in hertz */ + uint_32 sampling_rate; + +} syncinfo_t; + +typedef struct bsi_s +{ + uint_32 magic; + /* Bit stream identification == 0x8 */ + uint_16 bsid; + /* Bit stream mode */ + uint_16 bsmod; + /* Audio coding mode */ + uint_16 acmod; + /* If we're using the centre channel then */ + /* centre mix level */ + uint_16 cmixlev; + /* If we're using the surround channel then */ + /* surround mix level */ + uint_16 surmixlev; + /* If we're in 2/0 mode then */ + /* Dolby surround mix level - NOT USED - */ + uint_16 dsurmod; + /* Low frequency effects on */ + uint_16 lfeon; + /* Dialogue Normalization level */ + uint_16 dialnorm; + /* Compression exists */ + uint_16 compre; + /* Compression level */ + uint_16 compr; + /* Language code exists */ + uint_16 langcode; + /* Language code */ + uint_16 langcod; + /* Audio production info exists*/ + uint_16 audprodie; + uint_16 mixlevel; + uint_16 roomtyp; + /* If we're in dual mono mode (acmod == 0) then extra stuff */ + uint_16 dialnorm2; + uint_16 compr2e; + uint_16 compr2; + uint_16 langcod2e; + uint_16 langcod2; + uint_16 audprodi2e; + uint_16 mixlevel2; + uint_16 roomtyp2; + /* Copyright bit */ + uint_16 copyrightb; + /* Original bit */ + uint_16 origbs; + /* Timecode 1 exists */ + uint_16 timecod1e; + /* Timecode 1 */ + uint_16 timecod1; + /* Timecode 2 exists */ + uint_16 timecod2e; + /* Timecode 2 */ + uint_16 timecod2; + /* Additional bit stream info exists */ + uint_16 addbsie; + /* Additional bit stream length - 1 (in bytes) */ + uint_16 addbsil; + /* Additional bit stream information (max 64 bytes) */ + uint_8 addbsi[64]; + + /* Information not in the AC-3 bitstream, but derived */ + /* Number of channels (excluding LFE) + * Derived from acmod */ + uint_16 nfchans; +} bsi_t; + + +/* more pain */ +typedef struct audblk_s +{ + uint_32 magic1; + /* block switch bit indexed by channel num */ + uint_16 blksw[5]; + /* dither enable bit indexed by channel num */ + uint_16 dithflag[5]; + /* dynamic range gain exists */ + uint_16 dynrnge; + /* dynamic range gain */ + uint_16 dynrng; + /* if acmod==0 then */ + /* dynamic range 2 gain exists */ + uint_16 dynrng2e; + /* dynamic range 2 gain */ + uint_16 dynrng2; + /* coupling strategy exists */ + uint_16 cplstre; + /* coupling in use */ + uint_16 cplinu; + /* channel coupled */ + uint_16 chincpl[5]; + /* if acmod==2 then */ + /* Phase flags in use */ + uint_16 phsflginu; + /* coupling begin frequency code */ + uint_16 cplbegf; + /* coupling end frequency code */ + uint_16 cplendf; + /* coupling band structure bits */ + uint_16 cplbndstrc[18]; + /* Do coupling co-ords exist for this channel? */ + uint_16 cplcoe[5]; + /* Master coupling co-ordinate */ + uint_16 mstrcplco[5]; + /* Per coupling band coupling co-ordinates */ + uint_16 cplcoexp[5][18]; + uint_16 cplcomant[5][18]; + /* Phase flags for dual mono */ + uint_16 phsflg[18]; + /* Is there a rematrixing strategy */ + uint_16 rematstr; + /* Rematrixing bits */ + uint_16 rematflg[4]; + /* Coupling exponent strategy */ + uint_16 cplexpstr; + /* Exponent strategy for full bandwidth channels */ + uint_16 chexpstr[5]; + /* Exponent strategy for lfe channel */ + uint_16 lfeexpstr; + /* Channel bandwidth for independent channels */ + uint_16 chbwcod[5]; + /* The absolute coupling exponent */ + uint_16 cplabsexp; + /* Coupling channel exponents (D15 mode gives 18 * 12 /3 encoded exponents */ + uint_16 cplexps[18 * 12 / 3]; + /* Sanity checking constant */ + uint_32 magic2; + /* fbw channel exponents */ + uint_16 exps[5][252 / 3]; + /* channel gain range */ + uint_16 gainrng[5]; + /* low frequency exponents */ + uint_16 lfeexps[3]; + + /* Bit allocation info */ + uint_16 baie; + /* Slow decay code */ + uint_16 sdcycod; + /* Fast decay code */ + uint_16 fdcycod; + /* Slow gain code */ + uint_16 sgaincod; + /* dB per bit code */ + uint_16 dbpbcod; + /* masking floor code */ + uint_16 floorcod; + + /* SNR offset info */ + uint_16 snroffste; + /* coarse SNR offset */ + uint_16 csnroffst; + /* coupling fine SNR offset */ + uint_16 cplfsnroffst; + /* coupling fast gain code */ + uint_16 cplfgaincod; + /* fbw fine SNR offset */ + uint_16 fsnroffst[5]; + /* fbw fast gain code */ + uint_16 fgaincod[5]; + /* lfe fine SNR offset */ + uint_16 lfefsnroffst; + /* lfe fast gain code */ + uint_16 lfefgaincod; + + /* Coupling leak info */ + uint_16 cplleake; + /* coupling fast leak initialization */ + uint_16 cplfleak; + /* coupling slow leak initialization */ + uint_16 cplsleak; + + /* delta bit allocation info */ + uint_16 deltbaie; + /* coupling delta bit allocation exists */ + uint_16 cpldeltbae; + /* fbw delta bit allocation exists */ + uint_16 deltbae[5]; + /* number of cpl delta bit segments */ + uint_16 cpldeltnseg; + /* coupling delta bit allocation offset */ + uint_16 cpldeltoffst[8]; + /* coupling delta bit allocation length */ + uint_16 cpldeltlen[8]; + /* coupling delta bit allocation length */ + uint_16 cpldeltba[8]; + /* number of delta bit segments */ + uint_16 deltnseg[5]; + /* fbw delta bit allocation offset */ + uint_16 deltoffst[5][8]; + /* fbw delta bit allocation length */ + uint_16 deltlen[5][8]; + /* fbw delta bit allocation length */ + uint_16 deltba[5][8]; + + /* skip length exists */ + uint_16 skiple; + /* skip length */ + uint_16 skipl; + + //Removed Feb 2000 -ah + /* channel mantissas */ + //uint_16 chmant[5][256]; + + /* coupling mantissas */ + uint_16 cplmant[256]; + + //Removed Feb 2000 -ah + /* coupling mantissas */ + //uint_16 lfemant[7]; + + + /* -- Information not in the bitstream, but derived thereof -- */ + + /* Number of coupling sub-bands */ + uint_16 ncplsubnd; + + /* Number of combined coupling sub-bands + * Derived from ncplsubnd and cplbndstrc */ + uint_16 ncplbnd; + + /* Number of exponent groups by channel + * Derived from strmant, endmant */ + uint_16 nchgrps[5]; + + /* Number of coupling exponent groups + * Derived from cplbegf, cplendf, cplexpstr */ + uint_16 ncplgrps; + + /* End mantissa numbers of fbw channels */ + uint_16 endmant[5]; + + /* Start and end mantissa numbers for the coupling channel */ + uint_16 cplstrtmant; + uint_16 cplendmant; + + /* Decoded exponent info */ + uint_16 fbw_exp[5][256]; + uint_16 cpl_exp[256]; + uint_16 lfe_exp[7]; + + /* Bit allocation pointer results */ + uint_16 fbw_bap[5][256]; + uint_16 cpl_bap[256]; + uint_16 lfe_bap[7]; + + uint_32 magic3; +} audblk_t; + + diff --git a/ac3dec/bit_allocate.c b/ac3dec/bit_allocate.c new file mode 100644 index 000000000..053e09cd0 --- /dev/null +++ b/ac3dec/bit_allocate.c @@ -0,0 +1,494 @@ +/* + * bit_allocate.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdlib.h> +#include <string.h> +#include "ac3.h" +#include "ac3_internal.h" + + + +static inline sint_16 logadd(sint_16 a,sint_16 b); +static sint_16 calc_lowcomp(sint_16 a,sint_16 b0,sint_16 b1,sint_16 bin); +static inline uint_16 min(sint_16 a,sint_16 b); +static inline uint_16 max(sint_16 a,sint_16 b); +static void ba_compute_psd(sint_16 start, sint_16 end, sint_16 exps[], + sint_16 psd[], sint_16 bndpsd[]); + +static void ba_compute_excitation(sint_16 start, sint_16 end,sint_16 fgain, + sint_16 fastleak, sint_16 slowleak, sint_16 is_lfe, sint_16 bndpsd[], + sint_16 excite[]); +static void ba_compute_mask(sint_16 start, sint_16 end, uint_16 fscod, + uint_16 deltbae, uint_16 deltnseg, uint_16 deltoffst[], uint_16 deltba[], + uint_16 deltlen[], sint_16 excite[], sint_16 mask[]); +static void ba_compute_bap(sint_16 start, sint_16 end, sint_16 snroffset, + sint_16 psd[], sint_16 mask[], sint_16 bap[]); + +/* Misc LUTs for bit allocation process */ + +static sint_16 slowdec[] = { 0x0f, 0x11, 0x13, 0x15 }; +static sint_16 fastdec[] = { 0x3f, 0x53, 0x67, 0x7b }; +static sint_16 slowgain[] = { 0x540, 0x4d8, 0x478, 0x410 }; +static sint_16 dbpbtab[] = { 0x000, 0x700, 0x900, 0xb00 }; + +static uint_16 floortab[] = { 0x2f0, 0x2b0, 0x270, 0x230, 0x1f0, 0x170, 0x0f0, 0xf800 }; +static sint_16 fastgain[] = { 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400 }; + + +static sint_16 bndtab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, + 34, 37, 40, 43, 46, 49, 55, 61, 67, 73, + 79, 85, 97, 109, 121, 133, 157, 181, 205, 229 }; + +static sint_16 bndsz[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, + 6, 12, 12, 12, 12, 24, 24, 24, 24, 24 }; + +static sint_16 masktab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 28, 28, 29, + 29, 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, + 34, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 37, + 37, 37, 37, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 40, + 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, 0, 0 }; + + +static sint_16 latab[] = { 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003b, 0x003a, 0x0039, + 0x0038, 0x0037, 0x0036, 0x0035, 0x0034, 0x0034, 0x0033, 0x0032, + 0x0031, 0x0030, 0x002f, 0x002f, 0x002e, 0x002d, 0x002c, 0x002c, + 0x002b, 0x002a, 0x0029, 0x0029, 0x0028, 0x0027, 0x0026, 0x0026, + 0x0025, 0x0024, 0x0024, 0x0023, 0x0023, 0x0022, 0x0021, 0x0021, + 0x0020, 0x0020, 0x001f, 0x001e, 0x001e, 0x001d, 0x001d, 0x001c, + 0x001c, 0x001b, 0x001b, 0x001a, 0x001a, 0x0019, 0x0019, 0x0018, + 0x0018, 0x0017, 0x0017, 0x0016, 0x0016, 0x0015, 0x0015, 0x0015, + 0x0014, 0x0014, 0x0013, 0x0013, 0x0013, 0x0012, 0x0012, 0x0012, + 0x0011, 0x0011, 0x0011, 0x0010, 0x0010, 0x0010, 0x000f, 0x000f, + 0x000f, 0x000e, 0x000e, 0x000e, 0x000d, 0x000d, 0x000d, 0x000d, + 0x000c, 0x000c, 0x000c, 0x000c, 0x000b, 0x000b, 0x000b, 0x000b, + 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0009, 0x0009, 0x0009, + 0x0009, 0x0009, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0005, 0x0005, + 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0004, 0x0004, + 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, + 0x0004, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0002, + 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0002, 0x0002, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000}; + +static sint_16 hth[][50] = {{ 0x04d0, 0x04d0, 0x0440, 0x0400, 0x03e0, 0x03c0, 0x03b0, 0x03b0, + 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390, + 0x0380, 0x0380, 0x0370, 0x0370, 0x0360, 0x0360, 0x0350, 0x0350, + 0x0340, 0x0340, 0x0330, 0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0, + 0x02f0, 0x02f0, 0x0300, 0x0310, 0x0340, 0x0390, 0x03e0, 0x0420, + 0x0460, 0x0490, 0x04a0, 0x0460, 0x0440, 0x0440, 0x0520, 0x0800, + 0x0840, 0x0840 }, + + { 0x04f0, 0x04f0, 0x0460, 0x0410, 0x03e0, 0x03d0, 0x03c0, 0x03b0, + 0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, + 0x0390, 0x0380, 0x0380, 0x0380, 0x0370, 0x0370, 0x0360, 0x0360, + 0x0350, 0x0350, 0x0340, 0x0340, 0x0320, 0x0310, 0x0300, 0x02f0, + 0x02f0, 0x02f0, 0x02f0, 0x0300, 0x0320, 0x0350, 0x0390, 0x03e0, + 0x0420, 0x0450, 0x04a0, 0x0490, 0x0460, 0x0440, 0x0480, 0x0630, + 0x0840, 0x0840 }, + + { 0x0580, 0x0580, 0x04b0, 0x0450, 0x0420, 0x03f0, 0x03e0, 0x03d0, + 0x03c0, 0x03b0, 0x03b0, 0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, + 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390, 0x0390, + 0x0380, 0x0380, 0x0380, 0x0370, 0x0360, 0x0350, 0x0340, 0x0330, + 0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0, 0x02f0, 0x0300, 0x0310, + 0x0330, 0x0350, 0x03c0, 0x0410, 0x0470, 0x04a0, 0x0460, 0x0440, + 0x0450, 0x04e0 }}; + + +static sint_16 baptab[] = { 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, + 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, + 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; + +static sint_16 sdecay; +static sint_16 fdecay; +static sint_16 sgain; +static sint_16 dbknee; +static sint_16 floor; +static sint_16 psd[256]; +static sint_16 bndpsd[256]; +static sint_16 excite[256]; +static sint_16 mask[256]; + +static inline uint_16 +max(sint_16 a,sint_16 b) +{ + return (a > b ? a : b); +} + +static inline uint_16 +min(sint_16 a,sint_16 b) +{ + return (a < b ? a : b); +} + +static inline sint_16 +logadd(sint_16 a,sint_16 b) +{ + sint_16 c; + sint_16 address; + + c = a - b; + address = min((abs(c) >> 1), 255); + + if (c >= 0) + return(a + latab[address]); + else + return(b + latab[address]); +} + + +void bit_allocate(uint_16 fscod, bsi_t *bsi, audblk_t *audblk) +{ + uint_16 i; + sint_16 fgain; + sint_16 snroffset; + sint_16 start; + sint_16 end; + sint_16 fastleak; + sint_16 slowleak; + + /* Only perform bit_allocation if the exponents have changed or we + * have new sideband information */ + if (audblk->chexpstr[0] == 0 && audblk->chexpstr[1] == 0 && + audblk->chexpstr[2] == 0 && audblk->chexpstr[3] == 0 && + audblk->chexpstr[4] == 0 && audblk->cplexpstr == 0 && + audblk->lfeexpstr == 0 && audblk->baie == 0 && + audblk->snroffste == 0 && audblk->deltbaie == 0) + return; + + /* Do some setup before we do the bit alloc */ + sdecay = slowdec[audblk->sdcycod]; + fdecay = fastdec[audblk->fdcycod]; + sgain = slowgain[audblk->sgaincod]; + dbknee = dbpbtab[audblk->dbpbcod]; + floor = floortab[audblk->floorcod]; + + /* if all the SNR offset constants are zero then the whole block is zero */ + if(!audblk->csnroffst && !audblk->fsnroffst[0] && + !audblk->fsnroffst[1] && !audblk->fsnroffst[2] && + !audblk->fsnroffst[3] && !audblk->fsnroffst[4] && + !audblk->cplfsnroffst && !audblk->lfefsnroffst) + { + memset(audblk->fbw_bap,0,sizeof(uint_16) * 256 * 5); + memset(audblk->cpl_bap,0,sizeof(uint_16) * 256); + memset(audblk->lfe_bap,0,sizeof(uint_16) * 7); + return; + } + + + for(i = 0; i < bsi->nfchans; i++) + { + start = 0; + end = audblk->endmant[i] ; + fgain = fastgain[audblk->fgaincod[i]]; + snroffset = (((audblk->csnroffst - 15) << 4) + audblk->fsnroffst[i]) << 2 ; + fastleak = 0; + slowleak = 0; + + ba_compute_psd(start, end, audblk->fbw_exp[i], psd, bndpsd); + + ba_compute_excitation(start, end , fgain, fastleak, slowleak, 0, bndpsd, excite); + + ba_compute_mask(start, end, fscod, audblk->deltbae[i], audblk->deltnseg[i], + audblk->deltoffst[i], audblk->deltba[i], audblk->deltlen[i], excite, mask); + + ba_compute_bap(start, end, snroffset, psd, mask, audblk->fbw_bap[i]); + } + + if(audblk->cplinu) + { + start = audblk->cplstrtmant; + end = audblk->cplendmant; + fgain = fastgain[audblk->cplfgaincod]; + snroffset = (((audblk->csnroffst - 15) << 4) + audblk->cplfsnroffst) << 2 ; + fastleak = (audblk->cplfleak << 8) + 768; + slowleak = (audblk->cplsleak << 8) + 768; + + ba_compute_psd(start, end, audblk->cpl_exp, psd, bndpsd); + + ba_compute_excitation(start, end , fgain, fastleak, slowleak, 0, bndpsd, excite); + + ba_compute_mask(start, end, fscod, audblk->cpldeltbae, audblk->cpldeltnseg, + audblk->cpldeltoffst, audblk->cpldeltba, audblk->cpldeltlen, excite, mask); + + ba_compute_bap(start, end, snroffset, psd, mask, audblk->cpl_bap); + } + + if(bsi->lfeon) + { + start = 0; + end = 7; + fgain = fastgain[audblk->lfefgaincod]; + snroffset = (((audblk->csnroffst - 15) << 4) + audblk->lfefsnroffst) << 2 ; + fastleak = 0; + slowleak = 0; + + ba_compute_psd(start, end, audblk->lfe_exp, psd, bndpsd); + + ba_compute_excitation(start, end , fgain, fastleak, slowleak, 1, bndpsd, excite); + + /* Perform no delta bit allocation for lfe */ + ba_compute_mask(start, end, fscod, 2, 0, 0, 0, 0, excite, mask); + + ba_compute_bap(start, end, snroffset, psd, mask, audblk->lfe_bap); + } +} + + +static void ba_compute_psd(sint_16 start, sint_16 end, sint_16 exps[], + sint_16 psd[], sint_16 bndpsd[]) +{ + int bin,i,j,k; + sint_16 lastbin = 0; + + /* Map the exponents into dBs */ + for (bin=start; bin<end; bin++) + { + psd[bin] = (3072 - (exps[bin] << 7)); + } + + /* Integrate the psd function over each bit allocation band */ + j = start; + k = masktab[start]; + + do + { + lastbin = min(bndtab[k] + bndsz[k], end); + bndpsd[k] = psd[j]; + j++; + + for (i = j; i < lastbin; i++) + { + bndpsd[k] = logadd(bndpsd[k], psd[j]); + j++; + } + + k++; + } while (end > lastbin); +} + +static void ba_compute_excitation(sint_16 start, sint_16 end,sint_16 fgain, + sint_16 fastleak, sint_16 slowleak, sint_16 is_lfe, sint_16 bndpsd[], + sint_16 excite[]) +{ + int bin; + sint_16 bndstrt; + sint_16 bndend; + sint_16 lowcomp = 0; + sint_16 begin = 0; + + /* Compute excitation function */ + bndstrt = masktab[start]; + bndend = masktab[end - 1] + 1; + + if (bndstrt == 0) /* For fbw and lfe channels */ + { + lowcomp = calc_lowcomp(lowcomp, bndpsd[0], bndpsd[1], 0); + excite[0] = bndpsd[0] - fgain - lowcomp; + lowcomp = calc_lowcomp(lowcomp, bndpsd[1], bndpsd[2], 1); + excite[1] = bndpsd[1] - fgain - lowcomp; + begin = 7 ; + + /* Note: Do not call calc_lowcomp() for the last band of the lfe channel, (bin = 6) */ + for (bin = 2; bin < 7; bin++) + { + if (!(is_lfe && (bin == 6))) + lowcomp = calc_lowcomp(lowcomp, bndpsd[bin], bndpsd[bin+1], bin); + fastleak = bndpsd[bin] - fgain; + slowleak = bndpsd[bin] - sgain; + excite[bin] = fastleak - lowcomp; + + if (!(is_lfe && (bin == 6))) + { + if (bndpsd[bin] <= bndpsd[bin+1]) + { + begin = bin + 1 ; + break; + } + } + } + + for (bin = begin; bin < min(bndend, 22); bin++) + { + if (!(is_lfe && (bin == 6))) + lowcomp = calc_lowcomp(lowcomp, bndpsd[bin], bndpsd[bin+1], bin); + fastleak -= fdecay ; + fastleak = max(fastleak, bndpsd[bin] - fgain); + slowleak -= sdecay ; + slowleak = max(slowleak, bndpsd[bin] - sgain); + excite[bin] = max(fastleak - lowcomp, slowleak); + } + begin = 22; + } + else /* For coupling channel */ + { + begin = bndstrt; + } + + for (bin = begin; bin < bndend; bin++) + { + fastleak -= fdecay; + fastleak = max(fastleak, bndpsd[bin] - fgain); + slowleak -= sdecay; + slowleak = max(slowleak, bndpsd[bin] - sgain); + excite[bin] = max(fastleak, slowleak) ; + } +} + +static void ba_compute_mask(sint_16 start, sint_16 end, uint_16 fscod, + uint_16 deltbae, uint_16 deltnseg, uint_16 deltoffst[], uint_16 deltba[], + uint_16 deltlen[], sint_16 excite[], sint_16 mask[]) +{ + int bin,k; + sint_16 bndstrt; + sint_16 bndend; + sint_16 delta; + + bndstrt = masktab[start]; + bndend = masktab[end - 1] + 1; + + /* Compute the masking curve */ + + for (bin = bndstrt; bin < bndend; bin++) + { + if (bndpsd[bin] < dbknee) + { + excite[bin] += ((dbknee - bndpsd[bin]) >> 2); + } + mask[bin] = max(excite[bin], hth[fscod][bin]); + } + + /* Perform delta bit modulation if necessary */ + if ((deltbae == DELTA_BIT_REUSE) || (deltbae == DELTA_BIT_NEW)) + { + sint_16 band = 0; + sint_16 seg = 0; + + for (seg = 0; seg < deltnseg+1; seg++) + { + band += deltoffst[seg]; + if (deltba[seg] >= 4) + { + delta = (deltba[seg] - 3) << 7; + } + else + { + delta = (deltba[seg] - 4) << 7; + } + + for (k = 0; k < deltlen[seg]; k++) + { + mask[band] += delta; + band++; + } + } + } +} + +static void ba_compute_bap(sint_16 start, sint_16 end, sint_16 snroffset, + sint_16 psd[], sint_16 mask[], sint_16 bap[]) +{ + int i,j,k; + sint_16 lastbin = 0; + sint_16 address = 0; + + /* Compute the bit allocation pointer for each bin */ + i = start; + j = masktab[start]; + + do + { + lastbin = min(bndtab[j] + bndsz[j], end); + mask[j] -= snroffset; + mask[j] -= floor; + + if (mask[j] < 0) + mask[j] = 0; + + mask[j] &= 0x1fe0; + mask[j] += floor; + for (k = i; k < lastbin; k++) + { + address = (psd[i] - mask[j]) >> 5; + address = min(63, max(0, address)); + bap[i] = baptab[address]; + i++; + } + j++; + } while (end > lastbin); +} + +static sint_16 +calc_lowcomp(sint_16 a,sint_16 b0,sint_16 b1,sint_16 bin) +{ + + if (bin < 7) + { + if ((b0 + 256) == b1) + a = 384; + else if (b0 > b1) + a = max(0, a - 64); + } + else if (bin < 20) + { + if ((b0 + 256) == b1) + a = 320; + else if (b0 > b1) + a = max(0, a - 64) ; + } + else + a = max(0, a - 128); + + return(a); +} + diff --git a/ac3dec/bit_allocate.h b/ac3dec/bit_allocate.h new file mode 100644 index 000000000..e48b0b2bb --- /dev/null +++ b/ac3dec/bit_allocate.h @@ -0,0 +1,24 @@ +/* + * bit_allocate.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +void bit_allocate(uint_16 fscod, bsi_t *bsi, audblk_t *audblk); diff --git a/ac3dec/bitstream.c b/ac3dec/bitstream.c new file mode 100644 index 000000000..296d5ee3d --- /dev/null +++ b/ac3dec/bitstream.c @@ -0,0 +1,76 @@ +/* + * bitstream.c + * + * Copyright (C) Aaron Holtzman - Dec 1999 + * + * This file is part of ac3dec, a free AC-3 audio decoder + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "ac3.h" +#include "ac3_internal.h" +#include "bitstream.h" + + +uint_8 *buffer_start = 0; +uint_32 bits_left = 0; +uint_32 current_word; + +static inline void +bitstream_fill_current() +{ + current_word = *((uint_32*)buffer_start)++; + current_word = swab32(current_word); +} + +// +// The fast paths for _get is in the +// bitstream.h header file so it can be inlined. +// +// The "bottom half" of this routine is suffixed _bh +// +// -ah +// + +uint_32 +bitstream_get_bh(uint_32 num_bits) +{ + uint_32 result; + + num_bits -= bits_left; + result = (current_word << (32 - bits_left)) >> (32 - bits_left); + + bitstream_fill_current(); + + if(num_bits != 0) + result = (result << num_bits) | (current_word >> (32 - num_bits)); + + bits_left = 32 - num_bits; + + return result; +} + +void +bitstream_init(uint_8 *start) +{ + //initialize the start of the buffer + buffer_start = start; + bits_left = 0; +} diff --git a/ac3dec/bitstream.h b/ac3dec/bitstream.h new file mode 100644 index 000000000..335193064 --- /dev/null +++ b/ac3dec/bitstream.h @@ -0,0 +1,76 @@ +/* + * bitstream.h + * + * Copyright (C) Aaron Holtzman - Dec 1999 + * + * This file is part of ac3dec, a free AC-3 audio decoder + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +//My new and improved vego-matic endian swapping routine +//(stolen from the kernel) +#ifdef WORDS_BIGENDIAN + +# define swab32(x) (x) + +#else + +# if defined (__i386__) + +# define swab32(x) __i386_swab32(x) + static inline const uint_32 __i386_swab32(uint_32 x) + { + __asm__("bswap %0" : "=r" (x) : "0" (x)); + return x; + } + +# else + +# define swab32(x)\ +((((uint_8*)&x)[0] << 24) | (((uint_8*)&x)[1] << 16) | \ + (((uint_8*)&x)[2] << 8) | (((uint_8*)&x)[3])) + +# endif +#endif + +extern uint_32 bits_left; +extern uint_32 current_word; + +void bitstream_init(uint_8 *start); + +uint_8 bitstream_get_byte(void); + +uint_8 *bitstream_get_buffer_start(void); +void bitstream_buffer_frame(uint_32 frame_size); + +uint_32 bitstream_get_bh(uint_32 num_bits); + +static inline uint_32 +bitstream_get(uint_32 num_bits) +{ + uint_32 result; + + if(num_bits < bits_left) + { + result = (current_word << (32 - bits_left)) >> (32 - num_bits); + bits_left -= num_bits; + return result; + } + + return bitstream_get_bh(num_bits); +} + diff --git a/ac3dec/coeff.c b/ac3dec/coeff.c new file mode 100644 index 000000000..b9f03ff65 --- /dev/null +++ b/ac3dec/coeff.c @@ -0,0 +1,353 @@ +/* + * coeff.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include <stdlib.h> +#include <stdio.h> +#include "ac3.h" +#include "ac3_internal.h" + + +#include "decode.h" +#include "bitstream.h" +#include "dither.h" +#include "coeff.h" + +// +//Lookup tables of 0.15 two's complement quantization values +// +static const uint_16 q_1[3] = +{ + ( -2 << 15)/3, 0,( 2 << 15)/3 +}; + +static const uint_16 q_2[5] = +{ + ( -4 << 15)/5,( -2 << 15)/5, 0, + ( 2 << 15)/5,( 4 << 15)/5 +}; + +static const uint_16 q_3[7] = +{ + ( -6 << 15)/7,( -4 << 15)/7,( -2 << 15)/7, 0, + ( 2 << 15)/7,( 4 << 15)/7,( 6 << 15)/7 +}; + +static const uint_16 q_4[11] = +{ + (-10 << 15)/11,(-8 << 15)/11,(-6 << 15)/11, ( -4 << 15)/11,(-2 << 15)/11, 0, + ( 2 << 15)/11,( 4 << 15)/11,( 6 << 15)/11, ( 8 << 15)/11,(10 << 15)/11 +}; + +static const uint_16 q_5[15] = +{ + (-14 << 15)/15,(-12 << 15)/15,(-10 << 15)/15, + ( -8 << 15)/15,( -6 << 15)/15,( -4 << 15)/15, + ( -2 << 15)/15, 0 ,( 2 << 15)/15, + ( 4 << 15)/15,( 6 << 15)/15,( 8 << 15)/15, + ( 10 << 15)/15,( 12 << 15)/15,( 14 << 15)/15 +}; + +// +// Scale factors for convert_to_float +// + +static const uint_32 u32_scale_factors[25] = +{ + 0x38000000, //2 ^ -(0 + 15) + 0x37800000, //2 ^ -(1 + 15) + 0x37000000, //2 ^ -(2 + 15) + 0x36800000, //2 ^ -(3 + 15) + 0x36000000, //2 ^ -(4 + 15) + 0x35800000, //2 ^ -(5 + 15) + 0x35000000, //2 ^ -(6 + 15) + 0x34800000, //2 ^ -(7 + 15) + 0x34000000, //2 ^ -(8 + 15) + 0x33800000, //2 ^ -(9 + 15) + 0x33000000, //2 ^ -(10 + 15) + 0x32800000, //2 ^ -(11 + 15) + 0x32000000, //2 ^ -(12 + 15) + 0x31800000, //2 ^ -(13 + 15) + 0x31000000, //2 ^ -(14 + 15) + 0x30800000, //2 ^ -(15 + 15) + 0x30000000, //2 ^ -(16 + 15) + 0x2f800000, //2 ^ -(17 + 15) + 0x2f000000, //2 ^ -(18 + 15) + 0x2e800000, //2 ^ -(19 + 15) + 0x2e000000, //2 ^ -(20 + 15) + 0x2d800000, //2 ^ -(21 + 15) + 0x2d000000, //2 ^ -(22 + 15) + 0x2c800000, //2 ^ -(23 + 15) + 0x2c000000 //2 ^ -(24 + 15) +}; + +static float *scale_factor = (float*)u32_scale_factors; + +//These store the persistent state of the packed mantissas +static uint_16 m_1[3]; +static uint_16 m_2[3]; +static uint_16 m_4[2]; +static uint_16 m_1_pointer; +static uint_16 m_2_pointer; +static uint_16 m_4_pointer; + +//Conversion from bap to number of bits in the mantissas +//zeros account for cases 0,1,2,4 which are special cased +static uint_16 qnttztab[16] = { 0, 0, 0, 3, 0 , 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16}; + +static void coeff_reset(void); +static sint_16 coeff_get_mantissa(uint_16 bap, uint_16 dithflag); +static void coeff_uncouple_ch(float samples[],bsi_t *bsi,audblk_t *audblk,uint_32 ch); + +// +// Convert a 0.15 fixed point number into IEEE single +// precision floating point and scale by 2^-exp +// +static inline float +convert_to_float(uint_16 exp, sint_16 mantissa) +{ + float x; + + //the scale by 2^-15 is built into the scale factor table + x = mantissa * scale_factor[exp]; + + return x; +} + +void +coeff_unpack(bsi_t *bsi, audblk_t *audblk, stream_samples_t samples) +{ + uint_16 i,j; + uint_32 done_cpl = 0; + sint_16 mantissa; + + coeff_reset(); + + for(i=0; i< bsi->nfchans; i++) + { + for(j=0; j < audblk->endmant[i]; j++) + { + mantissa = coeff_get_mantissa(audblk->fbw_bap[i][j],audblk->dithflag[i]); + samples[i][j] = convert_to_float(audblk->fbw_exp[i][j],mantissa); + } + + if(audblk->cplinu && audblk->chincpl[i] && !(done_cpl)) + { + // ncplmant is equal to 12 * ncplsubnd + // Don't dither coupling channel until channel separation so that + // interchannel noise is uncorrelated + for(j=audblk->cplstrtmant; j < audblk->cplendmant; j++) + audblk->cplmant[j] = coeff_get_mantissa(audblk->cpl_bap[j],0); + done_cpl = 1; + } + } + + //uncouple the channel if necessary + if(audblk->cplinu) + { + for(i=0; i< bsi->nfchans; i++) + { + if(audblk->chincpl[i]) + coeff_uncouple_ch(samples[i],bsi,audblk,i); + } + + } + + if(bsi->lfeon) + { + // There are always 7 mantissas for lfe, no dither for lfe + for(j=0; j < 7 ; j++) + { + mantissa = coeff_get_mantissa(audblk->lfe_bap[j],0); + samples[5][j] = convert_to_float(audblk->lfe_exp[j],mantissa); + } + } +} + +// +//Fetch a mantissa from the bitstream +// +//The mantissa returned is a signed 0.15 fixed point number +// +static sint_16 +coeff_get_mantissa(uint_16 bap, uint_16 dithflag) +{ + uint_16 mantissa; + uint_16 group_code; + + //If the bap is 0-5 then we have special cases to take care of + switch(bap) + { + case 0: + if(dithflag) + mantissa = dither_gen(); + else + mantissa = 0; + break; + + case 1: + if(m_1_pointer > 2) + { + group_code = bitstream_get(5); + + if(group_code > 26) + goto error; + + m_1[0] = group_code / 9; + m_1[1] = (group_code % 9) / 3; + m_1[2] = (group_code % 9) % 3; + m_1_pointer = 0; + } + mantissa = m_1[m_1_pointer++]; + mantissa = q_1[mantissa]; + break; + case 2: + + if(m_2_pointer > 2) + { + group_code = bitstream_get(7); + + if(group_code > 124) + goto error; + + m_2[0] = group_code / 25; + m_2[1] = (group_code % 25) / 5 ; + m_2[2] = (group_code % 25) % 5 ; + m_2_pointer = 0; + } + mantissa = m_2[m_2_pointer++]; + mantissa = q_2[mantissa]; + break; + + case 3: + mantissa = bitstream_get(3); + + if(mantissa > 6) + goto error; + + mantissa = q_3[mantissa]; + break; + + case 4: + if(m_4_pointer > 1) + { + group_code = bitstream_get(7); + + if(group_code > 120) + goto error; + + m_4[0] = group_code / 11; + m_4[1] = group_code % 11; + m_4_pointer = 0; + } + mantissa = m_4[m_4_pointer++]; + mantissa = q_4[mantissa]; + break; + + case 5: + mantissa = bitstream_get(4); + + if(mantissa > 14) + goto error; + + mantissa = q_5[mantissa]; + break; + + default: + mantissa = bitstream_get(qnttztab[bap]); + mantissa <<= 16 - qnttztab[bap]; + } + + return mantissa; + + + +error: + if(!error_flag) + fprintf(stderr,"** Invalid mantissa - skipping frame **\n"); + error_flag = 1; + + return 0; +} + +// +// Reset the mantissa state +// +static void +coeff_reset(void) +{ + m_1[2] = m_1[1] = m_1[0] = 0; + m_2[2] = m_2[1] = m_2[0] = 0; + m_4[1] = m_4[0] = 0; + m_1_pointer = m_2_pointer = m_4_pointer = 3; +} + +// +// Uncouple the coupling channel into a fbw channel +// +static void +coeff_uncouple_ch(float samples[],bsi_t *bsi,audblk_t *audblk,uint_32 ch) +{ + uint_32 bnd = 0; + uint_32 sub_bnd = 0; + uint_32 i,j; + float cpl_coord = 1.0; + uint_32 cpl_exp_tmp; + uint_32 cpl_mant_tmp; + sint_16 mantissa; + + + for(i=audblk->cplstrtmant;i<audblk->cplendmant;) + { + if(!audblk->cplbndstrc[sub_bnd++]) + { + cpl_exp_tmp = audblk->cplcoexp[ch][bnd] + 3 * audblk->mstrcplco[ch]; + if(audblk->cplcoexp[ch][bnd] == 15) + cpl_mant_tmp = (audblk->cplcomant[ch][bnd]) << 11; + else + cpl_mant_tmp = ((0x10) | audblk->cplcomant[ch][bnd]) << 10; + + cpl_coord = convert_to_float(cpl_exp_tmp,cpl_mant_tmp) * 8.0f; + + //Invert the phase for the right channel if necessary + if(bsi->acmod == 0x2 && audblk->phsflginu && ch == 1 && audblk->phsflg[bnd]) + cpl_coord *= -1; + + bnd++; + } + + for(j=0;j < 12; j++) + { + //Get new dither values for each channel if necessary, so + //the channels are uncorrelated + if(audblk->dithflag[ch] && audblk->cpl_bap[i] == 0) + mantissa = dither_gen(); + else + mantissa = audblk->cplmant[i]; + + samples[i] = cpl_coord * convert_to_float(audblk->cpl_exp[i],mantissa); + + i++; + } + } +} diff --git a/ac3dec/coeff.h b/ac3dec/coeff.h new file mode 100644 index 000000000..dc822a9bd --- /dev/null +++ b/ac3dec/coeff.h @@ -0,0 +1,24 @@ +/* + * coeff.h + * + * Copyright (C) Aaron Holtzman - Feb 2000 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +void coeff_unpack(bsi_t *bsi, audblk_t *audblk,stream_samples_t samples); diff --git a/ac3dec/crc.c b/ac3dec/crc.c new file mode 100644 index 000000000..3210ce7f8 --- /dev/null +++ b/ac3dec/crc.c @@ -0,0 +1,96 @@ +/* + * crc.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include "ac3.h" +#include "ac3_internal.h" + +#include <sys/time.h> + +#include "crc.h" + +static const uint_16 crc_lut[256] = +{ + 0x0000,0x8005,0x800f,0x000a,0x801b,0x001e,0x0014,0x8011, + 0x8033,0x0036,0x003c,0x8039,0x0028,0x802d,0x8027,0x0022, + 0x8063,0x0066,0x006c,0x8069,0x0078,0x807d,0x8077,0x0072, + 0x0050,0x8055,0x805f,0x005a,0x804b,0x004e,0x0044,0x8041, + 0x80c3,0x00c6,0x00cc,0x80c9,0x00d8,0x80dd,0x80d7,0x00d2, + 0x00f0,0x80f5,0x80ff,0x00fa,0x80eb,0x00ee,0x00e4,0x80e1, + 0x00a0,0x80a5,0x80af,0x00aa,0x80bb,0x00be,0x00b4,0x80b1, + 0x8093,0x0096,0x009c,0x8099,0x0088,0x808d,0x8087,0x0082, + 0x8183,0x0186,0x018c,0x8189,0x0198,0x819d,0x8197,0x0192, + 0x01b0,0x81b5,0x81bf,0x01ba,0x81ab,0x01ae,0x01a4,0x81a1, + 0x01e0,0x81e5,0x81ef,0x01ea,0x81fb,0x01fe,0x01f4,0x81f1, + 0x81d3,0x01d6,0x01dc,0x81d9,0x01c8,0x81cd,0x81c7,0x01c2, + 0x0140,0x8145,0x814f,0x014a,0x815b,0x015e,0x0154,0x8151, + 0x8173,0x0176,0x017c,0x8179,0x0168,0x816d,0x8167,0x0162, + 0x8123,0x0126,0x012c,0x8129,0x0138,0x813d,0x8137,0x0132, + 0x0110,0x8115,0x811f,0x011a,0x810b,0x010e,0x0104,0x8101, + 0x8303,0x0306,0x030c,0x8309,0x0318,0x831d,0x8317,0x0312, + 0x0330,0x8335,0x833f,0x033a,0x832b,0x032e,0x0324,0x8321, + 0x0360,0x8365,0x836f,0x036a,0x837b,0x037e,0x0374,0x8371, + 0x8353,0x0356,0x035c,0x8359,0x0348,0x834d,0x8347,0x0342, + 0x03c0,0x83c5,0x83cf,0x03ca,0x83db,0x03de,0x03d4,0x83d1, + 0x83f3,0x03f6,0x03fc,0x83f9,0x03e8,0x83ed,0x83e7,0x03e2, + 0x83a3,0x03a6,0x03ac,0x83a9,0x03b8,0x83bd,0x83b7,0x03b2, + 0x0390,0x8395,0x839f,0x039a,0x838b,0x038e,0x0384,0x8381, + 0x0280,0x8285,0x828f,0x028a,0x829b,0x029e,0x0294,0x8291, + 0x82b3,0x02b6,0x02bc,0x82b9,0x02a8,0x82ad,0x82a7,0x02a2, + 0x82e3,0x02e6,0x02ec,0x82e9,0x02f8,0x82fd,0x82f7,0x02f2, + 0x02d0,0x82d5,0x82df,0x02da,0x82cb,0x02ce,0x02c4,0x82c1, + 0x8243,0x0246,0x024c,0x8249,0x0258,0x825d,0x8257,0x0252, + 0x0270,0x8275,0x827f,0x027a,0x826b,0x026e,0x0264,0x8261, + 0x0220,0x8225,0x822f,0x022a,0x823b,0x023e,0x0234,0x8231, + 0x8213,0x0216,0x021c,0x8219,0x0208,0x820d,0x8207,0x0202 +}; + +static uint_16 state; + +void +crc_init(void) +{ + state = 0; +} + + +inline void crc_process_byte(uint_8 data) +{ + state = crc_lut[data ^ (state>>8)] ^ (state<<8); +} + +void +crc_process_frame(uint_8 *data,uint_32 num_bytes) +{ + uint_32 i; + + for(i=0;i<num_bytes;i++) + crc_process_byte(data[i]); +} + +int +crc_validate(void) +{ + return(state == 0); +} diff --git a/ac3dec/crc.h b/ac3dec/crc.h new file mode 100644 index 000000000..07d57b154 --- /dev/null +++ b/ac3dec/crc.h @@ -0,0 +1,27 @@ +/* + * crc.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +int crc_validate(void); +void crc_init(void); +void crc_process_byte(uint_8 data); +void crc_process_frame(uint_8 *data,uint_32 num_bytes); diff --git a/ac3dec/debug.c b/ac3dec/debug.c new file mode 100644 index 000000000..b7d6a3b08 --- /dev/null +++ b/ac3dec/debug.c @@ -0,0 +1,58 @@ +/* + * + * debug.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdlib.h> +#include "debug.h" + +static int debug_level = -1; + +// Determine is debug output is required. +// We could potentially have multiple levels of debug info +int debug_is_on(void) +{ + char *env_var; + + if(debug_level < 0) + { + env_var = getenv("AC3_DEBUG"); + + if (env_var) + { + debug_level = 1; + } + else + debug_level = 0; + } + + return debug_level; +} + +//If you don't have gcc, then ya don't get debug output +#ifndef __GNUC__ +void dprintf(char fmt[],...) +{ + int foo = 0; +} +#endif + diff --git a/ac3dec/debug.h b/ac3dec/debug.h new file mode 100644 index 000000000..f45cb5b1a --- /dev/null +++ b/ac3dec/debug.h @@ -0,0 +1,37 @@ +/* + * + * debug.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +int debug_is_on(void); + +#ifdef __GNUC__ +#define dprintf(format,args...)\ +{\ + if (debug_is_on())\ + {\ + fprintf(stderr,format,## args);\ + }\ +} +#else +void dprintf(char fmt[],...); +#endif diff --git a/ac3dec/decode.c b/ac3dec/decode.c new file mode 100644 index 000000000..5e7f034bd --- /dev/null +++ b/ac3dec/decode.c @@ -0,0 +1,269 @@ +/* + * decode.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * Added support for DVB-s PCI card by: + * Matjaz Thaler <matjaz.thaler@rd.iskraemeco.si> - November 2000 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <sys/time.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "ac3.h" +#include "ac3_internal.h" +#include "bitstream.h" +#include "imdct.h" +#include "exponent.h" +#include "coeff.h" +#include "bit_allocate.h" +#include "parse.h" +#include "crc.h" +#include "stats.h" +#include "rematrix.h" +#include "sanity_check.h" +#include "downmix.h" +#include "debug.h" + +#define AC3_BUFFER_SIZE (6*1024*16) + +//our global config structure +ac3_config_t ac3_config; +uint_32 error_flag = 0; + +static audblk_t audblk; +static bsi_t bsi; +static syncinfo_t syncinfo; +static uint_32 frame_count = 0; +//static uint_32 is_output_initialized = 0; + +//the floating point samples for one audblk +static stream_samples_t samples; + +//the integer samples for the entire frame (with enough space for 2 ch out) +//if this size change, be sure to change the size when muting +static sint_16 s16_samples[2 * 6 * 256]; + + +//Storage for the syncframe +#define SYNC_BUFFER_MAX_SIZE 4096 +static uint_8 sync_buffer[SYNC_BUFFER_MAX_SIZE]; +static uint_32 sync_buffer_size = 0;; + +uint_32 +decode_sync_buffer_syncframe(syncinfo_t *syncinfo, uint_8 **start,uint_8 *end) +{ + uint_8 *cur = *start; + uint_16 syncword = syncinfo->syncword; + uint_32 ret = 0; + + // + // Find an ac3 sync frame. + // +resync: + + while(syncword != 0x0b77) + { + if(cur >= end) + goto done; + syncword = (syncword << 8) + *cur++; + } + + //need the next 3 bytes to decide how big the frame is + while(sync_buffer_size < 3) + { + if(cur >= end) + goto done; + + sync_buffer[sync_buffer_size++] = *cur++; + } + + parse_syncinfo(syncinfo,sync_buffer); + stats_print_syncinfo(syncinfo); + + while(sync_buffer_size < syncinfo->frame_size * 2 - 2) + { + if(cur >= end) + goto done; + + sync_buffer[sync_buffer_size++] = *cur++; + } + + // Check the crc over the entire frame + crc_init(); + crc_process_frame(sync_buffer,syncinfo->frame_size * 2 - 2); + + if(!crc_validate()) + { + fprintf(stderr,"** CRC failed - skipping frame **\n"); + syncword = 0xffff; + sync_buffer_size = 0; + goto resync; + } + + // + //if we got to this point, we found a valid ac3 frame to decode + // + + bitstream_init(sync_buffer); + //get rid of the syncinfo struct as we already parsed it + bitstream_get(24); + + //reset the syncword for next time + syncword = 0xffff; + sync_buffer_size = 0; + ret = 1; + +done: + syncinfo->syncword = syncword; + *start = cur; + return ret; +} + +void +decode_mute(void) +{ + fprintf(stderr,"muting frame\n"); + //mute the frame + memset(s16_samples,0,sizeof(sint_16) * 256 * 2 * 6); + error_flag = 0; +} + + +void +ac3_init(ac3_config_t *config) +{ + memcpy(&ac3_config,config,sizeof(ac3_config_t)); + + imdct_init(); + sanity_check_init(&syncinfo,&bsi,&audblk); + + // ac3_output = *foo; +} + +uint_32 ac3_decode_data(uint_8 *data_start,uint_8 *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data) +{ + uint_32 i; + int datasize; + char *data; + + if(ac3reset != 0){ + syncinfo.syncword = 0xffff; + sync_buffer_size = 0; + } + + while(decode_sync_buffer_syncframe(&syncinfo,&data_start,data_end)) + { + dprintf("(decode) begin frame %d\n",frame_count++); + + if(error_flag) + { + decode_mute(); + continue; + } + + parse_bsi(&bsi); + + for(i=0; i < 6; i++) + { + //Initialize freq/time sample storage + memset(samples,0,sizeof(float) * 256 * (bsi.nfchans + bsi.lfeon)); + + // Extract most of the audblk info from the bitstream + // (minus the mantissas + parse_audblk(&bsi,&audblk); + + // Take the differential exponent data and turn it into + // absolute exponents + exponent_unpack(&bsi,&audblk); + if(error_flag) + goto error; + + // Figure out how many bits per mantissa + bit_allocate(syncinfo.fscod,&bsi,&audblk); + + // Extract the mantissas from the stream and + // generate floating point frequency coefficients + coeff_unpack(&bsi,&audblk,samples); + if(error_flag) + goto error; + + if(bsi.acmod == 0x2) + rematrix(&audblk,samples); + + // Convert the frequency samples into time samples + imdct(&bsi,&audblk,samples); + + // Downmix into the requested number of channels + // and convert floating point to sint_16 + downmix(&bsi,samples,&s16_samples[i * 2 * 256]); + + sanity_check(&syncinfo,&bsi,&audblk); + if(error_flag) + goto error; + + continue; + } + + parse_auxdata(&syncinfo); + + /* + if(!is_output_initialized) + { + ac3_output.open(16,syncinfo.sampling_rate,2); + is_output_initialized = 1; + } + */ + data = (char *)s16_samples; + datasize = 0; + while(datasize < 6144){ + if(((*input_pointer+1) % AC3_BUFFER_SIZE) != *output_pointer){ // There is room in the sync_buffer + ac3_data[*input_pointer]=data[datasize]; + datasize++; + *input_pointer = (*input_pointer+1) % AC3_BUFFER_SIZE; + } + else{ + *input_pointer = *output_pointer = 0; + break; + } + } + + + //write(1, s16_samples, 256 * 6 * 2* 2); + //ac3_output.play(s16_samples, 256 * 6 * 2); +error: + ; + //find a new frame + } + + return 0; +} diff --git a/ac3dec/decode.h b/ac3dec/decode.h new file mode 100644 index 000000000..bb84a1105 --- /dev/null +++ b/ac3dec/decode.h @@ -0,0 +1,22 @@ +/* + * decode.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ diff --git a/ac3dec/dither.c b/ac3dec/dither.c new file mode 100644 index 000000000..31e74f629 --- /dev/null +++ b/ac3dec/dither.c @@ -0,0 +1,115 @@ +/* + * dither.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include <stdlib.h> +#include <stdio.h> +#include "ac3.h" +#include "ac3_internal.h" + + +#include "dither.h" + + +const uint_16 dither_lut[256] = +{ + 0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055, + 0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb, + 0x21cd, 0x81dc, 0xc1fe, 0x61ef, 0x41ba, 0xe1ab, 0xa189, 0x0198, + 0xe123, 0x4132, 0x0110, 0xa101, 0x8154, 0x2145, 0x6167, 0xc176, + 0x439a, 0xe38b, 0xa3a9, 0x03b8, 0x23ed, 0x83fc, 0xc3de, 0x63cf, + 0x8374, 0x2365, 0x6347, 0xc356, 0xe303, 0x4312, 0x0330, 0xa321, + 0x6257, 0xc246, 0x8264, 0x2275, 0x0220, 0xa231, 0xe213, 0x4202, + 0xa2b9, 0x02a8, 0x428a, 0xe29b, 0xc2ce, 0x62df, 0x22fd, 0x82ec, + 0x8734, 0x2725, 0x6707, 0xc716, 0xe743, 0x4752, 0x0770, 0xa761, + 0x47da, 0xe7cb, 0xa7e9, 0x07f8, 0x27ad, 0x87bc, 0xc79e, 0x678f, + 0xa6f9, 0x06e8, 0x46ca, 0xe6db, 0xc68e, 0x669f, 0x26bd, 0x86ac, + 0x6617, 0xc606, 0x8624, 0x2635, 0x0660, 0xa671, 0xe653, 0x4642, + 0xc4ae, 0x64bf, 0x249d, 0x848c, 0xa4d9, 0x04c8, 0x44ea, 0xe4fb, + 0x0440, 0xa451, 0xe473, 0x4462, 0x6437, 0xc426, 0x8404, 0x2415, + 0xe563, 0x4572, 0x0550, 0xa541, 0x8514, 0x2505, 0x6527, 0xc536, + 0x258d, 0x859c, 0xc5be, 0x65af, 0x45fa, 0xe5eb, 0xa5c9, 0x05d8, + 0xae79, 0x0e68, 0x4e4a, 0xee5b, 0xce0e, 0x6e1f, 0x2e3d, 0x8e2c, + 0x6e97, 0xce86, 0x8ea4, 0x2eb5, 0x0ee0, 0xaef1, 0xeed3, 0x4ec2, + 0x8fb4, 0x2fa5, 0x6f87, 0xcf96, 0xefc3, 0x4fd2, 0x0ff0, 0xafe1, + 0x4f5a, 0xef4b, 0xaf69, 0x0f78, 0x2f2d, 0x8f3c, 0xcf1e, 0x6f0f, + 0xede3, 0x4df2, 0x0dd0, 0xadc1, 0x8d94, 0x2d85, 0x6da7, 0xcdb6, + 0x2d0d, 0x8d1c, 0xcd3e, 0x6d2f, 0x4d7a, 0xed6b, 0xad49, 0x0d58, + 0xcc2e, 0x6c3f, 0x2c1d, 0x8c0c, 0xac59, 0x0c48, 0x4c6a, 0xec7b, + 0x0cc0, 0xacd1, 0xecf3, 0x4ce2, 0x6cb7, 0xcca6, 0x8c84, 0x2c95, + 0x294d, 0x895c, 0xc97e, 0x696f, 0x493a, 0xe92b, 0xa909, 0x0918, + 0xe9a3, 0x49b2, 0x0990, 0xa981, 0x89d4, 0x29c5, 0x69e7, 0xc9f6, + 0x0880, 0xa891, 0xe8b3, 0x48a2, 0x68f7, 0xc8e6, 0x88c4, 0x28d5, + 0xc86e, 0x687f, 0x285d, 0x884c, 0xa819, 0x0808, 0x482a, 0xe83b, + 0x6ad7, 0xcac6, 0x8ae4, 0x2af5, 0x0aa0, 0xaab1, 0xea93, 0x4a82, + 0xaa39, 0x0a28, 0x4a0a, 0xea1b, 0xca4e, 0x6a5f, 0x2a7d, 0x8a6c, + 0x4b1a, 0xeb0b, 0xab29, 0x0b38, 0x2b6d, 0x8b7c, 0xcb5e, 0x6b4f, + 0x8bf4, 0x2be5, 0x6bc7, 0xcbd6, 0xeb83, 0x4b92, 0x0bb0, 0xaba1 +}; + +uint_16 lfsr_state = 1; + +// +// see dither_gen (inline-able) in dither.h +// + +#if 0 + +// +// this is the old dither_gen with is much slower than the new inlined +// lut version and is still here because it's easier to understand. +// + +/* + * Generate eight bits of pseudo-entropy using a 16 bit linear + * feedback shift register (LFSR). The primitive polynomial used + * is 1 + x^4 + x^14 + x^16. + * + * The distribution is uniform, over the range [-0.707,0.707] + * + */ + +uint_16 dither_gen(void) +{ + int i; + uint_32 state; + + //explicitly bring the state into a local var as gcc > 3.0? + //doesn't know how to optimize out the stores + state = lfsr_state; + + //Generate eight pseudo random bits + for(i=0;i<8;i++) + { + state <<= 1; + + if(state & 0x10000) + state ^= 0xa011; + } + + lfsr_state = state; + + return (((((sint_32)state<<8)>>8) * (sint_32) (0.707106 * 256.0))>>16); +} + +#endif diff --git a/ac3dec/dither.h b/ac3dec/dither.h new file mode 100644 index 000000000..6d68e1b54 --- /dev/null +++ b/ac3dec/dither.h @@ -0,0 +1,37 @@ +/* + * dither.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +extern uint_16 lfsr_state; +extern const uint_16 dither_lut[256]; + +static inline uint_16 dither_gen(void) +{ + sint_16 state; + + state = dither_lut[lfsr_state >> 8] ^ (lfsr_state << 8); + + lfsr_state = (uint_16) state; + + return ((state * (sint_32) (0.707106 * 256.0))>>8); +} diff --git a/ac3dec/downmix.c b/ac3dec/downmix.c new file mode 100644 index 000000000..94bc51a81 --- /dev/null +++ b/ac3dec/downmix.c @@ -0,0 +1,428 @@ +/* + * + * downmix.c + * + * Copyright (C) Aaron Holtzman - Sept 1999 + * + * Originally based on code by Yuqing Deng. + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include "ac3.h" +#include "ac3_internal.h" + + +#include "decode.h" +#include "downmix.h" +#include "debug.h" + + +//Pre-scaled downmix coefficients +static float cmixlev_lut[4] = { 0.2928, 0.2468, 0.2071, 0.2468 }; +static float smixlev_lut[4] = { 0.2928, 0.2071, 0.0 , 0.2071 }; + +static void +downmix_3f_2r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) +{ + uint_32 j; + float right_tmp; + float left_tmp; + float clev,slev; + float *centre = 0, *left = 0, *right = 0, *left_sur = 0, *right_sur = 0; + + left = samples[0]; + centre = samples[1]; + right = samples[2]; + left_sur = samples[3]; + right_sur = samples[4]; + + clev = cmixlev_lut[bsi->cmixlev]; + slev = smixlev_lut[bsi->surmixlev]; + +#if defined DOLBY_SURROUND + for (j = 0; j < 256; j++) + { + right_tmp = *left_sur++ + *right_sur++; + left_tmp = 1.4142f * *left++ + *centre - right_tmp; + right_tmp += 1.4142f * *right++ + *centre++; + + s16_samples[j * 2 ] = (sint_16) (left_tmp * 16000.0f); + s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 16000.0f); + } +#else + for (j = 0; j < 256; j++) + { + left_tmp = 0.4142f * *left++ + clev * *centre + slev * *left_sur++; + right_tmp= 0.4142f * *right++ + clev * *centre++ + slev * *right_sur++; + + s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); + s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); + } +#endif +} + +static void +downmix_2f_2r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) +{ + uint_32 j; + float right_tmp; + float left_tmp; + float slev; + float *left = 0, *right = 0, *left_sur = 0, *right_sur = 0; + + left = samples[0]; + right = samples[1]; + left_sur = samples[2]; + right_sur = samples[3]; + + slev = smixlev_lut[bsi->surmixlev]; + + for (j = 0; j < 256; j++) + { + left_tmp = 0.4142f * *left++ + slev * *left_sur++; + right_tmp= 0.4142f * *right++ + slev * *right_sur++; + + s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); + s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); + } +} + +static void +downmix_3f_1r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) +{ + uint_32 j; + float right_tmp; + float left_tmp; + float clev,slev; + float *centre = 0, *left = 0, *right = 0, *sur = 0; + + left = samples[0]; + centre = samples[1]; + right = samples[2]; + //Mono surround + sur = samples[3]; + + clev = cmixlev_lut[bsi->cmixlev]; + slev = smixlev_lut[bsi->surmixlev]; + + for (j = 0; j < 256; j++) + { + left_tmp = 0.4142f * *left++ + clev * *centre++ + slev * *sur; + right_tmp= 0.4142f * *right++ + clev * *centre + slev * *sur++; + + s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); + s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); + } +} + + +static void +downmix_2f_1r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) +{ + uint_32 j; + float right_tmp; + float left_tmp; + float slev; + float *left = 0, *right = 0, *sur = 0; + + left = samples[0]; + right = samples[1]; + //Mono surround + sur = samples[2]; + + slev = smixlev_lut[bsi->surmixlev]; + + for (j = 0; j < 256; j++) + { + left_tmp = 0.4142f * *left++ + slev * *sur; + right_tmp= 0.4142f * *right++ + slev * *sur++; + + s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); + s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); + } +} + +static void +downmix_3f_0r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) +{ + uint_32 j; + float right_tmp; + float left_tmp; + float clev; + float *centre = 0, *left = 0, *right = 0; + + left = samples[0]; + centre = samples[1]; + right = samples[2]; + + clev = cmixlev_lut[bsi->cmixlev]; + + for (j = 0; j < 256; j++) + { + left_tmp = 0.4142f * *left++ + clev * *centre; + right_tmp= 0.4142f * *right++ + clev * *centre++; + + s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); + s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); + } +} + +static void +downmix_2f_0r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) +{ + uint_32 j; + float *left = 0, *right = 0; + + left = samples[0]; + right = samples[1]; + + for (j = 0; j < 256; j++) + { + s16_samples[j * 2 ] = (sint_16) (*left++ * 32767.0f); + s16_samples[j * 2 + 1] = (sint_16) (*right++ * 32767.0f); + } +} + +static void +downmix_1f_0r_to_2ch(float *centre,sint_16 *s16_samples) +{ + uint_32 j; + float tmp; + + //Mono program! + + for (j = 0; j < 256; j++) + { + tmp = 32767.0f * 0.7071f * *centre++; + + s16_samples[j * 2 ] = s16_samples[j * 2 + 1] = (sint_16) tmp; + } +} + +// +// Downmix into 2 or 4 channels (4 ch isn't in quite yet) +// +// The downmix function names have the following format +// +// downmix_Xf_Yr_to_[2|4]ch[_dolby] +// +// where X = number of front channels +// Y = number of rear channels +// [2|4] = number of output channels +// [_dolby] = with or without dolby surround mix +// + +void downmix(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) +{ + if(bsi->acmod > 7) + dprintf("(downmix) invalid acmod number\n"); + + // + //There are two main cases, with or without Dolby Surround + // + if(ac3_config.flags & AC3_DOLBY_SURR_ENABLE) + { + fprintf(stderr,"Dolby Surround Mixes not currently enabled\n"); + exit(1); + } + + //Non-Dolby surround downmixes + switch(bsi->acmod) + { + // 3/2 + case 7: + downmix_3f_2r_to_2ch(bsi,samples,s16_samples); + break; + + // 2/2 + case 6: + downmix_2f_2r_to_2ch(bsi,samples,s16_samples); + break; + + // 3/1 + case 5: + downmix_3f_1r_to_2ch(bsi,samples,s16_samples); + break; + + // 2/1 + case 4: + downmix_2f_1r_to_2ch(bsi,samples,s16_samples); + break; + + // 3/0 + case 3: + downmix_3f_0r_to_2ch(bsi,samples,s16_samples); + break; + + case 2: + downmix_2f_0r_to_2ch(bsi,samples,s16_samples); + break; + + // 1/0 + case 1: + downmix_1f_0r_to_2ch(samples[0],s16_samples); + break; + + // 1+1 + case 0: + downmix_1f_0r_to_2ch(samples[ac3_config.dual_mono_ch_sel],s16_samples); + break; + } +} + + + +#if 0 + + //the dolby mixes lay here for the time being + switch(bsi->acmod) + { + // 3/2 + case 7: + left = samples[0]; + centre = samples[1]; + right = samples[2]; + left_sur = samples[3]; + right_sur = samples[4]; + + for (j = 0; j < 256; j++) + { + right_tmp = 0.2265f * *left_sur++ + 0.2265f * *right_sur++; + left_tmp = -1 * right_tmp; + right_tmp += 0.3204f * *right++ + 0.2265f * *centre; + left_tmp += 0.3204f * *left++ + 0.2265f * *centre++; + + samples[1][j] = right_tmp; + samples[0][j] = left_tmp; + } + + break; + + // 2/2 + case 6: + left = samples[0]; + right = samples[1]; + left_sur = samples[2]; + right_sur = samples[3]; + + for (j = 0; j < 256; j++) + { + right_tmp = 0.2265f * *left_sur++ + 0.2265f * *right_sur++; + left_tmp = -1 * right_tmp; + right_tmp += 0.3204f * *right++; + left_tmp += 0.3204f * *left++ ; + + samples[1][j] = right_tmp; + samples[0][j] = left_tmp; + } + break; + + // 3/1 + case 5: + left = samples[0]; + centre = samples[1]; + right = samples[2]; + //Mono surround + right_sur = samples[3]; + + for (j = 0; j < 256; j++) + { + right_tmp = 0.2265f * *right_sur++; + left_tmp = -1 * right_tmp; + right_tmp += 0.3204f * *right++ + 0.2265f * *centre; + left_tmp += 0.3204f * *left++ + 0.2265f * *centre++; + + samples[1][j] = right_tmp; + samples[0][j] = left_tmp; + } + break; + + // 2/1 + case 4: + left = samples[0]; + right = samples[1]; + //Mono surround + right_sur = samples[2]; + + for (j = 0; j < 256; j++) + { + right_tmp = 0.2265f * *right_sur++; + left_tmp = -1 * right_tmp; + right_tmp += 0.3204f * *right++; + left_tmp += 0.3204f * *left++; + + samples[1][j] = right_tmp; + samples[0][j] = left_tmp; + } + break; + + // 3/0 + case 3: + left = samples[0]; + centre = samples[1]; + right = samples[2]; + + for (j = 0; j < 256; j++) + { + right_tmp = 0.3204f * *right++ + 0.2265f * *centre; + left_tmp = 0.3204f * *left++ + 0.2265f * *centre++; + + samples[1][j] = right_tmp; + samples[0][j] = left_tmp; + } + break; + + // 2/0 + case 2: + //Do nothing! + break; + + // 1/0 + case 1: + //Mono program! + right = samples[0]; + + for (j = 0; j < 256; j++) + { + right_tmp = 0.7071f * *right++; + + samples[1][j] = right_tmp; + samples[0][j] = right_tmp; + } + + break; + + // 1+1 + case 0: + //Dual mono, output selected by user + right = samples[ac3_config.dual_mono_ch_sel]; + + for (j = 0; j < 256; j++) + { + right_tmp = 0.7071f * *right++; + + samples[1][j] = right_tmp; + samples[0][j] = right_tmp; + } + break; +#endif diff --git a/ac3dec/downmix.h b/ac3dec/downmix.h new file mode 100644 index 000000000..7537c6229 --- /dev/null +++ b/ac3dec/downmix.h @@ -0,0 +1,28 @@ +/* + * + * downmix.h + * + * Copyright (C) Aaron Holtzman - Sept 1999 + * + * Originally based on code by Yeqing Deng. + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +void downmix(bsi_t* bsi, stream_samples_t stream_samples,sint_16 *s16_samples); diff --git a/ac3dec/exponent.c b/ac3dec/exponent.c new file mode 100644 index 000000000..98111a5ba --- /dev/null +++ b/ac3dec/exponent.c @@ -0,0 +1,135 @@ +/* + * exponent.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include <stdlib.h> +#include <stdio.h> +#include "ac3.h" +#include "ac3_internal.h" + + +#include "decode.h" +#include "exponent.h" + + +static void exp_unpack_ch(uint_16 type,uint_16 expstr,uint_16 ngrps,uint_16 initial_exp, + uint_16 exps[], uint_16 *dest); + +void +exponent_unpack( bsi_t *bsi, audblk_t *audblk) +{ + uint_16 i; + + for(i=0; i< bsi->nfchans; i++) + exp_unpack_ch(UNPACK_FBW, audblk->chexpstr[i], audblk->nchgrps[i], audblk->exps[i][0], + &audblk->exps[i][1], audblk->fbw_exp[i]); + + if(audblk->cplinu) + exp_unpack_ch(UNPACK_CPL, audblk->cplexpstr, audblk->ncplgrps, audblk->cplabsexp << 1, + audblk->cplexps, &audblk->cpl_exp[audblk->cplstrtmant]); + + if(bsi->lfeon) + exp_unpack_ch(UNPACK_LFE, audblk->lfeexpstr, 2, audblk->lfeexps[0], + &audblk->lfeexps[1], audblk->lfe_exp); +} + + +static void +exp_unpack_ch(uint_16 type,uint_16 expstr,uint_16 ngrps,uint_16 initial_exp, + uint_16 exps[], uint_16 *dest) +{ + uint_16 i,j; + sint_16 exp_acc; + sint_16 exp_1,exp_2,exp_3; + + if(expstr == EXP_REUSE) + return; + + /* Handle the initial absolute exponent */ + exp_acc = initial_exp; + j = 0; + + /* In the case of a fbw channel then the initial absolute values is + * also an exponent */ + if(type != UNPACK_CPL) + dest[j++] = exp_acc; + + /* Loop through the groups and fill the dest array appropriately */ + for(i=0; i< ngrps; i++) + { + if(exps[i] > 124) + goto error; + + exp_1 = exps[i] / 25; + exp_2 = (exps[i] - (exp_1 * 25)) / 5; + exp_3 = exps[i] - (exp_1 * 25) - (exp_2 * 5) ; + + exp_acc += (exp_1 - 2); + + switch(expstr) + { + case EXP_D45: + dest[j++] = exp_acc; + dest[j++] = exp_acc; + case EXP_D25: + dest[j++] = exp_acc; + case EXP_D15: + dest[j++] = exp_acc; + } + + exp_acc += (exp_2 - 2); + + switch(expstr) + { + case EXP_D45: + dest[j++] = exp_acc; + dest[j++] = exp_acc; + case EXP_D25: + dest[j++] = exp_acc; + case EXP_D15: + dest[j++] = exp_acc; + } + + exp_acc += (exp_3 - 2); + + switch(expstr) + { + case EXP_D45: + dest[j++] = exp_acc; + dest[j++] = exp_acc; + case EXP_D25: + dest[j++] = exp_acc; + case EXP_D15: + dest[j++] = exp_acc; + } + } + + return; + + goto error; +error: + if(!error_flag) + fprintf(stderr,"** Invalid exponent - skipping frame **\n"); + error_flag = 1; +} + diff --git a/ac3dec/exponent.h b/ac3dec/exponent.h new file mode 100644 index 000000000..06c59db03 --- /dev/null +++ b/ac3dec/exponent.h @@ -0,0 +1,28 @@ +/* + * exponent.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define UNPACK_FBW 1 +#define UNPACK_CPL 2 +#define UNPACK_LFE 4 + +void exponent_unpack( bsi_t *bsi, audblk_t *audblk); diff --git a/ac3dec/imdct.c b/ac3dec/imdct.c new file mode 100644 index 000000000..ae2794ed7 --- /dev/null +++ b/ac3dec/imdct.c @@ -0,0 +1,468 @@ +/* + * imdct.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include "ac3.h" +#include "ac3_internal.h" + + +#include "decode.h" +#include "imdct.h" + +void imdct_do_256(float data[],float delay[]); +void imdct_do_512(float data[],float delay[]); + +typedef struct complex_s +{ + float real; + float imag; +} complex_t; + + +#define N 512 + + +/* 128 point bit-reverse LUT */ +static uint_8 bit_reverse_512[128] = { + 0x00, 0x40, 0x20, 0x60, 0x10, 0x50, 0x30, 0x70, + 0x08, 0x48, 0x28, 0x68, 0x18, 0x58, 0x38, 0x78, + 0x04, 0x44, 0x24, 0x64, 0x14, 0x54, 0x34, 0x74, + 0x0c, 0x4c, 0x2c, 0x6c, 0x1c, 0x5c, 0x3c, 0x7c, + 0x02, 0x42, 0x22, 0x62, 0x12, 0x52, 0x32, 0x72, + 0x0a, 0x4a, 0x2a, 0x6a, 0x1a, 0x5a, 0x3a, 0x7a, + 0x06, 0x46, 0x26, 0x66, 0x16, 0x56, 0x36, 0x76, + 0x0e, 0x4e, 0x2e, 0x6e, 0x1e, 0x5e, 0x3e, 0x7e, + 0x01, 0x41, 0x21, 0x61, 0x11, 0x51, 0x31, 0x71, + 0x09, 0x49, 0x29, 0x69, 0x19, 0x59, 0x39, 0x79, + 0x05, 0x45, 0x25, 0x65, 0x15, 0x55, 0x35, 0x75, + 0x0d, 0x4d, 0x2d, 0x6d, 0x1d, 0x5d, 0x3d, 0x7d, + 0x03, 0x43, 0x23, 0x63, 0x13, 0x53, 0x33, 0x73, + 0x0b, 0x4b, 0x2b, 0x6b, 0x1b, 0x5b, 0x3b, 0x7b, + 0x07, 0x47, 0x27, 0x67, 0x17, 0x57, 0x37, 0x77, + 0x0f, 0x4f, 0x2f, 0x6f, 0x1f, 0x5f, 0x3f, 0x7f}; + +static uint_8 bit_reverse_256[64] = { + 0x00, 0x20, 0x10, 0x30, 0x08, 0x28, 0x18, 0x38, + 0x04, 0x24, 0x14, 0x34, 0x0c, 0x2c, 0x1c, 0x3c, + 0x02, 0x22, 0x12, 0x32, 0x0a, 0x2a, 0x1a, 0x3a, + 0x06, 0x26, 0x16, 0x36, 0x0e, 0x2e, 0x1e, 0x3e, + 0x01, 0x21, 0x11, 0x31, 0x09, 0x29, 0x19, 0x39, + 0x05, 0x25, 0x15, 0x35, 0x0d, 0x2d, 0x1d, 0x3d, + 0x03, 0x23, 0x13, 0x33, 0x0b, 0x2b, 0x1b, 0x3b, + 0x07, 0x27, 0x17, 0x37, 0x0f, 0x2f, 0x1f, 0x3f}; + +static complex_t buf[128]; + +/* Twiddle factor LUT */ +static complex_t *w[7]; +static complex_t w_1[1]; +static complex_t w_2[2]; +static complex_t w_4[4]; +static complex_t w_8[8]; +static complex_t w_16[16]; +static complex_t w_32[32]; +static complex_t w_64[64]; + +/* Twiddle factors for IMDCT */ +static float xcos1[128]; +static float xsin1[128]; +static float xcos2[64]; +static float xsin2[64]; + +/* Delay buffer for time domain interleaving */ +static float delay[6][256]; + +/* Windowing function for Modified DCT - Thank you acroread */ +static float window[] = { + 0.00014, 0.00024, 0.00037, 0.00051, 0.00067, 0.00086, 0.00107, 0.00130, + 0.00157, 0.00187, 0.00220, 0.00256, 0.00297, 0.00341, 0.00390, 0.00443, + 0.00501, 0.00564, 0.00632, 0.00706, 0.00785, 0.00871, 0.00962, 0.01061, + 0.01166, 0.01279, 0.01399, 0.01526, 0.01662, 0.01806, 0.01959, 0.02121, + 0.02292, 0.02472, 0.02662, 0.02863, 0.03073, 0.03294, 0.03527, 0.03770, + 0.04025, 0.04292, 0.04571, 0.04862, 0.05165, 0.05481, 0.05810, 0.06153, + 0.06508, 0.06878, 0.07261, 0.07658, 0.08069, 0.08495, 0.08935, 0.09389, + 0.09859, 0.10343, 0.10842, 0.11356, 0.11885, 0.12429, 0.12988, 0.13563, + 0.14152, 0.14757, 0.15376, 0.16011, 0.16661, 0.17325, 0.18005, 0.18699, + 0.19407, 0.20130, 0.20867, 0.21618, 0.22382, 0.23161, 0.23952, 0.24757, + 0.25574, 0.26404, 0.27246, 0.28100, 0.28965, 0.29841, 0.30729, 0.31626, + 0.32533, 0.33450, 0.34376, 0.35311, 0.36253, 0.37204, 0.38161, 0.39126, + 0.40096, 0.41072, 0.42054, 0.43040, 0.44030, 0.45023, 0.46020, 0.47019, + 0.48020, 0.49022, 0.50025, 0.51028, 0.52031, 0.53033, 0.54033, 0.55031, + 0.56026, 0.57019, 0.58007, 0.58991, 0.59970, 0.60944, 0.61912, 0.62873, + 0.63827, 0.64774, 0.65713, 0.66643, 0.67564, 0.68476, 0.69377, 0.70269, + 0.71150, 0.72019, 0.72877, 0.73723, 0.74557, 0.75378, 0.76186, 0.76981, + 0.77762, 0.78530, 0.79283, 0.80022, 0.80747, 0.81457, 0.82151, 0.82831, + 0.83496, 0.84145, 0.84779, 0.85398, 0.86001, 0.86588, 0.87160, 0.87716, + 0.88257, 0.88782, 0.89291, 0.89785, 0.90264, 0.90728, 0.91176, 0.91610, + 0.92028, 0.92432, 0.92822, 0.93197, 0.93558, 0.93906, 0.94240, 0.94560, + 0.94867, 0.95162, 0.95444, 0.95713, 0.95971, 0.96217, 0.96451, 0.96674, + 0.96887, 0.97089, 0.97281, 0.97463, 0.97635, 0.97799, 0.97953, 0.98099, + 0.98236, 0.98366, 0.98488, 0.98602, 0.98710, 0.98811, 0.98905, 0.98994, + 0.99076, 0.99153, 0.99225, 0.99291, 0.99353, 0.99411, 0.99464, 0.99513, + 0.99558, 0.99600, 0.99639, 0.99674, 0.99706, 0.99736, 0.99763, 0.99788, + 0.99811, 0.99831, 0.99850, 0.99867, 0.99882, 0.99895, 0.99908, 0.99919, + 0.99929, 0.99938, 0.99946, 0.99953, 0.99959, 0.99965, 0.99969, 0.99974, + 0.99978, 0.99981, 0.99984, 0.99986, 0.99988, 0.99990, 0.99992, 0.99993, + 0.99994, 0.99995, 0.99996, 0.99997, 0.99998, 0.99998, 0.99998, 0.99999, + 0.99999, 0.99999, 0.99999, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, + 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000 }; + + +static inline void swap_cmplx(complex_t *a, complex_t *b) +{ + complex_t tmp; + + tmp = *a; + *a = *b; + *b = tmp; +} + + + +static inline complex_t cmplx_mult(complex_t a, complex_t b) +{ + complex_t ret; + + ret.real = a.real * b.real - a.imag * b.imag; + ret.imag = a.real * b.imag + a.imag * b.real; + + return ret; +} + +void imdct_init(void) +{ + int i,k; + complex_t angle_step; + complex_t current_angle; + + /* Twiddle factors to turn IFFT into IMDCT */ + for( i=0; i < 128; i++) + { + xcos1[i] = -cos(2.0f * M_PI * (8*i+1)/(8*N)) ; + xsin1[i] = -sin(2.0f * M_PI * (8*i+1)/(8*N)) ; + } + + /* More twiddle factors to turn IFFT into IMDCT */ + for( i=0; i < 64; i++) + { + xcos2[i] = -cos(2.0f * M_PI * (8*i+1)/(4*N)) ; + xsin2[i] = -sin(2.0f * M_PI * (8*i+1)/(4*N)) ; + } + + /* Canonical twiddle factors for FFT */ + w[0] = w_1; + w[1] = w_2; + w[2] = w_4; + w[3] = w_8; + w[4] = w_16; + w[5] = w_32; + w[6] = w_64; + + for( i = 0; i < 7; i++) + { + angle_step.real = cos(-2.0 * M_PI / (1 << (i+1))); + angle_step.imag = sin(-2.0 * M_PI / (1 << (i+1))); + + current_angle.real = 1.0; + current_angle.imag = 0.0; + + for (k = 0; k < 1 << i; k++) + { + w[i][k] = current_angle; + current_angle = cmplx_mult(current_angle,angle_step); + } + } +} + +void +imdct_do_512(float data[],float delay[]) +{ + int i,k; + int p,q; + int m; + int two_m; + int two_m_plus_one; + + float tmp_a_i; + float tmp_a_r; + float tmp_b_i; + float tmp_b_r; + + float *data_ptr; + float *delay_ptr; + float *window_ptr; + + // + // 512 IMDCT with source and dest data in 'data' + // + + // Pre IFFT complex multiply plus IFFT cmplx conjugate and bit reverse + // permutation + for( i=0; i < 128; i++) + { + k = bit_reverse_512[i]; + + /* z[i] = (X[256-2*i-1] + j * X[2*i]) * (xcos1[i] + j * xsin1[i]) ; */ + buf[k].real = (data[256-2*i-1] * xcos1[i]) - (data[2*i] * xsin1[i]); + buf[k].imag = -1.0 * ((data[2*i] * xcos1[i]) + (data[256-2*i-1] * xsin1[i])); + } + + // FFT Merge + for (m=0; m < 7; m++) + { + if(m) + two_m = (1 << m); + else + two_m = 1; + + two_m_plus_one = (1 << (m+1)); + + for(k = 0; k < two_m; k++) + { + for(i = 0; i < 128; i += two_m_plus_one) + { + p = k + i; + q = p + two_m; + tmp_a_r = buf[p].real; + tmp_a_i = buf[p].imag; + tmp_b_r = buf[q].real * w[m][k].real - buf[q].imag * w[m][k].imag; + tmp_b_i = buf[q].imag * w[m][k].real + buf[q].real * w[m][k].imag; + buf[p].real = tmp_a_r + tmp_b_r; + buf[p].imag = tmp_a_i + tmp_b_i; + buf[q].real = tmp_a_r - tmp_b_r; + buf[q].imag = tmp_a_i - tmp_b_i; + + } + } + } + + /* Post IFFT complex multiply plus IFFT complex conjugate*/ + for( i=0; i < 128; i++) + { + /* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; */ + tmp_a_r = buf[i].real; + tmp_a_i = buf[i].imag; + //Note that I flipped the signs on the imaginary ops to do the complex conj + buf[i].real =(tmp_a_r * xcos1[i]) + (tmp_a_i * xsin1[i]); + buf[i].imag =(tmp_a_r * xsin1[i]) - (tmp_a_i * xcos1[i]); + } + + data_ptr = data; + delay_ptr = delay; + window_ptr = window; + + /* Window and convert to real valued signal */ + for(i=0; i< 64; i++) + { + *data_ptr++ = 2.0f * (-buf[64+i].imag * *window_ptr++ + *delay_ptr++); + *data_ptr++ = 2.0f * ( buf[64-i-1].real * *window_ptr++ + *delay_ptr++); + } + + for(i=0; i< 64; i++) + { + *data_ptr++ = 2.0f * (-buf[i].real * *window_ptr++ + *delay_ptr++); + *data_ptr++ = 2.0f * ( buf[128-i-1].imag * *window_ptr++ + *delay_ptr++); + } + + /* The trailing edge of the window goes into the delay line */ + delay_ptr = delay; + + for(i=0; i< 64; i++) + { + *delay_ptr++ = -buf[64+i].real * *--window_ptr; + *delay_ptr++ = buf[64-i-1].imag * *--window_ptr; + } + + for(i=0; i<64; i++) + { + *delay_ptr++ = buf[i].imag * *--window_ptr; + *delay_ptr++ = -buf[128-i-1].real * *--window_ptr; + } +} + +void +imdct_do_256(float data[],float delay[]) +{ + int i,k; + int p,q; + int m; + int two_m; + int two_m_plus_one; + + float tmp_a_i; + float tmp_a_r; + float tmp_b_i; + float tmp_b_r; + + float *data_ptr; + float *delay_ptr; + float *window_ptr; + + complex_t *buf_1, *buf_2; + + buf_1 = &buf[0]; + buf_2 = &buf[64]; + + // Pre IFFT complex multiply plus IFFT cmplx conjugate and bit reverse + // permutation + for(i=0; i<64; i++) + { + /* X1[i] = X[2*i] */ + /* X2[i] = X[2*i+1] */ + + k = bit_reverse_256[i]; + + p = 2 * (128-2*i-1); + q = 2 * (2 * i); + + /* Z1[i] = (X1[128-2*i-1] + j * X1[2*i]) * (xcos2[i] + j * xsin2[i]); */ + buf_1[k].real = data[p] * xcos2[i] - data[q] * xsin2[i]; + buf_1[k].imag = -1.0f * (data[q] * xcos2[i] + data[p] * xsin2[i]); + /* Z2[i] = (X2[128-2*i-1] + j * X2[2*i]) * (xcos2[i] + j * xsin2[i]); */ + buf_2[k].real = data[p + 1] * xcos2[i] - data[q + 1] * xsin2[i]; + buf_2[k].imag = -1.0f * ( data[q + 1] * xcos2[i] + data[p + 1] * xsin2[i]); + } + + // FFT Merge + for (m=0; m < 6; m++) + { + two_m = (1 << m); + two_m_plus_one = (1 << (m+1)); + + if(m) + two_m = (1 << m); + else + two_m = 1; + + for(k = 0; k < two_m; k++) + { + for(i = 0; i < 64; i += two_m_plus_one) + { + p = k + i; + q = p + two_m; + //Do block 1 + tmp_a_r = buf_1[p].real; + tmp_a_i = buf_1[p].imag; + tmp_b_r = buf_1[q].real * w[m][k].real - buf_1[q].imag * w[m][k].imag; + tmp_b_i = buf_1[q].imag * w[m][k].real + buf_1[q].real * w[m][k].imag; + buf_1[p].real = tmp_a_r + tmp_b_r; + buf_1[p].imag = tmp_a_i + tmp_b_i; + buf_1[q].real = tmp_a_r - tmp_b_r; + buf_1[q].imag = tmp_a_i - tmp_b_i; + + //Do block 2 + tmp_a_r = buf_2[p].real; + tmp_a_i = buf_2[p].imag; + tmp_b_r = buf_2[q].real * w[m][k].real - buf_2[q].imag * w[m][k].imag; + tmp_b_i = buf_2[q].imag * w[m][k].real + buf_2[q].real * w[m][k].imag; + buf_2[p].real = tmp_a_r + tmp_b_r; + buf_2[p].imag = tmp_a_i + tmp_b_i; + buf_2[q].real = tmp_a_r - tmp_b_r; + buf_2[q].imag = tmp_a_i - tmp_b_i; + + } + } + } + + // Post IFFT complex multiply + for( i=0; i < 64; i++) + { + //Note that I flipped the signs on the imaginary ops to do the complex conj + + /* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */ + tmp_a_r = buf_1[i].real; + tmp_a_i = buf_1[i].imag; + buf_1[i].real =(tmp_a_r * xcos2[i]) + (tmp_a_i * xsin2[i]); + buf_1[i].imag =(tmp_a_r * xsin2[i]) - (tmp_a_i * xcos2[i]); + /* y2[n] = z2[n] * (xcos2[n] + j * xsin2[n]) ; */ + tmp_a_r = buf_2[i].real; + tmp_a_i = buf_2[i].imag; + buf_2[i].real =(tmp_a_r * xcos2[i]) + (tmp_a_i * xsin2[i]); + buf_2[i].imag =(tmp_a_r * xsin2[i]) - (tmp_a_i * xcos2[i]); + } + + data_ptr = data; + delay_ptr = delay; + window_ptr = window; + + /* Window and convert to real valued signal */ + for(i=0; i< 64; i++) + { + *data_ptr++ = 2.0f * (-buf_1[i].imag * *window_ptr++ + *delay_ptr++); + *data_ptr++ = 2.0f * ( buf_1[64-i-1].real * *window_ptr++ + *delay_ptr++); + } + + for(i=0; i< 64; i++) + { + *data_ptr++ = 2.0f * (-buf_1[i].real * *window_ptr++ + *delay_ptr++); + *data_ptr++ = 2.0f * ( buf_1[64-i-1].imag * *window_ptr++ + *delay_ptr++); + } + + delay_ptr = delay; + + for(i=0; i< 64; i++) + { + *delay_ptr++ = -buf_2[i].real * *--window_ptr; + *delay_ptr++ = buf_2[64-i-1].imag * *--window_ptr; + } + + for(i=0; i< 64; i++) + { + *delay_ptr++ = buf_2[i].imag * *--window_ptr; + *delay_ptr++ = -buf_2[64-i-1].real * *--window_ptr; + } +} + +//FIXME remove - for timing code +///#include <sys/time.h> +//FIXME remove + +void +imdct(bsi_t *bsi,audblk_t *audblk, stream_samples_t samples) { + int i; + + //handy timing code + //struct timeval start,end; + + //gettimeofday(&start,0); + + for(i=0; i<bsi->nfchans;i++) + { + if(audblk->blksw[i]) + imdct_do_256(samples[i],delay[i]); + else + imdct_do_512(samples[i],delay[i]); + } + //gettimeofday(&end,0); + //printf("imdct %ld us\n",(end.tv_sec - start.tv_sec) * 1000000 + + //end.tv_usec - start.tv_usec); + + //XXX We don't bother with the IMDCT for the LFE as it's currently + //unused. + //if (bsi->lfeon) + // imdct_do_512(coeffs->lfe,samples->channel[5],delay[5]); + // +} diff --git a/ac3dec/imdct.h b/ac3dec/imdct.h new file mode 100644 index 000000000..750aa8798 --- /dev/null +++ b/ac3dec/imdct.h @@ -0,0 +1,26 @@ +/* + * imdct.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +void imdct(bsi_t *bsi,audblk_t *audblk, stream_samples_t samples); +void imdct_init(void); diff --git a/ac3dec/parse.c b/ac3dec/parse.c new file mode 100644 index 000000000..3560bc5ab --- /dev/null +++ b/ac3dec/parse.c @@ -0,0 +1,597 @@ +/* + * parse.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include "ac3.h" +#include "ac3_internal.h" + + +#include "bitstream.h" +#include "stats.h" +#include "debug.h" +#include "parse.h" + +/* Misc LUT */ +static const uint_16 nfchans[8] = {2,1,2,3,3,4,4,5}; + +struct frmsize_s +{ + uint_16 bit_rate; + uint_16 frm_size[3]; +}; + +static const struct frmsize_s frmsizecod_tbl[64] = +{ + { 32 ,{64 ,69 ,96 } }, + { 32 ,{64 ,70 ,96 } }, + { 40 ,{80 ,87 ,120 } }, + { 40 ,{80 ,88 ,120 } }, + { 48 ,{96 ,104 ,144 } }, + { 48 ,{96 ,105 ,144 } }, + { 56 ,{112 ,121 ,168 } }, + { 56 ,{112 ,122 ,168 } }, + { 64 ,{128 ,139 ,192 } }, + { 64 ,{128 ,140 ,192 } }, + { 80 ,{160 ,174 ,240 } }, + { 80 ,{160 ,175 ,240 } }, + { 96 ,{192 ,208 ,288 } }, + { 96 ,{192 ,209 ,288 } }, + { 112 ,{224 ,243 ,336 } }, + { 112 ,{224 ,244 ,336 } }, + { 128 ,{256 ,278 ,384 } }, + { 128 ,{256 ,279 ,384 } }, + { 160 ,{320 ,348 ,480 } }, + { 160 ,{320 ,349 ,480 } }, + { 192 ,{384 ,417 ,576 } }, + { 192 ,{384 ,418 ,576 } }, + { 224 ,{448 ,487 ,672 } }, + { 224 ,{448 ,488 ,672 } }, + { 256 ,{512 ,557 ,768 } }, + { 256 ,{512 ,558 ,768 } }, + { 320 ,{640 ,696 ,960 } }, + { 320 ,{640 ,697 ,960 } }, + { 384 ,{768 ,835 ,1152 } }, + { 384 ,{768 ,836 ,1152 } }, + { 448 ,{896 ,975 ,1344 } }, + { 448 ,{896 ,976 ,1344 } }, + { 512 ,{1024 ,1114 ,1536 } }, + { 512 ,{1024 ,1115 ,1536 } }, + { 576 ,{1152 ,1253 ,1728 } }, + { 576 ,{1152 ,1254 ,1728 } }, + { 640 ,{1280 ,1393 ,1920 } }, + { 640 ,{1280 ,1394 ,1920 } } +}; + +/* Parse a syncinfo structure, minus the sync word */ +void +parse_syncinfo(syncinfo_t *syncinfo,uint_8 *data) +{ + // + // We need to read in the entire syncinfo struct (0x0b77 + 24 bits) + // in order to determine how big the frame is + // + + // Get the sampling rate + syncinfo->fscod = (data[2] >> 6) & 0x3; + + if(syncinfo->fscod == 3) + { + //invalid sampling rate code + error_flag = 1; + return; + } + else if(syncinfo->fscod == 2) + syncinfo->sampling_rate = 32000; + else if(syncinfo->fscod == 1) + syncinfo->sampling_rate = 44100; + else + syncinfo->sampling_rate = 48000; + + // Get the frame size code + syncinfo->frmsizecod = data[2] & 0x3f; + + // Calculate the frame size and bitrate + syncinfo->frame_size = + frmsizecod_tbl[syncinfo->frmsizecod].frm_size[syncinfo->fscod]; + syncinfo->bit_rate = frmsizecod_tbl[syncinfo->frmsizecod].bit_rate; + +} + +/* + * This routine fills a bsi struct from the AC3 stream + */ + +void +parse_bsi(bsi_t *bsi) +{ + uint_32 i; + + /* Check the AC-3 version number */ + bsi->bsid = bitstream_get(5); + + /* Get the audio service provided by the steram */ + bsi->bsmod = bitstream_get(3); + + /* Get the audio coding mode (ie how many channels)*/ + bsi->acmod = bitstream_get(3); + /* Predecode the number of full bandwidth channels as we use this + * number a lot */ + bsi->nfchans = nfchans[bsi->acmod]; + + /* If it is in use, get the centre channel mix level */ + if ((bsi->acmod & 0x1) && (bsi->acmod != 0x1)) + bsi->cmixlev = bitstream_get(2); + + /* If it is in use, get the surround channel mix level */ + if (bsi->acmod & 0x4) + bsi->surmixlev = bitstream_get(2); + + /* Get the dolby surround mode if in 2/0 mode */ + if(bsi->acmod == 0x2) + bsi->dsurmod= bitstream_get(2); + + /* Is the low frequency effects channel on? */ + bsi->lfeon = bitstream_get(1); + + /* Get the dialogue normalization level */ + bsi->dialnorm = bitstream_get(5); + + /* Does compression gain exist? */ + bsi->compre = bitstream_get(1); + if (bsi->compre) + { + /* Get compression gain */ + bsi->compr = bitstream_get(8); + } + + /* Does language code exist? */ + bsi->langcode = bitstream_get(1); + if (bsi->langcode) + { + /* Get langauge code */ + bsi->langcod = bitstream_get(8); + } + + /* Does audio production info exist? */ + bsi->audprodie = bitstream_get(1); + if (bsi->audprodie) + { + /* Get mix level */ + bsi->mixlevel = bitstream_get(5); + + /* Get room type */ + bsi->roomtyp = bitstream_get(2); + } + + /* If we're in dual mono mode then get some extra info */ + if (bsi->acmod ==0) + { + /* Get the dialogue normalization level two */ + bsi->dialnorm2 = bitstream_get(5); + + /* Does compression gain two exist? */ + bsi->compr2e = bitstream_get(1); + if (bsi->compr2e) + { + /* Get compression gain two */ + bsi->compr2 = bitstream_get(8); + } + + /* Does language code two exist? */ + bsi->langcod2e = bitstream_get(1); + if (bsi->langcod2e) + { + /* Get langauge code two */ + bsi->langcod2 = bitstream_get(8); + } + + /* Does audio production info two exist? */ + bsi->audprodi2e = bitstream_get(1); + if (bsi->audprodi2e) + { + /* Get mix level two */ + bsi->mixlevel2 = bitstream_get(5); + + /* Get room type two */ + bsi->roomtyp2 = bitstream_get(2); + } + } + + /* Get the copyright bit */ + bsi->copyrightb = bitstream_get(1); + + /* Get the original bit */ + bsi->origbs = bitstream_get(1); + + /* Does timecode one exist? */ + bsi->timecod1e = bitstream_get(1); + + if(bsi->timecod1e) + bsi->timecod1 = bitstream_get(14); + + /* Does timecode two exist? */ + bsi->timecod2e = bitstream_get(1); + + if(bsi->timecod2e) + bsi->timecod2 = bitstream_get(14); + + /* Does addition info exist? */ + bsi->addbsie = bitstream_get(1); + + if(bsi->addbsie) + { + /* Get how much info is there */ + bsi->addbsil = bitstream_get(6); + + /* Get the additional info */ + for(i=0;i<(bsi->addbsil + 1);i++) + bsi->addbsi[i] = bitstream_get(8); + } + + stats_print_bsi(bsi); +} + +/* More pain inducing parsing */ +void +parse_audblk(bsi_t *bsi,audblk_t *audblk) +{ + int i,j; + + for (i=0;i < bsi->nfchans; i++) + { + /* Is this channel an interleaved 256 + 256 block ? */ + audblk->blksw[i] = bitstream_get(1); + } + + for (i=0;i < bsi->nfchans; i++) + { + /* Should we dither this channel? */ + audblk->dithflag[i] = bitstream_get(1); + } + + /* Does dynamic range control exist? */ + audblk->dynrnge = bitstream_get(1); + if (audblk->dynrnge) + { + /* Get dynamic range info */ + audblk->dynrng = bitstream_get(8); + } + + /* If we're in dual mono mode then get the second channel DR info */ + if (bsi->acmod == 0) + { + /* Does dynamic range control two exist? */ + audblk->dynrng2e = bitstream_get(1); + if (audblk->dynrng2e) + { + /* Get dynamic range info */ + audblk->dynrng2 = bitstream_get(8); + } + } + + /* Does coupling strategy exist? */ + audblk->cplstre = bitstream_get(1); + if (audblk->cplstre) + { + /* Is coupling turned on? */ + audblk->cplinu = bitstream_get(1); + if(audblk->cplinu) + { + for(i=0;i < bsi->nfchans; i++) + audblk->chincpl[i] = bitstream_get(1); + if(bsi->acmod == 0x2) + audblk->phsflginu = bitstream_get(1); + audblk->cplbegf = bitstream_get(4); + audblk->cplendf = bitstream_get(4); + audblk->ncplsubnd = (audblk->cplendf + 2) - audblk->cplbegf + 1; + + /* Calculate the start and end bins of the coupling channel */ + audblk->cplstrtmant = (audblk->cplbegf * 12) + 37 ; + audblk->cplendmant = ((audblk->cplendf + 3) * 12) + 37; + + /* The number of combined subbands is ncplsubnd minus each combined + * band */ + audblk->ncplbnd = audblk->ncplsubnd; + + for(i=1; i< audblk->ncplsubnd; i++) + { + audblk->cplbndstrc[i] = bitstream_get(1); + audblk->ncplbnd -= audblk->cplbndstrc[i]; + } + } + } + + if(audblk->cplinu) + { + /* Loop through all the channels and get their coupling co-ords */ + for(i=0;i < bsi->nfchans;i++) + { + if(!audblk->chincpl[i]) + continue; + + /* Is there new coupling co-ordinate info? */ + audblk->cplcoe[i] = bitstream_get(1); + + if(audblk->cplcoe[i]) + { + audblk->mstrcplco[i] = bitstream_get(2); + for(j=0;j < audblk->ncplbnd; j++) + { + audblk->cplcoexp[i][j] = bitstream_get(4); + audblk->cplcomant[i][j] = bitstream_get(4); + } + } + } + + /* If we're in dual mono mode, there's going to be some phase info */ + if( (bsi->acmod == 0x2) && audblk->phsflginu && + (audblk->cplcoe[0] || audblk->cplcoe[1])) + { + for(j=0;j < audblk->ncplbnd; j++) + audblk->phsflg[j] = bitstream_get(1); + + } + } + + /* If we're in dual mono mode, there may be a rematrix strategy */ + if(bsi->acmod == 0x2) + { + audblk->rematstr = bitstream_get(1); + if(audblk->rematstr) + { + if (audblk->cplinu == 0) + { + for(i = 0; i < 4; i++) + audblk->rematflg[i] = bitstream_get(1); + } + if((audblk->cplbegf > 2) && audblk->cplinu) + { + for(i = 0; i < 4; i++) + audblk->rematflg[i] = bitstream_get(1); + } + if((audblk->cplbegf <= 2) && audblk->cplinu) + { + for(i = 0; i < 3; i++) + audblk->rematflg[i] = bitstream_get(1); + } + if((audblk->cplbegf == 0) && audblk->cplinu) + for(i = 0; i < 2; i++) + audblk->rematflg[i] = bitstream_get(1); + + } + } + + if (audblk->cplinu) + { + /* Get the coupling channel exponent strategy */ + audblk->cplexpstr = bitstream_get(2); + audblk->ncplgrps = (audblk->cplendmant - audblk->cplstrtmant) / + (3 << (audblk->cplexpstr-1)); + } + + for(i = 0; i < bsi->nfchans; i++) + audblk->chexpstr[i] = bitstream_get(2); + + /* Get the exponent strategy for lfe channel */ + if(bsi->lfeon) + audblk->lfeexpstr = bitstream_get(1); + + /* Determine the bandwidths of all the fbw channels */ + for(i = 0; i < bsi->nfchans; i++) + { + uint_16 grp_size; + + if(audblk->chexpstr[i] != EXP_REUSE) + { + if (audblk->cplinu && audblk->chincpl[i]) + { + audblk->endmant[i] = audblk->cplstrtmant; + } + else + { + audblk->chbwcod[i] = bitstream_get(6); + audblk->endmant[i] = ((audblk->chbwcod[i] + 12) * 3) + 37; + } + + /* Calculate the number of exponent groups to fetch */ + grp_size = 3 * (1 << (audblk->chexpstr[i] - 1)); + audblk->nchgrps[i] = (audblk->endmant[i] - 1 + (grp_size - 3)) / grp_size; + } + } + + /* Get the coupling exponents if they exist */ + if(audblk->cplinu && (audblk->cplexpstr != EXP_REUSE)) + { + audblk->cplabsexp = bitstream_get(4); + for(i=0;i< audblk->ncplgrps;i++) + audblk->cplexps[i] = bitstream_get(7); + } + + /* Get the fwb channel exponents */ + for(i=0;i < bsi->nfchans; i++) + { + if(audblk->chexpstr[i] != EXP_REUSE) + { + audblk->exps[i][0] = bitstream_get(4); + for(j=1;j<=audblk->nchgrps[i];j++) + audblk->exps[i][j] = bitstream_get(7); + audblk->gainrng[i] = bitstream_get(2); + } + } + + /* Get the lfe channel exponents */ + if(bsi->lfeon && (audblk->lfeexpstr != EXP_REUSE)) + { + audblk->lfeexps[0] = bitstream_get(4); + audblk->lfeexps[1] = bitstream_get(7); + audblk->lfeexps[2] = bitstream_get(7); + } + + /* Get the parametric bit allocation parameters */ + audblk->baie = bitstream_get(1); + + if(audblk->baie) + { + audblk->sdcycod = bitstream_get(2); + audblk->fdcycod = bitstream_get(2); + audblk->sgaincod = bitstream_get(2); + audblk->dbpbcod = bitstream_get(2); + audblk->floorcod = bitstream_get(3); + } + + /* Get the SNR off set info if it exists */ + audblk->snroffste = bitstream_get(1); + + if(audblk->snroffste) + { + audblk->csnroffst = bitstream_get(6); + + if(audblk->cplinu) + { + audblk->cplfsnroffst = bitstream_get(4); + audblk->cplfgaincod = bitstream_get(3); + } + + for(i = 0;i < bsi->nfchans; i++) + { + audblk->fsnroffst[i] = bitstream_get(4); + audblk->fgaincod[i] = bitstream_get(3); + } + if(bsi->lfeon) + { + + audblk->lfefsnroffst = bitstream_get(4); + audblk->lfefgaincod = bitstream_get(3); + } + } + + /* Get coupling leakage info if it exists */ + if(audblk->cplinu) + { + audblk->cplleake = bitstream_get(1); + + if(audblk->cplleake) + { + audblk->cplfleak = bitstream_get(3); + audblk->cplsleak = bitstream_get(3); + } + } + + /* Get the delta bit alloaction info */ + audblk->deltbaie = bitstream_get(1); + + if(audblk->deltbaie) + { + if(audblk->cplinu) + audblk->cpldeltbae = bitstream_get(2); + + for(i = 0;i < bsi->nfchans; i++) + audblk->deltbae[i] = bitstream_get(2); + + if (audblk->cplinu && (audblk->cpldeltbae == DELTA_BIT_NEW)) + { + audblk->cpldeltnseg = bitstream_get(3); + for(i = 0;i < audblk->cpldeltnseg + 1; i++) + { + audblk->cpldeltoffst[i] = bitstream_get(5); + audblk->cpldeltlen[i] = bitstream_get(4); + audblk->cpldeltba[i] = bitstream_get(3); + } + } + + for(i = 0;i < bsi->nfchans; i++) + { + if (audblk->deltbae[i] == DELTA_BIT_NEW) + { + audblk->deltnseg[i] = bitstream_get(3); + for(j = 0; j < audblk->deltnseg[i] + 1; j++) + { + audblk->deltoffst[i][j] = bitstream_get(5); + audblk->deltlen[i][j] = bitstream_get(4); + audblk->deltba[i][j] = bitstream_get(3); + } + } + } + } + + /* Check to see if there's any dummy info to get */ + if((audblk->skiple = bitstream_get(1))) + { + uint_16 skip_data; + + audblk->skipl = bitstream_get(9); + //XXX remove + //fprintf(stderr,"(parse) skipping %d bytes\n",audblk->skipl); + + for(i = 0; i < audblk->skipl ; i++) + { + skip_data = bitstream_get(8); + //XXX remove + //fprintf(stderr,"skipped data %2x\n",skip_data); + //if(skip_data != 0) + //{ + //dprintf("(parse) Invalid skipped data %2x\n",skip_data); + //exit(1); + //} + } + } + + stats_print_audblk(bsi,audblk); +} + +void +parse_auxdata(syncinfo_t *syncinfo) +{ + //FIXME keep this now that we don't really need it? +#if 0 + int i; + int skip_length; + uint_16 crc; + uint_16 auxdatae; + + skip_length = (syncinfo->frame_size * 16) - bitstream_get_total_bits() - 17 - 1; + + //XXX remove + //dprintf("(auxdata) skipping %d auxbits\n",skip_length); + + for(i=0; i < skip_length; i++) + //printf("Skipped bit %i\n",(uint_16)bitstream_get(1)); + bitstream_get(1); + + //get the auxdata exists bit + auxdatae = bitstream_get(1); + + //XXX remove + //dprintf("auxdatae = %i\n",auxdatae); + + //Skip the CRC reserved bit + bitstream_get(1); + + //Get the crc + crc = bitstream_get(16); +#endif +} + + diff --git a/ac3dec/parse.h b/ac3dec/parse.h new file mode 100644 index 000000000..cdaee66f4 --- /dev/null +++ b/ac3dec/parse.h @@ -0,0 +1,28 @@ +/* + * parse.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +void parse_syncinfo(syncinfo_t *syncinfo,uint_8 *data); +void parse_audblk(bsi_t *bsi,audblk_t *audblk); +void parse_bsi(bsi_t *bsi); +void parse_auxdata(syncinfo_t *syncinfo); + diff --git a/ac3dec/rematrix.c b/ac3dec/rematrix.c new file mode 100644 index 000000000..caa709430 --- /dev/null +++ b/ac3dec/rematrix.c @@ -0,0 +1,83 @@ +/* + * rematrix.c + * + * Copyright (C) Aaron Holtzman - July 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include "ac3.h" +#include "ac3_internal.h" + + +#include "decode.h" +#include "rematrix.h" + +struct rematrix_band_s +{ + uint_32 start; + uint_32 end; +}; + +struct rematrix_band_s rematrix_band[] = { {13,24}, {25,36}, {37 ,60}, {61,252}}; + +static inline uint_32 min(uint_32 a,uint_32 b); + +static inline uint_32 +min(uint_32 a,uint_32 b) +{ + return (a < b ? a : b); +} + +/* This routine simply does stereo rematixing for the 2 channel + * stereo mode */ +void rematrix(audblk_t *audblk, stream_samples_t samples) +{ + uint_32 num_bands; + uint_32 start; + uint_32 end; + uint_32 i,j; + float left,right; + + if(!audblk->cplinu || audblk->cplbegf > 2) + num_bands = 4; + else if (audblk->cplbegf > 0) + num_bands = 3; + else + num_bands = 2; + + for(i=0;i < num_bands; i++) + { + if(!audblk->rematflg[i]) + continue; + + start = rematrix_band[i].start; + end = min(rematrix_band[i].end ,12 * audblk->cplbegf + 36); + + for(j=start;j < end; j++) + { + left = samples[0][j] + samples[1][j]; + right = samples[0][j] - samples[1][j]; + samples[0][j] = left; + samples[1][j] = right; + } + } +} diff --git a/ac3dec/rematrix.h b/ac3dec/rematrix.h new file mode 100644 index 000000000..0be6528f6 --- /dev/null +++ b/ac3dec/rematrix.h @@ -0,0 +1,25 @@ +/* + * rematrix.h + * + * Copyright (C) Aaron Holtzman - July 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +void rematrix(audblk_t *audblk, stream_samples_t samples); diff --git a/ac3dec/sanity_check.c b/ac3dec/sanity_check.c new file mode 100644 index 000000000..461f20ea9 --- /dev/null +++ b/ac3dec/sanity_check.c @@ -0,0 +1,131 @@ +/* + * sanity_check.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include "ac3.h" +#include "ac3_internal.h" +#include "sanity_check.h" + + +void +sanity_check_init(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk) +{ + syncinfo->magic = AC3_MAGIC_NUMBER; + bsi->magic = AC3_MAGIC_NUMBER; + audblk->magic1 = AC3_MAGIC_NUMBER; + audblk->magic2 = AC3_MAGIC_NUMBER; + audblk->magic3 = AC3_MAGIC_NUMBER; +} + +void +sanity_check(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk) +{ + int i; + + if(syncinfo->magic != AC3_MAGIC_NUMBER) + { + fprintf(stderr,"\n** Sanity check failed -- syncinfo magic number **"); + error_flag = 1; + } + + if(bsi->magic != AC3_MAGIC_NUMBER) + { + fprintf(stderr,"\n** Sanity check failed -- bsi magic number **"); + error_flag = 1; + } + + if(audblk->magic1 != AC3_MAGIC_NUMBER) + { + fprintf(stderr,"\n** Sanity check failed -- audblk magic number 1 **"); + error_flag = 1; + } + + if(audblk->magic2 != AC3_MAGIC_NUMBER) + { + fprintf(stderr,"\n** Sanity check failed -- audblk magic number 2 **"); + error_flag = 1; + } + + if(audblk->magic3 != AC3_MAGIC_NUMBER) + { + fprintf(stderr,"\n** Sanity check failed -- audblk magic number 3 **"); + error_flag = 1; + } + + for(i = 0;i < 5 ; i++) + { + if (audblk->fbw_exp[i][255] !=0 || audblk->fbw_exp[i][254] !=0 || + audblk->fbw_exp[i][253] !=0) + { + fprintf(stderr,"\n** Sanity check failed -- fbw_exp out of bounds **"); + error_flag = 1; + } + + if (audblk->fbw_bap[i][255] !=0 || audblk->fbw_bap[i][254] !=0 || + audblk->fbw_bap[i][253] !=0) + { + fprintf(stderr,"\n** Sanity check failed -- fbw_bap out of bounds **"); + error_flag = 1; + } + + } + + if (audblk->cpl_exp[255] !=0 || audblk->cpl_exp[254] !=0 || + audblk->cpl_exp[253] !=0) + { + fprintf(stderr,"\n** Sanity check failed -- cpl_exp out of bounds **"); + error_flag = 1; + } + + if (audblk->cpl_bap[255] !=0 || audblk->cpl_bap[254] !=0 || + audblk->cpl_bap[253] !=0) + { + fprintf(stderr,"\n** Sanity check failed -- cpl_bap out of bounds **"); + error_flag = 1; + } + + if (audblk->cplmant[255] !=0 || audblk->cplmant[254] !=0 || + audblk->cplmant[253] !=0) + { + fprintf(stderr,"\n** Sanity check failed -- cpl_mant out of bounds **"); + error_flag = 1; + } + + if ((audblk->cplinu == 1) && (audblk->cplbegf > (audblk->cplendf+2))) + { + fprintf(stderr,"\n** Sanity check failed -- cpl params inconsistent **"); + error_flag = 1; + } + + for(i=0; i < bsi->nfchans; i++) + { + if((audblk->chincpl[i] == 0) && (audblk->chbwcod[i] > 60)) + { + fprintf(stderr,"\n** Sanity check failed -- chbwcod too big **"); + error_flag = 1; + } + } + + return; +} diff --git a/ac3dec/sanity_check.h b/ac3dec/sanity_check.h new file mode 100644 index 000000000..c4ca63a21 --- /dev/null +++ b/ac3dec/sanity_check.h @@ -0,0 +1,27 @@ +/* + * sanity_check.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define AC3_MAGIC_NUMBER 0xdeadbeef + +void sanity_check_init(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk); +void sanity_check(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk); diff --git a/ac3dec/stats.c b/ac3dec/stats.c new file mode 100644 index 000000000..cfeb453f4 --- /dev/null +++ b/ac3dec/stats.c @@ -0,0 +1,178 @@ +/* + * stats.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdlib.h> +#include <stdio.h> +//#include "config.h" +#include "ac3.h" +#include "ac3_internal.h" + + +#include "decode.h" +#include "stats.h" +#include "debug.h" + + +static const char *service_ids[8] = +{ + "CM","ME","VI","HI", + "D", "C","E", "VO" +}; + +struct mixlev_s +{ + float clev; + char *desc; +}; + +static const struct mixlev_s cmixlev_tbl[4] = +{ + {0.707, "(-3.0 dB)"}, {0.595, "(-4.5 dB)"}, + {0.500, "(-6.0 dB)"}, {1.0, "Invalid"} +}; + +static const struct mixlev_s smixlev_tbl[4] = +{ + {0.707, "(-3.0 dB)"}, {0.500, "(-6.0 dB)"}, + { 0.0, "off "}, { 1.0, "Invalid"} +}; + +static const char *language[128] = +{ + "unknown", "Albanian", "Breton", "Catalan", "Croatian", "Welsh", "Czech", "Danish", + "German", "English", "Spanish", "Esperanto", "Estonian", "Basque", "Faroese", "French", + "Frisian", "Irish", "Gaelic", "Galician", "Icelandic", "Italian", "Lappish", "Latin", + "Latvian", "Luxembourgian", "Lithuanian", "Hungarian", "Maltese", "Dutch", "Norwegian", "Occitan", + "Polish", "Portugese", "Romanian", "Romansh", "Serbian", "Slovak", "Slovene", "Finnish", + "Swedish", "Turkish", "Flemish", "Walloon", "0x2c", "0x2d", "0x2e", "0x2f", + "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", + "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "0x3f", + "background", "0x41", "0x42", "0x43", "0x44", "Zulu", "Vietnamese", "Uzbek", + "Urdu", "Ukrainian", "Thai", "Telugu", "Tatar", "Tamil", "Tadzhik", "Swahili", + "Sranan Tongo", "Somali", "Sinhalese", "Shona", "Serbo-Croat", "Ruthenian", "Russian", "Quechua", + "Pustu", "Punjabi", "Persian", "Papamiento", "Oriya", "Nepali", "Ndebele", "Marathi", + "Moldavian", "Malaysian", "Malagasay", "Macedonian", "Laotian", "Korean", "Khmer", "Kazakh", + "Kannada", "Japanese", "Indonesian", "Hindi", "Hebrew", "Hausa", "Gurani", "Gujurati", + "Greek", "Georgian", "Fulani", "Dari", "Churash", "Chinese", "Burmese", "Bulgarian", + "Bengali", "Belorussian", "Bambora", "Azerbijani", "Assamese", "Armenian", "Arabic", "Amharic" +}; + +void stats_print_banner(syncinfo_t *syncinfo,bsi_t *bsi) +{ + fprintf(stdout,"ac3dec-0.6.2-cvs (C) 2000 Aaron Holtzman (aholtzma@ess.engr.uvic.ca)\n"); + + fprintf(stdout,"%d.%d Mode ",bsi->nfchans,bsi->lfeon); + fprintf(stdout,"%2.1f KHz",syncinfo->sampling_rate * 1e-3); + fprintf(stdout,"%4d kbps ",syncinfo->bit_rate); + if (bsi->langcode && (bsi->langcod < 128)) + fprintf(stdout,"%s ", language[bsi->langcod]); + + switch(bsi->bsmod) + { + case 0: + fprintf(stdout,"Complete Main Audio Service"); + break; + case 1: + fprintf(stdout,"Music and Effects Audio Service"); + case 2: + fprintf(stdout,"Visually Impaired Audio Service"); + break; + case 3: + fprintf(stdout,"Hearing Impaired Audio Service"); + break; + case 4: + fprintf(stdout,"Dialogue Audio Service"); + break; + case 5: + fprintf(stdout,"Commentary Audio Service"); + break; + case 6: + fprintf(stdout,"Emergency Audio Service"); + break; + case 7: + fprintf(stdout,"Voice Over Audio Service"); + break; + } + fprintf(stdout,"\n"); +} + +void stats_print_syncinfo(syncinfo_t *syncinfo) +{ + dprintf("(syncinfo) "); + + switch (syncinfo->fscod) + { + case 2: + dprintf("32 KHz "); + break; + case 1: + dprintf("44.1 KHz "); + break; + case 0: + dprintf("48 KHz "); + break; + default: + dprintf("Invalid sampling rate "); + break; + } + + dprintf("%4d kbps %4d words per frame\n",syncinfo->bit_rate, + syncinfo->frame_size); + +} + +void stats_print_bsi(bsi_t *bsi) +{ + dprintf("(bsi) "); + dprintf("%s",service_ids[bsi->bsmod]); + dprintf(" %d.%d Mode ",bsi->nfchans,bsi->lfeon); + if ((bsi->acmod & 0x1) && (bsi->acmod != 0x1)) + dprintf(" Centre Mix Level %s ",cmixlev_tbl[bsi->cmixlev].desc); + if (bsi->acmod & 0x4) + dprintf(" Sur Mix Level %s ",smixlev_tbl[bsi->cmixlev].desc); + dprintf("\n"); + +} + +char *exp_strat_tbl[4] = {"R ","D15 ","D25 ","D45 "}; + +void stats_print_audblk(bsi_t *bsi,audblk_t *audblk) +{ + uint_32 i; + + dprintf("(audblk) "); + dprintf("%s ",audblk->cplinu ? "cpl on " : "cpl off"); + dprintf("%s ",audblk->baie? "bai " : " "); + dprintf("%s ",audblk->snroffste? "snroffst " : " "); + dprintf("%s ",audblk->deltbaie? "deltba " : " "); + dprintf("%s ",audblk->phsflginu? "phsflg " : " "); + dprintf("(%s %s %s %s %s) ",exp_strat_tbl[audblk->chexpstr[0]], + exp_strat_tbl[audblk->chexpstr[1]],exp_strat_tbl[audblk->chexpstr[2]], + exp_strat_tbl[audblk->chexpstr[3]],exp_strat_tbl[audblk->chexpstr[4]]); + dprintf("["); + for(i=0;i<bsi->nfchans;i++) + dprintf("%1d",audblk->blksw[i]); + dprintf("]"); + + dprintf("\n"); +} diff --git a/ac3dec/stats.h b/ac3dec/stats.h new file mode 100644 index 000000000..8a9ecb69b --- /dev/null +++ b/ac3dec/stats.h @@ -0,0 +1,27 @@ +/* + * stats.h + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +void stats_print_syncinfo(syncinfo_t *syncinfo); +void stats_print_bsi(bsi_t *bsi); +void stats_print_audblk(bsi_t *bsi,audblk_t *audblk); +void stats_print_banner(syncinfo_t *syncinfo,bsi_t *bsi); diff --git a/channels.conf b/channels.conf index 8fc1a980c..1f62f70d9 100644 --- a/channels.conf +++ b/channels.conf @@ -94,7 +94,7 @@ Cinedom 5B:11720:h:0:27500:1791:1792:0:3:177 Cinedom 5C:12070:h:0:27500:1023:1024:0:3:186 :Beta Digital CNBC:12148:h:0:27500:255:256:0:3:35 -Liberty TV.com:12610:V:0:22000:941:943:0:0:12199 +Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199 :PW Erotic Beate-Uhse.TV:11758:h:0:27500:3839:3840:0:3:21 Blue Movie 1:11758:h:0:27500:1791:1792:0:3:513 diff --git a/config.h b/config.h index 58d038241..bbf5d6594 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.55 2001/07/27 13:32:53 kls Exp $ + * $Id: config.h 1.57 2001/08/06 16:44:38 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.85" +#define VDRVERSION "0.90" #define MaxBuffer 10000 diff --git a/dvbapi.c b/dvbapi.c index 07b6f61bc..0524f00f2 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,9 +4,14 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.96 2001/07/29 10:32:50 kls Exp $ + * DVD support initially written by Andreas Schultz <aschultz@warp10.net> + * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> + * + * $Id: dvbapi.c 1.101 2001/08/06 16:24:13 kls Exp $ */ +//#define DVDDEBUG 1 + #include "dvbapi.h" #include <dirent.h> #include <errno.h> @@ -21,6 +26,13 @@ extern "C" { #include <sys/stat.h> #include <sys/time.h> #include <unistd.h> + +#ifdef DVDSUPPORT +extern "C" { +#include "ac3dec/ac3.h" +} +#endif //DVDSUPPORT + #include "config.h" #include "recording.h" #include "remux.h" @@ -40,7 +52,8 @@ extern "C" { // The size of the array used to buffer video data: // (must be larger than MINVIDEODATA - see remux.h) -#define VIDEOBUFSIZE (1024*1024) +#define VIDEOBUFSIZE (1024*1024) +#define AC3_BUFFER_SIZE (6*1024*16) // The maximum size of a single frame: #define MAXFRAMESIZE (192*1024) @@ -437,7 +450,7 @@ int cFileName::NextFile(void) // --- cRecordBuffer --------------------------------------------------------- -class cRecordBuffer : public cRingBuffer { +class cRecordBuffer : public cRingBufferLinear { private: cDvbApi *dvbApi; cFileName fileName; @@ -460,7 +473,7 @@ class cRecordBuffer : public cRingBuffer { }; cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2) -:cRingBuffer(VIDEOBUFSIZE, true) +:cRingBufferLinear(VIDEOBUFSIZE, true) ,fileName(FileName, true) ,remux(VPid, APid1, APid2, DPid1, DPid2, true) { @@ -615,70 +628,228 @@ int ReadFrame(int f, uchar *b, int Length, int Max) return r; } -// --- cReplayBuffer --------------------------------------------------------- +// --- cPlayBuffer --------------------------------------------------------- -class cReplayBuffer : public cRingBuffer { -private: +class cPlayBuffer : public cRingBufferFrame { +protected: cDvbApi *dvbApi; - cIndexFile *index; - cFileName fileName; - int fileOffset; int videoDev, audioDev; FILE *dolbyDev; - int replayFile; - bool eof; int blockInput, blockOutput; - bool paused, fastForward, fastRewind; - int lastIndex, stillIndex, playIndex; + bool still, paused, fastForward, fastRewind; + int readIndex, writeIndex; + bool canDoTrickMode; bool canToggleAudioTrack; uchar audioTrack; + virtual void Empty(bool Block = false); + virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {} + virtual void Output(void); +public: + cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev); + virtual ~cPlayBuffer(); + virtual void Pause(void); + virtual void Play(void); + virtual void Forward(void); + virtual void Backward(void); + virtual int SkipFrames(int Frames) { return -1; } + virtual void SkipSeconds(int Seconds) {} + virtual void Goto(int Position, bool Still = false) {} + virtual void GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { Current = Total = -1; } + bool CanToggleAudioTrack(void) { return canToggleAudioTrack; }; + virtual void ToggleAudioTrack(void); + }; + +cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev) +:cRingBufferFrame(VIDEOBUFSIZE) +{ + dvbApi = DvbApi; + videoDev = VideoDev; + audioDev = AudioDev; + dolbyDev = NULL; + blockInput = blockOutput = false; + still = paused = fastForward = fastRewind = false; + readIndex = writeIndex = -1; + canDoTrickMode = false; + canToggleAudioTrack = false; + audioTrack = 0xC0; + if (cDvbApi::AudioCommand()) { + dolbyDev = popen(cDvbApi::AudioCommand(), "w"); + if (!dolbyDev) + esyslog(LOG_ERR, "ERROR: can't open pipe to audio command '%s'", cDvbApi::AudioCommand()); + } +} + +cPlayBuffer::~cPlayBuffer() +{ + if (dolbyDev) + pclose(dolbyDev); +} + +void cPlayBuffer::Output(void) +{ + dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); + + while (Busy()) { + if (blockOutput) { + if (blockOutput > 1) + blockOutput = 1; + continue; + } + const cFrame *frame = Get(); + if (frame) { + StripAudioPackets((uchar *)frame->Data(), frame->Count(), (fastForward || fastRewind) ? 0x00 : audioTrack);//XXX + for (int i = 0; i < ((paused && fastRewind) ? 24 : 1); i++) { // show every I_FRAME 24 times in slow rewind mode to achieve roughly the same speed as in slow forward mode + const uchar *p = frame->Data(); + int r = frame->Count(); + while (r > 0 && Busy() && !blockOutput) { + cFile::FileReadyForWriting(videoDev, 100); + int w = write(videoDev, p, r); + if (w > 0) { + p += w; + r -= w; + } + else if (w < 0 && errno != EAGAIN) { + LOG_ERROR; + Stop(); + return; + } + } + writeIndex = frame->Index(); + } + Drop(frame); + } + } + + dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); +} + +void cPlayBuffer::Empty(bool Block) +{ + if (!(blockInput || blockOutput)) { + blockInput = blockOutput = 2; + EnablePut(); + EnableGet(); + time_t t0 = time(NULL); + while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2) + usleep(1); + Lock(); + readIndex = writeIndex; + cRingBufferFrame::Clear(); + CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER)); + CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER)); + } + if (!Block) { + blockInput = blockOutput = 0; + Unlock(); + } +} + +void cPlayBuffer::Pause(void) +{ + paused = !paused; + bool empty = fastForward || fastRewind; + if (empty) + Empty(true); + fastForward = fastRewind = false; + CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE)); + CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); + still = false; + if (empty) + Empty(false); +} + +void cPlayBuffer::Play(void) +{ + if (fastForward || fastRewind || paused) { + bool empty = !paused || fastRewind; + if (empty) + Empty(true); + still = false; + CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY)); + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); + CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); + if (empty) + Empty(false); + fastForward = fastRewind = paused = false; + } +} + +void cPlayBuffer::Forward(void) +{ + if (canDoTrickMode || paused) { + bool empty = !paused || fastRewind; + if (empty) { + Empty(true); + if (fastForward) + readIndex -= 150; // this about compensates for the buffered data, so that we don't get too far ahead + } + still = false; + fastForward = !fastForward; + fastRewind = false; + if (paused) + CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2)); + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward)); + CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused)); + if (empty) + Empty(false); + } +} + +void cPlayBuffer::Backward(void) +{ + if (canDoTrickMode) { + Empty(true); + still = false; + fastRewind = !fastRewind; + fastForward = false; + if (paused) + CHECK(ioctl(videoDev, fastRewind ? VIDEO_CONTINUE : VIDEO_FREEZE)); + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind)); + CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused)); + Empty(false); + } +} + +void cPlayBuffer::ToggleAudioTrack(void) +{ + if (CanToggleAudioTrack()) { + audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0; + Empty(); + } +} + +// --- cReplayBuffer --------------------------------------------------------- + +class cReplayBuffer : public cPlayBuffer { +private: + cIndexFile *index; + cFileName fileName; + int replayFile; + bool eof; bool NextFile(uchar FileNumber = 0, int FileOffset = -1); - void Clear(bool Block = false); void Close(void); - void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00); + virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00); void DisplayFrame(uchar *b, int Length); int Resume(void); bool Save(void); protected: virtual void Input(void); - virtual void Output(void); public: cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName); virtual ~cReplayBuffer(); - void Pause(void); - void Play(void); - void Forward(void); - void Backward(void); - int SkipFrames(int Frames); - void SkipSeconds(int Seconds); - void Goto(int Position, bool Still = false); - void GetIndex(int &Current, int &Total, bool SnapToIFrame = false); - bool CanToggleAudioTrack(void) { return canToggleAudioTrack; } - void ToggleAudioTrack(void); + virtual int SkipFrames(int Frames); + virtual void SkipSeconds(int Seconds); + virtual void Goto(int Position, bool Still = false); + virtual void GetIndex(int &Current, int &Total, bool SnapToIFrame = false); }; cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName) -:cRingBuffer(VIDEOBUFSIZE) +:cPlayBuffer(DvbApi, VideoDev, AudioDev) ,fileName(FileName, false) { - dvbApi = DvbApi; index = NULL; - fileOffset = 0; - videoDev = VideoDev; - audioDev = AudioDev; - dolbyDev = NULL; - if (cDvbApi::AudioCommand()) { - dolbyDev = popen(cDvbApi::AudioCommand(), "w"); - if (!dolbyDev) - esyslog(LOG_ERR, "ERROR: can't open pipe to audio command '%s'", cDvbApi::AudioCommand()); - } replayFile = fileName.Open(); eof = false; - blockInput = blockOutput = false; - paused = fastForward = fastRewind = false; - lastIndex = stillIndex = playIndex = -1; - canToggleAudioTrack = false; - audioTrack = 0xC0; if (!fileName.Name()) return; // Create the index file: @@ -690,6 +861,7 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const delete index; index = NULL; } + canDoTrickMode = index != NULL; dvbApi->SetModeReplay(); Start(); } @@ -699,8 +871,6 @@ cReplayBuffer::~cReplayBuffer() Stop(); Save(); Close(); - if (dolbyDev) - pclose(dolbyDev); dvbApi->SetModeNormal(false); delete index; } @@ -709,22 +879,23 @@ void cReplayBuffer::Input(void) { dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid()); - int ResumeIndex = Resume(); - if (ResumeIndex >= 0) - isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, IndexToHMSF(ResumeIndex, true)); + readIndex = Resume(); + if (readIndex >= 0) + isyslog(LOG_INFO, "resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true)); - int lastIndex = -1; - int brakeCounter = 0; uchar b[MAXFRAMESIZE]; while (Busy() && (blockInput || NextFile())) { - if (!blockInput && stillIndex < 0) { + if (blockInput) { + if (blockInput > 1) + blockInput = 1; + continue; + } + if (!still) { int r = 0; if (fastForward && !paused || fastRewind) { - int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset); uchar FileNumber; int FileOffset, Length; - if (!paused || (brakeCounter++ % 24) == 0) // show every I_FRAME 24 times in rmSlowRewind mode to achieve roughly the same speed as in slow forward mode - Index = index->GetNextIFrame(Index, fastForward, &FileNumber, &FileOffset, &Length); + int Index = index->GetNextIFrame(readIndex, fastForward, &FileNumber, &FileOffset, &Length); if (Index >= 0) { if (!NextFile(FileNumber, FileOffset)) break; @@ -734,126 +905,85 @@ void cReplayBuffer::Input(void) Play(); continue; } - lastIndex = Index; - playIndex = -1; + readIndex = Index; r = ReadFrame(replayFile, b, Length, sizeof(b)); - StripAudioPackets(b, r); } else if (index) { - lastIndex = -1; - playIndex = (playIndex >= 0) ? playIndex + 1 : index->Get(fileName.Number(), fileOffset); uchar FileNumber; int FileOffset, Length; - if (!(index->Get(playIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) + readIndex++; + if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) break; r = ReadFrame(replayFile, b, Length, sizeof(b)); - StripAudioPackets(b, r, audioTrack); } else // allows replay even if the index file is missing r = read(replayFile, b, sizeof(b)); if (r > 0) { - uchar *p = b; - while (r > 0 && Busy() && !blockInput) { - int w = Put(p, r); - p += w; - r -= w; - usleep(1); // this keeps the CPU load low - } + cFrame *frame = new cFrame(b, r, readIndex); + while (Busy() && !blockInput && !Put(frame)) + ; } - else if (r ==0) + else if (r == 0) eof = true; else if (r < 0 && errno != EAGAIN) { LOG_ERROR; break; } } - else + else//XXX usleep(1); // this keeps the CPU load low - if (blockInput > 1) - blockInput = 1; } dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid()); } -void cReplayBuffer::Output(void) -{ - dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); - - uchar b[MINVIDEODATA]; - while (Busy()) { - int r = blockOutput ? 0 : Get(b, sizeof(b)); - if (r > 0) { - uchar *p = b; - while (r > 0 && Busy() && !blockOutput) { - cFile::FileReadyForWriting(videoDev, 100); - int w = write(videoDev, p, r); - if (w > 0) { - p += w; - r -= w; - fileOffset += w; - } - else if (w < 0 && errno != EAGAIN) { - LOG_ERROR; - Stop(); - return; - } - } - } - else - usleep(1); // this keeps the CPU load low - if (blockOutput > 1) - blockOutput = 1; - } - - dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); -} - void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except) { - for (int i = 0; i < Length - 6; i++) { - if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { - uchar c = b[i + 3]; - int l = b[i + 4] * 256 + b[i + 5] + 6; - switch (c) { - case 0xBD: // dolby - if (Except && dolbyDev) { - int written = b[i + 8] + 9; // skips the PES header - int n = l - written; - while (n > 0) { - int w = fwrite(&b[i + written], 1, n, dolbyDev); - if (w < 0) { - LOG_ERROR; - break; + if (canDoTrickMode) { + for (int i = 0; i < Length - 6; i++) { + if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { + uchar c = b[i + 3]; + int l = b[i + 4] * 256 + b[i + 5] + 6; + switch (c) { + case 0xBD: // dolby + if (Except && dolbyDev) { + int written = b[i + 8] + 9; // skips the PES header + int n = l - written; + while (n > 0) { + int w = fwrite(&b[i + written], 1, n, dolbyDev); + if (w < 0) { + LOG_ERROR; + break; + } + n -= w; + written += w; } - n -= w; - written += w; - } - } - // continue with deleting the data - otherwise it disturbs DVB replay - case 0xC0 ... 0xC1: // audio - if (c == 0xC1) - canToggleAudioTrack = true; - if (!Except || c != Except) { - int n = l; - for (int j = i; j < Length && n--; j++) - b[j] = 0x00; - } - break; - case 0xE0 ... 0xEF: // video - break; - default: - //esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c); - l = 0; - } - if (l) - i += l - 1; // the loop increments, too! + } + // continue with deleting the data - otherwise it disturbs DVB replay + case 0xC0 ... 0xC1: // audio + if (c == 0xC1) + canToggleAudioTrack = true; + if (!Except || c != Except) { + int n = l; + for (int j = i; j < Length && n--; j++) + b[j] = 0x00; + } + break; + case 0xE0 ... 0xEF: // video + break; + default: + //esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c); + l = 0; + } + if (l) + i += l - 1; // the loop increments, too! + } + /*XXX + else + esyslog(LOG_ERR, "ERROR: broken packet header"); + XXX*/ } - /*XXX - else - esyslog(LOG_ERR, "ERROR: broken packet header"); - XXX*/ - } + } } void cReplayBuffer::DisplayFrame(uchar *b, int Length) @@ -865,87 +995,11 @@ void cReplayBuffer::DisplayFrame(uchar *b, int Length) CHECK(ioctl(videoDev, VIDEO_STILLPICTURE, &sp)); } -void cReplayBuffer::Clear(bool Block) -{ - if (!(blockInput || blockOutput)) { - blockInput = blockOutput = 2; - time_t t0 = time(NULL); - while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2) - usleep(1); - Lock(); - cRingBuffer::Clear(); - playIndex = -1; - CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER)); - CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER)); - } - if (!Block) { - blockInput = blockOutput = 0; - Unlock(); - } -} - -void cReplayBuffer::Pause(void) -{ - paused = !paused; - CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE)); - if (fastForward || fastRewind) { - if (paused) - Clear(); - fastForward = fastRewind = false; - } - CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); - stillIndex = -1; -} - -void cReplayBuffer::Play(void) -{ - if (fastForward || fastRewind || paused) { - if (!paused) - Clear(); - stillIndex = -1; - CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY)); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); - CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); - fastForward = fastRewind = paused = false; - } -} - -void cReplayBuffer::Forward(void) -{ - if (index || paused) { - if (!paused) - Clear(true); - stillIndex = -1; - fastForward = !fastForward; - fastRewind = false; - if (paused) - CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2)); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward)); - CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused)); - if (!paused) - Clear(false); - } -} - -void cReplayBuffer::Backward(void) -{ - if (index) { - Clear(true); - stillIndex = -1; - fastRewind = !fastRewind; - fastForward = false; - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind)); - CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused)); - Clear(false); - } -} - void cReplayBuffer::Close(void) { if (replayFile >= 0) { fileName.Close(); replayFile = -1; - fileOffset = 0; } } @@ -966,7 +1020,7 @@ int cReplayBuffer::Resume(void) bool cReplayBuffer::Save(void) { if (index) { - int Index = index->Get(fileName.Number(), fileOffset); + int Index = writeIndex; if (Index >= 0) { Index -= RESUMEBACKUP; if (Index > 0) @@ -995,8 +1049,8 @@ int cReplayBuffer::SkipFrames(int Frames) void cReplayBuffer::SkipSeconds(int Seconds) { if (index && Seconds) { - Clear(true); - int Index = index->Get(fileName.Number(), fileOffset); + Empty(true); + int Index = writeIndex; if (Index >= 0) { if (Seconds < 0) { int sec = index->Last() / FRAMESPERSEC; @@ -1008,10 +1062,9 @@ void cReplayBuffer::SkipSeconds(int Seconds) Index = 1; // not '0', to allow GetNextIFrame() below to work! uchar FileNumber; int FileOffset; - if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0) - NextFile(FileNumber, FileOffset); + readIndex = writeIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) - 1; // Input() will first increment it! } - Clear(false); + Empty(false); Play(); } } @@ -1019,7 +1072,7 @@ void cReplayBuffer::SkipSeconds(int Seconds) void cReplayBuffer::Goto(int Index, bool Still) { if (index) { - Clear(true); + Empty(true); if (paused) CHECK(ioctl(videoDev, VIDEO_CONTINUE)); if (++Index <= 0) @@ -1028,28 +1081,27 @@ void cReplayBuffer::Goto(int Index, bool Still) int FileOffset, Length; Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { - stillIndex = Index; - playIndex = -1; + still = true; uchar b[MAXFRAMESIZE]; int r = ReadFrame(replayFile, b, Length, sizeof(b)); if (r > 0) DisplayFrame(b, r); - fileOffset += Length; paused = true; } else - stillIndex = playIndex = -1; - Clear(false); + still = false; + readIndex = writeIndex = Index; + Empty(false); } } void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) { if (index) { - if (stillIndex >= 0) - Current = stillIndex; + if (still) + Current = readIndex; else { - Current = index->Get(fileName.Number(), fileOffset); + Current = writeIndex; if (SnapToIFrame) { int i1 = index->GetNextIFrame(Current + 1, false); int i2 = index->GetNextIFrame(Current, true); @@ -1064,10 +1116,8 @@ void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) { - if (FileNumber > 0) { - fileOffset = FileOffset; + if (FileNumber > 0) replayFile = fileName.SetOffset(FileNumber, FileOffset); - } else if (replayFile >= 0 && eof) { Close(); replayFile = fileName.NextFile(); @@ -1076,17 +1126,892 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) return replayFile >= 0; } -void cReplayBuffer::ToggleAudioTrack(void) +#ifdef DVDSUPPORT +// --- cDVDplayBuffer -------------------------------------------------------- + +class cDVDplayBuffer : public cPlayBuffer { +private: + uchar audioTrack; + + cDVD *dvd;//XXX necessary??? + + int titleid; + int chapid; + int angle; + dvd_file_t *title; + ifo_handle_t *vmg_file; + ifo_handle_t *vts_file; + + int doplay; + int cyclestate; + int prevcycle; + int brakeCounter; + int skipCnt; + + tt_srpt_t *tt_srpt; + vts_ptt_srpt_t *vts_ptt_srpt; + pgc_t *cur_pgc; + dsi_t dsi_pack; + unsigned int next_vobu; + unsigned int prev_vobu; + unsigned int next_ilvu_start; + unsigned int cur_output_size; + unsigned int min_output_size; + unsigned int pktcnt; + int pgc_id; + int start_cell; + int next_cell; + int prev_cell; + int cur_cell; + unsigned int cur_pack; + int ttn; + int pgn; + + uchar *data; + + int logAudioTrack; + int maxAudioTrack; + + ac3_config_t ac3_config; + enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat; + uchar *ac3data; + int ac3inp; + int ac3outp; + int lpcm_count; + int is_nav_pack(unsigned char *buffer); + void Close(void); + virtual void Empty(bool Block = false); + int decode_packet(unsigned char *sector, int iframe); + int ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType); + bool PacketStart(uchar **Data, int len); + int GetPacketType(const uchar *Data); + int GetStuffingLen(const uchar *Data); + int GetPacketLength(const uchar *Data); + int GetPESHeaderLength(const uchar *Data); + int SendPCM(int size); + void playDecodedAC3(void); + void handleAC3(unsigned char *sector, int length); + void putFrame(unsigned char *sector, int length); + unsigned int getAudioStream(unsigned int StreamId); + void setChapid(void); + void NextState(int State) { prevcycle = cyclestate; cyclestate = State; } +protected: + virtual void Input(void); +public: + cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title); + virtual ~cDVDplayBuffer(); + virtual int SkipFrames(int Frames); + virtual void SkipSeconds(int Seconds); + virtual void Goto(int Position, bool Still = false); + virtual void GetIndex(int &Current, int &Total, bool SnapToIFrame = false); + virtual void ToggleAudioTrack(void); + }; + +#define cOPENDVD 0 +#define cOPENTITLE 1 +#define cOPENCHAPTER 2 +#define cOUTCELL 3 +#define cREADFRAME 4 +#define cOUTPACK 5 +#define cOUTFRAMES 6 + +#define aAC3 0x80 +#define aLPCM 0xA0 + +cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title) +:cPlayBuffer(DvbApi, VideoDev, AudioDev) +{ + dvd = DvD; + titleid = title; + chapid = 0; + angle = 0; + cyclestate = cOPENDVD; + prevcycle = 0; + brakeCounter = 0; + skipCnt = 0; + logAudioTrack = 0; + canToggleAudioTrack = true;//XXX determine from cDVD! + ac3_config.num_output_ch = 2; + // ac3_config.flags = /* mm_accel() | */ MM_ACCEL_MLIB; + ac3_config.flags = 0; + ac3_init(&ac3_config); + data = new uchar[1024 * DVD_VIDEO_LB_LEN]; + ac3data = new uchar[AC3_BUFFER_SIZE]; + ac3inp = ac3outp = 0; + ac3stat = AC3_START; + canDoTrickMode = true; + dvbApi->SetModeReplay(); + Start(); +} + +cDVDplayBuffer::~cDVDplayBuffer() { - if (CanToggleAudioTrack()) { - audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0; - Clear(); + Stop(); + Close(); + dvbApi->SetModeNormal(false); + delete ac3data; + delete data; +} + +unsigned int cDVDplayBuffer::getAudioStream(unsigned int StreamId) +{ + unsigned int trackID; + + if ((cyclestate < cOPENCHAPTER) || (StreamId > 7)) + return 0; + if (!(cur_pgc->audio_control[StreamId] & 0x8000)) + return 0; + int track = (cur_pgc->audio_control[StreamId] >> 8) & 0x07; + switch (vts_file->vtsi_mat->vts_audio_attr[track].audio_format) { + case 0: // ac3 + trackID = aAC3; + break; + case 2: // mpeg1 + case 3: // mpeg2ext + case 4: // lpcm + case 6: // dts + trackID = aLPCM; + break; + default: esyslog(LOG_ERR, "ERROR: unknown Audio stream info"); + return 0; + } + trackID |= track; + return trackID; +} + +void cDVDplayBuffer::ToggleAudioTrack(void) +{ + unsigned int newTrack; + + if (CanToggleAudioTrack() && maxAudioTrack != 0) { + logAudioTrack = (logAudioTrack + 1) % maxAudioTrack; + if ((newTrack = getAudioStream(logAudioTrack)) != 0) + audioTrack = newTrack; +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVB: Audio Stream ID changed to: %x", audioTrack); +#endif + ac3stat = AC3_START; + ac3outp = ac3inp; + } +} + +/** + * Returns true if the pack is a NAV pack. This check is clearly insufficient, + * and sometimes we incorrectly think that valid other packs are NAV packs. I + * need to make this stronger. + */ +inline int cDVDplayBuffer::is_nav_pack(unsigned char *buffer) +{ + return buffer[41] == 0xbf && buffer[1027] == 0xbf; +} + +void cDVDplayBuffer::Input(void) +{ + dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid()); + + doplay = true; + while (Busy() && doplay) { + if (blockInput) { + if (blockInput > 1) + blockInput = 1; + continue; + } + + //BEGIN: ripped from play_title + + /** + * Playback by cell in this pgc, starting at the cell for our chapter. + */ + + //dsyslog(LOG_INFO, "DVD: cyclestate: %d", cyclestate); + switch (cyclestate) { + + case cOPENDVD: // open the DVD and get all the basic information + { + if (!dvd->isValid()) { + doplay = false; + break; + } + + /** + * Load the video manager to find out the information about the titles on + * this disc. + */ + vmg_file = dvd->openVMG(); + if (!vmg_file) { + esyslog(LOG_ERR, "ERROR: can't open VMG info"); + doplay = false; + break; + } + tt_srpt = vmg_file->tt_srpt; + + NextState(cOPENTITLE); + break; + } + + case cOPENTITLE: // open the selected title + { + /** + * Make sure our title number is valid. + */ + isyslog(LOG_INFO, "DVD: there are %d titles on this DVD", tt_srpt->nr_of_srpts); + if (titleid < 0 || titleid >= tt_srpt->nr_of_srpts) { + esyslog(LOG_ERR, "ERROR: invalid title %d", titleid + 1); + doplay = false; + break; + } + + /** + * Load the VTS information for the title set our title is in. + */ + vts_file = dvd->openVTS(tt_srpt->title[titleid].title_set_nr); + if (!vts_file) { + esyslog(LOG_ERR, "ERROR: can't open the title %d info file", tt_srpt->title[titleid].title_set_nr); + doplay = false; + break; + } + + NextState(cOPENCHAPTER); + break; + } + + case cOPENCHAPTER: + { + /** + * Make sure the chapter number is valid for this title. + */ + isyslog(LOG_INFO, "DVD: there are %d chapters in this title", tt_srpt->title[titleid].nr_of_ptts); + if (chapid < 0 || chapid >= tt_srpt->title[titleid].nr_of_ptts) { + esyslog(LOG_ERR, "ERROR: invalid chapter %d", chapid + 1); + doplay = false; + break; + } + + /** + * Determine which program chain we want to watch. This is based on the + * chapter number. + */ + ttn = tt_srpt->title[titleid].vts_ttn; + vts_ptt_srpt = vts_file->vts_ptt_srpt; + pgc_id = vts_ptt_srpt->title[ttn - 1].ptt[chapid].pgcn; + pgn = vts_ptt_srpt->title[ttn - 1].ptt[chapid].pgn; + cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_id - 1].pgc; + start_cell = cur_pgc->program_map[pgn - 1] - 1; + + /** + * setup Audio information + **/ + for (maxAudioTrack = 0; maxAudioTrack < 8; maxAudioTrack++) { + if (!(cur_pgc->audio_control[maxAudioTrack] & 0x8000)) + break; + } + canToggleAudioTrack = (maxAudioTrack > 0); + // init the AudioInformation + audioTrack = getAudioStream(logAudioTrack); +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVD: max: %d, track: %x", maxAudioTrack, audioTrack); +#endif + + /** + * We've got enough info, time to open the title set data. + */ + title = dvd->openTitle(tt_srpt->title[titleid].title_set_nr, DVD_READ_TITLE_VOBS); + if (!title) { + esyslog(LOG_ERR, "ERROR: can't open title VOBS (VTS_%02d_1.VOB).", tt_srpt->title[titleid].title_set_nr); + doplay = false; + break; + } + + /** + * Playback by cell in this pgc, starting at the cell for our chapter. + */ + next_cell = start_cell; + prev_cell = start_cell; + cur_cell = start_cell; + + NextState(cOUTCELL); + break; + } + + case cOUTCELL: + { +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVD: new cell: %d", cur_cell); + dsyslog(LOG_INFO, "DVD: vob_id: %x, cell_nr: %x", cur_pgc->cell_position[cur_cell].vob_id_nr, cur_pgc->cell_position[cur_cell].cell_nr); +#endif + + if (cur_cell < 0) { + cur_cell = 0; + Backward(); + } + doplay = (cur_cell < cur_pgc->nr_of_cells); + if (!doplay) + break; + + /* Check if we're entering an angle block. */ + if (cur_pgc->cell_playback[cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK) { + cur_cell += angle; + for (int i = 0; ; ++i) { + if (cur_pgc->cell_playback[cur_cell + i].block_mode == BLOCK_MODE_LAST_CELL) { + next_cell = cur_cell + i + 1; + break; + } + } + } + else { + next_cell = cur_cell + 1; + prev_cell = cur_cell - 1; + } + + // init settings for next state + if (!fastRewind) + cur_pack = cur_pgc->cell_playback[cur_cell].first_sector; + else + cur_pack = cur_pgc->cell_playback[cur_cell].last_vobu_start_sector; + + NextState(cOUTPACK); + break; + } + + case cOUTPACK: + { +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVD: new pack: %d", cur_pack); +#endif + /** + * We loop until we're out of this cell. + */ + + if (!fastRewind) { + if (cur_pack >= cur_pgc->cell_playback[cur_cell].last_sector) { + cur_cell = next_cell; +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVD: end of pack"); +#endif + NextState(cOUTCELL); + break; + } + } + else { +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVD: prev: %d, curr: %x, next: %x, prev: %x", prevcycle, cur_pack, next_vobu, prev_vobu); +#endif + if ((cur_pack & 0x80000000) != 0) { + cur_cell = prev_cell; +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVD: start of pack"); +#endif + NextState(cOUTCELL); + break; + } + } + + /** + * Read NAV packet. + */ + int len = DVDReadBlocks(title, cur_pack, 1, data); + if (len == 0) { + esyslog(LOG_ERR, "ERROR: read failed for block %d", cur_pack); + doplay = false; + break; + } + if (!is_nav_pack(data)) { + esyslog(LOG_ERR, "ERROR: no nav_pack"); + return; + } + + /** + * Parse the contained dsi packet. + */ + navRead_DSI(&dsi_pack, &(data[DSI_START_BYTE]), sizeof(dsi_t)); + if (cur_pack != dsi_pack.dsi_gi.nv_pck_lbn) { + esyslog(LOG_ERR, "ERROR: cur_pack != dsi_pack.dsi_gi.nv_pck_lbn"); + return; + } + // navPrint_DSI(&dsi_pack); + + /** + * Determine where we go next. These values are the ones we mostly + * care about. + */ + next_ilvu_start = cur_pack + dsi_pack.sml_agli.data[angle].address; + cur_output_size = dsi_pack.dsi_gi.vobu_ea; + min_output_size = dsi_pack.dsi_gi.vobu_1stref_ea; + + /** + * If we're not at the end of this cell, we can determine the next + * VOBU to display using the VOBU_SRI information section of the + * DSI. Using this value correctly follows the current angle, + * avoiding the doubled scenes in The Matrix, and makes our life + * really happy. + * + * Otherwise, we set our next address past the end of this cell to + * force the code above to go to the next cell in the program. + */ + if (dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) + next_vobu = cur_pack + (dsi_pack.vobu_sri.next_vobu & 0x7fffffff); + else + next_vobu = cur_pack + cur_output_size + 1; + + if (dsi_pack.vobu_sri.prev_vobu != SRI_END_OF_CELL) + prev_vobu = cur_pack - (dsi_pack.vobu_sri.prev_vobu & 0x7fffffff); + else { +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVD: cur: %x, prev: %x", cur_pack, dsi_pack.vobu_sri.prev_vobu); +#endif + prev_vobu = 0x80000000; + } + +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVD: curr: %x, next: %x, prev: %x", cur_pack, next_vobu, prev_vobu); +#endif + if (cur_output_size >= 1024) { + esyslog(LOG_ERR, "ERROR: cur_output_size >= 1024"); + return; + } + cur_pack++; + + NextState(cREADFRAME); + break; + } + + case cREADFRAME: + { + int trickMode = (fastForward && !paused || fastRewind); + + /* FIXME: + * the entire trickMode code relies on the assumtion + * that there is only one I-FRAME per PACK + * + * I have no clue wether that is correct or not !!! + */ + if (trickMode && (skipCnt++ % 4 != 0)) { + cur_pack = (!fastRewind) ? next_vobu : prev_vobu; + NextState(cOUTPACK); + break; + } + + if (trickMode) + cur_output_size = min_output_size; + + /** + * Read in cursize packs. + */ +#ifdef DVDDEBUG + dsyslog(LOG_INFO, "DVD: read pack: %d", cur_pack); +#endif + int len = DVDReadBlocks(title, cur_pack, cur_output_size, data); + if (len != (int)cur_output_size * DVD_VIDEO_LB_LEN) { + esyslog(LOG_ERR, "ERROR: read failed for %d blocks at %d", cur_output_size, cur_pack); + doplay = false; + break; + } + pktcnt = 0; + NextState(cOUTFRAMES); + break; + } + + case cOUTFRAMES: + { + int trickMode = (fastForward && !paused || fastRewind); + + /** + * Output cursize packs. + */ + if (pktcnt >= cur_output_size) { + cur_pack = next_vobu; + NextState(cOUTPACK); + break; + } + //dsyslog(LOG_INFO, "DVD: pack: %d, frame: %d", cur_pack, pktcnt); + + if (decode_packet(&data[pktcnt * DVD_VIDEO_LB_LEN], trickMode) != 1) { //we've got a video packet + if (trickMode) { + //dsyslog(LOG_INFO, "DVD: did pack: %d", pktcnt); + cur_pack = (!fastRewind) ? next_vobu : prev_vobu; + NextState(cOUTPACK); + break; + } + } + + pktcnt++; + + if (pktcnt >= cur_output_size) { + cur_pack = next_vobu; + NextState(cOUTPACK); + break; + } + break; + } + + default: + { + esyslog(LOG_ERR, "ERROR: cyclestate %d not known", cyclestate); + return; + } + } + + // dsyslog(LOG_INF, "DVD: new cyclestate: %d, pktcnt: %d, cur: %d", cyclestate, pktcnt, cur_output_size); + } + + dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid()); +} + +#define NO_PICTURE 0 +#define SC_PICTURE 0x00 + +inline bool cDVDplayBuffer::PacketStart(uchar **Data, int len) +{ + while (len > 6 && !((*Data)[0] == 0x00 && (*Data)[1] == 0x00 && (*Data)[2] == 0x01)) + (*Data)++; + return ((*Data)[0] == 0x00 && (*Data)[1] == 0x00 && (*Data)[2] == 0x01); +} + +inline int cDVDplayBuffer::GetPacketType(const uchar *Data) +{ + return Data[3]; +} + +inline int cDVDplayBuffer::GetStuffingLen(const uchar *Data) +{ + return Data[13] & 0x07; +} + +inline int cDVDplayBuffer::GetPacketLength(const uchar *Data) +{ + return (Data[4] << 8) + Data[5] + 6; +} + +inline int cDVDplayBuffer::GetPESHeaderLength(const uchar *Data) +{ + return (Data[8]); +} + +int cDVDplayBuffer::ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType) +{ + // Scans the video packet starting at Offset and returns its length. + // If the return value is -1 the packet was not completely in the buffer. + + int Length = GetPacketLength(Data); + if (Length > 0 && Length <= Count) { + int i = 8; // the minimum length of the video packet header + i += Data[i] + 1; // possible additional header bytes + for (; i < Length; i++) { + if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { + switch (Data[i + 3]) { + case SC_PICTURE: *PictureType = (uchar)(Data[i + 5] >> 3) & 0x07; + return Length; + } + } + } + PictureType = NO_PICTURE; + return Length; + } + return -1; +} + +#define SYSTEM_HEADER 0xBB +#define PROG_STREAM_MAP 0xBC +#ifndef PRIVATE_STREAM1 +#define PRIVATE_STREAM1 0xBD +#endif +#define PADDING_STREAM 0xBE +#ifndef PRIVATE_STREAM2 +#define PRIVATE_STREAM2 0xBF +#endif +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +// data=PCM samples, 16 bit, LSB first, 48kHz, stereo +int cDVDplayBuffer::SendPCM(int size) +{ + +#define MAXSIZE 2032 + + uchar buffer[MAXSIZE + 16]; + int length = 0; + int p_size; + + if (ac3inp == ac3outp) + return 1; + + while (size > 0) { + if (size >= MAXSIZE) + p_size = MAXSIZE; + else + p_size = size; + length = 10; + + while (p_size) { + if (ac3outp != ac3inp) { // data in the buffer + buffer[(length + 6) ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder + // XXX there is no 'swab' here??? (kls) + p_size--; + length++; + ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE; + } + else + break; + } + + buffer[0] = 0x00; + buffer[1] = 0x00; + buffer[2] = 0x01; + buffer[3] = PRIVATE_STREAM1; + + buffer[4] = (length >> 8) & 0xff; + buffer[5] = length & 0xff; + + buffer[6] = 0x80; + buffer[7] = 0x00; + buffer[8] = 0x00; + + buffer[9] = aLPCM; // substream ID + buffer[10] = 0x00; // other stuff (see DVD specs), ignored by driver + buffer[11] = 0x00; + buffer[12] = 0x00; + buffer[13] = 0x00; + buffer[14] = 0x00; + buffer[15] = 0x00; + + length += 6; + + putFrame(buffer, length); + size -= MAXSIZE; + } + return 0; +} + +void cDVDplayBuffer::playDecodedAC3(void) +{ + int ac3_datasize = (AC3_BUFFER_SIZE + ac3inp - ac3outp) % AC3_BUFFER_SIZE; + + if (ac3_datasize) { + if (ac3_datasize > 1024 * 48) + SendPCM(3096); + else if (ac3_datasize > 1024 * 32) + SendPCM(1536); + else if (ac3_datasize > 1024 * 16 && !(lpcm_count % 2)) + SendPCM(1536); + else if (ac3_datasize && !(lpcm_count % 4)) + SendPCM(1536); + lpcm_count++; + } + else + lpcm_count=0; +} + +void cDVDplayBuffer::handleAC3(unsigned char *sector, int length) +{ + if (dolbyDev) { + while (length > 0) { + int w = fwrite(sector, 1, length , dolbyDev); + if (w < 0) { + LOG_ERROR; + break; + } + length -= w; + sector += w; + } + } + else { + if (ac3stat == AC3_PLAY) + ac3_decode_data(sector, sector+length, 0, &ac3inp, &ac3outp, (char *)ac3data); + else if (ac3stat == AC3_START) { + ac3_decode_data(sector, sector+length, 1, &ac3inp, &ac3outp, (char *)ac3data); + ac3stat = AC3_PLAY; + } } + //playDecodedAC3(); } +void cDVDplayBuffer::putFrame(unsigned char *sector, int length) +{ + cFrame *frame = new cFrame(sector, length); + while (Busy() && !blockInput && !Put(frame)) + ; +} + +int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode) +{ + uchar pt = 1; +#if 0 + uchar *osect = sector; +#endif + + //make sure we got a PS packet header + if (!PacketStart(§or, DVD_VIDEO_LB_LEN) && GetPacketType(sector) != 0xBA) { + esyslog(LOG_ERR, "ERROR: got unexpected packet: %x %x %x %x", sector[0], sector[1], sector[2], sector[3]); + return -1; + } + + int offset = 14 + GetStuffingLen(sector); + sector += offset; + int r = DVD_VIDEO_LB_LEN - offset; + int datalen = r; + + sector[6] &= 0x8f; + uchar *data = sector; + + switch (GetPacketType(sector)) { + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + { + ScanVideoPacket(sector, r, &pt); + if (trickMode && pt != 1) + return pt; + break; + } + case AUDIO_STREAM_S ... AUDIO_STREAM_E: { + // no sound in trick mode + if (trickMode) + return 1; + if (audioTrack != GetPacketType(sector)) + return 5; + break; + } + case PRIVATE_STREAM1: + { + datalen = GetPacketLength(sector); + //skip optional Header bytes + datalen -= GetPESHeaderLength(sector); + data += GetPESHeaderLength(sector); + //skip mandatory header bytes + data += 3; + //fallthrough is intended + } + case PRIVATE_STREAM2: + { + //FIXME: Stream1 + Stream2 is ok, but is Stream2 alone also? + + // no sound in trick mode + if (trickMode) + return 1; + + // skip PS header bytes + data += 6; + // data now points to the beginning of the payload + + if (audioTrack == *data) { + switch (audioTrack & 0xF8) { + case aAC3: + data += 4; + // correct a3 data lenght - FIXME: why 13 ??? + datalen -= 13; + handleAC3(data, datalen); + break; + case aLPCM: + // write(audio, sector+14 , sector[19]+(sector[18]<<8)+6); + putFrame(sector, GetPacketLength(sector)); + break; + default: + break; + } + } + return pt; + } + default: + case SYSTEM_HEADER: + case PROG_STREAM_MAP: + { + esyslog(LOG_ERR, "ERROR: don't know what to do - packetType: %x", GetPacketType(sector)); + // just skip them for now,l but try to debug it + dsyslog(LOG_INFO, "DVD: curr cell: %8x, Nr of cells: %8x", cur_cell, cur_pgc->nr_of_cells); + dsyslog(LOG_INFO, "DVD: curr pack: %8x, last sector: %8x", cur_pack, cur_pgc->cell_playback[cur_cell].last_sector); + dsyslog(LOG_INFO, "DVD: curr pkt: %8x, output size: %8x", pktcnt, cur_output_size); +#if 0 + // looks like my DVD is/was brocken ....... + for (int n = 0; n <= 255; n++) { + dsyslog(LOG_INFO, "%4x %2x %2x %2x %2x %2x %2x %2x %2x", n * 8, + osect[n * 8 + 0], osect[n * 8 + 1], osect[n * 8 + 2], osect[n * 8 + 3], + osect[n * 8 + 4], osect[n * 8 + 5], osect[n * 8 + 6], osect[n * 8 + 7]); + } + return 0; +#endif + return pt; + } + } + putFrame(sector, r); + if ((audioTrack & 0xF8) == aAC3) + playDecodedAC3(); + return pt; +} + +void cDVDplayBuffer::Empty(bool Block) +{ + if (!(blockInput || blockOutput)) { + cPlayBuffer::Empty(true); + ac3stat = AC3_START; + ac3outp = ac3inp; + } + if (!Block) + cPlayBuffer::Empty(false); +} + +void cDVDplayBuffer::Close(void) +{ + dvd->Close(); +} + +int cDVDplayBuffer::SkipFrames(int Frames) +{ + return -1; +} + +/* Figure out the correct pgN from the cell and update state. */ +void cDVDplayBuffer::setChapid(void) +{ + int new_pgN = 0; + + while (new_pgN < cur_pgc->nr_of_programs && cur_cell >= cur_pgc->program_map[new_pgN]) + new_pgN++; + + if (new_pgN == cur_pgc->nr_of_programs) { /* We are at the last program */ + if (cur_cell > cur_pgc->nr_of_cells) + chapid = 1; /* We are past the last cell */ + } + + chapid = new_pgN; +} + +void cDVDplayBuffer::SkipSeconds(int Seconds) +{ + if (Seconds) { + setChapid(); + int newchapid = Seconds > 0 ? chapid + 1 : chapid - 1; + + if (newchapid >= 0 && newchapid < tt_srpt->title[titleid].nr_of_ptts) { + Empty(true); + chapid = newchapid; + NextState(cOPENCHAPTER); + if (ac3stat != AC3_STOP) + ac3stat = AC3_START; + ac3outp = ac3inp; + Empty(false); + Play(); + } + } +} + +void cDVDplayBuffer::Goto(int Index, bool Still) +{ +} + +void cDVDplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) +{ + Current = Total = -1; +} +#endif //DVDSUPPORT + // --- cTransferBuffer ------------------------------------------------------- -class cTransferBuffer : public cRingBuffer { +class cTransferBuffer : public cRingBufferLinear { private: cDvbApi *dvbApi; int fromDevice, toDevice; @@ -1102,7 +2027,7 @@ class cTransferBuffer : public cRingBuffer { }; cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid) -:cRingBuffer(VIDEOBUFSIZE, true) +:cRingBufferLinear(VIDEOBUFSIZE, true) ,remux(VPid, APid, 0, 0, 0) { dvbApi = DvbApi; @@ -2212,7 +3137,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, esyslog(LOG_ERR, "ERROR %d in qpsk get event", res); } else - esyslog(LOG_ERR, "ERROR: timeout while tuning\n"); + esyslog(LOG_ERR, "ERROR: timeout while tuning"); } else if (fd_qamfe >= 0) { // DVB-C @@ -2239,7 +3164,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, esyslog(LOG_ERR, "ERROR %d in qam get event", res); } else - esyslog(LOG_ERR, "ERROR: timeout while tuning\n"); + esyslog(LOG_ERR, "ERROR: timeout while tuning"); } else { esyslog(LOG_ERR, "ERROR: attempt to set channel without DVB-S or DVB-C device"); @@ -2411,6 +3336,36 @@ bool cDvbApi::StartReplay(const char *FileName) return false; } +#ifdef DVDSUPPORT +bool cDvbApi::StartDVDplay(cDVD *dvd, int TitleID) +{ + if (Recording()) { + esyslog(LOG_ERR, "ERROR: StartDVDplay() called while recording - ignored!"); + return false; + } + StopTransfer(); + StopReplay(); + if (fd_video >= 0 && fd_audio >= 0) { + + // Check DeviceName: + + if (!dvd) { + esyslog(LOG_ERR, "ERROR: StartDVDplay: DVD device is (null)"); + return false; + } + + // Create replay buffer: + + replayBuffer = new cDVDplayBuffer(this, fd_video, fd_audio, dvd, TitleID); + if (replayBuffer) + return true; + else + esyslog(LOG_ERR, "ERROR: can't allocate replaying buffer"); + } + return false; +} +#endif //DVDSUPPORT + void cDvbApi::StopReplay(void) { if (replayBuffer) { diff --git a/dvbapi.h b/dvbapi.h index 2203d799e..41193ae74 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.42 2001/07/27 11:40:38 kls Exp $ + * $Id: dvbapi.h 1.44 2001/08/05 15:57:45 kls Exp $ */ #ifndef __DVBAPI_H @@ -26,7 +26,11 @@ #include <ost/audio.h> #include <ost/osd.h> #include <stdio.h> + #include "dvbosd.h" +#ifdef DVDSUPPORT +#include "dvd.h" +#endif //DVDSUPPORT #include "eit.h" #include "thread.h" @@ -44,7 +48,11 @@ int HMSFToIndex(const char *HMSF); class cChannel; class cRecordBuffer; +class cPlayBuffer; class cReplayBuffer; +#ifdef DVDSUPPORT +class cDVDplayBuffer; +#endif //DVDSUPPORT class cTransferBuffer; class cCuttingBuffer; @@ -60,6 +68,9 @@ class cVideoCutter { class cDvbApi { friend class cRecordBuffer; friend class cReplayBuffer; +#ifdef DVDSUPPORT + friend class cDVDplayBuffer; +#endif //DVDSUPPORT friend class cTransferBuffer; private: int videoDev; @@ -202,7 +213,7 @@ class cDvbApi { private: cRecordBuffer *recordBuffer; - cReplayBuffer *replayBuffer; + cPlayBuffer *replayBuffer; int ca; int priority; int Ca(void) { return ca; } @@ -238,6 +249,10 @@ class cDvbApi { // 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. +#ifdef DVDSUPPORT + bool StartDVDplay(cDVD *dvd, int TitleID);//XXX dvd parameter necessary??? + // Starts replaying the given TitleID on the DVD. +#endif //DVDSUPPORT void StopReplay(void); // Stops the current replay session (if any). void Pause(void); diff --git a/dvd.c b/dvd.c new file mode 100644 index 000000000..841e998b0 --- /dev/null +++ b/dvd.c @@ -0,0 +1,148 @@ +/* + * dvd.c: Functions for handling DVDs + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * Initially written by Andreas Schultz <aschultz@warp10.net> + * + * $Id: dvd.c 1.3 2001/08/06 16:07:44 kls Exp $ + */ + +#ifdef DVDSUPPORT + +//#define DVDSUPPORTDEBUG 1 +//#define DEBUG_BUFFER 1 + +#include <fcntl.h> +#include <linux/cdrom.h> +#include <string.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include "dvd.h" + +// --- cDVD ---------------------------------------------------------------------------- + +const char *cDVD::deviceName = "/dev/dvd"; +cDVD *cDVD::dvdInstance = NULL; + +cDVD *cDVD::getDVD(void) +{ + if (!dvdInstance) + new cDVD; + return dvdInstance; +} + +cDVD::cDVD(void) +{ + dvd = NULL; + title = NULL; + vmg_file = NULL; + vts_file = NULL; + dvdInstance = this; +} + +cDVD::~cDVD() +{ + Close(); +} + +int cDVD::Command(int Cmd) +{ + int result = -1; + int f; + if ((f = open(deviceName, O_RDONLY | O_NONBLOCK)) > 0) { + result = ioctl(f, Cmd, 0); + close(f); + } + return result; +} + +void cDVD::SetDeviceName(const char *DeviceName) +{ + deviceName = strdup(DeviceName); +} + +const char *cDVD::DeviceName(void) +{ + return deviceName; +} + +bool cDVD::DriveExists(void) +{ + return access(deviceName, F_OK) == 0; +} + +bool cDVD::DiscOk(void) +{ + return Command(CDROM_DRIVE_STATUS) == CDS_DISC_OK; +} + +void cDVD::Eject(void) +{ + if (dvdInstance) + dvdInstance->Close(); + Command(CDROMEJECT); +} + +void cDVD::Open(void) +{ + if (!dvd) + dvd = DVDOpen(deviceName); +} + +void cDVD::Close(void) +{ +#ifdef DVDSUPPORTDEBUG + dsyslog(LOG_INFO, "DVD: cDVD::Close(%p): vts: %p, vmg: %p, title: %p, dvd: %p", this, vts_file, vmg_file, title, dvd); +#endif + if (vts_file) + ifoClose(vts_file); + if (vmg_file) + ifoClose(vmg_file); + if (title) + DVDCloseFile(title); + if (dvd) + DVDClose(dvd); + vts_file = NULL; + vmg_file = NULL; + title = NULL; + dvd = NULL; +} + +ifo_handle_t *cDVD::openVMG(void) +{ + if (!isValid()) + return NULL; + if (!vmg_file) + vmg_file = ifoOpen(dvd, 0); + return vmg_file; +} + +ifo_handle_t *cDVD::openVTS(int TitleSet) +{ + if (!isValid()) + return NULL; + if (vts_file && (titleset != TitleSet)) { + ifoClose(vts_file); + vts_file = NULL; + } + if (!vts_file) { + titleset = TitleSet; + vts_file = ifoOpen(dvd, TitleSet); + } + return vts_file; +} + +dvd_file_t *cDVD::openTitle(int Title, dvd_read_domain_t domain) +{ + if (!isValid()) + return NULL; + if (title) + DVDCloseFile(title); + title = DVDOpenFile(dvd, Title, domain); + return title; +} + +#endif //DVDSUPPORT diff --git a/dvd.h b/dvd.h new file mode 100644 index 000000000..68fc1d38f --- /dev/null +++ b/dvd.h @@ -0,0 +1,53 @@ +/* + * dvd.h: Functions for handling DVDs + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * Initially written by Andreas Schultz <aschultz@warp10.net> + * + * $Id: dvd.h 1.3 2001/08/05 16:00:57 kls Exp $ + */ + +#ifndef __DVD_H +#define __DVD_H + +#ifdef DVDSUPPORT + +#include <dvdread/dvd_reader.h> +#include <dvdread/ifo_types.h> +#include <dvdread/ifo_read.h> +#include <dvdread/dvd_udf.h> +#include <dvdread/nav_read.h> +#include <dvdread/nav_print.h> + +class cDVD { +private: + static cDVD *dvdInstance; + static const char *deviceName; + dvd_reader_t *dvd; + dvd_file_t *title; + ifo_handle_t *vmg_file; + ifo_handle_t *vts_file; + int titleset; + static int Command(int Cmd); +public: + cDVD(void); + ~cDVD(); + static void SetDeviceName(const char *DeviceName); + static const char *DeviceName(void); + static bool DriveExists(void); + static bool DiscOk(void); + static void Eject(void); + void Open(void); + void Close(void); + bool isValid(void) { return (dvd != NULL); } + ifo_handle_t *openVMG(void); + ifo_handle_t *openVTS(int TitleSet); + dvd_file_t *openTitle(int Title, dvd_read_domain_t domain); + static cDVD *getDVD(void); + }; + +#endif //DVDSUPPORT + +#endif //__DVD_H diff --git a/i18n.c b/i18n.c index 571eea92d..ebc366d9d 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.26 2001/07/27 13:32:43 kls Exp $ + * $Id: i18n.c 1.27 2001/08/02 14:40:16 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -113,6 +113,15 @@ const tPhrase Phrases[] = { "Enregistrements", "Opptak", }, + { "DVD", + "DVD", + "DVD", + "DVD", + "DVD", + "DVD", + "DVD", + "DVD", + }, { "Setup", "Einstellungen", "Nastavitve", @@ -194,7 +203,7 @@ const tPhrase Phrases[] = { "Prochains programmes", "Hvilket program er neste?", }, - // Button texts (must not be more than 10 characters!): + // Button texts (should not be more than 10 characters!): { "Edit", "Editieren", "Uredi", @@ -321,6 +330,15 @@ const tPhrase Phrases[] = { "Langue", "Sprk", }, + { "Eject DVD", + "DVD auswerfen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // Confirmations: { "Delete channel?", "Kanal lschen?", diff --git a/menu.c b/menu.c index 30532a7d6..e25b23041 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.88 2001/07/28 16:17:28 kls Exp $ + * $Id: menu.c 1.95 2001/08/05 16:09:41 kls Exp $ */ #include "menu.h" @@ -590,7 +590,7 @@ cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel) index = Index; channel = Channel; if (channel->groupSep) - SetColor(clrWhite, clrCyan); + SetColor(clrCyan, clrBackground); Set(); } @@ -600,7 +600,7 @@ void cMenuChannelItem::Set(void) if (!channel->groupSep) asprintf(&buffer, "%d\t%s", channel->number, channel->name ); else - asprintf(&buffer, "\t%s", channel->name); + asprintf(&buffer, "---\t%s ----------------------------------------------------------------", channel->name); SetText(buffer, false); } @@ -1590,6 +1590,80 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) return state; } +#ifdef DVDSUPPORT +// --- cMenuDVDItem ---------------------------------------------------------- + +class cMenuDVDItem : public cOsdItem { + private: + int title; + int chapters; + virtual void Set(void); +public: + cMenuDVDItem(int Title, int Chapters); + int Title(void) { return title; } + }; + +cMenuDVDItem::cMenuDVDItem(int Title, int Chapters) +{ + title = Title; + chapters = Chapters; + Set(); +} + +void cMenuDVDItem::Set(void) +{ + char *buffer = NULL; + asprintf(&buffer, " %2d.\tTitle - \t%2d\tChapters", title + 1, chapters); + SetText(buffer, false); +} + +// --- cMenuDVD -------------------------------------------------------------- + +cMenuDVD::cMenuDVD(void) +:cOsdMenu(tr("DVD"), 5, 8, 3) +{ + if ((dvd = cDVD::getDVD())) { + dvd->Open(); + ifo_handle_t *vmg = dvd->openVMG(); + if (vmg) { + dsyslog(LOG_INFO, "DVD: vmg: %p", vmg);//XXX + tt_srpt_t *tt_srpt = vmg->tt_srpt; + dsyslog(LOG_INFO, "DVD: tt_srpt: %p", tt_srpt);//XXX + for (int i = 0; i < tt_srpt->nr_of_srpts; i++) + Add(new cMenuDVDItem(i, tt_srpt->title[i].nr_of_ptts)); + } + } + SetHelp(tr("Play"), NULL, NULL, NULL); + Display(); +} + +eOSState cMenuDVD::Play(void) +{ + cMenuDVDItem *ri = (cMenuDVDItem *)Get(Current()); + if (ri) { + cReplayControl::SetDVD(dvd, ri->Title()); + isyslog(LOG_INFO, "DVD: playing title %d", ri->Title()); + return osReplay; + } + return osContinue; +} + +eOSState cMenuDVD::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case kOk: + case kRed: return Play(); + case kMenu: return osEnd; + default: break; + } + } + return state; +} +#endif //DVDSUPPORT + // --- cMenuSetup ------------------------------------------------------------ class cMenuSetup : public cOsdMenu { @@ -1714,23 +1788,21 @@ eOSState cMenuCommands::ProcessKey(eKeys Key) #define STOP_RECORDING tr(" Stop recording ") -static const char *hk(int n, const char *s) -{ - static char buffer[32]; - snprintf(buffer, sizeof(buffer), " %d %s", n, s); - return buffer; -} - cMenuMain::cMenuMain(bool Replaying) :cOsdMenu(tr("Main")) { - Add(new cOsdItem(hk(1, tr("Schedule")), osSchedule)); - Add(new cOsdItem(hk(2, tr("Channels")), osChannels)); - Add(new cOsdItem(hk(3, tr("Timers")), osTimers)); - Add(new cOsdItem(hk(4, tr("Recordings")), osRecordings)); - Add(new cOsdItem(hk(5, tr("Setup")), osSetup)); + digit = 0; + Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); + Add(new cOsdItem(hk(tr("Channels")), osChannels)); + Add(new cOsdItem(hk(tr("Timers")), osTimers)); + Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); +#ifdef DVDSUPPORT + if (cDVD::DriveExists()) + Add(new cOsdItem(hk(tr("DVD")), osDVD)); +#endif //DVDSUPPORT + Add(new cOsdItem(hk(tr("Setup")), osSetup)); if (Commands.Count()) - Add(new cOsdItem(hk(6, tr("Commands")), osCommands)); + Add(new cOsdItem(hk(tr("Commands")), osCommands)); if (Replaying) Add(new cOsdItem(tr(" Stop replaying"), osStopReplay)); const char *s = NULL; @@ -1741,13 +1813,30 @@ cMenuMain::cMenuMain(bool Replaying) delete buffer; } if (cVideoCutter::Active()) - Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit)); - SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); + Add(new cOsdItem(hk(tr(" Cancel editing")), osCancelEdit)); + const char *DVDbutton = +#ifdef DVDSUPPORT + cDVD::DiscOk() ? tr("Eject DVD") : NULL; +#else + NULL; +#endif //DVDSUPPORT + SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, DVDbutton, cReplayControl::LastReplayed() ? tr("Resume") : NULL); Display(); lastActivity = time(NULL); SetHasHotkeys(); } +const char *cMenuMain::hk(const char *s) +{ + static char buffer[32]; + if (digit < 9) { + snprintf(buffer, sizeof(buffer), " %d %s", ++digit, s); + return buffer; + } + else + return s; +} + eOSState cMenuMain::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); @@ -1757,6 +1846,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key) case osChannels: return AddSubMenu(new cMenuChannels); case osTimers: return AddSubMenu(new cMenuTimers); case osRecordings: return AddSubMenu(new cMenuRecordings); +#ifdef DVDSUPPORT + case osDVD: return AddSubMenu(new cMenuDVD); +#endif //DVDSUPPORT case osSetup: return AddSubMenu(new cMenuSetup); case osCommands: return AddSubMenu(new cMenuCommands); case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { @@ -1773,22 +1865,31 @@ eOSState cMenuMain::ProcessKey(eKeys Key) } break; default: switch (Key) { - case kMenu: state = osEnd; break; - case kRed: if (!HasSubMenu()) - state = osRecord; - break; - case kGreen: if (!HasSubMenu()) { - if (cDvbApi::PrimaryDvbApi->CanToggleAudioTrack()) { - Interface->Clear(); - cDvbApi::PrimaryDvbApi->ToggleAudioTrack(); - state = osEnd; - } - } - break; - case kBlue: if (!HasSubMenu()) - state = osReplay; - break; - default: break; + case kMenu: state = osEnd; break; + case kRed: if (!HasSubMenu()) + state = osRecord; + break; + case kGreen: if (!HasSubMenu()) { + if (cDvbApi::PrimaryDvbApi->CanToggleAudioTrack()) { + Interface->Clear(); + cDvbApi::PrimaryDvbApi->ToggleAudioTrack(); + state = osEnd; + } + } + break; +#ifdef DVDSUPPORT + case kYellow: if (!HasSubMenu()) { + if (cDVD::DiscOk()) { + cDVD::Eject(); + state = osEnd; + } + } + break; +#endif //DVDSUPPORT + case kBlue: if (!HasSubMenu()) + state = osReplay; + break; + default: break; } } if (Key != kNone) @@ -2144,6 +2245,10 @@ void cProgressBar::Mark(int x, bool Start, bool Current) char *cReplayControl::fileName = NULL; char *cReplayControl::title = NULL; +#ifdef DVDSUPPORT +cDVD *cReplayControl::dvd = NULL;//XXX +int cReplayControl::titleid = 0;//XXX +#endif //DVDSUPPORT cReplayControl::cReplayControl(void) { @@ -2155,6 +2260,10 @@ cReplayControl::cReplayControl(void) marks.Load(fileName); dvbApi->StartReplay(fileName); } +#ifdef DVDSUPPORT + else if (dvd) + dvbApi->StartDVDplay(dvd, titleid);//XXX +#endif //DVDSUPPORT } cReplayControl::~cReplayControl() @@ -2171,6 +2280,15 @@ void cReplayControl::SetRecording(const char *FileName, const char *Title) title = Title ? strdup(Title) : NULL; } +#ifdef DVDSUPPORT +void cReplayControl::SetDVD(cDVD *DVD, int Title)//XXX +{ + SetRecording(NULL, NULL); + dvd = DVD; + titleid = Title; +} +#endif //DVDSUPPORT + const char *cReplayControl::LastReplayed(void) { return fileName; @@ -2216,10 +2334,10 @@ bool cReplayControl::ShowProgress(bool Initial) } if (Total != lastTotal) { Interface->Write(-7, 2, IndexToHMSF(Total)); - Interface->Flush(); - lastTotal = Total; + if (!Initial) + Interface->Flush(); } - if (Current != lastCurrent) { + if (Current != lastCurrent || Total != lastTotal) { #ifdef DEBUG_OSD int p = Width() * Current / Total; Interface->Fill(0, 1, p, 1, clrGreen); @@ -2227,12 +2345,14 @@ bool cReplayControl::ShowProgress(bool Initial) #else cProgressBar ProgressBar(Width() * dvbApi->CellWidth(), dvbApi->LineHeight(), Current, Total, marks); Interface->SetBitmap(0, dvbApi->LineHeight(), ProgressBar); - Interface->Flush(); + if (!Initial) + Interface->Flush(); #endif Interface->Write(0, 2, IndexToHMSF(Current, displayFrames)); Interface->Flush(); lastCurrent = Current; } + lastTotal = Total; return true; } return false; @@ -2338,11 +2458,10 @@ eOSState cReplayControl::ProcessKey(eKeys Key) // Positioning: case kUp: dvbApi->Play(); break; case kDown: dvbApi->Pause(); break; - case kLeft: dvbApi->Backward(); break; - case kRight: dvbApi->Forward(); break; case kLeft|k_Release: + case kLeft: dvbApi->Backward(); break; case kRight|k_Release: - dvbApi->Play(); break; + case kRight: dvbApi->Forward(); break; case kGreen|k_Repeat: case kGreen: dvbApi->SkipSeconds(-60); break; case kYellow|k_Repeat: diff --git a/menu.h b/menu.h index adc10b726..c47e5cbd8 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.20 2001/07/28 13:59:29 kls Exp $ + * $Id: menu.h 1.22 2001/08/05 16:04:58 kls Exp $ */ #ifndef _MENU_H @@ -13,17 +13,22 @@ #define _GNU_SOURCE #include "dvbapi.h" +#ifdef DVDSUPPORT +#include "dvd.h" +#endif //DVDSUPPORT #include "osd.h" #include "recording.h" class cMenuMain : public cOsdMenu { private: time_t lastActivity; + int digit; + const char *hk(const char *s); public: cMenuMain(bool Replaying); virtual eOSState ProcessKey(eKeys Key); }; - + class cDisplayChannel : public cOsdBase { private: bool withInfo, group; @@ -39,6 +44,18 @@ class cDisplayChannel : public cOsdBase { virtual eOSState ProcessKey(eKeys Key); }; +#ifdef DVDSUPPORT +class cMenuDVD : public cOsdMenu { +private: + cDVD *dvd;//XXX member really necessary??? + eOSState Play(void); + eOSState Eject(void); +public: + cMenuDVD(void); + virtual eOSState ProcessKey(eKeys Key); + }; +#endif //DVDSUPPORT + class cMenuRecordings : public cOsdMenu { private: cRecordings Recordings; @@ -88,6 +105,10 @@ class cReplayControl : public cOsdBase { void Show(int Seconds = 0); void Hide(void); static char *fileName; +#ifdef DVDSUPPORT + static cDVD *dvd;//XXX member really necessary??? + static int titleid;//XXX +#endif //DVDSUPPORT static char *title; bool ShowProgress(bool Initial); void MarkToggle(void); @@ -101,6 +122,9 @@ class cReplayControl : public cOsdBase { virtual eOSState ProcessKey(eKeys Key); bool Visible(void) { return visible; } static void SetRecording(const char *FileName, const char *Title); +#ifdef DVDSUPPORT + static void SetDVD(cDVD *DVD, int Title);//XXX +#endif //DVDSUPPORT static const char *LastReplayed(void); static void ClearLastReplayed(const char *FileName); }; diff --git a/osd.c b/osd.c index c29c98316..daedc1ee4 100644 --- a/osd.c +++ b/osd.c @@ -4,11 +4,10 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.16 2001/02/24 16:26:11 kls Exp $ + * $Id: osd.c 1.17 2001/08/02 14:18:17 kls Exp $ */ #include "osd.h" -#include <assert.h> #include <string.h> #include "i18n.h" diff --git a/osd.h b/osd.h index a1977be4f..ec1b11571 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.22 2001/07/27 11:33:30 kls Exp $ + * $Id: osd.h 1.23 2001/08/02 13:48:34 kls Exp $ */ #ifndef __OSD_H @@ -27,6 +27,7 @@ enum eOSState { osUnknown, osCommands, osRecord, osReplay, + osDVD, osStopRecord, osStopReplay, osCancelEdit, @@ -43,7 +44,7 @@ class cOsdItem : public cListObject { protected: bool fresh; bool userColor; - eDvbColor fgColor, bgColor; + eDvbColor fgColor, bgColor; public: cOsdItem(eOSState State = osUnknown); cOsdItem(const char *Text, eOSState State = osUnknown); @@ -55,7 +56,7 @@ class cOsdItem : public cListObject { virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); virtual void Set(void) {} virtual eOSState ProcessKey(eKeys Key); - }; +}; class cOsdBase { protected: @@ -67,7 +68,7 @@ class cOsdBase { int Height(void) { return Interface->Height(); } bool NeedsFastResponse(void) { return needsFastResponse; } virtual eOSState ProcessKey(eKeys Key) = 0; - }; +}; class cOsdMenu : public cOsdBase, public cList<cOsdItem> { private: diff --git a/ringbuffer.c b/ringbuffer.c index 8511a1c23..7e09b2af5 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -7,7 +7,7 @@ * Parts of this file were inspired by the 'ringbuffy.c' from the * LinuxDVB driver (see linuxtv.org). * - * $Id: ringbuffer.c 1.2 2001/05/20 11:58:08 kls Exp $ + * $Id: ringbuffer.c 1.4 2001/08/05 12:17:45 kls Exp $ */ #include "ringbuffer.h" @@ -41,61 +41,128 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics) { size = Size; statistics = Statistics; - buffer = NULL; inputThread = NULL; outputThread = NULL; + busy = false; maxFill = 0; +} + +cRingBuffer::~cRingBuffer() +{ + delete inputThread; + delete outputThread; + if (statistics) + dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1)); +} + +void cRingBuffer::WaitForPut(void) +{ + putMutex.Lock(); + readyForPut.Wait(putMutex); + putMutex.Unlock(); +} + +void cRingBuffer::WaitForGet(void) +{ + getMutex.Lock(); + readyForGet.Wait(getMutex); + getMutex.Unlock(); +} + +void cRingBuffer::EnablePut(void) +{ + readyForPut.Broadcast(); +} + +void cRingBuffer::EnableGet(void) +{ + readyForGet.Broadcast(); +} + +bool cRingBuffer::Start(void) +{ + if (!busy) { + busy = true; + outputThread = new cRingBufferOutputThread(this); + if (!outputThread->Start()) + DELETENULL(outputThread); + inputThread = new cRingBufferInputThread(this); + if (!inputThread->Start()) { + DELETENULL(inputThread); + DELETENULL(outputThread); + } + busy = outputThread && inputThread; + } + return busy; +} + +bool cRingBuffer::Active(void) +{ + return outputThread && outputThread->Active() && inputThread && inputThread->Active(); +} + +void cRingBuffer::Stop(void) +{ busy = false; - if (size > 1) { // 'size - 1' must not be 0! - buffer = new uchar[size]; + for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) { + if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active()))) + break; + } + DELETENULL(inputThread); + DELETENULL(outputThread); +} + +// --- cRingBufferLinear ---------------------------------------------------- + +cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics) +:cRingBuffer(Size, Statistics) +{ + buffer = NULL; + if (Size > 1) { // 'Size - 1' must not be 0! + buffer = new uchar[Size]; if (!buffer) - esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size); + esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", Size); Clear(); } else - esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", size); + esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", Size); } -cRingBuffer::~cRingBuffer() +cRingBufferLinear::~cRingBufferLinear() { - delete inputThread; - delete outputThread; delete buffer; - if (statistics) - dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1)); } -int cRingBuffer::Available(void) +int cRingBufferLinear::Available(void) { - mutex.Lock(); + Lock(); int diff = head - tail; - int cont = (diff >= 0) ? diff : size + diff; - mutex.Unlock(); - return cont; + Unlock(); + return (diff >= 0) ? diff : Size() + diff; } -void cRingBuffer::Clear(void) +void cRingBufferLinear::Clear(void) { - mutex.Lock(); + Lock(); head = tail = 0; - mutex.Unlock(); + Unlock(); } -int cRingBuffer::Put(const uchar *Data, int Count) +int cRingBufferLinear::Put(const uchar *Data, int Count) { if (Count > 0) { - mutex.Lock(); - int rest = size - head; + Lock(); + int rest = Size() - head; int diff = tail - head; - mutex.Unlock(); - int free = (diff > 0) ? diff - 1 : size + diff - 1; + Unlock(); + int free = (diff > 0) ? diff - 1 : Size() + diff - 1; if (statistics) { - int fill = size - free - 1 + Count; - if (fill >= size) - fill = size - 1; + int fill = Size() - free - 1 + Count; + if (fill >= Size()) + fill = Size() - 1; if (fill > maxFill) { maxFill = fill; - int percent = maxFill * 100 / (size - 1); + int percent = maxFill * 100 / (Size() - 1); if (percent > 75) dsyslog(LOG_INFO, "buffer usage: %d%%", percent); } @@ -120,14 +187,14 @@ int cRingBuffer::Put(const uchar *Data, int Count) return Count; } -int cRingBuffer::Get(uchar *Data, int Count) +int cRingBufferLinear::Get(uchar *Data, int Count) { if (Count > 0) { - mutex.Lock(); - int rest = size - tail; + Lock(); + int rest = Size() - tail; int diff = head - tail; - mutex.Unlock(); - int cont = (diff >= 0) ? diff : size + diff; + Unlock(); + int cont = (diff >= 0) ? diff : Size() + diff; if (rest <= 0) return 0; if (cont < Count) @@ -146,36 +213,112 @@ int cRingBuffer::Get(uchar *Data, int Count) return Count; } -bool cRingBuffer::Start(void) +// --- cFrame ---------------------------------------------------------------- + +cFrame::cFrame(const uchar *Data, int Count, int Index) { - if (!busy) { - busy = true; - outputThread = new cRingBufferOutputThread(this); - if (!outputThread->Start()) - DELETENULL(outputThread); - inputThread = new cRingBufferInputThread(this); - if (!inputThread->Start()) { - DELETENULL(inputThread); - DELETENULL(outputThread); + count = Count; + index = Index; + data = new uchar[count]; + if (data) + memcpy(data, Data, count); + else + esyslog(LOG_ERR, "ERROR: can't allocate frame buffer (count=%d)", count); + next = NULL; +} + +cFrame::~cFrame() +{ + delete data; +} + +// --- cRingBufferFrame ------------------------------------------------------ + +cRingBufferFrame::cRingBufferFrame(int Size, bool Statistics = false) +:cRingBuffer(Size, Statistics) +{ + head = NULL; + currentFill = 0; +} + +cRingBufferFrame::~cRingBufferFrame() +{ + Clear(); +} + +void cRingBufferFrame::Clear(void) +{ + Lock(); + const cFrame *p; + while ((p = Get(false)) != NULL) + Drop(p); + Unlock(); + EnablePut(); + EnableGet(); +} + +bool cRingBufferFrame::Put(cFrame *Frame) +{ + if (Frame->Count() <= Free()) { + Lock(); + if (head) { + Frame->next = head->next; + head->next = Frame; + head = Frame; } - busy = outputThread && inputThread; + else { + head = Frame->next = Frame; + } + currentFill += Frame->Count(); + Unlock(); + EnableGet(); + return true; } - return busy; + WaitForPut(); + return false; } -bool cRingBuffer::Active(void) +const cFrame *cRingBufferFrame::Get(bool Wait) { - return outputThread && outputThread->Active() && inputThread && inputThread->Active(); + Lock(); + cFrame *p = head ? head->next : NULL; + Unlock(); + if (!p && Wait) + WaitForGet(); + return p; } -void cRingBuffer::Stop(void) +void cRingBufferFrame::Delete(const cFrame *Frame) { - busy = false; - for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) { - if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active()))) - break; - } - DELETENULL(inputThread); - DELETENULL(outputThread); + currentFill -= Frame->Count(); + delete Frame; +} + +void cRingBufferFrame::Drop(const cFrame *Frame) +{ + Lock(); + if (head) { + if (Frame == head->next) { + if (head->next != head) { + head->next = Frame->next; + Delete(Frame); + } + else { + Delete(head); + head = NULL; + } + } + else + esyslog(LOG_ERR, "ERROR: attempt to drop wrong frame from ring buffer!"); + } + Unlock(); + EnablePut(); } +int cRingBufferFrame::Available(void) +{ + Lock(); + int av = currentFill; + Unlock(); + return av; +} diff --git a/ringbuffer.h b/ringbuffer.h index 49be769c2..f61d9e04c 100644 --- a/ringbuffer.h +++ b/ringbuffer.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ringbuffer.h 1.2 2001/05/20 11:56:44 kls Exp $ + * $Id: ringbuffer.h 1.4 2001/08/05 11:12:06 kls Exp $ */ #ifndef __RINGBUFFER_H @@ -24,24 +24,24 @@ class cRingBuffer { cRingBufferInputThread *inputThread; cRingBufferOutputThread *outputThread; cMutex mutex; - int size, head, tail; - uchar *buffer; - int maxFill; + cCondVar readyForPut, readyForGet; + cMutex putMutex, getMutex; + int size; bool busy; - bool statistics; protected: + int maxFill;//XXX + bool statistics;//XXX + void WaitForPut(void); + void WaitForGet(void); + void EnablePut(void); + void EnableGet(void); + virtual void Clear(void) = 0; + virtual int Available(void) = 0; + int Free(void) { return size - Available() - 1; } void Lock(void) { mutex.Lock(); } void Unlock(void) { mutex.Unlock(); } - int Available(void); + int Size(void) { return size; } bool Busy(void) { return busy; } - void Clear(void); - // Immediately clears the ring buffer. - int Put(const uchar *Data, int Count); - // Puts at most Count bytes of Data into the ring buffer. - // Returns the number of bytes actually stored. - int Get(uchar *Data, int Count); - // Gets at most Count bytes of Data from the ring buffer. - // Returns the number of bytes actually retrieved. virtual void Input(void) = 0; // Runs as a separate thread and shall continuously read data from // a source and call Put() to store the data in the ring buffer. @@ -56,4 +56,60 @@ class cRingBuffer { void Stop(void); }; +class cRingBufferLinear : public cRingBuffer { +private: + int head, tail; + uchar *buffer; +protected: + virtual int Available(void); + virtual void Clear(void); + // Immediately clears the ring buffer. + int Put(const uchar *Data, int Count); + // Puts at most Count bytes of Data into the ring buffer. + // Returns the number of bytes actually stored. + int Get(uchar *Data, int Count); + // Gets at most Count bytes of Data from the ring buffer. + // Returns the number of bytes actually retrieved. +public: + cRingBufferLinear(int Size, bool Statistics = false); + virtual ~cRingBufferLinear(); + }; + +class cFrame { + friend class cRingBufferFrame; +private: + cFrame *next; + uchar *data; + int count; + int index; +public: + cFrame(const uchar *Data, int Count, int Index = -1); + ~cFrame(); + const uchar *Data(void) const { return data; } + int Count(void) const { return count; } + int Index(void) const { return index; } + }; + +class cRingBufferFrame : public cRingBuffer { +private: + cFrame *head; + int currentFill; + void Delete(const cFrame *Frame); +protected: + virtual int Available(void); + virtual void Clear(void); + // Immediately clears the ring buffer. + bool Put(cFrame *Frame); + // Puts the Frame into the ring buffer. + // Returns true if this was possible. + const cFrame *Get(bool Wait = true); + // Gets the next frame from the ring buffer. + // The actual data still remains in the buffer until Drop() is called. + void Drop(const cFrame *Frame); + // Drops the Frame that has just been fetched with Get(). +public: + cRingBufferFrame(int Size, bool Statistics = false); + virtual ~cRingBufferFrame(); + }; + #endif // __RINGBUFFER_H diff --git a/thread.c b/thread.c index e253ea042..bfc8aab12 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.9 2001/06/27 11:34:41 kls Exp $ + * $Id: thread.c 1.11 2001/08/05 10:36:52 kls Exp $ */ #include "thread.h" @@ -14,6 +14,42 @@ #include <unistd.h> #include "tools.h" +// --- cCondVar -------------------------------------------------------------- + +cCondVar::cCondVar(void) +{ + pthread_cond_init(&cond, 0); +} + +cCondVar::~cCondVar() +{ + pthread_cond_destroy(&cond); +} + +bool cCondVar::Wait(cMutex &Mutex) +{ + return pthread_cond_wait(&cond, &Mutex.mutex); +} + +/* +bool cCondVar::TimedWait(cMutex &Mutex, unsigned long tmout) +{ + return pthread_cond_timedwait(&cond, &Mutex.mutex, tmout); +} +*/ + +void cCondVar::Broadcast(void) +{ + pthread_cond_broadcast(&cond); +} + +/* +void cCondVar::Signal(void) +{ + pthread_cond_signal(&cond); +} +*/ + // --- cMutex ---------------------------------------------------------------- cMutex::cMutex(void) @@ -85,6 +121,7 @@ bool cThread::Start(void) running = true; parentPid = getpid(); pthread_create(&thread, NULL, (void *(*) (void *))&StartThread, (void *)this); + pthread_setschedparam(thread, SCHED_RR, 0); usleep(10000); // otherwise calling Active() immediately after Start() causes a "pure virtual method called" error } return true; //XXX return value of pthread_create()??? diff --git a/thread.h b/thread.h index bf9804d33..e8e796eb1 100644 --- a/thread.h +++ b/thread.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.6 2001/06/27 11:22:04 kls Exp $ + * $Id: thread.h 1.8 2001/08/05 10:36:47 kls Exp $ */ #ifndef __THREAD_H @@ -13,7 +13,22 @@ #include <pthread.h> #include <sys/types.h> +class cMutex; + +class cCondVar { +private: + pthread_cond_t cond; +public: + cCondVar(void); + ~cCondVar(); + bool Wait(cMutex &Mutex); + //bool TimedWait(cMutex &Mutex, unsigned long tmout); + void Broadcast(void); + //void Signal(void); + }; + class cMutex { + friend class cCondVar; private: pthread_mutex_t mutex; pid_t lockingPid; diff --git a/tools.c b/tools.c index de1a52c39..c75efbb99 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.34 2001/05/20 08:30:54 kls Exp $ + * $Id: tools.c 1.35 2001/08/05 12:38:06 kls Exp $ */ #define _GNU_SOURCE @@ -406,8 +406,8 @@ bool cFile::FileReady(int FileDes, int TimeoutMs) FD_SET(FileDes, &set); if (TimeoutMs < 100) TimeoutMs = 100; - timeout.tv_sec = 0; - timeout.tv_usec = TimeoutMs * 1000; + timeout.tv_sec = TimeoutMs / 1000; + timeout.tv_usec = (TimeoutMs % 1000) * 1000; return select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(FileDes, &set); } diff --git a/vdr.c b/vdr.c index 12b1a5381..15a69de06 100644 --- a/vdr.c +++ b/vdr.c @@ -2,27 +2,27 @@ * vdr.c: Video Disk Recorder main program * * Copyright (C) 2000 Klaus Schmidinger - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * + * * The author can be reached at kls@cadsoft.de * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.58 2001/06/23 12:29:41 kls Exp $ + * $Id: vdr.c 1.61 2001/08/05 16:15:51 kls Exp $ */ #include <getopt.h> @@ -31,6 +31,9 @@ #include <unistd.h> #include "config.h" #include "dvbapi.h" +#ifdef DVDSUPPORT +#include "dvd.h" +#endif //DVDSUPPORT #include "i18n.h" #include "interface.h" #include "menu.h" @@ -85,14 +88,15 @@ int main(int argc, char *argv[]) { "log", required_argument, NULL, 'l' }, { "port", required_argument, NULL, 'p' }, { "video", required_argument, NULL, 'v' }, + { "dvd", required_argument, NULL, 'V' }, { "watchdog", required_argument, NULL, 'w' }, { "terminal", required_argument, NULL, 't' }, { 0 } }; - + int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "a:c:dD:hl:p:v:w:t:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:hl:p:v:V:w:t:", long_options, &option_index)) != -1) { switch (c) { case 'a': cDvbApi::SetAudioCommand(optarg); break; @@ -124,6 +128,7 @@ int main(int argc, char *argv[]) " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" " 0 turns off SVDRP\n" " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" + " -V DEV, --dvd=DEV use DEV as the DVD device (default: %s)\n" " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n" " seconds (default: %d); '0' disables the watchdog\n" " -t TTY, --terminal=TTY controlling tty\n" @@ -131,6 +136,11 @@ int main(int argc, char *argv[]) "Report bugs to <vdr-bugs@cadsoft.de>\n", DEFAULTSVDRPPORT, VideoDirectory, +#ifdef DVDSUPPORT + cDVD::DeviceName(), +#else + "no DVD support", +#endif //DVDSUPPORT DEFAULTWATCHDOG ); return 0; @@ -158,6 +168,18 @@ int main(int argc, char *argv[]) while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') optarg[strlen(optarg) - 1] = 0; break; + case 'V': +#ifdef DVDSUPPORT + cDVD::SetDeviceName(optarg); + if (!cDVD::DriveExists()) { + fprintf(stderr, "vdr: DVD drive not found: %s\n", optarg); + return 2; + } +#else + fprintf(stderr, "vdr: DVD support has not been compiled in!"); + return 2; +#endif //DVDSUPPORT + break; case 'w': if (isnumber(optarg)) { int t = atoi(optarg); if (t >= 0) { @@ -173,7 +195,7 @@ int main(int argc, char *argv[]) } // Log file: - + if (SysLogLevel > 0) openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); @@ -324,6 +346,12 @@ int main(int argc, char *argv[]) DELETENULL(ReplayControl); ReplayControl = new cReplayControl; break; +#ifdef DVDSUPPORT + case osDVD: DELETENULL(Menu); + DELETENULL(ReplayControl); + Menu = new cMenuDVD; + break; +#endif //DVDSUPPORT case osStopReplay: DELETENULL(*Interact); DELETENULL(ReplayControl); @@ -358,7 +386,7 @@ int main(int argc, char *argv[]) case kRight: if (!Interface->Recording()) { int SaveGroup = CurrentGroup; if (NORMALKEY(key) == kRight) - CurrentGroup = Channels.GetNextGroup(CurrentGroup) ; + CurrentGroup = Channels.GetNextGroup(CurrentGroup) ; else CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup); if (CurrentGroup < 0) From efea0f64d08052b0189d962101e1a3634d4adfc8 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 12 Aug 2001 18:00:00 +0200 Subject: [PATCH 021/307] Version 0.91 - Fixed displaying colored button texts that are too long. - Suppressing replay progress display when replaying a DVD. - Updated channels.conf.cable (thanks to Uwe Scheffler). - Updated French OSD texts (thanks to Jean-Claude Repetto). - Improved AC3 decoding when replaying DVDs (thanks to Matjaz Thaler). - Fixed handling DVB card indexes when using only one card in a multi-card system. - Changed the 'Eject DVD' button text to a simple 'Eject' (the German text was too long...). - Made the font file generation more stable (thanks to Artur Skawina). - Changed the default value for the "DiSEqC" setup parameter to "off". - The new command line option '-E' can be used to define where the EPG data shall be written to. This is especially useful if VDR runs in a system that turns off the video disk when it is not used, and therefore needs to write the EPG file to a ramdisk (or turn off writing it alltogether). See 'vdr --help' for details. - Making sure the disk is up and running before starting recording (this is important for systems that turn off the video disk when it is not used). - Added the "Jump" function in replay mode (thanks to Stefan Huelswitt). See the description of the "Red" key in MANUAL under "Replay Control" for details. - Fixed displaying editing marks when toggling a mark in "pause" mode. - If there is no free DVB device to record, the log message will now be given only once. - Made I/O more robust by handling EINTR (thanks to Werner Fink). --- CONTRIBUTORS | 13 + HISTORY | 32 +- INSTALL | 11 + MANUAL | 6 +- Makefile | 18 +- ac3dec/Makefile | 14 +- ac3dec/ac3.h | 56 ++-- ac3dec/ac3_internal.h | 251 ++++++++------- ac3dec/bit_allocate.c | 278 ++++++++-------- ac3dec/bit_allocate.h | 2 +- ac3dec/bitstream.c | 53 +-- ac3dec/bitstream.h | 54 +--- ac3dec/bswap.h | 80 +++++ ac3dec/cmplx.h | 29 ++ ac3dec/coeff.c | 446 ++++++++++++++----------- ac3dec/cpu_accel.c | 129 ++++++++ ac3dec/crc.c | 26 +- ac3dec/crc.h | 4 +- ac3dec/debug.c | 16 +- ac3dec/debug.h | 10 +- ac3dec/decode.c | 251 ++++++++------- ac3dec/dither.c | 13 +- ac3dec/dither.h | 12 +- ac3dec/downmix.c | 441 +++---------------------- ac3dec/downmix.h | 8 +- ac3dec/downmix_c.c | 161 +++++++++ ac3dec/downmix_c.h | 32 ++ ac3dec/downmix_i386.S | 92 ++++++ ac3dec/downmix_i386.h | 27 ++ ac3dec/downmix_kni.S | 396 +++++++++++++++++++++++ ac3dec/downmix_kni.h | 32 ++ ac3dec/exponent.c | 61 ++-- ac3dec/imdct.c | 734 +++++++++++++++++++++++------------------- ac3dec/imdct.h | 2 +- ac3dec/imdct512_kni.S | 548 +++++++++++++++++++++++++++++++ ac3dec/imdct_c.c | 218 +++++++++++++ ac3dec/imdct_c.h | 36 +++ ac3dec/imdct_kni.c | 103 ++++++ ac3dec/imdct_kni.h | 36 +++ ac3dec/mm_accel.h | 36 +++ ac3dec/parse.c | 252 ++++----------- ac3dec/parse.h | 4 +- ac3dec/rematrix.c | 54 ++-- ac3dec/sanity_check.c | 85 +++-- ac3dec/sanity_check.h | 4 +- ac3dec/srfft.c | 305 ++++++++++++++++++ ac3dec/srfft.h | 39 +++ ac3dec/srfft_kni.S | 289 +++++++++++++++++ ac3dec/srfft_kni.h | 30 ++ ac3dec/srfft_kni_c.c | 93 ++++++ ac3dec/srfftp.h | 305 ++++++++++++++++++ ac3dec/stats.c | 26 +- channels.conf.cable | 264 ++++++++------- config.c | 13 +- config.h | 7 +- dvbapi.c | 64 ++-- dvbapi.h | 9 +- eit.c | 28 +- eit.h | 5 +- i18n.c | 61 ++-- interface.c | 4 +- menu.c | 130 +++++++- menu.h | 7 +- recording.c | 8 +- remote.c | 6 +- svdrp.c | 6 +- tools.c | 61 +++- tools.h | 5 +- vdr.c | 23 +- 69 files changed, 4985 insertions(+), 1969 deletions(-) create mode 100644 ac3dec/bswap.h create mode 100644 ac3dec/cmplx.h create mode 100644 ac3dec/cpu_accel.c create mode 100644 ac3dec/downmix_c.c create mode 100644 ac3dec/downmix_c.h create mode 100644 ac3dec/downmix_i386.S create mode 100644 ac3dec/downmix_i386.h create mode 100644 ac3dec/downmix_kni.S create mode 100644 ac3dec/downmix_kni.h create mode 100644 ac3dec/imdct512_kni.S create mode 100644 ac3dec/imdct_c.c create mode 100644 ac3dec/imdct_c.h create mode 100644 ac3dec/imdct_kni.c create mode 100644 ac3dec/imdct_kni.h create mode 100644 ac3dec/mm_accel.h create mode 100644 ac3dec/srfft.c create mode 100644 ac3dec/srfft.h create mode 100644 ac3dec/srfft_kni.S create mode 100644 ac3dec/srfft_kni.h create mode 100644 ac3dec/srfft_kni_c.c create mode 100644 ac3dec/srfftp.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 46a84101f..241c86140 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -99,6 +99,7 @@ Stefan Huelswitt <huels@iname.com> for fixing the repeat function with LIRC for making the position of the channel display configurable for making the width and height of the OSD configurable + for implementing the "Jump" function in replay mode Ulrich Rder <dynamite@efr-net.de> for pointing out that there are channels that have a symbol rate higher than @@ -116,3 +117,15 @@ Aaron Holtzman Wolfgang Henselmann-Weiss <Wolfgang_Henselmann@betaresearch.de> for fixing calculating the timeout value in cFile::FileReady() + +Uwe Scheffler <UweScheffler@t-online.de> + for his help in keeping 'channels.conf.cable' up to date + +Matjaz Thaler <matjaz.thaler@guest.arnes.si> + for improving AC3 decoding when replaying DVDs + +Artur Skawina <skawina@geocities.com> + for improving the font file generation in the Makefile + +Werner Fink <werner@suse.de> + for making I/O more robust by handling EINTR diff --git a/HISTORY b/HISTORY index 041e4423f..715b66823 100644 --- a/HISTORY +++ b/HISTORY @@ -83,7 +83,7 @@ Video Disk Recorder Revision History with file names that contain blanks, all blanks in recording file names are converted to underscores. - The polarization can now be given in uppercase or lowercase characters in - channels.conf. + 'channels.conf'. - Fixed buffer initialization to work with DVB driver version 0.6. - Implemented the "Simple Video Disk Recorder Protocol" (SVDRP) to control the VDR over a network connection. @@ -147,7 +147,7 @@ Video Disk Recorder Revision History the OSD to no longer be displayed (thanks to Niels de Carpentier). - Added the '-m486' option to the compiler call. - If a channel name contains a colon (':') it is now replaced with a '|' in - channels.conf. + 'channels.conf'. - Not everybody appears to like the "page scrolling" mechanism introduced by Heino Goldenstein in version 0.61, so this is now configurable via the "Setup" menu. @@ -621,3 +621,31 @@ Video Disk Recorder Revision History - Ringbuffer uses semaphores to signal empty/full conditions. - Fixed calculating the timeout value in cFile::FileReady() (thanks to Wolfgang Henselmann-Weiss). + +2001-08-12: Version 0.91 + +- Fixed displaying colored button texts that are too long. +- Suppressing replay progress display when replaying a DVD. +- Updated channels.conf.cable (thanks to Uwe Scheffler). +- Updated French OSD texts (thanks to Jean-Claude Repetto). +- Improved AC3 decoding when replaying DVDs (thanks to Matjaz Thaler). +- Fixed handling DVB card indexes when using only one card in a multi-card + system. +- Changed the 'Eject DVD' button text to a simple 'Eject' (the German text + was too long...). +- Made the font file generation more stable (thanks to Artur Skawina). +- Changed the default value for the "DiSEqC" setup parameter to "off". +- The new command line option '-E' can be used to define where the EPG data + shall be written to. This is especially useful if VDR runs in a system + that turns off the video disk when it is not used, and therefore needs + to write the EPG file to a ramdisk (or turn off writing it alltogether). + See 'vdr --help' for details. +- Making sure the disk is up and running before starting recording (this + is important for systems that turn off the video disk when it is not used). +- Added the "Jump" function in replay mode (thanks to Stefan Huelswitt). + See the description of the "Red" key in MANUAL under "Replay Control" for + details. +- Fixed displaying editing marks when toggling a mark in "pause" mode. +- If there is no free DVB device to record, the log message will now be given + only once. +- Made I/O more robust by handling EINTR (thanks to Werner Fink). diff --git a/INSTALL b/INSTALL index 86b4a1eee..946e06de9 100644 --- a/INSTALL +++ b/INSTALL @@ -23,6 +23,9 @@ to activate DVD support. VDR then also needs the package 'libdvdread' in order to replay DVDs. This package is expected to be located in the directory ../DVD (seen from the VDR directory). Adjust the definition of DVDDIR in the Makefile if necessary. +You can find 'libdvdread' at + + http://www.dtek.chalmers.se/groups/dvd/downloads.html VDR requires the card driver version 0.9.0 or higher to work properly. You need to load the dvb.o module *without* option @@ -190,6 +193,14 @@ As a starting point you can copy the 'channels.conf' file that comes with the VDR archive into your video directory (or into your config directory, respectively, in case you have redirected it with the -c option). +Setting up DiSEqC: +------------------ + +If you are using a DVB-S card with a satellite equipment that needs to be +accessed using DiSEqC, you have to go to the "Setup" menu and set the "DiSEqC" +parameter to "on". Also check the "DiSEqC" parameters for the various channels +and set them to the necessary values. + Running VDR with DVB-C (cable): ------------------------------- diff --git a/MANUAL b/MANUAL index 59ff57c93..17f024836 100644 --- a/MANUAL +++ b/MANUAL @@ -17,7 +17,7 @@ Video Disk Recorder User's Manual Ok Ch display Select Switch Edit Accept Play Progress disp. Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on Back - Menu off Main menu Main menu Discard Main menu Recordings menu - Red - Record Edit Edit - Play - + Red - Record Edit Edit - Play Jump Green - Language New New - Rewind Skip -60s Yellow - Eject DVD Delete Delete - Delete Skip +60s Blue - Resume Mark Mark - Summary Stop @@ -172,6 +172,10 @@ Video Disk Recorder User's Manual backward at a slower speed; press again to return to pause mode. Pressing and holding down the button performs the function until the button is released again. + - Red Jump to a specific location. Enter the time you want to jump to + and then press "Left" or "Right" to jump relative to the current + position, "Up" to jump to an absolute position, and "Down" to + jump and pause at an absolute position. - Green Yellow Skips about 60 seconds back or forward. Pressing and holding down the button performs the function until diff --git a/Makefile b/Makefile index 891871741..7fcc62a8c 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,9 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.24 2001/08/06 16:13:42 kls Exp $ +# $Id: Makefile 1.25 2001/08/10 16:46:45 kls Exp $ + +.DELETE_ON_ERROR: DVBDIR = ../DVB DVDDIR = ../DVD @@ -82,16 +84,14 @@ vdr: $(OBJS) $(AC3LIB) # The font files: fontfix.c: - genfontfile "cFont::tPixelData FontFix" $(FIXFONT) > $@ + ./genfontfile "cFont::tPixelData FontFix" "$(FIXFONT)" > $@ fontosd.c: - genfontfile "cFont::tPixelData FontOsd" $(OSDFONT) > $@ + ./genfontfile "cFont::tPixelData FontOsd" "$(OSDFONT)" > $@ # The font file generator: -genfontfile.o: genfontfile.c - gcc -O2 -c $< -genfontfile: genfontfile.o - gcc -o $@ -L/usr/X11R6/lib $< -lX11 +genfontfile: genfontfile.c + gcc -o $@ -O2 -L/usr/X11R6/lib $< -lX11 # The ac3dec library: @@ -103,5 +103,7 @@ $(AC3LIB): clean: make -C $(AC3DIR) clean -rm -f $(OBJS) vdr genfontfile genfontfile.o core *~ -CLEAN: clean +fontclean: -rm -f fontfix.c fontosd.c +CLEAN: clean fontclean + diff --git a/ac3dec/Makefile b/ac3dec/Makefile index a0547e915..7ab5ad028 100644 --- a/ac3dec/Makefile +++ b/ac3dec/Makefile @@ -1,10 +1,16 @@ # # Makefile for 'ac3dec' # -# $Id: Makefile 1.1 2001/08/03 12:58:06 kls Exp $ +# $Id: Makefile 1.2 2001/08/10 12:44:07 kls Exp $ + +#OBJS = coeff.o decode.o exponent.o rematrix.o bit_allocate.o crc.o dither.o\ +# imdct.o sanity_check.o bitstream.o debug.o downmix.o parse.o stats.o\ +# downmix_c.o imdct.o + +OBJS = bit_allocate.o bitstream.o coeff.o cpu_accel.o crc.o debug.o decode.o\ + dither.o downmix.o downmix_c.o exponent.o imdct.o imdct_c.o imdct_kni.o\ + parse.o rematrix.o sanity_check.o srfft.o srfft_kni_c.o stats.o -OBJS = coeff.o decode.o exponent.o rematrix.o bit_allocate.o crc.o dither.o\ - imdct.o sanity_check.o bitstream.o debug.o downmix.o parse.o stats.o DEFINES += -DDOLBY_SURROUND @@ -16,7 +22,7 @@ libac3.a: $(OBJS) # Implicit rules: %.o: %.c - gcc -g -O2 -Wall -m486 -c $(DEFINES) $< + gcc -g -O2 -Wall -m486 -I./ -c $(DEFINES) $< clean: rm -f *~ libac3.a $(OBJS) diff --git a/ac3dec/ac3.h b/ac3dec/ac3.h index 4919fc504..d325f3bb3 100644 --- a/ac3dec/ac3.h +++ b/ac3dec/ac3.h @@ -22,39 +22,37 @@ * */ -#ifndef AARONS_TYPES -#define AARONS_TYPES -typedef unsigned long long uint_64; -typedef unsigned int uint_32; -typedef unsigned short uint_16; -typedef unsigned char uint_8; - -typedef signed long long sint_64; -typedef signed int sint_32; -typedef signed short sint_16; -typedef signed char sint_8; +#define AC3_BUFFER_SIZE (6*1024*16) + +#ifndef __AC3_H__ +#define __AC3_H__ + +#ifdef __OMS__ +#include <oms/plugin/output_audio.h> +#else +//#include "audio_out.h" #endif -#define AC3_DOLBY_SURR_ENABLE 0x1 -#define AC3_3DNOW_ENABLE 0x2 -#define AC3_MMX_ENABLE 0x4 -#define AC3_ALTIVEC_ENABLE 0x8 - -typedef struct ac3_config_s -{ - //Bit flags that enable various things - uint_32 flags; - //Callback that points the decoder to new stream data - void (*fill_buffer_callback)(uint_8 **, uint_8 **); - //Number of discrete channels in final output (for downmixing) - uint_16 num_output_ch; - //Which channel of a dual mono stream to select - uint_16 dual_mono_ch_sel; -} ac3_config_t; +#include <inttypes.h> -void ac3_init(ac3_config_t *); -uint_32 ac3_decode_data(uint_8 *data_start,uint_8 *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data); +#define AC3_DOLBY_SURR_ENABLE (1<<0) +#define AC3_ALTIVEC_ENABLE (1<<1) +typedef struct ac3_config_s { + // Bit flags that enable various things + uint32_t flags; + // Number of discrete channels in final output (for downmixing) + uint16_t num_output_ch; + // Which channel of a dual mono stream to select + uint16_t dual_mono_ch_sel; +} ac3_config_t; +void ac3dec_init (void); +#ifdef __OMS__ +size_t ac3dec_decode_data (plugin_output_audio_t *output, uint8_t *data_start, uint8_t *data_end); +#else +size_t ac3dec_decode_data (uint8_t *data_start ,uint8_t *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data); +#endif +#endif diff --git a/ac3dec/ac3_internal.h b/ac3dec/ac3_internal.h index 235189ede..259396fdc 100644 --- a/ac3dec/ac3_internal.h +++ b/ac3dec/ac3_internal.h @@ -25,6 +25,8 @@ #define inline #endif +#include <setjmp.h> + /* Exponent strategy constants */ #define EXP_REUSE (0) #define EXP_D15 (1) @@ -43,7 +45,8 @@ typedef float stream_samples_t[6][256]; /* global config structure */ extern ac3_config_t ac3_config; /* global error flag */ -extern uint_32 error_flag; +extern jmp_buf error_jmp_mark; +#define HANDLE_ERROR() longjmp (error_jmp_mark, -1) /* Everything you wanted to know about band structure */ /* @@ -72,273 +75,279 @@ extern uint_32 error_flag; typedef struct syncinfo_s { - uint_32 magic; + uint32_t magic; /* Sync word == 0x0B77 */ - uint_16 syncword; + uint16_t syncword; /* crc for the first 5/8 of the sync block */ - /* uint_16 crc1; */ + /* uint16_t crc1; */ /* Stream Sampling Rate (kHz) 0 = 48, 1 = 44.1, 2 = 32, 3 = reserved */ - uint_16 fscod; + uint16_t fscod; /* Frame size code */ - uint_16 frmsizecod; + uint16_t frmsizecod; /* Information not in the AC-3 bitstream, but derived */ /* Frame size in 16 bit words */ - uint_16 frame_size; + uint16_t frame_size; /* Bit rate in kilobits */ - uint_16 bit_rate; + uint16_t bit_rate; /* sampling rate in hertz */ - uint_32 sampling_rate; + uint32_t sampling_rate; } syncinfo_t; typedef struct bsi_s { - uint_32 magic; + uint32_t magic; /* Bit stream identification == 0x8 */ - uint_16 bsid; + uint16_t bsid; /* Bit stream mode */ - uint_16 bsmod; + uint16_t bsmod; /* Audio coding mode */ - uint_16 acmod; + uint16_t acmod; /* If we're using the centre channel then */ /* centre mix level */ - uint_16 cmixlev; + uint16_t cmixlev; /* If we're using the surround channel then */ /* surround mix level */ - uint_16 surmixlev; + uint16_t surmixlev; /* If we're in 2/0 mode then */ /* Dolby surround mix level - NOT USED - */ - uint_16 dsurmod; + uint16_t dsurmod; /* Low frequency effects on */ - uint_16 lfeon; + uint16_t lfeon; /* Dialogue Normalization level */ - uint_16 dialnorm; + uint16_t dialnorm; /* Compression exists */ - uint_16 compre; + uint16_t compre; /* Compression level */ - uint_16 compr; + uint16_t compr; /* Language code exists */ - uint_16 langcode; + uint16_t langcode; /* Language code */ - uint_16 langcod; + uint16_t langcod; /* Audio production info exists*/ - uint_16 audprodie; - uint_16 mixlevel; - uint_16 roomtyp; + uint16_t audprodie; + uint16_t mixlevel; + uint16_t roomtyp; /* If we're in dual mono mode (acmod == 0) then extra stuff */ - uint_16 dialnorm2; - uint_16 compr2e; - uint_16 compr2; - uint_16 langcod2e; - uint_16 langcod2; - uint_16 audprodi2e; - uint_16 mixlevel2; - uint_16 roomtyp2; + uint16_t dialnorm2; + uint16_t compr2e; + uint16_t compr2; + uint16_t langcod2e; + uint16_t langcod2; + uint16_t audprodi2e; + uint16_t mixlevel2; + uint16_t roomtyp2; /* Copyright bit */ - uint_16 copyrightb; + uint16_t copyrightb; /* Original bit */ - uint_16 origbs; + uint16_t origbs; /* Timecode 1 exists */ - uint_16 timecod1e; + uint16_t timecod1e; /* Timecode 1 */ - uint_16 timecod1; + uint16_t timecod1; /* Timecode 2 exists */ - uint_16 timecod2e; + uint16_t timecod2e; /* Timecode 2 */ - uint_16 timecod2; + uint16_t timecod2; /* Additional bit stream info exists */ - uint_16 addbsie; + uint16_t addbsie; /* Additional bit stream length - 1 (in bytes) */ - uint_16 addbsil; + uint16_t addbsil; /* Additional bit stream information (max 64 bytes) */ - uint_8 addbsi[64]; + uint8_t addbsi[64]; /* Information not in the AC-3 bitstream, but derived */ /* Number of channels (excluding LFE) * Derived from acmod */ - uint_16 nfchans; + uint16_t nfchans; } bsi_t; /* more pain */ typedef struct audblk_s { - uint_32 magic1; + uint32_t magic1; /* block switch bit indexed by channel num */ - uint_16 blksw[5]; + uint16_t blksw[5]; /* dither enable bit indexed by channel num */ - uint_16 dithflag[5]; + uint16_t dithflag[5]; /* dynamic range gain exists */ - uint_16 dynrnge; + uint16_t dynrnge; /* dynamic range gain */ - uint_16 dynrng; + uint16_t dynrng; /* if acmod==0 then */ /* dynamic range 2 gain exists */ - uint_16 dynrng2e; + uint16_t dynrng2e; /* dynamic range 2 gain */ - uint_16 dynrng2; + uint16_t dynrng2; /* coupling strategy exists */ - uint_16 cplstre; + uint16_t cplstre; /* coupling in use */ - uint_16 cplinu; + uint16_t cplinu; /* channel coupled */ - uint_16 chincpl[5]; + uint16_t chincpl[5]; /* if acmod==2 then */ /* Phase flags in use */ - uint_16 phsflginu; + uint16_t phsflginu; /* coupling begin frequency code */ - uint_16 cplbegf; + uint16_t cplbegf; /* coupling end frequency code */ - uint_16 cplendf; + uint16_t cplendf; /* coupling band structure bits */ - uint_16 cplbndstrc[18]; + uint16_t cplbndstrc[18]; /* Do coupling co-ords exist for this channel? */ - uint_16 cplcoe[5]; + uint16_t cplcoe[5]; /* Master coupling co-ordinate */ - uint_16 mstrcplco[5]; + uint16_t mstrcplco[5]; /* Per coupling band coupling co-ordinates */ - uint_16 cplcoexp[5][18]; - uint_16 cplcomant[5][18]; + uint16_t cplcoexp[5][18]; + uint16_t cplcomant[5][18]; /* Phase flags for dual mono */ - uint_16 phsflg[18]; + uint16_t phsflg[18]; /* Is there a rematrixing strategy */ - uint_16 rematstr; + uint16_t rematstr; /* Rematrixing bits */ - uint_16 rematflg[4]; + uint16_t rematflg[4]; /* Coupling exponent strategy */ - uint_16 cplexpstr; + uint16_t cplexpstr; /* Exponent strategy for full bandwidth channels */ - uint_16 chexpstr[5]; + uint16_t chexpstr[5]; /* Exponent strategy for lfe channel */ - uint_16 lfeexpstr; + uint16_t lfeexpstr; /* Channel bandwidth for independent channels */ - uint_16 chbwcod[5]; + uint16_t chbwcod[5]; /* The absolute coupling exponent */ - uint_16 cplabsexp; + uint16_t cplabsexp; /* Coupling channel exponents (D15 mode gives 18 * 12 /3 encoded exponents */ - uint_16 cplexps[18 * 12 / 3]; + uint16_t cplexps[18 * 12 / 3]; /* Sanity checking constant */ - uint_32 magic2; + uint32_t magic2; /* fbw channel exponents */ - uint_16 exps[5][252 / 3]; + uint16_t exps[5][252 / 3]; /* channel gain range */ - uint_16 gainrng[5]; + uint16_t gainrng[5]; /* low frequency exponents */ - uint_16 lfeexps[3]; + uint16_t lfeexps[3]; /* Bit allocation info */ - uint_16 baie; + uint16_t baie; /* Slow decay code */ - uint_16 sdcycod; + uint16_t sdcycod; /* Fast decay code */ - uint_16 fdcycod; + uint16_t fdcycod; /* Slow gain code */ - uint_16 sgaincod; + uint16_t sgaincod; /* dB per bit code */ - uint_16 dbpbcod; + uint16_t dbpbcod; /* masking floor code */ - uint_16 floorcod; + uint16_t floorcod; /* SNR offset info */ - uint_16 snroffste; + uint16_t snroffste; /* coarse SNR offset */ - uint_16 csnroffst; + uint16_t csnroffst; /* coupling fine SNR offset */ - uint_16 cplfsnroffst; + uint16_t cplfsnroffst; /* coupling fast gain code */ - uint_16 cplfgaincod; + uint16_t cplfgaincod; /* fbw fine SNR offset */ - uint_16 fsnroffst[5]; + uint16_t fsnroffst[5]; /* fbw fast gain code */ - uint_16 fgaincod[5]; + uint16_t fgaincod[5]; /* lfe fine SNR offset */ - uint_16 lfefsnroffst; + uint16_t lfefsnroffst; /* lfe fast gain code */ - uint_16 lfefgaincod; + uint16_t lfefgaincod; /* Coupling leak info */ - uint_16 cplleake; + uint16_t cplleake; /* coupling fast leak initialization */ - uint_16 cplfleak; + uint16_t cplfleak; /* coupling slow leak initialization */ - uint_16 cplsleak; + uint16_t cplsleak; /* delta bit allocation info */ - uint_16 deltbaie; + uint16_t deltbaie; /* coupling delta bit allocation exists */ - uint_16 cpldeltbae; + uint16_t cpldeltbae; /* fbw delta bit allocation exists */ - uint_16 deltbae[5]; + uint16_t deltbae[5]; /* number of cpl delta bit segments */ - uint_16 cpldeltnseg; + uint16_t cpldeltnseg; /* coupling delta bit allocation offset */ - uint_16 cpldeltoffst[8]; + uint16_t cpldeltoffst[8]; /* coupling delta bit allocation length */ - uint_16 cpldeltlen[8]; + uint16_t cpldeltlen[8]; /* coupling delta bit allocation length */ - uint_16 cpldeltba[8]; + uint16_t cpldeltba[8]; /* number of delta bit segments */ - uint_16 deltnseg[5]; + uint16_t deltnseg[5]; /* fbw delta bit allocation offset */ - uint_16 deltoffst[5][8]; + uint16_t deltoffst[5][8]; /* fbw delta bit allocation length */ - uint_16 deltlen[5][8]; + uint16_t deltlen[5][8]; /* fbw delta bit allocation length */ - uint_16 deltba[5][8]; + uint16_t deltba[5][8]; /* skip length exists */ - uint_16 skiple; + uint16_t skiple; /* skip length */ - uint_16 skipl; + uint16_t skipl; //Removed Feb 2000 -ah + //added Jul 2000 ++dent /* channel mantissas */ - //uint_16 chmant[5][256]; + uint16_t chmant[5][256]; /* coupling mantissas */ - uint_16 cplmant[256]; +// uint16_t cplmant[256]; + + //Added Jun 2000 -MaXX + /* coupling floats */ + float cpl_flt[ 256 ]; //Removed Feb 2000 -ah + //added Jul 2000 ++dent /* coupling mantissas */ - //uint_16 lfemant[7]; + uint16_t lfemant[7]; /* -- Information not in the bitstream, but derived thereof -- */ /* Number of coupling sub-bands */ - uint_16 ncplsubnd; + uint16_t ncplsubnd; /* Number of combined coupling sub-bands * Derived from ncplsubnd and cplbndstrc */ - uint_16 ncplbnd; + uint16_t ncplbnd; /* Number of exponent groups by channel * Derived from strmant, endmant */ - uint_16 nchgrps[5]; + uint16_t nchgrps[5]; /* Number of coupling exponent groups * Derived from cplbegf, cplendf, cplexpstr */ - uint_16 ncplgrps; + uint16_t ncplgrps; /* End mantissa numbers of fbw channels */ - uint_16 endmant[5]; + uint16_t endmant[5]; /* Start and end mantissa numbers for the coupling channel */ - uint_16 cplstrtmant; - uint_16 cplendmant; + uint16_t cplstrtmant; + uint16_t cplendmant; /* Decoded exponent info */ - uint_16 fbw_exp[5][256]; - uint_16 cpl_exp[256]; - uint_16 lfe_exp[7]; + uint16_t fbw_exp[5][256]; + uint16_t cpl_exp[256]; + uint16_t lfe_exp[7]; /* Bit allocation pointer results */ - uint_16 fbw_bap[5][256]; - uint_16 cpl_bap[256]; - uint_16 lfe_bap[7]; + uint16_t fbw_bap[5][256]; + uint16_t cpl_bap[256]; + uint16_t lfe_bap[7]; - uint_32 magic3; + uint32_t magic3; } audblk_t; diff --git a/ac3dec/bit_allocate.c b/ac3dec/bit_allocate.c index 053e09cd0..008743402 100644 --- a/ac3dec/bit_allocate.c +++ b/ac3dec/bit_allocate.c @@ -28,46 +28,46 @@ -static inline sint_16 logadd(sint_16 a,sint_16 b); -static sint_16 calc_lowcomp(sint_16 a,sint_16 b0,sint_16 b1,sint_16 bin); -static inline uint_16 min(sint_16 a,sint_16 b); -static inline uint_16 max(sint_16 a,sint_16 b); -static void ba_compute_psd(sint_16 start, sint_16 end, sint_16 exps[], - sint_16 psd[], sint_16 bndpsd[]); - -static void ba_compute_excitation(sint_16 start, sint_16 end,sint_16 fgain, - sint_16 fastleak, sint_16 slowleak, sint_16 is_lfe, sint_16 bndpsd[], - sint_16 excite[]); -static void ba_compute_mask(sint_16 start, sint_16 end, uint_16 fscod, - uint_16 deltbae, uint_16 deltnseg, uint_16 deltoffst[], uint_16 deltba[], - uint_16 deltlen[], sint_16 excite[], sint_16 mask[]); -static void ba_compute_bap(sint_16 start, sint_16 end, sint_16 snroffset, - sint_16 psd[], sint_16 mask[], sint_16 bap[]); +static inline int16_t logadd(int16_t a,int16_t b); +static int16_t calc_lowcomp(int16_t a,int16_t b0,int16_t b1,int16_t bin); +static inline uint16_t min(int16_t a,int16_t b); +static inline uint16_t max(int16_t a,int16_t b); +static void ba_compute_psd(int16_t start, int16_t end, int16_t exps[], + int16_t psd[], int16_t bndpsd[]); + +static void ba_compute_excitation(int16_t start, int16_t end,int16_t fgain, + int16_t fastleak, int16_t slowleak, int16_t is_lfe, int16_t bndpsd[], + int16_t excite[]); +static void ba_compute_mask(int16_t start, int16_t end, uint16_t fscod, + uint16_t deltbae, uint16_t deltnseg, uint16_t deltoffst[], uint16_t deltba[], + uint16_t deltlen[], int16_t excite[], int16_t mask[]); +static void ba_compute_bap(int16_t start, int16_t end, int16_t snroffset, + int16_t psd[], int16_t mask[], int16_t bap[]); /* Misc LUTs for bit allocation process */ -static sint_16 slowdec[] = { 0x0f, 0x11, 0x13, 0x15 }; -static sint_16 fastdec[] = { 0x3f, 0x53, 0x67, 0x7b }; -static sint_16 slowgain[] = { 0x540, 0x4d8, 0x478, 0x410 }; -static sint_16 dbpbtab[] = { 0x000, 0x700, 0x900, 0xb00 }; +static int16_t slowdec[] = { 0x0f, 0x11, 0x13, 0x15 }; +static int16_t fastdec[] = { 0x3f, 0x53, 0x67, 0x7b }; +static int16_t slowgain[] = { 0x540, 0x4d8, 0x478, 0x410 }; +static int16_t dbpbtab[] = { 0x000, 0x700, 0x900, 0xb00 }; -static uint_16 floortab[] = { 0x2f0, 0x2b0, 0x270, 0x230, 0x1f0, 0x170, 0x0f0, 0xf800 }; -static sint_16 fastgain[] = { 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400 }; +static uint16_t floortab[] = { 0x2f0, 0x2b0, 0x270, 0x230, 0x1f0, 0x170, 0x0f0, 0xf800 }; +static int16_t fastgain[] = { 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400 }; -static sint_16 bndtab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +static int16_t bndtab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 34, 37, 40, 43, 46, 49, 55, 61, 67, 73, 79, 85, 97, 109, 121, 133, 157, 181, 205, 229 }; -static sint_16 bndsz[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +static int16_t bndsz[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 24, 24, 24, 24, 24 }; -static sint_16 masktab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +static int16_t masktab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 37, @@ -85,7 +85,7 @@ static sint_16 masktab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, 0, 0 }; -static sint_16 latab[] = { 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003b, 0x003a, 0x0039, +static int16_t latab[] = { 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003b, 0x003a, 0x0039, 0x0038, 0x0037, 0x0036, 0x0035, 0x0034, 0x0034, 0x0033, 0x0032, 0x0031, 0x0030, 0x002f, 0x002f, 0x002e, 0x002d, 0x002c, 0x002c, 0x002b, 0x002a, 0x0029, 0x0029, 0x0028, 0x0027, 0x0026, 0x0026, @@ -119,7 +119,7 @@ static sint_16 latab[] = { 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003b, 0x003 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; -static sint_16 hth[][50] = {{ 0x04d0, 0x04d0, 0x0440, 0x0400, 0x03e0, 0x03c0, 0x03b0, 0x03b0, +static int16_t hth[][50] = {{ 0x04d0, 0x04d0, 0x0440, 0x0400, 0x03e0, 0x03c0, 0x03b0, 0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390, 0x0380, 0x0380, 0x0370, 0x0370, 0x0360, 0x0360, 0x0350, 0x0350, 0x0340, 0x0340, 0x0330, 0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0, @@ -144,38 +144,50 @@ static sint_16 hth[][50] = {{ 0x04d0, 0x04d0, 0x0440, 0x0400, 0x03e0, 0x03c0, 0x 0x0450, 0x04e0 }}; -static sint_16 baptab[] = { 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, +static int16_t baptab[] = { 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; -static sint_16 sdecay; -static sint_16 fdecay; -static sint_16 sgain; -static sint_16 dbknee; -static sint_16 floor; -static sint_16 psd[256]; -static sint_16 bndpsd[256]; -static sint_16 excite[256]; -static sint_16 mask[256]; - -static inline uint_16 -max(sint_16 a,sint_16 b) +static int16_t sdecay; +static int16_t fdecay; +static int16_t sgain; +static int16_t dbknee; +static int16_t floor; +static int16_t psd[256]; +static int16_t bndpsd[256]; +static int16_t excite[256]; +static int16_t mask[256]; + + +/** + * + **/ + +static inline uint16_t max(int16_t a,int16_t b) { return (a > b ? a : b); } + + +/** + * + **/ -static inline uint_16 -min(sint_16 a,sint_16 b) +static inline uint16_t min(int16_t a,int16_t b) { return (a < b ? a : b); } -static inline sint_16 -logadd(sint_16 a,sint_16 b) + +/** + * + **/ + +static inline int16_t logadd(int16_t a,int16_t b) { - sint_16 c; - sint_16 address; + int16_t c; + int16_t address; c = a - b; address = min((abs(c) >> 1), 255); @@ -187,15 +199,19 @@ logadd(sint_16 a,sint_16 b) } -void bit_allocate(uint_16 fscod, bsi_t *bsi, audblk_t *audblk) +/** + * + **/ + +void bit_allocate(uint16_t fscod, bsi_t *bsi, audblk_t *audblk) { - uint_16 i; - sint_16 fgain; - sint_16 snroffset; - sint_16 start; - sint_16 end; - sint_16 fastleak; - sint_16 slowleak; + uint16_t i; + int16_t fgain; + int16_t snroffset; + int16_t start; + int16_t end; + int16_t fastleak; + int16_t slowleak; /* Only perform bit_allocation if the exponents have changed or we * have new sideband information */ @@ -217,11 +233,10 @@ void bit_allocate(uint_16 fscod, bsi_t *bsi, audblk_t *audblk) if(!audblk->csnroffst && !audblk->fsnroffst[0] && !audblk->fsnroffst[1] && !audblk->fsnroffst[2] && !audblk->fsnroffst[3] && !audblk->fsnroffst[4] && - !audblk->cplfsnroffst && !audblk->lfefsnroffst) - { - memset(audblk->fbw_bap,0,sizeof(uint_16) * 256 * 5); - memset(audblk->cpl_bap,0,sizeof(uint_16) * 256); - memset(audblk->lfe_bap,0,sizeof(uint_16) * 7); + !audblk->cplfsnroffst && !audblk->lfefsnroffst) { + memset(audblk->fbw_bap,0,sizeof(uint16_t) * 256 * 5); + memset(audblk->cpl_bap,0,sizeof(uint16_t) * 256); + memset(audblk->lfe_bap,0,sizeof(uint16_t) * 7); return; } @@ -245,8 +260,7 @@ void bit_allocate(uint_16 fscod, bsi_t *bsi, audblk_t *audblk) ba_compute_bap(start, end, snroffset, psd, mask, audblk->fbw_bap[i]); } - if(audblk->cplinu) - { + if(audblk->cplinu) { start = audblk->cplstrtmant; end = audblk->cplendmant; fgain = fastgain[audblk->cplfgaincod]; @@ -264,8 +278,7 @@ void bit_allocate(uint_16 fscod, bsi_t *bsi, audblk_t *audblk) ba_compute_bap(start, end, snroffset, psd, mask, audblk->cpl_bap); } - if(bsi->lfeon) - { + if(bsi->lfeon) { start = 0; end = 7; fgain = fastgain[audblk->lfefgaincod]; @@ -285,15 +298,18 @@ void bit_allocate(uint_16 fscod, bsi_t *bsi, audblk_t *audblk) } -static void ba_compute_psd(sint_16 start, sint_16 end, sint_16 exps[], - sint_16 psd[], sint_16 bndpsd[]) +/** + * + **/ + +static void ba_compute_psd(int16_t start, int16_t end, int16_t exps[], + int16_t psd[], int16_t bndpsd[]) { int bin,i,j,k; - sint_16 lastbin = 0; + int16_t lastbin = 0; /* Map the exponents into dBs */ - for (bin=start; bin<end; bin++) - { + for (bin=start; bin<end; bin++) { psd[bin] = (3072 - (exps[bin] << 7)); } @@ -301,14 +317,12 @@ static void ba_compute_psd(sint_16 start, sint_16 end, sint_16 exps[], j = start; k = masktab[start]; - do - { + do { lastbin = min(bndtab[k] + bndsz[k], end); bndpsd[k] = psd[j]; j++; - for (i = j; i < lastbin; i++) - { + for (i = j; i < lastbin; i++) { bndpsd[k] = logadd(bndpsd[k], psd[j]); j++; } @@ -317,49 +331,49 @@ static void ba_compute_psd(sint_16 start, sint_16 end, sint_16 exps[], } while (end > lastbin); } -static void ba_compute_excitation(sint_16 start, sint_16 end,sint_16 fgain, - sint_16 fastleak, sint_16 slowleak, sint_16 is_lfe, sint_16 bndpsd[], - sint_16 excite[]) + +/** + * + **/ + +static void ba_compute_excitation(int16_t start, int16_t end,int16_t fgain, + int16_t fastleak, int16_t slowleak, int16_t is_lfe, int16_t bndpsd[], + int16_t excite[]) { int bin; - sint_16 bndstrt; - sint_16 bndend; - sint_16 lowcomp = 0; - sint_16 begin = 0; + int16_t bndstrt; + int16_t bndend; + int16_t lowcomp = 0; + int16_t begin = 0; /* Compute excitation function */ bndstrt = masktab[start]; bndend = masktab[end - 1] + 1; - if (bndstrt == 0) /* For fbw and lfe channels */ - { + if (bndstrt == 0) { /* For fbw and lfe channels */ lowcomp = calc_lowcomp(lowcomp, bndpsd[0], bndpsd[1], 0); excite[0] = bndpsd[0] - fgain - lowcomp; lowcomp = calc_lowcomp(lowcomp, bndpsd[1], bndpsd[2], 1); excite[1] = bndpsd[1] - fgain - lowcomp; begin = 7 ; - /* Note: Do not call calc_lowcomp() for the last band of the lfe channel, (bin = 6) */ - for (bin = 2; bin < 7; bin++) - { +// Note: Do not call calc_lowcomp() for the last band of the lfe channel,(bin=6) + for (bin = 2; bin < 7; bin++) { if (!(is_lfe && (bin == 6))) lowcomp = calc_lowcomp(lowcomp, bndpsd[bin], bndpsd[bin+1], bin); fastleak = bndpsd[bin] - fgain; slowleak = bndpsd[bin] - sgain; excite[bin] = fastleak - lowcomp; - if (!(is_lfe && (bin == 6))) - { - if (bndpsd[bin] <= bndpsd[bin+1]) - { + if (!(is_lfe && (bin == 6))) { + if (bndpsd[bin] <= bndpsd[bin+1]) { begin = bin + 1 ; break; } } } - for (bin = begin; bin < min(bndend, 22); bin++) - { + for (bin = begin; bin < min(bndend, 22); bin++) { if (!(is_lfe && (bin == 6))) lowcomp = calc_lowcomp(lowcomp, bndpsd[bin], bndpsd[bin+1], bin); fastleak -= fdecay ; @@ -371,12 +385,9 @@ static void ba_compute_excitation(sint_16 start, sint_16 end,sint_16 fgain, begin = 22; } else /* For coupling channel */ - { begin = bndstrt; - } - for (bin = begin; bin < bndend; bin++) - { + for (bin = begin; bin < bndend; bin++) { fastleak -= fdecay; fastleak = max(fastleak, bndpsd[bin] - fgain); slowleak -= sdecay; @@ -385,49 +396,47 @@ static void ba_compute_excitation(sint_16 start, sint_16 end,sint_16 fgain, } } -static void ba_compute_mask(sint_16 start, sint_16 end, uint_16 fscod, - uint_16 deltbae, uint_16 deltnseg, uint_16 deltoffst[], uint_16 deltba[], - uint_16 deltlen[], sint_16 excite[], sint_16 mask[]) + +/** + * + **/ + +static void ba_compute_mask(int16_t start, int16_t end, uint16_t fscod, + uint16_t deltbae, uint16_t deltnseg, uint16_t deltoffst[], uint16_t deltba[], + uint16_t deltlen[], int16_t excite[], int16_t mask[]) { int bin,k; - sint_16 bndstrt; - sint_16 bndend; - sint_16 delta; + int16_t bndstrt; + int16_t bndend; + int16_t delta; bndstrt = masktab[start]; bndend = masktab[end - 1] + 1; /* Compute the masking curve */ - for (bin = bndstrt; bin < bndend; bin++) - { - if (bndpsd[bin] < dbknee) - { + for (bin = bndstrt; bin < bndend; bin++) { + if (bndpsd[bin] < dbknee) { excite[bin] += ((dbknee - bndpsd[bin]) >> 2); } mask[bin] = max(excite[bin], hth[fscod][bin]); } /* Perform delta bit modulation if necessary */ - if ((deltbae == DELTA_BIT_REUSE) || (deltbae == DELTA_BIT_NEW)) - { - sint_16 band = 0; - sint_16 seg = 0; + if ((deltbae == DELTA_BIT_REUSE) || (deltbae == DELTA_BIT_NEW)) { + int16_t band = 0; + int16_t seg = 0; - for (seg = 0; seg < deltnseg+1; seg++) - { + for (seg = 0; seg < deltnseg+1; seg++) { band += deltoffst[seg]; - if (deltba[seg] >= 4) - { + + if (deltba[seg] >= 4) { delta = (deltba[seg] - 3) << 7; - } - else - { + } else { delta = (deltba[seg] - 4) << 7; } - for (k = 0; k < deltlen[seg]; k++) - { + for (k = 0; k < deltlen[seg]; k++) { mask[band] += delta; band++; } @@ -435,19 +444,23 @@ static void ba_compute_mask(sint_16 start, sint_16 end, uint_16 fscod, } } -static void ba_compute_bap(sint_16 start, sint_16 end, sint_16 snroffset, - sint_16 psd[], sint_16 mask[], sint_16 bap[]) + +/** + * + **/ + +static void ba_compute_bap(int16_t start, int16_t end, int16_t snroffset, + int16_t psd[], int16_t mask[], int16_t bap[]) { int i,j,k; - sint_16 lastbin = 0; - sint_16 address = 0; + int16_t lastbin = 0; + int16_t address = 0; /* Compute the bit allocation pointer for each bin */ i = start; j = masktab[start]; - do - { + do { lastbin = min(bndtab[j] + bndsz[j], end); mask[j] -= snroffset; mask[j] -= floor; @@ -457,8 +470,7 @@ static void ba_compute_bap(sint_16 start, sint_16 end, sint_16 snroffset, mask[j] &= 0x1fe0; mask[j] += floor; - for (k = i; k < lastbin; k++) - { + for (k = i; k < lastbin; k++) { address = (psd[i] - mask[j]) >> 5; address = min(63, max(0, address)); bap[i] = baptab[address]; @@ -468,25 +480,25 @@ static void ba_compute_bap(sint_16 start, sint_16 end, sint_16 snroffset, } while (end > lastbin); } -static sint_16 -calc_lowcomp(sint_16 a,sint_16 b0,sint_16 b1,sint_16 bin) + +/** + * + **/ + +static int16_t calc_lowcomp (int16_t a, int16_t b0, int16_t b1, int16_t bin) { - if (bin < 7) - { + if (bin < 7) { if ((b0 + 256) == b1) a = 384; else if (b0 > b1) a = max(0, a - 64); - } - else if (bin < 20) - { + } else if (bin < 20) { if ((b0 + 256) == b1) a = 320; else if (b0 > b1) a = max(0, a - 64) ; - } - else + } else a = max(0, a - 128); return(a); diff --git a/ac3dec/bit_allocate.h b/ac3dec/bit_allocate.h index e48b0b2bb..a6a3c7703 100644 --- a/ac3dec/bit_allocate.h +++ b/ac3dec/bit_allocate.h @@ -21,4 +21,4 @@ * */ -void bit_allocate(uint_16 fscod, bsi_t *bsi, audblk_t *audblk); +void bit_allocate(uint16_t fscod, bsi_t *bsi, audblk_t *audblk); diff --git a/ac3dec/bitstream.c b/ac3dec/bitstream.c index 296d5ee3d..f48d2408a 100644 --- a/ac3dec/bitstream.c +++ b/ac3dec/bitstream.c @@ -23,54 +23,57 @@ #include <stdlib.h> #include <stdio.h> +#include <inttypes.h> + +#include <bswap.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "ac3.h" #include "ac3_internal.h" #include "bitstream.h" -uint_8 *buffer_start = 0; -uint_32 bits_left = 0; -uint_32 current_word; +uint32_t bits_left = 0; +uint64_t current_word; +uint64_t *buffer_start = 0; + + +static inline uint64_t getdword (void) +{ + return be2me_64 (*buffer_start++); +} + -static inline void -bitstream_fill_current() +static inline void bitstream_fill_current (void) { - current_word = *((uint_32*)buffer_start)++; - current_word = swab32(current_word); + //current_word = bswap_64 (*buffer_start++); + current_word = getdword (); } -// -// The fast paths for _get is in the -// bitstream.h header file so it can be inlined. -// -// The "bottom half" of this routine is suffixed _bh -// -// -ah -// - -uint_32 -bitstream_get_bh(uint_32 num_bits) + +uint32_t bitstream_get_bh (uint32_t num_bits) { - uint_32 result; + uint32_t result; num_bits -= bits_left; - result = (current_word << (32 - bits_left)) >> (32 - bits_left); + result = (current_word << (64 - bits_left)) >> (64 - bits_left); bitstream_fill_current(); if(num_bits != 0) - result = (result << num_bits) | (current_word >> (32 - num_bits)); + result = (result << num_bits) | (current_word >> (64 - num_bits)); - bits_left = 32 - num_bits; + bits_left = 64 - num_bits; return result; } -void -bitstream_init(uint_8 *start) + +void bitstream_init (uint8_t *start) { //initialize the start of the buffer - buffer_start = start; + buffer_start = (uint64_t *) start; bits_left = 0; } diff --git a/ac3dec/bitstream.h b/ac3dec/bitstream.h index 335193064..f34726a77 100644 --- a/ac3dec/bitstream.h +++ b/ac3dec/bitstream.h @@ -21,56 +21,24 @@ * */ -//My new and improved vego-matic endian swapping routine -//(stolen from the kernel) -#ifdef WORDS_BIGENDIAN -# define swab32(x) (x) +#include <inttypes.h> -#else +extern uint32_t bits_left; +extern uint64_t current_word; -# if defined (__i386__) +void bitstream_init(uint8_t *start); +inline uint32_t bitstream_get_bh(uint32_t num_bits); -# define swab32(x) __i386_swab32(x) - static inline const uint_32 __i386_swab32(uint_32 x) - { - __asm__("bswap %0" : "=r" (x) : "0" (x)); - return x; - } - -# else - -# define swab32(x)\ -((((uint_8*)&x)[0] << 24) | (((uint_8*)&x)[1] << 16) | \ - (((uint_8*)&x)[2] << 8) | (((uint_8*)&x)[3])) - -# endif -#endif - -extern uint_32 bits_left; -extern uint_32 current_word; - -void bitstream_init(uint_8 *start); - -uint_8 bitstream_get_byte(void); - -uint_8 *bitstream_get_buffer_start(void); -void bitstream_buffer_frame(uint_32 frame_size); - -uint_32 bitstream_get_bh(uint_32 num_bits); - -static inline uint_32 -bitstream_get(uint_32 num_bits) +static inline uint32_t bitstream_get (uint32_t num_bits) { - uint_32 result; - - if(num_bits < bits_left) - { - result = (current_word << (32 - bits_left)) >> (32 - num_bits); + uint32_t result; + + if (num_bits < bits_left) { + result = (current_word << (64 - bits_left)) >> (64 - num_bits); bits_left -= num_bits; return result; } - return bitstream_get_bh(num_bits); + return bitstream_get_bh (num_bits); } - diff --git a/ac3dec/bswap.h b/ac3dec/bswap.h new file mode 100644 index 000000000..73d398aa1 --- /dev/null +++ b/ac3dec/bswap.h @@ -0,0 +1,80 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#ifndef __BSWAP_H__ +#define __BSWAP_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_BYTESWAP_H +#include <byteswap.h> +#else + +#include <inttypes.h> + +#ifdef WORDS_BIGENDIAN +// FIXME these need to actually swap ;) +#define bswap_16(x) (x) +#define bswap_32(x) (x) +#define bswap_64(x) (x) +#else +// This is wrong, 'cannot take address of ...' +#define bswap_16(x) ((((uint8_t*)&x)[2] << 8) \ + | (((uint8_t*)&x)[3])) + +// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. +#define bswap_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#define bswap_64(x) \ + (__extension__ \ + ({ union { __extension__ unsigned long long int __ll; \ + unsigned long int __l[2]; } __w, __r; \ + __w.__ll = (x); \ + __r.__l[0] = bswap_32 (__w.__l[1]); \ + __r.__l[1] = bswap_32 (__w.__l[0]); \ + __r.__ll; })) +#endif + +#endif + +// be2me ... BigEndian to MachineEndian +// le2me ... LittleEndian to MachineEndian + +#ifdef WORDS_BIGENDIAN +#define be2me_16(x) (x) +#define be2me_32(x) (x) +#define be2me_64(x) (x) +#define le2me_16(x) bswap_16(x) +#define le2me_32(x) bswap_32(x) +#define le2me_64(x) bswap_64(x) +#else +#define be2me_16(x) bswap_16(x) +#define be2me_32(x) bswap_32(x) +#define be2me_64(x) bswap_64(x) +#define le2me_16(x) (x) +#define le2me_32(x) (x) +#define le2me_64(x) (x) +#endif + +#endif diff --git a/ac3dec/cmplx.h b/ac3dec/cmplx.h new file mode 100644 index 000000000..9f74721ec --- /dev/null +++ b/ac3dec/cmplx.h @@ -0,0 +1,29 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#ifndef __COMPLEX_H__ +#define __COMPLEX_H__ + +typedef struct complex { + float re; + float im; +} complex_t; + +#endif diff --git a/ac3dec/coeff.c b/ac3dec/coeff.c index b9f03ff65..7d5579cae 100644 --- a/ac3dec/coeff.c +++ b/ac3dec/coeff.c @@ -28,51 +28,183 @@ #include "ac3_internal.h" -#include "decode.h" #include "bitstream.h" #include "dither.h" #include "coeff.h" + // //Lookup tables of 0.15 two's complement quantization values // -static const uint_16 q_1[3] = +#define Q0 ((-2 << 15) / 3.0) +#define Q1 (0) +#define Q2 ((2 << 15) / 3.0) + +static const float q_1_0[ 32 ] = { - ( -2 << 15)/3, 0,( 2 << 15)/3 -}; + Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, + Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, + 0,0,0,0,0 +}; -static const uint_16 q_2[5] = +static const float q_1_1[ 32 ] = { - ( -4 << 15)/5,( -2 << 15)/5, 0, - ( 2 << 15)/5,( 4 << 15)/5 -}; + Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, + Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, + Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, + 0,0,0,0,0 +}; -static const uint_16 q_3[7] = +static const float q_1_2[ 32 ] = +{ + Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, + Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, + Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, + 0,0,0,0,0 +}; + +#undef Q0 +#undef Q1 +#undef Q2 + +#define Q0 ((-4 << 15) / 5.0) +#define Q1 ((-2 << 15) / 5.0) +#define Q2 (0) +#define Q3 ((2 << 15) / 5.0) +#define Q4 ((4 << 15) / 5.0) + +static const float q_2_0[ 128 ] = +{ + Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, + Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, + Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, + Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, + Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, + Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3, + Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3, + Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4, + Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4, + 0,0,0 +}; + +static const float q_2_1[ 128 ] = +{ + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3, + Q4,Q4,Q4,Q4,Q4,Q0,Q0,Q0,Q0,Q0, + Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2, + Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3, + Q4,Q4,Q4,Q4,Q4,Q0,Q0,Q0,Q0,Q0, + Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2, + Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3, + Q4,Q4,Q4,Q4,Q4,0,0,0 + }; + +static const float q_2_2[ 128 ] = + { + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,0,0,0 +}; + +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +#undef Q4 + +static const float q_3[7] = { - ( -6 << 15)/7,( -4 << 15)/7,( -2 << 15)/7, 0, - ( 2 << 15)/7,( 4 << 15)/7,( 6 << 15)/7 + (-6 << 15)/7.0, (-4 << 15)/7.0, (-2 << 15)/7.0, 0.0, + ( 2 << 15)/7.0, ( 4 << 15)/7.0, ( 6 << 15)/7.0 }; -static const uint_16 q_4[11] = +#define Q0 ((-10 << 15) / 11.0) +#define Q1 ((-8 << 15) / 11.0) +#define Q2 ((-6 << 15) / 11.0) +#define Q3 ((-4 << 15) / 11.0) +#define Q4 ((-2 << 15) / 11.0) +#define Q5 (0) +#define Q6 ((2 << 15) / 11.0) +#define Q7 ((4 << 15) / 11.0) +#define Q8 ((6 << 15) / 11.0) +#define Q9 ((8 << 15) / 11.0) +#define QA ((10 << 15) / 11.0) + +static const float q_4_0[ 128 ] = { - (-10 << 15)/11,(-8 << 15)/11,(-6 << 15)/11, ( -4 << 15)/11,(-2 << 15)/11, 0, - ( 2 << 15)/11,( 4 << 15)/11,( 6 << 15)/11, ( 8 << 15)/11,(10 << 15)/11 + Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, + Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, + Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, + Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, + Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, + Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, + Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, + Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, + Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, + Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, + QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, + 0, 0, 0, 0, 0, 0, 0 + }; + +static const float q_4_1[ 128 ] = +{ + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + 0, 0, 0, 0, 0, 0, 0 }; -static const uint_16 q_5[15] = +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +#undef Q4 +#undef Q5 +#undef Q6 +#undef Q7 +#undef Q8 +#undef Q9 +#undef QA + +static const float q_5[15] = { - (-14 << 15)/15,(-12 << 15)/15,(-10 << 15)/15, - ( -8 << 15)/15,( -6 << 15)/15,( -4 << 15)/15, - ( -2 << 15)/15, 0 ,( 2 << 15)/15, - ( 4 << 15)/15,( 6 << 15)/15,( 8 << 15)/15, - ( 10 << 15)/15,( 12 << 15)/15,( 14 << 15)/15 -}; + (-14 << 15)/15.0,(-12 << 15)/15.0,(-10 << 15)/15.0, + ( -8 << 15)/15.0,( -6 << 15)/15.0,( -4 << 15)/15.0, + ( -2 << 15)/15.0, 0.0 ,( 2 << 15)/15.0, + ( 4 << 15)/15.0,( 6 << 15)/15.0,( 8 << 15)/15.0, + ( 10 << 15)/15.0,( 12 << 15)/15.0,( 14 << 15)/15.0 +}; // // Scale factors for convert_to_float // -static const uint_32 u32_scale_factors[25] = +static const uint32_t u32_scale_factors[25] = { 0x38000000, //2 ^ -(0 + 15) 0x37800000, //2 ^ -(1 + 15) @@ -104,230 +236,179 @@ static const uint_32 u32_scale_factors[25] = static float *scale_factor = (float*)u32_scale_factors; //These store the persistent state of the packed mantissas -static uint_16 m_1[3]; -static uint_16 m_2[3]; -static uint_16 m_4[2]; -static uint_16 m_1_pointer; -static uint_16 m_2_pointer; -static uint_16 m_4_pointer; +static float q_1[2]; +static float q_2[2]; +static float q_4[1]; +static int32_t q_1_pointer; +static int32_t q_2_pointer; +static int32_t q_4_pointer; +static float __inline__ +coeff_get_float(uint16_t bap, uint16_t dithflag, uint16_t exp); //Conversion from bap to number of bits in the mantissas //zeros account for cases 0,1,2,4 which are special cased -static uint_16 qnttztab[16] = { 0, 0, 0, 3, 0 , 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16}; - -static void coeff_reset(void); -static sint_16 coeff_get_mantissa(uint_16 bap, uint_16 dithflag); -static void coeff_uncouple_ch(float samples[],bsi_t *bsi,audblk_t *audblk,uint_32 ch); - -// -// Convert a 0.15 fixed point number into IEEE single -// precision floating point and scale by 2^-exp -// -static inline float -convert_to_float(uint_16 exp, sint_16 mantissa) +static uint16_t qnttztab[16] = { - float x; - - //the scale by 2^-15 is built into the scale factor table - x = mantissa * scale_factor[exp]; + 0, 0, 0, 3, + 0, 4, 5, 6, + 7, 8, 9, 10, + 11, 12, 14, 16 +}; - return x; -} +static void coeff_reset(void); +static float coeff_get_float(uint16_t bap, uint16_t dithflag, uint16_t exp); +static void coeff_uncouple_ch(float samples[],bsi_t *bsi,audblk_t *audblk,uint32_t ch); -void -coeff_unpack(bsi_t *bsi, audblk_t *audblk, stream_samples_t samples) +void coeff_unpack(bsi_t *bsi, audblk_t *audblk, stream_samples_t samples) { - uint_16 i,j; - uint_32 done_cpl = 0; - sint_16 mantissa; + uint16_t i,j; + uint32_t done_cpl = 0; coeff_reset(); - for(i=0; i< bsi->nfchans; i++) - { + for(i=0; i< bsi->nfchans; i++) { for(j=0; j < audblk->endmant[i]; j++) - { - mantissa = coeff_get_mantissa(audblk->fbw_bap[i][j],audblk->dithflag[i]); - samples[i][j] = convert_to_float(audblk->fbw_exp[i][j],mantissa); - } + samples[i][j] = coeff_get_float(audblk->fbw_bap[i][j], audblk->dithflag[i], audblk->fbw_exp[i][j]); - if(audblk->cplinu && audblk->chincpl[i] && !(done_cpl)) - { + if(audblk->cplinu && audblk->chincpl[i] && !(done_cpl)) { // ncplmant is equal to 12 * ncplsubnd - // Don't dither coupling channel until channel separation so that - // interchannel noise is uncorrelated + // Don't dither coupling channel until channel + // separation so that interchannel noise is uncorrelated for(j=audblk->cplstrtmant; j < audblk->cplendmant; j++) - audblk->cplmant[j] = coeff_get_mantissa(audblk->cpl_bap[j],0); + audblk->cpl_flt[j] = coeff_get_float(audblk->cpl_bap[j],0, audblk->cpl_exp[j]); done_cpl = 1; } } //uncouple the channel if necessary - if(audblk->cplinu) - { - for(i=0; i< bsi->nfchans; i++) - { + if(audblk->cplinu) { + for(i=0; i< bsi->nfchans; i++) { if(audblk->chincpl[i]) coeff_uncouple_ch(samples[i],bsi,audblk,i); } } - if(bsi->lfeon) - { + if(bsi->lfeon) { // There are always 7 mantissas for lfe, no dither for lfe for(j=0; j < 7 ; j++) - { - mantissa = coeff_get_mantissa(audblk->lfe_bap[j],0); - samples[5][j] = convert_to_float(audblk->lfe_exp[j],mantissa); - } + samples[5][j] = coeff_get_float(audblk->lfe_bap[j], 0, audblk->lfe_exp[j]); } } -// -//Fetch a mantissa from the bitstream -// -//The mantissa returned is a signed 0.15 fixed point number -// -static sint_16 -coeff_get_mantissa(uint_16 bap, uint_16 dithflag) + +/** + * Fetch a float from the bitstream + **/ + +static float inline coeff_get_float (uint16_t bap, uint16_t dithflag, uint16_t exp) { - uint_16 mantissa; - uint_16 group_code; + uint16_t dummy = 0; //If the bap is 0-5 then we have special cases to take care of - switch(bap) - { + switch(bap) { case 0: if(dithflag) - mantissa = dither_gen(); - else - mantissa = 0; - break; + return (dither_gen() * scale_factor[exp]); + + return 0.0; case 1: - if(m_1_pointer > 2) - { - group_code = bitstream_get(5); - - if(group_code > 26) - goto error; - - m_1[0] = group_code / 9; - m_1[1] = (group_code % 9) / 3; - m_1[2] = (group_code % 9) % 3; - m_1_pointer = 0; - } - mantissa = m_1[m_1_pointer++]; - mantissa = q_1[mantissa]; - break; + if (q_1_pointer >= 0) + return(q_1[q_1_pointer--] * scale_factor[exp]); + + if ((dummy = bitstream_get (5)) > 26) + goto error; + + q_1[1] = q_1_1[dummy]; + q_1[0] = q_1_2[dummy]; + q_1_pointer = 1; + + return (q_1_0[dummy] * scale_factor[exp]); + case 2: + if(q_2_pointer >= 0) + return (q_2[q_2_pointer--] * scale_factor[exp]); - if(m_2_pointer > 2) - { - group_code = bitstream_get(7); + if ((dummy = bitstream_get (7)) > 124) + goto error; - if(group_code > 124) - goto error; + q_2[1] = q_2_1[dummy]; + q_2[0] = q_2_2[dummy]; + q_2_pointer = 1; - m_2[0] = group_code / 25; - m_2[1] = (group_code % 25) / 5 ; - m_2[2] = (group_code % 25) % 5 ; - m_2_pointer = 0; - } - mantissa = m_2[m_2_pointer++]; - mantissa = q_2[mantissa]; - break; + return (q_2_0[dummy] * scale_factor[exp]); case 3: - mantissa = bitstream_get(3); - - if(mantissa > 6) + if ((dummy = bitstream_get (3)) > 6) goto error; - mantissa = q_3[mantissa]; - break; + return (q_3[dummy] * scale_factor[exp]); case 4: - if(m_4_pointer > 1) - { - group_code = bitstream_get(7); + if(q_4_pointer >= 0) + return (q_4[q_4_pointer--] * scale_factor[exp]); - if(group_code > 120) - goto error; + if ((dummy = bitstream_get (7)) > 120) + goto error; - m_4[0] = group_code / 11; - m_4[1] = group_code % 11; - m_4_pointer = 0; - } - mantissa = m_4[m_4_pointer++]; - mantissa = q_4[mantissa]; - break; + q_4[0] = q_4_1[dummy]; + q_4_pointer = 0; - case 5: - mantissa = bitstream_get(4); + return (q_4_0[dummy] * scale_factor[exp]); - if(mantissa > 14) + case 5: + if ((dummy = bitstream_get (4)) > 14) goto error; - mantissa = q_5[mantissa]; - break; + return (q_5[dummy] * scale_factor[exp]); default: - mantissa = bitstream_get(qnttztab[bap]); - mantissa <<= 16 - qnttztab[bap]; + dummy = bitstream_get(qnttztab[bap]); + dummy <<= 16 - qnttztab[bap]; + return ((int16_t)dummy * scale_factor[exp]); } - return mantissa; - - - error: - if(!error_flag) - fprintf(stderr,"** Invalid mantissa - skipping frame **\n"); - error_flag = 1; - - return 0; +#ifdef DEBUG + fprintf(stderr,"** Invalid mantissa - skipping frame **\n"); +#endif + HANDLE_ERROR(); } -// -// Reset the mantissa state -// -static void -coeff_reset(void) + +/** + * Reset the mantissa state + **/ + +static void coeff_reset(void) { - m_1[2] = m_1[1] = m_1[0] = 0; - m_2[2] = m_2[1] = m_2[0] = 0; - m_4[1] = m_4[0] = 0; - m_1_pointer = m_2_pointer = m_4_pointer = 3; + q_1_pointer = q_2_pointer = q_4_pointer = -1; } -// -// Uncouple the coupling channel into a fbw channel -// -static void -coeff_uncouple_ch(float samples[],bsi_t *bsi,audblk_t *audblk,uint_32 ch) + +/** + * Uncouple the coupling channel into a fbw channel + **/ + +static void coeff_uncouple_ch (float samples[],bsi_t *bsi,audblk_t *audblk,uint32_t ch) { - uint_32 bnd = 0; - uint_32 sub_bnd = 0; - uint_32 i,j; + uint32_t bnd = 0; + uint32_t sub_bnd = 0; + uint32_t i,j; float cpl_coord = 1.0; - uint_32 cpl_exp_tmp; - uint_32 cpl_mant_tmp; - sint_16 mantissa; - + uint32_t cpl_exp_tmp; + uint32_t cpl_mant_tmp; - for(i=audblk->cplstrtmant;i<audblk->cplendmant;) - { - if(!audblk->cplbndstrc[sub_bnd++]) - { + for (i=audblk->cplstrtmant;i<audblk->cplendmant;) { + if (!audblk->cplbndstrc[sub_bnd++]) { cpl_exp_tmp = audblk->cplcoexp[ch][bnd] + 3 * audblk->mstrcplco[ch]; - if(audblk->cplcoexp[ch][bnd] == 15) + if (audblk->cplcoexp[ch][bnd] == 15) cpl_mant_tmp = (audblk->cplcomant[ch][bnd]) << 11; else cpl_mant_tmp = ((0x10) | audblk->cplcomant[ch][bnd]) << 10; - cpl_coord = convert_to_float(cpl_exp_tmp,cpl_mant_tmp) * 8.0f; + cpl_coord = (cpl_mant_tmp * scale_factor[cpl_exp_tmp]) * 8.0f; //Invert the phase for the right channel if necessary if(bsi->acmod == 0x2 && audblk->phsflginu && ch == 1 && audblk->phsflg[bnd]) @@ -336,16 +417,13 @@ coeff_uncouple_ch(float samples[],bsi_t *bsi,audblk_t *audblk,uint_32 ch) bnd++; } - for(j=0;j < 12; j++) - { - //Get new dither values for each channel if necessary, so - //the channels are uncorrelated - if(audblk->dithflag[ch] && audblk->cpl_bap[i] == 0) - mantissa = dither_gen(); + for(j=0;j < 12; j++) { + // Get new dither values for each channel if necessary, + // so the channels are uncorrelated + if(audblk->dithflag[ch] && !audblk->cpl_bap[i]) + samples[i] = cpl_coord * (dither_gen() * scale_factor[audblk->cpl_exp[i]]); else - mantissa = audblk->cplmant[i]; - - samples[i] = cpl_coord * convert_to_float(audblk->cpl_exp[i],mantissa); + samples[i] = cpl_coord * audblk->cpl_flt[i]; i++; } diff --git a/ac3dec/cpu_accel.c b/ac3dec/cpu_accel.c new file mode 100644 index 000000000..e01db83f6 --- /dev/null +++ b/ac3dec/cpu_accel.c @@ -0,0 +1,129 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#include <inttypes.h> +#include "mm_accel.h" + +//#ifdef __i386__ +#if 0 + +#ifdef __PIC__ +#define cpuid(op, eax, ebx, ecx, edx) \ + __asm__ __volatile__ ("pushl %%ebx\n\t" \ + "cpuid\n\t" \ + "movl %%ebx, %%esi\n\t" \ + "popl %%ebx" \ + : "=a" (eax), \ + "=S" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "a" (op) \ + : "cc") +#else +#define cpuid(op, eax, ebx, ecx, edx) \ + __asm__("cpuid" \ + : "=a" (eax), \ + "=b" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "a" (op) \ + : "cc") +#endif + +static inline int has_cpuid () +{ + return 1; +/* + uint32_t eax, ebx; + + asm ("pushfl\n\t" + "popl %0\n\t" + "movl %0,%1\n\t" + "xorl $0x200000,%0\n\t" + "pushl %0\n\t" + "popfl\n\t" + "pushfl\n\t" + "popl %0" + : "=a" (eax), + "=b" (ebx) + : + : "cc"); + + return (eax != ebx); +*/ +} + + +static uint32_t x86_accel (void) +{ + uint32_t eax, ebx, ecx, edx; + int AMD; + uint32_t caps; + + if (!has_cpuid ()) // no cpuid + return 0; + + cpuid (0x00000000, eax, ebx, ecx, edx); + if (!eax) // vendor string only + return 0; + + AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65); + + cpuid (0x00000001, eax, ebx, ecx, edx); + if (! (edx & 0x00800000)) // no MMX + return 0; + + caps = OMS_ACCEL_X86_MMX; + if (edx & 0x02000000) // SSE - identical to AMD MMX extensions + caps = OMS_ACCEL_X86_MMX | OMS_ACCEL_X86_MMXEXT; + + cpuid (0x80000000, eax, ebx, ecx, edx); + if (eax < 0x80000001) // no extended capabilities + return caps; + + cpuid (0x80000001, eax, ebx, ecx, edx); + + if (edx & 0x80000000) + caps |= OMS_ACCEL_X86_3DNOW; + + if (AMD && (edx & 0x00400000)) // AMD MMX extensions + caps |= OMS_ACCEL_X86_MMXEXT; + + return caps; +} +#endif + +uint32_t mm_accel (void) +{ +//#ifdef __i386__ +#if 0 + static int got_accel = 0; + static uint32_t accel; + + if (!got_accel) { + got_accel = 1; + accel = x86_accel (); + } + + return accel; +#else + return 0; +#endif +} diff --git a/ac3dec/crc.c b/ac3dec/crc.c index 3210ce7f8..2d5ef8065 100644 --- a/ac3dec/crc.c +++ b/ac3dec/crc.c @@ -30,7 +30,7 @@ #include "crc.h" -static const uint_16 crc_lut[256] = +static const uint16_t crc_lut[256] = { 0x0000,0x8005,0x800f,0x000a,0x801b,0x001e,0x0014,0x8011, 0x8033,0x0036,0x003c,0x8039,0x0028,0x802d,0x8027,0x0022, @@ -66,31 +66,31 @@ static const uint_16 crc_lut[256] = 0x8213,0x0216,0x021c,0x8219,0x0208,0x820d,0x8207,0x0202 }; -static uint_16 state; +static uint16_t state; -void -crc_init(void) + +void crc_init(void) { state = 0; } -inline void crc_process_byte(uint_8 data) +inline void crc_process_byte (uint8_t data) { state = crc_lut[data ^ (state>>8)] ^ (state<<8); } -void -crc_process_frame(uint_8 *data,uint_32 num_bytes) + +void crc_process_frame (uint8_t *data,uint32_t num_bytes) { - uint_32 i; + uint32_t i; - for(i=0;i<num_bytes;i++) - crc_process_byte(data[i]); + for(i=0; i<num_bytes; i++) + crc_process_byte (data[i]); } -int -crc_validate(void) + +int crc_validate(void) { - return(state == 0); + return (state == 0); } diff --git a/ac3dec/crc.h b/ac3dec/crc.h index 07d57b154..16489656c 100644 --- a/ac3dec/crc.h +++ b/ac3dec/crc.h @@ -23,5 +23,5 @@ int crc_validate(void); void crc_init(void); -void crc_process_byte(uint_8 data); -void crc_process_frame(uint_8 *data,uint_32 num_bytes); +void crc_process_byte(uint8_t data); +void crc_process_frame(uint8_t *data,uint32_t num_bytes); diff --git a/ac3dec/debug.c b/ac3dec/debug.c index b7d6a3b08..b84511d7f 100644 --- a/ac3dec/debug.c +++ b/ac3dec/debug.c @@ -31,18 +31,8 @@ static int debug_level = -1; // We could potentially have multiple levels of debug info int debug_is_on(void) { - char *env_var; - - if(debug_level < 0) - { - env_var = getenv("AC3_DEBUG"); - - if (env_var) - { - debug_level = 1; - } - else - debug_level = 0; + if(debug_level < 0) { + debug_level = getenv ("AC3_DEBUG") ? 1 : 0; } return debug_level; @@ -52,7 +42,7 @@ int debug_is_on(void) #ifndef __GNUC__ void dprintf(char fmt[],...) { - int foo = 0; + return; } #endif diff --git a/ac3dec/debug.h b/ac3dec/debug.h index f45cb5b1a..691d40329 100644 --- a/ac3dec/debug.h +++ b/ac3dec/debug.h @@ -22,16 +22,20 @@ * */ -int debug_is_on(void); +int debug_is_on (void); #ifdef __GNUC__ -#define dprintf(format,args...)\ +#ifdef DEBUG +#define dprintf(args...)\ {\ if (debug_is_on())\ {\ - fprintf(stderr,format,## args);\ + fprintf(stderr, args);\ }\ } #else +#define dprintf(args...) { }; +#endif +#else void dprintf(char fmt[],...); #endif diff --git a/ac3dec/decode.c b/ac3dec/decode.c index 5e7f034bd..fb852055c 100644 --- a/ac3dec/decode.c +++ b/ac3dec/decode.c @@ -3,9 +3,6 @@ * * Copyright (C) Aaron Holtzman - May 1999 * - * Added support for DVB-s PCI card by: - * Matjaz Thaler <matjaz.thaler@rd.iskraemeco.si> - November 2000 - * * This file is part of ac3dec, a free Dolby AC-3 stream decoder. * * ac3dec is free software; you can redistribute it and/or modify @@ -22,6 +19,17 @@ * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * + *------------------------------------------------------------ + * + * Thomas Mirlacher <dent@cosy.sbg.ac.at> + * added OMS support + * 11 Jan 2001 + * Thomas Mirlacher <dent@cosy.sbg.ac.at> + * faster error response using jmp functions + * + * 9 Aug 2001 + * Matjaz Thaler <matjaz.thaler@rd.iskraemeco.si> + * Added support for DVB-s PCI card * */ @@ -34,14 +42,17 @@ #include <errno.h> #include <string.h> #include <sys/time.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> + +#ifdef __OMS__ +#include <oms/oms.h> +#include <oms/plugin/output_audio.h> +#endif #include "ac3.h" #include "ac3_internal.h" #include "bitstream.h" +#include "downmix.h" +#include "srfft.h" #include "imdct.h" #include "exponent.h" #include "coeff.h" @@ -51,96 +62,91 @@ #include "stats.h" #include "rematrix.h" #include "sanity_check.h" -#include "downmix.h" #include "debug.h" - -#define AC3_BUFFER_SIZE (6*1024*16) - +#ifndef __OMS__ +//#include "audio_out.h" +#endif //our global config structure ac3_config_t ac3_config; -uint_32 error_flag = 0; static audblk_t audblk; static bsi_t bsi; static syncinfo_t syncinfo; -static uint_32 frame_count = 0; -//static uint_32 is_output_initialized = 0; +#ifndef __OMS__ +static uint32_t done_banner; +#endif +static uint32_t is_output_initialized = 0; //the floating point samples for one audblk static stream_samples_t samples; //the integer samples for the entire frame (with enough space for 2 ch out) //if this size change, be sure to change the size when muting -static sint_16 s16_samples[2 * 6 * 256]; - +static int16_t s16_samples[2 * 6 * 256] __attribute__ ((aligned(16))); +// downmix stuff +static float cmixlev_lut[4] = { 0.707, 0.595, 0.500, 0.707 }; +static float smixlev_lut[4] = { 0.707, 0.500, 0.0 , 0.500 }; +static dm_par_t dm_par; + //Storage for the syncframe -#define SYNC_BUFFER_MAX_SIZE 4096 -static uint_8 sync_buffer[SYNC_BUFFER_MAX_SIZE]; -static uint_32 sync_buffer_size = 0;; +#define BUFFER_MAX_SIZE 4096 +static uint8_t buffer[BUFFER_MAX_SIZE]; +static uint32_t buffer_size = 0;; +// for error handling +jmp_buf error_jmp_mark; -uint_32 -decode_sync_buffer_syncframe(syncinfo_t *syncinfo, uint_8 **start,uint_8 *end) +static uint32_t decode_buffer_syncframe (syncinfo_t *syncinfo, uint8_t **start, uint8_t *end) { - uint_8 *cur = *start; - uint_16 syncword = syncinfo->syncword; - uint_32 ret = 0; + uint8_t *cur = *start; + uint16_t syncword = syncinfo->syncword; + uint32_t ret = 0; - // // Find an ac3 sync frame. - // -resync: - - while(syncword != 0x0b77) - { - if(cur >= end) + while (syncword != 0x0b77) { + if (cur >= end) goto done; syncword = (syncword << 8) + *cur++; } //need the next 3 bytes to decide how big the frame is - while(sync_buffer_size < 3) - { + while (buffer_size < 3) { if(cur >= end) goto done; - sync_buffer[sync_buffer_size++] = *cur++; + buffer[buffer_size++] = *cur++; } - parse_syncinfo(syncinfo,sync_buffer); - stats_print_syncinfo(syncinfo); + parse_syncinfo (syncinfo,buffer); + stats_print_syncinfo (syncinfo); - while(sync_buffer_size < syncinfo->frame_size * 2 - 2) - { + while (buffer_size < syncinfo->frame_size * 2 - 2) { if(cur >= end) goto done; - sync_buffer[sync_buffer_size++] = *cur++; + buffer[buffer_size++] = *cur++; } - + +#if 0 // Check the crc over the entire frame crc_init(); - crc_process_frame(sync_buffer,syncinfo->frame_size * 2 - 2); + crc_process_frame (buffer, syncinfo->frame_size * 2 - 2); - if(!crc_validate()) - { + if (!crc_validate()) { fprintf(stderr,"** CRC failed - skipping frame **\n"); - syncword = 0xffff; - sync_buffer_size = 0; - goto resync; + goto done; } - - // +#endif + //if we got to this point, we found a valid ac3 frame to decode - // - bitstream_init(sync_buffer); + bitstream_init (buffer); //get rid of the syncinfo struct as we already parsed it - bitstream_get(24); + bitstream_get (24); //reset the syncword for next time syncword = 0xffff; - sync_buffer_size = 0; + buffer_size = 0; ret = 1; done: @@ -149,100 +155,131 @@ decode_sync_buffer_syncframe(syncinfo_t *syncinfo, uint_8 **start,uint_8 *end) return ret; } -void -decode_mute(void) + +void inline decode_mute (void) { - fprintf(stderr,"muting frame\n"); //mute the frame - memset(s16_samples,0,sizeof(sint_16) * 256 * 2 * 6); - error_flag = 0; + memset (s16_samples, 0, sizeof(int16_t) * 256 * 2 * 6); } -void -ac3_init(ac3_config_t *config) +void ac3dec_init (void) { - memcpy(&ac3_config,config,sizeof(ac3_config_t)); - - imdct_init(); - sanity_check_init(&syncinfo,&bsi,&audblk); - - // ac3_output = *foo; +// FIXME - don't do that statically here + ac3_config.num_output_ch = 2; + ac3_config.flags = 0; + + imdct_init (); + downmix_init (); + memset (&syncinfo, 0, sizeof (syncinfo)); + memset (&bsi, 0, sizeof (bsi)); + memset (&audblk, 0, sizeof (audblk)); + sanity_check_init (&syncinfo,&bsi,&audblk); } -uint_32 ac3_decode_data(uint_8 *data_start,uint_8 *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data) +#ifdef __OMS__ +size_t ac3dec_decode_data (plugin_output_audio_t *output, uint8_t *data_start, uint8_t *data_end) +#else +size_t ac3dec_decode_data (uint8_t *data_start ,uint8_t *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data) +#endif { - uint_32 i; + uint32_t i; int datasize; char *data; + if(ac3reset != 0){ syncinfo.syncword = 0xffff; - sync_buffer_size = 0; + buffer_size = 0; + } + + if (setjmp (error_jmp_mark) < 0) { + ac3dec_init (); + return 0; } - - while(decode_sync_buffer_syncframe(&syncinfo,&data_start,data_end)) - { - dprintf("(decode) begin frame %d\n",frame_count++); - if(error_flag) - { - decode_mute(); - continue; + while (decode_buffer_syncframe (&syncinfo, &data_start, data_end)) { + parse_bsi (&bsi); + +#ifndef __OMS__ + if(!done_banner) { + // stats_print_banner(&syncinfo,&bsi); + done_banner = 1; } +#endif + + // compute downmix parameters + // downmix to tow channels for now + dm_par.clev = 0.0; dm_par.slev = 0.0; dm_par.unit = 1.0; + if (bsi.acmod & 0x1) // have center + dm_par.clev = cmixlev_lut[bsi.cmixlev]; + + if (bsi.acmod & 0x4) // have surround channels + dm_par.slev = smixlev_lut[bsi.surmixlev]; - parse_bsi(&bsi); + dm_par.unit /= 1.0 + dm_par.clev + dm_par.slev; + dm_par.clev *= dm_par.unit; + dm_par.slev *= dm_par.unit; - for(i=0; i < 6; i++) - { + for(i=0; i < 6; i++) { //Initialize freq/time sample storage - memset(samples,0,sizeof(float) * 256 * (bsi.nfchans + bsi.lfeon)); + memset (samples, 0, sizeof(float) * 256 * (bsi.nfchans + bsi.lfeon)); // Extract most of the audblk info from the bitstream // (minus the mantissas - parse_audblk(&bsi,&audblk); + parse_audblk (&bsi,&audblk); // Take the differential exponent data and turn it into // absolute exponents - exponent_unpack(&bsi,&audblk); - if(error_flag) - goto error; + exponent_unpack (&bsi,&audblk); // Figure out how many bits per mantissa - bit_allocate(syncinfo.fscod,&bsi,&audblk); + bit_allocate (syncinfo.fscod,&bsi,&audblk); // Extract the mantissas from the stream and // generate floating point frequency coefficients - coeff_unpack(&bsi,&audblk,samples); - if(error_flag) - goto error; + coeff_unpack (&bsi,&audblk,samples); - if(bsi.acmod == 0x2) - rematrix(&audblk,samples); + if (bsi.acmod == 0x2) + rematrix (&audblk,samples); // Convert the frequency samples into time samples - imdct(&bsi,&audblk,samples); + imdct (&bsi,&audblk,samples, &s16_samples[i * 2 * 256], &dm_par); // Downmix into the requested number of channels - // and convert floating point to sint_16 - downmix(&bsi,samples,&s16_samples[i * 2 * 256]); + // and convert floating point to int16_t + // downmix(&bsi,samples,&s16_samples[i * 2 * 256]); - sanity_check(&syncinfo,&bsi,&audblk); - if(error_flag) - goto error; + if (sanity_check(&syncinfo,&bsi,&audblk) < 0) { + HANDLE_ERROR (); + return 0; + } continue; } - - parse_auxdata(&syncinfo); - /* - if(!is_output_initialized) - { - ac3_output.open(16,syncinfo.sampling_rate,2); + if (!is_output_initialized) { +#ifdef __OMS__ + plugin_output_audio_attr_t attr; +#ifdef __sun__ + attr.format = 16; +#else + attr.format = AFMT_S16_NE; +#endif + attr.speed = syncinfo.sampling_rate; + attr.channels = 2; + + // output->setup (&attr); +#else + // ao_functions->open (16, syncinfo.sampling_rate, 2); +#endif is_output_initialized = 1; } - */ + +#ifdef __OMS__ + output->write (s16_samples, 256 * 6 * 2 * 2); +#else + // ao_functions->play(s16_samples, 256 * 6 * 2); data = (char *)s16_samples; datasize = 0; while(datasize < 6144){ @@ -257,13 +294,11 @@ uint_32 ac3_decode_data(uint_8 *data_start,uint_8 *data_end, int ac3reset, int * } } +#endif - //write(1, s16_samples, 256 * 6 * 2* 2); - //ac3_output.play(s16_samples, 256 * 6 * 2); -error: - ; - //find a new frame } + decode_mute (); + return 0; } diff --git a/ac3dec/dither.c b/ac3dec/dither.c index 31e74f629..079c04d6d 100644 --- a/ac3dec/dither.c +++ b/ac3dec/dither.c @@ -31,7 +31,7 @@ #include "dither.h" -const uint_16 dither_lut[256] = +const uint16_t dither_lut[256] = { 0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055, 0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb, @@ -67,7 +67,7 @@ const uint_16 dither_lut[256] = 0x8bf4, 0x2be5, 0x6bc7, 0xcbd6, 0xeb83, 0x4b92, 0x0bb0, 0xaba1 }; -uint_16 lfsr_state = 1; +uint16_t lfsr_state = 1; // // see dither_gen (inline-able) in dither.h @@ -89,18 +89,17 @@ uint_16 lfsr_state = 1; * */ -uint_16 dither_gen(void) +uint16_t dither_gen(void) { int i; - uint_32 state; + uint32_t state; //explicitly bring the state into a local var as gcc > 3.0? //doesn't know how to optimize out the stores state = lfsr_state; //Generate eight pseudo random bits - for(i=0;i<8;i++) - { + for(i=0;i<8;i++) { state <<= 1; if(state & 0x10000) @@ -109,7 +108,7 @@ uint_16 dither_gen(void) lfsr_state = state; - return (((((sint_32)state<<8)>>8) * (sint_32) (0.707106 * 256.0))>>16); + return (((((int32_t)state<<8)>>8) * (int32_t) (0.707106 * 256.0))>>16); } #endif diff --git a/ac3dec/dither.h b/ac3dec/dither.h index 6d68e1b54..abb9f518e 100644 --- a/ac3dec/dither.h +++ b/ac3dec/dither.h @@ -22,16 +22,16 @@ */ -extern uint_16 lfsr_state; -extern const uint_16 dither_lut[256]; +extern uint16_t lfsr_state; +extern const uint16_t dither_lut[256]; -static inline uint_16 dither_gen(void) +static inline uint16_t dither_gen(void) { - sint_16 state; + int16_t state; state = dither_lut[lfsr_state >> 8] ^ (lfsr_state << 8); - lfsr_state = (uint_16) state; + lfsr_state = (uint16_t) state; - return ((state * (sint_32) (0.707106 * 256.0))>>8); + return ((state * (int32_t) (0.707106 * 256.0))>>8); } diff --git a/ac3dec/downmix.c b/ac3dec/downmix.c index 94bc51a81..8eac3e21f 100644 --- a/ac3dec/downmix.c +++ b/ac3dec/downmix.c @@ -1,10 +1,7 @@ /* - * - * downmix.c + * imdct.c * - * Copyright (C) Aaron Holtzman - Sept 1999 - * - * Originally based on code by Yuqing Deng. + * Copyright (C) Aaron Holtzman - May 1999 * * This file is part of ac3dec, a free Dolby AC-3 stream decoder. * @@ -28,401 +25,65 @@ #include <stdlib.h> #include <stdio.h> #include <math.h> +#include <mm_accel.h> + #include "ac3.h" #include "ac3_internal.h" - -#include "decode.h" -#include "downmix.h" #include "debug.h" +#include "downmix.h" +#include "downmix_c.h" +#include "downmix_i386.h" +#ifdef HAVE_KNI +#include "downmix_kni.h" +#endif +void (*downmix_3f_2r_to_2ch)(float *samples, dm_par_t * dm_par); +void (*downmix_3f_1r_to_2ch)(float *samples, dm_par_t * dm_par); +void (*downmix_2f_2r_to_2ch)(float *samples, dm_par_t * dm_par); +void (*downmix_2f_1r_to_2ch)(float *samples, dm_par_t * dm_par); +void (*downmix_3f_0r_to_2ch)(float *samples, dm_par_t * dm_par); +void (*stream_sample_2ch_to_s16)(int16_t *s16_samples, float *left, float *right); +void (*stream_sample_1ch_to_s16)(int16_t *s16_samples, float *center); -//Pre-scaled downmix coefficients -static float cmixlev_lut[4] = { 0.2928, 0.2468, 0.2071, 0.2468 }; -static float smixlev_lut[4] = { 0.2928, 0.2071, 0.0 , 0.2071 }; -static void -downmix_3f_2r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) +void downmix_init() { - uint_32 j; - float right_tmp; - float left_tmp; - float clev,slev; - float *centre = 0, *left = 0, *right = 0, *left_sur = 0, *right_sur = 0; - - left = samples[0]; - centre = samples[1]; - right = samples[2]; - left_sur = samples[3]; - right_sur = samples[4]; - - clev = cmixlev_lut[bsi->cmixlev]; - slev = smixlev_lut[bsi->surmixlev]; - -#if defined DOLBY_SURROUND - for (j = 0; j < 256; j++) +#ifdef __i386__ +#ifdef HAVE_KNI + uint32_t accel = mm_accel (); + +// other dowmixing should go here too + if (accel & MM_ACCEL_X86_MMXEXT) { + dprintf("Using SSE for downmix\n"); + downmix_3f_2r_to_2ch = downmix_3f_2r_to_2ch_kni; + downmix_2f_2r_to_2ch = downmix_2f_2r_to_2ch_kni; + downmix_3f_1r_to_2ch = downmix_3f_1r_to_2ch_kni; + downmix_2f_1r_to_2ch = downmix_2f_1r_to_2ch_kni; + downmix_3f_0r_to_2ch = downmix_3f_0r_to_2ch_kni; + stream_sample_2ch_to_s16 = stream_sample_2ch_to_s16_kni; + stream_sample_1ch_to_s16 = stream_sample_1ch_to_s16_kni; + } else if (accel & MM_ACCEL_X86_3DNOW) { + } else +#endif +#endif { - right_tmp = *left_sur++ + *right_sur++; - left_tmp = 1.4142f * *left++ + *centre - right_tmp; - right_tmp += 1.4142f * *right++ + *centre++; - - s16_samples[j * 2 ] = (sint_16) (left_tmp * 16000.0f); - s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 16000.0f); - } + downmix_3f_2r_to_2ch = downmix_3f_2r_to_2ch_c; + downmix_2f_2r_to_2ch = downmix_2f_2r_to_2ch_c; + downmix_3f_1r_to_2ch = downmix_3f_1r_to_2ch_c; + downmix_2f_1r_to_2ch = downmix_2f_1r_to_2ch_c; + downmix_3f_0r_to_2ch = downmix_3f_0r_to_2ch_c; +#ifdef __i386__ +#if 1 + stream_sample_2ch_to_s16 = stream_sample_2ch_to_s16_c; + stream_sample_1ch_to_s16 = stream_sample_1ch_to_s16_c; #else - for (j = 0; j < 256; j++) - { - left_tmp = 0.4142f * *left++ + clev * *centre + slev * *left_sur++; - right_tmp= 0.4142f * *right++ + clev * *centre++ + slev * *right_sur++; - - s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); - s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); - } + stream_sample_2ch_to_s16 = stream_sample_2ch_to_s16_i386; + stream_sample_1ch_to_s16 = stream_sample_1ch_to_s16_i386; +#endif +#else + stream_sample_2ch_to_s16 = stream_sample_2ch_to_s16_c; + stream_sample_1ch_to_s16 = stream_sample_1ch_to_s16_c; #endif -} - -static void -downmix_2f_2r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) -{ - uint_32 j; - float right_tmp; - float left_tmp; - float slev; - float *left = 0, *right = 0, *left_sur = 0, *right_sur = 0; - - left = samples[0]; - right = samples[1]; - left_sur = samples[2]; - right_sur = samples[3]; - - slev = smixlev_lut[bsi->surmixlev]; - - for (j = 0; j < 256; j++) - { - left_tmp = 0.4142f * *left++ + slev * *left_sur++; - right_tmp= 0.4142f * *right++ + slev * *right_sur++; - - s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); - s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); - } -} - -static void -downmix_3f_1r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) -{ - uint_32 j; - float right_tmp; - float left_tmp; - float clev,slev; - float *centre = 0, *left = 0, *right = 0, *sur = 0; - - left = samples[0]; - centre = samples[1]; - right = samples[2]; - //Mono surround - sur = samples[3]; - - clev = cmixlev_lut[bsi->cmixlev]; - slev = smixlev_lut[bsi->surmixlev]; - - for (j = 0; j < 256; j++) - { - left_tmp = 0.4142f * *left++ + clev * *centre++ + slev * *sur; - right_tmp= 0.4142f * *right++ + clev * *centre + slev * *sur++; - - s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); - s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); - } -} - - -static void -downmix_2f_1r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) -{ - uint_32 j; - float right_tmp; - float left_tmp; - float slev; - float *left = 0, *right = 0, *sur = 0; - - left = samples[0]; - right = samples[1]; - //Mono surround - sur = samples[2]; - - slev = smixlev_lut[bsi->surmixlev]; - - for (j = 0; j < 256; j++) - { - left_tmp = 0.4142f * *left++ + slev * *sur; - right_tmp= 0.4142f * *right++ + slev * *sur++; - - s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); - s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); - } -} - -static void -downmix_3f_0r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) -{ - uint_32 j; - float right_tmp; - float left_tmp; - float clev; - float *centre = 0, *left = 0, *right = 0; - - left = samples[0]; - centre = samples[1]; - right = samples[2]; - - clev = cmixlev_lut[bsi->cmixlev]; - - for (j = 0; j < 256; j++) - { - left_tmp = 0.4142f * *left++ + clev * *centre; - right_tmp= 0.4142f * *right++ + clev * *centre++; - - s16_samples[j * 2 ] = (sint_16) (left_tmp * 32767.0f); - s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f); - } -} - -static void -downmix_2f_0r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) -{ - uint_32 j; - float *left = 0, *right = 0; - - left = samples[0]; - right = samples[1]; - - for (j = 0; j < 256; j++) - { - s16_samples[j * 2 ] = (sint_16) (*left++ * 32767.0f); - s16_samples[j * 2 + 1] = (sint_16) (*right++ * 32767.0f); - } -} - -static void -downmix_1f_0r_to_2ch(float *centre,sint_16 *s16_samples) -{ - uint_32 j; - float tmp; - - //Mono program! - - for (j = 0; j < 256; j++) - { - tmp = 32767.0f * 0.7071f * *centre++; - - s16_samples[j * 2 ] = s16_samples[j * 2 + 1] = (sint_16) tmp; - } -} - -// -// Downmix into 2 or 4 channels (4 ch isn't in quite yet) -// -// The downmix function names have the following format -// -// downmix_Xf_Yr_to_[2|4]ch[_dolby] -// -// where X = number of front channels -// Y = number of rear channels -// [2|4] = number of output channels -// [_dolby] = with or without dolby surround mix -// - -void downmix(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples) -{ - if(bsi->acmod > 7) - dprintf("(downmix) invalid acmod number\n"); - - // - //There are two main cases, with or without Dolby Surround - // - if(ac3_config.flags & AC3_DOLBY_SURR_ENABLE) - { - fprintf(stderr,"Dolby Surround Mixes not currently enabled\n"); - exit(1); - } - - //Non-Dolby surround downmixes - switch(bsi->acmod) - { - // 3/2 - case 7: - downmix_3f_2r_to_2ch(bsi,samples,s16_samples); - break; - - // 2/2 - case 6: - downmix_2f_2r_to_2ch(bsi,samples,s16_samples); - break; - - // 3/1 - case 5: - downmix_3f_1r_to_2ch(bsi,samples,s16_samples); - break; - - // 2/1 - case 4: - downmix_2f_1r_to_2ch(bsi,samples,s16_samples); - break; - - // 3/0 - case 3: - downmix_3f_0r_to_2ch(bsi,samples,s16_samples); - break; - - case 2: - downmix_2f_0r_to_2ch(bsi,samples,s16_samples); - break; - - // 1/0 - case 1: - downmix_1f_0r_to_2ch(samples[0],s16_samples); - break; - - // 1+1 - case 0: - downmix_1f_0r_to_2ch(samples[ac3_config.dual_mono_ch_sel],s16_samples); - break; } } - - - -#if 0 - - //the dolby mixes lay here for the time being - switch(bsi->acmod) - { - // 3/2 - case 7: - left = samples[0]; - centre = samples[1]; - right = samples[2]; - left_sur = samples[3]; - right_sur = samples[4]; - - for (j = 0; j < 256; j++) - { - right_tmp = 0.2265f * *left_sur++ + 0.2265f * *right_sur++; - left_tmp = -1 * right_tmp; - right_tmp += 0.3204f * *right++ + 0.2265f * *centre; - left_tmp += 0.3204f * *left++ + 0.2265f * *centre++; - - samples[1][j] = right_tmp; - samples[0][j] = left_tmp; - } - - break; - - // 2/2 - case 6: - left = samples[0]; - right = samples[1]; - left_sur = samples[2]; - right_sur = samples[3]; - - for (j = 0; j < 256; j++) - { - right_tmp = 0.2265f * *left_sur++ + 0.2265f * *right_sur++; - left_tmp = -1 * right_tmp; - right_tmp += 0.3204f * *right++; - left_tmp += 0.3204f * *left++ ; - - samples[1][j] = right_tmp; - samples[0][j] = left_tmp; - } - break; - - // 3/1 - case 5: - left = samples[0]; - centre = samples[1]; - right = samples[2]; - //Mono surround - right_sur = samples[3]; - - for (j = 0; j < 256; j++) - { - right_tmp = 0.2265f * *right_sur++; - left_tmp = -1 * right_tmp; - right_tmp += 0.3204f * *right++ + 0.2265f * *centre; - left_tmp += 0.3204f * *left++ + 0.2265f * *centre++; - - samples[1][j] = right_tmp; - samples[0][j] = left_tmp; - } - break; - - // 2/1 - case 4: - left = samples[0]; - right = samples[1]; - //Mono surround - right_sur = samples[2]; - - for (j = 0; j < 256; j++) - { - right_tmp = 0.2265f * *right_sur++; - left_tmp = -1 * right_tmp; - right_tmp += 0.3204f * *right++; - left_tmp += 0.3204f * *left++; - - samples[1][j] = right_tmp; - samples[0][j] = left_tmp; - } - break; - - // 3/0 - case 3: - left = samples[0]; - centre = samples[1]; - right = samples[2]; - - for (j = 0; j < 256; j++) - { - right_tmp = 0.3204f * *right++ + 0.2265f * *centre; - left_tmp = 0.3204f * *left++ + 0.2265f * *centre++; - - samples[1][j] = right_tmp; - samples[0][j] = left_tmp; - } - break; - - // 2/0 - case 2: - //Do nothing! - break; - - // 1/0 - case 1: - //Mono program! - right = samples[0]; - - for (j = 0; j < 256; j++) - { - right_tmp = 0.7071f * *right++; - - samples[1][j] = right_tmp; - samples[0][j] = right_tmp; - } - - break; - - // 1+1 - case 0: - //Dual mono, output selected by user - right = samples[ac3_config.dual_mono_ch_sel]; - - for (j = 0; j < 256; j++) - { - right_tmp = 0.7071f * *right++; - - samples[1][j] = right_tmp; - samples[0][j] = right_tmp; - } - break; -#endif diff --git a/ac3dec/downmix.h b/ac3dec/downmix.h index 7537c6229..dcfe1e12e 100644 --- a/ac3dec/downmix.h +++ b/ac3dec/downmix.h @@ -25,4 +25,10 @@ * */ -void downmix(bsi_t* bsi, stream_samples_t stream_samples,sint_16 *s16_samples); +typedef struct dm_par_s { + float unit; + float clev; + float slev; +} dm_par_t; + +void downmix_init(); diff --git a/ac3dec/downmix_c.c b/ac3dec/downmix_c.c new file mode 100644 index 000000000..875d785e4 --- /dev/null +++ b/ac3dec/downmix_c.c @@ -0,0 +1,161 @@ +/* + * downmix_c.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include "ac3.h" +#include "ac3_internal.h" + +#include "debug.h" +#include "downmix.h" +#include "downmix_c.h" + + +void downmix_3f_2r_to_2ch_c (float *samples, dm_par_t *dm_par) +{ + int i; + float *left, *right, *center, *left_sur, *right_sur; + float left_tmp, right_tmp; + + left = samples; + right = samples + 256 * 2; + center = samples + 256; + left_sur = samples + 256 * 3; + right_sur = samples + 256 * 4; + + for (i=0; i < 256; i++) { +#if defined DOLBY_SURROUND + left_tmp = dm_par->unit * *left + dm_par->clev * *center - dm_par->slev * (*left_sur + *right_sur); + right_tmp= dm_par->unit * *right++ + dm_par->clev * *center + dm_par->slev * (*left_sur++ + *right_sur++); +#else + left_tmp = dm_par->unit * *left + dm_par->clev * *center + dm_par->slev * *left_sur++; + right_tmp= dm_par->unit * *right++ + dm_par->clev * *center + dm_par->slev * *right_sur++; +#endif + *left++ = left_tmp; + *center++ = right_tmp; + + } +} + + +void downmix_2f_2r_to_2ch_c (float *samples, dm_par_t *dm_par) +{ + int i; + float *left, *right, *left_sur, *right_sur; + float left_tmp, right_tmp; + + left = &samples[0]; + right = &samples[256]; + left_sur = &samples[512]; + right_sur = &samples[768]; + + for (i = 0; i < 256; i++) { + left_tmp = dm_par->unit * *left + dm_par->slev * *left_sur++; + right_tmp= dm_par->unit * *right + dm_par->slev * *right_sur++; + *left++ = left_tmp; + *right++ = right_tmp; + } +} + + +void downmix_3f_1r_to_2ch_c (float *samples, dm_par_t *dm_par) +{ + int i; + float *left, *right, *center, *right_sur; + float left_tmp, right_tmp; + + left = &samples[0]; + right = &samples[512]; + center = &samples[256]; + right_sur = &samples[768]; + + for (i = 0; i < 256; i++) { + left_tmp = dm_par->unit * *left + dm_par->clev * *center - dm_par->slev * *right_sur; + right_tmp= dm_par->unit * *right++ + dm_par->clev * *center + dm_par->slev * *right_sur++; + *left++ = left_tmp; + *center++ = right_tmp; + } +} + + +void downmix_2f_1r_to_2ch_c (float *samples, dm_par_t *dm_par) +{ + int i; + float *left, *right, *right_sur; + float left_tmp, right_tmp; + + left = &samples[0]; + right = &samples[256]; + right_sur = &samples[512]; + + for (i = 0; i < 256; i++) { + left_tmp = dm_par->unit * *left - dm_par->slev * *right_sur; + right_tmp= dm_par->unit * *right + dm_par->slev * *right_sur++; + *left++ = left_tmp; + *right++ = right_tmp; + } +} + + +void downmix_3f_0r_to_2ch_c (float *samples, dm_par_t *dm_par) +{ + int i; + float *left, *right, *center; + float left_tmp, right_tmp; + + left = &samples[0]; + center = &samples[256]; + right = &samples[512]; + + for (i = 0; i < 256; i++) { + left_tmp = dm_par->unit * *left + dm_par->clev * *center; + right_tmp= dm_par->unit * *right++ + dm_par->clev * *center; + *left++ = left_tmp; + *center++ = right_tmp; + } +} + + +void stream_sample_2ch_to_s16_c (int16_t *s16_samples, float *left, float *right) +{ + int i; + + for (i=0; i < 256; i++) { + *s16_samples++ = (int16_t) *left++; + *s16_samples++ = (int16_t) *right++; + } +} + + +void stream_sample_1ch_to_s16_c (int16_t *s16_samples, float *center) +{ + int i; + float tmp; + + for (i=0; i < 256; i++) { + *s16_samples++ = tmp = (int16_t) (0.7071f * *center++); + *s16_samples++ = tmp; + } +} diff --git a/ac3dec/downmix_c.h b/ac3dec/downmix_c.h new file mode 100644 index 000000000..3643f65e8 --- /dev/null +++ b/ac3dec/downmix_c.h @@ -0,0 +1,32 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#ifndef __DOWNMIX_C_H__ +#define __DOWNMIX_C_H__ + +void downmix_3f_2r_to_2ch_c(float *samples, dm_par_t * dm_par); +void downmix_3f_1r_to_2ch_c(float *samples, dm_par_t * dm_par); +void downmix_2f_2r_to_2ch_c(float *samples, dm_par_t * dm_par); +void downmix_2f_1r_to_2ch_c(float *samples, dm_par_t * dm_par); +void downmix_3f_0r_to_2ch_c(float *samples, dm_par_t * dm_par); +void stream_sample_2ch_to_s16_c(int16_t *s16_samples, float *left, float *right); +void stream_sample_1ch_to_s16_c(int16_t *s16_samples, float *center); + +#endif diff --git a/ac3dec/downmix_i386.S b/ac3dec/downmix_i386.S new file mode 100644 index 000000000..20f2e8c37 --- /dev/null +++ b/ac3dec/downmix_i386.S @@ -0,0 +1,92 @@ +/* This is basicly gcc generated. + * Only the floating point rounding mode loads and saves + * are removed in the stream_sample_to_s16 functions. + */ + +#ifdef __i386__ + + .file "downmix.c" + .version "01.01" +gcc2_compiled.: +.text + .align 4 +.globl stream_sample_2ch_to_s16_i386 + .type stream_sample_2ch_to_s16_i386,@function +stream_sample_2ch_to_s16_i386: + pushl %ebp + movl %esp,%ebp + subl $28,%esp + pushl %edi + pushl %esi + pushl %ebx + movl 8(%ebp),%edx + movl 12(%ebp),%ebx + movl 16(%ebp),%ecx + movl $255,%esi + .p2align 4,,7 +.L373: + flds (%ebx) + fistpl -8(%ebp) + movl -8(%ebp),%eax + movw %ax,(%edx) + addl $2,%edx + addl $4,%ebx + flds (%ecx) + fistpl -8(%ebp) + movl -8(%ebp),%eax + movw %ax,(%edx) + addl $4,%ecx + addl $2,%edx + decl %esi + jns .L373 + popl %ebx + popl %esi + popl %edi + leave + ret +.Lfe6: + .size stream_sample_2ch_to_s16_i386,.Lfe6-stream_sample_2ch_to_s16_i386 +.section .rodata + .align 4 +.LC46: + .long 0x3f350481 +.text + .align 4 +.globl stream_sample_1ch_to_s16_i386 + .type stream_sample_1ch_to_s16_i386,@function +stream_sample_1ch_to_s16_i386: + pushl %ebp + movl %esp,%ebp + subl $16,%esp + pushl %esi + pushl %ebx + movl 8(%ebp),%edx + movl 12(%ebp),%ecx + flds .LC46 + movl $255,%ebx + .p2align 4,,7 +.L379: + flds (%ecx) + fmul %st(1),%st + fistpl -8(%ebp) + movl -8(%ebp),%eax + movw %ax,-2(%ebp) + addl $4,%ecx + flds -2(%ebp) + fistpl -8(%ebp) + movl -8(%ebp),%eax + movw %ax,(%edx) + addl $2,%edx + movw %ax,(%edx) + addl $2,%edx + decl %ebx + jns .L379 + fstp %st(0) + popl %ebx + popl %esi + leave + ret +.Lfe7: + .size stream_sample_1ch_to_s16_i386,.Lfe7-stream_sample_1ch_to_s16_i386 + .ident "GCC: (GNU) 2.95.3 19991030 (prerelease)" +#endif diff --git a/ac3dec/downmix_i386.h b/ac3dec/downmix_i386.h new file mode 100644 index 000000000..e34d7d6cf --- /dev/null +++ b/ac3dec/downmix_i386.h @@ -0,0 +1,27 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#ifndef __DOWNMIX_I386_H__ +#define __DOWNMIX_I386_H__ + +void stream_sample_2ch_to_s16_i386(int16_t *s16_samples, float *left, float *right); +void stream_sample_1ch_to_s16_i386(int16_t *s16_samples, float *center); + +#endif diff --git a/ac3dec/downmix_kni.S b/ac3dec/downmix_kni.S new file mode 100644 index 000000000..7df8c060f --- /dev/null +++ b/ac3dec/downmix_kni.S @@ -0,0 +1,396 @@ +/* + * downmix_kni.S + * + * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - October 2000 + * + * + * downmix_kni.S is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * downmix_kni.S is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef __i386__ + +.section .rodata + .align 4 +sqrt2: .float 0f0.7071068 + .p2align 5,0, + + .section .text + + .align 4 + .global downmix_3f_2r_to_2ch_kni + .type downmix_3f_2r_to_2ch_kni, @function + +downmix_3f_2r_to_2ch_kni: + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %ecx + + movl 8(%ebp), %eax /* samples[] */ + movl 12(%ebp), %ebx /* &dm_par */ + movl $64, %ecx /* loop counter */ + + movss (%ebx), %xmm5 /* unit */ + shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ + + movss 4(%ebx), %xmm6 /* clev */ + shufps $0, %xmm6, %xmm6 /* clev | clev | clev | clev */ + + movss 8(%ebx), %xmm7 /* slev */ + shufps $0, %xmm7, %xmm7 /* slev | slev | slev | slev */ + +.loop: + movaps (%eax), %xmm0 /* left */ + movaps 2048(%eax), %xmm1 /* right */ + movaps 1024(%eax), %xmm2 /* center */ + mulps %xmm5, %xmm0 + mulps %xmm5, %xmm1 + + mulps %xmm6, %xmm2 + movaps 3072(%eax), %xmm3 /* leftsur */ + movaps 4096(%eax), %xmm4 /* rithgsur */ + addps %xmm2, %xmm0 + addps %xmm2, %xmm1 + + mulps %xmm7, %xmm3 + mulps %xmm7, %xmm4 + addps %xmm3, %xmm0 + addps %xmm4, %xmm1 + + movaps %xmm0, (%eax) + movaps %xmm1, 1024(%eax) + + addl $16, %eax + decl %ecx + jnz .loop + + popl %ecx + popl %ebx + popl %eax + + leave + ret + .p2align 4,,7 + + .global downmix_2f_2r_to_2ch_kni + .type downmix_2f_2r_to_2ch_kni, @function + +downmix_2f_2r_to_2ch_kni: + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %ecx + + movl 8(%ebp), %eax /* samples[] */ + movl 12(%ebp), %ebx /* &dm_par */ + movl $64, %ecx /* loop counter */ + + movss (%ebx), %xmm5 /* unit */ + shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ + + movss 8(%ebx), %xmm7 /* slev */ + shufps $0, %xmm7, %xmm7 /* slev | slev | slev | slev */ + +.loop3: + movaps (%eax), %xmm0 /* left */ + movaps 1024(%eax), %xmm1 /* right */ + movaps 2048(%eax), %xmm3 /* leftsur */ + mulps %xmm5, %xmm0 + mulps %xmm5, %xmm1 + + movaps 3072(%eax), %xmm4 /* rightsur */ + + mulps %xmm7, %xmm3 + mulps %xmm7, %xmm4 + addps %xmm3, %xmm0 + addps %xmm4, %xmm1 + + movaps %xmm0, (%eax) + movaps %xmm1, 1024(%eax) + + addl $16, %eax + decl %ecx + jnz .loop3 + + popl %ecx + popl %ebx + popl %eax + + leave + ret + .p2align 4,,7 + + .global downmix_3f_1r_to_2ch_kni + .type downmix_3f_1r_to_2ch_kni, @function + +downmix_3f_1r_to_2ch_kni: + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %ecx + + movl 8(%ebp), %eax /* samples[] */ + movl 12(%ebp), %ebx /* &dm_par */ + movl $64, %ecx /* loop counter */ + + movss (%ebx), %xmm5 /* unit */ + shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ + + movss 4(%ebx), %xmm6 /* clev */ + shufps $0, %xmm6, %xmm6 /* clev | clev | clev | clev */ + + movss 8(%ebx), %xmm7 /* slev */ + shufps $0, %xmm7, %xmm7 /* slev | slev | slev | slev */ + +.loop4: + movaps (%eax), %xmm0 /* left */ + movaps 2048(%eax), %xmm1 /* right */ + movaps 1024(%eax), %xmm2 /* center */ + mulps %xmm5, %xmm0 + mulps %xmm5, %xmm1 + + mulps %xmm6, %xmm2 + movaps 3072(%eax), %xmm3 /* sur */ + + addps %xmm2, %xmm0 + mulps %xmm7, %xmm3 + + addps %xmm2, %xmm1 + + subps %xmm3, %xmm0 + addps %xmm3, %xmm1 + + movaps %xmm0, (%eax) + movaps %xmm1, 1024(%eax) + + addl $16, %eax + decl %ecx + jnz .loop4 + + popl %ecx + popl %ebx + popl %eax + + leave + ret + .p2align 4,,7 + + .global downmix_2f_1r_to_2ch_kni + .type downmix_2f_1r_to_2ch_kni, @function + +downmix_2f_1r_to_2ch_kni: + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %ecx + + movl 8(%ebp), %eax /* samples[] */ + movl 12(%ebp), %ebx /* &dm_par */ + movl $64, %ecx /* loop counter */ + + movss (%ebx), %xmm5 /* unit */ + shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ + + movss 8(%ebx), %xmm7 /* slev */ + shufps $0, %xmm7, %xmm7 /* slev | slev | slev | slev */ + +.loop5: + movaps (%eax), %xmm0 /* left */ + movaps 1024(%eax), %xmm1 /* right */ + + mulps %xmm5, %xmm0 + mulps %xmm5, %xmm1 + + movaps 2048(%eax), %xmm3 /* sur */ + + mulps %xmm7, %xmm3 + + subps %xmm3, %xmm0 + addps %xmm3, %xmm1 + + movaps %xmm0, (%eax) + movaps %xmm1, 1024(%eax) + + addl $16, %eax + decl %ecx + jnz .loop5 + + popl %ecx + popl %ebx + popl %eax + + leave + ret + .p2align 4,,7 + + .global downmix_3f_0r_to_2ch_kni + .type downmix_3f_0r_to_2ch_kni, @function + +downmix_3f_0r_to_2ch_kni: + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %ecx + + movl 8(%ebp), %eax /* samples[] */ + movl 12(%ebp), %ebx /* &dm_par */ + movl $64, %ecx /* loop counter */ + + movss (%ebx), %xmm5 /* unit */ + shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ + + movss 4(%ebx), %xmm6 /* clev */ + shufps $0, %xmm6, %xmm6 /* clev | clev | clev | clev */ + + +.loop6: + movaps (%eax), %xmm0 /* left */ + movaps 2048(%eax), %xmm1 /* right */ + movaps 1024(%eax), %xmm2 /* center */ + mulps %xmm5, %xmm0 + mulps %xmm5, %xmm1 + + mulps %xmm6, %xmm2 + + addps %xmm2, %xmm0 + + addps %xmm2, %xmm1 + + movaps %xmm0, (%eax) + movaps %xmm1, 1024(%eax) + + addl $16, %eax + decl %ecx + jnz .loop6 + + popl %ecx + popl %ebx + popl %eax + + leave + ret + .p2align 4,,7 + + .global stream_sample_2ch_to_s16_kni + .type stream_sample_2ch_to_s16_kni, @function + +stream_sample_2ch_to_s16_kni: + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %edx + pushl %ecx + + movl 8(%ebp), %eax /* s16_samples */ + movl 12(%ebp), %ebx /* left */ + movl 16(%ebp), %edx /* right */ + movl $64, %ecx + +.loop1: + movaps (%ebx), %xmm0 /* l3 | l2 | l1 | l0 */ + movaps (%edx), %xmm1 /* r3 | r2 | r1 | r0 */ + movhlps %xmm0, %xmm2 /* l3 | l2 */ + movhlps %xmm1, %xmm3 /* r3 | r2 */ + unpcklps %xmm1, %xmm0 /* r1 | l1 | r0 | l0 */ + unpcklps %xmm3, %xmm2 /* r3 | l3 | r2 | l2 */ + + cvtps2pi %xmm0, %mm0 /* r0 l0 --> mm0, int_32 */ + movhlps %xmm0, %xmm0 + cvtps2pi %xmm0, %mm1 /* r1 l1 --> mm1, int_32 */ + + cvtps2pi %xmm2, %mm2 /* r2 l2 --> mm2, int_32 */ + movhlps %xmm2, %xmm2 + cvtps2pi %xmm2, %mm3 /* r3 l3 --> mm3, int_32 */ + packssdw %mm1, %mm0 /* r1 l1 r0 l0 --> mm0, int_16 */ + packssdw %mm3, %mm2 /* r3 l3 r2 l2 --> mm2, int_16 */ + + movq %mm0, (%eax) + movq %mm2, 8(%eax) + addl $16, %eax + addl $16, %ebx + addl $16, %edx + + decl %ecx + jnz .loop1 + + popl %ecx + popl %edx + popl %ebx + popl %eax + + emms + + leave + ret + .p2align 4,,7 + + .global stream_sample_1ch_to_s16_kni + .type stream_sample_1ch_to_s16_kni, @function + +stream_sample_1ch_to_s16_kni: + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %ecx + + movl $sqrt2, %eax + movss (%eax), %xmm7 + movl 8(%ebp), %eax /* s16_samples */ + movl 12(%ebp), %ebx /* left */ + shufps $0, %xmm7, %xmm7 + movl $64, %ecx + +.loop2: + movaps (%ebx), %xmm0 /* c3 | c2 | c1 | c0 */ + mulps %xmm7, %xmm0 + movhlps %xmm0, %xmm2 /* c3 | c2 */ + + cvtps2pi %xmm0, %mm0 /* c1 c0 --> mm0, int_32 */ + cvtps2pi %xmm2, %mm1 /* c3 c2 --> mm1, int_32 */ + + packssdw %mm0, %mm0 /* c1 c1 c0 c0 --> mm0, int_16 */ + packssdw %mm1, %mm1 /* c3 c3 c2 c2 --> mm1, int_16 */ + + movq %mm0, (%eax) + movq %mm1, 8(%eax) + addl $16, %eax + addl $16, %ebx + + decl %ecx + jnz .loop2 + + popl %ecx + popl %ebx + popl %eax + + emms + leave + ret +#endif diff --git a/ac3dec/downmix_kni.h b/ac3dec/downmix_kni.h new file mode 100644 index 000000000..323f2a754 --- /dev/null +++ b/ac3dec/downmix_kni.h @@ -0,0 +1,32 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#ifndef __DOWNMIX_KNI_H__ +#define __DOWNMIX_KNI_H__ + +void downmix_3f_2r_to_2ch_kni(float *samples, dm_par_t * dm_par); +void downmix_3f_1r_to_2ch_kni(float *samples, dm_par_t * dm_par); +void downmix_2f_2r_to_2ch_kni(float *samples, dm_par_t * dm_par); +void downmix_2f_1r_to_2ch_kni(float *samples, dm_par_t * dm_par); +void downmix_3f_0r_to_2ch_kni(float *samples, dm_par_t * dm_par); +void stream_sample_2ch_to_s16_kni(int16_t *s16_samples, float *left, float *right); +void stream_sample_1ch_to_s16_kni(int16_t *s16_samples, float *center); + +#endif diff --git a/ac3dec/exponent.c b/ac3dec/exponent.c index 98111a5ba..16fca4652 100644 --- a/ac3dec/exponent.c +++ b/ac3dec/exponent.c @@ -28,41 +28,43 @@ #include "ac3_internal.h" -#include "decode.h" #include "exponent.h" -static void exp_unpack_ch(uint_16 type,uint_16 expstr,uint_16 ngrps,uint_16 initial_exp, - uint_16 exps[], uint_16 *dest); +static inline void exp_unpack_ch(uint16_t type,uint16_t expstr,uint16_t ngrps,uint16_t initial_exp, uint16_t exps[], uint16_t *dest); -void -exponent_unpack( bsi_t *bsi, audblk_t *audblk) + +/** + * + **/ + +void exponent_unpack( bsi_t *bsi, audblk_t *audblk) { - uint_16 i; + uint16_t i; for(i=0; i< bsi->nfchans; i++) - exp_unpack_ch(UNPACK_FBW, audblk->chexpstr[i], audblk->nchgrps[i], audblk->exps[i][0], - &audblk->exps[i][1], audblk->fbw_exp[i]); + exp_unpack_ch(UNPACK_FBW, audblk->chexpstr[i], audblk->nchgrps[i], audblk->exps[i][0], &audblk->exps[i][1], audblk->fbw_exp[i]); if(audblk->cplinu) - exp_unpack_ch(UNPACK_CPL, audblk->cplexpstr, audblk->ncplgrps, audblk->cplabsexp << 1, - audblk->cplexps, &audblk->cpl_exp[audblk->cplstrtmant]); + exp_unpack_ch(UNPACK_CPL, audblk->cplexpstr, audblk->ncplgrps, audblk->cplabsexp << 1, audblk->cplexps, &audblk->cpl_exp[audblk->cplstrtmant]); if(bsi->lfeon) - exp_unpack_ch(UNPACK_LFE, audblk->lfeexpstr, 2, audblk->lfeexps[0], - &audblk->lfeexps[1], audblk->lfe_exp); + exp_unpack_ch(UNPACK_LFE, audblk->lfeexpstr, 2, audblk->lfeexps[0], &audblk->lfeexps[1], audblk->lfe_exp); } -static void -exp_unpack_ch(uint_16 type,uint_16 expstr,uint_16 ngrps,uint_16 initial_exp, - uint_16 exps[], uint_16 *dest) +/** + * + **/ + +static inline void exp_unpack_ch(uint16_t type,uint16_t expstr,uint16_t ngrps,uint16_t initial_exp, + uint16_t exps[], uint16_t *dest) { - uint_16 i,j; - sint_16 exp_acc; - sint_16 exp_1,exp_2,exp_3; + uint16_t i,j; + int16_t exp_acc; + int16_t exp_1,exp_2,exp_3; - if(expstr == EXP_REUSE) + if (expstr == EXP_REUSE) return; /* Handle the initial absolute exponent */ @@ -75,8 +77,7 @@ exp_unpack_ch(uint_16 type,uint_16 expstr,uint_16 ngrps,uint_16 initial_exp, dest[j++] = exp_acc; /* Loop through the groups and fill the dest array appropriately */ - for(i=0; i< ngrps; i++) - { + for(i=0; i< ngrps; i++) { if(exps[i] > 124) goto error; @@ -86,8 +87,7 @@ exp_unpack_ch(uint_16 type,uint_16 expstr,uint_16 ngrps,uint_16 initial_exp, exp_acc += (exp_1 - 2); - switch(expstr) - { + switch(expstr) { case EXP_D45: dest[j++] = exp_acc; dest[j++] = exp_acc; @@ -99,8 +99,7 @@ exp_unpack_ch(uint_16 type,uint_16 expstr,uint_16 ngrps,uint_16 initial_exp, exp_acc += (exp_2 - 2); - switch(expstr) - { + switch(expstr) { case EXP_D45: dest[j++] = exp_acc; dest[j++] = exp_acc; @@ -112,8 +111,7 @@ exp_unpack_ch(uint_16 type,uint_16 expstr,uint_16 ngrps,uint_16 initial_exp, exp_acc += (exp_3 - 2); - switch(expstr) - { + switch(expstr) { case EXP_D45: dest[j++] = exp_acc; dest[j++] = exp_acc; @@ -125,11 +123,10 @@ exp_unpack_ch(uint_16 type,uint_16 expstr,uint_16 ngrps,uint_16 initial_exp, } return; - - goto error; error: - if(!error_flag) - fprintf(stderr,"** Invalid exponent - skipping frame **\n"); - error_flag = 1; +#ifdef DEBUG + fprintf (stderr,"** Invalid exponent - skipping frame **\n"); +#endif + HANDLE_ERROR (); } diff --git a/ac3dec/imdct.c b/ac3dec/imdct.c index ae2794ed7..c09ef4138 100644 --- a/ac3dec/imdct.c +++ b/ac3dec/imdct.c @@ -28,75 +28,48 @@ #include "ac3.h" #include "ac3_internal.h" - -#include "decode.h" +#include "downmix.h" #include "imdct.h" +#include "imdct_c.h" +#ifdef HAVE_KNI +#include "imdct_kni.h" +#endif +#include "srfft.h" -void imdct_do_256(float data[],float delay[]); -void imdct_do_512(float data[],float delay[]); -typedef struct complex_s -{ - float real; - float imag; -} complex_t; +extern void (*downmix_3f_2r_to_2ch)(float *samples, dm_par_t * dm_par); +extern void (*downmix_3f_1r_to_2ch)(float *samples, dm_par_t * dm_par); +extern void (*downmix_2f_2r_to_2ch)(float *samples, dm_par_t * dm_par); +extern void (*downmix_2f_1r_to_2ch)(float *samples, dm_par_t * dm_par); +extern void (*downmix_3f_0r_to_2ch)(float *samples, dm_par_t * dm_par); + +extern void (*stream_sample_2ch_to_s16)(int16_t *s16_samples, float *left, float *right); +extern void (*stream_sample_1ch_to_s16)(int16_t *s16_samples, float *center); + +void (*fft_64p) (complex_t *); +void (*imdct_do_512) (float data[],float delay[]); +void (*imdct_do_512_nol) (float data[], float delay[]); + +void imdct_do_256 (float data[],float delay[]); #define N 512 +/* static complex_t buf[128]; */ +//static complex_t buf[128] __attribute__((aligned(16))); +complex_t buf[128] __attribute__((aligned(16))); -/* 128 point bit-reverse LUT */ -static uint_8 bit_reverse_512[128] = { - 0x00, 0x40, 0x20, 0x60, 0x10, 0x50, 0x30, 0x70, - 0x08, 0x48, 0x28, 0x68, 0x18, 0x58, 0x38, 0x78, - 0x04, 0x44, 0x24, 0x64, 0x14, 0x54, 0x34, 0x74, - 0x0c, 0x4c, 0x2c, 0x6c, 0x1c, 0x5c, 0x3c, 0x7c, - 0x02, 0x42, 0x22, 0x62, 0x12, 0x52, 0x32, 0x72, - 0x0a, 0x4a, 0x2a, 0x6a, 0x1a, 0x5a, 0x3a, 0x7a, - 0x06, 0x46, 0x26, 0x66, 0x16, 0x56, 0x36, 0x76, - 0x0e, 0x4e, 0x2e, 0x6e, 0x1e, 0x5e, 0x3e, 0x7e, - 0x01, 0x41, 0x21, 0x61, 0x11, 0x51, 0x31, 0x71, - 0x09, 0x49, 0x29, 0x69, 0x19, 0x59, 0x39, 0x79, - 0x05, 0x45, 0x25, 0x65, 0x15, 0x55, 0x35, 0x75, - 0x0d, 0x4d, 0x2d, 0x6d, 0x1d, 0x5d, 0x3d, 0x7d, - 0x03, 0x43, 0x23, 0x63, 0x13, 0x53, 0x33, 0x73, - 0x0b, 0x4b, 0x2b, 0x6b, 0x1b, 0x5b, 0x3b, 0x7b, - 0x07, 0x47, 0x27, 0x67, 0x17, 0x57, 0x37, 0x77, - 0x0f, 0x4f, 0x2f, 0x6f, 0x1f, 0x5f, 0x3f, 0x7f}; - -static uint_8 bit_reverse_256[64] = { - 0x00, 0x20, 0x10, 0x30, 0x08, 0x28, 0x18, 0x38, - 0x04, 0x24, 0x14, 0x34, 0x0c, 0x2c, 0x1c, 0x3c, - 0x02, 0x22, 0x12, 0x32, 0x0a, 0x2a, 0x1a, 0x3a, - 0x06, 0x26, 0x16, 0x36, 0x0e, 0x2e, 0x1e, 0x3e, - 0x01, 0x21, 0x11, 0x31, 0x09, 0x29, 0x19, 0x39, - 0x05, 0x25, 0x15, 0x35, 0x0d, 0x2d, 0x1d, 0x3d, - 0x03, 0x23, 0x13, 0x33, 0x0b, 0x2b, 0x1b, 0x3b, - 0x07, 0x27, 0x17, 0x37, 0x0f, 0x2f, 0x1f, 0x3f}; - -static complex_t buf[128]; - -/* Twiddle factor LUT */ -static complex_t *w[7]; -static complex_t w_1[1]; -static complex_t w_2[2]; -static complex_t w_4[4]; -static complex_t w_8[8]; -static complex_t w_16[16]; -static complex_t w_32[32]; -static complex_t w_64[64]; +/* Delay buffer for time domain interleaving */ +static float delay[6][256]; +static float delay1[6][256]; /* Twiddle factors for IMDCT */ -static float xcos1[128]; -static float xsin1[128]; static float xcos2[64]; static float xsin2[64]; -/* Delay buffer for time domain interleaving */ -static float delay[6][256]; - /* Windowing function for Modified DCT - Thank you acroread */ -static float window[] = { +//static float window[] = { +float window[] = { 0.00014, 0.00024, 0.00037, 0.00051, 0.00067, 0.00086, 0.00107, 0.00130, 0.00157, 0.00187, 0.00220, 0.00256, 0.00297, 0.00341, 0.00390, 0.00443, 0.00501, 0.00564, 0.00632, 0.00706, 0.00785, 0.00871, 0.00962, 0.01061, @@ -128,146 +101,116 @@ static float window[] = { 0.99978, 0.99981, 0.99984, 0.99986, 0.99988, 0.99990, 0.99992, 0.99993, 0.99994, 0.99995, 0.99996, 0.99997, 0.99998, 0.99998, 0.99998, 0.99999, 0.99999, 0.99999, 0.99999, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, - 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000 }; - + 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000 +}; -static inline void swap_cmplx(complex_t *a, complex_t *b) +//static const int pm128[128] = +const int pm128[128] = { - complex_t tmp; - - tmp = *a; - *a = *b; - *b = tmp; -} - - - -static inline complex_t cmplx_mult(complex_t a, complex_t b) + 0, 16, 32, 48, 64, 80, 96, 112, 8, 40, 72, 104, 24, 56, 88, 120, + 4, 20, 36, 52, 68, 84, 100, 116, 12, 28, 44, 60, 76, 92, 108, 124, + 2, 18, 34, 50, 66, 82, 98, 114, 10, 42, 74, 106, 26, 58, 90, 122, + 6, 22, 38, 54, 70, 86, 102, 118, 14, 46, 78, 110, 30, 62, 94, 126, + 1, 17, 33, 49, 65, 81, 97, 113, 9, 41, 73, 105, 25, 57, 89, 121, + 5, 21, 37, 53, 69, 85, 101, 117, 13, 29, 45, 61, 77, 93, 109, 125, + 3, 19, 35, 51, 67, 83, 99, 115, 11, 43, 75, 107, 27, 59, 91, 123, + 7, 23, 39, 55, 71, 87, 103, 119, 15, 31, 47, 63, 79, 95, 111, 127 +}; + +static const int pm64[64] = { - complex_t ret; - - ret.real = a.real * b.real - a.imag * b.imag; - ret.imag = a.real * b.imag + a.imag * b.real; - - return ret; -} - -void imdct_init(void) -{ - int i,k; - complex_t angle_step; - complex_t current_angle; - - /* Twiddle factors to turn IFFT into IMDCT */ - for( i=0; i < 128; i++) - { - xcos1[i] = -cos(2.0f * M_PI * (8*i+1)/(8*N)) ; - xsin1[i] = -sin(2.0f * M_PI * (8*i+1)/(8*N)) ; - } - - /* More twiddle factors to turn IFFT into IMDCT */ - for( i=0; i < 64; i++) - { - xcos2[i] = -cos(2.0f * M_PI * (8*i+1)/(4*N)) ; - xsin2[i] = -sin(2.0f * M_PI * (8*i+1)/(4*N)) ; - } - - /* Canonical twiddle factors for FFT */ - w[0] = w_1; - w[1] = w_2; - w[2] = w_4; - w[3] = w_8; - w[4] = w_16; - w[5] = w_32; - w[6] = w_64; - - for( i = 0; i < 7; i++) - { - angle_step.real = cos(-2.0 * M_PI / (1 << (i+1))); - angle_step.imag = sin(-2.0 * M_PI / (1 << (i+1))); - - current_angle.real = 1.0; - current_angle.imag = 0.0; - - for (k = 0; k < 1 << i; k++) - { - w[i][k] = current_angle; - current_angle = cmplx_mult(current_angle,angle_step); - } + 0, 8, 16, 24, 32, 40, 48, 56, + 4, 20, 36, 52, 12, 28, 44, 60, + 2, 10, 18, 26, 34, 42, 50, 58, + 6, 14, 22, 30, 38, 46, 54, 62, + 1, 9, 17, 25, 33, 41, 49, 57, + 5, 21, 37, 53, 13, 29, 45, 61, + 3, 11, 19, 27, 35, 43, 51, 59, + 7, 23, 39, 55, 15, 31, 47, 63 +}; + + +void imdct_init (void) + { + int i; + float scale = 255.99609372; + +#ifdef __i386__ +#ifdef HAVE_KNI + if (!imdct_init_kni ()); + else +#endif +#endif + if (!imdct_init_c ()); + + // More twiddle factors to turn IFFT into IMDCT */ + for (i=0; i < 64; i++) { + xcos2[i] = cos(2.0f * M_PI * (8*i+1)/(4*N)) * scale; + xsin2[i] = sin(2.0f * M_PI * (8*i+1)/(4*N)) * scale; } } -void -imdct_do_512(float data[],float delay[]) + +void imdct_do_256 (float data[],float delay[]) { - int i,k; - int p,q; - int m; - int two_m; - int two_m_plus_one; + int i, j, k; + int p, q; float tmp_a_i; float tmp_a_r; - float tmp_b_i; - float tmp_b_r; float *data_ptr; float *delay_ptr; float *window_ptr; - - // - // 512 IMDCT with source and dest data in 'data' - // - - // Pre IFFT complex multiply plus IFFT cmplx conjugate and bit reverse - // permutation - for( i=0; i < 128; i++) - { - k = bit_reverse_512[i]; - - /* z[i] = (X[256-2*i-1] + j * X[2*i]) * (xcos1[i] + j * xsin1[i]) ; */ - buf[k].real = (data[256-2*i-1] * xcos1[i]) - (data[2*i] * xsin1[i]); - buf[k].imag = -1.0 * ((data[2*i] * xcos1[i]) + (data[256-2*i-1] * xsin1[i])); - } - // FFT Merge - for (m=0; m < 7; m++) - { - if(m) - two_m = (1 << m); - else - two_m = 1; - - two_m_plus_one = (1 << (m+1)); - - for(k = 0; k < two_m; k++) - { - for(i = 0; i < 128; i += two_m_plus_one) - { - p = k + i; - q = p + two_m; - tmp_a_r = buf[p].real; - tmp_a_i = buf[p].imag; - tmp_b_r = buf[q].real * w[m][k].real - buf[q].imag * w[m][k].imag; - tmp_b_i = buf[q].imag * w[m][k].real + buf[q].real * w[m][k].imag; - buf[p].real = tmp_a_r + tmp_b_r; - buf[p].imag = tmp_a_i + tmp_b_i; - buf[q].real = tmp_a_r - tmp_b_r; - buf[q].imag = tmp_a_i - tmp_b_i; + complex_t *buf1, *buf2; - } - } + buf1 = &buf[0]; + buf2 = &buf[64]; + +// Pre IFFT complex multiply plus IFFT complex conjugate + for (k=0; k<64; k++) { + /* X1[k] = X[2*k] */ + /* X2[k] = X[2*k+1] */ + + j = pm64[k]; + p = 2 * (128-2*j-1); + q = 2 * (2 * j); + + /* Z1[k] = (X1[128-2*k-1] + j * X1[2*k]) * (xcos2[k] + j * xsin2[k]); */ + buf1[k].re = data[p] * xcos2[j] - data[q] * xsin2[j]; + buf1[k].im = -1.0f * (data[q] * xcos2[j] + data[p] * xsin2[j]); + /* Z2[k] = (X2[128-2*k-1] + j * X2[2*k]) * (xcos2[k] + j * xsin2[k]); */ + buf2[k].re = data[p + 1] * xcos2[j] - data[q + 1] * xsin2[j]; + buf2[k].im = -1.0f * ( data[q + 1] * xcos2[j] + data[p + 1] * xsin2[j]); } - /* Post IFFT complex multiply plus IFFT complex conjugate*/ - for( i=0; i < 128; i++) - { - /* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; */ - tmp_a_r = buf[i].real; - tmp_a_i = buf[i].imag; - //Note that I flipped the signs on the imaginary ops to do the complex conj - buf[i].real =(tmp_a_r * xcos1[i]) + (tmp_a_i * xsin1[i]); - buf[i].imag =(tmp_a_r * xsin1[i]) - (tmp_a_i * xcos1[i]); + fft_64p(&buf1[0]); + fft_64p(&buf2[0]); + +#ifdef DEBUG + //DEBUG FFT +#if 0 + printf ("Post FFT, buf1\n"); + for (i=0; i < 64; i++) + printf("%d %f %f\n", i, buf_1[i].re, buf_1[i].im); + printf ("Post FFT, buf2\n"); + for (i=0; i < 64; i++) + printf("%d %f %f\n", i, buf_2[i].re, buf_2[i].im); +#endif +#endif + + + // Post IFFT complex multiply + for( i=0; i < 64; i++) { + tmp_a_r = buf1[i].re; + tmp_a_i = -buf1[i].im; + buf1[i].re =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); + buf1[i].im =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); + tmp_a_r = buf2[i].re; + tmp_a_i = -buf2[i].im; + buf2[i].re =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); + buf2[i].im =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); } data_ptr = data; @@ -275,164 +218,122 @@ imdct_do_512(float data[],float delay[]) window_ptr = window; /* Window and convert to real valued signal */ - for(i=0; i< 64; i++) - { - *data_ptr++ = 2.0f * (-buf[64+i].imag * *window_ptr++ + *delay_ptr++); - *data_ptr++ = 2.0f * ( buf[64-i-1].real * *window_ptr++ + *delay_ptr++); + for(i=0; i< 64; i++) { + *data_ptr++ = -buf1[i].im * *window_ptr++ + *delay_ptr++; + *data_ptr++ = buf1[64-i-1].re * *window_ptr++ + *delay_ptr++; } - for(i=0; i< 64; i++) - { - *data_ptr++ = 2.0f * (-buf[i].real * *window_ptr++ + *delay_ptr++); - *data_ptr++ = 2.0f * ( buf[128-i-1].imag * *window_ptr++ + *delay_ptr++); + for(i=0; i< 64; i++) { + *data_ptr++ = -buf1[i].re * *window_ptr++ + *delay_ptr++; + *data_ptr++ = buf1[64-i-1].im * *window_ptr++ + *delay_ptr++; } - /* The trailing edge of the window goes into the delay line */ delay_ptr = delay; - for(i=0; i< 64; i++) - { - *delay_ptr++ = -buf[64+i].real * *--window_ptr; - *delay_ptr++ = buf[64-i-1].imag * *--window_ptr; + for(i=0; i< 64; i++) { + *delay_ptr++ = -buf2[i].re * *--window_ptr; + *delay_ptr++ = buf2[64-i-1].im * *--window_ptr; } - for(i=0; i<64; i++) - { - *delay_ptr++ = buf[i].imag * *--window_ptr; - *delay_ptr++ = -buf[128-i-1].real * *--window_ptr; + for(i=0; i< 64; i++) { + *delay_ptr++ = buf2[i].im * *--window_ptr; + *delay_ptr++ = -buf2[64-i-1].re * *--window_ptr; } } -void -imdct_do_256(float data[],float delay[]) + +/** + * + **/ + +void imdct_do_256_nol (float data[], float delay[]) { - int i,k; - int p,q; - int m; - int two_m; - int two_m_plus_one; + int i, j, k; + int p, q; float tmp_a_i; float tmp_a_r; - float tmp_b_i; - float tmp_b_r; float *data_ptr; float *delay_ptr; float *window_ptr; - complex_t *buf_1, *buf_2; - - buf_1 = &buf[0]; - buf_2 = &buf[64]; - - // Pre IFFT complex multiply plus IFFT cmplx conjugate and bit reverse - // permutation - for(i=0; i<64; i++) - { - /* X1[i] = X[2*i] */ - /* X2[i] = X[2*i+1] */ - - k = bit_reverse_256[i]; - - p = 2 * (128-2*i-1); - q = 2 * (2 * i); - - /* Z1[i] = (X1[128-2*i-1] + j * X1[2*i]) * (xcos2[i] + j * xsin2[i]); */ - buf_1[k].real = data[p] * xcos2[i] - data[q] * xsin2[i]; - buf_1[k].imag = -1.0f * (data[q] * xcos2[i] + data[p] * xsin2[i]); - /* Z2[i] = (X2[128-2*i-1] + j * X2[2*i]) * (xcos2[i] + j * xsin2[i]); */ - buf_2[k].real = data[p + 1] * xcos2[i] - data[q + 1] * xsin2[i]; - buf_2[k].imag = -1.0f * ( data[q + 1] * xcos2[i] + data[p + 1] * xsin2[i]); - } - - // FFT Merge - for (m=0; m < 6; m++) - { - two_m = (1 << m); - two_m_plus_one = (1 << (m+1)); - - if(m) - two_m = (1 << m); - else - two_m = 1; - - for(k = 0; k < two_m; k++) - { - for(i = 0; i < 64; i += two_m_plus_one) - { - p = k + i; - q = p + two_m; - //Do block 1 - tmp_a_r = buf_1[p].real; - tmp_a_i = buf_1[p].imag; - tmp_b_r = buf_1[q].real * w[m][k].real - buf_1[q].imag * w[m][k].imag; - tmp_b_i = buf_1[q].imag * w[m][k].real + buf_1[q].real * w[m][k].imag; - buf_1[p].real = tmp_a_r + tmp_b_r; - buf_1[p].imag = tmp_a_i + tmp_b_i; - buf_1[q].real = tmp_a_r - tmp_b_r; - buf_1[q].imag = tmp_a_i - tmp_b_i; - - //Do block 2 - tmp_a_r = buf_2[p].real; - tmp_a_i = buf_2[p].imag; - tmp_b_r = buf_2[q].real * w[m][k].real - buf_2[q].imag * w[m][k].imag; - tmp_b_i = buf_2[q].imag * w[m][k].real + buf_2[q].real * w[m][k].imag; - buf_2[p].real = tmp_a_r + tmp_b_r; - buf_2[p].imag = tmp_a_i + tmp_b_i; - buf_2[q].real = tmp_a_r - tmp_b_r; - buf_2[q].imag = tmp_a_i - tmp_b_i; - - } - } - } - - // Post IFFT complex multiply - for( i=0; i < 64; i++) - { - //Note that I flipped the signs on the imaginary ops to do the complex conj - - /* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */ - tmp_a_r = buf_1[i].real; - tmp_a_i = buf_1[i].imag; - buf_1[i].real =(tmp_a_r * xcos2[i]) + (tmp_a_i * xsin2[i]); - buf_1[i].imag =(tmp_a_r * xsin2[i]) - (tmp_a_i * xcos2[i]); - /* y2[n] = z2[n] * (xcos2[n] + j * xsin2[n]) ; */ - tmp_a_r = buf_2[i].real; - tmp_a_i = buf_2[i].imag; - buf_2[i].real =(tmp_a_r * xcos2[i]) + (tmp_a_i * xsin2[i]); - buf_2[i].imag =(tmp_a_r * xsin2[i]) - (tmp_a_i * xcos2[i]); - } - - data_ptr = data; - delay_ptr = delay; - window_ptr = window; - - /* Window and convert to real valued signal */ - for(i=0; i< 64; i++) - { - *data_ptr++ = 2.0f * (-buf_1[i].imag * *window_ptr++ + *delay_ptr++); - *data_ptr++ = 2.0f * ( buf_1[64-i-1].real * *window_ptr++ + *delay_ptr++); - } - - for(i=0; i< 64; i++) - { - *data_ptr++ = 2.0f * (-buf_1[i].real * *window_ptr++ + *delay_ptr++); - *data_ptr++ = 2.0f * ( buf_1[64-i-1].imag * *window_ptr++ + *delay_ptr++); - } - - delay_ptr = delay; - - for(i=0; i< 64; i++) - { - *delay_ptr++ = -buf_2[i].real * *--window_ptr; - *delay_ptr++ = buf_2[64-i-1].imag * *--window_ptr; - } - - for(i=0; i< 64; i++) - { - *delay_ptr++ = buf_2[i].imag * *--window_ptr; - *delay_ptr++ = -buf_2[64-i-1].real * *--window_ptr; + complex_t *buf1, *buf2; + + buf1 = &buf[0]; + buf2 = &buf[64]; + + /* Pre IFFT complex multiply plus IFFT cmplx conjugate */ + for(k=0; k<64; k++) { + /* X1[k] = X[2*k] */ + /* X2[k] = X[2*k+1] */ + j = pm64[k]; + p = 2 * (128-2*j-1); + q = 2 * (2 * j); + + /* Z1[k] = (X1[128-2*k-1] + j * X1[2*k]) * (xcos2[k] + j * xsin2[k]); */ + buf1[k].re = data[p] * xcos2[j] - data[q] * xsin2[j]; + buf1[k].im = -1.0f * (data[q] * xcos2[j] + data[p] * xsin2[j]); + /* Z2[k] = (X2[128-2*k-1] + j * X2[2*k]) * (xcos2[k] + j * xsin2[k]); */ + buf2[k].re = data[p + 1] * xcos2[j] - data[q + 1] * xsin2[j]; + buf2[k].im = -1.0f * ( data[q + 1] * xcos2[j] + data[p + 1] * xsin2[j]); + } + + + fft_64p(&buf1[0]); + fft_64p(&buf2[0]); + +#ifdef DEBUG + //DEBUG FFT +#if 0 + printf("Post FFT, buf1\n"); + for (i=0; i < 64; i++) + printf("%d %f %f\n", i, buf_1[i].re, buf_1[i].im); + printf("Post FFT, buf2\n"); + for (i=0; i < 64; i++) + printf("%d %f %f\n", i, buf_2[i].re, buf_2[i].im); +#endif +#endif + + /* Post IFFT complex multiply */ + for( i=0; i < 64; i++) { + /* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */ + tmp_a_r = buf1[i].re; + tmp_a_i = -buf1[i].im; + buf1[i].re =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); + buf1[i].im =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); + /* y2[n] = z2[n] * (xcos2[n] + j * xsin2[n]) ; */ + tmp_a_r = buf2[i].re; + tmp_a_i = -buf2[i].im; + buf2[i].re =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); + buf2[i].im =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); + } + + data_ptr = data; + delay_ptr = delay; + window_ptr = window; + + /* Window and convert to real valued signal, no overlap */ + for(i=0; i< 64; i++) { + *data_ptr++ = -buf1[i].im * *window_ptr++; + *data_ptr++ = buf1[64-i-1].re * *window_ptr++; + } + + for(i=0; i< 64; i++) { + *data_ptr++ = -buf1[i].re * *window_ptr++ + *delay_ptr++; + *data_ptr++ = buf1[64-i-1].im * *window_ptr++ + *delay_ptr++; + } + + delay_ptr = delay; + + for(i=0; i< 64; i++) { + *delay_ptr++ = -buf2[i].re * *--window_ptr; + *delay_ptr++ = buf2[64-i-1].im * *--window_ptr; + } + + for(i=0; i< 64; i++) { + *delay_ptr++ = buf2[i].im * *--window_ptr; + *delay_ptr++ = -buf2[64-i-1].re * *--window_ptr; } } @@ -440,29 +341,190 @@ imdct_do_256(float data[],float delay[]) ///#include <sys/time.h> //FIXME remove -void -imdct(bsi_t *bsi,audblk_t *audblk, stream_samples_t samples) { +void imdct (bsi_t *bsi,audblk_t *audblk, stream_samples_t samples, int16_t *s16_samples, dm_par_t* dm_par) +{ int i; + int doable = 0; + float *center=NULL, *left, *right, *left_sur, *right_sur; + float *delay_left, *delay_right; + float *delay1_left, *delay1_right, *delay1_center, *delay1_sr, *delay1_sl; + float right_tmp, left_tmp; + void (*do_imdct)(float data[], float deley[]); + + // test if dm in frequency is doable + if (!(doable = audblk->blksw[0])) + do_imdct = imdct_do_512; + else + do_imdct = imdct_do_256; + + // downmix in the frequency domain if all the channels + // use the same imdct + for (i=0; i < bsi->nfchans; i++) { + if (doable != audblk->blksw[i]) { + do_imdct = NULL; + break; + } + } - //handy timing code - //struct timeval start,end; + if (do_imdct) { + //dowmix first and imdct + switch(bsi->acmod) { + case 7: // 3/2 + downmix_3f_2r_to_2ch (samples[0], dm_par); + break; + case 6: // 2/2 + downmix_2f_2r_to_2ch (samples[0], dm_par); + break; + case 5: // 3/1 + downmix_3f_1r_to_2ch (samples[0], dm_par); + break; + case 4: // 2/1 + downmix_2f_1r_to_2ch (samples[0], dm_par); + break; + case 3: // 3/0 + downmix_3f_0r_to_2ch (samples[0], dm_par); + break; + case 2: + break; + default: // 1/0 + if (bsi->acmod == 1) + center = samples[0]; + else if (bsi->acmod == 0) + center = samples[ac3_config.dual_mono_ch_sel]; + do_imdct(center, delay[0]); // no downmix + + stream_sample_1ch_to_s16 (s16_samples, center); + + return; + //goto done; + break; + } - //gettimeofday(&start,0); - - for(i=0; i<bsi->nfchans;i++) - { - if(audblk->blksw[i]) - imdct_do_256(samples[i],delay[i]); - else - imdct_do_512(samples[i],delay[i]); + do_imdct (samples[0], delay[0]); + do_imdct (samples[1], delay[1]); + stream_sample_2ch_to_s16(s16_samples, samples[0], samples[1]); + + } else { //imdct and then dowmix + // delay and samples should be saved and mixed + //fprintf(stderr, "time domain downmix\n"); + for (i=0; i<bsi->nfchans; i++) { + if (audblk->blksw[i]) + imdct_do_256_nol (samples[i],delay1[i]); + else + imdct_do_512_nol (samples[i],delay1[i]); + } + + // mix the sample, overlap + switch(bsi->acmod) { + case 7: // 3/2 + left = samples[0]; + center = samples[1]; + right = samples[2]; + left_sur = samples[3]; + right_sur = samples[4]; + delay_left = delay[0]; + delay_right = delay[1]; + delay1_left = delay1[0]; + delay1_center = delay1[1]; + delay1_right = delay1[2]; + delay1_sl = delay1[3]; + delay1_sr = delay1[4]; + + for (i = 0; i < 256; i++) { + left_tmp = dm_par->unit * *left++ + dm_par->clev * *center + dm_par->slev * *left_sur++; + right_tmp= dm_par->unit * *right++ + dm_par->clev * *center++ + dm_par->slev * *right_sur++; + *s16_samples++ = (int16_t)(left_tmp + *delay_left); + *s16_samples++ = (int16_t)(right_tmp + *delay_right); + *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->clev * *delay1_center + dm_par->slev * *delay1_sl++; + *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *center++ + dm_par->slev * *delay1_sr++; + } + break; + case 6: // 2/2 + left = samples[0]; + right = samples[1]; + left_sur = samples[2]; + right_sur = samples[3]; + delay_left = delay[0]; + delay_right = delay[1]; + delay1_left = delay1[0]; + delay1_right = delay1[1]; + delay1_sl = delay1[2]; + delay1_sr = delay1[3]; + + for (i = 0; i < 256; i++) { + left_tmp = dm_par->unit * *left++ + dm_par->slev * *left_sur++; + right_tmp= dm_par->unit * *right++ + dm_par->slev * *right_sur++; + *s16_samples++ = (int16_t)(left_tmp + *delay_left); + *s16_samples++ = (int16_t)(right_tmp + *delay_right); + *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->slev * *delay1_sl++; + *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->slev * *delay1_sr++; + } + break; + case 5: // 3/1 + left = samples[0]; + center = samples[1]; + right = samples[2]; + right_sur = samples[3]; + delay_left = delay[0]; + delay_right = delay[1]; + delay1_left = delay1[0]; + delay1_center = delay1[1]; + delay1_right = delay1[2]; + delay1_sl = delay1[3]; + + for (i = 0; i < 256; i++) { + left_tmp = dm_par->unit * *left++ + dm_par->clev * *center - dm_par->slev * *right_sur; + right_tmp= dm_par->unit * *right++ + dm_par->clev * *center++ + dm_par->slev * *right_sur++; + *s16_samples++ = (int16_t)(left_tmp + *delay_left); + *s16_samples++ = (int16_t)(right_tmp + *delay_right); + *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->clev * *delay1_center + dm_par->slev * *delay1_sl; + *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *center++ + dm_par->slev * *delay1_sl++; + } + break; + case 4: // 2/1 + left = samples[0]; + right = samples[1]; + right_sur = samples[2]; + delay_left = delay[0]; + delay_right = delay[1]; + delay1_left = delay1[0]; + delay1_right = delay1[1]; + delay1_sl = delay1[2]; + + for (i = 0; i < 256; i++) { + left_tmp = dm_par->unit * *left++ - dm_par->slev * *right_sur; + right_tmp= dm_par->unit * *right++ + dm_par->slev * *right_sur++; + *s16_samples++ = (int16_t)(left_tmp + *delay_left); + *s16_samples++ = (int16_t)(right_tmp + *delay_right); + *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->slev * *delay1_sl; + *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->slev * *delay1_sl++; + } + break; + case 3: // 3/0 + left = samples[0]; + center = samples[1]; + right = samples[2]; + delay_left = delay[0]; + delay_right = delay[1]; + delay1_left = delay1[0]; + delay1_center = delay1[1]; + delay1_right = delay1[2]; + + for (i = 0; i < 256; i++) { + left_tmp = dm_par->unit * *left++ + dm_par->clev * *center; + right_tmp= dm_par->unit * *right++ + dm_par->clev * *center++; + *s16_samples++ = (int16_t)(left_tmp + *delay_left); + *s16_samples++ = (int16_t)(right_tmp + *delay_right); + *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->clev * *delay1_center; + *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *center++; + } + break; + case 2: // copy to output + for (i = 0; i < 256; i++) { + *s16_samples++ = (int16_t)samples[0][i]; + *s16_samples++ = (int16_t)samples[1][i]; + } + break; + } } - //gettimeofday(&end,0); - //printf("imdct %ld us\n",(end.tv_sec - start.tv_sec) * 1000000 + - //end.tv_usec - start.tv_usec); - - //XXX We don't bother with the IMDCT for the LFE as it's currently - //unused. - //if (bsi->lfeon) - // imdct_do_512(coeffs->lfe,samples->channel[5],delay[5]); - // } diff --git a/ac3dec/imdct.h b/ac3dec/imdct.h index 750aa8798..8f10af00b 100644 --- a/ac3dec/imdct.h +++ b/ac3dec/imdct.h @@ -22,5 +22,5 @@ * */ -void imdct(bsi_t *bsi,audblk_t *audblk, stream_samples_t samples); +void imdct (bsi_t *bsi,audblk_t *audblk, stream_samples_t samples, int16_t *s16_samples, dm_par_t *dm_par); void imdct_init(void); diff --git a/ac3dec/imdct512_kni.S b/ac3dec/imdct512_kni.S new file mode 100644 index 000000000..10b8de6fe --- /dev/null +++ b/ac3dec/imdct512_kni.S @@ -0,0 +1,548 @@ +/* + * imdct512_kni.S + * + * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - October 2000 + * + * + * imdct512_kni.S is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * imdct512_kni.S is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef __i386__ + +.text + .align 4 +.global imdct512_pre_ifft_twiddle_kni + .type imdct512_pre_ifft_twiddle_kni, @function +imdct512_pre_ifft_twiddle_kni: + + pushl %ebp + movl %esp, %ebp + addl $-4, %esp /* local variable, loop counter */ + + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + + movl 8(%ebp), %eax /* pmt */ + movl 12(%ebp), %ebx /* buf */ + movl 16(%ebp), %ecx /* data */ + movl 20(%ebp), %edx /* xcos_sin_sse */ + movl $64, -4(%ebp) + + +.loop: + movl (%eax), %esi + movl 4(%eax), %edi + movss (%ecx, %esi, 8), %xmm1 /* 2j */ + movss (%ecx, %edi, 8), %xmm3 /* 2(j+1) */ + + shll $1, %esi + shll $1, %edi + + movaps (%edx, %esi, 8), %xmm0; /* -c_j | -s_j | -s_j | c_j */ + movaps (%edx, %edi, 8), %xmm2; /* -c_j+1 | -s_j+1 | -s_j+1 | c_j+1 */ + + negl %esi + negl %edi + + movss 1020(%ecx, %esi, 4), %xmm4 /* 255-2j */ + addl $8, %eax + movss 1020(%ecx, %edi, 4), %xmm5 /* 255-2(j+1) */ + + shufps $0, %xmm1, %xmm4 /* 2j | 2j | 255-2j | 255-2j */ + shufps $0, %xmm3, %xmm5 /* 2(j+1) | 2(j+1) | 255-2(j+1) | 255-2(j+1) */ + mulps %xmm4, %xmm0 + mulps %xmm5, %xmm2 + movhlps %xmm0, %xmm1 + movhlps %xmm2, %xmm3 + addl $16, %ebx + addps %xmm1, %xmm0 + addps %xmm3, %xmm2 + movlhps %xmm2, %xmm0 + movaps %xmm0, -16(%ebx) + decl -4(%ebp) + jnz .loop + + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + popl %eax + + addl $4, %esp + popl %ebp + + ret + .p2align 4,0 + +.global imdct512_post_ifft_twiddle_kni + .type imdct512_post_ifft_twiddle_kni, @function +imdct512_post_ifft_twiddle_kni: + + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %ecx + + movl 8(%ebp), %eax /* buf[] */ + movl 12(%ebp), %ebx /* xcos_sin_sse[] */ + movl $32, %ecx /* loop counter */ + +.loop1: + movaps (%eax), %xmm0 /* im1 | re1 | im0 | re0 */ + + movaps (%ebx), %xmm2 /* -c | -s | -s | c */ + movhlps %xmm0, %xmm1 /* im1 | re1 */ + movaps 16(%ebx), %xmm3 /* -c1 | -s1 | -s1 | c1 */ + + shufps $0x50, %xmm0, %xmm0 /* im0 | im0 | re0 | re0 */ + shufps $0x50, %xmm1, %xmm1 /* im1 | im1 | re1 | re1 */ + + movaps 16(%eax), %xmm4 /* im3 | re3 | im2 | re2 */ + + shufps $0x27, %xmm2, %xmm2 /* c | -s | -s | -c */ + movhlps %xmm4, %xmm5 /* im3 | re3 */ + shufps $0x27, %xmm3, %xmm3 /* c1 | -s1 | -s1 | -c1 */ + + movaps 32(%ebx), %xmm6 /* -c2 | -s2 | -s2 | c2 */ + movaps 48(%ebx), %xmm7 /* -c3 | -s3 | -s3 | c3 */ + + shufps $0x50, %xmm4, %xmm4 /* im2 | im2 | re2 | re2 */ + shufps $0x50, %xmm5, %xmm5 /* im3 | im3 | re3 | re3 */ + + mulps %xmm2, %xmm0 + mulps %xmm3, %xmm1 + + shufps $0x27, %xmm6, %xmm6 /* c2 | -s2 | -s2 | -c2 */ + shufps $0x27, %xmm7, %xmm7 /* c3 | -s3 | -s3 | -c3 */ + + movhlps %xmm0, %xmm2 + movhlps %xmm1, %xmm3 + + mulps %xmm6, %xmm4 + mulps %xmm7, %xmm5 + + addps %xmm2, %xmm0 + addps %xmm3, %xmm1 + + movhlps %xmm4, %xmm6 + movhlps %xmm5, %xmm7 + + addps %xmm6, %xmm4 + addps %xmm7, %xmm5 + + movlhps %xmm1, %xmm0 + movlhps %xmm5, %xmm4 + + movaps %xmm0, (%eax) + movaps %xmm4, 16(%eax) + addl $64, %ebx + addl $32, %eax + decl %ecx + jnz .loop1 + + popl %ecx + popl %ebx + popl %eax + + leave + ret + .p2align 4,0 + +.global imdct512_window_delay_kni + .type imdct512_window_delay_kni, @function +imdct512_window_delay_kni: + + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 20(%ebp), %ebx /* delay */ + movl 16(%ebp), %edx /* window */ + + movl 8(%ebp), %eax /* buf */ + movl $16, %ecx /* loop count */ + leal 516(%eax), %esi /* buf[64].im */ + leal 504(%eax), %edi /* buf[63].re */ + movl 12(%ebp), %eax /* data */ +.first_128_samples: + + movss (%esi), %xmm0 + movss 8(%esi), %xmm2 + movss (%edi), %xmm1 + movss -8(%edi), %xmm3 + + movlhps %xmm2, %xmm0 /* 0.0 | im1 | 0.0 | im0 */ + movlhps %xmm3, %xmm1 /* 0.0 | re1 | 0.0 | re0 */ + + movaps (%edx), %xmm4 /* w3 | w2 | w1 | w0 */ + movaps (%ebx), %xmm5 /* d3 | d2 | d1 | d0 */ + shufps $0xb1, %xmm1, %xmm1 /* re1 | 0.0 | re0 | 0.0 */ + + movss 16(%esi), %xmm6 /* im2 */ + movss 24(%esi), %xmm7 /* im3 */ + subps %xmm1, %xmm0 /* -re1 | im1 | -re0 | im0 */ + movss -16(%edi), %xmm2 /* re2 */ + movss -24(%edi), %xmm3 /* re3 */ + mulps %xmm4, %xmm0 + movlhps %xmm7, %xmm6 /* 0.0 | im3 | 0.0 | im2 */ + movlhps %xmm3, %xmm2 /* 0.0 | re3 | 0.0 | re2 */ + addps %xmm5, %xmm0 + shufps $0xb1, %xmm2, %xmm2 /* re3 | 0.0 | re2 | 0.0 */ + movaps 16(%edx), %xmm4 /* w7 | w6 | w5 | w4 */ + movaps 16(%ebx), %xmm5 /* d7 | d6 | d5 | d4 */ + subps %xmm2, %xmm6 /* -re3 | im3 | -re2 | im2 */ + addl $32, %edx + movaps %xmm0, (%eax) + addl $32, %ebx + mulps %xmm4, %xmm6 + addl $32, %esi + addl $32, %eax + addps %xmm5, %xmm6 + addl $-32, %edi + movaps %xmm6, -16(%eax) + decl %ecx + jnz .first_128_samples + + movl 8(%ebp), %esi /* buf[0].re */ + leal 1020(%esi), %edi /* buf[127].im */ + movl $16, %ecx /* loop count */ +.second_128_samples: + + movss (%esi), %xmm0 /* buf[i].re */ + movss 8(%esi), %xmm2 /* re1 */ + movss (%edi), %xmm1 /* buf[127-i].im */ + movss -8(%edi), %xmm3 /* im1 */ + + movlhps %xmm2, %xmm0 /* 0.0 | re1 | 0.0 | re0 */ + movlhps %xmm3, %xmm1 /* 0.0 | im1 | 0.0 | im1 */ + + movaps (%edx), %xmm4 /* w3 | w2 | w1 | w0 */ + movaps (%ebx), %xmm5 /* d3 | d2 | d1 | d0 */ + + shufps $0xb1, %xmm1, %xmm1 /* im1 | 0.0 | im0 | 0.0 */ + movss 16(%esi), %xmm6 /* re2 */ + movss 24(%esi), %xmm7 /* re3 */ + movss -16(%edi), %xmm2 /* im2 */ + movss -24(%edi), %xmm3 /* im3 */ + subps %xmm1, %xmm0 /* -im1 | re1 | -im0 | re0 */ + movlhps %xmm7, %xmm6 /* 0.0 | re3 | 0.0 | re2 */ + movlhps %xmm3, %xmm2 /* 0.0 | im3 | 0.0 | im2 */ + mulps %xmm4, %xmm0 + shufps $0xb1, %xmm2, %xmm2 /* im3 | 0.0 | im2 | 0.0 */ + movaps 16(%edx), %xmm4 /* w7 | w6 | w5 | w4 */ + addl $32, %esi + subps %xmm2, %xmm6 /* -im3 | re3 | -im2 | re2 */ + addps %xmm5, %xmm0 + mulps %xmm4, %xmm6 + addl $-32, %edi + movaps 16(%ebx), %xmm5 /* d7 | d6 | d5 | d4 */ + movaps %xmm0, (%eax) + addps %xmm5, %xmm6 + addl $32, %edx + addl $32, %eax + addl $32, %ebx + movaps %xmm6, -16(%eax) + decl %ecx + jnz .second_128_samples + + movl 8(%ebp), %eax + leal 512(%eax), %esi /* buf[64].re */ + leal 508(%eax), %edi /* buf[63].im */ + movl $16, %ecx /* loop count */ + movl 20(%ebp), %eax /* delay */ +.first_128_delay: + + movss (%esi), %xmm0 + movss 8(%esi), %xmm2 + movss (%edi), %xmm1 + movss -8(%edi), %xmm3 + + movlhps %xmm2, %xmm0 /* 0.0 | re1 | 0.0 | re0 */ + movlhps %xmm3, %xmm1 /* 0.0 | im1 | 0.0 | im0 */ + + movaps -16(%edx), %xmm4 /* w3 | w2 | w1 | w0 */ + shufps $0xb1, %xmm1, %xmm1 /* im1 | 0.0 | im0 | 0.0 */ + movss 16(%esi), %xmm6 /* re2 */ + movss 24(%esi), %xmm7 /* re3 */ + movss -16(%edi), %xmm2 /* im2 */ + movss -24(%edi), %xmm3 /* im3 */ + subps %xmm1, %xmm0 /* -im1 | re1 | -im0 | re0 */ + addl $-32, %edx + movlhps %xmm7, %xmm6 /* 0.0 | re3 | 0.0 | re2 */ + movlhps %xmm3, %xmm2 /* 0.0 | im3 | 0.0 | im2 */ + mulps %xmm4, %xmm0 + movaps (%edx), %xmm5 /* w7 | w6 | w5 | w4 */ + shufps $0xb1, %xmm2, %xmm2 /* im3 | 0.0 | im2 | 0.0 */ + movaps %xmm0, (%eax) + addl $32, %esi + subps %xmm2, %xmm6 /* -im3 | re3 | -im2 | re2 */ + addl $-32, %edi + mulps %xmm5, %xmm6 + addl $32, %eax + movaps %xmm6, -16(%eax) + decl %ecx + jnz .first_128_delay + + movl 8(%ebp), %ebx + leal 4(%ebx), %esi /* buf[0].im */ + leal 1016(%ebx), %edi /* buf[127].re */ + movl $16, %ecx /* loop count */ +.second_128_delay: + + movss (%esi), %xmm0 + movss 8(%esi), %xmm2 + movss (%edi), %xmm1 + movss -8(%edi), %xmm3 + + movlhps %xmm2, %xmm0 /* 0.0 | im1 | 0.0 | im0 */ + movlhps %xmm3, %xmm1 /* 0.0 | re1 | 0.0 | re0 */ + + movaps -16(%edx), %xmm4 /* w3 | w2 | w1 | w0 */ + shufps $0xb1, %xmm1, %xmm1 /* re1 | 0.0 | re0 | 0.0 */ + movss 16(%esi), %xmm6 /* im2 */ + movss 24(%esi), %xmm7 /* im3 */ + movss -16(%edi), %xmm2 /* re2 */ + movss -24(%edi), %xmm3 /* re3 */ + subps %xmm0, %xmm1 /* re1 | -im1 | re0 | -im0 */ + addl $-32, %edx + movlhps %xmm7, %xmm6 /* 0.0 | im3 | 0.0 | im2 */ + movlhps %xmm3, %xmm2 /* 0.0 | re3 | 0.0 | re2 */ + mulps %xmm4, %xmm1 + movaps (%edx), %xmm5 /* w7 | w6 | w5 | w4 */ + shufps $0xb1, %xmm2, %xmm2 /* re3 | 0.0 | re2 | 0.0 */ + movaps %xmm1, (%eax) + addl $32, %esi + subps %xmm6, %xmm2 /* re | -im3 | re | -im2 */ + addl $-32, %edi + mulps %xmm5, %xmm2 + addl $32, %eax + movaps %xmm2, -16(%eax) + decl %ecx + jnz .second_128_delay + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + + leave + ret + .p2align 4,0 + +.global imdct512_window_delay_nol_kni + .type imdct512_window_delay_nol_kni, @function +imdct512_window_delay_nol_kni: + + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + /* movl 20(%ebp), %ebx delay */ + movl 16(%ebp), %edx /* window */ + + movl 8(%ebp), %eax /* buf */ + movl $16, %ecx /* loop count */ + leal 516(%eax), %esi /* buf[64].im */ + leal 504(%eax), %edi /* buf[63].re */ + movl 12(%ebp), %eax /* data */ +.first_128_sample: + + movss (%esi), %xmm0 + movss 8(%esi), %xmm2 + movss (%edi), %xmm1 + movss -8(%edi), %xmm3 + + movlhps %xmm2, %xmm0 /* 0.0 | im1 | 0.0 | im0 */ + movlhps %xmm3, %xmm1 /* 0.0 | re1 | 0.0 | re0 */ + + movaps (%edx), %xmm4 /* w3 | w2 | w1 | w0 */ + /* movaps (%ebx), %xmm5 d3 | d2 | d1 | d0 */ + shufps $0xb1, %xmm1, %xmm1 /* re1 | 0.0 | re0 | 0.0 */ + + movss 16(%esi), %xmm6 /* im2 */ + movss 24(%esi), %xmm7 /* im3 */ + subps %xmm1, %xmm0 /* -re1 | im1 | -re0 | im0 */ + movss -16(%edi), %xmm2 /* re2 */ + movss -24(%edi), %xmm3 /* re3 */ + mulps %xmm4, %xmm0 + movlhps %xmm7, %xmm6 /* 0.0 | im3 | 0.0 | im2 */ + movlhps %xmm3, %xmm2 /* 0.0 | re3 | 0.0 | re2 */ + /* addps %xmm5, %xmm0 */ + shufps $0xb1, %xmm2, %xmm2 /* re3 | 0.0 | re2 | 0.0 */ + movaps 16(%edx), %xmm4 /* w7 | w6 | w5 | w4 */ + /* movaps 16(%ebx), %xmm5 d7 | d6 | d5 | d4 */ + subps %xmm2, %xmm6 /* -re3 | im3 | -re2 | im2 */ + addl $32, %edx + movaps %xmm0, (%eax) + /* addl $32, %ebx */ + mulps %xmm4, %xmm6 + addl $32, %esi + addl $32, %eax + /* addps %xmm5, %xmm6 */ + addl $-32, %edi + movaps %xmm6, -16(%eax) + decl %ecx + jnz .first_128_sample + + movl 8(%ebp), %esi /* buf[0].re */ + leal 1020(%esi), %edi /* buf[127].im */ + movl $16, %ecx /* loop count */ +.second_128_sample: + + movss (%esi), %xmm0 /* buf[i].re */ + movss 8(%esi), %xmm2 /* re1 */ + movss (%edi), %xmm1 /* buf[127-i].im */ + movss -8(%edi), %xmm3 /* im1 */ + + movlhps %xmm2, %xmm0 /* 0.0 | re1 | 0.0 | re0 */ + movlhps %xmm3, %xmm1 /* 0.0 | im1 | 0.0 | im1 */ + + movaps (%edx), %xmm4 /* w3 | w2 | w1 | w0 */ + /* movaps (%ebx), %xmm5 d3 | d2 | d1 | d0 */ + + shufps $0xb1, %xmm1, %xmm1 /* im1 | 0.0 | im0 | 0.0 */ + movss 16(%esi), %xmm6 /* re2 */ + movss 24(%esi), %xmm7 /* re3 */ + movss -16(%edi), %xmm2 /* im2 */ + movss -24(%edi), %xmm3 /* im3 */ + subps %xmm1, %xmm0 /* -im1 | re1 | -im0 | re0 */ + movlhps %xmm7, %xmm6 /* 0.0 | re3 | 0.0 | re2 */ + movlhps %xmm3, %xmm2 /* 0.0 | im3 | 0.0 | im2 */ + mulps %xmm4, %xmm0 + shufps $0xb1, %xmm2, %xmm2 /* im3 | 0.0 | im2 | 0.0 */ + movaps 16(%edx), %xmm4 /* w7 | w6 | w5 | w4 */ + addl $32, %esi + subps %xmm2, %xmm6 /* -im3 | re3 | -im2 | re2 */ + /* addps %xmm5, %xmm0 */ + mulps %xmm4, %xmm6 + addl $-32, %edi + /* movaps 16(%ebx), %xmm5 d7 | d6 | d5 | d4 */ + movaps %xmm0, (%eax) + /* addps %xmm5, %xmm6 */ + addl $32, %edx + addl $32, %eax + /* addl $32, %ebx */ + movaps %xmm6, -16(%eax) + decl %ecx + jnz .second_128_sample + + movl 8(%ebp), %eax + leal 512(%eax), %esi /* buf[64].re */ + leal 508(%eax), %edi /* buf[63].im */ + movl $16, %ecx /* loop count */ + movl 20(%ebp), %eax /* delay */ +.first_128_delays: + + movss (%esi), %xmm0 + movss 8(%esi), %xmm2 + movss (%edi), %xmm1 + movss -8(%edi), %xmm3 + + movlhps %xmm2, %xmm0 /* 0.0 | re1 | 0.0 | re0 */ + movlhps %xmm3, %xmm1 /* 0.0 | im1 | 0.0 | im0 */ + + movaps -16(%edx), %xmm4 /* w3 | w2 | w1 | w0 */ + shufps $0xb1, %xmm1, %xmm1 /* im1 | 0.0 | im0 | 0.0 */ + movss 16(%esi), %xmm6 /* re2 */ + movss 24(%esi), %xmm7 /* re3 */ + movss -16(%edi), %xmm2 /* im2 */ + movss -24(%edi), %xmm3 /* im3 */ + subps %xmm1, %xmm0 /* -im1 | re1 | -im0 | re0 */ + addl $-32, %edx + movlhps %xmm7, %xmm6 /* 0.0 | re3 | 0.0 | re2 */ + movlhps %xmm3, %xmm2 /* 0.0 | im3 | 0.0 | im2 */ + mulps %xmm4, %xmm0 + movaps (%edx), %xmm5 /* w7 | w6 | w5 | w4 */ + shufps $0xb1, %xmm2, %xmm2 /* im3 | 0.0 | im2 | 0.0 */ + movaps %xmm0, (%eax) + addl $32, %esi + subps %xmm2, %xmm6 /* -im3 | re3 | -im2 | re2 */ + addl $-32, %edi + mulps %xmm5, %xmm6 + addl $32, %eax + movaps %xmm6, -16(%eax) + decl %ecx + jnz .first_128_delays + + movl 8(%ebp), %ebx + leal 4(%ebx), %esi /* buf[0].im */ + leal 1016(%ebx), %edi /* buf[127].re */ + movl $16, %ecx /* loop count */ +.second_128_delays: + + movss (%esi), %xmm0 + movss 8(%esi), %xmm2 + movss (%edi), %xmm1 + movss -8(%edi), %xmm3 + + movlhps %xmm2, %xmm0 /* 0.0 | im1 | 0.0 | im0 */ + movlhps %xmm3, %xmm1 /* 0.0 | re1 | 0.0 | re0 */ + + movaps -16(%edx), %xmm4 /* w3 | w2 | w1 | w0 */ + shufps $0xb1, %xmm1, %xmm1 /* re1 | 0.0 | re0 | 0.0 */ + movss 16(%esi), %xmm6 /* im2 */ + movss 24(%esi), %xmm7 /* im3 */ + movss -16(%edi), %xmm2 /* re2 */ + movss -24(%edi), %xmm3 /* re3 */ + subps %xmm0, %xmm1 /* re1 | -im1 | re0 | -im0 */ + addl $-32, %edx + movlhps %xmm7, %xmm6 /* 0.0 | im3 | 0.0 | im2 */ + movlhps %xmm3, %xmm2 /* 0.0 | re3 | 0.0 | re2 */ + mulps %xmm4, %xmm1 + movaps (%edx), %xmm5 /* w7 | w6 | w5 | w4 */ + shufps $0xb1, %xmm2, %xmm2 /* re3 | 0.0 | re2 | 0.0 */ + movaps %xmm1, (%eax) + addl $32, %esi + subps %xmm6, %xmm2 /* re | -im3 | re | -im2 */ + addl $-32, %edi + mulps %xmm5, %xmm2 + addl $32, %eax + movaps %xmm2, -16(%eax) + decl %ecx + jnz .second_128_delays + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + + leave + ret + .p2align 4,0 +#endif diff --git a/ac3dec/imdct_c.c b/ac3dec/imdct_c.c new file mode 100644 index 000000000..1f2bfe849 --- /dev/null +++ b/ac3dec/imdct_c.c @@ -0,0 +1,218 @@ +/* + * imdct.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include "ac3.h" +#include "ac3_internal.h" + +#include "downmix.h" +#include "imdct_c.h" +#include "srfft.h" + + +#define N 512 + +extern void (*imdct_do_512) (float data[],float delay[]); +extern void (*imdct_do_512_nol) (float data[], float delay[]); +extern void (*fft_64p) (complex_t *); + +extern const int pm128[]; +extern float window[]; +extern complex_t buf[128]; + +extern void fft_64p_c (complex_t *); +extern void fft_128p_c (complex_t *); + +static void imdct_do_512_c (float data[],float delay[]); +static void imdct_do_512_nol_c (float data[], float delay[]); + +/* Twiddle factors for IMDCT */ +static float xcos1[128] __attribute__((aligned(16))); +static float xsin1[128] __attribute__((aligned(16))); + + +int imdct_init_c (void) +{ + int i; + float scale = 255.99609372; + + imdct_do_512 = imdct_do_512_c; + imdct_do_512_nol = imdct_do_512_nol_c; + fft_64p = fft_64p_c; + + /* Twiddle factors to turn IFFT into IMDCT */ + + for (i=0; i < 128; i++) { + xcos1[i] = cos(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + xsin1[i] = sin(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + } + + return 0; +} + + +static void imdct_do_512_c (float data[], float delay[]) +{ + int i, j; + float tmp_a_r, tmp_a_i; + float *data_ptr; + float *delay_ptr; + float *window_ptr; + +// 512 IMDCT with source and dest data in 'data' +// Pre IFFT complex multiply plus IFFT complex conjugate + + for( i=0; i < 128; i++) { + j = pm128[i]; + //a = (data[256-2*j-1] - data[2*j]) * (xcos1[j] + xsin1[j]); + //c = data[2*j] * xcos1[j]; + //b = data[256-2*j-1] * xsin1[j]; + //buf1[i].re = a - b + c; + //buf1[i].im = b + c; + buf[i].re = (data[256-2*j-1] * xcos1[j]) - (data[2*j] * xsin1[j]); + buf[i].im = -1.0 * (data[2*j] * xcos1[j] + data[256-2*j-1] * xsin1[j]); + } + + fft_128p_c (&buf[0]); + +// Post IFFT complex multiply plus IFFT complex conjugate + for (i=0; i < 128; i++) { + tmp_a_r = buf[i].re; + tmp_a_i = buf[i].im; + //a = (tmp_a_r - tmp_a_i) * (xcos1[j] + xsin1[j]); + //b = tmp_a_r * xsin1[j]; + //c = tmp_a_i * xcos1[j]; + //buf[j].re = a - b + c; + //buf[j].im = b + c; + buf[i].re =(tmp_a_r * xcos1[i]) + (tmp_a_i * xsin1[i]); + buf[i].im =(tmp_a_r * xsin1[i]) - (tmp_a_i * xcos1[i]); + } + + data_ptr = data; + delay_ptr = delay; + window_ptr = window; + +// Window and convert to real valued signal + for (i=0; i< 64; i++) { + *data_ptr++ = -buf[64+i].im * *window_ptr++ + *delay_ptr++; + *data_ptr++ = buf[64-i-1].re * *window_ptr++ + *delay_ptr++; + } + + for(i=0; i< 64; i++) { + *data_ptr++ = -buf[i].re * *window_ptr++ + *delay_ptr++; + *data_ptr++ = buf[128-i-1].im * *window_ptr++ + *delay_ptr++; + } + +// The trailing edge of the window goes into the delay line + delay_ptr = delay; + + for(i=0; i< 64; i++) { + *delay_ptr++ = -buf[64+i].re * *--window_ptr; + *delay_ptr++ = buf[64-i-1].im * *--window_ptr; + } + + for(i=0; i<64; i++) { + *delay_ptr++ = buf[i].im * *--window_ptr; + *delay_ptr++ = -buf[128-i-1].re * *--window_ptr; + } +} + + +static void imdct_do_512_nol_c (float data[], float delay[]) +{ + int i, j; + + float tmp_a_i; + float tmp_a_r; + + float *data_ptr; + float *delay_ptr; + float *window_ptr; + + // + // 512 IMDCT with source and dest data in 'data' + // + + // Pre IFFT complex multiply plus IFFT cmplx conjugate + + for( i=0; i < 128; i++) { + /* z[i] = (X[256-2*i-1] + j * X[2*i]) * (xcos1[i] + j * xsin1[i]) */ + j = pm128[i]; + //a = (data[256-2*j-1] - data[2*j]) * (xcos1[j] + xsin1[j]); + //c = data[2*j] * xcos1[j]; + //b = data[256-2*j-1] * xsin1[j]; + //buf1[i].re = a - b + c; + + //buf1[i].im = b + c; + buf[i].re = (data[256-2*j-1] * xcos1[j]) - (data[2*j] * xsin1[j]); + buf[i].im = -1.0 * (data[2*j] * xcos1[j] + data[256-2*j-1] * xsin1[j]); + } + + fft_128p_c (&buf[0]); + + /* Post IFFT complex multiply plus IFFT complex conjugate*/ + for (i=0; i < 128; i++) { + /* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; */ + /* int j1 = i; */ + tmp_a_r = buf[i].re; + tmp_a_i = buf[i].im; + //a = (tmp_a_r - tmp_a_i) * (xcos1[j] + xsin1[j]); + //b = tmp_a_r * xsin1[j]; + //c = tmp_a_i * xcos1[j]; + //buf[j].re = a - b + c; + //buf[j].im = b + c; + buf[i].re =(tmp_a_r * xcos1[i]) + (tmp_a_i * xsin1[i]); + buf[i].im =(tmp_a_r * xsin1[i]) - (tmp_a_i * xcos1[i]); + } + + data_ptr = data; + delay_ptr = delay; + window_ptr = window; + + /* Window and convert to real valued signal, no overlap here*/ + for (i=0; i< 64; i++) { + *data_ptr++ = -buf[64+i].im * *window_ptr++; + *data_ptr++ = buf[64-i-1].re * *window_ptr++; + } + + for(i=0; i< 64; i++) { + *data_ptr++ = -buf[i].re * *window_ptr++; + *data_ptr++ = buf[128-i-1].im * *window_ptr++; + } + + /* The trailing edge of the window goes into the delay line */ + delay_ptr = delay; + + for(i=0; i< 64; i++) { + *delay_ptr++ = -buf[64+i].re * *--window_ptr; + *delay_ptr++ = buf[64-i-1].im * *--window_ptr; + } + + for(i=0; i<64; i++) { + *delay_ptr++ = buf[i].im * *--window_ptr; + *delay_ptr++ = -buf[128-i-1].re * *--window_ptr; + } +} diff --git a/ac3dec/imdct_c.h b/ac3dec/imdct_c.h new file mode 100644 index 000000000..d2c31b54b --- /dev/null +++ b/ac3dec/imdct_c.h @@ -0,0 +1,36 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#ifndef __IMDCT_C_H__ +#define __IMDCT_C_H__ + +#include "cmplx.h" + +int imdct_init_c (void); + +void fft_128p_c (complex_t *); +void fft_64p_c (complex_t *); + +void imdct512_pre_ifft_twiddle_c (const int *pmt, complex_t *buf, float *data, float *xcos_sin_sse); +void imdct512_post_ifft_twiddle_c (complex_t *buf, float *xcos_sin_sse); +void imdct512_window_delay_c (complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); +void imdct512_window_delay_nol_c (complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); + +#endif diff --git a/ac3dec/imdct_kni.c b/ac3dec/imdct_kni.c new file mode 100644 index 000000000..b44547a95 --- /dev/null +++ b/ac3dec/imdct_kni.c @@ -0,0 +1,103 @@ +/* + * imdct_kni.c + * + * Copyright (C) Aaron Holtzman - May 1999 + * + * This file is part of ac3dec, a free Dolby AC-3 stream decoder. + * + * ac3dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ac3dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#ifdef __i386__ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <mm_accel.h> +#include "ac3.h" +#include "ac3_internal.h" + +#include "downmix.h" +#include "imdct_kni.h" +#include "srfft.h" + +#define N 512 + +/* Delay buffer for time domain interleaving */ +static float xcos_sin_sse[128 * 4] __attribute__((aligned(16))); + +extern void (*imdct_do_512) (float data[],float delay[]); +extern void (*imdct_do_512_nol) (float data[], float delay[]); +extern void (*fft_64p) (complex_t *); + +extern const int pm128[]; +extern float window[]; +extern complex_t buf[128]; + +extern void fft_64p_kni (complex_t *); +extern void fft_128p_kni (complex_t *); + +static void imdct_do_512_kni (float data[], float delay[]); +static void imdct_do_512_nol_kni (float data[], float delay[]); + + +int imdct_init_kni (void) +{ + uint32_t accel = mm_accel (); + + if (accel & MM_ACCEL_X86_MMXEXT) { + int i; + float scale = 255.99609372; + + fprintf (stderr, "Using SSE for IMDCT\n"); + imdct_do_512 = imdct_do_512_kni; + imdct_do_512_nol = imdct_do_512_nol_kni; + fft_64p = fft_64p_kni; + + for (i=0; i < 128; i++) { + float xcos_i = cos(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + float xsin_i = sin(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + xcos_sin_sse[i * 4] = xcos_i; + xcos_sin_sse[i * 4 + 1] = -xsin_i; + xcos_sin_sse[i * 4 + 2] = -xsin_i; + xcos_sin_sse[i * 4 + 3] = -xcos_i; + } + + return 0; + } else + return -1; +} + + +static void imdct_do_512_kni (float data[], float delay[]) +{ + imdct512_pre_ifft_twiddle_kni (pm128, buf, data, xcos_sin_sse); + fft_128p_kni (buf); + imdct512_post_ifft_twiddle_kni (buf, xcos_sin_sse); + imdct512_window_delay_kni (buf, data, window, delay); +} + + +static void imdct_do_512_nol_kni (float data[], float delay[]) +{ + imdct512_pre_ifft_twiddle_kni (pm128, buf, data, xcos_sin_sse); + fft_128p_kni (buf); + imdct512_post_ifft_twiddle_kni (buf, xcos_sin_sse); + imdct512_window_delay_nol_kni (buf, data, window, delay); +} + +#endif diff --git a/ac3dec/imdct_kni.h b/ac3dec/imdct_kni.h new file mode 100644 index 000000000..2193c0753 --- /dev/null +++ b/ac3dec/imdct_kni.h @@ -0,0 +1,36 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#ifndef __IMDCT_KNI_H__ +#define __IMDCT_KNI_H__ + +#include "cmplx.h" + +int imdct_init_kni (void); + +void fft_128p_kni(complex_t *); +void fft_64p_kni(complex_t *); + +void imdct512_pre_ifft_twiddle_kni(const int *pmt, complex_t *buf, float *data, float *xcos_sin_sse); +void imdct512_post_ifft_twiddle_kni(complex_t *buf, float *xcos_sin_sse); +void imdct512_window_delay_kni(complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); +void imdct512_window_delay_nol_kni(complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); + +#endif diff --git a/ac3dec/mm_accel.h b/ac3dec/mm_accel.h new file mode 100644 index 000000000..82dc5837f --- /dev/null +++ b/ac3dec/mm_accel.h @@ -0,0 +1,36 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#ifndef __MM_ACCEL_H__ +#define __MM_ACCEL_H__ + +#include <inttypes.h> + +// generic accelerations +#define MM_ACCEL_MLIB 0x00000001 + +// x86 accelerations +#define MM_ACCEL_X86_MMX 0x80000000 +#define MM_ACCEL_X86_3DNOW 0x40000000 +#define MM_ACCEL_X86_MMXEXT 0x20000000 + +uint32_t mm_accel (void); + +#endif diff --git a/ac3dec/parse.c b/ac3dec/parse.c index 3560bc5ab..49ea57c67 100644 --- a/ac3dec/parse.c +++ b/ac3dec/parse.c @@ -31,15 +31,16 @@ #include "bitstream.h" #include "stats.h" #include "debug.h" +#include "crc.h" #include "parse.h" /* Misc LUT */ -static const uint_16 nfchans[8] = {2,1,2,3,3,4,4,5}; +static const uint16_t nfchans[8] = {2,1,2,3,3,4,4,5}; struct frmsize_s { - uint_16 bit_rate; - uint_16 frm_size[3]; + uint16_t bit_rate; + uint16_t frm_size[3]; }; static const struct frmsize_s frmsizecod_tbl[64] = @@ -85,8 +86,7 @@ static const struct frmsize_s frmsizecod_tbl[64] = }; /* Parse a syncinfo structure, minus the sync word */ -void -parse_syncinfo(syncinfo_t *syncinfo,uint_8 *data) +void parse_syncinfo(syncinfo_t *syncinfo, uint8_t *data) { // // We need to read in the entire syncinfo struct (0x0b77 + 24 bits) @@ -96,10 +96,8 @@ parse_syncinfo(syncinfo_t *syncinfo,uint_8 *data) // Get the sampling rate syncinfo->fscod = (data[2] >> 6) & 0x3; - if(syncinfo->fscod == 3) - { + if(syncinfo->fscod == 3) { //invalid sampling rate code - error_flag = 1; return; } else if(syncinfo->fscod == 2) @@ -119,15 +117,13 @@ parse_syncinfo(syncinfo_t *syncinfo,uint_8 *data) } -/* + +/** * This routine fills a bsi struct from the AC3 stream - */ + **/ -void -parse_bsi(bsi_t *bsi) +void parse_bsi(bsi_t *bsi) { - uint_32 i; - /* Check the AC-3 version number */ bsi->bsid = bitstream_get(5); @@ -159,25 +155,19 @@ parse_bsi(bsi_t *bsi) bsi->dialnorm = bitstream_get(5); /* Does compression gain exist? */ - bsi->compre = bitstream_get(1); - if (bsi->compre) - { + if ((bsi->compre = bitstream_get(1))) { /* Get compression gain */ bsi->compr = bitstream_get(8); } /* Does language code exist? */ - bsi->langcode = bitstream_get(1); - if (bsi->langcode) - { + if ((bsi->langcode = bitstream_get(1))) { /* Get langauge code */ bsi->langcod = bitstream_get(8); } /* Does audio production info exist? */ - bsi->audprodie = bitstream_get(1); - if (bsi->audprodie) - { + if ((bsi->audprodie = bitstream_get(1))) { /* Get mix level */ bsi->mixlevel = bitstream_get(5); @@ -186,31 +176,24 @@ parse_bsi(bsi_t *bsi) } /* If we're in dual mono mode then get some extra info */ - if (bsi->acmod ==0) - { + if (!bsi->acmod) { /* Get the dialogue normalization level two */ bsi->dialnorm2 = bitstream_get(5); /* Does compression gain two exist? */ - bsi->compr2e = bitstream_get(1); - if (bsi->compr2e) - { + if ((bsi->compr2e = bitstream_get(1))) { /* Get compression gain two */ bsi->compr2 = bitstream_get(8); } /* Does language code two exist? */ - bsi->langcod2e = bitstream_get(1); - if (bsi->langcod2e) - { + if ((bsi->langcod2e = bitstream_get(1))) { /* Get langauge code two */ bsi->langcod2 = bitstream_get(8); } /* Does audio production info two exist? */ - bsi->audprodi2e = bitstream_get(1); - if (bsi->audprodi2e) - { + if ((bsi->audprodi2e = bitstream_get(1))) { /* Get mix level two */ bsi->mixlevel2 = bitstream_get(5); @@ -226,22 +209,17 @@ parse_bsi(bsi_t *bsi) bsi->origbs = bitstream_get(1); /* Does timecode one exist? */ - bsi->timecod1e = bitstream_get(1); - - if(bsi->timecod1e) + if ((bsi->timecod1e = bitstream_get(1))) bsi->timecod1 = bitstream_get(14); /* Does timecode two exist? */ - bsi->timecod2e = bitstream_get(1); - - if(bsi->timecod2e) + if ((bsi->timecod2e = bitstream_get(1))) bsi->timecod2 = bitstream_get(14); /* Does addition info exist? */ - bsi->addbsie = bitstream_get(1); + if ((bsi->addbsie = bitstream_get(1))) { + uint32_t i; - if(bsi->addbsie) - { /* Get how much info is there */ bsi->addbsil = bitstream_get(6); @@ -253,52 +231,41 @@ parse_bsi(bsi_t *bsi) stats_print_bsi(bsi); } + /* More pain inducing parsing */ -void -parse_audblk(bsi_t *bsi,audblk_t *audblk) +void parse_audblk(bsi_t *bsi,audblk_t *audblk) { int i,j; - for (i=0;i < bsi->nfchans; i++) - { + for (i=0; i < bsi->nfchans; i++) { /* Is this channel an interleaved 256 + 256 block ? */ audblk->blksw[i] = bitstream_get(1); } - for (i=0;i < bsi->nfchans; i++) - { + for (i=0;i < bsi->nfchans; i++) { /* Should we dither this channel? */ audblk->dithflag[i] = bitstream_get(1); } /* Does dynamic range control exist? */ - audblk->dynrnge = bitstream_get(1); - if (audblk->dynrnge) - { + if ((audblk->dynrnge = bitstream_get(1))) { /* Get dynamic range info */ audblk->dynrng = bitstream_get(8); } /* If we're in dual mono mode then get the second channel DR info */ - if (bsi->acmod == 0) - { + if (bsi->acmod == 0) { /* Does dynamic range control two exist? */ - audblk->dynrng2e = bitstream_get(1); - if (audblk->dynrng2e) - { + if ((audblk->dynrng2e = bitstream_get(1))) { /* Get dynamic range info */ audblk->dynrng2 = bitstream_get(8); } } /* Does coupling strategy exist? */ - audblk->cplstre = bitstream_get(1); - if (audblk->cplstre) - { + if ((audblk->cplstre = bitstream_get(1))) { /* Is coupling turned on? */ - audblk->cplinu = bitstream_get(1); - if(audblk->cplinu) - { + if ((audblk->cplinu = bitstream_get(1))) { for(i=0;i < bsi->nfchans; i++) audblk->chincpl[i] = bitstream_get(1); if(bsi->acmod == 0x2) @@ -315,30 +282,23 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) * band */ audblk->ncplbnd = audblk->ncplsubnd; - for(i=1; i< audblk->ncplsubnd; i++) - { + for(i=1; i< audblk->ncplsubnd; i++) { audblk->cplbndstrc[i] = bitstream_get(1); audblk->ncplbnd -= audblk->cplbndstrc[i]; } } } - if(audblk->cplinu) - { + if(audblk->cplinu) { /* Loop through all the channels and get their coupling co-ords */ - for(i=0;i < bsi->nfchans;i++) - { + for(i=0;i < bsi->nfchans;i++) { if(!audblk->chincpl[i]) continue; /* Is there new coupling co-ordinate info? */ - audblk->cplcoe[i] = bitstream_get(1); - - if(audblk->cplcoe[i]) - { + if ((audblk->cplcoe[i] = bitstream_get(1))) { audblk->mstrcplco[i] = bitstream_get(2); - for(j=0;j < audblk->ncplbnd; j++) - { + for(j=0;j < audblk->ncplbnd; j++) { audblk->cplcoexp[i][j] = bitstream_get(4); audblk->cplcomant[i][j] = bitstream_get(4); } @@ -347,8 +307,7 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) /* If we're in dual mono mode, there's going to be some phase info */ if( (bsi->acmod == 0x2) && audblk->phsflginu && - (audblk->cplcoe[0] || audblk->cplcoe[1])) - { + (audblk->cplcoe[0] || audblk->cplcoe[1])) { for(j=0;j < audblk->ncplbnd; j++) audblk->phsflg[j] = bitstream_get(1); @@ -356,23 +315,17 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) } /* If we're in dual mono mode, there may be a rematrix strategy */ - if(bsi->acmod == 0x2) - { - audblk->rematstr = bitstream_get(1); - if(audblk->rematstr) - { - if (audblk->cplinu == 0) - { + if(bsi->acmod == 0x2) { + if ((audblk->rematstr = bitstream_get(1))) { + if (!audblk->cplinu) { for(i = 0; i < 4; i++) audblk->rematflg[i] = bitstream_get(1); } - if((audblk->cplbegf > 2) && audblk->cplinu) - { + if((audblk->cplbegf > 2) && audblk->cplinu) { for(i = 0; i < 4; i++) audblk->rematflg[i] = bitstream_get(1); } - if((audblk->cplbegf <= 2) && audblk->cplinu) - { + if((audblk->cplbegf <= 2) && audblk->cplinu) { for(i = 0; i < 3; i++) audblk->rematflg[i] = bitstream_get(1); } @@ -383,8 +336,7 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) } } - if (audblk->cplinu) - { + if (audblk->cplinu) { /* Get the coupling channel exponent strategy */ audblk->cplexpstr = bitstream_get(2); audblk->ncplgrps = (audblk->cplendmant - audblk->cplstrtmant) / @@ -399,18 +351,13 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) audblk->lfeexpstr = bitstream_get(1); /* Determine the bandwidths of all the fbw channels */ - for(i = 0; i < bsi->nfchans; i++) - { - uint_16 grp_size; - - if(audblk->chexpstr[i] != EXP_REUSE) - { - if (audblk->cplinu && audblk->chincpl[i]) - { + for(i = 0; i < bsi->nfchans; i++) { + uint16_t grp_size; + + if(audblk->chexpstr[i] != EXP_REUSE) { + if (audblk->cplinu && audblk->chincpl[i]) { audblk->endmant[i] = audblk->cplstrtmant; - } - else - { + } else { audblk->chbwcod[i] = bitstream_get(6); audblk->endmant[i] = ((audblk->chbwcod[i] + 12) * 3) + 37; } @@ -422,18 +369,15 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) } /* Get the coupling exponents if they exist */ - if(audblk->cplinu && (audblk->cplexpstr != EXP_REUSE)) - { + if(audblk->cplinu && (audblk->cplexpstr != EXP_REUSE)) { audblk->cplabsexp = bitstream_get(4); for(i=0;i< audblk->ncplgrps;i++) audblk->cplexps[i] = bitstream_get(7); } /* Get the fwb channel exponents */ - for(i=0;i < bsi->nfchans; i++) - { - if(audblk->chexpstr[i] != EXP_REUSE) - { + for(i=0;i < bsi->nfchans; i++) { + if(audblk->chexpstr[i] != EXP_REUSE) { audblk->exps[i][0] = bitstream_get(4); for(j=1;j<=audblk->nchgrps[i];j++) audblk->exps[i][j] = bitstream_get(7); @@ -442,8 +386,7 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) } /* Get the lfe channel exponents */ - if(bsi->lfeon && (audblk->lfeexpstr != EXP_REUSE)) - { + if(bsi->lfeon && (audblk->lfeexpstr != EXP_REUSE)) { audblk->lfeexps[0] = bitstream_get(4); audblk->lfeexps[1] = bitstream_get(7); audblk->lfeexps[2] = bitstream_get(7); @@ -452,8 +395,7 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) /* Get the parametric bit allocation parameters */ audblk->baie = bitstream_get(1); - if(audblk->baie) - { + if(audblk->baie) { audblk->sdcycod = bitstream_get(2); audblk->fdcycod = bitstream_get(2); audblk->sgaincod = bitstream_get(2); @@ -464,23 +406,19 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) /* Get the SNR off set info if it exists */ audblk->snroffste = bitstream_get(1); - if(audblk->snroffste) - { + if(audblk->snroffste) { audblk->csnroffst = bitstream_get(6); - if(audblk->cplinu) - { + if(audblk->cplinu) { audblk->cplfsnroffst = bitstream_get(4); audblk->cplfgaincod = bitstream_get(3); } - for(i = 0;i < bsi->nfchans; i++) - { + for(i = 0;i < bsi->nfchans; i++) { audblk->fsnroffst[i] = bitstream_get(4); audblk->fgaincod[i] = bitstream_get(3); } - if(bsi->lfeon) - { + if(bsi->lfeon) { audblk->lfefsnroffst = bitstream_get(4); audblk->lfefgaincod = bitstream_get(3); @@ -488,12 +426,10 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) } /* Get coupling leakage info if it exists */ - if(audblk->cplinu) - { + if(audblk->cplinu) { audblk->cplleake = bitstream_get(1); - if(audblk->cplleake) - { + if(audblk->cplleake) { audblk->cplfleak = bitstream_get(3); audblk->cplsleak = bitstream_get(3); } @@ -502,32 +438,26 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) /* Get the delta bit alloaction info */ audblk->deltbaie = bitstream_get(1); - if(audblk->deltbaie) - { + if(audblk->deltbaie) { if(audblk->cplinu) audblk->cpldeltbae = bitstream_get(2); for(i = 0;i < bsi->nfchans; i++) audblk->deltbae[i] = bitstream_get(2); - if (audblk->cplinu && (audblk->cpldeltbae == DELTA_BIT_NEW)) - { + if (audblk->cplinu && (audblk->cpldeltbae == DELTA_BIT_NEW)) { audblk->cpldeltnseg = bitstream_get(3); - for(i = 0;i < audblk->cpldeltnseg + 1; i++) - { + for(i = 0;i < audblk->cpldeltnseg + 1; i++) { audblk->cpldeltoffst[i] = bitstream_get(5); audblk->cpldeltlen[i] = bitstream_get(4); audblk->cpldeltba[i] = bitstream_get(3); } } - for(i = 0;i < bsi->nfchans; i++) - { - if (audblk->deltbae[i] == DELTA_BIT_NEW) - { + for(i = 0;i < bsi->nfchans; i++) { + if (audblk->deltbae[i] == DELTA_BIT_NEW) { audblk->deltnseg[i] = bitstream_get(3); - for(j = 0; j < audblk->deltnseg[i] + 1; j++) - { + for(j = 0; j < audblk->deltnseg[i] + 1; j++) { audblk->deltoffst[i][j] = bitstream_get(5); audblk->deltlen[i][j] = bitstream_get(4); audblk->deltba[i][j] = bitstream_get(3); @@ -537,61 +467,15 @@ parse_audblk(bsi_t *bsi,audblk_t *audblk) } /* Check to see if there's any dummy info to get */ - if((audblk->skiple = bitstream_get(1))) - { - uint_16 skip_data; + if((audblk->skiple = bitstream_get(1))) { + uint16_t skip_data; audblk->skipl = bitstream_get(9); - //XXX remove - //fprintf(stderr,"(parse) skipping %d bytes\n",audblk->skipl); - for(i = 0; i < audblk->skipl ; i++) - { + for (i = 0; i < audblk->skipl; i++) { skip_data = bitstream_get(8); - //XXX remove - //fprintf(stderr,"skipped data %2x\n",skip_data); - //if(skip_data != 0) - //{ - //dprintf("(parse) Invalid skipped data %2x\n",skip_data); - //exit(1); - //} } } stats_print_audblk(bsi,audblk); } - -void -parse_auxdata(syncinfo_t *syncinfo) -{ - //FIXME keep this now that we don't really need it? -#if 0 - int i; - int skip_length; - uint_16 crc; - uint_16 auxdatae; - - skip_length = (syncinfo->frame_size * 16) - bitstream_get_total_bits() - 17 - 1; - - //XXX remove - //dprintf("(auxdata) skipping %d auxbits\n",skip_length); - - for(i=0; i < skip_length; i++) - //printf("Skipped bit %i\n",(uint_16)bitstream_get(1)); - bitstream_get(1); - - //get the auxdata exists bit - auxdatae = bitstream_get(1); - - //XXX remove - //dprintf("auxdatae = %i\n",auxdatae); - - //Skip the CRC reserved bit - bitstream_get(1); - - //Get the crc - crc = bitstream_get(16); -#endif -} - - diff --git a/ac3dec/parse.h b/ac3dec/parse.h index cdaee66f4..6264fea1d 100644 --- a/ac3dec/parse.h +++ b/ac3dec/parse.h @@ -21,8 +21,6 @@ * */ -void parse_syncinfo(syncinfo_t *syncinfo,uint_8 *data); +void parse_syncinfo(syncinfo_t *syncinfo,uint8_t *data); void parse_audblk(bsi_t *bsi,audblk_t *audblk); void parse_bsi(bsi_t *bsi); -void parse_auxdata(syncinfo_t *syncinfo); - diff --git a/ac3dec/rematrix.c b/ac3dec/rematrix.c index caa709430..f1df19b19 100644 --- a/ac3dec/rematrix.c +++ b/ac3dec/rematrix.c @@ -28,52 +28,60 @@ #include "ac3_internal.h" -#include "decode.h" #include "rematrix.h" + struct rematrix_band_s { - uint_32 start; - uint_32 end; + uint32_t start; + uint32_t end; +} rematrix_band[] = { + {13, 24}, + {25, 36}, + {37, 60}, + {61, 252} }; -struct rematrix_band_s rematrix_band[] = { {13,24}, {25,36}, {37 ,60}, {61,252}}; -static inline uint_32 min(uint_32 a,uint_32 b); +/** + * + **/ -static inline uint_32 -min(uint_32 a,uint_32 b) +inline uint32_t min (uint32_t a, uint32_t b) { - return (a < b ? a : b); + return (a < b) ? a : b; } -/* This routine simply does stereo rematixing for the 2 channel - * stereo mode */ -void rematrix(audblk_t *audblk, stream_samples_t samples) + +/** + * This routine simply does stereo remartixing for the 2 channel + * stereo mode + **/ + +void rematrix (audblk_t *audblk, stream_samples_t samples) { - uint_32 num_bands; - uint_32 start; - uint_32 end; - uint_32 i,j; - float left,right; + uint32_t num_bands; + uint32_t start; + uint32_t end; + int i,j; - if(!audblk->cplinu || audblk->cplbegf > 2) + if (!audblk->cplinu || audblk->cplbegf > 2) num_bands = 4; else if (audblk->cplbegf > 0) num_bands = 3; else num_bands = 2; - for(i=0;i < num_bands; i++) - { - if(!audblk->rematflg[i]) + for (i=0; i < num_bands; i++) { + if (!audblk->rematflg[i]) continue; start = rematrix_band[i].start; - end = min(rematrix_band[i].end ,12 * audblk->cplbegf + 36); + end = min (rematrix_band[i].end ,12 * audblk->cplbegf + 36); - for(j=start;j < end; j++) - { + for (j=start;j < end; j++) { + float left,right; + left = samples[0][j] + samples[1][j]; right = samples[0][j] - samples[1][j]; samples[0][j] = left; diff --git a/ac3dec/sanity_check.c b/ac3dec/sanity_check.c index 461f20ea9..d475de14f 100644 --- a/ac3dec/sanity_check.c +++ b/ac3dec/sanity_check.c @@ -28,8 +28,11 @@ #include "sanity_check.h" -void -sanity_check_init(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk) +/** + * + **/ + +void sanity_check_init(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk) { syncinfo->magic = AC3_MAGIC_NUMBER; bsi->magic = AC3_MAGIC_NUMBER; @@ -38,94 +41,84 @@ sanity_check_init(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk) audblk->magic3 = AC3_MAGIC_NUMBER; } -void -sanity_check(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk) + +/** + * + **/ + +int sanity_check(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk) { int i; - if(syncinfo->magic != AC3_MAGIC_NUMBER) - { + if(syncinfo->magic != AC3_MAGIC_NUMBER) { fprintf(stderr,"\n** Sanity check failed -- syncinfo magic number **"); - error_flag = 1; + return -1; } - if(bsi->magic != AC3_MAGIC_NUMBER) - { + if(bsi->magic != AC3_MAGIC_NUMBER) { fprintf(stderr,"\n** Sanity check failed -- bsi magic number **"); - error_flag = 1; + return -1; } - if(audblk->magic1 != AC3_MAGIC_NUMBER) - { + if(audblk->magic1 != AC3_MAGIC_NUMBER) { fprintf(stderr,"\n** Sanity check failed -- audblk magic number 1 **"); - error_flag = 1; + return -1; } - if(audblk->magic2 != AC3_MAGIC_NUMBER) - { + if(audblk->magic2 != AC3_MAGIC_NUMBER) { fprintf(stderr,"\n** Sanity check failed -- audblk magic number 2 **"); - error_flag = 1; + return -1; } - if(audblk->magic3 != AC3_MAGIC_NUMBER) - { + if(audblk->magic3 != AC3_MAGIC_NUMBER) { fprintf(stderr,"\n** Sanity check failed -- audblk magic number 3 **"); - error_flag = 1; + return -1; } - for(i = 0;i < 5 ; i++) - { + for(i = 0;i < 5 ; i++) { if (audblk->fbw_exp[i][255] !=0 || audblk->fbw_exp[i][254] !=0 || - audblk->fbw_exp[i][253] !=0) - { + audblk->fbw_exp[i][253] !=0) { fprintf(stderr,"\n** Sanity check failed -- fbw_exp out of bounds **"); - error_flag = 1; + return -1; } if (audblk->fbw_bap[i][255] !=0 || audblk->fbw_bap[i][254] !=0 || - audblk->fbw_bap[i][253] !=0) - { + audblk->fbw_bap[i][253] !=0) { fprintf(stderr,"\n** Sanity check failed -- fbw_bap out of bounds **"); - error_flag = 1; + return -1; } } if (audblk->cpl_exp[255] !=0 || audblk->cpl_exp[254] !=0 || - audblk->cpl_exp[253] !=0) - { + audblk->cpl_exp[253] !=0) { fprintf(stderr,"\n** Sanity check failed -- cpl_exp out of bounds **"); - error_flag = 1; + return -1; } if (audblk->cpl_bap[255] !=0 || audblk->cpl_bap[254] !=0 || - audblk->cpl_bap[253] !=0) - { + audblk->cpl_bap[253] !=0) { fprintf(stderr,"\n** Sanity check failed -- cpl_bap out of bounds **"); - error_flag = 1; + return -1; } - if (audblk->cplmant[255] !=0 || audblk->cplmant[254] !=0 || - audblk->cplmant[253] !=0) - { + if (audblk->cpl_flt[255] !=0 || audblk->cpl_flt[254] !=0 || + audblk->cpl_flt[253] !=0) { fprintf(stderr,"\n** Sanity check failed -- cpl_mant out of bounds **"); - error_flag = 1; + return -1; } - if ((audblk->cplinu == 1) && (audblk->cplbegf > (audblk->cplendf+2))) - { + if ((audblk->cplinu == 1) && (audblk->cplbegf > (audblk->cplendf+2))) { fprintf(stderr,"\n** Sanity check failed -- cpl params inconsistent **"); - error_flag = 1; + return -1; } - for(i=0; i < bsi->nfchans; i++) - { - if((audblk->chincpl[i] == 0) && (audblk->chbwcod[i] > 60)) - { + for(i=0; i < bsi->nfchans; i++) { + if((audblk->chincpl[i] == 0) && (audblk->chbwcod[i] > 60)) { fprintf(stderr,"\n** Sanity check failed -- chbwcod too big **"); - error_flag = 1; + return -1; } } - return; + return 0; } diff --git a/ac3dec/sanity_check.h b/ac3dec/sanity_check.h index c4ca63a21..ead9399c9 100644 --- a/ac3dec/sanity_check.h +++ b/ac3dec/sanity_check.h @@ -23,5 +23,5 @@ #define AC3_MAGIC_NUMBER 0xdeadbeef -void sanity_check_init(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk); -void sanity_check(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk); +void sanity_check_init (syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk); +int sanity_check (syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk); diff --git a/ac3dec/srfft.c b/ac3dec/srfft.c new file mode 100644 index 000000000..4cbb62954 --- /dev/null +++ b/ac3dec/srfft.c @@ -0,0 +1,305 @@ +/* + * srfft.c + * + * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - April 2000 + * + * 64 and 128 point split radix fft for ac3dec + * + * The algorithm is desribed in the book: + * "Computational Frameworks of the Fast Fourier Transform". + * + * The ideas and the the organization of code borrowed from djbfft written by + * D. J. Bernstein <djb@cr.py.to>. djbff can be found at + * http://cr.yp.to/djbfft.html. + * + * srfft.c is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * srfft.c is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdio.h> + +#include "srfft.h" +#include "srfftp.h" + +void fft_8 (complex_t *x); + +void fft_4(complex_t *x) +{ + /* delta_p = 1 here */ + /* x[k] = sum_{i=0..3} x[i] * w^{i*k}, w=e^{-2*pi/4} + */ + + register float yt_r, yt_i, yb_r, yb_i, u_r, u_i, vi_r, vi_i; + + yt_r = x[0].re; + yb_r = yt_r - x[2].re; + yt_r += x[2].re; + + u_r = x[1].re; + vi_i = x[3].re - u_r; + u_r += x[3].re; + + u_i = x[1].im; + vi_r = u_i - x[3].im; + u_i += x[3].im; + + yt_i = yt_r; + yt_i += u_r; + x[0].re = yt_i; + yt_r -= u_r; + x[2].re = yt_r; + yt_i = yb_r; + yt_i += vi_r; + x[1].re = yt_i; + yb_r -= vi_r; + x[3].re = yb_r; + + yt_i = x[0].im; + yb_i = yt_i - x[2].im; + yt_i += x[2].im; + + yt_r = yt_i; + yt_r += u_i; + x[0].im = yt_r; + yt_i -= u_i; + x[2].im = yt_i; + yt_r = yb_i; + yt_r += vi_i; + x[1].im = yt_r; + yb_i -= vi_i; + x[3].im = yb_i; +} + + +void fft_8 (complex_t *x) +{ + /* delta_p = diag{1, sqrt(i)} here */ + /* x[k] = sum_{i=0..7} x[i] * w^{i*k}, w=e^{-2*pi/8} + */ + register float wT1_r, wT1_i, wB1_r, wB1_i, wT2_r, wT2_i, wB2_r, wB2_i; + + wT1_r = x[1].re; + wT1_i = x[1].im; + wB1_r = x[3].re; + wB1_i = x[3].im; + + x[1] = x[2]; + x[2] = x[4]; + x[3] = x[6]; + fft_4(&x[0]); + + + /* x[0] x[4] */ + wT2_r = x[5].re; + wT2_r += x[7].re; + wT2_r += wT1_r; + wT2_r += wB1_r; + wT2_i = wT2_r; + wT2_r += x[0].re; + wT2_i = x[0].re - wT2_i; + x[0].re = wT2_r; + x[4].re = wT2_i; + + wT2_i = x[5].im; + wT2_i += x[7].im; + wT2_i += wT1_i; + wT2_i += wB1_i; + wT2_r = wT2_i; + wT2_r += x[0].im; + wT2_i = x[0].im - wT2_i; + x[0].im = wT2_r; + x[4].im = wT2_i; + + /* x[2] x[6] */ + wT2_r = x[5].im; + wT2_r -= x[7].im; + wT2_r += wT1_i; + wT2_r -= wB1_i; + wT2_i = wT2_r; + wT2_r += x[2].re; + wT2_i = x[2].re - wT2_i; + x[2].re = wT2_r; + x[6].re = wT2_i; + + wT2_i = x[5].re; + wT2_i -= x[7].re; + wT2_i += wT1_r; + wT2_i -= wB1_r; + wT2_r = wT2_i; + wT2_r += x[2].im; + wT2_i = x[2].im - wT2_i; + x[2].im = wT2_i; + x[6].im = wT2_r; + + + /* x[1] x[5] */ + wT2_r = wT1_r; + wT2_r += wB1_i; + wT2_r -= x[5].re; + wT2_r -= x[7].im; + wT2_i = wT1_i; + wT2_i -= wB1_r; + wT2_i -= x[5].im; + wT2_i += x[7].re; + + wB2_r = wT2_r; + wB2_r += wT2_i; + wT2_i -= wT2_r; + wB2_r *= HSQRT2; + wT2_i *= HSQRT2; + wT2_r = wB2_r; + wB2_r += x[1].re; + wT2_r = x[1].re - wT2_r; + + wB2_i = x[5].re; + x[1].re = wB2_r; + x[5].re = wT2_r; + + wT2_r = wT2_i; + wT2_r += x[1].im; + wT2_i = x[1].im - wT2_i; + wB2_r = x[5].im; + x[1].im = wT2_r; + x[5].im = wT2_i; + + /* x[3] x[7] */ + wT1_r -= wB1_i; + wT1_i += wB1_r; + wB1_r = wB2_i - x[7].im; + wB1_i = wB2_r + x[7].re; + wT1_r -= wB1_r; + wT1_i -= wB1_i; + wB1_r = wT1_r + wT1_i; + wB1_r *= HSQRT2; + wT1_i -= wT1_r; + wT1_i *= HSQRT2; + wB2_r = x[3].re; + wB2_i = wB2_r + wT1_i; + wB2_r -= wT1_i; + x[3].re = wB2_i; + x[7].re = wB2_r; + wB2_i = x[3].im; + wB2_r = wB2_i + wB1_r; + wB2_i -= wB1_r; + x[3].im = wB2_i; + x[7].im = wB2_r; +} + + +void fft_asmb(int k, complex_t *x, complex_t *wTB, + const complex_t *d, const complex_t *d_3) +{ + register complex_t *x2k, *x3k, *x4k, *wB; + register float a_r, a_i, a1_r, a1_i, u_r, u_i, v_r, v_i; + + x2k = x + 2 * k; + x3k = x2k + 2 * k; + x4k = x3k + 2 * k; + wB = wTB + 2 * k; + + TRANSZERO(x[0],x2k[0],x3k[0],x4k[0]); + TRANS(x[1],x2k[1],x3k[1],x4k[1],wTB[1],wB[1],d[1],d_3[1]); + + --k; + for(;;) { + TRANS(x[2],x2k[2],x3k[2],x4k[2],wTB[2],wB[2],d[2],d_3[2]); + TRANS(x[3],x2k[3],x3k[3],x4k[3],wTB[3],wB[3],d[3],d_3[3]); + if (!--k) break; + x += 2; + x2k += 2; + x3k += 2; + x4k += 2; + d += 2; + d_3 += 2; + wTB += 2; + wB += 2; + } + +} + +void fft_asmb16(complex_t *x, complex_t *wTB) +{ + register float a_r, a_i, a1_r, a1_i, u_r, u_i, v_r, v_i; + int k = 2; + + /* transform x[0], x[8], x[4], x[12] */ + TRANSZERO(x[0],x[4],x[8],x[12]); + + /* transform x[1], x[9], x[5], x[13] */ + TRANS(x[1],x[5],x[9],x[13],wTB[1],wTB[5],delta16[1],delta16_3[1]); + + /* transform x[2], x[10], x[6], x[14] */ + TRANSHALF_16(x[2],x[6],x[10],x[14]); + + /* transform x[3], x[11], x[7], x[15] */ + TRANS(x[3],x[7],x[11],x[15],wTB[3],wTB[7],delta16[3],delta16_3[3]); + +} + + +void fft_64p_c (complex_t *a) +{ + fft_8(&a[0]); fft_4(&a[8]); fft_4(&a[12]); + fft_asmb16(&a[0], &a[8]); + + fft_8(&a[16]), fft_8(&a[24]); + fft_asmb(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8(&a[32]); fft_4(&a[40]); fft_4(&a[44]); + fft_asmb16(&a[32], &a[40]); + + fft_8(&a[48]); fft_4(&a[56]); fft_4(&a[60]); + fft_asmb16(&a[48], &a[56]); + + fft_asmb(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); +} + + +void fft_128p_c (complex_t *a) +{ + fft_8(&a[0]); fft_4(&a[8]); fft_4(&a[12]); + fft_asmb16(&a[0], &a[8]); + + fft_8(&a[16]), fft_8(&a[24]); + fft_asmb(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8(&a[32]); fft_4(&a[40]); fft_4(&a[44]); + fft_asmb16(&a[32], &a[40]); + + fft_8(&a[48]); fft_4(&a[56]); fft_4(&a[60]); + fft_asmb16(&a[48], &a[56]); + + fft_asmb(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); + + fft_8(&a[64]); fft_4(&a[72]); fft_4(&a[76]); + /* fft_16(&a[64]); */ + fft_asmb16(&a[64], &a[72]); + + fft_8(&a[80]); fft_8(&a[88]); + + /* fft_32(&a[64]); */ + fft_asmb(4, &a[64], &a[80],&delta32[0], &delta32_3[0]); + + fft_8(&a[96]); fft_4(&a[104]), fft_4(&a[108]); + /* fft_16(&a[96]); */ + fft_asmb16(&a[96], &a[104]); + + fft_8(&a[112]), fft_8(&a[120]); + /* fft_32(&a[96]); */ + fft_asmb(4, &a[96], &a[112], &delta32[0], &delta32_3[0]); + + /* fft_128(&a[0]); */ + fft_asmb(16, &a[0], &a[64], &delta128[0], &delta128_3[0]); +} diff --git a/ac3dec/srfft.h b/ac3dec/srfft.h new file mode 100644 index 000000000..7916092a4 --- /dev/null +++ b/ac3dec/srfft.h @@ -0,0 +1,39 @@ +/* + * srfft.h + * + * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - April 2000 + * + * 64 and 128 point split radix fft for ac3dec + * + * The algorithm is desribed in the book: + * "Computational Frameworks of the Fast Fourier Transform". + * + * The ideas and the the organization of code borrowed from djbfft written by + * D. J. Bernstein <djb@cr.py.to>. djbff can be found at + * http://cr.yp.to/djbfft.html. + * + * srfft.h is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * srfft.h is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef SRFFT_H__ +#define SRFFT_H__ + +#include "cmplx.h" + +void fft_64p_c (complex_t *x); +void fft_128p_c (complex_t *x); + +#endif /* SRFFT_H__ */ diff --git a/ac3dec/srfft_kni.S b/ac3dec/srfft_kni.S new file mode 100644 index 000000000..a42a41b14 --- /dev/null +++ b/ac3dec/srfft_kni.S @@ -0,0 +1,289 @@ +/* + * srfft_kni.S + * + * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - October 2000 + * + * + * srfft_kni.S is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * srfft_kni.S is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef __i386__ + +.section .rodata + .align 16 +hsqrt2: .float 0f0.707106781188 + .float 0f0.707106781188 + .float 0f-0.707106781188 + .float 0f-0.707106781188 +C_1: .float 0f-1.0 + .float 0f1.0 + .float 0f-1.0 + .float 0f1.0 + +.text + .align 4 +.global fft_4_kni + .type fft_4_kni, @function +fft_4_kni: + pushl %ebp + movl %esp, %ebp + movl 8(%ebp), %eax /* complex_t * */ + + movaps (%eax), %xmm0 /* x[1] | x[0] */ + movaps 16(%eax), %xmm2 /* x[3] | x[2] */ + movaps %xmm0, %xmm1 /* x[1] | x[0] */ + addps %xmm2, %xmm0 /* x[1] + x[3] | x[0] + x[2] */ + subps %xmm2, %xmm1 /* x[1] - x[3] | x[0] - x[2] */ + xorps %xmm6, %xmm6 + movhlps %xmm1, %xmm4 /* x[1] - x[3] */ + movhlps %xmm0, %xmm3 /* x[1] + x[3] */ + subss %xmm4, %xmm6 /* -(x[1] - x[3]).re */ + movlhps %xmm1, %xmm0 /* x[0] - x[2] | x[0] + x[2] */ + movss %xmm6, %xmm4 /* (x[1] - x[3]).im | (x[3]-x[1]).re */ + movaps %xmm0, %xmm2 /* x[0] - x[2] | x[0] + x[2] */ + shufps $0x14, %xmm4, %xmm3 /* -i*(x[2] - x[3] | x[2] + x[3] */ + addps %xmm3, %xmm0 + subps %xmm3, %xmm2 + movaps %xmm0, (%eax) + movaps %xmm2, 16(%eax) + + leave + ret + + + .align 4 +.global fft_8_kni + .type fft_8_kni, @function +fft_8_kni: + pushl %ebp + movl %esp, %ebp + movl 8(%ebp), %eax /* complext_t */ + + pushl %ebx + movlps (%eax), %xmm0 /* x[0] */ + movlps 32(%eax), %xmm1 /* x[4] */ + movhps 16(%eax), %xmm0 /* x[2] | x[0] */ + movhps 48(%eax), %xmm1 /* x[6] | x[4] */ + movaps %xmm0, %xmm2 /* x[2] | x[0] */ + xorps %xmm3, %xmm3 + addps %xmm1, %xmm0 /* x[2] + x[6] | x[0] + x[4] */ + subps %xmm1, %xmm2 /* x[2] - x[6] | x[0] - x[4] */ + movhlps %xmm0, %xmm5 /* x[2] + x[6] */ + movhlps %xmm2, %xmm4 + movlhps %xmm2, %xmm0 /* x[0] - x[4] | x[0] + x[4] */ + subss %xmm4, %xmm3 /* -(x[2]-x[6]).re */ + movaps %xmm0, %xmm7 /* x[0] - x[4] | x[0] + x[4] */ + movss %xmm3, %xmm4 /* (x[2]-x[6]).im | -(x[2]-x[6]).re */ + movlps 8(%eax), %xmm1 /* x[1] */ + shufps $0x14, %xmm4, %xmm5 /* -i*(x[2] - x[6]) | x[2] + x[6] */ + + addps %xmm5, %xmm0 /* yt */ + subps %xmm5, %xmm7 /* yb */ + + movhps 24(%eax), %xmm1 /* x[3] | x[1] */ + movl $hsqrt2, %ebx + movlps 40(%eax), %xmm2 /* x[5] */ + movhps 56(%eax), %xmm2 /* /x[7] | x[5] */ + movaps %xmm1, %xmm3 /* x[3] | x[1] */ + addps %xmm2, %xmm1 /* x[3] + x[7] | x[1] + x[5] */ + subps %xmm2, %xmm3 /* x[3] - x[7] | x[1] - x[5] */ + movaps (%ebx), %xmm4 /* -1/sqrt2 | -1/sqrt2 | 1/sqrt2 | 1/sqrt2 */ + movaps %xmm3, %xmm6 /* x[3] - x[7] | x[1] - x[5] */ + mulps %xmm4, %xmm3 + shufps $0xc8, %xmm4, %xmm4 /* -1/sqrt2 | 1/sqrt2 | -1/sqrt2 | 1/sqrt2 */ + shufps $0xb1, %xmm6, %xmm6 + mulps %xmm4, %xmm6 + addps %xmm3, %xmm6 /* (-1-i)/sqrt2 * (x[3]-x[7]) | (1-i)/sqrt2 * (x[1] - x[5] */ + movhlps %xmm1, %xmm5 /* x[3] + x[7] */ + movlhps %xmm6, %xmm1 /* (1+i)/sqrt2 * (x[1]-x[5]) | x[1]+x[5] */ + shufps $0xe4, %xmm6, %xmm5 /* (-1-i)/sqrt2 * (x[3]-x[7]) | x[3]+x[7] */ + movaps %xmm1, %xmm3 /* (1-i)/sqrt2 * (x[1]-x[5]) | x[1]+x[5] */ + movl $C_1, %ebx + addps %xmm5, %xmm1 /* u */ + subps %xmm5, %xmm3 /* v */ + movaps %xmm0, %xmm2 /* yb */ + movaps %xmm7, %xmm4 /* yt */ + movaps (%ebx), %xmm5 + mulps %xmm5, %xmm3 + addps %xmm1, %xmm0 /* yt + u */ + subps %xmm1, %xmm2 /* yt - u */ + shufps $0xb1, %xmm3, %xmm3 /* -i * v */ + movaps %xmm0, (%eax) + movaps %xmm2, 32(%eax) + addps %xmm3, %xmm4 /* yb - i*v */ + subps %xmm3, %xmm7 /* yb + i*v */ + movaps %xmm4, 16(%eax) + movaps %xmm7, 48(%eax) + + popl %ebx + leave + ret + + .align 4 +.global fft_asmb_kni + .type fft_asmb, @function +fft_asmb_kni: + pushl %ebp + movl %esp, %ebp + + subl $4, %esp + + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 8(%ebp), %ecx /* k */ + movl 12(%ebp), %eax /* x */ + movl %ecx, -4(%ebp) /* k */ + movl 16(%ebp), %ebx /* wT */ + movl 20(%ebp), %edx /* d */ + movl 24(%ebp), %esi /* d3 */ + shll $4, %ecx /* 16k */ + addl $8, %edx + leal (%eax, %ecx, 2), %edi + addl $8, %esi + + /* TRANSZERO and TRANS */ + movaps (%eax), %xmm0 /* x[1] | x[0] */ + movaps (%ebx), %xmm1 /* wT[1] | wT[0] */ + movaps (%ebx, %ecx), %xmm2 /* wB[1] | wB[0] */ + movlps (%edx), %xmm3 /* d */ + movlps (%esi), %xmm4 /* d3 */ + movhlps %xmm1, %xmm5 /* wT[1] */ + movhlps %xmm2, %xmm6 /* wB[1] */ + shufps $0x50, %xmm3, %xmm3 /* d[1].im | d[1].im | d[1].re | d[1].re */ + shufps $0x50, %xmm4, %xmm4 /* d3[1].im | d3[1].im | d3[i].re | d3[i].re */ + movlhps %xmm5, %xmm5 /* wT[1] | wT[1] */ + movlhps %xmm6, %xmm6 /* wB[1] | wB[1] */ + mulps %xmm3, %xmm5 + mulps %xmm4, %xmm6 + movhlps %xmm5, %xmm7 /* wT[1].im * d[1].im | wT[1].re * d[1].im */ + movlhps %xmm6, %xmm5 /* wB[1].im * d3[1].re | wB[1].re * d3[1].re | wT[1].im * d[1].re | wT[1].re * d[1].re */ + shufps $0xb1, %xmm6, %xmm7 /* wB[1].re * d3[1].im | wB[i].im * d3[1].im | wT[1].re * d[1].im | wT[1].im * d[1].im */ + movl $C_1, %edi + movaps (%edi), %xmm4 + mulps %xmm4, %xmm7 + addps %xmm7, %xmm5 /* wB[1] * d3[1] | wT[1] * d[1] */ + movlhps %xmm5, %xmm1 /* d[1] * wT[1] | wT[0] */ + shufps $0xe4, %xmm5, %xmm2 /* d3[1] * wB[1] | wB[0] */ + movaps %xmm1, %xmm3 /* d[1] * wT[1] | wT[0] */ + leal (%eax, %ecx, 2), %edi + addps %xmm2, %xmm1 /* u */ + subps %xmm2, %xmm3 /* v */ + mulps %xmm4, %xmm3 + movaps (%eax, %ecx), %xmm5 /* xk[1] | xk[0] */ + shufps $0xb1, %xmm3, %xmm3 /* -i * v */ + movaps %xmm0, %xmm2 /* x[1] | x[0] */ + movaps %xmm5, %xmm6 /* xk[1] | xk[0] */ + addps %xmm1, %xmm0 + subps %xmm1, %xmm2 + addps %xmm3, %xmm5 + subps %xmm3, %xmm6 + movaps %xmm0, (%eax) + movaps %xmm2, (%edi) + movaps %xmm5, (%eax, %ecx) + movaps %xmm6, (%edi, %ecx) + addl $16, %eax + addl $16, %ebx + addl $8, %edx + addl $8, %esi + decl -4(%ebp) + +.loop: + movaps (%ebx), %xmm0 /* wT[1] | wT[0] */ + movaps (%edx), %xmm1 /* d[1] | d[0] */ + + movaps (%ebx, %ecx), %xmm4 /* wB[1] | wB[0] */ + movaps (%esi), %xmm5 /* d3[1] | d3[0] */ + + movhlps %xmm0, %xmm2 /* wT[1] */ + movhlps %xmm1, %xmm3 /* d[1] */ + + movhlps %xmm4, %xmm6 /* wB[1] */ + movhlps %xmm5, %xmm7 /* d3[1] */ + + shufps $0x50, %xmm1, %xmm1 /* d[0].im | d[0].im | d[0].re | d[0].re */ + shufps $0x50, %xmm3, %xmm3 /* d[1].im | d[1].im | d[1].re | d[1].re */ + + movlhps %xmm0, %xmm0 /* wT[0] | wT[0] */ + shufps $0x50, %xmm5, %xmm5 /* d3[0].im | d3[0].im | d3[0].re | d3[0].re */ + movlhps %xmm2, %xmm2 /* wT[1] | wT[1] */ + shufps $0x50, %xmm7, %xmm7 /* d3[1].im | d3[1].im | d3[1].re | d3[1].re */ + + mulps %xmm1, %xmm0 /* d[0].im * wT[0].im | d[0].im * wT[0].re | d[0].re * wT[0].im | d[0].re * wT[0].re */ + mulps %xmm3, %xmm2 /* d[1].im * wT[1].im | d[1].im * wT[1].re | d[1].re * wT[1].im | d[1].re * wT[1].re */ + movlhps %xmm4, %xmm4 /* wB[0] | wB[0] */ + movlhps %xmm6, %xmm6 /* wB[1] | wB[1] */ + + movhlps %xmm0, %xmm1 /* d[0].im * wT[0].im | d[0].im * wT[0].re */ + movlhps %xmm2, %xmm0 /* d[1].re * wT[1].im | d[1].re * wT[1].re | d[0].re * wT[0].im | d[0].re * wT[0].re */ + mulps %xmm5, %xmm4 /* wB[0].im * d3[0].im | wB[0].re * d3[0].im | wB[0].im * d3[0].re | wB[0].re * d3[0].re */ + mulps %xmm7, %xmm6 /* wB[1].im * d3[1].im | wB[1].re * d3[1].im | wB[1].im * d3[1].re | wB[1].re * d3[1].re */ + shufps $0xb1, %xmm2, %xmm1 /* d[1].im * wT[1].re | d[1].im * wT[1].im | d[0].im * wT[0].re | d[0].im * wT[0].im */ + movl $C_1, %edi + movaps (%edi), %xmm3 /* 1.0 | -1.0 | 1.0 | -1.0 */ + + movhlps %xmm4, %xmm5 /* wB[0].im * d3[0].im | wB[0].re * d3[0].im */ + mulps %xmm3, %xmm1 /* d[1].im * wT[1].re | -d[1].im * wT[1].im | d[0].im * wT[0].re | -d[0].im * wT[0].im */ + movlhps %xmm6, %xmm4 /* wB[1].im * d3[1].re | wB[1].re * d3[1].re | wB[0].im * d3[0].re | wB[0].im * d3[0].re */ + addps %xmm1, %xmm0 /* wT[1] * d[1] | wT[0] * d[0] */ + + shufps $0xb1, %xmm6, %xmm5 /* wB[1].re * d3[1].im | wB[1].im * d3[1].im | wB[0].re * d3[0].im | wB[0].im * d3[0].im */ + mulps %xmm3, %xmm5 /* wB[1].re * d3[1].im | -wB[1].im * d3[1].im | wB[0].re * d3[0].im | -wB[0].im * d3[0].im */ + addps %xmm5, %xmm4 /* wB[1] * d3[1] | wB[0] * d3[0] */ + + movaps %xmm0, %xmm1 /* wT[1] * d[1] | wT[0] * d[0] */ + addps %xmm4, %xmm0 /* u */ + subps %xmm4, %xmm1 /* v */ + movaps (%eax), %xmm6 /* x[1] | x[0] */ + leal (%eax, %ecx, 2), %edi + mulps %xmm3, %xmm1 + addl $16, %ebx + addl $16, %esi + shufps $0xb1, %xmm1, %xmm1 /* -i * v */ + movaps (%eax, %ecx), %xmm7 /* xk[1] | xk[0] */ + movaps %xmm6, %xmm2 + movaps %xmm7, %xmm4 + addps %xmm0, %xmm6 + subps %xmm0, %xmm2 + movaps %xmm6, (%eax) + movaps %xmm2, (%edi) + addps %xmm1, %xmm7 + subps %xmm1, %xmm4 + addl $16, %edx + movaps %xmm7, (%eax, %ecx) + movaps %xmm4, (%edi, %ecx) + + addl $16, %eax + decl -4(%ebp) + jnz .loop + +.end: + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + + addl $4, %esp + + leave + ret +#endif diff --git a/ac3dec/srfft_kni.h b/ac3dec/srfft_kni.h new file mode 100644 index 000000000..6dc468e34 --- /dev/null +++ b/ac3dec/srfft_kni.h @@ -0,0 +1,30 @@ +/***** +* +* This file is part of the OMS program. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****/ + +#ifndef __SRFF_KNI__ +#define __SRFF_KNI__ + +#include "cmplx.h" + +void fft_4_kni (complex_t *a); +void fft_8_kni (complex_t *a); +void fft_asmb_kni (int, complex_t*, complex_t *, complex_t *, complex_t*); + +#endif diff --git a/ac3dec/srfft_kni_c.c b/ac3dec/srfft_kni_c.c new file mode 100644 index 000000000..d461110fc --- /dev/null +++ b/ac3dec/srfft_kni_c.c @@ -0,0 +1,93 @@ +/* + * srfft_kni.c + * + * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - April 2000 + * + * 64 and 128 point split radix fft for ac3dec + * + * The algorithm is desribed in the book: + * "Computational Frameworks of the Fast Fourier Transform". + * + * The ideas and the the organization of code borrowed from djbfft written by + * D. J. Bernstein <djb@cr.py.to>. djbff can be found at + * http://cr.yp.to/djbfft.html. + * + * srfft.c is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * srfft.c is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef __i386__ + +#include <stdio.h> + +#include "srfft_kni.h" +#include "srfftp.h" + +void fft_64p_kni(complex_t *a) +{ + fft_8_kni(&a[0]); fft_4_kni(&a[8]); fft_4_kni(&a[12]); + fft_asmb_kni(2, &a[0], &a[8], &delta16[0], &delta16_3[0]); + + fft_8_kni(&a[16]), fft_8_kni(&a[24]); + fft_asmb_kni(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8_kni(&a[32]); fft_4_kni(&a[40]); fft_4_kni(&a[44]); + fft_asmb_kni(2, &a[32], &a[40], &delta16[0], &delta16_3[0]); + + fft_8_kni(&a[48]); fft_4_kni(&a[56]); fft_4_kni(&a[60]); + fft_asmb_kni(2, &a[48], &a[56], &delta16[0], &delta16_3[0]); + + fft_asmb_kni(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); +} + + +void fft_128p_kni(complex_t *a) +{ + fft_8_kni(&a[0]); fft_4_kni(&a[8]); fft_4_kni(&a[12]); + fft_asmb_kni(2, &a[0], &a[8], &delta16[0], &delta16_3[0]); + + fft_8_kni(&a[16]), fft_8_kni(&a[24]); + fft_asmb_kni(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8_kni(&a[32]); fft_4_kni(&a[40]); fft_4_kni(&a[44]); + fft_asmb_kni(2, &a[32], &a[40], &delta16[0], &delta16_3[0]); + + fft_8_kni(&a[48]); fft_4_kni(&a[56]); fft_4_kni(&a[60]); + fft_asmb_kni(2, &a[48], &a[56], &delta16[0], &delta16_3[0]); + + fft_asmb_kni(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); + + fft_8_kni(&a[64]); fft_4_kni(&a[72]); fft_4_kni(&a[76]); + /* fft_16(&a[64]); */ + fft_asmb_kni(2, &a[64], &a[72], &delta16[0], &delta16_3[0]); + + fft_8_kni(&a[80]); fft_8_kni(&a[88]); + + /* fft_32(&a[64]); */ + fft_asmb_kni(4, &a[64], &a[80],&delta32[0], &delta32_3[0]); + + fft_8_kni(&a[96]); fft_4_kni(&a[104]), fft_4_kni(&a[108]); + /* fft_16(&a[96]); */ + fft_asmb_kni(2, &a[96], &a[104], &delta16[0], &delta16_3[0]); + + fft_8_kni(&a[112]), fft_8_kni(&a[120]); + /* fft_32(&a[96]); */ + fft_asmb_kni(4, &a[96], &a[112], &delta32[0], &delta32_3[0]); + + /* fft_128(&a[0]); */ + fft_asmb_kni(16, &a[0], &a[64], &delta128[0], &delta128_3[0]); +} + +#endif diff --git a/ac3dec/srfftp.h b/ac3dec/srfftp.h new file mode 100644 index 000000000..6f4471530 --- /dev/null +++ b/ac3dec/srfftp.h @@ -0,0 +1,305 @@ + +/* + * srfftp.h + * + * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - April 2000 + * + * 64 and 128 point split radix fft for ac3dec + * + * The algorithm is desribed in the book: + * "Computational Frameworks of the Fast Fourier Transform". + * + * The ideas and the the organization of code borrowed from djbfft written by + * D. J. Bernstein <djb@cr.py.to>. djbff can be found at + * http://cr.yp.to/djbfft.html. + * + * srfftp.h is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * srfftp.h is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef SRFFTP_H__ +#define SRFFTP_H__ + +#include "cmplx.h" + +static complex_t delta16[4] = + { {1.00000000000000, 0.00000000000000}, + {0.92387953251129, -0.38268343236509}, + {0.70710678118655, -0.70710678118655}, + {0.38268343236509, -0.92387953251129}}; + +static complex_t delta16_3[4] = + { {1.00000000000000, 0.00000000000000}, + {0.38268343236509, -0.92387953251129}, + {-0.70710678118655, -0.70710678118655}, + {-0.92387953251129, 0.38268343236509}}; + +static complex_t delta32[8] = + { {1.00000000000000, 0.00000000000000}, + {0.98078528040323, -0.19509032201613}, + {0.92387953251129, -0.38268343236509}, + {0.83146961230255, -0.55557023301960}, + {0.70710678118655, -0.70710678118655}, + {0.55557023301960, -0.83146961230255}, + {0.38268343236509, -0.92387953251129}, + {0.19509032201613, -0.98078528040323}}; + +static complex_t delta32_3[8] = + { {1.00000000000000, 0.00000000000000}, + {0.83146961230255, -0.55557023301960}, + {0.38268343236509, -0.92387953251129}, + {-0.19509032201613, -0.98078528040323}, + {-0.70710678118655, -0.70710678118655}, + {-0.98078528040323, -0.19509032201613}, + {-0.92387953251129, 0.38268343236509}, + {-0.55557023301960, 0.83146961230255}}; + +static complex_t delta64[16] = + { {1.00000000000000, 0.00000000000000}, + {0.99518472667220, -0.09801714032956}, + {0.98078528040323, -0.19509032201613}, + {0.95694033573221, -0.29028467725446}, + {0.92387953251129, -0.38268343236509}, + {0.88192126434836, -0.47139673682600}, + {0.83146961230255, -0.55557023301960}, + {0.77301045336274, -0.63439328416365}, + {0.70710678118655, -0.70710678118655}, + {0.63439328416365, -0.77301045336274}, + {0.55557023301960, -0.83146961230255}, + {0.47139673682600, -0.88192126434835}, + {0.38268343236509, -0.92387953251129}, + {0.29028467725446, -0.95694033573221}, + {0.19509032201613, -0.98078528040323}, + {0.09801714032956, -0.99518472667220}}; + +static complex_t delta64_3[16] = + { {1.00000000000000, 0.00000000000000}, + {0.95694033573221, -0.29028467725446}, + {0.83146961230255, -0.55557023301960}, + {0.63439328416365, -0.77301045336274}, + {0.38268343236509, -0.92387953251129}, + {0.09801714032956, -0.99518472667220}, + {-0.19509032201613, -0.98078528040323}, + {-0.47139673682600, -0.88192126434836}, + {-0.70710678118655, -0.70710678118655}, + {-0.88192126434835, -0.47139673682600}, + {-0.98078528040323, -0.19509032201613}, + {-0.99518472667220, 0.09801714032956}, + {-0.92387953251129, 0.38268343236509}, + {-0.77301045336274, 0.63439328416365}, + {-0.55557023301960, 0.83146961230255}, + {-0.29028467725446, 0.95694033573221}}; + +static complex_t delta128[32] = + { {1.00000000000000, 0.00000000000000}, + {0.99879545620517, -0.04906767432742}, + {0.99518472667220, -0.09801714032956}, + {0.98917650996478, -0.14673047445536}, + {0.98078528040323, -0.19509032201613}, + {0.97003125319454, -0.24298017990326}, + {0.95694033573221, -0.29028467725446}, + {0.94154406518302, -0.33688985339222}, + {0.92387953251129, -0.38268343236509}, + {0.90398929312344, -0.42755509343028}, + {0.88192126434836, -0.47139673682600}, + {0.85772861000027, -0.51410274419322}, + {0.83146961230255, -0.55557023301960}, + {0.80320753148064, -0.59569930449243}, + {0.77301045336274, -0.63439328416365}, + {0.74095112535496, -0.67155895484702}, + {0.70710678118655, -0.70710678118655}, + {0.67155895484702, -0.74095112535496}, + {0.63439328416365, -0.77301045336274}, + {0.59569930449243, -0.80320753148064}, + {0.55557023301960, -0.83146961230255}, + {0.51410274419322, -0.85772861000027}, + {0.47139673682600, -0.88192126434835}, + {0.42755509343028, -0.90398929312344}, + {0.38268343236509, -0.92387953251129}, + {0.33688985339222, -0.94154406518302}, + {0.29028467725446, -0.95694033573221}, + {0.24298017990326, -0.97003125319454}, + {0.19509032201613, -0.98078528040323}, + {0.14673047445536, -0.98917650996478}, + {0.09801714032956, -0.99518472667220}, + {0.04906767432742, -0.99879545620517}}; + +static complex_t delta128_3[32] = + { {1.00000000000000, 0.00000000000000}, + {0.98917650996478, -0.14673047445536}, + {0.95694033573221, -0.29028467725446}, + {0.90398929312344, -0.42755509343028}, + {0.83146961230255, -0.55557023301960}, + {0.74095112535496, -0.67155895484702}, + {0.63439328416365, -0.77301045336274}, + {0.51410274419322, -0.85772861000027}, + {0.38268343236509, -0.92387953251129}, + {0.24298017990326, -0.97003125319454}, + {0.09801714032956, -0.99518472667220}, + {-0.04906767432742, -0.99879545620517}, + {-0.19509032201613, -0.98078528040323}, + {-0.33688985339222, -0.94154406518302}, + {-0.47139673682600, -0.88192126434836}, + {-0.59569930449243, -0.80320753148065}, + {-0.70710678118655, -0.70710678118655}, + {-0.80320753148065, -0.59569930449243}, + {-0.88192126434835, -0.47139673682600}, + {-0.94154406518302, -0.33688985339222}, + {-0.98078528040323, -0.19509032201613}, + {-0.99879545620517, -0.04906767432742}, + {-0.99518472667220, 0.09801714032956}, + {-0.97003125319454, 0.24298017990326}, + {-0.92387953251129, 0.38268343236509}, + {-0.85772861000027, 0.51410274419322}, + {-0.77301045336274, 0.63439328416365}, + {-0.67155895484702, 0.74095112535496}, + {-0.55557023301960, 0.83146961230255}, + {-0.42755509343028, 0.90398929312344}, + {-0.29028467725446, 0.95694033573221}, + {-0.14673047445536, 0.98917650996478}}; + +#define HSQRT2 0.707106781188; + +#define TRANSZERO(A0,A4,A8,A12) { \ + u_r = wTB[0].re; \ + v_i = u_r - wTB[k*2].re; \ + u_r += wTB[k*2].re; \ + u_i = wTB[0].im; \ + v_r = wTB[k*2].im - u_i; \ + u_i += wTB[k*2].im; \ + a_r = A0.re; \ + a_i = A0.im; \ + a1_r = a_r; \ + a1_r += u_r; \ + A0.re = a1_r; \ + a_r -= u_r; \ + A8.re = a_r; \ + a1_i = a_i; \ + a1_i += u_i; \ + A0.im = a1_i; \ + a_i -= u_i; \ + A8.im = a_i; \ + a1_r = A4.re; \ + a1_i = A4.im; \ + a_r = a1_r; \ + a_r -= v_r; \ + A4.re = a_r; \ + a1_r += v_r; \ + A12.re = a1_r; \ + a_i = a1_i; \ + a_i -= v_i; \ + A4.im = a_i; \ + a1_i += v_i; \ + A12.im = a1_i; \ + } + +#define TRANSHALF_16(A2,A6,A10,A14) {\ + u_r = wTB[2].re; \ + a_r = u_r; \ + u_i = wTB[2].im; \ + u_r += u_i; \ + u_i -= a_r; \ + a_r = wTB[6].re; \ + a1_r = a_r; \ + a_i = wTB[6].im; \ + a_r = a_i - a_r; \ + a_i += a1_r; \ + v_i = u_r - a_r; \ + u_r += a_r; \ + v_r = u_i + a_i; \ + u_i -= a_i; \ + v_i *= HSQRT2; \ + v_r *= HSQRT2; \ + u_r *= HSQRT2; \ + u_i *= HSQRT2; \ + a_r = A2.re; \ + a_i = A2.im; \ + a1_r = a_r; \ + a1_r += u_r; \ + A2.re = a1_r; \ + a_r -= u_r; \ + A10.re = a_r; \ + a1_i = a_i; \ + a1_i += u_i; \ + A2.im = a1_i; \ + a_i -= u_i; \ + A10.im = a_i; \ + a1_r = A6.re; \ + a1_i = A6.im; \ + a_r = a1_r; \ + a1_r += v_r; \ + A6.re = a1_r; \ + a_r -= v_r; \ + A14.re = a_r; \ + a_i = a1_i; \ + a1_i -= v_i; \ + A6.im = a1_i; \ + a_i += v_i; \ + A14.im = a_i; \ + } + +#define TRANS(A1,A5,A9,A13,WT,WB,D,D3) { \ + u_r = WT.re; \ + a_r = u_r; \ + a_r *= D.im; \ + u_r *= D.re; \ + a_i = WT.im; \ + a1_i = a_i; \ + a1_i *= D.re; \ + a_i *= D.im; \ + u_r -= a_i; \ + u_i = a_r; \ + u_i += a1_i; \ + a_r = WB.re; \ + a1_r = a_r; \ + a1_r *= D3.re; \ + a_r *= D3.im; \ + a_i = WB.im; \ + a1_i = a_i; \ + a_i *= D3.re; \ + a1_i *= D3.im; \ + a1_r -= a1_i; \ + a_r += a_i; \ + v_i = u_r - a1_r; \ + u_r += a1_r; \ + v_r = a_r - u_i; \ + u_i += a_r; \ + a_r = A1.re; \ + a_i = A1.im; \ + a1_r = a_r; \ + a1_r += u_r; \ + A1.re = a1_r; \ + a_r -= u_r; \ + A9.re = a_r; \ + a1_i = a_i; \ + a1_i += u_i; \ + A1.im = a1_i; \ + a_i -= u_i; \ + A9.im = a_i; \ + a1_r = A5.re; \ + a1_i = A5.im; \ + a_r = a1_r; \ + a1_r -= v_r; \ + A5.re = a1_r; \ + a_r += v_r; \ + A13.re = a_r; \ + a_i = a1_i; \ + a1_i -= v_i; \ + A5.im = a1_i; \ + a_i += v_i; \ + A13.im = a_i; \ + } + +#endif diff --git a/ac3dec/stats.c b/ac3dec/stats.c index cfeb453f4..4bdad09a1 100644 --- a/ac3dec/stats.c +++ b/ac3dec/stats.c @@ -28,16 +28,16 @@ #include "ac3_internal.h" -#include "decode.h" #include "stats.h" #include "debug.h" - +#if !defined (__GNUC__) || defined (DEBUG) static const char *service_ids[8] = { "CM","ME","VI","HI", "D", "C","E", "VO" }; +#endif struct mixlev_s { @@ -77,9 +77,10 @@ static const char *language[128] = "Bengali", "Belorussian", "Bambora", "Azerbijani", "Assamese", "Armenian", "Arabic", "Amharic" }; + void stats_print_banner(syncinfo_t *syncinfo,bsi_t *bsi) { - fprintf(stdout,"ac3dec-0.6.2-cvs (C) 2000 Aaron Holtzman (aholtzma@ess.engr.uvic.ca)\n"); + // fprintf(stdout,PACKAGE"-"VERSION" (C) 2000 Aaron Holtzman (aholtzma@ess.engr.uvic.ca)\n"); fprintf(stdout,"%d.%d Mode ",bsi->nfchans,bsi->lfeon); fprintf(stdout,"%2.1f KHz",syncinfo->sampling_rate * 1e-3); @@ -87,8 +88,7 @@ void stats_print_banner(syncinfo_t *syncinfo,bsi_t *bsi) if (bsi->langcode && (bsi->langcod < 128)) fprintf(stdout,"%s ", language[bsi->langcod]); - switch(bsi->bsmod) - { + switch(bsi->bsmod) { case 0: fprintf(stdout,"Complete Main Audio Service"); break; @@ -116,12 +116,12 @@ void stats_print_banner(syncinfo_t *syncinfo,bsi_t *bsi) fprintf(stdout,"\n"); } -void stats_print_syncinfo(syncinfo_t *syncinfo) + +void stats_print_syncinfo (syncinfo_t *syncinfo) { dprintf("(syncinfo) "); - switch (syncinfo->fscod) - { + switch (syncinfo->fscod) { case 2: dprintf("32 KHz "); break; @@ -140,9 +140,9 @@ void stats_print_syncinfo(syncinfo_t *syncinfo) syncinfo->frame_size); } + -void stats_print_bsi(bsi_t *bsi) -{ +void stats_print_bsi(bsi_t *bsi) { dprintf("(bsi) "); dprintf("%s",service_ids[bsi->bsmod]); dprintf(" %d.%d Mode ",bsi->nfchans,bsi->lfeon); @@ -154,11 +154,11 @@ void stats_print_bsi(bsi_t *bsi) } + char *exp_strat_tbl[4] = {"R ","D15 ","D25 ","D45 "}; -void stats_print_audblk(bsi_t *bsi,audblk_t *audblk) -{ - uint_32 i; +void stats_print_audblk(bsi_t *bsi,audblk_t *audblk) { + uint32_t i; dprintf("(audblk) "); dprintf("%s ",audblk->cplinu ? "cpl on " : "cpl off"); diff --git a/channels.conf.cable b/channels.conf.cable index c60fb8f6d..60b3eb573 100644 --- a/channels.conf.cable +++ b/channels.conf.cable @@ -1,99 +1,47 @@ -:verschlsselte Fernsehprogramme -Extreme Sport:346:h:0:6900:801:802:0:1:50700 -Bloomberg:346:h:0:6900:811:812:0:1:50701 -Fashion TV:346:h:0:6900:821:822:0:1:50702 -BET ON JAZZ:346:h:0:6900:841:842:0:1:50704 -LANDSCAPE:346:h:0:6900:831:832:0:1:50703 -Einstein:346:h:0:6900:623:624:0:1:50719 -Single TV:346:h:0:6900:621:622:0:1:50706 -Einstein:346:h:0:6900:255:256:0:1:40100 -GOLDSTAR TV:354:h:0:6900:3839:3840:0:1:518 -HEIMATKANAL:354:h:0:6900:2815:2816:0:1:517 -FILMPALAST:354:h:0:6900:2559:2560:0:1:516 -FILMPALAST:354:h:0:6900:1535:1536:0:1:195 -FILMPALAST:354:h:0:6900:1279:1280:0:1:194 -FILMPALAST:354:h:0:6900:255:256:0:1:177 -FILMPALAST:354:h:0:6900:767:768:0:1:179 -FILMPALAST:354:h:0:6900:511:513:0:1:178 -FILMPALAST:354:h:0:6900:1023:1024:0:1:193 -BLUE MOVIE 1:354:h:0:6900:255:256:0:1:513 -BLUE MOVIE 2:354:h:0:6900:255:256:0:1:514 -BLUE MOVIE 3:354:h:0:6900:255:256:0:1:515 -SPORT 1:362:h:0:6900:255:256:0:1:17 -F1 Boxenstrasse:362:h:0:6900:2815:2816:0:1:240 -F1 Cockpit:362:h:0:6900:2559:2560:0:1:242 -F1 Multikanal:362:h:0:6900:2047:2048:0:1:243 -SPORT 1:362:h:0:6900:255:256:0:1:180 -SPORT 1:362:h:0:6900:255:256:0:1:181 -SPORT 1:362:h:0:6900:255:256:0:1:182 -SPORT 1:362:h:0:6900:255:256:0:1:183 -SPORT 1:362:h:0:6900:255:256:0:1:176 -SPORT 1:362:h:0:6900:255:256:0:1:190 -PREMIERE:370:h:0:6900:511:512:0:1:10 -STAR KINO:370:h:0:6900:767:768:0:1:9 -CINE ACTION:370:h:0:6900:1023:1024:0:1:20 -CINE COMEDY:370:h:0:6900:1279:1280:0:1:29 -SCI-FANTASY:370:h:0:6900:1535:1536:0:1:41 -ROMANTIC MOVIES:370:h:0:6900:1791:1792:0:1:11 -BEATE-UHSE.TV:370:h:0:6900:2047:2048:0:1:21 -13 TH STREET:370:h:0:6900:2303:2304:0:1:43 -FOX KIDS:370:h:0:6900:255:256:0:1:22 -SUNSET:378:h:0:6900:1023:1024:0:1:16 -COMEDY:378:h:0:6900:1279:1280:0:1:28 +:verschlsselte Fernsehprogramm +PREMIERE 1:370:h:0:6900:511:512:0:1:10 +PREMIERE 2:370:h:0:6900:1791:1792:0:1:11 +PREMIERE 3:370:h:0:6900:2303:2304:0:1:43 +PREMIERE ACTION:370:h:0:6900:1023:1024:0:1:20 +PREMIERE SCI-FI:370:h:0:6900:1535:1536:0:1:41 +PREMIERE STAR:370:h:0:6900:767:768:0:1:9 +PREMIERE COMEDY:370:h:0:6900:1279:1280:0:1:29 +13 TH STREET:378:h:0:6900:2303:2304:0:1:42 KRIMI &CO:378:h:0:6900:1535:1536:0:1:23 +STUDIO UNIVERSAL:402:h:0:6900:1050:1054:0:1:36 DISCOVERY CHANNEL:378:h:0:6900:1791:1792:0:1:14 -CLASSICA:378:h:0:6900:767:768:0:1:15 -SUPERDOM:378:h:0:6900:2303:2304:0:1:42 -K-TOON:378:h:0:6900:511:512:0:1:12 -SUPERDOM:378:h:0:6900:2047:2048:0:1:192 -SUPERDOM:378:h:0:6900:2559:2560:0:1:187 -JUNIOR:378:h:0:6900:255:256:0:1:19 -SUPERDOM 5:378:h:0:6900:2815:2816:0:1:213 -KICK 1:386:h:0:6900:255:257:0:1:26 -KICK 4:386:h:0:6900:1279:1281:0:1:188 -KICK 4:386:h:0:6900:1535:1536:0:1:189 -SPORT 2:386:h:0:6900:2047:2048:0:1:27 -KICK 4:386:h:0:6900:1023:1024:0:1:186 -KICK 2:386:h:0:6900:2559:2560:0:1:300 -KICK 4:386:h:0:6900:767:769:0:1:185 -SPORT 3:386:h:0:6900:2303:2304:0:1:18 -SUPERDOM 3:386:h:0:6900:3583:3584:0:1:211 -SPORT 4:386:h:0:6900:255:256:0:1:24 -KICK 3:386:h:0:6900:255:256:0:1:301 -KICK 4:386:h:0:6900:255:256:0:1:302 -KICK 4:386:h:0:6900:255:256:0:1:184 -KICK 4:386:h:0:6900:255:256:0:1:191 -EuroNews:394:h:0:6900:255:256:0:1:65039 -SEASONS:402:h:0:6900:1040:1044:0:1:33 DISNEY CHANNEL:402:h:0:6900:1030:1034:0:1:34 -STUDIO UNIVERSAL:402:h:0:6900:1050:1054:0:1:36 +SUNSET:378:h:0:6900:1023:1024:0:1:16 PLANET:402:h:0:6900:1100:1104:0:1:13 -BBC PRIME:402:h:0:6900:255:256:0:1:32 -ATV:402:h:0:6900:255:256:0:1:39 +SEASONS:402:h:0:6900:1040:1044:0:1:33 +CLASSICA:378:h:0:6900:767:768:0:1:15 +GOLDSTAR TV:378:h:0:6900:3839:3840:0:1:518 +FILMPALAST:378:h:0:6900:2559:2560:0:1:516 +HEIMATKANAL:378:h:0:6900:2815:2816:0:1:517 +FOX KIDS:378:h:0:6900:1279:1280:0:1:28 +JUNIOR:378:h:0:6900:255:256:0:1:19 +K-TOON:378:h:0:6900:12:13:0:1:12 :Fernsehprogramme -Leitseite:346:h:0:6900:2254:0:0:0:5004 -Via 1 - Schner Reisen:346:h:0:6900:611:612:0:0:50705 -PREMIERE WORLD:370:h:0:6900:255:256:32:0:8 +Das Erste:410:h:0:6900:101:102:104:0:28106 ZDF:394:h:0:6900:110:120:130:0:28006 -3sat:394:h:0:6900:210:220:230:0:28007 -KiKa:394:h:0:6900:255:256:0:0:28008 -Eurosport:394:h:0:6900:410:420:430:0:28009 ZDF.info:394:h:0:6900:610:620:0:0:28011 -EuroNews:394:h:0:6900:2221:2233:768:0:28015 -ZDF Theaterkanal:394:h:0:6900:1110:1120:0:0:28016 ZDF.doku:394:h:0:6900:660:670:0:0:28014 +ZDF Theaterkanal:394:h:0:6900:3440:3441:0:0:28016 +3sat:394:h:0:6900:210:220:230:0:28007 +KiKa:394:h:0:6900:310:320:330:0:28008 +EuroNews:394:h:0:6900:2221:2233:768:0:28015 +Eurosport:394:h:0:6900:410:420:430:0:28009 +DW-tv:610:h:0:6900:634:632:0:0:6101 +CNBC:394:h:0:6900:510:520:530:0:28010 Test-R:410:h:0:6900:901:902:104:0:28130 Bayerisches FS:410:h:0:6900:201:202:204:0:28107 WDR FERNSEHEN:410:h:0:6900:601:602:604:0:28111 arte:410:h:0:6900:401:402:404:0:28109 SR Fernsehen Suedwest:410:h:0:6900:501:502:504:0:28110 -Das Erste:410:h:0:6900:101:102:104:0:28106 hessen fernsehen:410:h:0:6900:301:302:304:0:28108 BR-alpha:410:h:0:6900:701:702:704:0:28112 SWR Fernsehen:410:h:0:6900:801:802:804:0:28113 -Phoenix:410:h:0:6900:255:256:0:0:28114 -Phoenix:410:h:0:6900:255:256:0:0:61225 -ARD-Online-Kanal:426:h:0:6900:0:1801:0:0:28218 +Phoenix:410:h:0:6900:901:902:0:0:28114 EinsExtra:426:h:0:6900:101:102:0:0:28201 EinsFestival:426:h:0:6900:201:202:0:0:28202 EinsMuXx:426:h:0:6900:301:302:0:0:28203 @@ -101,36 +49,87 @@ MDR FERNSEHEN:426:h:0:6900:401:402:404:0:28204 ORB-Fernsehen:426:h:0:6900:501:502:504:0:28205 B1 Berlin:426:h:0:6900:601:602:604:0:28206 N3:426:h:0:6900:2401:2402:2404:0:28224 -TV Polonia:434:h:0:6900:641:642:0:0:53204 -Kanal D:434:h:0:6900:651:652:0:0:53205 -RTP international:434:h:0:6900:661:662:0:0:53206 +:Mediavision +Extreme Sport:346:h:0:6900:801:802:0:1:50700 +Bloomberg:346:h:0:6900:811:812:0:1:50701 +Single TV:346:h:0:6900:621:622:0:1:50706 +Fashion TV:346:h:0:6900:821:822:0:1:50702 +BET ON JAZZ:346:h:0:6900:841:842:0:1:50704 +LANDSCAPE:346:h:0:6900:831:832:0:1:50703 +Einstein:346:h:0:6900:623:624:0:1:50719 +Leitseite:346:h:0:6900:2254:0:0:0:5004 +Via 1 - Schner Reisen:346:h:0:6900:611:612:0:0:50705 +Parlamentsfernsehen:610:h:0:6900:33:36:47:0:6100 +:Diverse TV-Sender +TV Polonia:434:h:0:6900:641:642:0:1:53204 +Kanal D:434:h:0:6900:651:652:0:1:53205 +RTP international:434:h:0:6900:661:662:0:1:53206 +ERT-Sat:434:h:0:6900:691:692:0:1:53209 +CNE:434:h:0:6900:4056:4057:0:1:53208 +ZEE TV:442:h:0:6900:517:773:0:1:53301 +NTV i:442:h:0:6900:514:515:0:1:53302 +Leonardo:610:h:0:6900:653:652:0:1:6102 +Alice:610:h:0:6900:651:650:0:1:6103 +Nuvolari:610:h:0:6900:649:648:0:1:6104 ATV:434:h:0:6900:631:632:0:0:53203 -ERT-Sat:434:h:0:6900:691:692:0:0:53209 -CNE:434:h:0:6900:255:256:0:0:53208 -ERT-Sat:434:h:0:6900:255:256:0:0:48587 -ZEE TV:442:h:0:6900:517:773:0:0:53301 -NTV i:442:h:0:6900:514:515:0:0:53302 -:verschlsselte Radioprogramme -LOVE SONGS:362:h:0:6900:0:320:0:1:163 -MUSICALS:362:h:0:6900:0:336:0:1:164 -EASY LISTENING:362:h:0:6900:0:304:0:1:162 -HITLISTE:362:h:0:6900:0:784:0:1:150 -ALTERNATIVE ROCK:362:h:0:6900:0:800:0:1:151 -DANCE:362:h:0:6900:0:816:0:1:152 -COUNTRY:362:h:0:6900:0:352:0:1:153 -CLASSIC ROCK:362:h:0:6900:0:544:0:1:154 -FILMMUSIK:362:h:0:6900:0:368:0:1:155 -DEUTSCHE HITS:362:h:0:6900:0:384:0:1:156 -SOUL CLASSICS:362:h:0:6900:0:400:0:1:157 -TRK MZIGI:362:h:0:6900:0:560:0:1:158 -GOLD:362:h:0:6900:0:576:0:1:159 -KLASSIK POPULR:362:h:0:6900:0:592:0:1:145 -KLASS. SYMPHONIEN:362:h:0:6900:0:608:0:1:146 -OPER & VOKALMUSIK:362:h:0:6900:0:624:0:1:147 -BAROCKMUSIK:362:h:0:6900:0:640:0:1:148 -SCHLAGER:378:h:0:6900:0:320:0:1:166 -VOLKSMUSIK:378:h:0:6900:0:336:0:1:167 -OLD GOLD:378:h:0:6900:0:304:0:1:165 +unknown:434:h:0:6900:2570:2571:0:0:18954 +TW1:610:h:0:6900:6106:6107:0:0:6106 +unknown:346:h:0:6900:2930:2931:0:0:11122 +unknown:394:h:0:6900:1844:1845:0:1:59188 +unknown:410:h:0:6900:627:628:0:1:627 +PREMIERE WORLD:370:h:0:6900:255:256:32:0:8 +:Premiere World Bundesliga +SUPERDOM:386:h:0:6900:255:257:0:1:26 +Superdom:362:h:0:6900:255:256:0:1:26 +Spiel 1:362:h:0:6900:255:256,257:0:1:17 +Spiel 2:362:h:0:6900:2047:2048,2049:0:1:240 +BuLi-Konferenz:362:h:0:6900:3071:3072,3073:0:1:208 +BuLi-Spiel 1:362:h:0:6900:3327:3328,3329:0:1:209 +BuLi-Spiel 2:362:h:0:6900:2303:2304,2305:0:1:210 +BuLi-Spiel 3:362:h:0:6900:3583:3584,3585:0:1:211 +BuLi-Spiel 4:362:h:0:6900:2559:2560,2561:0:1:212 +BuLi-Spiel 5:362:h:0:6900:2815:2816,2817:0:1:213 +:Premiere Sport +PR-SPORT 1:362:h:0:6900:255:256:0:1:17 +PR-SPORT 2:362:h:0:6900:3327:3328:0:1:27 +PR-SPORT 3:362:h:0:6900:2815:2816:0:1:18 +:Premiere Formel 1 +F1 Studio:362:h:0:6900:255:256:0:1:17 +F1 Box:362:h:0:6900:2047:2048:0:1:240 +F1 Verfolger:362:h:0:6900:2303:2304:0:1:241 +F1 Cockpit:362:h:0:6900:2559:2560:0:1:242 +F1 Multi:362:h:0:6900:2815:2816:0:1:243 +F1 Info:362:h:0:6900:3071:3072:0:1:244 +:Premiere Cinedom 1 +Cinedom 1A:362:h:0:6900:1535:1536,1537:0:1:176 +Cinedom 1B:386:h:0:6900:1535:1536,1537:0:1:178 +Cinedom 1C:362:h:0:6900:511:512,513:0:1:180 +Cinedom 1D:354:h:0:6900:511:512,513:0:1:190 +:Premiere Cinedom 2 +Cinedom 2A:386:h:0:6900:1791:1792:0:1:179 +Cinedom 2B:362:h:0:6900:1279:1280:0:1:183 +Cinedom 2C:386:h:0:6900:511:512:0:1:184 +Cinedom 2D:386:h:0:6900:1279:1280:0:1:188 +Cinedom 2E:354:h:0:6900:1023:1024:0:1:193 +: Premiere Cinedom 3 +Cinedom 3A:362:h:0:6900:1023:1024:0:1:182 +Cinedom 3B:386:h:0:6900:767:768:0:1:185 +Cinedom 3C:354:h:0:6900:2559:2560:0:1:192 +Cinedom 3D:354:h:0:6900:1535:1536:0:1:195 +: Premiere Cinedom 4 +Cinedom 4A:362:h:0:6900:767:768:0:1:181 +Cinedom 4B:386:h:0:6900:2047:2048:0:1:187 +Cinedom 4C:354:h:0:6900:767:768:0:1:191 +: Premiere Cinedom 5 +Cinedom 5A:386:h:0:6900:1023:1024:0:1:186 +Cinedom 5B:354:h:0:6900:1279:1280:0:1:194 +: Premiere Cinedom Deluxe +CINEDOM DELUXE:354:h:0:6900:255:256,257;259:0:1:189 +:Premiere Erotic +BEATE-UHSE.TV:354:h:0:6900:3839:3840:0:1:21 +BLUE MOVIE 1:354:h:0:6900:1791:1792:0:1:513 +BLUE MOVIE 2:354:h:0:6900:2047:2048:0:1:514 +BLUE MOVIE 3:354:h:0:6900:2303:2304:0:1:515 :Radioprogramme 100,6:354:h:0:6900:0:1312:0:0:161 DLR-Berlin:394:h:0:6900:0:710:0:0:28012 @@ -142,26 +141,49 @@ Bremen 2:410:h:0:6900:0:3801:0:0:28128 Bayern 1:410:h:0:6900:0:3601:0:0:28126 NDR 4 Info:410:h:0:6900:0:3701:0:0:28127 SR 1:410:h:0:6900:0:3901:0:0:28129 -HR2 plus:410:h:0:6900:0:3401:0:0:28124 -HR2:410:h:0:6900:0:3301:0:0:28123 -hr-chronos:410:h:0:6900:0:3201:0:0:28122 +hr-klassik:410:h:0:6900:0:3401:0:0:28124 +hr2:410:h:0:6900:0:3301:0:0:28123 HR XXL:410:h:0:6900:0:3501:0:0:28125 +hr-chronos:410:h:0:6900:0:3201:0:0:28122 Radio 3:426:h:0:6900:0:701:0:0:28207 MDR KULTUR:426:h:0:6900:0:801:0:0:28208 Fritz:426:h:0:6900:0:901:0:0:28209 JUMP:426:h:0:6900:0:1001:0:0:28210 MDR info:426:h:0:6900:0:1101:0:0:28211 SPUTNIK:426:h:0:6900:0:1201:0:0:28212 -SFB4 Multikulti:426:h:0:6900:0:1301:0:0:28213 +RADIOmultikulti:426:h:0:6900:0:1301:0:0:28213 SWR-2:426:h:0:6900:0:1401:0:0:28214 WDR3:426:h:0:6900:0:1501:0:0:28215 WDR Radio 5:426:h:0:6900:0:1601:0:0:28216 -All Jazz:442:h:0:6900:0:535:0:0:53350 +:verschlsselte Radioprogramme +KLASSIK POPULR:378:h:0:6900:0:592:0:1:145 +KLASS. SYMPHONIEN:378:h:0:6900:0:608:0:1:146 +OPER & VOKALMUSIK:378:h:0:6900:0:624:0:1:147 +BAROCKMUSIK:378:h:0:6900:0:640:0:1:148 +JAZZ:378:h:0:6900:0:656:0:1:149 +HITLISTE:378:h:0:6900:0:784:0:1:150 +ALTERNATIVE ROCK:378:h:0:6900:0:800:0:1:151 +DANCE:378:h:0:6900:0:816:0:1:152 +COUNTRY:378:h:0:6900:0:352:0:1:153 +CLASSIC ROCK:378:h:0:6900:0:544:0:1:154 +FILMMUSIK:378:h:0:6900:0:368:0:1:155 +DEUTSCHE HITS:402:h:0:6900:0:1156:0:1:156 +SOUL CLASSICS:402:h:0:6900:0:1161:0:1:157 +TRK MZIGI:402:h:0:6900:0:1166:0:1:158 +GOLD:402:h:0:6900:0:1171:0:1:159 +EASY LISTENING:402:h:0:6900:0:1201:0:1:162 +LOVE SONGS:402:h:0:6900:0:1191:0:1:163 +MUSICALS:402:h:0:6900:0:1196:0:1:164 +OLD GOLD:402:h:0:6900:0:1186:0:1:165 +SCHLAGER:402:h:0:6900:0:1176:0:1:166 +VOLKSMUSIK:402:h:0:6900:0:1181:0:1:167 +All Jazz:442:h:0:6900:0:535:0:1:53350 Cristal New Age:442:h:0:6900:0:536:0:0:53351 -Movie Sounds:442:h:0:6900:0:537:0:0:53352 -Sinfonica:442:h:0:6900:0:538:0:0:53353 -Opernfestival:442:h:0:6900:0:539:0:0:53354 -Barock Fantasie:442:h:0:6900:0:540:0:0:53355 -Musica Camerata:442:h:0:6900:0:541:0:0:53356 -Musica Antica:442:h:0:6900:0:542:0:0:53357 -Adagio:442:h:0:6900:0:543:0:0:53358 +Movie Sounds:442:h:0:6900:0:537:0:1:53352 +Sinfonica:442:h:0:6900:0:538:0:1:53353 +Opernfestival:442:h:0:6900:0:539:0:1:53354 +Barock Fantasie:442:h:0:6900:0:540:0:1:53355 +Musica Camerata:442:h:0:6900:0:541:0:1:53356 +Musica Antica:442:h:0:6900:0:542:0:1:53357 +Adagio:442:h:0:6900:0:543:0:1:53358 +Jazz Legends:442:h:0:6900:0:544:0:1:53359 diff --git a/config.c b/config.c index 8e0cce300..27cd62edf 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.52 2001/07/27 13:45:28 kls Exp $ + * $Id: config.c 1.54 2001/08/11 15:34:42 kls Exp $ */ #include "config.h" @@ -320,7 +320,7 @@ char *cTimer::buffer = NULL; cTimer::cTimer(bool Instant) { startTime = stopTime = 0; - recording = false; + recording = pending = false; active = Instant; cChannel *ch = Channels.GetByNumber(cDvbApi::CurrentChannel()); channel = ch ? ch->number : 0; @@ -343,7 +343,7 @@ cTimer::cTimer(bool Instant) cTimer::cTimer(const cEventInfo *EventInfo) { startTime = stopTime = 0; - recording = false; + recording = pending = false; active = true; cChannel *ch = Channels.GetByServiceID(EventInfo->GetServiceID()); channel = ch ? ch->number : 0; @@ -570,6 +570,11 @@ void cTimer::SetRecording(bool Recording) isyslog(LOG_INFO, "timer %d %s", Index() + 1, recording ? "start" : "stop"); } +void cTimer::SetPending(bool Pending) +{ + pending = Pending; +} + cTimer *cTimer::GetMatch(void) { time_t t = time(NULL); // all timers must be checked against the exact same time to correctly handle Priority! @@ -764,7 +769,7 @@ cSetup::cSetup(void) LnbSLOF = 11700; LnbFrequLo = 9750; LnbFrequHi = 10600; - DiSEqC = 1; + DiSEqC = 0; SetSystemTime = 0; MarginStart = 2; MarginStop = 10; diff --git a/config.h b/config.h index bbf5d6594..c9faf6cb4 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.57 2001/08/06 16:44:38 kls Exp $ + * $Id: config.h 1.59 2001/08/11 15:28:21 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.90" +#define VDRVERSION "0.91" #define MaxBuffer 10000 @@ -122,7 +122,7 @@ class cTimer : public cListObject { static const char *ToText(cTimer *Timer); public: enum { MaxFileName = 256 }; - bool recording; + bool recording, pending; int active; int channel; int day; @@ -145,6 +145,7 @@ class cTimer : public cListObject { time_t StartTime(void); time_t StopTime(void); void SetRecording(bool Recording); + void SetPending(bool Pending); static cTimer *GetMatch(void); static int TimeToInt(int t); static time_t Day(time_t t); diff --git a/dvbapi.c b/dvbapi.c index 0524f00f2..4c3861054 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.101 2001/08/06 16:24:13 kls Exp $ + * $Id: dvbapi.c 1.106 2001/08/12 15:09:42 kls Exp $ */ //#define DVDDEBUG 1 @@ -53,13 +53,10 @@ extern "C" { // The size of the array used to buffer video data: // (must be larger than MINVIDEODATA - see remux.h) #define VIDEOBUFSIZE (1024*1024) -#define AC3_BUFFER_SIZE (6*1024*16) // The maximum size of a single frame: #define MAXFRAMESIZE (192*1024) -#define FRAMESPERSEC 25 - // The maximum file size is limited by the range that can be covered // with 'int'. 4GB might be possible (if the range is considered // 'unsigned'), 2GB should be possible (even if the range is considered @@ -85,6 +82,8 @@ extern "C" { #define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls +#define FATALERRNO (errno != EAGAIN && errno != EINTR) + typedef unsigned char uchar; const char *IndexToHMSF(int Index, bool WithFrame) @@ -161,7 +160,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) if (index) { f = open(fileName, O_RDONLY); if (f >= 0) { - if ((int)read(f, index, buf.st_size) != buf.st_size) { + if ((int)safe_read(f, index, buf.st_size) != buf.st_size) { esyslog(LOG_ERR, "ERROR: can't read from file '%s'", fileName); delete index; index = NULL; @@ -225,7 +224,7 @@ bool cIndexFile::CatchUp(void) int offset = (last + 1) * sizeof(tIndex); int delta = (newLast - last) * sizeof(tIndex); if (lseek(f, offset, SEEK_SET) == offset) { - if (read(f, &index[last + 1], delta) != delta) { + if (safe_read(f, &index[last + 1], delta) != delta) { esyslog(LOG_ERR, "ERROR: can't read from index"); delete index; index = NULL; @@ -252,7 +251,7 @@ void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) { if (f >= 0) { tIndex i = { FileOffset, PictureType, FileNumber, 0 }; - if (write(f, &i, sizeof(i)) != sizeof(i)) { + if (safe_write(f, &i, sizeof(i)) != sizeof(i)) { esyslog(LOG_ERR, "ERROR: can't write to index file"); close(f); f = -1; @@ -545,7 +544,7 @@ void cRecordBuffer::Input(void) t = time(NULL); } else if (r < 0) { - if (errno != EAGAIN) { + if (FATALERRNO) { LOG_ERROR; if (errno != EBUFFEROVERFLOW) break; @@ -572,8 +571,9 @@ void cRecordBuffer::Output(void) int r = 0; for (;;) { int g = Get(b + r, sizeof(b) - r); - if (g > 0) { + if (g > 0) r += g; + if (r > 0) { int Count = r, Result; const uchar *p = remux.Process(b, Count, Result, &pictureType); if (p) { @@ -583,7 +583,7 @@ void cRecordBuffer::Output(void) if (index && pictureType != NO_PICTURE) index->Write(pictureType, fileName.Number(), fileSize); while (Result > 0) { - int w = write(recordFile, p, Result); + int w = safe_write(recordFile, p, Result); if (w < 0) { LOG_ERROR_STR(fileName.Name()); recording = false; @@ -622,7 +622,7 @@ int ReadFrame(int f, uchar *b, int Length, int Max) esyslog(LOG_ERR, "ERROR: frame larger than buffer (%d > %d)", Length, Max); Length = Max; } - int r = read(f, b, Length); + int r = safe_read(f, b, Length); if (r < 0) LOG_ERROR; return r; @@ -708,7 +708,7 @@ void cPlayBuffer::Output(void) p += w; r -= w; } - else if (w < 0 && errno != EAGAIN) { + else if (w < 0 && FATALERRNO) { LOG_ERROR; Stop(); return; @@ -925,7 +925,7 @@ void cReplayBuffer::Input(void) } else if (r == 0) eof = true; - else if (r < 0 && errno != EAGAIN) { + else if (r < 0 && FATALERRNO) { LOG_ERROR; break; } @@ -1172,7 +1172,6 @@ class cDVDplayBuffer : public cPlayBuffer { int logAudioTrack; int maxAudioTrack; - ac3_config_t ac3_config; enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat; uchar *ac3data; int ac3inp; @@ -1231,10 +1230,7 @@ cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD skipCnt = 0; logAudioTrack = 0; canToggleAudioTrack = true;//XXX determine from cDVD! - ac3_config.num_output_ch = 2; - // ac3_config.flags = /* mm_accel() | */ MM_ACCEL_MLIB; - ac3_config.flags = 0; - ac3_init(&ac3_config); + ac3dec_init(); data = new uchar[1024 * DVD_VIDEO_LB_LEN]; ac3data = new uchar[AC3_BUFFER_SIZE]; ac3inp = ac3outp = 0; @@ -1823,9 +1819,9 @@ void cDVDplayBuffer::handleAC3(unsigned char *sector, int length) } else { if (ac3stat == AC3_PLAY) - ac3_decode_data(sector, sector+length, 0, &ac3inp, &ac3outp, (char *)ac3data); + ac3dec_decode_data(sector, sector + length, 0, &ac3inp, &ac3outp, (char *)ac3data); else if (ac3stat == AC3_START) { - ac3_decode_data(sector, sector+length, 1, &ac3inp, &ac3outp, (char *)ac3data); + ac3dec_decode_data(sector, sector + length, 1, &ac3inp, &ac3outp, (char *)ac3data); ac3stat = AC3_PLAY; } } @@ -2078,7 +2074,7 @@ void cTransferBuffer::Input(void) } } else if (r < 0) { - if (errno != EAGAIN) { + if (FATALERRNO) { LOG_ERROR; if (errno != EBUFFEROVERFLOW) break; @@ -2112,7 +2108,7 @@ void cTransferBuffer::Output(void) p += w; r -= w; } - else if (w < 0 && errno != EAGAIN) { + else if (w < 0 && FATALERRNO) { LOG_ERROR; Stop(); return; @@ -2221,7 +2217,7 @@ void cCuttingBuffer::Action(void) } LastIFrame = 0; } - write(toFile, buffer, Length); + safe_write(toFile, buffer, Length); toIndex->Write(PictureType, toFileName->Number(), FileSize); FileSize += Length; if (!LastIFrame) @@ -2316,6 +2312,7 @@ cDvbApi::cDvbApi(int n) transferringFromDvbApi = NULL; ca = 0; priority = -1; + cardIndex = n; // Devices that are only present on DVB-C or DVB-S cards: @@ -2423,7 +2420,7 @@ cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) int index = Ca - 1; for (int i = 0; i < MAXDVBAPI; i++) { if (dvbApi[i]) { - if (i == index) { // means we need exactly _this_ device + if (dvbApi[i]->CardIndex() == index) { // means we need exactly _this_ device d = dvbApi[i]; break; } @@ -2450,15 +2447,6 @@ cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) ? d : NULL; } -int cDvbApi::Index(void) -{ - for (int i = 0; i < MAXDVBAPI; i++) { - if (dvbApi[i] == this) - return i; - } - return -1; -} - bool cDvbApi::Probe(const char *FileName) { if (access(FileName, F_OK) == 0) { @@ -2956,7 +2944,7 @@ int cDvbApi::SetModeRecord(void) SetPids(true); if (fd_dvr >= 0) close(fd_dvr); - fd_dvr = OstOpen(DEV_OST_DVR, Index(), O_RDONLY | O_NONBLOCK); + fd_dvr = OstOpen(DEV_OST_DVR, CardIndex(), O_RDONLY | O_NONBLOCK); if (fd_dvr < 0) LOG_ERROR; return fd_dvr; @@ -3066,7 +3054,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, // If this card can't receive this channel, we must not actually switch // the channel here, because that would irritate the driver when we // start replaying in Transfer Mode immediately after switching the channel: - bool NeedsTransferMode = (this == PrimaryDvbApi && Ca && Ca != Index() + 1); + bool NeedsTransferMode = (this == PrimaryDvbApi && Ca && Ca != CardIndex() + 1); if (!NeedsTransferMode) { @@ -3282,6 +3270,10 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) if (!MakeDirs(FileName, true)) return false; + // Make sure the disk is up and running: + + SpinUpDisk(FileName); + // Create recording buffer: recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1, aPid2, dPid1, dPid2); @@ -3505,7 +3497,7 @@ void cEITScanner::Process(void) if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) { time_t now = time(NULL); if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) { - for (int i = 0; i < cDvbApi::NumDvbApis; i++) { + for (int i = 0; i < MAXDVBAPI; i++) { cDvbApi *DvbApi = cDvbApi::GetDvbApi(i + 1, MAXPRIORITY); if (DvbApi) { if (DvbApi != cDvbApi::PrimaryDvbApi || (cDvbApi::NumDvbApis == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) { diff --git a/dvbapi.h b/dvbapi.h index 41193ae74..2cd57bfa1 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.44 2001/08/05 15:57:45 kls Exp $ + * $Id: dvbapi.h 1.46 2001/08/11 12:22:01 kls Exp $ */ #ifndef __DVBAPI_H @@ -40,6 +40,8 @@ typedef struct CRect { signed short x, y, width, height; }; +#define FRAMESPERSEC 25 + const char *IndexToHMSF(int Index, bool WithFrame = false); // Converts the given index to a string, optionally containing the frame number. int HMSFToIndex(const char *HMSF); @@ -93,6 +95,7 @@ class cDvbApi { private: static cDvbApi *dvbApi[MAXDVBAPI]; static int useDvbApi; + int cardIndex; public: static cDvbApi *PrimaryDvbApi; static void SetUseDvbApi(int n); @@ -111,8 +114,8 @@ class cDvbApi { // will be returned. // The caller must check whether the returned DVB device is actually // recording and stop recording if necessary. - int Index(void); - // Returns the index of this DvbApi. + int CardIndex(void) { return cardIndex; } + // Returns the card index of this DvbApi (0 ... MAXDVBAPI - 1). static bool Probe(const char *FileName); // Probes for existing DVB devices. static bool Init(void); diff --git a/eit.c b/eit.c index 3de610209..14738f3b2 100644 --- a/eit.c +++ b/eit.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.16 2001/05/26 10:58:01 kls Exp $ + * $Id: eit.c 1.19 2001/08/12 15:04:37 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -1099,10 +1099,12 @@ bool cEIT::WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, // --- cSIProcessor ---------------------------------------------------------- #define MAX_FILTERS 20 +#define EPGDATAFILENAME "epg.data" int cSIProcessor::numSIProcessors = 0; cSchedules *cSIProcessor::schedules = NULL; cMutex cSIProcessor::schedulesMutex; +const char *cSIProcessor::epgDataFileName = EPGDATAFILENAME; /** */ cSIProcessor::cSIProcessor(const char *FileName) @@ -1129,6 +1131,20 @@ cSIProcessor::~cSIProcessor() delete fileName; } +void cSIProcessor::SetEpgDataFileName(const char *FileName) +{ + epgDataFileName = NULL; + if (FileName) + epgDataFileName = strdup(DirectoryOk(FileName) ? AddDirectory(FileName, EPGDATAFILENAME) : FileName); +} + +const char *cSIProcessor::GetEpgDataFileName(void) +{ + if (epgDataFileName) + return *epgDataFileName == '/' ? epgDataFileName : AddDirectory(VideoDirectory, epgDataFileName); + return NULL; +} + void cSIProcessor::SetStatus(bool On) { LOCK_THREAD; @@ -1174,16 +1190,18 @@ void cSIProcessor::Action() schedulesMutex.Unlock(); lastCleanup = now; } - if (now - lastDump > 600) + if (epgDataFileName && now - lastDump > 600) { LOCK_THREAD; schedulesMutex.Lock(); - FILE *f = fopen(AddDirectory(VideoDirectory, "epg.data"), "w"); + FILE *f = fopen(GetEpgDataFileName(), "w"); if (f) { schedules->Dump(f); fclose(f); } + else + LOG_ERROR; lastDump = now; schedulesMutex.Unlock(); } @@ -1211,11 +1229,11 @@ void cSIProcessor::Action() { /* read section */ unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) - if (read(filters[a].handle, buf, 3) == 3) + if (safe_read(filters[a].handle, buf, 3) == 3) { int seclen = ((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF); int pid = filters[a].pid; - int n = read(filters[a].handle, buf + 3, seclen); + int n = safe_read(filters[a].handle, buf + 3, seclen); if (n == seclen) { seclen += 3; diff --git a/eit.h b/eit.h index e6bbd13e6..d4ba69f69 100644 --- a/eit.h +++ b/eit.h @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.7 2001/05/25 12:56:53 kls Exp $ + * $Id: eit.h 1.8 2001/08/11 09:06:17 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -126,6 +126,7 @@ class cSIProcessor : public cThread { static int numSIProcessors; static cSchedules *schedules; static cMutex schedulesMutex; + static const char *epgDataFileName; bool masterSIProcessor; bool useTStime; SIP_FILTER *filters; @@ -137,6 +138,8 @@ class cSIProcessor : public cThread { public: cSIProcessor(const char *FileName); ~cSIProcessor(); + static void SetEpgDataFileName(const char *FileName); + static const char *GetEpgDataFileName(void); void SetStatus(bool On); bool SetUseTSTime(bool use); bool SetCurrentServiceID(unsigned short servid); diff --git a/i18n.c b/i18n.c index ebc366d9d..3d75c245d 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.27 2001/08/02 14:40:16 kls Exp $ + * $Id: i18n.c 1.31 2001/08/11 13:22:24 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -164,7 +164,7 @@ const tPhrase Phrases[] = { "Eventi", "Uitzending", "Evento", - "Evnement", + "Evnement", "Hendelse" }, { "Summary", @@ -330,13 +330,13 @@ const tPhrase Phrases[] = { "Langue", "Sprk", }, - { "Eject DVD", - "DVD auswerfen", - "", // TODO + { "Eject", + "Auswerfen", "", // TODO "", // TODO "", // TODO "", // TODO + "Ejection", "", // TODO }, // Confirmations: @@ -413,14 +413,14 @@ const tPhrase Phrases[] = { "Polarisation", "Polaritet", }, - { "Diseqc", - "Diseqc", - "Diseqc", - "Diseqc", - "Diseqc", - "Diseqc", - "Diseqc", - "Diseqc", + { "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", + "DiSEqC", }, { "Srate", "Srate", @@ -428,7 +428,7 @@ const tPhrase Phrases[] = { "Srate", "Srate", "Srate", - "Srate", + "Frq. Symbole", "Symbolrate", }, { "Vpid", @@ -437,7 +437,7 @@ const tPhrase Phrases[] = { "Vpid", "Vpid", "Vpid", - "Vpid", + "PID Vido", "Video pid", }, { "Apid1", @@ -446,7 +446,7 @@ const tPhrase Phrases[] = { "Apid1", "Apid1", "Apid1", - "Apid1", + "PID Audio (1)", "Audio pid1", }, { "Apid2", @@ -455,7 +455,7 @@ const tPhrase Phrases[] = { "Apid2", "Apid2", "Apid2", - "Apid2", + "PID Audio (2)", "Audio pid2", }, { "Dpid1", @@ -464,7 +464,7 @@ const tPhrase Phrases[] = { "Dpid1", "Dpid1", "Dpid1", - "Dpid1", + "PID AC3 (1)", "AC3 pid1", }, { "Dpid2", @@ -473,7 +473,7 @@ const tPhrase Phrases[] = { "Dpid2", "Dpid2", "Dpid2", - "Dpid2", + "PID AC3 (2)", "AC3 pid2", }, { "Tpid", @@ -482,7 +482,7 @@ const tPhrase Phrases[] = { "Tpid", "Tpid", "Tpid", - "Tpid", + "PID Tltexte", "Teletext pid", }, { "CA", @@ -491,7 +491,7 @@ const tPhrase Phrases[] = { "CA", "CA", "CA", - "CA", + "Cryptage", "Kortleser", }, { "Pnr", @@ -500,7 +500,7 @@ const tPhrase Phrases[] = { "Pnr", "Pnr", "Pnr", - "Pnr", + "Num. Progr.", "Program Id", }, // Timer parameters: @@ -710,7 +710,7 @@ const tPhrase Phrases[] = { "LnbSLOF", "LnbSLOF", "LnbSLOF", - "LnbSLOF", + "Limite de bandes LNB", "LO-grensefrekvens", }, { "LnbFrequLo", @@ -827,6 +827,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Position infos chanes", "", // TODO }, { "OSDwidth", @@ -835,6 +836,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Largeur affichage", "", // TODO }, { "OSDheight", @@ -843,6 +845,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Hauteur affichage", "", // TODO }, // The days of the week: @@ -1098,6 +1101,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "haut", "", // TODO }, { "bottom", @@ -1106,6 +1110,15 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "bas", + "", // TODO + }, + { "Jump: ", // note the trailing blank + "Springen: ", + "", // TODO + "", // TODO + "", // TODO + "", // TODO "", // TODO }, { " Stop replaying", // note the leading blank! @@ -1141,7 +1154,7 @@ const tPhrase Phrases[] = { "Cambio su card DVB primaria...", "Eerste DVB-kaart wordt omgeschakeld...", "A mudar placa DVB primaria...", - "Changement de carte DVB...", + "Changement de carte DVB principale...", "Bytter hoved DVB-enhet... ", }, { "Up/Dn for new location - OK to move", diff --git a/interface.c b/interface.c index 03dca06f2..e2d83b359 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.39 2001/07/28 14:57:52 kls Exp $ + * $Id: interface.c 1.40 2001/08/07 16:23:28 kls Exp $ */ #include "interface.h" @@ -328,7 +328,7 @@ void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvb { if (open && Text) { const int w = Width() / 4; - int l = (w - strlen(Text)) / 2; + int l = (w - int(strlen(Text))) / 2; if (l < 0) l = 0; cDvbApi::PrimaryDvbApi->Fill(Index * w, -1, w, 1, BgColor); diff --git a/menu.c b/menu.c index e25b23041..0f89fab32 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.95 2001/08/05 16:09:41 kls Exp $ + * $Id: menu.c 1.103 2001/08/12 12:42:37 kls Exp $ */ #include "menu.h" @@ -545,7 +545,7 @@ cMenuEditChannel::cMenuEditChannel(int Index) Add(new cMenuEditStrItem( tr("Name"), data.name, sizeof(data.name), FileNameChars)); Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency, 10000, 13000)); //TODO exact limits??? Add(new cMenuEditChrItem( tr("Polarization"), &data.polarization, "hv")); - Add(new cMenuEditIntItem( tr("Diseqc"), &data.diseqc, 0, 10)); //TODO exact limits??? + Add(new cMenuEditIntItem( tr("DiSEqC"), &data.diseqc, 0, 10)); //TODO exact limits??? Add(new cMenuEditIntItem( tr("Srate"), &data.srate, 22000, 30000)); //TODO exact limits - toggle??? Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0xFFFE)); Add(new cMenuEditIntItem( tr("Apid1"), &data.apid1, 0, 0xFFFE)); @@ -1813,10 +1813,10 @@ cMenuMain::cMenuMain(bool Replaying) delete buffer; } if (cVideoCutter::Active()) - Add(new cOsdItem(hk(tr(" Cancel editing")), osCancelEdit)); + Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit)); const char *DVDbutton = #ifdef DVDSUPPORT - cDVD::DiscOk() ? tr("Eject DVD") : NULL; + cDVD::DiscOk() ? tr("Eject") : NULL; #else NULL; #endif //DVDSUPPORT @@ -2070,14 +2070,15 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer = new cTimer(true); Timers.Add(timer); Timers.Save(); - asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), dvbApi->Index() + 1); + asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), dvbApi->CardIndex() + 1); } + timer->SetPending(true); timer->SetRecording(true); if (Channels.SwitchTo(timer->channel, dvbApi)) { cRecording Recording(timer); if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority)) Recording.WriteSummary(); - Interface->DisplayRecording(dvbApi->Index(), true); + Interface->DisplayRecording(dvbApi->CardIndex(), true); } else cThread::EmergencyExit(true); @@ -2102,7 +2103,7 @@ void cRecordControl::Stop(bool KeepInstant) Timers.Save(); } timer = NULL; - Interface->DisplayRecording(dvbApi->Index(), false); + Interface->DisplayRecording(dvbApi->CardIndex(), false); } } @@ -2134,8 +2135,8 @@ bool cRecordControls::Start(cTimer *Timer) } } } - else if (!Timer || Timer->priority >= Setup.PrimaryLimit) - esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch); + else if (!Timer || (Timer->priority >= Setup.PrimaryLimit && !Timer->pending)) + isyslog(LOG_ERR, "no free DVB device to record channel %d!", ch); } else esyslog(LOG_ERR, "ERROR: channel %d not defined!", ch); @@ -2158,7 +2159,7 @@ void cRecordControls::Stop(cDvbApi *DvbApi) for (int i = 0; i < MAXDVBAPI; i++) { if (RecordControls[i]) { if (RecordControls[i]->Uses(DvbApi)) { - isyslog(LOG_INFO, "stopping recording on DVB device %d due to higher priority", DvbApi->Index() + 1); + isyslog(LOG_INFO, "stopping recording on DVB device %d due to higher priority", DvbApi->CardIndex() + 1); RecordControls[i]->Stop(true); } } @@ -2256,6 +2257,7 @@ cReplayControl::cReplayControl(void) visible = shown = displayFrames = false; lastCurrent = lastTotal = -1; timeoutShow = 0; + timeSearchActive = false; if (fileName) { marks.Load(fileName); dvbApi->StartReplay(fileName); @@ -2305,10 +2307,8 @@ void cReplayControl::ClearLastReplayed(const char *FileName) void cReplayControl::Show(int Seconds) { if (!visible) { - Interface->Open(Setup.OSDwidth, -3); - needsFastResponse = visible = true; shown = ShowProgress(true); - if (Seconds > 0) + if (shown && Seconds > 0) timeoutShow = time(NULL) + Seconds; } } @@ -2326,6 +2326,10 @@ bool cReplayControl::ShowProgress(bool Initial) int Current, Total; if (dvbApi->GetIndex(Current, Total) && Total > 0) { + if (!visible) { + Interface->Open(Setup.OSDwidth, -3); + needsFastResponse = visible = true; + } if (Initial) { Interface->Clear(); if (title) @@ -2358,11 +2362,104 @@ bool cReplayControl::ShowProgress(bool Initial) return false; } +void cReplayControl::TimeSearchDisplay(void) +{ + char buf[64]; + int len; + + strcpy(buf, tr("Jump: ")); + len = strlen(buf); + + switch (timeSearchPos) { + case 1: sprintf(buf + len, "%01d-:--", timeSearchHH / 10); break; + case 2: sprintf(buf + len, "%02d:--", timeSearchHH); break; + case 3: sprintf(buf + len, "%02d:%01d-", timeSearchHH, timeSearchMM / 10); break; + case 4: sprintf(buf + len, "%02d:%02d", timeSearchHH, timeSearchMM); break; + default: sprintf(buf + len, "--:--"); break; + } + + Interface->Write(12, 2, buf); +} + +void cReplayControl::TimeSearchProcess(eKeys Key) +{ + int Seconds = timeSearchHH * 3600 + timeSearchMM * 60; + switch (Key) { + case k0 ... k9: + { + int n = Key - k0; + int s = (lastTotal / FRAMESPERSEC); + int m = s / 60 % 60; + int h = s / 3600; + switch (timeSearchPos) { + case 0: if (n * 10 <= h) { + timeSearchHH = n * 10; + timeSearchPos++; + } + break; + case 1: if (timeSearchHH + n <= h) { + timeSearchHH += n; + timeSearchPos++; + } + break; + case 2: if (n <= 5 && timeSearchHH * 60 + n * 10 <= h * 60 + m) { + timeSearchMM += n * 10; + timeSearchPos++; + } + break; + case 3: if (timeSearchHH * 60 + timeSearchMM + n <= h * 60 + m) { + timeSearchMM += n; + timeSearchPos++; + } + break; + } + TimeSearchDisplay(); + } + break; + case kLeft: + case kRight: + dvbApi->SkipSeconds(Seconds * (Key == kRight ? 1 : -1)); + timeSearchActive = false; + break; + case kUp: + case kDown: + dvbApi->Goto(Seconds * FRAMESPERSEC, Key == kDown); + timeSearchActive = false; + break; + default: + timeSearchActive = false; + break; + } + + if (!timeSearchActive) { + if (timeSearchHide) + Hide(); + else + Interface->Fill(12, 2, Width() - 22, 1, clrBackground); + } +} + +void cReplayControl::TimeSearch(void) +{ + timeSearchHH = timeSearchMM = timeSearchPos = 0; + timeSearchHide = false; + if (!visible) { + Show(); + if (visible) + timeSearchHide = true; + else + return; + } + TimeSearchDisplay(); + timeSearchActive = true; +} + void cReplayControl::MarkToggle(void) { int Current, Total; if (dvbApi->GetIndex(Current, Total, true)) { cMark *m = marks.Get(Current); + lastCurrent = -1; // triggers redisplay if (m) marks.Del(m); else { @@ -2454,6 +2551,10 @@ eOSState cReplayControl::ProcessKey(eKeys Key) } bool DisplayedFrames = displayFrames; displayFrames = false; + if (timeSearchActive && Key != kNone) { + TimeSearchProcess(Key); + return osContinue; + } switch (Key) { // Positioning: case kUp: dvbApi->Play(); break; @@ -2462,6 +2563,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key) case kLeft: dvbApi->Backward(); break; case kRight|k_Release: case kRight: dvbApi->Forward(); break; + case kRed: TimeSearch(); break; case kGreen|k_Repeat: case kGreen: dvbApi->SkipSeconds(-60); break; case kYellow|k_Repeat: @@ -2496,7 +2598,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key) } } if (DisplayedFrames && !displayFrames) - Interface->Fill(0, 2, Width() / 2, 1, clrBackground); + Interface->Fill(0, 2, 11, 1, clrBackground); return osContinue; } diff --git a/menu.h b/menu.h index c47e5cbd8..f75ca8670 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.22 2001/08/05 16:04:58 kls Exp $ + * $Id: menu.h 1.23 2001/08/11 14:08:50 kls Exp $ */ #ifndef _MENU_H @@ -102,6 +102,11 @@ class cReplayControl : public cOsdBase { bool visible, shown, displayFrames; int lastCurrent, lastTotal; time_t timeoutShow; + bool timeSearchActive, timeSearchHide; + int timeSearchHH, timeSearchMM, timeSearchPos; + void TimeSearchDisplay(void); + void TimeSearchProcess(eKeys Key); + void TimeSearch(void); void Show(int Seconds = 0); void Hide(void); static char *fileName; diff --git a/recording.c b/recording.c index ddca1a4b2..0190d108f 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.32 2001/06/16 10:33:20 kls Exp $ + * $Id: recording.c 1.33 2001/08/12 15:09:59 kls Exp $ */ #define _GNU_SOURCE @@ -141,7 +141,7 @@ int cResumeFile::Read(void) if (fileName) { int f = open(fileName, O_RDONLY); if (f >= 0) { - if (read(f, &resume, sizeof(resume)) != sizeof(resume)) { + if (safe_read(f, &resume, sizeof(resume)) != sizeof(resume)) { resume = -1; LOG_ERROR_STR(fileName); } @@ -158,7 +158,7 @@ bool cResumeFile::Save(int Index) if (fileName) { int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (f >= 0) { - if (write(f, &Index, sizeof(Index)) != sizeof(Index)) + if (safe_write(f, &Index, sizeof(Index)) != sizeof(Index)) LOG_ERROR_STR(fileName); close(f); return true; @@ -243,7 +243,7 @@ cRecording::cRecording(const char *FileName) int size = buf.st_size; summary = new char[size + 1]; // +1 for terminating 0 if (summary) { - int rbytes = read(f, summary, size); + int rbytes = safe_read(f, summary, size); if (rbytes >= 0) { summary[rbytes] = 0; if (rbytes != size) diff --git a/remote.c b/remote.c index db8fa870d..eed91105b 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16. * - * $Id: remote.c 1.23 2001/07/27 10:17:19 kls Exp $ + * $Id: remote.c 1.24 2001/08/12 15:07:26 kls Exp $ */ #include "remote.h" @@ -199,7 +199,7 @@ int cRcIoRCU::ReceiveByte(int TimeoutMs) // Returns the byte if one was received within a timeout, -1 otherwise if (cFile::FileReady(f, TimeoutMs)) { unsigned char b; - if (read(f, &b, 1) == 1) + if (safe_read(f, &b, 1) == 1) return b; else LOG_ERROR; @@ -436,7 +436,7 @@ void cRcIoLIRC::Action(void) LOCK_THREAD; - if (cFile::FileReady(f, REPEATLIMIT) && read(f, buf, sizeof(buf)) > 21) { + if (cFile::FileReady(f, REPEATLIMIT) && safe_read(f, buf, sizeof(buf)) > 21) { if (!receivedData) { // only accept new data the previous data has been fetched int count; sscanf(buf, "%*x %x %29s", &count, LastKeyName); // '29' in '%29s' is LIRC_KEY_BUF-1! diff --git a/svdrp.c b/svdrp.c index a626fdade..d3bceec1d 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.20 2001/07/22 13:58:48 kls Exp $ + * $Id: svdrp.c 1.21 2001/08/12 15:10:16 kls Exp $ */ #define _GNU_SOURCE @@ -264,7 +264,7 @@ bool cSVDRP::Send(const char *s, int length) { if (length < 0) length = strlen(s); - int wbytes = write(file, s, length); + int wbytes = safe_write(file, s, length); if (wbytes == length) return true; if (wbytes < 0) { @@ -920,7 +920,7 @@ void cSVDRP::Process(void) lastActivity = time(NULL); if (file.Ready(false)) { unsigned char c; - int r = read(file, &c, 1); + int r = safe_read(file, &c, 1); if (r > 0) { if (c == '\n' || c == 0x00) { // strip trailing whitespace: diff --git a/tools.c b/tools.c index c75efbb99..e6aba17a5 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.35 2001/08/05 12:38:06 kls Exp $ + * $Id: tools.c 1.39 2001/08/12 15:12:54 kls Exp $ */ #define _GNU_SOURCE @@ -15,6 +15,7 @@ #if defined(DEBUG_OSD) #include <ncurses.h> #endif +#include <stdlib.h> #include <sys/time.h> #include <unistd.h> @@ -22,9 +23,33 @@ int SysLogLevel = 3; +ssize_t safe_read(int filedes, void *buffer, size_t size) +{ + for (;;) { + ssize_t p = read(filedes, buffer, size); + if (p < 0 && errno == EINTR) { + dsyslog(LOG_INFO, "EINTR while reading from file handle %d - retrying", filedes); + continue; + } + return p; + } +} + +ssize_t safe_write(int filedes, const void *buffer, size_t size) +{ + for (;;) { + ssize_t p = write(filedes, buffer, size); + if (p < 0 && errno == EINTR) { + dsyslog(LOG_INFO, "EINTR while writing to file handle %d - retrying", filedes); + continue; + } + return p; + } +} + void writechar(int filedes, char c) { - write(filedes, &c, sizeof(c)); + safe_write(filedes, &c, sizeof(c)); } char *readline(FILE *f) @@ -312,6 +337,38 @@ char *ReadLink(const char *FileName) return TargetName ? strdup(TargetName) : NULL; } +bool SpinUpDisk(const char *FileName) +{ + static char *buf = NULL; + for (int n = 0; n < 10; n++) { + delete buf; + if (DirectoryOk(FileName)) + asprintf(&buf, "%s/vdr-%06d", *FileName ? FileName : ".", n); + else + asprintf(&buf, "%s.vdr-%06d", FileName, n); + if (access(buf, F_OK) != 0) { // the file does not exist + timeval tp1, tp2; + gettimeofday(&tp1, NULL); + int f = open(buf, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + // O_SYNC doesn't work on all file systems + if (f >= 0) { + close(f); + system("sync"); + remove(buf); + gettimeofday(&tp2, NULL); + double seconds = (((long long)tp2.tv_sec * 1000000 + tp2.tv_usec) - ((long long)tp1.tv_sec * 1000000 + tp1.tv_usec)) / 1000000.0; + if (seconds > 0.5) + dsyslog(LOG_INFO, "SpinUpDisk took %.2f seconds\n", seconds); + return true; + } + else + LOG_ERROR_STR(buf); + } + } + esyslog(LOG_ERR, "ERROR: SpinUpDisk failed"); + return false; +} + // --- cFile ----------------------------------------------------------------- bool cFile::files[FD_SETSIZE] = { false }; diff --git a/tools.h b/tools.h index b4a0cb672..bf2e46b52 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.26 2001/05/20 08:29:45 kls Exp $ + * $Id: tools.h 1.28 2001/08/12 15:13:02 kls Exp $ */ #ifndef __TOOLS_H @@ -33,6 +33,8 @@ extern int SysLogLevel; template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }; +ssize_t safe_read(int filedes, void *buffer, size_t size); +ssize_t safe_write(int filedes, const void *buffer, size_t size); void writechar(int filedes, char c); char *readline(FILE *f); char *strn0cpy(char *dest, const char *src, size_t n); @@ -50,6 +52,7 @@ bool MakeDirs(const char *FileName, bool IsDirectory = false); bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false); char *ReadLink(const char *FileName); +bool SpinUpDisk(const char *FileName); class cFile { private: diff --git a/vdr.c b/vdr.c index 15a69de06..af305419a 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.61 2001/08/05 16:15:51 kls Exp $ + * $Id: vdr.c 1.63 2001/08/11 15:33:30 kls Exp $ */ #include <getopt.h> @@ -84,6 +84,7 @@ int main(int argc, char *argv[]) { "config", required_argument, NULL, 'c' }, { "daemon", no_argument, NULL, 'd' }, { "device", required_argument, NULL, 'D' }, + { "epgfile", required_argument, NULL, 'E' }, { "help", no_argument, NULL, 'h' }, { "log", required_argument, NULL, 'l' }, { "port", required_argument, NULL, 'p' }, @@ -91,12 +92,12 @@ int main(int argc, char *argv[]) { "dvd", required_argument, NULL, 'V' }, { "watchdog", required_argument, NULL, 'w' }, { "terminal", required_argument, NULL, 't' }, - { 0 } + { NULL } }; int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "a:c:dD:hl:p:v:V:w:t:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:t:v:V:w:", long_options, &option_index)) != -1) { switch (c) { case 'a': cDvbApi::SetAudioCommand(optarg); break; @@ -113,27 +114,34 @@ int main(int argc, char *argv[]) fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg); return 2; break; + case 'E': cSIProcessor::SetEpgDataFileName(*optarg != '-' ? optarg : NULL); + break; case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80| " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n" " -c DIR, --config=DIR read config files from DIR (default is to read them\n" " from the video directory)\n" - " -h, --help display this help and exit\n" " -d, --daemon run in daemon mode\n" " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n" " there may be several -D options (default: all DVB\n" " devices will be used)\n" + " -E FILE --epgfile=FILE write the EPG data into the given FILE (default is\n" + " %s); use '-E-' to disable this\n" + " if FILE is a directory, the default EPG file will be\n" + " created in that directory\n" + " -h, --help display this help and exit\n" " -l LEVEL, --log=LEVEL set log level (default: 3)\n" " 0 = no logging, 1 = errors only,\n" " 2 = errors and info, 3 = errors, info and debug\n" " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" " 0 turns off SVDRP\n" + " -t TTY, --terminal=TTY controlling tty\n" " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" " -V DEV, --dvd=DEV use DEV as the DVD device (default: %s)\n" " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n" " seconds (default: %d); '0' disables the watchdog\n" - " -t TTY, --terminal=TTY controlling tty\n" "\n" "Report bugs to <vdr-bugs@cadsoft.de>\n", + cSIProcessor::GetEpgDataFileName() ? cSIProcessor::GetEpgDataFileName() : "'-'", DEFAULTSVDRPPORT, VideoDirectory, #ifdef DVDSUPPORT @@ -317,9 +325,8 @@ int main(int argc, char *argv[]) if (!Menu) { cTimer *Timer = cTimer::GetMatch(); if (Timer) { - if (!cRecordControls::Start(Timer)) { - //TODO need to do something to prevent the timer from hitting over and over again... - } + if (!cRecordControls::Start(Timer)) + Timer->SetPending(true); } cRecordControls::Process(); } From 371bf0665eda455c67926999f52b4850cd8529e4 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sat, 18 Aug 2001 18:00:00 +0200 Subject: [PATCH 022/307] Version 0.92 - The "channel not sync'ed" log message now also lists the card number. - Now using the EIT services from 'libdtv' (thanks to Rolf Hakenes), which provides EPG information for NVOD ("Near Video On Demand") channels. - Doing some bug fixing on the EPG data (some tv stations apparently have their own idea on how to fill in the data...). The level up to which EPG bugs are fixed can be controlled with the EPGBugfixLevel parameter in the "Setup" menu (see MANUAL for details, and cEventInfo::FixEpgBugs() in eit.c for the actual implementation). - Fixed broken recordings after a driver buffer overflow. - Fixed the chirping sound after Pause/Play of a DVD (thanks to Andreas Schultz). --- CONTRIBUTORS | 3 + HISTORY | 14 + MANUAL | 18 + Makefile | 19 +- config.c | 5 +- config.h | 5 +- dvbapi.c | 24 +- eit.c | 669 +++++------------ eit.h | 15 +- i18n.c | 11 +- libdtv/COPYING | 339 +++++++++ libdtv/Makefile | 73 ++ libdtv/README | 27 + libdtv/liblx/COPYING | 339 +++++++++ libdtv/liblx/Makefile | 62 ++ libdtv/liblx/liblx.h | 448 +++++++++++ libdtv/liblx/xListFuncs.c | 187 +++++ libdtv/liblx/xMemMgt.c | 621 +++++++++++++++ libdtv/libsi/COPYING | 339 +++++++++ libdtv/libsi/Makefile | 83 ++ libdtv/libsi/README | 2 + libdtv/libsi/include/libsi.h | 816 ++++++++++++++++++++ libdtv/libsi/include/si_tables.h | 1205 ++++++++++++++++++++++++++++++ libdtv/libsi/si_debug_services.c | 487 ++++++++++++ libdtv/libsi/si_debug_services.h | 217 ++++++ libdtv/libsi/si_parser.c | 881 ++++++++++++++++++++++ libdtv/libvdr/COPYING | 339 +++++++++ libdtv/libvdr/Makefile | 62 ++ libdtv/libvdr/libvdr.c | 169 +++++ libdtv/libvdr/libvdr.h | 111 +++ menu.c | 38 +- menu.h | 4 +- remux.c | 21 +- tools.c | 28 +- tools.h | 4 +- 35 files changed, 7179 insertions(+), 506 deletions(-) create mode 100644 libdtv/COPYING create mode 100644 libdtv/Makefile create mode 100644 libdtv/README create mode 100644 libdtv/liblx/COPYING create mode 100644 libdtv/liblx/Makefile create mode 100644 libdtv/liblx/liblx.h create mode 100644 libdtv/liblx/xListFuncs.c create mode 100644 libdtv/liblx/xMemMgt.c create mode 100644 libdtv/libsi/COPYING create mode 100644 libdtv/libsi/Makefile create mode 100644 libdtv/libsi/README create mode 100644 libdtv/libsi/include/libsi.h create mode 100644 libdtv/libsi/include/si_tables.h create mode 100644 libdtv/libsi/si_debug_services.c create mode 100644 libdtv/libsi/si_debug_services.h create mode 100644 libdtv/libsi/si_parser.c create mode 100644 libdtv/libvdr/COPYING create mode 100644 libdtv/libvdr/Makefile create mode 100644 libdtv/libvdr/libvdr.c create mode 100644 libdtv/libvdr/libvdr.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 241c86140..c055c1759 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -129,3 +129,6 @@ Artur Skawina <skawina@geocities.com> Werner Fink <werner@suse.de> for making I/O more robust by handling EINTR + +Rolf Hakenes <hakenes@hippomi.de> + for providing 'libdtv' and adapting the EIT mechanisms to it diff --git a/HISTORY b/HISTORY index 715b66823..b76067bd0 100644 --- a/HISTORY +++ b/HISTORY @@ -649,3 +649,17 @@ Video Disk Recorder Revision History - If there is no free DVB device to record, the log message will now be given only once. - Made I/O more robust by handling EINTR (thanks to Werner Fink). + +2001-08-18: Version 0.92 + +- The "channel not sync'ed" log message now also lists the card number. +- Now using the EIT services from 'libdtv' (thanks to Rolf Hakenes), which + provides EPG information for NVOD ("Near Video On Demand") channels. +- Doing some bug fixing on the EPG data (some tv stations apparently have + their own idea on how to fill in the data...). The level up to which EPG + bugs are fixed can be controlled with the EPGBugfixLevel parameter in the + "Setup" menu (see MANUAL for details, and cEventInfo::FixEpgBugs() in eit.c + for the actual implementation). +- Fixed broken recordings after a driver buffer overflow. +- Fixed the chirping sound after Pause/Play of a DVD (thanks to Andreas + Schultz). diff --git a/MANUAL b/MANUAL index 17f024836..9d7748120 100644 --- a/MANUAL +++ b/MANUAL @@ -351,6 +351,24 @@ Video Disk Recorder User's Manual A value of '0' completely turns off scanning on both single and multiple card systems. + EPGBugfixLevel = 2 Some tv stations transmit weirdly formatted EPG data. + VDR attempts to fix these bugs up to the given level: + 0 = no EPG fixing + 1 = basic fixing of text location (Title, Subtitle and + Extended Description) + 2 = removal of excess whitespace and hyphens + 3 = fixing the date in timestamps between 00:00 and 06:00 + (use with care - hopefully one day Pro7 and Kabel1 + will learn how to read the clock/calender) + Default is '2', which will do all textual fixes, but + leaves out the timestamp fixes, since these might cause + recordings to fail. Use '3' at your own risk. + Note that after changing the setting of this parameter + any EPG data that has already been received will remain + in its existing format - only newly received data will + be fixed accordingly. Restart VDR if you want to make sure + all data is fixed. + SVDRPTimeout = 300 The time (in seconds) of inactivity on an open SVDRP connection after which the connection is automatically closed. Default is 300, a value of 0 means no timeout. diff --git a/Makefile b/Makefile index 7fcc62a8c..067f34abc 100644 --- a/Makefile +++ b/Makefile @@ -4,16 +4,19 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.25 2001/08/10 16:46:45 kls Exp $ +# $Id: Makefile 1.26 2001/08/15 13:56:11 kls Exp $ .DELETE_ON_ERROR: DVBDIR = ../DVB DVDDIR = ../DVD AC3DIR = ./ac3dec +DTVDIR = ./libdtv INCLUDES = -I$(DVBDIR)/ost/include +DTVLIB = $(DTVDIR)/libdtv.a + ifdef DVD INCLUDES += -I$(DVDDIR)/libdvdread LIBDIRS += -L$(DVDDIR)/libdvdread/dvdread/.libs @@ -57,10 +60,10 @@ font: genfontfile fontfix.c fontosd.c # Dependencies: config.o : config.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h recording.h remux.h ringbuffer.h thread.h tools.h videodir.h +dvbapi.o : dvbapi.c $(AC3DIR)/ac3.h config.h dvbapi.h dvbosd.h dvd.h eit.h font.h recording.h remux.h ringbuffer.h thread.h tools.h videodir.h dvbosd.o : dvbosd.c dvbosd.h font.h tools.h dvd.o : dvd.c dvd.h -eit.o : eit.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h thread.h tools.h videodir.h +eit.o : eit.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h $(DTVDIR)/libdtv.h thread.h tools.h videodir.h font.o : font.c font.h fontfix.c fontosd.c tools.h i18n.o : i18n.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h thread.h tools.h interface.o : interface.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h @@ -78,8 +81,8 @@ videodir.o : videodir.c tools.h videodir.h # The main program: -vdr: $(OBJS) $(AC3LIB) - g++ -g -O2 $(OBJS) -lncurses -ljpeg -lpthread $(LIBDIRS) $(DVDLIB) $(AC3LIB) -o vdr +vdr: $(OBJS) $(AC3LIB) $(DTVLIB) + g++ -g -O2 $(OBJS) -lncurses -ljpeg -lpthread $(LIBDIRS) $(DVDLIB) $(AC3LIB) $(DTVLIB) -o vdr # The font files: @@ -98,10 +101,16 @@ genfontfile: genfontfile.c $(AC3LIB): make -C $(AC3DIR) all +# The libdtv library: + +$(DTVLIB) $(DTVDIR)/libdtv.h: + make -C $(DTVDIR) all + # Housekeeping: clean: make -C $(AC3DIR) clean + make -C $(DTVDIR) clean -rm -f $(OBJS) vdr genfontfile genfontfile.o core *~ fontclean: -rm -f fontfix.c fontosd.c diff --git a/config.c b/config.c index 27cd62edf..aed32549d 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.54 2001/08/11 15:34:42 kls Exp $ + * $Id: config.c 1.55 2001/08/17 13:02:01 kls Exp $ */ #include "config.h" @@ -774,6 +774,7 @@ cSetup::cSetup(void) MarginStart = 2; MarginStop = 10; EPGScanTimeout = 5; + EPGBugfixLevel = 2; SVDRPTimeout = 300; PrimaryLimit = 0; DefaultPriority = 50; @@ -804,6 +805,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); + else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); @@ -869,6 +871,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "MarginStart = %d\n", MarginStart); fprintf(f, "MarginStop = %d\n", MarginStop); fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout); + fprintf(f, "EPGBugfixLevel = %d\n", EPGBugfixLevel); fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout); fprintf(f, "PrimaryLimit = %d\n", PrimaryLimit); fprintf(f, "DefaultPriority = %d\n", DefaultPriority); diff --git a/config.h b/config.h index c9faf6cb4..ce77598b0 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.59 2001/08/11 15:28:21 kls Exp $ + * $Id: config.h 1.61 2001/08/17 13:00:48 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.91" +#define VDRVERSION "0.92" #define MaxBuffer 10000 @@ -280,6 +280,7 @@ class cSetup { int SetSystemTime; int MarginStart, MarginStop; int EPGScanTimeout; + int EPGBugfixLevel; int SVDRPTimeout; int PrimaryLimit; int DefaultPriority, DefaultLifetime; diff --git a/dvbapi.c b/dvbapi.c index 4c3861054..6ff39b3df 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.106 2001/08/12 15:09:42 kls Exp $ + * $Id: dvbapi.c 1.109 2001/08/19 15:09:48 kls Exp $ */ //#define DVDDEBUG 1 @@ -545,9 +545,13 @@ void cRecordBuffer::Input(void) } else if (r < 0) { if (FATALERRNO) { - LOG_ERROR; - if (errno != EBUFFEROVERFLOW) + if (errno == EBUFFEROVERFLOW) { // this error code is not defined in the library + esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); + } + else { + LOG_ERROR; break; + } } } if (time(NULL) - t > MAXBROKENTIMEOUT) { @@ -752,7 +756,7 @@ void cPlayBuffer::Pause(void) Empty(true); fastForward = fastRewind = false; CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE)); - CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); + //CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); //XXX this caused chirping sound when playing a DVD still = false; if (empty) Empty(false); @@ -767,7 +771,7 @@ void cPlayBuffer::Play(void) still = false; CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY)); CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); - CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); + //CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); //XXX this caused chirping sound when playing a DVD if (empty) Empty(false); fastForward = fastRewind = paused = false; @@ -2075,9 +2079,13 @@ void cTransferBuffer::Input(void) } else if (r < 0) { if (FATALERRNO) { - LOG_ERROR; - if (errno != EBUFFEROVERFLOW) + if (errno == EBUFFEROVERFLOW) { // this error code is not defined in the library + esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); + } + else { + LOG_ERROR; break; + } } } } @@ -3160,7 +3168,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, } if (!ChannelSynced) { - esyslog(LOG_ERR, "ERROR: channel %d not sync'ed!", ChannelNumber); + esyslog(LOG_ERR, "ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1); if (this == PrimaryDvbApi) cThread::RaisePanic(); return false; diff --git a/eit.c b/eit.c index 14738f3b2..d2927ccc0 100644 --- a/eit.c +++ b/eit.c @@ -4,6 +4,9 @@ begin : Fri Aug 25 2000 copyright : (C) 2000 by Robert Schneider email : Robert.Schneider@web.de + + 2001-08-15: Adapted to 'libdtv' by Rolf Hakenes <hakenes@hippomi.de> + ***************************************************************************/ /*************************************************************************** @@ -13,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.19 2001/08/12 15:04:37 kls Exp $ + * $Id: eit.c 1.22 2001/08/19 14:44:32 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -33,6 +36,7 @@ #include <time.h> #include <unistd.h> #include "config.h" +#include "libdtv/libdtv.h" #include "videodir.h" // --- cMJD ------------------------------------------------------------------ @@ -144,32 +148,6 @@ time_t cMJD::GetTime_t() // --- cTDT ------------------------------------------------------------------ -typedef struct { - u_char table_id : 8; - -#if BYTE_ORDER == BIG_ENDIAN - u_char section_syntax_indicator : 1; - u_char : 3; - u_char section_length_hi : 4; -#else - u_char section_length_hi : 4; - u_char : 3; - u_char section_syntax_indicator : 1; -#endif - - u_char section_length_lo : 8; - - - u_char utc_date_hi : 8; - u_char utc_date_lo : 8; - u_char utc_hour : 4; - u_char utc_hour_ten : 4; - u_char utc_min : 4; - u_char utc_min_ten : 4; - u_char utc_sec : 4; - u_char utc_sec_ten : 4; -} tdt_t; - class cTDT { public: cTDT(tdt_t *ptdt); @@ -183,11 +161,11 @@ class cTDT { cMJD mjd; // kls 2001-03-02: made this a member instead of a pointer (it wasn't deleted in the destructor!) }; +#define BCD2DEC(b) (((b >> 4) & 0x0F) * 10 + (b & 0x0F)) + cTDT::cTDT(tdt_t *ptdt) :tdt(*ptdt) -,mjd(tdt.utc_date_hi, tdt.utc_date_lo, tdt.utc_hour_ten * 10 + tdt.utc_hour, - tdt.utc_min_ten * 10 + tdt.utc_min, - tdt.utc_sec_ten * 10 + tdt.utc_sec) +,mjd(tdt.utc_mjd_hi, tdt.utc_mjd_lo, BCD2DEC(tdt.utc_time_h), BCD2DEC(tdt.utc_time_m), BCD2DEC(tdt.utc_time_s)) { } @@ -212,7 +190,6 @@ cEventInfo::cEventInfo(unsigned short serviceid, unsigned short eventid) tTime = 0; uEventID = eventid; uServiceID = serviceid; - cExtendedDescriptorNumber = 0; nChannelNumber = 0; } @@ -302,7 +279,7 @@ unsigned short cEventInfo::GetEventID() const return uEventID; } /** */ -bool cEventInfo::SetTitle(char *string) +bool cEventInfo::SetTitle(const char *string) { if (string == NULL) return false; @@ -314,7 +291,7 @@ bool cEventInfo::SetTitle(char *string) return true; } /** */ -bool cEventInfo::SetSubtitle(char *string) +bool cEventInfo::SetSubtitle(const char *string) { if (string == NULL) return false; @@ -326,7 +303,7 @@ bool cEventInfo::SetSubtitle(char *string) return true; } /** */ -bool cEventInfo::AddExtendedDescription(char *string) +bool cEventInfo::AddExtendedDescription(const char *string) { int size = 0; bool first = true; @@ -376,16 +353,6 @@ void cEventInfo::SetServiceID(unsigned short servid) { uServiceID = servid; } -/** */ -u_char cEventInfo::GetExtendedDescriptorNumber() const -{ - return cExtendedDescriptorNumber; -} -/** */ -void cEventInfo::IncreaseExtendedDescriptorNumber() -{ - cExtendedDescriptorNumber++; -} /** */ unsigned short cEventInfo::GetServiceID() const @@ -408,6 +375,116 @@ void cEventInfo::Dump(FILE *f, const char *Prefix) const } } +void cEventInfo::FixEpgBugs(void) +{ + if (Setup.EPGBugfixLevel == 0) + return; + + // Some TV stations apparently have their own idea about how to fill in the + // EPG data. Let's fix their bugs as good as we can: + if (pTitle) { + + // Pro7 preceeds the Subtitle with the Title: + // + // Title + // Title / Subtitle + // + if (pSubtitle && strstr(pSubtitle, pTitle) == pSubtitle) { + char *p = pSubtitle + strlen(pTitle); + const char *delim = " / "; + if (strstr(p, delim) == p) { + p += strlen(delim); + memmove(pSubtitle, p, strlen(p) + 1); + } + } + + // VOX and VIVA put the Subtitle in quotes and use either the Subtitle + // or the Extended Description field, depending on how long the string is: + // + // Title + // "Subtitle". Extended Description + // + if ((pSubtitle == NULL) != (pExtendedDescription == NULL)) { + char *p = pSubtitle ? pSubtitle : pExtendedDescription; + if (*p == '"') { + const char *delim = "\"."; + char *e = strstr(p + 1, delim); + if (e) { + *e = 0; + char *s = strdup(p + 1); + char *d = strdup(e + strlen(delim)); + delete pSubtitle; + delete pExtendedDescription; + pSubtitle = s; + pExtendedDescription = d; + } + } + } + + // VOX and VIVA put the Extended Description into the Subtitle (preceeded + // by a blank) if there is no actual Subtitle and the Extended Description + // is short enough: + // + // Title + // Extended Description + // + if (pSubtitle && !pExtendedDescription) { + if (*pSubtitle == ' ') { + memmove(pSubtitle, pSubtitle + 1, strlen(pSubtitle)); + pExtendedDescription = pSubtitle; + pSubtitle = NULL; + } + } + } + + // Pro7 sometimes repeats the Title in the Subtitle: + // + // Title + // Title + // + if (pSubtitle && strcmp(pTitle, pSubtitle) == 0) { + delete pSubtitle; + pSubtitle = NULL; + } + + if (Setup.EPGBugfixLevel <= 1) + return; + + // Some channels apparently try to do some formatting in the texts, + // which is a bad idea because they have no way of knowing the width + // of the window that will actually display the text. + // Remove excess whitespace: + pTitle = compactspace(pTitle); + pSubtitle = compactspace(pSubtitle); + pExtendedDescription = compactspace(pExtendedDescription); + // Remove superfluous hyphens: + if (pExtendedDescription) { + char *p = pExtendedDescription + 1; + while (*p) { + if (*p == '-' && *(p + 1) == ' ' && *(p + 2) && islower(*(p - 1)) && islower(*(p + 2))) { + if (!startswith(p + 2, "und ")) // special case in German, as in "Lach- und Sachgeschichten" + memmove(p, p + 2, strlen(p + 2) + 1); + } + p++; + } + } + + if (Setup.EPGBugfixLevel <= 2) + return; + + // Pro7 and Kabel1 apparently are unable to use a calendar/clock, + // because all events between 00:00 and 06:00 have the date of the + // day before (sometimes even this correction doesn't help). + // Channels are recognized by their ServiceID, which may only work + // correctly on the ASTRA satellite system. + if (uServiceID == 898 // Pro-7 + || uServiceID == 899) { // Kabel 1 + tm *t = localtime(&tTime); + if (t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec <= 6 * 3600) + tTime += 24 * 3600; + } +} + // --- cSchedule ------------------------------------------------------------- cSchedule::cSchedule(unsigned short servid) @@ -425,7 +502,7 @@ const cEventInfo * cSchedule::GetPresentEvent() const { // checking temporal sanity of present event (kls 2000-11-01) time_t now = time(NULL); - if (pPresent && !(pPresent->GetTime() <= now && now <= pPresent->GetTime() + pPresent->GetDuration())) +//XXX if (pPresent && !(pPresent->GetTime() <= now && now <= pPresent->GetTime() + pPresent->GetDuration())) { cEventInfo *pe = Events.First(); while (pe != NULL) @@ -435,6 +512,7 @@ const cEventInfo * cSchedule::GetPresentEvent() const pe = Events.Next(pe); } } + return NULL;//XXX return pPresent; } /** */ @@ -443,7 +521,7 @@ const cEventInfo * cSchedule::GetFollowingEvent() const // checking temporal sanity of following event (kls 2000-11-01) time_t now = time(NULL); const cEventInfo *pr = GetPresentEvent(); // must have it verified! - if (pFollowing && !(pr && pr->GetTime() + pr->GetDuration() <= pFollowing->GetTime())) +if (pr)//XXX if (pFollowing && !(pr && pr->GetTime() + pr->GetDuration() <= pFollowing->GetTime())) { int minDt = INT_MAX; cEventInfo *pe = Events.First(), *pf = NULL; @@ -459,6 +537,7 @@ const cEventInfo * cSchedule::GetFollowingEvent() const } return pf; } + return NULL;//XXX return pFollowing; } /** */ @@ -491,7 +570,7 @@ const cEventInfo * cSchedule::GetEvent(time_t tTime) const cEventInfo *pe = Events.First(); while (pe != NULL) { - if (pe->GetTime() == tTime) + if (pe->GetTime() <= tTime && tTime <= pe->GetTime() + pe->GetDuration()) return pe; pe = Events.Next(pe); @@ -536,7 +615,7 @@ void cSchedule::Cleanup(time_t tTime) pEvent = Events.Get(a); if (pEvent == NULL) break; - if (pEvent->GetTime() + pEvent->GetDuration() < tTime) + if (pEvent->GetTime() + pEvent->GetDuration() + 3600 < tTime) // adding one hour for safety { Events.Del(pEvent); a--; @@ -627,170 +706,28 @@ void cSchedules::Dump(FILE *f, const char *Prefix) const // --- cEIT ------------------------------------------------------------------ -#define DEC(N) dec << setw(N) << setfill(int('0')) -#define HEX(N) hex << setw(N) << setfill(int('0')) - -#define EIT_STUFFING_DESCRIPTOR 0x42 -#define EIT_LINKAGE_DESCRIPTOR 0x4a -#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d -#define EIT_EXTENDED_EVENT_DESCRIPTOR 0x4e -#define EIT_TIME_SHIFTED_EVENT_DESCRIPTOR 0x4f -#define EIT_COMPONENT_DESCRIPTOR 0x50 -#define EIT_CA_IDENTIFIER_DESCRIPTOR 0x53 -#define EIT_CONTENT_DESCRIPTOR 0x54 -#define EIT_PARENTAL_RATING_DESCRIPTOR 0x55 -#define EIT_TELEPHONE_DESCRIPTOR 0x57 -#define EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR 0x5e -#define EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR 0x5f -#define EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR 0x61 -#define EIT_DATA_BROADCAST_DESCRIPTOR 0x64 -#define EIT_PDC_DESCRIPTOR 0x69 - -typedef struct eit_struct { - u_char table_id : 8; - -#if BYTE_ORDER == BIG_ENDIAN - u_char section_syntax_indicator : 1; - u_char : 3; - u_char section_length_hi : 4; -#else - u_char section_length_hi : 4; - u_char : 3; - u_char section_syntax_indicator : 1; -#endif - - u_char section_length_lo : 8; - - u_char service_id_hi : 8; - u_char service_id_lo : 8; - -#if BYTE_ORDER == BIG_ENDIAN - u_char : 2; - u_char version_number : 5; - u_char current_next_indicator : 1; -#else - u_char current_next_indicator : 1; - u_char version_number : 5; - u_char : 2; -#endif - - u_char section_number : 8; - u_char last_section_number : 8; - u_char transport_stream_id_hi : 8; - u_char transport_stream_id_lo : 8; - u_char original_network_id_hi : 8; - u_char original_network_id_lo : 8; - u_char segment_last_section_number : 8; - u_char segment_last_table_id : 8; -} eit_t; - -typedef struct eit_loop_struct { - u_char event_id_hi : 8; - u_char event_id_lo : 8; - - u_char date_hi : 8; - u_char date_lo : 8; - u_char time_hour : 4; - u_char time_hour_ten : 4; - u_char time_minute : 4; - u_char time_minute_ten : 4; - u_char time_second : 4; - u_char time_second_ten : 4; - - u_char dur_hour : 4; - u_char dur_hour_ten : 4; - u_char dur_minute : 4; - u_char dur_minute_ten : 4; - u_char dur_second : 4; - u_char dur_second_ten : 4; - -#if BYTE_ORDER == BIG_ENDIAN - u_char running_status : 3; - u_char free_ca_mode : 1; - u_char descriptors_loop_length_hi : 4; -#else - u_char descriptors_loop_length_hi : 4; - u_char free_ca_mode : 1; - u_char running_status : 3; -#endif - - u_char descriptors_loop_length_lo : 8; -} eit_loop_t; - -typedef struct eit_short_event_struct { - u_char descriptor_tag : 8; - u_char descriptor_length : 8; - - u_char language_code_1 : 8; - u_char language_code_2 : 8; - u_char language_code_3 : 8; - - u_char event_name_length : 8; -} eit_short_event_t; - -typedef struct eit_extended_event_struct { - u_char descriptor_tag : 8; - u_char descriptor_length : 8; - - u_char last_descriptor_number : 4; - u_char descriptor_number : 4; - - u_char language_code_1 : 8; - u_char language_code_2 : 8; - u_char language_code_3 : 8; - - u_char length_of_items : 8; -} eit_extended_event_t; - -typedef struct eit_content_descriptor { - u_char descriptor_tag : 8; - u_char descriptor_length : 8; -} eit_content_descriptor_t; - -typedef struct eit_content_loop { - u_char content_nibble_level_2 : 4; - u_char content_nibble_level_1 : 4; - u_char user_nibble_2 : 4; - u_char user_nibble_1 : 4; -} eit_content_loop_t; - class cEIT { private: cSchedules *schedules; public: - cEIT(void *buf, int length, cSchedules *Schedules); + cEIT(unsigned char *buf, int length, cSchedules *Schedules); ~cEIT(); /** */ - int ProcessEIT(); + int ProcessEIT(unsigned char *buffer); protected: // Protected methods - /** */ - int strdvbcpy(unsigned char *dst, unsigned char *src, int max); /** returns true if this EIT covers a present/following information, false if it's schedule information */ bool IsPresentFollowing(); - /** */ - bool WriteShortEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf); - /** */ - bool WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf); protected: // Protected attributes - int buflen; -protected: // Protected attributes - /** */ - u_char buffer[4097]; /** Table ID of this EIT struct */ u_char tid; - /** EITs service id (program number) */ - u_short pid; }; -cEIT::cEIT(void * buf, int length, cSchedules *Schedules) +cEIT::cEIT(unsigned char * buf, int length, cSchedules *Schedules) { - buflen = length < int(sizeof(buffer)) ? length : sizeof(buffer); - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, buf, buflen); - tid = buffer[0]; + tid = buf[0]; schedules = Schedules; } @@ -799,162 +736,72 @@ cEIT::~cEIT() } /** */ -int cEIT::ProcessEIT() -{ - int bufact = 0; - eit_t *eit; - eit_loop_t *eitloop; - u_char tmp[256]; - - if (bufact + (int)sizeof(eit_t) > buflen) - return 0; - eit = (eit_t *)buffer; - bufact += sizeof(eit_t); - - unsigned int service = (eit->service_id_hi << 8) | eit->service_id_lo; - - while(bufact + (int)sizeof(eit_loop_t) <= buflen) - { - eitloop = (eit_loop_t *)&buffer[bufact]; - bufact += sizeof(eit_loop_t); - - int descdatalen = (eitloop->descriptors_loop_length_hi << 8) + eitloop->descriptors_loop_length_lo; - int descdataact = 0; - - while (descdataact < descdatalen && bufact < buflen) - { - switch (buffer[bufact]) - { - eit_content_descriptor_t *cont; - eit_content_loop_t *contloop; - - case EIT_STUFFING_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_STUFFING_DESCRIPTOR"); - break; - - case EIT_LINKAGE_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_LINKAGE_DESCRIPTOR"); - break; - - case EIT_SHORT_EVENT_DESCRIPTOR: - WriteShortEventDescriptor(service, eitloop, &buffer[bufact]); - break; - - case EIT_EXTENDED_EVENT_DESCRIPTOR: - WriteExtEventDescriptor(service, eitloop, &buffer[bufact]); - break; - - case EIT_TIME_SHIFTED_EVENT_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_TIME_SHIFTED_EVENT_DESCRIPTOR"); - break; - - case EIT_COMPONENT_DESCRIPTOR : - if (buffer[bufact + 1] > 6) // kls 2001-02-24: otherwise strncpy() causes a segfault in strdvbcpy() - strdvbcpy(tmp, &buffer[bufact + 8], buffer[bufact + 1] - 6); - //dsyslog(LOG_INFO, "Found EIT_COMPONENT_DESCRIPTOR %c%c%c 0x%02x/0x%02x/0x%02x '%s'\n", buffer[bufact + 5], buffer[bufact + 6], buffer[bufact + 7], buffer[2], buffer[3], buffer[4], tmp); - break; - - case EIT_CA_IDENTIFIER_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_CA_IDENTIFIER_DESCRIPTOR"); - break; - - case EIT_CONTENT_DESCRIPTOR : - cont = (eit_content_descriptor_t *)buffer; - contloop = (eit_content_loop_t *)&buffer[sizeof(eit_content_descriptor_t)]; - //dsyslog(LOG_INFO, "Found EIT_CONTENT_DESCRIPTOR 0x%02x/0x%02x\n", contloop->content_nibble_level_1, contloop->content_nibble_level_2); - break; - - case EIT_PARENTAL_RATING_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_PARENTAL_RATING_DESCRIPTOR"); - break; - - case EIT_TELEPHONE_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_TELEPHONE_DESCRIPTOR"); - break; - - case EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR"); - break; - - case EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR"); - break; - - case EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR"); - break; - - case EIT_DATA_BROADCAST_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_DATA_BROADCAST_DESCRIPTOR"); - break; - - case EIT_PDC_DESCRIPTOR : - //dsyslog(LOG_INFO, "Found EIT_PDC_DESCRIPTOR"); - break; - - default: - //dsyslog(LOG_INFO, "Found unhandled descriptor 0x%02x with length of %04d\n", (int)buffer[bufact], (int)buffer[bufact + 1]); - break; - } - descdataact += (buffer[bufact + 1] + 2); - bufact += (buffer[bufact + 1] + 2); +int cEIT::ProcessEIT(unsigned char *buffer) +{ + cEventInfo *pEvent, *rEvent = NULL; + cSchedule *pSchedule, *rSchedule = NULL; + struct LIST *VdrProgramInfos; + struct VdrProgramInfo *VdrProgramInfo; + + if (!buffer) + return -1; + + VdrProgramInfos = createVdrProgramInfos(buffer); + + if (VdrProgramInfos) { + for (VdrProgramInfo = (struct VdrProgramInfo *) VdrProgramInfos->Head; VdrProgramInfo; VdrProgramInfo = (struct VdrProgramInfo *) xSucc (VdrProgramInfo)) { + pSchedule = (cSchedule *)schedules->GetSchedule(VdrProgramInfo->ServiceID); + if (!pSchedule) { + schedules->Add(new cSchedule(VdrProgramInfo->ServiceID)); + pSchedule = (cSchedule *)schedules->GetSchedule(VdrProgramInfo->ServiceID); + if (!pSchedule) + break; + } + if (VdrProgramInfo->ReferenceServiceID) { + rSchedule = (cSchedule *)schedules->GetSchedule(VdrProgramInfo->ReferenceServiceID); + if (!rSchedule) + break; + rEvent = (cEventInfo *)rSchedule->GetEvent((unsigned short)VdrProgramInfo->ReferenceEventID); + if (!rEvent) + break; + } + pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID); + if (!pEvent) { + pSchedule->Events.Add(new cEventInfo(VdrProgramInfo->ServiceID, VdrProgramInfo->EventID)); + pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID); + if (!pEvent) + break; + if (rEvent) { + pEvent->SetTitle(rEvent->GetTitle()); + pEvent->SetSubtitle(rEvent->GetSubtitle()); + pEvent->SetTime(VdrProgramInfo->StartTime); + pEvent->SetDuration(VdrProgramInfo->Duration); + pEvent->AddExtendedDescription(rEvent->GetExtendedDescription()); + pEvent->FixEpgBugs(); + } + else { + pEvent->SetTitle(VdrProgramInfo->ShortName); + pEvent->SetSubtitle(VdrProgramInfo->ShortText); + pEvent->SetTime(VdrProgramInfo->StartTime); + pEvent->SetDuration(VdrProgramInfo->Duration); + pEvent->AddExtendedDescription(VdrProgramInfo->ExtendedName); + pEvent->AddExtendedDescription(VdrProgramInfo->ExtendedText); + pEvent->FixEpgBugs(); + } + } + if (IsPresentFollowing()) { + if ((GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_PAUSING) || (GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_RUNNING)) + pSchedule->SetPresentEvent(pEvent); + else if (GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_AWAITING) + pSchedule->SetFollowingEvent(pEvent); + } + } } - } + xMemFreeAll(NULL); return 0; } -/** */ -int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) -{ - int a = 0; - - // kls 2001-02-24: if we come in with negative values, the caller must - // have done something wrong and the strncpy() below will cause a segfault - if (max <= 0) - { - *dst = 0; - return 0; - } - - if (*src == 0x05 || (*src >= 0x20 && *src <= 0xff)) - { - for (a = 0; a < max; a++) - { - if (*src == 0) - break; - - if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff)) - *dst++ = *src++; - else - { - // if ((*src > '~' && *src < 0xa0) || *src == 0xff) - // cerr << "found special character 0x" << HEX(2) << (int)*src << endl; - src++; - } - } - *dst = 0; - } - else - { - const char *ret; - - switch (*src) - { - case 0x01: ret = "Coding according to character table 1"; break; - case 0x02: ret = "Coding according to character table 2"; break; - case 0x03: ret = "Coding according to character table 3"; break; - case 0x04: ret = "Coding according to character table 4"; break; - case 0x10: ret = "Coding according to ISO/IEC 8859"; break; - case 0x11: ret = "Coding according to ISO/IEC 10646"; break; - case 0x12: ret = "Coding according to KSC 5601"; break; - default: ret = "Unknown coding"; break; - } - strncpy((char *)dst, ret, max); - } - return a; -} - /** returns true if this EIT covers a present/following information, false if it's schedule information */ @@ -966,136 +813,6 @@ bool cEIT::IsPresentFollowing() return false; } -/** */ -bool cEIT::WriteShortEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf) -{ - u_char tmp[256]; - eit_short_event_t *evt = (eit_short_event_t *)buf; - unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); - cEventInfo *pEvent; - - //isyslog(LOG_INFO, "Found Short Event Descriptor"); - - cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - { - schedules->Add(new cSchedule(service)); - pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - return false; - } - - /* cSchedule::GetPresentEvent() and cSchedule::GetFollowingEvent() verify - the temporal sanity of these events, so calling them here appears to - be a bad idea... (kls 2000-11-01) - // - // if we are working on a present/following info, let's see whether - // we already have present/following info for this service and if yes - // check whether it's the same eventid, if yes, just return, nothing - // left to do. - // - if (IsPresentFollowing()) - { - if (eitloop->running_status == 4 || eitloop->running_status == 3) - pEvent = (cEventInfo *)pSchedule->GetPresentEvent(); - else - pEvent = (cEventInfo *)pSchedule->GetFollowingEvent(); - - if (pEvent != NULL) - if (pEvent->GetEventID() == eventid) - return true; - } - */ - - // - // let's see whether we have that eventid already - // in case not, we have to create a new cEventInfo for it - // - pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); - if (pEvent == NULL) - { - pSchedule->Events.Add(new cEventInfo(service, eventid)); - pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); - if (pEvent == NULL) - return false; - - strdvbcpy(tmp, &buf[sizeof(eit_short_event_t)], evt->event_name_length); - pEvent->SetTitle((char *)tmp); - strdvbcpy(tmp, &buf[sizeof(eit_short_event_t) + evt->event_name_length + 1], - (int)buf[sizeof(eit_short_event_t) + evt->event_name_length]); - pEvent->SetSubtitle((char *)tmp); - cMJD mjd(eitloop->date_hi, eitloop->date_lo, - eitloop->time_hour_ten * 10 + eitloop->time_hour, - eitloop->time_minute_ten * 10 + eitloop->time_minute, - eitloop->time_second_ten * 10 + eitloop->time_second); - pEvent->SetTime(mjd.GetTime_t()); - pEvent->SetDuration((long)((long)((eitloop->dur_hour_ten * 10 + eitloop->dur_hour) * 60l * 60l) + - (long)((eitloop->dur_minute_ten * 10 + eitloop->dur_minute) * 60l) + - (long)(eitloop->dur_second_ten * 10 + eitloop->dur_second))); - } - - if (IsPresentFollowing()) - { - if (eitloop->running_status == 4 || eitloop->running_status == 3) - pSchedule->SetPresentEvent(pEvent); - else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0) - pSchedule->SetFollowingEvent(pEvent); - } - - return true; -} - -/** */ -bool cEIT::WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf) -{ - u_char tmp[256]; - eit_extended_event_t *evt = (eit_extended_event_t *)buf; - int bufact, buflen; - unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo); - cEventInfo *pEvent; - - //isyslog(LOG_INFO, "Found Extended Event Descriptor"); - - cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - { - schedules->Add(new cSchedule(service)); - pSchedule = (cSchedule *)schedules->GetSchedule(service); - if (pSchedule == NULL) - return false; - } - - pEvent = (cEventInfo *)pSchedule->GetEvent(eventid); - if (pEvent == NULL) - return false; - - if (evt->descriptor_number != pEvent->GetExtendedDescriptorNumber()) - return false; - - bufact = sizeof(eit_extended_event_t); - buflen = buf[1] + 2; - - if (evt->length_of_items > 0) - { - while (bufact - sizeof(eit_extended_event_t) < evt->length_of_items) - { - strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); - // could use value in tmp now to do something, - // haven't seen any items as of yet transmitted from satellite - bufact += (buf[bufact] + 1); - } - } - - strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]); - if (pEvent->AddExtendedDescription((char *)tmp)) - { - pEvent->IncreaseExtendedDescriptorNumber(); - return true; - } - - return false; -} - // --- cSIProcessor ---------------------------------------------------------- #define MAX_FILTERS 20 @@ -1262,7 +979,7 @@ void cSIProcessor::Action() schedulesMutex.Lock(); cEIT ceit(buf, seclen, schedules); - ceit.ProcessEIT(); + ceit.ProcessEIT(buf); schedulesMutex.Unlock(); } else diff --git a/eit.h b/eit.h index d4ba69f69..8ca5f1e53 100644 --- a/eit.h +++ b/eit.h @@ -4,6 +4,9 @@ begin : Fri Aug 25 2000 copyright : (C) 2000 by Robert Schneider email : Robert.Schneider@web.de + + 2001-08-15: Adapted to 'libdtv' by Rolf Hakenes <hakenes@hippomi.de> + ***************************************************************************/ /*************************************************************************** @@ -13,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.8 2001/08/11 09:06:17 kls Exp $ + * $Id: eit.h 1.10 2001/08/15 15:47:31 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -35,19 +38,17 @@ class cEventInfo : public cListObject { unsigned short uEventID; // Event ID of this event long lDuration; // duration of event in seconds time_t tTime; // Start time - u_char cExtendedDescriptorNumber; // current extended descriptor number that has to be inserted int nChannelNumber; // the actual channel number from VDR's channel list (used in cMenuSchedule for sorting by channel number) protected: void SetFollowing(bool foll); void SetPresent(bool pres); - bool SetTitle(char *string); + bool SetTitle(const char *string); void SetServiceID(unsigned short servid); void SetEventID(unsigned short evid); void SetDuration(long l); void SetTime(time_t t); - bool AddExtendedDescription(char *string); - bool SetSubtitle(char *string); - void IncreaseExtendedDescriptorNumber(void); + bool AddExtendedDescription(const char *string); + bool SetSubtitle(const char *string); cEventInfo(unsigned short serviceid, unsigned short eventid); public: ~cEventInfo(); @@ -62,11 +63,11 @@ class cEventInfo : public cListObject { unsigned short GetEventID(void) const; long GetDuration(void) const; time_t GetTime(void) const; - u_char GetExtendedDescriptorNumber(void) const; unsigned short GetServiceID(void) const; int GetChannelNumber(void) const { return nChannelNumber; } void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' void Dump(FILE *f, const char *Prefix = "") const; + void FixEpgBugs(void); }; class cSchedule : public cListObject { diff --git a/i18n.c b/i18n.c index 3d75c245d..987822862 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.31 2001/08/11 13:22:24 kls Exp $ + * $Id: i18n.c 1.32 2001/08/17 13:03:15 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -776,6 +776,15 @@ const tPhrase Phrases[] = { "Temps maxi EPG", "Ledig tid fr EPG-sk", }, + { "EPGBugfixLevel", + "EPG Fehlerbereinigung", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "SVDRPTimeout", "SVDRP Timeout", "", // TODO diff --git a/libdtv/COPYING b/libdtv/COPYING new file mode 100644 index 000000000..a43ea2126 --- /dev/null +++ b/libdtv/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libdtv/Makefile b/libdtv/Makefile new file mode 100644 index 000000000..50a140044 --- /dev/null +++ b/libdtv/Makefile @@ -0,0 +1,73 @@ +############################################################## +### ### +### Makefile: global makefile for libdtv ### +### ### +############################################################## + +## $Revision: 1.1 $ +## $Date: 2001/06/25 12:53:00 $ +## $Author: kls $ +## +## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +## +## libdtv is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## libdtv is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You may have received a copy of the GNU General Public License +## along with libdtv; see the file COPYING. If not, write to the +## Free Software Foundation, Inc., 59 Temple Place - Suite 330, +## Boston, MA 02111-1307, USA. +# +# +# + +# +# adapt this to your GNU make executable +# +MAKE = make + +AR = ar +ARFLAGS = ru +RANLIB = ranlib + +SUBDIRS = liblx libsi libvdr + +all: newdist + +new: clean newdist + +clean: + @echo "making all clean..." + @for i in $(SUBDIRS);\ + do \ + ( echo $$i; cd $$i ;\ + $(MAKE) clean ) ;\ + done + @rm -rf lib include libdtv.* + +newdist: + @mkdir -p include lib + @echo "making all distributions..." + @for i in $(SUBDIRS) ;\ + do \ + ( cd $$i ;\ + $(MAKE) new dist ) ;\ + done + @echo "making libdtv.a/libdtv.h..." + @cat include/* > libdtv.h + @mkdir -p tmp + @for i in $(SUBDIRS) ;\ + do \ + ( cd tmp;\ + $(AR) x ../lib/$$i.a;\ + $(AR) $(ARFLAGS) ../libdtv.a *;\ + rm -f *) ;\ + done + @rm -rf lib include tmp diff --git a/libdtv/README b/libdtv/README new file mode 100644 index 000000000..88ee04904 --- /dev/null +++ b/libdtv/README @@ -0,0 +1,27 @@ +DTV System Information Library +============================== + +This is intended to support the VDR application of Klaus Schmidinger with +extended EIT support, mainly on NVOD channels. +Bug reports and suggestions are very appreciated and should be sent to +hakenes@hippomi.de + +Have fun, + + (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. + +libdtv is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +libdtv is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You may have received a copy of the GNU General Public License +along with libdtv; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + diff --git a/libdtv/liblx/COPYING b/libdtv/liblx/COPYING new file mode 100644 index 000000000..a43ea2126 --- /dev/null +++ b/libdtv/liblx/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libdtv/liblx/Makefile b/libdtv/liblx/Makefile new file mode 100644 index 000000000..a8034dec2 --- /dev/null +++ b/libdtv/liblx/Makefile @@ -0,0 +1,62 @@ +############################################################## +### ### +### Makefile: local makefile for liblx ### +### ### +############################################################## + +## $Revision: 1.1 $ +## $Date: 2001/06/26 07:18:42 $ +## $Author: kls $ +## +## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +## +## dtv_scan is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## dtv_scan is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You may have received a copy of the GNU General Public License +## along with dtv_scan; see the file COPYING. If not, write to the +## Free Software Foundation, Inc., 59 Temple Place - Suite 330, +## Boston, MA 02111-1307, USA. +# +# +# +CC = gcc +CFLAGS = -O2 -g -pedantic -Wmissing-prototypes -Wstrict-prototypes \ + -Wimplicit -D__USE_FIXED_PROTOTYPES__ # -DDEBUG + + +AR = ar +ARFLAGS = r +RANLIB = ranlib +RM = rm -f +CP = cp + +LXINCLUDE = liblx.h +LXLIB = liblx.a +LXOBJS = xMemMgt.o xListFuncs.o + +all : $(LXLIB) + +clean : + @echo "cleaning workspace..." + @$(RM) $(LXOBJS) $(LXLIB) + +new : clean all + +$(LXLIB) : $(LXOBJS) + @echo "updating library..." + @$(AR) $(ARFLAGS) $(LXLIB) $(LXOBJS) + @$(RANLIB) $(LXLIB) + +dist: all + @echo "distributing liblx.a and liblx.h..." + @$(CP) $(LXLIB) ../lib + @$(CP) $(LXINCLUDE) ../include + diff --git a/libdtv/liblx/liblx.h b/libdtv/liblx/liblx.h new file mode 100644 index 000000000..f2527e7ab --- /dev/null +++ b/libdtv/liblx/liblx.h @@ -0,0 +1,448 @@ +////////////////////////////////////////////////////////////// +/// /// +/// liblx.h: definitions necessary for the liblx package /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/06/26 07:18:42 $ +// $Author: kls $ +// +// (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// liblx is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// liblx is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with liblx; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#ifndef LIBLX_H +#define LIBLX_H + +#ifndef NULL +#define NULL 0 +#endif + + +/* + * + * list support structures + * + */ +struct NODE +{ + struct NODE *Succ; + struct NODE *Pred; + char *Name; + unsigned short HashKey; +}; + +struct LIST +{ + struct NODE *Head; + struct NODE *Tail; + char *Name; + unsigned long Size; +}; + + +/* + * + * memory managment structures + * + */ +struct MEM_ENTRY +{ + struct MEM_ENTRY *Succ; + struct MEM_ENTRY *Pred; + unsigned long Size; +}; + +struct MEM_CHUNK +{ + struct MEM_CHUNK *Succ; + struct MEM_CHUNK *Pred; + unsigned long Size; + struct MEM_ENTRY *FirstFreeMemEntry; + struct MEM_ENTRY *FirstUsedMemEntry; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * + * list functions (package xList) + * + */ + unsigned short xHashKey (char *); + struct LIST *xNewList (char *); + struct NODE *xNewNode (char *, unsigned long); + struct NODE *xFindName (struct LIST *, char *); +/* + * + * memory management + * + */ + void xMemAllo (unsigned long, unsigned char **); + void xMemFre (unsigned char *); + void xMemFreeAll (struct MEM_CHUNK **); + void xMemMerge (struct MEM_CHUNK **); + struct MEM_CHUNK **xGetRemember (void); + void xSetRemember (struct MEM_CHUNK **); + void xPrintMemList (struct MEM_CHUNK **); + unsigned long xGetMemSize (struct MEM_CHUNK **); +extern unsigned long xAllocatedMemory; + char *xSetText (char *); + +#ifdef __cplusplus +} +#endif + + +#define MEM_CHUNK_SIZE 65536 + +#define xMemAlloc(size, ptr) \ + xMemAllo (((unsigned long)((size))), ((unsigned char **)((ptr)))) +#define xMemFree(ptr) xMemFre (((unsigned char *)((ptr)))) +/* + * + * list support macros + * + */ +/*---------------------------------------------------------------------* + | | + | xCreateNode (NodeStruct,Name) allocates a correctly sized and | + | typed node struct. | + | | + *---------------------------------------------------------------------*/ +#define xCreateNode(NodeStruct,Name) \ + (NodeStruct) = (void *) xNewNode(Name, sizeof(*(NodeStruct))) + + +/*---------------------------------------------------------------------* + | | + | xSize (List) scans for the ->Size field of a list struct | + | | + *---------------------------------------------------------------------*/ +#define xSize(List) ((List) ? ((struct LIST *)(List))->Size : 0) + + +/*---------------------------------------------------------------------* + | | + | xName (NodeStruct) scans for the ->Node.Name of a node struct | + | | + *---------------------------------------------------------------------*/ +#define xName(NodeStruct) (((struct NODE *)(NodeStruct))->Name) + + +/*---------------------------------------------------------------------* + | | + | xSucc (NodeStruct) scans for the ->Node.Succ of a node struct | + | | + *---------------------------------------------------------------------*/ +#define xSucc(NodeStruct) (((struct NODE *)(NodeStruct))->Succ) + + +/*---------------------------------------------------------------------* + | | + | xPred (NodeStruct) scans for the ->Node.Pred of a node struct | + | | + *---------------------------------------------------------------------*/ +#define xPred(NodeStruct) (((struct NODE *)(NodeStruct))->Pred) + + +/*---------------------------------------------------------------------* + | | + | xForeach(List,NodeStruct) builds a loop to process each list | + | element. | + | | + *---------------------------------------------------------------------*/ +#define xForeach(List,NodeStruct) \ + if (List) for ((NodeStruct) = (void *) ((struct LIST *)(List))->Head; \ + (NodeStruct); (NodeStruct) = (void *) xSucc (NodeStruct)) + + +/*---------------------------------------------------------------------* + | | + | xForeachReverse(List,NodeStruct) builds a loop to process each | + | element in reverse order. | + | | + *---------------------------------------------------------------------*/ +#define xForeachReverse(List,NodeStruct) \ + if (List) for ((NodeStruct) = (void *) ((struct LIST *)(List))->Tail; \ + NodeStruct; (NodeStruct) = (void *) xPred (NodeStruct)) + + +/*---------------------------------------------------------------------* + | | + | xRemove(List,NodeStruct) unchains a node struct out of a list. | + | | + *---------------------------------------------------------------------*/ +#define xRemove(List,NodeStruct) \ + do \ + { \ + struct NODE *TmpNode; \ + struct LIST *TmpList; \ + \ + TmpNode = ((struct NODE *)(NodeStruct)); \ + TmpList = ((struct LIST *)(List)); \ + \ + if (TmpNode->Pred) \ + (TmpNode->Pred)->Succ = TmpNode->Succ; \ + else TmpList->Head = TmpNode->Succ; \ + if (TmpNode->Succ) \ + (TmpNode->Succ)->Pred = TmpNode->Pred; \ + else TmpList->Tail = TmpNode->Pred; \ + TmpList->Size --; \ + } while (0) + + +/************************************************************************* + * * + * function : xAddHead * + * * + * arguments : List - pointer to a LIST structure * + * * + * Node - pointer to a NODE structure * + * * + *-----------------------------------------------------------------------* + * * + * xAddHead() inserts 'Node' at the head of 'List'. * + * * + *************************************************************************/ +#define xAddHead(List, NodeStruct) \ + do { \ + struct NODE *TmpNode; \ + struct LIST *TmpList; \ + \ + TmpNode = ((struct NODE *)(NodeStruct)); \ + TmpList = ((struct LIST *)(List)); \ + \ + if (TmpList->Head) { \ + TmpNode->Pred = NULL; \ + TmpNode->Succ = TmpList->Head; \ + (TmpList->Head)->Pred = TmpNode; \ + TmpList->Head = TmpNode; } \ + else { \ + TmpList->Head = TmpNode; \ + TmpList->Tail = TmpNode; \ + TmpNode->Pred = NULL; \ + TmpNode->Succ = NULL; } \ + TmpList->Size++; \ + } while (0) + + +/************************************************************************* + * * + * function : xAddTail * + * * + * arguments : List - pointer to a LIST structure * + * * + * Node - pointer to a NODE structure * + * * + *-----------------------------------------------------------------------* + * * + * xAddTail() inserts 'Node' at the tail of 'List'. * + * * + *************************************************************************/ +#define xAddTail(List, NodeStruct) \ + do { \ + struct NODE *TmpNode; \ + struct LIST *TmpList; \ + \ + TmpNode = ((struct NODE *)(NodeStruct)); \ + TmpList = ((struct LIST *)(List)); \ + \ + if (TmpList->Head) { \ + TmpNode->Succ = NULL; \ + TmpNode->Pred = TmpList->Tail; \ + (TmpList->Tail)->Succ = TmpNode; \ + TmpList->Tail = TmpNode; } \ + else { \ + TmpList->Head = TmpNode; \ + TmpList->Tail = TmpNode; \ + TmpNode->Pred = NULL; \ + TmpNode->Succ = NULL; } \ + TmpList->Size++; \ + } while (0) + + +/************************************************************************* + * * + * function : xRemHead * + * * + * arguments : List - pointer to a LIST structure * + * * + *-----------------------------------------------------------------------* + * * + * xRemHead() removes a Node from head of 'List'. * + * * + *************************************************************************/ +#define xRemHead(List) \ + do { \ + struct LIST *TmpList; \ + \ + TmpList = ((struct LIST *)(List)); \ + \ + if (TmpList->Head) \ + { \ + TmpList->Head = (TmpList->Head)->Succ; \ + if (TmpList->Head) (TmpList->Head)->Pred = NULL; \ + else TmpList->Tail = NULL; \ + TmpList->Size--; \ + } \ + } while (0) + + +/************************************************************************* + * * + * function : xRemTail * + * * + * arguments : List - pointer to a LIST structure * + * * + *-----------------------------------------------------------------------* + * * + * xRemTail() removes a Node from the tail of 'List'. * + * * + *************************************************************************/ +#define xRemTail(List) \ + do { \ + struct LIST *TmpList; \ + \ + TmpList = ((struct LIST *)(List)); \ + \ + if (TmpList->Tail) \ + { \ + TmpList->Tail = (TmpList->Tail)->Pred; \ + if (TmpList->Tail) (TmpList->Tail)->Succ = NULL; \ + else TmpList->Head = NULL; \ + TmpList->Size--; \ + } \ + } while (0) + + +/************************************************************************* + * * + * function : xConCat * + * * + * arguments : DestinationList - pointer to the destination * + * LIST structure * + * * + * SourceList - pointer to the source LIST structure * + * * + *-----------------------------------------------------------------------* + * * + * xConCat() concats 'SourceList' with 'DestinationList' and clears * + * 'SourceList'. * + * * + *************************************************************************/ +#define xConCat(DestinationList, SourceList) \ + do { \ + struct LIST *SrcList; \ + struct LIST *DstList; \ + \ + SrcList = ((struct LIST *)(SourceList)); \ + DstList = ((struct LIST *)(DestinationList)); \ + \ + if (DstList && SrcList) \ + { \ + if (DstList->Head) { \ + if (SrcList->Head) { \ + (DstList->Tail)->Succ = SrcList->Head; \ + (SrcList->Head)->Pred = DstList->Tail; \ + DstList->Tail = SrcList->Tail; \ + DstList->Size += SrcList->Size; \ + SrcList->Size = 0; \ + SrcList->Head = NULL; \ + SrcList->Tail = NULL; } } \ + else { \ + DstList->Head = SrcList->Head; \ + DstList->Tail = SrcList->Tail; \ + DstList->Size += SrcList->Size; \ + SrcList->Size = 0; \ + SrcList->Head = NULL; \ + SrcList->Tail = NULL; } \ + } \ + else if (SrcList) ((struct LIST *)(DestinationList)) = SrcList; \ + } while (0) + + + +#define xJoinList(SourceList, DestinationList, NodeStruct) \ + do { \ + struct NODE *KeyNode; \ + struct NODE *TmpNode; \ + struct LIST *SrcList; \ + struct LIST *DstList; \ + \ + KeyNode = ((struct NODE *)(NodeStruct)); \ + SrcList = ((struct LIST *)(SourceList)); \ + DstList = ((struct LIST *)(DestinationList)); \ + \ + if (SrcList->Head) \ + { \ + TmpNode = KeyNode->Succ; \ + KeyNode->Succ = SrcList->Head; \ + SrcList->Tail->Succ = TmpNode; \ + SrcList->Head->Pred = KeyNode; \ + if (!TmpNode) DstList->Tail = SrcList->Tail; \ + else TmpNode->Pred = SrcList->Tail; \ + DstList->Size += SrcList->Size; \ + SrcList->Size = 0; \ + SrcList->Head = NULL; \ + SrcList->Tail = NULL; \ + } \ + } while (0) + +#define xJoin(SourceNode, DestinationList, NodeStruct) \ + do { \ + struct NODE *KeyNode; \ + struct NODE *TmpNode; \ + struct NODE *SrcNode; \ + struct LIST *DstList; \ + \ + KeyNode = ((struct NODE *)(NodeStruct)); \ + SrcNode = ((struct NODE *)(SourceNode)); \ + DstList = ((struct LIST *)(DestinationList)); \ + \ + if (SrcNode) \ + { \ + TmpNode = KeyNode->Succ; \ + KeyNode->Succ = SrcNode; \ + SrcNode->Succ = TmpNode; \ + SrcNode->Pred = KeyNode; \ + if (!TmpNode) DstList->Tail = SrcNode; \ + else TmpNode->Pred = SrcNode; \ + DstList->Size += 1; \ + } \ + } while (0) + +#define xClearList(SrcList) \ + do { \ + (SrcList)->Size = 0; \ + (SrcList)->Head = NULL; \ + (SrcList)->Tail = NULL; \ + } while (0) + +#define xSetName(nodestruct, name) \ + do { \ + struct NODE *TmpNode; \ + \ + TmpNode = (struct NODE *) (nodestruct); \ + \ + TmpNode->Name = xSetText (name); \ + TmpNode->HashKey = xHashKey (name); \ + } while (0) + +#endif diff --git a/libdtv/liblx/xListFuncs.c b/libdtv/liblx/xListFuncs.c new file mode 100644 index 000000000..34df7a895 --- /dev/null +++ b/libdtv/liblx/xListFuncs.c @@ -0,0 +1,187 @@ +////////////////////////////////////////////////////////////// +/// /// +/// xListFuncs.c: list handling functions of liblx /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/06/25 12:29:47 $ +// $Author: kls $ +// +// (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// liblx is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// liblx is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with liblx; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#include "liblx.h" + + +/************************************************************************* + * * + * function : xHashKey * + * * + * arguments : Name - character pointer * + * * + * return : 16 Bit CRC checksum as hashkey * + * * + *************************************************************************/ +unsigned short xHashKey (Name) + +char *Name; +{ + unsigned short Key = 0; + unsigned long Value; + char *Ptr; + + if (!Name) return (0); + + for (Ptr = Name; *Ptr; Ptr++) { + Value = ((Key >> 8) ^ (*Ptr)) & 0xFF; + Value = Value ^ (Value >> 4); + Key = 0xFFFF & ((Key << 8) ^ Value ^ (Value << 5) ^ (Value << 12)); + } + return (Key); +} + + +/************************************************************************* + * * + * function : xNewNode * + * * + * arguments : Name - character pointer to the node's name * + * * + * Size - size of the surrounding structure in bytes * + * * + * return : pointer to a correct initialized NODE structure * + * * + *-----------------------------------------------------------------------* + * * + * xNewNode() allocates memory for a NODE structure and initializes * + * it properly. If argument Name points to a string, it copies that * + * into a new allocated memory area and assigns Node->Name to it. * + * Because NODE's are often part of bigger structures, the size of * + * the surrounding structure could be specified to allocate it. * + * * + *************************************************************************/ + +struct NODE *xNewNode (Name, Size) + +char *Name; +unsigned long Size; +{ + struct NODE *Node; + + if (Size < sizeof(struct NODE)) Size = sizeof(struct NODE); + + xMemAlloc (Size, &Node); + + Node->Succ = NULL; + Node->Pred = NULL; + + if (Name == NULL) + { + Node->Name = NULL; + Node->HashKey = 0; + } + else + { + xMemAlloc (strlen (Name) + 1, &(Node->Name)); + strcpy (Node->Name, Name); + Node->HashKey = xHashKey (Name); + } + + return (Node); +} + + +/************************************************************************* + * * + * function : xNewList * + * * + * arguments : Name - character pointer to the list's name * + * * + * return : pointer to a correct initialized LIST structure * + * * + *-----------------------------------------------------------------------* + * * + * xNewList() allocates memory for a LIST structure and initializes * + * it properly. If argument Name points to a string, it copies that * + * into a new allocated memory area and assigns List->Name to it. * + * * + *************************************************************************/ + +struct LIST *xNewList (Name) + +char *Name; +{ + struct LIST *List; + + xMemAlloc (sizeof(struct LIST), &List); + + List->Head = NULL; + List->Tail = NULL; + List->Size = 0; + + if (Name == NULL) + { + List->Name = NULL; + } + else + { + xMemAlloc (strlen (Name) + 1, &(List->Name)); + strcpy (List->Name, Name); + } + + return (List); +} + + + +/************************************************************************* + * * + * function : xFindName * + * * + * arguments : List - pointer to a LIST structure * + * * + * Name - pointer to a name string * + * * + * return : pointer to a NODE structure * + * * + *-----------------------------------------------------------------------* + * * + * xFindName() looks for element with name 'Name' in list 'List' and * + * returns its NODE structure. * + * * + *************************************************************************/ + +struct NODE *xFindName (List, Name) + +struct LIST *List; +char *Name; +{ + struct NODE *Node; + unsigned short HashKey; + + if (!Name || !List) return (NULL); + + HashKey = xHashKey (Name); + + for (Node = List->Head; Node; Node = Node->Succ) + if (HashKey == Node->HashKey) + if (Node->Name) + if (strcmp (Node->Name, Name) == 0) return (Node); + + return (NULL); +} diff --git a/libdtv/liblx/xMemMgt.c b/libdtv/liblx/xMemMgt.c new file mode 100644 index 000000000..363ee4a59 --- /dev/null +++ b/libdtv/liblx/xMemMgt.c @@ -0,0 +1,621 @@ +////////////////////////////////////////////////////////////// +/// /// +/// xMemMgt.c: memory management functions of liblx /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/06/25 12:29:47 $ +// $Author: kls $ +// +// (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// liblx is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// liblx is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with liblx; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#include <stdio.h> +#include <malloc.h> + +#include "liblx.h" + +#ifdef DEBUG +void logPrintf(int, char *, ...); +#endif + +static struct MEM_CHUNK *xRememberKey = NULL; + +static struct MEM_CHUNK **xRememberPtr = &xRememberKey; + +unsigned long xAllocatedMemory = 0; + +/************************************************************************* + * * + * function : xMemAlloc * + * * + * parameter : Size - size of the requested memory area * + * * + * DataPointer - pointer to data pointer * + * * + * return : none * + * * + *-----------------------------------------------------------------------* + * * + * xMemAlloc() is a clustered, remembering memory management routine. * + * It uses its own tables for free and used memory blocks on private * + * memory area. With xMemFree(), you can free this memory likewise * + * the C free() routine, with xMemFreeAll() all memory at once. * + * By changing the current remember key with xSetRemember() you can * + * define a local memory area, which can be freed by only one call of * + * xMemFreeAll() (see xSetRemember() / xGetRemember()). * + * * + *************************************************************************/ + +void xMemAllo (Size, DataPointer) + +unsigned long Size; +unsigned char **DataPointer; +{ + struct MEM_CHUNK *MemChunk, *MemChunkPred; + struct MEM_ENTRY *MemEntry, *MemEntryPred; + long int NewSize; + unsigned short FoundFlag; +#ifdef DEBUG + unsigned char *ptr; +#endif + + while (Size % 4) Size++; + + if (Size > (MEM_CHUNK_SIZE - sizeof(struct MEM_CHUNK) - + sizeof(struct MEM_ENTRY))) + { + NewSize = Size + sizeof(struct MEM_CHUNK) + sizeof(struct MEM_ENTRY); + + if (MemChunk = (*xRememberPtr)) + { + do + { + MemChunkPred = MemChunk; + } while (MemChunk = MemChunk->Succ); + } + else MemChunkPred = (struct MEM_CHUNK *) &(*xRememberPtr); + + MemChunk = MemChunkPred->Succ = (struct MEM_CHUNK *) malloc (NewSize); + xAllocatedMemory += NewSize; + +#ifdef DEBUG + for (ptr = (unsigned char *) MemChunk; ptr < (unsigned char *) + (MemChunk) + NewSize; ptr++) + *ptr = (((unsigned long)ptr)&1) ? 0x55 : 0xAA; +#endif + + if (!MemChunk) + { +#ifdef DEBUG + logPrintf (0, "Not enough memory...\r\n"); +#endif + exit (1); + } + + MemChunk->Size = NewSize; + MemChunk->Pred = MemChunkPred; + MemChunk->Succ = NULL; + MemChunk->FirstFreeMemEntry = NULL; + MemChunk->FirstUsedMemEntry = + MemEntry = (struct MEM_ENTRY *) ((unsigned char *)MemChunk + + sizeof(struct MEM_CHUNK)); + + MemEntry->Size = Size; + MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstUsedMemEntry; + MemEntry->Succ = NULL; + + *DataPointer = (unsigned char *) ((unsigned char *)MemEntry + + sizeof(struct MEM_ENTRY)); +#ifdef DEBUG_CALLS + logPrintf (0, "xMemAlloc: %x, %d bytes\r\n", *DataPointer, Size); +#endif + return; + } + + MemEntry = NULL; + FoundFlag = 0; + + if (MemChunk = (*xRememberPtr)) + { + do + { + if (MemEntry = MemChunk->FirstFreeMemEntry) + do + { + if (Size <= MemEntry->Size) FoundFlag = 1; + } while ((FoundFlag == 0) && (MemEntry = MemEntry->Succ)); + MemChunkPred = MemChunk; + } while ((FoundFlag == 0) && (MemChunk = MemChunk->Succ)); + } + else MemChunkPred = (struct MEM_CHUNK *) &(*xRememberPtr); + + if (!MemEntry) + { + MemChunk = MemChunkPred->Succ = + (struct MEM_CHUNK *) malloc (MEM_CHUNK_SIZE); + xAllocatedMemory += MEM_CHUNK_SIZE; + +#ifdef DEBUG + for (ptr = (unsigned char *) MemChunk; ptr < (unsigned char *) + (MemChunk) + MEM_CHUNK_SIZE; ptr++) + *ptr = (((unsigned long)ptr)&1) ? 0x55 : 0xAA; +#endif + + if (!MemChunk) + { +#ifdef DEBUG + logPrintf (0, "Not enough memory...\r\n"); +#endif + exit (1); + } + + MemChunk->Size = MEM_CHUNK_SIZE; + MemChunk->Pred = MemChunkPred; + MemChunk->Succ = NULL; + MemChunk->FirstUsedMemEntry = NULL; + MemChunk->FirstFreeMemEntry = + MemEntry = (struct MEM_ENTRY *) + ((unsigned char *)MemChunk + sizeof(struct MEM_CHUNK)); + + MemEntry->Size = MEM_CHUNK_SIZE - sizeof(struct MEM_CHUNK) - + sizeof(struct MEM_ENTRY); + MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstFreeMemEntry; + MemEntry->Succ = NULL; + } + + NewSize = MemEntry->Size - sizeof(struct MEM_ENTRY) - Size; + + MemEntry->Size = Size; + *DataPointer = (unsigned char *) + ((unsigned char *)MemEntry + sizeof(struct MEM_ENTRY)); + +#ifdef DEBUG + for (ptr = *DataPointer; ptr < (unsigned char *) + (*DataPointer) + Size; ptr++) + { + if (((unsigned long )ptr)&1) + { if (*ptr != 0x55) + logPrintf (0, "freed memory was used\r\n"); } + else { if (*ptr != 0xAA) + logPrintf (0, "freed memory was used\r\n"); } + } +#endif + + if (MemEntry->Succ) + ((struct MEM_ENTRY *)MemEntry->Succ)->Pred = MemEntry->Pred; + ((struct MEM_ENTRY *)MemEntry->Pred)->Succ = MemEntry->Succ; + + if (MemChunk->FirstUsedMemEntry) + MemChunk->FirstUsedMemEntry->Pred = MemEntry; + MemEntry->Succ = MemChunk->FirstUsedMemEntry; + MemChunk->FirstUsedMemEntry = MemEntry; + MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstUsedMemEntry; + + if (NewSize > 0) + { + MemEntry = (struct MEM_ENTRY *) + ((unsigned char *)MemEntry + sizeof(struct MEM_ENTRY) + Size); + MemEntry->Size = NewSize; + + if (MemChunk->FirstFreeMemEntry) + MemChunk->FirstFreeMemEntry->Pred = MemEntry; + MemEntry->Succ = MemChunk->FirstFreeMemEntry; + MemChunk->FirstFreeMemEntry = MemEntry; + MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstFreeMemEntry; + } +#ifdef DEBUG_CALLS + logPrintf (0, "xMemAlloc: %x, %d bytes\r\n", *DataPointer, Size); +#endif + return; +} + + + +/************************************************************************* + * * + * function : xMemFree * + * * + * parameter : DataPointer - data pointer * + * * + * return : none * + * * + *-----------------------------------------------------------------------* + * * + * xMemFree() frees with xMemAlloc() allocated memory. * + * * + *************************************************************************/ + +void xMemFre (DataPointer) + +unsigned char *DataPointer; +{ + struct MEM_CHUNK *MemChunk, *MemChunkPred; + struct MEM_ENTRY *MemEntry, *TempEntry, *PredEntry, *SuccEntry; + unsigned short FoundFlag; +#ifdef DEBUG + unsigned char *ptr; +#endif + + if (!DataPointer) + { + return; + } + else + { + MemEntry = NULL; + FoundFlag = 0; + + if (MemChunk = (*xRememberPtr)) + do + { + if (MemEntry = MemChunk->FirstUsedMemEntry) + do + { + if (DataPointer == (unsigned char *) ((unsigned char *) MemEntry + + sizeof(struct MEM_ENTRY))) FoundFlag = 1; + } while ((FoundFlag == 0) && (MemEntry = MemEntry->Succ)); + } while ((FoundFlag == 0) && (MemChunk = MemChunk->Succ)); + + if (FoundFlag == 1) + { +#ifdef DEBUG_CALLS + logPrintf (0, "xMemFree: %x, %d bytes\r\n", DataPointer, MemEntry->Size); +#endif + if (MemEntry->Succ) + ((struct MEM_ENTRY *)MemEntry->Succ)->Pred = MemEntry->Pred; + ((struct MEM_ENTRY *)MemEntry->Pred)->Succ = MemEntry->Succ; + + if (!MemChunk->FirstUsedMemEntry) + { + if (MemChunk->Succ) + ((struct MEM_CHUNK *)MemChunk->Succ)->Pred = MemChunk->Pred; + ((struct MEM_CHUNK *)MemChunk->Pred)->Succ = MemChunk->Succ; + if (xAllocatedMemory > 0) xAllocatedMemory -= MemChunk->Size; + free (MemChunk); + return; + } + + FoundFlag = 0; + PredEntry = NULL; + SuccEntry = NULL; + if (TempEntry = MemChunk->FirstFreeMemEntry) + do + { + if ((struct MEM_ENTRY *)((unsigned char *)TempEntry + + TempEntry->Size + sizeof(struct MEM_ENTRY)) == MemEntry) + { + FoundFlag ++; + PredEntry = TempEntry; + } + if ((struct MEM_ENTRY *)((unsigned char *)MemEntry + + MemEntry->Size + sizeof(struct MEM_ENTRY)) == TempEntry) + { + FoundFlag ++; + SuccEntry = TempEntry; + } + } while ((FoundFlag != 2) && (TempEntry = TempEntry->Succ)); + + if (PredEntry) + { + if (SuccEntry) + { + /* Vorgdnger + Nachfolger */ + + if (SuccEntry->Succ) + ((struct MEM_ENTRY *)SuccEntry->Succ)->Pred = SuccEntry->Pred; + ((struct MEM_ENTRY *)SuccEntry->Pred)->Succ = SuccEntry->Succ; + + PredEntry->Size += MemEntry->Size + sizeof(struct MEM_ENTRY) + + SuccEntry->Size + sizeof(struct MEM_ENTRY); + } + else + { + /* nur Vorgaenger */ + + PredEntry->Size += MemEntry->Size + sizeof(struct MEM_ENTRY); + } +#ifdef DEBUG + for (ptr = (unsigned char *) (PredEntry) + sizeof(struct MEM_ENTRY); + ptr < (unsigned char *) (PredEntry) + sizeof(struct MEM_ENTRY) + + PredEntry->Size; ptr++) + *ptr = (((unsigned long)ptr)&1) ? 0x55 : 0xAA; +#endif + } + else + { + if (SuccEntry) + { + /* nur Nachfolger */ + + if (SuccEntry->Succ) + ((struct MEM_ENTRY *)SuccEntry->Succ)->Pred = SuccEntry->Pred; + ((struct MEM_ENTRY *)SuccEntry->Pred)->Succ = SuccEntry->Succ; + + MemEntry->Size += SuccEntry->Size + sizeof(struct MEM_ENTRY); + } + + if (MemChunk->FirstFreeMemEntry) + MemChunk->FirstFreeMemEntry->Pred = MemEntry; + MemEntry->Succ = MemChunk->FirstFreeMemEntry; + MemChunk->FirstFreeMemEntry = MemEntry; + MemEntry->Pred = (struct MEM_ENTRY *) &MemChunk->FirstFreeMemEntry; +#ifdef DEBUG + for (ptr = (unsigned char *) (MemEntry) + sizeof(struct MEM_ENTRY); + ptr < (unsigned char *) (MemEntry) + sizeof(struct MEM_ENTRY) + + MemEntry->Size; ptr++) + *ptr = (((unsigned long)ptr)&1) ? 0x55 : 0xAA; +#endif + } + } +#ifdef DEBUG_CALLS + else + logPrintf (0, "xMemFree: tried to free unallocated data %x\r\n", DataPointer); +#endif + } + return; +} + + + +/************************************************************************* + * * + * function : xMemFreeAll * + * * + * parameter : RememberPtr * + * * + * return : none * + * * + *-----------------------------------------------------------------------* + * * + * xMemFreeAll() frees all with xMemAlloc() allocated memory. If Re- * + * memberPtr is not NULL, the MEM_CHUNK structure from the specified * + * Address is freed, otherwise the natural MEM_CHUNK will be done. * + * * + *************************************************************************/ + + +void xMemFreeAll (RememberPtr) + +struct MEM_CHUNK **RememberPtr; +{ + struct MEM_CHUNK *MemChunk, *MemChunkPred; + + if (RememberPtr) + { + if (MemChunkPred = (*RememberPtr)) + do + { + MemChunk = MemChunkPred->Succ; + if (xAllocatedMemory > 0) xAllocatedMemory -= MemChunkPred->Size; + free (MemChunkPred); + } while (MemChunkPred = MemChunk); + *RememberPtr = NULL; + } + else + { + if (MemChunkPred = (*xRememberPtr)) + do + { + MemChunk = MemChunkPred->Succ; + if (xAllocatedMemory > 0) xAllocatedMemory -= MemChunkPred->Size; + free (MemChunkPred); + } while (MemChunkPred = MemChunk); + *xRememberPtr = NULL; + } +} + + +/************************************************************************* + * * + * function : xMemMerge * + * * + * parameter : RememberPtr * + * * + * return : none * + * * + *-----------------------------------------------------------------------* + * * + * xMemMerge() merges the memory area pointed to by RememberKey with * + * the currently used in xRememberPtr. * + * * + *************************************************************************/ + +void xMemMerge (RememberPtr) + +struct MEM_CHUNK **RememberPtr; +{ + struct MEM_CHUNK *MemChunk, *MemChunkPred; + + if (RememberPtr) + { + if (MemChunk = (*xRememberPtr)) + { + while (MemChunk->Succ) MemChunk = MemChunk->Succ; + MemChunk->Succ = (*RememberPtr); + *RememberPtr = NULL; + } + else (*xRememberPtr = *RememberPtr); + } + return; +} + +/************************************************************************* + * * + * function : xGetRemember * + * * + * parameter : none * + * * + * return : pointer to a MEM_CHUNK tree * + * * + *-----------------------------------------------------------------------* + * * + * xGetRemember() returns the currently used MEM_CHUNK tree. * + * * + *************************************************************************/ + + +struct MEM_CHUNK **xGetRemember () +{ + return (xRememberPtr); +} + + +/************************************************************************* + * * + * function : xSetRemember * + * * + * parameter : pointer to a MEM_CHUNK tree * + * * + * return : none * + * * + *-----------------------------------------------------------------------* + * * + * xSetRemember() redefines the currently used MEM_CHUNK pointer. If * + * RememberPtr is NULL, the natural MEM_CHUNK is reloaded. * + * * + *************************************************************************/ + + +void xSetRemember (RememberPtr) + +struct MEM_CHUNK **RememberPtr; +{ + if (RememberPtr) + xRememberPtr = RememberPtr; + else + xRememberPtr = &xRememberKey; +} + +/************************************************************************* + * * + * function : xPrintMemList * + * * + * parameter : pointer to a MEM_CHUNK tree * + * * + * return : none * + * * + *-----------------------------------------------------------------------* + * * + * xPrintMemList() prints the currently allocated memory blocks of * + * the specified RememberPtr. * + * * + *************************************************************************/ + + +void xPrintMemList (Remember) + +struct MEM_CHUNK **Remember; +{ + struct MEM_CHUNK *MemChunk; + struct MEM_ENTRY *MemEntry; + + fprintf (stderr, "MemChunkPtr = %x\n", (int) Remember); + + if (MemChunk = *Remember) + do + { + fprintf (stderr, "\tMemChunk at %x with Size %d\n", (int) MemChunk, + (int) MemChunk->Size); + + if (MemEntry = MemChunk->FirstFreeMemEntry) + do + { + fprintf (stderr, "\t\tFree MemEntry at %x (%x) with Size %d\n", + (int) MemEntry, (int)((unsigned char *)MemEntry + + sizeof(struct MEM_ENTRY)), (int) MemEntry->Size); + + } while (MemEntry = MemEntry->Succ); + + if (MemEntry = MemChunk->FirstUsedMemEntry) + do + { + fprintf (stderr, "\t\tUsed MemEntry at %x (%x) with Size %d\n", + (int) MemEntry, (int)((unsigned char *)MemEntry + + sizeof(struct MEM_ENTRY)), (int) MemEntry->Size); + + } while (MemEntry = MemEntry->Succ); + + } while (MemChunk = MemChunk->Succ); + else fprintf (stderr, "\tNo current MemChunk\n"); +} + + +/************************************************************************* + * * + * function : xGetMemSize * + * * + * parameter : pointer to a MEM_CHUNK tree * + * * + * return : none * + * * + *-----------------------------------------------------------------------* + * * + * xGetMemSize() gets the size of the currently allocated memory * + * blocks of the specified (or natural if NULL) RememberPtr * + * * + *************************************************************************/ + + +unsigned long xGetMemSize (RememberPtr) + +struct MEM_CHUNK **RememberPtr; +{ + struct MEM_CHUNK *MemChunk; + struct MEM_ENTRY *MemEntry; + unsigned long Result = 0; + + if (RememberPtr) MemChunk = *RememberPtr; + else MemChunk = xRememberKey; + + if (MemChunk) + do { Result += (unsigned long) MemChunk->Size; } + while (MemChunk = MemChunk->Succ); + + return (Result); +} + + +/************************************************************************* + * * + * function : xSetText * + * * + * arguments : xText - pointer to a string * + * * + * return : pointer to an new allocated string * + * * + *-----------------------------------------------------------------------* + * * + * xSetText() allocates memory for the string pointed to by 'xText' * + * and duplicates it. * + * * + *************************************************************************/ + +char *xSetText (xText) + +char *xText; +{ + char *NewText; + + if (!xText) return (NULL); + + xMemAlloc (strlen(xText) + 1, &NewText); + strcpy (NewText, xText); + + return (NewText); +} diff --git a/libdtv/libsi/COPYING b/libdtv/libsi/COPYING new file mode 100644 index 000000000..a43ea2126 --- /dev/null +++ b/libdtv/libsi/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libdtv/libsi/Makefile b/libdtv/libsi/Makefile new file mode 100644 index 000000000..4b939b944 --- /dev/null +++ b/libdtv/libsi/Makefile @@ -0,0 +1,83 @@ +############################################################## +### ### +### Makefile: local makefile for libsi ### +### ### +############################################################## + +## $Revision: 1.1 $ +## $Date: 2001/08/15 14:47:22 $ +## $Author: kls $ +## +## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +## +## dtv_scan is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## dtv_scan is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You may have received a copy of the GNU General Public License +## along with dtv_scan; see the file COPYING. If not, write to the +## Free Software Foundation, Inc., 59 Temple Place - Suite 330, +## Boston, MA 02111-1307, USA. +# +# +# + +.DELETE_ON_ERROR: + +CC = gcc +CFLAGS = -O2 -g -Wmissing-prototypes -Wstrict-prototypes \ + -DNAPI -Wimplicit -D__USE_FIXED_PROTOTYPES__ # -ansi -pedantic + +INCDIRS = -Iinclude -I../include +DISTDIR = ../lib +DISTINCDIR = ../include +INCLUDES = include/libsi.h include/si_tables.h +MAKEDEPEND = gcc -M + +LIBDIRS = -L. -L../lib +LIBS = -lsi -llx + +AR = ar +ARFLAGS = ru +RANLIB = ranlib + +SILIB = libsi.a +OBJS = si_parser.o si_debug_services.o + +all : $(SILIB) + +clean : + @echo cleaning workspace... + @rm -f $(OBJS) $(SILIB) *~ + @rm -f Makefile.dep + +depend : Makefile.dep +Makefile.dep : + @echo "updating dependencies..." + @$(MAKEDEPEND) $(INCDIRS) $(OBJS:%.o=%.c) $(SITEST_OBJS:%.o=%.c) \ + $(SISCAN_OBJS:%.o=%.c) > Makefile.dep + +new : clean depend all + +dist: all + @echo "distributing $(SILIB) to $(DISTDIR)..." + @cp $(SILIB) $(DISTDIR) + @cp $(INCLUDES) $(DISTINCDIR) + @$(RANLIB) $(DISTDIR)/$(SILIB) + +$(SILIB) : $(OBJS) + @echo updating library... + @$(AR) $(ARFLAGS) $(SILIB) $(OBJS) + @$(RANLIB) $(SILIB) + +.c.o : + @echo compiling $<... + @$(CC) $(DEFINES) $(CFLAGS) $(INCDIRS) -c $< + +include Makefile.dep diff --git a/libdtv/libsi/README b/libdtv/libsi/README new file mode 100644 index 000000000..4f1be1ab5 --- /dev/null +++ b/libdtv/libsi/README @@ -0,0 +1,2 @@ +DVB - System Information Library +================================ diff --git a/libdtv/libsi/include/libsi.h b/libdtv/libsi/include/libsi.h new file mode 100644 index 000000000..3790ae156 --- /dev/null +++ b/libdtv/libsi/include/libsi.h @@ -0,0 +1,816 @@ +////////////////////////////////////////////////////////////// +/// /// +/// libsi.h: definitions for data structures of libsi /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/06/26 07:18:43 $ +// $Author: kls $ +// +// (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// libsi is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// libsi is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with libsi; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#ifndef LIBSI_H +#define LIBSI_H + +#include <time.h> +#include <sys/types.h> +#include <asm/types.h> + + + /* Program Identifier */ + +#define PID_PAT 0x00 /* Program Association Table */ +#define PID_BAT 0x01 /* Bouquet Association Table */ +#define PID_CAT 0x01 /* Conditional Access Table */ +#define PID_NIT 0x10 /* Network Information Table */ +#define PID_SDT 0x11 /* Service Description Table */ +#define PID_EIT 0x12 /* Event Information Table */ +#define PID_RST 0x13 /* Running Status Table */ +#define PID_TDT 0x14 /* Time Date Table */ +#define PID_TOT 0x14 /* Time Offset Table */ +#define PID_ST 0x14 /* Stuffing Table */ + /* 0x15 - 0x1F */ /* Reserved for future use */ + + /* Table Identifier */ + +#define TID_PAT 0x00 /* Program Association Section */ +#define TID_CAT 0x01 /* Conditional Access Section */ +#define TID_PMT 0x02 /* Conditional Access Section */ + /* 0x03 - 0x3F */ /* Reserved for future use */ +#define TID_NIT_ACT 0x40 /* Network Information Section - + actual */ +#define TID_NIT_OTH 0x41 /* Network Information Section - + other */ +#define TID_SDT_ACT 0x42 /* Service Description Section - + actual */ +#define TID_SDT_OTH 0x46 /* Service Description Section - + other */ +#define TID_EIT_ACT 0x4E /* Event Information Section - + actual */ +#define TID_EIT_OTH 0x4F /* Event Information Section - + other */ +#define TID_EIT_ACT_SCH 0x50 /* Event Information Section - + actual, schedule */ +#define TID_EIT_OTH_SCH 0x60 /* Event Information Section - + other, schedule */ +#define TID_TDT 0x70 /* Time Date Section */ +#define TID_TOT 0x73 /* Time Offset Section */ +#define TID_CA_ECM_0 0x80 +#define TID_CA_ECM_1 0x81 + +#define TID_BAT 0x01 /* Bouquet Association Section */ + +#define TID_EIT 0x12 /* Event Information Section */ +#define TID_RST 0x13 /* Running Status Section */ +#define TID_ST 0x14 /* Stuffung Section */ + /* 0xFF */ /* Reserved for future use */ + + /* Descriptor Identifier */ + + /* defined by ISO/IEC 13818-1 */ + +#define DESCR_VIDEO_STREAM 0x02 +#define DESCR_AUDIO_STREAM 0x03 +#define DESCR_HIERARCHY 0x04 +#define DESCR_REGISTRATION 0x05 +#define DESCR_DATA_STREAM_ALIGN 0x06 +#define DESCR_TARGET_BACKGRID 0x07 +#define DESCR_VIDEO_WINDOW 0x08 +#define DESCR_CA 0x09 +#define DESCR_ISO_639_LANGUAGE 0x0A +#define DESCR_SYSTEM_CLOCK 0x0B +#define DESCR_MULTIPLEX_BUFFER_UTIL 0x0C +#define DESCR_COPYRIGHT 0x0D +#define DESCR_MAXIMUM_BITRATE 0x0E +#define DESCR_PRIVATE_DATA_IND 0x0F +#define DESCR_SMOOTHING_BUFFER 0x10 +#define DESCR_STD 0x11 +#define DESCR_IBP 0x12 + /* 0x13 - 0x3F */ /* Reserved */ + + /* defined by ETSI */ + +#define DESCR_NW_NAME 0x40 +#define DESCR_SERVICE_LIST 0x41 +#define DESCR_STUFFING 0x42 +#define DESCR_SAT_DEL_SYS 0x43 +#define DESCR_CABLE_DEL_SYS 0x44 +#define DESCR_VBI_DATA 0x45 +#define DESCR_VBI_TELETEXT 0x46 +#define DESCR_BOUQUET_NAME 0x47 +#define DESCR_SERVICE 0x48 +#define DESCR_COUNTRY_AVAIL 0x49 +#define DESCR_LINKAGE 0x4A +#define DESCR_NVOD_REF 0x4B +#define DESCR_TIME_SHIFTED_SERVICE 0x4C +#define DESCR_SHORT_EVENT 0x4D +#define DESCR_EXTENDED_EVENT 0x4E +#define DESCR_TIME_SHIFTED_EVENT 0x4F +#define DESCR_COMPONENT 0x50 +#define DESCR_MOSAIC 0x51 +#define DESCR_STREAM_ID 0x52 +#define DESCR_CA_IDENT 0x53 +#define DESCR_CONTENT 0x54 +#define DESCR_PARENTAL_RATING 0x55 +#define DESCR_TELETEXT 0x56 +#define DESCR_TELEPHONE 0x57 +#define DESCR_LOCAL_TIME_OFF 0x58 +#define DESCR_SUBTITLING 0x59 +#define DESCR_TERR_DEL_SYS 0x5A +#define DESCR_ML_NW_NAME 0x5B +#define DESCR_ML_BQ_NAME 0x5C +#define DESCR_ML_SERVICE_NAME 0x5D +#define DESCR_ML_COMPONENT 0x5E +#define DESCR_PRIV_DATA_SPEC 0x5F +#define DESCR_SERVICE_MOVE 0x60 +#define DESCR_SHORT_SMOOTH_BUF 0x61 +#define DESCR_FREQUENCY_LIST 0x62 +#define DESCR_PARTIAL_TP_STREAM 0x63 +#define DESCR_DATA_BROADCAST 0x64 +#define DESCR_CA_SYSTEM 0x65 +#define DESCR_DATA_BROADCAST_ID 0x66 +#define DESCR_TRANSPORT_STREAM 0x67 +#define DESCR_DSNG 0x68 +#define DESCR_PDC 0x69 +#define DESCR_AC3 0x6A +#define DESCR_ANCILLARY_DATA 0x6B +#define DESCR_CELL_LIST 0x6C +#define DESCR_CELL_FREQ_LINK 0x6D +#define DESCR_ANNOUNCEMENT_SUPPORT 0x6E + + +#define MAX_SECTION_BUFFER 4096 + + +/* Strukturen zur Aufnahme der SDT und EIT Informationen */ + +struct Service { + struct NODE Node; + int ServiceID; + int TransportStreamID; + int OriginalNetworkID; + int SdtVersion; + unsigned short Status; + struct LIST *Descriptors; + struct LIST *Events; +}; + +#define EIT_SCHEDULE_FLAG 0x0001 +#define GetScheduleFlag(x) ((x)&EIT_SCHEDULE_FLAG) +#define SetScheduleFlag(x) ((x)|=EIT_SCHEDULE_FLAG) +#define EIT_PRESENT_FOLLOWING_FLAG 0x0002 +#define GetPresentFollowing(x) ((x)&EIT_PRESENT_FOLLOWING_FLAG) +#define SetPresentFollowing(x) ((x)|=EIT_PRESENT_FOLLOWING_FLAG) +#define RUNNING_STATUS_NOT_RUNNING 0x0000 +#define RUNNING_STATUS_AWAITING 0x0004 +#define RUNNING_STATUS_PAUSING 0x0008 +#define RUNNING_STATUS_RUNNING 0x000C +#define GetRunningStatus(x) ((x)&RUNNING_STATUS_RUNNING) +#define SetRunningStatus(x,s) ((x)|=((s)&RUNNING_STATUS_RUNNING)) +#define FREE_TO_AIR 0x0000 +#define CONDITIONAL_ACCESS 0x0010 +#define GetConditionalAccess(x) ((x)&CONDITIONAL_ACCESS) +#define SetConditionalAccess(x) ((x)|=CONDITIONAL_ACCESS) + +#define CreateService(service, svid, tsid, onid, vers, sta) \ + do \ + { \ + xCreateNode (service, NULL); \ + service->ServiceID = svid; \ + service->TransportStreamID = tsid; \ + service->OriginalNetworkID = onid; \ + service->SdtVersion = vers; \ + service->Status = sta; \ + service->Descriptors = xNewList (NULL); \ + service->Events = xNewList (NULL); \ + } while (0) + + +struct Event { + struct NODE Node; + int EventID; + int ServiceID; + int EitVersion; + int TransportStreamID; + int OriginalNetworkID; + time_t StartTime; + time_t Duration; + unsigned short Status; + struct LIST *Descriptors; +}; + +#define CreateEvent(event, evid, svid, tsid, onid, vers, sta) \ + do \ + { \ + xCreateNode (event, NULL); \ + event->EventID = evid; \ + event->ServiceID = svid; \ + event->TransportStreamID = tsid; \ + event->OriginalNetworkID = onid; \ + event->EitVersion = vers; \ + event->Status = sta; \ + event->Descriptors = xNewList (NULL); \ + } while (0) + + +/* Strukturen zur Aufnahme der PAT und PMT Informationen */ + +struct Program { + struct NODE Node; + int ProgramID; + int TransportStreamID; + int NetworkPID; + int PatVersion; + struct LIST *Pids; +}; + +#define CreateProgram(program, pgid, tsid, npid, vers) \ + do \ + { \ + xCreateNode (program, NULL); \ + program->ProgramID = pgid; \ + program->TransportStreamID = tsid; \ + program->NetworkPID = npid; \ + program->PatVersion = vers; \ + program->Pids = xNewList (NULL); \ + } while (0) + +struct Pid { + struct NODE Node; + int ProgramID; + int PcrPID; + int PmtVersion; + struct LIST *Descriptors; + struct LIST *InfoList; +}; + +#define CreatePid(pid, pgid, pcid, vers) \ + do \ + { \ + xCreateNode (pid, NULL); \ + pid->ProgramID = pgid; \ + pid->PcrPID = pcid; \ + pid->PmtVersion = vers; \ + pid->Descriptors = xNewList (NULL); \ + pid->InfoList = xNewList (NULL); \ + } while (0) + +struct PidInfo { + struct NODE Node; + int StreamType; + int ElementaryPid; + struct LIST *Descriptors; +}; + +#define CreatePidInfo(pidinfo, styp, epid) \ + do \ + { \ + xCreateNode (pidinfo, NULL); \ + pidinfo->StreamType = styp; \ + pidinfo->ElementaryPid = epid; \ + pidinfo->Descriptors = xNewList (NULL); \ + } while (0) + + +#define STREAMTYPE_ISO_VIDEO 1 +#define STREAMTYPE_13818_VIDEO 2 +#define STREAMTYPE_11172_AUDIO 3 +#define STREAMTYPE_13818_AUDIO 4 +#define STREAMTYPE_VIDEOTEXT 6 +#define STREAMTYPE_13522_MPEG 7 +#define STREAMTYPE_ITU_222 8 +#define STREAMTYPE_13818_A 9 +#define STREAMTYPE_13818_B 10 +#define STREAMTYPE_13818_C 11 +#define STREAMTYPE_13818_D 12 +#define STREAMTYPE_13818_AUX 13 + +/* Descriptors */ + +#define DescriptorTag(x) ((struct Descriptor *)(x))->Tag + +struct Descriptor { + struct NODE Node; + unsigned short Tag; +}; + + +/* Iso639LanguageDescriptor */ + +struct Iso639LanguageDescriptor { + struct NODE Node; + unsigned short Tag; + char LanguageCode[4]; +}; + +#define CreateIso639LanguageDescriptor(descr, lc1, lc2, lc3) \ + do \ + { \ + xCreateNode (((struct Iso639LanguageDescriptor *)descr), NULL); \ + ((struct Iso639LanguageDescriptor *)descr)->Tag = DESCR_ISO_639_LANGUAGE; \ + ((struct Iso639LanguageDescriptor *)descr)->LanguageCode[0] = lc1; \ + ((struct Iso639LanguageDescriptor *)descr)->LanguageCode[1] = lc2; \ + ((struct Iso639LanguageDescriptor *)descr)->LanguageCode[2] = lc3; \ + ((struct Iso639LanguageDescriptor *)descr)->LanguageCode[3] = '\0'; \ + } while (0) + + +/* AncillaryDataDescriptor */ + +struct AncillaryDataDescriptor { + struct NODE Node; + unsigned short Tag; + unsigned short Identifier; +}; + +#define ANCILLARY_DATA_DVD_VIDEO 0x0001 +#define ANCILLARY_DATA_EXTENDED 0x0002 +#define ANCILLARY_DATA_SWITCHING 0x0004 +#define ANCILLARY_DATA_DAB 0x0008 +#define ANCILLARY_DATA_SCALE_FACTOR 0x0010 + +#define CreateAncillaryDataDescriptor(descr, id) \ + do \ + { \ + xCreateNode (((struct AncillaryDataDescriptor *)descr), NULL); \ + ((struct AncillaryDataDescriptor *)descr)->Tag = DESCR_ANCILLARY_DATA; \ + ((struct AncillaryDataDescriptor *)descr)->Identifier = id; \ + } while (0) + + +/* BouquetNameDescriptor */ + +struct BouquetNameDescriptor { + struct NODE Node; /* Node enthlt Namen */ + unsigned short Tag; +}; + +#define CreateBouquetNameDescriptor(descr, text) \ + do \ + { \ + xCreateNode (((struct BouquetNameDescriptor *)descr), text); \ + ((struct BouquetNameDescriptor *)descr)->Tag = DESCR_BOUQUET_NAME; \ + } while (0) + + +/* CountryAvailabilityDescriptor */ + +struct CountryAvailabilityDescriptor { + struct NODE Node; + unsigned short Tag; + unsigned short AvailibilityFlag; + unsigned short Amount; /* CountryCodes */ + char *CountryCodes; +}; + +#define COUNTRIES_ARE_AVAILABLE 0x0001 +#define COUNTRIES_ARE_UNAVAILABLE 0x0000 + +#define CreateCountryAvailabilityDescriptor(descr, ava) \ + do \ + { \ + xCreateNode (((struct CountryAvailabilityDescriptor *)descr), NULL); \ + ((struct CountryAvailabilityDescriptor *)descr)->Tag = DESCR_COUNTRY_AVAIL; \ + ((struct CountryAvailabilityDescriptor *)descr)->AvailibilityFlag = ava; \ + ((struct CountryAvailabilityDescriptor *)descr)->Amount = 0; \ + ((struct CountryAvailabilityDescriptor *)descr)->CountryCodes = NULL; \ + } while (0) + +#define AddCountryAvailabilityCode(descr, lc1, lc2, lc3) \ + do \ + { \ + char tmpbuf[4], *tmpptr, *ttptr; \ + \ + tmpbuf[0] = lc1; tmpbuf[1] = lc2; \ + tmpbuf[2] = lc3; tmpbuf[3] = '\0'; \ + xMemAlloc (((struct CountryAvailabilityDescriptor *)descr)->Amount*4 + 8, &tmpptr); \ + ttptr = tmpptr; \ + if (((struct CountryAvailabilityDescriptor *)descr)->CountryCodes) { \ + memcpy (ttptr, ((struct CountryAvailabilityDescriptor *)descr)->CountryCodes, \ + ((struct CountryAvailabilityDescriptor *)descr)->Amount*4); \ + ttptr += ((struct CountryAvailabilityDescriptor *)descr)->Amount*4; \ + } \ + memcpy (ttptr, tmpbuf, 4); \ + ((struct CountryAvailabilityDescriptor *)descr)->CountryCodes = tmpptr; \ + } while (0) + + +/* CaIdentifierDescriptor */ + +struct CaIdentifierDescriptor { + struct NODE Node; + unsigned short Tag; + unsigned short Amount; /* SystemIDs */ + unsigned short *SystemID; +}; + +#define CreateCaIdentifierDescriptor(descr, amo) \ + do \ + { \ + xCreateNode (((struct CaIdentifierDescriptor *)descr), NULL); \ + ((struct CaIdentifierDescriptor *)descr)->Tag = DESCR_CA_IDENT; \ + ((struct CaIdentifierDescriptor *)descr)->Amount = amo; \ + xMemAlloc (amo*2+2, &((struct CaIdentifierDescriptor *)descr)->SystemID); \ + } while (0) + +#define SetCaIdentifierID(descr, num, id) \ + ((struct CaIdentifierDescriptor *)descr)->SystemID[num] = id +#define GetCaIdentifierID(descr, num) (((struct CaIdentifierDescriptor *)descr)->SystemID[num]) + + +/* StreamIdentifierDescriptor */ + +struct StreamIdentifierDescriptor { + struct NODE Node; + unsigned short Tag; + unsigned short ComponentTag; +}; + +#define CreateStreamIdentifierDescriptor(descr, ctag) \ + do \ + { \ + xCreateNode (((struct StreamIdentifierDescriptor *)descr), NULL); \ + ((struct StreamIdentifierDescriptor *)descr)->Tag = DESCR_STREAM_ID; \ + ((struct StreamIdentifierDescriptor *)descr)->ComponentTag = (ctag); \ + } while (0) + + +/* DataBroadcastDescriptor */ + +struct DataBroadcastDescriptor { + struct NODE Node; /* Node enthlt DescriptorText */ + unsigned short Tag; + unsigned short DataBroadcastID; + unsigned short ComponentTag; + unsigned short SelectorLength; + unsigned char *SelectorBytes; + char LanguageCode[4]; +}; + +struct MosaicDescriptor { + struct NODE Node; + unsigned short Tag; + /* to be defined */ +}; + +struct MultiLingualServiceDescriptor { + struct NODE Node; + unsigned short Tag; + /* to be defined */ +}; + + +/* NvodReferenceDescriptor */ + +struct NvodReferenceDescriptor { + struct NODE Node; + unsigned short Tag; + struct LIST *Items; +}; + +#define CreateNvodReferenceDescriptor(descr) \ + do \ + { \ + xCreateNode (((struct NvodReferenceDescriptor *)descr), NULL); \ + ((struct NvodReferenceDescriptor *)descr)->Tag = DESCR_NVOD_REF; \ + ((struct NvodReferenceDescriptor *)descr)->Items = xNewList (NULL); \ + } while (0) + +struct NvodReferenceItem { + struct NODE Node; + int TransportStreamID; + int OriginalNetworkID; + int ServiceID; +}; + +#define CreateNvodReferenceItem(itm, tpid, onid, svid) \ + do \ + { \ + xCreateNode (itm, NULL); \ + itm->TransportStreamID = tpid; \ + itm->OriginalNetworkID = onid; \ + itm->ServiceID = svid; \ + } while (0) + +#define AddNvodReferenceItem(desc, tpid, onid, svid) \ + do \ + { \ + struct NvodReferenceItem *item; \ + \ + CreateNvodReferenceItem(item, tpid, onid, svid); \ + xAddTail (((struct NvodReferenceDescriptor *)desc)->Items, item); \ + } while (0) + + +/* LinkageDescriptor */ + +struct LinkageDescriptor { + struct NODE Node; + unsigned short Tag; + int TransportStreamID; + int OriginalNetworkID; + int ServiceID; + int LinkageType; + int PrivateDataLength; + unsigned char *PrivateData; +}; + +#define CreateLinkageDescriptor(descr, tpid, onid, svid, ltyp, pdl, pdp) \ + do \ + { \ + xCreateNode (((struct LinkageDescriptor *)descr), NULL); \ + ((struct LinkageDescriptor *)descr)->Tag = DESCR_LINKAGE; \ + ((struct LinkageDescriptor *)descr)->TransportStreamID = tpid; \ + ((struct LinkageDescriptor *)descr)->OriginalNetworkID = onid; \ + ((struct LinkageDescriptor *)descr)->ServiceID = svid; \ + ((struct LinkageDescriptor *)descr)->LinkageType = ltyp; \ + ((struct LinkageDescriptor *)descr)->PrivateDataLength = pdl; \ + xMemAlloc ((pdl)+1, &(((struct LinkageDescriptor *) \ + descr)->PrivateData)); \ + memcpy ((((struct LinkageDescriptor *)descr)->PrivateData),(pdp),(pdl));\ + } while (0) + + +/* ServiceDescriptor */ + +struct ServiceDescriptor { + struct NODE Node; /* Node enthlt ServiceName */ + unsigned short Tag; + unsigned short ServiceType; + char *ServiceProvider; +}; + +#define CreateServiceDescriptor(descr, styp, prov, name) \ + do \ + { \ + xCreateNode (((struct ServiceDescriptor *)descr), name); \ + ((struct ServiceDescriptor *)descr)->Tag = DESCR_SERVICE; \ + ((struct ServiceDescriptor *)descr)->ServiceType = styp; \ + ((struct ServiceDescriptor *)descr)->ServiceProvider = prov; \ + } while (0) + + + +struct TelephoneDescriptor { + struct NODE Node; + unsigned short Tag; + /* to be defined */ +}; + + +/* TimeShiftedServiceDescriptor */ + +struct TimeShiftedServiceDescriptor { + struct NODE Node; + unsigned short Tag; + int ReferenceServiceID; +}; + +#define CreateTimeShiftedServiceDescriptor(descr, svid) \ + do \ + { \ + xCreateNode (((struct TimeShiftedServiceDescriptor *)descr), NULL); \ + ((struct TimeShiftedServiceDescriptor *)descr)->Tag = DESCR_TIME_SHIFTED_SERVICE; \ + ((struct TimeShiftedServiceDescriptor *)descr)->ReferenceServiceID = svid; \ + } while (0) + + +/* TimeShiftedEventDescriptor */ + +struct TimeShiftedEventDescriptor { + struct NODE Node; + unsigned short Tag; + int ReferenceServiceID; + int ReferenceEventID; +}; + +#define CreateTimeShiftedEventDescriptor(descr, svid, evid) \ + do \ + { \ + xCreateNode (((struct TimeShiftedEventDescriptor *)descr), NULL); \ + ((struct TimeShiftedEventDescriptor *)descr)->Tag = DESCR_TIME_SHIFTED_EVENT; \ + ((struct TimeShiftedEventDescriptor *)descr)->ReferenceServiceID = svid; \ + ((struct TimeShiftedEventDescriptor *)descr)->ReferenceEventID = evid; \ + } while (0) + + +/* ComponentDescriptor */ + +struct ComponentDescriptor { + struct NODE Node; /* Node enthlt ComponentText */ + unsigned short Tag; + unsigned short StreamContent; + unsigned short ComponentType; + unsigned short ComponentTag; + char LanguageCode[4]; +}; + +#define CreateComponentDescriptor(descr, scnt, ctyp, tag, lc1, lc2, lc3, txt) \ + do \ + { \ + xCreateNode (((struct ComponentDescriptor *)descr), txt); \ + ((struct ComponentDescriptor *)descr)->Tag = DESCR_COMPONENT; \ + ((struct ComponentDescriptor *)descr)->StreamContent = scnt; \ + ((struct ComponentDescriptor *)descr)->ComponentType = ctyp; \ + ((struct ComponentDescriptor *)descr)->ComponentTag = tag; \ + ((struct ComponentDescriptor *)descr)->LanguageCode[0] = lc1; \ + ((struct ComponentDescriptor *)descr)->LanguageCode[1] = lc2; \ + ((struct ComponentDescriptor *)descr)->LanguageCode[2] = lc3; \ + ((struct ComponentDescriptor *)descr)->LanguageCode[3] = '\0'; \ + } while (0) + + +/* ContentDescriptor */ + +struct ContentDescriptor { + struct NODE Node; + unsigned short Tag; + unsigned short Amount; /* ContentIDs */ + unsigned short *ContentID; +}; + +#define CreateContentDescriptor(descr, amo) \ + do \ + { \ + xCreateNode (((struct ContentDescriptor *)descr), NULL); \ + ((struct ContentDescriptor *)descr)->Tag = DESCR_CONTENT; \ + ((struct ContentDescriptor *)descr)->Amount = amo; \ + xMemAlloc (amo*2+2, &((struct ContentDescriptor *)descr)->ContentID); \ + } while (0) + +#define SetContentID(descr, num, cnib1, cnib2, unib1, unib2) \ + do \ + { \ + ((struct ContentDescriptor *)descr)->ContentID[num] = \ + ((cnib1&0xF) << 12) | ((cnib2&0xF) << 8) | \ + ((unib1&0xF) << 4) | (unib2&0xF); \ + } while (0) +#define GetContentContentNibble1(descr, num) ((((struct ContentDescriptor *)descr)->ContentID[num]&0xF000) >> 12) +#define GetContentContentNibble2(descr, num) ((((struct ContentDescriptor *)descr)->ContentID[num]&0x0F00) >> 8) +#define GetContentUserNibble1(descr, num) ((((struct ContentDescriptor *)descr)->ContentID[num]&0x00F0) >> 4) +#define GetContentUserNibble2(descr, num) (((struct ContentDescriptor *)descr)->ContentID[num]&0x000F) + + +/* ExtendedEventDescriptor */ + +struct ExtendedEventDescriptor { + struct NODE Node; /* Node enthlt EventText */ + unsigned short Tag; + unsigned short DescriptorNumber; + unsigned short LastDescriptorNumber; + char LanguageCode[4]; + struct LIST *Items; +}; + +#define CreateExtendedEventDescriptor(descr, dnum, ldnb, lc1, lc2, lc3, text) \ + do \ + { \ + xCreateNode (((struct ExtendedEventDescriptor *)descr), text); \ + ((struct ExtendedEventDescriptor *)descr)->Tag = DESCR_EXTENDED_EVENT; \ + ((struct ExtendedEventDescriptor *)descr)->DescriptorNumber = dnum; \ + ((struct ExtendedEventDescriptor *)descr)->LastDescriptorNumber = ldnb; \ + ((struct ExtendedEventDescriptor *)descr)->LanguageCode[0] = lc1; \ + ((struct ExtendedEventDescriptor *)descr)->LanguageCode[1] = lc2; \ + ((struct ExtendedEventDescriptor *)descr)->LanguageCode[2] = lc3; \ + ((struct ExtendedEventDescriptor *)descr)->LanguageCode[3] = '\0'; \ + ((struct ExtendedEventDescriptor *)descr)->Items = xNewList (NULL); \ + } while (0) + +struct ExtendedEventItem { + struct NODE Node; /* Node enthlt ItemDescription Text */ + char *Text; +}; + +#define CreateExtendedEventItem(itm, dtxt, text) \ + do \ + { \ + xCreateNode (itm, dtxt); \ + itm->Text = text; \ + } while (0) + +#define AddExtendedEventItem(desc, dtxt, text) \ + do \ + { \ + struct ExtendedEventItem *item; \ + \ + CreateExtendedEventItem(item, dtxt, text); \ + xAddTail (((struct ExtendedEventDescriptor *)desc)->Items, item); \ + } while (0) + + +/* ParentalRatingDescriptor */ + +struct ParentalRatingDescriptor { + struct NODE Node; + unsigned short Tag; + struct LIST *Ratings; +}; + +#define CreateParentalRatingDescriptor(descr) \ + do \ + { \ + xCreateNode (((struct ParentalRatingDescriptor *)descr), NULL); \ + ((struct ParentalRatingDescriptor *)descr)->Tag = DESCR_PARENTAL_RATING; \ + ((struct ParentalRatingDescriptor *)descr)->Ratings = xNewList (NULL); \ + } while (0) + +struct ParentalRating { + struct NODE Node; /* Node enthlt ItemDescription Text */ + char LanguageCode[4]; + char Rating; +}; + +#define CreateParentalRating(rat, lc1, lc2, lc3, val) \ + do \ + { \ + xCreateNode (rat, NULL); \ + rat->LanguageCode[0] = lc1; \ + rat->LanguageCode[1] = lc2; \ + rat->LanguageCode[2] = lc3; \ + rat->LanguageCode[3] = '\0'; \ + rat->Rating = val; \ + } while (0) + +#define AddParentalRating(desc, lc1, lc2, lc3, val) \ + do \ + { \ + struct ParentalRating *item; \ + \ + CreateParentalRating(item, lc1, lc2, lc3, val); \ + xAddTail (((struct ParentalRatingDescriptor *)desc)->Ratings, item); \ + } while (0) + +/* ShortEventDescriptor */ + +struct ShortEventDescriptor { + struct NODE Node; /* Node enthlt EventName */ + unsigned short Tag; + char LanguageCode[4]; + char *Text; +}; + +#define CreateShortEventDescriptor(descr, name, lc1, lc2, lc3, text) \ + do \ + { \ + xCreateNode (((struct ShortEventDescriptor *)descr), name); \ + ((struct ShortEventDescriptor *)descr)->Tag = DESCR_SHORT_EVENT; \ + ((struct ShortEventDescriptor *)descr)->LanguageCode[0] = lc1; \ + ((struct ShortEventDescriptor *)descr)->LanguageCode[1] = lc2; \ + ((struct ShortEventDescriptor *)descr)->LanguageCode[2] = lc3; \ + ((struct ShortEventDescriptor *)descr)->LanguageCode[3] = '\0'; \ + ((struct ShortEventDescriptor *)descr)->Text = text; \ + } while (0) + + + +/* Prototypes */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* si_parser.c */ + +struct LIST *siParsePAT (u_char *); +struct Pid *siParsePMT (u_char *); +struct LIST *siParseSDT (u_char *); +struct LIST *siParseEIT (u_char *); +time_t siParseTDT (u_char *); +void siParseDescriptors (struct LIST *, u_char *, u_int, u_char); +void siParseDescriptor (struct LIST *, u_char *); +char *siGetDescriptorText (u_char *, u_int); +u_long crc32 (char *data, int len); + +/* si_debug_services.c */ + +void siDebugServices (struct LIST *); +void siDebugService (struct Service *); +void siDebugEvents (char *, struct LIST *); +void siDebugPrograms (char *, struct LIST *); +void siDebugProgram (struct Program *); +void siDebugPids (char *, struct LIST *); +void siDebugDescriptors (char *, struct LIST *); +void siDebugEitServices (struct LIST *); +void siDebugEitEvents (char *, struct LIST *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libdtv/libsi/include/si_tables.h b/libdtv/libsi/include/si_tables.h new file mode 100644 index 000000000..517838af8 --- /dev/null +++ b/libdtv/libsi/include/si_tables.h @@ -0,0 +1,1205 @@ +////////////////////////////////////////////////////////////// +/// /// +/// si_tables.h: definitions for data structures of the /// +/// incoming SI data stream /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/06/25 12:41:20 $ +// $Author: kls $ +// +// (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// libsi is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// libsi is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with libsi; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#ifndef SI_TABLES_H +#define SI_TABLES_H + +#define HILO(x) (x##_hi << 8 | x##_lo) + +#define MjdToEpochTime(x) (((x##_hi << 8 | x##_lo)-40587)*86400) +#define BcdTimeToSeconds(x) ((3600 * ((10*((x##_h & 0xF0)>>4)) + (x##_h & 0xF))) + \ + (60 * ((10*((x##_m & 0xF0)>>4)) + (x##_m & 0xF))) + \ + ((10*((x##_s & 0xF0)>>4)) + (x##_s & 0xF))) + +#define TableHasMoreSections(x) (((pat_t *)(x))->last_section_number > ((pat_t *)(x))->section_number) +#define GetTableId(x) ((pat_t *)(x))->table_id +#define GetSectionNumber(x) ((pat_t *)(x))->section_number +#define GetLastSectionNumber(x) ((pat_t *)(x))->last_section_number +#define GetServiceId(x) (((eit_t *)(x))->service_id_hi << 8) | ((eit_t *)(x))->service_id_lo + +/* + * + * ETSI ISO/IEC 13818-1 specifies SI which is referred to as PSI. The PSI + * data provides information to enable automatic configuration of the + * receiver to demultiplex and decode the various streams of programs + * within the multiplex. The PSI data is structured as four types of table. + * The tables are transmitted in sections. + * + * 1) Program Association Table (PAT): + * + * - for each service in the multiplex, the PAT indicates the location + * (the Packet Identifier (PID) values of the Transport Stream (TS) + * packets) of the corresponding Program Map Table (PMT). + * It also gives the location of the Network Information Table (NIT). + * + */ + +#define PAT_LEN 8 + +typedef struct { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char dummy :1; // has to be 0 + u_char :2; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :2; + u_char dummy :1; // has to be 0 + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; +} pat_t; + +#define PAT_PROG_LEN 4 + +typedef struct { + u_char program_number_hi :8; + u_char program_number_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char network_pid_hi :5; +#else + u_char network_pid_hi :5; + u_char :3; +#endif + u_char network_pid_lo :8; + /* or program_map_pid (if prog_num=0)*/ +} pat_prog_t; + +/* + * + * 2) Conditional Access Table (CAT): + * + * - the CAT provides information on the CA systems used in the + * multiplex; the information is private and dependent on the CA + * system, but includes the location of the EMM stream, when + * applicable. + * + */ + /* TO BE DONE */ +/* + * + * 3) Program Map Table (PMT): + * + * - the PMT identifies and indicates the locations of the streams that + * make up each service, and the location of the Program Clock + * Reference fields for a service. + * + */ + +#define PMT_LEN 12 + +typedef struct { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char dummy :1; // has to be 0 + u_char :2; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :2; + u_char dummy :1; // has to be 0 + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char program_number_hi :8; + u_char program_number_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char PCR_PID_hi :5; +#else + u_char PCR_PID_hi :5; + u_char :3; +#endif + u_char PCR_PID_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char program_info_length_hi :4; +#else + u_char program_info_length_hi :4; + u_char :4; +#endif + u_char program_info_length_lo :8; + //descriptors +} pmt_t; + +#define PMT_INFO_LEN 5 + +typedef struct { + u_char stream_type :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char elementary_PID_hi :5; +#else + u_char elementary_PID_hi :5; + u_char :3; +#endif + u_char elementary_PID_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char ES_info_length_hi :4; +#else + u_char ES_info_length_hi :4; + u_char :4; +#endif + u_char ES_info_length_lo :8; + // descriptors +} pmt_info_t; + +/* + * + * 4) Network Information Table (NIT): + * + * - the NIT is intended to provide information about the physical + * network. The syntax and semantics of the NIT are defined in + * ETSI EN 300 468. + * + */ + +#define NIT_LEN 10 + +typedef struct { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char network_id_hi :8; + u_char network_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char network_descriptor_length_hi :4; +#else + u_char network_descriptor_length_hi :4; + u_char :4; +#endif + u_char network_descriptor_length_lo :8; + /* descriptors */ +} nit_t; + +#define SIZE_NIT_MID 2 + +typedef struct { // after descriptors +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char transport_stream_loop_length_hi :4; +#else + u_char transport_stream_loop_length_hi :4; + u_char :4; +#endif + u_char transport_stream_loop_length_lo :8; +} nit_mid_t; + +#define SIZE_NIT_END 4 + +struct nit_end_struct { + long CRC; +}; + +#define NIT_TS_LEN 6 + +typedef struct { + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char transport_descriptors_length_hi :4; +#else + u_char transport_descriptors_length_hi :4; + u_char :4; +#endif + u_char transport_descriptors_length_lo :8; + /* descriptors */ +} nit_ts_t; + +/* + * + * In addition to the PSI, data is needed to provide identification of + * services and events for the user. In contrast with the PAT, CAT, and + * PMT of the PSI, which give information only for the multiplex in which + * they are contained (the actual multiplex), the additional information + * defined within the present document can also provide information on + * services and events carried by different multiplexes, and even on other + * networks. This data is structured as nine tables: + * + * 1) Bouquet Association Table (BAT): + * + * - the BAT provides information regarding bouquets. As well as giving + * the name of the bouquet, it provides a list of services for each + * bouquet. + * + */ + /* TO BE DONE */ +/* + * + * 2) Service Description Table (SDT): + * + * - the SDT contains data describing the services in the system e.g. + * names of services, the service provider, etc. + * + */ + +#define SDT_LEN 11 + +typedef struct { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char :8; +} sdt_t; + +#define SDT_DESCR_LEN 5 + +typedef struct { + u_char service_id_hi :8; + u_char service_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :6; + u_char eit_schedule_flag :1; + u_char eit_present_following_flag :1; + u_char running_status :3; + u_char free_ca_mode :1; + u_char descriptors_loop_length_hi :4; +#else + u_char eit_present_following_flag :1; + u_char eit_schedule_flag :1; + u_char :6; + u_char descriptors_loop_length_hi :4; + u_char free_ca_mode :1; + u_char running_status :3; +#endif + u_char descriptors_loop_length_lo :8; +} sdt_descr_t; + +/* + * + * 3) Event Information Table (EIT): + * + * - the EIT contains data concerning events or programmes such as event + * name, start time, duration, etc.; - the use of different descriptors + * allows the transmission of different kinds of event information e.g. + * for different service types. + * + */ + +#define EIT_LEN 14 + +typedef struct { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char service_id_hi :8; + u_char service_id_lo :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number :8; + u_char last_section_number :8; + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char segment_last_section_number :8; + u_char segment_last_table_id :8; +} eit_t; + +#define EIT_EVENT_LEN 12 + +typedef struct { + u_char event_id_hi :8; + u_char event_id_lo :8; + u_char mjd_hi :8; + u_char mjd_lo :8; + u_char start_time_h :8; + u_char start_time_m :8; + u_char start_time_s :8; + u_char duration_h :8; + u_char duration_m :8; + u_char duration_s :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char running_status :3; + u_char free_ca_mode :1; + u_char descriptors_loop_length_hi :4; +#else + u_char descriptors_loop_length_hi :4; + u_char free_ca_mode :1; + u_char running_status :3; +#endif + u_char descriptors_loop_length_lo :8; +} eit_event_t; + +/* + * + * 4) Running Status Table (RST): + * + * - the RST gives the status of an event (running/not running). The RST + * updates this information and allows timely automatic switching to + * events. + * + */ + /* TO BE DONE */ +/* + * + * 5) Time and Date Table (TDT): + * + * - the TDT gives information relating to the present time and date. + * This information is given in a separate table due to the frequent + * updating of this information. + * + */ + +#define TDT_LEN 8 + +typedef struct { + u_char table_id :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo :8; + u_char utc_mjd_hi :8; + u_char utc_mjd_lo :8; + u_char utc_time_h :8; + u_char utc_time_m :8; + u_char utc_time_s :8; +} tdt_t; + +/* + * + * 6) Time Offset Table (TOT): + * + * - the TOT gives information relating to the present time and date and + * local time offset. This information is given in a separate table due + * to the frequent updating of the time information. + * + */ + /* TO BE DONE */ +/* + * + * 7) Stuffing Table (ST): + * + * - the ST is used to invalidate existing sections, for example at + * delivery system boundaries. + * + */ + /* TO BE DONE */ +/* + * + * 8) Selection Information Table (SIT): + * + * - the SIT is used only in "partial" (i.e. recorded) bitstreams. It + * carries a summary of the SI information required to describe the + * streams in the partial bitstream. + * + */ + /* TO BE DONE */ +/* + * + * 9) Discontinuity Information Table (DIT): + * + * - the DIT is used only in "partial" (i.e. recorded) bitstreams. + * It is inserted where the SI information in the partial bitstream may + * be discontinuous. Where applicable the use of descriptors allows a + * flexible approach to the organization of the tables and allows for + * future compatible extensions. + * + */ + /* TO BE DONE */ +/* + * + * The following describes the different descriptors that can be used within + * the SI. + * + * The following semantics apply to all the descriptors defined in this + * subclause: + * + * descriptor_tag: The descriptor tag is an 8-bit field which identifies + * each descriptor. Those values with MPEG-2 normative + * meaning are described in ISO/IEC 13818-1. The values of + * descriptor_tag are defined in 'libsi.h' + * descriptor_length: The descriptor length is an 8-bit field specifying the + * total number of bytes of the data portion of the + * descriptor following the byte defining the value of + * this field. + * + */ + +#define DESCR_GEN_LEN 2 +typedef struct descr_gen_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; +} descr_gen_t; +#define CastGenericDescriptor(x) ((descr_gen_t *)(x)) + +#define GetDescriptorTag(x) (((descr_gen_t *) x)->descriptor_tag) +#define GetDescriptorLength(x) (((descr_gen_t *) x)->descriptor_length+DESCR_GEN_LEN) + + +/* 0x0A iso_639_language_descriptor */ + +#define DESCR_ISO_639_LANGUAGE_LEN 5 +typedef struct descr_iso_639_language_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; +} descr_iso_639_language_t; +#define CastIso639LanguageDescriptor(x) ((descr_iso_639_language_t *)(x)) + + +/* 0x40 network_name_descriptor */ + +#define DESCR_NETWORK_NAME_LEN XX +typedef struct descr_network_name_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_network_name_t; +#define CastNetworkNameDescriptor(x) ((descr_network_name_t *)(x)) + + +/* 0x41 service_list_descriptor */ + +#define DESCR_SERVICE_LIST_LEN XX +typedef struct descr_service_list_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_service_list_t; +#define CastServiceListDescriptor(x) ((descr_service_list_t *)(x)) + + +/* 0x42 stuffing_descriptor */ + +#define DESCR_STUFFING_LEN XX +typedef struct descr_stuffing_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_stuffing_t; +#define CastStuffingDescriptor(x) ((descr_stuffing_t *)(x)) + + +/* 0x43 satellite_delivery_system_descriptor */ + +#define DESCR_SATELLITE_DELIVERY_SYSTEM_LEN 13 +typedef struct descr_satellite_delivery_system_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char frequency1 :8; + u_char frequency2 :8; + u_char frequency3 :8; + u_char frequency4 :8; + u_char orbital_position1 :8; + u_char orbital_position2 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char modulation :5; + u_char polarization :2; + u_char west_east_flag :1; +#else + u_char west_east_flag :1; + u_char polarization :2; + u_char modulation :5; +#endif + u_char symbol_rate1 :8; + u_char symbol_rate2 :8; + u_char symbol_rate3 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char symbol_rate4 :4; + u_char fec_inner :4; +#else + u_char fec_inner :4; + u_char symbol_rate4 :4; +#endif +} descr_satellite_delivery_system_t; +#define CastSatelliteDeliverySystemDescriptor(x) ((descr_satellite_delivery_system_t *)(x)) + + +/* 0x44 cable_delivery_system_descriptor */ + +#define DESCR_CABLE_DELIVERY_SYSTEM_LEN 13 +typedef struct descr_cable_delivery_system_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char frequency1 :8; + u_char frequency2 :8; + u_char frequency3 :8; + u_char frequency4 :8; + u_char reserved1 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char reserved2 :4; + u_char fec_outer :4; +#else + u_char fec_outer :4; + u_char reserved2 :4; +#endif + u_char modulation :8; + u_char symbol_rate1 :8; + u_char symbol_rate2 :8; + u_char symbol_rate3 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char symbol_rate4 :4; + u_char fec_inner :4; +#else + u_char fec_inner :4; + u_char symbol_rate4 :4; +#endif +} descr_cable_delivery_system_t; +#define CastCableDeliverySystemDescriptor(x) ((descr_cable_delivery_system_t *)(x)) + + +/* 0x45 vbi_data_descriptor */ + +#define DESCR_VBI_DATA_LEN XX +typedef struct descr_vbi_data_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_vbi_data_t; +#define CastVbiDataDescriptor(x) ((descr_vbi_data_t *)(x)) + + +/* 0x46 vbi_teletext_descriptor */ + +#define DESCR_VBI_TELETEXT_LEN XX +typedef struct descr_vbi_teletext_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_vbi_teletext_t; +#define CastVbiDescriptor(x) ((descr_vbi_teletext_t *)(x)) + + +/* 0x47 bouquet_name_descriptor */ + +#define DESCR_BOUQUET_NAME_LEN 2 +typedef struct descr_bouquet_name_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; +} descr_bouquet_name_t; +#define CastBouquetNameDescriptor(x) ((descr_bouquet_name_t *)(x)) + + +/* 0x48 service_descriptor */ + +#define DESCR_SERVICE_LEN 4 +typedef struct descr_service_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char service_type :8; + u_char provider_name_length :8; +} descr_service_t; +#define CastServiceDescriptor(x) ((descr_service_t *)(x)) + + +/* 0x49 country_availability_descriptor */ + +#define DESCR_COUNTRY_AVAILABILITY_LEN 3 +typedef struct descr_country_availability_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char country_availability_flag :1; + u_char reserved :7; +#else + u_char reserved :7; + u_char country_availability_flag :1; +#endif +} descr_country_availability_t; +#define CastCountryAvailabilityDescriptor(x) ((descr_country_availability_t *)(x)) + + +/* 0x4A linkage_descriptor */ + +#define DESCR_LINKAGE_LEN 9 +typedef struct descr_linkage_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char service_id_hi :8; + u_char service_id_lo :8; + u_char linkage_type :8; +} descr_linkage_t; +#define CastLinkageDescriptor(x) ((descr_linkage_t *)(x)) + + +/* 0x4B nvod_reference_descriptor */ + +#define DESCR_NVOD_REFERENCE_LEN 2 +typedef struct descr_nvod_reference_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; +} descr_nvod_reference_t; +#define CastNvodReferenceDescriptor(x) ((descr_nvod_reference_t *)(x)) + +#define ITEM_NVOD_REFERENCE_LEN 6 +typedef struct item_nvod_reference_struct { + u_char transport_stream_id_hi :8; + u_char transport_stream_id_lo :8; + u_char original_network_id_hi :8; + u_char original_network_id_lo :8; + u_char service_id_hi :8; + u_char service_id_lo :8; +} item_nvod_reference_t; +#define CastNvodReferenceItem(x) ((item_nvod_reference_t *)(x)) + + + +/* 0x4C time_shifted_service_descriptor */ + +#define DESCR_TIME_SHIFTED_SERVICE_LEN 4 +typedef struct descr_time_shifted_service_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char reference_service_id_hi :8; + u_char reference_service_id_lo :8; +} descr_time_shifted_service_t; +#define CastTimeShiftedServiceDescriptor(x) ((descr_time_shifted_service_t *)(x)) + + +/* 0x4D short_event_descriptor */ + +#define DESCR_SHORT_EVENT_LEN 6 +typedef struct descr_short_event_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char event_name_length :8; +} descr_short_event_t; +#define CastShortEventDescriptor(x) ((descr_short_event_t *)(x)) + + +/* 0x4E extended_event_descriptor */ + +#define DESCR_EXTENDED_EVENT_LEN 7 +typedef struct descr_extended_event_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +#if BYTE_ORDER == BIG_ENDIAN + u_char descriptor_number :4; + u_char last_descriptor_number :4; +#else + u_char last_descriptor_number :4; + u_char descriptor_number :4; +#endif + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char length_of_items :8; +} descr_extended_event_t; +#define CastExtendedEventDescriptor(x) ((descr_extended_event_t *)(x)) + +#define ITEM_EXTENDED_EVENT_LEN 1 +typedef struct item_extended_event_struct { + u_char item_description_length :8; +} item_extended_event_t; +#define CastExtendedEventItem(x) ((item_extended_event_t *)(x)) + + +/* 0x4F time_shifted_event_descriptor */ + +#define DESCR_TIME_SHIFTED_EVENT_LEN 6 +typedef struct descr_time_shifted_event_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char reference_service_id_hi :8; + u_char reference_service_id_lo :8; + u_char reference_event_id_hi :8; + u_char reference_event_id_lo :8; +} descr_time_shifted_event_t; +#define CastTimeShiftedEventDescriptor(x) ((descr_time_shifted_event_t *)(x)) + + +/* 0x50 component_descriptor */ + +#define DESCR_COMPONENT_LEN 8 +typedef struct descr_component_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char reserved :4; + u_char stream_content :4; +#else + u_char stream_content :4; + u_char reserved :4; +#endif + u_char component_type :8; + u_char component_tag :8; + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; +} descr_component_t; +#define CastComponentDescriptor(x) ((descr_component_t *)(x)) + + +/* 0x51 mosaic_descriptor */ + +#define DESCR_MOSAIC_LEN XX +typedef struct descr_mosaic_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_mosaic_t; +#define CastMosaicDescriptor(x) ((descr_mosaic_t *)(x)) + + +/* 0x52 stream_identifier_descriptor */ + +#define DESCR_STREAM_IDENTIFIER_LEN 3 +typedef struct descr_stream_identifier_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char component_tag :8; +} descr_stream_identifier_t; +#define CastStreamIdentifierDescriptor(x) ((descr_stream_identifier_t *)(x)) + + +/* 0x53 ca_identifier_descriptor */ + +#define DESCR_CA_IDENTIFIER_LEN 2 +typedef struct descr_ca_identifier_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; +} descr_ca_identifier_t; +#define CastCaIdentifierDescriptor(x) ((descr_ca_identifier_t *)(x)) + + +/* 0x54 content_descriptor */ + +#define DESCR_CONTENT_LEN 2 +typedef struct descr_content_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; +} descr_content_t; +#define CastContentDescriptor(x) ((descr_content_t *)(x)) + +typedef struct nibble_content_struct { +#if BYTE_ORDER == BIG_ENDIAN + u_char content_nibble_level_1 :4; + u_char content_nibble_level_2 :4; + u_char user_nibble_1 :4; + u_char user_nibble_2 :4; +#else + u_char user_nibble_2 :4; + u_char user_nibble_1 :4; + u_char content_nibble_level_2 :4; + u_char content_nibble_level_1 :4; +#endif +} nibble_content_t; +#define CastContentNibble(x) ((nibble_content_t *)(x)) + + +/* 0x55 parental_rating_descriptor */ + +#define DESCR_PARENTAL_RATING_LEN 2 +typedef struct descr_parental_rating_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; +} descr_parental_rating_t; +#define CastParentalRatingDescriptor(x) ((descr_parental_rating_t *)(x)) + +#define PARENTAL_RATING_LEN 4 +typedef struct parental_rating_struct { + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char rating :8; +} parental_rating_t; +#define CastParentalRating(x) ((parental_rating_t *)(x)) + + +/* 0x56 teletext_descriptor */ + +#define DESCR_TELETEXT_LEN XX +typedef struct descr_teletext_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_teletext_t; +#define CastTeletextDescriptor(x) ((descr_teletext_t *)(x)) + + +/* 0x57 telephone_descriptor */ + +#define DESCR_TELEPHONE_LEN XX +typedef struct descr_telephone_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_telephone_t; +#define CastTelephoneDescriptor(x) ((descr_telephone_t *)(x)) + + +/* 0x58 local_time_offset_descriptor */ + +#define DESCR_LOCAL_TIME_OFFSET_LEN XX +typedef struct descr_local_time_offset_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_local_time_offset_t; +#define CastLocalTimeOffsetDescriptor(x) ((descr_local_time_offset_t *)(x)) + + +/* 0x59 subtitling_descriptor */ + +#define DESCR_SUBTITLING_LEN XX +typedef struct descr_subtitling_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_subtitling_t; +#define CastSubtitlingDescriptor(x) ((descr_subtitling_t *)(x)) + + +/* 0x5A terrestrial_delivery_system_descriptor */ + +#define DESCR_TERRESTRIAL_DELIVERY_SYSTEM_LEN XX +typedef struct descr_terrestrial_delivery_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_terrestrial_delivery_system_t; +#define CastTerrestrialDeliverySystemDescriptor(x) ((descr_terrestrial_delivery_system_t *)(x)) + + +/* 0x5B multilingual_network_name_descriptor */ + +#define DESCR_MULTILINGUAL_NETWORK_NAME_LEN XX +typedef struct descr_multilingual_network_name_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_multilingual_network_name_t; +#define CastMultilingualNetworkNameDescriptor(x) ((descr_multilingual_network_name_t *)(x)) + + +/* 0x5C multilingual_bouquet_name_descriptor */ + +#define DESCR_MULTILINGUAL_BOUQUET_NAME_LEN XX +typedef struct descr_multilingual_bouquet_name_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_multilingual_bouquet_name_t; +#define CastMultilingualBouquetNameDescriptor(x) ((descr_multilingual_bouquet_name_t *)(x)) + + +/* 0x5D multilingual_service_name_descriptor */ + +#define DESCR_MULTILINGUAL_SERVICE_NAME_LEN XX +typedef struct descr_multilingual_service_name_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_multilingual_service_name_t; +#define CastMultilingualServiceNameDescriptor(x) ((descr_multilingual_service_name_t *)(x)) + + +/* 0x5E multilingual_component_descriptor */ + +#define DESCR_MULTILINGUAL_COMPONENT_LEN XX +typedef struct descr_multilingual_component_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_multilingual_component_t; +#define CastMultilingualComponentDescriptor(x) ((descr_multilingual_component_t *)(x)) + + +/* 0x5F private_data_specifier_descriptor */ + +#define DESCR_PRIVATE_DATA_SPECIFIER_LEN XX +typedef struct descr_private_data_specifier_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_private_data_specifier_t; +#define CastPrivateDataSpecifierDescriptor(x) ((descr_private_data_specifier_t *)(x)) + + +/* 0x60 service_move_descriptor */ + +#define DESCR_SERVICE_MOVE_LEN XX +typedef struct descr_service_move_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_service_move_t; +#define CastServiceMoveDescriptor(x) ((descr_service_move_t *)(x)) + + +/* 0x61 short_smoothing_buffer_descriptor */ + +#define DESCR_SHORT_SMOOTHING_BUFFER_LEN XX +typedef struct descr_short_smoothing_buffer_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_short_smoothing_buffer_t; +#define CastShortSmoothingBufferDescriptor(x) ((descr_short_smoothing_buffer_t *)(x)) + + +/* 0x62 frequency_list_descriptor */ + +#define DESCR_FREQUENCY_LIST_LEN XX +typedef struct descr_frequency_list_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_frequency_list_t; +#define CastFrequencyListDescriptor(x) ((descr_frequency_list_t *)(x)) + + +/* 0x63 partial_transport_stream_descriptor */ + +#define DESCR_PARTIAL_TRANSPORT_STREAM_LEN XX +typedef struct descr_partial_transport_stream_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_partial_transport_stream_t; +#define CastPartialDescriptor(x) ((descr_partial_transport_stream_t *)(x)) + + +/* 0x64 data_broadcast_descriptor */ + +#define DESCR_DATA_BROADCAST_LEN XX +typedef struct descr_data_broadcast_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_data_broadcast_t; +#define CastDataBroadcastDescriptor(x) ((descr_data_broadcast_t *)(x)) + + +/* 0x65 ca_system_descriptor */ + +#define DESCR_CA_SYSTEM_LEN XX +typedef struct descr_ca_system_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_ca_system_t; +#define CastCaSystemDescriptor(x) ((descr_ca_system_t *)(x)) + + +/* 0x66 data_broadcast_id_descriptor */ + +#define DESCR_DATA_BROADCAST_ID_LEN XX +typedef struct descr_data_broadcast_id_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_data_broadcast_id_t; +#define CastDataBroadcastIdDescriptor(x) ((descr_data_broadcast_id_t *)(x)) + + +/* 0x67 transport_stream_descriptor */ + +#define DESCR_TRANSPORT_STREAM_LEN XX +typedef struct descr_transport_stream_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_transport_stream_t; +#define CastTransportStreamDescriptor(x) ((descr_transport_stream_t *)(x)) + + +/* 0x68 dsng_descriptor */ + +#define DESCR_DSNG_LEN XX +typedef struct descr_dsng_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_dsng_t; +#define CastDsngDescriptor(x) ((descr_dsng_t *)(x)) + + +/* 0x69 pdc_descriptor */ + +#define DESCR_PDC_LEN XX +typedef struct descr_pdc_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_pdc_t; +#define CastPdcDescriptor(x) ((descr_pdc_t *)(x)) + + +/* 0x6A ac3_descriptor */ + +#define DESCR_AC3_LEN XX +typedef struct descr_ac3_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_ac3_t; +#define CastAc3Descriptor(x) ((descr_ac3_t *)(x)) + + +/* 0x6B ancillary_data_descriptor */ + +#define DESCR_ANCILLARY_DATA_LEN 3 +typedef struct descr_ancillary_data_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + u_char ancillary_data_identifier :8; +} descr_ancillary_data_t; +#define CastAncillaryDataDescriptor(x) ((descr_ancillary_data_t *)(x)) + + +/* 0x6C cell_list_descriptor */ + +#define DESCR_CELL_LIST_LEN XX +typedef struct descr_cell_list_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_cell_list_t; +#define CastCellListDescriptor(x) ((descr_cell_list_t *)(x)) + + +/* 0x6D cell_frequency_link_descriptor */ + +#define DESCR_CELL_FREQUENCY_LINK_LEN XX +typedef struct descr_cell_frequency_link_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_cell_frequency_link_t; +#define CastCellFrequencyLinkDescriptor(x) ((descr_cell_frequency_link_t *)(x)) + + +/* 0x6E announcement_support_descriptor */ + +#define DESCR_ANNOUNCEMENT_SUPPORT_LEN XX +typedef struct descr_announcement_support_struct { + u_char descriptor_tag :8; + u_char descriptor_length :8; + /* TBD */ +} descr_announcement_support_t; +#define CastAnnouncementSupportDescriptor(x) ((descr_announcement_support_t *)(x)) + +#endif diff --git a/libdtv/libsi/si_debug_services.c b/libdtv/libsi/si_debug_services.c new file mode 100644 index 000000000..dd09cff8c --- /dev/null +++ b/libdtv/libsi/si_debug_services.c @@ -0,0 +1,487 @@ +////////////////////////////////////////////////////////////// +/// /// +/// si_debug_services.c: debugging functions for libsi /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/08/15 14:40:55 $ +// $Author: kls $ +// +// (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// libsi is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// libsi is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with libsi; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "../liblx/liblx.h" +#include "libsi.h" +#include "si_debug_services.h" + + + + +void siDebugServices (struct LIST *Services) +{ + struct Service *Service; + + if (!Services) return; + + xForeach (Services, Service) + { + printf ("Service\n=======\n"); + printf (" ServiceID: %d\n", Service->ServiceID); + printf (" TransportStreamID: %d\n", Service->TransportStreamID); + printf (" OriginalNetworkID: %d\n", Service->OriginalNetworkID); + printf (" SdtVersion: %d\n", Service->SdtVersion); + printf (" Status: "); + if (GetScheduleFlag (Service->Status)) + printf ("SCHEDULE_INFO "); + if (GetPresentFollowing(Service->Status)) + printf ("PRESENT_FOLLOWING "); + switch (GetRunningStatus (Service->Status)) + { + case RUNNING_STATUS_NOT_RUNNING: + printf ("RUNNING_STATUS_NOT_RUNNING\n"); + break; + + case RUNNING_STATUS_AWAITING: + printf ("RUNNING_STATUS_AWAITING\n"); + break; + + case RUNNING_STATUS_PAUSING: + printf ("RUNNING_STATUS_PAUSING\n"); + break; + + case RUNNING_STATUS_RUNNING: + printf ("RUNNING_STATUS_RUNNING\n"); + break; + } + siDebugDescriptors (" ", Service->Descriptors); + siDebugEvents (" ", Service->Events); + } + return; +} + +void siDebugService (struct Service *Service) +{ + if (!Service) return; + + printf ("Service\r\n=======\r\n"); + printf (" ServiceID: %d\r\n", Service->ServiceID); + printf (" TransportStreamID: %d\r\n", Service->TransportStreamID); + printf (" OriginalNetworkID: %d\r\n", Service->OriginalNetworkID); + printf (" SdtVersion: %d\r\n", Service->SdtVersion); + printf (" Status: "); + if (GetScheduleFlag (Service->Status)) + printf ("SCHEDULE_INFO "); + if (GetPresentFollowing(Service->Status)) + printf ("PRESENT_FOLLOWING "); + switch (GetRunningStatus (Service->Status)) + { + case RUNNING_STATUS_NOT_RUNNING: + printf ("RUNNING_STATUS_NOT_RUNNING\r\n"); + break; + + case RUNNING_STATUS_AWAITING: + printf ("RUNNING_STATUS_AWAITING\r\n"); + break; + + case RUNNING_STATUS_PAUSING: + printf ("RUNNING_STATUS_PAUSING\r\n"); + break; + + case RUNNING_STATUS_RUNNING: + printf ("RUNNING_STATUS_RUNNING\r\n"); + break; + } + siDebugDescriptors ("\r ", Service->Descriptors); + siDebugEvents ("\r ", Service->Events); + + return; +} + +void siDebugEvents (char *Prepend, struct LIST *EventList) +{ + struct Event *Event; + char NewPrepend[32]; + + if (!EventList) return; + + xForeach (EventList, Event) + { + printf ("%sEvent\n%s=====\n", Prepend, Prepend); + printf ("%s EventID: %d\n", Prepend, Event->EventID); + printf ("%s ServiceID: %d\n", Prepend, Event->ServiceID); + printf ("%s TransportStreamID: %d\n", Prepend, Event->TransportStreamID); + printf ("%s OriginalNetworkID: %d\n", Prepend, Event->OriginalNetworkID); + printf ("%s EitVersion: %d\n", Prepend, Event->EitVersion); + printf ("%s StartTime: %s", Prepend, ctime (&Event->StartTime)); + printf ("%s Duration: %d Minuten\n", Prepend, Event->Duration/60); + printf ("%s Status: "); + switch (GetRunningStatus (Event->Status)) + { + case RUNNING_STATUS_NOT_RUNNING: + printf ("RUNNING_STATUS_NOT_RUNNING\n"); + break; + + case RUNNING_STATUS_AWAITING: + printf ("RUNNING_STATUS_AWAITING\n"); + break; + + case RUNNING_STATUS_PAUSING: + printf ("RUNNING_STATUS_PAUSING\n"); + break; + + case RUNNING_STATUS_RUNNING: + printf ("RUNNING_STATUS_RUNNING\n"); + break; + } + sprintf (NewPrepend, "%s ", Prepend); + siDebugDescriptors (NewPrepend, Event->Descriptors); + } + return; +} + + +void siDebugPrograms (char *Prepend, struct LIST *ProgramList) +{ + struct Program *Program; + char NewPrepend[32]; + + if (!ProgramList) return; + + xForeach (ProgramList, Program) + { + printf ("%sProgram\n%s=======\n", Prepend, Prepend); + printf ("%s ProgramID: %d\n", Prepend, Program->ProgramID); + printf ("%s TransportStreamID: %d\n", Prepend, Program->TransportStreamID); + printf ("%s NetworkPID: %d\n", Prepend, Program->NetworkPID); + printf ("%s PatVersion: %d\n", Prepend, Program->PatVersion); + + sprintf (NewPrepend, "%s ", Prepend); + siDebugPids (NewPrepend, Program->Pids); + } + return; +} + +void siDebugProgram (struct Program *Program) +{ + if (!Program) return; + + printf ("Program\r\n=======\r\n"); + printf (" ProgramID: %d\r\n", Program->ProgramID); + printf (" TransportStreamID: %d\r\n", Program->TransportStreamID); + printf (" NetworkPID: %d\r\n", Program->NetworkPID); + printf (" PatVersion: %d\r\n", Program->PatVersion); + + siDebugPids ("\r ", Program->Pids); + + return; +} + +void siDebugPids (char *Prepend, struct LIST *PidList) +{ + struct Pid *Pid; + struct PidInfo *PidInfo; + char NewPrepend[32]; + int index; + + if (!PidList) return; + + xForeach (PidList, Pid) + { + printf ("%sPid\n%s===\n", Prepend, Prepend); + printf ("%s ProgramID: %d\n", Prepend, Pid->ProgramID); + printf ("%s PcrPid: %d\n", Prepend, Pid->PcrPID); + printf ("%s PmtVersion: %d\n", Prepend, Pid->PmtVersion); + + xForeach (Pid->InfoList, PidInfo) + { + printf ("%s PidInfo\n%s =======\n", Prepend, Prepend); + index = PidInfo->StreamType; + if (index > 0x0F && index <= 0x7F) index = 0x0E; + if (index >= 0x80) index = 0x0F; + printf ("%s StreamType: %s\n", Prepend, StreamTypes[index]); + printf ("%s ElementaryPid: %d\n", Prepend, PidInfo->ElementaryPid); + + sprintf (NewPrepend, "%s ", Prepend); + siDebugDescriptors (NewPrepend, PidInfo->Descriptors); + } + } + return; +} + + +void siDebugDescriptors (char *Prepend, struct LIST *Descriptors) +{ + struct Descriptor *Descriptor; + int i; + + xForeach (Descriptors, Descriptor) + { + switch (DescriptorTag (Descriptor)) + { + case DESCR_ANCILLARY_DATA: + printf ("%sDescriptor: Ancillary Data\n", Prepend); + printf ("%s Identifier: ", Prepend); + if (((struct AncillaryDataDescriptor *)Descriptor)-> + Identifier & ANCILLARY_DATA_DVD_VIDEO) + printf ("DVD-Video Ancillary Data "); + if (((struct AncillaryDataDescriptor *)Descriptor)-> + Identifier & ANCILLARY_DATA_EXTENDED) + printf ("Extended Ancillary Data "); + if (((struct AncillaryDataDescriptor *)Descriptor)-> + Identifier & ANCILLARY_DATA_SWITCHING) + printf ("Announcement Switching Data "); + if (((struct AncillaryDataDescriptor *)Descriptor)-> + Identifier & ANCILLARY_DATA_DAB) + printf ("DAB Ancillary Data "); + if (((struct AncillaryDataDescriptor *)Descriptor)-> + Identifier & ANCILLARY_DATA_SCALE_FACTOR) + printf ("Scale Factor Error Check (ScF-CRC) "); + printf ("\n"); + break; + + case DESCR_BOUQUET_NAME: + printf ("%sDescriptor: Bouquet Name\n", Prepend); + printf ("%s Name: %s\n", Prepend, xName (Descriptor)); + break; + + case DESCR_COMPONENT: + printf ("%sDescriptor: Component\n", Prepend); + printf ("%s Text: %s\n", Prepend, xName (Descriptor)); + printf ("%s Content/Type: ", Prepend); + for (i = 0; i < COMPONENT_TYPE_NUMBER; i++) + if ((((struct ComponentDescriptor *)Descriptor)-> + StreamContent == ComponentTypes[i].Content) && + (((struct ComponentDescriptor *)Descriptor)-> + ComponentType == ComponentTypes[i].Type)) + { printf ("%s\n", ComponentTypes[i].Description); break; } + if (i == COMPONENT_TYPE_NUMBER) { printf ("unbekannt\n"); } + printf ("%s ComponentTag: 0x%02x\n", Prepend, + ((struct ComponentDescriptor *)Descriptor)->ComponentTag); + printf ("%s LanguageCode: %s\n", Prepend, + ((struct ComponentDescriptor *)Descriptor)->LanguageCode); + break; + + case DESCR_SERVICE: + printf ("%sDescriptor: Service\n", Prepend); + printf ("%s Name: %s\n", Prepend, xName (Descriptor)); + printf ("%s ServiceType: ", Prepend); + for (i = 0; i < SERVICE_TYPE_NUMBER; i++) + if ((((struct ServiceDescriptor *)Descriptor)-> + ServiceType == ServiceTypes[i].Type)) + { printf ("%s\n", ServiceTypes[i].Description); break; } + if (i == SERVICE_TYPE_NUMBER) { printf ("unbekannt\n"); } + printf ("%s ServiceProvider: %s\n", Prepend, + ((struct ServiceDescriptor *)Descriptor)->ServiceProvider); + break; + + case DESCR_COUNTRY_AVAIL: + printf ("%sDescriptor: Country Availability\n", Prepend); + printf ("%s Type: %s\n", Prepend, (((struct CountryAvailabilityDescriptor *)Descriptor)-> + AvailibilityFlag == COUNTRIES_ARE_AVAILABLE) ? "countries are available" : + "countries are unavailable"); + { + char *cptr = ((struct CountryAvailabilityDescriptor *)Descriptor)->CountryCodes; int j; + for (j = 0; j < ((struct CountryAvailabilityDescriptor *)Descriptor)->Amount; j++) + { printf ("%s Country: %s\n", Prepend, cptr); cptr += 4; } + } + break; + + case DESCR_SHORT_EVENT: + printf ("%sDescriptor: Short Event\n", Prepend); + printf ("%s Name: %s\n", Prepend, xName (Descriptor)); + printf ("%s LanguageCode: %s\n", Prepend, + ((struct ShortEventDescriptor *)Descriptor)->LanguageCode); + printf ("%s Text: %s\n", Prepend, + ((struct ShortEventDescriptor *)Descriptor)->Text); + break; + + case DESCR_EXTENDED_EVENT: + { + struct ExtendedEventItem *Item; + + printf ("%sDescriptor: Extended Event\n", Prepend); + printf ("%s Text: %s\n", Prepend, xName (Descriptor)); + printf ("%s DescriptorNumber: %d\n", Prepend, + ((struct ExtendedEventDescriptor *)Descriptor)->DescriptorNumber); + printf ("%s LastDescriptorNumber: %d\n", Prepend, + ((struct ExtendedEventDescriptor *)Descriptor)->LastDescriptorNumber); + printf ("%s LanguageCode: %s\n", Prepend, + ((struct ExtendedEventDescriptor *)Descriptor)->LanguageCode); + xForeach (((struct ExtendedEventDescriptor *)Descriptor)->Items, Item) + { + printf ("%s Item:\n"); + printf ("%s Description: %s\n", xName(Item)); + printf ("%s Text: %s\n", Item->Text); + } + } + break; + + case DESCR_CA_IDENT: + printf ("%sDescriptor: Conditional Access Identity\n", Prepend); + { + int j; + for (j = 0; j < ((struct CaIdentifierDescriptor *)Descriptor)->Amount; j++) + printf ("%s SystemID: 0x%04x\n", Prepend, GetCaIdentifierID (Descriptor, j)); + } + break; + + case DESCR_CONTENT: + printf ("%sDescriptor: Content\n", Prepend); + { + int j; + for (j = 0; j < ((struct ContentDescriptor *)Descriptor)->Amount; j++) + { + printf ("%s Content: ", Prepend); + for (i = 0; i < CONTENT_TYPE_NUMBER; i++) + if ((GetContentContentNibble1(Descriptor, j) == ContentTypes[i].Nibble1) && + (GetContentContentNibble2(Descriptor, j) == ContentTypes[i].Nibble2)) + { printf ("%s\n", ContentTypes[i].Description); break; } + if (i == CONTENT_TYPE_NUMBER) { printf ("unbekannt\n"); } + printf ("%s User-Nibble 1: 0x%1x\n", Prepend, GetContentUserNibble1(Descriptor, j)); + printf ("%s User-Nibble 2: 0x%1x\n", Prepend, GetContentUserNibble2(Descriptor, j)); + } + } + break; + + case DESCR_PARENTAL_RATING: + { + struct ParentalRating *Rating; + + printf ("%sDescriptor: Parental Rating\n", Prepend); + xForeach (((struct ParentalRatingDescriptor *)Descriptor)->Ratings, Rating) + { + printf ("%s Rating:\n"); + printf ("%s LanguageCode: %s\n", Rating->LanguageCode); + printf ("%s Rating: "); + if (Rating->Rating == 0) printf ("(undefined)\n"); + else { if (Rating->Rating <= 0x10) printf ("minimum age is %d\n", Rating->Rating + 3); + else printf ("(rating is provider defined)\n"); } + } + } + break; + + case DESCR_NVOD_REF: + { + struct NvodReferenceItem *Item; + + printf ("%sDescriptor: NVOD Reference\n", Prepend); + xForeach (((struct NvodReferenceDescriptor *)Descriptor)->Items, Item) + { + printf ("%s Item:\n", Prepend); + printf ("%s ServiceID: %d\n", Prepend, Item->ServiceID); + printf ("%s TransportStreamID: %d\n", Prepend, Item->TransportStreamID); + printf ("%s OriginalNetworkID: %d\n", Prepend, Item->OriginalNetworkID); + } + } + break; + + case DESCR_TIME_SHIFTED_SERVICE: + printf ("%sDescriptor: Time Shifted Service\n", Prepend); + printf ("%s ReferenceServiceID: %d\n", Prepend, + ((struct TimeShiftedServiceDescriptor *) + Descriptor)->ReferenceServiceID); + break; + + case DESCR_TIME_SHIFTED_EVENT: + printf ("%sDescriptor: Time Shifted Event\n", Prepend); + printf ("%s ReferenceServiceID: %d\n", Prepend, + ((struct TimeShiftedEventDescriptor *) + Descriptor)->ReferenceServiceID); + printf ("%s ReferenceEventID: %d\n", Prepend, + ((struct TimeShiftedEventDescriptor *) + Descriptor)->ReferenceEventID); + break; + + case DESCR_ISO_639_LANGUAGE: + printf ("%sDescriptor: ISO 639 Language\n", Prepend); + printf ("%s LanguageCode: %s\n", Prepend, + ((struct Iso639LanguageDescriptor *)Descriptor)->LanguageCode); + break; + + case DESCR_STREAM_ID: + printf ("%sDescriptor: Stream Identifier\n", Prepend); + printf ("%s ComponentTag: %d\n", Prepend, + ((struct StreamIdentifierDescriptor *)Descriptor)->ComponentTag); + break; + + case DESCR_LINKAGE: + printf ("%sDescriptor: Linkage\n", Prepend); + printf ("%s TransportStreamID: %d\n", Prepend, + ((struct LinkageDescriptor *)Descriptor)->TransportStreamID); + printf ("%s OriginalNetworkID: %d\n", Prepend, + ((struct LinkageDescriptor *)Descriptor)->OriginalNetworkID); + printf ("%s ServiceID: %d\n", Prepend, + ((struct LinkageDescriptor *)Descriptor)->ServiceID); + printf ("%s LinkageType: %d\n", Prepend, + ((struct LinkageDescriptor *)Descriptor)->LinkageType); + if (((struct LinkageDescriptor *)Descriptor)->PrivateDataLength) + { + int j; + printf ("%s PrivateData: ", Prepend); + for (j = 0; j < ((struct LinkageDescriptor *) + Descriptor)->PrivateDataLength; j++) + printf ("0x%02X ", ((struct LinkageDescriptor *) + Descriptor)->PrivateData[j]); + printf ("\n"); + } + break; + + case DESCR_NW_NAME: + case DESCR_SERVICE_LIST: + case DESCR_STUFFING: + case DESCR_SAT_DEL_SYS: + case DESCR_CABLE_DEL_SYS: + case DESCR_VBI_DATA: + case DESCR_VBI_TELETEXT: + case DESCR_MOSAIC: + case DESCR_TELETEXT: + case DESCR_TELEPHONE: + case DESCR_LOCAL_TIME_OFF: + case DESCR_SUBTITLING: + case DESCR_TERR_DEL_SYS: + case DESCR_ML_NW_NAME: + case DESCR_ML_BQ_NAME: + case DESCR_ML_SERVICE_NAME: + case DESCR_ML_COMPONENT: + case DESCR_PRIV_DATA_SPEC: + case DESCR_SERVICE_MOVE: + case DESCR_SHORT_SMOOTH_BUF: + case DESCR_FREQUENCY_LIST: + case DESCR_PARTIAL_TP_STREAM: + case DESCR_DATA_BROADCAST: + case DESCR_CA_SYSTEM: + case DESCR_DATA_BROADCAST_ID: + case DESCR_TRANSPORT_STREAM: + case DESCR_DSNG: + case DESCR_PDC: + case DESCR_AC3: + case DESCR_CELL_LIST: + case DESCR_CELL_FREQ_LINK: + case DESCR_ANNOUNCEMENT_SUPPORT: + default: + printf ("%sDescriptor: (noch nicht untersttzt)\n", Prepend); + break; + } + } + return; +} + diff --git a/libdtv/libsi/si_debug_services.h b/libdtv/libsi/si_debug_services.h new file mode 100644 index 000000000..33528dbbb --- /dev/null +++ b/libdtv/libsi/si_debug_services.h @@ -0,0 +1,217 @@ +////////////////////////////////////////////////////////////// +/// /// +/// si_debug_services.h: local debugging definitions /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/06/25 12:29:47 $ +// $Author: kls $ +// +// (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// libsi is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// libsi is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with libsi; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + + +struct component_type { + u_char Content; + u_char Type; + char *Description; +}; + +static struct component_type ComponentTypes[] = { + { 0x01, 0x01, "video, 4:3 aspect ratio, 25 Hz" }, + { 0x01, 0x02, "video, 16:9 aspect ratio with pan vectors, 25 Hz" }, + { 0x01, 0x03, "video, 16:9 aspect ratio without pan vectors, 25 Hz" }, + { 0x01, 0x04, "video, > 16:9 aspect ratio, 25 Hz" }, + { 0x01, 0x05, "video, 4:3 aspect ratio, 30 Hz" }, + { 0x01, 0x06, "video, 16:9 aspect ratio with pan vectors, 30 Hz" }, + { 0x01, 0x07, "video, 16:9 aspect ratio without pan vectors, 30 Hz" }, + { 0x01, 0x08, "video, > 16:9 aspect ratio, 30 Hz" }, + { 0x01, 0x09, "HD video, 4:3 aspect ratio, 25 Hz" }, + { 0x01, 0x0A, "HD video, 16:9 aspect ratio with pan vectors, 25 Hz" }, + { 0x01, 0x0B, "HD video, 16:9 aspect ratio without pan vectors, 25 Hz" }, + { 0x01, 0x0C, "HD video, > 16:9 aspect ratio, 25 Hz" }, + { 0x01, 0x0D, "HD video, 4:3 aspect ratio, 30 Hz" }, + { 0x01, 0x0E, "HD video, 16:9 aspect ratio with pan vectors, 30 Hz" }, + { 0x01, 0x0F, "HD video, 16:9 aspect ratio without pan vectors, 30 Hz" }, + { 0x01, 0x10, "HD video, > 16:9 aspect ratio, 30 Hz" }, + { 0x02, 0x01, "audio, single mono channel" }, + { 0x02, 0x02, "audio, dual mono channel" }, + { 0x02, 0x03, "audio, stereo (2 channel)" }, + { 0x02, 0x04, "audio, multi lingual, multi channel" }, + { 0x02, 0x05, "audio, surround sound" }, + { 0x02, 0x40, "audio description for the visually impaired" }, + { 0x02, 0x41, "audio for the hard of hearing" }, + { 0x03, 0x01, "EBU Teletext subtitles" }, + { 0x03, 0x02, "associated EBU Teletext" }, + { 0x03, 0x03, "VBI data" }, + { 0x03, 0x10, "DVB subtitles (normal), no aspect criticality" }, + { 0x03, 0x11, "DVB subtitles (normal), aspect 4:3 only" }, + { 0x03, 0x12, "DVB subtitles (normal), aspect 16:9 only" }, + { 0x03, 0x13, "DVB subtitles (normal), aspect 2.21:1 only" }, + { 0x03, 0x20, "DVB subtitles (hard of hearing), no aspect criticality" }, + { 0x03, 0x21, "DVB subtitles (hard of hearing), aspect 4:3 only" }, + { 0x03, 0x22, "DVB subtitles (hard of hearing), aspect 16:9 only" }, + { 0x03, 0x23, "DVB subtitles (hard of hearing), aspect 2.21:1 only" } +}; +#define COMPONENT_TYPE_NUMBER 35 + + +struct service_type { + u_char Type; + char *Description; +}; + +static struct service_type ServiceTypes[] = { + { 0x01, "digital television service" }, + { 0x02, "digital radio sound service" }, + { 0x03, "Teletext service" }, + { 0x04, "NVOD reference service" }, + { 0x05, "NVOD time-shifted service" }, + { 0x06, "mosaic service" }, + { 0x07, "PAL coded signal" }, + { 0x08, "SECAM coded signal" }, + { 0x09, "D/D2-MAC" }, + { 0x0A, "FM Radio" }, + { 0x0B, "NTSC coded signal" }, + { 0x0C, "data broadcast service" }, + { 0x0D, "common interface data" }, + { 0x0E, "RCS Map" }, + { 0x0F, "RCS FLS" }, + { 0x10, "DVB MHP service" } +}; +#define SERVICE_TYPE_NUMBER 16 + + +struct content_type { + u_char Nibble1; + u_char Nibble2; + char *Description; +}; + +static struct content_type ContentTypes[] = { + /* Movie/Drama: */ + { 0x01, 0x00, "movie/drama (general)" }, + { 0x01, 0x01, "detective/thriller" }, + { 0x01, 0x02, "adventure/western/war" }, + { 0x01, 0x03, "science fiction/fantasy/horror" }, + { 0x01, 0x04, "comedy" }, + { 0x01, 0x05, "soap/melodrama/folkloric" }, + { 0x01, 0x06, "romance" }, + { 0x01, 0x07, "serious/classical/religious/historical movie/drama" }, + { 0x01, 0x08, "adult movie/drama" }, + /* News/Current affairs: */ + { 0x02, 0x00, "news/current affairs (general)" }, + { 0x02, 0x01, "news/weather report" }, + { 0x02, 0x02, "news magazine" }, + { 0x02, 0x03, "documentary" }, + { 0x02, 0x04, "discussion/interview/debate" }, + /* Show/Game show: */ + { 0x03, 0x00, "show/game show (general)" }, + { 0x03, 0x01, "game show/quiz/contest" }, + { 0x03, 0x02, "variety show" }, + { 0x03, 0x03, "talk show" }, + /* Sports: */ + { 0x04, 0x00, "sports (general)" }, + { 0x04, 0x01, "special events (Olympic Games, World Cup etc.)" }, + { 0x04, 0x02, "sports magazines" }, + { 0x04, 0x03, "football/soccer" }, + { 0x04, 0x04, "tennis/squash" }, + { 0x04, 0x05, "team sports (excluding football)" }, + { 0x04, 0x06, "athletics" }, + { 0x04, 0x07, "motor sport" }, + { 0x04, 0x08, "water sport" }, + { 0x04, 0x09, "winter sports" }, + { 0x04, 0x0A, "equestrian" }, + { 0x04, 0x0B, "martial sports" }, + /* Children's/Youth programmes: */ + { 0x05, 0x00, "children's/youth programmes (general)" }, + { 0x05, 0x01, "pre-school children's programmes" }, + { 0x05, 0x02, "entertainment programmes for 6 to14" }, + { 0x05, 0x03, "entertainment programmes for 10 to 16" }, + { 0x05, 0x04, "informational/educational/school programmes" }, + { 0x05, 0x05, "cartoons/puppets" }, + /* Music/Ballet/Dance: */ + { 0x06, 0x00, "music/ballet/dance (general)" }, + { 0x06, 0x01, "rock/pop" }, + { 0x06, 0x02, "serious music/classical music" }, + { 0x06, 0x03, "folk/traditional music" }, + { 0x06, 0x04, "jazz" }, + { 0x06, 0x05, "musical/opera" }, + { 0x06, 0x06, "ballet" }, + /* Arts/Culture (without music): */ + { 0x07, 0x00, "arts/culture (without music, general)" }, + { 0x07, 0x01, "performing arts" }, + { 0x07, 0x02, "fine arts" }, + { 0x07, 0x03, "religion" }, + { 0x07, 0x04, "popular culture/traditional arts" }, + { 0x07, 0x05, "literature" }, + { 0x07, 0x06, "film/cinema" }, + { 0x07, 0x07, "experimental film/video" }, + { 0x07, 0x08, "broadcasting/press" }, + { 0x07, 0x09, "new media" }, + { 0x07, 0x0A, "arts/culture magazines" }, + { 0x07, 0x0B, "fashion" }, + /* Social/Political issues/Economics: */ + { 0x08, 0x00, "social/political issues/economics (general)" }, + { 0x08, 0x01, "magazines/reports/documentary" }, + { 0x08, 0x02, "economics/social advisory" }, + { 0x08, 0x03, "remarkable people" }, + /* Children's/Youth programmes: */ + /* Education/ Science/Factual topics: */ + { 0x09, 0x00, "education/science/factual topics (general)" }, + { 0x09, 0x01, "nature/animals/environment" }, + { 0x09, 0x02, "technology/natural sciences" }, + { 0x09, 0x03, "medicine/physiology/psychology" }, + { 0x09, 0x04, "foreign countries/expeditions" }, + { 0x09, 0x05, "social/spiritual sciences" }, + { 0x09, 0x06, "further education" }, + { 0x09, 0x07, "languages" }, + /* Leisure hobbies: */ + { 0x0A, 0x00, "leisure hobbies (general)" }, + { 0x0A, 0x01, "tourism/travel" }, + { 0x0A, 0x02, "handicraft" }, + { 0x0A, 0x03, "motoring" }, + { 0x0A, 0x04, "fitness & health" }, + { 0x0A, 0x05, "cooking" }, + { 0x0A, 0x06, "advertisement/shopping" }, + { 0x0A, 0x07, "gardening" }, + { 0x0B, 0x00, "original language" }, + { 0x0B, 0x01, "black & white" }, + { 0x0B, 0x02, "unpublished" }, + { 0x0B, 0x03, "live broadcast" } +}; +#define CONTENT_TYPE_NUMBER 79 + +static char StreamTypes[][70] = { + "ITU-T|ISO/IEC Reserved", + "ISO/IEC Video", + "13818-2 Video or 11172-2 constrained parameter video stream", + "ISO/IEC 11172 Audio", + "ISO/IEC 13818-3 Audio", + "private_sections", + "packets containing private data / Videotext", + "ISO/IEC 13522 MPEG", + "ITU-T Rec. H.222.1", + "ISO/IEC 13818-6 type A", + "ISO/IEC 13818-6 type B", + "ISO/IEC 13818-6 type C", + "ISO/IEC 13818-6 type D", + "ISO/IEC 13818-1 auxiliary", + "ITU-T Rec. H.222.0 | ISO 13818-1 Reserved", + "User private" +}; diff --git a/libdtv/libsi/si_parser.c b/libdtv/libsi/si_parser.c new file mode 100644 index 000000000..acafa7b2e --- /dev/null +++ b/libdtv/libsi/si_parser.c @@ -0,0 +1,881 @@ +////////////////////////////////////////////////////////////// +/// /// +/// si_parser.c: main parsing functions of libsi /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/08/15 14:41:45 $ +// $Author: kls $ +// +// (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// libsi is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// libsi is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with libsi; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#include <stdio.h> +#include <math.h> +#include <time.h> + +#include "../liblx/liblx.h" +#include "libsi.h" +#include "si_tables.h" + + + +struct LIST *siParsePAT (u_char *Buffer) +{ + pat_t *Pat; + pat_prog_t *PatProgram; + u_char *Ptr; + u_int SectionLength; + int TransportStreamID; + int PatVersion; + struct Program *Program; + struct LIST *ProgramList = NULL; + + if (!Buffer) return NULL; + + Pat = (pat_t *) Buffer; Ptr = Buffer; + + if (Pat->table_id != TID_PAT) { +// fprintf (stderr, "PAT: wrong TID %d\n", Pat->table_id); + return NULL; + } + + SectionLength = HILO (Pat->section_length) + 3 - PAT_LEN - 4; + + if (crc32 (Ptr, HILO (Pat->section_length) + 3)) return (NULL); + + TransportStreamID = HILO (Pat->transport_stream_id); + PatVersion = Pat->version_number; + + Ptr += PAT_LEN; + + while (SectionLength > 0) + { + PatProgram = (pat_prog_t *) Ptr; + + CreateProgram (Program, HILO (PatProgram->program_number), + TransportStreamID, HILO (PatProgram->network_pid), PatVersion); + + if (!ProgramList) ProgramList = xNewList (NULL); + xAddTail (ProgramList, Program); + + SectionLength -= PAT_PROG_LEN; + Ptr += PAT_PROG_LEN; + } + + return (ProgramList); +} + + +struct Pid *siParsePMT (u_char *Buffer) +{ + pmt_t *Pmt; + pmt_info_t *PmtInfo; + u_char *Ptr; + u_int SectionLength, ProgramInfoLength, + StreamLength, LoopLength; + int ProgramID; + int PcrID; + int PmtVersion; + struct Pid *Pid; + struct PidInfo *PidInfo; + + if (!Buffer) return NULL; + + Pmt = (pmt_t *) Buffer; Ptr = Buffer; + + if (Pmt->table_id != TID_PMT) { +// fprintf (stderr, "PMT: wrong TID %d\n", Pmt->table_id); + return NULL; + } + + SectionLength = HILO (Pmt->section_length) + 3 - 4; + + if (crc32 (Ptr, HILO (Pmt->section_length) + 3)) return (NULL); + + ProgramInfoLength = HILO (Pmt->program_info_length); + StreamLength = SectionLength - ProgramInfoLength - PMT_LEN; + + ProgramID = HILO (Pmt->program_number); + PmtVersion = Pmt->version_number; + PcrID = HILO (Pmt->PCR_PID); + + Ptr += PMT_LEN; + + CreatePid (Pid, ProgramID, PcrID, PmtVersion); + + siParseDescriptors (Pid->Descriptors, Ptr, ProgramInfoLength, Pmt->table_id); + + Ptr += ProgramInfoLength; + + while (StreamLength > 0) + { + PmtInfo = (pmt_info_t *) Ptr; + + CreatePidInfo (PidInfo, PmtInfo->stream_type, + HILO (PmtInfo->elementary_PID)); + + LoopLength = HILO (PmtInfo->ES_info_length); + Ptr += PMT_INFO_LEN; + + siParseDescriptors (PidInfo->Descriptors, Ptr, LoopLength, Pmt->table_id); + + xAddTail (Pid->InfoList, PidInfo); + + StreamLength -= LoopLength + PMT_INFO_LEN; + Ptr += LoopLength; + } + + return (Pid); +} + + +struct LIST *siParseSDT (u_char *Buffer) +{ + sdt_t *Sdt; + sdt_descr_t *SdtDescriptor; + u_char *Ptr; + u_int SectionLength, LoopLength; + int TransportStreamID; + int SdtVersion; + int OriginalNetworkID; + struct Service *Service; + struct LIST *ServiceList = NULL; + + if (!Buffer) return NULL; + + Sdt = (sdt_t *) Buffer; Ptr = Buffer; + + if (Sdt->table_id != TID_SDT_ACT && Sdt->table_id != TID_SDT_OTH) { +// fprintf (stderr, "SDT: wrong TID %d\n", Sdt->table_id); + return NULL; + } + + SectionLength = HILO (Sdt->section_length) + 3 - SDT_LEN - 4; + + if (crc32 (Ptr, HILO (Sdt->section_length) + 3)) return (NULL); + + TransportStreamID = HILO (Sdt->transport_stream_id); + SdtVersion = Sdt->version_number; + OriginalNetworkID = HILO (Sdt->original_network_id); + + Ptr += SDT_LEN; + + while (SectionLength > 0) + { + SdtDescriptor = (sdt_descr_t *) Ptr; + + CreateService (Service, HILO (SdtDescriptor->service_id), + TransportStreamID, OriginalNetworkID, SdtVersion, + SdtDescriptor->free_ca_mode ? CONDITIONAL_ACCESS : FREE_TO_AIR); + + switch (SdtDescriptor->running_status) + { + case 0x01: + SetRunningStatus (Service->Status, RUNNING_STATUS_NOT_RUNNING); + break; + + case 0x02: + SetRunningStatus (Service->Status, RUNNING_STATUS_AWAITING); + break; + + case 0x03: + SetRunningStatus (Service->Status, RUNNING_STATUS_PAUSING); + break; + + case 0x04: + default: + SetRunningStatus (Service->Status, RUNNING_STATUS_RUNNING); + break; + } + if (SdtDescriptor->eit_schedule_flag) + SetScheduleFlag (Service->Status); + if (SdtDescriptor->eit_present_following_flag) + SetPresentFollowing (Service->Status); + + LoopLength = HILO (SdtDescriptor->descriptors_loop_length); + Ptr += SDT_DESCR_LEN; + + siParseDescriptors (Service->Descriptors, Ptr, LoopLength, Sdt->table_id); + + if (!ServiceList) ServiceList = xNewList (NULL); + xAddTail (ServiceList, Service); + + SectionLength -= LoopLength + SDT_DESCR_LEN; + Ptr += LoopLength; + } + + return (ServiceList); +} + + +struct LIST *siParseEIT (u_char *Buffer) +{ + eit_t *Eit; + eit_event_t *EitEvent; + u_char *Ptr; + u_int SectionLength, LoopLength; + int ServiceID; + int EitVersion; + int TransportStreamID; + int OriginalNetworkID; + struct Event *Event; + struct LIST *EventList = NULL; + + if (!Buffer) return NULL; + + Eit = (eit_t *) Buffer; Ptr = Buffer; + + if (Eit->table_id != TID_EIT_ACT && Eit->table_id != TID_EIT_OTH && + !(Eit->table_id >= TID_EIT_ACT_SCH && + Eit->table_id <= TID_EIT_ACT_SCH + 0x0F) && + !(Eit->table_id >= TID_EIT_OTH_SCH && + Eit->table_id <= TID_EIT_OTH_SCH + 0x0F)) { +// fprintf (stderr, "EIT: wrong TID %d\n", Eit->table_id); + return NULL; + } + + SectionLength = HILO (Eit->section_length) + 3 - EIT_LEN - 4; + + if (crc32 (Ptr, HILO (Eit->section_length) + 3)) return (NULL); + + ServiceID = HILO (Eit->service_id); + TransportStreamID = HILO (Eit->transport_stream_id); + EitVersion = Eit->version_number; + OriginalNetworkID = HILO (Eit->original_network_id); + + Ptr += EIT_LEN; + + while (SectionLength > 0) + { + struct tm thisTime; + int year, month, day; + double mjd; + + EitEvent = (eit_event_t *) Ptr; + + CreateEvent (Event, HILO (EitEvent->event_id), ServiceID, + TransportStreamID, OriginalNetworkID, EitVersion, + EitEvent->free_ca_mode ? CONDITIONAL_ACCESS : FREE_TO_AIR); + + switch (EitEvent->running_status) + { + case 0x01: + SetRunningStatus (Event->Status, RUNNING_STATUS_NOT_RUNNING); + break; + + case 0x02: + SetRunningStatus (Event->Status, RUNNING_STATUS_AWAITING); + break; + + case 0x03: + SetRunningStatus (Event->Status, RUNNING_STATUS_PAUSING); + break; + + case 0x04: + default: + SetRunningStatus (Event->Status, RUNNING_STATUS_RUNNING); + break; + } + Event->StartTime = MjdToEpochTime (EitEvent->mjd) + + BcdTimeToSeconds (EitEvent->start_time); + Event->Duration = BcdTimeToSeconds (EitEvent->duration); + + LoopLength = HILO (EitEvent->descriptors_loop_length); + Ptr += EIT_EVENT_LEN; + + siParseDescriptors (Event->Descriptors, Ptr, LoopLength, Eit->table_id); + + if (!EventList) EventList = xNewList (NULL); + xAddTail (EventList, Event); + + SectionLength -= LoopLength + EIT_EVENT_LEN; + Ptr += LoopLength; + } + + return (EventList); +} + + +time_t siParseTDT (u_char *Buffer) +{ + tdt_t *Tdt; + u_char *Ptr; + u_int SectionLength; + int TdtVersion; + time_t CurrentTime; + + if (!Buffer) return 0; + + Tdt = (tdt_t *) Buffer; Ptr = Buffer; + + if (Tdt->table_id != TID_TDT) { +// fprintf (stderr, "TDT: wrong TID %d\n", Tdt->table_id); + return 0; + } + + SectionLength = HILO (Tdt->section_length) + 3; /* no CRC ?! */ + + CurrentTime = MjdToEpochTime (Tdt->utc_mjd) + + BcdTimeToSeconds (Tdt->utc_time); + + return (CurrentTime); +} + + +void siParseDescriptors (struct LIST *Descriptors, u_char *Buffer, + u_int Length, u_char TableID) +{ + u_int DescriptorLength; + u_char *Ptr; + + DescriptorLength = 0; + Ptr = Buffer; + + while (DescriptorLength < Length) + { + switch (TableID) + { + case TID_NIT_ACT: case TID_NIT_OTH: + switch (GetDescriptorTag(Ptr)) + { + case DESCR_NW_NAME: + case DESCR_SERVICE_LIST: + case DESCR_STUFFING: + case DESCR_SAT_DEL_SYS: + case DESCR_CABLE_DEL_SYS: + case DESCR_LINKAGE: + case DESCR_TERR_DEL_SYS: + case DESCR_ML_NW_NAME: + case DESCR_PRIV_DATA_SPEC: + case DESCR_CELL_LIST: + case DESCR_CELL_FREQ_LINK: + case DESCR_ANNOUNCEMENT_SUPPORT: + siParseDescriptor (Descriptors, Ptr); + break; + + default: + /* fprintf (stderr, "forbidden descriptor 0x%x in NIT\n", + GetDescriptorTag(Ptr));*/ + break; + } + break; + + case TID_BAT: + switch (GetDescriptorTag(Ptr)) + { + case DESCR_SERVICE_LIST: + case DESCR_STUFFING: + case DESCR_BOUQUET_NAME: + case DESCR_SERVICE: + case DESCR_COUNTRY_AVAIL: + case DESCR_LINKAGE: + case DESCR_CA_IDENT: + case DESCR_ML_BQ_NAME: + case DESCR_PRIV_DATA_SPEC: + siParseDescriptor (Descriptors, Ptr); + break; + + default: + /*fprintf (stderr, "forbidden descriptor 0x%x in BAT\n", + GetDescriptorTag(Ptr));*/ + break; + } + break; + + case TID_SDT_ACT: case TID_SDT_OTH: + switch (GetDescriptorTag(Ptr)) + { + case DESCR_STUFFING: + case DESCR_BOUQUET_NAME: + case DESCR_SERVICE: + case DESCR_COUNTRY_AVAIL: + case DESCR_LINKAGE: + case DESCR_NVOD_REF: + case DESCR_TIME_SHIFTED_SERVICE: + case DESCR_MOSAIC: + case DESCR_CA_IDENT: + case DESCR_TELEPHONE: + case DESCR_ML_SERVICE_NAME: + case DESCR_PRIV_DATA_SPEC: + case DESCR_DATA_BROADCAST: + siParseDescriptor (Descriptors, Ptr); + break; + + default: + /* fprintf (stderr, "forbidden descriptor 0x%x in SDT\n", + GetDescriptorTag(Ptr)); */ + break; + } + break; + + case TID_EIT_ACT: case TID_EIT_OTH: + case TID_EIT_ACT_SCH: case TID_EIT_OTH_SCH: + case TID_EIT_ACT_SCH+1: case TID_EIT_OTH_SCH+1: + case TID_EIT_ACT_SCH+2: case TID_EIT_OTH_SCH+2: + case TID_EIT_ACT_SCH+3: case TID_EIT_OTH_SCH+3: + case TID_EIT_ACT_SCH+4: case TID_EIT_OTH_SCH+4: + case TID_EIT_ACT_SCH+5: case TID_EIT_OTH_SCH+5: + case TID_EIT_ACT_SCH+6: case TID_EIT_OTH_SCH+6: + case TID_EIT_ACT_SCH+7: case TID_EIT_OTH_SCH+7: + case TID_EIT_ACT_SCH+8: case TID_EIT_OTH_SCH+8: + case TID_EIT_ACT_SCH+9: case TID_EIT_OTH_SCH+9: + case TID_EIT_ACT_SCH+10: case TID_EIT_OTH_SCH+10: + case TID_EIT_ACT_SCH+11: case TID_EIT_OTH_SCH+11: + case TID_EIT_ACT_SCH+12: case TID_EIT_OTH_SCH+12: + case TID_EIT_ACT_SCH+13: case TID_EIT_OTH_SCH+13: + case TID_EIT_ACT_SCH+14: case TID_EIT_OTH_SCH+14: + case TID_EIT_ACT_SCH+15: case TID_EIT_OTH_SCH+15: + switch (GetDescriptorTag(Ptr)) + { + case DESCR_STUFFING: + case DESCR_LINKAGE: + case DESCR_SHORT_EVENT: + case DESCR_EXTENDED_EVENT: + case DESCR_TIME_SHIFTED_EVENT: + case DESCR_COMPONENT: + case DESCR_CA_IDENT: + case DESCR_CONTENT: + case DESCR_PARENTAL_RATING: + case DESCR_TELEPHONE: + case DESCR_ML_COMPONENT: + case DESCR_PRIV_DATA_SPEC: + case DESCR_SHORT_SMOOTH_BUF: + case DESCR_DATA_BROADCAST: + case DESCR_PDC: + siParseDescriptor (Descriptors, Ptr); + break; + + default: + /*fprintf (stderr, "forbidden descriptor 0x%x in EIT\n", + GetDescriptorTag(Ptr));*/ + break; + } + break; + + case TID_TOT: + switch (GetDescriptorTag(Ptr)) + { + case DESCR_LOCAL_TIME_OFF: + siParseDescriptor (Descriptors, Ptr); + break; + + default: + /*fprintf (stderr, "forbidden descriptor 0x%x in TOT\n", + GetDescriptorTag(Ptr));*/ + break; + } + break; + + case TID_PMT: + switch (GetDescriptorTag(Ptr)) + { + case DESCR_VBI_DATA: + case DESCR_VBI_TELETEXT: + case DESCR_MOSAIC: + case DESCR_STREAM_ID: + case DESCR_TELETEXT: + case DESCR_SUBTITLING: + case DESCR_PRIV_DATA_SPEC: + case DESCR_SERVICE_MOVE: + case DESCR_CA_SYSTEM: + case DESCR_DATA_BROADCAST_ID: + case DESCR_AC3: + case DESCR_ANCILLARY_DATA: + case DESCR_VIDEO_STREAM: + case DESCR_AUDIO_STREAM: + case DESCR_HIERARCHY: + case DESCR_REGISTRATION: + case DESCR_DATA_STREAM_ALIGN: + case DESCR_TARGET_BACKGRID: + case DESCR_VIDEO_WINDOW: + case DESCR_CA: + case DESCR_ISO_639_LANGUAGE: + case DESCR_SYSTEM_CLOCK: + case DESCR_MULTIPLEX_BUFFER_UTIL: + case DESCR_COPYRIGHT: + case DESCR_MAXIMUM_BITRATE: + siParseDescriptor (Descriptors, Ptr); + break; + + default: + /* fprintf (stderr, "forbidden descriptor 0x%x in PMT\n", + GetDescriptorTag(Ptr)); */ + break; + } + break; + + default: + fprintf (stderr, "descriptor 0x%x in unsupported table 0x%x\n", + GetDescriptorTag(Ptr), TableID); + break; + } + DescriptorLength += GetDescriptorLength (Ptr); + Ptr += GetDescriptorLength (Ptr); + } + return; +} + + +void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) +{ + struct NODE *Descriptor = NULL; + char *Text , *Text2; + u_char *Ptr; + int Length, i; + + if (!Descriptors || !Buffer) return; + + Ptr = Buffer; + + switch (GetDescriptorTag(Buffer)) + { + case DESCR_ANCILLARY_DATA: + CreateAncillaryDataDescriptor (Descriptor, + CastAncillaryDataDescriptor(Buffer)->ancillary_data_identifier); + break; + + case DESCR_BOUQUET_NAME: + Text = siGetDescriptorText (Buffer + DESCR_BOUQUET_NAME_LEN, + GetDescriptorLength (Buffer) - DESCR_BOUQUET_NAME_LEN); + CreateBouquetNameDescriptor (Descriptor, Text); +// xMemFree (Text); + break; + + case DESCR_COMPONENT: + Text = siGetDescriptorText (Buffer + DESCR_COMPONENT_LEN, + GetDescriptorLength (Buffer) - DESCR_COMPONENT_LEN); + CreateComponentDescriptor (Descriptor, + CastComponentDescriptor(Buffer)->stream_content, + CastComponentDescriptor(Buffer)->component_type, + CastComponentDescriptor(Buffer)->component_tag, + CastComponentDescriptor(Buffer)->lang_code1, + CastComponentDescriptor(Buffer)->lang_code2, + CastComponentDescriptor(Buffer)->lang_code3, Text); +// xMemFree (Text); + break; + + case DESCR_SERVICE: + Text = siGetDescriptorText (Buffer + DESCR_SERVICE_LEN, + CastServiceDescriptor(Buffer)->provider_name_length); + Text2 = siGetDescriptorText (Buffer + DESCR_SERVICE_LEN + + CastServiceDescriptor(Buffer)->provider_name_length + 1, + *((u_char *)(Buffer + DESCR_SERVICE_LEN + + CastServiceDescriptor(Buffer)->provider_name_length))); + CreateServiceDescriptor (Descriptor, + CastServiceDescriptor(Buffer)->service_type, Text, Text2); +// xMemFree (Text2); + break; + + case DESCR_COUNTRY_AVAIL: + CreateCountryAvailabilityDescriptor (Descriptor, + CastCountryAvailabilityDescriptor(Buffer)->country_availability_flag); + Length = GetDescriptorLength (Buffer) - DESCR_COUNTRY_AVAILABILITY_LEN; + Ptr += DESCR_COUNTRY_AVAILABILITY_LEN; + while (Length > 0) + { AddCountryAvailabilityCode(Descriptor, + Ptr[0], Ptr[1], Ptr[2]); Ptr += 3; Length -= 3; } + break; + + case DESCR_SHORT_EVENT: + Text = siGetDescriptorText (Buffer + DESCR_SHORT_EVENT_LEN, + CastShortEventDescriptor(Buffer)->event_name_length); + Text2 = siGetDescriptorText (Buffer + DESCR_SHORT_EVENT_LEN + + CastShortEventDescriptor(Buffer)->event_name_length + 1, + *((u_char *)(Buffer + DESCR_SHORT_EVENT_LEN + + CastShortEventDescriptor(Buffer)->event_name_length))); + CreateShortEventDescriptor (Descriptor, Text, + CastShortEventDescriptor(Buffer)->lang_code1, + CastShortEventDescriptor(Buffer)->lang_code2, + CastShortEventDescriptor(Buffer)->lang_code3, Text2); +// xMemFree (Text); + break; + + case DESCR_EXTENDED_EVENT: + Text = siGetDescriptorText (Buffer + DESCR_EXTENDED_EVENT_LEN + + CastExtendedEventDescriptor(Buffer)->length_of_items + 1, + *((u_char *)(Buffer + DESCR_EXTENDED_EVENT_LEN + + CastExtendedEventDescriptor(Buffer)->length_of_items))); + CreateExtendedEventDescriptor (Descriptor, + CastExtendedEventDescriptor(Buffer)->descriptor_number, + CastExtendedEventDescriptor(Buffer)->last_descriptor_number, + CastExtendedEventDescriptor(Buffer)->lang_code1, + CastExtendedEventDescriptor(Buffer)->lang_code2, + CastExtendedEventDescriptor(Buffer)->lang_code3, Text); +// xMemFree (Text); + Length = CastExtendedEventDescriptor(Buffer)->length_of_items; + Ptr += DESCR_EXTENDED_EVENT_LEN; + while (Length > 0) + { + Text = siGetDescriptorText (Ptr + ITEM_EXTENDED_EVENT_LEN, + CastExtendedEventItem(Ptr)->item_description_length); + Text2 = siGetDescriptorText (Ptr + ITEM_EXTENDED_EVENT_LEN + + CastExtendedEventItem(Ptr)->item_description_length + 1, + *((u_char *)(Ptr + ITEM_EXTENDED_EVENT_LEN + + CastExtendedEventItem(Ptr)->item_description_length))); + AddExtendedEventItem (Descriptor, Text2, Text); +// xMemFree (Text2); + Length -= ITEM_EXTENDED_EVENT_LEN + CastExtendedEventItem(Ptr)->item_description_length + + *((u_char *)(Ptr + ITEM_EXTENDED_EVENT_LEN + + CastExtendedEventItem(Ptr)->item_description_length)) + 1; + Ptr += ITEM_EXTENDED_EVENT_LEN + CastExtendedEventItem(Ptr)->item_description_length + + *((u_char *)(Ptr + ITEM_EXTENDED_EVENT_LEN + + CastExtendedEventItem(Ptr)->item_description_length)) + 1; + } + break; + + case DESCR_CA_IDENT: + CreateCaIdentifierDescriptor (Descriptor, + (GetDescriptorLength(Buffer) - DESCR_CA_IDENTIFIER_LEN) / 2); + Length = GetDescriptorLength (Buffer) - DESCR_CA_IDENTIFIER_LEN; + Ptr += DESCR_CA_IDENTIFIER_LEN; i = 0; + while (Length > 0) + { SetCaIdentifierID(Descriptor, i, *((u_short *) Ptr)); + Length -= 2; Ptr += 2; i++; } + break; + + case DESCR_CONTENT: + CreateContentDescriptor (Descriptor, + (GetDescriptorLength(Buffer) - DESCR_CONTENT_LEN) / 2); + Length = GetDescriptorLength (Buffer) - DESCR_CONTENT_LEN; + Ptr += DESCR_CONTENT_LEN; i = 0; + while (Length > 0) + { SetContentID(Descriptor, i, CastContentNibble(Ptr)->content_nibble_level_1, + CastContentNibble(Ptr)->content_nibble_level_2, + CastContentNibble(Ptr)->user_nibble_1, + CastContentNibble(Ptr)->user_nibble_2); + Length -= 2; Ptr += 2; i++; } + break; + + case DESCR_STUFFING: + /* intentionally ignored */ + break; + + case DESCR_PARENTAL_RATING: + CreateParentalRatingDescriptor (Descriptor); + Length = GetDescriptorLength (Buffer) - DESCR_PARENTAL_RATING_LEN; + Ptr += DESCR_PARENTAL_RATING_LEN; i = 0; + while (Length > 0) + { AddParentalRating (Descriptor, CastParentalRating(Ptr)->lang_code1, + CastParentalRating(Ptr)->lang_code2, CastParentalRating(Ptr)->lang_code3, + CastParentalRating(Ptr)->rating); + Length -= PARENTAL_RATING_LEN; Ptr += PARENTAL_RATING_LEN; i++; } + break; + + case DESCR_NVOD_REF: + CreateNvodReferenceDescriptor (Descriptor); + Length = GetDescriptorLength (Buffer) - DESCR_NVOD_REFERENCE_LEN; + Ptr += DESCR_NVOD_REFERENCE_LEN; + while (Length > 0) + { + AddNvodReferenceItem (Descriptor, + HILO (CastNvodReferenceItem(Ptr)->transport_stream_id), + HILO (CastNvodReferenceItem(Ptr)->original_network_id), + HILO (CastNvodReferenceItem(Ptr)->service_id)); + Length -= ITEM_NVOD_REFERENCE_LEN; + Ptr += ITEM_NVOD_REFERENCE_LEN; + } + break; + + case DESCR_TIME_SHIFTED_SERVICE: + CreateTimeShiftedServiceDescriptor (Descriptor, + HILO (CastTimeShiftedServiceDescriptor(Ptr)->reference_service_id)); + break; + + case DESCR_TIME_SHIFTED_EVENT: + CreateTimeShiftedEventDescriptor (Descriptor, + HILO (CastTimeShiftedEventDescriptor(Ptr)->reference_service_id), + HILO (CastTimeShiftedEventDescriptor(Ptr)->reference_event_id)); + break; + + case DESCR_ISO_639_LANGUAGE: + CreateIso639LanguageDescriptor (Descriptor, + CastIso639LanguageDescriptor(Buffer)->lang_code1, + CastIso639LanguageDescriptor(Buffer)->lang_code2, + CastIso639LanguageDescriptor(Buffer)->lang_code3); + break; + + case DESCR_STREAM_ID: + CreateStreamIdentifierDescriptor (Descriptor, + CastStreamIdentifierDescriptor(Ptr)->component_tag); + break; + + case DESCR_LINKAGE: + CreateLinkageDescriptor (Descriptor, + HILO (CastLinkageDescriptor(Ptr)->transport_stream_id), + HILO (CastLinkageDescriptor(Ptr)->original_network_id), + HILO (CastLinkageDescriptor(Ptr)->service_id), + CastLinkageDescriptor(Ptr)->linkage_type, + GetDescriptorLength (Ptr) - DESCR_LINKAGE_LEN, + Ptr + DESCR_LINKAGE_LEN); + break; + + case DESCR_VIDEO_STREAM: + case DESCR_AUDIO_STREAM: + case DESCR_HIERARCHY: + case DESCR_REGISTRATION: + case DESCR_DATA_STREAM_ALIGN: + case DESCR_TARGET_BACKGRID: + case DESCR_VIDEO_WINDOW: + case DESCR_CA: + case DESCR_SYSTEM_CLOCK: + case DESCR_MULTIPLEX_BUFFER_UTIL: + case DESCR_COPYRIGHT: + case DESCR_MAXIMUM_BITRATE: + case DESCR_PRIVATE_DATA_IND: + case DESCR_SMOOTHING_BUFFER: + case DESCR_STD: + case DESCR_IBP: + case DESCR_NW_NAME: + case DESCR_SERVICE_LIST: + case DESCR_SAT_DEL_SYS: + case DESCR_CABLE_DEL_SYS: + case DESCR_VBI_DATA: + case DESCR_VBI_TELETEXT: + case DESCR_MOSAIC: + case DESCR_TELETEXT: + case DESCR_TELEPHONE: + case DESCR_LOCAL_TIME_OFF: + case DESCR_SUBTITLING: + case DESCR_TERR_DEL_SYS: + case DESCR_ML_NW_NAME: + case DESCR_ML_BQ_NAME: + case DESCR_ML_SERVICE_NAME: + case DESCR_ML_COMPONENT: + case DESCR_PRIV_DATA_SPEC: + case DESCR_SERVICE_MOVE: + case DESCR_SHORT_SMOOTH_BUF: + case DESCR_FREQUENCY_LIST: + case DESCR_PARTIAL_TP_STREAM: + case DESCR_DATA_BROADCAST: + case DESCR_CA_SYSTEM: + case DESCR_DATA_BROADCAST_ID: + case DESCR_TRANSPORT_STREAM: + case DESCR_DSNG: + case DESCR_PDC: + case DESCR_AC3: + case DESCR_CELL_LIST: + case DESCR_CELL_FREQ_LINK: + case DESCR_ANNOUNCEMENT_SUPPORT: + default: + /* fprintf (stderr, "unsupported descriptor 0x%x\n", + GetDescriptorTag(Buffer)); */ + break; + } + if (Descriptor) xAddTail (Descriptors, Descriptor); + return; +} + + +/* + * ToDo: ETSI conformal text definition + */ +char *siGetDescriptorText (u_char *Buffer, u_int Length) +{ + char *tmp, *result; + int i; + + if (*Buffer == 0x05 || (*Buffer >= 0x20 && *Buffer <= 0xff)) + { + xMemAlloc (Length+1, &result); + tmp = result; + for (i = 0; i < Length; i++) + { + if (*Buffer == 0) break; + + if ((*Buffer >= ' ' && *Buffer <= '~') || + (*Buffer >= 0xa0 && *Buffer <= 0xff)) *tmp++ = *Buffer++; + else Buffer++; + } + *tmp = '\0'; + } + else + { + switch (*Buffer) + { + case 0x01: result = xSetText ("Coding according to character table 1"); break; + case 0x02: result = xSetText ("Coding according to character table 2"); break; + case 0x03: result = xSetText ("Coding according to character table 3"); break; + case 0x04: result = xSetText ("Coding according to character table 4"); break; + case 0x10: result = xSetText ("Coding according to ISO/IEC 8859"); break; + case 0x11: result = xSetText ("Coding according to ISO/IEC 10646"); break; + case 0x12: result = xSetText ("Coding according to KSC 5601"); break; + default: result = xSetText ("Unknown coding"); break; + } + } + + return (result); +} + +// CRC32 lookup table for polynomial 0x04c11db7 + +static u_long crc_table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; + +u_long crc32 (char *data, int len) +{ + register int i; + u_long crc = 0xffffffff; + + for (i=0; i<len; i++) + crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff]; + + return crc; +} diff --git a/libdtv/libvdr/COPYING b/libdtv/libvdr/COPYING new file mode 100644 index 000000000..a43ea2126 --- /dev/null +++ b/libdtv/libvdr/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libdtv/libvdr/Makefile b/libdtv/libvdr/Makefile new file mode 100644 index 000000000..8aecffc61 --- /dev/null +++ b/libdtv/libvdr/Makefile @@ -0,0 +1,62 @@ +############################################################## +### ### +### Makefile: local makefile for libvdr ### +### ### +############################################################## + +## $Revision: 1.1 $ +## $Date: 2001/08/15 14:05:16 $ +## $Author: kls $ +## +## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +## +## libdtv is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## libdtv is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You may have received a copy of the GNU General Public License +## along with libdtv; see the file COPYING. If not, write to the +## Free Software Foundation, Inc., 59 Temple Place - Suite 330, +## Boston, MA 02111-1307, USA. +# +# +# +CC = gcc +CFLAGS = -O2 -g -Wmissing-prototypes -Wstrict-prototypes \ + -Wimplicit -D__USE_FIXED_PROTOTYPES__ -I../include # -DDEBUG + + +AR = ar +ARFLAGS = r +RANLIB = ranlib +RM = rm -f +CP = cp + +VDRINCLUDE = libvdr.h +VDRLIB = libvdr.a +VDROBJS = libvdr.o + +all : $(VDRLIB) + +clean : + @echo "cleaning workspace..." + @$(RM) $(VDROBJS) $(VDRLIB) + +new : clean all + +$(VDRLIB) : $(VDROBJS) + @echo "updating library..." + @$(AR) $(ARFLAGS) $(VDRLIB) $(VDROBJS) + @$(RANLIB) $(VDRLIB) + +dist: all + @echo "distributing libvdr.a and libvdr.h..." + @$(CP) $(VDRLIB) ../lib + @$(CP) $(VDRINCLUDE) ../include + diff --git a/libdtv/libvdr/libvdr.c b/libdtv/libvdr/libvdr.c new file mode 100644 index 000000000..5caa5d7c4 --- /dev/null +++ b/libdtv/libvdr/libvdr.c @@ -0,0 +1,169 @@ +////////////////////////////////////////////////////////////// +/// /// +/// libvdr.c: routines to parse the DVB-SI stream /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/08/15 14:05:24 $ +// $Author: kls $ +// +// (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// libvdr is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// libvdr is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with libvdr; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#include <liblx.h> +#include <libsi.h> +#include <si_tables.h> +#include "libvdr.h" + + + +struct LIST *createVdrProgramInfos (unsigned char *siBuffer) +{ + struct VdrProgramInfo *VdrProgramInfo; + struct LIST *Result, *EventList; + struct Event *Event; + struct Descriptor *Descriptor; + + if (!siBuffer) return (NULL); + + if (!(EventList = siParseEIT (siBuffer))) return (NULL); + + Result = xNewList (NULL); + + xForeach (EventList, Event) + { + VdrProgramInfo = NULL; + + xForeach (Event->Descriptors, Descriptor) + { + switch (Descriptor->Tag) + { + case DESCR_SHORT_EVENT: + { + if (!xName(Descriptor) || !xName(Descriptor)[0]) + break; + + if (!VdrProgramInfo) + { + CreateVdrProgramInfo(VdrProgramInfo, + Event->EventID, Event->TransportStreamID, + Event->ServiceID, Event->StartTime, + Event->Duration, Event->Status); + + VdrProgramInfo->ShortName = + xSetText (xName (Descriptor)); + VdrProgramInfo->ShortText = + xSetText (((struct ShortEventDescriptor + *)Descriptor)->Text); + memcpy (VdrProgramInfo->LanguageCode, ((struct + ShortEventDescriptor *)Descriptor)-> + LanguageCode, 4); + } + } + break; + + case DESCR_TIME_SHIFTED_EVENT: + { + struct tm *StartTime; + + if (!VdrProgramInfo) + { + CreateVdrProgramInfo(VdrProgramInfo, + Event->EventID, Event->TransportStreamID, + Event->ServiceID, Event->StartTime, + Event->Duration, Event->Status); + + VdrProgramInfo->ReferenceServiceID = + ((struct TimeShiftedEventDescriptor + *)Descriptor)->ReferenceServiceID; + VdrProgramInfo->ReferenceEventID = + ((struct TimeShiftedEventDescriptor + *)Descriptor)->ReferenceEventID; + } + } + break; + + case DESCR_EXTENDED_EVENT: + { + struct ExtendedEventItem *Item; + + if (VdrProgramInfo) + { + if (xName (Descriptor)) + AddToText (xName (Descriptor), + VdrProgramInfo->ExtendedName); + xForeach (((struct ExtendedEventDescriptor*) + Descriptor)->Items, Item) + { + AddItemToText (xName (Item), + VdrProgramInfo->ExtendedText); + AddItemToText (Item->Text, + VdrProgramInfo->ExtendedText); + } + } + } + break; + + case DESCR_CONTENT: + { + int i, j; + + if (VdrProgramInfo) + { + for (j = 0; j < ((struct ContentDescriptor*) + Descriptor)->Amount; j++) + { + VdrProgramInfo->ContentNibble1 = + GetContentContentNibble1(Descriptor, j); + VdrProgramInfo->ContentNibble2 = + GetContentContentNibble2(Descriptor, j); + } + } + } + break; + + case DESCR_PARENTAL_RATING: + { + struct ParentalRating *Rating; + + if (VdrProgramInfo) + { + xForeach (((struct ParentalRatingDescriptor *) + Descriptor)->Ratings, Rating) + if (!strncmp (VdrProgramInfo->LanguageCode, + Rating->LanguageCode, 3)) + VdrProgramInfo->Rating = Rating->Rating; + } + } + break; + } + } + if (VdrProgramInfo) xAddTail (Result, VdrProgramInfo); + } + + return (Result); +} diff --git a/libdtv/libvdr/libvdr.h b/libdtv/libvdr/libvdr.h new file mode 100644 index 000000000..6fde10be3 --- /dev/null +++ b/libdtv/libvdr/libvdr.h @@ -0,0 +1,111 @@ +////////////////////////////////////////////////////////////// +/// /// +/// libvdr.h: definitions necessary for the libvdr package /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 1.1 $ +// $Date: 2001/08/15 10:54:13 $ +// $Author: kls $ +// +// (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. +// +// libvdr is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// libvdr is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with libvdr; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#ifndef LIBVDR_H +#define LIBVDR_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct LIST *createVdrProgramInfos (unsigned char *); + +#ifdef __cplusplus +} +#endif + +struct VdrProgramInfo { + struct NODE Node; + int EventID; + int TransportStreamID; + int ServiceID; + time_t StartTime; + time_t Duration; + unsigned short Status; + char LanguageCode[4]; + unsigned short Rating; + unsigned short ContentNibble1; + unsigned short ContentNibble2; + char *ShortName; + char *ShortText; + char *ExtendedName; + char *ExtendedText; + int ReferenceServiceID; + int ReferenceEventID; +}; + + +#define CreateVdrProgramInfo(cinf, evid, tpid, svid, stst, dura, sta) \ + do \ + { \ + xCreateNode (cinf, NULL); \ + cinf->EventID = evid; \ + cinf->TransportStreamID = tpid; \ + cinf->ServiceID = svid; \ + cinf->StartTime = stst; \ + cinf->Duration = dura; \ + cinf->Status = sta; \ + cinf->LanguageCode[0] = 0; \ + cinf->Rating = 0; \ + cinf->ContentNibble1 = 0; \ + cinf->ContentNibble2 = 0; \ + cinf->ShortName = NULL; \ + cinf->ShortText = NULL; \ + cinf->ExtendedName = NULL; \ + cinf->ExtendedText = NULL; \ + cinf->ReferenceServiceID = 0; \ + cinf->ReferenceEventID = 0; \ + } while (0) + +#define AddToText(src, dest) \ + do { \ + if (dest) \ + { \ + char *tmbuf; \ + xMemAlloc (strlen (src) + strlen (dest) + 4, &tmbuf); \ + sprintf (tmbuf, "%s%s", (dest), (src)); \ + xMemFree (dest); (dest) = tmbuf; \ + } else { \ + (dest) = xSetText (src); \ + } \ + } while (0) + + +#define AddItemToText(src, dest) \ + do { \ + if (dest) \ + { \ + char *tmbuf; \ + xMemAlloc (strlen (src) + strlen (dest) + 4, &tmbuf); \ + sprintf (tmbuf, "%s|%s", (dest), (src)); \ + xMemFree (dest); (dest) = tmbuf; \ + } else { \ + (dest) = xSetText (src); \ + } \ + } while (0) + +#endif diff --git a/menu.c b/menu.c index 0f89fab32..4cc43f099 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.103 2001/08/12 12:42:37 kls Exp $ + * $Id: menu.c 1.105 2001/08/19 14:45:31 kls Exp $ */ #include "menu.h" @@ -17,6 +17,7 @@ #include "i18n.h" #define MENUTIMEOUT 120 // seconds +#define MAXWAIT4EPGINFO 10 // seconds const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#^"; @@ -1701,6 +1702,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart)); Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop)); Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout)); + Add(new cMenuEditIntItem( tr("EPGBugfixLevel"), &data.EPGBugfixLevel, 0, 3)); Add(new cMenuEditIntItem( tr("SVDRPTimeout"), &data.SVDRPTimeout)); Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("DefaultPriority"), &data.DefaultPriority, 0, MAXPRIORITY)); @@ -2062,6 +2064,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) { + eventInfo = NULL; instantId = NULL; dvbApi = DvbApi; if (!dvbApi) dvbApi = cDvbApi::PrimaryDvbApi;//XXX @@ -2075,6 +2078,11 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer->SetPending(true); timer->SetRecording(true); if (Channels.SwitchTo(timer->channel, dvbApi)) { + if (GetEventInfo()) { + //XXX this is in preparation for storing recordings in subdirectories and giving them the name of the Subtitle + dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", eventInfo->GetTitle(), eventInfo->GetSubtitle());//XXX + //XXX modify timer's name and summary, mark it as modified (revert later when stopping) + } cRecording Recording(timer); if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority)) Recording.WriteSummary(); @@ -2090,6 +2098,34 @@ cRecordControl::~cRecordControl() delete instantId; } +bool cRecordControl::GetEventInfo(void) +{ + cChannel *channel = Channels.GetByNumber(timer->channel); + time_t Time = timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2; + for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) { + { + cThreadLock ThreadLock; + const cSchedules *Schedules = dvbApi->Schedules(&ThreadLock); + if (Schedules) { + const cSchedule *Schedule = Schedules->GetSchedule(channel->pnr); + if (Schedule) { + eventInfo = Schedule->GetEvent(Time); + if (eventInfo) { + if (seconds > 0) + dsyslog(LOG_INFO, "got EPG info after %d seconds", seconds); + return true; + } + } + } + } + if (seconds == 0) + dsyslog(LOG_INFO, "waiting for EPG info..."); + sleep(1); + } + dsyslog(LOG_INFO, "no EPG info available"); + return false; +} + void cRecordControl::Stop(bool KeepInstant) { if (timer) { diff --git a/menu.h b/menu.h index f75ca8670..d6db00285 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.23 2001/08/11 14:08:50 kls Exp $ + * $Id: menu.h 1.24 2001/08/18 10:22:43 kls Exp $ */ #ifndef _MENU_H @@ -72,7 +72,9 @@ class cRecordControl { private: cDvbApi *dvbApi; cTimer *timer; + const cEventInfo *eventInfo; char *instantId; + bool GetEventInfo(void); public: cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL); virtual ~cRecordControl(); diff --git a/remux.c b/remux.c index 3c7ec6e62..f89b897b6 100644 --- a/remux.c +++ b/remux.c @@ -8,7 +8,7 @@ * the Linux DVB driver's 'tuxplayer' example and were rewritten to suit * VDR's needs. * - * $Id: remux.c 1.5 2001/06/24 16:37:23 kls Exp $ + * $Id: remux.c 1.6 2001/08/19 11:52:05 kls Exp $ */ /* The calling interface of the 'cRemux::Process()' function is defined @@ -489,6 +489,8 @@ void cRemux::SetAudioPid(int APid) resultCount = resultDelivered = 0; } +#define TS_SYNC_BYTE 0x47 + const uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar *PictureType) { uchar dummyPictureType; @@ -511,12 +513,27 @@ XXX*/ resultDelivered = 0; } + int used = 0; + + // Make sure we are looking at a TS packet: + + while (Count > TS_SIZE) { + if (Data[0] == TS_SYNC_BYTE && Data[TS_SIZE] == TS_SYNC_BYTE) + break; + Data++; + Count--; + used++; + } + if (used) + esyslog(LOG_ERR, "ERROR: skipped %d byte to sync on TS packet", used); + // Convert incoming TS data into multiplexed PES: - int used = 0; for (int i = 0; i < Count; i += TS_SIZE) { if (Count - i < TS_SIZE) break; + if (Data[i] != TS_SYNC_BYTE) + break; int pid = GetPid(Data + i + 1); if (Data[i + 3] & 0x10) { // got payload if (pid == vPid) vTS2PES->ts_to_pes(Data + i); diff --git a/tools.c b/tools.c index e6aba17a5..30b675b2e 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.39 2001/08/12 15:12:54 kls Exp $ + * $Id: tools.c 1.40 2001/08/17 12:45:42 kls Exp $ */ #define _GNU_SOURCE @@ -103,6 +103,32 @@ char *stripspace(char *s) return s; } +char *compactspace(char *s) +{ + if (s && *s) { + char *t = stripspace(skipspace(s)); + char *p = t; + while (p && *p) { + char *q = skipspace(p); + if (q - p > 1) + memmove(p + 1, q, strlen(q) + 1); + p++; + } + if (t != s) + memmove(s, t, strlen(t) + 1); + } + return s; +} + +bool startswith(const char *s, const char *p) +{ + while (*p) { + if (*p++ != *s++) + return false; + } + return true; +} + bool isempty(const char *s) { return !(s && *skipspace(s)); diff --git a/tools.h b/tools.h index bf2e46b52..af7958fef 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.28 2001/08/12 15:13:02 kls Exp $ + * $Id: tools.h 1.29 2001/08/17 12:44:39 kls Exp $ */ #ifndef __TOOLS_H @@ -41,6 +41,8 @@ char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); char *skipspace(const char *s); char *stripspace(char *s); +char *compactspace(char *s); +bool startswith(const char *s, const char *p); bool isempty(const char *s); int time_ms(void); void delay_ms(int ms); From ae8fe25312b6b0ec18fd0c6c2a275f334ada02db Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 26 Aug 2001 18:00:00 +0200 Subject: [PATCH 023/307] Version 0.93 - The menus and the channel display now show the current date and time. - The new Setup parameter MaxVideoFileSize can be used to customize the maximum size of the recorded video files. - Fixed a bug in handling repeating timers that record over midnight (the calculation of matching timers has been completely rewritten). - Timers that are currently recording are now marked with '#' in the "Timers" menu. - Timers are now sorted in the "Timers" menu, showing the sequence in which they will be recording. This can be disabled in the "Setup" menu. Note that the "Mark" button doesn't work if timers are displayed sorted. --- HISTORY | 13 +++++ MANUAL | 25 +++++++- channels.conf | 2 + config.c | 157 +++++++++++++++++++++++++++++++------------------- config.h | 16 +++-- dvbapi.c | 22 +++---- dvbapi.h | 11 +++- i18n.c | 29 +++++++++- interface.c | 4 +- libdtv/x.txt | 55 ++++++++++++++++++ menu.c | 66 +++++++++++++-------- osd.c | 12 ++-- osd.h | 6 +- tools.c | 34 ++++++++++- tools.h | 5 +- vdr.c | 4 +- 16 files changed, 344 insertions(+), 117 deletions(-) create mode 100644 libdtv/x.txt diff --git a/HISTORY b/HISTORY index b76067bd0..250d85728 100644 --- a/HISTORY +++ b/HISTORY @@ -663,3 +663,16 @@ Video Disk Recorder Revision History - Fixed broken recordings after a driver buffer overflow. - Fixed the chirping sound after Pause/Play of a DVD (thanks to Andreas Schultz). + +2001-08-26: Version 0.93 + +- The menus and the channel display now show the current date and time. +- The new Setup parameter MaxVideoFileSize can be used to customize the + maximum size of the recorded video files. +- Fixed a bug in handling repeating timers that record over midnight (the + calculation of matching timers has been completely rewritten). +- Timers that are currently recording are now marked with '#' in the "Timers" + menu. +- Timers are now sorted in the "Timers" menu, showing the sequence in which + they will be recording. This can be disabled in the "Setup" menu. Note + that the "Mark" button doesn't work if timers are displayed sorted. diff --git a/MANUAL b/MANUAL index 9d7748120..ae93099fb 100644 --- a/MANUAL +++ b/MANUAL @@ -8,7 +8,7 @@ Video Disk Recorder User's Manual possible, several keys have different meanings in the various modes: - Key Normal Main Channels Timer Edit/New Recordings Replay + Key Normal Main Channels Timers Edit/New Recordings Replay Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause @@ -20,9 +20,12 @@ Video Disk Recorder User's Manual Red - Record Edit Edit - Play Jump Green - Language New New - Rewind Skip -60s Yellow - Eject DVD Delete Delete - Delete Skip +60s - Blue - Resume Mark Mark - Summary Stop + Blue - Resume Mark Mark(1) - Summary Stop 0..9 Ch select - - - Numeric inp. - Editing + (1) The "Mark" button in the "Timers" menu only works if sorting the timers + has been disabled in the "Setup" menu. + * Navigating through the On Screen Menus The "Main" menu can be called up with the "Menu" key of your remote @@ -34,7 +37,8 @@ Video Disk Recorder User's Manual any changes that might have been made in the current menu. In the "Timers" menu, the current timer can be enabled or disabled with - the "Right" or "Left" key, respectively (enabled timers are marked with ">"). + the "Right" or "Left" key, respectively (enabled timers are marked with '>', + timers that are currently recording are marked with '#'). "Ok" here opens the "Edit timer" menu. Textual options, like channel names or recording file names, can be edited @@ -296,6 +300,12 @@ Video Disk Recorder User's Manual OSDLanguage = 0 Defines the language used to display the OSD texts. 0 = Englisch 1 = Deutsch + 2 = Slovenian + 3 = Italian + 4 = Dutch + 5 = Portugese + 6 = French + 7 = Norwegian PrimaryDVB = 1 Defines the primary DVB interface (i.e. the one that will display the menus and will react on input through @@ -373,6 +383,10 @@ Video Disk Recorder User's Manual connection after which the connection is automatically closed. Default is 300, a value of 0 means no timeout. + SortTimers = 1 Turns sorting the timers in the "Timers" menu on/off. + Timers are sorted by ascending start times, with the + first one being the next timer that will start. + PrimaryLimit = 0 The minimum priority a timer must have to be allowed to use the primary DVB interface, or to force another timer with higher priority to use the primary DVB interface. @@ -398,6 +412,11 @@ Video Disk Recorder User's Manual OSDwidth = 52 The width and height of the OSD . OSDheight = 18 The valid ranges are width=40...56, height=12...21. + MaxVideoFileSize=2000 The maximum size of a single recorded video file in MB. + The valid range is 100...2000. Default is 2000, but + you may want to use smaller values if you are planning + on archiving a recording to CD. + * Executing system commands The "Main" menu option "Commands" allows you to execute any system commands diff --git a/channels.conf b/channels.conf index 1f62f70d9..9c904916e 100644 --- a/channels.conf +++ b/channels.conf @@ -192,4 +192,6 @@ Video Italia:12610:v:0:22000:121:122:0:0:12220 AC 3 promo:12670:v:0:22000:308:256:0:0:0 ORF/ZDF:12699:h:0:22000:506:507:0:0:13012 VIVA:12670:v:0:22000:309:310:0:0:12732 +VIVA2:12552:v:0:22000:171:172:0:0:12120 MTV Central Europe:12699:v:0:22000:3031:3032:0:0:28643 +IFA-TV:10832:h:0:22000:132:133:32:0:7251 diff --git a/config.c b/config.c index aed32549d..ad4b9dad4 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.55 2001/08/17 13:02:01 kls Exp $ + * $Id: config.c 1.59 2001/08/26 14:46:43 kls Exp $ */ #include "config.h" @@ -394,6 +394,13 @@ cTimer& cTimer::operator= (const cTimer &Timer) return *this; } +bool cTimer::operator< (const cTimer &Timer) +{ + time_t t1 = StartTime(); + time_t t2 = (*(cTimer *)&Timer).StartTime(); + return t1 < t2 || (t1 == t2 && priority > Timer.priority); +} + const char *cTimer::ToText(cTimer *Timer) { delete buffer; @@ -415,13 +422,6 @@ int cTimer::TimeToInt(int t) return (t / 100 * 60 + t % 100) * 60; } -time_t cTimer::Day(time_t t) -{ - struct tm d = *localtime(&t); - d.tm_hour = d.tm_min = d.tm_sec = 0; - return mktime(&d); -} - int cTimer::ParseDay(const char *s) { char *tail; @@ -511,43 +511,66 @@ bool cTimer::IsSingleEvent(void) return (day & 0x80000000) == 0; } +int cTimer::GetMDay(time_t t) +{ + return localtime(&t)->tm_mday; +} + +int cTimer::GetWDay(time_t t) +{ + int weekday = localtime(&t)->tm_wday; + return weekday == 0 ? 6 : weekday - 1; // we start with monday==0! +} + +bool cTimer::DayMatches(time_t t) +{ + return IsSingleEvent() ? GetMDay(t) == day : (day & (1 << GetWDay(t))) != 0; +} + +time_t cTimer::IncDay(time_t t, int Days) +{ + tm tm = *localtime(&t); + tm.tm_mday += Days; // now tm_mday may be out of its valid range + int h = tm.tm_hour; // save original hour to compensate for DST change + t = mktime(&tm); // normalize all values + tm.tm_hour = h; // compensate for DST change + return mktime(&tm); // calculate final result +} + +time_t cTimer::SetTime(time_t t, int SecondsFromMidnight) +{ + tm tm = *localtime(&t); + tm.tm_hour = SecondsFromMidnight / 3600; + tm.tm_min = (SecondsFromMidnight % 3600) / 60; + tm.tm_sec = SecondsFromMidnight % 60; + return mktime(&tm); +} + bool cTimer::Matches(time_t t) { - if (active) { - if (t == 0) - t = time(NULL); - struct tm now = *localtime(&t); - int weekday = now.tm_wday == 0 ? 6 : now.tm_wday - 1; // we start with monday==0! - int begin = TimeToInt(start); - int end = TimeToInt(stop); - bool twoDays = (end < begin); - - bool todayMatches = false, yesterdayMatches = false; - if ((day & 0x80000000) != 0) { - if ((day & (1 << weekday)) != 0) - todayMatches = true; - else if (twoDays) { - int yesterday = weekday == 0 ? 6 : weekday - 1; - if ((day & (1 << yesterday)) != 0) - yesterdayMatches = true; - } - } - else if (day == now.tm_mday) - todayMatches = true; - else if (twoDays) { - time_t ty = t - SECSINDAY; - if (day == localtime(&ty)->tm_mday) - yesterdayMatches = true; - } - if (todayMatches || (twoDays && yesterdayMatches)) { - startTime = Day(t - (yesterdayMatches ? SECSINDAY : 0)) + begin; - stopTime = startTime + (twoDays ? SECSINDAY - begin + end : end - begin); - } - else - startTime = stopTime = 0; - return startTime <= t && t <= stopTime; - } - return false; + startTime = stopTime = 0; + if (t == 0) + t = time(NULL); + + int begin = TimeToInt(start); // seconds from midnight + int length = TimeToInt(stop) - begin; + if (length < 0) + length += SECSINDAY; + + int DaysToCheck = IsSingleEvent() ? 31 : 7; + for (int i = -1; i <= DaysToCheck; i++) { + time_t t0 = IncDay(t, i); + if (DayMatches(t0)) { + time_t a = SetTime(t0, begin); + time_t b = a + length; + if (t <= b) { + startTime = a; + stopTime = b; + break; + } + } + } + return active && startTime <= t && t <= stopTime; } time_t cTimer::StartTime(void) @@ -575,21 +598,6 @@ void cTimer::SetPending(bool Pending) pending = Pending; } -cTimer *cTimer::GetMatch(void) -{ - time_t t = time(NULL); // all timers must be checked against the exact same time to correctly handle Priority! - cTimer *t0 = NULL; - cTimer *ti = (cTimer *)Timers.First(); - while (ti) { - if (!ti->recording && ti->Matches(t)) { - if (!t0 || ti->priority > t0->priority) - t0 = ti; - } - ti = (cTimer *)ti->Next(); - } - return t0; -} - // --- cCommand ------------------------------------------------------------- char *cCommand::result = NULL; @@ -753,6 +761,33 @@ cTimer *cTimers::GetTimer(cTimer *Timer) return NULL; } +cTimer *cTimers::GetMatch(void) +{ + time_t t = time(NULL); // all timers must be checked against the exact same time to correctly handle Priority! + cTimer *t0 = NULL; + cTimer *ti = First(); + while (ti) { + if (!ti->recording && ti->Matches(t)) { + if (!t0 || ti->priority > t0->priority) + t0 = ti; + } + ti = (cTimer *)ti->Next(); + } + return t0; +} + +cTimer *cTimers::GetNextActiveTimer(void) +{ + cTimer *t0 = NULL; + cTimer *ti = First(); + while (ti) { + if (ti->active && (!t0 || *ti < *t0)) + t0 = ti; + ti = (cTimer *)ti->Next(); + } + return t0; +} + // -- cSetup ----------------------------------------------------------------- cSetup Setup; @@ -776,6 +811,7 @@ cSetup::cSetup(void) EPGScanTimeout = 5; EPGBugfixLevel = 2; SVDRPTimeout = 300; + SortTimers = 1; PrimaryLimit = 0; DefaultPriority = 50; DefaultLifetime = 50; @@ -783,6 +819,7 @@ cSetup::cSetup(void) ChannelInfoPos = 0; OSDwidth = 52; OSDheight = 18; + MaxVideoFileSize = MAXVIDEOFILESIZE; CurrentChannel = -1; } @@ -807,6 +844,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); + else if (!strcasecmp(Name, "SortTimers")) SortTimers = atoi(Value); else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); @@ -814,6 +852,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); + else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else return false; @@ -873,6 +912,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout); fprintf(f, "EPGBugfixLevel = %d\n", EPGBugfixLevel); fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout); + fprintf(f, "SortTimers = %d\n", SortTimers); fprintf(f, "PrimaryLimit = %d\n", PrimaryLimit); fprintf(f, "DefaultPriority = %d\n", DefaultPriority); fprintf(f, "DefaultLifetime = %d\n", DefaultLifetime); @@ -880,6 +920,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "ChannelInfoPos = %d\n", ChannelInfoPos); fprintf(f, "OSDwidth = %d\n", OSDwidth); fprintf(f, "OSDheight = %d\n", OSDheight); + fprintf(f, "MaxVideoFileSize = %d\n", MaxVideoFileSize); fprintf(f, "CurrentChannel = %d\n", CurrentChannel); f.Close(); isyslog(LOG_INFO, "saved setup to %s", FileName); diff --git a/config.h b/config.h index ce77598b0..70f35740b 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.61 2001/08/17 13:00:48 kls Exp $ + * $Id: config.h 1.66 2001/08/26 14:46:53 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.92" +#define VDRVERSION "0.93" #define MaxBuffer 10000 @@ -137,18 +137,22 @@ class cTimer : public cListObject { cTimer(const cEventInfo *EventInfo); virtual ~cTimer(); cTimer& operator= (const cTimer &Timer); + bool operator< (const cTimer &Timer); const char *ToText(void); bool Parse(const char *s); bool Save(FILE *f); bool IsSingleEvent(void); + int GetMDay(time_t t); + int GetWDay(time_t t); + bool DayMatches(time_t t); + time_t IncDay(time_t t, int Days); + time_t SetTime(time_t t, int SecondsFromMidnight); bool Matches(time_t t = 0); time_t StartTime(void); time_t StopTime(void); void SetRecording(bool Recording); void SetPending(bool Pending); - static cTimer *GetMatch(void); static int TimeToInt(int t); - static time_t Day(time_t t); static int ParseDay(const char *s); static const char *PrintDay(int d); }; @@ -251,6 +255,8 @@ class cChannels : public cConfig<cChannel> { class cTimers : public cConfig<cTimer> { public: cTimer *GetTimer(cTimer *Timer); + cTimer *GetMatch(void); + cTimer *GetNextActiveTimer(void); }; class cCommands : public cConfig<cCommand> {}; @@ -282,11 +288,13 @@ class cSetup { int EPGScanTimeout; int EPGBugfixLevel; int SVDRPTimeout; + int SortTimers; int PrimaryLimit; int DefaultPriority, DefaultLifetime; int VideoFormat; int ChannelInfoPos; int OSDwidth, OSDheight; + int MaxVideoFileSize; int CurrentChannel; cSetup(void); bool Load(const char *FileName); diff --git a/dvbapi.c b/dvbapi.c index 6ff39b3df..51434e12a 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.109 2001/08/19 15:09:48 kls Exp $ + * $Id: dvbapi.c 1.110 2001/08/25 13:52:38 kls Exp $ */ //#define DVDDEBUG 1 @@ -50,20 +50,16 @@ extern "C" { #define DEV_OST_VIDEO "/dev/ost/video" #define DEV_OST_AUDIO "/dev/ost/audio" +#define KILOBYTE(n) ((n) * 1024) +#define MEGABYTE(n) ((n) * 1024 * 1024) + // The size of the array used to buffer video data: // (must be larger than MINVIDEODATA - see remux.h) -#define VIDEOBUFSIZE (1024*1024) +#define VIDEOBUFSIZE MEGABYTE(1) // The maximum size of a single frame: -#define MAXFRAMESIZE (192*1024) - -// The maximum file size is limited by the range that can be covered -// with 'int'. 4GB might be possible (if the range is considered -// 'unsigned'), 2GB should be possible (even if the range is considered -// 'signed'), so let's use 1GB for absolute safety (the actual file size -// may be slightly higher because we stop recording only before the next -// 'I' frame, to have a complete Group Of Pictures): -#define MAXVIDEOFILESIZE (1024*1024*1024) // Byte +#define MAXFRAMESIZE KILOBYTE(192) + #define MAXFILESPERRECORDING 255 #define MINFREEDISKSPACE (512) // MB @@ -517,7 +513,7 @@ bool cRecordBuffer::RunningLowOnDiskSpace(void) bool cRecordBuffer::NextFile(void) { if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME - if (fileSize > MAXVIDEOFILESIZE || RunningLowOnDiskSpace()) { + if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) { recordFile = fileName.NextFile(); fileSize = 0; } @@ -2217,7 +2213,7 @@ void cCuttingBuffer::Action(void) // Write one frame: if (PictureType == I_FRAME) { // every file shall start with an I_FRAME - if (FileSize > MAXVIDEOFILESIZE) { + if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) { toFile = toFileName->NextFile(); if (toFile < 0) break; diff --git a/dvbapi.h b/dvbapi.h index 2cd57bfa1..c93a9f35d 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.46 2001/08/11 12:22:01 kls Exp $ + * $Id: dvbapi.h 1.47 2001/08/25 13:37:00 kls Exp $ */ #ifndef __DVBAPI_H @@ -42,6 +42,15 @@ typedef struct CRect { #define FRAMESPERSEC 25 +// The maximum file size is limited by the range that can be covered +// with 'int'. 4GB might be possible (if the range is considered +// 'unsigned'), 2GB should be possible (even if the range is considered +// 'signed'), so let's use 2000MB for absolute safety (the actual file size +// may be slightly higher because we stop recording only before the next +// 'I' frame, to have a complete Group Of Pictures): +#define MAXVIDEOFILESIZE 2000 // MB +#define MINVIDEOFILESIZE 100 // MB + const char *IndexToHMSF(int Index, bool WithFrame = false); // Converts the given index to a string, optionally containing the frame number. int HMSFToIndex(const char *HMSF); diff --git a/i18n.c b/i18n.c index 987822862..35a6bb1e9 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.32 2001/08/17 13:03:15 kls Exp $ + * $Id: i18n.c 1.35 2001/08/26 13:45:10 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -794,6 +794,15 @@ const tPhrase Phrases[] = { "Temps maxi SVDRP", "Ubrukt SVDRP-levetid", }, + { "SortTimers", + "Timer sortieren", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "PrimaryLimit", "Primr-Limit", "", // TODO @@ -857,6 +866,15 @@ const tPhrase Phrases[] = { "Hauteur affichage", "", // TODO }, + { "MaxVideoFileSize", + "Max. Video Dateigre", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // The days of the week: { "MTWTFSS", "MDMDFSS", @@ -867,6 +885,15 @@ const tPhrase Phrases[] = { "LMMJVSD", "MTOTFLS", }, + { "MonTueWedThuFriSatSun", // must all be 3 letters! + "MonDieMitDonFreSamSon", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // Learning keys: { "Learning Remote Control Keys", "Fernbedienungs-Codes lernen", diff --git a/interface.c b/interface.c index e2d83b359..1e06f4af2 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.40 2001/08/07 16:23:28 kls Exp $ + * $Id: interface.c 1.41 2001/08/25 13:15:00 kls Exp $ */ #include "interface.h" @@ -271,7 +271,7 @@ void cInterface::Title(const char *s) unsigned int n = t - s; if (n >= sizeof(buffer)) n = sizeof(buffer) - 1; - strn0cpy(buffer, s, n); + strn0cpy(buffer, s, n + 1); Write(1, 0, buffer, clrBlack, clrCyan); t++; Write(-(cDvbApi::PrimaryDvbApi->WidthInCells(t) + 1), 0, t, clrBlack, clrCyan); diff --git a/libdtv/x.txt b/libdtv/x.txt new file mode 100644 index 000000000..0d12dddb8 --- /dev/null +++ b/libdtv/x.txt @@ -0,0 +1,55 @@ +Hallo ZDF-EPG-Redaktion! + +Es wrde mich interessieren, warum im digitalen EPG des +ZDF (ber Astra) die Beschreibung der Sendungen oftmals +Trennungsstriche und zustzliche Leerzeichen enthlt. +So zum Beispiel bei folgendem Eintrag: + +---------------------------------------------------- + ZDF 23.08 10:50 - 11:35 + + Mit Leib und Seele + + Der einzige Mensch + + Stehlin hat die Frhmesse abge- sagt und sein + Kommen im Pfarr- haus angekndigt. August, erbost + ber die Heimlichkeiten und Re- dereien von + Stutz, erzwingt eine Aussprache mit Stehlin. +---------------------------------------------------- + +der ohne Trennungsstriche so aussehen knnte: + +---------------------------------------------------- + ZDF 23.08 10:50 - 11:35 + + Mit Leib und Seele + + Der einzige Mensch + + Stehlin hat die Frhmesse abgesagt und sein + Kommen im Pfarrhaus angekndigt. August, erbost + ber die Heimlichkeiten und Redereien von Stutz, + erzwingt eine Aussprache mit Stehlin. +---------------------------------------------------- + +Ich kann mir das nur so erklren, da Sie konkrete Annahmen +darber machen, mit welcher Zeilenlnge die Set-Top-Box diese +Texte darstellt - aber das ist in meinen Augen eine ziemlich +verwegene Annahme, denn es sollte ja wohl der STB berlassen bleiben, +wie gro das Fenster fr die Darstellung des EPG ist. + +Pro-7 zum Beispiel macht sowas nicht, wodurch der Text deultich +besser dargestellt wird. + +Wenn Sie wenigstens nach dem (bzw. statt des) Bindestrich(s) ein deutlich +erkennbares Sonderzeichen einfgen wrden, dann knnte man das zuverlssig +herausfiltern, aber so macht der ZDF-EPG immer wieder einen +schlechten Eindruck. + +ber eine Antwort von Ihnen wrde ich mich sehr freuen. + +MfG +Klaus Schmidinger + + diff --git a/menu.c b/menu.c index 4cc43f099..6d6eae8e2 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.105 2001/08/19 14:45:31 kls Exp $ + * $Id: menu.c 1.109 2001/08/26 14:03:27 kls Exp $ */ #include "menu.h" @@ -957,25 +957,30 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key) class cMenuTimerItem : public cOsdItem { private: - int index; cTimer *timer; public: - cMenuTimerItem(int Index, cTimer *Timer); + cMenuTimerItem(cTimer *Timer); + virtual bool operator< (const cListObject &ListObject); virtual void Set(void); + cTimer *Timer(void) { return timer; } }; -cMenuTimerItem::cMenuTimerItem(int Index, cTimer *Timer) +cMenuTimerItem::cMenuTimerItem(cTimer *Timer) { - index = Index; timer = Timer; Set(); } +bool cMenuTimerItem::operator< (const cListObject &ListObject) +{ + return *timer < *((cMenuTimerItem *)&ListObject)->timer; +} + void cMenuTimerItem::Set(void) { char *buffer = NULL; asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s", - timer->active ? '>' : ' ', + timer->active ? timer->recording ? '#' : '>' : ' ', timer->channel, timer->PrintDay(timer->day), timer->start / 100, @@ -996,6 +1001,7 @@ class cMenuTimers : public cOsdMenu { eOSState Del(void); virtual void Move(int From, int To); eOSState Summary(void); + cTimer *CurrentTimer(void); public: cMenuTimers(void); virtual eOSState ProcessKey(eKeys Key); @@ -1008,15 +1014,23 @@ cMenuTimers::cMenuTimers(void) cTimer *timer; while ((timer = Timers.Get(i)) != NULL) { - Add(new cMenuTimerItem(i, timer)); + Add(new cMenuTimerItem(timer)); i++; } - SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark")); + if (Setup.SortTimers) + Sort(); + SetHelp(tr("Edit"), tr("New"), tr("Delete"), Setup.SortTimers ? NULL : tr("Mark")); +} + +cTimer *cMenuTimers::CurrentTimer(void) +{ + cMenuTimerItem *item = (cMenuTimerItem *)Get(Current()); + return item ? item->Timer() : NULL; } eOSState cMenuTimers::Activate(bool On) { - cTimer *timer = Timers.Get(Current()); + cTimer *timer = CurrentTimer(); if (timer && timer->active != On) { timer->active = On; RefreshCurrent(); @@ -1031,8 +1045,8 @@ eOSState cMenuTimers::Edit(void) { if (HasSubMenu() || Count() == 0) return osContinue; - isyslog(LOG_INFO, "editing timer %d", Current() + 1); - return AddSubMenu(new cMenuEditTimer(Current())); + isyslog(LOG_INFO, "editing timer %d", CurrentTimer()->Index() + 1); + return AddSubMenu(new cMenuEditTimer(CurrentTimer()->Index())); } eOSState cMenuTimers::New(void) @@ -1041,22 +1055,22 @@ eOSState cMenuTimers::New(void) return osContinue; cTimer *timer = new cTimer; Timers.Add(timer); - Add(new cMenuTimerItem(timer->Index()/*XXX*/, timer), true); + Add(new cMenuTimerItem(timer), true); Timers.Save(); isyslog(LOG_INFO, "timer %d added", timer->Index() + 1); - return AddSubMenu(new cMenuEditTimer(Current(), true)); + return AddSubMenu(new cMenuEditTimer(timer->Index(), true)); } eOSState cMenuTimers::Del(void) { // Check if this timer is active: - int Index = Current(); - cTimer *ti = Timers.Get(Index); + cTimer *ti = CurrentTimer(); if (ti) { if (!ti->recording) { if (Interface->Confirm(tr("Delete timer?"))) { - Timers.Del(Timers.Get(Index)); - cOsdMenu::Del(Index); + int Index = ti->Index(); + Timers.Del(ti); + cOsdMenu::Del(Current()); Timers.Save(); Display(); isyslog(LOG_INFO, "timer %d deleted", Index + 1); @@ -1081,7 +1095,7 @@ eOSState cMenuTimers::Summary(void) { if (HasSubMenu() || Count() == 0) return osContinue; - cTimer *ti = Timers.Get(Current()); + cTimer *ti = CurrentTimer(); if (ti && ti->summary && *ti->summary) return AddSubMenu(new cMenuText(tr("Summary"), ti->summary)); return Edit(); // convenience for people not using the Summary feature ;-) @@ -1109,7 +1123,9 @@ eOSState cMenuTimers::ProcessKey(eKeys Key) case kRed: return Edit(); case kGreen: return New(); case kYellow: return Del(); - case kBlue: Mark(); break; + case kBlue: if (!Setup.SortTimers) + Mark(); + break; default: break; } } @@ -1137,6 +1153,7 @@ cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch) char *buffer; asprintf(&buffer, "%-17.*s\t%.*s %s - %s", 17, channel->name, 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString()); SetTitle(buffer, false); + delete buffer; int Line = 2; cMenuTextItem *item; const char *Title = eventInfo->GetTitle(); @@ -1377,7 +1394,8 @@ void cMenuSchedule::PrepareSchedule(cChannel *Channel) Clear(); char *buffer = NULL; asprintf(&buffer, tr("Schedule - %s"), Channel->name); - SetTitle(buffer, false); + SetTitle(buffer); + delete buffer; if (schedules) { const cSchedule *Schedule = Channel->pnr ? schedules->GetSchedule(Channel->pnr) : schedules->GetSchedule(); int num = Schedule->NumEvents(); @@ -1704,6 +1722,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout)); Add(new cMenuEditIntItem( tr("EPGBugfixLevel"), &data.EPGBugfixLevel, 0, 3)); Add(new cMenuEditIntItem( tr("SVDRPTimeout"), &data.SVDRPTimeout)); + Add(new cMenuEditBoolItem(tr("SortTimers"), &data.SortTimers)); Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("DefaultPriority"), &data.DefaultPriority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("DefaultLifetime"), &data.DefaultLifetime, 0, MAXLIFETIME)); @@ -1711,6 +1730,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditBoolItem(tr("ChannelInfoPos"), &data.ChannelInfoPos, tr("bottom"), tr("top"))); Add(new cMenuEditIntItem( tr("OSDwidth"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); Add(new cMenuEditIntItem( tr("OSDheight"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); + Add(new cMenuEditIntItem( tr("MaxVideoFileSize"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); } eOSState cMenuSetup::ProcessKey(eKeys Key) @@ -1951,10 +1971,8 @@ void cDisplayChannel::DisplayChannel(const cChannel *Channel) snprintf(buffer, BufSize, "%s", Channel ? Channel->name : tr("*** Invalid Channel ***")); Interface->Fill(0, 0, Setup.OSDwidth, 1, clrBackground); Interface->Write(0, 0, buffer); - time_t t = time(NULL); - struct tm *now = localtime(&t); - snprintf(buffer, BufSize, "%02d:%02d", now->tm_hour, now->tm_min); - Interface->Write(-5, 0, buffer); + const char *date = DayDateTime(); + Interface->Write(-strlen(date), 0, date); } void cDisplayChannel::DisplayInfo(void) diff --git a/osd.c b/osd.c index daedc1ee4..02f437481 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.17 2001/08/02 14:18:17 kls Exp $ + * $Id: osd.c 1.18 2001/08/25 13:15:16 kls Exp $ */ #include "osd.h" @@ -78,7 +78,8 @@ cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4) { hasHotkeys = false; visible = false; - title = strdup(Title); + title = NULL; + SetTitle(Title); cols[0] = c0; cols[1] = c1; cols[2] = c2; @@ -109,10 +110,13 @@ void cOsdMenu::SetStatus(const char *s) Interface->Status(status); } -void cOsdMenu::SetTitle(const char *Title, bool Copy) +void cOsdMenu::SetTitle(const char *Title, bool ShowDate) { delete title; - title = Copy ? strdup(Title) : Title; + if (ShowDate) + asprintf(&title, "%s\t%s", Title, DayDateTime(time(NULL))); + else + title = strdup(Title); } void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue) diff --git a/osd.h b/osd.h index ec1b11571..2d243f166 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.23 2001/08/02 13:48:34 kls Exp $ + * $Id: osd.h 1.24 2001/08/25 12:56:46 kls Exp $ */ #ifndef __OSD_H @@ -72,7 +72,7 @@ class cOsdBase { class cOsdMenu : public cOsdBase, public cList<cOsdItem> { private: - const char *title; + char *title; int cols[cInterface::MaxCols]; int first, current, marked; cOsdMenu *subMenu; @@ -94,7 +94,7 @@ class cOsdMenu : public cOsdBase, public cList<cOsdItem> { eOSState AddSubMenu(cOsdMenu *SubMenu); bool HasSubMenu(void) { return subMenu; } void SetStatus(const char *s); - void SetTitle(const char *Title, bool Copy = true); + void SetTitle(const char *Title, bool ShowDate = true); void SetHelp(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); virtual void Del(int Index); public: diff --git a/tools.c b/tools.c index 30b675b2e..f51bc85d4 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.40 2001/08/17 12:45:42 kls Exp $ + * $Id: tools.c 1.43 2001/08/26 15:45:41 kls Exp $ */ #define _GNU_SOURCE @@ -17,7 +17,9 @@ #endif #include <stdlib.h> #include <sys/time.h> +#include <time.h> #include <unistd.h> +#include "i18n.h" #define MaxBuffer 1000 @@ -395,6 +397,20 @@ bool SpinUpDisk(const char *FileName) return false; } +const char *DayDateTime(time_t t) +{ + static char buffer[32]; + if (t == 0) + time(&t); + tm *tm = localtime(&t); + int weekday = tm->tm_wday == 0 ? 6 : tm->tm_wday - 1; // we start with monday==0! + const char *day = tr("MonTueWedThuFriSatSun"); + day += weekday * 3; + strncpy(buffer, day, 3); + snprintf(buffer + 3, sizeof(buffer) - 3, " %2d.%02d %02d:%02d", tm->tm_mday, tm->tm_mon + 1, tm->tm_hour, tm->tm_min); + return buffer; +} + // --- cFile ----------------------------------------------------------------- bool cFile::files[FD_SETSIZE] = { false }; @@ -677,3 +693,19 @@ int cListBase::Count(void) const return n; } +void cListBase::Sort(void) +{ + bool swapped; + do { + swapped = false; + cListObject *object = objects; + while (object) { + if (object->Next() && *object->Next() < *object) { + Move(object->Next(), object); + swapped = true; + } + object = object->Next(); + } + } while (swapped); +} + diff --git a/tools.h b/tools.h index af7958fef..2f89f3f0e 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.29 2001/08/17 12:44:39 kls Exp $ + * $Id: tools.h 1.31 2001/08/26 12:52:49 kls Exp $ */ #ifndef __TOOLS_H @@ -55,6 +55,7 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false); char *ReadLink(const char *FileName); bool SpinUpDisk(const char *FileName); +const char *DayDateTime(time_t t = 0); class cFile { private: @@ -94,6 +95,7 @@ class cListObject { public: cListObject(void); virtual ~cListObject(); + virtual bool operator< (const cListObject &ListObject) { return false; } void Append(cListObject *Object); void Unlink(void); int Index(void); @@ -114,6 +116,7 @@ class cListBase { virtual void Clear(void); cListObject *Get(int Index) const; int Count(void) const; + void Sort(void); }; template<class T> class cList : public cListBase { diff --git a/vdr.c b/vdr.c index af305419a..3f8f8da83 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.63 2001/08/11 15:33:30 kls Exp $ + * $Id: vdr.c 1.64 2001/08/26 15:02:00 kls Exp $ */ #include <getopt.h> @@ -323,7 +323,7 @@ int main(int argc, char *argv[]) } // Timers and Recordings: if (!Menu) { - cTimer *Timer = cTimer::GetMatch(); + cTimer *Timer = Timers.GetMatch(); if (Timer) { if (!cRecordControls::Start(Timer)) Timer->SetPending(true); From bb18b9e0b449afff418f010c1b2e255acd3fbad3 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 2 Sep 2001 18:00:00 +0200 Subject: [PATCH 024/307] Version 0.94 - Implemented automatic shutdown (see INSTALL and MANUAL for details). - New SVDRP command NEXT to show the next timer event. - The new remote control key "Power" can be used to turn the VDR machine off (this requires the presence of the '-s' option). - Fixed code for the default "Ok" button on the PC keyboard (was 0x162 on the "good old" keyboards (with the F-keys at the left side), while it changed to 0x15E on the newer keyboards). - When a recording is edited, the summary information (if present) is now also copied. - When a recording is running on the primary interface, any attempt to change the current channel will now lead to a "Channel locked" message. - The main program loop now first checks whether any timer recordings are finished, before starting a new timer recording. This is important in case one timer ends at the same time another timer starts. - New setup parameter OSDMessageTime to define how long an OSD message shall be displayed. - The "File" parameter of a timer can now contain the '~' character to store the recording in a hierarchical directory structure. The '~' character has been chosen since the file system's directory delimiter '/' may be part of a regular programme name (showing the directory hierarchy in the "Recordings" menu will follow later). - Repeating timers now create recordings that contain the 'Subtitle' information from the EPG data in their file name. Typically (on tv stations that care about their viewers) this contains the episode title of a series. The subtitle is appended to the timer's file name, separated by a '~' character, so that it results in all recordings of this timer being collected in a common subdirectory. You can disable this with the 'UseSubtitle' parameter in the "Setup" menu. - The summary information is now taken from the EPG data at the actual time of recording (no longer at the time the timer is created in the "Schedule" menu). If a timer already has summary data, that data will be used. If you have repeating timers in your 'timers.conf', you may want to make sure they do NOT contain any summary information (that's the last field in the timer definitions). Use your favourite text editor to delete that information. That way every recording will store the actual summary data at the time of the recording. --- FORMATS | 4 +- HISTORY | 39 ++++++++++++++++ INSTALL | 52 +++++++++++++++++++++ MANUAL | 34 ++++++++++++++ Makefile | 29 ++++-------- config.c | 35 +++++++-------- config.h | 10 +++-- dvbapi.c | 6 ++- i18n.c | 74 +++++++++++++++++++++++++++++- interface.c | 15 ++++--- interface.h | 8 ++-- keys-pc.conf | Bin 283 -> 300 bytes libdtv/x.txt | 55 ----------------------- menu.c | 38 +++++++--------- menu.h | 6 +-- recording.c | 49 ++++++++++++++++---- recording.h | 5 ++- svdrp.c | 35 ++++++++++++++- svdrp.h | 3 +- vdr.c | 124 +++++++++++++++++++++++++++++++++++++-------------- videodir.c | 22 ++++++--- 21 files changed, 456 insertions(+), 187 deletions(-) delete mode 100644 libdtv/x.txt diff --git a/FORMATS b/FORMATS index 03739ee50..3c5d36d43 100644 --- a/FORMATS +++ b/FORMATS @@ -67,7 +67,9 @@ Video Disk Recorder File Formats be automatically deleted by a new recording with higher priority, 99 means that this recording will never be automatically deleted - Name of timer (will be used to name the recording); if the name contains - any ':' characters, these have to be replaced with '|' + any ':' characters, these have to be replaced with '|'. If the name shall + contain subdirectories, these have to be delimited by '~' (since the '/' + character may be part of a regular programme name). - Summary (any newline characters in the summary have to be replaced with '|'; the summary may contain ':' characters) diff --git a/HISTORY b/HISTORY index 250d85728..d2be05446 100644 --- a/HISTORY +++ b/HISTORY @@ -676,3 +676,42 @@ Video Disk Recorder Revision History - Timers are now sorted in the "Timers" menu, showing the sequence in which they will be recording. This can be disabled in the "Setup" menu. Note that the "Mark" button doesn't work if timers are displayed sorted. + +2001-09-02: Version 0.94 + +- Implemented automatic shutdown (see INSTALL and MANUAL for details). +- New SVDRP command NEXT to show the next timer event. +- The new remote control key "Power" can be used to turn the VDR machine + off (this requires the presence of the '-s' option). +- Fixed code for the default "Ok" button on the PC keyboard (was 0x162 on + the "good old" keyboards (with the F-keys at the left side), while it changed + to 0x15E on the newer keyboards). +- When a recording is edited, the summary information (if present) is now + also copied. +- When a recording is running on the primary interface, any attempt to change + the current channel will now lead to a "Channel locked" message. +- The main program loop now first checks whether any timer recordings are + finished, before starting a new timer recording. This is important in case + one timer ends at the same time another timer starts. +- New setup parameter OSDMessageTime to define how long an OSD message shall + be displayed. +- The "File" parameter of a timer can now contain the '~' character to store + the recording in a hierarchical directory structure. The '~' character has + been chosen since the file system's directory delimiter '/' may be part of + a regular programme name (showing the directory hierarchy in the "Recordings" + menu will follow later). +- Repeating timers now create recordings that contain the 'Subtitle' information + from the EPG data in their file name. Typically (on tv stations that care + about their viewers) this contains the episode title of a series. The + subtitle is appended to the timer's file name, separated by a '~' character, + so that it results in all recordings of this timer being collected in a + common subdirectory. You can disable this with the 'UseSubtitle' parameter + in the "Setup" menu. +- The summary information is now taken from the EPG data at the actual time of + recording (no longer at the time the timer is created in the "Schedule" menu). + If a timer already has summary data, that data will be used. If you have + repeating timers in your 'timers.conf', you may want to make sure they do + NOT contain any summary information (that's the last field in the timer + definitions). Use your favourite text editor to delete that information. + That way every recording will store the actual summary data at the time of + the recording. diff --git a/INSTALL b/INSTALL index 946e06de9..e15f13ee9 100644 --- a/INSTALL +++ b/INSTALL @@ -98,6 +98,57 @@ call to the VDR program, be sure to NOT use the '-d' option! Otherwise VDR will go into 'deamon' mode and the initial program call will return immediately! +Automatic shutdown: +------------------- + +If you define a shutdown command via the '-s' command line option, VDR +will call the given command if there is currently no recording or replay +active, the user has been inactive for at least MinUserInactivity minutes +and the next timer event is at least MinEventTimeout minutes in the future +(see the Setup parameters in MANUAL). + +The command given in the '-s' option will be called with two parameters. +The first one is the time (in UTC) of the next timer event (as a time_t +type number), and the second one is the number of seconds from the current +time until the next timer event. Your program can choose which one to use +for programming some sort of hardware device that makes sure the computer +will be restarted in time before the next timer event. Your program must +also initiate the actual shutdown procedure of the computer. After this +your program should return to VDR. VDR will not automatically exit after +calling the shutdown program, but will rather continue normally untit it +receives a SIGTERM when the computer is actually shut down. So in case +the shutdown fails, or the shutdown program for some reason decides not to +perform a shutdown, VDR will stay up and running. + +If there are currently no timers active, both parameters will be '0'. +In that case the program shall not set the hardware for automatic restart +and only perform the system shutdown. A program that uses the second parameter +to set the hardware for restart must therefore also check whether the first +parameter is '0'. + +Before the shutdown program is called, the user will be prompted to inform +him that the system is about to shut down. If any remote control key is +pressed while this prompt is visible, the shutdown will be cancelled (and +tried again after another MinUserInactivity minutes). The shutdown prompt +will be displayed for 5 minutes, which should be enough time for the user +to react. + +A sample shell script to be used with the '-s' option might look like this: + +#!/bin/sh +setRTCwakeup $(($1 - 300)) +sudo halt + +Here 'setRTCwakeup' would be some program that uses the first parameter +(which is the absolute time of the next timer event) to set the Real Time +Clock so that it wakes up the computer 5 minutes (i.e. 300 seconds) before +that event. The 'sudo halt' command then shuts down the computer. +You will have to substitute both commands with whatever applies to your +particular hard- and software environment. + +If the '-s' option is present, the VDR machine can be turned off by pressing +the "Power" key on the remote control. + Command line options: --------------------- @@ -239,6 +290,7 @@ The default PC key assignments are: Back 'End' in numeric block Red, Green, Yellow, Blue 'F1'..'F4' 0..9 '0'..'9' in top row + Power 'P' If you prefer different key assignments, or if the default doesn't work for your keyboard, simply delete the file 'keys-pc.conf' and restart 'vdr' to get diff --git a/MANUAL b/MANUAL index ae93099fb..c6b5efd7a 100644 --- a/MANUAL +++ b/MANUAL @@ -22,6 +22,7 @@ Video Disk Recorder User's Manual Yellow - Eject DVD Delete Delete - Delete Skip +60s Blue - Resume Mark Mark(1) - Summary Stop 0..9 Ch select - - - Numeric inp. - Editing + Power Shutdown - - - - - - (1) The "Mark" button in the "Timers" menu only works if sorting the timers has been disabled in the "Setup" menu. @@ -284,6 +285,18 @@ Video Disk Recorder User's Manual time, so it is possible to have a "repeating timer" store all its recordings under the same name; they will be distinguishable by their date and time). + If the file name contains the special character '~', the recording + will be stored in a hierarchical directory structure. For instance, + a file name of "Sci-Fi~Star Trek~Voyager" will result in a directory + structure "/video/Sci-Fi/Star_Trek/Voyager". The '~' character has + been chosen for this since the file system's directory delimiter '/' + may be part of a regular programme name. + Repeating timers create recordings that contain the 'Subtitle' + information from the EPG data in their file name. Typically (on tv + stations that care about their viewers) this contains the episode + title of a series. The subtitle is appended to the timer's file name, + separated by a '~' character, so that it results in all recordings + of this timer being collected in a common subdirectory. If this field is left blank, the channel name will be used to form the name of the recording. @@ -401,6 +414,14 @@ Video Disk Recorder User's Manual means that this recording will never be deleted automatically. + UseSubtitle = 1 Repeating timers use the EPG's 'Subtitle' information to + create recording file names in a hierarchical structure + (for instance to gather all episodes of a series in a + common subdirectory). This parameter can be used to + control this. + 0 = don't use the 'Subtitle' + 1 = use it (and create subdirectories) + VideoFormat = 0 The video format (or aspect ratio) of the tv set in use. 0 = 4:3 1 = 16:9 @@ -412,11 +433,24 @@ Video Disk Recorder User's Manual OSDwidth = 52 The width and height of the OSD . OSDheight = 18 The valid ranges are width=40...56, height=12...21. + OSDMessageTime = 1 The time (in seconds) how long an informational + message shall be displayed on the OSD. The valid range + is 1...60. + MaxVideoFileSize=2000 The maximum size of a single recorded video file in MB. The valid range is 100...2000. Default is 2000, but you may want to use smaller values if you are planning on archiving a recording to CD. + MinEventTimeout=120 If the command line option '-s' has been set, VDR will + MinUserInactivity=120 automatically shutdown the computer if the next timer + event is at least MinEventTimeout minutes in the future, + and the user has been inactive for at least + MinUserInactivity minutes. Setting MinUserInactivity + to 0 disables the automatic shutdown, while still + retaining the possibility to manually shutdown the + computer. + * Executing system commands The "Main" menu option "Commands" allows you to execute any system commands diff --git a/Makefile b/Makefile index 067f34abc..f39be0886 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.26 2001/08/15 13:56:11 kls Exp $ +# $Id: Makefile 1.27 2001/08/31 13:13:30 kls Exp $ .DELETE_ON_ERROR: @@ -59,25 +59,12 @@ font: genfontfile fontfix.c fontosd.c # Dependencies: -config.o : config.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -dvbapi.o : dvbapi.c $(AC3DIR)/ac3.h config.h dvbapi.h dvbosd.h dvd.h eit.h font.h recording.h remux.h ringbuffer.h thread.h tools.h videodir.h -dvbosd.o : dvbosd.c dvbosd.h font.h tools.h -dvd.o : dvd.c dvd.h -eit.o : eit.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h $(DTVDIR)/libdtv.h thread.h tools.h videodir.h -font.o : font.c font.h fontfix.c fontosd.c tools.h -i18n.o : i18n.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h thread.h tools.h -interface.o : interface.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h -menu.o : menu.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h -osd.o : osd.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h -recording.o : recording.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h -remote.o : remote.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h remote.h thread.h tools.h -remux.o : remux.c remux.h thread.h tools.h -ringbuffer.o: ringbuffer.c ringbuffer.h thread.h tools.h -svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h -thread.o : thread.c thread.h tools.h -tools.o : tools.c tools.h -vdr.o : vdr.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h -videodir.o : videodir.c tools.h videodir.h +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +include $(DEPFILE) # The main program: @@ -111,7 +98,7 @@ $(DTVLIB) $(DTVDIR)/libdtv.h: clean: make -C $(AC3DIR) clean make -C $(DTVDIR) clean - -rm -f $(OBJS) vdr genfontfile genfontfile.o core *~ + -rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core *~ fontclean: -rm -f fontfix.c fontosd.c CLEAN: clean fontclean diff --git a/config.c b/config.c index ad4b9dad4..a97d7e4c4 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.59 2001/08/26 14:46:43 kls Exp $ + * $Id: config.c 1.64 2001/09/02 15:04:13 kls Exp $ */ #include "config.h" @@ -38,6 +38,7 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! { k7, "7", 0 }, { k8, "8", 0 }, { k9, "9", 0 }, + { kPower, "Power", 0 }, { kNone, "", 0 }, }; @@ -364,21 +365,6 @@ cTimer::cTimer(const cEventInfo *EventInfo) if (!isempty(Title)) strn0cpy(file, EventInfo->GetTitle(), sizeof(file)); summary = NULL; - const char *Subtitle = EventInfo->GetSubtitle(); - if (isempty(Subtitle)) - Subtitle = ""; - const char *Summary = EventInfo->GetExtendedDescription(); - if (isempty(Summary)) - Summary = ""; - if (*Subtitle || *Summary) { - asprintf(&summary, "%s%s%s", Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary); - char *p = summary; - while (*p) { - if (*p == '\n') - *p = '|'; - p++; - } - } } cTimer::~cTimer() @@ -570,7 +556,7 @@ bool cTimer::Matches(time_t t) } } } - return active && startTime <= t && t <= stopTime; + return active && startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers } time_t cTimer::StartTime(void) @@ -761,9 +747,8 @@ cTimer *cTimers::GetTimer(cTimer *Timer) return NULL; } -cTimer *cTimers::GetMatch(void) +cTimer *cTimers::GetMatch(time_t t) { - time_t t = time(NULL); // all timers must be checked against the exact same time to correctly handle Priority! cTimer *t0 = NULL; cTimer *ti = First(); while (ti) { @@ -815,11 +800,15 @@ cSetup::cSetup(void) PrimaryLimit = 0; DefaultPriority = 50; DefaultLifetime = 50; + UseSubtitle = 1; VideoFormat = VIDEO_FORMAT_4_3; ChannelInfoPos = 0; OSDwidth = 52; OSDheight = 18; + OSDMessageTime = 1; MaxVideoFileSize = MAXVIDEOFILESIZE; + MinEventTimeout = 120; + MinUserInactivity = 120; CurrentChannel = -1; } @@ -848,11 +837,15 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); + else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); + else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); + else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); + else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else return false; @@ -916,11 +909,15 @@ bool cSetup::Save(const char *FileName) fprintf(f, "PrimaryLimit = %d\n", PrimaryLimit); fprintf(f, "DefaultPriority = %d\n", DefaultPriority); fprintf(f, "DefaultLifetime = %d\n", DefaultLifetime); + fprintf(f, "UseSubtitle = %d\n", UseSubtitle); fprintf(f, "VideoFormat = %d\n", VideoFormat); fprintf(f, "ChannelInfoPos = %d\n", ChannelInfoPos); fprintf(f, "OSDwidth = %d\n", OSDwidth); fprintf(f, "OSDheight = %d\n", OSDheight); + fprintf(f, "OSDMessageTime = %d\n", OSDMessageTime); fprintf(f, "MaxVideoFileSize = %d\n", MaxVideoFileSize); + fprintf(f, "MinEventTimeout = %d\n", MinEventTimeout); + fprintf(f, "MinUserInactivity = %d\n", MinUserInactivity); fprintf(f, "CurrentChannel = %d\n", CurrentChannel); f.Close(); isyslog(LOG_INFO, "saved setup to %s", FileName); diff --git a/config.h b/config.h index 70f35740b..c3fab9a8a 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.66 2001/08/26 14:46:53 kls Exp $ + * $Id: config.h 1.72 2001/09/02 15:45:17 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.93" +#define VDRVERSION "0.94" #define MaxBuffer 10000 @@ -44,6 +44,7 @@ enum eKeys { // "Up" and "Down" must be the first two keys! kYellow, kBlue, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, + kPower, kNone, // The following flags are OR'd with the above codes: k_Repeat = 0x8000, @@ -255,7 +256,7 @@ class cChannels : public cConfig<cChannel> { class cTimers : public cConfig<cTimer> { public: cTimer *GetTimer(cTimer *Timer); - cTimer *GetMatch(void); + cTimer *GetMatch(time_t t); cTimer *GetNextActiveTimer(void); }; @@ -291,10 +292,13 @@ class cSetup { int SortTimers; int PrimaryLimit; int DefaultPriority, DefaultLifetime; + int UseSubtitle; int VideoFormat; int ChannelInfoPos; int OSDwidth, OSDheight; + int OSDMessageTime; int MaxVideoFileSize; + int MinEventTimeout, MinUserInactivity; int CurrentChannel; cSetup(void); bool Load(const char *FileName); diff --git a/dvbapi.c b/dvbapi.c index 51434e12a..8e502ed15 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.110 2001/08/25 13:52:38 kls Exp $ + * $Id: dvbapi.c 1.111 2001/09/01 13:27:52 kls Exp $ */ //#define DVDDEBUG 1 @@ -2256,8 +2256,10 @@ cCuttingBuffer *cVideoCutter::cuttingBuffer = NULL; bool cVideoCutter::Start(const char *FileName) { if (!cuttingBuffer) { - const char *EditedVersionName = PrefixVideoFileName(FileName, '%'); + cRecording Recording(FileName); + const char *EditedVersionName = Recording.PrefixFileName('%'); if (EditedVersionName && RemoveVideoFile(EditedVersionName) && MakeDirs(EditedVersionName, true)) { + Recording.WriteSummary(); cuttingBuffer = new cCuttingBuffer(FileName, EditedVersionName); return true; } diff --git a/i18n.c b/i18n.c index 35a6bb1e9..086d85a3c 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.35 2001/08/26 13:45:10 kls Exp $ + * $Id: i18n.c 1.39 2001/09/02 15:17:33 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -385,6 +385,24 @@ const tPhrase Phrases[] = { "Annuler les modifications?", "Avbryte redigering", }, + { "Recording - shut down anyway?", + "Aufnahme luft - trotzdem ausschalten?", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Press any key to cancel shutdown", + "Taste drcken um Shutdown abzubrechen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // Channel parameters: { "Name", "Name", @@ -658,6 +676,15 @@ const tPhrase Phrases[] = { "Montage dj en cours!", "Redigeringsprosessen er allerede aktiv!", }, + { "Can't shutdown - option '-s' not given!", + "Shutdown unmglich - Option '-s' fehlt!", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // Setup parameters: { "OSD-Language", "OSD-Sprache", @@ -830,6 +857,15 @@ const tPhrase Phrases[] = { "Dure de vie par dfaut", "Normal levetid (Timer)", }, + { "UseSubtitle", + "Subtitle verwenden", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "VideoFormat", "Video Format", "", // TODO @@ -866,6 +902,15 @@ const tPhrase Phrases[] = { "Hauteur affichage", "", // TODO }, + { "OSDMessageTime", + "OSD Nachricht Dauer", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "MaxVideoFileSize", "Max. Video Dateigre", "", // TODO @@ -875,6 +920,24 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO }, + { "MinEventTimeout", + "Mindest Event Pause", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "MinUserInactivity", + "Mindest User Inaktivitt", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // The days of the week: { "MTWTFSS", "MDMDFSS", @@ -1112,6 +1175,15 @@ const tPhrase Phrases[] = { "Bleu", "Bl", }, + { "Power", + "Ausschalten", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // Miscellaneous: { "yes", "ja", diff --git a/interface.c b/interface.c index 1e06f4af2..8695a3670 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.41 2001/08/25 13:15:00 kls Exp $ + * $Id: interface.c 1.44 2001/09/01 15:18:46 kls Exp $ */ #include "interface.h" @@ -20,6 +20,7 @@ cInterface::cInterface(int SVDRPport) cols[0] = 0; width = height = 0; keyFromWait = kNone; + interrupted = false; rcIo = NULL; SVDRP = NULL; #if defined(REMOTE_RCU) @@ -105,16 +106,19 @@ void cInterface::PutKey(eKeys Key) eKeys cInterface::Wait(int Seconds, bool KeepChar) { + if (Seconds == 0) + Seconds = Setup.OSDMessageTime; Flush(); eKeys Key = kNone; time_t timeout = time(NULL) + Seconds; for (;;) { Key = GetKey(); - if ((Key != kNone && (RAWKEY(Key) != kOk || RAWKEY(Key) == Key)) || time(NULL) > timeout) + if ((Key != kNone && (RAWKEY(Key) != kOk || RAWKEY(Key) == Key)) || time(NULL) > timeout || interrupted) break; } if (KeepChar && ISRAWKEY(Key)) keyFromWait = Key; + interrupted = false; return Key; } @@ -312,12 +316,13 @@ void cInterface::Error(const char *s) Close(); } -bool cInterface::Confirm(const char *s) +bool cInterface::Confirm(const char *s, int Seconds, bool WaitForTimeout) { Open(); isyslog(LOG_INFO, "confirm: %s", s); Status(s, clrBlack, clrYellow); - bool result = Wait(10) == kOk; + eKeys k = Wait(Seconds); + bool result = WaitForTimeout ? k == kNone : k == kOk; Status(NULL); Close(); isyslog(LOG_INFO, "%sconfirmed", result ? "" : "not "); @@ -353,7 +358,7 @@ void cInterface::QueryKeys(void) WriteText(1, 5, tr("Press any key on the RC unit")); Flush(); #ifndef REMOTE_KBD - unsigned char Code = 0; + unsigned char Code = '0'; unsigned short Address; #endif for (;;) { diff --git a/interface.h b/interface.h index 2b0e2f1ae..dbfa1bca7 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.22 2001/07/27 11:38:01 kls Exp $ + * $Id: interface.h 1.24 2001/09/01 15:14:50 kls Exp $ */ #ifndef __INTERFACE_H @@ -23,17 +23,19 @@ class cInterface { int open; int cols[MaxCols]; eKeys keyFromWait; + bool interrupted; cSVDRP *SVDRP; cRcIoBase *rcIo; unsigned int GetCh(bool Wait = true, bool *Repeat = NULL, bool *Release = NULL); void QueryKeys(void); void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor); - eKeys Wait(int Seconds = 1, bool KeepChar = false); + eKeys Wait(int Seconds = 0, bool KeepChar = false); public: cInterface(int SVDRPport = 0); ~cInterface(); void Open(int NumCols = 0, int NumLines = 0); void Close(void); + void Interrupt(void) { interrupted = true; } int Width(void) { return width; } int Height(void) { return height; } eKeys GetKey(bool Wait = true); @@ -52,7 +54,7 @@ class cInterface { void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan); void Info(const char *s); void Error(const char *s); - bool Confirm(const char *s); + bool Confirm(const char *s, int Seconds = 10, bool WaitForTimeout = false); void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); void LearnKeys(void); void DisplayChannelNumber(int Number); diff --git a/keys-pc.conf b/keys-pc.conf index cb0192be3fcc6e296bcd6efd69c099dfd7fdf664..ab4b58d5e775d71cc950c523290e77cd5b6d97c4 100644 GIT binary patch delta 38 qcmbQuw1$bzIX@+p(_kW-J(H>HME5I#0r};rMG6WE24G-nzy$!)z6ucl delta 20 bcmZ3(G@FUdIX@+plVKv8J(HQyME5HIIXwl! diff --git a/libdtv/x.txt b/libdtv/x.txt deleted file mode 100644 index 0d12dddb8..000000000 --- a/libdtv/x.txt +++ /dev/null @@ -1,55 +0,0 @@ -Hallo ZDF-EPG-Redaktion! - -Es wrde mich interessieren, warum im digitalen EPG des -ZDF (ber Astra) die Beschreibung der Sendungen oftmals -Trennungsstriche und zustzliche Leerzeichen enthlt. -So zum Beispiel bei folgendem Eintrag: - ----------------------------------------------------- - ZDF 23.08 10:50 - 11:35 - - Mit Leib und Seele - - Der einzige Mensch - - Stehlin hat die Frhmesse abge- sagt und sein - Kommen im Pfarr- haus angekndigt. August, erbost - ber die Heimlichkeiten und Re- dereien von - Stutz, erzwingt eine Aussprache mit Stehlin. ----------------------------------------------------- - -der ohne Trennungsstriche so aussehen knnte: - ----------------------------------------------------- - ZDF 23.08 10:50 - 11:35 - - Mit Leib und Seele - - Der einzige Mensch - - Stehlin hat die Frhmesse abgesagt und sein - Kommen im Pfarrhaus angekndigt. August, erbost - ber die Heimlichkeiten und Redereien von Stutz, - erzwingt eine Aussprache mit Stehlin. ----------------------------------------------------- - -Ich kann mir das nur so erklren, da Sie konkrete Annahmen -darber machen, mit welcher Zeilenlnge die Set-Top-Box diese -Texte darstellt - aber das ist in meinen Augen eine ziemlich -verwegene Annahme, denn es sollte ja wohl der STB berlassen bleiben, -wie gro das Fenster fr die Darstellung des EPG ist. - -Pro-7 zum Beispiel macht sowas nicht, wodurch der Text deultich -besser dargestellt wird. - -Wenn Sie wenigstens nach dem (bzw. statt des) Bindestrich(s) ein deutlich -erkennbares Sonderzeichen einfgen wrden, dann knnte man das zuverlssig -herausfiltern, aber so macht der ZDF-EPG immer wieder einen -schlechten Eindruck. - -ber eine Antwort von Ihnen wrde ich mich sehr freuen. - -MfG -Klaus Schmidinger - - diff --git a/menu.c b/menu.c index 6d6eae8e2..5ff54cbd8 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.109 2001/08/26 14:03:27 kls Exp $ + * $Id: menu.c 1.115 2001/09/02 15:27:54 kls Exp $ */ #include "menu.h" @@ -19,7 +19,7 @@ #define MENUTIMEOUT 120 // seconds #define MAXWAIT4EPGINFO 10 // seconds -const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#^"; +const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#~^"; // --- cMenuEditItem --------------------------------------------------------- @@ -494,6 +494,7 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key) if (value[pos] == '^') value[pos] = 0; pos = -1; + stripspace(value); break; } // run into default @@ -1159,17 +1160,6 @@ cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch) const char *Title = eventInfo->GetTitle(); const char *Subtitle = eventInfo->GetSubtitle(); const char *ExtendedDescription = eventInfo->GetExtendedDescription(); - // Some channels send a 'Subtitle' that should actually be the 'ExtendedDescription' - // (their 'ExtendedDescription' is then empty). In order to handle this correctly - // we silently shift that text to where it belongs. - // The German TV station 'VOX' is notorious for this - why can't they do it correctly - // like all the others? Well, at least like those who actually send the full range - // of information (like, e.g., 'Sat.1'). Some stations (like 'RTL') don't even - // bother sending anything but the 'Title'... - if (isempty(ExtendedDescription) && !isempty(Subtitle) && int(strlen(Subtitle)) > 2 * Setup.OSDwidth) { - ExtendedDescription = Subtitle; - Subtitle = NULL; - } if (!isempty(Title)) { Add(item = new cMenuTextItem(Title, 1, Line, Setup.OSDwidth - 2, -1, clrCyan)); Line += item->Height() + 1; @@ -1726,11 +1716,15 @@ void cMenuSetup::Set(void) Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("DefaultPriority"), &data.DefaultPriority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("DefaultLifetime"), &data.DefaultLifetime, 0, MAXLIFETIME)); + Add(new cMenuEditBoolItem(tr("UseSubtitle"), &data.UseSubtitle)); Add(new cMenuEditBoolItem(tr("VideoFormat"), &data.VideoFormat, "4:3", "16:9")); Add(new cMenuEditBoolItem(tr("ChannelInfoPos"), &data.ChannelInfoPos, tr("bottom"), tr("top"))); Add(new cMenuEditIntItem( tr("OSDwidth"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); Add(new cMenuEditIntItem( tr("OSDheight"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); + Add(new cMenuEditIntItem( tr("OSDMessageTime"), &data.OSDMessageTime, 1, 60)); Add(new cMenuEditIntItem( tr("MaxVideoFileSize"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); + Add(new cMenuEditIntItem( tr("MinEventTimeout"), &data.MinEventTimeout)); + Add(new cMenuEditIntItem( tr("MinUserInactivity"), &data.MinUserInactivity)); } eOSState cMenuSetup::ProcessKey(eKeys Key) @@ -2096,12 +2090,14 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer->SetPending(true); timer->SetRecording(true); if (Channels.SwitchTo(timer->channel, dvbApi)) { + const char *Subtitle = NULL; + const char *Summary = NULL; if (GetEventInfo()) { - //XXX this is in preparation for storing recordings in subdirectories and giving them the name of the Subtitle - dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", eventInfo->GetTitle(), eventInfo->GetSubtitle());//XXX - //XXX modify timer's name and summary, mark it as modified (revert later when stopping) + dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", eventInfo->GetTitle(), eventInfo->GetSubtitle()); + Subtitle = eventInfo->GetSubtitle(); + Summary = eventInfo->GetExtendedDescription(); } - cRecording Recording(timer); + cRecording Recording(timer, Subtitle, Summary); if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority)) Recording.WriteSummary(); Interface->DisplayRecording(dvbApi->CardIndex(), true); @@ -2161,9 +2157,9 @@ void cRecordControl::Stop(bool KeepInstant) } } -bool cRecordControl::Process(void) +bool cRecordControl::Process(time_t t) { - if (!timer || !timer->Matches()) + if (!timer || !timer->Matches(t)) return false; AssertFreeDiskSpace(timer->priority); return true; @@ -2233,11 +2229,11 @@ const char *cRecordControls::GetInstantId(const char *LastInstantId) return NULL; } -void cRecordControls::Process(void) +void cRecordControls::Process(time_t t) { for (int i = 0; i < MAXDVBAPI; i++) { if (RecordControls[i]) { - if (!RecordControls[i]->Process()) + if (!RecordControls[i]->Process(t)) DELETENULL(RecordControls[i]); } } diff --git a/menu.h b/menu.h index d6db00285..2c5ed3941 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.24 2001/08/18 10:22:43 kls Exp $ + * $Id: menu.h 1.25 2001/09/01 14:52:48 kls Exp $ */ #ifndef _MENU_H @@ -78,7 +78,7 @@ class cRecordControl { public: cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL); virtual ~cRecordControl(); - bool Process(void); + bool Process(time_t t); bool Uses(cDvbApi *DvbApi) { return DvbApi == dvbApi; } void Stop(bool KeepInstant = false); bool IsInstant(void) { return instantId; } @@ -93,7 +93,7 @@ class cRecordControls { static void Stop(const char *InstantId); static void Stop(cDvbApi *DvbApi); static const char *GetInstantId(const char *LastInstantId); - static void Process(void); + static void Process(time_t t); static bool Active(void); }; diff --git a/recording.c b/recording.c index 0190d108f..f65737812 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.33 2001/08/12 15:09:59 kls Exp $ + * $Id: recording.c 1.36 2001/09/02 15:09:28 kls Exp $ */ #define _GNU_SOURCE @@ -179,6 +179,7 @@ void cResumeFile::Delete(void) struct tCharExchange { char a; char b; }; tCharExchange CharExchange[] = { + { '~', '/' }, { ' ', '_' }, { '\'', '\x01' }, { '/', '\x02' }, @@ -190,24 +191,45 @@ tCharExchange CharExchange[] = { char *ExchangeChars(char *s, bool ToFileSystem) { - for (struct tCharExchange *ce = CharExchange; ce->a && ce->b; ce++) - strreplace(s, ToFileSystem ? ce->a : ce->b, ToFileSystem ? ce->b : ce->a); + char *p = s; + while (*p) { + for (struct tCharExchange *ce = CharExchange; ce->a && ce->b; ce++) { + if (*p == (ToFileSystem ? ce->a : ce->b)) { + *p = ToFileSystem ? ce->b : ce->a; + break; + } + } + p++; + } return s; } -cRecording::cRecording(cTimer *Timer) +cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary) { titleBuffer = NULL; fileName = NULL; - name = strdup(Timer->file); + if (Timer->IsSingleEvent() || !Setup.UseSubtitle) + name = strdup(Timer->file); + else { + if (isempty(Subtitle)) + Subtitle = " "; + asprintf(&name, "%s~%s", Timer->file, Subtitle); + } // substitute characters that would cause problems in file names: strreplace(name, '\n', ' '); - summary = Timer->summary ? strdup(Timer->summary) : NULL; - if (summary) - strreplace(summary, '|', '\n'); start = Timer->StartTime(); priority = Timer->priority; lifetime = Timer->lifetime; + // handle summary: + summary = !isempty(Timer->summary) ? strdup(Timer->summary) : NULL; + if (!summary) { + if (isempty(Subtitle)) + Subtitle = ""; + if (isempty(Summary)) + Summary = ""; + if (*Subtitle || *Summary) + asprintf(&summary, "%s%s%s", Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary); + } } cRecording::cRecording(const char *FileName) @@ -311,6 +333,17 @@ const char *cRecording::Title(char Delimiter, bool NewIndicator) return titleBuffer; } +const char *cRecording::PrefixFileName(char Prefix) +{ + const char *p = PrefixVideoFileName(FileName(), Prefix); + if (p) { + delete fileName; + fileName = strdup(p); + return fileName; + } + return NULL; +} + bool cRecording::WriteSummary(void) { if (summary) { diff --git a/recording.h b/recording.h index 059133e72..e1af3db3c 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.14 2001/06/02 10:00:25 kls Exp $ + * $Id: recording.h 1.16 2001/09/02 11:35:56 kls Exp $ */ #ifndef __RECORDING_H @@ -39,12 +39,13 @@ class cRecording : public cListObject { time_t start; int priority; int lifetime; - cRecording(cTimer *Timer); + cRecording(cTimer *Timer, const char *Subtitle, const char *Summary); cRecording(const char *FileName); ~cRecording(); const char *FileName(void); const char *Title(char Delimiter = ' ', bool NewIndicator = false); const char *Summary(void) { return summary; } + const char *PrefixFileName(char Prefix); bool WriteSummary(void); bool Delete(void); // Changes the file name so that it will no longer be visible in the "Recordings" menu diff --git a/svdrp.c b/svdrp.c index d3bceec1d..5f8aad403 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.21 2001/08/12 15:10:16 kls Exp $ + * $Id: svdrp.c 1.22 2001/09/01 09:50:03 kls Exp $ */ #define _GNU_SOURCE @@ -166,6 +166,16 @@ const char *HelpPages[] = { " Create a new timer. Settings must be in the same format as returned\n" " by the LSTT command. It is an error if a timer with the same channel,\n" " day, start and stop time already exists.", + "NEXT [ abs | rel ]\n" + " Show the next timer event. If no option is given, the output will be\n" + " in human readable form. With option 'abs' the absolute time of the next\n" + " event will be given as the number of seconds since the epoch (time_t\n" + " format), while with option 'rel' the relative time will be given as the\n" + " number of seconds from now until the event. If the absolute time given\n" + " is smaller than the current time, or if the relative time is less than\n" + " zero, this means that the timer is currently recording and has started\n" + " at the given time. The first value in the resulting line is the number\n" + " of the timer.", "OVLF <sizex> <sizey> <fbaddr> <bpp> <palette>\n" " Set the size, address depth and palette of the overlay.", "OVLG <sizex> <sizey> <posx> <posy>\n" @@ -737,6 +747,28 @@ void cSVDRP::CmdNEWT(const char *Option) Reply(501, "Missing timer settings"); } +void cSVDRP::CmdNEXT(const char *Option) +{ + cTimer *t = Timers.GetNextActiveTimer(); + if (t) { + time_t Start = t->StartTime(); + int Number = t->Index() + 1; + if (!*Option) { + char *s = ctime(&Start); + s[strlen(s) - 1] = 0; // strip trailing newline + Reply(250, "%d %s", Number, s); + } + else if (strcasecmp(Option, "ABS") == 0) + Reply(250, "%d %ld", Number, Start); + else if (strcasecmp(Option, "REL") == 0) + Reply(250, "%d %ld", Number, Start - time(NULL)); + else + Reply(501, "Unknown option: \"%s\"", Option); + } + else + Reply(550, "No active timers"); +} + void cSVDRP::CmdOVLF(const char *Option) { if (*Option) { @@ -893,6 +925,7 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("MOVT")) CmdMOVT(s); else if (CMD("NEWC")) CmdNEWC(s); else if (CMD("NEWT")) CmdNEWT(s); + else if (CMD("NEXT")) CmdNEXT(s); else if (CMD("OVLF")) CmdOVLF(s); else if (CMD("OVLG")) CmdOVLG(s); else if (CMD("OVLC")) CmdOVLC(s); diff --git a/svdrp.h b/svdrp.h index 83827082a..503439a4b 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.9 2001/04/01 15:05:38 kls Exp $ + * $Id: svdrp.h 1.10 2001/09/01 09:24:50 kls Exp $ */ #ifndef __SVDRP_H @@ -56,6 +56,7 @@ class cSVDRP { void CmdMOVT(const char *Option); void CmdNEWC(const char *Option); void CmdNEWT(const char *Option); + void CmdNEXT(const char *Option); void CmdOVLF(const char *Option); void CmdOVLG(const char *Option); void CmdOVLC(const char *Option); diff --git a/vdr.c b/vdr.c index 3f8f8da83..efb5e1c38 100644 --- a/vdr.c +++ b/vdr.c @@ -22,9 +22,10 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.64 2001/08/26 15:02:00 kls Exp $ + * $Id: vdr.c 1.68 2001/09/01 14:50:40 kls Exp $ */ +#define _GNU_SOURCE #include <getopt.h> #include <signal.h> #include <stdlib.h> @@ -48,13 +49,16 @@ #endif #define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping +#define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown static int Interrupted = 0; static void SignalHandler(int signum) { - if (signum != SIGPIPE) + if (signum != SIGPIPE) { Interrupted = signum; + Interface->Interrupt(); + } signal(signum, SignalHandler); } @@ -77,7 +81,8 @@ int main(int argc, char *argv[]) const char *ConfigDirectory = NULL; bool DaemonMode = false; int WatchdogTimeout = DEFAULTWATCHDOG; - char *Terminal = NULL; + const char *Terminal = NULL; + const char *Shutdown = NULL; static struct option long_options[] = { { "audio", required_argument, NULL, 'a' }, @@ -88,16 +93,17 @@ int main(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "log", required_argument, NULL, 'l' }, { "port", required_argument, NULL, 'p' }, + { "shutdown", required_argument, NULL, 's' }, + { "terminal", required_argument, NULL, 't' }, { "video", required_argument, NULL, 'v' }, { "dvd", required_argument, NULL, 'V' }, { "watchdog", required_argument, NULL, 'w' }, - { "terminal", required_argument, NULL, 't' }, { NULL } }; int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:t:v:V:w:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:s:t:v:V:w:", long_options, &option_index)) != -1) { switch (c) { case 'a': cDvbApi::SetAudioCommand(optarg); break; @@ -134,6 +140,7 @@ int main(int argc, char *argv[]) " 2 = errors and info, 3 = errors, info and debug\n" " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" " 0 turns off SVDRP\n" + " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" " -t TTY, --terminal=TTY controlling tty\n" " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" " -V DEV, --dvd=DEV use DEV as the DVD device (default: %s)\n" @@ -170,6 +177,8 @@ int main(int argc, char *argv[]) return 2; } break; + case 's': Shutdown = optarg; + break; case 't': Terminal = optarg; break; case 'v': VideoDirectory = optarg; @@ -292,8 +301,9 @@ int main(int argc, char *argv[]) cReplayControl *ReplayControl = NULL; int LastChannel = -1; int PreviousChannel = cDvbApi::CurrentChannel(); - time_t LastActivity = time(NULL); + time_t LastActivity = 0; int MaxLatencyTime = 0; + bool ForceShutdown = false; if (WatchdogTimeout > 0) { dsyslog(LOG_INFO, "setting watchdog timer to %d seconds", WatchdogTimeout); @@ -323,18 +333,21 @@ int main(int argc, char *argv[]) } // Timers and Recordings: if (!Menu) { - cTimer *Timer = Timers.GetMatch(); + time_t Now = time(NULL); // must do both following calls with the exact same time! + cRecordControls::Process(Now); + cTimer *Timer = Timers.GetMatch(Now); if (Timer) { if (!cRecordControls::Start(Timer)) Timer->SetPending(true); } - cRecordControls::Process(); } // User Input: cOsdBase **Interact = Menu ? &Menu : (cOsdBase **)&ReplayControl; eKeys key = Interface->GetKey(!*Interact || !(*Interact)->NeedsFastResponse()); - if (NORMALKEY(key) != kNone) + if (NORMALKEY(key) != kNone) { EITScanner.Activity(); + LastActivity = time(NULL); + } if (*Interact) { switch ((*Interact)->ProcessKey(key)) { case osMenu: DELETENULL(Menu); @@ -383,39 +396,50 @@ int main(int argc, char *argv[]) break; // Direct Channel Select: case k1 ... k9: - if (!Interface->Recording()) - Menu = new cDisplayChannel(key); + Menu = new cDisplayChannel(key); break; // Left/Right rotates trough channel groups: case kLeft|k_Repeat: case kLeft: case kRight|k_Repeat: - case kRight: if (!Interface->Recording()) { - int SaveGroup = CurrentGroup; - if (NORMALKEY(key) == kRight) - CurrentGroup = Channels.GetNextGroup(CurrentGroup) ; - else - CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup); - if (CurrentGroup < 0) - CurrentGroup = SaveGroup; - Menu = new cDisplayChannel(CurrentGroup, false, true); - } - break; + case kRight: { + int SaveGroup = CurrentGroup; + if (NORMALKEY(key) == kRight) + CurrentGroup = Channels.GetNextGroup(CurrentGroup) ; + else + CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup); + if (CurrentGroup < 0) + CurrentGroup = SaveGroup; + Menu = new cDisplayChannel(CurrentGroup, false, true); + break; + } // Up/Down Channel Select: case kUp|k_Repeat: case kUp: case kDown|k_Repeat: - case kDown: if (!Interface->Recording()) { - int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1); - cChannel *channel = Channels.GetByNumber(n); - if (channel) - channel->Switch(); - } - break; + case kDown: { + int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1); + cChannel *channel = Channels.GetByNumber(n); + if (channel) + channel->Switch(); + break; + } // Menu Control: case kMenu: Menu = new cMenuMain(ReplayControl); break; // Viewing Control: case kOk: LastChannel = -1; break; // forces channel display + // Power off: + case kPower: isyslog(LOG_INFO, "Power button pressed"); + if (!Shutdown) { + Interface->Error(tr("Can't shutdown - option '-s' not given!")); + break; + } + if (cRecordControls::Active()) { + if (Interface->Confirm(tr("Recording - shut down anyway?"))) + ForceShutdown = true; + } + LastActivity = 1; // not 0, see below! + break; default: break; } } @@ -423,14 +447,46 @@ int main(int argc, char *argv[]) EITScanner.Process(); cVideoCutter::Active(); } - if (!*Interact && !cRecordControls::Active()) { - if (time(NULL) - LastActivity > ACTIVITYTIMEOUT) { + if (!*Interact && (!cRecordControls::Active() || ForceShutdown)) { + time_t Now = time(NULL); + if (Now - LastActivity > ACTIVITYTIMEOUT) { + // Shutdown: + if (Shutdown && (Setup.MinUserInactivity && Now - LastActivity > Setup.MinUserInactivity * 60 || ForceShutdown)) { + ForceShutdown = false; + cTimer *timer = Timers.GetNextActiveTimer(); + time_t Next = timer ? timer->StartTime() : 0; + time_t Delta = timer ? Next - Now : 0; + if (timer) + dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next)); + if (!Next || Delta > Setup.MinEventTimeout * 60) { + if (!LastActivity) { + // Apparently the user started VDR manually + dsyslog(LOG_INFO, "assuming manual start of VDR"); + LastActivity = Now; + continue; // skip the rest of the housekeeping for now + } + if (WatchdogTimeout > 0) + signal(SIGALRM, SIG_IGN); + if (Interface->Confirm(tr("Press any key to cancel shutdown"), LastActivity == 1 ? 5 : SHUTDOWNWAIT, true)) { + char *cmd; + asprintf(&cmd, "%s %ld %ld", Shutdown, Next, Delta); + isyslog(LOG_INFO, "executing '%s'", cmd); + system(cmd); + delete cmd; + } + else if (WatchdogTimeout > 0) { + alarm(WatchdogTimeout); + if (signal(SIGALRM, Watchdog) == SIG_IGN) + signal(SIGALRM, SIG_IGN); + } + LastActivity = Now; // don't try again too soon + continue; // skip the rest of the housekeeping for now + } + } + // Disk housekeeping: RemoveDeletedRecordings(); - LastActivity = time(NULL); } } - else - LastActivity = time(NULL); } if (Interrupted) isyslog(LOG_INFO, "caught signal %d", Interrupted); diff --git a/videodir.c b/videodir.c index 6f35a3dcc..d9d3f8524 100644 --- a/videodir.c +++ b/videodir.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: videodir.c 1.5 2001/05/01 09:48:57 kls Exp $ + * $Id: videodir.c 1.6 2001/09/02 14:55:15 kls Exp $ */ #include "videodir.h" @@ -188,13 +188,21 @@ const char *PrefixVideoFileName(const char *FileName, char Prefix) if (!PrefixedName || strlen(PrefixedName) <= strlen(FileName)) PrefixedName = (char *)realloc(PrefixedName, strlen(FileName) + 2); if (PrefixedName) { - strcpy(PrefixedName, VideoDirectory); - char *p = PrefixedName + strlen(PrefixedName); - *p++ = '/'; - *p++ = Prefix; - strcpy(p, FileName + strlen(VideoDirectory) + 1); + const char *p = FileName + strlen(FileName); // p points at the terminating 0 + int n = 2; + while (p-- > FileName && n > 0) { + if (*p == '/') { + if (--n == 0) { + int l = p - FileName + 1; + strncpy(PrefixedName, FileName, l); + PrefixedName[l] = Prefix; + strcpy(PrefixedName + l + 1, p + 1); + return PrefixedName; + } + } + } } - return PrefixedName; + return NULL; } void RemoveEmptyVideoDirectories(void) From 156831036e9b0fcbfc719033cc89e08c1985cad6 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 16 Sep 2001 18:00:00 +0200 Subject: [PATCH 025/307] Version 0.95 - Fixed behaviour in case the shutdown didn't take place (there were many "next timer event at..." messages in that case). - Reduced the default value for MinEventTimeout to 30 minutes. - Fixed detecting manual start in shutdown feature. - An error message is now displayed in case the Transfer Mode can't be started because the necessary DVB card is currently recording (or there is no DVB card that can access this channel). - Fixed toggling channels with the '0' key in case the "Ok" button has been pressed to display the current/next information. - Pressing the "Power" key now always initiates the shutdown sequence (after user confirmation in case of a recording timer), event if there is currently a menu or a replay session active. Note the additional remarks in INSTALL regarding the values of the two parameters given to the shutdown program in case of a currently recording timer. - Switching through channel groups with the "Left" and "Right" keys now always starts at the group that contains the current channel. - Implemented "Multi Speed Mode" (thanks to Stefan Huelswitt). - Implemented backtracing to hit the right spot after fast forward/rewind (thanks to Stefan Huelswitt). - Implemented replay mode display (thanks to Stefan Huelswitt, with a few rewrites by kls). - Changed the size of all input buffers used to parse config files or receive SVDRP commands to the same value of 10KB. This allows long strings to be used in the 'summary' field of a timer, for instance. - The pipe to the Dolby Digital replay command (option '-a') now closes all unused file descriptors in the child process to avoid crashing when the OSD is used (thanks to Andreas Vitting). - Switched to the driver's new tuning API (VDR now requires a driver version dated 2001-09-14 or higher). - Changed obsolete macro VIDEO_WINDOW_CHROMAKEY to VID_TYPE_CHROMAKEY (thanks to Guido Fiala). - New version of the "Master-Timer" tool (thanks to Matthias Schniedermeyer). - Better error handling when writing configuration files. - Fixed putting the final editing mark into the edited version's marks file. - Fixed manipulating an editing mark at the very end of a recording. - Fixed starting a new replay immediately after stopping a previous one (had caused a mix between live video and replay). - Three new keys ("Volume+", Volume-" and "Mute") to control the DVB card's audio output volume. - New version of the 'epg2timers' tool (thanks to Carsten Koch). --- CONTRIBUTORS | 9 +- HISTORY | 43 + INSTALL | 15 +- MANUAL | 22 +- Tools/epg2timers/README | 151 ++ Tools/epg2timers/epg2timers.cxx | 578 ++++- Tools/epg2timers/epg_channel_names | 400 +++ Tools/epg2timers/get_merkliste.pl | 82 + Tools/epg2timers/loadvdr.pl | 89 + Tools/epg2timers/update_timers | 22 + Tools/epg2timers/update_timers.old | 24 + Tools/master-timer/LIESMICH | 154 +- Tools/master-timer/README | 54 +- Tools/master-timer/THANKS | 18 + Tools/master-timer/Todo | 4 - Tools/master-timer/convert-DTV2VDR.pl | 151 ++ Tools/master-timer/convert-oldtorecord.pl | 61 + Tools/master-timer/master-timer.pl | 2231 +++++++++-------- Tools/master-timer/sample/channels-to-scan | 4 +- Tools/master-timer/sample/config | 38 +- .../master-timer/sample/convert-channel-list | 26 + Tools/master-timer/sample/deepblack | 251 +- Tools/master-timer/sample/subtitle-movie | 11 + Tools/master-timer/sample/torecord | 116 +- config.c | 59 +- config.h | 22 +- dvbapi.c | 486 ++-- dvbapi.h | 26 +- i18n.c | 56 +- keys-pc.conf | 3 + menu.c | 112 +- menu.h | 11 +- svdrp.c | 6 +- svdrp.h | 6 +- thread.c | 106 +- thread.h | 18 +- tools.c | 26 +- tools.h | 13 +- vdr.c | 59 +- 39 files changed, 3969 insertions(+), 1594 deletions(-) create mode 100644 Tools/epg2timers/README create mode 100644 Tools/epg2timers/epg_channel_names create mode 100755 Tools/epg2timers/get_merkliste.pl create mode 100755 Tools/epg2timers/loadvdr.pl create mode 100755 Tools/epg2timers/update_timers create mode 100755 Tools/epg2timers/update_timers.old create mode 100644 Tools/master-timer/THANKS create mode 100755 Tools/master-timer/convert-DTV2VDR.pl create mode 100755 Tools/master-timer/convert-oldtorecord.pl create mode 100644 Tools/master-timer/sample/convert-channel-list diff --git a/CONTRIBUTORS b/CONTRIBUTORS index c055c1759..9090ca9f3 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -100,10 +100,13 @@ Stefan Huelswitt <huels@iname.com> for making the position of the channel display configurable for making the width and height of the OSD configurable for implementing the "Jump" function in replay mode + for implementing "Multi Speed Mode" + for implementing backtracing for fast forward/rewind + for implementing the replay mode display Ulrich Rder <dynamite@efr-net.de> for pointing out that there are channels that have a symbol rate higher than - 27500. + 27500 Helmut Schchner <schaechner@yahoo.com> for his support in keeping the Premiere World channels up to date in 'channels.conf' @@ -132,3 +135,7 @@ Werner Fink <werner@suse.de> Rolf Hakenes <hakenes@hippomi.de> for providing 'libdtv' and adapting the EIT mechanisms to it + +Andreas Vitting <Andreas@huji.de> + for providing code that closes all unused file descriptors in the child + process of a pipe (used in cPipe) diff --git a/HISTORY b/HISTORY index d2be05446..4b68aebca 100644 --- a/HISTORY +++ b/HISTORY @@ -715,3 +715,46 @@ Video Disk Recorder Revision History definitions). Use your favourite text editor to delete that information. That way every recording will store the actual summary data at the time of the recording. + +2001-09-16: Version 0.95 + +- Fixed behaviour in case the shutdown didn't take place (there were many + "next timer event at..." messages in that case). +- Reduced the default value for MinEventTimeout to 30 minutes. +- Fixed detecting manual start in shutdown feature. +- An error message is now displayed in case the Transfer Mode can't be + started because the necessary DVB card is currently recording (or there + is no DVB card that can access this channel). +- Fixed toggling channels with the '0' key in case the "Ok" button has been + pressed to display the current/next information. +- Pressing the "Power" key now always initiates the shutdown sequence (after + user confirmation in case of a recording timer), event if there is currently + a menu or a replay session active. Note the additional remarks in INSTALL + regarding the values of the two parameters given to the shutdown program + in case of a currently recording timer. +- Switching through channel groups with the "Left" and "Right" keys now + always starts at the group that contains the current channel. +- Implemented "Multi Speed Mode" (thanks to Stefan Huelswitt). +- Implemented backtracing to hit the right spot after fast forward/rewind + (thanks to Stefan Huelswitt). +- Implemented replay mode display (thanks to Stefan Huelswitt, with a few + rewrites by kls). +- Changed the size of all input buffers used to parse config files or receive + SVDRP commands to the same value of 10KB. This allows long strings to be + used in the 'summary' field of a timer, for instance. +- The pipe to the Dolby Digital replay command (option '-a') now closes all + unused file descriptors in the child process to avoid crashing when the + OSD is used (thanks to Andreas Vitting). +- Switched to the driver's new tuning API (VDR now requires a driver version + dated 2001-09-14 or higher). +- Changed obsolete macro VIDEO_WINDOW_CHROMAKEY to VID_TYPE_CHROMAKEY (thanks + to Guido Fiala). +- New version of the "Master-Timer" tool (thanks to Matthias Schniedermeyer). +- Better error handling when writing configuration files. +- Fixed putting the final editing mark into the edited version's marks file. +- Fixed manipulating an editing mark at the very end of a recording. +- Fixed starting a new replay immediately after stopping a previous one (had + caused a mix between live video and replay). +- Three new keys ("Volume+", Volume-" and "Mute") to control the DVB card's + audio output volume. +- New version of the 'epg2timers' tool (thanks to Carsten Koch). diff --git a/INSTALL b/INSTALL index e15f13ee9..56200e86e 100644 --- a/INSTALL +++ b/INSTALL @@ -27,11 +27,8 @@ You can find 'libdvdread' at http://www.dtek.chalmers.se/groups/dvd/downloads.html -VDR requires the card driver version 0.9.0 or higher -to work properly. You need to load the dvb.o module *without* option -'outstream=0' (previous versions of VDR required this option to have -the driver supply the data in AV_PES format; as of version 0.70 VDR -works with PES format). +VDR requires the card driver version dated 2001-09-14 or higher +to work properly. After extracting the package, change into the VDR directory and type 'make'. This should produce an executable file @@ -126,6 +123,12 @@ and only perform the system shutdown. A program that uses the second parameter to set the hardware for restart must therefore also check whether the first parameter is '0'. +If a timer is currently recording, the parameters will reflect the start +time of that timer. This means that the first parameter will be a time in +the past, and the second parameter will be a negative number. This only +happens if the user presses the "Power" key while a timer is currently +recording. + Before the shutdown program is called, the user will be prompted to inform him that the system is about to shut down. If any remote control key is pressed while this prompt is visible, the shutdown will be cancelled (and @@ -291,6 +294,8 @@ The default PC key assignments are: Red, Green, Yellow, Blue 'F1'..'F4' 0..9 '0'..'9' in top row Power 'P' + Volume+/- '+', '-' + Mute 'm' If you prefer different key assignments, or if the default doesn't work for your keyboard, simply delete the file 'keys-pc.conf' and restart 'vdr' to get diff --git a/MANUAL b/MANUAL index c6b5efd7a..05f2f3ca9 100644 --- a/MANUAL +++ b/MANUAL @@ -8,7 +8,7 @@ Video Disk Recorder User's Manual possible, several keys have different meanings in the various modes: - Key Normal Main Channels Timers Edit/New Recordings Replay + Key Normal Main Channels Timers Edit/New Recordings Replay Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause @@ -23,6 +23,9 @@ Video Disk Recorder User's Manual Blue - Resume Mark Mark(1) - Summary Stop 0..9 Ch select - - - Numeric inp. - Editing Power Shutdown - - - - - - + Volume+ Volume up - - - - - - + Volume- Volume down - - - - - - + Mute Mute - - - - - - (1) The "Mark" button in the "Timers" menu only works if sorting the timers has been disabled in the "Setup" menu. @@ -177,6 +180,10 @@ Video Disk Recorder User's Manual backward at a slower speed; press again to return to pause mode. Pressing and holding down the button performs the function until the button is released again. + If "Multi Speed Mode" has been enabled in the "Setup" menu, the + function of these buttons changes in a way that gives you three + fast and slow speeds, through which you can switch by pressing + the respective button several times. - Red Jump to a specific location. Enter the time you want to jump to and then press "Left" or "Right" to jump relative to the current position, "Up" to jump to an absolute position, and "Down" to @@ -442,7 +449,7 @@ Video Disk Recorder User's Manual you may want to use smaller values if you are planning on archiving a recording to CD. - MinEventTimeout=120 If the command line option '-s' has been set, VDR will + MinEventTimeout=30 If the command line option '-s' has been set, VDR will MinUserInactivity=120 automatically shutdown the computer if the next timer event is at least MinEventTimeout minutes in the future, and the user has been inactive for at least @@ -451,6 +458,17 @@ Video Disk Recorder User's Manual retaining the possibility to manually shutdown the computer. + MultiSpeedMode = 0 Defines the function of the "Left" and "Right" keys in + replay mode. If set to 0, one speed will be used, while + if set to 1 there will be three speeds for fast and slow + search, respectively. + 0 = off + 1 = on + + ShowReplayMode = 0 Turns displaying the current replay mode on or off. + 0 = off + 1 = on + * Executing system commands The "Main" menu option "Commands" allows you to execute any system commands diff --git a/Tools/epg2timers/README b/Tools/epg2timers/README new file mode 100644 index 000000000..53888b160 --- /dev/null +++ b/Tools/epg2timers/README @@ -0,0 +1,151 @@ +Overview. +========= + +The 4 modules in this directory are designed to allow vdr timer +programming via the http://tvtv.de web EPG (Electronic Program Guide). + +Once you have these modules properly configured and installed, +you should be able to simply click on the things you want vdr +to record in the http://tvtv.de web EPG and be done with it. +Everything else can be handled automatically. + + + +Module description. +=================== + +The http://tvtv.de web EPG creates a so-called "merkliste" +("a list of items to remember") containing all the broadcasts +you selected. + +1. The perl script "get_merkliste.pl" transfers this "merkliste" + from the http://tvtv.de web site to a local file "merkliste.html". + +2. The C++ program "epg2timers" converts this HTML file into vdr's + timers.conf format. + +3. The perl script "loadvdr.pl" pumps these new timer entries + into a running vdr using telnet and the SVDRP protocol. + +4. The shell script "update_timers" implements the overall + control of the entire process. + It retrieves the latest merkliste from http://tvtv.de, + converts it to timers.conf format and sends the timer entries + to vdr. + + + +Configuration. +============== + +get_merkliste.pl requires configuration of the "files_to_fetch" +variable preset. +Log in to your http://tvtv.de account and click on the "Bookmark" +item in the "Setup" submenu of the "Mein Programm" side bar menu. +This will open a window with a URL in the location field that ends +with an ID value. Replace the xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +in the "files_to_fetch" variable preset with your ID value. +If you are using an HTTP proxy, uncomment the line containing +the $ua->proxy call and put your proxy details in. + +epg2timers.cxx allows various items to be configured, but it +should work out of the box. See "tvtv.de channel names" below. + +update_timers must know where to find the get_merkliste.pl +perl script and the compiled epg2timers binary. Both must be +in a directory pointed to by the TOOLDIR variable. +update_timers also must know where to find vdr's current +channels.conf file. Put that into the CHANPATH. + +Depending on the price of your internet access, you may want to +run update_timers more or less frequently. It may also be a good +idea to run it at times where it is unlikely to interfere with +your current use of vdr. Configure a crontab entry according to +these personal preferences. Here is the entry I use: +1 2 * * * /home/cko/bin/update_timers +It runs update_timers only once a night at 02:01 a.m. + + +Installation. +============= +Create your TOOLDIR directory if it does not already exist. +Copy get_merkliste.pl and loadvdr.pl into it, compile epg2timers.cxx +with the command: + g++ epg2timers.cxx -o epg2timers +and move the epg2timers binary into the TOOLDIR directory. + +The get_merkliste.pl script requires certain packages to run. +Besides of course perl, install perl-libwww-perl (at least +that's the name on SuSE 7.2, it may have a different name in +your distribution). + +If you have problems with SVDRP and loadvdr.pl, you may want to +try out the update_timers.old script, which replaces the timers.conf +file directly and kills vdr (assuming that it will be restarted +by the runvdr script) to make vdr reload the timers.conf file. + + +tvtv.de channel names. +====================== +The file epg_channel_names contains the names of all channels +currently (as of September 9, 2001) supported by the tvtv.de +web EPG. The variable "channel_map" in epg2timers.cxx maps +these names into PNRs (aka Service IDs). I have initialized +this table with provider names converted from a d-box channel +scan of Astra 19.2E, so the PNRs should be correct for that +satellite, but most of the names propably aren't yet- I simply +had not enough time yet to go through epg_channel_names +and insert all its channel names at the proper places in the +channel map. Consider the map supplied an example. ;-) +If you fix any of the entries, please send me a patch. +For my own humble purposes, the table works well as it is. +Of course, your channels.conf must contain the matching +PNRs (last field in each line). + + +To Do. +====== +These are just ideas. They MAY get implemented. +If you want them to happen, contribute a patch. ;-) + +* Support vdr hierarchical directories (after vdr does) + by mapping the http://tvtv.de genre texts into + directory names. +* start_time_safety_margin for epg2timers. + + +Authors. +======== +Carsten Koch: epg2timers.cxx, update_timers, this README file. + +Axel Gruber and +Rolf Hakenes: get_merkliste.pl + +Peter Ahlert: loadvdr.pl + + +Credits. +======== +I am grateful (in chronological order) to + +* Klaus Schmidinger for his excellent vdr program and for + keeping an open mind in all directions. + +* Suse (my wife, not the Linux distributor ;-) for encouraging me to + write epg2timers in June 2000 and for her constant patience and support. + +* Andreas Steinhauser for periodically criticizing the epg2timers + "manual mode" until I came up with the idea to fully automatize it + and for contributing ideas. + +* Axel Gruber for reminding me half a year later, for pushing + the idea until it got implemented, for asking for new features + all the time and for contributing ideas. + +* Axel Gruber and Rolf Hakenes for contributing the get_merkliste.pl + perl script. + +* Peter Ahlert for contributing the loadvdr.pl perl script. + + +Carsten, September 2001. diff --git a/Tools/epg2timers/epg2timers.cxx b/Tools/epg2timers/epg2timers.cxx index 07e8182d7..94e1c8a4b 100644 --- a/Tools/epg2timers/epg2timers.cxx +++ b/Tools/epg2timers/epg2timers.cxx @@ -1,13 +1,13 @@ /* - * epg2timers.cxx: Convert an EPG "merkliste" page (http://www.tvtv.de) to a timers.conf - * file for Klaus Schmidinger's vdr (http://www.cadsoft.de/people/kls/vdr). + * epg2timers.cxx: Convert an EPG "merkliste" HTML page (http://tvtv.de) + * to timers.conf format for Klaus Schmidinger's vdr + * (http://www.cadsoft.de/people/kls/vdr). * - * Copyright (C) 2000 Carsten Koch + * Copyright (C) 2000, 2001 Carsten Koch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,65 +23,349 @@ */ +#include <malloc.h> #include <stdio.h> #include <string.h> +#include <unistd.h> +// User-configurable options. -static const char date_line[] = "\t<td align=center valign=middle colspan=3><span id=fb-b10>"; -static const char start_time_line[] = " \t\t<td bgcolor=\"#7f98bf\" align=center><span id=\"fb-w14\"><nobr> "; -static const char stop_time_line[] = "\t\t\t<tr><td bgcolor=\"#002b64\" align=center><span id=\"fn-w9\">bis "; -static const char channel_line[] = "\t\t\t<tr><td bgcolor=\"#002b64\" align=center><span id=\"fb-w9\">"; -static const char title_line[] = "\t\t\t\t<td bgcolor=\"#002b64\" align=left width=100%><span id=\"fb-w10\">"; -static const char summary_line[] = "\t\t\t<table border=0 cellpadding=10 cellspacing=0 bgcolor=\"white\" width=100%>"; -static const char * const channel_names[] = +static const int stop_time_safety_margin = 10; // add 10 minutes to stop time in case start was delayed +static const int recording_priority = 50; // vdr recording priority setting for all timer entries generated +static const int recording_lifetime = 98; // vdr recording life time setting for all timer entries generated + + +// Usually, you should not want to change any of these. + +static const int max_title = 256; // maximum length+1 of title file name generated +static const int max_genre = 32; // maximum length+1 of genre text parsed +static const int max_line = 1024; // line buffer (not used when parsing summary text) +static const int max_summary = 9000; // Summary can be up to 9000 bytes long (a bit shorter than vdr's SVDRP command buffer) +static const int max_vdr_channel = 1000; // maximum size+1 of your channels.conf + +// The following table maps http://tvtv.de channel names into Astra 19.2E PIDs. +// It is incomplete. Contributions welcome. + +typedef struct { -"3sat", -"ARTE", -"*B1 Berlin", -"BR3", -"Bloomberg TV", -"BR Alpha", -"CNN", -"ARD", -"*DW-tv", -"Eins Extra", -"Eins Festival", -"Eins MuXx", -"euroNEWS", -"HR3", -"Kabel1", -"Kinderkanal", -"MDR", -"MTV", -"NDR", -"NTV", -"ORB", -"*ORF1", -"Phoenix", -"PRO7", -"RTL", -"RTL2", -"SAT1", -"skynews", -"SWF", -"Super RTL", -"TM3", -"TW1", -"VOX", -"WDR", -"Theaterkanal", -"ZDF", -"ZDF.doku", -"ZDF.info", -"" + const char * tvtv_name; + unsigned short pnr; +} map_entry; + + +static const map_entry channel_map[] = +{ + // Deutschsprachig + {"13th Street", 42}, + {"3sat", 28007}, + {"ARTE", 28109}, + {"B1", 28206}, + {"BR3", 28107}, + {"BR-alpha", 28112}, + {"ARD", 28106}, + {"Discovery", 14}, + {"Disney Channel", 34}, + {"Eins Extra", 28201}, + {"Eins Festival", 28202}, + {"Eins MuXx", 28203}, + {"Filmpalast", 516}, + {"FOX KIDS", 28}, + {"Heimatkanal", 517}, + {"HR", 28108}, + {"Junior", 19}, + {"Kabel 1", 899}, + {"Kinderkanal", 28008}, + {"Krimi&Co", 23}, + {"K-Toon", 12}, + {"Liberty TV.com", 12199}, + {"MDR", 28204}, + {"NDR", 28224}, + {"NEUN LIVE", 897}, + {"ORB", 28205}, + {"ORF1", 13001}, + {"ORF2", 13002}, + {"Phoenix", 28114}, + {"Planet", 13}, + {"Premiere 1", 10}, + {"Premiere 2", 11}, + {"Premiere 3", 43}, + {"Premiere Action", 20}, + {"Premiere Comedy", 29}, + {"Premiere SCI-FI", 41}, + {"Premiere Star", 9}, + {"PREMIERE WORLD", 8}, + {"ProSieben", 898}, + {"RTL", 12003}, + {"RTL2", 12020}, + {"SAT.1", 46}, + {"SeaSonS", 33}, + {"SR", 28110}, + {"Studio Universal", 36}, + {"Sunset", 16}, + {"Super RTL", 12040}, + {"Test-Z1", 28305}, + {"TW1", 13013}, + {"Via 1 - Schner Reise", 44}, + {"VOX", 12060}, + {"WDR", 28111}, + {"ZDF", 28006}, + {"ZDF.doku", 28014}, + {"ZDF.info", 28011}, + // Movies + {"AXN", 29506}, + {"CANAL+", 29100}, + {"CANAL+ AZUL", 29101}, + {"CANAL+ ROJO", 29102}, + {"CANAL+ VERT", 8208}, + {"CANAL+ 16/9", 8204}, + {"CANAL+ 16|9", 29024}, + {"C+ROOD", 4005}, + {"CINE CINEMA I", 8206}, + {"CINE CINEMA II", 8002}, + {"CINE CINEMA III", 8003}, + {"CINE CLASSICS", 8709}, + {"CINE CINEMA 16/9", 8301}, + {"cinecinemas", 4008}, + {"CINECLASSICS", 29203}, + {"Cinedom 1", 176}, + {"Cinedom 1B", 178}, + {"Cinedom 1C", 180}, + {"Cinedom 1D", 190}, + {"Cinedom 2", 179}, + {"Cinedom 2B", 183}, + {"Cinedom 2C", 184}, + {"Cinedom 2D", 188}, + {"Cinedom 2E", 193}, + {"Cinedom 3", 182}, + {"Cinedom 3B", 185}, + {"Cinedom 3C", 192}, + {"Cinedom 3D", 195}, + {"Cinedom 4", 181}, + {"Cinedom 4B", 187}, + {"Cinedom 4C", 191}, + {"Cinedom 5", 186}, + {"Cinedom 5B", 194}, + {"Cindedom Deluxe", 189}, + {"CINEMANA AZUL", 29501}, + {"CINEMANA ROJO", 29605}, + {"CINEMANA", 29500}, + {"K1", 8401}, + {"K2", 8402}, + {"K3", 8403}, + {"K4", 8404}, + {"K5", 8405}, + {"K6", 8406}, + {"K7", 8407}, + {"K9", 8409}, + {"K12", 8412}, + {"TAQUILLA 1", 29206}, + {"TAQUILLA 2", 29207}, + {"TAQUILLA 3", 29502}, + {"TAQUILLA 4", 29503}, + {"TAQUILLA 5", 29504}, + {"TAQUILLA 6", 29301}, + {"TAQUILLA 7", 29302}, + {"TAQUILLA 8", 29303}, + {"TAQUILLA 11", 29316}, + {"TAQUILLA 12", 29610}, + {"TAQUILLA 13", 29402}, + {"TAQUILLA 14", 29212}, + {"TAQUILLA 16|9", 29606}, + // Music + {"40 LATINO", 29031}, + {"40 TV", 29110}, + {"CANAL+ JAUNE", 8203}, + {"CLASSICA", 15}, + {"GOLDSTAR TV", 518}, + {"MCM 2", 8305}, + {"MCM AFRICA", 8307}, + {"MCM", 8302}, + {"MTV 2", 28649}, + {"MTV 6", 28641}, + {"MTV Base", 28645}, + {"MTV Central", 28643}, + {"MTV F", 28642}, + {"MTV Hits", 28644}, + {"MUZZIK", 8007}, + {"RFM TV", 17008}, + {"TMF", 5015}, + {"VH1 Classic", 28647}, + {"VH1", 28646}, + {"Video Italia", 12220}, + {"VIVA ZWEI", 12120}, + {"VIVA", 12732}, + {"ZIK'/XXL", 17004}, + // News + {"BBC WORLD", 17007}, + {"Bloomberg TV", 12160}, + {"CNBC", 28010}, + {"CNBC", 35}, + {"CNBC-NBC", 29202}, + {"CNN", 28512}, + {"DW-tv", 9005}, + {"EuroNews", 28015}, + {"FOX NEWS", 29032}, + {"N24", 47}, + {"n-tv", 12730}, + {"Sky News", 3995}, + // Netherlands + {"NED1", 4011}, + {"NED2", 4012}, + {"NED3", 4013}, + {"NET5", 5004}, + {"RTL4", 2004}, + {"RTL5", 2005}, + {"SBS6", 5005}, + {"V8/Fox Kids", 5020}, + {"Yorin", 5010}, + // Porn + {"BEATE-UHSE.TV", 21}, + {"Blue Movie1", 513}, + {"Blue Movie2", 514}, + {"Blue Movie3", 515}, + {"K10", 8410}, + {"TAQUILLA X", 29213}, + {"TAQUILLA X", 29602}, + {"TAQUILLA XX", 29607}, + {"X-ZONE", 4009}, + // Sports + {"C+BLAUW", 4006}, + {"DSF", 900}, + {"EUROSPORT", 8101}, + {"Eurosport", 28009}, + {"EUROSPORT", 29310}, + {"EUROSPORTNEWS", 29037}, + {"PATHE SPORT|", 8009}, + {"PREMIERE SPORT 1", 17}, + {"PREMIERE SPORT 2", 27}, + {"SUPERDOM", 26}, + // French + {"13EME RUE", 8703}, + {"AB 1", 17001}, + {"AB MOTEURS", 17000}, + {"ACTION", 17010}, + {"ALLOCINE TV", 8308}, + {"ANIMAUX", 17002}, + {"ARTE", 9009}, + {"BLOOMBERG TV", 8004}, + {"CA TV", 8610}, + {"CANAL+", 8201}, + {"CANAL+ BLEU", 8202}, + {"CANAL J", 8108}, + {"CANAL JIMMY", 8006}, + {"CANALCLUB", 8812}, + {"Cartoon Network", 28511}, + {"CLUB TELEACHAT", 8303}, + {"COMEDIE !", 8702}, + {"CONTACT TV", 8804}, + {"CUISINE.TV", 8112}, + {"DEMAIN !", 8701}, + {"DISNEY CHANNEL", 8207}, + {"DT CSAT 10", 9159}, + {"ENCYCLOPEDIA", 17003}, + {"ESCALES", 17005}, + {"EURONEWS", 8505}, + {"FORUM", 8707}, + {"FRANCE 2", 8801}, + {"FRANCE 3", 8802}, + {"GAME ONE", 8717}, + {"i TELEVISION", 8010}, + {"KIOSQUE", 8704}, + {"KTO", 8304}, + {"LA CHAINE METEO", 8008}, + {"LA CINQUIEME", 8501}, + {"LaChaneHistoire", 17006}, + {"LCI", 8107}, + {"LCP", 8506}, + {"L'EQUIPE TV", 8706}, + {"LibertyTV.com", 12280}, + {"MANGAS", 17011}, + {"MONTECARLO TMC", 8102}, + {"Motors TV", 12300}, + {"NAT GEOGRAPHIC", 8310}, + {"PAD", 8211}, + {"PARIS PREMIERE", 8104}, + {"PLANETE 2", 8507}, + {"PLANETE", 8103}, + {"PMU sur Canal+", 8210}, + {"RFO SAT", 8708}, + {"SANTE - VIE", 8110}, + {"SEASONS", 8001}, + {"TCM", 28515}, + {"TEST CDN 1", 8616}, + {"TEST CDN 3", 8627}, + {"TiJi", 8309}, + {"TV 5", 9001}, + {"TV BREIZH", 8502}, + {"TV Puls", 20601}, + {"TV5 Europe", 12240}, + {"VOYAGE", 8105}, + // Spanish + {"ANDALUCA TV", 29011}, + {"Bloomberg", 12721}, + {"CALLE 13", 29609}, + {"Canal Canarias", 29700}, + {"Cartoon Network", 29314}, + {"CNN+", 29020}, + {"DISCOVERY", 29116}, + {"DISNEY CHANNEL", 29111}, + {"DOCUMANA", 29200}, + {"ESTILO", 29305}, + {"ETB", 29035}, + {"FASHION TV", 29115}, + {"FOX KIDS", 29209}, + {"FOX", 29507}, + {"MOSAICO", 29315}, + {"MTEO", 29014}, + {"Nat Geo Channel", 29034}, + {"NICK-PARAMOUNT", 29312}, + {"RTPI", 9006}, + {"SEASONS", 29204}, + {"TAQUILLA 0", 29205}, + {"TCM.", 28516}, + {"TVC INT.", 29701}, + {"VIAJAR", 29306}, + // Miscellaneous + {"Alice", 12200}, + {"Canal Algerie", 9008}, + {"CANALPRO TV", 8516}, + {"ESC1 - EGYPTE", 9003}, + {"FASHION TV.COM", 17009}, + {"Home Shopping Euro", 45}, + {"Home Shopping Euro", 40}, + {"Kabel 1 Austria", 20004}, + {"Kabel 1 Schweiz", 20003}, + {"Polonia 1/Top Sho", 20366}, + {"ProSieben A", 20002}, + {"ProSieben Schweiz", 20001}, + {"QVC GERMANY", 12100}, + {"RAI 1", 9004}, + {"REAL MADRID TV", 29019}, + {"RealityTV", 20309}, + {"RTL TELE Letzebuerg", 3994}, + {"RTM - MAROC", 9002}, + {"SDWEST BW", 28113}, + {"SDWEST RP", 28231}, + {"Super 1", 20364}, + {"Travel", 28001}, + {"TV7", 9007}, + {"TV-NIEP II", 12740}, + {"Wishline", 12320} }; + + +// Nothing user-configurable below this line. + +static const char date_line[] = "\t<td align=center valign=middle colspan=3><span id=fb-b10>"; +static const char start_time_line[] = " \t\t<td id=\"jobview-box-date\" align=center><nobr> "; +static const char stop_time_line[] = "\t\t\t<tr><td id=\"line\" align=center><span id=\"fn-w9\">bis "; +static const char channel_line[] = "\t\t\t<tr><td align=center><span id=\"fb-w9\">"; +static const char title_line[] = "\t\t\t\t<td align=left width=100%><span id=\"fb-w10\">"; +static const char summary_line[] = "<span id=\"fn-b8\">"; +static const char genre_line[] = "\t\t\t\t<td align=right valign=center nowrap><span id=\"fn-w10\">"; + static const int month_lengths[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -static const int max_channel = sizeof(channel_names)/sizeof(char *); -static const int max_title = 50; // maximum length of title file name generated -static const int max_line = 1024; // line buffer (not used when parsing summary text) -static const int max_summary = 5000; // Summary can be up to 5000 bytes long -static const int stop_time_safety_margin = 10; // add 10 minutes to stop time in case start was delayed @@ -102,6 +386,10 @@ char map_special_char(const char * const word) return ''; else if (strcmp(word, "szlig") == 0) return ''; + else if (strcmp(word, "nbsp") == 0) + return ' '; + else if (strcmp(word, "amp") == 0) + return '&'; return ' '; } @@ -109,40 +397,52 @@ char map_special_char(const char * const word) -void read_file_name(const char * const line, char * const file_name) +void read_file_name_and_title(const char * const line, char * const file_name, char * const title) { int line_index = sizeof(title_line) - 1; int title_index = 0; - char ch = line[line_index++]; + int file_name_index = 0; + char ch; do { + ch = line[line_index++]; if (ch == '&') { char word[10]; int i = 0; while ((line[line_index + i] != ';') && (i < 9)) - word[i++] = line[line_index + i]; - word[i] = 0; - ch = map_special_char(word); - line_index += i; + { + word[i] = line[line_index + i]; i++; + } + if (line[line_index + i] == ';') + { + word[i] = 0; + ch = map_special_char(word); + line_index += i; + } } switch (ch) { - case '': file_name[title_index++] = 'a'; file_name[title_index++] = 'e'; break; - case '': file_name[title_index++] = 'o'; file_name[title_index++] = 'e'; break; - case '': file_name[title_index++] = 'u'; file_name[title_index++] = 'e'; break; - case '': file_name[title_index++] = 'A'; file_name[title_index++] = 'e'; break; - case '': file_name[title_index++] = 'O'; file_name[title_index++] = 'e'; break; - case '': file_name[title_index++] = 'U'; file_name[title_index++] = 'e'; break; - case '': file_name[title_index++] = 's'; file_name[title_index++] = 's'; break; + case '': file_name[file_name_index++] = 'a'; file_name[file_name_index++] = 'e'; break; + case '': file_name[file_name_index++] = 'o'; file_name[file_name_index++] = 'e'; break; + case '': file_name[file_name_index++] = 'u'; file_name[file_name_index++] = 'e'; break; + case '': file_name[file_name_index++] = 'A'; file_name[file_name_index++] = 'e'; break; + case '': file_name[file_name_index++] = 'O'; file_name[file_name_index++] = 'e'; break; + case '': file_name[file_name_index++] = 'U'; file_name[file_name_index++] = 'e'; break; + case '': file_name[file_name_index++] = 's'; file_name[file_name_index++] = 's'; break; + case ' ': file_name[file_name_index++] = '_'; break; + case '&': + file_name[file_name_index++] = 'u'; file_name[file_name_index++] = 'n'; file_name[file_name_index++] = 'd'; + break; default: - if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9'))) - file_name[title_index++] = ch; + if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || (ch == '-')) + file_name[file_name_index++] = ch; } - ch = int(line[line_index++]); - } while ((title_index < max_title-1) && (ch != '<') && (ch != 0) && (line_index < max_line-1)); - file_name[title_index] = 0; + title[title_index++] = ch; + } while ((file_name_index < max_title-5) && (ch != '<') && (ch != 0)); + file_name[file_name_index] = 0; + title[title_index-1] = 0; } @@ -184,7 +484,7 @@ void read_summary(char * const summary) word[word_index++] = ch; } while ((word_index < 6) && (ch != '>') && (ch != EOF)); while ((ch != '>') && (ch != EOF)) ch = getchar(); - if (strncmp("/table", word, 6) == 0) + if (strncmp("/span", word, 4) == 0) done = true; } break; @@ -207,62 +507,150 @@ void read_summary(char * const summary) +int find_channel_number(const unsigned short * const vdr_pnrs, const char * const channel_name) + +{ + for (int tvtv_channel_number = 0; tvtv_channel_number < sizeof(channel_map)/sizeof(map_entry); tvtv_channel_number++) + if (strcmp(channel_name, channel_map[tvtv_channel_number].tvtv_name) == 0) + for (int vdr_channel_number = 0; vdr_pnrs[vdr_channel_number] != 0xFFFF; vdr_channel_number++) + if (vdr_pnrs[vdr_channel_number] == channel_map[tvtv_channel_number].pnr) + return vdr_channel_number; + fprintf(stderr, "Error - channel '%s' not recognized.\n", channel_name); + exit(1); + /*NOTREACHED*/ +} + + -main() +unsigned short * read_vdr_pnrs(const char * const channels_conf_file_name) + { - int channel = 0; + FILE * channels_conf = fopen(channels_conf_file_name, "r"); + if (channels_conf == NULL) + { + perror("unable to open channels.conf."); + exit(1); + } + unsigned short * vdr_pnrs = (unsigned short *) malloc(max_vdr_channel * sizeof(unsigned short)); + int vdr_channel_number = 0; + while (!feof(channels_conf) && (vdr_channel_number < max_vdr_channel-1)) + { + char line[1024]; + fgets(line, sizeof(line)-1, channels_conf); + int pnr; + if ((line[0] != ':') && + (sscanf(line, "%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%d", &pnr) == 1)) + vdr_pnrs[vdr_channel_number++] = pnr; + } + vdr_pnrs[vdr_channel_number++] = 0xFFFF; // sentinel + fprintf(stderr, "%d pnrs.\n", vdr_channel_number); + return (unsigned short *) realloc(vdr_pnrs, vdr_channel_number * sizeof(unsigned short)); +} + + + + +void process_input(const unsigned short * const vdr_pnrs) + +{ + + int channel = -1; int day = -1; int next_day = -1; int start_time = -1; - int stop_time = -1; + int stop_hour = -1; + int stop_minute= -1; + char genre[max_genre] = {0}; char summary[max_summary] = {0}; char file_name[max_title] = {0}; + char title[max_title] = {0}; while (!feof(stdin)) { char line[max_line]; fgets(line, max_line-1, stdin); + line[max_line-1] = 0; if (strncmp(line, date_line, sizeof(date_line)-1) == 0) { const int month = (line[sizeof(date_line) + 6]- '0') * 10 + line[sizeof(date_line) + 7]-'0'; day = (line[sizeof(date_line) + 3]- '0') * 10 + line[sizeof(date_line) + 4]-'0'; - next_day = day == month_lengths[month]? 1 : day + 1; + next_day = day == month_lengths[month-1]? 1 : day + 1; } else if (strncmp(line, start_time_line, sizeof(start_time_line)-1) == 0) - { start_time = (line[sizeof(start_time_line) - 1] - '0') * 1000 + (line[sizeof(start_time_line) ] - '0') * 100 + (line[sizeof(start_time_line) + 2] - '0') * 10 + (line[sizeof(start_time_line) + 3] - '0'); - } else if (strncmp(line, stop_time_line, sizeof(stop_time_line)-1) == 0) { - stop_time = ((line[sizeof(stop_time_line) - 1] - '0') * 1000 + - (line[sizeof(stop_time_line) ] - '0') * 100 + - (line[sizeof(stop_time_line) + 2] - '0') * 10 + - (line[sizeof(stop_time_line) + 3] - '0') + stop_time_safety_margin) % 2400; - if ((day < 0) || (start_time < 0) || (file_name[0] == 0) || (channel == max_channel)) + stop_hour = (line[sizeof(stop_time_line) - 1] - '0') * 10 + + (line[sizeof(stop_time_line) ] - '0'); + stop_minute = (line[sizeof(stop_time_line) + 2] - '0') * 10 + + (line[sizeof(stop_time_line) + 3] - '0') + + stop_time_safety_margin; + if (stop_minute > 59) + { + stop_minute -= 60; + if (stop_hour == 23) + stop_hour = 0; + else + stop_hour++; + } + if ((day < 0) || (start_time < 0) || (file_name[0] == 0) || (channel == -1)) + { fprintf(stderr, "Input data error.\n"); + exit(1); + } else - printf("1:%03d:%02d:%04d:%04d:2:7:%s:%s\n", channel+1, start_time < 600? next_day : day, start_time, stop_time, file_name, summary); - start_time = -1; stop_time = -1; file_name[0] = 0; summary[0] = 0; channel = max_channel; + printf("1:%03d:%02d:%04d:%02d%02d:%d:%d:%s:\"%s\" %s||%s||||||(epg2timers)\n", + channel+1, start_time < 600? next_day : day, start_time, stop_hour, stop_minute, + recording_priority, recording_lifetime, file_name, + title, genre, summary); + start_time = -1; channel = -1; + file_name[0] = 0; summary[0] = 0; genre[0] = 0; } else if (strncmp(line, title_line, sizeof(title_line)-1) == 0) - read_file_name(line, file_name); + read_file_name_and_title(line, file_name, title); else if (strncmp(line, channel_line, sizeof(channel_line)-1) == 0) { int i = sizeof(channel_line); - while ((i < max_line-1) && (line[i] != '<')) i++; + while ((line[i] != '<') && (line[i] != 0)) i++; line[i] = 0; // end of string - for (channel = 0; (channel < max_channel) && - (strcmp(line + sizeof(channel_line) - 1, channel_names[channel]) != 0); - channel++); - if (channel == max_channel) - fprintf(stderr, "Error - channel '%s' not recognized.\n", line + sizeof(channel_line) - 1); + channel = find_channel_number(vdr_pnrs, line + sizeof(channel_line) - 1); } else if (strncmp(line, summary_line, sizeof(summary_line)-1) == 0) read_summary(summary); + else if (strncmp(line, genre_line, sizeof(genre_line)-1) == 0) + { + int genre_index; + for (genre_index = 0; genre_index < max_genre-1; genre_index++) + { + const char ch = line[genre_index + sizeof(genre_line)-1]; + if ((ch == 0) || (ch == '&') || (ch == '<')) + break; + genre[genre_index] = ch; + } + genre[genre_index] = 0; + } } } + + + +main(int argc, char *argv[]) + +{ + fprintf(stderr, "epg2timers Version 0.5, 15-Sep-2001.\n"); + + if (argc != 2) + { + fprintf(stderr, "usage: %s channels.conf\n", argv[0]); + exit(1); + } + + const unsigned short * const vdr_pnrs = read_vdr_pnrs(argv[1]); + process_input(vdr_pnrs); + exit(0); +} diff --git a/Tools/epg2timers/epg_channel_names b/Tools/epg2timers/epg_channel_names new file mode 100644 index 000000000..2633a9909 --- /dev/null +++ b/Tools/epg2timers/epg_channel_names @@ -0,0 +1,400 @@ +ATV,at +ORF1,at +ORF2,at +TW1,at + +Club RTL,be +Ketnet/Canvas,be +TVI,be +tv1,be + +SF1,ch +sf2,ch + +13th Street,de +3sat,de,at,ch +ARD,de +ARTE,de +B1,de +BBC World,de +BEATE-UHSE.TV,de +BR-alpha,de +BR3,de +Bet on Jazz,de +Bloomberg TV,de +Blue Movie1,de +Blue Movie2,de +Blue Movie3,de +CNBC,de +CNN,de +Cartoon,de +Cindedom Deluxe,de +Cinedom 1,de +Cinedom 2,de +Cinedom 3,de +Cinedom 4,de +Cinedom 5,de +Classica,de +DSF,de +Discovery,de +Disney Channel,de +Eins Extra,de +Eins Festival,de +Eins MuXx,de +EuroNews,de +Eurosport,de +FOX KIDS,de +Filmpalast,de +Goldstar TV,de +HH-1,de +HR,de +Heimatkanal,de +Junior,de +K-Toon,de +Kabel 1,de +Kinderkanal,de +Krimi&Co,de +MDR,de +MTV,de +MTV2,de +N24,de +NBC,de +NDR,de +NEUN LIVE,de +ONYX,de +ORB,de +Phoenix,de +Planet,de +Premiere 1,de +Premiere 2,de +Premiere 3,de +Premiere Action,de +Premiere Comedy,de +Premiere SCI-FI,de +Premiere Sport1,de +Premiere Sport2,de +Premiere Sport3,de +Premiere Star,de +Premiere analog,de +ProSieben,de +QVC,de +RTL,de +RTL2,de +SAT.1,de +SR,de +SWR BW,de +SWR RP,de +SeaSonS,de +Studio Universal,de +Sunset,de +Super RTL,de +TNT,de +TRT,de,tr +TV.BERLIN,de +Theaterkanal,de +VIVA,de +VIVA2,de +VOX,de +WDR,de +ZDF,de +ZDF.doku,de +ZDF.info,de +n-tv,de +skynews,de +tv.m,de + +Danmark 1,dk +TV2 Danmark,dk + +MTV3,fi +Nelonen 4,fi +Subtv,fi +TV1,fi +TV2,fi + +13me Rue,fr +AB 1,fr +Arte,fr +Arte Sat,fr +Canal J,fr +Canal Jimmy,fr +Canal+,fr +Canal+ Bel. bleu,fr +Canal+ Bel. jaune,fr +Canal+ Belgique,fr +Canal+ bleu,fr +Canal+ jaune,fr +Canal+ vert,fr +Cin Cinmas 1,fr +Cin Cinmas 2,fr +Cin Cinmas 3,fr +Cin Classics,fr +Cinfaz,fr +Cinstar 1,fr +Cinstar 2,fr +Cintoile,fr +Comdie !,fr +Disney Channel,fr +Escale,fr +Eurosport,fr +Festival,fr +Fox Kids,fr +France 2,fr +France 3,fr +Histoire,fr +LCI,fr +La Cinquime Sat,fr +La chane histoire,fr +La cinquime,fr +M6,fr +M6 Music,fr +MCM,fr +MTV,fr +Mangas,fr +Mezzo,fr +Muzzik,fr +Odysse,fr +Paris Premire,fr +Path sport,fr +Plante,fr +RTBF 1,fr +RTBF 2,fr +RTL 9,fr +Srie Club,fr +TCM,fr +TF1,fr +TMC,fr +TSR 1,fr +TSR 2,fr +TV5,fr +Tltoon,fr +Tva,fr +Voyage,fr +XXL,fr + +ANIMALplanet,hu +Budapest TV,hu +Duna TV,hu +FILMMZEUM,hu +FOX KIDS/SPORTS,hu +FNIX TV,hu +Game Channel,hu +HBO,hu +Hallmark,hu +MAGYAR ATV,hu +Minimax,hu +National Geographic,hu +Nickelodeon,hu +RTL Klub,hu +Romantica,hu +SATeLIT,hu +SPORT1,hu +Spektrum TV,hu +TV2,hu +VIASAT3,hu +VIVA+,hu +fix.tv,hu +m1,hu +m2,hu + ++ Calcio,it ++ F1,it +Adult +,it +CANALE 5,it +Canal Jimmy,it +Canale Viaggi,it +Cartoon Network,it +Cine Classics,it +CineCinemas 1,it +CineCinemas 2,it +Classica,it +Cult Network,it +Discovery Channel,it +Disney Channel,it +Euro News,it +Eurosport,it +Hallmark,it +Happy Channel,it +ITALIA 1,it +La 7,it +MTV,it +MTV - TMC 2,it +Marcopolo,it +Match Music,it +Milan Channel,it +Nuvolari Motor,it +Odeon,it +Planete,it +Primafila,it +RAI 1,it +RAI 2,it +RAI 3,it +RAI Sat Fiction,it +RETE 4,it +Raisat Album,it +Raisat Art,it +Raisat Cinema,it +Raisat Educational,it +Raisat Gambero Rosso,it +Raisat Nettuno 1,it +Raisat Nettuno 2,it +Raisat Ragazzi,it +Raisat Show,it +Raisat Sport,it +SNAI Sat,it +Salute e benessere,it +Sat 2000,it +Satisfation Club TV,it +Seasons,it +Stream Calcio,it +Stream News,it +Studio Universal,it +TSI 1,it +TSI 2,it +TVL,it +Tele+ 16:9,it +Tele+ Bianco,it +Tele+ Grigio,it +Tele+ Nero,it +VIVA - Rete A,it + +Netherland 1,nl +Netherland 2,nl +Netherland 3,nl + +ATV Avrupa,tr +Kanal D,tr +Kral TV,tr +NTV Turkey,tr +Show TV,tr +Star TV,tr + +Adult Channel,uk +Adventure One,uk +Anglia,uk +BBC Choice,uk +BBC Choice NI,uk +BBC Choice Scotland,uk +BBC Choice Wales,uk +BBC Knowledge,uk +BBC News 24,uk +BBC Parliament,uk +BBC Prime,uk +BBC World,uk +BBC1,uk +BBC1 North. Ireland,uk +BBC1 Scotland,uk +BBC1 Wales,uk +BBC2,uk +BBC2 North. Ireland,uk +BBC2 Scotland,uk +BBC2 Wales,uk +Bangla TV,uk +Bloomberg TV,uk +Border,uk +Bravo (Analogue),uk +Bravo (Digital),uk +British Eurosport,uk +CNBC Europe,uk +CNN,uk +Carlton Central,uk +Carlton Cinema,uk +Carlton Food,uk +Carlton Westcountry,uk +Carlton/LWT,uk +Cartoon Network,uk +Challenge TV,uk +Channel 4,uk +Channel 5,uk +Channel Television,uk +Disc. Animal Planet,uk +Disc. Channel (Ana.),uk +Disc. Civilisations,uk +Disc. Home Leisure,uk +Disc. Sci-Trek,uk +Disc. Travel Advent.,uk +Discovery Channel,uk +Discovery Kids,uk +Discovery Wings,uk +Disney,uk +Euronews,uk +Fantasy Ch. Dig.,uk +Fantasy Channel,uk +Film Four,uk +Fox Kids,uk +Grampian,uk +Granada,uk +Granada Breeze,uk +Granada Men & Motors,uk +Granada Plus,uk +HTV Wales,uk +HTV West,uk +Hallmark,uk +History Channel,uk +ITN News Channel,uk +ITV Sport Channel,uk +ITV Sport Plus,uk +ITV2,uk +Landscape,uk +Living,uk +MTV UK,uk +MUTV,uk +Meridian,uk +National Geographic,uk +Network 2,uk +Nick Junior,uk +Nick Junior Analogue,uk +Nickelodeon (dig.),uk +Nickleodeon (ana.),uk +Pakistani Channel,uk +Paramount Comedy,uk +Performance,uk +Play UK,uk +Playboy TV,uk +QVC,uk +RTE1,uk +Racing Channel,uk +Rapture TV,uk +S2,uk +S4C,uk +S4C digidol,uk +SKY Cinema,uk +SKY Movie Max(SDig.),uk +SKY Movie Max(ana.),uk +SKY News,uk +SKY Premier(Digital),uk +SKY Premier(OnDigi),uk +SKY Sports 1,uk +SKY Sports 2,uk +SKY Sports 3,uk +Sci-Fi Cable,uk +Sci-Fi Satelite,uk +Scottish,uk +Screenshop,uk +Shop!,uk +Sky Movie Max(OnDig),uk +Sky One,uk +Sky One (OnDigital),uk +Sky Premier(Ana.),uk +Sky Sports .com,uk +Sky Sports Extra,uk +Sky Travel,uk +Sony Entertainment,uk +TCM,uk +TCM (Analogue),uk +TG4,uk +TV3,uk +Tara Television,uk +The Box,uk +Trouble Analogue,uk +Trouble Digital,uk +Tyne Tees Television,uk +UK Drama,uk +UK Gold,uk +UK Gold 2,uk +UK Horizons,uk +UK Style,uk +Ulster ,uk +VH1,uk +Yorkshire,uk +Zee TV,uk diff --git a/Tools/epg2timers/get_merkliste.pl b/Tools/epg2timers/get_merkliste.pl new file mode 100755 index 000000000..bb23fa3b2 --- /dev/null +++ b/Tools/epg2timers/get_merkliste.pl @@ -0,0 +1,82 @@ +#!/usr/bin/perl +# Create a user agent object + +use HTML::Entities; +use HTML::Parser; +use LWP::UserAgent; +use IO::Handle; + +STDOUT->autoflush(1); + +$ua = new LWP::UserAgent; +$ua->agent("Mozilla/9.1 " . $ua->agent); +# $ua->proxy('http', 'http://localhost:8080/'); + +$filename = "merkliste.html"; +$base_url = "http://www.tvtv.de"; +# Hier das Bookmark von TVTV eintragen: +@files_to_fetch = ("/cgi-bin/bookmark.cgi?id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + +$num = 0; +$state = 0; + +$p = HTML::Parser->new( api_version => 3, + start_h => [\&fparser_start, "tagname, attr"], + unbroken_text => 1 ); + +foreach $url (@files_to_fetch) { + $nurl = $base_url . $url; + print "Getting " . $nurl . "...\n"; + $req = new HTTP::Request GET => $nurl; + $res = $ua->request($req); + if ($res->is_success) { + open (OUTFILE, ">" . $filename); + print OUTFILE $res->content; + close (OUTFILE); + $p->parse ($res->content); + $p->eof; + } else { + print "...FAILED\n"; + } +} +# Zielordner fuer die Speicherung der Merkliste: + +print "...saved to 'merkliste.html'\n"; +sub fparser_start { + my($tagname, $attr_t) = @_; + my(%attr) = %$attr_t; + + if ($tagname eq "frame") { + if ($state == 1) { + if (($attr{name} eq "frame_main") || + ($attr{name} eq "frame_nav") || + ($attr{name} eq "frame_nav_bottom")) { + push @files_to_fetch, $attr{src}; + } + } + if ($state == 2) { + if (($attr{name} eq "frame_content")) { + push @files_to_fetch, $attr{src}; + } + } + } + if ($tagname eq "a") { + if ($attr{href} ne "") { + $last_href = $attr{href}; + if ($state == 0) { + push @files_to_fetch, $last_href; + $state = 1; + } + } + } + if ($tagname eq "img") { + if ($state == 1) { + if ($attr{src} =~ /b_joblist/i) { + $state = 2; + push @files_to_fetch, $last_href; + } + } + } +} + + diff --git a/Tools/epg2timers/loadvdr.pl b/Tools/epg2timers/loadvdr.pl new file mode 100755 index 000000000..485b0a4a5 --- /dev/null +++ b/Tools/epg2timers/loadvdr.pl @@ -0,0 +1,89 @@ +#!/usr/bin/perl +# +# 0.01 loadvdr (peter) +# 0.02 delete old entries before updating (peter) +# 0.03 dumped Net::Telnet because of lost connections +# +# please submit diffs to petera@gmx.net +# +# ./epg2timers < merkliste.html | perl -w loadvdr.pl +# +# + +use Socket; +use Getopt::Std; + +@resp = (); + +$Dest = "localhost"; +$Port = 2001; + +$Timeout = 10; # max. seconds to wait for response + +$SIG{ALRM} = sub { Error("timeout"); }; +alarm($Timeout); + +$iaddr = inet_aton($Dest) || Error("no host: $Dest"); +$paddr = sockaddr_in($Port, $iaddr); + +$proto = getprotobyname('tcp'); +socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!"); +connect(SOCK, $paddr) || Error("connect: $!"); +select(SOCK); $| = 1; +Receive_void(); + +Send("lstt"); + +foreach $item (reverse @resp){ + if ($item =~ /^250.(\d{1,2}).*\(epg2timers\)/) { + Send_void("DELT $1"); + } +} + +while (defined ($line = <STDIN>)) { + chomp $line; + Send_void("UPDT $line"); +} + +Send("quit"); +close(SOCK) || Error("close: $!"); + + + +sub Send +{ + my $cmd = shift || Error("no command to send"); + print SOCK "$cmd\r\n"; + Receive(); +} + +sub Send_void +{ + my $cmd = $_[0]; + print SOCK "$cmd\r\n"; + Receive_void(); +} + +sub Receive +{ + while (<SOCK>) { + chomp; + push @resp,$_; + last if substr($_, 3, 1) ne "-"; + } +} + +sub Receive_void +{ + while (<SOCK>) { + last if substr($_, 3, 1) ne "-"; + } +} + +sub Error +{ + print STDERR "@_\n"; + close(SOCK); + exit 0; +} + diff --git a/Tools/epg2timers/update_timers b/Tools/epg2timers/update_timers new file mode 100755 index 000000000..3849841b6 --- /dev/null +++ b/Tools/epg2timers/update_timers @@ -0,0 +1,22 @@ +#!/bin/sh + +# update_timers: retrieve a new "merkliste" from http://tvtv.de, +# convert it to vdr format and transmit it to vdr via SVDRP. + +TOOLDIR="/home/cko/bin" +CHANPATH="/home/cko/VDR/channels.conf" + +cd /tmp +rm -f merkliste.html + +# if you have a slow dial up connection to your name server and/or ISP, +# this will avoid a timeout in get_merkliste.pl. +ping -c 2 www.tvtv.de + +# get the "merkliste". +$TOOLDIR/get_merkliste.pl + +if [ -s merkliste.html ] ; then + # convert merkliste.html to timers.conf format and transmit it to vdr. + $TOOLDIR/epg2timers $CHANPATH < merkliste.html | $TOOLDIR/loadvdr.pl +fi diff --git a/Tools/epg2timers/update_timers.old b/Tools/epg2timers/update_timers.old new file mode 100755 index 000000000..c4c3f5c5e --- /dev/null +++ b/Tools/epg2timers/update_timers.old @@ -0,0 +1,24 @@ +#!/bin/sh + +# update_timers: load a new "merkliste" from http://tvtv.de +# and create a new VDR timer configuration file (timers.conf) +# from it. Restart VDR if the timers have changed. + +TOOLDIR="/home/cko/bin" +VDRDIR="/home/cko/VDR" + +cd /tmp +rm -f merkliste.html epgtimers.new epgtimers.old vdrtimers.old +ping -c 2 www.tvtv.de +$TOOLDIR/get_merkliste.pl +if [ -s merkliste.html ] ; then + $TOOLDIR/epg2timers $VDRDIR/channels.conf < merkliste.html | sort -t: +2.0 -5.0 > epgtimers.new + fgrep '(epg2timers)' $VDRDIR/timers.conf | sort -t: +2.0 -5.0 > epgtimers.old + if ! cmp -s epgtimers.old epgtimers.new ; then + /sbin/killproc $VDRDIR/vdr + fgrep -v '(epg2timers)' $VDRDIR/timers.conf > vdrtimers.old + cat epgtimers.new vdrtimers.old | sort -t: +2.0 -5.0 > $VDRDIR/timers.conf + echo "Timers updated." + fi +fi +rm -f merkliste.html epgtimers.new epgtimers.old vdrtimers.old diff --git a/Tools/master-timer/LIESMICH b/Tools/master-timer/LIESMICH index 969487507..8e53da955 100644 --- a/Tools/master-timer/LIESMICH +++ b/Tools/master-timer/LIESMICH @@ -1,106 +1,70 @@ - Master-Timer - ============ +Master-Timer +============ +(w) by Matthias Schniedermeyer (ms@citd.de) 1. Einleitung ------------- Master-Timer ist ein System zum automatischen Aufnehmen von Serien und Filmen. +Beim Aufruf werden die Konfigurationsdateien gelesen, die Datei "epg.data" im +aktuellen Verzeichnis nach passenden Sendungen durchsucht und die ermittelten +Timer per SVDRP in VDR programmiert. Danach beendet sich Master-Timer. -2. Voraussetzungen ------------------- +Entsprechend empfiehlt es sich, Master-Timer per cronjob aufzurufen. -VDR liefert die "epg.data". - -3. Konfigurationsdateien +2. Konfigurationsdateien ------------------------ -Alle Konfigurationsdateien liegen unter "<HOME>.master-timer" - -config: Eine Ansammlung von Key-Value Paaren. Alle sind "optional" und - erhalten dann die angegebenen Default-Werte - -(# = Kommentarzeilen) -marginstart (Default 600) - Anzahl der "Sicherheits" Sekunden die ein Timer frueher beginnen soll - -marginstop (Default 600) - Anzahl der "Sicherheits" Sekunden die ein Timer laenger dauern soll - -defaultprio (Default 50) - Die Prioritaet die fuer Timer verwendet wird wo keine Prioritaet - angegeben ist - -DVBCards (Default 1) - Anzahl der vorhandenen DVB-Karten (Derzeit nicht verwendet) - -Dest-Host (Default "localhost") - Host-name oder IP des Rechners auf dem VDR laeuft - -Dest-Port (Default "2001") - Port der VDR verwendet - -jointimers (Default 0) - Sollen aufeinanderfolgende Timer auf den gleichen Kanal zusammengefasst - werden (0 = "Nein", alles andere "Ja") - -debug (Default 0) - Debug-Level, die einzelnen Debug-Werte muessen aus folgenden Werten - zusammengezaehlt werden - 1 : Dump "torecord" - 2 : Dump all timers - 4 : Show when a timer will be deleted - 8 : Dump the "Done" REs - 16 : Verbose Config-Reading - -deepblack: Eine Liste von Titeln die man NIEMALS NIMMER sehen will - Jede Zeile = 1 Titel - -subtitle-movies: Eine Liste der "Subtitel" die ein Zeichen fuer einen Film sind - (Soweit die von den Sendern richtig ausgefuellt sind.) - Jede Zeile = 1 Subtitel - -torecord: Die Sachen die man Aufnehmen will - Jede Zeile = 1 Timer -# Format: (Every field is "optional". -# [Title RE|Subtitle RE|Description RE|Channel-Name|Timeframe|Prio|Timer-Title] -# -# To record something at least one of the "Title", "Subtitle" or "Description" -# Fields has to be provided. This 3 fields are "include" and the rest are -# "exclude" fields! -# -# More than one channel definition can be provided. The delimiter is ";" -# Additionaly you can make a "blacklist" of Channels when you prepent a "!" to the first Channel Definition -# The "!" is only tested for the FIRST Channel definition. -# You can only have a white or a blacklist (Mixing doesn't make sense!) -# -# ex. Record the series "Deep Space Nine" on Sci-Fantasy in the timeframe 09:00 - 14:00 -# Deep Space Nine|||Sci-Fantasy|0900-1400|99|DS9 -# -# Record all "Actionfilm"s with "Schwarzenegger" -# |Actionfilm|Schwarzenegger -# - - -done: The titles/subtitles which are already recorded/should not be recorded - (Programmed Timers which got inserted into "done" will be deleted - automaticaly) - -4. Notices ----------- - -- Recordings "overlapping" on the same channel, will be joined into one Timer -- Title/Subtitle/Descriptions are "fixed" for Channel that don't fill them - out "correctly" (Currently the "Bugs" from Pro-7/VOX/VIVA) - Pro7: Remove the Title from the Subtitle '<Title> / <Subtitle>' - VOX/VIVA: Subtitle is enclosed into "" and after ". " is the description - VIVA: When the Subtitle beginns with space the subtitle is moved to - description - All (except the second VIVA one) fixes are tried onto ALL Subtitles. - -5. Known-Bugs -------------- +Alle Konfigurationsdateien liegen unter "~/.master-timer". Es werden +regulaere Ausdruecke ohne Unterscheidung der Gross-/Kleinschreibung +benutzt. + +config: Die Hauptkonfigurationsdatei. + +deepblack: Eine Negativliste von Titeln, die man NIEMALS NIMMER sehen will. + Die epg-datensaetze werden beim Parsen einfach entfernt. + +subtitle-movies: Eine Liste der "Subtitel", die ein Zeichen fuer einen Film + sind (soweit die von den Sendern richtig ausgefuellt sind). Die + Einstellungen in dieser Datei werden fuer das Makro "MOVIE" in torecord + benutzt. + Kommentarzeilen sind nicht erlaubt. + +torecord: Liste der aufzunehmenden Filme. + +done: Liste der Titel/Subtitel, die bereits aufgenommen wurden. Timer, die + hier auftauchen, werden in VDR automatisch geloescht. + +channels-to-scan: Diese Kanaele werden vom Skript "scan-channels" durch- + geschaltet (zwecks Einlesen der EPG-Daten). Die Datei wird von Master- + Timer selbst nicht benutzt. + +3. Anmerkungen +-------------- + +- einige Sender fuellen die EPG-Felder nicht korrekt aus. Diese Fehler + werden von Master-Timer automatisch korrigiert. + + Pro7: Title aus dem Subtitle entfernen '<Title> / <Subtitle>' + Pro7: Timer zwischen 00:00 und 05:00 werden einen Tag in die Zukunft + verschoben (Als unguten Nebeneffekt hat dies zur Folge das zum + aktuellen Tag NICHT die epg-Daten das folgenden Tags (=Das was in + der Fernsehzeitschrift noch auf der gleichen Seite ist) mehr gesendet + werden. Wenn man also "Last Minute" etwas aufnehmen will, dann muss + man (leider) einen Timer "per Hand" in VDR einprogrammieren!) + VOX/VIVA: Subtitle ist in "" eingeschlossen nd nach ". " steht die description + VIVA: Wenn der Subtitle mit einem Space beginnt, dann wird der komplette + Subtitle in die Description verschoben + RTL2: Wenn der EPG-Datensatz eine Dauer von kleiner/gleich 1 Sekunde hat, + wird er einfach verworfen. + +Bis auf den jeweils 2ten VIVA&Pro-7 Bug werden die Fixes an jedem +epg-Datensatz ausprobiert. + +4. Bekannte Bugs +---------------- -- It isn't checked if there are enough DVB-Cards -- Overlapping Timers, on the same channel, are always joined -- JOINed timers which are "done" don't get deleted automaticaly +- Es wird nicht geprueft ob noch genug DVB-Karten vorhanden sind +- "Joined timers" werden nur automatisch geloescht wenn alle dazugehoerigen + Sendungen "done" sind. diff --git a/Tools/master-timer/README b/Tools/master-timer/README index c71e6e185..05cc41acc 100644 --- a/Tools/master-timer/README +++ b/Tools/master-timer/README @@ -1,43 +1,49 @@ - Master-Timer (w) by Matthias Schniedermeyer (ms@citd.de) - ============ +Master-Timer +============ +(w) by Matthias Schniedermeyer (ms@citd.de) 1. Introduction --------------- -Master-Timer ist a system for recording Films/Series automaticaly +Master-Timer is a system designed for automatically recording movies. +Upon execution it reads its configuration files, scans the file "epg.data" +in the current directory for matching titles and programs them via SVDRP +into VDR. -2. Requierements ----------------- +You may for example run Master-Timer as a cron job. -epg.data - -3. Config-Files +2. Config files --------------- -For all files: One Entry per Line. Each line is a "Regular Expresion" - So you can use all Perl-Style REs you want. - The RE are matched with "i" so they are case insensitive! - (Except for the "done"-list, these must match excatly!) +Configuration files are located in "~/.master-timer". Each entry is a +regular expression so you can use all Perl style REs you want. They are +processed case insensitive. + +config: Main configuration file. -deepblack: Blacklist of "Titles" you NEVER EVER want to get to you eyes +deepblack: Blacklist of "titles" you NEVER EVER want to see. -subtitle-movies: A list of "Subtitles" which indicate a movie. - (For Channels that correctly fill out the Subtitle. - e.g. it won't work for *eRTL*) +subtitle-movies: A list of "Subtitles" which indicate a movie (used + by the "MOVIE" macro in torecord). + For channels that correctly fill out the subtitle e.g. it will not + work with *eRTL*. -torecord: The titles/subtitles/Description you want to record +torecord: The titles you want to record. done: The titles/subtitles which are already recorded/should not be recorded - (Programmed Timers which got inserted into "done" will be deleted - automaticaly) + Programmed timers which got inserted into "done" will be deleted + automatically. + +channels-to-scan: Used only by the separate "scan-channels" script which + switches through channels in order to get EPG data. 4. Notices ---------- -- Recordings "overlapping" on the same channel, will be joined into one Timer -- Title/Subtitle/Descriptions are "fixed" for Channel that don't fill them - out "correctly" (Currently the "Bugs" from Pro-7/VOX/VIVA) +- Recordings overlapping on the same channel will be joined into one timer +- Title/Subtitle/Descriptions are "fixed" for channels that don't fill them + out correctly (Pro-7/VOX/VIVA) Pro7: Remove the Title from the Subtitle '<Title> / <Subtitle>' VOX/VIVA: Subtitle is enclosed into "" and after ". " is the description VIVA: When the Subtitle beginns with space the subtitle is moved to @@ -48,5 +54,5 @@ done: The titles/subtitles which are already recorded/should not be recorded ------------- - It isn't checked if there are enough DVB-Cards -- Overlapping Timers, on the same channel, are always joined -- JOINed timers which are "done" don't get deleted automaticaly +- Overlapping timers on the same channel are always joined +- Joined timers which are "done" don't get deleted automatically diff --git a/Tools/master-timer/THANKS b/Tools/master-timer/THANKS new file mode 100644 index 000000000..04bb13bad --- /dev/null +++ b/Tools/master-timer/THANKS @@ -0,0 +1,18 @@ +Klaus Schmidinger + - VDR + +Malte Kiesel + - Suggestions + - Bug Reports + - Documentation Updates for README/LIESMICH/torecord/deepblack/config + +Guido Fiala + - Suggestions + - Bug Repots + - finding bugs i found just before i read that part of his mails + (First the bug, then the errormessages! Otherwise i will search/find + the bug myself :-))) ) + +Axel Gruber + - Suggestions + - Bug Reports diff --git a/Tools/master-timer/Todo b/Tools/master-timer/Todo index 722ee969c..1757ade08 100644 --- a/Tools/master-timer/Todo +++ b/Tools/master-timer/Todo @@ -1,9 +1,5 @@ -- "Intelligenter" Kanal-Scanner (z.B. nur 1 Kanal fuer ein - Sender-"Gruppe") -- Filtern nach Serie/Film - "Komfortable" Anzeige, mit Black & Whitelisten, fuer Genres/Titeln usw. -- Unterstueztung von 1xVDR pro Karte - Abspielen (mit automatischen "killen" des "Frontend"-VDRs) von Aufzeichnungen - "View"-Timer d.h. Timer der nicht Aufnimmt sondern nur den Kanal aendert diff --git a/Tools/master-timer/convert-DTV2VDR.pl b/Tools/master-timer/convert-DTV2VDR.pl new file mode 100755 index 000000000..fb2a78310 --- /dev/null +++ b/Tools/master-timer/convert-DTV2VDR.pl @@ -0,0 +1,151 @@ +#!/usr/bin/perl -w + +use strict; + +# The EPG-Entrys +my (%Entry, %channel, $mode); + +# 0 = VDR -> DTV +# 1 = DTV -> VDR +$mode = 0; + +read_channel_list(); +if ($mode) { + &read_dtv(); + &read_epgdata(); +} else { + &read_epgdata(); + &read_dtv(); +} +&print_VDR(); + +sub read_epgdata { + my ($channel, $duration, $title, $subtitle, $description, $time); + open (FI,"epg.data") or die ("Can't open file \"epg.data\"\n"); + + while (<FI>) { + # Begin Channel + if (/^C\s(\d+)\s+(.+)/) { + $channel=$2; + while (<FI>) { + # End Channel + if (/^c$/) { + last; + } + # Begin Timer + elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/) { + # Undef this Variables because it is possibel that not every timer uses this values + undef $duration; + undef $subtitle; + undef $description; + + $time=$2; + $duration=$3; + } + # Title + elsif (/^T\s(.*)/) { + $title=$1; + } + # Subtitle + elsif (/^S\s(.*)/) { + $subtitle=$1; + } + # Description + elsif (/^D\s(.*)/) { + $description=$1; + } + # End Timer + elsif (/^e$/) { + if ($mode) { + # DTV -> VDR + $Entry{$channel}{$time}{subtitle}=$subtitle if ($subtitle); + if ($description) { + if ($Entry{$channel}{$time}{description}) { + $Entry{$channel}{$time}{description} = "DTV: '$Entry{$channel}{$time}{description}' VDR: '$description'"; + } else { + $Entry{$channel}{$time}{description} = "DTV: '' VDR: '$description'"; + } + } + } else { + # VDR -> DTV + $Entry{$channel}{$time}{title}=$title; + $Entry{$channel}{$time}{duration}=$duration; + $Entry{$channel}{$time}{subtitle}=$subtitle if ($subtitle); + $Entry{$channel}{$time}{description}=$description if ($description); + } + } + } + } + } + close (FI); +} + +sub read_dtv { + my ($channel, $time, $duration, $title, $category, $subtitle, $description); + open (FI,$ARGV[0]) or die "Can't open DTV-File"; + + while (<FI>) { + chomp; + ($channel, $time, $duration, $title, $category, $subtitle, $description) = split (/\|/); + if (!$channel{$channel}) { + next; + } + $channel = $channel{$channel}; + if ($mode) { + # DTV -> VDR + if (!$subtitle && $description =~ /^\"(.*?)\"\:\s(.*)/) { + $Entry{$channel}{$time}{subtitle} = $1; + $description = $2; + } + $Entry{$channel}{$time}{title} = $title; + $Entry{$channel}{$time}{duration} = $duration; + $Entry{$channel}{$time}{subtitle} = $subtitle if ($subtitle); + $Entry{$channel}{$time}{category} = $category if ($category); + $Entry{$channel}{$time}{description} = $description if ($description); + } else { + # VDR -> DTV + $Entry{$channel}{$time}{category} = $category if ($category); + if ($description) { + if (!$Entry{$channel}{$time}{subtitle} && $description =~ /^\"(.*?)\"\:\s(.*)/) { + $Entry{$channel}{$time}{subtitle} = $1; + $description = $2; + } + if ($Entry{$channel}{$time}{description}) { + $Entry{$channel}{$time}{description} = "DTV: '$description' VDR: '$Entry{$channel}{$time}{description}'"; + } else { + $Entry{$channel}{$time}{description} = "DTV: '$description' VDR: ''"; + } + } + } + } + close (FI); +} + +sub read_channel_list { + my ($old, $new); + open (FI,"$ENV{HOME}/.master-timer/convert-channel-list") or die ("Can't read channel-List"); + while (<FI>) { + chomp; + ($old, $new) = split (/\|/); + $channel{$old} = $new; + } + close (FI); +} + +sub print_VDR() { + my ($channel, $title, $time); + foreach $channel (sort keys %Entry) { + print "C 1 $channel\n"; + foreach $time (sort keys %{%Entry->{$channel}}) { + if ($Entry{$channel}{$time}{duration}) { + print "E 1 $time $Entry{$channel}{$time}{duration}\n"; + print "K $Entry{$channel}{$time}{category}\n" if ($Entry{$channel}{$time}{category}); + print "T $Entry{$channel}{$time}{title}\n"; + print "S $Entry{$channel}{$time}{subtitle}\n" if ($Entry{$channel}{$time}{subtitle}); + print "D $Entry{$channel}{$time}{description}\n" if ($Entry{$channel}{$time}{description}); + print "e\n"; + } + } + print "c\n"; + } +} diff --git a/Tools/master-timer/convert-oldtorecord.pl b/Tools/master-timer/convert-oldtorecord.pl new file mode 100755 index 000000000..853c20bab --- /dev/null +++ b/Tools/master-timer/convert-oldtorecord.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl + +while (<>) + { + chomp; + if ($_ && !(/^\#/)) + { + ($title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine) = split (/\|/,$_); + + if ($timer_title) { + print "[$timer_title]\n"; + } elsif ($title) { + print "[$title]\n"; + } elsif ($subtitle) { + print "[$subtitle]\n"; + } elsif ($description) { + print "[$description]\n"; + } else { + die ("Illegal Format"); + } + + # Accept torecord only if it is for the current machine + if ($title) + { + print "Title = $title\n"; + } + if ($subtitle) + { + print "Subtitle = $subtitle\n"; + } + if ($description) + { + print "Description = $description\n"; + } + if ($channel) + { + print "Channel = $channel\n"; + } + if ($timeframe) + { + print "Timeframe = $timeframe\n"; + } + if ($prio) + { + print "Prio = $prio\n"; + } + if ($timer_title) + { + print "Timertitle = $timer_title\n"; + } + if ($margin) + { + print "Margin = $margin\n"; + } + if ($machine) + { + print "Instance = $machine\n"; + } + print "\n"; + } + } diff --git a/Tools/master-timer/master-timer.pl b/Tools/master-timer/master-timer.pl index 3b98acc8d..5ddf90940 100755 --- a/Tools/master-timer/master-timer.pl +++ b/Tools/master-timer/master-timer.pl @@ -5,6 +5,8 @@ use Socket; # For converting the Timers, read from VDR, back to Unix-Timestamps use Time::Local; +# For parsing the command line +use Getopt::Std; # Debugmode # You have to add the following numbers to build the debug-var @@ -13,7 +15,9 @@ # 4 : Show when a timer will be deleted # 8 : Dump the "Done" REs # 16 : Verbose Config-Reading -my $debug = 0; +# 32 : Dump Program Variable +# 64 : Excessive deepblack/torecord debuging +my $debug = 6; # The Supervariable Program # %Program{$title}{$channel}{$time}{duration} @@ -23,26 +27,51 @@ # The Supervariable Timer # %Timer{$time}{$channel}{$title}{duration} # {subtitle} +# {description} # {prio} +# {lifetime} # {real_title} # {VDR} (Already programmed) # The Value of VDR is ">0" for the position in the Timer-List or "R" for a "Repeating" Timer. # A Value of >1.000.000 is a Master Timer-Timer which is already programmed into VDR +# The Supervariable torecord/deepblack +# $torecord{timercount} +# {titleRE} +# {subtitleRE} +# {descriptionRE} +# {title}[COUNT] +# {subtitle}[COUNT] +# {description}[COUNT] +# {timeframe}[COUNT] +# {blackchannel}[COUNT] or {channel}[COUNT] +# {weekday}[COUNT] +# {minlength}[COUNT] +# {maxlength}[COUNT] +# {prio}[COUNT] +# {timertitle}[COUNT] +# {marginstart}[COUNT] +# {marginstop}[COUNT] +# {instance}[COUNT] + # Variable-Definition my (%Program, @channels, %channels, %Timer); # Which Subtitles are Movies my ($subtitle_movie); +my ($test_subtitle_movie); # Blacklist -my ($title_deepblack); +my (%deepblack); # What is already recorded/Should not be recorded my ($title_done, $subtitle_done); # What to record -my ($title_torecord, $subtitle_torecord, $description_torecord, @title_torecord, @subtitle_torecord, @description_torecord, @channel_torecord, @timeframe_torecord, @prio_torecord, @timer_title_torecord, $num_torecord, @marginstart_torecord, @marginstop_torecord, @machine_torecord); +my (%torecord); + +# The Commandline +my (%Opts); # Default Priority for Timers (Config: defaultprio) my $default_prio = 50; @@ -63,1107 +92,1321 @@ # Which VDR-Instance shall be used my $currentVDR = 1; -# Working-Variables -my ($title, $duration, $subtitle, $channel, $time, $description, $hit); -my (@time, @date); +# Where are the Config-Files +my $configdir = "$ENV{HOME}/.master-timer"; -sub sub_die - { - my ($error) = @_; - &closesocket(); - die "$error"; - } +# Should the description be transfered to VDR? +my $Description = 0; +# Working-Variables +my ($title, $duration, $subtitle, $channel, $time, $description, $category, $hit); +my (@time, @date); -if ($ARGV[0]) - { - $currentVDR = $ARGV[0]; - } +END { + &closesocket(); +} &init(); &dumpdone() if ($debug & 8); -&dumptorecord() if ($debug & 1); +&dumptorecord("torecord") if ($debug & 1); +&dumptorecord("deepblack") if ($debug & 1); +print "Subtitle-Movie \"$subtitle_movie\"\n" if($debug & 1); +# If we only have to dump the running series then exit after dumping them +if ($Opts{s}) { + &dumpepgdata; + exit 0; +} +&processdone(); &fetchVDRTimers(); &process_torecord(); print "Timers before joining\n" if ($debug & 2 && $jointimers); &dumptimers() if ($debug & 2); -if ($jointimers) - { - &jointimers(); - print "Timers after joining\n" if ($debug & 2); - &dumptimers() if ($debug & 2); - } + +if ($jointimers) { + &jointimers(); + print "Timers after joining\n" if ($debug & 2); + &dumptimers() if ($debug & 2); +} + +&dumpepgdata if ($debug & 32); &printtimers(); &transfertimers(); -&closesocket(); + +# +# End of Program +# # # Subfunctions # -sub dumpdone() - { - print "Start Done-dump\n"; - print "Titledone: \"$title_done\"\n"; - print "Subtitledone \"$subtitle_done\"\n"; - print "End Done-dump\n"; +sub dumpdone() { + print "Start Done-dump\n"; + print "Titledone: \"$title_done\"\n"; + print "Subtitledone \"$subtitle_done\"\n"; + print "End Done-dump\n"; +} + +sub dumpepgdata () { + print "Start EPG-Dump\n"; + foreach $title (sort keys %Program) { + foreach $channel (sort keys %{%Program->{$title}}) { + foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}}) { + print "Title: \"$title\" "; + if (!$Opts{s}) { + print "Subtitle: \"$Program{$title}{$channel}{$time}{subtitle}\" " if ($Program{$title}{$channel}{$time}{subtitle}); + print "Time: \"$time\""; + } + print "Channel: \"$channel\""; + print "\n"; + if ($Opts{s}) { + last; + } + } + } + } + print "End EPG-Dump\n"; +} + + +sub dumptorecord() { + my ($context) = shift; + my ($rContext); + + if ($context eq "torecord") { + $rContext = \%torecord; + } elsif ($context eq "deepblack") { + $rContext = \%deepblack; + } else { + die ("Illegal Context"); } -sub dumptorecord() - { - print "Start Torecord-dump\n"; - print "Regex-Title: $title_torecord\n"; - print "Regex-Subtitle: $subtitle_torecord\n"; - print "Regex-Description: $description_torecord\n"; - foreach my $num (0 .. $num_torecord) - { - print "Timer Number $num: "; - - print "Title: \"$title_torecord[$num]\" " if ($title_torecord[$num]); - print "Title: \"\" " unless ($title_torecord[$num]); - - print "Subtitle: \"$subtitle_torecord[$num]\" "if ($subtitle_torecord[$num]); - print "Subtitle: \"\" " unless ($subtitle_torecord[$num]); + print "Start $context-dump\n"; + print "Regex-Title: $$rContext{titleRE}\n"; + print "Regex-Subtitle: $$rContext{subtitleRE}\n"; + print "Regex-Description: $$rContext{descriptionRE}\n"; + foreach my $num (0 .. $$rContext{timercount}) { + print "Entry Number $num: "; + + print "Title: \"$$rContext{title}[$num]\" " if ($$rContext{title}[$num]); + print "Title: \"\" " unless ($$rContext{title}[$num]); + + print "Subtitle: \"$$rContext{subtitle}[$num]\" "if ($$rContext{subtitle}[$num]); + print "Subtitle: \"\" " unless ($$rContext{subtitle}[$num]); + + print "Description: \"$$rContext{description}[$num]\" " if ($$rContext{description}[$num]); + print "Description: \"\" " unless ($$rContext{description}[$num]); + + print "Category: \"$$rContext{category}[$num]\" " if ($$rContext{category}[$num]); + print "Category: \"\" " unless ($$rContext{category}[$num]); - print "Description: \"$description_torecord[$num]\" " if ($description_torecord[$num]); - print "Description: \"\" " unless ($description_torecord[$num]); + print "Timeframe: \"$$rContext{timeframe}[$num]\" " if ($$rContext{timeframe}[$num]); + print "Timeframe: \"\" " unless ($$rContext{timeframe}[$num]); - print "Timeframe: \"$timeframe_torecord[$num]\" " if ($timeframe_torecord[$num]); - print "Timeframe: \"\" " unless ($timeframe_torecord[$num]); + print "Weekday: \"$$rContext{weekday}[$num]\" " if ($$rContext{weekday}[$num]); + print "Weekday: \"\" " unless ($$rContext{weekday}[$num]); - print "Channel: \"". join (";",@{$channel_torecord[$num]})."\" " if ($channel_torecord[$num]); - print "Channel: \"\" " unless ($channel_torecord[$num]); + print "Channel: \"$$rContext{channel}[$num]\" " if ($$rContext{channel}[$num]); + print "Channel: \"\" " unless ($$rContext{channel}[$num]); - print "Prio: \"$prio_torecord[$num]\" " if ($prio_torecord[$num]); - print "Prio: \"\" " unless ($prio_torecord[$num]); + print "Blackchannel: \"$$rContext{blackchannel}[$num]\" " if ($$rContext{blackchannel}[$num]); + print "Blackchannel: \"\" " unless ($$rContext{blackchannel}[$num]); - print "Timertitle: \"$timer_title_torecord[$num]\" " if ($timer_title_torecord[$num]); - print "Timertitle: \"\" " unless ($timer_title_torecord[$num]); + print "Prio: \"$$rContext{prio}[$num]\" " if ($$rContext{prio}[$num]); + print "Prio: \"\" " unless ($$rContext{prio}[$num]); + + print "Timertitle: \"$$rContext{timertitle}[$num]\" " if ($$rContext{timertitle}[$num]); + print "Timertitle: \"\" " unless ($$rContext{timertitle}[$num]); - print "Marginstart: \"$marginstart_torecord[$num]\" " if ($marginstart_torecord[$num]); - print "Marginstart: \"\" " unless ($marginstart_torecord[$num]); + print "Marginstart: \"$$rContext{marginstart}[$num]\" " if ($$rContext{marginstart}[$num]); + print "Marginstart: \"\" " unless ($$rContext{marginstart}[$num]); - print "Marginstop: \"$marginstop_torecord[$num]\" " if ($marginstop_torecord[$num]); - print "Marginstop: \"\" " unless ($marginstop_torecord[$num]); + print "Marginstop: \"$$rContext{marginstop}[$num]\" " if ($$rContext{marginstop}[$num]); + print "Marginstop: \"\" " unless ($$rContext{marginstop}[$num]); - print "Machine: \"$machine_torecord[$num]\" " if ($machine_torecord[$num]); - print "Machine: \"\" " unless ($machine_torecord[$num]); + print "Minlength: \"$$rContext{minlength}[$num]\" " if ($$rContext{minlength}[$num]); + print "Minlength: \"\" " unless ($$rContext{minlength}[$num]); - print "\n"; - } - print "End Torecord-dump\n"; + print "Maxlength: \"$$rContext{maxlength}[$num]\" " if ($$rContext{maxlength}[$num]); + print "Maxlength: \"\" " unless ($$rContext{maxlength}[$num]); + + print "Instance: \"$$rContext{instance}[$num]\" " if ($$rContext{instance}[$num]); + print "Instance: \"\" " unless ($$rContext{instance}[$num]); + + print "\n"; } + print "End $context-dump\n"; +} -sub dumptimers() - { - print "Start Timers-dump\n"; - foreach $time (sort {$a <=> $b} keys %Timer) - { - foreach $channel (sort keys %{%Timer->{$time}}) - { - foreach $title (sort keys %{%Timer->{$time}->{$channel}}) - { - my ($prio, @time, @date, @time2); - my ($realtitle); - @time = &GetTime ($time); - @date = &GetDay ($time); - @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); - $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; - $prio = $Timer{$time}{$channel}{$title}{prio}; - $realtitle = $Timer{$time}{$channel}{$title}{real_title}; - print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\":$Timer{$time}{$channel}{$title}{VDR}\n"; - } - } +sub dumptimers() { + print "Start Timers-dump\n"; + foreach $time (sort {$a <=> $b} keys %Timer) { + foreach $channel (sort keys %{%Timer->{$time}}) { + foreach $title (sort keys %{%Timer->{$time}->{$channel}}) { + my ($prio, $lifetime, @time, @date, @time2); + my ($realtitle); + @time = &GetTime ($time); + @date = &GetDay ($time); + @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); + $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; + $prio = $Timer{$time}{$channel}{$title}{prio}; + $lifetime = $Timer{$time}{$channel}{$title}{lifetime}; + $realtitle = $Timer{$time}{$channel}{$title}{real_title}; + print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:$lifetime:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\":$Timer{$time}{$channel}{$title}{VDR}\n"; } - print "End Timers-dump\n"; + } } + print "End Timers-dump\n"; +} -sub printtimers() - { - foreach $time (sort {$a <=> $b} keys %Timer) - { - foreach $channel (sort keys %{%Timer->{$time}}) - { - foreach $title (sort keys %{%Timer->{$time}->{$channel}}) - { - my ($prio, @time, @date, @time2); - if ($Timer{$time}{$channel}{$title}{VDR} eq 0) - { - my ($realtitle); - @time = &GetTime ($time); - @date = &GetDay ($time); - @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); - $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; - $prio = $Timer{$time}{$channel}{$title}{prio}; - $realtitle = $Timer{$time}{$channel}{$title}{real_title}; - - print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"\n"; - } - } - } +sub printtimers() { + foreach $time (sort {$a <=> $b} keys %Timer) { + foreach $channel (sort keys %{%Timer->{$time}}) { + foreach $title (sort keys %{%Timer->{$time}->{$channel}}) { + my ($prio, $lifetime, @time, @date, @time2); + if ($Timer{$time}{$channel}{$title}{VDR} eq 0) { + my ($realtitle); + @time = &GetTime ($time); + @date = &GetDay ($time); + @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); + $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; + $prio = $Timer{$time}{$channel}{$title}{prio}; + $lifetime = $Timer{$time}{$channel}{$title}{lifetime}; + $realtitle = $Timer{$time}{$channel}{$title}{real_title}; + + print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:$lifetime:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"\n"; + } } + } } +} -sub transfertimers() - { - foreach $time (sort {$a <=> $b} keys %Timer) - { - foreach $channel (sort keys %{%Timer->{$time}}) - { - foreach $title (sort keys %{%Timer->{$time}->{$channel}}) - { - my ($prio, @time, @date, @time2, $realtitle, $result); - if ($Timer{$time}{$channel}{$title}{VDR} eq 0) - { - @time = &GetTime ($time); - @date = &GetDay ($time); - @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); - $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; - $prio = $Timer{$time}{$channel}{$title}{prio}; - $realtitle = $Timer{$time}{$channel}{$title}{real_title}; - - ($result) = GetSend ("newt 2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\""); - print "Timer: $result" if ($debug & 2); - } - } +sub transfertimers() { + foreach $time (sort {$a <=> $b} keys %Timer) { + foreach $channel (sort keys %{%Timer->{$time}}) { + foreach $title (sort keys %{%Timer->{$time}->{$channel}}) { + my ($prio, $lifetime, $description, @time, @date, @time2, $realtitle, $result); + if ($Timer{$time}{$channel}{$title}{VDR} eq 0) { + @time = &GetTime ($time); + @date = &GetDay ($time); + @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); + $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; + $prio = $Timer{$time}{$channel}{$title}{prio}; + $lifetime = $Timer{$time}{$channel}{$title}{lifetime}; + if ($Description) { + $description = "||Description :\"$Timer{$time}{$channel}{$title}{description}\""; + } else { + $description = ""; } + $realtitle = $Timer{$time}{$channel}{$title}{real_title}; + + ($result) = GetSend ("newt 2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:$lifetime:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"$description"); + print "Timer: $result" if ($debug & 2); + } } + } } +} # Convert the Unix-Time-Stamp into "month" and "Day of month" -sub GetDay - { - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); - $mon++; - $mon = sprintf ("%02i",$mon); - $mday = sprintf ("%02i",$mday); - return ($mon, $mday); - } +sub GetDay { + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); + $mon++; + $mon = sprintf ("%02i",$mon); + $mday = sprintf ("%02i",$mday); + return ($mon, $mday); +} +# Convert the Unix-Time-Stramp into Weekday +sub GetWDay { + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); + return ($wday); +} # Convert the Unix-Time-Stramp into "hour" and "minute" -sub GetTime - { - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); - $hour = sprintf ("%02i",$hour); - $min = sprintf ("%02i",$min); - return ($hour, $min); - } +sub GetTime { + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); + $hour = sprintf ("%02i",$hour); + $min = sprintf ("%02i",$min); + return ($hour, $min); +} # Workaround some EPG-Bugs -sub correct_epg_data - { - if ($subtitle) - { - # For Pro-7. Remove $title from $subtitle - $subtitle =~ s/$title\s\/\s//; +sub correct_epg_data { + if ($subtitle) { + # For Pro-7. Remove $title from $subtitle + $subtitle =~ s/\Q$title\E\s\/\s//; - # For VOX & VIVA. The Format it '"<Subtitle>". <Description>' - if ($subtitle =~ /^\"(.*?)\"\.\s(.*)/) - { - # Lets see if there are Channels that where the VOX/VIVA scheme matches, but also have a description - if ($description) - { - sub_die ("Subtitle: \"$subtitle\"\nDescription\"$description\"\n"); - } - $subtitle = $1; - $description = $2; - } - elsif ($channel eq "VIVA") - { - if ($subtitle =~ /^\s(.*)/) - { - $subtitle = ""; - $description = $1; - } - } + # For VOX & VIVA. The Format it '"<Subtitle>". <Description>' + if ($subtitle =~ /^\"(.*?)\"\.\s(.*)/) { + # Lets see if there are Channels that where the VOX/VIVA scheme matches, but also have a description + if ($description) { + my $one = $1; + my $two = $2; + if ($description =~ /^DTV\:\s\'(.*)\' VDR:\s\'\'$/) { + $description = "DTV: '$1' VDR: '$two'"; + $subtitle = $one; + } else { + die ("Title: \"$title\" Channel: \"$channel\" Subtitle: \"$subtitle\"\nDescription: \"$description\"\n"); + } } - - # Workaround for the broken PRO-7/Kabel-1 EPG-Date. If Time is between 00.00 and 05.00 the time is shifted forward by a day - if ($channel eq "Pro-7" || $channel eq "Kabel-1") - { - my (@time); - @time = GetTime ($time); - if ($time[0] >= 0 && ($time[0] <= 4 || ($time[0] == 5 && $time[1] == 0))) - { - $time += 24*60*60; - } + $subtitle = $1; + $description = $2; + } + elsif ($channel eq "VIVA") { + if ($subtitle =~ /^\s(.*)/) { + $subtitle = ""; + $description = $1; } + } + } + + # Workaround for the broken PRO-7/Kabel-1 EPG-Date. If Time is between 00.00 and 05.00 the time is shifted forward by a day + if ($channel eq "Pro-7" || $channel eq "Kabel-1") { + my (@time); + @time = GetTime ($time); + if ($time[0] >= 0 && ($time[0] <= 4 || ($time[0] == 5 && $time[1] == 0))) { + $time += 24*60*60; + } + } } # Add a Recording into the "to record"-List -sub addtimer - { - my ($hit, $title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $VDR, $time2, $title2, $channel2, $marginstart, $marginstop); - ($title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $VDR, $marginstart, $marginstop) = @_; -# print "Title: \"$title\" Realtitle: \"$realtitle\" Subtitle: \"$subtitle\" Channel: \"$channel\" Time: \"$time\" Duration: \"$duration\" Prio: \"$prio\" VDR: \"$VDR\"\n"; - - $hit = 1; - - foreach $time2 (sort keys %Timer) - { - foreach $title2 (sort keys %{%Timer->{$time2}->{$channel}}) - { - my ($ctime, $ctime2); - $ctime = $time2; - $ctime2 = $time2 + $Timer{$time2}{$channel}{$title2}{duration}; - - if (($time >= $ctime) && ($time <= $ctime2)) - { - undef $hit; - } - } +sub addtimer { + my ($title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $lifetime, $description, $VDR, $time2, $title2, $channel2, $marginstart, $marginstop); + ($title, $realtitle, $subtitle, $description, $channel, $time, $duration, $prio, $lifetime, $VDR, $marginstart, $marginstop) = @_; +# print "Title: \"$title\" Realtitle: \"$realtitle\" Subtitle: \"$subtitle\" Channel: \"$channel\" Time: \"$time\" Duration: \"$duration\" Prio: \"$prio\" VDR: \"$VDR\"\n"; + + foreach $time2 (sort keys %Timer) { + foreach $title2 (sort keys %{%Timer->{$time2}->{$channel}}) { + my ($ctime, $ctime2); + $ctime = $time2; + $ctime2 = $time2 + $Timer{$time2}{$channel}{$title2}{duration}; + + if (($time >= $ctime) && ($time <= $ctime2)) { + return; } + } + } + $time -= $marginstart; + $duration += $marginstart + $marginstop; + $Timer{$time}{$channel}{$title}{duration}=$duration; + $Timer{$time}{$channel}{$title}{subtitle}=$subtitle; + $Timer{$time}{$channel}{$title}{description}=$description; + $Timer{$time}{$channel}{$title}{prio}=$prio; + $Timer{$time}{$channel}{$title}{lifetime}=$lifetime; + $Timer{$time}{$channel}{$title}{VDR}=$VDR; + $Timer{$time}{$channel}{$title}{real_title}=$realtitle; +} - if ($hit) - { - $time -= $marginstart; - $duration += $marginstart + $marginstop; - $Timer{$time}{$channel}{$title}{duration}=$duration; - $Timer{$time}{$channel}{$title}{subtitle}=$subtitle; - $Timer{$time}{$channel}{$title}{prio}=$prio; - $Timer{$time}{$channel}{$title}{VDR}=$VDR; - $Timer{$time}{$channel}{$title}{real_title}=$realtitle; - } - } +sub deltimer() { + my ($time, $channel, $title, $delete_from_VDR); + ($time, $channel, $title, $delete_from_VDR) = @_; -sub deltimer() - { - my ($time, $channel, $title, $delete_from_VDR); - ($time, $channel, $title, $delete_from_VDR) = @_; - -# if ($delete_from_VDR) -# { -# if ($Timer{$time}{$channel}{$title}{VDR}) -# { -# if ($Timer{$time}{$channel}{$title}{VDR} =~ s/ ^R/) -# { -# print "Error: A Repeating-Timer can't be deleted from VDR: \"$title\"\n"; -# } -# elsif ($Timer{$time}{$channel}{$title}{VDR} < 1000000) -# { -# print "A User-Programmed Timer has been deleted from VDR: \"$title\"\n"; -# } -# else -# { -# -# } -# } +# if ($delete_from_VDR) { +# if ($Timer{$time}{$channel}{$title}{VDR}) { +# if ($Timer{$time}{$channel}{$title}{VDR} =~ s/ ^R/) { +# print "Error: A Repeating-Timer can't be deleted from VDR: \"$title\"\n"; +# } +# elsif ($Timer{$time}{$channel}{$title}{VDR} < 1000000) { +# print "A User-Programmed Timer has been deleted from VDR: \"$title\"\n"; +# } +# else { +# # } +# } +# } + + delete $Timer{$time}{$channel}{$title}{duration}; + delete $Timer{$time}{$channel}{$title}{subtitle}; + delete $Timer{$time}{$channel}{$title}{prio}; + delete $Timer{$time}{$channel}{$title}{VDR}; + delete $Timer{$time}{$channel}{$title}{real_title}; + delete $Timer{$time}{$channel}{$title}; + delete $Timer{$time}{$channel} if (keys %{ $Timer{$time}{$channel} } == 1); + delete $Timer{$time} if (keys %{ $Timer{$time} } == 1); +} - delete $Timer{$time}{$channel}{$title}{duration}; - delete $Timer{$time}{$channel}{$title}{subtitle}; - delete $Timer{$time}{$channel}{$title}{prio}; - delete $Timer{$time}{$channel}{$title}{VDR}; - delete $Timer{$time}{$channel}{$title}{real_title}; - delete $Timer{$time}{$channel}{$title}; - delete $Timer{$time}{$channel} if (keys %{ $Timer{$time}{$channel} } == 1); - delete $Timer{$time} if (keys %{ $Timer{$time} } == 1); - } +sub delprogram() { + my ($title, $channel, $time); + ($title, $channel, $time) = @_; -sub jointimers - { - # - # FIXME: 2 Timers on the same channel will always be joined. - # It should be checked if there is another DVB-Card available. - # - # FIXME2: When one timer is already programmed in VDR, delete that timer in VDR. - my ($running, $counter, @times, $channel, $title, $channel2, $title2); - $running = 1; - outer: while ($running) - { - $counter = 0; - @times = sort {$a <=> $b} keys %Timer; - - # We only need to check till the second last timer. The last one can't have a overlapping one. - while ($counter < $#times) - { - foreach $channel (sort keys %{%Timer->{$times[$counter]}}) - { - foreach $title (sort keys %{%Timer->{$times[$counter]}->{$channel}}) - { - if ($times[$counter + 1] < ($times[$counter] + $Timer{$times[$counter]}{$channel}{$title}{duration})) - { - foreach $channel2 (sort keys %{%Timer->{$times[$counter + 1]}}) - { - foreach $title2 (sort keys %{%Timer->{$times[$counter + 1]}->{$channel}}) - { - if ($channel eq $channel2) - { - my ($duration, $subtitle, $prio, $realtitle, $duration2, $subtitle2, $prio2, $realtitle2); - # Values from Lower-Timer - $duration = $Timer{$times[$counter]}{$channel}{$title}{duration}; - $subtitle = $Timer{$times[$counter]}{$channel}{$title}{subtitle}; - $prio = $Timer{$times[$counter]}{$channel}{$title}{prio}; - $realtitle = $Timer{$times[$counter]}{$channel}{$title}{real_title}; - - # Values from Higher-Timer - $duration2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{duration}; - $subtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{subtitle}; - $prio2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{prio}; - $realtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{real_title}; - - # Use the Higher Priority for the new Timer - $prio = ($prio > $prio2) ? $prio : $prio2; - - # Delete the two "Obsolet" Timers - &deltimer ($times[$counter], $channel, $title); - &deltimer ($times[$counter + 1], $channel2, $title2); - - # And set the new one - &addtimer ("$title + $title2", "$realtitle\~$realtitle2", "$subtitle\~$subtitle2", $channel, $times[$counter], $duration2 + ($times[$counter + 1 ] - $times[$counter]),$prio,0,0,0); - - # Now a Value is "missing", so we will redo the whole thing. (This will do three-times JOIN correct) - redo outer; - } - } - } - } - } + delete $Program{$title}{$channel}{$time}; + delete $Program{$title}{$channel} if (keys %{ $Program{$title}{$channel} } == 1); + delete $Program{$title} if (keys %{ $Program{$title} } == 1); +} + +sub jointimers { + # + # FIXME: 2 Timers on the same channel will always be joined. + # It should be checked if there is another DVB-Card available. + # + # FIXME2: When one timer is already programmed in VDR, delete that timer in VDR. + my ($running, $counter, @times, $channel, $title, $channel2, $title2); + $running = 1; + outer: while ($running) { + $counter = 0; + @times = sort {$a <=> $b} keys %Timer; + + # We only need to check till the second last timer. The last one can't have a overlapping one. + while ($counter < $#times) { + foreach $channel (sort keys %{%Timer->{$times[$counter]}}) { + foreach $title (sort keys %{%Timer->{$times[$counter]}->{$channel}}) { + if ($times[$counter + 1] < ($times[$counter] + $Timer{$times[$counter]}{$channel}{$title}{duration})) { + foreach $channel2 (sort keys %{%Timer->{$times[$counter + 1]}}) { + foreach $title2 (sort keys %{%Timer->{$times[$counter + 1]}->{$channel}}) { + if ($channel eq $channel2) { + my ($duration, $subtitle, $description, $prio, $lifetime, $realtitle, $duration2, $subtitle2, $description2, $prio2, $lifetime2, $realtitle2); + # Values from Lower-Timer + $duration = $Timer{$times[$counter]}{$channel}{$title}{duration}; + $subtitle = $Timer{$times[$counter]}{$channel}{$title}{subtitle}; + $description = $Timer{$times[$counter]}{$channel}{$title}{description}; + $prio = $Timer{$times[$counter]}{$channel}{$title}{prio}; + $lifetime = $Timer{$times[$counter]}{$channel}{$title}{lifetime}; + $realtitle = $Timer{$times[$counter]}{$channel}{$title}{real_title}; + + # Values from Higher-Timer + $duration2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{duration}; + $subtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{subtitle}; + $description2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{description}; + $prio2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{prio}; + $lifetime2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{lifetime}; + $realtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{real_title}; + + # Use the Higher Priority/Lifetime for the new Timer + $prio = ($prio > $prio2) ? $prio : $prio2; + $lifetime = ($lifetime > $lifetime2) ? $lifetime : $lifetime2; + + # Delete the two "Obsolet" Timers + &deltimer ($times[$counter], $channel, $title); + &deltimer ($times[$counter + 1], $channel2, $title2); + + # And set the new one + &addtimer ("$title + $title2", "$realtitle\~$realtitle2", "$subtitle\~$subtitle2", "$description\~$description2", $channel, $times[$counter], $duration2 + ($times[$counter + 1 ] - $times[$counter]),$prio,$lifetime,0,0,0); + + # Now a Value is "missing", so we will redo the whole thing. (This will do three-times JOIN correct) + redo outer; + } } - $counter++; + } } - undef $running; + } } + $counter++; + } + undef $running; } +} -sub process_torecord - { - my ($first_hit, $prio, $timer_title); - foreach $title (sort keys %Program) - { - foreach $channel (sort keys %{%Program->{$title}}) - { - foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}}) - { - undef $hit; - - # First look if any of the Title/Subtitle/Description REs match - if ($title =~ /$title_torecord/i) - { - $hit = 1; - } - elsif ($Program{$title}{$channel}{$time}{subtitle} && $Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_torecord/i) - { - $hit = 1; - } - elsif ($Program{$title}{$channel}{$time}{description} && $Program{$title}{$channel}{$time}{description} =~ /$description_torecord/i) - { - $hit = 1; - } - - # Now look if we have a "exact" hit - if ($hit) - { - my ($counter); - undef $hit; - foreach $counter (0 .. $num_torecord) - { - - if ($title_torecord[$counter]) - { - if (!($title =~ /$title_torecord[$counter]/i)) - { - next; - } - } - - if ($subtitle_torecord[$counter]) - { - if (!($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_torecord[$counter]/i)) - { - next; - } - elsif (!$title_torecord[$counter] && !$description_torecord[$counter]) - { - next; - } - } - - if ($description_torecord[$counter]) - { - if ($Program{$title}{$channel}{$time}{description}) - { - if (!($Program{$title}{$channel}{$time}{description} =~ /$description_torecord[$counter]/i)) - { - next; - } - } - elsif (!$title_torecord[$counter] && !$subtitle_torecord[$counter]) - { - next; - } - } - - if ($channel_torecord[$counter]) - { - my ($hit); - # Blacklist-Mode - if ($channel_torecord[$counter][0] =~ /^!/) - { - $hit = 1; - foreach (0 .. $#{$channel_torecord[$counter]}) - { - # Strip a possibel "!" Charactar - $channel_torecord[$counter][$_] =~ /^!?(.*)/; - if ($channel =~ /^$1$/) - { - undef $hit; - last; - } - } - } - # Whitelist-Mode - else - { - undef $hit; - foreach (0 .. $#{$channel_torecord[$counter]}) - { - # Strip a possibel "!" Charactar - $channel_torecord[$counter][$_] =~ /^!?(.*)/; - if ($channel =~ /^$1$/) - { - $hit = 1; - last ; - } - } - } - if (!$hit) - { - next; - } - } - - if ($timeframe_torecord[$counter]) - { - my (@time, $time2, $ctime, $ctime2); - @time = GetTime($time); - $time2 = "$time[0]$time[1]"; - - ($ctime, $ctime2) = split (/\-/,$timeframe_torecord[$counter]); - - if (!$ctime) - { - $ctime = "0"; - } - if (!$ctime2) - { - $ctime2 = "2400"; - } - - if ($ctime < $ctime2) - { - if (!($time2 >= $ctime && $time2 <= $ctime2)) - { - next; - } - } - else - { - if (!(($time2 >= $ctime && $time2 <= "2400") || ($time2 >= "0" && $time2 <= $ctime2))) - { - next; - } - } - } - - if ($prio_torecord[$counter]) - { - $prio = $prio_torecord[$counter]; - } - else - { - $prio = 50; - } - - # What Title to use for the timer - if ($timer_title_torecord[$counter]) - { - $timer_title = $timer_title_torecord[$counter] - } - elsif ($title_torecord[$counter]) - { - $timer_title = $title_torecord[$counter] - } - else - { - $timer_title = $title; - } - - my ($subtitle); - if ($Program{$title}{$channel}{$time}{subtitle}) - { - $subtitle = $Program{$title}{$channel}{$time}{subtitle}; - } - else - { - $subtitle = ""; - } - - &addtimer ($timer_title,$title,$subtitle,$channel,$time,$Program{$title}{$channel}{$time}{duration},$prio,0,$marginstart_torecord[$counter],$marginstop_torecord[$counter]); - last; - } - } - } +sub process_torecord { + my ($subtitle, $description, $prio, $lifetime, $timertitle, $counter); + foreach $title (sort keys %Program) { + foreach $channel (sort keys %{%Program->{$title}}) { + foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}}) { + + $counter = &testtimer("torecord", $title, $channel, $time); + if ($counter ne "Nothing") { + + # What Priority + if ($torecord{prio}[$counter]) { + $prio = $torecord{prio}[$counter]; + } + else { + $prio = 50; + } + + # What Lifetime + if ($torecord{lifetime}[$counter]) { + $lifetime = $torecord{lifetime}[$counter]; + } + else { + $lifetime = 50; + } + + # What Title to use for the timer + if ($torecord{timertitle}[$counter]) { + $timertitle = $torecord{timertitle}[$counter] } + elsif ($torecord{title}[$counter]) { + $timertitle = $torecord{title}[$counter] + } + else { + $timertitle = $title; + } + + # What subtitle to use + if ($Program{$title}{$channel}{$time}{subtitle}) { + $subtitle = $Program{$title}{$channel}{$time}{subtitle}; + } + else { + $subtitle = ""; + } + + # What Description to use + if ($Program{$title}{$channel}{$time}{description}) { + $description = $Program{$title}{$channel}{$time}{description}; + } + else { + $description = ""; + } + + &addtimer ($timertitle,$title,$subtitle,$description,$channel,$time,$Program{$title}{$channel}{$time}{duration},$prio,$lifetime,0,$torecord{marginstart}[$counter],$torecord{marginstop}[$counter]); + } } + } } +} -# Open the connection to VDR -sub initsocket - { - my ($Dest, $Port) = split (/\:/,$Dest[$currentVDR - 1],2); - my $iaddr = inet_aton($Dest); - my $paddr = sockaddr_in($Port, $iaddr); - - socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp')); - connect(SOCKET, $paddr) or sub_die ("Can't connect to VDR\n"); - select(SOCKET); $| = 1; - select(STDOUT); - - while (<SOCKET>) { - last if substr($_, 3, 1) ne "-"; - } +# Test if a torecord/deepblack Entry matches the current EPG-Data-Field +sub testtimer { + my ($context) = shift; + my ($title) = shift; + my ($channel) = shift; + my ($time) = shift; + my ($counter, $rContext); + + if ($context eq "torecord") { + $rContext = \%torecord; + } elsif ($context eq "deepblack") { + $rContext = \%deepblack; + } else { + die ("Illegal Context"); } -# Send a command to VDR and read back the result -sub GetSend - { - my ($command, @retval); - - while ($command = shift) - { - print SOCKET "$command\r\n"; - while (<SOCKET>) { - (@retval) = (@retval, $_); - last if substr($_, 3, 1) ne "-"; + if ($debug & 64) { + print "\n"; + print "Context: \"$context\"\nTitle: \"$title\"\n"; + print "Subtitle: \"$Program{$title}{$channel}{$time}{subtitle}\"\n" if ($Program{$title}{$channel}{$time}{subtitle}); + print "Description \"$Program{$title}{$channel}{$time}{description}\"\n" if ($Program{$title}{$channel}{$time}{description}); + print "Category \"$Program{$title}{$channel}{$time}{category}\"\n" if ($Program{$title}{$channel}{$time}{category}); + print "Channel: $channel\n"; + print "Time: $time\n"; + print "Duration: $Program{$title}{$channel}{$time}{duration}\n"; + } + + # First look if any of the Title/Subtitle/Description REs match + if ($title =~ /$$rContext{titleRE}/i) { + print "Title hit\n" if ($debug & 64); + } + elsif ($Program{$title}{$channel}{$time}{subtitle} && $Program{$title}{$channel}{$time}{subtitle} =~ /$$rContext{subtitleRE}/i) { + print "SubTitle hit\n" if ($debug & 64); + }elsif ($Program{$title}{$channel}{$time}{subtitle} && $test_subtitle_movie && $Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_movie/) { + print "SubTitle-Movie hit\n" if ($debug & 64); + } + elsif ($Program{$title}{$channel}{$time}{description} && $Program{$title}{$channel}{$time}{description} =~ /$$rContext{descriptionRE}/i) { + print "Description hit\n" if ($debug & 64); + } else { + # No "Fast"-hit. Exiting + return "Nothing"; + } + + # Now look if we have a "exact" hit + print "In Exact Hit Loop\n" if ($debug & 64); + foreach my $counter (0 .. $$rContext{timercount}) { + + print "Before Title Match\n" if ($debug & 64); + if ($$rContext{title}[$counter]) { + print "In Title Match \"$$rContext{title}[$counter]\"\n" if ($debug & 64); + if (!($title =~ /$$rContext{title}[$counter]/i)) { + print "Title rejected\n" if ($debug & 64); + next; + } + } + + print "Before Subtitle Match\n" if ($debug & 64); + if ($$rContext{subtitle}[$counter]) { + print "In Subtitle Match \"$$rContext{subtitle}[$counter]\"\n" if ($debug & 64); + if ($Program{$title}{$channel}{$time}{subtitle}) { + if ($$rContext{subtitle}[$counter] =~ /^movie$/i) { + if (!($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_movie/i)) { + print "Subtitle rejected 1\n" if ($debug & 64); + next; + } + } + elsif ($$rContext{subtitle}[$counter] =~ /^\!movie$/i) { + if (($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_movie/i)) { + print "Subtitle rejected 2\n" if ($debug & 64); + next; + } + } + elsif (!($Program{$title}{$channel}{$time}{subtitle} =~ /$$rContext{subtitle}[$counter]/i)) { + print "Subtitle rejected 3\n" if ($debug & 64); + next; + } + } else { + # We had a Subtitle, but epg.data did not have a subtitle for this record so no chance to record this + print "Subtitle rejected 4\n" if ($debug & 64); + next; + } + } + + print "Before Description Match\n" if ($debug & 64); + if ($$rContext{description}[$counter]) { + print "In Description Match \"$$rContext{description}[$counter]\"\n" if ($debug & 64); + if ($Program{$title}{$channel}{$time}{description}) { + if (!($Program{$title}{$channel}{$time}{description} =~ /$$rContext{description}[$counter]/i)) { + print "Description rejected 1\n" if ($debug & 64); + next; + } + } + elsif (!$$rContext{title}[$counter] && !$$rContext{subtitle}[$counter]) { + print "Description rejected 2\n" if ($debug & 64); + next; + } + } + + print "Before Category Match\n" if ($debug & 64); + if ($$rContext{category}[$counter]) { + print "In Category Match \"$$rContext{category}[$counter]\"\n" if ($debug & 64); + if ($Program{$title}{$channel}{$time}{category}) { + my ($left, $right); + ($left, $right) = split (/\//, $$rContext{category}[$counter]); + if ($left) { + print "In Category Match Left \"$left\"\n" if ($debug & 64); + if (!($Program{$title}{$channel}{$time}{category} =~ /^$left\//)) { + print "Category rejected 1\n" if ($debug & 64); + next; + } + } + if ($right) { + print "In Category Match Right \"$right\"\n" if ($debug & 64); + if (!($Program{$title}{$channel}{$time}{category} =~ /\/$right$/)) { + print "Category rejected 2\n" if ($debug & 64); + next; + } + } + } else { + # We had a Category, but the epg.data not. So discard this Entry + print "Category rejected 3\n" if ($debug & 64); + next; + } + } + + print "Before Channel Match\n" if ($debug & 64); + if ($$rContext{channel}[$counter]) { + print "In Channel Match Whitelist-Mode \"$$rContext{channel}[$counter]\"\n" if ($debug & 64); + if (!($channel =~ /$$rContext{channel}[$counter]/)) { + print "Channel rejected\n" if ($debug & 64); + next; + } + } + + if ($$rContext{blackchannel}[$counter]) { + print "In Channel Match Blacklist-Mode \"$$rContext{blackchannel}[$counter]\"\n" if ($debug & 64); + if ($channel =~ /$$rContext{blackchannel}[$counter]/) { + print "Channel rejected\n" if ($debug & 64); + next; + } + } + + print "Before Timeframe Match\n" if ($debug & 64); + if ($$rContext{timeframe}[$counter]) { + print "In Timeframe Match \"$$rContext{timeframe}[$counter]\"\n" if ($debug & 64); + my (@time, $time2, $ctime, $ctime2); + @time = GetTime($time); + $time2 = "$time[0]$time[1]"; + + ($ctime, $ctime2) = split (/\-/,$$rContext{timeframe}[$counter]); + + if (!$ctime) { + $ctime = "0"; + } + if (!$ctime2) { + $ctime2 = "2400"; + } + + if ($ctime < $ctime2) { + if (!($time2 >= $ctime && $time2 <= $ctime2)) { + print "Timeframe rejected 1\n" if ($debug & 64); + next; + } + } + else { + if (!(($time2 >= $ctime && $time2 <= "2400") || ($time2 >= "0" && $time2 <= $ctime2))) { + print "Timeframe rejected 2\n" if ($debug & 64); + next; } } + } + + print "Before Weekday Match\n" if ($debug & 64); + if ($$rContext{weekday}[$counter]) { + print "In Weekday Match \"$$rContext{weekday}\"\n" if ($debug & 64); + my ($wday); + $wday = getWDay($time); + $$rContext{weekday}[$counter] =~ /(.)(.)(.)(.)(.)(.)(.)/; + if ($$wday eq "-") { + print "Weekday rejected\n" if ($debug & 64); + next; + } + } + + print "Before Minlength Match\n" if ($debug & 64); + if ($$rContext{minlength}[$counter]) { + print "In Minlength Match \"$$rContext{minlength}[$counter]\"\n" if ($debug & 64); + if ($Program{$title}{$channel}{$time}{duration} < $$rContext{minlength}[$counter]) { + print "Minlength rejected\n" if ($debug & 64); + next; + } + } - foreach my $retval (@retval) - { - $retval =~ s/\x0d//g; + print "Before Maxlength Match\n" if ($debug & 64); + if ($$rContext{maxlength}[$counter]) { + print "In Maxlength Match \"$$rContext{maxlength}[$counter]\"\n" if ($debug & 64); + if ($Program{$title}{$channel}{$time}{duration} > $$rContext{maxlength}[$counter]) { + print "Maxlength rejected\n" if ($debug & 64); + next; } - return (@retval); + } + + # All test passed. Accept this timer + print "All Tests passed entry accepted/blacklisted\n" if ($debug & 64); + return ($counter); + } + # Foreach ran out without a hit + return "Nothing"; +} + +# Open the connection to VDR +sub initsocket { + my ($Dest, $Port) = split (/\:/,$Dest[$currentVDR - 1],2); + my $iaddr = inet_aton($Dest); + my $paddr = sockaddr_in($Port, $iaddr); + my $Timeout = 10; # max. seconds to wait for response + + $SIG{ALRM} = sub { die("Timeout while connecting to VDR"); }; + alarm($Timeout); + + socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp')); + connect(SOCKET, $paddr) or die ("Can't connect to VDR\n"); + select(SOCKET); $| = 1; + select(STDOUT); + + while (<SOCKET>) { + last if substr($_, 3, 1) ne "-"; } + alarm(0); +} + +# Send a command to VDR and read back the result +sub GetSend { + my ($command, @retval); + + while ($command = shift) { + print SOCKET "$command\r\n"; + while (<SOCKET>) { + s/\x0d//g; + (@retval) = (@retval, $_); + last if substr($_, 3, 1) ne "-"; + } + } + return (@retval); +} # Close the socket to VDR -sub closesocket - { - print SOCKET "Quit\r\n"; - close(SOCKET); - } +sub closesocket { + print SOCKET "Quit\r\n"; + close(SOCKET); +} # Fetch the timers-List from VDR via SVDR and process it. -sub fetchVDRTimers - { - my (@timers, $timer, $position, $active, $channel, $day, $start, $end, $prio, $ttl, $title, $subtitle, $minute, $duration); - my ($utime, $utime2); - - # First fetch the timers-list from VDR - @timers = GetSend ("lstt"); - - foreach $timer (@timers) - { -# $timer =~ s/\x0d//g; - chomp $timer; - # a Valid Timer-line beginns with "250" - if ($timer =~ s/250-|250\s//) - { - # Extract the Position in front of the line - ($position, $timer) = split (/\s/,$timer,2); - -# print "Position: \"$position\" Timer: \"$timer\"\n"; - # Split the : seperated values - ($active, $channel, $day, $start, $end, $prio, $ttl, $title, $subtitle) = split (/\:/,$timer,9); - - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); - - # If the string is exactly 7 char wide, then its a "repeating"-timer - if ($active >= 1) - { - if ($day =~ /(.)(.)(.)(.)(.)(.)(.)/) - { - my (@days); - @days = ($1, $2, $3, $4, $5, $6, $7); - ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); - - $start =~ /(\d\d)(\d\d)/; - $hour = $1; - $minute = $2; - $utime = timelocal 0, $minute, $hour, $mday, $mon, $year; - $end =~ /(\d\d)(\d\d)/; - $hour = $1; - $minute = $2; - $utime2 = timelocal 0, $minute, $hour, $mday, $mon, $year; - if ($end < $start) - { - $utime2 += 24*60*60; - } - $duration = $utime2 - $utime; - - # "Normalize" the timestamp to monday - $utime = $utime - ($wday * 24 * 60 *60); - - foreach my $num (0 .. $#days) - { - if ($days[$num] ne "-") - { - my $utime3; - # Todays before today will be shifted in the next week - if (($num + 1) < $wday) - { - $utime3 = $utime + (($num + 7 + 1) * 24 * 60 * 60); - } - else - { - $utime3 = $utime + (($num + 1) * 24 * 60 * 60); - } - &addtimer ($title,$title,$subtitle,$channels[$channel],$utime3,$duration,$prio,"R$position",0,0); - } - } - } - - # When the Day-Value is between 1 and 31, then its a "One time" Timer - elsif (($day >= 1) && ($day <= 31)) - { - if ($active == "2") - { - $position += 1000000; - } - # When the Day is before the Current-Day, then the Timer is for the next month - if ($day < $mday) - { - $mon++; - if ($mon == 12) - { - $mon = 0; - $year ++; - } - } - $start =~ /(\d\d)(\d\d)/; - $hour = $1; - $minute = $2; - $utime = timelocal 0, $minute, $hour, $day, $mon, $year; - $end =~ /(\d\d)(\d\d)/; - $hour = $1; - $minute = $2; - $utime2 = timelocal 0, $minute, $hour, $day, $mon, $year; - if ($end < $start) - { - $utime2 += 24*60*60; - } - $duration = $utime2 - $utime; - - &addtimer ($title,$title,$subtitle,$channels[$channel],$utime,$duration,$prio,$position,0,0); - } +sub fetchVDRTimers { + my (@timers, $timer, $position, $active, $channel, $day, $start, $end, $prio, $lifetime, $title, $subtitle, $minute, $duration); + my ($utime, $utime2); + + # First fetch the timers-list from VDR + @timers = GetSend ("lstt"); + + foreach $timer (@timers) { + chomp $timer; + # a Valid Timer-line beginns with "250" + if ($timer =~ s/250-|250\s//) { + # Extract the Position in front of the line + ($position, $timer) = split (/\s/,$timer,2); + +# print "Position: \"$position\" Timer: \"$timer\"\n"; + # Split the : seperated values + ($active, $channel, $day, $start, $end, $prio, $lifetime, $title, $subtitle) = split (/\:/,$timer,9); + + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + + # If the string is exactly 7 char wide, then its a "repeating"-timer + if ($active >= 1) { + if ($day =~ /(.)(.)(.)(.)(.)(.)(.)/) { + my (@days); + @days = ($1, $2, $3, $4, $5, $6, $7); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + + $start =~ /(\d\d)(\d\d)/; + $hour = $1; + $minute = $2; + $utime = timelocal 0, $minute, $hour, $mday, $mon, $year; + $end =~ /(\d\d)(\d\d)/; + $hour = $1; + $minute = $2; + $utime2 = timelocal 0, $minute, $hour, $mday, $mon, $year; + if ($end < $start) { + $utime2 += 24*60*60; + } + $duration = $utime2 - $utime; + + # "Normalize" the timestamp to monday + $utime = $utime - ($wday * 24 * 60 *60); + + foreach my $num (0 .. $#days) { + if ($days[$num] ne "-") { + my $utime3; + # Days before today will be shifted in the next week + if (($num + 1) < $wday) { + $utime3 = $utime + (($num + 7 + 1) * 24 * 60 * 60); } + else { + $utime3 = $utime + (($num + 1) * 24 * 60 * 60); + } + &addtimer ($title,$title,$subtitle,"",$channels[$channel],$utime3,$duration,$prio,$lifetime,"R$position",0,0); + } + } + } + + # When the Day-Value is between 1 and 31, then its a "One time" Timer + elsif (($day >= 1) && ($day <= 31)) { + if ($active == "2") { + $position += 1000000; + } + # When the Day is before the Current-Day, then the Timer is for the next month + if ($day < $mday) { + $mon++; + if ($mon == 12) { + $mon = 0; + $year ++; + } } + $start =~ /(\d\d)(\d\d)/; + $hour = $1; + $minute = $2; + $utime = timelocal 0, $minute, $hour, $day, $mon, $year; + $end =~ /(\d\d)(\d\d)/; + $hour = $1; + $minute = $2; + $utime2 = timelocal 0, $minute, $hour, $day, $mon, $year; + if ($end < $start) { + $utime2 += 24*60*60; + } + $duration = $utime2 - $utime; + + &addtimer ($title,$title,$subtitle,"",$channels[$channel],$utime,$duration,$prio,$lifetime,$position,0,0); + } } + } } +} # Parse file "epg.data" -sub initepgdata - { - open (FI,"epg.data") or sub_die ("Can't open file \"epg.data\"\n"); - - while (<FI>) - { - # Begin Channel - if (/^C\s(\d+)\s+(.+)/) - { - $channel = $2; - while (<FI>) - { - # End Channel - if (/^c$/) - { - last; - } - # Begin Timer - elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/) - { - # Undef this Variables because it is possibel that not every timer uses this values - undef $duration; - undef $subtitle; - undef $description; - - $time=$2; - $duration=$3; - } - # Title - elsif (/^T\s(.*)/) - { - $title = $1; - } - # Subtitle - elsif (/^S\s(.*)/) - { - $subtitle=$1; - } - # Description - elsif (/^D\s(.*)/) - { - $description=$1; - } - # End Timer - elsif (/^e$/) - { - # Only accept timers that are in the future - if ($time < time) - { - next; - } - - # Work around the diffrent Bugs in the data - &correct_epg_data(); - - # Check if the title is in the DEEP-Blacklist - if ($title =~ /$title_deepblack/i) - { - next; - } - - # Check if the Title & Subtitle is in the Done-List - if ($title =~ /$title_done/) - { - if ($subtitle) - { - if ($subtitle =~ /$subtitle_done/) - { - next; - } - } - } - - $Program{$title}{$channel}{$time}{duration}=$duration; - if ($subtitle) - { - $Program{$title}{$channel}{$time}{subtitle}=$subtitle; - } - if ($description) - { - $Program{$title}{$channel}{$time}{description}=$description; - } - } - } +sub initepgdata { + open (FI,"epg.data") or die ("Can't open file \"epg.data\"\n"); + + while (<FI>) { + # Begin Channel + if (/^C\s(\d+)\s+(.+)/) { + $channel=$2; + while (<FI>) { + # End Channel + if (/^c$/) { + last; + } + # Begin Timer + elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/) { + # Undef this Variables because it is possibel that not every timer uses this values + undef $duration; + undef $subtitle; + undef $description; + undef $category; + + $time=$2; + $duration=$3; + } + # Title + elsif (/^T\s(.*)/) { + $title=$1; + } + # Subtitle + elsif (/^S\s(.*)/) { + $subtitle=$1; } + # Description + elsif (/^D\s(.*)/) { + $description=$1; + } + elsif (/^K\s(.*)/) { + $category=$1; + } + # End Timer + elsif (/^e$/) { + # Only accept timers that are in the future + if ($time < time) { + next; + } + # Only accept timers that are at least 2 Seconds long + if ($duration <= 1) { + next; + } + + # Work around the different Bugs in the data + &correct_epg_data(); + + # Check if the Title & Subtitle is in the Done-List (Only if Subtitle exists) + if ($subtitle && $title =~ /$title_done/ && $subtitle =~ /$subtitle_done/) { + next; + } + + $Program{$title}{$channel}{$time}{duration}=$duration; + if ($subtitle) { + $Program{$title}{$channel}{$time}{subtitle}=$subtitle; + } + if ($description) { + $Program{$title}{$channel}{$time}{description}=$description; + } + if ($category) { + $Program{$title}{$channel}{$time}{category}=$category; + } + # Check if the title is in the DEEP-Blacklist + if (&testtimer("deepblack", $title, $channel, $time) ne "Nothing") { + print "Deepblack: \"$title\"" if ($debug & 64); + print " $subtitle" if ($debug & 64 && $subtitle); + print "\n" if ($debug & 64); + &delprogram ($title, $channel, $time); + } + } + } } - close (FI); - } + } + close (FI); +} # What is a Movie (When correctly stored into Subtitle) -sub initmovie - { - my (@list,$list); - open (FI,"$ENV{HOME}/.master-timer/subtitle-movie") or return; - @list = <FI>; - close(FI); - - foreach $list (@list) - { - chomp $list; - } - $subtitle_movie = join ('|',@list); +sub initmovie { + my (@list,$list); + open (FI,"${configdir}/subtitle-movie") or return; + @list = <FI>; + close(FI); + + foreach $list (@list) { + chomp $list; } + $subtitle_movie = join ('|',@list); +} -# What should be blacklistet -sub initblacklist - { - my (@list,$list); - if (open (FI,"$ENV{HOME}/.master-timer/deepblack")) - { - @list = <FI>; - close(FI); - - foreach $list (@list) - { - chomp $list; - } - $title_deepblack = join ('|',@list); - } - else - { - $title_deepblack = "^\$"; +# What is already recorded/Should not be recorded +sub initdone { + my (@list,$list, %title_done, %subtitle_done, $title_temp, $subtitle_temp); + open (FI,"${configdir}/done") or return; + @list = <FI>; + close (FI); + + foreach $list (@list) { + chomp $list; + ($title_temp,$subtitle_temp) = split (/\|/,$list); + if ($title_temp) { + $title_done{"^\Q$title_temp\E\$"} = 1; + } + if ($subtitle_temp) { + $subtitle_done{"^\Q$subtitle_temp\E\$"} = 1; + } + } + $title_done = join ('|',sort keys %title_done); + $subtitle_done = join ('|',sort keys %subtitle_done); +} + +sub processdone { + # Now delete Timers in VDR that are already in the done-List + my ($list, @list, $position, $timer, $active, $g, $title, $subtitle, $counter, @todel); + $counter = 0; + @list = GetSend ("LSTT"); + + foreach $timer (@list) { + chomp $timer; + if ($timer =~ s/250-|250\s//) { + ($position, $timer) = split (/\s/,$timer,2); + # Split the : seperated values + ($active, $g, $g, $g, $g, $g, $g, $title, $subtitle) = split (/\:/,$timer,9); + if ($active == 2) { + # Title: "Shakespeare in Love"||Subtitle: "Romanze" + my ($ctitle, $csubtitle); + if ($subtitle && $subtitle =~ /^Title\:\s\"(.*)\"\|\|Subtitle\:\s\"(.*)\"/) { + $title = $1; + $subtitle = $2; + if ($subtitle) { + my (@titles, @subtitles, $num, $hit); + undef $hit; + @titles = split (/\~/,$title); + @subtitles = split (/\~/,$subtitle); + foreach $num (0 .. $#titles) { + if ($titles[$num] =~ /$title_done/ && $subtitles[$num] =~ /$subtitle_done/) { + $hit = 1; + } + else { + undef $hit; + last; + } + } + + if ($hit) { + my ($result); + print "Delete Timer: $title $subtitle\n" if ($debug & 4); + $position -= $counter; + ($result) = GetSend ("DELT $position"); + print "Result: $result" if ($debug & 4); + if ($result =~ /^250/) { + $counter++; + } + } + } + } } + } } +} -# What is already recorded/Should not be recorded -sub initdone - { - my (@list,$list, %title_done, %subtitle_done, $title_temp, $subtitle_temp); - if (open (FI,"$ENV{HOME}/.master-timer/done")) - { - @list = <FI>; - close (FI); - - foreach $list (@list) - { - chomp $list; - ($title_temp,$subtitle_temp) = split (/\|/,$list); - if ($title_temp) - { - $title_done{"^$title_temp\$"} = 1; - } - if ($subtitle_temp) - { - $subtitle_done{"^$subtitle_temp\$"} = 1; - } +# What should be recorded +sub inittorecord { + my ($context) = shift; + my ($rContext); + my (@title_list, @subtitle_list, @description_list, $line); + my (%Input); + my $counter = 0; + + if ($context eq "torecord") { + $rContext = \%torecord; + open (FI,"${configdir}/${context}") or die ("Can't open file \"$context\"\n"); + } elsif ($context eq "deepblack") { + $rContext = \%deepblack; + open (FI,"${configdir}/${context}") or return; + } else { + die ("Illegal Context"); + } + + + outer: while (<FI>) { + chomp if ($_); + if ($_ && !(/^\#/) && /^\[.*\]$/) { + $line = $.; + undef %Input; + while (<FI>) { + chomp; + if ($_ && !(/^\#/)) { + if (/^\[.*?\]$/) { + last; } - $title_done = join ('|',sort keys %title_done); - $subtitle_done = join ('|',sort keys %subtitle_done); - - # Ein paar Zeichen Escapen - $title_done =~ s/\?/\\\?/g; - $title_done =~ s/\+/\\\+/g; - $subtitle_done =~ s/\?/\\\?/g; - $subtitle_done =~ s/\+/\\\+/g; - - # Now delete Timers in VDR that are already in the done-List - my ($position, $timer, $active, $g, $title, $subtitle, $counter, @todel); - $counter = 0; - @list = GetSend ("LSTT"); - - foreach $timer (@list) - { -# $timer =~ s/0x0d//g; - chomp $timer; - if ($timer =~ s/250-|250\s//) - { - ($position, $timer) = split (/\s/,$timer,2); - # Split the : seperated values - ($active, $g, $g, $g, $g, $g, $g, $title, $subtitle) = split (/\:/,$timer,9); - if ($active == 2) - { - # Title: "Shakespeare in Love"||Subtitle: "Romanze" - my ($ctitle, $csubtitle); - if ($subtitle && $subtitle =~ /^Title\:\s\"(.*)\"\|\|Subtitle\:\s\"(.*)\"/) - { - $title = $1; - $subtitle = $2; - if ($subtitle) - { - my (@titles, @subtitles, $num, $hit); - undef $hit; - @titles = split (/\~/,$title); - @subtitles = split (/\~/,$subtitle); - foreach $num (0 .. $#titles) - { - if ($titles[$num] =~ /$title_done/ && $subtitles[$num] =~ /$subtitle_done/) - { - $hit = 1; - } - else - { - undef $hit; - last; - } - } - - if ($hit) - { - my ($result); - print "Delete Timer: $title $subtitle\n" if ($debug & 4); - $position -= $counter; - ($result) = GetSend ("DELT $position"); - print "Result: $result" if ($debug & 4); - if ($result =~ /^250/) - { - $counter++; - } - } - } - } - } - } + + my ($key, $value); + ($key, $value) = split (/\s+=\s+/); + + if ($key =~ /^title$/i) { + if ($Input{title}) { + $Input{title} .= "|$value"; + } else { + $Input{title} = $value; + } + print "Titel = $value\n" if ($debug & 16); + } + elsif ($key =~ /^subtitle$/i) { + if ($Input{subtitle}) { + $Input{subtitle} .= "|$value"; + } else { + $Input{subtitle} = $value; + } + print "Subtitel = $value\n" if ($debug & 16); + } + elsif ($key =~ /^description$/i) { + if ($Input{description}) { + $Input{description} .= "|$value"; + } else { + $Input{description} = $value; + } + print "Description = $value\n" if ($debug & 16); + } + elsif ($key =~ /^category$/i) { + $Input{category} = $value; + print "Category = $value\n" if ($debug & 16); + } + elsif ($key =~ /^channel$/i) { + if ($Input{channel}) { + $Input{channel} .= "|^$value\$"; + } else { + $Input{channel} = $value; + } + print "Channel = $value\n" if ($debug & 16); + } + elsif ($key =~ /^timeframe$/i) { + $Input{timeframe} = $value; + print "Timeframe = $value\n" if ($debug & 16); } + elsif ($key =~ /^weekday$/i) { + $Input{weekday} = $value; + print "Weekday = $value\n" if ($debug & 16); + } + elsif ($key =~ /^minlength$/i) { + $Input{minlength} = $value; + print "Minlength = $value\n" if ($debug & 16); + } + elsif ($key =~ /^maxlength$/i) { + $Input{maxlength} = $value; + print "Maxlength = $value\n" if ($debug & 16); + } + elsif ($key =~ /^prio$/i) { + $Input{prio} = $value; + print "Prio = $value\n" if ($debug & 16); + } + elsif ($key =~ /^lifetime$/i) { + $Input{lifetime} = $value; + print "Lifetime = $value\n" if ($debug & 16); + } + elsif ($key =~ /^timertitle$/i) { + $Input{timertitle} = $value; + print "Timertitel = $value\n" if ($debug & 16); + } + elsif ($key =~ /^margin$/i) { + $Input{margin} = $value; + print "Margin = $value\n" if ($debug & 16); + } + elsif ($key =~ /^instance$/i) { + $Input{instance} = $value; + print "Instance = $value\n" if ($debug & 16); + } else { + print "Unkown Key: \"$key\" with Value: \"$value\"\n"; + } + } } - } -# What should be recorded -sub inittorecord - { - my (@list, $list, $title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine, @title_list, @subtitle_list, @description_list); - my $counter = 0; - open (FI,"$ENV{HOME}/.master-timer/torecord") or sub_die ("Can't open file \"torecord\"\n"); - @list = <FI>; - close(FI); - - foreach $list (0 .. $#list) - { - chomp $list[$list]; - if ($list[$list] && !($list[$list] =~ /^\#/)) - { - ($title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine) = split (/\|/,$list[$list]); - - # Accept torecord only if it is for the current machine - if ((!$machine && $currentVDR == 1) || $machine == $currentVDR) - { - if ($title) - { - $title_torecord[$counter] = $title; - $title_list[$#title_list + 1] = $title; - } - if ($subtitle) - { - $subtitle_torecord[$counter] = $subtitle; - $subtitle_list[$#subtitle_list + 1] = $subtitle; - } - if ($description) - { - $description_torecord[$counter] = $description; - $description_list[$#description_list + 1] = $description; - } - if ($channel) - { - my (@temp); - @temp = split (/\;/,$channel); - foreach (0 .. $#temp) - { - $channel_torecord[$counter][$_] = $temp[$_]; - } - } - if ($timeframe) - { - $timeframe_torecord[$counter] = $timeframe; - } - if ($prio) - { - $prio_torecord[$counter] = $prio; - } - else - { - $prio_torecord[$counter] = $default_prio; - } - if ($timer_title) - { - $timer_title_torecord[$counter] = $timer_title; - } - if ($margin) - { - my ($start, $stop); - ($start, $stop) = split (/;/,$margin, 2); - $marginstart_torecord[$counter] = $start if ($start); - $marginstop_torecord[$counter] = $stop if ($stop); - } - # Set Default-Margins if not margins defined - $marginstart_torecord[$counter] = $marginstart if (!$marginstart_torecord[$counter]); - $marginstop_torecord[$counter] = $marginstop if (!$marginstop_torecord[$counter]); - $counter++; - } + # Accept entry only if it is for the current instance or for "no" instance + if (($Opts{s} && $Input{instance} && $Input{instance} eq "s") || !$Input{instance} || ($Input{instance} ne "s" && $Input{instance} == $currentVDR)) { + # Accept entry only if at least a Title/Subtitle/Description is provied + if (!$Input{title} && !$Input{subtitle} && !$Input{description}) { + print "No Title/Subtitle/Description Field. $context entry ignored. Block beginning at Line $line\n"; + redo outer; + } + + if ($Input{title}) { + $$rContext{title}[$counter] = $Input{title}; + $title_list[$#title_list + 1] = $Input{title}; + } + if ($Input{subtitle}) { + if ($Input{subtitle} =~ /^movie$/i || $Input{subtitle} =~ /^\!movie$/i) { + $test_subtitle_movie = 1; + } + $$rContext{subtitle}[$counter] = $Input{subtitle}; + $subtitle_list[$#subtitle_list + 1] = $Input{subtitle}; + } + if ($Input{description}) { + $$rContext{description}[$counter] = $Input{description}; + $description_list[$#description_list + 1] = $Input{description}; + } + if ($Input{category}) { + $$rContext{category}[$counter] = $Input{category}; + } + if ($Input{channel}) { + if ($Input{channel} =~ /\!/) { + $Input{channel} =~ s/\!//g; + $$rContext{blackchannel}[$counter] = $Input{channel}; + } else { + $$rContext{channel}[$counter] = $Input{channel}; } + } + if ($Input{timeframe}) { + $$rContext{timeframe}[$counter] = $Input{timeframe}; + } + if ($Input{weekday}) { + $$rContext{weekday}[$counter] = $Input{weekday}; + } + if ($Input{minlength}) { + if ($Input{minlength} =~ /^(\d+)m$/) { + $Input{minlength} = $1 * 60 + } elsif ($Input{minlength} =~ /^(\d+)h$/) { + $Input{minlength} = $1 * 60 * 60 + } + $$rContext{minlength}[$counter] = $Input{minlength}; + } + if ($Input{maxlength}) { + if ($Input{maxlength} =~ /^(\d+)m$/) { + $Input{maxlength} = $1 * 60 + } elsif ($Input{maxlength} =~ /^(\d+)h$/) { + $Input{maxlength} = $1 * 60 * 60 + } + $$rContext{maxlength}[$counter] = $Input{maxlength}; + } + if ($Input{prio}) { + $$rContext{prio}[$counter] = $Input{prio}; + } + if ($Input{lifetime}) { + $$rContext{lifetime}[$counter] = $Input{lifetime}; + } + else { + $$rContext{prio}[$counter] = $default_prio; + } + if ($Input{timertitle}) { + $$rContext{timertitle}[$counter] = $Input{timertitle}; + } + if ($Input{margin}) { + my ($start, $stop); + ($start, $stop) = split (/;/,$Input{margin}, 2); + $$rContext{marginstart}[$counter] = $start if ($start); + $$rContext{marginstop}[$counter] = $stop if ($stop); + } + # Set Default-Margins if no margins defined + $$rContext{marginstart}[$counter] = $marginstart if (!$$rContext{marginstart}[$counter]); + $$rContext{marginstop}[$counter] = $marginstop if (!$$rContext{marginstop}[$counter]); + $counter++; + if ($Input{instance}) { + $$rContext{instance}[$counter] = $Input{instance}; + } } + redo outer; + } + } + + $$rContext{timercount} = $counter - 1; + + $$rContext{titleRE} = join ('|',@title_list); + if ($$rContext{titleRE} && $$rContext{titleRE} =~ /\|.\|/) { + $$rContext{titleRE} = "."; + } + $$rContext{subtitleRE} = join ('|',@subtitle_list); + if ($$rContext{subtitleRE} && $$rContext{subtitleRE} =~ /\|.\|/) { + $$rContext{subtitleRE} = "."; + } + $$rContext{descriptionRE} = join ('|',@description_list); + if ($$rContext{descriptionRE} && $$rContext{descriptionRE} =~ /\|.\|/) { + $$rContext{descriptionRE} = "."; + } + + if (!$$rContext{titleRE}) { + $$rContext{titleRE} = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; + } + if (!$$rContext{subtitleRE}) { + $$rContext{subtitleRE} = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; + } + if (!$$rContext{descriptionRE}) { + $$rContext{descriptionRE} = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; + } +} + +# Parse "LSTC"-Command of VDR +sub initchannellist { + my ($counter, $chan, $garbage, $card, @temp_channels, $temp, $i); - $num_torecord = $counter - 1; + @temp_channels = GetSend ("LSTC"); - $title_torecord = join ('|',@title_list); - $subtitle_torecord = join ('|',@subtitle_list); - $description_torecord = join ('|',@description_list); + foreach $i (0 .. $#temp_channels) { + $temp = $temp_channels[$i]; + chomp $temp; - if (!$title_torecord) - { - $title_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; + if ($temp =~ s/250-|250\s//) { + ($counter, $temp) = split (/\s/,$temp,2); + ($chan, $garbage,$garbage, $garbage, $garbage, $garbage, $garbage, $card, $garbage) = split (/\:/,$temp); + $channels[$counter] = $chan; + $channels{$chan}{number} = $counter; + $channels{$chan}{card} = $card; + $counter++; + } + } +} + +sub initconfigfile { + open (FI,"${configdir}/config") or return; + while (<FI>) { + s/\#.*//; + chomp; + if ($_) { + my ($key, $value); + ($key, $value) = split (/\s+=\s+/); + if ($key =~ /^debug$/i) { + $debug = $value; + print "Debug-Level = $value\n" if ($debug & 16); } - if (!$subtitle_torecord) - { - $subtitle_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; + elsif ($key =~ /^marginstart$/i) { + print "Marginstart = $value\n" if ($debug & 16); + $marginstart = $value; } - if (!$description_torecord) - { - $description_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; + elsif ($key =~ /^marginstop$/i) { + print "Marginstop = $value\n" if ($debug & 16); + $marginstop = $value; } - } - -# Parse the "channels.conf" of VDR -sub initchannellist - { - my ($counter, $chan, $garbage, $card, @temp_channels, $temp, $i); - - @temp_channels = GetSend ("LSTC"); - - foreach $i (0 .. $#temp_channels) - { - $temp = $temp_channels[$i]; -# $temp =~ s/\x0d//g; - chomp $temp; - - if ($temp =~ s/250-|250\s//) - { - ($counter, $temp) = split (/\s/,$temp,2); - ($chan, $garbage,$garbage, $garbage, $garbage, $garbage, $garbage, $card, $garbage) = split (/\:/,$temp); - $channels[$counter] = $chan; - $channels{$chan}{number} = $counter; - $channels{$chan}{card} = $card; - $counter++; - } + elsif ($key =~ /^DVBCards$/i) { + print "DVB_Cards = $value\n" if ($debug & 16); + $DVB_cards = $value; + } + elsif ($key =~ /^defaultprio$/i) { + print "Default Priority = $value\n" if ($debug & 16); + $default_prio = $value; + } + elsif ($key =~ /^Dest$/i) { + print "Destination Host/IP:Port = $value\n" if ($debug & 16); + @Dest = split (/\s+/,$value); + } + elsif ($key =~ /^jointimers$/i) { + print "Join Timers = $value\n" if ($debug & 16); + $jointimers = $value; + } + elsif ($key =~ /^description$/i) { + print "Description = $value\n" if ($debug & 16); + $Description = $value; + } + else { + print "Unkown Key: \"$key\" with Value: \"$value\"\n"; } + } } + print "End Config\n" if ($debug & 16); +} -sub initconfigfile - { - open (FI,"$ENV{HOME}/.master-timer/config") or return; - while (<FI>) - { - s/\#.*//; - chomp; - if ($_) - { - my ($key, $value); - ($key, $value) = split (/\s+=\s+/); - if ($key =~ /^debug$/i) - { - $debug = $value; - print "Debug-Level = $value\n" if ($debug & 16); - } - elsif ($key =~ /^marginstart$/i) - { - print "Marginstart = $value\n" if ($debug & 16); - $marginstart = $value; - } - elsif ($key =~ /^marginstop$/i) - { - print "Marginstop = $value\n" if ($debug & 16); - $marginstop = $value; - } - elsif ($key =~ /^DVBCards$/i) - { - print "DVB_Cards = $value\n" if ($debug & 16); - $DVB_cards = $value; - } - elsif ($key =~ /^defaultprio$/i) - { - print "Default Priority = $value\n" if ($debug & 16); - $default_prio = $value; - } - elsif ($key =~ /^Dest$/i) - { - print "Destination Host/IP:Port = $value\n" if ($debug & 16); - @Dest = split (/\s+/,$value); - } - elsif ($key =~ /^jointimers$/i) - { - print "Join Timers = $value\n" if ($debug & 16); - $jointimers = $value; - } - else - { - print "Unkown Key: \"$key\" with Value: \"$value\"\n"; - } - } - } - print "End Config\n" if ($debug & 16); +sub initcommandline() { + my $Usage = qq{ +Usage: $0 [options] [Instance]... + +Options: -d hostname:Port hostname/ip:Port (localhost:2001) + -c configdir Directory where all config files are located + (~/.master-timer) + -i instance Which VDR-Instance, from the config-file, should be + used + -s Print all series from epg.data and exit + -v debuglevel Level of debug-messages to print + -h This Help-Page +}; + + # Only process commandline if not already processed + if (!$Opts{done}) { + die $Usage if (!getopts("d:p:c:i:sv:h",\%Opts)); } + die $Usage if ($Opts{h}); + # Mark the options as already processed + $Opts{done} = 1; -sub init - { - &initconfigfile(); - &initsocket(); - &initmovie(); - &initblacklist(); - &initdone(); - &initchannellist(); - &initepgdata(); - &inittorecord(); + if ($Opts{v}) { + $debug = $Opts{v}; + } + if ($Opts{i}) { + $currentVDR = $Opts{i}; + } + if ($Opts{d}) { + @Dest = ($Opts{d}); } + if ($Opts{c}) { + $configdir = $Opts{c}; + } +} + +sub init { + &initcommandline(); + &initconfigfile(); + # Process commandline a second time, so that configs from the config-file are overwritten + &initcommandline(); + &initsocket(); + &initmovie(); + &initdone(); + &initchannellist(); + &inittorecord("deepblack"); + &initepgdata(); + &inittorecord("torecord"); +} diff --git a/Tools/master-timer/sample/channels-to-scan b/Tools/master-timer/sample/channels-to-scan index 6acf15792..22f473d57 100644 --- a/Tools/master-timer/sample/channels-to-scan +++ b/Tools/master-timer/sample/channels-to-scan @@ -3,6 +3,4 @@ 3 4 5 -13 -18 -21 +49 diff --git a/Tools/master-timer/sample/config b/Tools/master-timer/sample/config index d01c8a858..3180943f4 100644 --- a/Tools/master-timer/sample/config +++ b/Tools/master-timer/sample/config @@ -1,14 +1,32 @@ -# How Many Seconds "too early" should the timer begin +# Master-Timer config file. Values shown here are defaults. + +# How many seconds "too early" should the timer begin marginstart = 600 -# How Many Seocnds "too long" should the timer end + +# How many seconds "too long" should the timer end marginstop = 600 -# When the Prio isn't provied in the config-File use this value + +# When the Prio isn't provided in the config file use this value defaultprio = 50 -# How many DVB-Cards are installed in the Computer (Not used yet) -DVBCards = 3 -# IP/Hostname:Port of the Destinations (Space is used for delimiter) -Dest-Host = localhost:2001 -# Should Timers on the same channels be joined when they overlapp (0 = off) -jointimers = 1 -# Debug-Level + +# How many DVB cards are installed in the computer (not used yet) +DVBCards = 1 + +# IP/Hostname:Port of the destination (space is used for delimiter) +Dest = localhost:2001 + +# Should timers on the same channels be joined when they overlap (0 = off) +jointimers = 0 + +# Should the description be transfered to VDR? +description = 0 + +# Debug level +# 1 : Dump "torecord" +# 2 : Dump all timers +# 4 : Show when a timer will be deleted +# 8 : Dump the "Done" REs +# 16 : Verbose config reading +# 32 : Dump program variables +# 64 : Excessive deepblack/torecord debuging debug = 0 diff --git a/Tools/master-timer/sample/convert-channel-list b/Tools/master-timer/sample/convert-channel-list new file mode 100644 index 000000000..a97f3c531 --- /dev/null +++ b/Tools/master-timer/sample/convert-channel-list @@ -0,0 +1,26 @@ +Kabel 1|Kabel 1 +MTV|MTV Central +PRW 13TH Street|13th Street +PRW Discovery Channel|Discovery Channel +PRW Disney Channel|Disney Channel +PRW FOX KIDS|Fox Kids +PRW Junior|Junior +PRW K-Toon|K-Toon +PRW Krimi & Co|Krimi &Co +PRW Planet|Planet +PRW Sci-Fantasy|Premiere Sci-Fi +PRW Studio Universal|Studio Universal +PRW Sunset|Sunset +Premiere Action|Premiere Action +Premiere Comedy|Premiere Comedy +Premiere STAR|Premiere Star +Premiere World 1|Premiere 1 +Premiere World 2|Premiere 2 +Premiere World 3|premiere 3 +Pro Sieben|Pro-7 +RTL|RTL +RTL 2|RTL2 +Sat.1|Sat.1 +Super RTL|Super RTL +Viva|VIVA +Vox|VOX diff --git a/Tools/master-timer/sample/deepblack b/Tools/master-timer/sample/deepblack index 63b4f9e94..12884fe73 100644 --- a/Tools/master-timer/sample/deepblack +++ b/Tools/master-timer/sample/deepblack @@ -1,79 +1,172 @@ -Fr alle Flle Stefanie -'MAX' - Das ganze Leben! -10 vor 11 -17:30 live -18:30 -24 Stunden -Andreas Trck -Arabella -^BIZZ$ -Big Brother -Britt - Der Talk um Eins -Brbel Schfer -Call TV -Chicago Hope - Endstation Hoffnung -Chicago Hope -DIE REDAKTION -Dauerwerbesendungen -Die Harald Schmidt Show -Die Oliver Geissen Show -Die Quiz Show -Doppelter Einsatz -Dr. Stefan Frank - Der Arzt, dem die Frauen vertrauen -EXCLUSIV -EXTRA -Ehekriege -Ein Bayer auf Rgen -Emergency Room -Explosiv - Das Magazin -GIRLSCAMP -Glcksrad -Gute Zeiten, schlechte Zeiten -Hallo, Onkel Doc! -Hans Meiser -Hercules -Hinter Gittern - Der Frauenknast -Infomercials -Jeder gegen Jeden -K1 DIE REPORTAGE -K1 Das Magazin -K1 Nachrichten -Kickers -Kochduell -Nachrichten -Nicole - Entscheidung am Nachmittag -OP ruft Dr. Bruckner -PREMIERE WORLD - Das Programm -PROSIEBEN REPORTAGE -Peter Imhof -Programm ab -Programm von -Punkt 12 -Punkt 6 -Punkt 9 -RTL II News -RTL SHOP -RTL aktuell -RTL-Nachtjournal -SAT.1-FRHSTCKSFERNSEHEN -Spiegel TV-Reportage -UEFA Champions -fussball -fball -Vera am Mittag -Wolffs Revier -Zapping -alphateam -peep! -s.a.m. -taff. -^blitz$ -SK Klsch -^Becker$ -Kommissar Rex -Fit For Fun TV -Nur die Liebe zhlt -Unsere kleine Farm -Die Waltons -^Die Zwei$ -^Sieben$ +# [<Anytext>] +# This marks the beginning of a deepblack-entry +# Title = <text> +# This matches a title +# Subtitle = <text> +# This matches a subtitle +# Description = <text> +# This matches a description +# Category = <left>/<right> +# This matches a DTV-Category +# Channel = <Channel> +# Restricts a deepblack-entry to a specific channel. +# A single "!" at start of channel list negates the selection. +# Timeframe = <begin>-<end> +# Restricts a deepblack-entry to a specific timeframe. +# No timers with start time in the timeframe will be programmed. +# minlength = <Number> +# Restricts a deepblack-entry to a specific minimum length +# (postfix "m" for minutes, "h" for hours.) +# maxlength = <Number> +# Restricts a deepblack-entry to a specific maximum length +# (postfix "m" for minutes, "h" for hours.) +# weekday = MTWTFSS +# Restricts a deepblack-entry to a specific weekday +# instance = <Number> +# Only apply this deepblack-entry for a specific Instance +# "s" is a special value used for "-s"-Mode +# +# The "Title", "Subtitle", "Description", "Channel"-Lines can be +# supplied any number of times for a specific entry +# +# To deepblack something at least one of the "Title", "Subtitle" or +# "Description" (If you don't have anything "better" use "Title = ." +# for this matches everything) fields has to be provided. +# These three fields are "include" and the rest are "exclude" fields. + +[Blacklist all Talkshows] +Title = . +Category = Talk + +[Blacklist all Lifestyles] +Title = . +Category = /Lifestyles + +[Blacklist Sport/Tennis] +Title = . +Category = Sport/Tennis + +[Record only ZDF and Pro7] +Title = . +Channel = !ZDF +Channel = ProSieben + +[Blacklist a timeframe] +Title = . +Timeframe = 1000-1400 + +[Blacklist everything with less than 5 minutes duration] +Title = . +maxlength = 5m + +[Sinnlose Serien] +Title = Fr alle Flle Stefanie +Title = Chicago Hope - Endstation Hoffnung +Title = Chicago Hope +Title = Doppelter Einsatz +Title = Dr. Stefan Frank - Der Arzt, dem die Frauen vertrauen +Title = Ehekriege +Title = Ein Bayer auf Rgen +Title = Emergency Room +Title = Gute Zeiten, schlechte Zeiten +Title = Hallo, Onkel Doc! +Title = Hercules +Title = Hinter Gittern - Der Frauenknast +Title = OP ruft Dr. Bruckner +Title = Wolffs Revier +Title = alphateam +Title = SK Klsch +Title = ^Becker$ +Title = Kommissar Rex +Title = Nur die Liebe zhlt +Title = Unsere kleine Farm +Title = Die Waltons +Title = ^Die Zwei$ + +[Glueckspiele] +Title = Die Quiz Show +Title = Glcksrad +Title = Jeder gegen Jeden +Title = Kochduell + +[Infotainment und Boulevardzeug] +Title = 'MAX' - Das ganze Leben! +Title = ^BIZZ$ +Title = Big Brother +Title = GIRLSCAMP +Title = Call TV +Title = DIE REDAKTION +Title = EXCLUSIV +Title = EXTRA +Title = Explosiv - Das Magazin +Title = K1 DIE REPORTAGE +Title = K1 Das Magazin +Title = PROSIEBEN REPORTAGE +Title = Fit For Fun TV +Title = peep! +Title = s.a.m. +Title = taff. +Title = ^blitz$ +Title = Die Harald Schmidt Show +Title = Spiegel TV-Reportage + +[Nachrichten] +Title = 10 vor 11 +Title = 17:30 live +Title = 18:30 +Title = 24 Stunden +Title = Punkt 12 +Title = Punkt 6 +Title = Punkt 9 +Title = RTL II News +Title = RTL aktuell +Title = RTL-Nachtjournal +Title = K1 Nachrichten +Title = Nachrichten + +[Talkshows] +Title = Andreas Trck +Title = Arabella +Title = Britt - Der Talk um Eins +Title = Brbel Schfer +Title = Die Oliver Geissen Show +Title = Peter Imhof +Title = Vera am Mittag +Title = Hans Meiser +Title = Nicole - Entscheidung am Nachmittag +Title = Franklin + +[So richtig Sinnloses] +Title = Dauerwerbesendungen +Title = Infomercials +Title = Kickers +Title = RTL SHOP +Title = SAT.1-FRHSTCKSFERNSEHEN +Title = Zapping + +[PREMIERE WORLD - Das Programm] +Title = PREMIERE WORLD - Das Programm +Title = Programm ab +Title = Programm von + +[Fussball] +Title = fussball +Title = fuball +Title = UEFA Champions + +#Sonstiges +[^Sieben$] +Title = ^Sieben$ + +[Starportrt Kevin Spacey] +Title = Starportrt Kevin Spacey + + +[All Movies for -s] +Subtitle = MOVIE +Instance = s + +[All >= 65m for -s] +Title = . +minlength = 65m +Instance = s diff --git a/Tools/master-timer/sample/subtitle-movie b/Tools/master-timer/sample/subtitle-movie index 3b5a0abf5..9bd357973 100644 --- a/Tools/master-timer/sample/subtitle-movie +++ b/Tools/master-timer/sample/subtitle-movie @@ -3,6 +3,7 @@ ^Actionkomdie$ ^Actionthriller$ ^Agentenfilm$ +^Beziehungskomdie$ ^Biografie$ ^Biographie$ ^Computeranimation$ @@ -12,19 +13,24 @@ ^Familiendrama$ ^Fantasy$ ^Fantasykomdie$ +^Fantasy-Komdie$ ^Gangsterfilm$ ^Gerichtsfilm$ ^Gesellschaftsdrama$ +^Historiendrama$ ^Horrorfilm$ ^Horrorkomdie$ +^Jugenddrama$ ^Kinderfilm$ ^Komdie$ ^Kriegsfilm$ ^Krimikomdie$ ^Kriminalfilm$ ^Liebesfilm$ +^Liebeskomdie$ ^Melodram$ ^Melodrama$ +^Monumentalfilm$ ^Musical$ ^Politthriller$ ^Psychothriller$ @@ -32,10 +38,15 @@ ^Romanze$ ^Satire$ ^Science-Fiction$ +^Science-Fiction-Komdie$ ^Spielfilm$ ^TV Movie$ ^TV-Drama$ +^Teil .$ +^Teil 0.$ ^Thriller$ +^Tragikomdie$ ^Western$ +^Westernkomdie$ ^Zeichentrick$ ^Zeichentrickkomdie$ diff --git a/Tools/master-timer/sample/torecord b/Tools/master-timer/sample/torecord index 030683068..0c97b9162 100644 --- a/Tools/master-timer/sample/torecord +++ b/Tools/master-timer/sample/torecord @@ -1,32 +1,90 @@ -# Format: (Every field is "optional". -# [Title RE|Subtitle RE|Description RE|Channel-Name|Timeframe|Prio|Timer-Title|Marginstart;Marginstop|VDR-Instance] +# [<Anytext>] +# This marks the beginning of a timer entry +# Title = <text> +# This matches a title +# Subtitle = <text> +# This matches a subtitle. +# You may use the magic "MOVIE" or "!MOVIE" which matches +# all entries from file "subtitle-movie". +# Description = <text> +# This matches a description +# Category = <left>/<right> +# This matches a DTV-Category +# Channel = <Channel> +# Restricts a time to a specific channel. +# A single "!" at start of channel list negates the selection. +# Timeframe = <begin>-<end> +# Restricts timer to a specific timeframe. +# Only timers with start time in the timeframe will be programmed. +# minlength = <Number> +# Restricts timer entry to a specific minimum length +# (postfix "m" for minutes, "h" for hours.) +# maxlength = <Number> +# Restricts a timer entry to a specific maximum length +# (postfix "m" for minutes, "h" for hours.) +# weekday = MTWTFSS +# Restricts a timer to a specific weekday +# Timertitle = <text> +# The title used for this timer. +# If this is not provided "Title" will be used. +# If "Title" is not provided the EPG title will be used. +# Margin = <Number>;<Number> +# Seconds added to the beginning and end of the timer. +# Positive numbers will lengthen the recording. +# instance = <Number> +# The instance of VDR for which this timer is. +# If this is not provided the timer is valid for ALL instances. # -# To record something at least one of the "Title", "Subtitle" or "Description" -# Fields has to be provided. This 3 fields are "include" and the rest are -# "exclude" fields! -# -# More than one channel definition can be provided. The delimiter is ";" -# Additionaly you can make a "blacklist" of Channels when you prepent a "!" to the first Channel Definition -# The "!" is only tested for the FIRST Channel definition. -# You can only have a white or a blacklist (Mixing doesn't make sense!) -# -# ex. Record the series "Deep Space Nine" on Sci-Fantasy in the timeframe 09:00 - 14:00 with 60 Seconds Marginstart and -60 Seconds Marginstop -# Deep Space Nine|||Sci-Fantasy|0900-1400|99|DS9|60;-60 +# The "Title", "Subtitle", "Description", "Channel"-Lines can be +# supplied any number of times for a specific entry # -# Record all "Actionfilm"s with "Schwarzenegger" -# |Actionfilm|Schwarzenegger -# -Babylon 5|||!Pro-7||99|60;-60|1 -Deep Space Nine|||||99|DS9|60;-60|2 -Seven Days|||||99| -Stargate|||||99| -Futurama||||2100-2300|50| -Ally McBeal|||||99| -Snoops|||||50| -^Friends$|||||99|Friends| -Pensacola|||||50| -seaQuest|||||50| -||Paltrow|Sci Fantasy;13th Street;Star Kino;Cine Action;Cine Comedy;Romantic Movies;Studio Universal;Premiere||99| -||Aniston|||99| -Matrix +# To record something at least one of the "Title", "Subtitle" or "Description" +# fields has to be provided. These three fields are "include" and the rest are +# "exclude" fields! + +[Dies ist ein Test-Timer] +Title = Titel +Subtitle = Subtitel +Description = Description +Category = Serie/Krimi +Channel = Pro-7 +Channel = VIVA +Timeframe = 1230-1830 +Prio = 50 +Lifetime = 50 +minlength = 10m +maxlength = 3h +weekday = ---T--- +Timertitle = Test +Margin = 600;600 +instance = 2 + +# Record Babylon 5 only if NOT playing on Pro 7; +# recording starts one minute too early and ends +# one minute too early (to skip following ads). +[Babylon 5] +Title = Babylon 5 +Channel = !Pro-7 +Prio = 99 +Margin = 60;-60 + +[DS9] +Title = Deep Space Nine +Prio = 99 +Timertitle = DS9 +Margin = 60;-60 + +[Seven Days] +Title = Seven Days +Prio = 99 + +[Stargate] +Title = Stargate +Prio = 99 + +[Aniston] +Description = Aniston +Prio = 99 +[Matrix] +Title = Matrix diff --git a/config.c b/config.c index a97d7e4c4..87e833235 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.64 2001/09/02 15:04:13 kls Exp $ + * $Id: config.c 1.72 2001/09/16 14:54:32 kls Exp $ */ #include "config.h" @@ -39,6 +39,9 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! { k8, "8", 0 }, { k9, "9", 0 }, { kPower, "Power", 0 }, + { kVolUp, "Volume+", 0 }, + { kVolDn, "Volume-", 0 }, + { kMute, "Mute", 0 }, { kNone, "", 0 }, }; @@ -72,7 +75,7 @@ bool cKeys::Load(const char *FileName) FILE *f = fopen(fileName, "r"); if (f) { int line = 0; - char buffer[MaxBuffer]; + char buffer[MAXPARSEBUFFER]; result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; @@ -122,24 +125,14 @@ bool cKeys::Load(const char *FileName) bool cKeys::Save(void) { - bool result = true; cSafeFile f(fileName); if (f.Open()) { - if (fprintf(f, "Code\t%c\nAddress\t%04X\n", code, address) > 0) { - for (tKey *k = keys; k->type != kNone; k++) { - if (fprintf(f, "%s\t%08X\n", k->name, k->code) <= 0) { - result = false; - break; - } - } - } - else - result = false; - f.Close(); + fprintf(f, "Code\t%c\nAddress\t%04X\n", code, address); + for (tKey *k = keys; k->type != kNone; k++) + fprintf(f, "%s\t%08X\n", k->name, k->code); + return f.Close(); } - else - result = false; - return result; + return false; } eKeys cKeys::Get(unsigned int Code) @@ -303,14 +296,19 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log) isyslog(LOG_INFO, "switching to channel %d", number); } for (int i = 3; i--;) { - if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr)) - return true; + switch (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr)) { + case scrOk: return true; + case scrNoTransfer: if (Interface) + Interface->Error(tr("Can't start Transfer Mode!")); + return false; + case scrFailed: break; // loop will retry + } esyslog(LOG_ERR, "retrying"); } return false; } if (DvbApi->Recording()) - Interface->Info(tr("Channel locked (recording)!")); + Interface->Error(tr("Channel locked (recording)!")); return false; } @@ -649,8 +647,6 @@ cCommands Commands; // -- cChannels -------------------------------------------------------------- -int CurrentGroup = -1; - cChannels Channels; bool cChannels::Load(const char *FileName) @@ -807,8 +803,10 @@ cSetup::cSetup(void) OSDheight = 18; OSDMessageTime = 1; MaxVideoFileSize = MAXVIDEOFILESIZE; - MinEventTimeout = 120; + MinEventTimeout = 30; MinUserInactivity = 120; + MultiSpeedMode = 0; + ShowReplayMode = 0; CurrentChannel = -1; } @@ -846,6 +844,8 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); + else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else return false; @@ -862,7 +862,7 @@ bool cSetup::Load(const char *FileName) FILE *f = fopen(fileName, "r"); if (f) { int line = 0; - char buffer[MaxBuffer]; + char buffer[MAXPARSEBUFFER]; bool result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; @@ -918,13 +918,14 @@ bool cSetup::Save(const char *FileName) fprintf(f, "MaxVideoFileSize = %d\n", MaxVideoFileSize); fprintf(f, "MinEventTimeout = %d\n", MinEventTimeout); fprintf(f, "MinUserInactivity = %d\n", MinUserInactivity); + fprintf(f, "MultiSpeedMode = %d\n", MultiSpeedMode); + fprintf(f, "ShowReplayMode = %d\n", ShowReplayMode); fprintf(f, "CurrentChannel = %d\n", CurrentChannel); - f.Close(); - isyslog(LOG_INFO, "saved setup to %s", FileName); - return true; + if (f.Close()) { + isyslog(LOG_INFO, "saved setup to %s", FileName); + return true; + } } - else - LOG_ERROR_STR(FileName); } else esyslog(LOG_ERR, "attempt to save setup without file name"); diff --git a/config.h b/config.h index c3fab9a8a..194d04e2b 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.72 2001/09/02 15:45:17 kls Exp $ + * $Id: config.h 1.79 2001/09/16 14:54:36 kls Exp $ */ #ifndef __CONFIG_H @@ -19,9 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.94" - -#define MaxBuffer 10000 +#define VDRVERSION "0.95" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -45,6 +43,9 @@ enum eKeys { // "Up" and "Down" must be the first two keys! kBlue, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, kPower, + kVolUp, + kVolDn, + kMute, kNone, // The following flags are OR'd with the above codes: k_Repeat = 0x8000, @@ -61,9 +62,9 @@ enum eKeys { // "Up" and "Down" must be the first two keys! #define kEditCut k2 #define kEditTest k8 -#define RAWKEY(k) ((k) & ~k_Flags) +#define RAWKEY(k) (eKeys((k) & ~k_Flags)) #define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) -#define NORMALKEY(k) ((k) & ~k_Repeat) +#define NORMALKEY(k) (eKeys((k) & ~k_Repeat)) struct tKey { eKeys type; @@ -192,7 +193,7 @@ template<class T> class cConfig : public cList<T> { FILE *f = fopen(fileName, "r"); if (f) { int line = 0; - char buffer[MaxBuffer]; + char buffer[MAXPARSEBUFFER]; result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; @@ -228,7 +229,8 @@ template<class T> class cConfig : public cList<T> { } l = (T *)l->Next(); } - f.Close(); + if (!f.Close()) + result = false; } else result = false; @@ -262,8 +264,6 @@ class cTimers : public cConfig<cTimer> { class cCommands : public cConfig<cCommand> {}; -extern int CurrentGroup; - extern cChannels Channels; extern cTimers Timers; extern cKeys Keys; @@ -299,6 +299,8 @@ class cSetup { int OSDMessageTime; int MaxVideoFileSize; int MinEventTimeout, MinUserInactivity; + int MultiSpeedMode; + int ShowReplayMode; int CurrentChannel; cSetup(void); bool Load(const char *FileName); diff --git a/dvbapi.c b/dvbapi.c index 8e502ed15..16b3e3084 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.111 2001/09/01 13:27:52 kls Exp $ + * $Id: dvbapi.c 1.125 2001/09/16 13:55:03 kls Exp $ */ //#define DVDDEBUG 1 @@ -40,18 +40,14 @@ extern "C" { #include "tools.h" #include "videodir.h" -#define DEV_VIDEO "/dev/video" -#define DEV_OST_OSD "/dev/ost/osd" -#define DEV_OST_QAMFE "/dev/ost/qamfe" -#define DEV_OST_QPSKFE "/dev/ost/qpskfe" -#define DEV_OST_SEC "/dev/ost/sec" -#define DEV_OST_DVR "/dev/ost/dvr" -#define DEV_OST_DEMUX "/dev/ost/demux" -#define DEV_OST_VIDEO "/dev/ost/video" -#define DEV_OST_AUDIO "/dev/ost/audio" - -#define KILOBYTE(n) ((n) * 1024) -#define MEGABYTE(n) ((n) * 1024 * 1024) +#define DEV_VIDEO "/dev/video" +#define DEV_OST_OSD "/dev/ost/osd" +#define DEV_OST_FRONTEND "/dev/ost/frontend" +#define DEV_OST_SEC "/dev/ost/sec" +#define DEV_OST_DVR "/dev/ost/dvr" +#define DEV_OST_DEMUX "/dev/ost/demux" +#define DEV_OST_VIDEO "/dev/ost/video" +#define DEV_OST_AUDIO "/dev/ost/audio" // The size of the array used to buffer video data: // (must be larger than MINVIDEODATA - see remux.h) @@ -288,7 +284,7 @@ int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *F int d = Forward ? 1 : -1; for (;;) { Index += d; - if (Index >= 0 && Index <= last - 100) { // '- 100': need to stay off the end! + if (Index >= 0 && Index <= last) { if (index[Index].type == I_FRAME) { if (FileNumber) *FileNumber = index[Index].number; @@ -628,19 +624,84 @@ int ReadFrame(int f, uchar *b, int Length, int Max) return r; } +// --- cBackTrace ---------------------------------------------------------- + +#define AVG_FRAME_SIZE 15000 // an assumption about the average frame size +#define DVB_BUF_SIZE (256 * 1024) // an assumption about the dvb firmware buffer size +#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) // how many entries are needed to backtrace buffer contents + +class cBackTrace { +private: + int index[BACKTRACE_ENTRIES]; + int length[BACKTRACE_ENTRIES]; + int pos, num; +public: + cBackTrace(void); + void Clear(void); + void Add(int Index, int Length); + int Get(bool Forward); + }; + +cBackTrace::cBackTrace(void) +{ + Clear(); +} + +void cBackTrace::Clear(void) +{ + pos = num = 0; +} + +void cBackTrace::Add(int Index, int Length) +{ + index[pos] = Index; + length[pos] = Length; + if (++pos >= BACKTRACE_ENTRIES) + pos = 0; + if (num < BACKTRACE_ENTRIES) + num++; +} + +int cBackTrace::Get(bool Forward) +{ + int p = pos; + int n = num; + int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); //XXX (256 * 1024) == DVB_BUF_SIZE ??? + int i = -1; + + while (n && l > 0) { + if (--p < 0) + p = BACKTRACE_ENTRIES - 1; + i = index[p] - 1; + l -= length[p]; + n--; + } + return i; +} + // --- cPlayBuffer --------------------------------------------------------- +#define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct? + class cPlayBuffer : public cRingBufferFrame { +private: + cBackTrace backTrace; protected: + enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill }; + enum ePlayDirs { pdForward, pdBackward }; + static int Speeds[]; cDvbApi *dvbApi; int videoDev, audioDev; - FILE *dolbyDev; + cPipe dolbyDev; int blockInput, blockOutput; - bool still, paused, fastForward, fastRewind; + ePlayModes playMode; + ePlayDirs playDir; + int trickSpeed; int readIndex, writeIndex; bool canDoTrickMode; bool canToggleAudioTrack; uchar audioTrack; + void TrickSpeed(int Increment); virtual void Empty(bool Block = false); virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {} virtual void Output(void); @@ -655,34 +716,38 @@ class cPlayBuffer : public cRingBufferFrame { virtual void SkipSeconds(int Seconds) {} virtual void Goto(int Position, bool Still = false) {} virtual void GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { Current = Total = -1; } + bool GetReplayMode(bool &Play, bool &Forward, int &Speed); bool CanToggleAudioTrack(void) { return canToggleAudioTrack; }; virtual void ToggleAudioTrack(void); }; +#define NORMAL_SPEED 4 // the index of the '1' entry in the following array +#define MAX_SPEEDS 3 // the offset of the maximum speed from normal speed in either direction +#define SPEED_MULT 12 // the speed multiplier +int cPlayBuffer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; + cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev) :cRingBufferFrame(VIDEOBUFSIZE) { dvbApi = DvbApi; videoDev = VideoDev; audioDev = AudioDev; - dolbyDev = NULL; blockInput = blockOutput = false; - still = paused = fastForward = fastRewind = false; + playMode = pmPlay; + playDir = pdForward; + trickSpeed = NORMAL_SPEED; readIndex = writeIndex = -1; canDoTrickMode = false; canToggleAudioTrack = false; audioTrack = 0xC0; if (cDvbApi::AudioCommand()) { - dolbyDev = popen(cDvbApi::AudioCommand(), "w"); - if (!dolbyDev) + if (!dolbyDev.Open(cDvbApi::AudioCommand(), "w")) esyslog(LOG_ERR, "ERROR: can't open pipe to audio command '%s'", cDvbApi::AudioCommand()); } } cPlayBuffer::~cPlayBuffer() { - if (dolbyDev) - pclose(dolbyDev); } void cPlayBuffer::Output(void) @@ -697,25 +762,24 @@ void cPlayBuffer::Output(void) } const cFrame *frame = Get(); if (frame) { - StripAudioPackets((uchar *)frame->Data(), frame->Count(), (fastForward || fastRewind) ? 0x00 : audioTrack);//XXX - for (int i = 0; i < ((paused && fastRewind) ? 24 : 1); i++) { // show every I_FRAME 24 times in slow rewind mode to achieve roughly the same speed as in slow forward mode - const uchar *p = frame->Data(); - int r = frame->Count(); - while (r > 0 && Busy() && !blockOutput) { - cFile::FileReadyForWriting(videoDev, 100); - int w = write(videoDev, p, r); - if (w > 0) { - p += w; - r -= w; - } - else if (w < 0 && FATALERRNO) { - LOG_ERROR; - Stop(); - return; - } - } - writeIndex = frame->Index(); - } + StripAudioPackets((uchar *)frame->Data(), frame->Count(), (playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX + const uchar *p = frame->Data(); + int r = frame->Count(); + while (r > 0 && Busy() && !blockOutput) { + cFile::FileReadyForWriting(videoDev, 100); + int w = write(videoDev, p, r); + if (w > 0) { + p += w; + r -= w; + } + else if (w < 0 && FATALERRNO) { + LOG_ERROR; + Stop(); + return; + } + } + writeIndex = frame->Index(); + backTrace.Add(frame->Index(), frame->Count()); Drop(frame); } } @@ -723,6 +787,26 @@ void cPlayBuffer::Output(void) dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); } +void cPlayBuffer::TrickSpeed(int Increment) +{ + int nts = trickSpeed + Increment; + if (Speeds[nts] == 1) { + trickSpeed = nts; + if (playMode == pmFast) + Play(); + else + Pause(); + } + else if (Speeds[nts]) { + trickSpeed = nts; + int Mult = (playMode == pmSlow && playDir == pdForward) ? 1 : SPEED_MULT; + int sp = (Speeds[nts] > 0) ? Mult / Speeds[nts] : -Speeds[nts] * Mult; + if (sp > MAX_VIDEO_SLOWMOTION) + sp = MAX_VIDEO_SLOWMOTION; + CHECK(ioctl(videoDev, VIDEO_SLOWMOTION, sp)); + } +} + void cPlayBuffer::Empty(bool Block) { if (!(blockInput || blockOutput)) { @@ -733,83 +817,153 @@ void cPlayBuffer::Empty(bool Block) while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2) usleep(1); Lock(); - readIndex = writeIndex; + if ((readIndex = backTrace.Get(playDir == pdForward)) < 0) + readIndex = writeIndex; cRingBufferFrame::Clear(); CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER)); CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER)); } if (!Block) { blockInput = blockOutput = 0; + backTrace.Clear(); Unlock(); } } void cPlayBuffer::Pause(void) { - paused = !paused; - bool empty = fastForward || fastRewind; - if (empty) - Empty(true); - fastForward = fastRewind = false; - CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE)); - //CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); //XXX this caused chirping sound when playing a DVD - still = false; - if (empty) - Empty(false); + if (playMode == pmPause || playMode == pmStill) + Play(); + else { + bool empty = (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)); + if (empty) + Empty(true); + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); + CHECK(ioctl(videoDev, VIDEO_FREEZE)); + playMode = pmPause; + if (empty) + Empty(false); + } } void cPlayBuffer::Play(void) { - if (fastForward || fastRewind || paused) { - bool empty = !paused || fastRewind; + if (playMode != pmPlay) { + bool empty = (playMode == pmStill || playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)); if (empty) Empty(true); - still = false; - CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY)); CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); - //CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); //XXX this caused chirping sound when playing a DVD + CHECK(ioctl(videoDev, VIDEO_CONTINUE)); + playMode = pmPlay; + playDir = pdForward; if (empty) Empty(false); - fastForward = fastRewind = paused = false; - } + } } void cPlayBuffer::Forward(void) { - if (canDoTrickMode || paused) { - bool empty = !paused || fastRewind; - if (empty) { - Empty(true); - if (fastForward) - readIndex -= 150; // this about compensates for the buffered data, so that we don't get too far ahead - } - still = false; - fastForward = !fastForward; - fastRewind = false; - if (paused) - CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2)); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward)); - CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused)); - if (empty) - Empty(false); + if (canDoTrickMode) { + switch (playMode) { + case pmFast: + if (Setup.MultiSpeedMode) { + TrickSpeed(playDir == pdForward ? 1 : -1); + break; + } + else if (playDir == pdForward) { + Play(); + break; + } + // run into pmPlay + case pmPlay: + Empty(true); + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); + playMode = pmFast; + playDir = pdForward; + trickSpeed = NORMAL_SPEED; + TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); + Empty(false); + break; + case pmSlow: + if (Setup.MultiSpeedMode) { + TrickSpeed(playDir == pdForward ? -1 : 1); + break; + } + else if (playDir == pdForward) { + Pause(); + break; + } + // run into pmPause + case pmStill: + case pmPause: + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); + playMode = pmSlow; + playDir = pdForward; + trickSpeed = NORMAL_SPEED; + TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); + break; + } } } void cPlayBuffer::Backward(void) { if (canDoTrickMode) { - Empty(true); - still = false; - fastRewind = !fastRewind; - fastForward = false; - if (paused) - CHECK(ioctl(videoDev, fastRewind ? VIDEO_CONTINUE : VIDEO_FREEZE)); - CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind)); - CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused)); - Empty(false); + switch (playMode) { + case pmFast: + if (Setup.MultiSpeedMode) { + TrickSpeed(playDir == pdBackward ? 1 : -1); + break; + } + else if (playDir == pdBackward) { + Play(); + break; + } + // run into pmPlay + case pmPlay: + Empty(true); + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); + playMode = pmFast; + playDir = pdBackward; + trickSpeed = NORMAL_SPEED; + TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); + Empty(false); + break; + case pmSlow: + if (Setup.MultiSpeedMode) { + TrickSpeed(playDir == pdBackward ? -1 : 1); + break; + } + else if (playDir == pdBackward) { + Pause(); + break; + } + // run into pmPause + case pmStill: + case pmPause: + Empty(true); + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); + playMode = pmSlow; + playDir = pdBackward; + trickSpeed = NORMAL_SPEED; + TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); + Empty(false); + break; + } } } +bool cPlayBuffer::GetReplayMode(bool &Play, bool &Forward, int &Speed) +{ + Play = (playMode == pmPlay || playMode == pmFast); + Forward = (playDir == pdForward); + if (playMode == pmFast || playMode == pmSlow) + Speed = Setup.MultiSpeedMode ? abs(trickSpeed - NORMAL_SPEED) : 0; + else + Speed = -1; + return true; +} + void cPlayBuffer::ToggleAudioTrack(void) { if (CanToggleAudioTrack()) { @@ -890,18 +1044,17 @@ void cReplayBuffer::Input(void) blockInput = 1; continue; } - if (!still) { + if (playMode != pmStill) { int r = 0; - if (fastForward && !paused || fastRewind) { + if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { uchar FileNumber; int FileOffset, Length; - int Index = index->GetNextIFrame(readIndex, fastForward, &FileNumber, &FileOffset, &Length); + int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length); if (Index >= 0) { if (!NextFile(FileNumber, FileOffset)) break; } else { - paused = fastForward = fastRewind = false; Play(); continue; } @@ -1073,23 +1226,21 @@ void cReplayBuffer::Goto(int Index, bool Still) { if (index) { Empty(true); - if (paused) - CHECK(ioctl(videoDev, VIDEO_CONTINUE)); if (++Index <= 0) Index = 1; // not '0', to allow GetNextIFrame() below to work! uchar FileNumber; int FileOffset, Length; Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { - still = true; uchar b[MAXFRAMESIZE]; int r = ReadFrame(replayFile, b, Length, sizeof(b)); - if (r > 0) + if (r > 0) { + if (playMode == pmPause) + CHECK(ioctl(videoDev, VIDEO_CONTINUE)); DisplayFrame(b, r); - paused = true; + } + playMode = pmStill; } - else - still = false; readIndex = writeIndex = Index; Empty(false); } @@ -1098,7 +1249,7 @@ void cReplayBuffer::Goto(int Index, bool Still) void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) { if (index) { - if (still) + if (playMode == pmStill) Current = readIndex; else { Current = writeIndex; @@ -1180,7 +1331,7 @@ class cDVDplayBuffer : public cPlayBuffer { int is_nav_pack(unsigned char *buffer); void Close(void); virtual void Empty(bool Block = false); - int decode_packet(unsigned char *sector, int iframe); + int decode_packet(unsigned char *sector, bool trickmode); int ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType); bool PacketStart(uchar **Data, int len); int GetPacketType(const uchar *Data); @@ -1460,7 +1611,7 @@ void cDVDplayBuffer::Input(void) } // init settings for next state - if (!fastRewind) + if (playDir == pdForward) cur_pack = cur_pgc->cell_playback[cur_cell].first_sector; else cur_pack = cur_pgc->cell_playback[cur_cell].last_vobu_start_sector; @@ -1478,7 +1629,7 @@ void cDVDplayBuffer::Input(void) * We loop until we're out of this cell. */ - if (!fastRewind) { + if (playDir == pdForward) { if (cur_pack >= cur_pgc->cell_playback[cur_cell].last_sector) { cur_cell = next_cell; #ifdef DVDDEBUG @@ -1573,7 +1724,7 @@ void cDVDplayBuffer::Input(void) case cREADFRAME: { - int trickMode = (fastForward && !paused || fastRewind); + bool trickMode = (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)); /* FIXME: * the entire trickMode code relies on the assumtion @@ -1582,7 +1733,7 @@ void cDVDplayBuffer::Input(void) * I have no clue wether that is correct or not !!! */ if (trickMode && (skipCnt++ % 4 != 0)) { - cur_pack = (!fastRewind) ? next_vobu : prev_vobu; + cur_pack = (playDir == pdForward) ? next_vobu : prev_vobu; NextState(cOUTPACK); break; } @@ -1609,7 +1760,7 @@ void cDVDplayBuffer::Input(void) case cOUTFRAMES: { - int trickMode = (fastForward && !paused || fastRewind); + bool trickMode = (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)); /** * Output cursize packs. @@ -1624,7 +1775,7 @@ void cDVDplayBuffer::Input(void) if (decode_packet(&data[pktcnt * DVD_VIDEO_LB_LEN], trickMode) != 1) { //we've got a video packet if (trickMode) { //dsyslog(LOG_INFO, "DVD: did pack: %d", pktcnt); - cur_pack = (!fastRewind) ? next_vobu : prev_vobu; + cur_pack = (playDir == pdForward) ? next_vobu : prev_vobu; NextState(cOUTPACK); break; } @@ -1835,7 +1986,7 @@ void cDVDplayBuffer::putFrame(unsigned char *sector, int length) ; } -int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode) +int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode) { uchar pt = 1; #if 0 @@ -2213,6 +2364,8 @@ void cCuttingBuffer::Action(void) // Write one frame: if (PictureType == I_FRAME) { // every file shall start with an I_FRAME + if (!Mark) // edited version shall end before next I-frame + break; if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) { toFile = toFileName->NextFile(); if (toFile < 0) @@ -2231,16 +2384,18 @@ void cCuttingBuffer::Action(void) if (Mark && Index >= Mark->position) { Mark = fromMarks.Next(Mark); + toMarks.Add(LastIFrame); + if (Mark) + toMarks.Add(toIndex->Last() + 1); + toMarks.Save(); if (Mark) { Index = Mark->position; Mark = fromMarks.Next(Mark); CurrentFileNumber = 0; // triggers SetOffset before reading next frame - toMarks.Add(LastIFrame); - toMarks.Add(toIndex->Last() + 1); - toMarks.Save(); } - else - break; // final end mark reached + // the 'else' case (i.e. 'final end mark reached') is handled above + // in 'Write one frame', so that the edited version will end right + // before the next I-frame. } } } @@ -2322,9 +2477,8 @@ cDvbApi::cDvbApi(int n) // Devices that are only present on DVB-C or DVB-S cards: - fd_qamfe = OstOpen(DEV_OST_QAMFE, n, O_RDWR); - fd_qpskfe = OstOpen(DEV_OST_QPSKFE, n, O_RDWR); - fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR); + fd_frontend = OstOpen(DEV_OST_FRONTEND, n, O_RDWR); + fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR); // Devices that all DVB cards must have: @@ -2355,7 +2509,7 @@ cDvbApi::cDvbApi(int n) // We only check the devices that must be present - the others will be checked before accessing them: - if (((fd_qpskfe >= 0 && fd_sec >= 0) || fd_qamfe >= 0) && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxd1 >= 0 && fd_demuxd2 >= 0 && fd_demuxt >= 0) { + if (fd_frontend >= 0 && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxd1 >= 0 && fd_demuxd2 >= 0 && fd_demuxt >= 0) { siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n)); if (!dvbApi[0]) // only the first one shall set the system time siProcessor->SetUseTSTime(Setup.SetSystemTime); @@ -2385,6 +2539,8 @@ cDvbApi::cDvbApi(int n) osd = NULL; #endif currentChannel = 1; + mute = false; + volume = 255; } cDvbApi::~cDvbApi() @@ -2475,7 +2631,7 @@ bool cDvbApi::Init(void) NumDvbApis = 0; for (int i = 0; i < MAXDVBAPI; i++) { if (useDvbApi == 0 || (useDvbApi & (1 << i)) != 0) { - if (Probe(OstName(DEV_OST_QPSKFE, i)) || Probe(OstName(DEV_OST_QAMFE, i))) + if (Probe(OstName(DEV_OST_FRONTEND, i))) dvbApi[NumDvbApis++] = new cDvbApi(i); else break; @@ -2674,7 +2830,10 @@ bool cDvbApi::OvlG(int SizeX, int SizeY, int PosX, int PosY) vw.width = SizeX; vw.height = SizeY; vw.chromakey = ovlPalette; - vw.flags = VIDEO_WINDOW_CHROMAKEY; // VIDEO_WINDOW_INTERLACE; //VIDEO_CLIP_BITMAP; +#ifndef VID_TYPE_CHROMAKEY // name changed somewhere down the road in kernel 2.4.x +#define VID_TYPE_CHROMAKEY VIDEO_WINDOW_CHROMAKEY +#endif + vw.flags = VID_TYPE_CHROMAKEY; // VIDEO_WINDOW_INTERLACE; //VIDEO_CLIP_BITMAP; vw.clips = ovlClipRects; vw.clipcount = ovlClipCount; result |= ioctl(videoDev, VIDIOCSWIN, &vw); @@ -2781,7 +2940,7 @@ void cDvbApi::Open(int w, int h) cols = w; rows = h; #ifdef DEBUG_OSD - window = subwin(stdscr, h, w, d, 0); + window = subwin(stdscr, h, w, d, (Setup.OSDwidth - w) / 2); syncok(window, true); #define B2C(b) (((b) * 1000) / 255) #define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b)) @@ -2799,7 +2958,7 @@ void cDvbApi::Open(int w, int h) w *= charWidth; h *= lineHeight; d *= lineHeight; - int x = (720 - (Setup.OSDwidth - 1) * charWidth) / 2; //TODO PAL vs. NTSC??? + int x = (720 - w + charWidth) / 2; //TODO PAL vs. NTSC??? int y = (576 - Setup.OSDheight * lineHeight) / 2 + d; //XXX osd = new cDvbOsd(fd_osd, x, y); @@ -3031,7 +3190,7 @@ bool cDvbApi::SetPids(bool ForRecording) SetDpid2(ForRecording ? dPid2 : 0, DMX_OUT_TS_TAP); } -bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr) +eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr) { // Make sure the siProcessor won't access the device while switching cThreadLock ThreadLock(siProcessor); @@ -3075,7 +3234,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, bool ChannelSynced = false; - if (fd_qpskfe >= 0 && fd_sec >= 0) { // DVB-S + if (fd_sec >= 0) { // DVB-S // Frequency offsets: @@ -3091,10 +3250,10 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, tone = SEC_TONE_ON; } - qpskParameters qpsk; - qpsk.iFrequency = freq * 1000UL; - qpsk.SymbolRate = Srate * 1000UL; - qpsk.FEC_inner = FEC_AUTO; + FrontendParameters Frontend; + Frontend.Frequency = freq * 1000UL; + Frontend.u.qpsk.SymbolRate = Srate * 1000UL; + Frontend.u.qpsk.FEC_inner = FEC_AUTO; int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; @@ -3118,65 +3277,65 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, // Tuning: - CHECK(ioctl(fd_qpskfe, QPSK_TUNE, &qpsk)); + CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); // Wait for channel sync: - if (cFile::FileReady(fd_qpskfe, 5000)) { - qpskEvent event; - int res = ioctl(fd_qpskfe, QPSK_GET_EVENT, &event); + if (cFile::FileReady(fd_frontend, 5000)) { + FrontendEvent event; + int res = ioctl(fd_frontend, FE_GET_EVENT, &event); if (res >= 0) ChannelSynced = event.type == FE_COMPLETION_EV; else - esyslog(LOG_ERR, "ERROR %d in qpsk get event", res); + esyslog(LOG_ERR, "ERROR %d in frontend get event", res); } else esyslog(LOG_ERR, "ERROR: timeout while tuning"); } - else if (fd_qamfe >= 0) { // DVB-C + else if (fd_frontend >= 0) { // DVB-C // Frequency and symbol rate: - qamParameters qam; - qam.Frequency = FrequencyMHz * 1000000UL; - qam.SymbolRate = Srate * 1000UL; - qam.FEC_inner = FEC_AUTO; - qam.QAM = QAM_64; + FrontendParameters Frontend; + Frontend.Frequency = FrequencyMHz * 1000000UL; + Frontend.u.qam.SymbolRate = Srate * 1000UL; + Frontend.u.qam.FEC_inner = FEC_AUTO; + Frontend.u.qam.QAM = QAM_64; // Tuning: - CHECK(ioctl(fd_qamfe, QAM_TUNE, &qam)); + CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); // Wait for channel sync: - if (cFile::FileReady(fd_qamfe, 5000)) { - qamEvent event; - int res = ioctl(fd_qamfe, QAM_GET_EVENT, &event); + if (cFile::FileReady(fd_frontend, 5000)) { + FrontendEvent event; + int res = ioctl(fd_frontend, FE_GET_EVENT, &event); if (res >= 0) ChannelSynced = event.type == FE_COMPLETION_EV; else - esyslog(LOG_ERR, "ERROR %d in qam get event", res); + esyslog(LOG_ERR, "ERROR %d in frontend get event", res); } else esyslog(LOG_ERR, "ERROR: timeout while tuning"); } else { esyslog(LOG_ERR, "ERROR: attempt to set channel without DVB-S or DVB-C device"); - return false; + return scrFailed; } if (!ChannelSynced) { esyslog(LOG_ERR, "ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1); if (this == PrimaryDvbApi) cThread::RaisePanic(); - return false; + return scrFailed; } // PID settings: if (!SetPids(false)) { esyslog(LOG_ERR, "ERROR: failed to set PIDs for channel %d", ChannelNumber); - return false; + return scrFailed; } SetTpid(Tpid, DMX_OUT_DECODER); if (fd_audio >= 0) @@ -3186,19 +3345,21 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, if (this == PrimaryDvbApi && siProcessor) siProcessor->SetCurrentServiceID(Pnr); + eSetChannelResult Result = scrOk; + // If this DVB card can't receive this channel, let's see if we can // use the card that actually can receive it and transfer data from there: if (NeedsTransferMode) { cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); - if (CaDvbApi) { - if (!CaDvbApi->Recording()) { - if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) { - SetModeReplay(); - transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video); - } + if (CaDvbApi && !CaDvbApi->Recording()) { + if ((Result = CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) == scrOk) { + SetModeReplay(); + transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video); } } + else + Result = scrNoTransfer; } if (fd_video >= 0 && fd_audio >= 0) { @@ -3206,7 +3367,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); } - return true; + return Result; } bool cDvbApi::Transferring(void) @@ -3372,8 +3533,10 @@ void cDvbApi::StopReplay(void) if (this == PrimaryDvbApi) { // let's explicitly switch the channel back in case it was in Transfer Mode: cChannel *Channel = Channels.GetByNumber(currentChannel); - if (Channel) + if (Channel) { Channel->Switch(this, false); + usleep(100000); // allow driver to sync in case a new replay will start immediately + } } } } @@ -3424,6 +3587,11 @@ bool cDvbApi::GetIndex(int &Current, int &Total, bool SnapToIFrame) return false; } +bool cDvbApi::GetReplayMode(bool &Play, bool &Forward, int &Speed) +{ + return replayBuffer && replayBuffer->GetReplayMode(Play, Forward, Speed); +} + void cDvbApi::Goto(int Position, bool Still) { if (replayBuffer) @@ -3456,6 +3624,24 @@ bool cDvbApi::ToggleAudioTrack(void) return false; } +void cDvbApi::ToggleMute(void) +{ + int OldVolume = volume; + mute = !mute; + SetVolume(0, mute); + volume = OldVolume; +} + +void cDvbApi::SetVolume(int Volume, bool Absolute) +{ + if (fd_audio >= 0) { + volume = min(max(Absolute ? Volume : volume + Volume, 0), 255); + audioMixer_t am; + am.volume_left = am.volume_right = volume; + CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am)); + } +} + void cDvbApi::SetAudioCommand(const char *Command) { delete audioCommand; diff --git a/dvbapi.h b/dvbapi.h index c93a9f35d..d0a68e795 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.47 2001/08/25 13:37:00 kls Exp $ + * $Id: dvbapi.h 1.51 2001/09/16 13:54:23 kls Exp $ */ #ifndef __DVBAPI_H @@ -56,6 +56,8 @@ const char *IndexToHMSF(int Index, bool WithFrame = false); int HMSFToIndex(const char *HMSF); // Converts the given string (format: "hh:mm:ss.ff") to an index. +enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed }; + class cChannel; class cRecordBuffer; @@ -85,7 +87,7 @@ class cDvbApi { friend class cTransferBuffer; private: int videoDev; - int fd_osd, fd_qpskfe, fd_qamfe, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxd1, fd_demuxd2, fd_demuxv, fd_demuxt; + int fd_osd, fd_frontend, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxd1, fd_demuxd2, fd_demuxv, fd_demuxt; int vPid, aPid1, aPid2, dPid1, dPid2; bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output); bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO, Vpid, Output); } @@ -203,7 +205,7 @@ class cDvbApi { private: int currentChannel; public: - bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr); + eSetChannelResult SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr); static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } int Channel(void) { return currentChannel; } @@ -287,6 +289,12 @@ class cDvbApi { bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); // Returns the current and total frame index, optionally snapped to the // nearest I-frame. + bool GetReplayMode(bool &Play, bool &Forward, int &Speed); + // Returns the current replay mode (if applicable). + // 'Play' tells whether we are playing or pausing, 'Forward' tells whether + // we are going forward or backward and 'Speed' is -1 if this is normal + // play/pause mode, 0 if it is single speed fast/slow forward/back mode + // and >0 if this is multi speed mode. void Goto(int Index, bool Still = false); // Positions to the given index and displays that frame as a still picture // if Still is true. @@ -307,6 +315,18 @@ class cDvbApi { public: static void SetAudioCommand(const char *Command); static const char *AudioCommand(void) { return audioCommand; } + + // Volume facilities: + +private: + bool mute; + int volume; +public: + void ToggleMute(void); + // Turns the volume off or on. + void SetVolume(int Volume, bool Absolute = false); + // Sets the volume to the given value, either absolutely or relative to + // the current volume. }; class cEITScanner { diff --git a/i18n.c b/i18n.c index 086d85a3c..5e440c951 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.39 2001/09/02 15:17:33 kls Exp $ + * $Id: i18n.c 1.43 2001/09/16 14:43:05 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -658,6 +658,15 @@ const tPhrase Phrases[] = { "Chane verrouille (enregistrement en cours)!", "Kanalen er lst (opptak)!", }, + { "Can't start Transfer Mode!", + "Transfer-Mode kann nicht gestartet werden!", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Can't start editing process!", "Schnitt kann nicht gestartet werden!", "Ne morem zaceti urejanja!", @@ -938,6 +947,24 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO }, + { "MultiSpeedMode", + "MultiSpeed Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "ShowReplayMode", + "Wiedergabe Status", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // The days of the week: { "MTWTFSS", "MDMDFSS", @@ -1184,6 +1211,33 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO }, + { "Volume+", + "Lautstrke+", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Volume-", + "Lautstrke-", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Mute", + "Stumm", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // Miscellaneous: { "yes", "ja", diff --git a/keys-pc.conf b/keys-pc.conf index ab4b58d5e..d727712d3 100644 --- a/keys-pc.conf +++ b/keys-pc.conf @@ -22,3 +22,6 @@ Blue 0000010C 8 00000038 9 00000039 Power 00000050 +Volume+ 0000002B +Volume- 0000002D +Mute 0000006D diff --git a/menu.c b/menu.c index 5ff54cbd8..98fd30235 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.115 2001/09/02 15:27:54 kls Exp $ + * $Id: menu.c 1.120 2001/09/15 10:36:31 kls Exp $ */ #include "menu.h" @@ -16,8 +16,9 @@ #include "eit.h" #include "i18n.h" -#define MENUTIMEOUT 120 // seconds -#define MAXWAIT4EPGINFO 10 // seconds +#define MENUTIMEOUT 120 // seconds +#define MAXWAIT4EPGINFO 10 // seconds +#define MODETIMEOUT 3 // seconds const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#~^"; @@ -1725,6 +1726,8 @@ void cMenuSetup::Set(void) Add(new cMenuEditIntItem( tr("MaxVideoFileSize"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); Add(new cMenuEditIntItem( tr("MinEventTimeout"), &data.MinEventTimeout)); Add(new cMenuEditIntItem( tr("MinUserInactivity"), &data.MinUserInactivity)); + Add(new cMenuEditBoolItem(tr("MultiSpeedMode"), &data.MultiSpeedMode)); + Add(new cMenuEditBoolItem(tr("ShowReplayMode"), &data.ShowReplayMode)); } eOSState cMenuSetup::ProcessKey(eKeys Key) @@ -1920,14 +1923,14 @@ eOSState cMenuMain::ProcessKey(eKeys Key) #define DIRECTCHANNELTIMEOUT 1000 //ms #define INFOTIMEOUT 5000 //ms -cDisplayChannel::cDisplayChannel(int Number, bool Switched, bool Group) +cDisplayChannel::cDisplayChannel(int Number, bool Switched) :cOsdBase(true) { - group = Group; - withInfo = !group && (!Switched || Setup.ShowInfoOnChSwitch); + group = -1; + withInfo = !Switched || Setup.ShowInfoOnChSwitch; lines = 0; oldNumber = number = 0; - cChannel *channel = Group ? Channels.Get(Number) : Channels.GetByNumber(Number); + cChannel *channel = Channels.GetByNumber(Number); Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? 5 : -5); if (channel) { DisplayChannel(channel); @@ -1939,6 +1942,7 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched, bool Group) cDisplayChannel::cDisplayChannel(eKeys FirstKey) :cOsdBase(true) { + group = -1; oldNumber = cDvbApi::CurrentChannel(); number = 0; lastTime = time_ms(); @@ -2049,6 +2053,32 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) } } break; + case kLeft: + case kRight: + withInfo = false; + if (group < 0) { + cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel()); + if (channel) + group = channel->Index(); + } + if (group >= 0) { + int SaveGroup = group; + if (Key == kRight) + group = Channels.GetNextGroup(group) ; + else + group = Channels.GetPrevGroup(group < 1 ? 1 : group); + if (group < 0) + group = SaveGroup; + cChannel *channel = Channels.Get(group); + if (channel) { + Interface->Clear(); + DisplayChannel(channel); + if (!channel->groupSep) + group = -1; + } + } + lastTime = time_ms(); + break; case kNone: if (number && time_ms() - lastTime > DIRECTCHANNELTIMEOUT) { if (number > 0 && !Channels.SwitchTo(number)) @@ -2059,8 +2089,8 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) //TODO //XXX case kGreen: return osEventNow; //XXX case kYellow: return osEventNext; - case kOk: if (group) - Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(CurrentGroup))->number); + case kOk: if (group >= 0) + Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(group))->number); return osEnd; default: Interface->PutKey(Key); return osEnd; @@ -2304,7 +2334,7 @@ int cReplayControl::titleid = 0;//XXX cReplayControl::cReplayControl(void) { dvbApi = cDvbApi::PrimaryDvbApi; - visible = shown = displayFrames = false; + visible = modeOnly = shown = displayFrames = false; lastCurrent = lastTotal = -1; timeoutShow = 0; timeSearchActive = false; @@ -2367,7 +2397,51 @@ void cReplayControl::Hide(void) { if (visible) { Interface->Close(); - needsFastResponse = visible = false; + needsFastResponse = visible = modeOnly = false; + } +} + +void cReplayControl::DisplayAtBottom(const char *s) +{ + if (s) { + int w = dvbApi->WidthInCells(s); + int d = max(Width() - w, 0) / 2; + Interface->Write(d, -1, s); + Interface->Flush(); + } + else + Interface->Fill(12, 2, Width() - 22, 1, clrBackground); +} + +void cReplayControl::ShowMode(void) +{ + if (Setup.ShowReplayMode && !timeSearchActive) { + bool Play, Forward; + int Speed; + if (dvbApi->GetReplayMode(Play, Forward, Speed)) { + + if (!visible) { + // open small display + Interface->Open(9, -1); + Interface->Clear(); + visible = modeOnly = true; + } + + timeoutShow = (modeOnly && !timeoutShow && Speed == -1 && Play) ? time(NULL) + MODETIMEOUT : 0; + const char *Mode; + if (Speed == -1) Mode = Play ? " > " : " || "; + else if (Play) Mode = Forward ? " X>> " : " <<X "; + else Mode = Forward ? " X|> " : " <|X "; + char buf[16]; + strn0cpy(buf, Mode, sizeof(buf)); + char *p = strchr(buf, 'X'); + if (p) + *p = Speed > 0 ? '1' + Speed - 1 : ' '; + + eDvbFont OldFont = Interface->SetFont(fontFix); + DisplayAtBottom(buf); + Interface->SetFont(OldFont); + } } } @@ -2407,6 +2481,7 @@ bool cReplayControl::ShowProgress(bool Initial) lastCurrent = Current; } lastTotal = Total; + ShowMode(); return true; } return false; @@ -2428,7 +2503,7 @@ void cReplayControl::TimeSearchDisplay(void) default: sprintf(buf + len, "--:--"); break; } - Interface->Write(12, 2, buf); + DisplayAtBottom(buf); } void cReplayControl::TimeSearchProcess(eKeys Key) @@ -2485,7 +2560,8 @@ void cReplayControl::TimeSearchProcess(eKeys Key) if (timeSearchHide) Hide(); else - Interface->Fill(12, 2, Width() - 22, 1, clrBackground); + DisplayAtBottom(); + ShowMode(); } } @@ -2493,6 +2569,8 @@ void cReplayControl::TimeSearch(void) { timeSearchHH = timeSearchMM = timeSearchPos = 0; timeSearchHide = false; + if (modeOnly) + Hide(); if (!visible) { Show(); if (visible) @@ -2596,7 +2674,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key) Hide(); timeoutShow = 0; } - else + else if (!modeOnly) shown = ShowProgress(!shown) || shown; } bool DisplayedFrames = displayFrames; @@ -2605,13 +2683,16 @@ eOSState cReplayControl::ProcessKey(eKeys Key) TimeSearchProcess(Key); return osContinue; } + bool DoShowMode = true; switch (Key) { // Positioning: case kUp: dvbApi->Play(); break; case kDown: dvbApi->Pause(); break; case kLeft|k_Release: + if (Setup.MultiSpeedMode) break; case kLeft: dvbApi->Backward(); break; case kRight|k_Release: + if (Setup.MultiSpeedMode) break; case kRight: dvbApi->Forward(); break; case kRed: TimeSearch(); break; case kGreen|k_Repeat: @@ -2622,6 +2703,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key) dvbApi->StopReplay(); return osEnd; default: { + DoShowMode = false; switch (Key) { // Editing: //XXX should we do this only when the ProgressDisplay is on??? @@ -2647,6 +2729,8 @@ eOSState cReplayControl::ProcessKey(eKeys Key) } } } + if (DoShowMode) + ShowMode(); if (DisplayedFrames && !displayFrames) Interface->Fill(0, 2, 11, 1, clrBackground); return osContinue; diff --git a/menu.h b/menu.h index 2c5ed3941..bb31c72a6 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.25 2001/09/01 14:52:48 kls Exp $ + * $Id: menu.h 1.28 2001/09/14 15:09:49 kls Exp $ */ #ifndef _MENU_H @@ -31,14 +31,15 @@ class cMenuMain : public cOsdMenu { class cDisplayChannel : public cOsdBase { private: - bool withInfo, group; + int group; + bool withInfo; int lines; int lastTime; int oldNumber, number; void DisplayChannel(const cChannel *Channel); void DisplayInfo(void); public: - cDisplayChannel(int Number, bool Switched, bool Group = false); + cDisplayChannel(int Number, bool Switched); cDisplayChannel(eKeys FirstKey); virtual ~cDisplayChannel(); virtual eOSState ProcessKey(eKeys Key); @@ -101,7 +102,7 @@ class cReplayControl : public cOsdBase { private: cDvbApi *dvbApi; cMarks marks; - bool visible, shown, displayFrames; + bool visible, modeOnly, shown, displayFrames; int lastCurrent, lastTotal; time_t timeoutShow; bool timeSearchActive, timeSearchHide; @@ -117,6 +118,8 @@ class cReplayControl : public cOsdBase { static int titleid;//XXX #endif //DVDSUPPORT static char *title; + void DisplayAtBottom(const char *s = NULL); + void ShowMode(void); bool ShowProgress(bool Initial); void MarkToggle(void); void MarkJump(bool Forward); diff --git a/svdrp.c b/svdrp.c index 5f8aad403..d1833612f 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.22 2001/09/01 09:50:03 kls Exp $ + * $Id: svdrp.c 1.23 2001/09/14 14:31:22 kls Exp $ */ #define _GNU_SOURCE @@ -262,7 +262,7 @@ void cSVDRP::Close(bool Timeout) { if (file.IsOpen()) { //TODO how can we get the *full* hostname? - char buffer[MAXCMDBUFFER]; + char buffer[BUFSIZ]; gethostname(buffer, sizeof(buffer)); Reply(221, "%s closing connection%s", buffer, Timeout ? " (timeout)" : ""); isyslog(LOG_INFO, "closing SVDRP connection"); //TODO store IP#??? @@ -944,7 +944,7 @@ void cSVDRP::Process(void) if (file.IsOpen() || file.Open(socket.Accept())) { if (SendGreeting) { //TODO how can we get the *full* hostname? - char buffer[MAXCMDBUFFER]; + char buffer[BUFSIZ]; gethostname(buffer, sizeof(buffer)); time_t now = time(NULL); Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now)); diff --git a/svdrp.h b/svdrp.h index 503439a4b..1c16f88b4 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.10 2001/09/01 09:24:50 kls Exp $ + * $Id: svdrp.h 1.11 2001/09/14 14:35:34 kls Exp $ */ #ifndef __SVDRP_H @@ -26,15 +26,13 @@ class cSocket { int Accept(void); }; -#define MAXCMDBUFFER 1024 - class cSVDRP { private: cSocket socket; cFile file; CRect ovlClipRects[MAXCLIPRECTS]; uint numChars; - char cmdLine[MAXCMDBUFFER]; + char cmdLine[MAXPARSEBUFFER]; char *message; time_t lastActivity; void Close(bool Timeout = false); diff --git a/thread.c b/thread.c index bfc8aab12..ec66440e0 100644 --- a/thread.c +++ b/thread.c @@ -4,12 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.11 2001/08/05 10:36:52 kls Exp $ + * $Id: thread.c 1.12 2001/09/15 13:00:58 kls Exp $ */ #include "thread.h" #include <errno.h> #include <signal.h> +#include <sys/resource.h> #include <sys/wait.h> #include <unistd.h> #include "tools.h" @@ -235,3 +236,106 @@ bool cThreadLock::Locked(void) return locked; } +// --- cPipe ----------------------------------------------------------------- + +// cPipe::Open() and cPipe::Close() are based on code originally received from +// Andreas Vitting <Andreas@huji.de> + +cPipe::cPipe(void) +{ + pid = -1; + f = NULL; +} + +cPipe::~cPipe() +{ + Close(); +} + +bool cPipe::Open(const char *Command, const char *Mode) +{ + int fd[2]; + + if (pipe(fd) < 0) { + LOG_ERROR; + return false; + } + if ((pid = fork()) < 0) { // fork failed + LOG_ERROR; + close(fd[0]); + close(fd[1]); + return false; + } + + char *mode = "w"; + int iopipe = 0; + + if (pid > 0) { // parent process + if (strcmp(Mode, "r") == 0) { + mode = "r"; + iopipe = 1; + } + close(fd[iopipe]); + f = fdopen(fd[1 - iopipe], mode); + if ((f = fdopen(fd[1 - iopipe], mode)) == NULL) { + LOG_ERROR; + close(fd[1 - iopipe]); + } + return f != NULL; + } + else { // child process + int iofd = STDOUT_FILENO; + if (strcmp(Mode, "w") == 0) { + mode = "r"; + iopipe = 1; + iofd = STDIN_FILENO; + } + close(fd[iopipe]); + if (dup2(fd[1 - iopipe], iofd) == -1) { // now redirect + LOG_ERROR; + close(fd[1 - iopipe]); + _exit(-1); + } + else { + for (int i = STDERR_FILENO + 1; i < fd[1 - iopipe]; i++) + close(i); //close all dup'ed filedescriptors + if (execl("/bin/sh", "sh", "-c", Command, NULL) == -1) { + LOG_ERROR_STR(Command); + close(fd[1 - iopipe]); + _exit(-1); + } + } + _exit(0); + } +} + +int cPipe::Close(void) +{ + int ret = -1; + + if (f) { + fclose(f); + f = NULL; + } + + if (pid >= 0) { + int status = 0; + struct rusage ru; + int i = 5; + while (ret == -1 && i > 0) { + usleep(1000); + ret = wait4(pid, &status, WNOHANG, &ru); + i--; + } + + if (!i) { + kill(pid, SIGKILL); + ret = -1; + } + else if (ret == -1 || !WIFEXITED(status)) + ret = -1; + pid = -1; + } + + return ret; +} diff --git a/thread.h b/thread.h index e8e796eb1..221f9ac7a 100644 --- a/thread.h +++ b/thread.h @@ -4,13 +4,14 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.8 2001/08/05 10:36:47 kls Exp $ + * $Id: thread.h 1.9 2001/09/15 12:46:52 kls Exp $ */ #ifndef __THREAD_H #define __THREAD_H #include <pthread.h> +#include <stdio.h> #include <sys/types.h> class cMutex; @@ -88,4 +89,19 @@ class cThreadLock { #define LOCK_THREAD cThreadLock ThreadLock(this) +// cPipe implements a pipe that closes all unnecessary file descriptors in +// the child process. + +class cPipe { +private: + pid_t pid; + FILE *f; +public: + cPipe(void); + ~cPipe(); + operator FILE* () { return f; } + bool Open(const char *Command, const char *Mode); + int Close(void); + }; + #endif //__THREAD_H diff --git a/tools.c b/tools.c index f51bc85d4..d6b65e55c 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.43 2001/08/26 15:45:41 kls Exp $ + * $Id: tools.c 1.45 2001/09/15 15:41:16 kls Exp $ */ #define _GNU_SOURCE @@ -21,8 +21,6 @@ #include <unistd.h> #include "i18n.h" -#define MaxBuffer 1000 - int SysLogLevel = 3; ssize_t safe_read(int filedes, void *buffer, size_t size) @@ -56,7 +54,7 @@ void writechar(int filedes, char c) char *readline(FILE *f) { - static char buffer[MaxBuffer]; + static char buffer[MAXPARSEBUFFER]; if (fgets(buffer, sizeof(buffer), f) > 0) { int l = strlen(buffer) - 1; if (l >= 0 && buffer[l] == '\n') @@ -556,13 +554,27 @@ bool cSafeFile::Open(void) return f != NULL; } -void cSafeFile::Close(void) +bool cSafeFile::Close(void) { + bool result = true; if (f) { - fclose(f); + if (ferror(f) != 0) { + LOG_ERROR_STR(tempName); + result = false; + } + if (fclose(f) < 0) { + LOG_ERROR_STR(tempName); + result = false; + } f = NULL; - rename(tempName, fileName); + if (result && rename(tempName, fileName) < 0) { + LOG_ERROR_STR(fileName); + result = false; + } } + else + result = false; + return result; } // --- cListObject ----------------------------------------------------------- diff --git a/tools.h b/tools.h index 2f89f3f0e..188adb458 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.31 2001/08/26 12:52:49 kls Exp $ + * $Id: tools.h 1.34 2001/09/15 15:22:57 kls Exp $ */ #ifndef __TOOLS_H @@ -29,9 +29,16 @@ extern int SysLogLevel; #define SECSINDAY 86400 +#define KILOBYTE(n) ((n) * 1024) +#define MEGABYTE(n) ((n) * 1024 * 1024) + +#define MAXPARSEBUFFER KILOBYTE(10) + #define DELETENULL(p) (delete (p), p = NULL) -template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }; +template<class T> inline T min(T a, T b) { return a <= b ? a : b; } +template<class T> inline T max(T a, T b) { return a >= b ? a : b; } +template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; } ssize_t safe_read(int filedes, void *buffer, size_t size); ssize_t safe_write(int filedes, const void *buffer, size_t size); @@ -86,7 +93,7 @@ class cSafeFile { ~cSafeFile(); operator FILE* () { return f; } bool Open(void); - void Close(void); + bool Close(void); }; class cListObject { diff --git a/vdr.c b/vdr.c index efb5e1c38..b288108d7 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.68 2001/09/01 14:50:40 kls Exp $ + * $Id: vdr.c 1.73 2001/09/16 14:54:45 kls Exp $ */ #define _GNU_SOURCE @@ -50,6 +50,9 @@ #define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping #define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown +#define MANUALSTART 600 // seconds the next timer must be in the future to assume manual start + +#define VOLUMEDELTA 5 // used to increase/decrease the volume static int Interrupted = 0; @@ -328,7 +331,8 @@ int main(int argc, char *argv[]) if (!EITScanner.Active() && cDvbApi::CurrentChannel() != LastChannel) { if (!Menu) Menu = new cDisplayChannel(cDvbApi::CurrentChannel(), LastChannel > 0); - PreviousChannel = LastChannel; + if (LastChannel > 0) + PreviousChannel = LastChannel; LastChannel = cDvbApi::CurrentChannel(); } // Timers and Recordings: @@ -348,7 +352,7 @@ int main(int argc, char *argv[]) EITScanner.Activity(); LastActivity = time(NULL); } - if (*Interact) { + if (*Interact && key != kPower) { switch ((*Interact)->ProcessKey(key)) { case osMenu: DELETENULL(Menu); Menu = new cMenuMain(ReplayControl); @@ -390,10 +394,12 @@ int main(int argc, char *argv[]) else { switch (key) { // Toggle channels: - case k0: - if (PreviousChannel != cDvbApi::CurrentChannel()) - Channels.SwitchTo(PreviousChannel); + case k0: { + int CurrentChannel = cDvbApi::CurrentChannel(); + Channels.SwitchTo(PreviousChannel); + PreviousChannel = CurrentChannel; break; + } // Direct Channel Select: case k1 ... k9: Menu = new cDisplayChannel(key); @@ -402,17 +408,9 @@ int main(int argc, char *argv[]) case kLeft|k_Repeat: case kLeft: case kRight|k_Repeat: - case kRight: { - int SaveGroup = CurrentGroup; - if (NORMALKEY(key) == kRight) - CurrentGroup = Channels.GetNextGroup(CurrentGroup) ; - else - CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup); - if (CurrentGroup < 0) - CurrentGroup = SaveGroup; - Menu = new cDisplayChannel(CurrentGroup, false, true); + case kRight: + Menu = new cDisplayChannel(NORMALKEY(key)); break; - } // Up/Down Channel Select: case kUp|k_Repeat: case kUp: @@ -428,8 +426,19 @@ int main(int argc, char *argv[]) case kMenu: Menu = new cMenuMain(ReplayControl); break; // Viewing Control: case kOk: LastChannel = -1; break; // forces channel display + // Volume Control: + case kVolUp|k_Repeat: + case kVolUp: + case kVolDn|k_Repeat: + case kVolDn: + cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA); + break; + case kMute: + cDvbApi::PrimaryDvbApi->ToggleMute(); + break; // Power off: case kPower: isyslog(LOG_INFO, "Power button pressed"); + DELETENULL(*Interact); if (!Shutdown) { Interface->Error(tr("Can't shutdown - option '-s' not given!")); break; @@ -451,20 +460,24 @@ int main(int argc, char *argv[]) time_t Now = time(NULL); if (Now - LastActivity > ACTIVITYTIMEOUT) { // Shutdown: - if (Shutdown && (Setup.MinUserInactivity && Now - LastActivity > Setup.MinUserInactivity * 60 || ForceShutdown)) { - ForceShutdown = false; + if (Shutdown && Setup.MinUserInactivity && Now - LastActivity > Setup.MinUserInactivity * 60) { cTimer *timer = Timers.GetNextActiveTimer(); time_t Next = timer ? timer->StartTime() : 0; time_t Delta = timer ? Next - Now : 0; - if (timer) - dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next)); - if (!Next || Delta > Setup.MinEventTimeout * 60) { - if (!LastActivity) { + if (!LastActivity) { + if (!timer || Delta > MANUALSTART) { // Apparently the user started VDR manually dsyslog(LOG_INFO, "assuming manual start of VDR"); LastActivity = Now; - continue; // skip the rest of the housekeeping for now + continue; // don't run into the actual shutdown procedure below } + else + LastActivity = 1; + } + if (!Next || Delta > Setup.MinEventTimeout * 60 || ForceShutdown) { + ForceShutdown = false; + if (timer) + dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next)); if (WatchdogTimeout > 0) signal(SIGALRM, SIG_IGN); if (Interface->Confirm(tr("Press any key to cancel shutdown"), LastActivity == 1 ? 5 : SHUTDOWNWAIT, true)) { From 66bab90b60048a46e401ea506d3aa65c43779700 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 23 Sep 2001 18:00:00 +0200 Subject: [PATCH 026/307] Version 0.96 - Made VDR compile with libdvdread-0.9.1 (thanks to Andreas Schultz). Note that you now _need_ version 0.9.1 of libdvdread to compile VDR with DVD support! - Several fixes to the replay mode display (thanks to Stefan Huelswitt): no more replay mode display when pressing the "Green" or "Yellow" button (Skip +/-60s); fixed timeout when pressing '0' to set an editing mark while the progress display is not shown; mode display is shown after progress display is closed; pressing "Ok" while the mode display is on brings up the progress display; no more unnecessary display of "normal play mode". - Supplying the new frontend parameter 'Inversion' (currently it is always set to INVERSION_AUTO, which should work with all channels on Astra). - Removing unnecessary double quotes from EPG Subtitle in EPGBugfixLevel >=1. - EPG info is now updated if the contents changes but the ID remains the same. - Fixed handling SVDRP commands whith more than one blank between the command word and the options. - The current volume setting is now saved to setup.conf and restored at the next program start. - New command line option '-r' to define a command that gets called before and after each recording (see INSTALL for details). - Implemented a check to see whether the system time is running linearly. - Writing the current time (as seen by VDR) into the log file when starting a timer recording (this may help debugging cases where timers don't start at the expected time). - Made the volume, mute and power keys work when a menu is active, too (thanks to Matthias Weingart). --- CONTRIBUTORS | 3 + FORMATS | 2 +- HISTORY | 28 +++++++ INSTALL | 57 ++++++++++++- config.c | 5 +- config.h | 5 +- dvbapi.c | 23 ++++-- dvbapi.h | 5 +- eit.c | 105 ++++++++++-------------- eit.h | 8 +- menu.c | 36 ++++++--- menu.h | 3 +- recording.c | 16 +++- recording.h | 14 +++- svdrp.c | 3 +- thread.c | 11 ++- tools.c | 15 +++- tools.h | 3 +- vdr.c | 220 ++++++++++++++++++++++++++++----------------------- 19 files changed, 358 insertions(+), 204 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9090ca9f3..f1157b1f7 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -139,3 +139,6 @@ Rolf Hakenes <hakenes@hippomi.de> Andreas Vitting <Andreas@huji.de> for providing code that closes all unused file descriptors in the child process of a pipe (used in cPipe) + +Matthias Weingart <matthias@pentax.boerde.de> + for fixing handling of the volume, mute and power keys when menus are active diff --git a/FORMATS b/FORMATS index 3c5d36d43..9142fd70d 100644 --- a/FORMATS +++ b/FORMATS @@ -102,7 +102,7 @@ Video Disk Recorder File Formats Examples: 1 Check for new mail: /usr/local/bin/checkmail 2>&1 - 2 CPU status : /usr/loval/bin/cpustatus 2>&1 + 2 CPU status : /usr/local/bin/cpustatus 2>&1 3 Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' If the first non-blank character of the 'title' is a digit in the range diff --git a/HISTORY b/HISTORY index 4b68aebca..143c2f45b 100644 --- a/HISTORY +++ b/HISTORY @@ -758,3 +758,31 @@ Video Disk Recorder Revision History - Three new keys ("Volume+", Volume-" and "Mute") to control the DVB card's audio output volume. - New version of the 'epg2timers' tool (thanks to Carsten Koch). + +2001-09-23: Version 0.96 + +- Made VDR compile with libdvdread-0.9.1 (thanks to Andreas Schultz). + Note that you now _need_ version 0.9.1 of libdvdread to compile VDR with + DVD support! +- Several fixes to the replay mode display (thanks to Stefan Huelswitt): + no more replay mode display when pressing the "Green" or "Yellow" button + (Skip +/-60s); fixed timeout when pressing '0' to set an editing mark while + the progress display is not shown; mode display is shown after progress + display is closed; pressing "Ok" while the mode display is on brings up + the progress display; no more unnecessary display of "normal play mode". +- Supplying the new frontend parameter 'Inversion' (currently it is always + set to INVERSION_AUTO, which should work with all channels on Astra). +- Removing unnecessary double quotes from EPG Subtitle in EPGBugfixLevel >=1. +- EPG info is now updated if the contents changes but the ID remains the same. +- Fixed handling SVDRP commands whith more than one blank between the command + word and the options. +- The current volume setting is now saved to setup.conf and restored at the + next program start. +- New command line option '-r' to define a command that gets called before and + after each recording (see INSTALL for details). +- Implemented a check to see whether the system time is running linearly. +- Writing the current time (as seen by VDR) into the log file when starting + a timer recording (this may help debugging cases where timers don't start + at the expected time). +- Made the volume, mute and power keys work when a menu is active, too (thanks + to Matthias Weingart). diff --git a/INSTALL b/INSTALL index 56200e86e..b942603ec 100644 --- a/INSTALL +++ b/INSTALL @@ -27,7 +27,12 @@ You can find 'libdvdread' at http://www.dtek.chalmers.se/groups/dvd/downloads.html -VDR requires the card driver version dated 2001-09-14 or higher +If you want to replay CSS encrypted DVDs you also need to get the 'libdvdcss' +library from + + http://www.videolan.org/libdvdcss/download.html + +VDR requires the Linux-DVB card driver version dated 2001-09-14 or higher to work properly. After extracting the package, change into the VDR directory @@ -112,10 +117,11 @@ for programming some sort of hardware device that makes sure the computer will be restarted in time before the next timer event. Your program must also initiate the actual shutdown procedure of the computer. After this your program should return to VDR. VDR will not automatically exit after -calling the shutdown program, but will rather continue normally untit it +calling the shutdown program, but will rather continue normally until it receives a SIGTERM when the computer is actually shut down. So in case the shutdown fails, or the shutdown program for some reason decides not to -perform a shutdown, VDR will stay up and running. +perform a shutdown, VDR will stay up and running and will call the shutdown +program again after another MinUserInactivity minutes. If there are currently no timers active, both parameters will be '0'. In that case the program shall not set the hardware for automatic restart @@ -152,6 +158,49 @@ particular hard- and software environment. If the '-s' option is present, the VDR machine can be turned off by pressing the "Power" key on the remote control. +Executing commands before and after a recording: +------------------------------------------------ + +You can use the '-r' option to define a program or script that gets called +before and after a recording is performed, and after an editing process +has finished. + +The program will be called with two string parameters. The first parameter +is one of + + before if this is *before* a recording starts + after if this is *after* a recording has finished + edited if this is after a recording has been *edited* + +and the second parameter contains the full name of the recording's +directory (which may not yet exists at that moment in the "before" case). +In the "edited" case it will be the name of the edited version. + +Within this program you can do anything you would like to do before and/or +after a recording or after an editing process. However, the program must return +as soon as possible, because otherwise it will block further execution of VDR. +Be especially careful to make sure the program returns before the watchdog +timeout you may have set up with the '-w' option! If the operation you want to +perform will take longer, you will have to run it as a background job. + +An example script for use with the '-r' option could look like this: + +#!/bin/sh +case "$1" in + before) + echo "Before recording $2" + ;; + after) + echo "After recording $2" + ;; + edited) + echo "Edited recording $2" + ;; + *) + echo "ERROR: unknown state: $1" + ;; + esac + Command line options: --------------------- @@ -177,7 +226,7 @@ You can use the '-V' option to overwrite this, as in Note that the user id under which VDR runs needs to have write access to the DVD device in order to replay CSS protected DVDs (which also requires -the presence of the 'libcss' library). +the presence of the 'libdvdcss' library). The video data directory: ------------------------- diff --git a/config.c b/config.c index 87e833235..4df73614d 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.72 2001/09/16 14:54:32 kls Exp $ + * $Id: config.c 1.73 2001/09/22 13:36:59 kls Exp $ */ #include "config.h" @@ -808,6 +808,7 @@ cSetup::cSetup(void) MultiSpeedMode = 0; ShowReplayMode = 0; CurrentChannel = -1; + CurrentVolume = MAXVOLUME; } bool cSetup::Parse(char *s) @@ -847,6 +848,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); else return false; return true; @@ -921,6 +923,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "MultiSpeedMode = %d\n", MultiSpeedMode); fprintf(f, "ShowReplayMode = %d\n", ShowReplayMode); fprintf(f, "CurrentChannel = %d\n", CurrentChannel); + fprintf(f, "CurrentVolume = %d\n", CurrentVolume); if (f.Close()) { isyslog(LOG_INFO, "saved setup to %s", FileName); return true; diff --git a/config.h b/config.h index 194d04e2b..8012cd26c 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.79 2001/09/16 14:54:36 kls Exp $ + * $Id: config.h 1.81 2001/09/22 13:37:05 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.95" +#define VDRVERSION "0.96" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -302,6 +302,7 @@ class cSetup { int MultiSpeedMode; int ShowReplayMode; int CurrentChannel; + int CurrentVolume; cSetup(void); bool Load(const char *FileName); bool Save(const char *FileName = NULL); diff --git a/dvbapi.c b/dvbapi.c index 16b3e3084..8a6e69152 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.125 2001/09/16 13:55:03 kls Exp $ + * $Id: dvbapi.c 1.129 2001/09/23 13:44:27 kls Exp $ */ //#define DVDDEBUG 1 @@ -1670,7 +1670,7 @@ void cDVDplayBuffer::Input(void) /** * Parse the contained dsi packet. */ - navRead_DSI(&dsi_pack, &(data[DSI_START_BYTE]), sizeof(dsi_t)); + navRead_DSI(&dsi_pack, &(data[DSI_START_BYTE])); if (cur_pack != dsi_pack.dsi_gi.nv_pck_lbn) { esyslog(LOG_ERR, "ERROR: cur_pack != dsi_pack.dsi_gi.nv_pck_lbn"); return; @@ -1748,7 +1748,7 @@ void cDVDplayBuffer::Input(void) dsyslog(LOG_INFO, "DVD: read pack: %d", cur_pack); #endif int len = DVDReadBlocks(title, cur_pack, cur_output_size, data); - if (len != (int)cur_output_size * DVD_VIDEO_LB_LEN) { + if (len != (int)cur_output_size) { esyslog(LOG_ERR, "ERROR: read failed for %d blocks at %d", cur_output_size, cur_pack); doplay = false; break; @@ -2406,16 +2406,18 @@ void cCuttingBuffer::Action(void) // --- cVideoCutter ---------------------------------------------------------- +char *cVideoCutter::editedVersionName = NULL; cCuttingBuffer *cVideoCutter::cuttingBuffer = NULL; bool cVideoCutter::Start(const char *FileName) { if (!cuttingBuffer) { cRecording Recording(FileName); - const char *EditedVersionName = Recording.PrefixFileName('%'); - if (EditedVersionName && RemoveVideoFile(EditedVersionName) && MakeDirs(EditedVersionName, true)) { + const char *evn = Recording.PrefixFileName('%'); + if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { + editedVersionName = strdup(evn); Recording.WriteSummary(); - cuttingBuffer = new cCuttingBuffer(FileName, EditedVersionName); + cuttingBuffer = new cCuttingBuffer(FileName, editedVersionName); return true; } } @@ -2434,6 +2436,9 @@ bool cVideoCutter::Active(void) if (cuttingBuffer->Active()) return true; Stop(); + cRecordingUserCommand::InvokeCommand(RUC_EDITEDRECORDING, editedVersionName); + delete editedVersionName; + editedVersionName = NULL; } return false; } @@ -2540,7 +2545,7 @@ cDvbApi::cDvbApi(int n) #endif currentChannel = 1; mute = false; - volume = 255; + volume = MAXVOLUME; } cDvbApi::~cDvbApi() @@ -3252,6 +3257,7 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char FrontendParameters Frontend; Frontend.Frequency = freq * 1000UL; + Frontend.Inversion = INVERSION_AUTO; Frontend.u.qpsk.SymbolRate = Srate * 1000UL; Frontend.u.qpsk.FEC_inner = FEC_AUTO; @@ -3298,6 +3304,7 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char FrontendParameters Frontend; Frontend.Frequency = FrequencyMHz * 1000000UL; + Frontend.Inversion = INVERSION_AUTO; Frontend.u.qam.SymbolRate = Srate * 1000UL; Frontend.u.qam.FEC_inner = FEC_AUTO; Frontend.u.qam.QAM = QAM_64; @@ -3635,7 +3642,7 @@ void cDvbApi::ToggleMute(void) void cDvbApi::SetVolume(int Volume, bool Absolute) { if (fd_audio >= 0) { - volume = min(max(Absolute ? Volume : volume + Volume, 0), 255); + volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME); audioMixer_t am; am.volume_left = am.volume_right = volume; CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am)); diff --git a/dvbapi.h b/dvbapi.h index d0a68e795..8e67f9b4b 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.51 2001/09/16 13:54:23 kls Exp $ + * $Id: dvbapi.h 1.53 2001/09/23 11:01:46 kls Exp $ */ #ifndef __DVBAPI_H @@ -51,6 +51,8 @@ typedef struct CRect { #define MAXVIDEOFILESIZE 2000 // MB #define MINVIDEOFILESIZE 100 // MB +#define MAXVOLUME 255 + const char *IndexToHMSF(int Index, bool WithFrame = false); // Converts the given index to a string, optionally containing the frame number. int HMSFToIndex(const char *HMSF); @@ -71,6 +73,7 @@ class cCuttingBuffer; class cVideoCutter { private: + static char *editedVersionName; static cCuttingBuffer *cuttingBuffer; public: static bool Start(const char *FileName); diff --git a/eit.c b/eit.c index d2927ccc0..1fceeef1e 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.22 2001/08/19 14:44:32 kls Exp $ + * $Id: eit.c 1.24 2001/09/22 13:07:21 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -279,59 +279,19 @@ unsigned short cEventInfo::GetEventID() const return uEventID; } /** */ -bool cEventInfo::SetTitle(const char *string) +void cEventInfo::SetTitle(const char *string) { - if (string == NULL) - return false; - - pTitle = strdup(string); - if (pTitle == NULL) - return false; - - return true; + pTitle = strcpyrealloc(pTitle, string); } /** */ -bool cEventInfo::SetSubtitle(const char *string) +void cEventInfo::SetSubtitle(const char *string) { - if (string == NULL) - return false; - - pSubtitle = strdup(string); - if (pSubtitle == NULL) - return false; - - return true; + pSubtitle = strcpyrealloc(pSubtitle, string); } /** */ -bool cEventInfo::AddExtendedDescription(const char *string) +void cEventInfo::SetExtendedDescription(const char *string) { - int size = 0; - bool first = true; - char *p; - - if (string == NULL) - return false; - - if (pExtendedDescription) - { - first = false; - size += strlen(pExtendedDescription); - } - - size += (strlen(string) + 1); - - p = (char *)realloc(pExtendedDescription, size); - if (p == NULL) - return false; - - if (first) - *p = 0; - - strcat(p, string); - - pExtendedDescription = p; - - return true; + pExtendedDescription = strcpyrealloc(pExtendedDescription, string); } /** */ void cEventInfo::SetTime(time_t t) @@ -447,6 +407,22 @@ void cEventInfo::FixEpgBugs(void) pSubtitle = NULL; } + // ZDF.info puts the Subtitle between double quotes, which is nothing + // but annoying (some even put a '.' after the closing '"'): + // + // Title + // "Subtitle"[.] + // + if (pSubtitle && *pSubtitle == '"') { + int l = strlen(pSubtitle); + if (l > 2 && (pSubtitle[l - 1] == '"' || (pSubtitle[l - 1] == '.' && pSubtitle[l - 2] == '"'))) { + memmove(pSubtitle, pSubtitle + 1, l); + char *p = strrchr(pSubtitle, '"'); + if (p) + *p = 0; + } + } + if (Setup.EPGBugfixLevel <= 1) return; @@ -767,28 +743,29 @@ int cEIT::ProcessEIT(unsigned char *buffer) } pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID); if (!pEvent) { + // If we don't have that event ID yet, we create a new one. + // Otherwise we copy the information into the existing event anyway, because the data might have changed. pSchedule->Events.Add(new cEventInfo(VdrProgramInfo->ServiceID, VdrProgramInfo->EventID)); pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID); if (!pEvent) break; - if (rEvent) { - pEvent->SetTitle(rEvent->GetTitle()); - pEvent->SetSubtitle(rEvent->GetSubtitle()); - pEvent->SetTime(VdrProgramInfo->StartTime); - pEvent->SetDuration(VdrProgramInfo->Duration); - pEvent->AddExtendedDescription(rEvent->GetExtendedDescription()); - pEvent->FixEpgBugs(); - } - else { - pEvent->SetTitle(VdrProgramInfo->ShortName); - pEvent->SetSubtitle(VdrProgramInfo->ShortText); - pEvent->SetTime(VdrProgramInfo->StartTime); - pEvent->SetDuration(VdrProgramInfo->Duration); - pEvent->AddExtendedDescription(VdrProgramInfo->ExtendedName); - pEvent->AddExtendedDescription(VdrProgramInfo->ExtendedText); - pEvent->FixEpgBugs(); - } } + if (rEvent) { + pEvent->SetTitle(rEvent->GetTitle()); + pEvent->SetSubtitle(rEvent->GetSubtitle()); + pEvent->SetExtendedDescription(rEvent->GetExtendedDescription()); + } + else { + pEvent->SetTitle(VdrProgramInfo->ShortName); + pEvent->SetSubtitle(VdrProgramInfo->ShortText); + pEvent->SetExtendedDescription(VdrProgramInfo->ExtendedName); + //XXX kls 2001-09-22: + //XXX apparently this never occurred, so I have simpified ExtendedDescription handling + //XXX pEvent->AddExtendedDescription(VdrProgramInfo->ExtendedText); + } + pEvent->SetTime(VdrProgramInfo->StartTime); + pEvent->SetDuration(VdrProgramInfo->Duration); + pEvent->FixEpgBugs(); if (IsPresentFollowing()) { if ((GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_PAUSING) || (GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_RUNNING)) pSchedule->SetPresentEvent(pEvent); diff --git a/eit.h b/eit.h index 8ca5f1e53..91d5b2b38 100644 --- a/eit.h +++ b/eit.h @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.10 2001/08/15 15:47:31 kls Exp $ + * $Id: eit.h 1.11 2001/09/22 11:43:21 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -42,13 +42,13 @@ class cEventInfo : public cListObject { protected: void SetFollowing(bool foll); void SetPresent(bool pres); - bool SetTitle(const char *string); + void SetTitle(const char *string); void SetServiceID(unsigned short servid); void SetEventID(unsigned short evid); void SetDuration(long l); void SetTime(time_t t); - bool AddExtendedDescription(const char *string); - bool SetSubtitle(const char *string); + void SetExtendedDescription(const char *string); + void SetSubtitle(const char *string); cEventInfo(unsigned short serviceid, unsigned short eventid); public: ~cEventInfo(); diff --git a/menu.c b/menu.c index 98fd30235..23b16e294 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.120 2001/09/15 10:36:31 kls Exp $ + * $Id: menu.c 1.127 2001/09/23 10:58:48 kls Exp $ */ #include "menu.h" @@ -2108,6 +2108,7 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) { eventInfo = NULL; instantId = NULL; + fileName = NULL; dvbApi = DvbApi; if (!dvbApi) dvbApi = cDvbApi::PrimaryDvbApi;//XXX timer = Timer; @@ -2128,7 +2129,9 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) Summary = eventInfo->GetExtendedDescription(); } cRecording Recording(timer, Subtitle, Summary); - if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority)) + fileName = strdup(Recording.FileName()); + cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); + if (dvbApi->StartRecord(fileName, Channels.GetByNumber(timer->channel)->ca, timer->priority)) Recording.WriteSummary(); Interface->DisplayRecording(dvbApi->CardIndex(), true); } @@ -2140,6 +2143,7 @@ cRecordControl::~cRecordControl() { Stop(true); delete instantId; + delete fileName; } bool cRecordControl::GetEventInfo(void) @@ -2184,6 +2188,7 @@ void cRecordControl::Stop(bool KeepInstant) } timer = NULL; Interface->DisplayRecording(dvbApi->CardIndex(), false); + cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName); } } @@ -2386,10 +2391,11 @@ void cReplayControl::ClearLastReplayed(const char *FileName) void cReplayControl::Show(int Seconds) { + if (modeOnly) + Hide(); if (!visible) { shown = ShowProgress(true); - if (shown && Seconds > 0) - timeoutShow = time(NULL) + Seconds; + timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0; } } @@ -2397,7 +2403,11 @@ void cReplayControl::Hide(void) { if (visible) { Interface->Close(); - needsFastResponse = visible = modeOnly = false; + needsFastResponse = visible = false; + if (!modeOnly) + ShowMode(); + else + modeOnly = false; } } @@ -2419,15 +2429,19 @@ void cReplayControl::ShowMode(void) bool Play, Forward; int Speed; if (dvbApi->GetReplayMode(Play, Forward, Speed)) { + bool NormalPlay = (Play && Speed == -1); if (!visible) { + if (NormalPlay) + return; // no need to do indicate ">" unless there was a different mode displayed before // open small display Interface->Open(9, -1); Interface->Clear(); visible = modeOnly = true; } - timeoutShow = (modeOnly && !timeoutShow && Speed == -1 && Play) ? time(NULL) + MODETIMEOUT : 0; + if (modeOnly && !timeoutShow && NormalPlay) + timeoutShow = time(NULL) + MODETIMEOUT; const char *Mode; if (Speed == -1) Mode = Play ? " > " : " || "; else if (Play) Mode = Forward ? " X>> " : " <<X "; @@ -2696,9 +2710,9 @@ eOSState cReplayControl::ProcessKey(eKeys Key) case kRight: dvbApi->Forward(); break; case kRed: TimeSearch(); break; case kGreen|k_Repeat: - case kGreen: dvbApi->SkipSeconds(-60); break; + case kGreen: dvbApi->SkipSeconds(-60); DoShowMode = false; break; case kYellow|k_Repeat: - case kYellow: dvbApi->SkipSeconds(60); break; + case kYellow: dvbApi->SkipSeconds( 60); DoShowMode = false; break; case kBlue: Hide(); dvbApi->StopReplay(); return osEnd; @@ -2721,7 +2735,11 @@ eOSState cReplayControl::ProcessKey(eKeys Key) switch (Key) { // Menu control: case kMenu: Hide(); return osMenu; // allow direct switching to menu - case kOk: visible ? Hide() : Show(); break; + case kOk: if (visible && !modeOnly) + Hide(); + else + Show(); + break; case kBack: return osRecordings; default: return osUnknown; } diff --git a/menu.h b/menu.h index bb31c72a6..f7411c61c 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.28 2001/09/14 15:09:49 kls Exp $ + * $Id: menu.h 1.30 2001/09/23 10:57:33 kls Exp $ */ #ifndef _MENU_H @@ -75,6 +75,7 @@ class cRecordControl { cTimer *timer; const cEventInfo *eventInfo; char *instantId; + char *fileName; bool GetEventInfo(void); public: cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL); diff --git a/recording.c b/recording.c index f65737812..df5040740 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.36 2001/09/02 15:09:28 kls Exp $ + * $Id: recording.c 1.37 2001/09/23 13:43:29 kls Exp $ */ #define _GNU_SOURCE @@ -513,3 +513,17 @@ cMark *cMarks::GetNext(int Position) return NULL; } +// --- cRecordingUserCommand ------------------------------------------------- + +const char *cRecordingUserCommand::command = NULL; + +void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName) +{ + if (command) { + char *cmd; + asprintf(&cmd, "%s %s '%s'", command, State, RecordingFileName); + isyslog(LOG_INFO, "executing '%s'", cmd); + system(cmd); + delete cmd; + } +} diff --git a/recording.h b/recording.h index e1af3db3c..d2391a907 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.16 2001/09/02 11:35:56 kls Exp $ + * $Id: recording.h 1.17 2001/09/23 13:43:58 kls Exp $ */ #ifndef __RECORDING_H @@ -83,4 +83,16 @@ class cMarks : public cConfig<cMark> { cMark *GetNext(int Position); }; +#define RUC_BEFORERECORDING "before" +#define RUC_AFTERRECORDING "after" +#define RUC_EDITEDRECORDING "edited" + +class cRecordingUserCommand { +private: + static const char *command; +public: + static void SetCommand(const char *Command) { command = Command; } + static void InvokeCommand(const char *State, const char *RecordingFileName); + }; + #endif //__RECORDING_H diff --git a/svdrp.c b/svdrp.c index d1833612f..3c90bb02d 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.23 2001/09/14 14:31:22 kls Exp $ + * $Id: svdrp.c 1.24 2001/09/22 13:30:02 kls Exp $ */ #define _GNU_SOURCE @@ -909,6 +909,7 @@ void cSVDRP::Execute(char *Cmd) s++; if (*s) *s++ = 0; + s = skipspace(s); if (CMD("CHAN")) CmdCHAN(s); else if (CMD("DELC")) CmdDELC(s); else if (CMD("DELT")) CmdDELT(s); diff --git a/thread.c b/thread.c index ec66440e0..f4ba76a19 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.12 2001/09/15 13:00:58 kls Exp $ + * $Id: thread.c 1.13 2001/09/23 14:04:35 kls Exp $ */ #include "thread.h" @@ -67,16 +67,19 @@ cMutex::~cMutex() void cMutex::Lock(void) { - if (getpid() != lockingPid || !locked) + if (getpid() != lockingPid || !locked) { pthread_mutex_lock(&mutex); - lockingPid = getpid(); + lockingPid = getpid(); + } locked++; } void cMutex::Unlock(void) { - if (!--locked) + if (!--locked) { + lockingPid = 0; pthread_mutex_unlock(&mutex); + } } // --- cThread --------------------------------------------------------------- diff --git a/tools.c b/tools.c index d6b65e55c..7238137ef 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.45 2001/09/15 15:41:16 kls Exp $ + * $Id: tools.c 1.46 2001/09/22 12:13:40 kls Exp $ */ #define _GNU_SOURCE @@ -64,6 +64,19 @@ char *readline(FILE *f) return NULL; } +char *strcpyrealloc(char *dest, const char *src) +{ + if (src) { + int l = max(dest ? strlen(dest) : 0, strlen(src)) + 1; // don't let the block get smaller! + dest = (char *)realloc(dest, l); + if (dest) + strcpy(dest, src); + else + esyslog(LOG_ERR, "ERROR: out of memory"); + } + return dest; +} + char *strn0cpy(char *dest, const char *src, size_t n) { char *s = dest; diff --git a/tools.h b/tools.h index 188adb458..cc67a8067 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.34 2001/09/15 15:22:57 kls Exp $ + * $Id: tools.h 1.35 2001/09/22 12:12:55 kls Exp $ */ #ifndef __TOOLS_H @@ -44,6 +44,7 @@ ssize_t safe_read(int filedes, void *buffer, size_t size); ssize_t safe_write(int filedes, const void *buffer, size_t size); void writechar(int filedes, char c); char *readline(FILE *f); +char *strcpyrealloc(char *dest, const char *src); char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); char *skipspace(const char *s); diff --git a/vdr.c b/vdr.c index b288108d7..d7c3f06e7 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.73 2001/09/16 14:54:45 kls Exp $ + * $Id: vdr.c 1.79 2001/09/23 14:33:39 kls Exp $ */ #define _GNU_SOURCE @@ -96,6 +96,7 @@ int main(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "log", required_argument, NULL, 'l' }, { "port", required_argument, NULL, 'p' }, + { "record", required_argument, NULL, 'r' }, { "shutdown", required_argument, NULL, 's' }, { "terminal", required_argument, NULL, 't' }, { "video", required_argument, NULL, 'v' }, @@ -106,7 +107,7 @@ int main(int argc, char *argv[]) int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:s:t:v:V:w:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:r:s:t:v:V:w:", long_options, &option_index)) != -1) { switch (c) { case 'a': cDvbApi::SetAudioCommand(optarg); break; @@ -143,6 +144,7 @@ int main(int argc, char *argv[]) " 2 = errors and info, 3 = errors, info and debug\n" " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" " 0 turns off SVDRP\n" + " -r CMD, --record=CMD call CMD before and after a recording\n" " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" " -t TTY, --terminal=TTY controlling tty\n" " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" @@ -180,6 +182,8 @@ int main(int argc, char *argv[]) return 2; } break; + case 'r': cRecordingUserCommand::SetCommand(optarg); + break; case 's': Shutdown = optarg; break; case 't': Terminal = optarg; @@ -278,6 +282,7 @@ int main(int argc, char *argv[]) cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); Channels.SwitchTo(Setup.CurrentChannel); + cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true); cEITScanner EITScanner; @@ -305,6 +310,7 @@ int main(int argc, char *argv[]) int LastChannel = -1; int PreviousChannel = cDvbApi::CurrentChannel(); time_t LastActivity = 0; + time_t LinearTime = time(NULL); int MaxLatencyTime = 0; bool ForceShutdown = false; @@ -314,6 +320,14 @@ int main(int argc, char *argv[]) } while (!Interrupted) { + // Test if we are running in the Einstein continuum: + time_t Now = time(NULL); + time_t LinearDelta = Now - LinearTime; + if (LinearDelta) { + if (LinearDelta < 0 || LinearDelta > 300) // assuming nothing will block for more than 5 minutes + esyslog(LOG_ERR, "ERROR: time warp detected (%d seconds)", LinearDelta); + LinearTime = Now; + } // Handle emergency exits: if (cThread::EmergencyExit()) { esyslog(LOG_ERR, "emergency exit requested - shutting down"); @@ -341,6 +355,7 @@ int main(int argc, char *argv[]) cRecordControls::Process(Now); cTimer *Timer = Timers.GetMatch(Now); if (Timer) { + dsyslog(LOG_INFO, "system time seen is %s", ctime(&Now)); if (!cRecordControls::Start(Timer)) Timer->SetPending(true); } @@ -352,106 +367,111 @@ int main(int argc, char *argv[]) EITScanner.Activity(); LastActivity = time(NULL); } - if (*Interact && key != kPower) { - switch ((*Interact)->ProcessKey(key)) { - case osMenu: DELETENULL(Menu); - Menu = new cMenuMain(ReplayControl); - break; - case osRecord: DELETENULL(Menu); - if (!cRecordControls::Start()) - Interface->Error(tr("No free DVB device to record!")); - break; - case osRecordings: - DELETENULL(Menu); - DELETENULL(ReplayControl); - Menu = new cMenuRecordings; - break; - case osReplay: DELETENULL(Menu); - DELETENULL(ReplayControl); - ReplayControl = new cReplayControl; - break; + // Keys that must work independent of any interactive mode: + switch (key) { + // Volume Control: + case kVolUp|k_Repeat: + case kVolUp: + case kVolDn|k_Repeat: + case kVolDn: + cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA); + break; + case kMute: + cDvbApi::PrimaryDvbApi->ToggleMute(); + break; + // Power off: + case kPower: isyslog(LOG_INFO, "Power button pressed"); + DELETENULL(*Interact); + if (!Shutdown) { + Interface->Error(tr("Can't shutdown - option '-s' not given!")); + break; + } + if (cRecordControls::Active()) { + if (Interface->Confirm(tr("Recording - shut down anyway?"))) + ForceShutdown = true; + } + LastActivity = 1; // not 0, see below! + break; + default: + if (*Interact) { + switch ((*Interact)->ProcessKey(key)) { + case osMenu: DELETENULL(Menu); + Menu = new cMenuMain(ReplayControl); + break; + case osRecord: DELETENULL(Menu); + if (!cRecordControls::Start()) + Interface->Error(tr("No free DVB device to record!")); + break; + case osRecordings: + DELETENULL(Menu); + DELETENULL(ReplayControl); + Menu = new cMenuRecordings; + break; + case osReplay: DELETENULL(Menu); + DELETENULL(ReplayControl); + ReplayControl = new cReplayControl; + break; #ifdef DVDSUPPORT - case osDVD: DELETENULL(Menu); - DELETENULL(ReplayControl); - Menu = new cMenuDVD; - break; + case osDVD: DELETENULL(Menu); + DELETENULL(ReplayControl); + Menu = new cMenuDVD; + break; #endif //DVDSUPPORT - case osStopReplay: - DELETENULL(*Interact); - DELETENULL(ReplayControl); - break; - case osSwitchDvb: - DELETENULL(*Interact); - Interface->Info(tr("Switching primary DVB...")); - cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); - break; - case osBack: - case osEnd: DELETENULL(*Interact); - break; - default: ; - } - } - else { - switch (key) { - // Toggle channels: - case k0: { - int CurrentChannel = cDvbApi::CurrentChannel(); - Channels.SwitchTo(PreviousChannel); - PreviousChannel = CurrentChannel; - break; - } - // Direct Channel Select: - case k1 ... k9: - Menu = new cDisplayChannel(key); - break; - // Left/Right rotates trough channel groups: - case kLeft|k_Repeat: - case kLeft: - case kRight|k_Repeat: - case kRight: - Menu = new cDisplayChannel(NORMALKEY(key)); - break; - // Up/Down Channel Select: - case kUp|k_Repeat: - case kUp: - case kDown|k_Repeat: - case kDown: { - int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1); - cChannel *channel = Channels.GetByNumber(n); - if (channel) - channel->Switch(); - break; - } - // Menu Control: - case kMenu: Menu = new cMenuMain(ReplayControl); break; - // Viewing Control: - case kOk: LastChannel = -1; break; // forces channel display - // Volume Control: - case kVolUp|k_Repeat: - case kVolUp: - case kVolDn|k_Repeat: - case kVolDn: - cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA); - break; - case kMute: - cDvbApi::PrimaryDvbApi->ToggleMute(); - break; - // Power off: - case kPower: isyslog(LOG_INFO, "Power button pressed"); - DELETENULL(*Interact); - if (!Shutdown) { - Interface->Error(tr("Can't shutdown - option '-s' not given!")); - break; - } - if (cRecordControls::Active()) { - if (Interface->Confirm(tr("Recording - shut down anyway?"))) - ForceShutdown = true; - } - LastActivity = 1; // not 0, see below! - break; - default: break; - } - } + case osStopReplay: + DELETENULL(*Interact); + DELETENULL(ReplayControl); + break; + case osSwitchDvb: + DELETENULL(*Interact); + Interface->Info(tr("Switching primary DVB...")); + cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); + break; + case osBack: + case osEnd: DELETENULL(*Interact); + break; + default: ; + } + } + else { + // Key functions in "normal" viewing mode: + switch (key) { + // Toggle channels: + case k0: { + int CurrentChannel = cDvbApi::CurrentChannel(); + Channels.SwitchTo(PreviousChannel); + PreviousChannel = CurrentChannel; + break; + } + // Direct Channel Select: + case k1 ... k9: + Menu = new cDisplayChannel(key); + break; + // Left/Right rotates trough channel groups: + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: + Menu = new cDisplayChannel(NORMALKEY(key)); + break; + // Up/Down Channel Select: + case kUp|k_Repeat: + case kUp: + case kDown|k_Repeat: + case kDown: { + int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1); + cChannel *channel = Channels.GetByNumber(n); + if (channel) + channel->Switch(); + break; + } + // Menu Control: + case kMenu: Menu = new cMenuMain(ReplayControl); break; + // Viewing Control: + case kOk: LastChannel = -1; break; // forces channel display + default: break; + } + } + } if (!Menu) { EITScanner.Process(); cVideoCutter::Active(); From 8465398c6d2a57bc30a07fb61353a7c8ba6db574 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 21 Oct 2001 18:00:00 +0200 Subject: [PATCH 027/307] =?UTF-8?q?Version=200.97=20-=20Implemented=20a=20?= =?UTF-8?q?lock=20file=20to=20prevent=20more=20than=20one=20instance=20of?= =?UTF-8?q?=20VDR=20from=20removing=20=20=20files=20from=20the=20video=20d?= =?UTF-8?q?irectory=20at=20the=20same=20time.=20-=20The=20new=20setup=20pa?= =?UTF-8?q?rameter=20SplitEditedFiles=20can=20be=20used=20to=20control=20w?= =?UTF-8?q?hether=20or=20=20=20not=20the=20result=20of=20an=20editing=20pr?= =?UTF-8?q?ocess=20shall=20be=20written=20into=20separate=20files.=20-=20F?= =?UTF-8?q?ixed=20handling=20repeat=20function=20when=20using=20LIRC=20(th?= =?UTF-8?q?anks=20to=20Matthias=20Weingart).=20-=20The=20shutdown=20progra?= =?UTF-8?q?m=20(defined=20with=20the=20'-s'=20option)=20now=20also=20gets?= =?UTF-8?q?=20the=20channel=20=20=20number=20and=20recording=20title=20of?= =?UTF-8?q?=20the=20timer=20(see=20INSTALL).=20-=20New=20channel=20data=20?= =?UTF-8?q?for=20'Premiere=20One',=20'Premiere=20X-Action',=20'Fox=20Kids?= =?UTF-8?q?=20T=FCrkce'=20=20=20and=20'N24'=20(thanks=20to=20Andreas=20Sha?= =?UTF-8?q?re,=20Ulrich=20R=F6der,=20Uwe=20Scheffler=20and=20Simon=20=20?= =?UTF-8?q?=20Bauschulte).=20Note=20that=20if=20you=20are=20using=20the=20?= =?UTF-8?q?default=20'channels.conf'=20or=20=20=20'channels.conf.cable'=20?= =?UTF-8?q?files=20you=20may=20need=20to=20check=20any=20exiting=20timers?= =?UTF-8?q?=20to=20see=20=20=20whether=20they=20still=20use=20the=20correc?= =?UTF-8?q?t=20channel=20number.=20-=20Fixed=20the=20"EPG=20bugfix"=20(som?= =?UTF-8?q?etimes=20had=20duplicate=20information=20in=20Subtitle=20and=20?= =?UTF-8?q?=20=20Extended=20Description).=20-=20Fixed=20checking=20for=20v?= =?UTF-8?q?alid=20video=20device=20when=20setting=20the=20video=20mode.=20?= =?UTF-8?q?-=20The=20external=20command=20'sort'=20is=20no=20longer=20requ?= =?UTF-8?q?ired.=20VDR=20now=20sorts=20the=20list=20of=20=20=20recordings?= =?UTF-8?q?=20itself,=20making=20sure=20that=20recordings=20that=20stem=20?= =?UTF-8?q?from=20repeating=20timers=20=20=20are=20sorted=20chronologicall?= =?UTF-8?q?y.=20Sorting=20is=20done=20according=20to=20the=20setting=20of?= =?UTF-8?q?=20the=20=20=20current=20locale,=20so=20you=20may=20want=20to?= =?UTF-8?q?=20make=20sure=20LC=5FCOLLATE=20is=20set=20to=20the=20desired?= =?UTF-8?q?=20=20=20value=20(see=20INSTALL).=20-=20Fixed=20handling=20'new?= =?UTF-8?q?line'=20characters=20in=20EPG=20texts=20(thanks=20to=20Rolf=20H?= =?UTF-8?q?akenes=20for=20=20=20an=20improved=20version=20of=20his=20'libd?= =?UTF-8?q?tv').=20=20=20Newline=20characters=20are=20always=20mapped=20to?= =?UTF-8?q?=20a=20single=20"blank"=20in=20VDR,=20because=20they=20=20=20wo?= =?UTF-8?q?uld=20otherwise=20disturb=20the=20Title=20and=20Subtitle=20layo?= =?UTF-8?q?ut=20in=20the=20channel=20display=20=20=20(where=20these=20are?= =?UTF-8?q?=20assumed=20to=20be=20single=20line=20texts)=20and=20would=20h?= =?UTF-8?q?ave=20to=20be=20=20=20specially=20handled=20in=20the=20'epg.dat?= =?UTF-8?q?a'=20file=20and=20the=20LSTE=20command=20in=20SVDRP.=20-=20Mapp?= =?UTF-8?q?ing=20`=20("backtick")=20characters=20in=20EPG=20texts=20to=20'?= =?UTF-8?q?=20(single=20quote).=20-=20Fixed=20timers=20starting=20and=20en?= =?UTF-8?q?ding=20at=20unexpected=20times.=20'localtime()'=20was=20not=20?= =?UTF-8?q?=20=20thread=20safe,=20now=20using=20localtime=5Fr().=20-=20Rem?= =?UTF-8?q?oved=20the=20"system=20time=20seen..."=20message.=20-=20Fixed?= =?UTF-8?q?=20a=20bug=20in=20the=20replay=20mode=20display=20when=20pressi?= =?UTF-8?q?ng=20the=20Green=20or=20Yellow=20=20=20button=20while=20in=20tr?= =?UTF-8?q?ick=20mode=20(thanks=20to=20Stefan=20Huelswitt)=20-=20Closing?= =?UTF-8?q?=20all=20open=20file=20descriptors=20when=20calling=20external?= =?UTF-8?q?=20programs.=20-=20The=20menu=20timeout=20now=20also=20works=20?= =?UTF-8?q?when=20pressing=20the=20"Back"=20button=20during=20replay=20=20?= =?UTF-8?q?=20to=20enter=20the=20"Recordings"=20menu.=20-=20Updated=20'cha?= =?UTF-8?q?nnels.conf'=20for=20the=20"Bundesliga"=20channels=20of=20Premie?= =?UTF-8?q?re=20World=20=20=20(thanks=20to=20Helmut=20Sch=E4chner).=20-=20?= =?UTF-8?q?Fixed=20reading=20timers.conf=20and=20channels.conf=20that=20co?= =?UTF-8?q?ntain=20blanks=20after=20numeric=20=20=20values.=20-=20Fixed=20?= =?UTF-8?q?handling=20trick=20modes=20near=20the=20beginning=20and=20end?= =?UTF-8?q?=20of=20a=20recording.=20-=20Pressing=20the=20"Back"=20button?= =?UTF-8?q?=20while=20replaying=20a=20DVD=20now=20leads=20to=20the=20DVD?= =?UTF-8?q?=20menu.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTORS | 10 +- HISTORY | 44 ++++++++ INSTALL | 26 ++++- MANUAL | 11 +- Makefile | 4 +- channels.conf | 24 +++-- channels.conf.cable | 151 +++++++++++++------------- config.c | 37 ++++--- config.h | 6 +- dvbapi.c | 130 ++++++++++++---------- eit.c | 35 ++++-- i18n.c | 11 +- libdtv/Makefile | 6 +- libdtv/liblx/Makefile | 6 +- libdtv/liblx/liblx.h | 6 +- libdtv/liblx/xListFuncs.c | 2 +- libdtv/liblx/xMemMgt.c | 2 +- libdtv/libsi/Makefile | 8 +- libdtv/libsi/include/libsi.h | 178 ++++++++++++++++++++++++++++--- libdtv/libsi/include/si_tables.h | 66 +++++++++--- libdtv/libsi/si_debug_services.c | 62 +++++++++-- libdtv/libsi/si_debug_services.h | 2 +- libdtv/libsi/si_parser.c | 72 +++++++++++-- libdtv/libvdr/Makefile | 6 +- libdtv/libvdr/libvdr.c | 4 +- libdtv/libvdr/libvdr.h | 6 +- menu.c | 26 +++-- menu.h | 7 +- recording.c | 66 ++++++++++-- recording.h | 6 +- remote.c | 3 +- svdrp.c | 4 +- thread.c | 36 ++++++- thread.h | 7 +- tools.c | 76 ++++++++++++- tools.h | 13 ++- vdr.c | 19 ++-- 37 files changed, 902 insertions(+), 276 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index f1157b1f7..3a04af16c 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -104,9 +104,10 @@ Stefan Huelswitt <huels@iname.com> for implementing backtracing for fast forward/rewind for implementing the replay mode display -Ulrich Rder <dynamite@efr-net.de> +Ulrich Rder <roeder@efr-net.de> for pointing out that there are channels that have a symbol rate higher than 27500 + for his support in keeping the Premiere World channels up to date in 'channels.conf' Helmut Schchner <schaechner@yahoo.com> for his support in keeping the Premiere World channels up to date in 'channels.conf' @@ -142,3 +143,10 @@ Andreas Vitting <Andreas@huji.de> Matthias Weingart <matthias@pentax.boerde.de> for fixing handling of the volume, mute and power keys when menus are active + for fixing the repeat function when using the LIRC remote control + +Andreas Share <a.share@t-online.de> + for his support in keeping the Premiere World channels up to date in 'channels.conf' + +Simon Bauschulte <SemiSchwabe@Brutzel.de> + for his support in keeping the Premiere World channels up to date in 'channels.conf' diff --git a/HISTORY b/HISTORY index 143c2f45b..5087c9ef1 100644 --- a/HISTORY +++ b/HISTORY @@ -786,3 +786,47 @@ Video Disk Recorder Revision History at the expected time). - Made the volume, mute and power keys work when a menu is active, too (thanks to Matthias Weingart). + +2001-10-21: Version 0.97 + +- Implemented a lock file to prevent more than one instance of VDR from removing + files from the video directory at the same time. +- The new setup parameter SplitEditedFiles can be used to control whether or + not the result of an editing process shall be written into separate files. +- Fixed handling repeat function when using LIRC (thanks to Matthias Weingart). +- The shutdown program (defined with the '-s' option) now also gets the channel + number and recording title of the timer (see INSTALL). +- New channel data for 'Premiere One', 'Premiere X-Action', 'Fox Kids Trkce' + and 'N24' (thanks to Andreas Share, Ulrich Rder, Uwe Scheffler and Simon + Bauschulte). Note that if you are using the default 'channels.conf' or + 'channels.conf.cable' files you may need to check any exiting timers to see + whether they still use the correct channel number. +- Fixed the "EPG bugfix" (sometimes had duplicate information in Subtitle and + Extended Description). +- Fixed checking for valid video device when setting the video mode. +- The external command 'sort' is no longer required. VDR now sorts the list of + recordings itself, making sure that recordings that stem from repeating timers + are sorted chronologically. Sorting is done according to the setting of the + current locale, so you may want to make sure LC_COLLATE is set to the desired + value (see INSTALL). +- Fixed handling 'newline' characters in EPG texts (thanks to Rolf Hakenes for + an improved version of his 'libdtv'). + Newline characters are always mapped to a single "blank" in VDR, because they + would otherwise disturb the Title and Subtitle layout in the channel display + (where these are assumed to be single line texts) and would have to be + specially handled in the 'epg.data' file and the LSTE command in SVDRP. +- Mapping ` ("backtick") characters in EPG texts to ' (single quote). +- Fixed timers starting and ending at unexpected times. 'localtime()' was not + thread safe, now using localtime_r(). +- Removed the "system time seen..." message. +- Fixed a bug in the replay mode display when pressing the Green or Yellow + button while in trick mode (thanks to Stefan Huelswitt) +- Closing all open file descriptors when calling external programs. +- The menu timeout now also works when pressing the "Back" button during replay + to enter the "Recordings" menu. +- Updated 'channels.conf' for the "Bundesliga" channels of Premiere World + (thanks to Helmut Schchner). +- Fixed reading timers.conf and channels.conf that contain blanks after numeric + values. +- Fixed handling trick modes near the beginning and end of a recording. +- Pressing the "Back" button while replaying a DVD now leads to the DVD menu. diff --git a/INSTALL b/INSTALL index b942603ec..e7e673162 100644 --- a/INSTALL +++ b/INSTALL @@ -90,6 +90,24 @@ option to set the controlling terminal, as in vdr:123:respawn:/usr/local/bin/vdr --terminal=/dev/tty8 -w 60 +Locale +------ + +When presenting the list of recordings, VDR sorts the entries according to +the current "locale" settings. This makes sure that special characters (like +the German "umlauts") appear at the expected positions. In order to benefit +from this you may have to set the locale environment variable, for instance + + export LANG=de_DE + +for a German locale. If you don't want this to result in German error messages +in the log file, it is sufficient to just set + + export LC_COLLATE=de_DE + +which only influences the way strings are sorted and leaves error messages +in English. + Automatic restart in case of hangups: ------------------------------------- @@ -109,7 +127,7 @@ active, the user has been inactive for at least MinUserInactivity minutes and the next timer event is at least MinEventTimeout minutes in the future (see the Setup parameters in MANUAL). -The command given in the '-s' option will be called with two parameters. +The command given in the '-s' option will be called with four parameters. The first one is the time (in UTC) of the next timer event (as a time_t type number), and the second one is the number of seconds from the current time until the next timer event. Your program can choose which one to use @@ -129,6 +147,12 @@ and only perform the system shutdown. A program that uses the second parameter to set the hardware for restart must therefore also check whether the first parameter is '0'. +The third parameter contains the number of the channel that will be recorded +by the next timer (or 0 if no timer is present), and the fourth parameter +contains the file name of the recording as defined in the timer (or an empty +string if no timer is present). These can be used by the shutdown program to +show that information on some display interface etc. + If a timer is currently recording, the parameters will reflect the start time of that timer. This means that the first parameter will be a time in the past, and the second parameter will be a negative number. This only diff --git a/MANUAL b/MANUAL index 05f2f3ca9..7bb1ec83f 100644 --- a/MANUAL +++ b/MANUAL @@ -8,7 +8,7 @@ Video Disk Recorder User's Manual possible, several keys have different meanings in the various modes: - Key Normal Main Channels Timers Edit/New Recordings Replay + Key Normal Main Channels Timers Edit/New Recordings Replay Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause @@ -386,7 +386,8 @@ Video Disk Recorder User's Manual 0 = no EPG fixing 1 = basic fixing of text location (Title, Subtitle and Extended Description) - 2 = removal of excess whitespace and hyphens + 2 = removal of excess whitespace and hyphens, mapping of + wrongly used characters 3 = fixing the date in timestamps between 00:00 and 06:00 (use with care - hopefully one day Pro7 and Kabel1 will learn how to read the clock/calender) @@ -449,6 +450,12 @@ Video Disk Recorder User's Manual you may want to use smaller values if you are planning on archiving a recording to CD. + SplitEditedFiles = 0 During the actual editing process VDR writes the result + into files that may grow up to MaxVideoFileSize. If you + prefer to have each marked sequence stored in a separate + file (named 001.vdr, 002.vdr, ...) you can set this + option to 1. + MinEventTimeout=30 If the command line option '-s' has been set, VDR will MinUserInactivity=120 automatically shutdown the computer if the next timer event is at least MinEventTimeout minutes in the future, diff --git a/Makefile b/Makefile index f39be0886..4efae4b12 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.27 2001/08/31 13:13:30 kls Exp $ +# $Id: Makefile 1.28 2001/10/07 15:14:50 kls Exp $ .DELETE_ON_ERROR: @@ -39,6 +39,8 @@ endif DEFINES += -DREMOTE_$(REMOTE) +DEFINES += -D_GNU_SOURCE + ifdef DEBUG_OSD DEFINES += -DDEBUG_OSD endif diff --git a/channels.conf b/channels.conf index 9c904916e..200fbfe01 100644 --- a/channels.conf +++ b/channels.conf @@ -24,7 +24,7 @@ Super RTL:12188:h:0:27500:165:120:65:0:12040 VOX:12188:h:0:27500:167:136:0:0:12060 DW TV:12363:v:0:27500:305:306:0:0:8905 Kabel 1:12480:v:0:27500:511:512:33:0:899 -tm3:12480:v:0:27500:767:768:0:0:897 +Neun Live:12480:v:0:27500:767:768:0:0:897 DSF:12480:v:0:27500:1023:1024:0:0:900 HOT:12480:v:0:27500:1279:1280:0:0:40 Bloomberg TV Germany:12551:v:0:22000:162:99:0:0:12160 @@ -52,9 +52,11 @@ Premiere World:11797:h:0:27500:255:256:32:0:8 Premiere 1:11797:h:0:27500:511:512:0:3:10 Premiere 2:11797:h:0:27500:1791:1792:0:3:11 Premiere 3:11797:h:0:27500:2303:2304:0:3:43 +Premiere One:12032:h:0:27500:3071:3072:0:3:51 Premiere Star:11797:h:0:27500:767:768:0:3:9 Premiere Sci-Fi:11797:h:0:27500:1535:1536:0:3:41 Premiere Action:11797:h:0:27500:1023:1024:0:3:20 +Premiere X-Action:11798:h:0:27500:2047:2048:0:3:50 Premiere Comedy:11797:h:0:27500:1279:1280:0:3:29 13th Street:12031:h:0:27500:2303:2304:0:3:42 Studio Universal:12090:V:0:27500:255:256:0:3:36 @@ -63,6 +65,7 @@ Heimatkanal:12031:h:0:27500:2815:2816:0:3:517 Discovery Channel:12031:h:0:27500:1791:1792:0:3:14 Planet:12090:V:0:27500:1279:1280:0:3:13 Fox Kids:12031:h:0:27500:1279:1280:0:3:28 +Fox Kids Trkce:11914:H:0:27500:767:768:8191:3:54 Junior:12031:h:0:27500:255:256:0:3:19 K-Toon:12031:h:0:27500:511:512:0:3:12 Disney Channel:12090:V:0:27500:767:768:0:3:34 @@ -93,6 +96,7 @@ Cinedom 5A:11758:h:0:27500:1279:1280:0:3:194 Cinedom 5B:11720:h:0:27500:1791:1792:0:3:177 Cinedom 5C:12070:h:0:27500:1023:1024:0:3:186 :Beta Digital +N24:11914:H:0:27500:255:256:8191:3:52 CNBC:12148:h:0:27500:255:256:0:3:35 Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199 :PW Erotic @@ -112,15 +116,15 @@ Verfolgerfeld:11720:h:0:27500:2303:2304:0:3:241 Cockpitkanal:11720:h:0:27500:2559:2560:0:3:242 Boxengasse:11720:h:0:27500:2047:2048:0:3:240 :Premiere World Bundesliga -Superdom:12070:h:0:27500:255:256:0:3:26 -Spiel 1:11719:h:0:27500:255:256,257:0:3:17 -Spiel 2:11719:h:0:27500:2047:2048,2049:0:3:240 -BuLi-Konferenz:12070:h:0:27500:3071:3072,3073:0:3:208 -BuLi-Spiel 1:12070:h:0:27500:3327:3328,3329:0:3:209 -BuLi-Spiel 2:12070:h:0:27500:2303:2304,2305:0:3:210 -BuLi-Spiel 3:12070:h:0:27500:3583:3584,3585:0:3:211 -BuLi-Spiel 4:12070:h:0:27500:2559:2560,2561:0:3:212 -BuLi-Spiel 5:12070:h:0:27500:2815:2816,2817:0:3:213 +Superdom:11758:h:0:27500:2815:8192:0:3:18 +BuLi-Konferenz:11758:h:0:27500:3071:3072,3073:0:3:215 +BuLi-Spiel 1:11719:h:0:27500:255:256,257:0:3:17 +BuLi-Spiel 2:11719:h:0:27500:2047:2048,2049:0:3:240 +BuLi-Spiel 3:11719:h:0:27500:3327:3328,3329:0:3:241 +BuLi-Spiel 4:11719:h:0:27500:2303:2304,2305:0:3:242 +BuLi-Spiel 5:11719:h:0:27500:3583:3584,3585:0:3:243 +BuLi-Spiel 6:11719:h:0:27500:2559:2560,2561:0:3:244 +BuLi-Spiel 7:11758:h:0:27500:2815:2816,2817:0:3:214 : TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601 Mosaico:11934:v:0:27500:165:100:0:0:29010 diff --git a/channels.conf.cable b/channels.conf.cable index 60b3eb573..6e0f43b70 100644 --- a/channels.conf.cable +++ b/channels.conf.cable @@ -1,54 +1,56 @@ :verschlsselte Fernsehprogramm -PREMIERE 1:370:h:0:6900:511:512:0:1:10 -PREMIERE 2:370:h:0:6900:1791:1792:0:1:11 -PREMIERE 3:370:h:0:6900:2303:2304:0:1:43 -PREMIERE ACTION:370:h:0:6900:1023:1024:0:1:20 +PREMIERE ONE:378:h:0:6900:3071:3072:0:1:51 +PREMIERE MOVIE 1:370:h:0:6900:511:512:0:1:10 +PREMIERE MOVIE 2:370:h:0:6900:1791:1792:0:1:11 +PREMIERE MOVIE 3:370:h:0:6900:2303:2304:0:1:43 +PREMIERE ACTION:370:h:0:6900:1023:1024,1025:0:1:20 +PREMIERE X-ACTION:370:h:0:6900:2047:2048,2049:0:1:50 PREMIERE SCI-FI:370:h:0:6900:1535:1536:0:1:41 PREMIERE STAR:370:h:0:6900:767:768:0:1:9 PREMIERE COMEDY:370:h:0:6900:1279:1280:0:1:29 -13 TH STREET:378:h:0:6900:2303:2304:0:1:42 +13 TH STREET:378:h:0:6900:2303:2304,2305:0:1:42 KRIMI &CO:378:h:0:6900:1535:1536:0:1:23 STUDIO UNIVERSAL:402:h:0:6900:1050:1054:0:1:36 DISCOVERY CHANNEL:378:h:0:6900:1791:1792:0:1:14 +FILMPALAST:378:h:0:6900:2559:2560:0:1:516 DISNEY CHANNEL:402:h:0:6900:1030:1034:0:1:34 SUNSET:378:h:0:6900:1023:1024:0:1:16 PLANET:402:h:0:6900:1100:1104:0:1:13 -SEASONS:402:h:0:6900:1040:1044:0:1:33 CLASSICA:378:h:0:6900:767:768:0:1:15 GOLDSTAR TV:378:h:0:6900:3839:3840:0:1:518 -FILMPALAST:378:h:0:6900:2559:2560:0:1:516 HEIMATKANAL:378:h:0:6900:2815:2816:0:1:517 +K-TOON:378:h:0:6900:511:512:0:1:12 FOX KIDS:378:h:0:6900:1279:1280:0:1:28 +KiKa:394:h:0:6900:310:320:330:0:28008 JUNIOR:378:h:0:6900:255:256:0:1:19 -K-TOON:378:h:0:6900:12:13:0:1:12 :Fernsehprogramme -Das Erste:410:h:0:6900:101:102:104:0:28106 -ZDF:394:h:0:6900:110:120:130:0:28006 +Das Erste:410:h:0:6900:101:102,88:104:0:28106 +ZDF:394:h:0:6900:110:120,121:130:0:28006 ZDF.info:394:h:0:6900:610:620:0:0:28011 ZDF.doku:394:h:0:6900:660:670:0:0:28014 -ZDF Theaterkanal:394:h:0:6900:3440:3441:0:0:28016 +ZDF Theaterkanal:394:h:0:6900:1110:1120:130:0:28016 +EinsExtra:426:h:0:6900:101:102:0:0:28201 +EinsFestival:426:h:0:6900:201:202:0:0:28202 +EinsMuXx:426:h:0:6900:301:302:0:0:28203 3sat:394:h:0:6900:210:220:230:0:28007 -KiKa:394:h:0:6900:310:320:330:0:28008 +arte:410:h:0:6900:401:402:404:0:28109 EuroNews:394:h:0:6900:2221:2233:768:0:28015 +Phoenix:410:h:0:6900:901:902:0:0:28114 Eurosport:394:h:0:6900:410:420:430:0:28009 DW-tv:610:h:0:6900:634:632:0:0:6101 CNBC:394:h:0:6900:510:520:530:0:28010 -Test-R:410:h:0:6900:901:902:104:0:28130 -Bayerisches FS:410:h:0:6900:201:202:204:0:28107 WDR FERNSEHEN:410:h:0:6900:601:602:604:0:28111 -arte:410:h:0:6900:401:402:404:0:28109 +MDR FERNSEHEN:426:h:0:6900:401:402:404:0:28204 SR Fernsehen Suedwest:410:h:0:6900:501:502:504:0:28110 -hessen fernsehen:410:h:0:6900:301:302:304:0:28108 +SuedWest BW:410:h:0:6900:801:802:804:0:28113 +SuedWest RP:426:h:0:6900:3101:3102:3104:0:28231 BR-alpha:410:h:0:6900:701:702:704:0:28112 -SWR Fernsehen:410:h:0:6900:801:802:804:0:28113 -Phoenix:410:h:0:6900:901:902:0:0:28114 -EinsExtra:426:h:0:6900:101:102:0:0:28201 -EinsFestival:426:h:0:6900:201:202:0:0:28202 -EinsMuXx:426:h:0:6900:301:302:0:0:28203 -MDR FERNSEHEN:426:h:0:6900:401:402:404:0:28204 -ORB-Fernsehen:426:h:0:6900:501:502:504:0:28205 B1 Berlin:426:h:0:6900:601:602:604:0:28206 N3:426:h:0:6900:2401:2402:2404:0:28224 +ORB-Fernsehen:426:h:0:6900:501:502:504:0:28205 +hessen fernsehen:410:h:0:6900:301:302:304:0:28108 +Bayerisches FS:410:h:0:6900:201:202:204:0:28107 +Test-R:410:h:0:6900:901:902:104:0:28130 :Mediavision Extreme Sport:346:h:0:6900:801:802:0:1:50700 Bloomberg:346:h:0:6900:811:812:0:1:50701 @@ -60,6 +62,7 @@ Einstein:346:h:0:6900:623:624:0:1:50719 Leitseite:346:h:0:6900:2254:0:0:0:5004 Via 1 - Schner Reisen:346:h:0:6900:611:612:0:0:50705 Parlamentsfernsehen:610:h:0:6900:33:36:47:0:6100 +Vh1 - Classic:610:h:0:6900:604:603:0:0:6106 :Diverse TV-Sender TV Polonia:434:h:0:6900:641:642:0:1:53204 Kanal D:434:h:0:6900:651:652:0:1:53205 @@ -68,18 +71,10 @@ ERT-Sat:434:h:0:6900:691:692:0:1:53209 CNE:434:h:0:6900:4056:4057:0:1:53208 ZEE TV:442:h:0:6900:517:773:0:1:53301 NTV i:442:h:0:6900:514:515:0:1:53302 -Leonardo:610:h:0:6900:653:652:0:1:6102 -Alice:610:h:0:6900:651:650:0:1:6103 -Nuvolari:610:h:0:6900:649:648:0:1:6104 ATV:434:h:0:6900:631:632:0:0:53203 -unknown:434:h:0:6900:2570:2571:0:0:18954 TW1:610:h:0:6900:6106:6107:0:0:6106 -unknown:346:h:0:6900:2930:2931:0:0:11122 -unknown:394:h:0:6900:1844:1845:0:1:59188 -unknown:410:h:0:6900:627:628:0:1:627 PREMIERE WORLD:370:h:0:6900:255:256:32:0:8 :Premiere World Bundesliga -SUPERDOM:386:h:0:6900:255:257:0:1:26 Superdom:362:h:0:6900:255:256:0:1:26 Spiel 1:362:h:0:6900:255:256,257:0:1:17 Spiel 2:362:h:0:6900:2047:2048,2049:0:1:240 @@ -90,9 +85,9 @@ BuLi-Spiel 3:362:h:0:6900:3583:3584,3585:0:1:211 BuLi-Spiel 4:362:h:0:6900:2559:2560,2561:0:1:212 BuLi-Spiel 5:362:h:0:6900:2815:2816,2817:0:1:213 :Premiere Sport -PR-SPORT 1:362:h:0:6900:255:256:0:1:17 -PR-SPORT 2:362:h:0:6900:3327:3328:0:1:27 -PR-SPORT 3:362:h:0:6900:2815:2816:0:1:18 +PREMIERE SPORT 1:362:h:0:6900:255:256:0:1:17 +PREMIERE SPORT 2:362:h:0:6900:3327:3328:0:1:27 +PREMIERE SPORT 3:354:h:0:6900:2815:2816:0:1:18 :Premiere Formel 1 F1 Studio:362:h:0:6900:255:256:0:1:17 F1 Box:362:h:0:6900:2047:2048:0:1:240 @@ -106,35 +101,40 @@ Cinedom 1B:386:h:0:6900:1535:1536,1537:0:1:178 Cinedom 1C:362:h:0:6900:511:512,513:0:1:180 Cinedom 1D:354:h:0:6900:511:512,513:0:1:190 :Premiere Cinedom 2 -Cinedom 2A:386:h:0:6900:1791:1792:0:1:179 -Cinedom 2B:362:h:0:6900:1279:1280:0:1:183 +Cinedom 2A:386:h:0:6900:1791:1792,1793:0:1:179 +Cinedom 2B:362:h:0:6900:1279:1280,1281:0:1:183 Cinedom 2C:386:h:0:6900:511:512:0:1:184 Cinedom 2D:386:h:0:6900:1279:1280:0:1:188 Cinedom 2E:354:h:0:6900:1023:1024:0:1:193 : Premiere Cinedom 3 -Cinedom 3A:362:h:0:6900:1023:1024:0:1:182 +Cinedom 3A:362:h:0:6900:1023:1024,1025:0:1:182 Cinedom 3B:386:h:0:6900:767:768:0:1:185 Cinedom 3C:354:h:0:6900:2559:2560:0:1:192 Cinedom 3D:354:h:0:6900:1535:1536:0:1:195 : Premiere Cinedom 4 -Cinedom 4A:362:h:0:6900:767:768:0:1:181 +Cinedom 4A:362:h:0:6900:767:768,769:0:1:181 Cinedom 4B:386:h:0:6900:2047:2048:0:1:187 Cinedom 4C:354:h:0:6900:767:768:0:1:191 : Premiere Cinedom 5 -Cinedom 5A:386:h:0:6900:1023:1024:0:1:186 -Cinedom 5B:354:h:0:6900:1279:1280:0:1:194 +Cinedom 5A:386:h:0:6900:1023:1024,1025:0:1:186 +Cinedom 5B:354:h:0:6900:1279:1280,1281:0:1:194 : Premiere Cinedom Deluxe -CINEDOM DELUXE:354:h:0:6900:255:256,257;259:0:1:189 +CINEDOM DELUXE:354:h:0:6900:255:256,257:0:1:189 :Premiere Erotic BEATE-UHSE.TV:354:h:0:6900:3839:3840:0:1:21 BLUE MOVIE 1:354:h:0:6900:1791:1792:0:1:513 BLUE MOVIE 2:354:h:0:6900:2047:2048:0:1:514 BLUE MOVIE 3:354:h:0:6900:2303:2304:0:1:515 :Radioprogramme -100,6:354:h:0:6900:0:1312:0:0:161 +Fritz:426:h:0:6900:0:901:0:0:28209 +HR XXL:410:h:0:6900:0:3501:0:0:28125 +JUMP:426:h:0:6900:0:1001:0:0:28210 +SPUTNIK:426:h:0:6900:0:1201:0:0:28212 +RADIOmultikulti:426:h:0:6900:0:1301:0:0:28213 DLR-Berlin:394:h:0:6900:0:710:0:0:28012 DLF-Kln:394:h:0:6900:0:810:0:0:28013 sterreich 1:394:h:0:6900:0:169:0:0:28017 +100,6:354:h:0:6900:0:1312:0:0:161 Bayern 4 Klassik:410:h:0:6900:0:3001:0:0:28120 B5 aktuell:410:h:0:6900:0:3101:0:0:28121 Bremen 2:410:h:0:6900:0:3801:0:0:28128 @@ -143,47 +143,42 @@ NDR 4 Info:410:h:0:6900:0:3701:0:0:28127 SR 1:410:h:0:6900:0:3901:0:0:28129 hr-klassik:410:h:0:6900:0:3401:0:0:28124 hr2:410:h:0:6900:0:3301:0:0:28123 -HR XXL:410:h:0:6900:0:3501:0:0:28125 hr-chronos:410:h:0:6900:0:3201:0:0:28122 Radio 3:426:h:0:6900:0:701:0:0:28207 MDR KULTUR:426:h:0:6900:0:801:0:0:28208 -Fritz:426:h:0:6900:0:901:0:0:28209 -JUMP:426:h:0:6900:0:1001:0:0:28210 MDR info:426:h:0:6900:0:1101:0:0:28211 -SPUTNIK:426:h:0:6900:0:1201:0:0:28212 -RADIOmultikulti:426:h:0:6900:0:1301:0:0:28213 SWR-2:426:h:0:6900:0:1401:0:0:28214 WDR3:426:h:0:6900:0:1501:0:0:28215 WDR Radio 5:426:h:0:6900:0:1601:0:0:28216 :verschlsselte Radioprogramme -KLASSIK POPULR:378:h:0:6900:0:592:0:1:145 -KLASS. SYMPHONIEN:378:h:0:6900:0:608:0:1:146 -OPER & VOKALMUSIK:378:h:0:6900:0:624:0:1:147 -BAROCKMUSIK:378:h:0:6900:0:640:0:1:148 -JAZZ:378:h:0:6900:0:656:0:1:149 -HITLISTE:378:h:0:6900:0:784:0:1:150 -ALTERNATIVE ROCK:378:h:0:6900:0:800:0:1:151 -DANCE:378:h:0:6900:0:816:0:1:152 -COUNTRY:378:h:0:6900:0:352:0:1:153 -CLASSIC ROCK:378:h:0:6900:0:544:0:1:154 -FILMMUSIK:378:h:0:6900:0:368:0:1:155 -DEUTSCHE HITS:402:h:0:6900:0:1156:0:1:156 -SOUL CLASSICS:402:h:0:6900:0:1161:0:1:157 -TRK MZIGI:402:h:0:6900:0:1166:0:1:158 -GOLD:402:h:0:6900:0:1171:0:1:159 -EASY LISTENING:402:h:0:6900:0:1201:0:1:162 -LOVE SONGS:402:h:0:6900:0:1191:0:1:163 -MUSICALS:402:h:0:6900:0:1196:0:1:164 -OLD GOLD:402:h:0:6900:0:1186:0:1:165 -SCHLAGER:402:h:0:6900:0:1176:0:1:166 -VOLKSMUSIK:402:h:0:6900:0:1181:0:1:167 -All Jazz:442:h:0:6900:0:535:0:1:53350 -Cristal New Age:442:h:0:6900:0:536:0:0:53351 -Movie Sounds:442:h:0:6900:0:537:0:1:53352 -Sinfonica:442:h:0:6900:0:538:0:1:53353 -Opernfestival:442:h:0:6900:0:539:0:1:53354 -Barock Fantasie:442:h:0:6900:0:540:0:1:53355 -Musica Camerata:442:h:0:6900:0:541:0:1:53356 -Musica Antica:442:h:0:6900:0:542:0:1:53357 -Adagio:442:h:0:6900:0:543:0:1:53358 -Jazz Legends:442:h:0:6900:0:544:0:1:53359 +ALTERNATIVE ROCK:378:h:0:6900:1:800:0:1:151 +HITLISTE:378:h:0:6900:1:784:0:1:150 +DANCE:378:h:0:6900:1:816:0:1:152 +EASY LISTENING:402:h:0:6900:1:1201:0:1:162 +CLASSIC ROCK:378:h:0:6900:1:544:0:1:154 +Cristal New Age:442:h:0:6900:1:536:0:0:53351 +Movie Sounds:442:h:0:6900:1:537:0:1:53352 +LOVE SONGS:402:h:0:6900:1:1191:0:1:163 +KLASSIK POPULR:378:h:0:6900:1:592:0:1:145 +KLASS. SYMPHONIEN:378:h:0:6900:1:608:0:1:146 +OPER & VOKALMUSIK:378:h:0:6900:1:624:0:1:147 +BAROCKMUSIK:378:h:0:6900:1:640:0:1:148 +JAZZ:378:h:0:6900:1:656:0:1:149 +COUNTRY:378:h:0:6900:1:352:0:1:153 +FILMMUSIK:378:h:0:6900:1:368:0:1:155 +DEUTSCHE HITS:402:h:0:6900:1:1156:0:1:156 +SOUL CLASSICS:402:h:0:6900:1:1161:0:1:157 +TRK MZIGI:402:h:0:6900:1:1166:0:1:158 +GOLD:402:h:0:6900:1:1171:0:1:159 +MUSICALS:402:h:0:6900:1:1196:0:1:164 +OLD GOLD:402:h:0:6900:1:1186:0:1:165 +SCHLAGER:402:h:0:6900:1:1176:0:1:166 +VOLKSMUSIK:402:h:0:6900:1:1181:0:1:167 +All Jazz:442:h:0:6900:1:535:0:1:53350 +Sinfonica:442:h:0:6900:1:538:0:1:53353 +Opernfestival:442:h:0:6900:1:539:0:1:53354 +Barock Fantasie:442:h:0:6900:1:540:0:1:53355 +Musica Camerata:442:h:0:6900:1:541:0:1:53356 +Musica Antica:442:h:0:6900:1:542:0:1:53357 +Adagio:442:h:0:6900:1:543:0:1:53358 +Jazz Legends:442:h:0:6900:1:544:0:1:53359 diff --git a/config.c b/config.c index 4df73614d..6ebaaacb9 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.73 2001/09/22 13:36:59 kls Exp $ + * $Id: config.c 1.76 2001/10/20 13:09:38 kls Exp $ */ #include "config.h" @@ -14,6 +14,10 @@ #include "i18n.h" #include "interface.h" +// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' +// format characters in order to allow any number of blanks after a numeric +// value! + // -- cKeys ------------------------------------------------------------------ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! @@ -251,16 +255,16 @@ bool cChannel::Parse(const char *s) else { groupSep = false; char *apidbuf = NULL; - int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%a[^:]:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apidbuf, &tpid, &ca, &pnr); + int fields = sscanf(s, "%a[^:]:%d :%c:%d :%d :%d :%a[^:]:%d :%d :%d ", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apidbuf, &tpid, &ca, &pnr); apid1 = apid2 = 0; dpid1 = dpid2 = 0; if (apidbuf) { char *p = strchr(apidbuf, ';'); if (p) *p++ = 0; - sscanf(apidbuf, "%d,%d", &apid1, &apid2); + sscanf(apidbuf, "%d ,%d ", &apid1, &apid2); if (p) - sscanf(p, "%d,%d", &dpid1, &dpid2); + sscanf(p, "%d ,%d ", &dpid1, &dpid2); delete apidbuf; } else @@ -324,7 +328,8 @@ cTimer::cTimer(bool Instant) cChannel *ch = Channels.GetByNumber(cDvbApi::CurrentChannel()); channel = ch ? ch->number : 0; time_t t = time(NULL); - struct tm *now = localtime(&t); + struct tm tm_r; + struct tm *now = localtime_r(&t, &tm_r); day = now->tm_mday; start = now->tm_hour * 100 + now->tm_min; stop = start + 200; // "instant recording" records 2 hours by default @@ -349,10 +354,11 @@ cTimer::cTimer(const cEventInfo *EventInfo) time_t tstart = EventInfo->GetTime(); time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60; tstart -= Setup.MarginStart * 60; - struct tm *time = localtime(&tstart); + struct tm tm_r; + struct tm *time = localtime_r(&tstart, &tm_r); day = time->tm_mday; start = time->tm_hour * 100 + time->tm_min; - time = localtime(&tstop); + time = localtime_r(&tstop, &tm_r); stop = time->tm_hour * 100 + time->tm_min; if (stop >= 2400) stop -= 2400; @@ -466,7 +472,7 @@ bool cTimer::Parse(const char *s) strcat(strn0cpy(s2, s, l2 + 1), " \n"); s = s2; } - if (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) { + if (8 <= sscanf(s, "%d :%d :%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) { if (summary && !*skipspace(summary)) { delete summary; summary = NULL; @@ -497,12 +503,14 @@ bool cTimer::IsSingleEvent(void) int cTimer::GetMDay(time_t t) { - return localtime(&t)->tm_mday; + struct tm tm_r; + return localtime_r(&t, &tm_r)->tm_mday; } int cTimer::GetWDay(time_t t) { - int weekday = localtime(&t)->tm_wday; + struct tm tm_r; + int weekday = localtime_r(&t, &tm_r)->tm_wday; return weekday == 0 ? 6 : weekday - 1; // we start with monday==0! } @@ -513,7 +521,8 @@ bool cTimer::DayMatches(time_t t) time_t cTimer::IncDay(time_t t, int Days) { - tm tm = *localtime(&t); + struct tm tm_r; + tm tm = *localtime_r(&t, &tm_r); tm.tm_mday += Days; // now tm_mday may be out of its valid range int h = tm.tm_hour; // save original hour to compensate for DST change t = mktime(&tm); // normalize all values @@ -523,7 +532,8 @@ time_t cTimer::IncDay(time_t t, int Days) time_t cTimer::SetTime(time_t t, int SecondsFromMidnight) { - tm tm = *localtime(&t); + struct tm tm_r; + tm tm = *localtime_r(&t, &tm_r); tm.tm_hour = SecondsFromMidnight / 3600; tm.tm_min = (SecondsFromMidnight % 3600) / 60; tm.tm_sec = SecondsFromMidnight % 60; @@ -803,6 +813,7 @@ cSetup::cSetup(void) OSDheight = 18; OSDMessageTime = 1; MaxVideoFileSize = MAXVIDEOFILESIZE; + SplitEditedFiles = 0; MinEventTimeout = 30; MinUserInactivity = 120; MultiSpeedMode = 0; @@ -843,6 +854,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); + else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); @@ -918,6 +930,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "OSDheight = %d\n", OSDheight); fprintf(f, "OSDMessageTime = %d\n", OSDMessageTime); fprintf(f, "MaxVideoFileSize = %d\n", MaxVideoFileSize); + fprintf(f, "SplitEditedFiles = %d\n", SplitEditedFiles); fprintf(f, "MinEventTimeout = %d\n", MinEventTimeout); fprintf(f, "MinUserInactivity = %d\n", MinUserInactivity); fprintf(f, "MultiSpeedMode = %d\n", MultiSpeedMode); diff --git a/config.h b/config.h index 8012cd26c..d0f0d77f3 100644 --- a/config.h +++ b/config.h @@ -4,13 +4,12 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.81 2001/09/22 13:37:05 kls Exp $ + * $Id: config.h 1.84 2001/10/07 15:13:23 kls Exp $ */ #ifndef __CONFIG_H #define __CONFIG_H -#define _GNU_SOURCE #include <stdio.h> #include <string.h> #include <time.h> @@ -19,7 +18,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.96" +#define VDRVERSION "0.97" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -298,6 +297,7 @@ class cSetup { int OSDwidth, OSDheight; int OSDMessageTime; int MaxVideoFileSize; + int SplitEditedFiles; int MinEventTimeout, MinUserInactivity; int MultiSpeedMode; int ShowReplayMode; diff --git a/dvbapi.c b/dvbapi.c index 8a6e69152..786dff7f0 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.129 2001/09/23 13:44:27 kls Exp $ + * $Id: dvbapi.c 1.132 2001/10/21 13:36:27 kls Exp $ */ //#define DVDDEBUG 1 @@ -72,6 +72,9 @@ extern "C" { // is broken: #define MAXBROKENTIMEOUT 30 // seconds +// The maximum time to wait before giving up while catching up on an index file: +#define MAXINDEXCATCHUP 2 // seconds + #define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls #define FATALERRNO (errno != EAGAIN && errno != EINTR) @@ -108,14 +111,14 @@ class cIndexFile { int size, last; tIndex *index; cResumeFile resumeFile; - bool CatchUp(void); + bool CatchUp(int Index = -1); public: cIndexFile(const char *FileName, bool Record); ~cIndexFile(); bool Ok(void) { return index != NULL; } void Write(uchar PictureType, uchar FileNumber, int FileOffset); bool Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType = NULL, int *Length = NULL); - int GetNextIFrame(int Index, bool Forward, uchar *FileNumber = NULL, int *FileOffset = NULL, int *Length = NULL); + int GetNextIFrame(int Index, bool Forward, uchar *FileNumber = NULL, int *FileOffset = NULL, int *Length = NULL, bool StayOffEnd = false); int Get(uchar FileNumber, int FileOffset); int Last(void) { CatchUp(); return last; } int GetResume(void) { return resumeFile.Read(); } @@ -199,42 +202,48 @@ cIndexFile::~cIndexFile() delete fileName; } -bool cIndexFile::CatchUp(void) +bool cIndexFile::CatchUp(int Index) { if (index && f >= 0) { - struct stat buf; - if (fstat(f, &buf) == 0) { - int newLast = buf.st_size / sizeof(tIndex) - 1; - if (newLast > last) { - if (size <= newLast) { - size *= 2; - if (size <= newLast) - size = newLast + 1; - } - index = (tIndex *)realloc(index, size * sizeof(tIndex)); - if (index) { - int offset = (last + 1) * sizeof(tIndex); - int delta = (newLast - last) * sizeof(tIndex); - if (lseek(f, offset, SEEK_SET) == offset) { - if (safe_read(f, &index[last + 1], delta) != delta) { - esyslog(LOG_ERR, "ERROR: can't read from index"); - delete index; - index = NULL; - close(f); - f = -1; - } - last = newLast; - return true; - } - else - LOG_ERROR; - } - else - esyslog(LOG_ERR, "ERROR: can't realloc() index"); - } - } - else - LOG_ERROR; + for (int i = 0; i <= MAXINDEXCATCHUP && (Index < 0 || Index >= last); i++) { + struct stat buf; + if (fstat(f, &buf) == 0) { + int newLast = buf.st_size / sizeof(tIndex) - 1; + if (newLast > last) { + if (size <= newLast) { + size *= 2; + if (size <= newLast) + size = newLast + 1; + } + index = (tIndex *)realloc(index, size * sizeof(tIndex)); + if (index) { + int offset = (last + 1) * sizeof(tIndex); + int delta = (newLast - last) * sizeof(tIndex); + if (lseek(f, offset, SEEK_SET) == offset) { + if (safe_read(f, &index[last + 1], delta) != delta) { + esyslog(LOG_ERR, "ERROR: can't read from index"); + delete index; + index = NULL; + close(f); + f = -1; + break; + } + last = newLast; + } + else + LOG_ERROR; + } + else + esyslog(LOG_ERR, "ERROR: can't realloc() index"); + } + } + else + LOG_ERROR; + if (Index >= last) + sleep(1); + else + return true; + } } return false; } @@ -256,7 +265,7 @@ void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType, int *Length) { if (index) { - CatchUp(); + CatchUp(Index); if (Index >= 0 && Index <= last) { *FileNumber = index[Index].number; *FileOffset = index[Index].offset; @@ -276,7 +285,7 @@ bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *Pictu return false; } -int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length) +int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length, bool StayOffEnd) { if (index) { if (Forward) @@ -284,7 +293,7 @@ int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *F int d = Forward ? 1 : -1; for (;;) { Index += d; - if (Index >= 0 && Index <= last) { + if (Index >= 0 && Index < last - ((Forward && StayOffEnd) ? 100 : 0)) { if (index[Index].type == I_FRAME) { if (FileNumber) *FileNumber = index[Index].number; @@ -1049,17 +1058,26 @@ void cReplayBuffer::Input(void) if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { uchar FileNumber; int FileOffset, Length; - int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length); + int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, true); if (Index >= 0) { if (!NextFile(FileNumber, FileOffset)) break; } else { - Play(); + // can't call Play() here, because those functions may only be + // called from the foreground thread - and we also don't need + // to empty the buffer here + CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); + CHECK(ioctl(videoDev, VIDEO_CONTINUE)); + playMode = pmPlay; + playDir = pdForward; continue; } readIndex = Index; r = ReadFrame(replayFile, b, Length, sizeof(b)); + // must call StripAudioPackets() here because the buffer is not emptied + // when falling back from "fast forward" to "play" (see above) + StripAudioPackets(b, r); } else if (index) { uchar FileNumber; @@ -1205,17 +1223,11 @@ void cReplayBuffer::SkipSeconds(int Seconds) Empty(true); int Index = writeIndex; if (Index >= 0) { - if (Seconds < 0) { - int sec = index->Last() / FRAMESPERSEC; - if (Seconds < -sec) - Seconds = -sec; - } - Index += Seconds * FRAMESPERSEC; - if (Index < 0) - Index = 1; // not '0', to allow GetNextIFrame() below to work! - uchar FileNumber; - int FileOffset; - readIndex = writeIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) - 1; // Input() will first increment it! + Index = max(Index + Seconds * FRAMESPERSEC, 0); + if (Index > 0) + Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true); + if (Index >= 0) + readIndex = writeIndex = Index - 1; // Input() will first increment it! } Empty(false); Play(); @@ -1250,9 +1262,9 @@ void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) { if (index) { if (playMode == pmStill) - Current = readIndex; + Current = max(readIndex, 0); else { - Current = writeIndex; + Current = max(writeIndex, 0); if (SnapToIFrame) { int i1 = index->GetNextIFrame(Current + 1, false); int i2 = index->GetNextIFrame(Current, true); @@ -2392,6 +2404,12 @@ void cCuttingBuffer::Action(void) Index = Mark->position; Mark = fromMarks.Next(Mark); CurrentFileNumber = 0; // triggers SetOffset before reading next frame + if (Setup.SplitEditedFiles) { + toFile = toFileName->NextFile(); + if (toFile < 0) + break; + FileSize = 0; + } } // the 'else' case (i.e. 'final end mark reached') is handled above // in 'Write one frame', so that the edited version will end right @@ -3163,7 +3181,7 @@ void cDvbApi::SetModeNormal(bool FromRecording) void cDvbApi::SetVideoFormat(videoFormat_t Format) { - if (fd_video) + if (fd_video >= 0) CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, Format)); } diff --git a/eit.c b/eit.c index 1fceeef1e..71ab54c3f 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.24 2001/09/22 13:07:21 kls Exp $ + * $Id: eit.c 1.28 2001/10/19 13:13:25 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -126,7 +126,8 @@ bool cMJD::SetSystemTime() struct tm *ptm; time_t loctim; - ptm = localtime(&mjdtime); + struct tm tm_r; + ptm = localtime_r(&mjdtime, &tm_r); loctim = time(NULL); if (abs(mjdtime - loctim) > 2) @@ -240,7 +241,8 @@ const char * cEventInfo::GetDate() const { static char szDate[25]; - strftime(szDate, sizeof(szDate), "%d.%m.%Y", localtime(&tTime)); + struct tm tm_r; + strftime(szDate, sizeof(szDate), "%d.%m.%Y", localtime_r(&tTime, &tm_r)); return szDate; } @@ -249,7 +251,8 @@ const char * cEventInfo::GetTimeString() const { static char szTime[25]; - strftime(szTime, sizeof(szTime), "%R", localtime(&tTime)); + struct tm tm_r; + strftime(szTime, sizeof(szTime), "%R", localtime_r(&tTime, &tm_r)); return szTime; } @@ -259,7 +262,8 @@ const char * cEventInfo::GetEndTimeString() const static char szEndTime[25]; time_t tEndTime = tTime + lDuration; - strftime(szEndTime, sizeof(szEndTime), "%R", localtime(&tEndTime)); + struct tm tm_r; + strftime(szEndTime, sizeof(szEndTime), "%R", localtime_r(&tEndTime, &tm_r)); return szEndTime; } @@ -337,6 +341,12 @@ void cEventInfo::Dump(FILE *f, const char *Prefix) const void cEventInfo::FixEpgBugs(void) { + // VDR can't usefully handle newline characters in the EPG data, so let's + // always convert them to blanks (independent of the setting of EPGBugfixLevel): + strreplace(pTitle, '\n', ' '); + strreplace(pSubtitle, '\n', ' '); + strreplace(pExtendedDescription, '\n', ' '); + if (Setup.EPGBugfixLevel == 0) return; @@ -395,7 +405,6 @@ void cEventInfo::FixEpgBugs(void) pSubtitle = NULL; } } - } // Pro7 sometimes repeats the Title in the Subtitle: // @@ -445,6 +454,13 @@ void cEventInfo::FixEpgBugs(void) } } + // Some channels use the ` ("backtick") character, where a ' (single quote) + // would be normally used. Actually, "backticks" in normal text don't make + // much sense, so let's replace them: + strreplace(pTitle, '`', '\''); + strreplace(pSubtitle, '`', '\''); + strreplace(pExtendedDescription, '`', '\''); + if (Setup.EPGBugfixLevel <= 2) return; @@ -455,10 +471,12 @@ void cEventInfo::FixEpgBugs(void) // correctly on the ASTRA satellite system. if (uServiceID == 898 // Pro-7 || uServiceID == 899) { // Kabel 1 - tm *t = localtime(&tTime); + struct tm tm_r; + tm *t = localtime_r(&tTime, &tm_r); if (t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec <= 6 * 3600) tTime += 24 * 3600; } + } } // --- cSchedule ------------------------------------------------------------- @@ -873,7 +891,8 @@ void cSIProcessor::Action() if (masterSIProcessor) { time_t now = time(NULL); - struct tm *ptm = localtime(&now); + struct tm tm_r; + struct tm *ptm = localtime_r(&now, &tm_r); if (now - lastCleanup > 3600 && ptm->tm_hour == 5) { LOCK_THREAD; diff --git a/i18n.c b/i18n.c index 5e440c951..926624a8a 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.43 2001/09/16 14:43:05 kls Exp $ + * $Id: i18n.c 1.44 2001/09/30 11:31:43 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -929,6 +929,15 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO }, + { "SplitEditedFiles", + "Editierte Dateien zerteilen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "MinEventTimeout", "Mindest Event Pause", "", // TODO diff --git a/libdtv/Makefile b/libdtv/Makefile index 50a140044..56cb53305 100644 --- a/libdtv/Makefile +++ b/libdtv/Makefile @@ -4,9 +4,9 @@ ### ### ############################################################## -## $Revision: 1.1 $ -## $Date: 2001/06/25 12:53:00 $ -## $Author: kls $ +## $Revision: 1.3 $ +## $Date: 2001/06/25 12:51:41 $ +## $Author: hakenes $ ## ## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. ## diff --git a/libdtv/liblx/Makefile b/libdtv/liblx/Makefile index a8034dec2..2531708ae 100644 --- a/libdtv/liblx/Makefile +++ b/libdtv/liblx/Makefile @@ -4,9 +4,9 @@ ### ### ############################################################## -## $Revision: 1.1 $ -## $Date: 2001/06/26 07:18:42 $ -## $Author: kls $ +## $Revision: 1.2 $ +## $Date: 2001/06/25 19:39:00 $ +## $Author: hakenes $ ## ## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. ## diff --git a/libdtv/liblx/liblx.h b/libdtv/liblx/liblx.h index f2527e7ab..26ea664ac 100644 --- a/libdtv/liblx/liblx.h +++ b/libdtv/liblx/liblx.h @@ -4,9 +4,9 @@ /// /// ////////////////////////////////////////////////////////////// -// $Revision: 1.1 $ -// $Date: 2001/06/26 07:18:42 $ -// $Author: kls $ +// $Revision: 1.2 $ +// $Date: 2001/06/25 19:39:00 $ +// $Author: hakenes $ // // (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // diff --git a/libdtv/liblx/xListFuncs.c b/libdtv/liblx/xListFuncs.c index 34df7a895..7457170eb 100644 --- a/libdtv/liblx/xListFuncs.c +++ b/libdtv/liblx/xListFuncs.c @@ -6,7 +6,7 @@ // $Revision: 1.1 $ // $Date: 2001/06/25 12:29:47 $ -// $Author: kls $ +// $Author: hakenes $ // // (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // diff --git a/libdtv/liblx/xMemMgt.c b/libdtv/liblx/xMemMgt.c index 363ee4a59..8f619bc8b 100644 --- a/libdtv/liblx/xMemMgt.c +++ b/libdtv/liblx/xMemMgt.c @@ -6,7 +6,7 @@ // $Revision: 1.1 $ // $Date: 2001/06/25 12:29:47 $ -// $Author: kls $ +// $Author: hakenes $ // // (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // diff --git a/libdtv/libsi/Makefile b/libdtv/libsi/Makefile index 4b939b944..38bff9351 100644 --- a/libdtv/libsi/Makefile +++ b/libdtv/libsi/Makefile @@ -4,9 +4,9 @@ ### ### ############################################################## -## $Revision: 1.1 $ -## $Date: 2001/08/15 14:47:22 $ -## $Author: kls $ +## $Revision: 1.4 $ +## $Date: 2001/10/07 10:24:46 $ +## $Author: hakenes $ ## ## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. ## @@ -80,4 +80,4 @@ $(SILIB) : $(OBJS) @echo compiling $<... @$(CC) $(DEFINES) $(CFLAGS) $(INCDIRS) -c $< -include Makefile.dep +-include Makefile.dep diff --git a/libdtv/libsi/include/libsi.h b/libdtv/libsi/include/libsi.h index 3790ae156..dda2b1e4e 100644 --- a/libdtv/libsi/include/libsi.h +++ b/libdtv/libsi/include/libsi.h @@ -4,9 +4,9 @@ /// /// ////////////////////////////////////////////////////////////// -// $Revision: 1.1 $ -// $Date: 2001/06/26 07:18:43 $ -// $Author: kls $ +// $Revision: 1.4 $ +// $Date: 2001/10/07 10:24:46 $ +// $Author: hakenes $ // // (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // @@ -288,18 +288,20 @@ struct PidInfo { } while (0) -#define STREAMTYPE_ISO_VIDEO 1 +#define STREAMTYPE_11172_VIDEO 1 #define STREAMTYPE_13818_VIDEO 2 #define STREAMTYPE_11172_AUDIO 3 #define STREAMTYPE_13818_AUDIO 4 -#define STREAMTYPE_VIDEOTEXT 6 -#define STREAMTYPE_13522_MPEG 7 -#define STREAMTYPE_ITU_222 8 -#define STREAMTYPE_13818_A 9 -#define STREAMTYPE_13818_B 10 -#define STREAMTYPE_13818_C 11 -#define STREAMTYPE_13818_D 12 -#define STREAMTYPE_13818_AUX 13 +#define STREAMTYPE_13818_PRIVATE 5 +#define STREAMTYPE_13818_PES_PRIVATE 6 +#define STREAMTYPE_13522_MHPEG 7 +#define STREAMTYPE_13818_DSMCC 8 +#define STREAMTYPE_ITU_222_1 9 +#define STREAMTYPE_13818_A 10 +#define STREAMTYPE_13818_B 11 +#define STREAMTYPE_13818_C 12 +#define STREAMTYPE_13818_D 13 +#define STREAMTYPE_13818_AUX 14 /* Descriptors */ @@ -331,6 +333,58 @@ struct Iso639LanguageDescriptor { } while (0) +/* Ac3Descriptor */ + +#define AC3_TYPE_FLAG 0x0001 +#define BS_ID_FLAG 0x0002 +#define MAIN_ID_FLAG 0x0004 +#define ASVC_FLAG 0x0008 + +struct Ac3Descriptor { + struct NODE Node; + unsigned short Tag; + unsigned short PresentFlags; + unsigned short Ac3Type; + unsigned short BsId; + unsigned short MainId; + unsigned short Asvc; + unsigned short Amount; /* AdditionalData */ + unsigned char *AdditionalData; +}; + +#define CreateAc3Descriptor(descr) \ + do \ + { \ + xCreateNode (((struct Ac3Descriptor *)descr), NULL); \ + ((struct Ac3Descriptor *)descr)->Tag = DESCR_AC3; \ + } while (0) + +#define AddAc3FlagAndValue(descr, flg, val) \ + do \ + { \ + if ((flg) & AC3_TYPE_FLAG) { \ + ((struct Ac3Descriptor *)descr)->PresentFlags |= AC3_TYPE_FLAG; \ + ((struct Ac3Descriptor *)descr)->Ac3Type = (val); } \ + else if ((flg) & BS_ID_FLAG) { \ + ((struct Ac3Descriptor *)descr)->PresentFlags |= BS_ID_FLAG; \ + ((struct Ac3Descriptor *)descr)->BsId = (val); } \ + else if ((flg) & MAIN_ID_FLAG) { \ + ((struct Ac3Descriptor *)descr)->PresentFlags |= MAIN_ID_FLAG; \ + ((struct Ac3Descriptor *)descr)->MainId = (val); } \ + else if ((flg) & ASVC_FLAG) { \ + ((struct Ac3Descriptor *)descr)->PresentFlags |= ASVC_FLAG; \ + ((struct Ac3Descriptor *)descr)->Asvc = (val); } \ + } while (0) + +#define AddAc3AdditionalData(descr, ptr, len) \ + do \ + { \ + xMemAlloc ((len)+1, &(((struct Ac3Descriptor *) \ + descr)->AdditionalData)); \ + memcpy ((((struct Ac3Descriptor *)descr)->AdditionalData),(ptr),(len)); \ + } while (0) + + /* AncillaryDataDescriptor */ struct AncillaryDataDescriptor { @@ -778,6 +832,106 @@ struct ShortEventDescriptor { } while (0) +/* TeletextDescriptor */ + +struct TeletextDescriptor { + struct NODE Node; + unsigned short Tag; + struct LIST *Items; +}; + +#define CreateTeletextDescriptor(descr) \ + do \ + { \ + xCreateNode (((struct TeletextDescriptor *)descr), NULL); \ + ((struct TeletextDescriptor *)descr)->Tag = DESCR_TELETEXT; \ + ((struct TeletextDescriptor *)descr)->Items = xNewList (NULL); \ + } while (0) + +#define TELETEXT_TYPE_INITIAL_PAGE 0x0001 +#define TELETEXT_TYPE_SUBTITLE_PAGE 0x0002 +#define TELETEXT_TYPE_ADDITIONAL_INFO 0x0003 +#define TELETEXT_TYPE_PROGRAM_SCHEDULE 0x0004 +#define TELETEXT_TYPE_HEARING_IMPAIRED 0x0005 + +struct TeletextItem { + struct NODE Node; + char LanguageCode[4]; + unsigned short Type; + unsigned short MagazineNumber; + unsigned short PageNumber; +}; + +#define CreateTeletextItem(itm, tp, mg, pg, lc1, lc2, lc3) \ + do \ + { \ + xCreateNode (itm, NULL); \ + ((struct TeletextItem *)itm)->Type = (tp); \ + ((struct TeletextItem *)itm)->MagazineNumber = (mg); \ + ((struct TeletextItem *)itm)->PageNumber = (mg); \ + ((struct TeletextItem *)itm)->LanguageCode[0] = (lc1); \ + ((struct TeletextItem *)itm)->LanguageCode[1] = (lc2); \ + ((struct TeletextItem *)itm)->LanguageCode[2] = (lc3); \ + ((struct TeletextItem *)itm)->LanguageCode[3] = '\0'; \ + } while (0) + +#define AddTeletextItem(desc, tp, mg, pg, lc1, lc2, lc3) \ + do \ + { \ + struct TeletextItem *item; \ + \ + CreateTeletextItem(item, tp, mg, pg, lc1, lc2, lc3); \ + xAddTail (((struct TeletextDescriptor *)desc)->Items, item); \ + } while (0) + + +/* SubtitlingDescriptor */ + +struct SubtitlingDescriptor { + struct NODE Node; + unsigned short Tag; + struct LIST *Items; +}; + +#define CreateSubtitlingDescriptor(descr) \ + do \ + { \ + xCreateNode (((struct SubtitlingDescriptor *)descr), NULL); \ + ((struct SubtitlingDescriptor *)descr)->Tag = DESCR_SUBTITLING; \ + ((struct SubtitlingDescriptor *)descr)->Items = xNewList (NULL); \ + } while (0) + +struct SubtitlingItem { + struct NODE Node; + char LanguageCode[4]; + unsigned char Type; + unsigned short CompositionPageId; + unsigned short AncillaryPageId; +}; + +#define CreateSubtitlingItem(itm, tp, cp, ap, lc1, lc2, lc3) \ + do \ + { \ + xCreateNode (itm, NULL); \ + ((struct SubtitlingItem *)itm)->Type = (tp); \ + ((struct SubtitlingItem *)itm)->CompositionPageId = (cp); \ + ((struct SubtitlingItem *)itm)->AncillaryPageId = (ap); \ + ((struct SubtitlingItem *)itm)->LanguageCode[0] = (lc1); \ + ((struct SubtitlingItem *)itm)->LanguageCode[1] = (lc2); \ + ((struct SubtitlingItem *)itm)->LanguageCode[2] = (lc3); \ + ((struct SubtitlingItem *)itm)->LanguageCode[3] = '\0'; \ + } while (0) + +#define AddSubtitlingItem(desc, tp, cp, ap, lc1, lc2, lc3) \ + do \ + { \ + struct SubtitlingItem *item; \ + \ + CreateSubtitlingItem(item, tp, cp, ap, lc1, lc2, lc3); \ + xAddTail (((struct SubtitlingDescriptor *)desc)->Items, item); \ + } while (0) + + /* Prototypes */ diff --git a/libdtv/libsi/include/si_tables.h b/libdtv/libsi/include/si_tables.h index 517838af8..dfda3bf9d 100644 --- a/libdtv/libsi/include/si_tables.h +++ b/libdtv/libsi/include/si_tables.h @@ -5,9 +5,9 @@ /// /// ////////////////////////////////////////////////////////////// -// $Revision: 1.1 $ -// $Date: 2001/06/25 12:41:20 $ -// $Author: kls $ +// $Revision: 1.3 $ +// $Date: 2001/10/07 10:24:46 $ +// $Author: hakenes $ // // (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // @@ -26,9 +26,6 @@ // Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. -#ifndef SI_TABLES_H -#define SI_TABLES_H - #define HILO(x) (x##_hi << 8 | x##_lo) #define MjdToEpochTime(x) (((x##_hi << 8 | x##_lo)-40587)*86400) @@ -930,14 +927,29 @@ typedef struct parental_rating_struct { /* 0x56 teletext_descriptor */ -#define DESCR_TELETEXT_LEN XX +#define DESCR_TELETEXT_LEN 2 typedef struct descr_teletext_struct { u_char descriptor_tag :8; u_char descriptor_length :8; - /* TBD */ } descr_teletext_t; #define CastTeletextDescriptor(x) ((descr_teletext_t *)(x)) +#define ITEM_TELETEXT_LEN 5 +typedef struct item_teletext_struct { + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char type :5; + u_char magazine_number :3; +#else + u_char magazine_number :3; + u_char type :5; +#endif + u_char page_number :8; +} item_teletext_t; +#define CastTeletextItem(x) ((item_teletext_t *)(x)) + /* 0x57 telephone_descriptor */ @@ -963,14 +975,26 @@ typedef struct descr_local_time_offset_struct { /* 0x59 subtitling_descriptor */ -#define DESCR_SUBTITLING_LEN XX +#define DESCR_SUBTITLING_LEN 2 typedef struct descr_subtitling_struct { u_char descriptor_tag :8; u_char descriptor_length :8; - /* TBD */ } descr_subtitling_t; #define CastSubtitlingDescriptor(x) ((descr_subtitling_t *)(x)) +#define ITEM_SUBTITLING_LEN 8 +typedef struct item_subtitling_struct { + u_char lang_code1 :8; + u_char lang_code2 :8; + u_char lang_code3 :8; + u_char subtitling_type :8; + u_char composition_page_id_hi :8; + u_char composition_page_id_lo :8; + u_char ancillary_page_id_hi :8; + u_char ancillary_page_id_lo :8; +} item_subtitling_t; +#define CastSubtitlingItem(x) ((item_subtitling_t *)(x)) + /* 0x5A terrestrial_delivery_system_descriptor */ @@ -1150,11 +1174,27 @@ typedef struct descr_pdc_struct { /* 0x6A ac3_descriptor */ -#define DESCR_AC3_LEN XX +#define DESCR_AC3_LEN 3 typedef struct descr_ac3_struct { u_char descriptor_tag :8; u_char descriptor_length :8; - /* TBD */ +#if BYTE_ORDER == BIG_ENDIAN + u_char ac3_type_flag :1; + u_char bsid_flag :1; + u_char mainid_flag :1; + u_char asvc_flag :1; + u_char reserved :4; +#else + u_char reserved :4; + u_char asvc_flag :1; + u_char mainid_flag :1; + u_char bsid_flag :1; + u_char ac3_type_flag :1; +#endif + u_char ac3_type :8; + u_char bsid :8; + u_char mainid :8; + u_char asvc :8; } descr_ac3_t; #define CastAc3Descriptor(x) ((descr_ac3_t *)(x)) @@ -1202,4 +1242,4 @@ typedef struct descr_announcement_support_struct { } descr_announcement_support_t; #define CastAnnouncementSupportDescriptor(x) ((descr_announcement_support_t *)(x)) -#endif + diff --git a/libdtv/libsi/si_debug_services.c b/libdtv/libsi/si_debug_services.c index dd09cff8c..ae2a92a6c 100644 --- a/libdtv/libsi/si_debug_services.c +++ b/libdtv/libsi/si_debug_services.c @@ -4,9 +4,9 @@ /// /// ////////////////////////////////////////////////////////////// -// $Revision: 1.1 $ -// $Date: 2001/08/15 14:40:55 $ -// $Author: kls $ +// $Revision: 1.4 $ +// $Date: 2001/10/07 10:24:46 $ +// $Author: hakenes $ // // (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // @@ -34,8 +34,6 @@ #include "si_debug_services.h" - - void siDebugServices (struct LIST *Services) { struct Service *Service; @@ -328,9 +326,9 @@ void siDebugDescriptors (char *Prepend, struct LIST *Descriptors) ((struct ExtendedEventDescriptor *)Descriptor)->LanguageCode); xForeach (((struct ExtendedEventDescriptor *)Descriptor)->Items, Item) { - printf ("%s Item:\n"); - printf ("%s Description: %s\n", xName(Item)); - printf ("%s Text: %s\n", Item->Text); + printf ("%s Item:\n", Prepend); + printf ("%s Description: %s\n", Prepend, xName(Item)); + printf ("%s Text: %s\n", Prepend, Item->Text); } } break; @@ -445,6 +443,52 @@ void siDebugDescriptors (char *Prepend, struct LIST *Descriptors) } break; + case DESCR_TELETEXT: + { + struct TeletextItem *Item; + + printf ("%sDescriptor: Teletext\n", Prepend); + xForeach (((struct TeletextDescriptor *)Descriptor)->Items, Item) + { + printf ("%s Item:\n"); + printf ("%s LanguageCode: %s\n", Prepend, Item->LanguageCode); + printf ("%s Type: ", Prepend); + switch (Item->Type) + { + case 0x01: printf ("initial Teletext page\n"); break; + case 0x02: printf ("Teletext subtitle page\n"); break; + case 0x03: printf ("additional information page\n"); break; + case 0x04: printf ("programme schedule page\n"); break; + case 0x05: printf ("Teletext subtitle page "); + printf ("for hearing impaired people\n"); break; + default: printf ("reserved for future use\n"); break; + } + printf ("%s MagazineNumber: %x\n", Prepend, Item->MagazineNumber); + printf ("%s PageNumber: %x\n", Prepend, Item->PageNumber); + } + } + break; + + case DESCR_SUBTITLING: + { + struct SubtitlingItem *Item; + + printf ("%sDescriptor: Subtitling\n", Prepend); + xForeach (((struct SubtitlingDescriptor *)Descriptor)->Items, Item) + { + printf ("%s Item:\n"); + printf ("%s LanguageCode: %s\n", Prepend, Item->LanguageCode); + printf ("%s Type: ", Prepend); + for (i = 0; i < COMPONENT_TYPE_NUMBER; i++) + if ((0x03 == ComponentTypes[i].Content) && + (Item->Type == ComponentTypes[i].Type)) + { printf ("%s\n", ComponentTypes[i].Description); break; } + printf ("%s CompositionPageId: %x\n", Prepend, Item->CompositionPageId); + printf ("%s AncillaryPageId: %x\n", Prepend, Item->AncillaryPageId); + } + } + break; + case DESCR_NW_NAME: case DESCR_SERVICE_LIST: case DESCR_STUFFING: @@ -453,10 +497,8 @@ void siDebugDescriptors (char *Prepend, struct LIST *Descriptors) case DESCR_VBI_DATA: case DESCR_VBI_TELETEXT: case DESCR_MOSAIC: - case DESCR_TELETEXT: case DESCR_TELEPHONE: case DESCR_LOCAL_TIME_OFF: - case DESCR_SUBTITLING: case DESCR_TERR_DEL_SYS: case DESCR_ML_NW_NAME: case DESCR_ML_BQ_NAME: diff --git a/libdtv/libsi/si_debug_services.h b/libdtv/libsi/si_debug_services.h index 33528dbbb..cd4f196b7 100644 --- a/libdtv/libsi/si_debug_services.h +++ b/libdtv/libsi/si_debug_services.h @@ -6,7 +6,7 @@ // $Revision: 1.1 $ // $Date: 2001/06/25 12:29:47 $ -// $Author: kls $ +// $Author: hakenes $ // // (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // diff --git a/libdtv/libsi/si_parser.c b/libdtv/libsi/si_parser.c index acafa7b2e..76d72c8f1 100644 --- a/libdtv/libsi/si_parser.c +++ b/libdtv/libsi/si_parser.c @@ -4,9 +4,9 @@ /// /// ////////////////////////////////////////////////////////////// -// $Revision: 1.1 $ -// $Date: 2001/08/15 14:41:45 $ -// $Author: kls $ +// $Revision: 1.4 $ +// $Date: 2001/10/07 10:24:46 $ +// $Author: hakenes $ // // (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // @@ -725,6 +725,62 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) Ptr + DESCR_LINKAGE_LEN); break; + case DESCR_TELETEXT: + CreateTeletextDescriptor (Descriptor); + Length = GetDescriptorLength (Buffer) - DESCR_TELETEXT_LEN; + Ptr += DESCR_TELETEXT_LEN; + while (Length > 0) + { + AddTeletextItem (Descriptor, + CastTeletextItem(Ptr)->type, + CastTeletextItem(Ptr)->magazine_number, + CastTeletextItem(Ptr)->page_number, + CastTeletextItem(Ptr)->lang_code1, + CastTeletextItem(Ptr)->lang_code2, + CastTeletextItem(Ptr)->lang_code3); + Length -= ITEM_TELETEXT_LEN; + Ptr += ITEM_TELETEXT_LEN; + } + break; + + case DESCR_AC3: + CreateAc3Descriptor (Descriptor); + Length = GetDescriptorLength (Buffer); + if (CastAc3Descriptor(Buffer)->ac3_type_flag) + { Length -= 1; Ptr += 1; AddAc3FlagAndValue (Descriptor, + AC3_TYPE_FLAG, CastAc3Descriptor(Buffer)->ac3_type); } + if (CastAc3Descriptor(Buffer)->bsid_flag) + { Length -= 1; Ptr += 1; AddAc3FlagAndValue (Descriptor, + BS_ID_FLAG, CastAc3Descriptor(Buffer)->bsid); } + if (CastAc3Descriptor(Buffer)->mainid_flag) + { Length -= 1; Ptr += 1; AddAc3FlagAndValue (Descriptor, + MAIN_ID_FLAG, CastAc3Descriptor(Buffer)->mainid); } + if (CastAc3Descriptor(Buffer)->asvc_flag) + { Length -= 1; Ptr += 1; AddAc3FlagAndValue (Descriptor, + ASVC_FLAG, CastAc3Descriptor(Buffer)->asvc); } + Length -= DESCR_AC3_LEN; + Ptr += DESCR_AC3_LEN; + if (Length) AddAc3AdditionalData (Descriptor, Ptr, Length); + break; + + case DESCR_SUBTITLING: + CreateSubtitlingDescriptor (Descriptor); + Length = GetDescriptorLength (Buffer) - DESCR_SUBTITLING_LEN; + Ptr += DESCR_SUBTITLING_LEN; + while (Length > 0) + { + AddSubtitlingItem (Descriptor, + CastSubtitlingItem(Ptr)->subtitling_type, + HILO (CastSubtitlingItem(Ptr)->composition_page_id), + HILO (CastSubtitlingItem(Ptr)->ancillary_page_id), + CastSubtitlingItem(Ptr)->lang_code1, + CastSubtitlingItem(Ptr)->lang_code2, + CastSubtitlingItem(Ptr)->lang_code3); + Length -= ITEM_SUBTITLING_LEN; + Ptr += ITEM_SUBTITLING_LEN; + } + break; + case DESCR_VIDEO_STREAM: case DESCR_AUDIO_STREAM: case DESCR_HIERARCHY: @@ -748,10 +804,8 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) case DESCR_VBI_DATA: case DESCR_VBI_TELETEXT: case DESCR_MOSAIC: - case DESCR_TELETEXT: case DESCR_TELEPHONE: case DESCR_LOCAL_TIME_OFF: - case DESCR_SUBTITLING: case DESCR_TERR_DEL_SYS: case DESCR_ML_NW_NAME: case DESCR_ML_BQ_NAME: @@ -768,7 +822,6 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) case DESCR_TRANSPORT_STREAM: case DESCR_DSNG: case DESCR_PDC: - case DESCR_AC3: case DESCR_CELL_LIST: case DESCR_CELL_FREQ_LINK: case DESCR_ANNOUNCEMENT_SUPPORT: @@ -799,8 +852,11 @@ char *siGetDescriptorText (u_char *Buffer, u_int Length) if (*Buffer == 0) break; if ((*Buffer >= ' ' && *Buffer <= '~') || - (*Buffer >= 0xa0 && *Buffer <= 0xff)) *tmp++ = *Buffer++; - else Buffer++; + (*Buffer == '\n') || + (*Buffer >= 0xa0 && *Buffer <= 0xff)) *tmp++ = *Buffer; + if (*Buffer == 0x8A) *tmp++ = '\n'; + if (*Buffer == 0x86 || *Buffer == 0x87) *tmp++ = ' '; + Buffer++; } *tmp = '\0'; } diff --git a/libdtv/libvdr/Makefile b/libdtv/libvdr/Makefile index 8aecffc61..8bcab4cb1 100644 --- a/libdtv/libvdr/Makefile +++ b/libdtv/libvdr/Makefile @@ -4,9 +4,9 @@ ### ### ############################################################## -## $Revision: 1.1 $ -## $Date: 2001/08/15 14:05:16 $ -## $Author: kls $ +## $Revision: 1.3 $ +## $Date: 2001/10/06 15:33:46 $ +## $Author: hakenes $ ## ## (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. ## diff --git a/libdtv/libvdr/libvdr.c b/libdtv/libvdr/libvdr.c index 5caa5d7c4..0ade4d39d 100644 --- a/libdtv/libvdr/libvdr.c +++ b/libdtv/libvdr/libvdr.c @@ -5,8 +5,8 @@ ////////////////////////////////////////////////////////////// // $Revision: 1.1 $ -// $Date: 2001/08/15 14:05:24 $ -// $Author: kls $ +// $Date: 2001/10/07 10:25:33 $ +// $Author: hakenes $ // // (C) 2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // diff --git a/libdtv/libvdr/libvdr.h b/libdtv/libvdr/libvdr.h index 6fde10be3..421b2e719 100644 --- a/libdtv/libvdr/libvdr.h +++ b/libdtv/libvdr/libvdr.h @@ -4,9 +4,9 @@ /// /// ////////////////////////////////////////////////////////////// -// $Revision: 1.1 $ -// $Date: 2001/08/15 10:54:13 $ -// $Author: kls $ +// $Revision: 1.4 $ +// $Date: 2001/10/06 15:33:46 $ +// $Author: hakenes $ // // (C) 1992-2001 Rolf Hakenes <hakenes@hippomi.de>, under the GNU GPL. // diff --git a/menu.c b/menu.c index 23b16e294..0242d91f9 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.127 2001/09/23 10:58:48 kls Exp $ + * $Id: menu.c 1.131 2001/10/21 14:28:14 kls Exp $ */ #include "menu.h" @@ -1636,11 +1636,12 @@ cMenuDVD::cMenuDVD(void) dvd->Open(); ifo_handle_t *vmg = dvd->openVMG(); if (vmg) { + int lastTitleID = cReplayControl::LastTitleID(); dsyslog(LOG_INFO, "DVD: vmg: %p", vmg);//XXX tt_srpt_t *tt_srpt = vmg->tt_srpt; dsyslog(LOG_INFO, "DVD: tt_srpt: %p", tt_srpt);//XXX for (int i = 0; i < tt_srpt->nr_of_srpts; i++) - Add(new cMenuDVDItem(i, tt_srpt->title[i].nr_of_ptts)); + Add(new cMenuDVDItem(i, tt_srpt->title[i].nr_of_ptts), i == lastTitleID); } } SetHelp(tr("Play"), NULL, NULL, NULL); @@ -1724,6 +1725,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditIntItem( tr("OSDheight"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); Add(new cMenuEditIntItem( tr("OSDMessageTime"), &data.OSDMessageTime, 1, 60)); Add(new cMenuEditIntItem( tr("MaxVideoFileSize"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); + Add(new cMenuEditBoolItem(tr("SplitEditedFiles"), &data.SplitEditedFiles)); Add(new cMenuEditIntItem( tr("MinEventTimeout"), &data.MinEventTimeout)); Add(new cMenuEditIntItem( tr("MinUserInactivity"), &data.MinUserInactivity)); Add(new cMenuEditBoolItem(tr("MultiSpeedMode"), &data.MultiSpeedMode)); @@ -1807,7 +1809,7 @@ eOSState cMenuCommands::ProcessKey(eKeys Key) #define STOP_RECORDING tr(" Stop recording ") -cMenuMain::cMenuMain(bool Replaying) +cMenuMain::cMenuMain(bool Replaying, eOSState State) :cOsdMenu(tr("Main")) { digit = 0; @@ -1843,6 +1845,13 @@ cMenuMain::cMenuMain(bool Replaying) Display(); lastActivity = time(NULL); SetHasHotkeys(); + switch (State) { + case osRecordings: AddSubMenu(new cMenuRecordings); break; +#ifdef DVDSUPPORT + case osDVD: AddSubMenu(new cMenuDVD); break; +#endif //DVDSUPPORT + default: break; + } } const char *cMenuMain::hk(const char *s) @@ -2374,6 +2383,11 @@ void cReplayControl::SetDVD(cDVD *DVD, int Title)//XXX dvd = DVD; titleid = Title; } + +int cReplayControl::LastTitleID(void) +{ + return titleid; +} #endif //DVDSUPPORT const char *cReplayControl::LastReplayed(void) @@ -2710,9 +2724,9 @@ eOSState cReplayControl::ProcessKey(eKeys Key) case kRight: dvbApi->Forward(); break; case kRed: TimeSearch(); break; case kGreen|k_Repeat: - case kGreen: dvbApi->SkipSeconds(-60); DoShowMode = false; break; + case kGreen: dvbApi->SkipSeconds(-60); break; case kYellow|k_Repeat: - case kYellow: dvbApi->SkipSeconds( 60); DoShowMode = false; break; + case kYellow: dvbApi->SkipSeconds( 60); break; case kBlue: Hide(); dvbApi->StopReplay(); return osEnd; @@ -2740,7 +2754,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key) else Show(); break; - case kBack: return osRecordings; + case kBack: return fileName ? osRecordings : osDVD; default: return osUnknown; } } diff --git a/menu.h b/menu.h index f7411c61c..b41a935b0 100644 --- a/menu.h +++ b/menu.h @@ -4,14 +4,12 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.30 2001/09/23 10:57:33 kls Exp $ + * $Id: menu.h 1.33 2001/10/21 14:26:01 kls Exp $ */ #ifndef _MENU_H #define _MENU_H -#define _GNU_SOURCE - #include "dvbapi.h" #ifdef DVDSUPPORT #include "dvd.h" @@ -25,7 +23,7 @@ class cMenuMain : public cOsdMenu { int digit; const char *hk(const char *s); public: - cMenuMain(bool Replaying); + cMenuMain(bool Replaying, eOSState State = osUnknown); virtual eOSState ProcessKey(eKeys Key); }; @@ -135,6 +133,7 @@ class cReplayControl : public cOsdBase { static void SetRecording(const char *FileName, const char *Title); #ifdef DVDSUPPORT static void SetDVD(cDVD *DVD, int Title);//XXX + static int LastTitleID(void); #endif //DVDSUPPORT static const char *LastReplayed(void); static void ClearLastReplayed(const char *FileName); diff --git a/recording.c b/recording.c index df5040740..fe56a6e69 100644 --- a/recording.c +++ b/recording.c @@ -4,10 +4,9 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.37 2001/09/23 13:43:29 kls Exp $ + * $Id: recording.c 1.42 2001/10/20 10:28:28 kls Exp $ */ -#define _GNU_SOURCE #include "recording.h" #include <errno.h> #include <fcntl.h> @@ -32,7 +31,7 @@ #define SUMMARYFILESUFFIX "/summary.vdr" #define MARKSFILESUFFIX "/marks.vdr" -#define FINDCMD "find %s -follow -type d -name '%s' 2> /dev/null | sort -df" +#define FINDCMD "find %s -follow -type d -name '%s' 2> /dev/null" #define MINDISKSPACE 1024 // MB @@ -45,6 +44,10 @@ void RemoveDeletedRecordings(void) { static time_t LastRemoveCheck = 0; if (time(NULL) - LastRemoveCheck > REMOVECHECKDELTA) { + // Make sure only one instance of VDR does this: + cLockFile LockFile(VideoDirectory); + if (!LockFile.Lock()) + return; // Remove the oldest file that has been "deleted": cRecordings Recordings; if (Recordings.Load(true)) { @@ -74,6 +77,10 @@ void AssertFreeDiskSpace(int Priority) static time_t LastFreeDiskCheck = 0; if (time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA) { if (!VideoFileSpaceAvailable(MINDISKSPACE)) { + // Make sure only one instance of VDR does this: + cLockFile LockFile(VideoDirectory); + if (!LockFile.Lock()) + return; // Remove the oldest file that has been "deleted": cRecordings Recordings; if (Recordings.Load(true)) { @@ -207,6 +214,7 @@ char *ExchangeChars(char *s, bool ToFileSystem) cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary) { titleBuffer = NULL; + sortBuffer = NULL; fileName = NULL; if (Timer->IsSingleEvent() || !Setup.UseSubtitle) name = strdup(Timer->file); @@ -235,6 +243,7 @@ cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary) cRecording::cRecording(const char *FileName) { titleBuffer = NULL; + sortBuffer = NULL; fileName = strdup(FileName); FileName += strlen(VideoDirectory) + 1; char *p = strrchr(FileName, '/'); @@ -243,7 +252,8 @@ cRecording::cRecording(const char *FileName) summary = NULL; if (p) { time_t now = time(NULL); - struct tm t = *localtime(&now); // this initializes the time zone in 't' + struct tm tm_r; + struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't' t.tm_isdst = -1; // makes sure mktime() will determine the correct dst setting 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; @@ -294,15 +304,55 @@ cRecording::cRecording(const char *FileName) cRecording::~cRecording() { delete titleBuffer; + delete sortBuffer; delete fileName; delete name; delete summary; } +char *cRecording::StripEpisodeName(char *s) +{ + char *t = s, *s1 = NULL, *s2 = NULL; + while (*t) { + if (*t == '/') { + if (s1) { + if (s2) + s1 = s2; + s2 = t; + } + else + s1 = t; + } + t++; + } + if (s1 && s2) + memmove(s1 + 1, s2, t - s2 + 1); + return s; +} + +char *cRecording::SortName(void) +{ + if (!sortBuffer) { + char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory) + 1)); + int l = strxfrm(NULL, s, 0); + sortBuffer = new char[l]; + strxfrm(sortBuffer, s, l); + delete s; + } + return sortBuffer; +} + +bool cRecording::operator< (const cListObject &ListObject) +{ + cRecording *r = (cRecording *)&ListObject; + return strcasecmp(SortName(), r->SortName()) < 0; +} + const char *cRecording::FileName(void) { if (!fileName) { - struct tm *t = localtime(&start); + struct tm tm_r; + struct tm *t = localtime_r(&start, &tm_r); ExchangeChars(name, true); asprintf(&fileName, NAMEFORMAT, VideoDirectory, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime); ExchangeChars(name, false); @@ -320,7 +370,8 @@ const char *cRecording::Title(char Delimiter, bool NewIndicator) } delete titleBuffer; titleBuffer = NULL; - struct tm *t = localtime(&start); + struct tm tm_r; + struct tm *t = localtime_r(&start, &tm_r); asprintf(&titleBuffer, "%02d.%02d%c%02d:%02d%c%c%s", t->tm_mday, t->tm_mon + 1, @@ -401,6 +452,7 @@ bool cRecordings::Load(bool Deleted) delete r; } pclose(p); + Sort(); result = Count() > 0; } else @@ -523,7 +575,7 @@ void cRecordingUserCommand::InvokeCommand(const char *State, const char *Recordi char *cmd; asprintf(&cmd, "%s %s '%s'", command, State, RecordingFileName); isyslog(LOG_INFO, "executing '%s'", cmd); - system(cmd); + SystemExec(cmd); delete cmd; } } diff --git a/recording.h b/recording.h index d2391a907..aead97e36 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.17 2001/09/23 13:43:58 kls Exp $ + * $Id: recording.h 1.18 2001/10/07 10:38:56 kls Exp $ */ #ifndef __RECORDING_H @@ -32,9 +32,12 @@ class cRecording : public cListObject { friend class cRecordings; private: char *titleBuffer; + char *sortBuffer; char *fileName; char *name; char *summary; + char *StripEpisodeName(char *s); + char *SortName(void); public: time_t start; int priority; @@ -42,6 +45,7 @@ class cRecording : public cListObject { cRecording(cTimer *Timer, const char *Subtitle, const char *Summary); cRecording(const char *FileName); ~cRecording(); + virtual bool operator< (const cListObject &ListObject); const char *FileName(void); const char *Title(char Delimiter = ' ', bool NewIndicator = false); const char *Summary(void) { return summary; } diff --git a/remote.c b/remote.c index eed91105b..26d7acbf7 100644 --- a/remote.c +++ b/remote.c @@ -6,7 +6,7 @@ * * Ported to LIRC by Carsten Koch <Carsten.Koch@icem.de> 2000-06-16. * - * $Id: remote.c 1.24 2001/08/12 15:07:26 kls Exp $ + * $Id: remote.c 1.25 2001/09/30 11:39:49 kls Exp $ */ #include "remote.h" @@ -451,6 +451,7 @@ void cRcIoLIRC::Action(void) if (Now - FirstTime < REPEATDELAY) continue; // repeat function kicks in after a short delay receivedData = receivedRepeat = true; + receivedRelease = false; } LastTime = Now; WakeUp(); diff --git a/svdrp.c b/svdrp.c index 3c90bb02d..43c55e467 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,11 +10,9 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.24 2001/09/22 13:30:02 kls Exp $ + * $Id: svdrp.c 1.25 2001/10/07 15:13:42 kls Exp $ */ -#define _GNU_SOURCE - #include "svdrp.h" #include <arpa/inet.h> #include <ctype.h> diff --git a/thread.c b/thread.c index f4ba76a19..b51489ec8 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.13 2001/09/23 14:04:35 kls Exp $ + * $Id: thread.c 1.15 2001/10/21 12:25:31 kls Exp $ */ #include "thread.h" @@ -161,7 +161,7 @@ void cThread::Cancel(int WaitSeconds) bool cThread::Lock(void) { - if (!lockingPid || lockingPid != getpid()) { + if (getpid() != lockingPid || !locked) { Mutex.Lock(); lockingPid = getpid(); } @@ -342,3 +342,35 @@ int cPipe::Close(void) return ret; } + +// --- SystemExec ------------------------------------------------------------ + +int SystemExec(const char *Command) +{ + pid_t pid; + + if ((pid = fork()) < 0) { // fork failed + LOG_ERROR; + return -1; + } + + if (pid > 0) { // parent process + int status; + if (waitpid(pid, &status, 0) < 0) { + LOG_ERROR; + return -1; + } + return status; + } + else { // child process + int MaxPossibleFileDescriptors = getdtablesize(); + for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++) + close(i); //close all dup'ed filedescriptors + if (execl("/bin/sh", "sh", "-c", Command, NULL) == -1) { + LOG_ERROR_STR(Command); + _exit(-1); + } + _exit(0); + } +} + diff --git a/thread.h b/thread.h index 221f9ac7a..89dcdf853 100644 --- a/thread.h +++ b/thread.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.9 2001/09/15 12:46:52 kls Exp $ + * $Id: thread.h 1.10 2001/10/20 10:25:19 kls Exp $ */ #ifndef __THREAD_H @@ -104,4 +104,9 @@ class cPipe { int Close(void); }; +// SystemExec() implements a 'system()' call that closes all unnecessary file +// descriptors in the child process. + +int SystemExec(const char *Command); + #endif //__THREAD_H diff --git a/tools.c b/tools.c index 7238137ef..472c50d73 100644 --- a/tools.c +++ b/tools.c @@ -4,10 +4,9 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.46 2001/09/22 12:13:40 kls Exp $ + * $Id: tools.c 1.50 2001/10/19 13:12:45 kls Exp $ */ -#define _GNU_SOURCE #include "tools.h" #include <ctype.h> #include <dirent.h> @@ -74,6 +73,10 @@ char *strcpyrealloc(char *dest, const char *src) else esyslog(LOG_ERR, "ERROR: out of memory"); } + else { + delete dest; + dest = NULL; + } return dest; } @@ -413,7 +416,8 @@ const char *DayDateTime(time_t t) static char buffer[32]; if (t == 0) time(&t); - tm *tm = localtime(&t); + struct tm tm_r; + tm *tm = localtime_r(&t, &tm_r); int weekday = tm->tm_wday == 0 ? 6 : tm->tm_wday - 1; // we start with monday==0! const char *day = tr("MonTueWedThuFriSatSun"); day += weekday * 3; @@ -590,6 +594,72 @@ bool cSafeFile::Close(void) return result; } +// --- cLockFile ------------------------------------------------------------- + +#define LOCKFILENAME ".lock-vdr" +#define LOCKFILESTALETIME 600 // seconds before considering a lock file "stale" + +cLockFile::cLockFile(const char *Directory) +{ + fileName = NULL; + f = -1; + if (DirectoryOk(Directory)) + asprintf(&fileName, "%s/%s", Directory, LOCKFILENAME); +} + +cLockFile::~cLockFile() +{ + Unlock(); + delete fileName; +} + +bool cLockFile::Lock(int WaitSeconds) +{ + if (f < 0 && fileName) { + time_t Timeout = time(NULL) + WaitSeconds; + do { + f = open(fileName, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (f < 0) { + if (errno == EEXIST) { + struct stat fs; + if (stat(fileName, &fs) == 0) { + if (time(NULL) - fs.st_mtime > LOCKFILESTALETIME) { + esyslog(LOG_ERR, "ERROR: removing stale lock file '%s'", fileName); + if (remove(fileName) < 0) { + LOG_ERROR_STR(fileName); + break; + } + continue; + } + } + else if (errno != ENOENT) { + LOG_ERROR_STR(fileName); + break; + } + } + else { + LOG_ERROR_STR(fileName); + break; + } + if (WaitSeconds) + sleep(1); + } + } while (f < 0 && time(NULL) < Timeout); + } + return f >= 0; +} + +void cLockFile::Unlock(void) +{ + if (f >= 0) { + close(f); + remove(fileName); + f = -1; + } + else + esyslog(LOG_ERR, "ERROR: attempt to unlock %s without holding a lock!", fileName); +} + // --- cListObject ----------------------------------------------------------- cListObject::cListObject(void) diff --git a/tools.h b/tools.h index cc67a8067..843cbf1db 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.35 2001/09/22 12:12:55 kls Exp $ + * $Id: tools.h 1.36 2001/09/30 10:20:59 kls Exp $ */ #ifndef __TOOLS_H @@ -97,6 +97,17 @@ class cSafeFile { bool Close(void); }; +class cLockFile { +private: + char *fileName; + int f; +public: + cLockFile(const char *Directory); + ~cLockFile(); + bool Lock(int WaitSeconds = 0); + void Unlock(void); + }; + class cListObject { private: cListObject *prev, *next; diff --git a/vdr.c b/vdr.c index d7c3f06e7..ce86fd0da 100644 --- a/vdr.c +++ b/vdr.c @@ -22,11 +22,11 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.79 2001/09/23 14:33:39 kls Exp $ + * $Id: vdr.c 1.86 2001/10/20 11:18:38 kls Exp $ */ -#define _GNU_SOURCE #include <getopt.h> +#include <locale.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> @@ -75,6 +75,10 @@ static void Watchdog(int signum) int main(int argc, char *argv[]) { + // Initiate locale: + + setlocale(LC_ALL, ""); + // Command line options: #define DEFAULTSVDRPPORT 2001 @@ -355,7 +359,6 @@ int main(int argc, char *argv[]) cRecordControls::Process(Now); cTimer *Timer = Timers.GetMatch(Now); if (Timer) { - dsyslog(LOG_INFO, "system time seen is %s", ctime(&Now)); if (!cRecordControls::Start(Timer)) Timer->SetPending(true); } @@ -405,7 +408,7 @@ int main(int argc, char *argv[]) case osRecordings: DELETENULL(Menu); DELETENULL(ReplayControl); - Menu = new cMenuRecordings; + Menu = new cMenuMain(ReplayControl, osRecordings); break; case osReplay: DELETENULL(Menu); DELETENULL(ReplayControl); @@ -414,7 +417,7 @@ int main(int argc, char *argv[]) #ifdef DVDSUPPORT case osDVD: DELETENULL(Menu); DELETENULL(ReplayControl); - Menu = new cMenuDVD; + Menu = new cMenuMain(ReplayControl, osDVD); break; #endif //DVDSUPPORT case osStopReplay: @@ -501,10 +504,12 @@ int main(int argc, char *argv[]) if (WatchdogTimeout > 0) signal(SIGALRM, SIG_IGN); if (Interface->Confirm(tr("Press any key to cancel shutdown"), LastActivity == 1 ? 5 : SHUTDOWNWAIT, true)) { + int Channel = timer ? timer->channel : 0; + const char *File = timer ? timer->file : ""; char *cmd; - asprintf(&cmd, "%s %ld %ld", Shutdown, Next, Delta); + asprintf(&cmd, "%s %ld %ld %d '%s'", Shutdown, Next, Delta, Channel, File); isyslog(LOG_INFO, "executing '%s'", cmd); - system(cmd); + SystemExec(cmd); delete cmd; } else if (WatchdogTimeout > 0) { From 6e1fd835558b4e70ad94a280a209f050ec0f7a75 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 4 Nov 2001 18:00:00 +0100 Subject: [PATCH 028/307] =?UTF-8?q?Version=200.98=20-=20Completed=20storin?= =?UTF-8?q?g=20the=20current=20audio=20volume=20in=20the=20setup.conf=20fi?= =?UTF-8?q?le=20(thanks=20=20=20to=20Andy=20Grobb).=20-=20Fixed=20closing?= =?UTF-8?q?=20the=20progress=20display=20with=20the=20"Back"=20key=20when?= =?UTF-8?q?=20in=20trick=20mode=20=20=20and=20Setup.ShowReplayMode=20is=20?= =?UTF-8?q?enabled=20(thanks=20to=20Stefan=20Huelswitt).=20-=20New=20SVDRP?= =?UTF-8?q?=20commands=20LSTR=20and=20DELR=20to=20list=20and=20delete=20re?= =?UTF-8?q?cordings=20(thanks=20to=20=20=20Thomas=20Heiligenmann).=20-=20F?= =?UTF-8?q?ixed=20a=20crash=20when=20pressing=20the=20'2'=20button=20while?= =?UTF-8?q?=20replaying=20a=20DVD.=20-=20Updated=20'channels.conf'=20for?= =?UTF-8?q?=20the=20"Bundesliga"=20channels=20of=20Premiere=20World=20=20?= =?UTF-8?q?=20(thanks=20to=20Mel=20Sch=E4chner).=20-=20Changed=20the=20tun?= =?UTF-8?q?ing=20code=20to=20use=20FrontendInfo=20to=20detect=20the=20type?= =?UTF-8?q?=20of=20DVB=20card.=20-=20Removed=20the=20recursion=20stuff=20f?= =?UTF-8?q?rom=20cThread=20(cMutex=20already=20does=20this).=20-=20Fixed?= =?UTF-8?q?=20handling=20the=20repeat=20function=20in=20the=20channel=20di?= =?UTF-8?q?splay.=20-=20Avoiding=20multiple=20EPG=20entries=20for=20the=20?= =?UTF-8?q?same=20event=20(thanks=20to=20Rolf=20Hakenes=20=20=20for=20some?= =?UTF-8?q?=20valuable=20information=20on=20how=20to=20do=20this).=20-=20A?= =?UTF-8?q?=20recording=20on=20the=20primary=20interface=20can=20now=20be?= =?UTF-8?q?=20stopped=20to=20make=20it=20continue=20=20=20on=20an=20other?= =?UTF-8?q?=20free=20DVB=20card=20(if=20one=20is=20free=20at=20the=20momen?= =?UTF-8?q?t).=20See=20MANUAL=20for=20=20=20details.=20-=20Added=20some=20?= =?UTF-8?q?missing=20teletext=20PIDs=20(thanks=20to=20Norbert=20Schmidt).?= =?UTF-8?q?=20-=20Added=20PTS=20to=20the=20converted=20PCM=20audio=20when?= =?UTF-8?q?=20replaying=20a=20DVD=20(thanks=20to=20Andreas=20=20=20Schultz?= =?UTF-8?q?).=20Now=20the=20audio=20and=20video=20of=20a=20DVD=20replayed?= =?UTF-8?q?=20over=20the=20DVB=20card's=20A/V=20=20=20out=20should=20alway?= =?UTF-8?q?s=20be=20in=20sync.=20-=20Fixed=20handling=20the=20"Power"=20ke?= =?UTF-8?q?y=20in=20case=20Setup.MinUserInactivity=20is=20set=20to=200=20t?= =?UTF-8?q?o=20=20=20disable=20automatic=20shutdown.=20-=20Added=20a=20fif?= =?UTF-8?q?th=20parameter=20to=20the=20'shutdown'=20call=20that=20indicate?= =?UTF-8?q?s=20the=20reason=20for=20=20=20this=20shutdown=20request=20(see?= =?UTF-8?q?=20INSTALL).=20-=20Fixed=20releasing=20'index'=20memory=20after?= =?UTF-8?q?=20recording=20or=20playback.=20-=20Fixed=20ejecting=20a=20DVD?= =?UTF-8?q?=20while=20it=20is=20being=20replayed.=20-=20Removed=20all=20vi?= =?UTF-8?q?deo=20overlay=20stuff=20from=20cDvbApi=20and=20SVDRP.=20Guido?= =?UTF-8?q?=20Fiala's=20new=20=20=20'kvdr'=20version=200.4=20now=20does=20?= =?UTF-8?q?these=20things=20itself.=20As=20a=20consequence=20of=20this=20y?= =?UTF-8?q?ou=20=20=20will=20now=20need=20to=20use=20kvdr=200.4=20or=20lat?= =?UTF-8?q?er.=20-=20The=20device=20/dev/video=20is=20now=20opened=20only?= =?UTF-8?q?=20if=20necessary=20(to=20GRAB=20an=20image),=20=20=20allowing?= =?UTF-8?q?=20other=20programs=20(like=20'kvdr',=20for=20instance)=20to=20?= =?UTF-8?q?use=20that=20device.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTORS | 14 +- HISTORY | 39 ++- INSTALL | 10 +- MANUAL | 14 + channels.conf | 36 +- config.h | 4 +- dvbapi.c | 941 ++++++++++++++++++++++---------------------------- dvbapi.h | 30 +- eit.c | 37 +- eit.h | 9 +- i18n.c | 11 +- menu.c | 96 ++++- menu.h | 3 +- ringbuffer.c | 5 +- ringbuffer.h | 8 +- svdrp.c | 183 ++++------ svdrp.h | 13 +- thread.c | 33 +- thread.h | 12 +- vdr.c | 10 +- 20 files changed, 732 insertions(+), 776 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 3a04af16c..2fdfcc1fb 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -23,6 +23,8 @@ Guido Fiala <gfiala@s.netic.de> for implementing the SVDRP command 'HITK' for implementing image grabbing for implementing overlay capabilities (see his 'kvdr' tool at http://www.s.netic.de/gfiala) + (overlay capabilities have been removed again in VDR 0.98, since kvdr version 0.4 + now does these things itself) for making the replay progress display avoid unnecessary code execution Robert Schneider <Robert.Schneider@lotus.com> @@ -109,12 +111,13 @@ Ulrich R 27500 for his support in keeping the Premiere World channels up to date in 'channels.conf' -Helmut Schchner <schaechner@yahoo.com> +Mel Schchner <schaechner@yahoo.com> for his support in keeping the Premiere World channels up to date in 'channels.conf' Andreas Schultz <aschultz@warp10.net> for adding support for replaying DVDs (much of this was derived from dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>) + for adding PTS to the converted PCM audio when replaying a DVD Aaron Holtzman for writing 'ac3dec' @@ -150,3 +153,12 @@ Andreas Share <a.share@t-online.de> Simon Bauschulte <SemiSchwabe@Brutzel.de> for his support in keeping the Premiere World channels up to date in 'channels.conf' + +Andy Grobb <Charly98@01019freenet.de> + for completing storing the current audio volume in the setup.conf file + +Thomas Heiligenmann <thomas@heiligenmann.de> + for implementing the SVDRP commands LSTR and DELR + +Norbert Schmidt <nschmidt-nrw@t-online.de> + for filling in some missing teletext PIDs diff --git a/HISTORY b/HISTORY index 5087c9ef1..c9d404e7e 100644 --- a/HISTORY +++ b/HISTORY @@ -595,7 +595,7 @@ Video Disk Recorder Revision History - When setting an editing mark while the progress display is not active, the display will now be turned on for a short while to indicate the successful setting of the mark. -- Updated 'channels.conf' for Premiere World (thanks to Helmut Schchner). +- Updated 'channels.conf' for Premiere World (thanks to Mel Schchner). Check your timers if you use this channels.conf file, since the sequence of several PW channels has been changed. - Changed the color of "Info" messages to "black on green" and that of the @@ -825,8 +825,43 @@ Video Disk Recorder Revision History - The menu timeout now also works when pressing the "Back" button during replay to enter the "Recordings" menu. - Updated 'channels.conf' for the "Bundesliga" channels of Premiere World - (thanks to Helmut Schchner). + (thanks to Mel Schchner). - Fixed reading timers.conf and channels.conf that contain blanks after numeric values. - Fixed handling trick modes near the beginning and end of a recording. - Pressing the "Back" button while replaying a DVD now leads to the DVD menu. + +2001-11-04: Version 0.98 + +- Completed storing the current audio volume in the setup.conf file (thanks + to Andy Grobb). +- Fixed closing the progress display with the "Back" key when in trick mode + and Setup.ShowReplayMode is enabled (thanks to Stefan Huelswitt). +- New SVDRP commands LSTR and DELR to list and delete recordings (thanks to + Thomas Heiligenmann). +- Fixed a crash when pressing the '2' button while replaying a DVD. +- Updated 'channels.conf' for the "Bundesliga" channels of Premiere World + (thanks to Mel Schchner). +- Changed the tuning code to use FrontendInfo to detect the type of DVB card. +- Removed the recursion stuff from cThread (cMutex already does this). +- Fixed handling the repeat function in the channel display. +- Avoiding multiple EPG entries for the same event (thanks to Rolf Hakenes + for some valuable information on how to do this). +- A recording on the primary interface can now be stopped to make it continue + on an other free DVB card (if one is free at the moment). See MANUAL for + details. +- Added some missing teletext PIDs (thanks to Norbert Schmidt). +- Added PTS to the converted PCM audio when replaying a DVD (thanks to Andreas + Schultz). Now the audio and video of a DVD replayed over the DVB card's A/V + out should always be in sync. +- Fixed handling the "Power" key in case Setup.MinUserInactivity is set to 0 to + disable automatic shutdown. +- Added a fifth parameter to the 'shutdown' call that indicates the reason for + this shutdown request (see INSTALL). +- Fixed releasing 'index' memory after recording or playback. +- Fixed ejecting a DVD while it is being replayed. +- Removed all video overlay stuff from cDvbApi and SVDRP. Guido Fiala's new + 'kvdr' version 0.4 now does these things itself. As a consequence of this you + will now need to use kvdr 0.4 or later. +- The device /dev/video is now opened only if necessary (to GRAB an image), + allowing other programs (like 'kvdr', for instance) to use that device. diff --git a/INSTALL b/INSTALL index e7e673162..d20bf1a13 100644 --- a/INSTALL +++ b/INSTALL @@ -25,7 +25,7 @@ directory ../DVD (seen from the VDR directory). Adjust the definition of DVDDIR in the Makefile if necessary. You can find 'libdvdread' at - http://www.dtek.chalmers.se/groups/dvd/downloads.html + http://www.dtek.chalmers.se/groups/dvd/downloads.shtml If you want to replay CSS encrypted DVDs you also need to get the 'libdvdcss' library from @@ -127,7 +127,7 @@ active, the user has been inactive for at least MinUserInactivity minutes and the next timer event is at least MinEventTimeout minutes in the future (see the Setup parameters in MANUAL). -The command given in the '-s' option will be called with four parameters. +The command given in the '-s' option will be called with five parameters. The first one is the time (in UTC) of the next timer event (as a time_t type number), and the second one is the number of seconds from the current time until the next timer event. Your program can choose which one to use @@ -153,6 +153,12 @@ contains the file name of the recording as defined in the timer (or an empty string if no timer is present). These can be used by the shutdown program to show that information on some display interface etc. +The fifth parameter indicates the reason why the shutdown was requested. +'0' means this is an automatic shutdown due to some timeout, while '1' means +that this is a user requested shutdown (resulting from pressing the "Power" +key). The shutdown program may use this information to decide whether or +not to actually perform the system shutdown. + If a timer is currently recording, the parameters will reflect the start time of that timer. This means that the first parameter will be a time in the past, and the second parameter will be a negative number. This only diff --git a/MANUAL b/MANUAL index 7bb1ec83f..a9e42a1bf 100644 --- a/MANUAL +++ b/MANUAL @@ -310,6 +310,20 @@ Video Disk Recorder User's Manual A timer can also be programmed by pressing the "Red" button on the "Schedule", "Now", "Next" or "Event" menus. +* Stopping a recording on the primary DVB interface + + If the primary DVB interface is currently recording, the user can't switch + the channel or replay another recording on that interface. However, if there + is an other DVB interface that is currently not recording and provides the + necessary conditional access facilities to continue the recording that is + currently being performed on the primary DVB interface, the Main menu will + contain an option that allows you to stop recording on the primary DVB + interface. Select that option to stop the ongoing recording and thus free the + primary DVB interface to allow channel switching or replaying. The interrupted + recording will be continued on an other free DVB interface. There may be a + short discontinuity at that point when replaying that recording later, so you + may want to place such an action for instance in a commercial break. + * Parameters in the "Setup" menu Select "Setup" from the "Main" menu to enter the setup menu. From there you can diff --git a/channels.conf b/channels.conf index 200fbfe01..c9bf996a2 100644 --- a/channels.conf +++ b/channels.conf @@ -2,19 +2,19 @@ RTL:12188:h:0:27500:163:104:105:0:12003 Sat.1:12480:v:0:27500:1791:1792:34:0:46 Pro-7:12480:v:0:27500:255:256;257:32:0:898 RTL2:12188:h:0:27500:166:128:68:0:12020 -ARD:11837:h:0:27500:101:102:0:0:28106 -BR3:11837:h:0:27500:201:202:0:0:28107 +ARD:11837:h:0:27500:101:102:104:0:28106 +BR3:11837:h:0:27500:201:202:204:0:28107 Hessen-3:11837:h:0:27500:301:302:0:0:28108 -N3:12110:h:0:27500:2401:2402:0:0:28224 -SR3:11837:h:0:27500:501:502:0:0:28110 +N3:12110:h:0:27500:2401:2402:2404:0:28224 +SR3:11837:h:0:27500:501:502:504:0:28110 WDR:11837:h:0:27500:601:602:0:0:28111 -BR-alpha:11837:h:0:27500:701:702:0:0:28112 -SWR BW:11837:h:0:27500:801:802:0:0:28113 -Phoenix:11837:h:0:27500:901:902:0:0:28114 +BR-alpha:11837:h:0:27500:701:702:704:0:28112 +SWR BW:11837:h:0:27500:801:802:804:0:28113 +Phoenix:11837:h:0:27500:901:902:904:0:28114 ZDF:11954:h:0:27500:110:120:130:0:28006 3sat:11954:h:0:27500:210:220:230:0:28007 -KiKa:11954:h:0:27500:310:320:0:0:28008 -arte:11836:h:0:27500:401:402:0:0:28109 +KiKa:11954:h:0:27500:310:320:330:0:28008 +arte:11836:h:0:27500:401:402:404:0:28109 ORF1:12692:h:0:22000:160:161:165:3:13001 ORF2:12692:h:0:22000:500:501:505:3:13002 ORF Sat:11954:h:0:27500:506:507:0:0:28010 @@ -42,10 +42,10 @@ EinsFestival:12110:h:0:27500:201:202:0:0:28202 EinsMuXx:12110:h:0:27500:301:302:0:0:28203 ZDF Theaterkanal:11954:h:0:27500:1110:1120:0:0:28016 ZDF.doku:11954:h:0:27500:660:670:0:0:28014 -MDR:12110:h:0:27500:401:402:0:0:28204 +MDR:12110:h:0:27500:401:402:404:0:28204 NICK-PARAMOUNT:12246:v:0:27500:167:108:0:0:29312 -ORB:12110:h:0:27500:501:502:0:0:28205 -B1:12110:h:0:27500:601:602:0:0:28206 +ORB:12110:h:0:27500:501:502:504:0:28205 +B1:12110:h:0:27500:601:602:604:0:28206 ARD Online-Kanal:12722:h:0:22000:0:701:0:0:0 :Premiere World Premiere World:11797:h:0:27500:255:256:32:0:8 @@ -117,14 +117,14 @@ Cockpitkanal:11720:h:0:27500:2559:2560:0:3:242 Boxengasse:11720:h:0:27500:2047:2048:0:3:240 :Premiere World Bundesliga Superdom:11758:h:0:27500:2815:8192:0:3:18 -BuLi-Konferenz:11758:h:0:27500:3071:3072,3073:0:3:215 +BuLi-Konferenz:11758:h:0:27500:3327:3328,3329:0:3:215 BuLi-Spiel 1:11719:h:0:27500:255:256,257:0:3:17 BuLi-Spiel 2:11719:h:0:27500:2047:2048,2049:0:3:240 -BuLi-Spiel 3:11719:h:0:27500:3327:3328,3329:0:3:241 -BuLi-Spiel 4:11719:h:0:27500:2303:2304,2305:0:3:242 -BuLi-Spiel 5:11719:h:0:27500:3583:3584,3585:0:3:243 -BuLi-Spiel 6:11719:h:0:27500:2559:2560,2561:0:3:244 -BuLi-Spiel 7:11758:h:0:27500:2815:2816,2817:0:3:214 +BuLi-Spiel 3:11719:h:0:27500:2303:2304,2305:0:3:241 +BuLi-Spiel 4:11719:h:0:27500:2559:2560,2561:0:3:242 +BuLi-Spiel 5:11719:h:0:27500:2815:2816,2817:0:3:243 +BuLi-Spiel 6:11719:h:0:27500:3071:3072,3073:0:3:244 +BuLi-Spiel 7:11758:h:0:27500:3071:3072,3073:0:3:214 : TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601 Mosaico:11934:v:0:27500:165:100:0:0:29010 diff --git a/config.h b/config.h index d0f0d77f3..574496931 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.84 2001/10/07 15:13:23 kls Exp $ + * $Id: config.h 1.85 2001/10/27 09:56:04 kls Exp $ */ #ifndef __CONFIG_H @@ -18,7 +18,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.97" +#define VDRVERSION "0.98" #define MAXPRIORITY 99 #define MAXLIFETIME 99 diff --git a/dvbapi.c b/dvbapi.c index 786dff7f0..f72782b4b 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.132 2001/10/21 13:36:27 kls Exp $ + * $Id: dvbapi.c 1.137 2001/11/04 12:05:36 kls Exp $ */ //#define DVDDEBUG 1 @@ -200,6 +200,7 @@ cIndexFile::~cIndexFile() if (f >= 0) close(f); delete fileName; + delete index; } bool cIndexFile::CatchUp(int Index) @@ -713,7 +714,10 @@ class cPlayBuffer : public cRingBufferFrame { void TrickSpeed(int Increment); virtual void Empty(bool Block = false); virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {} + virtual void PlayExternalDolby(const uchar *b, int MaxLength); virtual void Output(void); + void putFrame(cFrame *Frame); + void putFrame(unsigned char *Data, int Length, eFrameType Type = ftUnknown); public: cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev); virtual ~cPlayBuffer(); @@ -759,6 +763,28 @@ cPlayBuffer::~cPlayBuffer() { } +void cPlayBuffer::PlayExternalDolby(const uchar *b, int MaxLength) +{ + if (dolbyDev) { + if (b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01) { + if (b[3] == 0xBD) { // dolby + int l = b[4] * 256 + b[5] + 6; + int written = b[8] + 9; // skips the PES header + int n = min(l - written, MaxLength); + while (n > 0) { + int w = fwrite(&b[written], 1, n, dolbyDev); + if (w < 0) { + LOG_ERROR; + break; + } + n -= w; + written += w; + } + } + } + } +} + void cPlayBuffer::Output(void) { dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); @@ -771,24 +797,28 @@ void cPlayBuffer::Output(void) } const cFrame *frame = Get(); if (frame) { - StripAudioPackets((uchar *)frame->Data(), frame->Count(), (playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX - const uchar *p = frame->Data(); - int r = frame->Count(); - while (r > 0 && Busy() && !blockOutput) { - cFile::FileReadyForWriting(videoDev, 100); - int w = write(videoDev, p, r); - if (w > 0) { - p += w; - r -= w; - } - else if (w < 0 && FATALERRNO) { - LOG_ERROR; - Stop(); - return; + if (frame->Type() == ftDolby) + PlayExternalDolby(frame->Data(), frame->Count()); + else { + StripAudioPackets((uchar *)frame->Data(), frame->Count(), (playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX + const uchar *p = frame->Data(); + int r = frame->Count(); + while (r > 0 && Busy() && !blockOutput) { + cFile::FileReadyForWriting(videoDev, 100); + int w = write(videoDev, p, r); + if (w > 0) { + p += w; + r -= w; + } + else if (w < 0 && FATALERRNO) { + LOG_ERROR; + Stop(); + return; + } } - } - writeIndex = frame->Index(); - backTrace.Add(frame->Index(), frame->Count()); + writeIndex = frame->Index(); + backTrace.Add(frame->Index(), frame->Count()); + } Drop(frame); } } @@ -796,6 +826,20 @@ void cPlayBuffer::Output(void) dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); } +void cPlayBuffer::putFrame(cFrame *Frame) +{ + while (Busy() && !blockInput) { + if (Put(Frame)) + return; + } + delete Frame; // caller relies on frame being put, otherwise this would be a memory leak! +} + +void cPlayBuffer::putFrame(unsigned char *Data, int Length, eFrameType Type) +{ + putFrame(new cFrame(Data, Length, Type)); +} + void cPlayBuffer::TrickSpeed(int Increment) { int nts = trickSpeed + Increment; @@ -1089,11 +1133,8 @@ void cReplayBuffer::Input(void) } else // allows replay even if the index file is missing r = read(replayFile, b, sizeof(b)); - if (r > 0) { - cFrame *frame = new cFrame(b, r, readIndex); - while (Busy() && !blockInput && !Put(frame)) - ; - } + if (r > 0) + putFrame(new cFrame(b, r, ftUnknown, readIndex)); else if (r == 0) eof = true; else if (r < 0 && FATALERRNO) { @@ -1117,19 +1158,8 @@ void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except) int l = b[i + 4] * 256 + b[i + 5] + 6; switch (c) { case 0xBD: // dolby - if (Except && dolbyDev) { - int written = b[i + 8] + 9; // skips the PES header - int n = l - written; - while (n > 0) { - int w = fwrite(&b[i + written], 1, n, dolbyDev); - if (w < 0) { - LOG_ERROR; - break; - } - n -= w; - written += w; - } - } + if (Except && dolbyDev) + PlayExternalDolby(&b[i], Length - i); // continue with deleting the data - otherwise it disturbs DVB replay case 0xC0 ... 0xC1: // audio if (c == 0xC1) @@ -1290,10 +1320,166 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) } #ifdef DVDSUPPORT + +#define SYSTEM_HEADER 0xBB +#define PROG_STREAM_MAP 0xBC +#ifndef PRIVATE_STREAM1 +#define PRIVATE_STREAM1 0xBD +#endif +#define PADDING_STREAM 0xBE +#ifndef PRIVATE_STREAM2 +#define PRIVATE_STREAM2 0xBF +#endif +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define cOPENDVD 0 +#define cOPENTITLE 1 +#define cOPENCHAPTER 2 +#define cOUTCELL 3 +#define cREADFRAME 4 +#define cOUTPACK 5 +#define cOUTFRAMES 6 + +#define aAC3 0x80 +#define aLPCM 0xA0 + +// --- cAC3toPCM ------------------------------------------------------------- + +class cAC3toPCM { +private: + enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat; + uchar *ac3data; + int ac3inp; + int ac3outp; +public: + cAC3toPCM(void); + ~cAC3toPCM(); + void Clear(void); + void Put(unsigned char *sector, int length); + cFrame *Get(int size, uchar PTSflags = 0, uchar *PTSdata = 0); + }; + +cAC3toPCM::cAC3toPCM(void) +{ + ac3dec_init(); + ac3data = new uchar[AC3_BUFFER_SIZE]; + Clear(); +} + +cAC3toPCM::~cAC3toPCM() +{ + delete ac3data; +} + +void cAC3toPCM::Clear(void) +{ + ac3stat = AC3_START; + ac3outp = ac3inp = 0; +} + +void cAC3toPCM::Put(unsigned char *sector, int length) +{ + ac3dec_decode_data(sector, sector + length, ac3stat == AC3_START, &ac3inp, &ac3outp, (char *)ac3data); + ac3stat = AC3_PLAY; +} + +// data=PCM samples, 16 bit, LSB first, 48kHz, stereo +cFrame *cAC3toPCM::Get(int size, uchar PTSflags, uchar *PTSdata) +{ + if (ac3inp == ac3outp) + return NULL; + +#define MAXSIZE 2022 + + uchar buffer[2048]; + uchar *data; + + if (size > 0) { + int p_size = (size > MAXSIZE) ? MAXSIZE : size; + int length = 10; // default header bytes + int header = 0; + int stuffb = 0; + + switch (PTSflags) { + case 2: header = 5; // additional header bytes + stuffb = 1; + break; + case 3: header = 10; + break; + default: header = 0; + } + + // header = 0; //XXX ??? + stuffb = 0; //XXX ??? + + length += header; + length += stuffb; + + buffer[0] = 0x00; + buffer[1] = 0x00; + buffer[2] = 0x01; + buffer[3] = PRIVATE_STREAM1; + + buffer[6] = 0x80; + buffer[7] = PTSflags << 6; + buffer[8] = header + stuffb; + + if (header) + memcpy(&buffer[9], (void *)PTSdata, header); + + // add stuffing + data = buffer + 9 + header; + for (int cnt = 0; cnt < stuffb; cnt++) + data[cnt] = 0xff; + length += stuffb; + + // add data + data = buffer + 9 + header + stuffb + 7; + int cnt = 0; + while (p_size) { + if (ac3outp != ac3inp) { // data in the buffer + data[cnt ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder (the "xor" (^) is a swab!) + p_size--; + cnt++; + length++; + ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE; + } + else + break; + } + + data = buffer + 9 + header + stuffb; + data[0] = aLPCM; // substream ID + data[1] = 0x00; // other stuff (see DVB specs), ignored by driver + data[2] = 0x00; + data[3] = 0x00; + data[4] = 0x00; + data[5] = 0x00; + data[6] = 0x00; + + buffer[4] = (length >> 8) & 0xff; + buffer[5] = length & 0xff; + + length += 6; + + return new cFrame(buffer, length); + } + return NULL; +} + // --- cDVDplayBuffer -------------------------------------------------------- class cDVDplayBuffer : public cPlayBuffer { private: + cAC3toPCM AC3toPCM; uchar audioTrack; cDVD *dvd;//XXX necessary??? @@ -1308,7 +1494,6 @@ class cDVDplayBuffer : public cPlayBuffer { int doplay; int cyclestate; int prevcycle; - int brakeCounter; int skipCnt; tt_srpt_t *tt_srpt; @@ -1335,11 +1520,6 @@ class cDVDplayBuffer : public cPlayBuffer { int logAudioTrack; int maxAudioTrack; - enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat; - uchar *ac3data; - int ac3inp; - int ac3outp; - int lpcm_count; int is_nav_pack(unsigned char *buffer); void Close(void); virtual void Empty(bool Block = false); @@ -1350,10 +1530,7 @@ class cDVDplayBuffer : public cPlayBuffer { int GetStuffingLen(const uchar *Data); int GetPacketLength(const uchar *Data); int GetPESHeaderLength(const uchar *Data); - int SendPCM(int size); - void playDecodedAC3(void); - void handleAC3(unsigned char *sector, int length); - void putFrame(unsigned char *sector, int length); + void handleAC3(unsigned char *sector, int length, uchar PTSflags, uchar *PTSdata); unsigned int getAudioStream(unsigned int StreamId); void setChapid(void); void NextState(int State) { prevcycle = cyclestate; cyclestate = State; } @@ -1369,17 +1546,6 @@ class cDVDplayBuffer : public cPlayBuffer { virtual void ToggleAudioTrack(void); }; -#define cOPENDVD 0 -#define cOPENTITLE 1 -#define cOPENCHAPTER 2 -#define cOUTCELL 3 -#define cREADFRAME 4 -#define cOUTPACK 5 -#define cOUTFRAMES 6 - -#define aAC3 0x80 -#define aLPCM 0xA0 - cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title) :cPlayBuffer(DvbApi, VideoDev, AudioDev) { @@ -1389,15 +1555,10 @@ cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD angle = 0; cyclestate = cOPENDVD; prevcycle = 0; - brakeCounter = 0; skipCnt = 0; logAudioTrack = 0; canToggleAudioTrack = true;//XXX determine from cDVD! - ac3dec_init(); data = new uchar[1024 * DVD_VIDEO_LB_LEN]; - ac3data = new uchar[AC3_BUFFER_SIZE]; - ac3inp = ac3outp = 0; - ac3stat = AC3_START; canDoTrickMode = true; dvbApi->SetModeReplay(); Start(); @@ -1408,7 +1569,6 @@ cDVDplayBuffer::~cDVDplayBuffer() Stop(); Close(); dvbApi->SetModeNormal(false); - delete ac3data; delete data; } @@ -1449,8 +1609,7 @@ void cDVDplayBuffer::ToggleAudioTrack(void) #ifdef DVDDEBUG dsyslog(LOG_INFO, "DVB: Audio Stream ID changed to: %x", audioTrack); #endif - ac3stat = AC3_START; - ac3outp = ac3inp; + AC3toPCM.Clear(); } } @@ -1869,141 +2028,21 @@ int cDVDplayBuffer::ScanVideoPacket(const uchar *Data, int Count, uchar *Picture return -1; } -#define SYSTEM_HEADER 0xBB -#define PROG_STREAM_MAP 0xBC -#ifndef PRIVATE_STREAM1 -#define PRIVATE_STREAM1 0xBD -#endif -#define PADDING_STREAM 0xBE -#ifndef PRIVATE_STREAM2 -#define PRIVATE_STREAM2 0xBF -#endif -#define AUDIO_STREAM_S 0xC0 -#define AUDIO_STREAM_E 0xDF -#define VIDEO_STREAM_S 0xE0 -#define VIDEO_STREAM_E 0xEF -#define ECM_STREAM 0xF0 -#define EMM_STREAM 0xF1 -#define DSM_CC_STREAM 0xF2 -#define ISO13522_STREAM 0xF3 -#define PROG_STREAM_DIR 0xFF - -// data=PCM samples, 16 bit, LSB first, 48kHz, stereo -int cDVDplayBuffer::SendPCM(int size) -{ - -#define MAXSIZE 2032 - - uchar buffer[MAXSIZE + 16]; - int length = 0; - int p_size; - - if (ac3inp == ac3outp) - return 1; - - while (size > 0) { - if (size >= MAXSIZE) - p_size = MAXSIZE; - else - p_size = size; - length = 10; - - while (p_size) { - if (ac3outp != ac3inp) { // data in the buffer - buffer[(length + 6) ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder - // XXX there is no 'swab' here??? (kls) - p_size--; - length++; - ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE; - } - else - break; - } - - buffer[0] = 0x00; - buffer[1] = 0x00; - buffer[2] = 0x01; - buffer[3] = PRIVATE_STREAM1; - - buffer[4] = (length >> 8) & 0xff; - buffer[5] = length & 0xff; - - buffer[6] = 0x80; - buffer[7] = 0x00; - buffer[8] = 0x00; - - buffer[9] = aLPCM; // substream ID - buffer[10] = 0x00; // other stuff (see DVD specs), ignored by driver - buffer[11] = 0x00; - buffer[12] = 0x00; - buffer[13] = 0x00; - buffer[14] = 0x00; - buffer[15] = 0x00; - - length += 6; - - putFrame(buffer, length); - size -= MAXSIZE; - } - return 0; -} - -void cDVDplayBuffer::playDecodedAC3(void) +void cDVDplayBuffer::handleAC3(unsigned char *sector, int length, uchar PTSflags, uchar *PTSdata) { - int ac3_datasize = (AC3_BUFFER_SIZE + ac3inp - ac3outp) % AC3_BUFFER_SIZE; - - if (ac3_datasize) { - if (ac3_datasize > 1024 * 48) - SendPCM(3096); - else if (ac3_datasize > 1024 * 32) - SendPCM(1536); - else if (ac3_datasize > 1024 * 16 && !(lpcm_count % 2)) - SendPCM(1536); - else if (ac3_datasize && !(lpcm_count % 4)) - SendPCM(1536); - lpcm_count++; - } - else - lpcm_count=0; -} - -void cDVDplayBuffer::handleAC3(unsigned char *sector, int length) -{ - if (dolbyDev) { - while (length > 0) { - int w = fwrite(sector, 1, length , dolbyDev); - if (w < 0) { - LOG_ERROR; - break; - } - length -= w; - sector += w; - } - } - else { - if (ac3stat == AC3_PLAY) - ac3dec_decode_data(sector, sector + length, 0, &ac3inp, &ac3outp, (char *)ac3data); - else if (ac3stat == AC3_START) { - ac3dec_decode_data(sector, sector + length, 1, &ac3inp, &ac3outp, (char *)ac3data); - ac3stat = AC3_PLAY; - } - } - //playDecodedAC3(); -} - -void cDVDplayBuffer::putFrame(unsigned char *sector, int length) -{ - cFrame *frame = new cFrame(sector, length); - while (Busy() && !blockInput && !Put(frame)) - ; +#define PCM_FRAME_SIZE 1536 + AC3toPCM.Put(sector, length); + cFrame *frame; + if ((frame = AC3toPCM.Get(PCM_FRAME_SIZE, PTSflags, PTSdata)) != NULL) + putFrame(frame); + while ((frame = AC3toPCM.Get(PCM_FRAME_SIZE)) != NULL) + putFrame(frame); } int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode) { + //XXX kls 2001-11-03: do we really need all these different return values? uchar pt = 1; -#if 0 - uchar *osect = sector; -#endif //make sure we got a PS packet header if (!PacketStart(§or, DVD_VIDEO_LB_LEN) && GetPacketType(sector) != 0xBA) { @@ -2017,6 +2056,8 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode) int datalen = r; sector[6] &= 0x8f; + uchar PTSflags = sector[7] >> 6; + uchar *PTSdata = sector + 9; uchar *data = sector; switch (GetPacketType(sector)) { @@ -2025,6 +2066,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode) ScanVideoPacket(sector, r, &pt); if (trickMode && pt != 1) return pt; + putFrame(sector, r, ftVideo); break; } case AUDIO_STREAM_S ... AUDIO_STREAM_E: { @@ -2033,6 +2075,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode) return 1; if (audioTrack != GetPacketType(sector)) return 5; + putFrame(sector, r, ftAudio); break; } case PRIVATE_STREAM1: @@ -2060,14 +2103,15 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode) if (audioTrack == *data) { switch (audioTrack & 0xF8) { case aAC3: + if (dolbyDev) + putFrame(sector, r, ftDolby); data += 4; - // correct a3 data lenght - FIXME: why 13 ??? - datalen -= 13; - handleAC3(data, datalen); + datalen -= 13; // 3 (mandatory header) + 6 (PS header) + 4 (AC3 header) = 13 + handleAC3(data, datalen, PTSflags, PTSdata); break; case aLPCM: // write(audio, sector+14 , sector[19]+(sector[18]<<8)+6); - putFrame(sector, GetPacketLength(sector)); + putFrame(sector, GetPacketLength(sector), ftAudio); break; default: break; @@ -2096,9 +2140,6 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode) return pt; } } - putFrame(sector, r); - if ((audioTrack & 0xF8) == aAC3) - playDecodedAC3(); return pt; } @@ -2106,8 +2147,7 @@ void cDVDplayBuffer::Empty(bool Block) { if (!(blockInput || blockOutput)) { cPlayBuffer::Empty(true); - ac3stat = AC3_START; - ac3outp = ac3inp; + AC3toPCM.Clear(); } if (!Block) cPlayBuffer::Empty(false); @@ -2149,9 +2189,7 @@ void cDVDplayBuffer::SkipSeconds(int Seconds) Empty(true); chapid = newchapid; NextState(cOPENCHAPTER); - if (ac3stat != AC3_STOP) - ac3stat = AC3_START; - ac3outp = ac3inp; + AC3toPCM.Clear(); Empty(false); Play(); } @@ -2488,6 +2526,7 @@ char *cDvbApi::audioCommand = NULL; cDvbApi::cDvbApi(int n) { + frontendType = FrontendType(-1); // don't know how else to initialize this - there is no FE_UNKNOWN vPid = aPid1 = aPid2 = dPid1 = dPid2 = 0; siProcessor = NULL; recordBuffer = NULL; @@ -2518,10 +2557,6 @@ cDvbApi::cDvbApi(int n) fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK); fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK); - // Devices that may not be available, and are not necessary for normal operation: - - videoDev = OstOpen(DEV_VIDEO, n, O_RDWR); - // Devices that will be dynamically opened and closed when necessary: fd_dvr = -1; @@ -2536,15 +2571,14 @@ cDvbApi::cDvbApi(int n) siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n)); if (!dvbApi[0]) // only the first one shall set the system time siProcessor->SetUseTSTime(Setup.SetSystemTime); + FrontendInfo feinfo; + CHECK(ioctl(fd_frontend, FE_GET_INFO, &feinfo)); + frontendType = feinfo.type; } else esyslog(LOG_ERR, "ERROR: can't open video device %d", n); cols = rows = 0; - ovlGeoSet = ovlStat = ovlFbSet = false; - ovlBrightness = ovlColour = ovlHue = ovlContrast = 32768; - ovlClipCount = 0; - #if defined(DEBUG_OSD) || defined(REMOTE_KBD) initscr(); keypad(stdscr, true); @@ -2573,7 +2607,6 @@ cDvbApi::~cDvbApi() StopReplay(); StopRecord(); StopTransfer(); - OvlO(false); //Overlay off! // We're not explicitly closing any device files here, since this sometimes // caused segfaults. Besides, the program is about to terminate anyway... #if defined(DEBUG_OSD) || defined(REMOTE_KBD) @@ -2688,255 +2721,96 @@ const cSchedules *cDvbApi::Schedules(cThreadLock *ThreadLock) const bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) { - if (videoDev < 0) - return false; int result = 0; - // just do this once? - struct video_mbuf mbuf; - result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf); - int msize = mbuf.size; - // gf: this needs to be a protected member of cDvbApi! //XXX kls: WHY??? - unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); - if (!mem || mem == (unsigned char *)-1) - return false; - // set up the size and RGB - struct video_capability vc; - result |= ioctl(videoDev, VIDIOCGCAP, &vc); - struct video_mmap vm; - vm.frame = 0; - if ((SizeX > 0) && (SizeX <= vc.maxwidth) && - (SizeY > 0) && (SizeY <= vc.maxheight)) { - vm.width = SizeX; - vm.height = SizeY; - } - else { - vm.width = vc.maxwidth; - vm.height = vc.maxheight; - } - vm.format = VIDEO_PALETTE_RGB24; - // this needs to be done every time: - result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm); - result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame); - // make RGB out of BGR: - int memsize = vm.width * vm.height; - unsigned char *mem1 = mem; - for (int i = 0; i < memsize; i++) { - unsigned char tmp = mem1[2]; - mem1[2] = mem1[0]; - mem1[0] = tmp; - mem1 += 3; - } - - if (Quality < 0) - Quality = 255; //XXX is this 'best'??? - - isyslog(LOG_INFO, "grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height); - FILE *f = fopen(FileName, "wb"); - if (f) { - if (Jpeg) { - // write JPEG file: - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - jpeg_stdio_dest(&cinfo, f); - cinfo.image_width = vm.width; - cinfo.image_height = vm.height; - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; - - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, Quality, true); - jpeg_start_compress(&cinfo, true); - - int rs = vm.width * 3; - JSAMPROW rp[vm.height]; - for (int k = 0; k < vm.height; k++) - rp[k] = &mem[rs * k]; - jpeg_write_scanlines(&cinfo, rp, vm.height); - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - } - else { - // write PNM file: - if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 || - fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) { - LOG_ERROR_STR(FileName); - result |= 1; + int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR); + if (videoDev >= 0) { + struct video_mbuf mbuf; + result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf); + if (result == 0) { + int msize = mbuf.size; + unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); + if (mem && mem != (unsigned char *)-1) { + // set up the size and RGB + struct video_capability vc; + result |= ioctl(videoDev, VIDIOCGCAP, &vc); + struct video_mmap vm; + vm.frame = 0; + if ((SizeX > 0) && (SizeX <= vc.maxwidth) && + (SizeY > 0) && (SizeY <= vc.maxheight)) { + vm.width = SizeX; + vm.height = SizeY; + } + else { + vm.width = vc.maxwidth; + vm.height = vc.maxheight; + } + vm.format = VIDEO_PALETTE_RGB24; + result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm); + result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame); + // make RGB out of BGR: + int memsize = vm.width * vm.height; + unsigned char *mem1 = mem; + for (int i = 0; i < memsize; i++) { + unsigned char tmp = mem1[2]; + mem1[2] = mem1[0]; + mem1[0] = tmp; + mem1 += 3; + } + + if (Quality < 0) + Quality = 255; //XXX is this 'best'??? + + isyslog(LOG_INFO, "grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height); + FILE *f = fopen(FileName, "wb"); + if (f) { + if (Jpeg) { + // write JPEG file: + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, f); + cinfo.image_width = vm.width; + cinfo.image_height = vm.height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, Quality, true); + jpeg_start_compress(&cinfo, true); + + int rs = vm.width * 3; + JSAMPROW rp[vm.height]; + for (int k = 0; k < vm.height; k++) + rp[k] = &mem[rs * k]; + jpeg_write_scanlines(&cinfo, rp, vm.height); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + } + else { + // write PNM file: + if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 || + fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) { + LOG_ERROR_STR(FileName); + result |= 1; + } + } + fclose(f); + } + else { + LOG_ERROR_STR(FileName); + result |= 1; + } + munmap(mem, msize); } + else + result |= 1; } - fclose(f); - } - else { - LOG_ERROR_STR(FileName); - result |= 1; - } - - if (ovlStat && ovlGeoSet) { - // switch the Overlay on again (gf: why have i to do anything again?) - OvlG(ovlSizeX, ovlSizeY, ovlPosX, ovlPosY); - } - if (ovlFbSet) - OvlP(ovlBrightness, ovlColour, ovlHue, ovlContrast); - - munmap(mem, msize); - return result == 0; -} - -bool cDvbApi::OvlF(int SizeX, int SizeY, int FbAddr, int Bpp, int Palette) -{ - if (videoDev < 0) - return false; - int result = 0; - // get the actual X-Server settings??? - // plausibility-check problem: can't be verified w/o X-server!!! - if (SizeX <= 0 || SizeY <= 0 || FbAddr == 0 || Bpp / 8 > 4 || - Bpp / 8 <= 0 || Palette <= 0 || Palette > 13 || ovlClipCount < 0 || - SizeX > 4096 || SizeY > 4096) { - ovlFbSet = ovlGeoSet = false; - OvlO(false); - return false; - } - else { - dsyslog(LOG_INFO, "OvlF: %d %d %x %d %d", SizeX, SizeY, FbAddr, Bpp, Palette); - // this is the problematic part! - struct video_buffer vb; - result |= ioctl(videoDev, VIDIOCGFBUF, &vb); - vb.base = (void*)FbAddr; - vb.depth = Bpp; - vb.height = SizeY; - vb.width = SizeX; - vb.bytesperline = ((vb.depth + 1) / 8) * vb.width; - //now the real thing: setting the framebuffer - result |= ioctl(videoDev, VIDIOCSFBUF, &vb); - if (result) { - ovlFbSet = ovlGeoSet = false; - ovlClipCount = 0; - OvlO(false); - return false; - } - else { - ovlFbSizeX = SizeX; - ovlFbSizeY = SizeY; - ovlBpp = Bpp; - ovlPalette = Palette; - ovlFbSet = true; - return true; - } - } -} - -bool cDvbApi::OvlG(int SizeX, int SizeY, int PosX, int PosY) -{ - if (videoDev < 0) - return false; - int result = 0; - // get the actual X-Server settings??? - struct video_capability vc; - result |= ioctl(videoDev, VIDIOCGCAP, &vc); - if (!ovlFbSet) - return false; - if (SizeX < vc.minwidth || SizeY < vc.minheight || - SizeX > vc.maxwidth || SizeY>vc.maxheight -// || PosX > FbSizeX || PosY > FbSizeY -// PosX < -SizeX || PosY < -SizeY || - ) { - ovlGeoSet = false; - OvlO(false); - return false; - } - else { - struct video_window vw; - result |= ioctl(videoDev, VIDIOCGWIN, &vw); - vw.x = PosX; - vw.y = PosY; - vw.width = SizeX; - vw.height = SizeY; - vw.chromakey = ovlPalette; -#ifndef VID_TYPE_CHROMAKEY // name changed somewhere down the road in kernel 2.4.x -#define VID_TYPE_CHROMAKEY VIDEO_WINDOW_CHROMAKEY -#endif - vw.flags = VID_TYPE_CHROMAKEY; // VIDEO_WINDOW_INTERLACE; //VIDEO_CLIP_BITMAP; - vw.clips = ovlClipRects; - vw.clipcount = ovlClipCount; - result |= ioctl(videoDev, VIDIOCSWIN, &vw); - if (result) { - ovlGeoSet = false; - ovlClipCount = 0; - return false; - } - else { - ovlSizeX = SizeX; - ovlSizeY = SizeY; - ovlPosX = PosX; - ovlPosY = PosY; - ovlGeoSet = true; - ovlStat = true; - return true; - } + close(videoDev); } -} - -bool cDvbApi::OvlC(int ClipCount, CRect *cr) -{ - if (videoDev < 0) - return false; - if (ovlGeoSet && ovlFbSet) { - for (int i = 0; i < ClipCount; i++) { - ovlClipRects[i].x = cr[i].x; - ovlClipRects[i].y = cr[i].y; - ovlClipRects[i].width = cr[i].width; - ovlClipRects[i].height = cr[i].height; - ovlClipRects[i].next = &(ovlClipRects[i + 1]); - } - ovlClipCount = ClipCount; - //use it: - return OvlG(ovlSizeX, ovlSizeY, ovlPosX, ovlPosY); - } - return false; -} - -bool cDvbApi::OvlP(__u16 Brightness, __u16 Colour, __u16 Hue, __u16 Contrast) -{ - if (videoDev < 0) - return false; - int result = 0; - ovlBrightness = Brightness; - ovlColour = Colour; - ovlHue = Hue; - ovlContrast = Contrast; - struct video_picture vp; - if (!ovlFbSet) - return false; - result |= ioctl(videoDev, VIDIOCGPICT, &vp); - vp.brightness = Brightness; - vp.colour = Colour; - vp.hue = Hue; - vp.contrast = Contrast; - vp.depth = ovlBpp; - vp.palette = ovlPalette; // gf: is this always ok? VIDEO_PALETTE_RGB565; - result |= ioctl(videoDev, VIDIOCSPICT, &vp); return result == 0; } -bool cDvbApi::OvlO(bool Value) -{ - if (videoDev < 0) - return false; - int result = 0; - if (!ovlGeoSet && Value) - return false; - int one = 1; - int zero = 0; - result |= ioctl(videoDev, VIDIOCCAPTURE, Value ? &one : &zero); - ovlStat = Value; - if (result) { - ovlStat = false; - return false; - } - return true; -} - #ifdef DEBUG_OSD void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg) { @@ -3257,97 +3131,106 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char bool ChannelSynced = false; - if (fd_sec >= 0) { // DVB-S + switch (frontendType) { + case FE_QPSK: { // DVB-S - // Frequency offsets: + // Frequency offsets: - unsigned int freq = FrequencyMHz; - int tone = SEC_TONE_OFF; + unsigned int freq = FrequencyMHz; + int tone = SEC_TONE_OFF; - if (freq < (unsigned int)Setup.LnbSLOF) { - freq -= Setup.LnbFrequLo; - tone = SEC_TONE_OFF; - } - else { - freq -= Setup.LnbFrequHi; - tone = SEC_TONE_ON; - } + if (freq < (unsigned int)Setup.LnbSLOF) { + freq -= Setup.LnbFrequLo; + tone = SEC_TONE_OFF; + } + else { + freq -= Setup.LnbFrequHi; + tone = SEC_TONE_ON; + } - FrontendParameters Frontend; - Frontend.Frequency = freq * 1000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.qpsk.SymbolRate = Srate * 1000UL; - Frontend.u.qpsk.FEC_inner = FEC_AUTO; + FrontendParameters Frontend; + Frontend.Frequency = freq * 1000UL; + Frontend.Inversion = INVERSION_AUTO; + Frontend.u.qpsk.SymbolRate = Srate * 1000UL; + Frontend.u.qpsk.FEC_inner = FEC_AUTO; - int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; + int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; - // DiseqC: + // DiseqC: - secCommand scmd; - scmd.type = 0; - scmd.u.diseqc.addr = 0x10; - scmd.u.diseqc.cmd = 0x38; - scmd.u.diseqc.numParams = 1; - scmd.u.diseqc.params[0] = 0xF0 | ((Diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0); + secCommand scmd; + scmd.type = 0; + scmd.u.diseqc.addr = 0x10; + scmd.u.diseqc.cmd = 0x38; + scmd.u.diseqc.numParams = 1; + scmd.u.diseqc.params[0] = 0xF0 | ((Diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0); - secCmdSequence scmds; - scmds.voltage = volt; - scmds.miniCommand = SEC_MINI_NONE; - scmds.continuousTone = tone; - scmds.numCommands = Setup.DiSEqC ? 1 : 0; - scmds.commands = &scmd; + secCmdSequence scmds; + scmds.voltage = volt; + scmds.miniCommand = SEC_MINI_NONE; + scmds.continuousTone = tone; + scmds.numCommands = Setup.DiSEqC ? 1 : 0; + scmds.commands = &scmd; - CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); + CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); - // Tuning: + // Tuning: - CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); + CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); - // Wait for channel sync: + // Wait for channel sync: - if (cFile::FileReady(fd_frontend, 5000)) { - FrontendEvent event; - int res = ioctl(fd_frontend, FE_GET_EVENT, &event); - if (res >= 0) - ChannelSynced = event.type == FE_COMPLETION_EV; - else - esyslog(LOG_ERR, "ERROR %d in frontend get event", res); - } - else - esyslog(LOG_ERR, "ERROR: timeout while tuning"); - } - else if (fd_frontend >= 0) { // DVB-C + if (cFile::FileReady(fd_frontend, 5000)) { + FrontendEvent event; + int res = ioctl(fd_frontend, FE_GET_EVENT, &event); + if (res >= 0) + ChannelSynced = event.type == FE_COMPLETION_EV; + else + esyslog(LOG_ERR, "ERROR %d in frontend get event", res); + } + else + esyslog(LOG_ERR, "ERROR: timeout while tuning"); + } + break; + case FE_QAM: { // DVB-C - // Frequency and symbol rate: + // Frequency and symbol rate: - FrontendParameters Frontend; - Frontend.Frequency = FrequencyMHz * 1000000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.qam.SymbolRate = Srate * 1000UL; - Frontend.u.qam.FEC_inner = FEC_AUTO; - Frontend.u.qam.QAM = QAM_64; + FrontendParameters Frontend; + Frontend.Frequency = FrequencyMHz * 1000000UL; + Frontend.Inversion = INVERSION_AUTO; + Frontend.u.qam.SymbolRate = Srate * 1000UL; + Frontend.u.qam.FEC_inner = FEC_AUTO; + Frontend.u.qam.QAM = QAM_64; - // Tuning: + // Tuning: - CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); + CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); - // Wait for channel sync: + // Wait for channel sync: - if (cFile::FileReady(fd_frontend, 5000)) { - FrontendEvent event; - int res = ioctl(fd_frontend, FE_GET_EVENT, &event); - if (res >= 0) - ChannelSynced = event.type == FE_COMPLETION_EV; - else - esyslog(LOG_ERR, "ERROR %d in frontend get event", res); - } - else - esyslog(LOG_ERR, "ERROR: timeout while tuning"); - } - else { - esyslog(LOG_ERR, "ERROR: attempt to set channel without DVB-S or DVB-C device"); - return scrFailed; - } + if (cFile::FileReady(fd_frontend, 5000)) { + FrontendEvent event; + int res = ioctl(fd_frontend, FE_GET_EVENT, &event); + if (res >= 0) + ChannelSynced = event.type == FE_COMPLETION_EV; + else + esyslog(LOG_ERR, "ERROR %d in frontend get event", res); + } + else + esyslog(LOG_ERR, "ERROR: timeout while tuning"); + } + break; + case FE_OFDM: { // DVB-T + //XXX TODO: implement DVB-T tuning (anybody with a DVB-T card out there?) + esyslog(LOG_ERR, "ERROR: DVB-T tuning support not yet implemented"); + return scrFailed; + } + break; + default: + esyslog(LOG_ERR, "ERROR: attempt to set channel with unknown DVB frontend type"); + return scrFailed; + } if (!ChannelSynced) { esyslog(LOG_ERR, "ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1); diff --git a/dvbapi.h b/dvbapi.h index 8e67f9b4b..01bb2dd92 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.53 2001/09/23 11:01:46 kls Exp $ + * $Id: dvbapi.h 1.58 2001/11/04 11:39:42 kls Exp $ */ #ifndef __DVBAPI_H @@ -34,12 +34,6 @@ #include "eit.h" #include "thread.h" -// Overlay facilities -#define MAXCLIPRECTS 100 -typedef struct CRect { - signed short x, y, width, height; - }; - #define FRAMESPERSEC 25 // The maximum file size is limited by the range that can be covered @@ -89,7 +83,7 @@ class cDvbApi { #endif //DVDSUPPORT friend class cTransferBuffer; private: - int videoDev; + FrontendType frontendType; int fd_osd, fd_frontend, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxd1, fd_demuxd2, fd_demuxv, fd_demuxt; int vPid, aPid1, aPid2, dPid1, dPid2; bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output); @@ -154,21 +148,6 @@ class cDvbApi { bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); - // Overlay facilities - -private: - bool ovlStat, ovlGeoSet, ovlFbSet; - int ovlSizeX, ovlSizeY, ovlPosX, ovlPosY, ovlBpp, ovlPalette, ovlClips, ovlClipCount; - int ovlFbSizeX, ovlFbSizeY; - __u16 ovlBrightness, ovlColour, ovlHue, ovlContrast; - struct video_clip ovlClipRects[MAXCLIPRECTS]; -public: - bool OvlF(int SizeX, int SizeY, int FbAddr, int Bpp, int Palette); - bool OvlG(int SizeX, int SizeY, int PosX, int PosY); - bool OvlC(int ClipCount, CRect *Cr); - bool OvlP(__u16 Brightness, __u16 Color, __u16 Hue, __u16 Contrast); - bool OvlO(bool Value); - // On Screen Display facilities private: @@ -233,8 +212,6 @@ class cDvbApi { cPlayBuffer *replayBuffer; int ca; int priority; - int Ca(void) { return ca; } - // Returns the ca of the current recording session (0..MAXDVBAPI). int Priority(void) { return priority; } // Returns the priority of the current recording session (0..MAXPRIORITY), // or -1 if no recording is currently active. @@ -243,6 +220,8 @@ class cDvbApi { void SetModeReplay(void); void SetModeNormal(bool FromRecording); public: + int Ca(void) { return ca; } + // Returns the ca of the current recording session (0..MAXDVBAPI). int SecondsToFrames(int Seconds); // Returns the number of frames corresponding to the given number of seconds. bool Recording(void); @@ -330,6 +309,7 @@ class cDvbApi { void SetVolume(int Volume, bool Absolute = false); // Sets the volume to the given value, either absolutely or relative to // the current volume. + static int CurrentVolume(void) { return PrimaryDvbApi ? PrimaryDvbApi->volume : 0; } }; class cEITScanner { diff --git a/eit.c b/eit.c index 71ab54c3f..00792ab5f 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.28 2001/10/19 13:13:25 kls Exp $ + * $Id: eit.c 1.29 2001/10/28 13:51:22 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -189,6 +189,7 @@ cEventInfo::cEventInfo(unsigned short serviceid, unsigned short eventid) bIsPresent = bIsFollowing = false; lDuration = 0; tTime = 0; + uTableID = 0; uEventID = eventid; uServiceID = serviceid; nChannelNumber = 0; @@ -231,6 +232,12 @@ bool cEventInfo::IsFollowing() const { return bIsFollowing; } + +void cEventInfo::SetTableID(unsigned char tableid) +{ + uTableID = tableid; +} + /** */ void cEventInfo::SetFollowing(bool foll) { @@ -246,6 +253,12 @@ const char * cEventInfo::GetDate() const return szDate; } + +const unsigned char cEventInfo::GetTableID(void) const +{ + return uTableID; +} + /** */ const char * cEventInfo::GetTimeString() const { @@ -545,21 +558,26 @@ unsigned short cSchedule::GetServiceID() const return uServiceID; } /** */ -const cEventInfo * cSchedule::GetEvent(unsigned short uEventID) const +const cEventInfo * cSchedule::GetEvent(unsigned short uEventID, time_t tTime) const { + // Returns either the event info with the given uEventID or, if that one can't + // be found, the one with the given tTime (or NULL if neither can be found) cEventInfo *pe = Events.First(); + cEventInfo *pt = NULL; while (pe != NULL) { if (pe->GetEventID() == uEventID) return pe; + if (tTime > 0 && pe->GetTime() == tTime) // 'tTime < 0' is apparently used with NVOD channels + pt = pe; pe = Events.Next(pe); } - return NULL; + return pt; } /** */ -const cEventInfo * cSchedule::GetEvent(time_t tTime) const +const cEventInfo * cSchedule::GetEventAround(time_t tTime) const { cEventInfo *pe = Events.First(); while (pe != NULL) @@ -759,7 +777,7 @@ int cEIT::ProcessEIT(unsigned char *buffer) if (!rEvent) break; } - pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID); + pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID, VdrProgramInfo->StartTime); if (!pEvent) { // If we don't have that event ID yet, we create a new one. // Otherwise we copy the information into the existing event anyway, because the data might have changed. @@ -767,6 +785,14 @@ int cEIT::ProcessEIT(unsigned char *buffer) pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID); if (!pEvent) break; + pEvent->SetTableID(tid); + } + else { + // We have found an existing event, either through its event ID or its start time. + // If the new event comes from a table that belongs to an "other TS" and the existing + // one comes from a "actual TS" table, lets skip it. + if ((tid == 0x4F || tid == 0x60) && (pEvent->GetTableID() == 0x4E || pEvent->GetTableID() == 0x50)) + continue; } if (rEvent) { pEvent->SetTitle(rEvent->GetTitle()); @@ -774,6 +800,7 @@ int cEIT::ProcessEIT(unsigned char *buffer) pEvent->SetExtendedDescription(rEvent->GetExtendedDescription()); } else { + pEvent->SetTableID(tid); pEvent->SetTitle(VdrProgramInfo->ShortName); pEvent->SetSubtitle(VdrProgramInfo->ShortText); pEvent->SetExtendedDescription(VdrProgramInfo->ExtendedName); diff --git a/eit.h b/eit.h index 91d5b2b38..131419623 100644 --- a/eit.h +++ b/eit.h @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.11 2001/09/22 11:43:21 kls Exp $ + * $Id: eit.h 1.12 2001/10/28 12:33:10 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -29,6 +29,7 @@ class cEventInfo : public cListObject { friend class cSchedule; friend class cEIT; private: + unsigned char uTableID; // Table ID this event came from unsigned short uServiceID; // Service ID of program for that event bool bIsFollowing; // true if this is the next event on this channel bool bIsPresent; // true if this is the present event running @@ -40,6 +41,7 @@ class cEventInfo : public cListObject { time_t tTime; // Start time int nChannelNumber; // the actual channel number from VDR's channel list (used in cMenuSchedule for sorting by channel number) protected: + void SetTableID(unsigned char tableid); void SetFollowing(bool foll); void SetPresent(bool pres); void SetTitle(const char *string); @@ -52,6 +54,7 @@ class cEventInfo : public cListObject { cEventInfo(unsigned short serviceid, unsigned short eventid); public: ~cEventInfo(); + const unsigned char GetTableID(void) const; const char *GetTimeString(void) const; const char *GetEndTimeString(void) const; const char *GetDate(void) const; @@ -90,8 +93,8 @@ class cSchedule : public cListObject { const cEventInfo *GetPresentEvent(void) const; const cEventInfo *GetFollowingEvent(void) const; unsigned short GetServiceID(void) const; - const cEventInfo *GetEvent(unsigned short uEventID) const; - const cEventInfo *GetEvent(time_t tTime) const; + const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const; + const cEventInfo *GetEventAround(time_t tTime) const; const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); } int NumEvents(void) const { return Events.Count(); } void Dump(FILE *f, const char *Prefix = "") const; diff --git a/i18n.c b/i18n.c index 926624a8a..764dc3380 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.44 2001/09/30 11:31:43 kls Exp $ + * $Id: i18n.c 1.45 2001/10/28 16:04:58 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -376,6 +376,15 @@ const tPhrase Phrases[] = { "Arrter l'enregistrement?", "Stoppe opptak?", }, + { "on primary interface", + "auf dem primren Interface", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Cancel editing?", "Schneiden abbrechen?", "Zelite prekiniti urejanje?", diff --git a/menu.c b/menu.c index 0242d91f9..154f66cfa 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.131 2001/10/21 14:28:14 kls Exp $ + * $Id: menu.c 1.139 2001/11/04 10:37:18 kls Exp $ */ #include "menu.h" @@ -1808,11 +1808,15 @@ eOSState cMenuCommands::ProcessKey(eKeys Key) // --- cMenuMain ------------------------------------------------------------- #define STOP_RECORDING tr(" Stop recording ") +#define ON_PRIMARY_INTERFACE tr("on primary interface") cMenuMain::cMenuMain(bool Replaying, eOSState State) :cOsdMenu(tr("Main")) { digit = 0; + + // Basic menu items: + Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); Add(new cOsdItem(hk(tr("Channels")), osChannels)); Add(new cOsdItem(hk(tr("Timers")), osTimers)); @@ -1824,8 +1828,20 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) Add(new cOsdItem(hk(tr("Setup")), osSetup)); if (Commands.Count()) Add(new cOsdItem(hk(tr("Commands")), osCommands)); + + // Replay control: + if (Replaying) Add(new cOsdItem(tr(" Stop replaying"), osStopReplay)); + + // Record control: + + if (cRecordControls::StopPrimary()) { + char *buffer = NULL; + asprintf(&buffer, "%s%s", STOP_RECORDING, ON_PRIMARY_INTERFACE); + Add(new cOsdItem(buffer, osStopRecord)); + } + const char *s = NULL; while ((s = cRecordControls::GetInstantId(s)) != NULL) { char *buffer = NULL; @@ -1833,8 +1849,14 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) Add(new cOsdItem(buffer, osStopRecord)); delete buffer; } + + // Editing control: + if (cVideoCutter::Active()) Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit)); + + // Color buttons: + const char *DVDbutton = #ifdef DVDSUPPORT cDVD::DiscOk() ? tr("Eject") : NULL; @@ -1845,6 +1867,9 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) Display(); lastActivity = time(NULL); SetHasHotkeys(); + + // Initial submenus: + switch (State) { case osRecordings: AddSubMenu(new cMenuRecordings); break; #ifdef DVDSUPPORT @@ -1882,7 +1907,11 @@ eOSState cMenuMain::ProcessKey(eKeys Key) case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { cOsdItem *item = Get(Current()); if (item) { - cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING)); + const char *s = item->Text() + strlen(STOP_RECORDING); + if (strcmp(s, ON_PRIMARY_INTERFACE) == 0) + cRecordControls::StopPrimary(true); + else + cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING)); return osEnd; } } @@ -1908,6 +1937,14 @@ eOSState cMenuMain::ProcessKey(eKeys Key) #ifdef DVDSUPPORT case kYellow: if (!HasSubMenu()) { if (cDVD::DiscOk()) { + // We need to stop replaying a DVD before ejecting, + // otherwise the replay thread crashes. Currently + // checking LastReplayed() is pretty much the only way + // of finding out whether we are currently replaying a DVD + // (i.e. if LastReplayed() returns non-NULL, we are either + // replaying a normal recording, or nothing at all): + if (!cReplayControl::LastReplayed()) + cDvbApi::PrimaryDvbApi->StopReplay(); cDVD::Eject(); state = osEnd; } @@ -2062,7 +2099,9 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) } } break; + case kLeft|k_Repeat: case kLeft: + case kRight|k_Repeat: case kRight: withInfo = false; if (group < 0) { @@ -2072,7 +2111,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) } if (group >= 0) { int SaveGroup = group; - if (Key == kRight) + if (NORMALKEY(Key) == kRight) group = Channels.GetNextGroup(group) ; else group = Channels.GetPrevGroup(group < 1 ? 1 : group); @@ -2101,8 +2140,10 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) case kOk: if (group >= 0) Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(group))->number); return osEnd; - default: Interface->PutKey(Key); - return osEnd; + default: if (NORMALKEY(Key) == kUp || NORMALKEY(Key) == kDown || (Key & (k_Repeat | k_Release)) == 0) { + Interface->PutKey(Key); + return osEnd; + } }; if (time_ms() - lastTime < INFOTIMEOUT) { DisplayInfo(); @@ -2166,7 +2207,7 @@ bool cRecordControl::GetEventInfo(void) if (Schedules) { const cSchedule *Schedule = Schedules->GetSchedule(channel->pnr); if (Schedule) { - eventInfo = Schedule->GetEvent(Time); + eventInfo = Schedule->GetEventAround(Time); if (eventInfo) { if (seconds > 0) dsyslog(LOG_INFO, "got EPG info after %d seconds", seconds); @@ -2260,6 +2301,19 @@ void cRecordControls::Stop(cDvbApi *DvbApi) } } +bool cRecordControls::StopPrimary(bool DoIt) +{ + if (cDvbApi::PrimaryDvbApi->Recording()) { + cDvbApi *dvbApi = cDvbApi::GetDvbApi(cDvbApi::PrimaryDvbApi->Ca(), 0); + if (dvbApi) { + if (DoIt) + Stop(cDvbApi::PrimaryDvbApi); + return true; + } + } + return false; +} + const char *cRecordControls::GetInstantId(const char *LastInstantId) { for (int i = 0; i < MAXDVBAPI; i++) { @@ -2354,7 +2408,8 @@ cReplayControl::cReplayControl(void) timeSearchActive = false; if (fileName) { marks.Load(fileName); - dvbApi->StartReplay(fileName); + if (!dvbApi->StartReplay(fileName)) + Interface->Error(tr("Channel locked (recording)!")); } #ifdef DVDSUPPORT else if (dvd) @@ -2418,10 +2473,7 @@ void cReplayControl::Hide(void) if (visible) { Interface->Close(); needsFastResponse = visible = false; - if (!modeOnly) - ShowMode(); - else - modeOnly = false; + modeOnly = false; } } @@ -2664,15 +2716,18 @@ void cReplayControl::MarkMove(bool Forward) void cReplayControl::EditCut(void) { - Hide(); - if (!cVideoCutter::Active()) { - if (!cVideoCutter::Start(fileName)) - Interface->Error(tr("Can't start editing process!")); + if (fileName) { + Hide(); + if (!cVideoCutter::Active()) { + if (!cVideoCutter::Start(fileName)) + Interface->Error(tr("Can't start editing process!")); + else + Interface->Info(tr("Editing process started")); + } else - Interface->Info(tr("Editing process started")); + Interface->Error(tr("Editing process already active!")); + ShowMode(); } - else - Interface->Error(tr("Editing process already active!")); } void cReplayControl::EditTest(void) @@ -2700,6 +2755,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key) if (visible) { if (timeoutShow && time(NULL) > timeoutShow) { Hide(); + ShowMode(); timeoutShow = 0; } else if (!modeOnly) @@ -2749,8 +2805,10 @@ eOSState cReplayControl::ProcessKey(eKeys Key) switch (Key) { // Menu control: case kMenu: Hide(); return osMenu; // allow direct switching to menu - case kOk: if (visible && !modeOnly) + case kOk: if (visible && !modeOnly) { Hide(); + DoShowMode = true; + } else Show(); break; diff --git a/menu.h b/menu.h index b41a935b0..250d2ff52 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.33 2001/10/21 14:26:01 kls Exp $ + * $Id: menu.h 1.34 2001/10/28 15:21:04 kls Exp $ */ #ifndef _MENU_H @@ -92,6 +92,7 @@ class cRecordControls { static bool Start(cTimer *Timer = NULL); static void Stop(const char *InstantId); static void Stop(cDvbApi *DvbApi); + static bool StopPrimary(bool DoIt = false); static const char *GetInstantId(const char *LastInstantId); static void Process(time_t t); static bool Active(void); diff --git a/ringbuffer.c b/ringbuffer.c index 7e09b2af5..8b8420c16 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -7,7 +7,7 @@ * Parts of this file were inspired by the 'ringbuffy.c' from the * LinuxDVB driver (see linuxtv.org). * - * $Id: ringbuffer.c 1.4 2001/08/05 12:17:45 kls Exp $ + * $Id: ringbuffer.c 1.5 2001/11/03 09:50:46 kls Exp $ */ #include "ringbuffer.h" @@ -215,9 +215,10 @@ int cRingBufferLinear::Get(uchar *Data, int Count) // --- cFrame ---------------------------------------------------------------- -cFrame::cFrame(const uchar *Data, int Count, int Index) +cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index) { count = Count; + type = Type; index = Index; data = new uchar[count]; if (data) diff --git a/ringbuffer.h b/ringbuffer.h index f61d9e04c..7e1025b1e 100644 --- a/ringbuffer.h +++ b/ringbuffer.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ringbuffer.h 1.4 2001/08/05 11:12:06 kls Exp $ + * $Id: ringbuffer.h 1.5 2001/11/03 10:41:33 kls Exp $ */ #ifndef __RINGBUFFER_H @@ -75,18 +75,22 @@ class cRingBufferLinear : public cRingBuffer { virtual ~cRingBufferLinear(); }; +enum eFrameType { ftUnknown, ftVideo, ftAudio, ftDolby }; + class cFrame { friend class cRingBufferFrame; private: cFrame *next; uchar *data; int count; + eFrameType type; int index; public: - cFrame(const uchar *Data, int Count, int Index = -1); + cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1); ~cFrame(); const uchar *Data(void) const { return data; } int Count(void) const { return count; } + eFrameType Type(void) const { return type; } int Index(void) const { return index; } }; diff --git a/svdrp.c b/svdrp.c index 43c55e467..48c956391 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.25 2001/10/07 15:13:42 kls Exp $ + * $Id: svdrp.c 1.27 2001/11/04 11:25:05 kls Exp $ */ #include "svdrp.h" @@ -27,6 +27,7 @@ #include <sys/time.h> #include <unistd.h> #include "config.h" +#include "dvbapi.h" #include "interface.h" #include "tools.h" @@ -120,6 +121,12 @@ const char *HelpPages[] = { " it returns the current channel number and name.", "DELC <number>\n" " Delete channel.", + "DELR <number>\n" + " Delete the recording with the given number. Before a recording can be\n" + " deleted, an LSTR command must have been executed in order to retrieve\n" + " the recording numbers. The numbers don't change during subsequent DELR\n" + " commands. CAUTION: THERE IS NO CONFIRMATION PROMPT WHEN DELETING A\n" + " RECORDING - BE SURE YOU KNOW WHAT YOU ARE DOING!", "DELT <number>\n" " Delete timer.", "GRAB <filename> [ jpeg | pnm [ <quality> [ <sizex> <sizey> ] ] ]\n" @@ -137,6 +144,9 @@ const char *HelpPages[] = { " containing the given string as part of their name are listed.", "LSTE\n" " List EPG data.", + "LSTR [ <number> ]\n" + " List recordings. Without option, all recordings are listed. Otherwise\n" + " the summary for the given recording is listed.", "LSTT [ <number> ]\n" " List timers. Without option, all timers are listed. Otherwise\n" " only the given timer is listed.", @@ -174,16 +184,6 @@ const char *HelpPages[] = { " zero, this means that the timer is currently recording and has started\n" " at the given time. The first value in the resulting line is the number\n" " of the timer.", - "OVLF <sizex> <sizey> <fbaddr> <bpp> <palette>\n" - " Set the size, address depth and palette of the overlay.", - "OVLG <sizex> <sizey> <posx> <posy>\n" - " Set the size and position of the overlay.", - "OVLC <clipcount> <base16-CRect-array>\n" - " Set the overlay clipping rectangles.", - "OVLP <brightness> <colour> <hue> <contrast>\n" - " Set the picture parameters for the overlay.", - "OVLO 0 | 1\n" - " Switch the overlay on or off.", "UPDT <settings>\n" " Updates a timer. Settings must be in the same format as returned\n" " by the LSTT command. If a timer with the same channel, day, start\n" @@ -278,7 +278,6 @@ bool cSVDRP::Send(const char *s, int length) if (wbytes < 0) { LOG_ERROR; file.Close(); - cDvbApi::PrimaryDvbApi->OvlO(false); } else //XXX while...??? esyslog(LOG_ERR, "Wrote %d bytes to client while expecting %d\n", wbytes, length); @@ -380,6 +379,27 @@ void cSVDRP::CmdDELC(const char *Option) Reply(502, "DELC not yet implemented"); } +void cSVDRP::CmdDELR(const char *Option) +{ + if (*Option) { + if (isnumber(Option)) { + cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1); + if (recording) { + if (recording->Delete()) + Reply(250, "Recording \"%s\" deleted", Option); + else + Reply(554, "Error while deleting recording!"); + } + else + Reply(550, "Recording \"%s\" not found%s", Option, Recordings.Count() ? "" : " (use LSTR before deleting)"); + } + else + Reply(501, "Error in recording number \"%s\"", Option); + } + else + Reply(501, "Missing recording number"); +} + void cSVDRP::CmdDELT(const char *Option) { if (*Option) { @@ -589,6 +609,38 @@ void cSVDRP::CmdLSTE(const char *Option) Reply(451, "Can't get EPG data"); } +void cSVDRP::CmdLSTR(const char *Option) +{ + bool recordings = Recordings.Load(); + if (*Option) { + if (isnumber(Option)) { + cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1); + if (recording) { + if (recording->Summary()) { + char *summary = strdup(recording->Summary()); + Reply(250, "%s", strreplace(summary,'\n','|')); + delete summary; + } + else + Reply(550, "No summary availabe"); + } + else + Reply(550, "Recording \"%s\" not found", Option); + } + else + Reply(501, "Error in recording number \"%s\"", Option); + } + else if (recordings) { + cRecording *recording = Recordings.First(); + while (recording) { + Reply(recording == Recordings.Last() ? 250 : -250, "%d %s", recording->Index() + 1, recording->Title(' ', true)); + recording = Recordings.Next(recording); + } + } + else + Reply(550, "No recordings available"); +} + void cSVDRP::CmdLSTT(const char *Option) { if (*Option) { @@ -767,106 +819,6 @@ void cSVDRP::CmdNEXT(const char *Option) Reply(550, "No active timers"); } -void cSVDRP::CmdOVLF(const char *Option) -{ - if (*Option) { - int SizeX = 0, SizeY = 0, Bpp = 0, Palette = 0, FbAddr = 0; - if (5 == sscanf(Option, "%d %d %x %d %d", &SizeX, &SizeY, &FbAddr, &Bpp, &Palette)) { - //somehow_set_overlay_geometry; - if (cDvbApi::PrimaryDvbApi->OvlF(SizeX, SizeY, FbAddr, Bpp, Palette)) - Reply(250, "Overlay framebuffer set"); - else - Reply(451, "Illegal overlay framebuffer settings"); - } - else - Reply(501, "Could not parse overlay framebuffer settings"); - } - else - Reply(501, "Missing overlay framebuffer settings"); -} - -void cSVDRP::CmdOVLG(const char *Option) -{ - if (*Option) { - int SizeX = 0, SizeY = 0, PosX = 0, PosY = 0; - if (4 == sscanf(Option, "%d %d %d %d", &SizeX, &SizeY, &PosX, &PosY)) { - //somehow_set_overlay_geometry; - if (cDvbApi::PrimaryDvbApi->OvlG(SizeX, SizeY, PosX, PosY)) - Reply(250, "Overlay geometry set"); - else - Reply(451, "Illegal overlay geometry settings"); - } - else - Reply(501, "Could not parse overlay geometry settings"); - } - else - Reply(501, "Missing overlay geometry settings"); -} - -void cSVDRP::CmdOVLC(const char *Option) -{ - if (*Option) { - int ClipCount = 0; - unsigned char s[2 * MAXCLIPRECTS * sizeof(CRect) + 2]; - if (2 == sscanf(Option, "%d %s", &ClipCount, s)) { - // Base16-decoding of CRect-array: - unsigned char *p = (unsigned char*)ovlClipRects; - int i = 0, size = sizeof(CRect)*ClipCount; - for (int j = 0; i < size; i++) { - p[i] = (s[j++] - 65); - p[i] += (s[j++] - 65) << 4; - } - if (((unsigned)ClipCount == (i / sizeof(CRect))) && (ClipCount >= 0)) { - // apply it: - if (cDvbApi::PrimaryDvbApi->OvlC(ClipCount, ovlClipRects)) - Reply(250, "Overlay-Clipping set"); - else - Reply(451, "Illegal overlay clipping settings"); - return; - } - } - Reply(501, "Error parsing Overlay-Clipping settings"); - } - else - Reply(501, "Missing Clipping settings"); -} - -void cSVDRP::CmdOVLP(const char *Option) -{ - if (*Option) { - int Brightness = 0, Colour = 0, Hue = 0, Contrast = 0; - if (4 == sscanf(Option, "%d %d %d %d", &Brightness, &Colour, &Hue, &Contrast)) { - //somehow_set_overlay_picture_settings; - if (cDvbApi::PrimaryDvbApi->OvlP(Brightness, Colour, Hue, Contrast)) - Reply(250, "Overlay picture settings set"); - else - Reply(451, "Illegal overlay picture settings"); - } - else - Reply(501, "Could not parse overlay picture settings"); - } - else - Reply(501, "Missing overlay picture settings"); -} - -void cSVDRP::CmdOVLO(const char *Option) -{ - if (*Option) { - int Value; - if (1 == sscanf(Option, "%d", &Value)) { - //somehow_set_overlay_picture_settings; - if (cDvbApi::PrimaryDvbApi->OvlO(Value)) - Reply(250, "Overlay capture set"); - else - Reply(451, "Error setting overlay capture"); - } - else - Reply(501, "Could not parse status"); - } - else - Reply(501, "Missing overlay capture status"); -} - void cSVDRP::CmdUPDT(const char *Option) { if (*Option) { @@ -910,12 +862,14 @@ void cSVDRP::Execute(char *Cmd) s = skipspace(s); if (CMD("CHAN")) CmdCHAN(s); else if (CMD("DELC")) CmdDELC(s); + else if (CMD("DELR")) CmdDELR(s); else if (CMD("DELT")) CmdDELT(s); else if (CMD("GRAB")) CmdGRAB(s); else if (CMD("HELP")) CmdHELP(s); else if (CMD("HITK")) CmdHITK(s); else if (CMD("LSTC")) CmdLSTC(s); else if (CMD("LSTE")) CmdLSTE(s); + else if (CMD("LSTR")) CmdLSTR(s); else if (CMD("LSTT")) CmdLSTT(s); else if (CMD("MESG")) CmdMESG(s); else if (CMD("MODC")) CmdMODC(s); @@ -925,11 +879,6 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("NEWC")) CmdNEWC(s); else if (CMD("NEWT")) CmdNEWT(s); else if (CMD("NEXT")) CmdNEXT(s); - else if (CMD("OVLF")) CmdOVLF(s); - else if (CMD("OVLG")) CmdOVLG(s); - else if (CMD("OVLC")) CmdOVLC(s); - else if (CMD("OVLP")) CmdOVLP(s); - else if (CMD("OVLO")) CmdOVLO(s); else if (CMD("UPDT")) CmdUPDT(s); else if (CMD("QUIT")) Close(); else Reply(500, "Command unrecognized: \"%s\"", Cmd); diff --git a/svdrp.h b/svdrp.h index 1c16f88b4..e68a92e43 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,13 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.11 2001/09/14 14:35:34 kls Exp $ + * $Id: svdrp.h 1.13 2001/11/04 11:20:46 kls Exp $ */ #ifndef __SVDRP_H #define __SVDRP_H -#include "dvbapi.h" +#include "recording.h" #include "tools.h" class cSocket { @@ -30,7 +30,7 @@ class cSVDRP { private: cSocket socket; cFile file; - CRect ovlClipRects[MAXCLIPRECTS]; + cRecordings Recordings; uint numChars; char cmdLine[MAXPARSEBUFFER]; char *message; @@ -40,12 +40,14 @@ class cSVDRP { void Reply(int Code, const char *fmt, ...); void CmdCHAN(const char *Option); void CmdDELC(const char *Option); + void CmdDELR(const char *Option); void CmdDELT(const char *Option); void CmdGRAB(const char *Option); void CmdHELP(const char *Option); void CmdHITK(const char *Option); void CmdLSTC(const char *Option); void CmdLSTE(const char *Option); + void CmdLSTR(const char *Option); void CmdLSTT(const char *Option); void CmdMESG(const char *Option); void CmdMODC(const char *Option); @@ -55,11 +57,6 @@ class cSVDRP { void CmdNEWC(const char *Option); void CmdNEWT(const char *Option); void CmdNEXT(const char *Option); - void CmdOVLF(const char *Option); - void CmdOVLG(const char *Option); - void CmdOVLC(const char *Option); - void CmdOVLP(const char *Option); - void CmdOVLO(const char *Option); void CmdUPDT(const char *Option); void Execute(char *Cmd); public: diff --git a/thread.c b/thread.c index b51489ec8..7e5b0ea7f 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.15 2001/10/21 12:25:31 kls Exp $ + * $Id: thread.c 1.16 2001/10/27 13:23:06 kls Exp $ */ #include "thread.h" @@ -99,8 +99,7 @@ cThread::cThread(void) signalHandlerInstalled = true; } running = false; - parentPid = threadPid = lockingPid = 0; - locked = 0; + parentPid = threadPid = 0; } cThread::~cThread() @@ -159,24 +158,6 @@ void cThread::Cancel(int WaitSeconds) pthread_cancel(thread); } -bool cThread::Lock(void) -{ - if (getpid() != lockingPid || !locked) { - Mutex.Lock(); - lockingPid = getpid(); - } - locked++; - return true; -} - -void cThread::Unlock(void) -{ - if (!--locked) { - lockingPid = 0; - Mutex.Unlock(); - } -} - void cThread::WakeUp(void) { kill(parentPid, SIGIO); // makes any waiting 'select()' call return immediately @@ -228,17 +209,13 @@ bool cThreadLock::Lock(cThread *Thread) { if (Thread && !thread) { thread = Thread; - locked = Thread->Lock(); - return locked; + Thread->Lock(); + locked = true; + return true; } return false; } -bool cThreadLock::Locked(void) -{ - return locked; -} - // --- cPipe ----------------------------------------------------------------- // cPipe::Open() and cPipe::Close() are based on code originally received from diff --git a/thread.h b/thread.h index 89dcdf853..4547addeb 100644 --- a/thread.h +++ b/thread.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.10 2001/10/20 10:25:19 kls Exp $ + * $Id: thread.h 1.11 2001/10/27 13:22:20 kls Exp $ */ #ifndef __THREAD_H @@ -45,9 +45,8 @@ class cThread { friend class cThreadLock; private: pthread_t thread; - cMutex Mutex; - pid_t parentPid, threadPid, lockingPid; - int locked; + cMutex mutex; + pid_t parentPid, threadPid; bool running; static time_t lastPanic; static int panicLevel; @@ -55,8 +54,8 @@ class cThread { static bool signalHandlerInstalled; static void SignalHandler(int signum); static void *StartThread(cThread *Thread); - bool Lock(void); - void Unlock(void); + void Lock(void) { mutex.Lock(); } + void Unlock(void) { mutex.Unlock(); } protected: void WakeUp(void); virtual void Action(void) = 0; @@ -84,7 +83,6 @@ class cThreadLock { cThreadLock(cThread *Thread = NULL); ~cThreadLock(); bool Lock(cThread *Thread); - bool Locked(void); }; #define LOCK_THREAD cThreadLock ThreadLock(this) diff --git a/vdr.c b/vdr.c index ce86fd0da..886b09178 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.86 2001/10/20 11:18:38 kls Exp $ + * $Id: vdr.c 1.89 2001/11/03 12:23:45 kls Exp $ */ #include <getopt.h> @@ -483,7 +483,7 @@ int main(int argc, char *argv[]) time_t Now = time(NULL); if (Now - LastActivity > ACTIVITYTIMEOUT) { // Shutdown: - if (Shutdown && Setup.MinUserInactivity && Now - LastActivity > Setup.MinUserInactivity * 60) { + if (Shutdown && (Setup.MinUserInactivity || LastActivity == 1) && Now - LastActivity > Setup.MinUserInactivity * 60) { cTimer *timer = Timers.GetNextActiveTimer(); time_t Next = timer ? timer->StartTime() : 0; time_t Delta = timer ? Next - Now : 0; @@ -503,11 +503,12 @@ int main(int argc, char *argv[]) dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next)); if (WatchdogTimeout > 0) signal(SIGALRM, SIG_IGN); - if (Interface->Confirm(tr("Press any key to cancel shutdown"), LastActivity == 1 ? 5 : SHUTDOWNWAIT, true)) { + bool UserShutdown = key == kPower; + if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) { int Channel = timer ? timer->channel : 0; const char *File = timer ? timer->file : ""; char *cmd; - asprintf(&cmd, "%s %ld %ld %d '%s'", Shutdown, Next, Delta, Channel, File); + asprintf(&cmd, "%s %ld %ld %d '%s' %d", Shutdown, Next, Delta, Channel, File, UserShutdown); isyslog(LOG_INFO, "executing '%s'", cmd); SystemExec(cmd); delete cmd; @@ -529,6 +530,7 @@ int main(int argc, char *argv[]) if (Interrupted) isyslog(LOG_INFO, "caught signal %d", Interrupted); Setup.CurrentChannel = cDvbApi::CurrentChannel(); + Setup.CurrentVolume = cDvbApi::CurrentVolume(); Setup.Save(); cVideoCutter::Stop(); delete Menu; From b420457467ad0c8ae71f8b985914e85b7a0ff5aa Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 25 Nov 2001 18:00:00 +0100 Subject: [PATCH 029/307] Version 0.99pre1 - Fixed several channel definitions in 'channels.conf' (thanks to Thilo Wunderlich). - Added MPEG audio support for DVD (thanks to Andreas Schultz). - Implemented DVB-T support (thanks to Dave Chapman). This currently works only for UK channels. - Removed the range limits for the Frequency and Srate parameters of channel definitions. - Changed the maximum value for PIDs in channels.conf from 0xFFFE to 0x1FFF. - Fixed DVD audio sync problems (thanks to Andreas Schultz). - Fixed external AC3 replay for DVDs (thanks to Andreas Schultz). --- CONTRIBUTORS | 4 ++ FORMATS | 10 ++-- HISTORY | 13 +++++ INSTALL | 27 +++++---- ac3dec/ac3.h | 6 ++ ac3dec/decode.c | 8 +++ channels.conf | 51 ++++++++-------- channels.conf.terr | 11 ++++ config.h | 4 +- dvbapi.c | 141 +++++++++++++++++---------------------------- dvbapi.h | 4 +- dvd.c | 23 +++++++- dvd.h | 11 +++- menu.c | 18 +++--- 14 files changed, 188 insertions(+), 143 deletions(-) create mode 100644 channels.conf.terr diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 2fdfcc1fb..12154c812 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -59,6 +59,7 @@ Deti Fliegl <deti@fliegl.de> Dave Chapman <dave@dchapman.com> for implementing support for the teletext PID for his great support in switching to the NAPI + for implementing DVB-T support Hans-Peter Raschke <Hans-Peter.Raschke@Wintermann-DatenService.de> for his support in adapting VDR to DVB-C @@ -162,3 +163,6 @@ Thomas Heiligenmann <thomas@heiligenmann.de> Norbert Schmidt <nschmidt-nrw@t-online.de> for filling in some missing teletext PIDs + +Thilo Wunderlich <tw@ubcom.net> + for his help in keeping 'channels.conf' up to date diff --git a/FORMATS b/FORMATS index 9142fd70d..2a99e6efa 100644 --- a/FORMATS +++ b/FORMATS @@ -20,10 +20,10 @@ Video Disk Recorder File Formats - Name: the channel's name (if the name originally contains a ':' character it has to be replaced by '|') - - Frequency in MHz (as an integer) + - Frequency in MHz for DVB-S and DVB-C, kHz for DVB-T (as an integer) - Polarization (one of 'h', 'H', 'v', 'V') ** - Diseqc number ** - - Symbol rate + - Symbol rate *** - Video PID - Audio PID (either one number, or two, separated by a comma) If this channel also carries Dolby Digital sound, the Dolby PIDs follow @@ -33,8 +33,10 @@ Video Disk Recorder File Formats DVB card, 2 = can be decrypted by the second DVB card) - Program Number - Fields marked with ** are only meaningful for DVB-S (satellite) receivers. - DVB-C receivers simply ignore these. + Fields marked with ** are only meaningful for DVB-S receivers. + DVB-C and DVB-T receivers simply ignore these. + Fields marked with *** are only meaningful for DVB-S and DVB-C receivers. + DVB-T receivers simply ignore these. * timers.conf diff --git a/HISTORY b/HISTORY index c9d404e7e..3f00cb1a9 100644 --- a/HISTORY +++ b/HISTORY @@ -865,3 +865,16 @@ Video Disk Recorder Revision History will now need to use kvdr 0.4 or later. - The device /dev/video is now opened only if necessary (to GRAB an image), allowing other programs (like 'kvdr', for instance) to use that device. + +2001-11-25: Version 0.99 + +- Fixed several channel definitions in 'channels.conf' (thanks to Thilo + Wunderlich). +- Added MPEG audio support for DVD (thanks to Andreas Schultz). +- Implemented DVB-T support (thanks to Dave Chapman). + This currently works only for UK channels. +- Removed the range limits for the Frequency and Srate parameters of channel + definitions. +- Changed the maximum value for PIDs in channels.conf from 0xFFFE to 0x1FFF. +- Fixed DVD audio sync problems (thanks to Andreas Schultz). +- Fixed external AC3 replay for DVDs (thanks to Andreas Schultz). diff --git a/INSTALL b/INSTALL index d20bf1a13..0ab7edacb 100644 --- a/INSTALL +++ b/INSTALL @@ -334,16 +334,23 @@ accessed using DiSEqC, you have to go to the "Setup" menu and set the "DiSEqC" parameter to "on". Also check the "DiSEqC" parameters for the various channels and set them to the necessary values. -Running VDR with DVB-C (cable): -------------------------------- - -VDR automatically recognizes if the DVB card in use is a cable card. -The only things that needs to be different when using digital cable -is the 'channels.conf' file. The distribution archive contains a default -'channels.conf.cable', which cable users can rename or copy to 'channels.conf' -in order to receive cable channels. The format of this file is exactly the -same as for satellite channels (the fields containing "Polarization" and -"Diseqc" data are ignored in case of DVB-C). +Running VDR with DVB-C (cable) or DVB-T (terrestrial): +------------------------------------------------------ + +VDR automatically recognizes if the DVB card in use is a cable or a +terrestrial card. The only thing that needs to be different when using digital +cable or terrestrial reception is the 'channels.conf' file. The distribution +archive contains a default 'channels.conf.cable' and 'channels.conf.terr', +respectively, which users of such cards can rename or copy to 'channels.conf' +in order to receive digital cable or terrestrial channels. The format of these +files is exactly the same as for satellite channels (the fields containing +"Polarization" and "Diseqc" data are ignored in case of DVB-C and DVB-T, and +the "Frequency" is in kHz in case of DVB-T). + +You can even use a mixture of DVB-S, DVB-C and DVB-T cards in the same system. +All you need to do is to put all the channel definitions into one big +'channel.conf' file and set the 'Ca' parameter of each channel to the number +of the card that can receive it. Learning the remote control keys: --------------------------------- diff --git a/ac3dec/ac3.h b/ac3dec/ac3.h index d325f3bb3..8f268fbdb 100644 --- a/ac3dec/ac3.h +++ b/ac3dec/ac3.h @@ -19,7 +19,11 @@ * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * + *------------------------------------------------------------ * + * 24 Nov 2001 + * Andreas Schultz <aschultz@cs.uni-magdeburg.de> + * Added ac3_buffersize() */ #define AC3_BUFFER_SIZE (6*1024*16) @@ -55,4 +59,6 @@ size_t ac3dec_decode_data (plugin_output_audio_t *output, uint8_t *data_start, u size_t ac3dec_decode_data (uint8_t *data_start ,uint8_t *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data); #endif +uint32_t ac3_buffersize(); + #endif diff --git a/ac3dec/decode.c b/ac3dec/decode.c index fb852055c..1ff517c41 100644 --- a/ac3dec/decode.c +++ b/ac3dec/decode.c @@ -31,6 +31,9 @@ * Matjaz Thaler <matjaz.thaler@rd.iskraemeco.si> * Added support for DVB-s PCI card * + * 24 Nov 2001 + * Andreas Schultz <aschultz@cs.uni-magdeburg.de> + * Added ac3_buffersize() */ #ifdef HAVE_CONFIG_H @@ -96,6 +99,11 @@ static uint32_t buffer_size = 0;; // for error handling jmp_buf error_jmp_mark; +uint32_t ac3_buffersize() +{ + return buffer_size; +} + static uint32_t decode_buffer_syncframe (syncinfo_t *syncinfo, uint8_t **start, uint8_t *end) { uint8_t *cur = *start; diff --git a/channels.conf b/channels.conf index c9bf996a2..2cc3975f5 100644 --- a/channels.conf +++ b/channels.conf @@ -28,10 +28,10 @@ Neun Live:12480:v:0:27500:767:768:0:0:897 DSF:12480:v:0:27500:1023:1024:0:0:900 HOT:12480:v:0:27500:1279:1280:0:0:40 Bloomberg TV Germany:12551:v:0:22000:162:99:0:0:12160 -BLOOMBERG TV:11817:v:0:27500:163:92:0:0:8004 -Bloomberg:12168:v:0:27500:167:112:0:0:12721 +Bloomberg TV France:11817:v:0:27500:163:92:0:0:8004 +Bloomberg TV Spain:12168:v:0:27500:167:112:0:0:12721 Sky News:12552:v:0:22000:305:306:0:0:3995 -KinderNet:12574:h:0:22000:163:92:0:0:5020 +Fox Kids Netherlands:12574:h:0:22000:163:92:0:0:5020 Alice:12610:v:0:22000:162:96:0:0:12200 n-tv:12669:v:0:22000:162:96:55:0:12730 Grand Tourisme:12670:v:0:22000:289:290:0:0:17300 @@ -97,7 +97,7 @@ Cinedom 5B:11720:h:0:27500:1791:1792:0:3:177 Cinedom 5C:12070:h:0:27500:1023:1024:0:3:186 :Beta Digital N24:11914:H:0:27500:255:256:8191:3:52 -CNBC:12148:h:0:27500:255:256:0:3:35 +CNBC:11954:h:0:27500:510:520:0:0:28010 Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199 :PW Erotic Beate-Uhse.TV:11758:h:0:27500:3839:3840:0:3:21 @@ -105,9 +105,9 @@ Blue Movie 1:11758:h:0:27500:1791:1792:0:3:513 Blue Movie 2:11758:h:0:27500:2047:2048:0:3:514 Blue Movie 3:11758:h:0:27500:2303:2304:0:3:515 :Sportsworld -Premiere Sport 1:11719:h:0:27500:255:256:0:3:17 -Premiere Sport 2:11719:h:0:27500:3327:3328:0:3:27 -Premiere Sport 3:11758:h:0:27500:2815:2816:0:3:18 +Premiere Sport 1:11720:h:0:27500:255:256,257:0:3:17 +Premiere Sport 2:12070:h:0:27500:3839:3840:0:3:27 +Premiere Sport 3:12070:h:0:27500:255:256:0:3:26 :Formel 1 Infokanal:11720:h:0:27500:3071:3072:0:3:244 Multikanal:11720:h:0:27500:2815:2816:0:3:243 @@ -118,12 +118,12 @@ Boxengasse:11720:h:0:27500:2047:2048:0:3:240 :Premiere World Bundesliga Superdom:11758:h:0:27500:2815:8192:0:3:18 BuLi-Konferenz:11758:h:0:27500:3327:3328,3329:0:3:215 -BuLi-Spiel 1:11719:h:0:27500:255:256,257:0:3:17 -BuLi-Spiel 2:11719:h:0:27500:2047:2048,2049:0:3:240 -BuLi-Spiel 3:11719:h:0:27500:2303:2304,2305:0:3:241 -BuLi-Spiel 4:11719:h:0:27500:2559:2560,2561:0:3:242 -BuLi-Spiel 5:11719:h:0:27500:2815:2816,2817:0:3:243 -BuLi-Spiel 6:11719:h:0:27500:3071:3072,3073:0:3:244 +BuLi-Spiel 1:11720:h:0:27500:255:256,257:0:3:17 +BuLi-Spiel 2:11720:h:0:27500:2047:2048,2049:0:3:240 +BuLi-Spiel 3:11720:h:0:27500:2303:2304,2305:0:3:241 +BuLi-Spiel 4:11720:h:0:27500:2559:2560,2561:0:3:242 +BuLi-Spiel 5:11720:h:0:27500:2815:2816,2817:0:3:243 +BuLi-Spiel 6:11720:h:0:27500:3071:3072,3073:0:3:244 BuLi-Spiel 7:11758:h:0:27500:3071:3072,3073:0:3:214 : TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601 @@ -132,12 +132,12 @@ Andalucia TV:11934:v:0:27500:166:104:0:0:29011 TVC Internacional:11934:v:0:27500:167:108:0:0:0 Nasza TV:11992:h:0:27500:165:98:0:0:0 WishLine test:12012:v:0:27500:163:90:0:0:0 -Pro 7 Austria:12051:v:0:27500:161:84:0:0:0 -Kabel 1 Schweiz:12051:v:0:27500:162:163:0:0:0 -Kabel 1 Austria:12051:v:0:27500:166:167:0:0:0 -Pro 7 Schweiz:12051:v:0:27500:289:290:0:0:0 +Pro 7 Austria:12051:v:0:27500:161:84:0:0:20002 +Kabel 1 Schweiz:12051:v:0:27500:162:163:0:0:20003 +Kabel 1 Austria:12051:v:0:27500:166:167:0:0:20004 +Pro 7 Schweiz:12051:v:0:27500:289:290:0:0:20001 Kiosque:12129:v:0:27500:160:80:0:0:0 -KTO:12129:v:0:27500:170:120:0:0:0 +KTO:11739:v:0:27500:163:90:0:0:8304 TCM:12168:v:0:27500:160:80:0:0:0 Cartoon Network France & Spain:12168:v:0:27500:161:84:0:0:0 TVBS Europe:12168:v:0:27500:162:88:0:0:0 @@ -147,14 +147,14 @@ TCM Espania:12168:v:0:27500:164:96:0:0:0 MTV Spain:12168:v:0:27500:167:112:0:0:0 TCM France:12168:v:0:27500:169:64:0:0:0 RTL2 CH:12188:h:0:27500:164:112:0:0:0 -La Cinquieme:12207:v:0:27500:160:80:0:0:0 -ARTE:12207:v:0:27500:165:100:0:0:0 +La Cinquieme:12207:v:0:27500:160:80:0:0:8501 +LCP:12207:v:0:27500:165:100:0:0:8506 Post Filial TV:12226:h:0:27500:255:256:0:0:0 Canal Canaris:12246:v:0:27500:160:80:0:0:0 Canal Canaris:12246:v:0:27500:160:81:0:0:0 Canal Canaris:12246:v:0:27500:160:82:0:0:0 Canal Canaris:12246:v:0:27500:160:83:0:0:0 -AB Sat Passion promo:12266:h:0:27500:160:80:0:0:0 +AB Moteurs:12266:h:0:27500:160:80:0:0:17000 AB Channel 1:12266:h:0:27500:161:84:0:0:0 Taquilla 0:12285:v:0:27500:165:100:0:0:0 CSAT:12324:v:0:27500:160:80:0:0:0 @@ -174,7 +174,7 @@ Fashion TV:12402:v:0:27500:163:92:0:0:0 VideoService:12422:h:0:27500:255:256:0:0:0 Beta Research promo:12422:h:0:27500:1023:1024:0:0:0 Canal Canarias:12441:v:0:27500:160:80:0:0:0 -TVC International:12441:v:0:27500:512:660:0:0:0 +TVC International:12441:v:0:27500:512:660:0:0:29701 Fitur:12441:v:0:27500:514:662:0:0:0 Astra Info 1:12552:v:0:22000:164:112:0:0:0 Astra Info 2:12552:v:0:22000:165:120:0:0:0 @@ -185,17 +185,18 @@ Astra Vision 1:12552:v:0:22000:168:147:0:0:0 Astra Vision 1:12552:v:0:22000:168:148:0:0:0 Astra Vision 1:12552:v:0:22000:168:149:0:0:0 Astra Vision 1:12552:v:0:22000:168:150:0:0:0 -RTL Tele Letzebuerg:12552:v:0:22000:168:144:0:0:0 +RTL Tele Letzebuerg:12552:v:0:22000:168:144,146:0:0:3994 Astra Mosaic:12552:v:0:22000:175:176:0:0:0 MHP test:12604:h:0:22000:5632:0:0:0:0 VERONICA:12574:h:0:22000:161:84:0:0:5010 VH1 Classic:12699:v:0:22000:3071:3072:0:0:28647 -VH-1 Germany:12699:v:0:22000:3081:3082:0:0:28648 +MTV 2 Pop:12699:v:0:22000:3081:3082:0:0:28648 Via 1 - Schner Reisen:12148:h:0:27500:511:512:0:0:44 Video Italia:12610:v:0:22000:121:122:0:0:12220 AC 3 promo:12670:v:0:22000:308:256:0:0:0 ORF/ZDF:12699:h:0:22000:506:507:0:0:13012 VIVA:12670:v:0:22000:309:310:0:0:12732 VIVA2:12552:v:0:22000:171:172:0:0:12120 -MTV Central Europe:12699:v:0:22000:3031:3032:0:0:28643 +MTV German:12699:v:0:22000:3031:3032:0:0:28643 IFA-TV:10832:h:0:22000:132:133:32:0:7251 +QVC Germany:12552:v:0:22000:165:166:0:0:12100 diff --git a/channels.conf.terr b/channels.conf.terr new file mode 100644 index 000000000..bed1be8c4 --- /dev/null +++ b/channels.conf.terr @@ -0,0 +1,11 @@ +: UK channels +BBC ONE:505833:0:0:0:600:601:0:0:4164 +BBC TWO:505833:0:0:0:610:611:0:0:4228 +ITV 1:481833:0:0:0:512:650:0:0:8261 +Channel 4:481833:0:0:0:2827:2828:0:0:8384 +Channel 5:561833:0:0:0:6017:6018:0:0:12866 +ITV 2:481833:0:0:0:2818:2819:0:0:8325 +BBC CHOICE:505833:0:0:0:620:621:0:0:4351 +BBC NEWS 24:505833:0:0:0:640:641:0:0:4415 +BBC Knowledge:505833:0:0:0:630:631:0:0:4607 +Shop!:561833:0:0:0:6049:6050:0:0:13120 diff --git a/config.h b/config.h index 574496931..018d00ef2 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.85 2001/10/27 09:56:04 kls Exp $ + * $Id: config.h 1.86 2001/11/25 15:57:08 kls Exp $ */ #ifndef __CONFIG_H @@ -18,7 +18,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.98" +#define VDRVERSION "0.99" #define MAXPRIORITY 99 #define MAXLIFETIME 99 diff --git a/dvbapi.c b/dvbapi.c index f72782b4b..707db0d92 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz <aschultz@warp10.net> * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> * - * $Id: dvbapi.c 1.137 2001/11/04 12:05:36 kls Exp $ + * $Id: dvbapi.c 1.141 2001/11/25 16:38:09 kls Exp $ */ //#define DVDDEBUG 1 @@ -710,6 +710,7 @@ class cPlayBuffer : public cRingBufferFrame { int readIndex, writeIndex; bool canDoTrickMode; bool canToggleAudioTrack; + bool skipAC3bytes; uchar audioTrack; void TrickSpeed(int Increment); virtual void Empty(bool Block = false); @@ -752,6 +753,7 @@ cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev) readIndex = writeIndex = -1; canDoTrickMode = false; canToggleAudioTrack = false; + skipAC3bytes = false; audioTrack = 0xC0; if (cDvbApi::AudioCommand()) { if (!dolbyDev.Open(cDvbApi::AudioCommand(), "w")) @@ -769,7 +771,7 @@ void cPlayBuffer::PlayExternalDolby(const uchar *b, int MaxLength) if (b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01) { if (b[3] == 0xBD) { // dolby int l = b[4] * 256 + b[5] + 6; - int written = b[8] + 9; // skips the PES header + int written = b[8] + (skipAC3bytes ? 13 : 9); // skips the PES header int n = min(l - written, MaxLength); while (n > 0) { int w = fwrite(&b[written], 1, n, dolbyDev); @@ -1348,9 +1350,6 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) #define cOUTPACK 5 #define cOUTFRAMES 6 -#define aAC3 0x80 -#define aLPCM 0xA0 - // --- cAC3toPCM ------------------------------------------------------------- class cAC3toPCM { @@ -1406,22 +1405,16 @@ cFrame *cAC3toPCM::Get(int size, uchar PTSflags, uchar *PTSdata) int p_size = (size > MAXSIZE) ? MAXSIZE : size; int length = 10; // default header bytes int header = 0; - int stuffb = 0; switch (PTSflags) { case 2: header = 5; // additional header bytes - stuffb = 1; break; case 3: header = 10; break; default: header = 0; } - // header = 0; //XXX ??? - stuffb = 0; //XXX ??? - length += header; - length += stuffb; buffer[0] = 0x00; buffer[1] = 0x00; @@ -1430,19 +1423,13 @@ cFrame *cAC3toPCM::Get(int size, uchar PTSflags, uchar *PTSdata) buffer[6] = 0x80; buffer[7] = PTSflags << 6; - buffer[8] = header + stuffb; + buffer[8] = header; if (header) memcpy(&buffer[9], (void *)PTSdata, header); - // add stuffing - data = buffer + 9 + header; - for (int cnt = 0; cnt < stuffb; cnt++) - data[cnt] = 0xff; - length += stuffb; - // add data - data = buffer + 9 + header + stuffb + 7; + data = buffer + 9 + header + 7; int cnt = 0; while (p_size) { if (ac3outp != ac3inp) { // data in the buffer @@ -1456,7 +1443,7 @@ cFrame *cAC3toPCM::Get(int size, uchar PTSflags, uchar *PTSdata) break; } - data = buffer + 9 + header + stuffb; + data = buffer + 9 + header; data[0] = aLPCM; // substream ID data[1] = 0x00; // other stuff (see DVB specs), ignored by driver data[2] = 0x00; @@ -1560,6 +1547,7 @@ cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD canToggleAudioTrack = true;//XXX determine from cDVD! data = new uchar[1024 * DVD_VIDEO_LB_LEN]; canDoTrickMode = true; + skipAC3bytes = true; dvbApi->SetModeReplay(); Start(); } @@ -1574,28 +1562,12 @@ cDVDplayBuffer::~cDVDplayBuffer() unsigned int cDVDplayBuffer::getAudioStream(unsigned int StreamId) { - unsigned int trackID; - - if ((cyclestate < cOPENCHAPTER) || (StreamId > 7)) + if (cyclestate < cOPENCHAPTER || StreamId > 7) return 0; if (!(cur_pgc->audio_control[StreamId] & 0x8000)) return 0; int track = (cur_pgc->audio_control[StreamId] >> 8) & 0x07; - switch (vts_file->vtsi_mat->vts_audio_attr[track].audio_format) { - case 0: // ac3 - trackID = aAC3; - break; - case 2: // mpeg1 - case 3: // mpeg2ext - case 4: // lpcm - case 6: // dts - trackID = aLPCM; - break; - default: esyslog(LOG_ERR, "ERROR: unknown Audio stream info"); - return 0; - } - trackID |= track; - return trackID; + return dvd->getAudioTrack(track) | track; } void cDVDplayBuffer::ToggleAudioTrack(void) @@ -2033,8 +2005,10 @@ void cDVDplayBuffer::handleAC3(unsigned char *sector, int length, uchar PTSflags #define PCM_FRAME_SIZE 1536 AC3toPCM.Put(sector, length); cFrame *frame; - if ((frame = AC3toPCM.Get(PCM_FRAME_SIZE, PTSflags, PTSdata)) != NULL) - putFrame(frame); + if (ac3_buffersize() <= 100) { + if ((frame = AC3toPCM.Get(PCM_FRAME_SIZE, PTSflags, PTSdata)) != NULL) + putFrame(frame); + } while ((frame = AC3toPCM.Get(PCM_FRAME_SIZE)) != NULL) putFrame(frame); } @@ -3087,7 +3061,7 @@ bool cDvbApi::SetPids(bool ForRecording) SetDpid2(ForRecording ? dPid2 : 0, DMX_OUT_TS_TAP); } -eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr) +eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr) { // Make sure the siProcessor won't access the device while switching cThreadLock ThreadLock(siProcessor); @@ -3129,14 +3103,14 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char SetDpid2(0x1FFF, DMX_OUT_DECODER); SetTpid( 0x1FFF, DMX_OUT_DECODER); - bool ChannelSynced = false; + FrontendParameters Frontend; switch (frontendType) { case FE_QPSK: { // DVB-S // Frequency offsets: - unsigned int freq = FrequencyMHz; + unsigned int freq = Frequency; int tone = SEC_TONE_OFF; if (freq < (unsigned int)Setup.LnbSLOF) { @@ -3148,7 +3122,6 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char tone = SEC_TONE_ON; } - FrontendParameters Frontend; Frontend.Frequency = freq * 1000UL; Frontend.Inversion = INVERSION_AUTO; Frontend.u.qpsk.SymbolRate = Srate * 1000UL; @@ -3173,58 +3146,32 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char scmds.commands = &scmd; CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); - - // Tuning: - - CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); - - // Wait for channel sync: - - if (cFile::FileReady(fd_frontend, 5000)) { - FrontendEvent event; - int res = ioctl(fd_frontend, FE_GET_EVENT, &event); - if (res >= 0) - ChannelSynced = event.type == FE_COMPLETION_EV; - else - esyslog(LOG_ERR, "ERROR %d in frontend get event", res); - } - else - esyslog(LOG_ERR, "ERROR: timeout while tuning"); } break; case FE_QAM: { // DVB-C // Frequency and symbol rate: - FrontendParameters Frontend; - Frontend.Frequency = FrequencyMHz * 1000000UL; + Frontend.Frequency = Frequency * 1000000UL; Frontend.Inversion = INVERSION_AUTO; Frontend.u.qam.SymbolRate = Srate * 1000UL; Frontend.u.qam.FEC_inner = FEC_AUTO; Frontend.u.qam.QAM = QAM_64; - - // Tuning: - - CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); - - // Wait for channel sync: - - if (cFile::FileReady(fd_frontend, 5000)) { - FrontendEvent event; - int res = ioctl(fd_frontend, FE_GET_EVENT, &event); - if (res >= 0) - ChannelSynced = event.type == FE_COMPLETION_EV; - else - esyslog(LOG_ERR, "ERROR %d in frontend get event", res); - } - else - esyslog(LOG_ERR, "ERROR: timeout while tuning"); } break; case FE_OFDM: { // DVB-T - //XXX TODO: implement DVB-T tuning (anybody with a DVB-T card out there?) - esyslog(LOG_ERR, "ERROR: DVB-T tuning support not yet implemented"); - return scrFailed; + + // Frequency and OFDM paramaters: + + Frontend.Frequency = Frequency * 1000UL; + Frontend.Inversion = INVERSION_AUTO; + Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ; + Frontend.u.ofdm.HP_CodeRate=FEC_2_3; + Frontend.u.ofdm.LP_CodeRate=FEC_1_2; + Frontend.u.ofdm.Constellation=QAM_64; + Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K; + Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32; + Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE; } break; default: @@ -3232,12 +3179,28 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char return scrFailed; } - if (!ChannelSynced) { - esyslog(LOG_ERR, "ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1); - if (this == PrimaryDvbApi) - cThread::RaisePanic(); - return scrFailed; + // Tuning: + + CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); + + // Wait for channel sync: + + if (cFile::FileReady(fd_frontend, 5000)) { + FrontendEvent event; + int res = ioctl(fd_frontend, FE_GET_EVENT, &event); + if (res >= 0) { + if (event.type != FE_COMPLETION_EV) { + esyslog(LOG_ERR, "ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1); + if (this == PrimaryDvbApi) + cThread::RaisePanic(); + return scrFailed; + } + } + else + esyslog(LOG_ERR, "ERROR %d in frontend get event", res); } + else + esyslog(LOG_ERR, "ERROR: timeout while tuning"); // PID settings: @@ -3261,7 +3224,7 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char if (NeedsTransferMode) { cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); if (CaDvbApi && !CaDvbApi->Recording()) { - if ((Result = CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) == scrOk) { + if ((Result = CaDvbApi->SetChannel(ChannelNumber, Frequency, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) == scrOk) { SetModeReplay(); transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video); } diff --git a/dvbapi.h b/dvbapi.h index 01bb2dd92..aa4a5feb2 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.58 2001/11/04 11:39:42 kls Exp $ + * $Id: dvbapi.h 1.59 2001/11/24 11:03:16 kls Exp $ */ #ifndef __DVBAPI_H @@ -187,7 +187,7 @@ class cDvbApi { private: int currentChannel; public: - eSetChannelResult SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr); + eSetChannelResult SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr); static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } int Channel(void) { return currentChannel; } diff --git a/dvd.c b/dvd.c index 841e998b0..e061b1414 100644 --- a/dvd.c +++ b/dvd.c @@ -6,7 +6,7 @@ * * Initially written by Andreas Schultz <aschultz@warp10.net> * - * $Id: dvd.c 1.3 2001/08/06 16:07:44 kls Exp $ + * $Id: dvd.c 1.4 2001/11/10 13:38:50 kls Exp $ */ #ifdef DVDSUPPORT @@ -21,6 +21,7 @@ #include <unistd.h> #include "dvd.h" +#include "tools.h" // --- cDVD ---------------------------------------------------------------------------- @@ -145,4 +146,24 @@ dvd_file_t *cDVD::openTitle(int Title, dvd_read_domain_t domain) return title; } +int cDVD::getAudioTrack(int stream) +{ + if (getVTS()) { + switch (getVTS()->vtsi_mat->vts_audio_attr[stream].audio_format) { + case 0: // ac3 + return aAC3; + case 2: // mpeg1 + case 3: // mpeg2ext + return aMPEG; + case 4: // lpcm + return aLPCM; + case 6: // dts + return aDTS; + default: + esyslog(LOG_ERR, "ERROR: unknown Audio stream info"); + } + } + return 0; +} + #endif //DVDSUPPORT diff --git a/dvd.h b/dvd.h index 68fc1d38f..5ac145489 100644 --- a/dvd.h +++ b/dvd.h @@ -6,7 +6,7 @@ * * Initially written by Andreas Schultz <aschultz@warp10.net> * - * $Id: dvd.h 1.3 2001/08/05 16:00:57 kls Exp $ + * $Id: dvd.h 1.4 2001/11/10 13:38:25 kls Exp $ */ #ifndef __DVD_H @@ -21,6 +21,11 @@ #include <dvdread/nav_read.h> #include <dvdread/nav_print.h> +#define aAC3 0x80 +#define aDTS 0x88 +#define aLPCM 0xA0 +#define aMPEG 0xC0 + class cDVD { private: static cDVD *dvdInstance; @@ -44,8 +49,12 @@ class cDVD { bool isValid(void) { return (dvd != NULL); } ifo_handle_t *openVMG(void); ifo_handle_t *openVTS(int TitleSet); + ifo_handle_t *getVTS() { return vts_file; } dvd_file_t *openTitle(int Title, dvd_read_domain_t domain); static cDVD *getDVD(void); + int getAudioNrOfTracks() { return getVTS() ? getVTS()->vtsi_mat->nr_of_vts_audio_streams : 0; } + int getAudioLanguage(int stream) { return getVTS() ? getVTS()->vtsi_mat->vts_audio_attr[stream].lang_code : 0; } + int getAudioTrack(int stream); }; #endif //DVDSUPPORT diff --git a/menu.c b/menu.c index 154f66cfa..45899b1ac 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.139 2001/11/04 10:37:18 kls Exp $ + * $Id: menu.c 1.141 2001/11/24 13:20:37 kls Exp $ */ #include "menu.h" @@ -546,16 +546,16 @@ cMenuEditChannel::cMenuEditChannel(int Index) if (channel) { data = *channel; Add(new cMenuEditStrItem( tr("Name"), data.name, sizeof(data.name), FileNameChars)); - Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency, 10000, 13000)); //TODO exact limits??? + Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency)); Add(new cMenuEditChrItem( tr("Polarization"), &data.polarization, "hv")); Add(new cMenuEditIntItem( tr("DiSEqC"), &data.diseqc, 0, 10)); //TODO exact limits??? - Add(new cMenuEditIntItem( tr("Srate"), &data.srate, 22000, 30000)); //TODO exact limits - toggle??? - Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0xFFFE)); - Add(new cMenuEditIntItem( tr("Apid1"), &data.apid1, 0, 0xFFFE)); - Add(new cMenuEditIntItem( tr("Apid2"), &data.apid2, 0, 0xFFFE)); - Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0xFFFE)); - Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0xFFFE)); - Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0xFFFE)); + Add(new cMenuEditIntItem( tr("Srate"), &data.srate)); + Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Apid1"), &data.apid1, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Apid2"), &data.apid2, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("CA"), &data.ca, 0, cDvbApi::NumDvbApis)); Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0)); } From 27919ee969866b68fc95b327a047a9989e4b4153 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 27 Jan 2002 18:00:00 +0100 Subject: [PATCH 030/307] Version 0.99pre2 - Fixed setting the OSD size in the 'Confirm' interface call (thanks to Deti Fliegl). - Removed the 'read incomplete section...' error message in the EIT processor. - Fixed channel data for "DW TV" (thanks to Axel Gruber). - Added DPID to "PREMIERE MOVIE 1" in channels.conf.cable (thanks to Stephan Schreiber). - Prepared the OSD functions for multiple overlapping windows. - Removed the check to see whether the system time is running linearly. - Improved performance of SVDRP command entry. - Removed EPGBugfixLevel '3' - after more than a year Pro-7 finally managed to broadcast the correct timestamps for EPG events between 0:00 and 6:00! - Fixed failing watchdog timer if program hangs in OSD activities (thanks to Carsten Koch). - No longer requiring 'libncurses' if compiling without DEBUG_OSD=1 and REMOTE=KBD (thanks to Lauri Pesonen). - The "Recordings" menu now displays a hierarchical structure if there are subdirectories for the recordings. This can be controlled through the "RecordingDirs" parameter in the "Setup" menu. See "MANUAL/Replaying a Recording" for details. - Improved speed of setting the Help button texts. - Fixed handling file names that contain single quotes (') or dollar signs ($) in the call to the shutdown command (option '-s') and the recording command (option '-r'). - Improved error handling in the editing process; the resulting file will be deleted if an error occured. - A message is now prompted at the end of the editing process, indicating whether the process succeeded or failed. - Fixed setting the LastActivity timestamp after a shutdown prompt (thanks to Sergei Haller). - A message is now prompted if free disk space becomes low during recording. - The editing process now calls AssertFreeDiskSpace() to remove deleted recordings if the disk becomes full. - The "Main" menu now displays in its title the used disk space (in percent) and the estimated free disk space (in hh:mm), assuming a data rate of 30 MB per minute. - Activating the "Recordings" menu now displays "scanning recordings..." to give the user some feedback in case this takes longer. - Status messages are now displayed centered. - Removed the 'Tools' subdirectory from the VDR archive. All contributed tools can now be found at ftp://ftp.cadsoft.de/pub/people/kls/vdr/Tools. --- CONTRIBUTORS | 12 + HISTORY | 45 +- INSTALL | 2 +- MANUAL | 17 +- Makefile | 9 +- Tools/dvbrc2vdr/Makefile | 16 - Tools/dvbrc2vdr/channels.conf | 282 ---- Tools/dvbrc2vdr/dvbrc.hotbird | 63 - Tools/dvbrc2vdr/dvbrc2vdr.c | 183 --- Tools/dvbrc2vdr/hotbird2 | 878 ---------- Tools/dvbrc2vdr/test.conf | 799 ---------- Tools/epg2timers/README | 151 -- Tools/epg2timers/epg2timers.cxx | 656 -------- Tools/epg2timers/epg_channel_names | 400 ----- Tools/epg2timers/get_merkliste.pl | 82 - Tools/epg2timers/loadvdr.pl | 89 -- Tools/epg2timers/update_timers | 22 - Tools/epg2timers/update_timers.old | 24 - Tools/master-timer/LIESMICH | 70 - Tools/master-timer/README | 58 - Tools/master-timer/THANKS | 18 - Tools/master-timer/Todo | 6 - Tools/master-timer/convert-DTV2VDR.pl | 151 -- Tools/master-timer/convert-oldtorecord.pl | 61 - Tools/master-timer/master-timer.pl | 1412 ----------------- Tools/master-timer/process_summary.pl | 79 - Tools/master-timer/sample/channels-to-scan | 6 - Tools/master-timer/sample/config | 32 - .../master-timer/sample/convert-channel-list | 26 - Tools/master-timer/sample/deepblack | 172 -- Tools/master-timer/sample/done | 1 - Tools/master-timer/sample/subtitle-movie | 52 - Tools/master-timer/sample/torecord | 90 -- Tools/master-timer/scan-channels | 8 - Tools/schnitt/README | 111 -- Tools/schnitt/cut.pl | 35 - Tools/schnitt/cut2 | 2 - Tools/schnitt/cut2.pl | 39 - Tools/schnitt/cut3.pl | 40 - Tools/schnitt/cutall | 2 - Tools/schnitt/cutall2 | 5 - Tools/schnitt/cutall3.pl | 31 - Tools/schnitt/cutt | 106 -- Tools/schnitt/dump.c | 65 - Tools/schnitt/getpreviframe.pl | 25 - Tools/schnitt/index.php | 215 --- Tools/schnitt/lmplex | 51 - Tools/schnitt/mv2 | 30 - Tools/schnitt/play | 10 - Tools/schnitt/schnitt.pl | 27 - Tools/schnitt/schnitt2.pl | 93 -- Tools/schnitt/schnitt3.pl | 64 - Tools/schnitt/schnitt3.pl.new | 77 - Tools/schnitt/schnitt4.pl | 13 - Tools/schnitt/schnitt5.pl | 16 - Tools/schnitt/schnitt6.pl | 30 - Tools/schnitt/schnittcommon.pli | 64 - Tools/schnitt/show | 11 - Tools/schnitt/unsort | 25 - Tools/schnitt/vdr-remote.pl | 40 - Tools/schnitt/vdr2 | 2 - Tools/schnitt/vmount | 18 - Tools/statdvb2vdr/ch.pl | 250 --- Tools/xtvrc2vdr/Makefile | 16 - Tools/xtvrc2vdr/hotbird.conf | 191 --- Tools/xtvrc2vdr/xtvrc.hotbird | 1337 ---------------- Tools/xtvrc2vdr/xtvrc2vdr.c | 146 -- channels.conf | 4 +- channels.conf.cable | 2 +- config.c | 5 +- config.h | 5 +- dvbapi.c | 87 +- dvbapi.h | 6 +- dvbosd.c | 185 ++- dvbosd.h | 71 +- eit.c | 20 +- eit.h | 4 +- i18n.c | 70 +- interface.c | 26 +- menu.c | 208 ++- menu.h | 15 +- osd.c | 15 +- osd.h | 3 +- recording.c | 105 +- recording.h | 13 +- svdrp.c | 80 +- tools.c | 48 +- tools.h | 10 +- vdr.c | 22 +- videodir.c | 30 +- videodir.h | 7 +- 91 files changed, 875 insertions(+), 9325 deletions(-) delete mode 100644 Tools/dvbrc2vdr/Makefile delete mode 100644 Tools/dvbrc2vdr/channels.conf delete mode 100644 Tools/dvbrc2vdr/dvbrc.hotbird delete mode 100644 Tools/dvbrc2vdr/dvbrc2vdr.c delete mode 100644 Tools/dvbrc2vdr/hotbird2 delete mode 100644 Tools/dvbrc2vdr/test.conf delete mode 100644 Tools/epg2timers/README delete mode 100644 Tools/epg2timers/epg2timers.cxx delete mode 100644 Tools/epg2timers/epg_channel_names delete mode 100755 Tools/epg2timers/get_merkliste.pl delete mode 100755 Tools/epg2timers/loadvdr.pl delete mode 100755 Tools/epg2timers/update_timers delete mode 100755 Tools/epg2timers/update_timers.old delete mode 100644 Tools/master-timer/LIESMICH delete mode 100644 Tools/master-timer/README delete mode 100644 Tools/master-timer/THANKS delete mode 100644 Tools/master-timer/Todo delete mode 100755 Tools/master-timer/convert-DTV2VDR.pl delete mode 100755 Tools/master-timer/convert-oldtorecord.pl delete mode 100755 Tools/master-timer/master-timer.pl delete mode 100755 Tools/master-timer/process_summary.pl delete mode 100644 Tools/master-timer/sample/channels-to-scan delete mode 100644 Tools/master-timer/sample/config delete mode 100644 Tools/master-timer/sample/convert-channel-list delete mode 100644 Tools/master-timer/sample/deepblack delete mode 100644 Tools/master-timer/sample/done delete mode 100644 Tools/master-timer/sample/subtitle-movie delete mode 100644 Tools/master-timer/sample/torecord delete mode 100755 Tools/master-timer/scan-channels delete mode 100644 Tools/schnitt/README delete mode 100755 Tools/schnitt/cut.pl delete mode 100755 Tools/schnitt/cut2 delete mode 100755 Tools/schnitt/cut2.pl delete mode 100755 Tools/schnitt/cut3.pl delete mode 100755 Tools/schnitt/cutall delete mode 100755 Tools/schnitt/cutall2 delete mode 100755 Tools/schnitt/cutall3.pl delete mode 100755 Tools/schnitt/cutt delete mode 100644 Tools/schnitt/dump.c delete mode 100755 Tools/schnitt/getpreviframe.pl delete mode 100644 Tools/schnitt/index.php delete mode 100755 Tools/schnitt/lmplex delete mode 100755 Tools/schnitt/mv2 delete mode 100755 Tools/schnitt/play delete mode 100755 Tools/schnitt/schnitt.pl delete mode 100755 Tools/schnitt/schnitt2.pl delete mode 100755 Tools/schnitt/schnitt3.pl delete mode 100755 Tools/schnitt/schnitt3.pl.new delete mode 100755 Tools/schnitt/schnitt4.pl delete mode 100755 Tools/schnitt/schnitt5.pl delete mode 100755 Tools/schnitt/schnitt6.pl delete mode 100755 Tools/schnitt/schnittcommon.pli delete mode 100755 Tools/schnitt/show delete mode 100755 Tools/schnitt/unsort delete mode 100755 Tools/schnitt/vdr-remote.pl delete mode 100755 Tools/schnitt/vdr2 delete mode 100755 Tools/schnitt/vmount delete mode 100644 Tools/statdvb2vdr/ch.pl delete mode 100644 Tools/xtvrc2vdr/Makefile delete mode 100644 Tools/xtvrc2vdr/hotbird.conf delete mode 100644 Tools/xtvrc2vdr/xtvrc.hotbird delete mode 100644 Tools/xtvrc2vdr/xtvrc2vdr.c diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 12154c812..073e92719 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -8,6 +8,7 @@ Carsten Koch <Carsten.Koch@icem.de> for his idea of using multiple disks (and for testing this feature) for implementing the 'new recording' indicator for suggesting that the "Back" button in replay mode should bring up the "Recordings" menu + for fixing the watchdog timer if the program hangs in OSD activities Plamen Ganev <pganev@com-it.net> for fixing the frequency offset for Hotbird channels @@ -55,6 +56,7 @@ Alberto Carraro <bertocar@tin.it> Deti Fliegl <deti@fliegl.de> for implementing the 'CurrentChannel' setup parameter + for fixing setting the OSD size in the 'Confirm' interface call Dave Chapman <dave@dchapman.com> for implementing support for the teletext PID @@ -166,3 +168,13 @@ Norbert Schmidt <nschmidt-nrw@t-online.de> Thilo Wunderlich <tw@ubcom.net> for his help in keeping 'channels.conf' up to date + +Stephan Schreiber <stephan@sschreiber.de> + for his support in keeping the Premiere World channels up to date in 'channels.conf.cable' + +Lauri Pesonen <lauri.pesonen@firsthop.com> + for avoiding linking in 'libncurses' if compiling without DEBUG_OSD=1 and + REMOTE=KBD + +Sergei Haller <Sergei.Haller@math.uni-giessen.de> + for fixing the LastActivity timestamp after a shutdown prompt diff --git a/HISTORY b/HISTORY index 3f00cb1a9..7a57c9848 100644 --- a/HISTORY +++ b/HISTORY @@ -866,7 +866,7 @@ Video Disk Recorder Revision History - The device /dev/video is now opened only if necessary (to GRAB an image), allowing other programs (like 'kvdr', for instance) to use that device. -2001-11-25: Version 0.99 +2001-11-25: Version 0.99pre1 - Fixed several channel definitions in 'channels.conf' (thanks to Thilo Wunderlich). @@ -878,3 +878,46 @@ Video Disk Recorder Revision History - Changed the maximum value for PIDs in channels.conf from 0xFFFE to 0x1FFF. - Fixed DVD audio sync problems (thanks to Andreas Schultz). - Fixed external AC3 replay for DVDs (thanks to Andreas Schultz). + +2002-01-27: Version 0.99pre2 + +- Fixed setting the OSD size in the 'Confirm' interface call (thanks to + Deti Fliegl). +- Removed the 'read incomplete section...' error message in the EIT processor. +- Fixed channel data for "DW TV" (thanks to Axel Gruber). +- Added DPID to "PREMIERE MOVIE 1" in channels.conf.cable (thanks to Stephan + Schreiber). +- Prepared the OSD functions for multiple overlapping windows. +- Removed the check to see whether the system time is running linearly. +- Improved performance of SVDRP command entry. +- Removed EPGBugfixLevel '3' - after more than a year Pro-7 finally managed to + broadcast the correct timestamps for EPG events between 0:00 and 6:00! +- Fixed failing watchdog timer if program hangs in OSD activities (thanks to + Carsten Koch). +- No longer requiring 'libncurses' if compiling without DEBUG_OSD=1 and + REMOTE=KBD (thanks to Lauri Pesonen). +- The "Recordings" menu now displays a hierarchical structure if there are + subdirectories for the recordings. This can be controlled through the + "RecordingDirs" parameter in the "Setup" menu. + See "MANUAL/Replaying a Recording" for details. +- Improved speed of setting the Help button texts. +- Fixed handling file names that contain single quotes (') or dollar signs ($) + in the call to the shutdown command (option '-s') and the recording command + (option '-r'). +- Improved error handling in the editing process; the resulting file will be + deleted if an error occured. +- A message is now prompted at the end of the editing process, indicating + whether the process succeeded or failed. +- Fixed setting the LastActivity timestamp after a shutdown prompt (thanks to + Sergei Haller). +- A message is now prompted if free disk space becomes low during recording. +- The editing process now calls AssertFreeDiskSpace() to remove deleted + recordings if the disk becomes full. +- The "Main" menu now displays in its title the used disk space (in percent) + and the estimated free disk space (in hh:mm), assuming a data rate of 30 MB + per minute. +- Activating the "Recordings" menu now displays "scanning recordings..." to + give the user some feedback in case this takes longer. +- Status messages are now displayed centered. +- Removed the 'Tools' subdirectory from the VDR archive. All contributed tools + can now be found at ftp://ftp.cadsoft.de/pub/people/kls/vdr/Tools. diff --git a/INSTALL b/INSTALL index 0ab7edacb..d16509611 100644 --- a/INSTALL +++ b/INSTALL @@ -349,7 +349,7 @@ the "Frequency" is in kHz in case of DVB-T). You can even use a mixture of DVB-S, DVB-C and DVB-T cards in the same system. All you need to do is to put all the channel definitions into one big -'channel.conf' file and set the 'Ca' parameter of each channel to the number +'channels.conf' file and set the 'Ca' parameter of each channel to the number of the card that can receive it. Learning the remote control keys: diff --git a/MANUAL b/MANUAL index a9e42a1bf..99d91be94 100644 --- a/MANUAL +++ b/MANUAL @@ -159,6 +159,13 @@ Video Disk Recorder User's Manual 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. New recordings are marked with an '*'. + If the Setup parameter RecordingDirs has been set and there are recordings + from periodic timers organized in a subdirectory structure, only the + directory is displayed and it can be opened by pressing "Ok" (or the "Red" + button). A directory entry displays the total number of recordings within + that directory (and any possible subdirectory thereof) as well as the total + number of new recordings (as opposed to a recording's entry, which displays + the date and time of the recording). Playback can be stopped via the "Main" menu by selecting "Stop replaying", or by pressing the "Blue" button outside the menu. A previously stopped playback session can be resumed by pressing the "Blue" @@ -402,12 +409,7 @@ Video Disk Recorder User's Manual Extended Description) 2 = removal of excess whitespace and hyphens, mapping of wrongly used characters - 3 = fixing the date in timestamps between 00:00 and 06:00 - (use with care - hopefully one day Pro7 and Kabel1 - will learn how to read the clock/calender) - Default is '2', which will do all textual fixes, but - leaves out the timestamp fixes, since these might cause - recordings to fail. Use '3' at your own risk. + Default is '2'. Note that after changing the setting of this parameter any EPG data that has already been received will remain in its existing format - only newly received data will @@ -444,6 +446,9 @@ Video Disk Recorder User's Manual 0 = don't use the 'Subtitle' 1 = use it (and create subdirectories) + RecordingDirs = 1 Turns displaying the Recordings menu as a hierarchical + directory structure on or off. + VideoFormat = 0 The video format (or aspect ratio) of the tv set in use. 0 = 4:3 1 = 16:9 diff --git a/Makefile b/Makefile index 4efae4b12..38597e8d6 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.28 2001/10/07 15:14:50 kls Exp $ +# $Id: Makefile 1.29 2002/01/13 16:57:27 kls Exp $ .DELETE_ON_ERROR: @@ -37,12 +37,17 @@ ifndef REMOTE REMOTE = KBD endif +ifeq ($(REMOTE), KBD) +NCURSESLIB = -lncurses +endif + DEFINES += -DREMOTE_$(REMOTE) DEFINES += -D_GNU_SOURCE ifdef DEBUG_OSD DEFINES += -DDEBUG_OSD +NCURSESLIB = -lncurses endif ifdef VFAT @@ -71,7 +76,7 @@ include $(DEPFILE) # The main program: vdr: $(OBJS) $(AC3LIB) $(DTVLIB) - g++ -g -O2 $(OBJS) -lncurses -ljpeg -lpthread $(LIBDIRS) $(DVDLIB) $(AC3LIB) $(DTVLIB) -o vdr + g++ -g -O2 $(OBJS) $(NCURSESLIB) -ljpeg -lpthread $(LIBDIRS) $(DVDLIB) $(AC3LIB) $(DTVLIB) -o vdr # The font files: diff --git a/Tools/dvbrc2vdr/Makefile b/Tools/dvbrc2vdr/Makefile deleted file mode 100644 index 196f50bef..000000000 --- a/Tools/dvbrc2vdr/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# -# Makefile for dvbrc2vdr utility -# - -OBJS = dvbrc2vdr.o - -%.o: %.c - gcc -g -O2 -Wall -c $(DEFINES) $< - -all: dvbrc2vdr - -dvbrc2vdr: $(OBJS) - gcc -g -O2 $(OBJS) -o dvbrc2vdr - -clean: - -rm -f $(OBJS) dvbrc2vdr diff --git a/Tools/dvbrc2vdr/channels.conf b/Tools/dvbrc2vdr/channels.conf deleted file mode 100644 index d26699c1d..000000000 --- a/Tools/dvbrc2vdr/channels.conf +++ /dev/null @@ -1,282 +0,0 @@ -RAI Uno:11766:v:1:27500:160:80:0:0 -RAI Due:11766:v:1:27500:161:84:0:0 -RAI Tre:11766:v:1:27500:162:88:0:0 -Rete 4:11919:v:1:27500:514:670:0:0 -Canale 5:11919:v:1:27500:513:660:0:0 -Italia 1 :11919:v:1:27500:512:650:0:0 -Video Italia:12610:v:0:22000:121:122:0:0 -Grand Tour.:12670:v:0:22000:289:290:0:0 -AB Sat Passion promo:12266:h:0:27500:160:80:0:0 -Nuvolari Promo:12149:v:1:27500:176:177:0:0 -DigItaly:12673:v:1:27500:220:221:0:0 -NBC Europe:11054:h:1:27500:550:551:0:0 -Bloomberg TV UK:11642:h:1:27500:1560:1520:0:0 -Game Network:12673:v:1:27500:291:292:0:0 -Bulgaria TV:12540:h:1:27500:4612:4613:0:0 -Video Italia :12673:v:1:27500:340:341:0:0 -Racing Channel Test:11623:v:1:27500:223:243:0:0 -Fashion TV:12402:v:0:27500:163:92:0:0 -Palco Promo:12073:v:1:27500:161:84:0:0 -Coming Soon TV:12111:v:1:27500:310:311:0:0 -Alice:12149:v:1:27500:160:161:0:0 -RAI Mosaico:11766:v:1:27500:518:8191:0:0 -RAI SportSat:11804:v:1:27500:512:650:0:0 -Satisfaction TV:12092:h:1:27500:4192:4193:0:0 -RAI Nettuno Sat 2:11804:v:1:27500:513:651:0:0 -RAI Educational:11804:v:1:27500:514:652:0:0 -TelePace :11804:v:1:27500:515:653:0:0 -RAI News24:11804:v:1:27500:516:654:0:0 -AB Channel 1:12266:h:0:27500:161:84:0:0 -Studio Europa:12673:v:1:27500:230:231:0:0 -AB Passion:12692:h:1:27500:160:80:0:0 -Camera dei Deputati:11804:v:1:27500:517:655:0:0 -SAT 2000:11804:v:1:27500:518:656:0:0 -RAI NettunoSat 1:11804:v:1:27500:519:657:0:0 -Ante Prima:11881:v:1:27500:2435:2436:0:0 -Vetrina D+:12034:v:1:27500:166:105:0:0 -D+ Info:12073:v:1:27500:160:80:0:0 -SNAI:11881:v:1:27500:2561:2562:0:0 -RTL:12188:h:0:27500:163:104:0:0 -Sat.1:12480:v:0:27500:1791:1792:0:0 -Pro-7:12480:v:0:27500:255:256:0:0 -RTL2:12188:h:0:27500:166:128:0:0 -VOX:12188:h:0:27500:167:136:0:0 -ARD:11837:h:0:27500:101:102:0:0 -BR3:11837:h:0:27500:201:202:0:0 -INTV:11843:v:1:27500:2324:2325:0:0 -MC Sat Monte Carlo:12540:h:1:27500:5126:5122:0:0 -Hessen-3:11837:h:0:27500:301:302:0:0 -N3:11837:h:0:27500:401:402:0:0 -SR3:11837:h:0:27500:501:502:0:0 -WDR:11837:h:0:27500:601:602:0:0 -BR-alpha:11837:h:0:27500:701:702:0:0 -SWR BW:11837:h:0:27500:801:802:0:0 -Phoenix:11837:h:0:27500:901:902:0:0 -ZDF:11954:h:0:27500:110:120:0:0 -Test 3sat:11954:h:0:27500:210:220:0:0 -Kinderkanal:11954:h:0:27500:310:320:0:0 -arte:11954:h:0:27500:360:370:0:0 -Eurosport:11954:h:0:27500:410:420:0:0 -ZDF Infobox:11954:h:0:27500:610:620:0:0 -CNN:12168:v:0:27500:165:100:0:0 -Super RTL:12188:h:0:27500:165:120:0:0 -VOX:12188:h:0:27500:167:136:0:0 -ORF Sat:11954:h:0:27500:506:507:0:0 -DW TV:12363:v:0:27500:305:306:0:0 -Kabel 1:12480:v:0:27500:511:512:0:0 -TM3:12480:v:0:27500:767:768:0:0 -DSF:12480:v:0:27500:1023:1024:0:0 -HOT:12480:v:0:27500:1279:1280:0:0 -BloombergTV:12552:v:0:22000:162:99:0:0 -Sky News:12552:v:0:22000:305:306:0:0 -KinderNet:12574:h:0:22000:163:92:0:0 -Alice:12610:v:0:22000:162:96:0:0 -n-tv:12670:v:0:22000:162:96:0:0 -RAI Uno:12363:v:0:27500:289:290:0:0 -TW1:12692:h:0:22000:166:167:0:0 -Eins Extra:12722:h:0:22000:101:102:0:0 -Eins Festival:12722:h:0:22000:201:202:0:0 -Eins MuXx:12722:h:0:22000:301:302:0:0 -MDR:12722:h:0:22000:401:402:0:0 -ORB:12722:h:0:22000:501:502:0:0 -B1:12722:h:0:22000:601:602:0:0 -ARD Online-Kanal:12722:h:0:22000:8191:701:0:0 -Premiere World Promo:11798:h:0:27500:255:256:0:0 -Premiere:11798:h:0:27500:511:512:1:10 -Star Kino:11798:h:0:27500:767:768:1:9 -Cine Action:11798:h:0:27500:1023:1024:1:20 -Cine Comedy:11798:h:0:27500:1279:1280:1:29 -Sci Fantasy:11798:h:0:27500:1535:1536:1:41 -Romantic Movies:11798:h:0:27500:1791:1792:1:11 -Studio Universal:11798:h:0:27500:2047:2048:1:21 -TV Niepokalanow:11876:h:0:27500:305:321:0:0 -Mosaico:11934:v:0:27500:165:100:0:0 -Andalucia TV:11934:v:0:27500:166:104:0:0 -TVC Internacional:11934:v:0:27500:167:108:0:0 -Nasza TV:11992:h:0:27500:165:98:0:0 -WishLine test:12012:v:0:27500:163:92:0:0 -Pro 7 Austria:12051:v:0:27500:161:84:0:0 -Kabel 1 Schweiz:12051:v:0:27500:162:163:0:0 -Kabel 1 Austria:12051:v:0:27500:166:167:0:0 -Pro 7 Schweiz:12051:v:0:27500:289:290:0:0 -Kiosque:12129:v:0:27500:160:80:0:0 -KTO:12129:v:0:27500:170:120:0:0 -TCM:12168:v:0:27500:160:80:0:0 -Cartoon Network France & Spain:12168:v:0:27500:161:84:0:0 -TVBS Europe:12168:v:0:27500:162:88:0:0 -TVBS Europe:12168:v:0:27500:162:89:0:0 -Travel:12168:v:0:27500:163:92:0:0 -TCM Espania:12168:v:0:27500:164:96:0:0 -MTV Spain:12168:v:0:27500:167:112:0:0 -TCM France:12168:v:0:27500:169:64:0:0 -RTL2 CH:12188:h:0:27500:164:112:0:0 -La Cinquieme:12207:v:0:27500:160:80:0:0 -ARTE:12207:v:0:27500:165:100:0:0 -Post Filial TV:12226:h:0:27500:255:256:0:0 -Canal Canaris:12246:v:0:27500:160:80:0:0 -Canal Canaris:12246:v:0:27500:160:81:0:0 -Canal Canaris:12246:v:0:27500:160:82:0:0 -Canal Canaris:12246:v:0:27500:160:83:0:0 -Taquilla 0:12285:v:0:27500:165:100:0:0 -CSAT:12324:v:0:27500:160:80:0:0 -Mosaique:12324:v:0:27500:162:88:0:0 -Mosaique 2:12324:v:0:27500:163:92:0:0 -Mosaique 3:12324:v:0:27500:164:96:0:0 -Le Sesame C+:12324:v:0:27500:165:1965:0:0 -FEED:12344:h:0:27500:163:92:0:0 -RTM 1:12363:v:0:27500:162:96:0:0 -ESC 1:12363:v:0:27500:163:104:0:0 -TV5 Europe:12363:v:0:27500:164:112:0:0 -TV7 Tunisia:12363:v:0:27500:166:128:0:0 -ARTE:12363:v:0:27500:167:137:0:0 -RTP International:12363:v:0:27500:300:301:0:0 -VideoService:12422:h:0:27500:255:256:0:0 -Beta Research promo:12422:h:0:27500:1023:1024:0:0 -Canal Canarias:12441:v:0:27500:160:80:0:0 -TVC International:12441:v:0:27500:512:660:0:0 -Fitur:12441:v:0:27500:514:662:0:0 -Astra Info 1:12552:v:0:22000:164:112:0:0 -Astra Info 2:12552:v:0:22000:165:120:0:0 -Astra Vision 1:12552:v:0:22000:168:144:0:0 -Astra Vision 1:12552:v:0:22000:168:145:0:0 -Astra Vision 1:12552:v:0:22000:168:146:0:0 -Astra Vision 1:12552:v:0:22000:168:147:0:0 -Astra Vision 1:12552:v:0:22000:168:148:0:0 -Astra Vision 1:12552:v:0:22000:168:149:0:0 -Astra Vision 1:12552:v:0:22000:168:150:0:0 -RTL Tele Letzebuerg:12552:v:0:22000:168:144:0:0 -Astra Mosaic:12552:v:0:22000:175:176:0:0 -MHP test:12604:h:0:22000:5632:8191:0:0 -Bloomberg TV Spain:12610:v:0:22000:45:49:0:0 -AC 3 promo:12670:v:0:22000:308:256:0:0 -TV Polonia:10719:v:1:27500:163:92:0:0 -Credit Agricole:10834:v:1:27500:5321:5333:0:0 -La Chaine Parlementaire:10873:v:1:27500:1020:1030:0:0 -TMT:10892:v:1:27500:163:92:0:0 -Multivision Accueil:10911:v:1:27500:320:330:0:0 -RTL:11054:h:1:27500:160:80:0:0 -VOX:11054:h:1:27500:500:501:0:0 -Sat 1 A:11054:h:1:27500:511:512:0:0 -RTL II Austria:11054:h:1:27500:520:521:0:0 -ZDF:11054:h:1:27500:570:571:0:0 -K-TV:11054:h:1:27500:580:581:0:0 -Sat 1 Schweiz:11604:v:1:27500:101:102:0:0 -MKTV:11623:v:1:27500:222:242:0:0 -Olisat TV Promo:11623:v:1:27500:226:246:0:0 -Bloomberg TV Germany:11642:v:1:27500:1460:1420:0:0 -Bloomberg TV UK:11642:v:1:27500:1560:1520:0:0 -SAT 7:11642:v:1:27500:1660:1620:0:0 -Multivision 1:11662:v:1:27500:120:130:0:0 -Dubai EDTV:11746:v:1:27500:4130:4131:0:0 -Dubai Sport Channel:11746:v:1:27500:4386:4387:0:0 -Dubai Business Channel:11746:v:1:27500:4642:4643:0:0 -Dubai EDTV:11746:v:1:27500:4898:4899:0:0 -ERT Sat:11823:v:1:27500:521:740:0:0 -TVL:11843:v:1:27500:2441:2442:0:0 -Team TV :11881:v:1:27500:2305:2306:0:0 -ART Europe:12015:v:1:27500:164:96:0:0 -ESC 2:12015:v:1:27500:166:104:0:0 -ART Iqra:12015:v:1:27500:168:112:0:0 -Vacaciones TV:12092:v:1:27500:4112:4113:0:0 -TvL - TV Locale:12092:v:1:27500:4160:4161:0:0 -TVE Internacional:12092:v:1:27500:4208:4209:0:0 -TVG - TV de Galicia :12092:v:1:27500:4224:4225:0:0 -La Cadena Del Milagro:12092:v:1:27500:4368:4369:0:0 -Fiesta:12092:v:1:27500:4432:4433:0:0 -Visions Europe:12092:v:1:27500:4416:4417:0:0 -SateliTV/TV Sex Channel:12092:v:1:27500:4480:4481:0:0 -Krisma:12111:v:1:27500:200:201:0:0 -NTV:12111:v:1:27500:210:211:0:0 -Armenia TV 1:12111:v:1:27500:240:241:0:0 -SMAU Channel :12111:v:1:27500:260:261:0:0 -JSC - Al Jazeera Satellite Ch :12111:v:1:27500:270:271:0:0 -Il Tirreno Sat:12111:v:1:27500:280:301:0:0 -CCTV 4:12169:h:1:27500:516:690:0:0 -Kanali Vuolis:12169:v:1:27500:517:700:0:0 -Nova Promo:12169:v:1:27500:521:740:0:0 -ERT Sat :12188:v:1:27500:514:652:0:0 -Kanali Voulis:12188:v:1:27500:515:653:0:0 -OTE Promo:12188:v:1:27500:517:655:0:0 -TV 5 Europe:12245:v:1:27500:121:131:0:0 -Fashion TV:12245:h:1:27500:123:133:0:0 -TV Ajara:12245:v:1:27500:127:137:0:0 -Telekom TV:12265:v:1:27500:1460:1420:0:0 -SLO-TV1:12303:v:1:27500:200:201:0:0 -Polonia 1:12303:v:1:27500:205:206:0:0 -Super 1:12303:v:1:27500:207:208:0:0 -Sicilia Internacional:12303:v:1:27500:210:211:0:0 -SicilSat:12303:v:1:27500:225:226:0:0 -TBNE Italy:12303:v:1:27500:230:231:0:0 -Countdown TV:12303:v:1:27500:235:236:0:0 -Napoli International:12303:v:1:27500:240:241:0:0 -Magic TV:12303:v:1:27500:245:246:0:0 -TEST:12341:v:1:27500:165:108:0:0 -Colour Bars:12380:v:1:27500:3022:3032:0:0 -Tele 24 :12380:v:1:27500:3023:3033:0:0 -Abu Dhabi TV :12380:v:1:27500:3024:3034:0:0 -LCA:12380:v:1:27500:3025:3035:0:0 -RTV Montenegro:12380:v:1:27500:3026:3036:0:0 -SRG SSR Sat Access :12399:v:1:27500:165:98:0:0 -Jam-e-Jam Network 1 (IRIB 1):12437:v:1:27500:160:80:0:0 -Jam-e-Jam Network 2 (IRIB 2):12437:v:1:27500:161:82:0:0 -Sahar University Network:12437:v:1:27500:162:84:0:0 -Maharishi Open University:12476:v:1:27500:42:43:0:0 -Europe by Satellite:12476:h:1:27500:101:201:0:0 -Pink Backup:12476:v:1:27500:308:256:0:0 -Mizik Tropical:12476:h:1:27500:435:436:0:0 -TLI info card:12476:h:1:27500:771:768:0:0 -Liberty TV:12476:h:1:27500:941:942:0:0 -HRT TV 1:12520:v:1:27500:100:101:0:0 -HRT National:12520:v:1:27500:107:108:0:0 -BVN TV:12520:v:1:27500:210:211:0:0 -Sicilia International:12520:v:1:27500:501:502:0:0 -Sardegna Uno:12520:v:1:27500:503:504:0:0 -TGRT:12520:v:1:27500:505:506:0:0 -Euro Mediterraneo:12520:v:1:27500:510:511:0:0 -WWWTravel TV:12540:v:1:27500:1180:1183:0:0 -WWWTravel TV:12540:v:1:27500:1180:1184:0:0 -WWWTravel TV:12540:v:1:27500:1180:1185:0:0 -MBC:12597:v:1:27500:160:80:0:0 -SIMA-YEH-MOGHAVEMENT:12597:v:1:27500:161:84:0:0 -NITV (National Iran TV ):12597:v:1:27500:163:92:0:0 -BET International:12597:v:1:27500:167:108:0:0 -JSTV 2 Info Card:12597:v:1:27500:2011:2012:0:0 -EuroNews French:12597:v:1:27500:2221:2231:0:0 -EuroNews English:12597:v:1:27500:2221:2232:0:0 -EuroNews German:12597:v:1:27500:2221:2233:0:0 -EuroNews Italian:12597:v:1:27500:2221:2234:0:0 -EuroNews Spanish:12597:v:1:27500:2221:2235:0:0 -EuroNews Portuguese:12597:v:1:27500:2221:2236:0:0 -EuroNews English:12597:v:1:27500:2221:2237:0:0 -Canal Agro Rual:12597:v:1:27500:2321:2331:0:0 -MMO9:12616:v:1:27500:2561:2562:0:0 -Dubai Sport Channel:12654:v:1:27500:1060:1020:0:0 -Sharjah TV :12654:v:1:27500:1160:1120:0:0 -Qatar TV:12654:v:1:27500:1260:1220:0:0 -Saudi Channel 1 :12654:v:1:27500:1360:1320:0:0 -Kuwait Space Channel :12654:v:1:27500:1460:1420:0:0 -Libya TV:12654:v:1:27500:1560:1520:0:0 -Sudan TV:12654:v:1:27500:1660:1620:0:0 -Oman TV:12654:v:1:27500:1760:1720:0:0 -Jordan Satellite Channel:12654:v:1:27500:1860:1820:0:0 -Iraq Satellite Channel:12654:v:1:27500:1960:1920:0:0 -Thai TV 5 Global Network :12673:v:1:27500:200:201:0:0 -Telemarket:12673:v:1:27500:350:351:0:0 -Evision:12673:v:1:27500:360:361:0:0 -Onyx TV:12692:v:1:27500:161:84:0:0 -EWTN:10723:v:1:29900:1001:1201:0:0 -Test (Newslynx):10723:v:1:29900:1002:1202:0:0 -MTA International:10723:v:1:29900:1004:1204:0:0 -J TV Test:10992:v:1:27500:2436:2437:0:0 -Bloomberg UK Test Card:11242:v:1:27500:162:88:0:0 -Channel SUN TV:11604:h:1:27500:111:112:0:0 -Olisat TLC test card:11623:v:1:27500:225:245:0:0 -Channel SUN Test (KBT):11623:v:1:27500:229:249:0:0 -Rai way 3 test card:11766:v:1:27500:164:96:0:0 -Rai way 1 test card:11766:v:1:27500:515:653:0:0 -Rai way 2 test card:11766:v:1:27500:516:654:0:0 -Test (Local Satellite):12092:v:1:27500:4176:4177:0:0 -Retelsat Test:12092:v:1:27500:4464:4465:0:0 -AIT Test Card:12111:v:1:27500:220:221:0:0 -Fucino Test Card:12111:v:1:27500:230:231:0:0 -PGM1:12230:v:1:13396:1160:1121:0:0 diff --git a/Tools/dvbrc2vdr/dvbrc.hotbird b/Tools/dvbrc2vdr/dvbrc.hotbird deleted file mode 100644 index 8717fdbcc..000000000 --- a/Tools/dvbrc2vdr/dvbrc.hotbird +++ /dev/null @@ -1,63 +0,0 @@ -LNB ID 1 TYPE 1 LOF1 9750000 LOF2 10600000 SLOF 11800000 DISEQCNR 1 - SAT ID 1 NAME "Hotbird" LNBID 1 FMIN 12015000 FMAX 12100000 - TRANSPONDER ID 119c8 SATID 0001 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 - CHANNEL ID 0 NAME "T+ BIANCO" SATID ffffff TPID 119c8 SID 2b5d TYPE 1 VPID a0 APID 50 APID 51 TTPID 2c PCRPID a0 - CHANNEL ID 1 NAME "T+ NERO" SATID ffffff TPID 119c8 SID 2b5f TYPE 1 VPID a1 APID 54 APID 55 TTPID 2d PCRPID a1 - CHANNEL ID 2 NAME "T+ GRIGIO" SATID ffffff TPID 119c8 SID 2b61 TYPE 1 VPID a2 APID 58 APID 59 PCRPID a2 - CHANNEL ID 3 NAME "R4" SATID ffffff TPID 119c8 SID 18 TYPE 1 VPID a3 PCRPID a3 - CHANNEL ID 4 NAME "16:9 TELE+" SATID ffffff TPID 119c8 SID 2b63 TYPE 1 VPID a4 APID 60 APID 61 PCRPID a4 - CHANNEL ID 5 NAME "VETRINA D+" SATID ffffff TPID 119c8 SID 2b65 TYPE 1 PCRPID a5 - CHANNEL ID 6 NAME "R/RAGAZZI RAISAT" SATID ffffff TPID 119c8 SID 2b67 TYPE 1 PCRPID a6 - TRANSPONDER ID 11a90 SATID 0001 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 - CHANNEL ID 7 NAME "PALCO" SATID ffffff TPID 11a90 SID 2bc1 TYPE 1 PCRPID af - CHANNEL ID 8 NAME "INFO" SATID ffffff TPID 11a90 SID 2bc3 TYPE 1 VPID a1 PCRPID af - CHANNEL ID 9 NAME "P1" SATID ffffff TPID 11a90 SID 2bc5 TYPE 1 VPID a2 APID 58 APID 59 PCRPID af - CHANNEL ID a NAME "P2" SATID ffffff TPID 11a90 SID 2bc7 TYPE 1 VPID a3 APID 5c APID 5d PCRPID af - CHANNEL ID b NAME "P3" SATID ffffff TPID 11a90 SID 2bc9 TYPE 1 VPID a4 APID 60 APID 61 PCRPID af - CHANNEL ID c NAME "P4" SATID ffffff TPID 11a90 SID 2bcb TYPE 1 VPID a5 APID 64 APID 65 PCRPID af - CHANNEL ID d NAME "P5" SATID ffffff TPID 11a90 SID 2bcd TYPE 1 VPID a6 APID 68 APID 69 PCRPID af - CHANNEL ID e NAME "P6" SATID ffffff TPID 11a90 SID 2bcf TYPE 1 VPID a7 APID 6c APID 6d PCRPID af - TRANSPONDER ID 11964 SATID 0001 TYPE 1 FREQ 12015000 POL H SRATE 27500000 FEC 8 - CHANNEL ID f NAME "ART VARIETY" SATID ffffff TPID 11964 SID 19a TYPE 1 VPID a0 PCRPID a0 - CHANNEL ID 10 NAME "ART CHILDREN" SATID ffffff TPID 11964 SID 1a4 TYPE 1 VPID a1 PCRPID a1 - CHANNEL ID 11 NAME "ART MOVIES" SATID ffffff TPID 11964 SID 1ae TYPE 1 VPID a2 PCRPID a2 - CHANNEL ID 12 NAME "ART MUSIC" SATID ffffff TPID 11964 SID 1b8 TYPE 1 VPID a3 PCRPID a3 - CHANNEL ID 13 NAME "ART EUROPE" SATID ffffff TPID 11964 SID 1c2 TYPE 0 VPID a4 PCRPID a4 - CHANNEL ID 14 NAME "LBC EUROPE" SATID ffffff TPID 11964 SID 1cc TYPE 1 VPID a5 PCRPID a5 - CHANNEL ID 15 NAME "EGYPT SAT. CH. 2" SATID ffffff TPID 11964 SID 1d6 TYPE 1 VPID a6 PCRPID a6 - CHANNEL ID 16 NAME "ART SPORT" SATID ffffff TPID 11964 SID 1d8 TYPE 1 VPID a7 PCRPID a7 - CHANNEL ID 17 NAME "IQRA" SATID ffffff TPID 11964 SID 1da TYPE 1 VPID a8 PCRPID a8 - TRANSPONDER ID 11a2c SATID 0001 TYPE 1 FREQ 12341001 POL H SRATE 27500000 FEC 8 - CHANNEL ID ffffffff NAME "CNN" SATID ffffff TPID 11a2c SID 2ced TYPE 1 PCRPID af - CHANNEL ID ffffffff NAME "BBC" SATID ffffff TPID 11a2c SID 2cef TYPE 1 PCRPID af - CHANNEL ID ffffffff NAME "BLOOMBERG" SATID ffffff TPID 11a2c SID 2cf1 TYPE 1 PCRPID af - CHANNEL ID ffffffff NAME "CNBC" SATID ffffff TPID 11a2c SID 2cf3 TYPE 1 PCRPID af - CHANNEL ID ffffffff NAME "SKYNews" SATID ffffff TPID 11a2c SID 2cf5 TYPE 1 PCRPID af - CHANNEL ID ffffffff NAME "TST2" SATID ffffff TPID 11a2c SID 2cf7 TYPE 1 PCRPID af - CHANNEL ID ffffffff NAME "TV5" SATID ffffff TPID 11a2c SID 2cf9 TYPE 1 PCRPID af - CHANNEL ID ffffffff NAME "EPG" SATID ffffff TPID 11a2c SID 2cfb TYPE 1 PCRPID af - CHANNEL ID ffffffff NAME "CNN" SATID ffffff TPID 11a2c SID 2cfd TYPE 1 VPID a0 APID 50 PCRPID af - CHANNEL ID ffffffff NAME "CNBC" SATID ffffff TPID 11a2c SID 2cff TYPE 1 VPID a3 APID 5c PCRPID af - CHANNEL ID ffffffff NAME "TV5" SATID ffffff TPID 11a2c SID 2d01 TYPE 1 VPID a6 APID 68 PCRPID af - CHANNEL ID ffffffff NAME "BBC WORLD" SATID ffffff TPID 11a2c SID 2d03 TYPE 1 VPID a1 APID 54 PCRPID af - CHANNEL ID ffffffff SATID ffffff TPID 11a2c SID 2d4b TYPE 0 PCRPID 1ffe - CHANNEL ID ffffffff SATID ffffff TPID 11a2c SID 26fc TYPE 0 PCRPID 1ffe - CHANNEL ID ffffffff SATID ffffff TPID 11a2c SID 26fd TYPE 0 PCRPID 1ffe - TRANSPONDER ID 11af4 SATID 0001 TYPE 1 FREQ 12091901 POL H SRATE 27500000 FEC 8 - CHANNEL ID 27 NAME "Bolsa" SATID ffffff TPID 11af4 SID 222e TYPE 0 - CHANNEL ID 28 NAME "Testw" SATID ffffff TPID 11af4 SID 222f TYPE 0 - CHANNEL ID 29 NAME "SIRE" SATID ffffff TPID 11af4 SID 2230 TYPE 0 PCRPID 102 - CHANNEL ID 2a NAME "Telesierra" SATID ffffff TPID 11af4 SID 2200 TYPE 0 VPID 1040 APID 1041 PCRPID 1040 - CHANNEL ID 2b NAME "vtv" SATID ffffff TPID 11af4 SID 21fd TYPE 0 VPID 1010 APID 1012 APID 1011 APID 1013 PCRPID 1010 - CHANNEL ID 2c NAME "Satisfaction" SATID ffffff TPID 11af4 SID 2202 TYPE 0 VPID 1060 APID 1061 PCRPID 1060 - CHANNEL ID 2d NAME "C. Milagro" SATID ffffff TPID 11af4 SID 2207 TYPE 0 VPID 1110 APID 1111 PCRPID 1110 - CHANNEL ID 2e NAME "Fiesta" SATID ffffff TPID 11af4 SID 2210 TYPE 0 VPID 1150 APID 1151 APID 1152 PCRPID 1150 - CHANNEL ID 2f NAME "TVE Internacional" SATID ffffff TPID 11af4 SID 2203 TYPE 0 VPID 1070 APID 1071 PCRPID 1070 - CHANNEL ID 30 NAME "TV Galicia" SATID ffffff TPID 11af4 SID 2204 TYPE 0 APID 1090 PCRPID 1090 - CHANNEL ID 31 NAME "Radio Gallega" SATID ffffff TPID 11af4 SID 2205 TYPE 0 APID 1090 PCRPID 1090 - CHANNEL ID 32 NAME "Retelsat" SATID ffffff TPID 11af4 SID 2212 TYPE 1 VPID 1170 APID 1171 PCRPID 1170 - CHANNEL ID 33 NAME "Musicam 1" SATID ffffff TPID 11af4 SID 2209 TYPE 1 APID 1136 PCRPID 1136 - CHANNEL ID 34 NAME "Musicam 2" SATID ffffff TPID 11af4 SID 220a TYPE 1 APID 1131 PCRPID 1131 - CHANNEL ID 35 NAME "Musicam 3" SATID ffffff TPID 11af4 SID 220b TYPE 1 APID 1136 PCRPID 1136 - CHANNEL ID 36 NAME "Musicam 4" SATID ffffff TPID 11af4 SID 220c TYPE 1 APID 1136 PCRPID 1136 - CHANNEL ID 37 NAME "Musicam 5" SATID ffffff TPID 11af4 SID 220d TYPE 1 APID 1136 PCRPID 1136 diff --git a/Tools/dvbrc2vdr/dvbrc2vdr.c b/Tools/dvbrc2vdr/dvbrc2vdr.c deleted file mode 100644 index 243ddc02d..000000000 --- a/Tools/dvbrc2vdr/dvbrc2vdr.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * * dvbrc2vdr.c: Converts 'xtvrc' files to 'vdr' channel format - * * - * * Copyright (C) 2000 Plamen Ganev - * * - * * This program is free software; you can redistribute it and/or - * * modify it under the terms of the GNU General Public License - * * as published by the Free Software Foundation; either version 2 - * * of the License, or (at your option) any later version. - * * - * * This program is distributed in the hope that it will be useful, - * * but WITHOUT ANY WARRANTY; without even the implied warranty of - * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * * GNU General Public License for more details. - * * - * * You should have received a copy of the GNU General Public License - * * along with this program; if not, write to the Free Software - * * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * * - * * The author can be reached at pganev@comm.it - * * - * */ - - -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <stdlib.h> - -#define MAX_LINE_LEN 1024 -#define MAX_NAME 100 -#define TOKS ": \n\r" -#define NAMETOKS ":\n\r" - -typedef struct { - char Name[MAX_NAME+1]; - int freq; - int color, hue, bright, saturation ; - int nitv, input ; - int pol, srate, fec, vpid, apid, lnbnum, type; - int sid, pcrpid ; -} CHANNEL_DATA ; - -void strupr( char *s ){ - while ( s && *s ){ - *s = toupper(*s); - s++; - } -} - -/* Warning: This function uses the last strtol string! */ -int GetTpInfo( CHANNEL_DATA *channel ) -{ - // s is: ID x SATID x TYPE x FREQ x POL H/V SRATE x FEC x - char *p ; - - p = strtok( NULL, TOKS ) ; /* Skip ID */ - p = strtok( NULL, TOKS ) ; /* Skip x */ - p = strtok( NULL, TOKS ) ; /* Skip SatId */ - p = strtok( NULL, TOKS ) ; /* Skip x */ - p = strtok( NULL, TOKS ) ; /* Skip Type */ - p = strtok( NULL, TOKS ) ; /* Skip x */ - p = strtok( NULL, TOKS ) ; /* Skip Freq */ - p = strtok( NULL, TOKS ) ; /* Get Freq */ - channel->freq = atol( p ) / 1000 ; - p = strtok( NULL, TOKS ) ; /* Skip Pol */ - p = strtok( NULL, TOKS ) ; /* Get H/V */ - channel->pol = (*p=='V') ? 1 : 0 ; - p = strtok( NULL, TOKS ) ; /* Skip SRATE */ - p = strtok( NULL, TOKS ) ; /* Get srate */ - channel->srate = atol(p) / 1000 ; /* Convert SRATE */ - return 0; -} - -/* Warning: This function uses the last strtol string! */ -int GetChInfo( CHANNEL_DATA *channel ) -{ - /* s is: ID x NAME "name" SATID x TPID x SID x TYPE x VPID x APID x */ - char *p, *q ; - - p = strtok( NULL, TOKS ) ; - while ( p ) { - if ( !strcmp( p, "ID" )) { - p = strtok( NULL, TOKS ) ; - } else if ( !strcmp( p, "NAME")) { - while ( *p++ ); /* Jump to end of "NAME" */ - p++ ; /* One More */ - while ( *p == '"' ) p++ ; /* Skip the " */ - q = channel->Name ; - while ( *p != '"' ) - if ( *p == ':' ) - *q++ = '|', p++ ; - else - *q++ = *p++ ; /* Copy the name */ - *q = 0 ; - p++ ; - p = strtok( p, TOKS ) ; - channel->apid = 8190; - channel->vpid = 8190; - channel->pcrpid = 0 ; - channel->sid = 0; - } else if ( !strcmp( p, "VPID")) { - p = strtok( NULL, TOKS ) ; - channel->vpid = strtol( p, NULL, 16 ) ; - p = strtok( NULL, TOKS ) ; - } else if ( !strcmp( p, "APID")) { - p = strtok( NULL, TOKS ) ; - channel->apid = strtol( p, NULL, 16 ) ; - p = strtok( NULL, TOKS ) ; - } else if ( !strcmp( p, "SID")) { - p = strtok( NULL, TOKS ) ; - channel->sid = strtol( p, NULL, 16 ) ; - p = strtok( NULL, TOKS ) ; - } else if ( !strcmp( p, "PCRPID")) { - p = strtok( NULL, TOKS ) ; - channel->pcrpid = strtol( p, NULL, 16 ) ; - p = strtok( NULL, TOKS ) ; - } else { - p = strtok( NULL, TOKS ) ; - } - } - return 1; -} - -int ReadChannel( FILE *f, CHANNEL_DATA *channel ) { - static char s[MAX_LINE_LEN+1]; - char *p; - - while (fgets( s, MAX_LINE_LEN, f )){ - p = strtok( s, TOKS ) ; - strupr( p ) ; - - if ( !strcmp( p, "TRANSPONDER" )){ - GetTpInfo( channel ) ; - } else if ( !strcmp( p, "CHANNEL" ) ) { - GetChInfo( channel ) ; - return 1 ; - } - } - return 0 ; -} - -int main ( int argc, char *argv[] ){ - FILE *f, *fo ; - int cnt = 0; - CHANNEL_DATA channel ; - - if ( argc != 3 ){ - printf("USAGE: %s <dvbrc file> <vdr file>\n\n", argv[0] ) ; - return 0; - } - - if ( !(f=fopen(argv[1], "rt"))){ - printf("Can't open %s for reading\n\n", argv[1]); - return 0; - } - - if ( !(fo=fopen(argv[2], "wt"))){ - printf("Can't open %s for writing\n\n", argv[2]); - return 0; - } - - while ( ReadChannel( f, &channel ) ) { - cnt++; - fprintf(fo, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", - channel.Name , - channel.freq , - channel.pol ? 'v' : 'h' , - 1, //channel.lnbnum , - channel.srate , - channel.vpid , - channel.apid , - 0, //channel.type , - channel.sid ) ; - } - - printf( "%d channels read.\n\n", cnt ) ; - - fclose(f); - fclose(fo); - return 1; -} diff --git a/Tools/dvbrc2vdr/hotbird2 b/Tools/dvbrc2vdr/hotbird2 deleted file mode 100644 index 39c7b8779..000000000 --- a/Tools/dvbrc2vdr/hotbird2 +++ /dev/null @@ -1,878 +0,0 @@ -LNB ID 0 TYPE 1 LOF1 9750000 LOF2 10600000 SLOF 11800000 DISEQCNR 0 - SAT ID 0 NAME "HotBird" LNBID 0 FMIN 10700000 FMAX 12800000 - TRANSPONDER ID 2af8 SATID 0000 TYPE 1 FREQ 10719000 POL V SRATE 27500000 FEC 8 - CHANNEL ID 0 NAME "DISCOVERY" SATID ffffff TPID 2af8 SID 1132 TYPE 1 PCRPID a1 - CHANNEL ID 1 NAME "RTL7" SATID ffffff TPID 2af8 SID 1133 TYPE 1 PCRPID a2 - CHANNEL ID 2 NAME "TV POLONIA" SATID ffffff TPID 2af8 SID 1134 TYPE 1 PCRPID a3 - CHANNEL ID 3 NAME "EUROSPORT" SATID ffffff TPID 2af8 SID 1135 TYPE 1 PCRPID a4 - CHANNEL ID 4 NAME "PLANETE" SATID ffffff TPID 2af8 SID 1136 TYPE 1 PCRPID a5 - CHANNEL ID 5 NAME "SEASONS" SATID ffffff TPID 2af8 SID 1137 TYPE 1 PCRPID a6 - CHANNEL ID 6 NAME "VIVA Polska" SATID ffffff TPID 2af8 SID 1138 TYPE 1 PCRPID a7 - CHANNEL ID 7 NAME "MULTIMUSIC 4" SATID ffffff TPID 2af8 SID 1158 TYPE 1 APID 79 APID 7a APID 7b PCRPID 79 - CHANNEL ID 8 NAME "EPG" SATID ffffff TPID 2af8 SID 1162 TYPE 1 PCRPID a1 - CHANNEL ID 9 NAME "CYFRA+ GRY" SATID ffffff TPID 2af8 SID 116c TYPE 1 - TRANSPONDER ID 0101 SATID 0000 TYPE 1 FREQ 10722000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 2bc0 SATID 0000 TYPE 1 FREQ 0 POL V SRATE 27500000 FEC 8 - CHANNEL ID a NAME "Guide LC" SATID ffffff TPID 2bc0 SID 7d0 TYPE 0 APID 1f5e PCRPID 1f5e - CHANNEL ID b NAME "Cinestar 1" SATID ffffff TPID 2bc0 SID 4b1 TYPE 1 VPID 78 APID 82 PCRPID 78 - CHANNEL ID c NAME "Cinestar 2" SATID ffffff TPID 2bc0 SID 4b2 TYPE 1 VPID dc APID e6 PCRPID dc - CHANNEL ID d NAME "Cinetoile" SATID ffffff TPID 2bc0 SID 4b3 TYPE 1 VPID 140 APID 14a PCRPID 140 - CHANNEL ID e NAME "Shopping Avenue" SATID ffffff TPID 2bc0 SID 4b4 TYPE 1 VPID 1a4 APID 1ae PCRPID 1a4 - CHANNEL ID f NAME "Srie Club " SATID ffffff TPID 2bc0 SID 4b5 TYPE 1 VPID 208 APID 212 PCRPID 208 - CHANNEL ID 10 NAME "FUN TV" SATID ffffff TPID 2bc0 SID 4b6 TYPE 1 VPID 26c APID 276 PCRPID 26c - CHANNEL ID 11 NAME "Teva" SATID ffffff TPID 2bc0 SID 4b7 TYPE 1 VPID 2d0 APID 2da PCRPID 2d0 - CHANNEL ID 12 NAME "M6 Music" SATID ffffff TPID 2bc0 SID 4b8 TYPE 1 VPID 334 APID 33e PCRPID 334 - CHANNEL ID 13 NAME "Club Tlachat" SATID ffffff TPID 2bc0 SID 4b9 TYPE 1 VPID 398 APID 3a2 PCRPID 398 - TRANSPONDER ID 0103 SATID 0000 TYPE 1 FREQ 10775000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 2c88 SATID 0000 TYPE 1 FREQ 0 POL V SRATE 27500000 FEC 8 - CHANNEL ID 14 NAME "INFOSPORT" SATID ffffff TPID 2c88 SID 579 TYPE 1 VPID 78 APID 82 PCRPID 78 - CHANNEL ID 15 NAME "Rgions" SATID ffffff TPID 2c88 SID 57a TYPE 1 VPID dc APID e6 PCRPID dc - CHANNEL ID 16 NAME "Mezzo" SATID ffffff TPID 2c88 SID 57b TYPE 1 VPID 140 APID 14a PCRPID 140 - CHANNEL ID 17 NAME "01 01 15 97" SATID ffffff TPID 2c88 SID 5cb TYPE 0 - CHANNEL ID 18 NAME "01 01 17 97" SATID ffffff TPID 2c88 SID 5cd TYPE 0 - CHANNEL ID 19 NAME "01 02 17 97" SATID ffffff TPID 2c88 SID 5ce TYPE 0 - CHANNEL ID 1a NAME "01 02 15 97" SATID ffffff TPID 2c88 SID 5d0 TYPE 0 - CHANNEL ID 1b NAME "01 02 15 96" SATID ffffff TPID 2c88 SID 5d1 TYPE 0 - CHANNEL ID 1c NAME "01 03 17 10" SATID ffffff TPID 2c88 SID 5d2 TYPE 0 - CHANNEL ID 1d NAME "01 03 15 10" SATID ffffff TPID 2c88 SID 5d3 TYPE 0 - CHANNEL ID 1e NAME "Festival" SATID ffffff TPID 2c88 SID 57c TYPE 1 VPID 1a4 APID 1ae PCRPID 1a4 - CHANNEL ID 1f NAME "HISTOIRE " SATID ffffff TPID 2c88 SID 57d TYPE 1 VPID 208 APID 212 PCRPID 208 - CHANNEL ID 20 NAME "Tltoon" SATID ffffff TPID 2c88 SID 57e TYPE 1 VPID 26c APID 276 PCRPID 26c - CHANNEL ID 21 NAME "Odysse " SATID ffffff TPID 2c88 SID 57f TYPE 1 VPID 2d0 APID 2da PCRPID 2d0 - CHANNEL ID 22 NAME "France Musiques" SATID ffffff TPID 2c88 SID 58a TYPE 0 APID 33e PCRPID 33e - CHANNEL ID 23 NAME "Hector" SATID ffffff TPID 2c88 SID 58b TYPE 0 APID 33f PCRPID 33f - CHANNEL ID 24 NAME "FIP" SATID ffffff TPID 2c88 SID 58c TYPE 0 APID 340 PCRPID 340 - CHANNEL ID 25 NAME "France Inter" SATID ffffff TPID 2c88 SID 58d TYPE 0 APID 341 PCRPID 341 - CHANNEL ID 26 NAME "France Info" SATID ffffff TPID 2c88 SID 58e TYPE 0 APID 342 PCRPID 342 - CHANNEL ID 27 NAME "Elisa" SATID ffffff TPID 2c88 SID 58f TYPE 0 APID 343 PCRPID 343 - CHANNEL ID 28 NAME "France Culture" SATID ffffff TPID 2c88 SID 590 TYPE 0 APID 344 PCRPID 344 - CHANNEL ID 29 NAME "Radio Bleue" SATID ffffff TPID 2c88 SID 591 TYPE 0 APID 345 PCRPID 345 - CHANNEL ID 2a NAME "Le Mouv" SATID ffffff TPID 2c88 SID 592 TYPE 0 APID 346 PCRPID 346 - CHANNEL ID 2b NAME "TV5" SATID ffffff TPID 2c88 SID 581 TYPE 1 VPID 398 APID 3a2 PCRPID 398 - TRANSPONDER ID 2d50 SATID 0000 TYPE 1 FREQ 0 POL V SRATE 27500000 FEC 8 - CHANNEL ID 2c NAME "CENTRONICS" SATID ffffff TPID 2d50 SID 7d0 TYPE 0 - CHANNEL ID 2d NAME "FRANCE 2 " SATID ffffff TPID 2d50 SID 450 TYPE 1 VPID 140 PCRPID 140 - CHANNEL ID 2e NAME "FRANCE 3" SATID ffffff TPID 2d50 SID 452 TYPE 1 VPID 208 PCRPID 208 - CHANNEL ID 2f NAME "Crdit Agricole" SATID ffffff TPID 2d50 SID 14b5 TYPE 0 APID 14d5 PCRPID 14c9 - CHANNEL ID 30 NAME "tps foot" SATID ffffff TPID 2d50 SID 1450 TYPE 0 APID 146e PCRPID 146e - CHANNEL ID 31 NAME "LCI" SATID ffffff TPID 2d50 SID 44d TYPE 1 VPID 78 APID 82 PCRPID 78 - CHANNEL ID 32 NAME "EUROSPORT" SATID ffffff TPID 2d50 SID 44e TYPE 1 VPID dc APID e6 PCRPID dc - CHANNEL ID 33 NAME "FRANCE 2" SATID ffffff TPID 2d50 SID 44f TYPE 1 VPID 140 PCRPID 140 - CHANNEL ID 34 NAME "FRANCE 3" SATID ffffff TPID 2d50 SID 451 TYPE 1 VPID 208 PCRPID 208 - CHANNEL ID 35 NAME "I TELEVISION" SATID ffffff TPID 2d50 SID 454 TYPE 1 VPID 334 APID 33e PCRPID 334 - CHANNEL ID 36 NAME "TV Mail alphatest" SATID ffffff TPID 2d50 SID 1645 TYPE 0 - CHANNEL ID 37 NAME "CHAINE FI" SATID ffffff TPID 2d50 SID 14b4 TYPE 0 APID 14d2 APID 14d3 PCRPID 14d2 - CHANNEL ID 38 NAME "caisse d'pargne" SATID ffffff TPID 2d50 SID 14b7 TYPE 0 - CHANNEL ID 39 NAME "TV Mail" SATID ffffff TPID 2d50 SID 1644 TYPE 0 - TRANSPONDER ID 2e7c SATID 0000 TYPE 1 FREQ 10892000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 3a NAME "CANAL+" SATID ffffff TPID 2e7c SID 12c1 TYPE 1 PCRPID a0 - CHANNEL ID 3b NAME "CANAL+ ӣTY" SATID ffffff TPID 2e7c SID 12c2 TYPE 1 PCRPID a1 - CHANNEL ID 3c NAME "TMT" SATID ffffff TPID 2e7c SID 12c4 TYPE 1 PCRPID a3 - CHANNEL ID 3d NAME "ALE KINO!" SATID ffffff TPID 2e7c SID 12c5 TYPE 1 PCRPID a4 - CHANNEL ID 3e NAME "MINIMAX" SATID ffffff TPID 2e7c SID 12c6 TYPE 1 PCRPID a5 - CHANNEL ID 3f NAME "TVP 1" SATID ffffff TPID 2e7c SID 12c7 TYPE 1 PCRPID a6 - CHANNEL ID 40 NAME "TVP 2" SATID ffffff TPID 2e7c SID 12c8 TYPE 1 PCRPID a7 - CHANNEL ID 41 NAME "CANAL+ NIEBIESKI" SATID ffffff TPID 2e7c SID 12c9 TYPE 1 PCRPID a8 - CHANNEL ID 42 NAME "EPG" SATID ffffff TPID 2e7c SID 12f2 TYPE 1 TTPID 1f4 PCRPID a0 - TRANSPONDER ID 2ee0 SATID 0000 TYPE 1 FREQ 0 POL V SRATE 27500000 FEC 8 - CHANNEL ID 43 NAME "Multivision" SATID ffffff TPID 2ee0 SID 643 TYPE 0 VPID 140 PCRPID 140 - CHANNEL ID 44 NAME "Grand Classique" SATID ffffff TPID 2ee0 SID 672 TYPE 1 APID 33e PCRPID 33e - CHANNEL ID 45 NAME "Symphonies" SATID ffffff TPID 2ee0 SID 673 TYPE 1 APID 33f PCRPID 33f - CHANNEL ID 46 NAME "Baroque" SATID ffffff TPID 2ee0 SID 674 TYPE 1 APID 340 PCRPID 340 - CHANNEL ID 47 NAME "Opra" SATID ffffff TPID 2ee0 SID 675 TYPE 1 APID 341 PCRPID 341 - CHANNEL ID 48 NAME "Contemporain" SATID ffffff TPID 2ee0 SID 676 TYPE 1 APID 342 PCRPID 342 - CHANNEL ID 49 NAME "Relaxation" SATID ffffff TPID 2ee0 SID 677 TYPE 1 APID 343 PCRPID 343 - CHANNEL ID 4a NAME "Blues" SATID ffffff TPID 2ee0 SID 678 TYPE 1 APID 344 PCRPID 344 - CHANNEL ID 4b NAME "Jazz" SATID ffffff TPID 2ee0 SID 679 TYPE 1 APID 345 PCRPID 345 - CHANNEL ID 4c NAME "Big Band" SATID ffffff TPID 2ee0 SID 67a TYPE 1 APID 346 PCRPID 346 - CHANNEL ID 4d NAME "Jazz Moderne" SATID ffffff TPID 2ee0 SID 67b TYPE 1 APID 347 PCRPID 347 - CHANNEL ID 4e NAME "Les Tubes Franais" SATID ffffff TPID 2ee0 SID 67c TYPE 1 APID 348 PCRPID 348 - CHANNEL ID 4f NAME "RFO SAT" SATID ffffff TPID 2ee0 SID 641 TYPE 0 VPID 78 APID 82 PCRPID 78 - CHANNEL ID 50 NAME "Appli D1 LC" SATID ffffff TPID 2ee0 SID 690 TYPE 0 - CHANNEL ID 51 NAME "Cinefaz" SATID ffffff TPID 2ee0 SID 642 TYPE 1 VPID dc APID e6 PCRPID dc - CHANNEL ID 52 NAME "TurboPC" SATID ffffff TPID 2ee0 SID af1 TYPE 0 - CHANNEL ID 53 NAME "MTV2" SATID ffffff TPID 2ee0 SID 647 TYPE 1 VPID 2d0 APID 2da PCRPID 2d0 - CHANNEL ID 54 NAME "Rire et chansons" SATID ffffff TPID 2ee0 SID 65e TYPE 0 APID 3a2 PCRPID 3a2 - CHANNEL ID 55 NAME "Radio J" SATID ffffff TPID 2ee0 SID 65f TYPE 1 APID 3a3 PCRPID 3a3 - CHANNEL ID 56 NAME "Mosqueteiros" SATID ffffff TPID 2ee0 SID 660 TYPE 0 APID 3a4 PCRPID 3a4 - CHANNEL ID 57 NAME "Abysse" SATID ffffff TPID 2ee0 SID 661 TYPE 1 APID 3a5 PCRPID 3a5 - CHANNEL ID 58 NAME "RMC" SATID ffffff TPID 2ee0 SID 663 TYPE 1 APID 3a7 PCRPID 3a7 - CHANNEL ID 59 NAME "Radio Junior" SATID ffffff TPID 2ee0 SID 664 TYPE 0 APID 3a8 PCRPID 3a8 - CHANNEL ID 5a NAME "NETRADIO" SATID ffffff TPID 2ee0 SID 665 TYPE 0 APID 3a9 PCRPID 3a9 - CHANNEL ID 5b NAME "Nostalgie" SATID ffffff TPID 2ee0 SID 666 TYPE 0 APID 3aa PCRPID 3aa - CHANNEL ID 5c NAME "Skyrock" SATID ffffff TPID 2ee0 SID 667 TYPE 1 APID 3ab PCRPID 3ab - CHANNEL ID 5d NAME "Radio Coutoisie" SATID ffffff TPID 2ee0 SID 668 TYPE 0 APID 3ac PCRPID 3ac - CHANNEL ID 5e NAME "La Voix des Pays" SATID ffffff TPID 2ee0 SID 669 TYPE 0 APID 3ad PCRPID 3ad - CHANNEL ID 5f NAME "INFO EXPRESS" SATID ffffff TPID 2ee0 SID 157c TYPE 0 APID 159a PCRPID 159a - CHANNEL ID 60 NAME "METEO" SATID ffffff TPID 2ee0 SID 16a8 TYPE 0 APID 16c6 PCRPID 16c6 - CHANNEL ID 61 NAME "X X L" SATID ffffff TPID 2ee0 SID 1518 TYPE 1 - CHANNEL ID 62 NAME "Multivision Cinma" SATID ffffff TPID 2ee0 SID 1c20 TYPE 0 - CHANNEL ID 63 NAME "Multivision Sport" SATID ffffff TPID 2ee0 SID 1c84 TYPE 0 TTPID 18fb - CHANNEL ID 64 NAME "Multivision Spectacle" SATID ffffff TPID 2ee0 SID 1ce8 TYPE 0 - TRANSPONDER ID 2f44 SATID 0000 TYPE 1 FREQ 12673000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 65 NAME "Test OTV8" SATID ffffff TPID 2f44 SID 1d67 TYPE 1 PCRPID e80 - CHANNEL ID 66 NAME "Test OTV9" SATID ffffff TPID 2f44 SID 1d68 TYPE 1 PCRPID e80 - CHANNEL ID 67 NAME "Test OTV10" SATID ffffff TPID 2f44 SID 1d69 TYPE 1 PCRPID e80 - CHANNEL ID 68 NAME "Test OTV11" SATID ffffff TPID 2f44 SID 1d6a TYPE 1 VPID 201 PCRPID 1ffe - CHANNEL ID 69 NAME "Test31" SATID ffffff TPID 2f44 SID 1d4d TYPE 1 VPID 200 APID 28a PCRPID 1ffe - CHANNEL ID 6a NAME "CNN" SATID ffffff TPID 2f44 SID 1d4e TYPE 1 VPID 201 APID 294 PCRPID 1ffe - CHANNEL ID 6b NAME "Q24" SATID ffffff TPID 2f44 SID 1d4f TYPE 0 VPID 202 APID 29e APID 29f APID 2a9 APID 2b3 PCRPID 1ffe - CHANNEL ID 6c NAME "Test34" SATID ffffff TPID 2f44 SID 1d50 TYPE 1 VPID 203 APID 2a8 PCRPID 1ffe - CHANNEL ID 6d NAME "Test35" SATID ffffff TPID 2f44 SID 1d51 TYPE 1 VPID 204 APID 2b2 PCRPID 1ffe - CHANNEL ID 6e NAME "Test OTV1" SATID ffffff TPID 2f44 SID 1d60 TYPE 1 PCRPID e80 - CHANNEL ID 6f NAME "Test OTV2" SATID ffffff TPID 2f44 SID 1d61 TYPE 1 PCRPID e80 - CHANNEL ID 70 NAME "Test OTV3" SATID ffffff TPID 2f44 SID 1d62 TYPE 1 PCRPID e80 - CHANNEL ID 71 NAME "Test OTV4" SATID ffffff TPID 2f44 SID 1d63 TYPE 1 PCRPID e80 - CHANNEL ID 72 NAME "Test OTV5" SATID ffffff TPID 2f44 SID 1d64 TYPE 1 PCRPID e80 - CHANNEL ID 73 NAME "Test OTV6" SATID ffffff TPID 2f44 SID 1d65 TYPE 1 PCRPID e80 - CHANNEL ID 74 NAME "Test OTV7" SATID ffffff TPID 2f44 SID 1d66 TYPE 1 PCRPID e80 - CHANNEL ID 75 SATID ffffff TPID 2f44 SID 1d74 TYPE 0 - CHANNEL ID 76 SATID ffffff TPID 2f44 SID 1d75 TYPE 0 - TRANSPONDER ID 0109 SATID 0000 TYPE 1 FREQ 11033000 POL V SRATE 27500000 FEC 8 - TRANSPONDER ID 010a SATID 0000 TYPE 1 FREQ 11054000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 3264 SATID 0000 TYPE 1 FREQ 11095910 POL H SRATE 27500000 FEC 8 - CHANNEL ID ffffffff NAME "Telekom TV" SATID ffffff TPID 3264 SID e7f TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "FantasticOverOpal" SATID ffffff TPID 3264 SID e80 TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "Gilat" SATID ffffff TPID 3264 SID e81 TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "Siemens TV" SATID ffffff TPID 3264 SID e84 TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "S-TV" SATID ffffff TPID 3264 SID e85 TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "Optibase Encoder" SATID ffffff TPID 3264 SID e86 TYPE 0 VPID 20 PCRPID 20 - TRANSPONDER ID 010c SATID 0000 TYPE 1 FREQ 11130000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 010d SATID 0000 TYPE 1 FREQ 11131000 POL V SRATE 27500000 FEC 8 - TRANSPONDER ID 010e SATID 0000 TYPE 1 FREQ 11196000 POL V SRATE 27500000 FEC 8 - TRANSPONDER ID 010f SATID 0000 TYPE 1 FREQ 11205000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 0110 SATID 0000 TYPE 1 FREQ 11242000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 012c SATID 0000 TYPE 1 FREQ 11095910 POL H SRATE 27500000 FEC 8 - CHANNEL ID 7d NAME "FantasticOverOpal" SATID ffffff TPID 12c SID e76 TYPE 0 PCRPID 201 - TRANSPONDER ID 004d SATID 0000 TYPE 1 FREQ 11303750 POL H SRATE 27500000 FEC 8 - CHANNEL ID ffffffff NAME "Deutsche Bank / T1" SATID ffffff TPID 4d SID 1 TYPE 1 VPID 488 PCRPID 488 - CHANNEL ID 7f NAME "Animal Planet" SATID ffffff TPID 4d SID a TYPE 1 VPID 488 PCRPID 488 - CHANNEL ID 80 NAME "Discovery E Europe-English" SATID ffffff TPID 4d SID 14 TYPE 1 VPID 4ec PCRPID 4ec - CHANNEL ID ffffffff NAME "Wuerth KG / T21" SATID ffffff TPID 4d SID 15 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 82 NAME "Discovery Italy" SATID ffffff TPID 4d SID 1e TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID ffffffff NAME "BTI / T31" SATID ffffff TPID 4d SID 1f TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 84 NAME "Discovery Russia" SATID ffffff TPID 4d SID 28 TYPE 1 VPID 5b4 PCRPID 5b4 - CHANNEL ID ffffffff NAME "K-TV (MetroMux) / T41" SATID ffffff TPID 4d SID 29 TYPE 1 VPID 7a8 PCRPID 7a8 - CHANNEL ID 86 NAME "Animal Planet EE" SATID ffffff TPID 4d SID 32 TYPE 1 VPID 618 PCRPID 618 - CHANNEL ID 87 NAME "Animal Planet - Russian" SATID ffffff TPID 4d SID 33 TYPE 1 VPID 618 PCRPID 618 - CHANNEL ID 88 NAME "Discovery Netherlands" SATID ffffff TPID 4d SID 3c TYPE 1 VPID 67c PCRPID 67c - CHANNEL ID ffffffff NAME "Q English" SATID ffffff TPID 4d SID 46 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 8a NAME "Travel and Adventure" SATID ffffff TPID 4d SID 50 TYPE 1 VPID 744 PCRPID 744 - CHANNEL ID 8b NAME "Travel and Adventure- Russian" SATID ffffff TPID 4d SID 51 TYPE 1 VPID 744 PCRPID 744 - CHANNEL ID 8c NAME "New DCP" SATID ffffff TPID 4d SID 12c TYPE 1 APID 4c4 PCRPID 4c4 - CHANNEL ID 8d NAME "CCP" SATID ffffff TPID 4d SID 12d TYPE 1 VPID 4ec PCRPID 4ec - CHANNEL ID ffffffff NAME "Deutsche Bank / T2" SATID ffffff TPID 4d SID 2 TYPE 1 VPID 4ec PCRPID 4ec - CHANNEL ID 93 NAME "Channel Three" SATID ffffff TPID 4d SID 3 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 94 NAME "Channel Four" SATID ffffff TPID 4d SID 4 TYPE 0 VPID 5b4 PCRPID 5b4 - CHANNEL ID 95 NAME "Channel Five" SATID ffffff TPID 4d SID 5 TYPE 0 VPID 618 PCRPID 618 - CHANNEL ID 96 NAME "Channel 6 = Sat 7 Arabic" SATID ffffff TPID 4d SID 6 TYPE 0 VPID 67c PCRPID 67c - CHANNEL ID 97 NAME "Channel Seven" SATID ffffff TPID 4d SID 7 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 98 NAME "Q German" SATID ffffff TPID 4d SID 47 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 99 NAME "Q French" SATID ffffff TPID 4d SID 48 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 9a NAME "Q Dutch" SATID ffffff TPID 4d SID 49 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 1b8 NAME "DTAG / T11" SATID ffffff TPID 4d SID b TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1b9 NAME "DTAG 50 / T12" SATID ffffff TPID 4d SID c TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1ba NAME "Telekom TV" SATID ffffff TPID 4d SID d TYPE 1 VPID 5b4 PCRPID 5b4 - CHANNEL ID 1bb NAME "Gerling / T26" SATID ffffff TPID 4d SID 1a TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1bc NAME "Hornbach-D / T36" SATID ffffff TPID 4d SID 24 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1bd NAME "Hornbach-NL / T38" SATID ffffff TPID 4d SID 26 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1be NAME "Hornbach-CZ / T39" SATID ffffff TPID 4d SID 27 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1bf NAME "Testkanal" SATID ffffff TPID 4d SID 63 TYPE 0 VPID 67c PCRPID 67c - CHANNEL ID 1c0 NAME "KENCAST" SATID ffffff TPID 4d SID 6f TYPE 0 PCRPID 42e - TRANSPONDER ID 0113 SATID 0000 TYPE 1 FREQ 11338000 POL V SRATE 27500000 FEC 8 - TRANSPONDER ID 0114 SATID 0000 TYPE 1 FREQ 11371000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 0115 SATID 0000 TYPE 1 FREQ 11457000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 0116 SATID 0000 TYPE 1 FREQ 11464000 POL V SRATE 27500000 FEC 8 - TRANSPONDER ID 3c8c SATID 0000 TYPE 1 FREQ 11604100 POL H SRATE 27500000 FEC 8 - CHANNEL ID 8e NAME "SAT.1 CH" SATID ffffff TPID 3c8c SID 259 TYPE 0 VPID 65 APID 66 TTPID 69 PCRPID 69 - CHANNEL ID 8f NAME "KBT Channel SUN" SATID ffffff TPID 3c8c SID 25b TYPE 0 VPID 6f APID 70 PCRPID 6f - CHANNEL ID 90 NAME "big FM" SATID ffffff TPID 3c8c SID 25c TYPE 0 APID 71 PCRPID 71 - CHANNEL ID 91 NAME "Event" SATID ffffff TPID 3c8c SID 25a TYPE 0 VPID a0 APID a1 PCRPID a0 - TRANSPONDER ID 0118 SATID 0000 TYPE 1 FREQ 11623000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 004d SATID 0000 TYPE 1 FREQ 11642500 POL H SRATE 27500000 FEC 8 - CHANNEL ID ffffffff NAME "Deutsche Bank / T1" SATID ffffff TPID 4d SID 1 TYPE 1 VPID 488 PCRPID 488 - CHANNEL ID 7f NAME "Animal Planet" SATID ffffff TPID 4d SID a TYPE 1 VPID 488 PCRPID 488 - CHANNEL ID 80 NAME "Discovery E Europe-English" SATID ffffff TPID 4d SID 14 TYPE 1 VPID 4ec PCRPID 4ec - CHANNEL ID ffffffff NAME "Wuerth KG / T21" SATID ffffff TPID 4d SID 15 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 82 NAME "Discovery Italy" SATID ffffff TPID 4d SID 1e TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID ffffffff NAME "BTI / T31" SATID ffffff TPID 4d SID 1f TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 84 NAME "Discovery Russia" SATID ffffff TPID 4d SID 28 TYPE 1 VPID 5b4 PCRPID 5b4 - CHANNEL ID ffffffff NAME "K-TV (MetroMux) / T41" SATID ffffff TPID 4d SID 29 TYPE 1 VPID 7a8 PCRPID 7a8 - CHANNEL ID 86 NAME "Animal Planet EE" SATID ffffff TPID 4d SID 32 TYPE 1 VPID 618 PCRPID 618 - CHANNEL ID 87 NAME "Animal Planet - Russian" SATID ffffff TPID 4d SID 33 TYPE 1 VPID 618 PCRPID 618 - CHANNEL ID 88 NAME "Discovery Netherlands" SATID ffffff TPID 4d SID 3c TYPE 1 VPID 67c PCRPID 67c - CHANNEL ID ffffffff NAME "Q English" SATID ffffff TPID 4d SID 46 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 8a NAME "Travel and Adventure" SATID ffffff TPID 4d SID 50 TYPE 1 VPID 744 PCRPID 744 - CHANNEL ID 8b NAME "Travel and Adventure- Russian" SATID ffffff TPID 4d SID 51 TYPE 1 VPID 744 PCRPID 744 - CHANNEL ID 8c NAME "New DCP" SATID ffffff TPID 4d SID 12c TYPE 1 APID 4c4 PCRPID 4c4 - CHANNEL ID 8d NAME "CCP" SATID ffffff TPID 4d SID 12d TYPE 1 VPID 4ec PCRPID 4ec - CHANNEL ID ffffffff NAME "Deutsche Bank / T2" SATID ffffff TPID 4d SID 2 TYPE 1 VPID 4ec PCRPID 4ec - CHANNEL ID 93 NAME "Channel Three" SATID ffffff TPID 4d SID 3 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 94 NAME "Channel Four" SATID ffffff TPID 4d SID 4 TYPE 0 VPID 5b4 PCRPID 5b4 - CHANNEL ID 95 NAME "Channel Five" SATID ffffff TPID 4d SID 5 TYPE 0 VPID 618 PCRPID 618 - CHANNEL ID 96 NAME "Channel 6 = Sat 7 Arabic" SATID ffffff TPID 4d SID 6 TYPE 0 VPID 67c PCRPID 67c - CHANNEL ID 97 NAME "Channel Seven" SATID ffffff TPID 4d SID 7 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 98 NAME "Q German" SATID ffffff TPID 4d SID 47 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 99 NAME "Q French" SATID ffffff TPID 4d SID 48 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 9a NAME "Q Dutch" SATID ffffff TPID 4d SID 49 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 1b8 NAME "DTAG / T11" SATID ffffff TPID 4d SID b TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1b9 NAME "DTAG 50 / T12" SATID ffffff TPID 4d SID c TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1ba NAME "Telekom TV" SATID ffffff TPID 4d SID d TYPE 1 VPID 5b4 PCRPID 5b4 - CHANNEL ID 1bb NAME "Gerling / T26" SATID ffffff TPID 4d SID 1a TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1bc NAME "Hornbach-D / T36" SATID ffffff TPID 4d SID 24 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1bd NAME "Hornbach-NL / T38" SATID ffffff TPID 4d SID 26 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1be NAME "Hornbach-CZ / T39" SATID ffffff TPID 4d SID 27 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1bf NAME "Testkanal" SATID ffffff TPID 4d SID 63 TYPE 0 VPID 67c PCRPID 67c - CHANNEL ID 1c0 NAME "KENCAST" SATID ffffff TPID 4d SID 6f TYPE 0 PCRPID 42e - TRANSPONDER ID 011a SATID 0000 TYPE 1 FREQ 11662000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 3e1c SATID 0000 TYPE 1 FREQ 11681001 POL H SRATE 27500000 FEC 8 - CHANNEL ID 9b NAME "AB 1" SATID ffffff TPID 3e1c SID c9 TYPE 1 VPID a0 APID 50 TTPID 20 PCRPID a0 - CHANNEL ID 9c NAME "AB MOTEURS" SATID ffffff TPID 3e1c SID ca TYPE 1 VPID a1 APID 54 TTPID 23 PCRPID a1 - CHANNEL ID 9d NAME "ANIMAUX" SATID ffffff TPID 3e1c SID cb TYPE 1 VPID a2 APID 58 TTPID 26 PCRPID a2 - CHANNEL ID 9e NAME "CHASSE ET PECHE" SATID ffffff TPID 3e1c SID cc TYPE 1 VPID a3 APID 5c TTPID 29 PCRPID a3 - CHANNEL ID 9f NAME "XXL" SATID ffffff TPID 3e1c SID cd TYPE 1 VPID a4 APID 60 TTPID 2c PCRPID a4 - CHANNEL ID a0 NAME "MUSIQUE CLASSIQUE" SATID ffffff TPID 3e1c SID ce TYPE 1 VPID a5 APID 64 TTPID 2f PCRPID a5 - CHANNEL ID a1 NAME "ESCALES" SATID ffffff TPID 3e1c SID cf TYPE 1 VPID a6 APID 68 TTPID 32 PCRPID a6 - CHANNEL ID a2 NAME "FIT/chane HISTOIRE" SATID ffffff TPID 3e1c SID d0 TYPE 1 VPID a7 APID 6c TTPID 35 PCRPID a7 - CHANNEL ID a3 NAME "RFM TV" SATID ffffff TPID 3e1c SID d1 TYPE 1 VPID a8 APID 70 TTPID 38 PCRPID a8 - TRANSPONDER ID 13ec SATID 0000 TYPE 1 FREQ 11744599 POL H SRATE 27500000 FEC 8 - CHANNEL ID a4 NAME "EDTV DRAMA" SATID ffffff TPID 13ec SID 2520 TYPE 0 VPID 1322 PCRPID 1322 - CHANNEL ID a5 NAME "EDTV RADIO 02" SATID ffffff TPID 13ec SID 2534 TYPE 0 VPID 1322 PCRPID 1322 - CHANNEL ID a6 NAME "EDTV RADIO 01" SATID ffffff TPID 13ec SID 2533 TYPE 0 VPID 1322 PCRPID 1322 - CHANNEL ID a7 NAME "EDTV SPORT" SATID ffffff TPID 13ec SID 251e TYPE 0 VPID 1322 PCRPID 1322 - CHANNEL ID a8 NAME "EDTV BUSINESS" SATID ffffff TPID 13ec SID 251f TYPE 0 VPID 1322 PCRPID 1322 - TRANSPONDER ID 1450 SATID 0000 TYPE 1 FREQ 11765841 POL V SRATE 27500000 FEC 8 - CHANNEL ID a9 NAME "RAI1" SATID ffffff TPID 1450 SID d49 TYPE 0 VPID a0 PCRPID 1ffe - CHANNEL ID aa NAME "RAI2" SATID ffffff TPID 1450 SID d4a TYPE 0 VPID a1 PCRPID 1ffe - CHANNEL ID ab NAME "RAI3" SATID ffffff TPID 1450 SID d4b TYPE 0 VPID a2 PCRPID 1ffe - CHANNEL ID ac NAME "Rai Way TEST1" SATID ffffff TPID 1450 SID d4c TYPE 0 VPID 203 PCRPID 1ffe - CHANNEL ID ad NAME "Rai Way TEST2" SATID ffffff TPID 1450 SID d4d TYPE 0 VPID 204 PCRPID 1ffe - CHANNEL ID ae NAME "Rai Way TEST3" SATID ffffff TPID 1450 SID d4e TYPE 0 VPID a4 PCRPID 1ffe - CHANNEL ID af NAME "RAIMOSAICO" SATID ffffff TPID 1450 SID d4f TYPE 0 VPID 206 PCRPID 1ffe - CHANNEL ID b0 SATID ffffff TPID 1450 SID da2 TYPE 0 - TRANSPONDER ID 1518 SATID 0000 TYPE 1 FREQ 11765841 POL V SRATE 27500000 FEC 8 - CHANNEL ID b1 NAME "RAINews24" SATID ffffff TPID 1518 SID ce5 TYPE 0 VPID 204 PCRPID 1ffe - CHANNEL ID b2 NAME "CAMERA DEPUTATI" SATID ffffff TPID 1518 SID ce6 TYPE 0 VPID 205 PCRPID 1ffe - CHANNEL ID b3 NAME "TELEPACE" SATID ffffff TPID 1518 SID ce8 TYPE 0 VPID 203 PCRPID 1ffe - CHANNEL ID b4 NAME "RAISPORTSAT" SATID ffffff TPID 1518 SID ce9 TYPE 0 VPID 200 PCRPID 1ffe - CHANNEL ID b5 NAME "RAINettunoSAT2" SATID ffffff TPID 1518 SID cea TYPE 0 VPID 201 PCRPID 1ffe - CHANNEL ID b6 NAME "RAIeducational" SATID ffffff TPID 1518 SID ceb TYPE 0 VPID 202 PCRPID 1ffe - CHANNEL ID b7 NAME "RAINettunoSAT1" SATID ffffff TPID 1518 SID cec TYPE 0 VPID 207 PCRPID 1ffe - CHANNEL ID b8 NAME "SAT2000" SATID ffffff TPID 1518 SID ced TYPE 0 VPID 206 PCRPID 1ffe - CHANNEL ID b9 NAME "RADIOUNO" SATID ffffff TPID 1518 SID cef TYPE 0 APID 29e PCRPID 1ffe - CHANNEL ID ba NAME "RADIODUE" SATID ffffff TPID 1518 SID cf0 TYPE 0 APID 29f PCRPID 1ffe - CHANNEL ID bb NAME "RADIOTRE" SATID ffffff TPID 1518 SID cf1 TYPE 0 APID 2a0 PCRPID 1ffe - CHANNEL ID bc NAME "FDleggera" SATID ffffff TPID 1518 SID cf2 TYPE 0 APID 2a1 PCRPID 1ffe - CHANNEL ID bd NAME "FDauditorium" SATID ffffff TPID 1518 SID cf3 TYPE 0 APID 299 PCRPID 1ffe - CHANNEL ID be NAME "BLUSAT 2000" SATID ffffff TPID 1518 SID cf4 TYPE 0 APID 2a5 PCRPID 1ffe - CHANNEL ID bf NAME "GR PARLAMENTO" SATID ffffff TPID 1518 SID cf5 TYPE 0 APID 298 PCRPID 1ffe - CHANNEL ID c0 NAME "ISORADIO" SATID ffffff TPID 1518 SID cf6 TYPE 0 APID 295 PCRPID 1ffe - TRANSPONDER ID 157c SATID 0000 TYPE 1 FREQ 11823000 POL H SRATE 27500000 FEC 8 - CHANNEL ID c1 NAME "R1" SATID ffffff TPID 157c SID 12d TYPE 1 VPID 200 APID 28a PCRPID 1ffe - CHANNEL ID c2 NAME "R2" SATID ffffff TPID 157c SID 12e TYPE 1 VPID 201 APID 294 APID 295 PCRPID 1ffe - CHANNEL ID c3 NAME "R3" SATID ffffff TPID 157c SID 12f TYPE 1 VPID 202 APID 29e TTPID 242 PCRPID 1ffe - CHANNEL ID c4 NAME "R4" SATID ffffff TPID 157c SID 130 TYPE 1 VPID 203 APID 2a8 TTPID 243 PCRPID 1ffe - CHANNEL ID c5 NAME "R5" SATID ffffff TPID 157c SID 132 TYPE 1 VPID 124a APID 2bc TTPID 245 PCRPID 1ffe - CHANNEL ID c6 NAME "R6" SATID ffffff TPID 157c SID 133 TYPE 1 VPID 206 APID 2c6 PCRPID 1ffe - CHANNEL ID c7 NAME "R7" SATID ffffff TPID 157c SID 134 TYPE 1 VPID 207 APID 2d0 PCRPID 1ffe - CHANNEL ID c8 NAME "Love Radio" SATID ffffff TPID 157c SID 135 TYPE 1 APID 2c7 PCRPID 1ffe - CHANNEL ID c9 NAME "Greek Church" SATID ffffff TPID 157c SID 136 TYPE 1 APID 29f PCRPID 1ffe - CHANNEL ID ca NAME "Skai Radio" SATID ffffff TPID 157c SID 137 TYPE 1 APID 2e5 PCRPID 1ffe - CHANNEL ID cb NAME "MelodiRadio" SATID ffffff TPID 157c SID 138 TYPE 1 APID 2bd PCRPID 1ffe - CHANNEL ID cc NAME "ERA 3" SATID ffffff TPID 157c SID 139 TYPE 1 APID 28b PCRPID 1ffe - CHANNEL ID cd NAME "RR1" SATID ffffff TPID 157c SID 13a TYPE 1 APID 2a9 PCRPID 1ffe - CHANNEL ID ce NAME "RR2" SATID ffffff TPID 157c SID 13b TYPE 1 APID 2d1 PCRPID 1ffe - CHANNEL ID cf NAME "NOVA CINE" SATID ffffff TPID 157c SID 13c TYPE 1 VPID 209 APID 2e4 PCRPID 1ffe - CHANNEL ID d0 NAME "FILM NET" SATID ffffff TPID 157c SID 13d TYPE 1 VPID 200 APID 28a PCRPID 1ffe - CHANNEL ID d1 NAME "SSportK-T.V" SATID ffffff TPID 157c SID 13e TYPE 1 VPID 201 APID 294 APID 295 PCRPID 1ffe - CHANNEL ID d2 NAME "MEGA" SATID ffffff TPID 157c SID 13f TYPE 1 VPID 202 APID 29e TTPID 242 PCRPID 1ffe - CHANNEL ID d3 NAME "ANT-1" SATID ffffff TPID 157c SID 140 TYPE 1 VPID 203 APID 2a8 TTPID 243 PCRPID 1ffe - CHANNEL ID d4 NAME "STAR" SATID ffffff TPID 157c SID 141 TYPE 1 VPID 205 APID 2bc TTPID 245 PCRPID 1ffe - CHANNEL ID d5 NAME "Alter 5" SATID ffffff TPID 157c SID 142 TYPE 1 VPID 206 APID 2c6 PCRPID 1ffe - CHANNEL ID d6 NAME "NEW Tempo" SATID ffffff TPID 157c SID 143 TYPE 1 VPID 207 APID 2d0 PCRPID 1ffe - CHANNEL ID d7 NAME "Super Sport2" SATID ffffff TPID 157c SID 144 TYPE 1 VPID 204 APID 2b2 APID 2b3 PCRPID 1ffe - TRANSPONDER ID 15e0 SATID 0000 TYPE 1 FREQ 11843000 POL V SRATE 27500000 FEC 8 - CHANNEL ID d8 SATID ffffff TPID 15e0 SID fffe TYPE 0 - CHANNEL ID d9 NAME "INTV" SATID ffffff TPID 15e0 SID db0 TYPE 1 VPID 914 PCRPID 900 - CHANNEL ID da NAME "UNIV" SATID ffffff TPID 15e0 SID db3 TYPE 1 VPID 901 PCRPID 900 - CHANNEL ID db NAME "CULT" SATID ffffff TPID 15e0 SID db6 TYPE 1 VPID 903 PCRPID 900 - CHANNEL ID dc NAME "ERSP" SATID ffffff TPID 15e0 SID db9 TYPE 1 VPID 905 PCRPID 900 - CHANNEL ID dd NAME "SINT" SATID ffffff TPID 15e0 SID dbb TYPE 1 - CHANNEL ID de NAME "CART" SATID ffffff TPID 15e0 SID dbc TYPE 1 VPID 981 PCRPID 980 - CHANNEL ID df NAME "SINT" SATID ffffff TPID 15e0 SID dbf TYPE 1 - CHANNEL ID e0 NAME "DISC" SATID ffffff TPID 15e0 SID dc2 TYPE 1 VPID 985 PCRPID 980 - CHANNEL ID e1 NAME "SINT" SATID ffffff TPID 15e0 SID dc5 TYPE 1 - CHANNEL ID e2 NAME "TVL" SATID ffffff TPID 15e0 SID dc8 TYPE 1 VPID 989 PCRPID 980 - CHANNEL ID e3 NAME "SINT" SATID ffffff TPID 15e0 SID dca TYPE 1 - CHANNEL ID e4 NAME "ROCK" SATID ffffff TPID 15e0 SID dde TYPE 1 APID 910 PCRPID 900 - CHANNEL ID e5 NAME "RDS" SATID ffffff TPID 15e0 SID de1 TYPE 1 APID 911 PCRPID 900 - CHANNEL ID e6 NAME "RTL" SATID ffffff TPID 15e0 SID de4 TYPE 1 APID 912 PCRPID 900 - CHANNEL ID e7 NAME "101" SATID ffffff TPID 15e0 SID de7 TYPE 1 APID 913 PCRPID 900 - CHANNEL ID e8 NAME "RVOY" SATID ffffff TPID 15e0 SID dea TYPE 1 APID 90b PCRPID 900 - CHANNEL ID e9 NAME "RKFM" SATID ffffff TPID 15e0 SID deb TYPE 1 APID 90d PCRPID 900 - CHANNEL ID ea NAME "GLOB" SATID ffffff TPID 15e0 SID dec TYPE 1 APID 90c PCRPID 900 - CHANNEL ID eb NAME "ANT1" SATID ffffff TPID 15e0 SID ded TYPE 1 APID 90e PCRPID 900 - CHANNEL ID ec NAME "RRAD" SATID ffffff TPID 15e0 SID dee TYPE 1 APID 90f PCRPID 900 - CHANNEL ID ed NAME "MC01" SATID ffffff TPID 15e0 SID df0 TYPE 1 APID 908 PCRPID 908 - CHANNEL ID ee NAME "MC02" SATID ffffff TPID 15e0 SID df3 TYPE 1 APID 909 PCRPID 909 - CHANNEL ID ef NAME "MC03" SATID ffffff TPID 15e0 SID df6 TYPE 1 APID 90a PCRPID 90a - TRANSPONDER ID 1644 SATID 0000 TYPE 1 FREQ 12341001 POL H SRATE 27500000 FEC 8 - CHANNEL ID f0 NAME "P7" SATID ffffff TPID 1644 SID 2c25 TYPE 1 VPID a0 APID 50 APID 51 PCRPID af - CHANNEL ID f1 NAME "P8" SATID ffffff TPID 1644 SID 2c27 TYPE 1 VPID a1 APID 54 APID 55 PCRPID af - CHANNEL ID f2 NAME "P9" SATID ffffff TPID 1644 SID 2c29 TYPE 1 VPID a2 APID 58 APID 59 PCRPID af - CHANNEL ID f3 NAME "+GIOCHI" SATID ffffff TPID 1644 SID 2c2e TYPE 1 PCRPID af - CHANNEL ID f4 NAME "MM01" SATID ffffff TPID 1644 SID 2c2f TYPE 1 APID 259 PCRPID b0 - CHANNEL ID f5 NAME "MM02" SATID ffffff TPID 1644 SID 2c30 TYPE 0 APID 25a PCRPID b0 - CHANNEL ID f6 NAME "MM03" SATID ffffff TPID 1644 SID 2c31 TYPE 0 APID 25b PCRPID b0 - CHANNEL ID f7 NAME "MM04" SATID ffffff TPID 1644 SID 2c32 TYPE 0 APID 25c PCRPID b0 - CHANNEL ID f8 NAME "MM05" SATID ffffff TPID 1644 SID 2c33 TYPE 0 APID 25d PCRPID b0 - CHANNEL ID f9 NAME "MM06" SATID ffffff TPID 1644 SID 2c34 TYPE 0 APID 25e PCRPID b0 - CHANNEL ID fa NAME "MM07" SATID ffffff TPID 1644 SID 2c35 TYPE 0 APID 25f PCRPID b0 - CHANNEL ID fb NAME "MM08" SATID ffffff TPID 1644 SID 2c36 TYPE 0 APID 260 PCRPID b0 - CHANNEL ID fc NAME "MM09" SATID ffffff TPID 1644 SID 2c37 TYPE 0 APID 261 PCRPID b0 - CHANNEL ID fd NAME "MM10" SATID ffffff TPID 1644 SID 2c38 TYPE 0 APID 262 PCRPID b0 - CHANNEL ID fe NAME "MM11" SATID ffffff TPID 1644 SID 2c39 TYPE 1 APID 263 PCRPID b0 - CHANNEL ID ff NAME "MM12" SATID ffffff TPID 1644 SID 2c3a TYPE 0 APID 264 PCRPID b0 - CHANNEL ID 100 NAME "MM13" SATID ffffff TPID 1644 SID 2c3b TYPE 0 APID 265 PCRPID b0 - CHANNEL ID 101 NAME "MM14" SATID ffffff TPID 1644 SID 2c3c TYPE 0 APID 266 PCRPID b0 - CHANNEL ID 102 NAME "MM15" SATID ffffff TPID 1644 SID 2c3d TYPE 0 APID 267 PCRPID b0 - CHANNEL ID 103 NAME "MM16" SATID ffffff TPID 1644 SID 2c3e TYPE 0 APID 268 PCRPID b0 - CHANNEL ID 104 NAME "MM17" SATID ffffff TPID 1644 SID 2c3f TYPE 0 APID 269 PCRPID b0 - CHANNEL ID 105 NAME "MM18" SATID ffffff TPID 1644 SID 2c40 TYPE 0 APID 26a PCRPID b0 - CHANNEL ID 106 NAME "MM19" SATID ffffff TPID 1644 SID 2c41 TYPE 0 APID 26b PCRPID b0 - CHANNEL ID 107 NAME "MM20" SATID ffffff TPID 1644 SID 2c42 TYPE 0 APID 26c PCRPID b0 - CHANNEL ID 108 NAME "MM21" SATID ffffff TPID 1644 SID 2c43 TYPE 1 APID 26d PCRPID b0 - CHANNEL ID 109 NAME "MM22" SATID ffffff TPID 1644 SID 2c44 TYPE 0 APID 26e PCRPID b0 - CHANNEL ID 10a NAME "MM23" SATID ffffff TPID 1644 SID 2c45 TYPE 0 APID 26f PCRPID b0 - CHANNEL ID 10b NAME "MM24" SATID ffffff TPID 1644 SID 2c46 TYPE 0 APID 270 PCRPID b0 - CHANNEL ID 10c NAME "MM25" SATID ffffff TPID 1644 SID 2c47 TYPE 0 APID 271 PCRPID b0 - CHANNEL ID 10d NAME "MM26" SATID ffffff TPID 1644 SID 2c48 TYPE 0 APID 272 PCRPID b0 - CHANNEL ID 10e NAME "MM27" SATID ffffff TPID 1644 SID 2c49 TYPE 0 APID 273 PCRPID b0 - CHANNEL ID 10f NAME "MM28" SATID ffffff TPID 1644 SID 2c4a TYPE 0 APID 274 PCRPID b0 - CHANNEL ID 110 NAME "MM29" SATID ffffff TPID 1644 SID 2c4b TYPE 0 APID 275 PCRPID b0 - CHANNEL ID 111 NAME "MM30" SATID ffffff TPID 1644 SID 2c4c TYPE 0 APID 276 PCRPID b0 - CHANNEL ID 112 NAME "RCAP" SATID ffffff TPID 1644 SID 2c4d TYPE 1 APID 277 PCRPID b0 - CHANNEL ID 113 NAME "R105" SATID ffffff TPID 1644 SID 2c4e TYPE 0 APID 278 PCRPID b0 - CHANNEL ID 114 NAME "RDJ" SATID ffffff TPID 1644 SID 2c4f TYPE 0 APID 279 PCRPID b0 - CHANNEL ID 115 NAME "RITA" SATID ffffff TPID 1644 SID 2c50 TYPE 0 APID 27a PCRPID b0 - CHANNEL ID 116 NAME "RMC" SATID ffffff TPID 1644 SID 2c51 TYPE 0 APID 27b PCRPID b0 - CHANNEL ID 117 NAME "R101" SATID ffffff TPID 1644 SID 2c52 TYPE 0 APID 27c PCRPID b0 - CHANNEL ID 118 NAME "RRAD" SATID ffffff TPID 1644 SID 2c53 TYPE 0 APID 27d PCRPID b0 - CHANNEL ID 119 NAME "RR" SATID ffffff TPID 1644 SID 2c54 TYPE 0 APID 27e PCRPID b0 - CHANNEL ID 11a SATID ffffff TPID 1644 SID 2c61 TYPE 0 APID 259 APID 25a APID 25b APID 25c APID 25d APID 25e APID 25f APID 260 APID 261 APID 262 PCRPID b0 - CHANNEL ID 11b SATID ffffff TPID 1644 SID 2c62 TYPE 0 APID 263 APID 264 APID 265 APID 266 APID 267 APID 268 APID 269 APID 26a APID 26b APID 26c PCRPID b0 - CHANNEL ID 11c SATID ffffff TPID 1644 SID 2c63 TYPE 0 APID 26d APID 26e APID 26f APID 270 APID 271 APID 272 APID 273 APID 274 APID 275 APID 276 PCRPID b0 - CHANNEL ID 11d SATID ffffff TPID 1644 SID 2c64 TYPE 0 APID 277 APID 278 APID 279 APID 27a APID 27b APID 27c APID 27d APID 27e PCRPID b0 - CHANNEL ID 11e NAME "MULTIMUSICA" SATID ffffff TPID 1644 SID 2c58 TYPE 1 PCRPID b0 - CHANNEL ID 11f NAME "RADIO" SATID ffffff TPID 1644 SID 2c59 TYPE 1 PCRPID b0 - CHANNEL ID 120 NAME "MULTIMUSIC 1" SATID ffffff TPID 1644 SID 2c65 TYPE 1 APID 262 APID 259 APID 25a APID 25b APID 25c APID 25d APID 25e APID 25f APID 260 APID 261 PCRPID b0 - CHANNEL ID 121 NAME "MULTIMUSIC 2" SATID ffffff TPID 1644 SID 2c66 TYPE 1 APID 265 APID 266 APID 267 APID 263 APID 264 APID 268 APID 269 APID 26a APID 26b APID 26c PCRPID b0 - TRANSPONDER ID 16a8 SATID 0000 TYPE 1 FREQ 12713000 POL V SRATE 27500000 FEC 8 - CHANNEL ID 122 SATID ffffff TPID 16a8 SID fffe TYPE 0 - CHANNEL ID 123 NAME "TEAM" SATID ffffff TPID 16a8 SID e1a TYPE 1 VPID 901 PCRPID 900 - CHANNEL ID 124 NAME "SINT" SATID ffffff TPID 16a8 SID e1d TYPE 1 - CHANNEL ID 125 NAME "VIAG" SATID ffffff TPID 16a8 SID e20 TYPE 1 VPID 904 PCRPID 900 - CHANNEL ID 126 NAME "SINT" SATID ffffff TPID 16a8 SID e23 TYPE 1 - CHANNEL ID 127 NAME "EURO" SATID ffffff TPID 16a8 SID e26 TYPE 1 VPID 907 PCRPID 900 - CHANNEL ID 128 NAME "SINT" SATID ffffff TPID 16a8 SID e27 TYPE 1 - CHANNEL ID 129 NAME "CNN" SATID ffffff TPID 16a8 SID e29 TYPE 1 VPID 981 PCRPID 980 - CHANNEL ID 12a NAME "ante prima" SATID ffffff TPID 16a8 SID e2c TYPE 1 VPID 983 PCRPID 980 - CHANNEL ID 12b NAME "SNAI" SATID ffffff TPID 16a8 SID e2e TYPE 1 VPID a01 PCRPID a00 - CHANNEL ID 12c NAME "MPPV" SATID ffffff TPID 16a8 SID e30 TYPE 1 VPID a03 PCRPID a00 - CHANNEL ID 12d NAME "MC04" SATID ffffff TPID 16a8 SID e34 TYPE 1 APID a80 PCRPID a80 - CHANNEL ID 12e NAME "MC05" SATID ffffff TPID 16a8 SID e35 TYPE 1 APID a81 PCRPID a81 - CHANNEL ID 12f NAME "MC06" SATID ffffff TPID 16a8 SID e36 TYPE 1 APID a82 PCRPID a82 - CHANNEL ID 130 NAME "MC07" SATID ffffff TPID 16a8 SID e39 TYPE 1 APID a83 PCRPID a83 - CHANNEL ID 131 NAME "MC08" SATID ffffff TPID 16a8 SID e3c TYPE 1 APID a84 PCRPID a84 - CHANNEL ID 132 NAME "MC09" SATID ffffff TPID 16a8 SID e3f TYPE 1 APID a85 PCRPID a85 - CHANNEL ID 133 NAME "MC10" SATID ffffff TPID 16a8 SID e42 TYPE 1 APID a86 PCRPID a86 - CHANNEL ID 134 NAME "MC11" SATID ffffff TPID 16a8 SID e45 TYPE 1 APID a87 PCRPID a87 - CHANNEL ID 135 NAME "MC12" SATID ffffff TPID 16a8 SID e48 TYPE 1 APID a88 PCRPID a88 - CHANNEL ID 136 NAME "MC13" SATID ffffff TPID 16a8 SID e4b TYPE 1 APID a89 PCRPID a89 - CHANNEL ID 137 NAME "MC14" SATID ffffff TPID 16a8 SID e4e TYPE 1 APID a8a PCRPID a8a - CHANNEL ID 138 NAME "MC15" SATID ffffff TPID 16a8 SID e51 TYPE 1 APID a8b PCRPID a8b - CHANNEL ID 139 NAME "MC16" SATID ffffff TPID 16a8 SID e54 TYPE 1 APID a8c PCRPID a8c - CHANNEL ID 13a NAME "MC17" SATID ffffff TPID 16a8 SID e57 TYPE 1 APID a8d PCRPID a8d - CHANNEL ID 13b NAME "MC18" SATID ffffff TPID 16a8 SID e5a TYPE 1 APID a8e PCRPID a8e - TRANSPONDER ID 170c SATID 0000 TYPE 1 FREQ 12341001 POL H SRATE 27500000 FEC 8 - CHANNEL ID 13c NAME "MOSAICO D+" SATID ffffff TPID 170c SID 2c89 TYPE 1 VPID a1 APID 55 APID 51 APID 50 APID 54 PCRPID af - CHANNEL ID 13d NAME " MILAN CH." SATID ffffff TPID 170c SID 2c8b TYPE 1 VPID a2 APID 58 APID 59 PCRPID af - CHANNEL ID 13e NAME " INTER CH." SATID ffffff TPID 170c SID 2c8d TYPE 1 VPID a3 APID 5c APID 5d PCRPID af - CHANNEL ID 13f NAME "TST3" SATID ffffff TPID 170c SID 2c8f TYPE 1 PCRPID af - TRANSPONDER ID 1770 SATID 0000 TYPE 1 FREQ 11919280 POL V SRATE 27500000 FEC 8 - CHANNEL ID 140 NAME " I1" SATID ffffff TPID 1770 SID 1 TYPE 1 VPID 200 APID 28a TTPID 240 PCRPID 1ffe - CHANNEL ID 141 NAME " C5" SATID ffffff TPID 1770 SID 2 TYPE 1 VPID 201 APID 294 TTPID 241 PCRPID 1ffe - CHANNEL ID 142 NAME " R4" SATID ffffff TPID 1770 SID 3 TYPE 1 VPID 202 APID 29e TTPID 242 PCRPID 1ffe - CHANNEL ID 143 NAME "Test" SATID ffffff TPID 1770 SID 4 TYPE 1 VPID 203 APID 2a8 TTPID 243 PCRPID 1ffe - TRANSPONDER ID 003d SATID 0000 TYPE 1 FREQ 11938000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 144 NAME "NTV" SATID ffffff TPID 3d SID 1bc1 TYPE 1 VPID a4 APID 58 APID 59 PCRPID a4 - CHANNEL ID 145 NAME "NTV-PLUS" SATID ffffff TPID 3d SID 1bc2 TYPE 1 VPID a5 APID 5a APID 5b PCRPID a5 - CHANNEL ID 146 NAME "NTV Int.-HTB" SATID ffffff TPID 3d SID 1bbd TYPE 1 VPID a0 APID 50 PCRPID a0 - CHANNEL ID 147 NAME "NTV Int.-Nashe Kino" SATID ffffff TPID 3d SID 1bbe TYPE 1 VPID a1 APID 52 PCRPID a1 - CHANNEL ID 148 NAME "NTV Int.-Detsk. Mir" SATID ffffff TPID 3d SID 1bbf TYPE 1 VPID a2 APID 54 PCRPID a2 - TRANSPONDER ID 1838 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 - CHANNEL ID 149 NAME "DISNEY CHANNEL" SATID ffffff TPID 1838 SID 2a95 TYPE 1 PCRPID a0 - CHANNEL ID 14a NAME "DISCOVERY" SATID ffffff TPID 1838 SID 2a97 TYPE 1 VPID a1 PCRPID a1 - CHANNEL ID 14b NAME "EUSP" SATID ffffff TPID 1838 SID 2a99 TYPE 1 VPID a2 APID 58 APID 59 PCRPID a2 - CHANNEL ID 14c NAME "HAPPY CHANNEL" SATID ffffff TPID 1838 SID 2a9b TYPE 1 PCRPID a3 - CHANNEL ID 14d NAME "MATCH MUSIC" SATID ffffff TPID 1838 SID 2a9d TYPE 1 PCRPID a4 - CHANNEL ID 14e NAME "MTV" SATID ffffff TPID 1838 SID 2a9f TYPE 1 PCRPID a5 - CHANNEL ID 14f NAME "R/CINEMA RAISAT" SATID ffffff TPID 1838 SID 2aa1 TYPE 1 PCRPID a6 - TRANSPONDER ID 189c SATID 0000 TYPE 1 FREQ 12713000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 150 SATID ffffff TPID 189c SID fffe TYPE 0 - CHANNEL ID 151 NAME "cine stream" SATID ffffff TPID 189c SID 1e18 TYPE 1 VPID 200 APID 28a PCRPID 1ffe - CHANNEL ID 152 NAME "cine movie" SATID ffffff TPID 189c SID 1e1b TYPE 1 VPID 202 APID 29e PCRPID 1ffe - TRANSPONDER ID 1900 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 - CHANNEL ID 153 NAME "CLASSICA" SATID ffffff TPID 1900 SID 2af9 TYPE 1 PCRPID a0 - CHANNEL ID 154 NAME "R/GAM ROS RAISAT" SATID ffffff TPID 1900 SID 2afb TYPE 1 PCRPID a1 - CHANNEL ID 155 NAME "R/ALBUM RAISAT" SATID ffffff TPID 1900 SID 2afd TYPE 1 PCRPID a2 - CHANNEL ID 156 NAME "HALLMARK" SATID ffffff TPID 1900 SID 2aff TYPE 1 VPID a3 PCRPID a3 - CHANNEL ID 157 NAME "R/ART RAISAT" SATID ffffff TPID 1900 SID 2b01 TYPE 1 PCRPID a4 - CHANNEL ID 158 NAME "TST1" SATID ffffff TPID 1900 SID 2b03 TYPE 1 PCRPID a5 - CHANNEL ID 159 NAME "TMC" SATID ffffff TPID 1900 SID 2b05 TYPE 1 VPID a6 PCRPID a6 - CHANNEL ID 15a NAME "TMC2" SATID ffffff TPID 1900 SID 2b07 TYPE 1 VPID a7 PCRPID a7 - TRANSPONDER ID 1964 SATID 0000 TYPE 1 FREQ 12015000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 15b NAME "ART VARIETY" SATID ffffff TPID 1964 SID 19a TYPE 1 VPID a0 PCRPID a0 - CHANNEL ID 15c NAME "ART CHILDREN" SATID ffffff TPID 1964 SID 1a4 TYPE 1 VPID a1 PCRPID a1 - CHANNEL ID 15d NAME "ART MOVIES" SATID ffffff TPID 1964 SID 1ae TYPE 1 VPID a2 PCRPID a2 - CHANNEL ID 15e NAME "ART MUSIC" SATID ffffff TPID 1964 SID 1b8 TYPE 1 VPID a3 PCRPID a3 - CHANNEL ID 15f NAME "ART EUROPE" SATID ffffff TPID 1964 SID 1c2 TYPE 0 VPID a4 PCRPID a4 - CHANNEL ID 160 NAME "LBC EUROPE" SATID ffffff TPID 1964 SID 1cc TYPE 1 VPID a5 PCRPID a5 - CHANNEL ID 161 NAME "EGYPT SAT. CH. 2" SATID ffffff TPID 1964 SID 1d6 TYPE 1 VPID a6 PCRPID a6 - CHANNEL ID 162 NAME "ART SPORT" SATID ffffff TPID 1964 SID 1d8 TYPE 1 VPID a7 PCRPID a7 - CHANNEL ID 163 NAME "IQRA" SATID ffffff TPID 1964 SID 1da TYPE 1 VPID a8 PCRPID a8 - TRANSPONDER ID 19c8 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 - CHANNEL ID 164 NAME "T+ BIANCO" SATID ffffff TPID 19c8 SID 2b5d TYPE 1 VPID a0 APID 50 APID 51 TTPID 2c PCRPID a0 - CHANNEL ID 165 NAME "T+ NERO" SATID ffffff TPID 19c8 SID 2b5f TYPE 1 VPID a1 APID 54 APID 55 TTPID 2d PCRPID a1 - CHANNEL ID 166 NAME "T+ GRIGIO" SATID ffffff TPID 19c8 SID 2b61 TYPE 1 VPID a2 APID 58 APID 59 PCRPID a2 - CHANNEL ID 167 NAME "R4" SATID ffffff TPID 19c8 SID 18 TYPE 1 VPID a3 PCRPID a3 - CHANNEL ID 168 NAME "16:9 TELE+" SATID ffffff TPID 19c8 SID 2b63 TYPE 1 VPID a4 APID 60 APID 61 PCRPID a4 - CHANNEL ID 169 NAME "VETRINA D+" SATID ffffff TPID 19c8 SID 2b65 TYPE 1 PCRPID a5 - CHANNEL ID 16a NAME "R/RAGAZZI RAISAT" SATID ffffff TPID 19c8 SID 2b67 TYPE 1 PCRPID a6 - TRANSPONDER ID 1a2c SATID 0000 TYPE 1 FREQ 12341001 POL H SRATE 27500000 FEC 8 - CHANNEL ID 16b NAME "CNN" SATID ffffff TPID 1a2c SID 2ced TYPE 1 PCRPID af - CHANNEL ID 16c NAME "BBC" SATID ffffff TPID 1a2c SID 2cef TYPE 1 PCRPID af - CHANNEL ID 16d NAME "BLOOMBERG" SATID ffffff TPID 1a2c SID 2cf1 TYPE 1 PCRPID af - CHANNEL ID 16e NAME "CNBC" SATID ffffff TPID 1a2c SID 2cf3 TYPE 1 PCRPID af - CHANNEL ID 16f NAME "SKYNews" SATID ffffff TPID 1a2c SID 2cf5 TYPE 1 PCRPID af - CHANNEL ID 170 NAME "TST2" SATID ffffff TPID 1a2c SID 2cf7 TYPE 1 PCRPID af - CHANNEL ID 171 NAME "TV5" SATID ffffff TPID 1a2c SID 2cf9 TYPE 1 PCRPID af - CHANNEL ID 172 NAME "EPG" SATID ffffff TPID 1a2c SID 2cfb TYPE 1 PCRPID af - CHANNEL ID 173 NAME "CNN" SATID ffffff TPID 1a2c SID 2cfd TYPE 1 VPID a0 APID 50 PCRPID af - CHANNEL ID 174 NAME "CNBC" SATID ffffff TPID 1a2c SID 2cff TYPE 1 VPID a3 APID 5c PCRPID af - CHANNEL ID 175 NAME "TV5" SATID ffffff TPID 1a2c SID 2d01 TYPE 1 VPID a6 APID 68 PCRPID af - CHANNEL ID 176 NAME "BBC WORLD" SATID ffffff TPID 1a2c SID 2d03 TYPE 1 VPID a1 APID 54 PCRPID af - CHANNEL ID 177 SATID ffffff TPID 1a2c SID 2d4b TYPE 0 PCRPID 1ffe - CHANNEL ID 178 SATID ffffff TPID 1a2c SID 26fc TYPE 0 PCRPID 1ffe - CHANNEL ID 179 SATID ffffff TPID 1a2c SID 26fd TYPE 0 PCRPID 1ffe - TRANSPONDER ID 3264 SATID 0000 TYPE 1 FREQ 11095910 POL V SRATE 27500000 FEC 8 - CHANNEL ID ffffffff NAME "Telekom TV" SATID ffffff TPID 3264 SID e7f TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "FantasticOverOpal" SATID ffffff TPID 3264 SID e80 TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "Gilat" SATID ffffff TPID 3264 SID e81 TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "Siemens TV" SATID ffffff TPID 3264 SID e84 TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "S-TV" SATID ffffff TPID 3264 SID e85 TYPE 0 VPID 20 PCRPID 20 - CHANNEL ID ffffffff NAME "Optibase Encoder" SATID ffffff TPID 3264 SID e86 TYPE 0 VPID 20 PCRPID 20 - TRANSPONDER ID 1af4 SATID 0000 TYPE 1 FREQ 12091901 POL H SRATE 27500000 FEC 8 - CHANNEL ID 17a NAME "Bolsa" SATID ffffff TPID 1af4 SID 222e TYPE 0 - CHANNEL ID 17b NAME "Testw" SATID ffffff TPID 1af4 SID 222f TYPE 0 - CHANNEL ID 17c NAME "SIRE" SATID ffffff TPID 1af4 SID 2230 TYPE 0 PCRPID 102 - CHANNEL ID 17d NAME "Telesierra" SATID ffffff TPID 1af4 SID 2200 TYPE 0 VPID 1040 APID 1041 PCRPID 1040 - CHANNEL ID 17e NAME "vtv" SATID ffffff TPID 1af4 SID 21fd TYPE 0 VPID 1010 APID 1012 APID 1011 APID 1013 PCRPID 1010 - CHANNEL ID 17f NAME "Satisfaction" SATID ffffff TPID 1af4 SID 2202 TYPE 0 VPID 1060 APID 1061 PCRPID 1060 - CHANNEL ID 180 NAME "C. Milagro" SATID ffffff TPID 1af4 SID 2207 TYPE 0 VPID 1110 APID 1111 PCRPID 1110 - CHANNEL ID 181 NAME "Fiesta" SATID ffffff TPID 1af4 SID 2210 TYPE 0 VPID 1150 APID 1151 APID 1152 PCRPID 1150 - CHANNEL ID 182 NAME "TVE Internacional" SATID ffffff TPID 1af4 SID 2203 TYPE 0 VPID 1070 APID 1071 PCRPID 1070 - CHANNEL ID 183 NAME "TV Galicia" SATID ffffff TPID 1af4 SID 2204 TYPE 0 APID 1090 PCRPID 1090 - CHANNEL ID 184 NAME "Radio Gallega" SATID ffffff TPID 1af4 SID 2205 TYPE 0 APID 1090 PCRPID 1090 - CHANNEL ID 185 NAME "Retelsat" SATID ffffff TPID 1af4 SID 2212 TYPE 1 VPID 1170 APID 1171 PCRPID 1170 - CHANNEL ID 186 NAME "Musicam 1" SATID ffffff TPID 1af4 SID 2209 TYPE 1 APID 1136 PCRPID 1136 - CHANNEL ID 187 NAME "Musicam 2" SATID ffffff TPID 1af4 SID 220a TYPE 1 APID 1133 PCRPID 1133 - CHANNEL ID 188 NAME "Musicam 3" SATID ffffff TPID 1af4 SID 220b TYPE 1 APID 1136 PCRPID 1136 - CHANNEL ID 189 NAME "Musicam 4" SATID ffffff TPID 1af4 SID 220c TYPE 1 APID 1132 PCRPID 1132 - CHANNEL ID 18a NAME "Musicam 5" SATID ffffff TPID 1af4 SID 220d TYPE 1 APID 1136 PCRPID 1136 - TRANSPONDER ID 1b58 SATID 0000 TYPE 1 FREQ 12673000 POL V SRATE 27500000 FEC 8 - CHANNEL ID 18b NAME "HBCH FUCINO" SATID ffffff TPID 1b58 SID 2bd TYPE 0 VPID c8 APID c9 PCRPID c8 - CHANNEL ID 18c NAME "NTVi" SATID ffffff TPID 1b58 SID 2be TYPE 0 VPID d2 APID d3 APID d4 PCRPID d2 - CHANNEL ID 18d NAME "Test Telespazio" SATID ffffff TPID 1b58 SID 2bf TYPE 0 VPID dc APID dd PCRPID dc - CHANNEL ID 18e NAME "Test Telespazio" SATID ffffff TPID 1b58 SID 2c0 TYPE 0 VPID e6 APID e7 PCRPID e6 - CHANNEL ID 18f NAME "ARMENIA TV" SATID ffffff TPID 1b58 SID 2c1 TYPE 0 VPID f0 APID f1 APID f2 PCRPID f0 - CHANNEL ID 190 NAME "MEDNET" SATID ffffff TPID 1b58 SID 2c3 TYPE 0 VPID 104 APID 105 PCRPID 104 - CHANNEL ID 191 NAME "AL JAZEERA" SATID ffffff TPID 1b58 SID 2c4 TYPE 0 VPID 10e APID 10f PCRPID 10e - CHANNEL ID 192 NAME "TIRRENO SAT" SATID ffffff TPID 1b58 SID 2c5 TYPE 0 VPID 118 APID 12d TTPID 139 PCRPID 118 - CHANNEL ID 193 NAME "RADIO ROCK" SATID ffffff TPID 1b58 SID 2c7 TYPE 0 APID d4 PCRPID d2 - CHANNEL ID 194 NAME "RADIO ARMENIA" SATID ffffff TPID 1b58 SID 2c8 TYPE 0 APID f2 PCRPID f0 - CHANNEL ID 195 NAME "Coming Soon TV" SATID ffffff TPID 1b58 SID 2cd TYPE 0 APID 28 PCRPID 28 - TRANSPONDER ID 1c20 SATID 0000 TYPE 1 FREQ 12149000 POL V SRATE 27500000 FEC 8 - CHANNEL ID 196 NAME "AH-EDP1" SATID ffffff TPID 1c20 SID 1c21 TYPE 0 VPID 60 APID 61 PCRPID 60 - CHANNEL ID 197 NAME "AH-EDP2" SATID ffffff TPID 1c20 SID 1c22 TYPE 0 VPID 70 APID 71 PCRPID 70 - CHANNEL ID 198 NAME "AH-EDP3" SATID ffffff TPID 1c20 SID 1c23 TYPE 0 VPID 24 APID 25 PCRPID 24 - CHANNEL ID 199 NAME "AH-EMP4-DATA" SATID ffffff TPID 1c20 SID 1c24 TYPE 0 PCRPID 92 - CHANNEL ID 19a NAME "Alice" SATID ffffff TPID 1c20 SID 1c34 TYPE 0 VPID a0 APID a1 PCRPID a0 - CHANNEL ID 19b NAME "Nuvolari" SATID ffffff TPID 1c20 SID 1c35 TYPE 0 VPID b0 APID b1 PCRPID b0 - CHANNEL ID 19c NAME "Leonardo" SATID ffffff TPID 1c20 SID 1c36 TYPE 0 VPID 80 APID 81 PCRPID 80 - TRANSPONDER ID 1c84 SATID 0000 TYPE 1 FREQ 12169000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 19d NAME "Discovery" SATID ffffff TPID 1c84 SID 15f TYPE 1 VPID 200 PCRPID 1ffe - CHANNEL ID 19e NAME "R9" SATID ffffff TPID 1c84 SID 160 TYPE 1 VPID 201 PCRPID 1ffe - CHANNEL ID 19f NAME "BBC World" SATID ffffff TPID 1c84 SID 161 TYPE 1 VPID 202 PCRPID 1ffe - CHANNEL ID 1a0 NAME "CNN" SATID ffffff TPID 1c84 SID 162 TYPE 1 VPID 203 PCRPID 1ffe - CHANNEL ID 1a1 NAME "CCTV" SATID ffffff TPID 1c84 SID 163 TYPE 0 VPID 204 PCRPID 1ffe - CHANNEL ID 1a2 NAME "R10" SATID ffffff TPID 1c84 SID 165 TYPE 1 VPID 206 PCRPID 1ffe - CHANNEL ID 1a3 NAME "R8" SATID ffffff TPID 1c84 SID 166 TYPE 1 VPID 207 PCRPID 1ffe - CHANNEL ID 1a4 NAME "FILM SAT" SATID ffffff TPID 1c84 SID 167 TYPE 1 VPID 208 PCRPID 1ffe - CHANNEL ID 1a5 NAME "Cartoon" SATID ffffff TPID 1c84 SID 168 TYPE 1 VPID 203 PCRPID 1ffe - CHANNEL ID 1a6 NAME "Promo" SATID ffffff TPID 1c84 SID 169 TYPE 0 VPID 209 PCRPID 1ffe - CHANNEL ID 1a7 NAME "Tempo" SATID ffffff TPID 1c84 SID 16a TYPE 1 VPID 5a0 APID 28b PCRPID f80 - CHANNEL ID 1a8 NAME "Tempo" SATID ffffff TPID 1c84 SID 16b TYPE 1 APID 295 PCRPID f80 - CHANNEL ID 1a9 NAME "Tempo" SATID ffffff TPID 1c84 SID 16c TYPE 1 APID 29f PCRPID f80 - CHANNEL ID 1aa NAME "Tempo" SATID ffffff TPID 1c84 SID 16d TYPE 1 APID 2a9 PCRPID f80 - CHANNEL ID 1ab NAME "Tempo" SATID ffffff TPID 1c84 SID 16e TYPE 1 APID 2b3 PCRPID f80 - CHANNEL ID 1ac NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 16f TYPE 1 PCRPID 1080 - CHANNEL ID 1ad NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 171 TYPE 1 PCRPID 1080 - CHANNEL ID 1ae NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 172 TYPE 1 PCRPID 1080 - CHANNEL ID 1af NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 173 TYPE 1 VPID 42b PCRPID 1080 - CHANNEL ID 1b0 NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 174 TYPE 1 PCRPID 1080 - CHANNEL ID 1b1 NAME "NOVA INFO" SATID ffffff TPID 1c84 SID 175 TYPE 1 PCRPID 1080 - CHANNEL ID 1b2 NAME "NOVA Cinema" SATID ffffff TPID 1c84 SID 176 TYPE 1 PCRPID 1080 - CHANNEL ID 1b3 NAME "NET" SATID ffffff TPID 1c84 SID 178 TYPE 1 VPID 201 PCRPID 1ffe - CHANNEL ID 1b4 NAME "MAD T.V" SATID ffffff TPID 1c84 SID 179 TYPE 1 VPID 206 PCRPID 1ffe - CHANNEL ID 1b5 NAME "ET-1" SATID ffffff TPID 1c84 SID 17a TYPE 1 VPID 207 PCRPID 1ffe - CHANNEL ID 1b6 SATID ffffff TPID 1c84 SID 17b TYPE 0 PCRPID 1000 - CHANNEL ID 1b7 NAME "" SATID ffffff TPID 1c84 SID 180 TYPE 0 VPID 205 PCRPID 1ffe - TRANSPONDER ID 0131 SATID 0000 TYPE 1 FREQ 12188000 POL V SRATE 27500000 FEC 8 - TRANSPONDER ID 0132 SATID 0000 TYPE 1 FREQ 12203000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 0133 SATID 0000 TYPE 1 FREQ 12211000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 004d SATID 0000 TYPE 1 FREQ 12264500 POL V SRATE 27500000 FEC 8 - CHANNEL ID ffffffff NAME "Deutsche Bank / T1" SATID ffffff TPID 4d SID 1 TYPE 1 VPID 488 PCRPID 488 - CHANNEL ID 7f NAME "Animal Planet" SATID ffffff TPID 4d SID a TYPE 1 VPID 488 PCRPID 488 - CHANNEL ID 80 NAME "Discovery E Europe-English" SATID ffffff TPID 4d SID 14 TYPE 1 VPID 4ec PCRPID 4ec - CHANNEL ID ffffffff NAME "Wuerth KG / T21" SATID ffffff TPID 4d SID 15 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 82 NAME "Discovery Italy" SATID ffffff TPID 4d SID 1e TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID ffffffff NAME "BTI / T31" SATID ffffff TPID 4d SID 1f TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 84 NAME "Discovery Russia" SATID ffffff TPID 4d SID 28 TYPE 1 VPID 5b4 PCRPID 5b4 - CHANNEL ID ffffffff NAME "K-TV (MetroMux) / T41" SATID ffffff TPID 4d SID 29 TYPE 1 VPID 7a8 PCRPID 7a8 - CHANNEL ID 86 NAME "Animal Planet EE" SATID ffffff TPID 4d SID 32 TYPE 1 VPID 618 PCRPID 618 - CHANNEL ID 87 NAME "Animal Planet - Russian" SATID ffffff TPID 4d SID 33 TYPE 1 VPID 618 PCRPID 618 - CHANNEL ID 88 NAME "Discovery Netherlands" SATID ffffff TPID 4d SID 3c TYPE 1 VPID 67c PCRPID 67c - CHANNEL ID ffffffff NAME "Q English" SATID ffffff TPID 4d SID 46 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 8a NAME "Travel and Adventure" SATID ffffff TPID 4d SID 50 TYPE 1 VPID 744 PCRPID 744 - CHANNEL ID 8b NAME "Travel and Adventure- Russian" SATID ffffff TPID 4d SID 51 TYPE 1 VPID 744 PCRPID 744 - CHANNEL ID 8c NAME "New DCP" SATID ffffff TPID 4d SID 12c TYPE 1 APID 4c4 PCRPID 4c4 - CHANNEL ID 8d NAME "CCP" SATID ffffff TPID 4d SID 12d TYPE 1 VPID 4ec PCRPID 4ec - CHANNEL ID ffffffff NAME "Deutsche Bank / T2" SATID ffffff TPID 4d SID 2 TYPE 1 VPID 4ec PCRPID 4ec - CHANNEL ID 93 NAME "Channel Three" SATID ffffff TPID 4d SID 3 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 94 NAME "Channel Four" SATID ffffff TPID 4d SID 4 TYPE 0 VPID 5b4 PCRPID 5b4 - CHANNEL ID 95 NAME "Channel Five" SATID ffffff TPID 4d SID 5 TYPE 0 VPID 618 PCRPID 618 - CHANNEL ID 96 NAME "Channel 6 = Sat 7 Arabic" SATID ffffff TPID 4d SID 6 TYPE 0 VPID 67c PCRPID 67c - CHANNEL ID 97 NAME "Channel Seven" SATID ffffff TPID 4d SID 7 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 98 NAME "Q German" SATID ffffff TPID 4d SID 47 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 99 NAME "Q French" SATID ffffff TPID 4d SID 48 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 9a NAME "Q Dutch" SATID ffffff TPID 4d SID 49 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 1b8 NAME "DTAG / T11" SATID ffffff TPID 4d SID b TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1b9 NAME "DTAG 50 / T12" SATID ffffff TPID 4d SID c TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1ba NAME "Telekom TV" SATID ffffff TPID 4d SID d TYPE 1 VPID 5b4 PCRPID 5b4 - CHANNEL ID 1bb NAME "Gerling / T26" SATID ffffff TPID 4d SID 1a TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1bc NAME "Hornbach-D / T36" SATID ffffff TPID 4d SID 24 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1bd NAME "Hornbach-NL / T38" SATID ffffff TPID 4d SID 26 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1be NAME "Hornbach-CZ / T39" SATID ffffff TPID 4d SID 27 TYPE 1 VPID 550 PCRPID 550 - CHANNEL ID 1bf NAME "Testkanal" SATID ffffff TPID 4d SID 63 TYPE 0 VPID 67c PCRPID 67c - CHANNEL ID 1c0 NAME "KENCAST" SATID ffffff TPID 4d SID 6f TYPE 0 PCRPID 42e - TRANSPONDER ID 1f40 SATID 0000 TYPE 1 FREQ 12302880 POL V SRATE 27500000 FEC 8 - CHANNEL ID 1c1 NAME "SLO-TV1" SATID ffffff TPID 1f40 SID c81 TYPE 1 VPID c8 PCRPID c8 - CHANNEL ID 1c2 NAME "SLO-TV2" SATID ffffff TPID 1f40 SID c82 TYPE 1 VPID cb PCRPID cb - CHANNEL ID 1c3 NAME "POLONIA 1" SATID ffffff TPID 1f40 SID c83 TYPE 0 VPID cd PCRPID cd - CHANNEL ID 1c4 NAME "SLO-RA1-INF" SATID ffffff TPID 1f40 SID c84 TYPE 0 APID fa PCRPID fa - CHANNEL ID 1c5 NAME "SLO-RA2" SATID ffffff TPID 1f40 SID c85 TYPE 0 APID fb PCRPID fb - CHANNEL ID 1c6 NAME "SLO-RA3" SATID ffffff TPID 1f40 SID c86 TYPE 0 APID fc PCRPID fc - CHANNEL ID 1c7 NAME "SUPER 1" SATID ffffff TPID 1f40 SID c87 TYPE 0 VPID cf PCRPID cf - CHANNEL ID 1c8 NAME "NAPOLI INT." SATID ffffff TPID 1f40 SID c8a TYPE 0 VPID f0 PCRPID f0 - CHANNEL ID 1c9 NAME "MAGIC" SATID ffffff TPID 1f40 SID c8b TYPE 0 VPID f5 PCRPID f5 - CHANNEL ID 1ca NAME "COUNTDOWN" SATID ffffff TPID 1f40 SID c8c TYPE 0 VPID eb PCRPID eb - CHANNEL ID 1cb NAME "TBNE" SATID ffffff TPID 1f40 SID c8d TYPE 0 VPID e6 PCRPID e6 - CHANNEL ID 1cc NAME "SICILSAT" SATID ffffff TPID 1f40 SID c8e TYPE 0 VPID e1 PCRPID e1 - TRANSPONDER ID 1fa4 SATID 0000 TYPE 1 FREQ 10892000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 1cd NAME "TVP1" SATID ffffff TPID 1fa4 SID 1 TYPE 1 VPID 101 APID 102 APID 17df TTPID 103 PCRPID 101 - CHANNEL ID 1ce NAME "TVP2" SATID ffffff TPID 1fa4 SID 2 TYPE 1 VPID 141 APID 142 PCRPID 141 - CHANNEL ID 1cf NAME "POLSAT1" SATID ffffff TPID 1fa4 SID 3 TYPE 1 - CHANNEL ID 1d0 NAME "TV4" SATID ffffff TPID 1fa4 SID 4 TYPE 1 VPID 101 APID 102 APID 17df TTPID 103 PCRPID 101 - CHANNEL ID 1d1 NAME "POLSAT2" SATID ffffff TPID 1fa4 SID 5 TYPE 1 VPID 141 APID 142 PCRPID 141 - CHANNEL ID 1d2 NAME "WOT" SATID ffffff TPID 1fa4 SID 6 TYPE 1 - CHANNEL ID 1d3 NAME "DISCOVERY" SATID ffffff TPID 1fa4 SID f TYPE 1 VPID 101 APID 102 APID 17df TTPID 103 PCRPID 101 - CHANNEL ID 1d4 NAME "ANIMAL PLANET" SATID ffffff TPID 1fa4 SID 10 TYPE 1 VPID 141 APID 142 PCRPID 141 - CHANNEL ID 1d5 NAME "EpgOpenTV" SATID ffffff TPID 1fa4 SID e66 TYPE 0 - TRANSPONDER ID 2008 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 - CHANNEL ID 1d6 NAME "P10" SATID ffffff TPID 2008 SID 2d51 TYPE 1 VPID a0 APID 50 APID 51 PCRPID b0 - CHANNEL ID 1d7 NAME "P11" SATID ffffff TPID 2008 SID 2d53 TYPE 1 VPID a1 APID 54 APID 55 PCRPID b0 - CHANNEL ID 1d8 NAME "P12" SATID ffffff TPID 2008 SID 2d55 TYPE 1 VPID a2 APID 58 APID 59 PCRPID b0 - CHANNEL ID 1d9 NAME "P13" SATID ffffff TPID 2008 SID 2d57 TYPE 1 VPID a3 APID 5c APID 5d PCRPID b0 - CHANNEL ID 1da NAME "P14" SATID ffffff TPID 2008 SID 2d59 TYPE 1 VPID a4 APID 60 APID 61 PCRPID b0 - CHANNEL ID 1db NAME "P15" SATID ffffff TPID 2008 SID 2d5b TYPE 1 VPID a5 APID 64 APID 65 PCRPID b0 - CHANNEL ID 1dc NAME "P16" SATID ffffff TPID 2008 SID 2d5d TYPE 1 VPID a6 APID 68 APID 69 PCRPID b0 - CHANNEL ID 1dd NAME "PREMIUM" SATID ffffff TPID 2008 SID 2d5f TYPE 1 PCRPID af - CHANNEL ID 1de NAME "+F1" SATID ffffff TPID 2008 SID 2d61 TYPE 1 VPID a0 APID 51 APID 298 PCRPID b0 - CHANNEL ID 1df NAME "+F1" SATID ffffff TPID 2008 SID 2d63 TYPE 1 VPID a1 APID 29a APID 55 PCRPID b0 - CHANNEL ID 1e0 NAME "+F1" SATID ffffff TPID 2008 SID 2d65 TYPE 1 VPID a2 APID 59 APID 29b PCRPID b0 - CHANNEL ID 1e1 NAME "+F1" SATID ffffff TPID 2008 SID 2d67 TYPE 1 VPID a3 APID 5d APID 2a2 PCRPID b0 - CHANNEL ID 1e2 NAME "+F1" SATID ffffff TPID 2008 SID 2d69 TYPE 1 VPID a4 APID 61 APID 60 PCRPID b0 - CHANNEL ID 1e3 NAME "+F1" SATID ffffff TPID 2008 SID 2d6b TYPE 1 VPID a5 APID 65 APID 2a4 PCRPID b0 - CHANNEL ID 1e4 NAME "+F1" SATID ffffff TPID 2008 SID 2d6d TYPE 1 VPID a6 APID 69 APID 29a PCRPID b0 - CHANNEL ID 1e5 NAME "RMC" SATID ffffff TPID 2008 SID 2d6f TYPE 1 PCRPID b8 - CHANNEL ID 1e6 NAME "R101" SATID ffffff TPID 2008 SID 2d70 TYPE 1 PCRPID b8 - CHANNEL ID 1e7 NAME "RRAD" SATID ffffff TPID 2008 SID 2d71 TYPE 1 PCRPID b8 - TRANSPONDER ID 206c SATID 0000 TYPE 1 FREQ 10892000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 1e8 NAME "ON" SATID ffffff TPID 206c SID 7 TYPE 1 VPID 161 APID 162 PCRPID 161 - CHANNEL ID 1e9 NAME "DLA-CIEBIE" SATID ffffff TPID 206c SID 8 TYPE 1 VPID 211 APID 212 PCRPID 211 - CHANNEL ID 1ea NAME "KOMEDIA" SATID ffffff TPID 206c SID 9 TYPE 1 VPID 161 APID 162 PCRPID 161 - CHANNEL ID 1eb NAME "SMYK" SATID ffffff TPID 206c SID a TYPE 1 VPID 211 APID 212 PCRPID 211 - CHANNEL ID 1ec NAME "RELAKS" SATID ffffff TPID 206c SID b TYPE 1 VPID 161 APID 162 PCRPID 161 - CHANNEL ID 1ed NAME "INFO" SATID ffffff TPID 206c SID c TYPE 1 VPID 211 APID 212 PCRPID 211 - CHANNEL ID 1ee NAME "POLSAT SPORT" SATID ffffff TPID 206c SID d TYPE 1 VPID 161 APID 162 PCRPID 161 - TRANSPONDER ID 20d0 SATID 0000 TYPE 1 FREQ 12379000 POL V SRATE 27500000 FEC 8 - CHANNEL ID 1ef NAME "Paris Premire" SATID ffffff TPID 20d0 SID bb9 TYPE 1 VPID bcd APID bd7 PCRPID bcd - CHANNEL ID 1f0 NAME "OCC HB3" SATID ffffff TPID 20d0 SID bba TYPE 0 VPID bce APID bd8 PCRPID bce - CHANNEL ID 1f1 NAME "TELE 24 Switzerland" SATID ffffff TPID 20d0 SID bbb TYPE 0 VPID bcf APID bd9 PCRPID bcf - CHANNEL ID 1f2 NAME "AIR MEDIA" SATID ffffff TPID 20d0 SID c0f TYPE 0 APID dd1 PCRPID dd1 - CHANNEL ID 1f3 NAME "Abu Dhabi TV" SATID ffffff TPID 20d0 SID bbc TYPE 0 VPID bd0 APID bda PCRPID bd0 - CHANNEL ID 1f4 NAME "EMIRAT FM 1" SATID ffffff TPID 20d0 SID c0b TYPE 0 APID dcd PCRPID dcd - CHANNEL ID 1f5 NAME "EMIRAT FM2" SATID ffffff TPID 20d0 SID c0c TYPE 0 APID dce PCRPID dce - CHANNEL ID 1f6 NAME "Radio Italia " SATID ffffff TPID 20d0 SID c09 TYPE 0 APID dcb PCRPID dcb - CHANNEL ID 1f7 NAME "EQUIDIA INTER." SATID ffffff TPID 20d0 SID beb TYPE 1 VPID cf9 APID d03 APID d0d APID d17 PCRPID cf9 - CHANNEL ID 1f8 NAME "RTV MONTENEGRO" SATID ffffff TPID 20d0 SID bbe TYPE 0 VPID bd2 APID bdc PCRPID bd2 - CHANNEL ID 1f9 NAME "Radio Montenegro" SATID ffffff TPID 20d0 SID c10 TYPE 0 APID dd2 PCRPID dd2 - CHANNEL ID 1fa NAME "SERTE TEST" SATID ffffff TPID 20d0 SID bbd TYPE 0 VPID bd1 PCRPID bd1 - CHANNEL ID 1fb NAME "GAME 1" SATID ffffff TPID 20d0 SID bbf TYPE 1 VPID bd3 APID bdd PCRPID bd3 - TRANSPONDER ID 0055 SATID 0000 TYPE 1 FREQ 12398781 POL H SRATE 27500000 FEC 8 - CHANNEL ID 1fc NAME "SF 2" SATID ffffff TPID 55 SID 38b TYPE 1 VPID a3 APID 5c APID 5d TTPID 29 PCRPID a3 - CHANNEL ID 1fd NAME "SRG SSR Sat Access" SATID ffffff TPID 55 SID 38e TYPE 0 VPID a5 APID 62 APID 63 TTPID 2f PCRPID a5 - CHANNEL ID 1fe NAME "SF 1" SATID ffffff TPID 55 SID 385 TYPE 1 VPID a0 APID 50 APID 51 TTPID 20 PCRPID a0 - CHANNEL ID 1ff NAME "TSR 1" SATID ffffff TPID 55 SID 386 TYPE 1 VPID a1 APID 54 APID 55 TTPID 23 PCRPID a1 - CHANNEL ID 200 NAME "TSI 1" SATID ffffff TPID 55 SID 387 TYPE 1 VPID a2 APID 58 APID 59 TTPID 26 PCRPID a2 - CHANNEL ID 201 NAME "TSR 2" SATID ffffff TPID 55 SID 38c TYPE 1 VPID a4 APID 60 APID 61 TTPID 2c PCRPID a4 - CHANNEL ID 202 NAME "TSI 2" SATID ffffff TPID 55 SID 38d TYPE 1 VPID a6 APID 64 APID 65 TTPID 32 PCRPID a6 - CHANNEL ID 203 NAME "OPTION MUSIQUE" SATID ffffff TPID 55 SID 3bd TYPE 0 APID cc PCRPID cc - CHANNEL ID 204 NAME "ESPACE 2" SATID ffffff TPID 55 SID 3be TYPE 0 APID cd PCRPID cd - CHANNEL ID 205 NAME "SRI-F-I" SATID ffffff TPID 55 SID 3b7 TYPE 0 APID c7 PCRPID c7 - CHANNEL ID 206 NAME "SRI-EUROPA" SATID ffffff TPID 55 SID 3b9 TYPE 0 VPID 230 APID c8 PCRPID c8 - TRANSPONDER ID 2198 SATID 0000 TYPE 1 FREQ 12341001 POL V SRATE 27500000 FEC 8 - CHANNEL ID 207 NAME "POLO" SATID ffffff TPID 2198 SID 2db5 TYPE 1 VPID a0 APID 50 PCRPID a0 - CHANNEL ID 208 NAME "PLANETE" SATID ffffff TPID 2198 SID 2db7 TYPE 1 VPID a1 APID 54 PCRPID a1 - CHANNEL ID 209 NAME "JIMMY" SATID ffffff TPID 2198 SID 2db9 TYPE 1 VPID a2 APID 58 PCRPID a2 - CHANNEL ID 20a NAME "INN" SATID ffffff TPID 2198 SID 2dbb TYPE 1 VPID a3 APID 5c PCRPID a3 - CHANNEL ID 20b NAME "CIN1" SATID ffffff TPID 2198 SID 2dbd TYPE 1 VPID a4 APID 60 PCRPID a4 - CHANNEL ID 20c NAME "CIN2" SATID ffffff TPID 2198 SID 2dbf TYPE 1 VPID a5 APID 64 PCRPID a5 - CHANNEL ID 20d NAME "CINC" SATID ffffff TPID 2198 SID 2dc1 TYPE 1 VPID a6 APID 68 PCRPID a6 - CHANNEL ID 20e NAME "SEASONS" SATID ffffff TPID 2198 SID 2dc3 TYPE 1 VPID a7 APID 6c PCRPID a7 - CHANNEL ID 20f NAME "WISHLINE" SATID ffffff TPID 2198 SID 2dc5 TYPE 1 VPID a8 APID 55 APID 5d APID 59 PCRPID a8 - CHANNEL ID 210 NAME "MARCOPOLO" SATID ffffff TPID 2198 SID 2dc7 TYPE 1 VPID a0 APID 50 APID 51 PCRPID a0 - TRANSPONDER ID 0049 SATID 0000 TYPE 1 FREQ 12436999 POL H SRATE 27500000 FEC 8 - CHANNEL ID 211 NAME "JAAM-E-JAM 1" SATID ffffff TPID 49 SID 1 TYPE 0 VPID a0 APID 50 APID 51 PCRPID a0 - CHANNEL ID 212 NAME "JAAM-E-JAM 2" SATID ffffff TPID 49 SID 2 TYPE 0 VPID a1 APID 52 APID 53 TTPID 21 PCRPID a1 - CHANNEL ID 213 NAME "SAHAR" SATID ffffff TPID 49 SID 3 TYPE 0 VPID a2 APID 54 APID 55 PCRPID a2 - CHANNEL ID 214 NAME "TEST(SAHAR)" SATID ffffff TPID 49 SID 4 TYPE 0 VPID a3 APID 56 APID 57 PCRPID a3 - CHANNEL ID 215 NAME "IRINN" SATID ffffff TPID 49 SID 5 TYPE 0 VPID a4 APID 58 APID 59 PCRPID a4 - CHANNEL ID 216 NAME "TEST 2" SATID ffffff TPID 49 SID 6 TYPE 0 VPID a5 APID 5a PCRPID a5 - CHANNEL ID 217 NAME "IRIB1 RADIO" SATID ffffff TPID 49 SID 7 TYPE 0 APID 51 PCRPID a0 - CHANNEL ID 218 NAME "IRIB ARABIC /International 1 Radio" SATID ffffff TPID 49 SID 8 TYPE 0 APID 53 PCRPID a1 - TRANSPONDER ID 013d SATID 0000 TYPE 1 FREQ 12460000 POL V SRATE 27500000 FEC 8 - TRANSPONDER ID 013e SATID 0000 TYPE 1 FREQ 12484000 POL V SRATE 27500000 FEC 8 - TRANSPONDER ID 22c4 SATID 0000 TYPE 1 FREQ 12475499 POL H SRATE 27500000 FEC 8 - CHANNEL ID 219 NAME "INT1 FAMILY RADIO" SATID ffffff TPID 22c4 SID 2977 TYPE 0 APID 3c1 PCRPID 3c1 - CHANNEL ID 21a NAME "RADIO 74" SATID ffffff TPID 22c4 SID 2974 TYPE 0 APID 399 PCRPID 399 - CHANNEL ID 21b NAME "R 74 INT." SATID ffffff TPID 22c4 SID 2975 TYPE 0 APID 3a3 PCRPID 3a3 - CHANNEL ID 21c NAME "FAMILY Radio" SATID ffffff TPID 22c4 SID 2976 TYPE 0 APID 3b7 PCRPID 3b7 - CHANNEL ID 21d NAME "Temp" SATID ffffff TPID 22c4 SID 296f TYPE 0 VPID 303 PCRPID 300 - CHANNEL ID 21e NAME "SPREE Radio" SATID ffffff TPID 22c4 SID 299c TYPE 0 APID 1f5 PCRPID 1f5 - CHANNEL ID 21f NAME " RVI ( VRT ) " SATID ffffff TPID 22c4 SID 2972 TYPE 0 APID 385 PCRPID 385 - CHANNEL ID 220 NAME "EbS" SATID ffffff TPID 22c4 SID 2969 TYPE 0 VPID 65 APID c9 APID ca APID cb APID cc APID cd APID ce APID cf APID d0 APID d1 APID d2 APID d3 APID d4 APID d5 APID d6 APID d7 APID d8 TTPID 12d PCRPID 65 - CHANNEL ID 221 NAME "MOU.2" SATID ffffff TPID 22c4 SID 296a TYPE 0 VPID 2a PCRPID 2a - CHANNEL ID 222 NAME "MIZIK TROPICAL" SATID ffffff TPID 22c4 SID 296e TYPE 0 VPID 1b3 APID 1b4 PCRPID 1b3 - CHANNEL ID 223 NAME "MIZIK TROPICAL Radio" SATID ffffff TPID 22c4 SID 2970 TYPE 0 APID 321 PCRPID 321 - CHANNEL ID 224 NAME "Framboise Nord (CH)" SATID ffffff TPID 22c4 SID 2978 TYPE 0 APID 3cb PCRPID 3cb - CHANNEL ID 225 NAME "Framboise Sud (CH)" SATID ffffff TPID 22c4 SID 2979 TYPE 0 APID 3d5 PCRPID 3d5 - CHANNEL ID 226 NAME "PINK PLUS" SATID ffffff TPID 22c4 SID 296d TYPE 1 VPID 134 APID 100 APID 101 PCRPID 24 - CHANNEL ID 227 NAME "LIBERTYTV.COM" SATID ffffff TPID 22c4 SID 296b TYPE 0 VPID 3ad APID 3ae PCRPID 3ad - CHANNEL ID 228 NAME "KURDSAT" SATID ffffff TPID 22c4 SID 297a TYPE 0 VPID 258 APID 259 PCRPID 1ffe - CHANNEL ID 229 NAME "test2" SATID ffffff TPID 22c4 SID 297c TYPE 0 VPID bb8 APID bb9 TTPID bba PCRPID bb8 - TRANSPONDER ID 2328 SATID 0000 TYPE 1 FREQ 12519840 POL V SRATE 27500000 FEC 8 - CHANNEL ID 22a NAME "HRT-TV1" SATID ffffff TPID 2328 SID 206d TYPE 1 VPID 64 APID 65 TTPID 66 PCRPID 64 - CHANNEL ID 22b NAME "HRT-TV2" SATID ffffff TPID 2328 SID 206e TYPE 1 VPID 67 APID 68 TTPID 66 PCRPID 67 - CHANNEL ID 22c NAME "HRT-TV3" SATID ffffff TPID 2328 SID 206f TYPE 1 VPID 69 APID 6a TTPID 66 PCRPID 69 - CHANNEL ID 22d NAME "HRT-HR1" SATID ffffff TPID 2328 SID 2071 TYPE 0 APID 96 PCRPID 96 - CHANNEL ID 22e NAME "HRT-HR2" SATID ffffff TPID 2328 SID 2072 TYPE 0 APID 97 PCRPID 97 - CHANNEL ID 22f NAME "HRT-HR3" SATID ffffff TPID 2328 SID 2073 TYPE 0 APID 98 PCRPID 98 - CHANNEL ID 230 NAME "SICILIA INTERNATIONAL" SATID ffffff TPID 2328 SID 2075 TYPE 0 VPID 1f5 PCRPID 1f5 - CHANNEL ID 231 NAME "HRT-NATIONAL" SATID ffffff TPID 2328 SID 2070 TYPE 1 VPID 6b APID 6c TTPID 66 PCRPID 6b - CHANNEL ID 232 NAME "HRT-TEST" SATID ffffff TPID 2328 SID 2074 TYPE 1 VPID 6d APID 6e TTPID 66 PCRPID 6d - CHANNEL ID 233 NAME "SARDEGNA UNO" SATID ffffff TPID 2328 SID 2076 TYPE 0 VPID 1f7 PCRPID 1f7 - CHANNEL ID 234 NAME "R-HRVATSKA" SATID ffffff TPID 2328 SID 2077 TYPE 0 APID 99 PCRPID 99 - CHANNEL ID 235 NAME "EuroMed" SATID ffffff TPID 2328 SID 2078 TYPE 0 VPID 1fe PCRPID 1fe - CHANNEL ID 236 NAME "TGRT" SATID ffffff TPID 2328 SID 2079 TYPE 0 VPID 1f9 PCRPID 1f9 - CHANNEL ID 237 NAME "HR-TEST" SATID ffffff TPID 2328 SID 207a TYPE 0 APID 9a PCRPID 9a - CHANNEL ID 238 NAME "MINI-BVN" SATID ffffff TPID 2328 SID 207b TYPE 0 VPID d2 PCRPID d6 - TRANSPONDER ID 238c SATID 0000 TYPE 1 FREQ 12713000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 239 NAME "SIMS 91 LARIO" SATID ffffff TPID 238c SID 2262 TYPE 0 - CHANNEL ID 23a NAME "SKYPLEX TXP91" SATID ffffff TPID 238c SID 2261 TYPE 0 - CHANNEL ID 23b NAME "Skygate 18" SATID ffffff TPID 238c SID 2 TYPE 0 - CHANNEL ID 23c NAME "MA12_2905" SATID ffffff TPID 238c SID 226a TYPE 0 PCRPID 1113 - CHANNEL ID 23d NAME "ES13_1107" SATID ffffff TPID 238c SID 226b TYPE 0 PCRPID 1114 - CHANNEL ID 23e NAME "ASTONv0107" SATID ffffff TPID 238c SID 226f TYPE 0 PCRPID 1112 - CHANNEL ID 23f NAME "sisal" SATID ffffff TPID 238c SID 1 TYPE 1 VPID 1104 PCRPID 1104 - CHANNEL ID 240 NAME "service" SATID ffffff TPID 238c SID 3 TYPE 1 VPID 1104 PCRPID 1104 - CHANNEL ID 241 NAME "Skyplex 19" SATID ffffff TPID 238c SID 231f TYPE 0 - CHANNEL ID 242 NAME "Network" SATID ffffff TPID 238c SID 2320 TYPE 0 - CHANNEL ID 243 NAME "www.travel" SATID ffffff TPID 238c SID 2321 TYPE 0 VPID 49c APID 49f APID 4a0 TTPID 49d PCRPID 49c - CHANNEL ID 244 NAME "MagicStar" SATID ffffff TPID 238c SID 2322 TYPE 0 APID 4a4 PCRPID 4a4 - CHANNEL ID 245 NAME "Skygate 8" SATID ffffff TPID 238c SID 22de TYPE 0 - CHANNEL ID 246 NAME "UDLR" SATID ffffff TPID 238c SID 22df TYPE 0 APID 19fd - CHANNEL ID 247 NAME "UDLR UDcast" SATID ffffff TPID 238c SID 22e0 TYPE 0 - CHANNEL ID 248 NAME "Skygate 17" SATID ffffff TPID 238c SID 2264 TYPE 0 - CHANNEL ID 249 NAME "Netshow" SATID ffffff TPID 238c SID 226d TYPE 0 - CHANNEL ID 24a NAME "MEDIOLANUM" SATID ffffff TPID 238c SID 226e TYPE 0 VPID 1006 PCRPID 1006 - CHANNEL ID 24b NAME "Skygate 10" SATID ffffff TPID 238c SID 22c5 TYPE 0 - CHANNEL ID 24c NAME "HitCast Data 1" SATID ffffff TPID 238c SID 22c6 TYPE 0 - CHANNEL ID 24d NAME "HitCast S.Amer." SATID ffffff TPID 238c SID 22c7 TYPE 0 - CHANNEL ID 24e NAME "Skygate 1" SATID ffffff TPID 238c SID 22ac TYPE 0 - CHANNEL ID 24f NAME "MonteCarloSat" SATID ffffff TPID 238c SID 22ad TYPE 0 VPID 1407 APID 1402 PCRPID 1407 - CHANNEL ID 250 NAME "Bulgaria Radio" SATID ffffff TPID 238c SID 227c TYPE 0 APID 1207 - CHANNEL ID 251 NAME "skygate 600" SATID ffffff TPID 238c SID 227a TYPE 0 - TRANSPONDER ID 23f0 SATID 0000 TYPE 1 FREQ 12558201 POL V SRATE 27500000 FEC 8 - CHANNEL ID 252 NAME "SKYPLEX TXP92" SATID ffffff TPID 23f0 SID 238d TYPE 0 - CHANNEL ID 253 SATID ffffff TPID 23f0 SID 2491 TYPE 0 - CHANNEL ID 254 SATID ffffff TPID 23f0 SID 2492 TYPE 0 VPID b09 APID b02 TTPID b0a PCRPID b09 - CHANNEL ID 255 SATID ffffff TPID 23f0 SID 2493 TYPE 0 VPID b09 TTPID b0a PCRPID b0d - CHANNEL ID 256 SATID ffffff TPID 23f0 SID 2494 TYPE 0 VPID b09 TTPID b0a PCRPID b04 - CHANNEL ID 257 NAME "SKY_4" SATID ffffff TPID 23f0 SID 2487 TYPE 0 - CHANNEL ID 258 NAME "ESP Int'l" SATID ffffff TPID 23f0 SID 2488 TYPE 1 VPID a0f APID a02 APID a03 TTPID a10 PCRPID a0f - CHANNEL ID 259 NAME "ESP Romanian" SATID ffffff TPID 23f0 SID 2489 TYPE 1 APID a09 PCRPID a2c - CHANNEL ID 25a NAME "ESP Dutch" SATID ffffff TPID 23f0 SID 248a TYPE 1 VPID a0f APID a04 TTPID a10 PCRPID a2c - CHANNEL ID 25b NAME "ESP PolisI" SATID ffffff TPID 23f0 SID 248b TYPE 1 APID a05 PCRPID a2c - CHANNEL ID 25c SATID ffffff TPID 23f0 SID 248c TYPE 0 VPID a0f APID a06 TTPID a10 PCRPID a2c - CHANNEL ID 25d SATID ffffff TPID 23f0 SID 248d TYPE 0 VPID a0f APID a04 TTPID a10 PCRPID a2c - CHANNEL ID 25e SATID ffffff TPID 23f0 SID 248e TYPE 0 VPID a0f APID a08 TTPID a10 PCRPID a2c - CHANNEL ID 25f SATID ffffff TPID 23f0 SID 248f TYPE 0 APID a02 APID a03 APID a04 APID a05 PCRPID a0f - CHANNEL ID 260 SATID ffffff TPID 23f0 SID 2423 TYPE 0 - TRANSPONDER ID 0143 SATID 0000 TYPE 1 FREQ 12573000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 0144 SATID 0000 TYPE 1 FREQ 12590000 POL H SRATE 27500000 FEC 8 - TRANSPONDER ID 24b8 SATID 0000 TYPE 1 FREQ 12596560 POL V SRATE 27500000 FEC 8 - CHANNEL ID 261 NAME "JSTV 1" SATID ffffff TPID 24b8 SID 2015 TYPE 0 VPID 7d0 APID 7d2 APID 7d3 APID 7d2 PCRPID 7d0 - CHANNEL ID 262 NAME "JSTV 2" SATID ffffff TPID 24b8 SID 2016 TYPE 0 VPID 7db APID 7dc APID 7dd APID 7dd PCRPID 7db - CHANNEL ID 263 NAME "MBC" SATID ffffff TPID 24b8 SID 2009 TYPE 0 VPID a0 APID 50 APID 51 TTPID 20 PCRPID a0 - CHANNEL ID 264 NAME "Service 2" SATID ffffff TPID 24b8 SID 200a TYPE 0 VPID a1 APID 54 PCRPID a1 - CHANNEL ID 265 NAME "NITV" SATID ffffff TPID 24b8 SID 200c TYPE 0 VPID a3 APID 5c PCRPID a3 - CHANNEL ID 266 NAME "SIMAYE AZADI" SATID ffffff TPID 24b8 SID 200f TYPE 0 VPID a6 APID 6a PCRPID a6 - CHANNEL ID 267 NAME "BET" SATID ffffff TPID 24b8 SID 2010 TYPE 0 VPID a7 APID 6c APID 6d PCRPID a7 - CHANNEL ID 268 NAME "CNNI" SATID ffffff TPID 24b8 SID 2011 TYPE 1 VPID a8 APID 70 APID 71 TTPID 38 PCRPID a8 - CHANNEL ID 269 NAME "EuroNews" SATID ffffff TPID 24b8 SID 2013 TYPE 0 VPID 8ad APID 8b7 APID 8b8 APID 8b9 APID 8ba APID 8bb APID 8bc APID 8bd APID 8be TTPID 300 PCRPID 8ad - CHANNEL ID 26a NAME "Canal Rural" SATID ffffff TPID 24b8 SID 2014 TYPE 0 VPID 911 APID 91b APID 91c PCRPID 911 - CHANNEL ID 26b NAME "MediaHW" SATID ffffff TPID 24b8 SID 2063 TYPE 0 PCRPID fa0 - TRANSPONDER ID 251c SATID 0000 TYPE 1 FREQ 12615000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 26c SATID ffffff TPID 251c SID fffe TYPE 0 - CHANNEL ID 26d NAME "MMOV" SATID ffffff TPID 251c SID f46 TYPE 1 VPID a10 PCRPID a00 - CHANNEL ID 26e NAME "MMOV" SATID ffffff TPID 251c SID f49 TYPE 1 VPID a12 PCRPID a01 - CHANNEL ID 26f NAME "MMOV" SATID ffffff TPID 251c SID f4d TYPE 1 VPID a14 PCRPID a02 - CHANNEL ID 270 NAME "MMOV" SATID ffffff TPID 251c SID f4e TYPE 1 VPID a16 PCRPID a03 - CHANNEL ID 271 NAME "MMOV" SATID ffffff TPID 251c SID f4f TYPE 1 VPID a18 PCRPID a04 - CHANNEL ID 272 NAME "MMOV" SATID ffffff TPID 251c SID f50 TYPE 1 VPID a1a PCRPID a05 - CHANNEL ID 273 NAME "SC 1" SATID ffffff TPID 251c SID f51 TYPE 1 VPID a07 PCRPID a06 - CHANNEL ID 274 NAME "SC 2" SATID ffffff TPID 251c SID f54 TYPE 1 VPID a0a PCRPID a06 - CHANNEL ID 275 NAME "SC 3" SATID ffffff TPID 251c SID f57 TYPE 1 VPID a0d PCRPID a06 - CHANNEL ID 276 NAME "MC20" SATID ffffff TPID 251c SID f5f TYPE 1 APID 900 PCRPID 900 - CHANNEL ID 277 NAME "MC21" SATID ffffff TPID 251c SID f62 TYPE 1 APID 901 PCRPID 901 - CHANNEL ID 278 NAME "MC22" SATID ffffff TPID 251c SID f65 TYPE 1 APID 902 PCRPID 902 - CHANNEL ID 279 NAME "MC23" SATID ffffff TPID 251c SID f68 TYPE 1 APID 903 PCRPID 903 - CHANNEL ID 27a NAME "MC24" SATID ffffff TPID 251c SID f6b TYPE 1 APID 904 PCRPID 904 - CHANNEL ID 27b NAME "MC25" SATID ffffff TPID 251c SID f6e TYPE 1 APID 905 PCRPID 905 - CHANNEL ID 27c NAME "MC26" SATID ffffff TPID 251c SID f71 TYPE 1 APID 906 PCRPID 906 - CHANNEL ID 27d NAME "MC27" SATID ffffff TPID 251c SID f74 TYPE 1 APID 907 PCRPID 907 - CHANNEL ID 27e NAME "MC28" SATID ffffff TPID 251c SID f77 TYPE 1 APID 908 PCRPID 908 - CHANNEL ID 27f NAME "MC29" SATID ffffff TPID 251c SID f7a TYPE 1 APID 909 PCRPID 909 - CHANNEL ID 280 NAME "MC30" SATID ffffff TPID 251c SID f7d TYPE 1 APID 90a PCRPID 90a - CHANNEL ID 281 NAME "MC31" SATID ffffff TPID 251c SID f80 TYPE 1 APID 90b PCRPID 90b - CHANNEL ID 282 NAME "MC32" SATID ffffff TPID 251c SID f83 TYPE 1 APID 90c PCRPID 90c - CHANNEL ID 283 NAME "MC33" SATID ffffff TPID 251c SID f86 TYPE 1 APID 90d PCRPID 90d - CHANNEL ID 284 NAME "MC34" SATID ffffff TPID 251c SID f89 TYPE 1 APID 90e PCRPID 90e - CHANNEL ID 285 NAME "MC35" SATID ffffff TPID 251c SID f8c TYPE 1 APID 90f PCRPID 90f - CHANNEL ID 286 NAME "MC36" SATID ffffff TPID 251c SID f8f TYPE 1 APID 910 PCRPID 910 - CHANNEL ID 287 NAME "MC37" SATID ffffff TPID 251c SID f92 TYPE 1 APID 911 PCRPID 911 - CHANNEL ID 288 NAME "MC38" SATID ffffff TPID 251c SID f95 TYPE 1 APID 912 PCRPID 912 - CHANNEL ID 289 NAME "MC39" SATID ffffff TPID 251c SID f98 TYPE 1 APID 913 PCRPID 913 - TRANSPONDER ID 2580 SATID 0000 TYPE 1 FREQ 12635000 POL V SRATE 27500000 FEC 8 - CHANNEL ID 28a SATID ffffff TPID 2580 SID fffe TYPE 0 - CHANNEL ID 28b NAME "SC 4" SATID ffffff TPID 2580 SID fa1 TYPE 1 VPID a90 PCRPID a83 - CHANNEL ID 28c NAME "SC 5" SATID ffffff TPID 2580 SID fa2 TYPE 1 VPID a88 PCRPID a83 - CHANNEL ID 28d NAME "SC 6" SATID ffffff TPID 2580 SID fa3 TYPE 1 VPID a8d PCRPID a83 - CHANNEL ID 28e NAME "MMOV" SATID ffffff TPID 2580 SID fa7 TYPE 1 VPID a84 PCRPID a80 - CHANNEL ID 28f NAME "MMOV" SATID ffffff TPID 2580 SID faa TYPE 1 VPID a86 PCRPID a81 - CHANNEL ID 290 NAME "MMOV" SATID ffffff TPID 2580 SID fb0 TYPE 1 VPID a93 PCRPID a82 - CHANNEL ID 291 NAME "MMOV" SATID ffffff TPID 2580 SID fb3 TYPE 1 VPID a95 PCRPID a8b - CHANNEL ID 292 NAME "MMOV" SATID ffffff TPID 2580 SID fb6 TYPE 1 VPID a97 PCRPID a8c - CHANNEL ID 293 NAME "MMOV" SATID ffffff TPID 2580 SID fb9 TYPE 1 VPID b03 PCRPID b00 - CHANNEL ID 294 NAME "MMOV" SATID ffffff TPID 2580 SID fbc TYPE 1 VPID b05 PCRPID b01 - TRANSPONDER ID 25e4 SATID 0000 TYPE 1 FREQ 12654000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 295 NAME "Sharjah Arabsat Bouquet" SATID ffffff TPID 25e4 SID 1 TYPE 0 VPID 488 PCRPID 488 - CHANNEL ID 296 NAME "Qatar Arabsat Bouquet" SATID ffffff TPID 25e4 SID 2 TYPE 0 VPID 4ec PCRPID 4ec - CHANNEL ID 297 NAME "Saudi 1 Arabsat Bouquet" SATID ffffff TPID 25e4 SID 3 TYPE 0 VPID 550 PCRPID 550 - CHANNEL ID 298 NAME "Kuwait Arabsat Bouquet" SATID ffffff TPID 25e4 SID 4 TYPE 0 VPID 5b4 PCRPID 5b4 - CHANNEL ID 299 NAME "Libya Arabsat Bouquet" SATID ffffff TPID 25e4 SID 5 TYPE 0 VPID 618 PCRPID 618 - CHANNEL ID 29a NAME "Sudan Arabsat Bouquet" SATID ffffff TPID 25e4 SID 6 TYPE 0 VPID 67c PCRPID 67c - CHANNEL ID 29b NAME "Oman Arabsat Bouquet" SATID ffffff TPID 25e4 SID 7 TYPE 0 VPID 6e0 PCRPID 6e0 - CHANNEL ID 29c NAME "Jordan Arabsat Bouquet" SATID ffffff TPID 25e4 SID 8 TYPE 0 VPID 744 PCRPID 744 - CHANNEL ID 29d NAME "IRAQ TV" SATID ffffff TPID 25e4 SID 9 TYPE 0 VPID 7a8 PCRPID 7a8 - CHANNEL ID 29e NAME "Dubai Sport" SATID ffffff TPID 25e4 SID a TYPE 0 VPID 424 PCRPID 424 - CHANNEL ID 29f NAME "Qatar A2 Arabsat Bouquet" SATID ffffff TPID 25e4 SID c TYPE 0 APID 4c5 PCRPID 4c5 - CHANNEL ID 2a0 NAME "Saudi1 A2 Arabsat Bouquet" SATID ffffff TPID 25e4 SID d TYPE 0 APID 529 PCRPID 529 - CHANNEL ID 2a1 NAME "Kuwait A2 Arabsat Bouquet" SATID ffffff TPID 25e4 SID e TYPE 0 APID 58d PCRPID 58d - CHANNEL ID 2a2 NAME "Jordan A2 Arabsat Bouquet" SATID ffffff TPID 25e4 SID 12 TYPE 0 APID 71d PCRPID 71d - CHANNEL ID 2a3 NAME "Radio dubai sport" SATID ffffff TPID 25e4 SID 13 TYPE 0 APID 3fd PCRPID 3fd - TRANSPONDER ID 2648 SATID 0000 TYPE 1 FREQ 12673000 POL V SRATE 27500000 FEC 8 - CHANNEL ID 2a4 NAME "Digitaly" SATID ffffff TPID 2648 SID 106b TYPE 0 VPID dc APID dd APID de PCRPID dc - CHANNEL ID 2a5 NAME "Telemarket" SATID ffffff TPID 2648 SID 1073 TYPE 0 VPID 15e APID 15f PCRPID 15e - CHANNEL ID 2a6 NAME "Internet data 1" SATID ffffff TPID 2648 SID 1074 TYPE 0 TTPID 11f - CHANNEL ID 2a7 NAME "eVision" SATID ffffff TPID 2648 SID 1076 TYPE 0 VPID 168 APID 169 APID 16a APID 1be6 PCRPID 168 - CHANNEL ID 2a8 NAME "ANNI 60" SATID ffffff TPID 2648 SID 1086 TYPE 0 APID fa PCRPID fa - CHANNEL ID 2a9 NAME "R. Reporter" SATID ffffff TPID 2648 SID 1087 TYPE 0 APID fb PCRPID fb - CHANNEL ID 2aa NAME "Radio Italia S.M.I." SATID ffffff TPID 2648 SID 1088 TYPE 0 APID fc PCRPID fc - CHANNEL ID 2ab NAME "R. Tour" SATID ffffff TPID 2648 SID 1089 TYPE 0 APID fd PCRPID fd - CHANNEL ID 2ac NAME "R.Rinascente" SATID ffffff TPID 2648 SID 108a TYPE 0 APID fe PCRPID fe - CHANNEL ID 2ad NAME "R. Cooky" SATID ffffff TPID 2648 SID 108b TYPE 0 APID ff PCRPID ff - CHANNEL ID 2ae NAME "RadioBaby" SATID ffffff TPID 2648 SID 108c TYPE 0 APID 100 PCRPID 100 - CHANNEL ID 2af NAME "McDonalds" SATID ffffff TPID 2648 SID 108d TYPE 0 APID 101 PCRPID 101 - CHANNEL ID 2b0 NAME "TRBuonconsiglio" SATID ffffff TPID 2648 SID 108e TYPE 0 APID 191 PCRPID 191 - CHANNEL ID 2b1 NAME "R-Radio" SATID ffffff TPID 2648 SID 108f TYPE 0 APID 192 PCRPID 192 - CHANNEL ID 2b2 NAME "R. Donna" SATID ffffff TPID 2648 SID 1090 TYPE 0 APID 193 PCRPID 193 - CHANNEL ID 2b3 NAME "R. Reporter 2" SATID ffffff TPID 2648 SID 1091 TYPE 0 APID 194 PCRPID 194 - CHANNEL ID 2b4 NAME "R. West" SATID ffffff TPID 2648 SID 1092 TYPE 0 APID 195 PCRPID 195 - CHANNEL ID 2b5 NAME "Melodia Russia" SATID ffffff TPID 2648 SID 1093 TYPE 0 VPID 19f6 APID 196 PCRPID 196 - CHANNEL ID 2b6 NAME "Padre Pio" SATID ffffff TPID 2648 SID 1094 TYPE 0 APID 197 PCRPID 197 - CHANNEL ID 2b7 NAME "Thai TV5" SATID ffffff TPID 2648 SID 1069 TYPE 0 VPID c8 APID c9 APID ca PCRPID c8 - CHANNEL ID 2b8 NAME "Studio Europa" SATID ffffff TPID 2648 SID 106c TYPE 0 VPID e6 APID e7 PCRPID e6 - CHANNEL ID 2b9 NAME "Video Italia" SATID ffffff TPID 2648 SID 1072 TYPE 0 VPID 154 APID 155 APID 156 PCRPID 154 - TRANSPONDER ID 26ac SATID 0000 TYPE 1 FREQ 12692000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 2ba NAME "PASSIONS" SATID ffffff TPID 26ac SID 1f5 TYPE 0 VPID a0 PCRPID a0 - CHANNEL ID 2bb NAME "ONYX" SATID ffffff TPID 26ac SID 1f6 TYPE 0 VPID a1 PCRPID a1 - CHANNEL ID 2bc NAME "MANGAS" SATID ffffff TPID 26ac SID 1f7 TYPE 1 VPID a2 APID 58 TTPID 26 PCRPID a2 - CHANNEL ID 2bd NAME "ENCYCLOPEDIA" SATID ffffff TPID 26ac SID 1f8 TYPE 1 VPID a3 APID 5c TTPID 29 PCRPID a3 - CHANNEL ID 2be NAME "POLAR" SATID ffffff TPID 26ac SID 1f9 TYPE 1 VPID a4 APID 60 TTPID 2c PCRPID a4 - CHANNEL ID 2bf NAME "CINE PALACE" SATID ffffff TPID 26ac SID 1fa TYPE 1 VPID a5 APID 64 TTPID 2f PCRPID a5 - CHANNEL ID 2c0 NAME "ROMANCE" SATID ffffff TPID 26ac SID 1fb TYPE 1 VPID a6 APID 68 TTPID 32 PCRPID a6 - CHANNEL ID 2c1 NAME "RIRE" SATID ffffff TPID 26ac SID 1fc TYPE 1 VPID a7 APID 6c TTPID 35 PCRPID a7 - CHANNEL ID 2c2 NAME "ACTION" SATID ffffff TPID 26ac SID 1fd TYPE 1 VPID a8 APID 70 TTPID 38 PCRPID a8 - CHANNEL ID 2c3 NAME "ABsat test RADIO" SATID ffffff TPID 26ac SID 1fe TYPE 1 APID 65 PCRPID a5 - TRANSPONDER ID 2710 SATID 0000 TYPE 1 FREQ 12713000 POL V SRATE 27500000 FEC 8 - CHANNEL ID 2c4 SATID ffffff TPID 2710 SID fffe TYPE 0 - CHANNEL ID 2c5 NAME "MMOV" SATID ffffff TPID 2710 SID 10d0 TYPE 1 VPID a03 PCRPID a00 - CHANNEL ID 2c6 NAME "MMOV" SATID ffffff TPID 2710 SID 10d3 TYPE 1 VPID a05 PCRPID a01 - CHANNEL ID 2c7 NAME "MMOV" SATID ffffff TPID 2710 SID 10d6 TYPE 1 VPID a07 PCRPID a02 - CHANNEL ID 2c8 NAME "MMOV" SATID ffffff TPID 2710 SID 10d9 TYPE 1 VPID 904 PCRPID 900 - CHANNEL ID 2c9 NAME "MMOV" SATID ffffff TPID 2710 SID 10dc TYPE 1 VPID 90a PCRPID 901 - CHANNEL ID 2ca NAME "MMOV" SATID ffffff TPID 2710 SID 10e4 TYPE 1 VPID 906 PCRPID 902 - CHANNEL ID 2cb NAME "MMOV" SATID ffffff TPID 2710 SID 10e7 TYPE 1 VPID 908 PCRPID 903 - TRANSPONDER ID 2774 SATID 0000 TYPE 1 FREQ 12713000 POL H SRATE 27500000 FEC 8 - CHANNEL ID 2cc SATID ffffff TPID 2774 SID fffe TYPE 0 - CHANNEL ID 2cd NAME "SINT" SATID ffffff TPID 2774 SID 2262 TYPE 1 - CHANNEL ID 2ce NAME "info" SATID ffffff TPID 2774 SID 2264 TYPE 1 VPID 205 PCRPID 1ffe - CHANNEL ID 2cf NAME "SINT" SATID ffffff TPID 2774 SID 2266 TYPE 1 - CHANNEL ID 2d0 NAME "CFN" SATID ffffff TPID 2774 SID 2269 TYPE 1 VPID 20b PCRPID 1ffe - CHANNEL ID 2d1 NAME "SINT" SATID ffffff TPID 2774 SID 226c TYPE 1 - CHANNEL ID 2d2 NAME "duel" SATID ffffff TPID 2774 SID 226f TYPE 1 VPID 206 PCRPID 1ffe - CHANNEL ID 2d3 NAME "comedy" SATID ffffff TPID 2774 SID 2272 TYPE 1 VPID 203 PCRPID 1ffe - CHANNEL ID 2d4 NAME "fox kids" SATID ffffff TPID 2774 SID 2275 TYPE 1 VPID 201 PCRPID 1ffe diff --git a/Tools/dvbrc2vdr/test.conf b/Tools/dvbrc2vdr/test.conf deleted file mode 100644 index 31dddb777..000000000 --- a/Tools/dvbrc2vdr/test.conf +++ /dev/null @@ -1,799 +0,0 @@ -DISCOVERY:10719:v:1:27500:8190:8190:0:4402 -RTL7:10719:v:1:27500:8190:8190:0:4403 -TV POLONIA:10719:v:1:27500:8190:8190:0:4404 -EUROSPORT:10719:v:1:27500:8190:8190:0:4405 -PLANETE:10719:v:1:27500:8190:8190:0:4406 -SEASONS:10719:v:1:27500:8190:8190:0:4407 -VIVA Polska:10719:v:1:27500:8190:8190:0:4408 -MULTIMUSIC 4:10719:v:1:27500:8190:123:0:4440 -EPG:10719:v:1:27500:8190:8190:0:4450 -CYFRA+ GRY:10719:v:1:27500:8190:8190:0:4460 -Guide LC:0:v:1:27500:8190:8030:0:2000 -Cinestar 1:0:v:1:27500:120:130:0:1201 -Cinestar 2:0:v:1:27500:220:230:0:1202 -Cinetoile:0:v:1:27500:320:330:0:1203 -Shopping Avenue:0:v:1:27500:420:430:0:1204 -Srie Club :0:v:1:27500:520:530:0:1205 -FUN TV:0:v:1:27500:620:630:0:1206 -Teva:0:v:1:27500:720:730:0:1207 -M6 Music:0:v:1:27500:820:830:0:1208 -Club Tlachat:0:v:1:27500:920:930:0:1209 -INFOSPORT:0:v:1:27500:120:130:0:1401 -Rgions:0:v:1:27500:220:230:0:1402 -Mezzo:0:v:1:27500:320:330:0:1403 -01 01 15 97:0:v:1:27500:8190:8190:0:1483 -01 01 17 97:0:v:1:27500:8190:8190:0:1485 -01 02 17 97:0:v:1:27500:8190:8190:0:1486 -01 02 15 97:0:v:1:27500:8190:8190:0:1488 -01 02 15 96:0:v:1:27500:8190:8190:0:1489 -01 03 17 10:0:v:1:27500:8190:8190:0:1490 -01 03 15 10:0:v:1:27500:8190:8190:0:1491 -Festival:0:v:1:27500:420:430:0:1404 -HISTOIRE :0:v:1:27500:520:530:0:1405 -Tltoon:0:v:1:27500:620:630:0:1406 -Odysse :0:v:1:27500:720:730:0:1407 -France Musiques:0:v:1:27500:8190:830:0:1418 -Hector:0:v:1:27500:8190:831:0:1419 -FIP:0:v:1:27500:8190:832:0:1420 -France Inter:0:v:1:27500:8190:833:0:1421 -France Info:0:v:1:27500:8190:834:0:1422 -Elisa:0:v:1:27500:8190:835:0:1423 -France Culture:0:v:1:27500:8190:836:0:1424 -Radio Bleue:0:v:1:27500:8190:837:0:1425 -Le Mouv:0:v:1:27500:8190:838:0:1426 -TV5:0:v:1:27500:920:930:0:1409 -CENTRONICS:0:v:1:27500:8190:8190:0:2000 -FRANCE 2 :0:v:1:27500:320:8190:0:1104 -FRANCE 3:0:v:1:27500:520:8190:0:1106 -Crdit Agricole:0:v:1:27500:8190:5333:0:5301 -tps foot:0:v:1:27500:8190:5230:0:5200 -LCI:0:v:1:27500:120:130:0:1101 -EUROSPORT:0:v:1:27500:220:230:0:1102 -FRANCE 2:0:v:1:27500:320:8190:0:1103 -FRANCE 3:0:v:1:27500:520:8190:0:1105 -I TELEVISION:0:v:1:27500:820:830:0:1108 -TV Mail alphatest:0:v:1:27500:8190:8190:0:5701 -CHAINE FI:0:v:1:27500:8190:5331:0:5300 -caisse d'pargne:0:v:1:27500:8190:8190:0:5303 -TV Mail:0:v:1:27500:8190:8190:0:5700 -CANAL+:10892:h:1:27500:8190:8190:0:4801 -CANAL+ ӣTY:10892:h:1:27500:8190:8190:0:4802 -TMT:10892:h:1:27500:8190:8190:0:4804 -ALE KINO!:10892:h:1:27500:8190:8190:0:4805 -MINIMAX:10892:h:1:27500:8190:8190:0:4806 -TVP 1:10892:h:1:27500:8190:8190:0:4807 -TVP 2:10892:h:1:27500:8190:8190:0:4808 -CANAL+ NIEBIESKI:10892:h:1:27500:8190:8190:0:4809 -EPG:10892:h:1:27500:8190:8190:0:4850 -Multivision:0:v:1:27500:320:8190:0:1603 -Grand Classique:0:v:1:27500:8190:830:0:1650 -Symphonies:0:v:1:27500:8190:831:0:1651 -Baroque:0:v:1:27500:8190:832:0:1652 -Opra:0:v:1:27500:8190:833:0:1653 -Contemporain:0:v:1:27500:8190:834:0:1654 -Relaxation:0:v:1:27500:8190:835:0:1655 -Blues:0:v:1:27500:8190:836:0:1656 -Jazz:0:v:1:27500:8190:837:0:1657 -Big Band:0:v:1:27500:8190:838:0:1658 -Jazz Moderne:0:v:1:27500:8190:839:0:1659 -Les Tubes Franais:0:v:1:27500:8190:840:0:1660 -RFO SAT:0:v:1:27500:120:130:0:1601 -Appli D1 LC:0:v:1:27500:8190:8190:0:1680 -Cinefaz:0:v:1:27500:220:230:0:1602 -TurboPC:0:v:1:27500:8190:8190:0:2801 -MTV2:0:v:1:27500:720:730:0:1607 -Rire et chansons:0:v:1:27500:8190:930:0:1630 -Radio J:0:v:1:27500:8190:931:0:1631 -Mosqueteiros:0:v:1:27500:8190:932:0:1632 -Abysse:0:v:1:27500:8190:933:0:1633 -RMC:0:v:1:27500:8190:935:0:1635 -Radio Junior:0:v:1:27500:8190:936:0:1636 -NETRADIO:0:v:1:27500:8190:937:0:1637 -Nostalgie:0:v:1:27500:8190:938:0:1638 -Skyrock:0:v:1:27500:8190:939:0:1639 -Radio Coutoisie:0:v:1:27500:8190:940:0:1640 -La Voix des Pays:0:v:1:27500:8190:941:0:1641 -INFO EXPRESS:0:v:1:27500:8190:5530:0:5500 -METEO:0:v:1:27500:8190:5830:0:5800 -X X L:0:v:1:27500:8190:8190:0:5400 -Multivision Cinma:0:v:1:27500:8190:8190:0:7200 -Multivision Sport:0:v:1:27500:8190:8190:0:7300 -Multivision Spectacle:0:v:1:27500:8190:8190:0:7400 -Test OTV8:12673:h:1:27500:8190:8190:0:7527 -Test OTV9:12673:h:1:27500:8190:8190:0:7528 -Test OTV10:12673:h:1:27500:8190:8190:0:7529 -Test OTV11:12673:h:1:27500:513:8190:0:7530 -Test31:12673:h:1:27500:512:650:0:7501 -CNN:12673:h:1:27500:513:660:0:7502 -Q24:12673:h:1:27500:514:691:0:7503 -Test34:12673:h:1:27500:515:680:0:7504 -Test35:12673:h:1:27500:516:690:0:7505 -Test OTV1:12673:h:1:27500:8190:8190:0:7520 -Test OTV2:12673:h:1:27500:8190:8190:0:7521 -Test OTV3:12673:h:1:27500:8190:8190:0:7522 -Test OTV4:12673:h:1:27500:8190:8190:0:7523 -Test OTV5:12673:h:1:27500:8190:8190:0:7524 -Test OTV6:12673:h:1:27500:8190:8190:0:7525 -Test OTV7:12673:h:1:27500:8190:8190:0:7526 -Test OTV7:12673:h:1:27500:8190:8190:0:7540 -Test OTV7:12673:h:1:27500:8190:8190:0:7541 -Telekom TV:11095:h:1:27500:32:8190:0:3711 -FantasticOverOpal:11095:h:1:27500:32:8190:0:3712 -Gilat:11095:h:1:27500:32:8190:0:3713 -Siemens TV:11095:h:1:27500:32:8190:0:3716 -S-TV:11095:h:1:27500:32:8190:0:3717 -Optibase Encoder:11095:h:1:27500:32:8190:0:3718 -FantasticOverOpal:11095:h:1:27500:8190:8190:0:3702 -Deutsche Bank / T1:11303:h:1:27500:1160:8190:0:1 -Animal Planet:11303:h:1:27500:1160:8190:0:10 -Discovery E Europe-English:11303:h:1:27500:1260:8190:0:20 -Wuerth KG / T21:11303:h:1:27500:1360:8190:0:21 -Discovery Italy:11303:h:1:27500:1360:8190:0:30 -BTI / T31:11303:h:1:27500:1360:8190:0:31 -Discovery Russia:11303:h:1:27500:1460:8190:0:40 -K-TV (MetroMux) / T41:11303:h:1:27500:1960:8190:0:41 -Animal Planet EE:11303:h:1:27500:1560:8190:0:50 -Animal Planet - Russian:11303:h:1:27500:1560:8190:0:51 -Discovery Netherlands:11303:h:1:27500:1660:8190:0:60 -Q English:11303:h:1:27500:1760:8190:0:70 -Travel and Adventure:11303:h:1:27500:1860:8190:0:80 -Travel and Adventure- Russian:11303:h:1:27500:1860:8190:0:81 -New DCP:11303:h:1:27500:8190:1220:0:300 -CCP:11303:h:1:27500:1260:8190:0:301 -Deutsche Bank / T2:11303:h:1:27500:1260:8190:0:2 -Channel Three:11303:h:1:27500:1360:8190:0:3 -Channel Four:11303:h:1:27500:1460:8190:0:4 -Channel Five:11303:h:1:27500:1560:8190:0:5 -Channel 6 = Sat 7 Arabic:11303:h:1:27500:1660:8190:0:6 -Channel Seven:11303:h:1:27500:1760:8190:0:7 -Q German:11303:h:1:27500:1760:8190:0:71 -Q French:11303:h:1:27500:1760:8190:0:72 -Q Dutch:11303:h:1:27500:1760:8190:0:73 -DTAG / T11:11303:h:1:27500:1360:8190:0:11 -DTAG 50 / T12:11303:h:1:27500:1360:8190:0:12 -Telekom TV:11303:h:1:27500:1460:8190:0:13 -Gerling / T26:11303:h:1:27500:1360:8190:0:26 -Hornbach-D / T36:11303:h:1:27500:1360:8190:0:36 -Hornbach-NL / T38:11303:h:1:27500:1360:8190:0:38 -Hornbach-CZ / T39:11303:h:1:27500:1360:8190:0:39 -Testkanal:11303:h:1:27500:1660:8190:0:99 -KENCAST:11303:h:1:27500:8190:8190:0:111 -SAT.1 CH:11604:h:1:27500:101:102:0:601 -KBT Channel SUN:11604:h:1:27500:111:112:0:603 -big FM:11604:h:1:27500:8190:113:0:604 -Event:11604:h:1:27500:160:161:0:602 -Deutsche Bank / T1:11642:h:1:27500:1160:8190:0:1 -Animal Planet:11642:h:1:27500:1160:8190:0:10 -Discovery E Europe-English:11642:h:1:27500:1260:8190:0:20 -Wuerth KG / T21:11642:h:1:27500:1360:8190:0:21 -Discovery Italy:11642:h:1:27500:1360:8190:0:30 -BTI / T31:11642:h:1:27500:1360:8190:0:31 -Discovery Russia:11642:h:1:27500:1460:8190:0:40 -K-TV (MetroMux) / T41:11642:h:1:27500:1960:8190:0:41 -Animal Planet EE:11642:h:1:27500:1560:8190:0:50 -Animal Planet - Russian:11642:h:1:27500:1560:8190:0:51 -Discovery Netherlands:11642:h:1:27500:1660:8190:0:60 -Q English:11642:h:1:27500:1760:8190:0:70 -Travel and Adventure:11642:h:1:27500:1860:8190:0:80 -Travel and Adventure- Russian:11642:h:1:27500:1860:8190:0:81 -New DCP:11642:h:1:27500:8190:1220:0:300 -CCP:11642:h:1:27500:1260:8190:0:301 -Deutsche Bank / T2:11642:h:1:27500:1260:8190:0:2 -Channel Three:11642:h:1:27500:1360:8190:0:3 -Channel Four:11642:h:1:27500:1460:8190:0:4 -Channel Five:11642:h:1:27500:1560:8190:0:5 -Channel 6 = Sat 7 Arabic:11642:h:1:27500:1660:8190:0:6 -Channel Seven:11642:h:1:27500:1760:8190:0:7 -Q German:11642:h:1:27500:1760:8190:0:71 -Q French:11642:h:1:27500:1760:8190:0:72 -Q Dutch:11642:h:1:27500:1760:8190:0:73 -DTAG / T11:11642:h:1:27500:1360:8190:0:11 -DTAG 50 / T12:11642:h:1:27500:1360:8190:0:12 -Telekom TV:11642:h:1:27500:1460:8190:0:13 -Gerling / T26:11642:h:1:27500:1360:8190:0:26 -Hornbach-D / T36:11642:h:1:27500:1360:8190:0:36 -Hornbach-NL / T38:11642:h:1:27500:1360:8190:0:38 -Hornbach-CZ / T39:11642:h:1:27500:1360:8190:0:39 -Testkanal:11642:h:1:27500:1660:8190:0:99 -KENCAST:11642:h:1:27500:8190:8190:0:111 -AB 1:11681:h:1:27500:160:80:0:201 -AB MOTEURS:11681:h:1:27500:161:84:0:202 -ANIMAUX:11681:h:1:27500:162:88:0:203 -CHASSE ET PECHE:11681:h:1:27500:163:92:0:204 -XXL:11681:h:1:27500:164:96:0:205 -MUSIQUE CLASSIQUE:11681:h:1:27500:165:100:0:206 -ESCALES:11681:h:1:27500:166:104:0:207 -FIT/chane HISTOIRE:11681:h:1:27500:167:108:0:208 -RFM TV:11681:h:1:27500:168:112:0:209 -EDTV DRAMA:11744:h:1:27500:4898:8190:0:9504 -EDTV RADIO 02:11744:h:1:27500:4898:8190:0:9524 -EDTV RADIO 01:11744:h:1:27500:4898:8190:0:9523 -EDTV SPORT:11744:h:1:27500:4898:8190:0:9502 -EDTV BUSINESS:11744:h:1:27500:4898:8190:0:9503 -RAI1:11765:v:1:27500:160:8190:0:3401 -RAI2:11765:v:1:27500:161:8190:0:3402 -RAI3:11765:v:1:27500:162:8190:0:3403 -Rai Way TEST1:11765:v:1:27500:515:8190:0:3404 -Rai Way TEST2:11765:v:1:27500:516:8190:0:3405 -Rai Way TEST3:11765:v:1:27500:164:8190:0:3406 -RAIMOSAICO:11765:v:1:27500:518:8190:0:3407 -RAIMOSAICO:11765:v:1:27500:518:8190:0:3490 -RAINews24:11765:v:1:27500:516:8190:0:3301 -CAMERA DEPUTATI:11765:v:1:27500:517:8190:0:3302 -TELEPACE:11765:v:1:27500:515:8190:0:3304 -RAISPORTSAT:11765:v:1:27500:512:8190:0:3305 -RAINettunoSAT2:11765:v:1:27500:513:8190:0:3306 -RAIeducational:11765:v:1:27500:514:8190:0:3307 -RAINettunoSAT1:11765:v:1:27500:519:8190:0:3308 -SAT2000:11765:v:1:27500:518:8190:0:3309 -RADIOUNO:11765:v:1:27500:8190:670:0:3311 -RADIODUE:11765:v:1:27500:8190:671:0:3312 -RADIOTRE:11765:v:1:27500:8190:672:0:3313 -FDleggera:11765:v:1:27500:8190:673:0:3314 -FDauditorium:11765:v:1:27500:8190:665:0:3315 -BLUSAT 2000:11765:v:1:27500:8190:677:0:3316 -GR PARLAMENTO:11765:v:1:27500:8190:664:0:3317 -ISORADIO:11765:v:1:27500:8190:661:0:3318 -R1:11823:h:1:27500:512:650:0:301 -R2:11823:h:1:27500:513:661:0:302 -R3:11823:h:1:27500:514:670:0:303 -R4:11823:h:1:27500:515:680:0:304 -R5:11823:h:1:27500:4682:700:0:306 -R6:11823:h:1:27500:518:710:0:307 -R7:11823:h:1:27500:519:720:0:308 -Love Radio:11823:h:1:27500:8190:711:0:309 -Greek Church:11823:h:1:27500:8190:671:0:310 -Skai Radio:11823:h:1:27500:8190:741:0:311 -MelodiRadio:11823:h:1:27500:8190:701:0:312 -ERA 3:11823:h:1:27500:8190:651:0:313 -RR1:11823:h:1:27500:8190:681:0:314 -RR2:11823:h:1:27500:8190:721:0:315 -NOVA CINE:11823:h:1:27500:521:740:0:316 -FILM NET:11823:h:1:27500:512:650:0:317 -SSportK-T.V:11823:h:1:27500:513:661:0:318 -MEGA:11823:h:1:27500:514:670:0:319 -ANT-1:11823:h:1:27500:515:680:0:320 -STAR:11823:h:1:27500:517:700:0:321 -Alter 5:11823:h:1:27500:518:710:0:322 -NEW Tempo:11823:h:1:27500:519:720:0:323 -Super Sport2:11823:h:1:27500:516:691:0:324 -Super Sport2:11843:v:1:27500:516:691:0:65534 -INTV:11843:v:1:27500:2324:8190:0:3504 -UNIV:11843:v:1:27500:2305:8190:0:3507 -CULT:11843:v:1:27500:2307:8190:0:3510 -ERSP:11843:v:1:27500:2309:8190:0:3513 -SINT:11843:v:1:27500:8190:8190:0:3515 -CART:11843:v:1:27500:2433:8190:0:3516 -SINT:11843:v:1:27500:8190:8190:0:3519 -DISC:11843:v:1:27500:2437:8190:0:3522 -SINT:11843:v:1:27500:8190:8190:0:3525 -TVL:11843:v:1:27500:2441:8190:0:3528 -SINT:11843:v:1:27500:8190:8190:0:3530 -ROCK:11843:v:1:27500:8190:2320:0:3550 -RDS:11843:v:1:27500:8190:2321:0:3553 -RTL:11843:v:1:27500:8190:2322:0:3556 -101:11843:v:1:27500:8190:2323:0:3559 -RVOY:11843:v:1:27500:8190:2315:0:3562 -RKFM:11843:v:1:27500:8190:2317:0:3563 -GLOB:11843:v:1:27500:8190:2316:0:3564 -ANT1:11843:v:1:27500:8190:2318:0:3565 -RRAD:11843:v:1:27500:8190:2319:0:3566 -MC01:11843:v:1:27500:8190:2312:0:3568 -MC02:11843:v:1:27500:8190:2313:0:3571 -MC03:11843:v:1:27500:8190:2314:0:3574 -P7:12341:h:1:27500:160:81:0:11301 -P8:12341:h:1:27500:161:85:0:11303 -P9:12341:h:1:27500:162:89:0:11305 -+GIOCHI:12341:h:1:27500:8190:8190:0:11310 -MM01:12341:h:1:27500:8190:601:0:11311 -MM02:12341:h:1:27500:8190:602:0:11312 -MM03:12341:h:1:27500:8190:603:0:11313 -MM04:12341:h:1:27500:8190:604:0:11314 -MM05:12341:h:1:27500:8190:605:0:11315 -MM06:12341:h:1:27500:8190:606:0:11316 -MM07:12341:h:1:27500:8190:607:0:11317 -MM08:12341:h:1:27500:8190:608:0:11318 -MM09:12341:h:1:27500:8190:609:0:11319 -MM10:12341:h:1:27500:8190:610:0:11320 -MM11:12341:h:1:27500:8190:611:0:11321 -MM12:12341:h:1:27500:8190:612:0:11322 -MM13:12341:h:1:27500:8190:613:0:11323 -MM14:12341:h:1:27500:8190:614:0:11324 -MM15:12341:h:1:27500:8190:615:0:11325 -MM16:12341:h:1:27500:8190:616:0:11326 -MM17:12341:h:1:27500:8190:617:0:11327 -MM18:12341:h:1:27500:8190:618:0:11328 -MM19:12341:h:1:27500:8190:619:0:11329 -MM20:12341:h:1:27500:8190:620:0:11330 -MM21:12341:h:1:27500:8190:621:0:11331 -MM22:12341:h:1:27500:8190:622:0:11332 -MM23:12341:h:1:27500:8190:623:0:11333 -MM24:12341:h:1:27500:8190:624:0:11334 -MM25:12341:h:1:27500:8190:625:0:11335 -MM26:12341:h:1:27500:8190:626:0:11336 -MM27:12341:h:1:27500:8190:627:0:11337 -MM28:12341:h:1:27500:8190:628:0:11338 -MM29:12341:h:1:27500:8190:629:0:11339 -MM30:12341:h:1:27500:8190:630:0:11340 -RCAP:12341:h:1:27500:8190:631:0:11341 -R105:12341:h:1:27500:8190:632:0:11342 -RDJ:12341:h:1:27500:8190:633:0:11343 -RITA:12341:h:1:27500:8190:634:0:11344 -RMC:12341:h:1:27500:8190:635:0:11345 -R101:12341:h:1:27500:8190:636:0:11346 -RRAD:12341:h:1:27500:8190:637:0:11347 -RR:12341:h:1:27500:8190:638:0:11348 -RR:12341:h:1:27500:8190:610:0:11361 -RR:12341:h:1:27500:8190:620:0:11362 -RR:12341:h:1:27500:8190:630:0:11363 -RR:12341:h:1:27500:8190:638:0:11364 -MULTIMUSICA:12341:h:1:27500:8190:8190:0:11352 -RADIO:12341:h:1:27500:8190:8190:0:11353 -MULTIMUSIC 1:12341:h:1:27500:8190:609:0:11365 -MULTIMUSIC 2:12341:h:1:27500:8190:620:0:11366 -MULTIMUSIC 2:12713:v:1:27500:8190:620:0:65534 -TEAM:12713:v:1:27500:2305:8190:0:3610 -SINT:12713:v:1:27500:8190:8190:0:3613 -VIAG:12713:v:1:27500:2308:8190:0:3616 -SINT:12713:v:1:27500:8190:8190:0:3619 -EURO:12713:v:1:27500:2311:8190:0:3622 -SINT:12713:v:1:27500:8190:8190:0:3623 -CNN:12713:v:1:27500:2433:8190:0:3625 -ante prima:12713:v:1:27500:2435:8190:0:3628 -SNAI:12713:v:1:27500:2561:8190:0:3630 -MPPV:12713:v:1:27500:2563:8190:0:3632 -MC04:12713:v:1:27500:8190:2688:0:3636 -MC05:12713:v:1:27500:8190:2689:0:3637 -MC06:12713:v:1:27500:8190:2690:0:3638 -MC07:12713:v:1:27500:8190:2691:0:3641 -MC08:12713:v:1:27500:8190:2692:0:3644 -MC09:12713:v:1:27500:8190:2693:0:3647 -MC10:12713:v:1:27500:8190:2694:0:3650 -MC11:12713:v:1:27500:8190:2695:0:3653 -MC12:12713:v:1:27500:8190:2696:0:3656 -MC13:12713:v:1:27500:8190:2697:0:3659 -MC14:12713:v:1:27500:8190:2698:0:3662 -MC15:12713:v:1:27500:8190:2699:0:3665 -MC16:12713:v:1:27500:8190:2700:0:3668 -MC17:12713:v:1:27500:8190:2701:0:3671 -MC18:12713:v:1:27500:8190:2702:0:3674 -MOSAICO D+:12341:h:1:27500:161:84:0:11401 - MILAN CH.:12341:h:1:27500:162:89:0:11403 - INTER CH.:12341:h:1:27500:163:93:0:11405 -TST3:12341:h:1:27500:8190:8190:0:11407 - I1:11919:v:1:27500:512:650:0:1 - C5:11919:v:1:27500:513:660:0:2 - R4:11919:v:1:27500:514:670:0:3 -Test:11919:v:1:27500:515:680:0:4 -NTV:11938:h:1:27500:164:89:0:7105 -NTV-PLUS:11938:h:1:27500:165:91:0:7106 -NTV Int.-HTB:11938:h:1:27500:160:80:0:7101 -NTV Int.-Nashe Kino:11938:h:1:27500:161:82:0:7102 -NTV Int.-Detsk. Mir:11938:h:1:27500:162:84:0:7103 -DISNEY CHANNEL:12341:v:1:27500:8190:8190:0:10901 -DISCOVERY:12341:v:1:27500:161:8190:0:10903 -EUSP:12341:v:1:27500:162:89:0:10905 -HAPPY CHANNEL:12341:v:1:27500:8190:8190:0:10907 -MATCH MUSIC:12341:v:1:27500:8190:8190:0:10909 -MTV:12341:v:1:27500:8190:8190:0:10911 -R/CINEMA RAISAT:12341:v:1:27500:8190:8190:0:10913 -R/CINEMA RAISAT:12713:h:1:27500:8190:8190:0:65534 -cine stream:12713:h:1:27500:512:650:0:7704 -cine movie:12713:h:1:27500:514:670:0:7707 -CLASSICA:12341:v:1:27500:8190:8190:0:11001 -R/GAM ROS RAISAT:12341:v:1:27500:8190:8190:0:11003 -R/ALBUM RAISAT:12341:v:1:27500:8190:8190:0:11005 -HALLMARK:12341:v:1:27500:163:8190:0:11007 -R/ART RAISAT:12341:v:1:27500:8190:8190:0:11009 -TST1:12341:v:1:27500:8190:8190:0:11011 -TMC:12341:v:1:27500:166:8190:0:11013 -TMC2:12341:v:1:27500:167:8190:0:11015 -ART VARIETY:12015:h:1:27500:160:8190:0:410 -ART CHILDREN:12015:h:1:27500:161:8190:0:420 -ART MOVIES:12015:h:1:27500:162:8190:0:430 -ART MUSIC:12015:h:1:27500:163:8190:0:440 -ART EUROPE:12015:h:1:27500:164:8190:0:450 -LBC EUROPE:12015:h:1:27500:165:8190:0:460 -EGYPT SAT. CH. 2:12015:h:1:27500:166:8190:0:470 -ART SPORT:12015:h:1:27500:167:8190:0:472 -IQRA:12015:h:1:27500:168:8190:0:474 -T+ BIANCO:12341:v:1:27500:160:81:0:11101 -T+ NERO:12341:v:1:27500:161:85:0:11103 -T+ GRIGIO:12341:v:1:27500:162:89:0:11105 -R4:12341:v:1:27500:163:8190:0:24 -16|9 TELE+:12341:v:1:27500:164:97:0:11107 -VETRINA D+:12341:v:1:27500:8190:8190:0:11109 -R/RAGAZZI RAISAT:12341:v:1:27500:8190:8190:0:11111 -CNN:12341:h:1:27500:8190:8190:0:11501 -BBC:12341:h:1:27500:8190:8190:0:11503 -BLOOMBERG:12341:h:1:27500:8190:8190:0:11505 -CNBC:12341:h:1:27500:8190:8190:0:11507 -SKYNews:12341:h:1:27500:8190:8190:0:11509 -TST2:12341:h:1:27500:8190:8190:0:11511 -TV5:12341:h:1:27500:8190:8190:0:11513 -EPG:12341:h:1:27500:8190:8190:0:11515 -CNN:12341:h:1:27500:160:80:0:11517 -CNBC:12341:h:1:27500:163:92:0:11519 -TV5:12341:h:1:27500:166:104:0:11521 -BBC WORLD:12341:h:1:27500:161:84:0:11523 -BBC WORLD:12341:h:1:27500:161:84:0:11595 -BBC WORLD:12341:h:1:27500:161:84:0:9980 -BBC WORLD:12341:h:1:27500:161:84:0:9981 -Telekom TV:11095:v:1:27500:32:8190:0:3711 -FantasticOverOpal:11095:v:1:27500:32:8190:0:3712 -Gilat:11095:v:1:27500:32:8190:0:3713 -Siemens TV:11095:v:1:27500:32:8190:0:3716 -S-TV:11095:v:1:27500:32:8190:0:3717 -Optibase Encoder:11095:v:1:27500:32:8190:0:3718 -Bolsa:12091:h:1:27500:8190:8190:0:8750 -Testw:12091:h:1:27500:8190:8190:0:8751 -SIRE:12091:h:1:27500:8190:8190:0:8752 -Telesierra:12091:h:1:27500:4160:4161:0:8704 -vtv:12091:h:1:27500:4112:4115:0:8701 -Satisfaction:12091:h:1:27500:4192:4193:0:8706 -C. Milagro:12091:h:1:27500:4368:4369:0:8711 -Fiesta:12091:h:1:27500:4432:4434:0:8720 -TVE Internacional:12091:h:1:27500:4208:4209:0:8707 -TV Galicia:12091:h:1:27500:8190:4240:0:8708 -Radio Gallega:12091:h:1:27500:8190:4240:0:8709 -Retelsat:12091:h:1:27500:4464:4465:0:8722 -Musicam 1:12091:h:1:27500:8190:4406:0:8713 -Musicam 2:12091:h:1:27500:8190:4403:0:8714 -Musicam 3:12091:h:1:27500:8190:4406:0:8715 -Musicam 4:12091:h:1:27500:8190:4402:0:8716 -Musicam 5:12091:h:1:27500:8190:4406:0:8717 -HBCH FUCINO:12673:v:1:27500:200:201:0:701 -NTVi:12673:v:1:27500:210:212:0:702 -Test Telespazio:12673:v:1:27500:220:221:0:703 -Test Telespazio:12673:v:1:27500:230:231:0:704 -ARMENIA TV:12673:v:1:27500:240:242:0:705 -MEDNET:12673:v:1:27500:260:261:0:707 -AL JAZEERA:12673:v:1:27500:270:271:0:708 -TIRRENO SAT:12673:v:1:27500:280:301:0:709 -RADIO ROCK:12673:v:1:27500:8190:212:0:711 -RADIO ARMENIA:12673:v:1:27500:8190:242:0:712 -Coming Soon TV:12673:v:1:27500:8190:40:0:717 -AH-EDP1:12149:v:1:27500:96:97:0:7201 -AH-EDP2:12149:v:1:27500:112:113:0:7202 -AH-EDP3:12149:v:1:27500:36:37:0:7203 -AH-EMP4-DATA:12149:v:1:27500:8190:8190:0:7204 -Alice:12149:v:1:27500:160:161:0:7220 -Nuvolari:12149:v:1:27500:176:177:0:7221 -Leonardo:12149:v:1:27500:128:129:0:7222 -Discovery:12169:h:1:27500:512:8190:0:351 -R9:12169:h:1:27500:513:8190:0:352 -BBC World:12169:h:1:27500:514:8190:0:353 -CNN:12169:h:1:27500:515:8190:0:354 -CCTV:12169:h:1:27500:516:8190:0:355 -R10:12169:h:1:27500:518:8190:0:357 -R8:12169:h:1:27500:519:8190:0:358 -FILM SAT:12169:h:1:27500:520:8190:0:359 -Cartoon:12169:h:1:27500:515:8190:0:360 -Promo:12169:h:1:27500:521:8190:0:361 -Tempo:12169:h:1:27500:1440:651:0:362 -Tempo:12169:h:1:27500:8190:661:0:363 -Tempo:12169:h:1:27500:8190:671:0:364 -Tempo:12169:h:1:27500:8190:681:0:365 -Tempo:12169:h:1:27500:8190:691:0:366 -NOVA INFO:12169:h:1:27500:8190:8190:0:367 -NOVA INFO:12169:h:1:27500:8190:8190:0:369 -NOVA INFO:12169:h:1:27500:8190:8190:0:370 -NOVA INFO:12169:h:1:27500:1067:8190:0:371 -NOVA INFO:12169:h:1:27500:8190:8190:0:372 -NOVA INFO:12169:h:1:27500:8190:8190:0:373 -NOVA Cinema:12169:h:1:27500:8190:8190:0:374 -NET:12169:h:1:27500:513:8190:0:376 -MAD T.V:12169:h:1:27500:518:8190:0:377 -ET-1:12169:h:1:27500:519:8190:0:378 -ET-1:12169:h:1:27500:519:8190:0:379 -:12169:h:1:27500:517:8190:0:384 -Deutsche Bank / T1:12264:v:1:27500:1160:8190:0:1 -Animal Planet:12264:v:1:27500:1160:8190:0:10 -Discovery E Europe-English:12264:v:1:27500:1260:8190:0:20 -Wuerth KG / T21:12264:v:1:27500:1360:8190:0:21 -Discovery Italy:12264:v:1:27500:1360:8190:0:30 -BTI / T31:12264:v:1:27500:1360:8190:0:31 -Discovery Russia:12264:v:1:27500:1460:8190:0:40 -K-TV (MetroMux) / T41:12264:v:1:27500:1960:8190:0:41 -Animal Planet EE:12264:v:1:27500:1560:8190:0:50 -Animal Planet - Russian:12264:v:1:27500:1560:8190:0:51 -Discovery Netherlands:12264:v:1:27500:1660:8190:0:60 -Q English:12264:v:1:27500:1760:8190:0:70 -Travel and Adventure:12264:v:1:27500:1860:8190:0:80 -Travel and Adventure- Russian:12264:v:1:27500:1860:8190:0:81 -New DCP:12264:v:1:27500:8190:1220:0:300 -CCP:12264:v:1:27500:1260:8190:0:301 -Deutsche Bank / T2:12264:v:1:27500:1260:8190:0:2 -Channel Three:12264:v:1:27500:1360:8190:0:3 -Channel Four:12264:v:1:27500:1460:8190:0:4 -Channel Five:12264:v:1:27500:1560:8190:0:5 -Channel 6 = Sat 7 Arabic:12264:v:1:27500:1660:8190:0:6 -Channel Seven:12264:v:1:27500:1760:8190:0:7 -Q German:12264:v:1:27500:1760:8190:0:71 -Q French:12264:v:1:27500:1760:8190:0:72 -Q Dutch:12264:v:1:27500:1760:8190:0:73 -DTAG / T11:12264:v:1:27500:1360:8190:0:11 -DTAG 50 / T12:12264:v:1:27500:1360:8190:0:12 -Telekom TV:12264:v:1:27500:1460:8190:0:13 -Gerling / T26:12264:v:1:27500:1360:8190:0:26 -Hornbach-D / T36:12264:v:1:27500:1360:8190:0:36 -Hornbach-NL / T38:12264:v:1:27500:1360:8190:0:38 -Hornbach-CZ / T39:12264:v:1:27500:1360:8190:0:39 -Testkanal:12264:v:1:27500:1660:8190:0:99 -KENCAST:12264:v:1:27500:8190:8190:0:111 -SLO-TV1:12302:v:1:27500:200:8190:0:3201 -SLO-TV2:12302:v:1:27500:203:8190:0:3202 -POLONIA 1:12302:v:1:27500:205:8190:0:3203 -SLO-RA1-INF:12302:v:1:27500:8190:250:0:3204 -SLO-RA2:12302:v:1:27500:8190:251:0:3205 -SLO-RA3:12302:v:1:27500:8190:252:0:3206 -SUPER 1:12302:v:1:27500:207:8190:0:3207 -NAPOLI INT.:12302:v:1:27500:240:8190:0:3210 -MAGIC:12302:v:1:27500:245:8190:0:3211 -COUNTDOWN:12302:v:1:27500:235:8190:0:3212 -TBNE:12302:v:1:27500:230:8190:0:3213 -SICILSAT:12302:v:1:27500:225:8190:0:3214 -TVP1:10892:h:1:27500:257:6111:0:1 -TVP2:10892:h:1:27500:321:322:0:2 -POLSAT1:10892:h:1:27500:8190:8190:0:3 -TV4:10892:h:1:27500:257:6111:0:4 -POLSAT2:10892:h:1:27500:321:322:0:5 -WOT:10892:h:1:27500:8190:8190:0:6 -DISCOVERY:10892:h:1:27500:257:6111:0:15 -ANIMAL PLANET:10892:h:1:27500:321:322:0:16 -EpgOpenTV:10892:h:1:27500:8190:8190:0:3686 -P10:12341:v:1:27500:160:81:0:11601 -P11:12341:v:1:27500:161:85:0:11603 -P12:12341:v:1:27500:162:89:0:11605 -P13:12341:v:1:27500:163:93:0:11607 -P14:12341:v:1:27500:164:97:0:11609 -P15:12341:v:1:27500:165:101:0:11611 -P16:12341:v:1:27500:166:105:0:11613 -PREMIUM:12341:v:1:27500:8190:8190:0:11615 -+F1:12341:v:1:27500:160:664:0:11617 -+F1:12341:v:1:27500:161:85:0:11619 -+F1:12341:v:1:27500:162:667:0:11621 -+F1:12341:v:1:27500:163:674:0:11623 -+F1:12341:v:1:27500:164:96:0:11625 -+F1:12341:v:1:27500:165:676:0:11627 -+F1:12341:v:1:27500:166:666:0:11629 -RMC:12341:v:1:27500:8190:8190:0:11631 -R101:12341:v:1:27500:8190:8190:0:11632 -RRAD:12341:v:1:27500:8190:8190:0:11633 -ON:10892:h:1:27500:353:354:0:7 -DLA-CIEBIE:10892:h:1:27500:529:530:0:8 -KOMEDIA:10892:h:1:27500:353:354:0:9 -SMYK:10892:h:1:27500:529:530:0:10 -RELAKS:10892:h:1:27500:353:354:0:11 -INFO:10892:h:1:27500:529:530:0:12 -POLSAT SPORT:10892:h:1:27500:353:354:0:13 -Paris Premire:12379:v:1:27500:3021:3031:0:3001 -OCC HB3:12379:v:1:27500:3022:3032:0:3002 -TELE 24 Switzerland:12379:v:1:27500:3023:3033:0:3003 -AIR MEDIA:12379:v:1:27500:8190:3537:0:3087 -Abu Dhabi TV:12379:v:1:27500:3024:3034:0:3004 -EMIRAT FM 1:12379:v:1:27500:8190:3533:0:3083 -EMIRAT FM2:12379:v:1:27500:8190:3534:0:3084 -Radio Italia :12379:v:1:27500:8190:3531:0:3081 -EQUIDIA INTER.:12379:v:1:27500:3321:3351:0:3051 -RTV MONTENEGRO:12379:v:1:27500:3026:3036:0:3006 -Radio Montenegro:12379:v:1:27500:8190:3538:0:3088 -SERTE TEST:12379:v:1:27500:3025:8190:0:3005 -GAME 1:12379:v:1:27500:3027:3037:0:3007 -SF 2:12398:h:1:27500:163:93:0:907 -SRG SSR Sat Access:12398:h:1:27500:165:99:0:910 -SF 1:12398:h:1:27500:160:81:0:901 -TSR 1:12398:h:1:27500:161:85:0:902 -TSI 1:12398:h:1:27500:162:89:0:903 -TSR 2:12398:h:1:27500:164:97:0:908 -TSI 2:12398:h:1:27500:166:101:0:909 -OPTION MUSIQUE:12398:h:1:27500:8190:204:0:957 -ESPACE 2:12398:h:1:27500:8190:205:0:958 -SRI-F-I:12398:h:1:27500:8190:199:0:951 -SRI-EUROPA:12398:h:1:27500:560:200:0:953 -POLO:12341:v:1:27500:160:80:0:11701 -PLANETE:12341:v:1:27500:161:84:0:11703 -JIMMY:12341:v:1:27500:162:88:0:11705 -INN:12341:v:1:27500:163:92:0:11707 -CIN1:12341:v:1:27500:164:96:0:11709 -CIN2:12341:v:1:27500:165:100:0:11711 -CINC:12341:v:1:27500:166:104:0:11713 -SEASONS:12341:v:1:27500:167:108:0:11715 -WISHLINE:12341:v:1:27500:168:89:0:11717 -MARCOPOLO:12341:v:1:27500:160:81:0:11719 -JAAM-E-JAM 1:12436:h:1:27500:160:81:0:1 -JAAM-E-JAM 2:12436:h:1:27500:161:83:0:2 -SAHAR:12436:h:1:27500:162:85:0:3 -TEST(SAHAR):12436:h:1:27500:163:87:0:4 -IRINN:12436:h:1:27500:164:89:0:5 -TEST 2:12436:h:1:27500:165:90:0:6 -IRIB1 RADIO:12436:h:1:27500:8190:81:0:7 -IRIB ARABIC /International 1 Radio:12436:h:1:27500:8190:83:0:8 -INT1 FAMILY RADIO:12475:h:1:27500:8190:961:0:10615 -RADIO 74:12475:h:1:27500:8190:921:0:10612 -R 74 INT.:12475:h:1:27500:8190:931:0:10613 -FAMILY Radio:12475:h:1:27500:8190:951:0:10614 -Temp:12475:h:1:27500:771:8190:0:10607 -SPREE Radio:12475:h:1:27500:8190:501:0:10652 - RVI ( VRT ) :12475:h:1:27500:8190:901:0:10610 -EbS:12475:h:1:27500:101:216:0:10601 -MOU.2:12475:h:1:27500:42:8190:0:10602 -MIZIK TROPICAL:12475:h:1:27500:435:436:0:10606 -MIZIK TROPICAL Radio:12475:h:1:27500:8190:801:0:10608 -Framboise Nord (CH):12475:h:1:27500:8190:971:0:10616 -Framboise Sud (CH):12475:h:1:27500:8190:981:0:10617 -PINK PLUS:12475:h:1:27500:308:257:0:10605 -LIBERTYTV.COM:12475:h:1:27500:941:942:0:10603 -KURDSAT:12475:h:1:27500:600:601:0:10618 -test2:12475:h:1:27500:3000:3001:0:10620 -HRT-TV1:12519:v:1:27500:100:101:0:8301 -HRT-TV2:12519:v:1:27500:103:104:0:8302 -HRT-TV3:12519:v:1:27500:105:106:0:8303 -HRT-HR1:12519:v:1:27500:8190:150:0:8305 -HRT-HR2:12519:v:1:27500:8190:151:0:8306 -HRT-HR3:12519:v:1:27500:8190:152:0:8307 -SICILIA INTERNATIONAL:12519:v:1:27500:501:8190:0:8309 -HRT-NATIONAL:12519:v:1:27500:107:108:0:8304 -HRT-TEST:12519:v:1:27500:109:110:0:8308 -SARDEGNA UNO:12519:v:1:27500:503:8190:0:8310 -R-HRVATSKA:12519:v:1:27500:8190:153:0:8311 -EuroMed:12519:v:1:27500:510:8190:0:8312 -TGRT:12519:v:1:27500:505:8190:0:8313 -HR-TEST:12519:v:1:27500:8190:154:0:8314 -MINI-BVN:12519:v:1:27500:210:8190:0:8315 -SIMS 91 LARIO:12713:h:1:27500:8190:8190:0:8802 -SKYPLEX TXP91:12713:h:1:27500:8190:8190:0:8801 -Skygate 18:12713:h:1:27500:8190:8190:0:2 -MA12_2905:12713:h:1:27500:8190:8190:0:8810 -ES13_1107:12713:h:1:27500:8190:8190:0:8811 -ASTONv0107:12713:h:1:27500:8190:8190:0:8815 -sisal:12713:h:1:27500:4356:8190:0:1 -service:12713:h:1:27500:4356:8190:0:3 -Skyplex 19:12713:h:1:27500:8190:8190:0:8991 -Network:12713:h:1:27500:8190:8190:0:8992 -www.travel:12713:h:1:27500:1180:1184:0:8993 -MagicStar:12713:h:1:27500:8190:1188:0:8994 -Skygate 8:12713:h:1:27500:8190:8190:0:8926 -UDLR:12713:h:1:27500:8190:6653:0:8927 -UDLR UDcast:12713:h:1:27500:8190:8190:0:8928 -Skygate 17:12713:h:1:27500:8190:8190:0:8804 -Netshow:12713:h:1:27500:8190:8190:0:8813 -MEDIOLANUM:12713:h:1:27500:4102:8190:0:8814 -Skygate 10:12713:h:1:27500:8190:8190:0:8901 -HitCast Data 1:12713:h:1:27500:8190:8190:0:8902 -HitCast S.Amer.:12713:h:1:27500:8190:8190:0:8903 -Skygate 1:12713:h:1:27500:8190:8190:0:8876 -MonteCarloSat:12713:h:1:27500:5127:5122:0:8877 -Bulgaria Radio:12713:h:1:27500:8190:4615:0:8828 -skygate 600:12713:h:1:27500:8190:8190:0:8826 -SKYPLEX TXP92:12558:v:1:27500:8190:8190:0:9101 -SKYPLEX TXP92:12558:v:1:27500:8190:8190:0:9361 -SKYPLEX TXP92:12558:v:1:27500:2825:2818:0:9362 -SKYPLEX TXP92:12558:v:1:27500:2825:2818:0:9363 -SKYPLEX TXP92:12558:v:1:27500:2825:2818:0:9364 -SKY_4:12558:v:1:27500:8190:8190:0:9351 -ESP Int'l:12558:v:1:27500:2575:2563:0:9352 -ESP Romanian:12558:v:1:27500:8190:2569:0:9353 -ESP Dutch:12558:v:1:27500:2575:2564:0:9354 -ESP PolisI:12558:v:1:27500:8190:2565:0:9355 -ESP PolisI:12558:v:1:27500:2575:2566:0:9356 -ESP PolisI:12558:v:1:27500:2575:2564:0:9357 -ESP PolisI:12558:v:1:27500:2575:2568:0:9358 -ESP PolisI:12558:v:1:27500:2575:2565:0:9359 -ESP PolisI:12558:v:1:27500:2575:2565:0:9251 -JSTV 1:12596:v:1:27500:2000:2002:0:8213 -JSTV 2:12596:v:1:27500:2011:2013:0:8214 -MBC:12596:v:1:27500:160:81:0:8201 -Service 2:12596:v:1:27500:161:84:0:8202 -NITV:12596:v:1:27500:163:92:0:8204 -SIMAYE AZADI:12596:v:1:27500:166:106:0:8207 -BET:12596:v:1:27500:167:109:0:8208 -CNNI:12596:v:1:27500:168:113:0:8209 -EuroNews:12596:v:1:27500:2221:2238:0:8211 -Canal Rural:12596:v:1:27500:2321:2332:0:8212 -MediaHW:12596:v:1:27500:8190:8190:0:8291 -MediaHW:12615:h:1:27500:8190:8190:0:65534 -MMOV:12615:h:1:27500:2576:8190:0:3910 -MMOV:12615:h:1:27500:2578:8190:0:3913 -MMOV:12615:h:1:27500:2580:8190:0:3917 -MMOV:12615:h:1:27500:2582:8190:0:3918 -MMOV:12615:h:1:27500:2584:8190:0:3919 -MMOV:12615:h:1:27500:2586:8190:0:3920 -SC 1:12615:h:1:27500:2567:8190:0:3921 -SC 2:12615:h:1:27500:2570:8190:0:3924 -SC 3:12615:h:1:27500:2573:8190:0:3927 -MC20:12615:h:1:27500:8190:2304:0:3935 -MC21:12615:h:1:27500:8190:2305:0:3938 -MC22:12615:h:1:27500:8190:2306:0:3941 -MC23:12615:h:1:27500:8190:2307:0:3944 -MC24:12615:h:1:27500:8190:2308:0:3947 -MC25:12615:h:1:27500:8190:2309:0:3950 -MC26:12615:h:1:27500:8190:2310:0:3953 -MC27:12615:h:1:27500:8190:2311:0:3956 -MC28:12615:h:1:27500:8190:2312:0:3959 -MC29:12615:h:1:27500:8190:2313:0:3962 -MC30:12615:h:1:27500:8190:2314:0:3965 -MC31:12615:h:1:27500:8190:2315:0:3968 -MC32:12615:h:1:27500:8190:2316:0:3971 -MC33:12615:h:1:27500:8190:2317:0:3974 -MC34:12615:h:1:27500:8190:2318:0:3977 -MC35:12615:h:1:27500:8190:2319:0:3980 -MC36:12615:h:1:27500:8190:2320:0:3983 -MC37:12615:h:1:27500:8190:2321:0:3986 -MC38:12615:h:1:27500:8190:2322:0:3989 -MC39:12615:h:1:27500:8190:2323:0:3992 -MC39:12635:v:1:27500:8190:2323:0:65534 -SC 4:12635:v:1:27500:2704:8190:0:4001 -SC 5:12635:v:1:27500:2696:8190:0:4002 -SC 6:12635:v:1:27500:2701:8190:0:4003 -MMOV:12635:v:1:27500:2692:8190:0:4007 -MMOV:12635:v:1:27500:2694:8190:0:4010 -MMOV:12635:v:1:27500:2707:8190:0:4016 -MMOV:12635:v:1:27500:2709:8190:0:4019 -MMOV:12635:v:1:27500:2711:8190:0:4022 -MMOV:12635:v:1:27500:2819:8190:0:4025 -MMOV:12635:v:1:27500:2821:8190:0:4028 -Sharjah Arabsat Bouquet:12654:h:1:27500:1160:8190:0:1 -Qatar Arabsat Bouquet:12654:h:1:27500:1260:8190:0:2 -Saudi 1 Arabsat Bouquet:12654:h:1:27500:1360:8190:0:3 -Kuwait Arabsat Bouquet:12654:h:1:27500:1460:8190:0:4 -Libya Arabsat Bouquet:12654:h:1:27500:1560:8190:0:5 -Sudan Arabsat Bouquet:12654:h:1:27500:1660:8190:0:6 -Oman Arabsat Bouquet:12654:h:1:27500:1760:8190:0:7 -Jordan Arabsat Bouquet:12654:h:1:27500:1860:8190:0:8 -IRAQ TV:12654:h:1:27500:1960:8190:0:9 -Dubai Sport:12654:h:1:27500:1060:8190:0:10 -Qatar A2 Arabsat Bouquet:12654:h:1:27500:8190:1221:0:12 -Saudi1 A2 Arabsat Bouquet:12654:h:1:27500:8190:1321:0:13 -Kuwait A2 Arabsat Bouquet:12654:h:1:27500:8190:1421:0:14 -Jordan A2 Arabsat Bouquet:12654:h:1:27500:8190:1821:0:18 -Radio dubai sport:12654:h:1:27500:8190:1021:0:19 -Digitaly:12673:v:1:27500:220:222:0:4203 -Telemarket:12673:v:1:27500:350:351:0:4211 -Internet data 1:12673:v:1:27500:8190:8190:0:4212 -eVision:12673:v:1:27500:360:7142:0:4214 -ANNI 60:12673:v:1:27500:8190:250:0:4230 -R. Reporter:12673:v:1:27500:8190:251:0:4231 -Radio Italia S.M.I.:12673:v:1:27500:8190:252:0:4232 -R. Tour:12673:v:1:27500:8190:253:0:4233 -R.Rinascente:12673:v:1:27500:8190:254:0:4234 -R. Cooky:12673:v:1:27500:8190:255:0:4235 -RadioBaby:12673:v:1:27500:8190:256:0:4236 -McDonalds:12673:v:1:27500:8190:257:0:4237 -TRBuonconsiglio:12673:v:1:27500:8190:401:0:4238 -R-Radio:12673:v:1:27500:8190:402:0:4239 -R. Donna:12673:v:1:27500:8190:403:0:4240 -R. Reporter 2:12673:v:1:27500:8190:404:0:4241 -R. West:12673:v:1:27500:8190:405:0:4242 -Melodia Russia:12673:v:1:27500:6646:406:0:4243 -Padre Pio:12673:v:1:27500:8190:407:0:4244 -Thai TV5:12673:v:1:27500:200:202:0:4201 -Studio Europa:12673:v:1:27500:230:231:0:4204 -Video Italia:12673:v:1:27500:340:342:0:4210 -PASSIONS:12692:h:1:27500:160:8190:0:501 -ONYX:12692:h:1:27500:161:8190:0:502 -MANGAS:12692:h:1:27500:162:88:0:503 -ENCYCLOPEDIA:12692:h:1:27500:163:92:0:504 -POLAR:12692:h:1:27500:164:96:0:505 -CINE PALACE:12692:h:1:27500:165:100:0:506 -ROMANCE:12692:h:1:27500:166:104:0:507 -RIRE:12692:h:1:27500:167:108:0:508 -ACTION:12692:h:1:27500:168:112:0:509 -ABsat test RADIO:12692:h:1:27500:8190:101:0:510 -ABsat test RADIO:12713:v:1:27500:8190:101:0:65534 -MMOV:12713:v:1:27500:2563:8190:0:4304 -MMOV:12713:v:1:27500:2565:8190:0:4307 -MMOV:12713:v:1:27500:2567:8190:0:4310 -MMOV:12713:v:1:27500:2308:8190:0:4313 -MMOV:12713:v:1:27500:2314:8190:0:4316 -MMOV:12713:v:1:27500:2310:8190:0:4324 -MMOV:12713:v:1:27500:2312:8190:0:4327 -MMOV:12713:h:1:27500:2312:8190:0:65534 -SINT:12713:h:1:27500:8190:8190:0:8802 -info:12713:h:1:27500:517:8190:0:8804 -SINT:12713:h:1:27500:8190:8190:0:8806 -CFN:12713:h:1:27500:523:8190:0:8809 -SINT:12713:h:1:27500:8190:8190:0:8812 -duel:12713:h:1:27500:518:8190:0:8815 -comedy:12713:h:1:27500:515:8190:0:8818 -fox kids:12713:h:1:27500:513:8190:0:8821 diff --git a/Tools/epg2timers/README b/Tools/epg2timers/README deleted file mode 100644 index 53888b160..000000000 --- a/Tools/epg2timers/README +++ /dev/null @@ -1,151 +0,0 @@ -Overview. -========= - -The 4 modules in this directory are designed to allow vdr timer -programming via the http://tvtv.de web EPG (Electronic Program Guide). - -Once you have these modules properly configured and installed, -you should be able to simply click on the things you want vdr -to record in the http://tvtv.de web EPG and be done with it. -Everything else can be handled automatically. - - - -Module description. -=================== - -The http://tvtv.de web EPG creates a so-called "merkliste" -("a list of items to remember") containing all the broadcasts -you selected. - -1. The perl script "get_merkliste.pl" transfers this "merkliste" - from the http://tvtv.de web site to a local file "merkliste.html". - -2. The C++ program "epg2timers" converts this HTML file into vdr's - timers.conf format. - -3. The perl script "loadvdr.pl" pumps these new timer entries - into a running vdr using telnet and the SVDRP protocol. - -4. The shell script "update_timers" implements the overall - control of the entire process. - It retrieves the latest merkliste from http://tvtv.de, - converts it to timers.conf format and sends the timer entries - to vdr. - - - -Configuration. -============== - -get_merkliste.pl requires configuration of the "files_to_fetch" -variable preset. -Log in to your http://tvtv.de account and click on the "Bookmark" -item in the "Setup" submenu of the "Mein Programm" side bar menu. -This will open a window with a URL in the location field that ends -with an ID value. Replace the xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -in the "files_to_fetch" variable preset with your ID value. -If you are using an HTTP proxy, uncomment the line containing -the $ua->proxy call and put your proxy details in. - -epg2timers.cxx allows various items to be configured, but it -should work out of the box. See "tvtv.de channel names" below. - -update_timers must know where to find the get_merkliste.pl -perl script and the compiled epg2timers binary. Both must be -in a directory pointed to by the TOOLDIR variable. -update_timers also must know where to find vdr's current -channels.conf file. Put that into the CHANPATH. - -Depending on the price of your internet access, you may want to -run update_timers more or less frequently. It may also be a good -idea to run it at times where it is unlikely to interfere with -your current use of vdr. Configure a crontab entry according to -these personal preferences. Here is the entry I use: -1 2 * * * /home/cko/bin/update_timers -It runs update_timers only once a night at 02:01 a.m. - - -Installation. -============= -Create your TOOLDIR directory if it does not already exist. -Copy get_merkliste.pl and loadvdr.pl into it, compile epg2timers.cxx -with the command: - g++ epg2timers.cxx -o epg2timers -and move the epg2timers binary into the TOOLDIR directory. - -The get_merkliste.pl script requires certain packages to run. -Besides of course perl, install perl-libwww-perl (at least -that's the name on SuSE 7.2, it may have a different name in -your distribution). - -If you have problems with SVDRP and loadvdr.pl, you may want to -try out the update_timers.old script, which replaces the timers.conf -file directly and kills vdr (assuming that it will be restarted -by the runvdr script) to make vdr reload the timers.conf file. - - -tvtv.de channel names. -====================== -The file epg_channel_names contains the names of all channels -currently (as of September 9, 2001) supported by the tvtv.de -web EPG. The variable "channel_map" in epg2timers.cxx maps -these names into PNRs (aka Service IDs). I have initialized -this table with provider names converted from a d-box channel -scan of Astra 19.2E, so the PNRs should be correct for that -satellite, but most of the names propably aren't yet- I simply -had not enough time yet to go through epg_channel_names -and insert all its channel names at the proper places in the -channel map. Consider the map supplied an example. ;-) -If you fix any of the entries, please send me a patch. -For my own humble purposes, the table works well as it is. -Of course, your channels.conf must contain the matching -PNRs (last field in each line). - - -To Do. -====== -These are just ideas. They MAY get implemented. -If you want them to happen, contribute a patch. ;-) - -* Support vdr hierarchical directories (after vdr does) - by mapping the http://tvtv.de genre texts into - directory names. -* start_time_safety_margin for epg2timers. - - -Authors. -======== -Carsten Koch: epg2timers.cxx, update_timers, this README file. - -Axel Gruber and -Rolf Hakenes: get_merkliste.pl - -Peter Ahlert: loadvdr.pl - - -Credits. -======== -I am grateful (in chronological order) to - -* Klaus Schmidinger for his excellent vdr program and for - keeping an open mind in all directions. - -* Suse (my wife, not the Linux distributor ;-) for encouraging me to - write epg2timers in June 2000 and for her constant patience and support. - -* Andreas Steinhauser for periodically criticizing the epg2timers - "manual mode" until I came up with the idea to fully automatize it - and for contributing ideas. - -* Axel Gruber for reminding me half a year later, for pushing - the idea until it got implemented, for asking for new features - all the time and for contributing ideas. - -* Axel Gruber and Rolf Hakenes for contributing the get_merkliste.pl - perl script. - -* Peter Ahlert for contributing the loadvdr.pl perl script. - - -Carsten, September 2001. diff --git a/Tools/epg2timers/epg2timers.cxx b/Tools/epg2timers/epg2timers.cxx deleted file mode 100644 index 94e1c8a4b..000000000 --- a/Tools/epg2timers/epg2timers.cxx +++ /dev/null @@ -1,656 +0,0 @@ -/* - * epg2timers.cxx: Convert an EPG "merkliste" HTML page (http://tvtv.de) - * to timers.conf format for Klaus Schmidinger's vdr - * (http://www.cadsoft.de/people/kls/vdr). - * - * Copyright (C) 2000, 2001 Carsten Koch - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * - * The author can be reached at Carsten.Koch@icem.de - */ - - -#include <malloc.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -// User-configurable options. - -static const int stop_time_safety_margin = 10; // add 10 minutes to stop time in case start was delayed -static const int recording_priority = 50; // vdr recording priority setting for all timer entries generated -static const int recording_lifetime = 98; // vdr recording life time setting for all timer entries generated - - -// Usually, you should not want to change any of these. - -static const int max_title = 256; // maximum length+1 of title file name generated -static const int max_genre = 32; // maximum length+1 of genre text parsed -static const int max_line = 1024; // line buffer (not used when parsing summary text) -static const int max_summary = 9000; // Summary can be up to 9000 bytes long (a bit shorter than vdr's SVDRP command buffer) -static const int max_vdr_channel = 1000; // maximum size+1 of your channels.conf - -// The following table maps http://tvtv.de channel names into Astra 19.2E PIDs. -// It is incomplete. Contributions welcome. - -typedef struct -{ - const char * tvtv_name; - unsigned short pnr; -} map_entry; - - -static const map_entry channel_map[] = -{ - // Deutschsprachig - {"13th Street", 42}, - {"3sat", 28007}, - {"ARTE", 28109}, - {"B1", 28206}, - {"BR3", 28107}, - {"BR-alpha", 28112}, - {"ARD", 28106}, - {"Discovery", 14}, - {"Disney Channel", 34}, - {"Eins Extra", 28201}, - {"Eins Festival", 28202}, - {"Eins MuXx", 28203}, - {"Filmpalast", 516}, - {"FOX KIDS", 28}, - {"Heimatkanal", 517}, - {"HR", 28108}, - {"Junior", 19}, - {"Kabel 1", 899}, - {"Kinderkanal", 28008}, - {"Krimi&Co", 23}, - {"K-Toon", 12}, - {"Liberty TV.com", 12199}, - {"MDR", 28204}, - {"NDR", 28224}, - {"NEUN LIVE", 897}, - {"ORB", 28205}, - {"ORF1", 13001}, - {"ORF2", 13002}, - {"Phoenix", 28114}, - {"Planet", 13}, - {"Premiere 1", 10}, - {"Premiere 2", 11}, - {"Premiere 3", 43}, - {"Premiere Action", 20}, - {"Premiere Comedy", 29}, - {"Premiere SCI-FI", 41}, - {"Premiere Star", 9}, - {"PREMIERE WORLD", 8}, - {"ProSieben", 898}, - {"RTL", 12003}, - {"RTL2", 12020}, - {"SAT.1", 46}, - {"SeaSonS", 33}, - {"SR", 28110}, - {"Studio Universal", 36}, - {"Sunset", 16}, - {"Super RTL", 12040}, - {"Test-Z1", 28305}, - {"TW1", 13013}, - {"Via 1 - Schner Reise", 44}, - {"VOX", 12060}, - {"WDR", 28111}, - {"ZDF", 28006}, - {"ZDF.doku", 28014}, - {"ZDF.info", 28011}, - // Movies - {"AXN", 29506}, - {"CANAL+", 29100}, - {"CANAL+ AZUL", 29101}, - {"CANAL+ ROJO", 29102}, - {"CANAL+ VERT", 8208}, - {"CANAL+ 16/9", 8204}, - {"CANAL+ 16|9", 29024}, - {"C+ROOD", 4005}, - {"CINE CINEMA I", 8206}, - {"CINE CINEMA II", 8002}, - {"CINE CINEMA III", 8003}, - {"CINE CLASSICS", 8709}, - {"CINE CINEMA 16/9", 8301}, - {"cinecinemas", 4008}, - {"CINECLASSICS", 29203}, - {"Cinedom 1", 176}, - {"Cinedom 1B", 178}, - {"Cinedom 1C", 180}, - {"Cinedom 1D", 190}, - {"Cinedom 2", 179}, - {"Cinedom 2B", 183}, - {"Cinedom 2C", 184}, - {"Cinedom 2D", 188}, - {"Cinedom 2E", 193}, - {"Cinedom 3", 182}, - {"Cinedom 3B", 185}, - {"Cinedom 3C", 192}, - {"Cinedom 3D", 195}, - {"Cinedom 4", 181}, - {"Cinedom 4B", 187}, - {"Cinedom 4C", 191}, - {"Cinedom 5", 186}, - {"Cinedom 5B", 194}, - {"Cindedom Deluxe", 189}, - {"CINEMANA AZUL", 29501}, - {"CINEMANA ROJO", 29605}, - {"CINEMANA", 29500}, - {"K1", 8401}, - {"K2", 8402}, - {"K3", 8403}, - {"K4", 8404}, - {"K5", 8405}, - {"K6", 8406}, - {"K7", 8407}, - {"K9", 8409}, - {"K12", 8412}, - {"TAQUILLA 1", 29206}, - {"TAQUILLA 2", 29207}, - {"TAQUILLA 3", 29502}, - {"TAQUILLA 4", 29503}, - {"TAQUILLA 5", 29504}, - {"TAQUILLA 6", 29301}, - {"TAQUILLA 7", 29302}, - {"TAQUILLA 8", 29303}, - {"TAQUILLA 11", 29316}, - {"TAQUILLA 12", 29610}, - {"TAQUILLA 13", 29402}, - {"TAQUILLA 14", 29212}, - {"TAQUILLA 16|9", 29606}, - // Music - {"40 LATINO", 29031}, - {"40 TV", 29110}, - {"CANAL+ JAUNE", 8203}, - {"CLASSICA", 15}, - {"GOLDSTAR TV", 518}, - {"MCM 2", 8305}, - {"MCM AFRICA", 8307}, - {"MCM", 8302}, - {"MTV 2", 28649}, - {"MTV 6", 28641}, - {"MTV Base", 28645}, - {"MTV Central", 28643}, - {"MTV F", 28642}, - {"MTV Hits", 28644}, - {"MUZZIK", 8007}, - {"RFM TV", 17008}, - {"TMF", 5015}, - {"VH1 Classic", 28647}, - {"VH1", 28646}, - {"Video Italia", 12220}, - {"VIVA ZWEI", 12120}, - {"VIVA", 12732}, - {"ZIK'/XXL", 17004}, - // News - {"BBC WORLD", 17007}, - {"Bloomberg TV", 12160}, - {"CNBC", 28010}, - {"CNBC", 35}, - {"CNBC-NBC", 29202}, - {"CNN", 28512}, - {"DW-tv", 9005}, - {"EuroNews", 28015}, - {"FOX NEWS", 29032}, - {"N24", 47}, - {"n-tv", 12730}, - {"Sky News", 3995}, - // Netherlands - {"NED1", 4011}, - {"NED2", 4012}, - {"NED3", 4013}, - {"NET5", 5004}, - {"RTL4", 2004}, - {"RTL5", 2005}, - {"SBS6", 5005}, - {"V8/Fox Kids", 5020}, - {"Yorin", 5010}, - // Porn - {"BEATE-UHSE.TV", 21}, - {"Blue Movie1", 513}, - {"Blue Movie2", 514}, - {"Blue Movie3", 515}, - {"K10", 8410}, - {"TAQUILLA X", 29213}, - {"TAQUILLA X", 29602}, - {"TAQUILLA XX", 29607}, - {"X-ZONE", 4009}, - // Sports - {"C+BLAUW", 4006}, - {"DSF", 900}, - {"EUROSPORT", 8101}, - {"Eurosport", 28009}, - {"EUROSPORT", 29310}, - {"EUROSPORTNEWS", 29037}, - {"PATHE SPORT|", 8009}, - {"PREMIERE SPORT 1", 17}, - {"PREMIERE SPORT 2", 27}, - {"SUPERDOM", 26}, - // French - {"13EME RUE", 8703}, - {"AB 1", 17001}, - {"AB MOTEURS", 17000}, - {"ACTION", 17010}, - {"ALLOCINE TV", 8308}, - {"ANIMAUX", 17002}, - {"ARTE", 9009}, - {"BLOOMBERG TV", 8004}, - {"CA TV", 8610}, - {"CANAL+", 8201}, - {"CANAL+ BLEU", 8202}, - {"CANAL J", 8108}, - {"CANAL JIMMY", 8006}, - {"CANALCLUB", 8812}, - {"Cartoon Network", 28511}, - {"CLUB TELEACHAT", 8303}, - {"COMEDIE !", 8702}, - {"CONTACT TV", 8804}, - {"CUISINE.TV", 8112}, - {"DEMAIN !", 8701}, - {"DISNEY CHANNEL", 8207}, - {"DT CSAT 10", 9159}, - {"ENCYCLOPEDIA", 17003}, - {"ESCALES", 17005}, - {"EURONEWS", 8505}, - {"FORUM", 8707}, - {"FRANCE 2", 8801}, - {"FRANCE 3", 8802}, - {"GAME ONE", 8717}, - {"i TELEVISION", 8010}, - {"KIOSQUE", 8704}, - {"KTO", 8304}, - {"LA CHAINE METEO", 8008}, - {"LA CINQUIEME", 8501}, - {"LaChaneHistoire", 17006}, - {"LCI", 8107}, - {"LCP", 8506}, - {"L'EQUIPE TV", 8706}, - {"LibertyTV.com", 12280}, - {"MANGAS", 17011}, - {"MONTECARLO TMC", 8102}, - {"Motors TV", 12300}, - {"NAT GEOGRAPHIC", 8310}, - {"PAD", 8211}, - {"PARIS PREMIERE", 8104}, - {"PLANETE 2", 8507}, - {"PLANETE", 8103}, - {"PMU sur Canal+", 8210}, - {"RFO SAT", 8708}, - {"SANTE - VIE", 8110}, - {"SEASONS", 8001}, - {"TCM", 28515}, - {"TEST CDN 1", 8616}, - {"TEST CDN 3", 8627}, - {"TiJi", 8309}, - {"TV 5", 9001}, - {"TV BREIZH", 8502}, - {"TV Puls", 20601}, - {"TV5 Europe", 12240}, - {"VOYAGE", 8105}, - // Spanish - {"ANDALUCA TV", 29011}, - {"Bloomberg", 12721}, - {"CALLE 13", 29609}, - {"Canal Canarias", 29700}, - {"Cartoon Network", 29314}, - {"CNN+", 29020}, - {"DISCOVERY", 29116}, - {"DISNEY CHANNEL", 29111}, - {"DOCUMANA", 29200}, - {"ESTILO", 29305}, - {"ETB", 29035}, - {"FASHION TV", 29115}, - {"FOX KIDS", 29209}, - {"FOX", 29507}, - {"MOSAICO", 29315}, - {"MTEO", 29014}, - {"Nat Geo Channel", 29034}, - {"NICK-PARAMOUNT", 29312}, - {"RTPI", 9006}, - {"SEASONS", 29204}, - {"TAQUILLA 0", 29205}, - {"TCM.", 28516}, - {"TVC INT.", 29701}, - {"VIAJAR", 29306}, - // Miscellaneous - {"Alice", 12200}, - {"Canal Algerie", 9008}, - {"CANALPRO TV", 8516}, - {"ESC1 - EGYPTE", 9003}, - {"FASHION TV.COM", 17009}, - {"Home Shopping Euro", 45}, - {"Home Shopping Euro", 40}, - {"Kabel 1 Austria", 20004}, - {"Kabel 1 Schweiz", 20003}, - {"Polonia 1/Top Sho", 20366}, - {"ProSieben A", 20002}, - {"ProSieben Schweiz", 20001}, - {"QVC GERMANY", 12100}, - {"RAI 1", 9004}, - {"REAL MADRID TV", 29019}, - {"RealityTV", 20309}, - {"RTL TELE Letzebuerg", 3994}, - {"RTM - MAROC", 9002}, - {"SDWEST BW", 28113}, - {"SDWEST RP", 28231}, - {"Super 1", 20364}, - {"Travel", 28001}, - {"TV7", 9007}, - {"TV-NIEP II", 12740}, - {"Wishline", 12320} -}; - - -// Nothing user-configurable below this line. - -static const char date_line[] = "\t<td align=center valign=middle colspan=3><span id=fb-b10>"; -static const char start_time_line[] = " \t\t<td id=\"jobview-box-date\" align=center><nobr> "; -static const char stop_time_line[] = "\t\t\t<tr><td id=\"line\" align=center><span id=\"fn-w9\">bis "; -static const char channel_line[] = "\t\t\t<tr><td align=center><span id=\"fb-w9\">"; -static const char title_line[] = "\t\t\t\t<td align=left width=100%><span id=\"fb-w10\">"; -static const char summary_line[] = "<span id=\"fn-b8\">"; -static const char genre_line[] = "\t\t\t\t<td align=right valign=center nowrap><span id=\"fn-w10\">"; - -static const int month_lengths[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - - - - -char map_special_char(const char * const word) - -{ - if (strcmp(word, "auml") == 0) - return ''; - else if (strcmp(word, "ouml") == 0) - return ''; - else if (strcmp(word, "uuml") == 0) - return ''; - else if (strcmp(word, "Auml") == 0) - return ''; - else if (strcmp(word, "Ouml") == 0) - return ''; - else if (strcmp(word, "Uuml") == 0) - return ''; - else if (strcmp(word, "szlig") == 0) - return ''; - else if (strcmp(word, "nbsp") == 0) - return ' '; - else if (strcmp(word, "amp") == 0) - return '&'; - return ' '; -} - - - - - -void read_file_name_and_title(const char * const line, char * const file_name, char * const title) - -{ - int line_index = sizeof(title_line) - 1; - int title_index = 0; - int file_name_index = 0; - char ch; - do - { - ch = line[line_index++]; - if (ch == '&') - { - char word[10]; - int i = 0; - while ((line[line_index + i] != ';') && (i < 9)) - { - word[i] = line[line_index + i]; i++; - } - if (line[line_index + i] == ';') - { - word[i] = 0; - ch = map_special_char(word); - line_index += i; - } - } - switch (ch) - { - case '': file_name[file_name_index++] = 'a'; file_name[file_name_index++] = 'e'; break; - case '': file_name[file_name_index++] = 'o'; file_name[file_name_index++] = 'e'; break; - case '': file_name[file_name_index++] = 'u'; file_name[file_name_index++] = 'e'; break; - case '': file_name[file_name_index++] = 'A'; file_name[file_name_index++] = 'e'; break; - case '': file_name[file_name_index++] = 'O'; file_name[file_name_index++] = 'e'; break; - case '': file_name[file_name_index++] = 'U'; file_name[file_name_index++] = 'e'; break; - case '': file_name[file_name_index++] = 's'; file_name[file_name_index++] = 's'; break; - case ' ': file_name[file_name_index++] = '_'; break; - case '&': - file_name[file_name_index++] = 'u'; file_name[file_name_index++] = 'n'; file_name[file_name_index++] = 'd'; - break; - default: - if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || (ch == '-')) - file_name[file_name_index++] = ch; - } - title[title_index++] = ch; - } while ((file_name_index < max_title-5) && (ch != '<') && (ch != 0)); - file_name[file_name_index] = 0; - title[title_index-1] = 0; -} - - - -void read_summary(char * const summary) - -{ - int summary_index = 0; - int ch; - bool need_space = false; - bool done = false; - do - { - ch = getchar(); - switch (ch) - { - case '&': - { - char word[10]; - int i = 0; - ch = getchar(); - while ((ch != ';') && (ch != EOF) && (i < 9)) - { - word[i++] = ch; - ch = getchar(); - } - word[i] = 0; - if (need_space) {summary[summary_index++] = ' '; need_space = false;} - summary[summary_index++] = map_special_char(word); - } - break; - case '<': - { - char word[6]; - int word_index = 0; - do - { - ch = getchar(); - word[word_index++] = ch; - } while ((word_index < 6) && (ch != '>') && (ch != EOF)); - while ((ch != '>') && (ch != EOF)) ch = getchar(); - if (strncmp("/span", word, 4) == 0) - done = true; - } - break; - default: - { - if (ch <= ' ') - { - if (summary_index > 0) need_space = true; - } - else - { - if (need_space) {summary[summary_index++] = ' '; need_space = false;} - summary[summary_index++] = ch; - } - } - } - } while ((summary_index < max_summary - 2) && (!done) && (ch != EOF)); - summary[summary_index] = 0; -} - - - -int find_channel_number(const unsigned short * const vdr_pnrs, const char * const channel_name) - -{ - for (int tvtv_channel_number = 0; tvtv_channel_number < sizeof(channel_map)/sizeof(map_entry); tvtv_channel_number++) - if (strcmp(channel_name, channel_map[tvtv_channel_number].tvtv_name) == 0) - for (int vdr_channel_number = 0; vdr_pnrs[vdr_channel_number] != 0xFFFF; vdr_channel_number++) - if (vdr_pnrs[vdr_channel_number] == channel_map[tvtv_channel_number].pnr) - return vdr_channel_number; - fprintf(stderr, "Error - channel '%s' not recognized.\n", channel_name); - exit(1); - /*NOTREACHED*/ -} - - - - -unsigned short * read_vdr_pnrs(const char * const channels_conf_file_name) - -{ - FILE * channels_conf = fopen(channels_conf_file_name, "r"); - if (channels_conf == NULL) - { - perror("unable to open channels.conf."); - exit(1); - } - unsigned short * vdr_pnrs = (unsigned short *) malloc(max_vdr_channel * sizeof(unsigned short)); - int vdr_channel_number = 0; - while (!feof(channels_conf) && (vdr_channel_number < max_vdr_channel-1)) - { - char line[1024]; - fgets(line, sizeof(line)-1, channels_conf); - int pnr; - if ((line[0] != ':') && - (sscanf(line, "%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%d", &pnr) == 1)) - vdr_pnrs[vdr_channel_number++] = pnr; - } - vdr_pnrs[vdr_channel_number++] = 0xFFFF; // sentinel - fprintf(stderr, "%d pnrs.\n", vdr_channel_number); - return (unsigned short *) realloc(vdr_pnrs, vdr_channel_number * sizeof(unsigned short)); -} - - - - -void process_input(const unsigned short * const vdr_pnrs) - -{ - - int channel = -1; - int day = -1; - int next_day = -1; - int start_time = -1; - int stop_hour = -1; - int stop_minute= -1; - char genre[max_genre] = {0}; - char summary[max_summary] = {0}; - char file_name[max_title] = {0}; - char title[max_title] = {0}; - - while (!feof(stdin)) - { - char line[max_line]; - fgets(line, max_line-1, stdin); - line[max_line-1] = 0; - if (strncmp(line, date_line, sizeof(date_line)-1) == 0) - { - const int month = (line[sizeof(date_line) + 6]- '0') * 10 + line[sizeof(date_line) + 7]-'0'; - day = (line[sizeof(date_line) + 3]- '0') * 10 + line[sizeof(date_line) + 4]-'0'; - next_day = day == month_lengths[month-1]? 1 : day + 1; - } - else if (strncmp(line, start_time_line, sizeof(start_time_line)-1) == 0) - start_time = (line[sizeof(start_time_line) - 1] - '0') * 1000 + - (line[sizeof(start_time_line) ] - '0') * 100 + - (line[sizeof(start_time_line) + 2] - '0') * 10 + - (line[sizeof(start_time_line) + 3] - '0'); - else if (strncmp(line, stop_time_line, sizeof(stop_time_line)-1) == 0) - { - stop_hour = (line[sizeof(stop_time_line) - 1] - '0') * 10 + - (line[sizeof(stop_time_line) ] - '0'); - stop_minute = (line[sizeof(stop_time_line) + 2] - '0') * 10 + - (line[sizeof(stop_time_line) + 3] - '0') + - stop_time_safety_margin; - if (stop_minute > 59) - { - stop_minute -= 60; - if (stop_hour == 23) - stop_hour = 0; - else - stop_hour++; - } - if ((day < 0) || (start_time < 0) || (file_name[0] == 0) || (channel == -1)) - { - fprintf(stderr, "Input data error.\n"); - exit(1); - } - else - printf("1:%03d:%02d:%04d:%02d%02d:%d:%d:%s:\"%s\" %s||%s||||||(epg2timers)\n", - channel+1, start_time < 600? next_day : day, start_time, stop_hour, stop_minute, - recording_priority, recording_lifetime, file_name, - title, genre, summary); - start_time = -1; channel = -1; - file_name[0] = 0; summary[0] = 0; genre[0] = 0; - } - else if (strncmp(line, title_line, sizeof(title_line)-1) == 0) - read_file_name_and_title(line, file_name, title); - else if (strncmp(line, channel_line, sizeof(channel_line)-1) == 0) - { - int i = sizeof(channel_line); - while ((line[i] != '<') && (line[i] != 0)) i++; - line[i] = 0; // end of string - channel = find_channel_number(vdr_pnrs, line + sizeof(channel_line) - 1); - } - else if (strncmp(line, summary_line, sizeof(summary_line)-1) == 0) - read_summary(summary); - else if (strncmp(line, genre_line, sizeof(genre_line)-1) == 0) - { - int genre_index; - for (genre_index = 0; genre_index < max_genre-1; genre_index++) - { - const char ch = line[genre_index + sizeof(genre_line)-1]; - if ((ch == 0) || (ch == '&') || (ch == '<')) - break; - genre[genre_index] = ch; - } - genre[genre_index] = 0; - } - } -} - - - - -main(int argc, char *argv[]) - -{ - fprintf(stderr, "epg2timers Version 0.5, 15-Sep-2001.\n"); - - if (argc != 2) - { - fprintf(stderr, "usage: %s channels.conf\n", argv[0]); - exit(1); - } - - const unsigned short * const vdr_pnrs = read_vdr_pnrs(argv[1]); - process_input(vdr_pnrs); - exit(0); -} diff --git a/Tools/epg2timers/epg_channel_names b/Tools/epg2timers/epg_channel_names deleted file mode 100644 index 2633a9909..000000000 --- a/Tools/epg2timers/epg_channel_names +++ /dev/null @@ -1,400 +0,0 @@ -ATV,at -ORF1,at -ORF2,at -TW1,at - -Club RTL,be -Ketnet/Canvas,be -TVI,be -tv1,be - -SF1,ch -sf2,ch - -13th Street,de -3sat,de,at,ch -ARD,de -ARTE,de -B1,de -BBC World,de -BEATE-UHSE.TV,de -BR-alpha,de -BR3,de -Bet on Jazz,de -Bloomberg TV,de -Blue Movie1,de -Blue Movie2,de -Blue Movie3,de -CNBC,de -CNN,de -Cartoon,de -Cindedom Deluxe,de -Cinedom 1,de -Cinedom 2,de -Cinedom 3,de -Cinedom 4,de -Cinedom 5,de -Classica,de -DSF,de -Discovery,de -Disney Channel,de -Eins Extra,de -Eins Festival,de -Eins MuXx,de -EuroNews,de -Eurosport,de -FOX KIDS,de -Filmpalast,de -Goldstar TV,de -HH-1,de -HR,de -Heimatkanal,de -Junior,de -K-Toon,de -Kabel 1,de -Kinderkanal,de -Krimi&Co,de -MDR,de -MTV,de -MTV2,de -N24,de -NBC,de -NDR,de -NEUN LIVE,de -ONYX,de -ORB,de -Phoenix,de -Planet,de -Premiere 1,de -Premiere 2,de -Premiere 3,de -Premiere Action,de -Premiere Comedy,de -Premiere SCI-FI,de -Premiere Sport1,de -Premiere Sport2,de -Premiere Sport3,de -Premiere Star,de -Premiere analog,de -ProSieben,de -QVC,de -RTL,de -RTL2,de -SAT.1,de -SR,de -SWR BW,de -SWR RP,de -SeaSonS,de -Studio Universal,de -Sunset,de -Super RTL,de -TNT,de -TRT,de,tr -TV.BERLIN,de -Theaterkanal,de -VIVA,de -VIVA2,de -VOX,de -WDR,de -ZDF,de -ZDF.doku,de -ZDF.info,de -n-tv,de -skynews,de -tv.m,de - -Danmark 1,dk -TV2 Danmark,dk - -MTV3,fi -Nelonen 4,fi -Subtv,fi -TV1,fi -TV2,fi - -13me Rue,fr -AB 1,fr -Arte,fr -Arte Sat,fr -Canal J,fr -Canal Jimmy,fr -Canal+,fr -Canal+ Bel. bleu,fr -Canal+ Bel. jaune,fr -Canal+ Belgique,fr -Canal+ bleu,fr -Canal+ jaune,fr -Canal+ vert,fr -Cin Cinmas 1,fr -Cin Cinmas 2,fr -Cin Cinmas 3,fr -Cin Classics,fr -Cinfaz,fr -Cinstar 1,fr -Cinstar 2,fr -Cintoile,fr -Comdie !,fr -Disney Channel,fr -Escale,fr -Eurosport,fr -Festival,fr -Fox Kids,fr -France 2,fr -France 3,fr -Histoire,fr -LCI,fr -La Cinquime Sat,fr -La chane histoire,fr -La cinquime,fr -M6,fr -M6 Music,fr -MCM,fr -MTV,fr -Mangas,fr -Mezzo,fr -Muzzik,fr -Odysse,fr -Paris Premire,fr -Path sport,fr -Plante,fr -RTBF 1,fr -RTBF 2,fr -RTL 9,fr -Srie Club,fr -TCM,fr -TF1,fr -TMC,fr -TSR 1,fr -TSR 2,fr -TV5,fr -Tltoon,fr -Tva,fr -Voyage,fr -XXL,fr - -ANIMALplanet,hu -Budapest TV,hu -Duna TV,hu -FILMMZEUM,hu -FOX KIDS/SPORTS,hu -FNIX TV,hu -Game Channel,hu -HBO,hu -Hallmark,hu -MAGYAR ATV,hu -Minimax,hu -National Geographic,hu -Nickelodeon,hu -RTL Klub,hu -Romantica,hu -SATeLIT,hu -SPORT1,hu -Spektrum TV,hu -TV2,hu -VIASAT3,hu -VIVA+,hu -fix.tv,hu -m1,hu -m2,hu - -+ Calcio,it -+ F1,it -Adult +,it -CANALE 5,it -Canal Jimmy,it -Canale Viaggi,it -Cartoon Network,it -Cine Classics,it -CineCinemas 1,it -CineCinemas 2,it -Classica,it -Cult Network,it -Discovery Channel,it -Disney Channel,it -Euro News,it -Eurosport,it -Hallmark,it -Happy Channel,it -ITALIA 1,it -La 7,it -MTV,it -MTV - TMC 2,it -Marcopolo,it -Match Music,it -Milan Channel,it -Nuvolari Motor,it -Odeon,it -Planete,it -Primafila,it -RAI 1,it -RAI 2,it -RAI 3,it -RAI Sat Fiction,it -RETE 4,it -Raisat Album,it -Raisat Art,it -Raisat Cinema,it -Raisat Educational,it -Raisat Gambero Rosso,it -Raisat Nettuno 1,it -Raisat Nettuno 2,it -Raisat Ragazzi,it -Raisat Show,it -Raisat Sport,it -SNAI Sat,it -Salute e benessere,it -Sat 2000,it -Satisfation Club TV,it -Seasons,it -Stream Calcio,it -Stream News,it -Studio Universal,it -TSI 1,it -TSI 2,it -TVL,it -Tele+ 16:9,it -Tele+ Bianco,it -Tele+ Grigio,it -Tele+ Nero,it -VIVA - Rete A,it - -Netherland 1,nl -Netherland 2,nl -Netherland 3,nl - -ATV Avrupa,tr -Kanal D,tr -Kral TV,tr -NTV Turkey,tr -Show TV,tr -Star TV,tr - -Adult Channel,uk -Adventure One,uk -Anglia,uk -BBC Choice,uk -BBC Choice NI,uk -BBC Choice Scotland,uk -BBC Choice Wales,uk -BBC Knowledge,uk -BBC News 24,uk -BBC Parliament,uk -BBC Prime,uk -BBC World,uk -BBC1,uk -BBC1 North. Ireland,uk -BBC1 Scotland,uk -BBC1 Wales,uk -BBC2,uk -BBC2 North. Ireland,uk -BBC2 Scotland,uk -BBC2 Wales,uk -Bangla TV,uk -Bloomberg TV,uk -Border,uk -Bravo (Analogue),uk -Bravo (Digital),uk -British Eurosport,uk -CNBC Europe,uk -CNN,uk -Carlton Central,uk -Carlton Cinema,uk -Carlton Food,uk -Carlton Westcountry,uk -Carlton/LWT,uk -Cartoon Network,uk -Challenge TV,uk -Channel 4,uk -Channel 5,uk -Channel Television,uk -Disc. Animal Planet,uk -Disc. Channel (Ana.),uk -Disc. Civilisations,uk -Disc. Home Leisure,uk -Disc. Sci-Trek,uk -Disc. Travel Advent.,uk -Discovery Channel,uk -Discovery Kids,uk -Discovery Wings,uk -Disney,uk -Euronews,uk -Fantasy Ch. Dig.,uk -Fantasy Channel,uk -Film Four,uk -Fox Kids,uk -Grampian,uk -Granada,uk -Granada Breeze,uk -Granada Men & Motors,uk -Granada Plus,uk -HTV Wales,uk -HTV West,uk -Hallmark,uk -History Channel,uk -ITN News Channel,uk -ITV Sport Channel,uk -ITV Sport Plus,uk -ITV2,uk -Landscape,uk -Living,uk -MTV UK,uk -MUTV,uk -Meridian,uk -National Geographic,uk -Network 2,uk -Nick Junior,uk -Nick Junior Analogue,uk -Nickelodeon (dig.),uk -Nickleodeon (ana.),uk -Pakistani Channel,uk -Paramount Comedy,uk -Performance,uk -Play UK,uk -Playboy TV,uk -QVC,uk -RTE1,uk -Racing Channel,uk -Rapture TV,uk -S2,uk -S4C,uk -S4C digidol,uk -SKY Cinema,uk -SKY Movie Max(SDig.),uk -SKY Movie Max(ana.),uk -SKY News,uk -SKY Premier(Digital),uk -SKY Premier(OnDigi),uk -SKY Sports 1,uk -SKY Sports 2,uk -SKY Sports 3,uk -Sci-Fi Cable,uk -Sci-Fi Satelite,uk -Scottish,uk -Screenshop,uk -Shop!,uk -Sky Movie Max(OnDig),uk -Sky One,uk -Sky One (OnDigital),uk -Sky Premier(Ana.),uk -Sky Sports .com,uk -Sky Sports Extra,uk -Sky Travel,uk -Sony Entertainment,uk -TCM,uk -TCM (Analogue),uk -TG4,uk -TV3,uk -Tara Television,uk -The Box,uk -Trouble Analogue,uk -Trouble Digital,uk -Tyne Tees Television,uk -UK Drama,uk -UK Gold,uk -UK Gold 2,uk -UK Horizons,uk -UK Style,uk -Ulster ,uk -VH1,uk -Yorkshire,uk -Zee TV,uk diff --git a/Tools/epg2timers/get_merkliste.pl b/Tools/epg2timers/get_merkliste.pl deleted file mode 100755 index bb23fa3b2..000000000 --- a/Tools/epg2timers/get_merkliste.pl +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/perl -# Create a user agent object - -use HTML::Entities; -use HTML::Parser; -use LWP::UserAgent; -use IO::Handle; - -STDOUT->autoflush(1); - -$ua = new LWP::UserAgent; -$ua->agent("Mozilla/9.1 " . $ua->agent); -# $ua->proxy('http', 'http://localhost:8080/'); - -$filename = "merkliste.html"; -$base_url = "http://www.tvtv.de"; -# Hier das Bookmark von TVTV eintragen: -@files_to_fetch = ("/cgi-bin/bookmark.cgi?id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - -$num = 0; -$state = 0; - -$p = HTML::Parser->new( api_version => 3, - start_h => [\&fparser_start, "tagname, attr"], - unbroken_text => 1 ); - -foreach $url (@files_to_fetch) { - $nurl = $base_url . $url; - print "Getting " . $nurl . "...\n"; - $req = new HTTP::Request GET => $nurl; - $res = $ua->request($req); - if ($res->is_success) { - open (OUTFILE, ">" . $filename); - print OUTFILE $res->content; - close (OUTFILE); - $p->parse ($res->content); - $p->eof; - } else { - print "...FAILED\n"; - } -} -# Zielordner fuer die Speicherung der Merkliste: - -print "...saved to 'merkliste.html'\n"; -sub fparser_start { - my($tagname, $attr_t) = @_; - my(%attr) = %$attr_t; - - if ($tagname eq "frame") { - if ($state == 1) { - if (($attr{name} eq "frame_main") || - ($attr{name} eq "frame_nav") || - ($attr{name} eq "frame_nav_bottom")) { - push @files_to_fetch, $attr{src}; - } - } - if ($state == 2) { - if (($attr{name} eq "frame_content")) { - push @files_to_fetch, $attr{src}; - } - } - } - if ($tagname eq "a") { - if ($attr{href} ne "") { - $last_href = $attr{href}; - if ($state == 0) { - push @files_to_fetch, $last_href; - $state = 1; - } - } - } - if ($tagname eq "img") { - if ($state == 1) { - if ($attr{src} =~ /b_joblist/i) { - $state = 2; - push @files_to_fetch, $last_href; - } - } - } -} - - diff --git a/Tools/epg2timers/loadvdr.pl b/Tools/epg2timers/loadvdr.pl deleted file mode 100755 index 485b0a4a5..000000000 --- a/Tools/epg2timers/loadvdr.pl +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/perl -# -# 0.01 loadvdr (peter) -# 0.02 delete old entries before updating (peter) -# 0.03 dumped Net::Telnet because of lost connections -# -# please submit diffs to petera@gmx.net -# -# ./epg2timers < merkliste.html | perl -w loadvdr.pl -# -# - -use Socket; -use Getopt::Std; - -@resp = (); - -$Dest = "localhost"; -$Port = 2001; - -$Timeout = 10; # max. seconds to wait for response - -$SIG{ALRM} = sub { Error("timeout"); }; -alarm($Timeout); - -$iaddr = inet_aton($Dest) || Error("no host: $Dest"); -$paddr = sockaddr_in($Port, $iaddr); - -$proto = getprotobyname('tcp'); -socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!"); -connect(SOCK, $paddr) || Error("connect: $!"); -select(SOCK); $| = 1; -Receive_void(); - -Send("lstt"); - -foreach $item (reverse @resp){ - if ($item =~ /^250.(\d{1,2}).*\(epg2timers\)/) { - Send_void("DELT $1"); - } -} - -while (defined ($line = <STDIN>)) { - chomp $line; - Send_void("UPDT $line"); -} - -Send("quit"); -close(SOCK) || Error("close: $!"); - - - -sub Send -{ - my $cmd = shift || Error("no command to send"); - print SOCK "$cmd\r\n"; - Receive(); -} - -sub Send_void -{ - my $cmd = $_[0]; - print SOCK "$cmd\r\n"; - Receive_void(); -} - -sub Receive -{ - while (<SOCK>) { - chomp; - push @resp,$_; - last if substr($_, 3, 1) ne "-"; - } -} - -sub Receive_void -{ - while (<SOCK>) { - last if substr($_, 3, 1) ne "-"; - } -} - -sub Error -{ - print STDERR "@_\n"; - close(SOCK); - exit 0; -} - diff --git a/Tools/epg2timers/update_timers b/Tools/epg2timers/update_timers deleted file mode 100755 index 3849841b6..000000000 --- a/Tools/epg2timers/update_timers +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -# update_timers: retrieve a new "merkliste" from http://tvtv.de, -# convert it to vdr format and transmit it to vdr via SVDRP. - -TOOLDIR="/home/cko/bin" -CHANPATH="/home/cko/VDR/channels.conf" - -cd /tmp -rm -f merkliste.html - -# if you have a slow dial up connection to your name server and/or ISP, -# this will avoid a timeout in get_merkliste.pl. -ping -c 2 www.tvtv.de - -# get the "merkliste". -$TOOLDIR/get_merkliste.pl - -if [ -s merkliste.html ] ; then - # convert merkliste.html to timers.conf format and transmit it to vdr. - $TOOLDIR/epg2timers $CHANPATH < merkliste.html | $TOOLDIR/loadvdr.pl -fi diff --git a/Tools/epg2timers/update_timers.old b/Tools/epg2timers/update_timers.old deleted file mode 100755 index c4c3f5c5e..000000000 --- a/Tools/epg2timers/update_timers.old +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -# update_timers: load a new "merkliste" from http://tvtv.de -# and create a new VDR timer configuration file (timers.conf) -# from it. Restart VDR if the timers have changed. - -TOOLDIR="/home/cko/bin" -VDRDIR="/home/cko/VDR" - -cd /tmp -rm -f merkliste.html epgtimers.new epgtimers.old vdrtimers.old -ping -c 2 www.tvtv.de -$TOOLDIR/get_merkliste.pl -if [ -s merkliste.html ] ; then - $TOOLDIR/epg2timers $VDRDIR/channels.conf < merkliste.html | sort -t: +2.0 -5.0 > epgtimers.new - fgrep '(epg2timers)' $VDRDIR/timers.conf | sort -t: +2.0 -5.0 > epgtimers.old - if ! cmp -s epgtimers.old epgtimers.new ; then - /sbin/killproc $VDRDIR/vdr - fgrep -v '(epg2timers)' $VDRDIR/timers.conf > vdrtimers.old - cat epgtimers.new vdrtimers.old | sort -t: +2.0 -5.0 > $VDRDIR/timers.conf - echo "Timers updated." - fi -fi -rm -f merkliste.html epgtimers.new epgtimers.old vdrtimers.old diff --git a/Tools/master-timer/LIESMICH b/Tools/master-timer/LIESMICH deleted file mode 100644 index 8e53da955..000000000 --- a/Tools/master-timer/LIESMICH +++ /dev/null @@ -1,70 +0,0 @@ -Master-Timer -============ -(w) by Matthias Schniedermeyer (ms@citd.de) - - -1. Einleitung -------------- - -Master-Timer ist ein System zum automatischen Aufnehmen von Serien und Filmen. -Beim Aufruf werden die Konfigurationsdateien gelesen, die Datei "epg.data" im -aktuellen Verzeichnis nach passenden Sendungen durchsucht und die ermittelten -Timer per SVDRP in VDR programmiert. Danach beendet sich Master-Timer. - -Entsprechend empfiehlt es sich, Master-Timer per cronjob aufzurufen. - -2. Konfigurationsdateien ------------------------- - -Alle Konfigurationsdateien liegen unter "~/.master-timer". Es werden -regulaere Ausdruecke ohne Unterscheidung der Gross-/Kleinschreibung -benutzt. - -config: Die Hauptkonfigurationsdatei. - -deepblack: Eine Negativliste von Titeln, die man NIEMALS NIMMER sehen will. - Die epg-datensaetze werden beim Parsen einfach entfernt. - -subtitle-movies: Eine Liste der "Subtitel", die ein Zeichen fuer einen Film - sind (soweit die von den Sendern richtig ausgefuellt sind). Die - Einstellungen in dieser Datei werden fuer das Makro "MOVIE" in torecord - benutzt. - Kommentarzeilen sind nicht erlaubt. - -torecord: Liste der aufzunehmenden Filme. - -done: Liste der Titel/Subtitel, die bereits aufgenommen wurden. Timer, die - hier auftauchen, werden in VDR automatisch geloescht. - -channels-to-scan: Diese Kanaele werden vom Skript "scan-channels" durch- - geschaltet (zwecks Einlesen der EPG-Daten). Die Datei wird von Master- - Timer selbst nicht benutzt. - -3. Anmerkungen --------------- - -- einige Sender fuellen die EPG-Felder nicht korrekt aus. Diese Fehler - werden von Master-Timer automatisch korrigiert. - - Pro7: Title aus dem Subtitle entfernen '<Title> / <Subtitle>' - Pro7: Timer zwischen 00:00 und 05:00 werden einen Tag in die Zukunft - verschoben (Als unguten Nebeneffekt hat dies zur Folge das zum - aktuellen Tag NICHT die epg-Daten das folgenden Tags (=Das was in - der Fernsehzeitschrift noch auf der gleichen Seite ist) mehr gesendet - werden. Wenn man also "Last Minute" etwas aufnehmen will, dann muss - man (leider) einen Timer "per Hand" in VDR einprogrammieren!) - VOX/VIVA: Subtitle ist in "" eingeschlossen nd nach ". " steht die description - VIVA: Wenn der Subtitle mit einem Space beginnt, dann wird der komplette - Subtitle in die Description verschoben - RTL2: Wenn der EPG-Datensatz eine Dauer von kleiner/gleich 1 Sekunde hat, - wird er einfach verworfen. - -Bis auf den jeweils 2ten VIVA&Pro-7 Bug werden die Fixes an jedem -epg-Datensatz ausprobiert. - -4. Bekannte Bugs ----------------- - -- Es wird nicht geprueft ob noch genug DVB-Karten vorhanden sind -- "Joined timers" werden nur automatisch geloescht wenn alle dazugehoerigen - Sendungen "done" sind. diff --git a/Tools/master-timer/README b/Tools/master-timer/README deleted file mode 100644 index 05cc41acc..000000000 --- a/Tools/master-timer/README +++ /dev/null @@ -1,58 +0,0 @@ -Master-Timer -============ -(w) by Matthias Schniedermeyer (ms@citd.de) - - -1. Introduction ---------------- - -Master-Timer is a system designed for automatically recording movies. -Upon execution it reads its configuration files, scans the file "epg.data" -in the current directory for matching titles and programs them via SVDRP -into VDR. - -You may for example run Master-Timer as a cron job. - -2. Config files ---------------- - -Configuration files are located in "~/.master-timer". Each entry is a -regular expression so you can use all Perl style REs you want. They are -processed case insensitive. - -config: Main configuration file. - -deepblack: Blacklist of "titles" you NEVER EVER want to see. - -subtitle-movies: A list of "Subtitles" which indicate a movie (used - by the "MOVIE" macro in torecord). - For channels that correctly fill out the subtitle e.g. it will not - work with *eRTL*. - -torecord: The titles you want to record. - -done: The titles/subtitles which are already recorded/should not be recorded - Programmed timers which got inserted into "done" will be deleted - automatically. - -channels-to-scan: Used only by the separate "scan-channels" script which - switches through channels in order to get EPG data. - -4. Notices ----------- - -- Recordings overlapping on the same channel will be joined into one timer -- Title/Subtitle/Descriptions are "fixed" for channels that don't fill them - out correctly (Pro-7/VOX/VIVA) - Pro7: Remove the Title from the Subtitle '<Title> / <Subtitle>' - VOX/VIVA: Subtitle is enclosed into "" and after ". " is the description - VIVA: When the Subtitle beginns with space the subtitle is moved to - description - All (except the second VIVA one) fixes are tried onto ALL Subtitles. - -5. Known-Bugs -------------- - -- It isn't checked if there are enough DVB-Cards -- Overlapping timers on the same channel are always joined -- Joined timers which are "done" don't get deleted automatically diff --git a/Tools/master-timer/THANKS b/Tools/master-timer/THANKS deleted file mode 100644 index 04bb13bad..000000000 --- a/Tools/master-timer/THANKS +++ /dev/null @@ -1,18 +0,0 @@ -Klaus Schmidinger - - VDR - -Malte Kiesel - - Suggestions - - Bug Reports - - Documentation Updates for README/LIESMICH/torecord/deepblack/config - -Guido Fiala - - Suggestions - - Bug Repots - - finding bugs i found just before i read that part of his mails - (First the bug, then the errormessages! Otherwise i will search/find - the bug myself :-))) ) - -Axel Gruber - - Suggestions - - Bug Reports diff --git a/Tools/master-timer/Todo b/Tools/master-timer/Todo deleted file mode 100644 index 1757ade08..000000000 --- a/Tools/master-timer/Todo +++ /dev/null @@ -1,6 +0,0 @@ - -- "Komfortable" Anzeige, mit Black & Whitelisten, fuer Genres/Titeln usw. -- Abspielen (mit automatischen "killen" des "Frontend"-VDRs) von - Aufzeichnungen -- "View"-Timer d.h. Timer der nicht Aufnimmt sondern nur den Kanal aendert -- "unwichtige" Timer "verdraengen" wenn andere Aufnahmen anstehen. diff --git a/Tools/master-timer/convert-DTV2VDR.pl b/Tools/master-timer/convert-DTV2VDR.pl deleted file mode 100755 index fb2a78310..000000000 --- a/Tools/master-timer/convert-DTV2VDR.pl +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/perl -w - -use strict; - -# The EPG-Entrys -my (%Entry, %channel, $mode); - -# 0 = VDR -> DTV -# 1 = DTV -> VDR -$mode = 0; - -read_channel_list(); -if ($mode) { - &read_dtv(); - &read_epgdata(); -} else { - &read_epgdata(); - &read_dtv(); -} -&print_VDR(); - -sub read_epgdata { - my ($channel, $duration, $title, $subtitle, $description, $time); - open (FI,"epg.data") or die ("Can't open file \"epg.data\"\n"); - - while (<FI>) { - # Begin Channel - if (/^C\s(\d+)\s+(.+)/) { - $channel=$2; - while (<FI>) { - # End Channel - if (/^c$/) { - last; - } - # Begin Timer - elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/) { - # Undef this Variables because it is possibel that not every timer uses this values - undef $duration; - undef $subtitle; - undef $description; - - $time=$2; - $duration=$3; - } - # Title - elsif (/^T\s(.*)/) { - $title=$1; - } - # Subtitle - elsif (/^S\s(.*)/) { - $subtitle=$1; - } - # Description - elsif (/^D\s(.*)/) { - $description=$1; - } - # End Timer - elsif (/^e$/) { - if ($mode) { - # DTV -> VDR - $Entry{$channel}{$time}{subtitle}=$subtitle if ($subtitle); - if ($description) { - if ($Entry{$channel}{$time}{description}) { - $Entry{$channel}{$time}{description} = "DTV: '$Entry{$channel}{$time}{description}' VDR: '$description'"; - } else { - $Entry{$channel}{$time}{description} = "DTV: '' VDR: '$description'"; - } - } - } else { - # VDR -> DTV - $Entry{$channel}{$time}{title}=$title; - $Entry{$channel}{$time}{duration}=$duration; - $Entry{$channel}{$time}{subtitle}=$subtitle if ($subtitle); - $Entry{$channel}{$time}{description}=$description if ($description); - } - } - } - } - } - close (FI); -} - -sub read_dtv { - my ($channel, $time, $duration, $title, $category, $subtitle, $description); - open (FI,$ARGV[0]) or die "Can't open DTV-File"; - - while (<FI>) { - chomp; - ($channel, $time, $duration, $title, $category, $subtitle, $description) = split (/\|/); - if (!$channel{$channel}) { - next; - } - $channel = $channel{$channel}; - if ($mode) { - # DTV -> VDR - if (!$subtitle && $description =~ /^\"(.*?)\"\:\s(.*)/) { - $Entry{$channel}{$time}{subtitle} = $1; - $description = $2; - } - $Entry{$channel}{$time}{title} = $title; - $Entry{$channel}{$time}{duration} = $duration; - $Entry{$channel}{$time}{subtitle} = $subtitle if ($subtitle); - $Entry{$channel}{$time}{category} = $category if ($category); - $Entry{$channel}{$time}{description} = $description if ($description); - } else { - # VDR -> DTV - $Entry{$channel}{$time}{category} = $category if ($category); - if ($description) { - if (!$Entry{$channel}{$time}{subtitle} && $description =~ /^\"(.*?)\"\:\s(.*)/) { - $Entry{$channel}{$time}{subtitle} = $1; - $description = $2; - } - if ($Entry{$channel}{$time}{description}) { - $Entry{$channel}{$time}{description} = "DTV: '$description' VDR: '$Entry{$channel}{$time}{description}'"; - } else { - $Entry{$channel}{$time}{description} = "DTV: '$description' VDR: ''"; - } - } - } - } - close (FI); -} - -sub read_channel_list { - my ($old, $new); - open (FI,"$ENV{HOME}/.master-timer/convert-channel-list") or die ("Can't read channel-List"); - while (<FI>) { - chomp; - ($old, $new) = split (/\|/); - $channel{$old} = $new; - } - close (FI); -} - -sub print_VDR() { - my ($channel, $title, $time); - foreach $channel (sort keys %Entry) { - print "C 1 $channel\n"; - foreach $time (sort keys %{%Entry->{$channel}}) { - if ($Entry{$channel}{$time}{duration}) { - print "E 1 $time $Entry{$channel}{$time}{duration}\n"; - print "K $Entry{$channel}{$time}{category}\n" if ($Entry{$channel}{$time}{category}); - print "T $Entry{$channel}{$time}{title}\n"; - print "S $Entry{$channel}{$time}{subtitle}\n" if ($Entry{$channel}{$time}{subtitle}); - print "D $Entry{$channel}{$time}{description}\n" if ($Entry{$channel}{$time}{description}); - print "e\n"; - } - } - print "c\n"; - } -} diff --git a/Tools/master-timer/convert-oldtorecord.pl b/Tools/master-timer/convert-oldtorecord.pl deleted file mode 100755 index 853c20bab..000000000 --- a/Tools/master-timer/convert-oldtorecord.pl +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/perl - -while (<>) - { - chomp; - if ($_ && !(/^\#/)) - { - ($title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine) = split (/\|/,$_); - - if ($timer_title) { - print "[$timer_title]\n"; - } elsif ($title) { - print "[$title]\n"; - } elsif ($subtitle) { - print "[$subtitle]\n"; - } elsif ($description) { - print "[$description]\n"; - } else { - die ("Illegal Format"); - } - - # Accept torecord only if it is for the current machine - if ($title) - { - print "Title = $title\n"; - } - if ($subtitle) - { - print "Subtitle = $subtitle\n"; - } - if ($description) - { - print "Description = $description\n"; - } - if ($channel) - { - print "Channel = $channel\n"; - } - if ($timeframe) - { - print "Timeframe = $timeframe\n"; - } - if ($prio) - { - print "Prio = $prio\n"; - } - if ($timer_title) - { - print "Timertitle = $timer_title\n"; - } - if ($margin) - { - print "Margin = $margin\n"; - } - if ($machine) - { - print "Instance = $machine\n"; - } - print "\n"; - } - } diff --git a/Tools/master-timer/master-timer.pl b/Tools/master-timer/master-timer.pl deleted file mode 100755 index 5ddf90940..000000000 --- a/Tools/master-timer/master-timer.pl +++ /dev/null @@ -1,1412 +0,0 @@ -#!/usr/bin/perl -w - -use strict; -# For the TCP-Connection to VDR -use Socket; -# For converting the Timers, read from VDR, back to Unix-Timestamps -use Time::Local; -# For parsing the command line -use Getopt::Std; - -# Debugmode -# You have to add the following numbers to build the debug-var -# 1 : Dump the "torecord" -# 2 : Dump all timers -# 4 : Show when a timer will be deleted -# 8 : Dump the "Done" REs -# 16 : Verbose Config-Reading -# 32 : Dump Program Variable -# 64 : Excessive deepblack/torecord debuging -my $debug = 6; - -# The Supervariable Program -# %Program{$title}{$channel}{$time}{duration} -# {subtitle} -# {description} - -# The Supervariable Timer -# %Timer{$time}{$channel}{$title}{duration} -# {subtitle} -# {description} -# {prio} -# {lifetime} -# {real_title} -# {VDR} (Already programmed) -# The Value of VDR is ">0" for the position in the Timer-List or "R" for a "Repeating" Timer. -# A Value of >1.000.000 is a Master Timer-Timer which is already programmed into VDR - -# The Supervariable torecord/deepblack -# $torecord{timercount} -# {titleRE} -# {subtitleRE} -# {descriptionRE} -# {title}[COUNT] -# {subtitle}[COUNT] -# {description}[COUNT] -# {timeframe}[COUNT] -# {blackchannel}[COUNT] or {channel}[COUNT] -# {weekday}[COUNT] -# {minlength}[COUNT] -# {maxlength}[COUNT] -# {prio}[COUNT] -# {timertitle}[COUNT] -# {marginstart}[COUNT] -# {marginstop}[COUNT] -# {instance}[COUNT] - -# Variable-Definition -my (%Program, @channels, %channels, %Timer); - -# Which Subtitles are Movies -my ($subtitle_movie); -my ($test_subtitle_movie); - -# Blacklist -my (%deepblack); - -# What is already recorded/Should not be recorded -my ($title_done, $subtitle_done); - -# What to record -my (%torecord); - -# The Commandline -my (%Opts); - -# Default Priority for Timers (Config: defaultprio) -my $default_prio = 50; - -# How many DVB-S cards are there (Config: DVBCards) -my $DVB_cards = 1; - -# How many seconds to substract from the time and to add to the duration -my $marginstart = 60*10; # Config: Marginstart -my $marginstop = 60*10; # Config: Marginstop - -# Shall Timers, on the same channel, be joined if they overlap -my $jointimers = 0; - -# Hostname/IP of DVB-Computer and the Port of VDR -my @Dest = ("localhost:2001"); # Config: Dest - -# Which VDR-Instance shall be used -my $currentVDR = 1; - -# Where are the Config-Files -my $configdir = "$ENV{HOME}/.master-timer"; - -# Should the description be transfered to VDR? -my $Description = 0; - -# Working-Variables -my ($title, $duration, $subtitle, $channel, $time, $description, $category, $hit); -my (@time, @date); - -END { - &closesocket(); -} - -&init(); -&dumpdone() if ($debug & 8); -&dumptorecord("torecord") if ($debug & 1); -&dumptorecord("deepblack") if ($debug & 1); -print "Subtitle-Movie \"$subtitle_movie\"\n" if($debug & 1); -# If we only have to dump the running series then exit after dumping them -if ($Opts{s}) { - &dumpepgdata; - exit 0; -} -&processdone(); -&fetchVDRTimers(); -&process_torecord(); -print "Timers before joining\n" if ($debug & 2 && $jointimers); -&dumptimers() if ($debug & 2); - -if ($jointimers) { - &jointimers(); - print "Timers after joining\n" if ($debug & 2); - &dumptimers() if ($debug & 2); -} - -&dumpepgdata if ($debug & 32); - -&printtimers(); -&transfertimers(); - -# -# End of Program -# - -# -# Subfunctions -# - -sub dumpdone() { - print "Start Done-dump\n"; - print "Titledone: \"$title_done\"\n"; - print "Subtitledone \"$subtitle_done\"\n"; - print "End Done-dump\n"; -} - -sub dumpepgdata () { - print "Start EPG-Dump\n"; - foreach $title (sort keys %Program) { - foreach $channel (sort keys %{%Program->{$title}}) { - foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}}) { - print "Title: \"$title\" "; - if (!$Opts{s}) { - print "Subtitle: \"$Program{$title}{$channel}{$time}{subtitle}\" " if ($Program{$title}{$channel}{$time}{subtitle}); - print "Time: \"$time\""; - } - print "Channel: \"$channel\""; - print "\n"; - if ($Opts{s}) { - last; - } - } - } - } - print "End EPG-Dump\n"; -} - - -sub dumptorecord() { - my ($context) = shift; - my ($rContext); - - if ($context eq "torecord") { - $rContext = \%torecord; - } elsif ($context eq "deepblack") { - $rContext = \%deepblack; - } else { - die ("Illegal Context"); - } - - print "Start $context-dump\n"; - print "Regex-Title: $$rContext{titleRE}\n"; - print "Regex-Subtitle: $$rContext{subtitleRE}\n"; - print "Regex-Description: $$rContext{descriptionRE}\n"; - foreach my $num (0 .. $$rContext{timercount}) { - print "Entry Number $num: "; - - print "Title: \"$$rContext{title}[$num]\" " if ($$rContext{title}[$num]); - print "Title: \"\" " unless ($$rContext{title}[$num]); - - print "Subtitle: \"$$rContext{subtitle}[$num]\" "if ($$rContext{subtitle}[$num]); - print "Subtitle: \"\" " unless ($$rContext{subtitle}[$num]); - - print "Description: \"$$rContext{description}[$num]\" " if ($$rContext{description}[$num]); - print "Description: \"\" " unless ($$rContext{description}[$num]); - - print "Category: \"$$rContext{category}[$num]\" " if ($$rContext{category}[$num]); - print "Category: \"\" " unless ($$rContext{category}[$num]); - - print "Timeframe: \"$$rContext{timeframe}[$num]\" " if ($$rContext{timeframe}[$num]); - print "Timeframe: \"\" " unless ($$rContext{timeframe}[$num]); - - print "Weekday: \"$$rContext{weekday}[$num]\" " if ($$rContext{weekday}[$num]); - print "Weekday: \"\" " unless ($$rContext{weekday}[$num]); - - print "Channel: \"$$rContext{channel}[$num]\" " if ($$rContext{channel}[$num]); - print "Channel: \"\" " unless ($$rContext{channel}[$num]); - - print "Blackchannel: \"$$rContext{blackchannel}[$num]\" " if ($$rContext{blackchannel}[$num]); - print "Blackchannel: \"\" " unless ($$rContext{blackchannel}[$num]); - - print "Prio: \"$$rContext{prio}[$num]\" " if ($$rContext{prio}[$num]); - print "Prio: \"\" " unless ($$rContext{prio}[$num]); - - print "Timertitle: \"$$rContext{timertitle}[$num]\" " if ($$rContext{timertitle}[$num]); - print "Timertitle: \"\" " unless ($$rContext{timertitle}[$num]); - - print "Marginstart: \"$$rContext{marginstart}[$num]\" " if ($$rContext{marginstart}[$num]); - print "Marginstart: \"\" " unless ($$rContext{marginstart}[$num]); - - print "Marginstop: \"$$rContext{marginstop}[$num]\" " if ($$rContext{marginstop}[$num]); - print "Marginstop: \"\" " unless ($$rContext{marginstop}[$num]); - - print "Minlength: \"$$rContext{minlength}[$num]\" " if ($$rContext{minlength}[$num]); - print "Minlength: \"\" " unless ($$rContext{minlength}[$num]); - - print "Maxlength: \"$$rContext{maxlength}[$num]\" " if ($$rContext{maxlength}[$num]); - print "Maxlength: \"\" " unless ($$rContext{maxlength}[$num]); - - print "Instance: \"$$rContext{instance}[$num]\" " if ($$rContext{instance}[$num]); - print "Instance: \"\" " unless ($$rContext{instance}[$num]); - - print "\n"; - } - print "End $context-dump\n"; -} - -sub dumptimers() { - print "Start Timers-dump\n"; - foreach $time (sort {$a <=> $b} keys %Timer) { - foreach $channel (sort keys %{%Timer->{$time}}) { - foreach $title (sort keys %{%Timer->{$time}->{$channel}}) { - my ($prio, $lifetime, @time, @date, @time2); - my ($realtitle); - @time = &GetTime ($time); - @date = &GetDay ($time); - @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); - $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; - $prio = $Timer{$time}{$channel}{$title}{prio}; - $lifetime = $Timer{$time}{$channel}{$title}{lifetime}; - $realtitle = $Timer{$time}{$channel}{$title}{real_title}; - print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:$lifetime:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\":$Timer{$time}{$channel}{$title}{VDR}\n"; - } - } - } - print "End Timers-dump\n"; -} - -sub printtimers() { - foreach $time (sort {$a <=> $b} keys %Timer) { - foreach $channel (sort keys %{%Timer->{$time}}) { - foreach $title (sort keys %{%Timer->{$time}->{$channel}}) { - my ($prio, $lifetime, @time, @date, @time2); - if ($Timer{$time}{$channel}{$title}{VDR} eq 0) { - my ($realtitle); - @time = &GetTime ($time); - @date = &GetDay ($time); - @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); - $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; - $prio = $Timer{$time}{$channel}{$title}{prio}; - $lifetime = $Timer{$time}{$channel}{$title}{lifetime}; - $realtitle = $Timer{$time}{$channel}{$title}{real_title}; - - print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:$lifetime:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"\n"; - } - } - } - } -} - -sub transfertimers() { - foreach $time (sort {$a <=> $b} keys %Timer) { - foreach $channel (sort keys %{%Timer->{$time}}) { - foreach $title (sort keys %{%Timer->{$time}->{$channel}}) { - my ($prio, $lifetime, $description, @time, @date, @time2, $realtitle, $result); - if ($Timer{$time}{$channel}{$title}{VDR} eq 0) { - @time = &GetTime ($time); - @date = &GetDay ($time); - @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration}); - $subtitle = $Timer{$time}{$channel}{$title}{subtitle}; - $prio = $Timer{$time}{$channel}{$title}{prio}; - $lifetime = $Timer{$time}{$channel}{$title}{lifetime}; - if ($Description) { - $description = "||Description :\"$Timer{$time}{$channel}{$title}{description}\""; - } else { - $description = ""; - } - $realtitle = $Timer{$time}{$channel}{$title}{real_title}; - - ($result) = GetSend ("newt 2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:$lifetime:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"$description"); - print "Timer: $result" if ($debug & 2); - } - } - } - } -} - -# Convert the Unix-Time-Stamp into "month" and "Day of month" -sub GetDay { - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); - $mon++; - $mon = sprintf ("%02i",$mon); - $mday = sprintf ("%02i",$mday); - return ($mon, $mday); -} -# Convert the Unix-Time-Stramp into Weekday -sub GetWDay { - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); - return ($wday); -} - -# Convert the Unix-Time-Stramp into "hour" and "minute" -sub GetTime { - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift); - $hour = sprintf ("%02i",$hour); - $min = sprintf ("%02i",$min); - return ($hour, $min); -} - -# Workaround some EPG-Bugs -sub correct_epg_data { - if ($subtitle) { - # For Pro-7. Remove $title from $subtitle - $subtitle =~ s/\Q$title\E\s\/\s//; - - # For VOX & VIVA. The Format it '"<Subtitle>". <Description>' - if ($subtitle =~ /^\"(.*?)\"\.\s(.*)/) { - # Lets see if there are Channels that where the VOX/VIVA scheme matches, but also have a description - if ($description) { - my $one = $1; - my $two = $2; - if ($description =~ /^DTV\:\s\'(.*)\' VDR:\s\'\'$/) { - $description = "DTV: '$1' VDR: '$two'"; - $subtitle = $one; - } else { - die ("Title: \"$title\" Channel: \"$channel\" Subtitle: \"$subtitle\"\nDescription: \"$description\"\n"); - } - } - $subtitle = $1; - $description = $2; - } - elsif ($channel eq "VIVA") { - if ($subtitle =~ /^\s(.*)/) { - $subtitle = ""; - $description = $1; - } - } - } - - # Workaround for the broken PRO-7/Kabel-1 EPG-Date. If Time is between 00.00 and 05.00 the time is shifted forward by a day - if ($channel eq "Pro-7" || $channel eq "Kabel-1") { - my (@time); - @time = GetTime ($time); - if ($time[0] >= 0 && ($time[0] <= 4 || ($time[0] == 5 && $time[1] == 0))) { - $time += 24*60*60; - } - } -} - -# Add a Recording into the "to record"-List -sub addtimer { - my ($title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $lifetime, $description, $VDR, $time2, $title2, $channel2, $marginstart, $marginstop); - ($title, $realtitle, $subtitle, $description, $channel, $time, $duration, $prio, $lifetime, $VDR, $marginstart, $marginstop) = @_; -# print "Title: \"$title\" Realtitle: \"$realtitle\" Subtitle: \"$subtitle\" Channel: \"$channel\" Time: \"$time\" Duration: \"$duration\" Prio: \"$prio\" VDR: \"$VDR\"\n"; - - foreach $time2 (sort keys %Timer) { - foreach $title2 (sort keys %{%Timer->{$time2}->{$channel}}) { - my ($ctime, $ctime2); - $ctime = $time2; - $ctime2 = $time2 + $Timer{$time2}{$channel}{$title2}{duration}; - - if (($time >= $ctime) && ($time <= $ctime2)) { - return; - } - } - } - - $time -= $marginstart; - $duration += $marginstart + $marginstop; - $Timer{$time}{$channel}{$title}{duration}=$duration; - $Timer{$time}{$channel}{$title}{subtitle}=$subtitle; - $Timer{$time}{$channel}{$title}{description}=$description; - $Timer{$time}{$channel}{$title}{prio}=$prio; - $Timer{$time}{$channel}{$title}{lifetime}=$lifetime; - $Timer{$time}{$channel}{$title}{VDR}=$VDR; - $Timer{$time}{$channel}{$title}{real_title}=$realtitle; -} - -sub deltimer() { - my ($time, $channel, $title, $delete_from_VDR); - ($time, $channel, $title, $delete_from_VDR) = @_; - -# if ($delete_from_VDR) { -# if ($Timer{$time}{$channel}{$title}{VDR}) { -# if ($Timer{$time}{$channel}{$title}{VDR} =~ s/ ^R/) { -# print "Error: A Repeating-Timer can't be deleted from VDR: \"$title\"\n"; -# } -# elsif ($Timer{$time}{$channel}{$title}{VDR} < 1000000) { -# print "A User-Programmed Timer has been deleted from VDR: \"$title\"\n"; -# } -# else { -# -# } -# } -# } - - delete $Timer{$time}{$channel}{$title}{duration}; - delete $Timer{$time}{$channel}{$title}{subtitle}; - delete $Timer{$time}{$channel}{$title}{prio}; - delete $Timer{$time}{$channel}{$title}{VDR}; - delete $Timer{$time}{$channel}{$title}{real_title}; - delete $Timer{$time}{$channel}{$title}; - delete $Timer{$time}{$channel} if (keys %{ $Timer{$time}{$channel} } == 1); - delete $Timer{$time} if (keys %{ $Timer{$time} } == 1); -} - -sub delprogram() { - my ($title, $channel, $time); - ($title, $channel, $time) = @_; - - delete $Program{$title}{$channel}{$time}; - delete $Program{$title}{$channel} if (keys %{ $Program{$title}{$channel} } == 1); - delete $Program{$title} if (keys %{ $Program{$title} } == 1); -} - -sub jointimers { - # - # FIXME: 2 Timers on the same channel will always be joined. - # It should be checked if there is another DVB-Card available. - # - # FIXME2: When one timer is already programmed in VDR, delete that timer in VDR. - my ($running, $counter, @times, $channel, $title, $channel2, $title2); - $running = 1; - outer: while ($running) { - $counter = 0; - @times = sort {$a <=> $b} keys %Timer; - - # We only need to check till the second last timer. The last one can't have a overlapping one. - while ($counter < $#times) { - foreach $channel (sort keys %{%Timer->{$times[$counter]}}) { - foreach $title (sort keys %{%Timer->{$times[$counter]}->{$channel}}) { - if ($times[$counter + 1] < ($times[$counter] + $Timer{$times[$counter]}{$channel}{$title}{duration})) { - foreach $channel2 (sort keys %{%Timer->{$times[$counter + 1]}}) { - foreach $title2 (sort keys %{%Timer->{$times[$counter + 1]}->{$channel}}) { - if ($channel eq $channel2) { - my ($duration, $subtitle, $description, $prio, $lifetime, $realtitle, $duration2, $subtitle2, $description2, $prio2, $lifetime2, $realtitle2); - # Values from Lower-Timer - $duration = $Timer{$times[$counter]}{$channel}{$title}{duration}; - $subtitle = $Timer{$times[$counter]}{$channel}{$title}{subtitle}; - $description = $Timer{$times[$counter]}{$channel}{$title}{description}; - $prio = $Timer{$times[$counter]}{$channel}{$title}{prio}; - $lifetime = $Timer{$times[$counter]}{$channel}{$title}{lifetime}; - $realtitle = $Timer{$times[$counter]}{$channel}{$title}{real_title}; - - # Values from Higher-Timer - $duration2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{duration}; - $subtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{subtitle}; - $description2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{description}; - $prio2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{prio}; - $lifetime2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{lifetime}; - $realtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{real_title}; - - # Use the Higher Priority/Lifetime for the new Timer - $prio = ($prio > $prio2) ? $prio : $prio2; - $lifetime = ($lifetime > $lifetime2) ? $lifetime : $lifetime2; - - # Delete the two "Obsolet" Timers - &deltimer ($times[$counter], $channel, $title); - &deltimer ($times[$counter + 1], $channel2, $title2); - - # And set the new one - &addtimer ("$title + $title2", "$realtitle\~$realtitle2", "$subtitle\~$subtitle2", "$description\~$description2", $channel, $times[$counter], $duration2 + ($times[$counter + 1 ] - $times[$counter]),$prio,$lifetime,0,0,0); - - # Now a Value is "missing", so we will redo the whole thing. (This will do three-times JOIN correct) - redo outer; - } - } - } - } - } - } - $counter++; - } - undef $running; - } -} - -sub process_torecord { - my ($subtitle, $description, $prio, $lifetime, $timertitle, $counter); - foreach $title (sort keys %Program) { - foreach $channel (sort keys %{%Program->{$title}}) { - foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}}) { - - $counter = &testtimer("torecord", $title, $channel, $time); - if ($counter ne "Nothing") { - - # What Priority - if ($torecord{prio}[$counter]) { - $prio = $torecord{prio}[$counter]; - } - else { - $prio = 50; - } - - # What Lifetime - if ($torecord{lifetime}[$counter]) { - $lifetime = $torecord{lifetime}[$counter]; - } - else { - $lifetime = 50; - } - - # What Title to use for the timer - if ($torecord{timertitle}[$counter]) { - $timertitle = $torecord{timertitle}[$counter] - } - elsif ($torecord{title}[$counter]) { - $timertitle = $torecord{title}[$counter] - } - else { - $timertitle = $title; - } - - # What subtitle to use - if ($Program{$title}{$channel}{$time}{subtitle}) { - $subtitle = $Program{$title}{$channel}{$time}{subtitle}; - } - else { - $subtitle = ""; - } - - # What Description to use - if ($Program{$title}{$channel}{$time}{description}) { - $description = $Program{$title}{$channel}{$time}{description}; - } - else { - $description = ""; - } - - &addtimer ($timertitle,$title,$subtitle,$description,$channel,$time,$Program{$title}{$channel}{$time}{duration},$prio,$lifetime,0,$torecord{marginstart}[$counter],$torecord{marginstop}[$counter]); - } - } - } - } -} - -# Test if a torecord/deepblack Entry matches the current EPG-Data-Field -sub testtimer { - my ($context) = shift; - my ($title) = shift; - my ($channel) = shift; - my ($time) = shift; - my ($counter, $rContext); - - if ($context eq "torecord") { - $rContext = \%torecord; - } elsif ($context eq "deepblack") { - $rContext = \%deepblack; - } else { - die ("Illegal Context"); - } - - if ($debug & 64) { - print "\n"; - print "Context: \"$context\"\nTitle: \"$title\"\n"; - print "Subtitle: \"$Program{$title}{$channel}{$time}{subtitle}\"\n" if ($Program{$title}{$channel}{$time}{subtitle}); - print "Description \"$Program{$title}{$channel}{$time}{description}\"\n" if ($Program{$title}{$channel}{$time}{description}); - print "Category \"$Program{$title}{$channel}{$time}{category}\"\n" if ($Program{$title}{$channel}{$time}{category}); - print "Channel: $channel\n"; - print "Time: $time\n"; - print "Duration: $Program{$title}{$channel}{$time}{duration}\n"; - } - - # First look if any of the Title/Subtitle/Description REs match - if ($title =~ /$$rContext{titleRE}/i) { - print "Title hit\n" if ($debug & 64); - } - elsif ($Program{$title}{$channel}{$time}{subtitle} && $Program{$title}{$channel}{$time}{subtitle} =~ /$$rContext{subtitleRE}/i) { - print "SubTitle hit\n" if ($debug & 64); - }elsif ($Program{$title}{$channel}{$time}{subtitle} && $test_subtitle_movie && $Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_movie/) { - print "SubTitle-Movie hit\n" if ($debug & 64); - } - elsif ($Program{$title}{$channel}{$time}{description} && $Program{$title}{$channel}{$time}{description} =~ /$$rContext{descriptionRE}/i) { - print "Description hit\n" if ($debug & 64); - } else { - # No "Fast"-hit. Exiting - return "Nothing"; - } - - # Now look if we have a "exact" hit - print "In Exact Hit Loop\n" if ($debug & 64); - foreach my $counter (0 .. $$rContext{timercount}) { - - print "Before Title Match\n" if ($debug & 64); - if ($$rContext{title}[$counter]) { - print "In Title Match \"$$rContext{title}[$counter]\"\n" if ($debug & 64); - if (!($title =~ /$$rContext{title}[$counter]/i)) { - print "Title rejected\n" if ($debug & 64); - next; - } - } - - print "Before Subtitle Match\n" if ($debug & 64); - if ($$rContext{subtitle}[$counter]) { - print "In Subtitle Match \"$$rContext{subtitle}[$counter]\"\n" if ($debug & 64); - if ($Program{$title}{$channel}{$time}{subtitle}) { - if ($$rContext{subtitle}[$counter] =~ /^movie$/i) { - if (!($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_movie/i)) { - print "Subtitle rejected 1\n" if ($debug & 64); - next; - } - } - elsif ($$rContext{subtitle}[$counter] =~ /^\!movie$/i) { - if (($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_movie/i)) { - print "Subtitle rejected 2\n" if ($debug & 64); - next; - } - } - elsif (!($Program{$title}{$channel}{$time}{subtitle} =~ /$$rContext{subtitle}[$counter]/i)) { - print "Subtitle rejected 3\n" if ($debug & 64); - next; - } - } else { - # We had a Subtitle, but epg.data did not have a subtitle for this record so no chance to record this - print "Subtitle rejected 4\n" if ($debug & 64); - next; - } - } - - print "Before Description Match\n" if ($debug & 64); - if ($$rContext{description}[$counter]) { - print "In Description Match \"$$rContext{description}[$counter]\"\n" if ($debug & 64); - if ($Program{$title}{$channel}{$time}{description}) { - if (!($Program{$title}{$channel}{$time}{description} =~ /$$rContext{description}[$counter]/i)) { - print "Description rejected 1\n" if ($debug & 64); - next; - } - } - elsif (!$$rContext{title}[$counter] && !$$rContext{subtitle}[$counter]) { - print "Description rejected 2\n" if ($debug & 64); - next; - } - } - - print "Before Category Match\n" if ($debug & 64); - if ($$rContext{category}[$counter]) { - print "In Category Match \"$$rContext{category}[$counter]\"\n" if ($debug & 64); - if ($Program{$title}{$channel}{$time}{category}) { - my ($left, $right); - ($left, $right) = split (/\//, $$rContext{category}[$counter]); - if ($left) { - print "In Category Match Left \"$left\"\n" if ($debug & 64); - if (!($Program{$title}{$channel}{$time}{category} =~ /^$left\//)) { - print "Category rejected 1\n" if ($debug & 64); - next; - } - } - if ($right) { - print "In Category Match Right \"$right\"\n" if ($debug & 64); - if (!($Program{$title}{$channel}{$time}{category} =~ /\/$right$/)) { - print "Category rejected 2\n" if ($debug & 64); - next; - } - } - } else { - # We had a Category, but the epg.data not. So discard this Entry - print "Category rejected 3\n" if ($debug & 64); - next; - } - } - - print "Before Channel Match\n" if ($debug & 64); - if ($$rContext{channel}[$counter]) { - print "In Channel Match Whitelist-Mode \"$$rContext{channel}[$counter]\"\n" if ($debug & 64); - if (!($channel =~ /$$rContext{channel}[$counter]/)) { - print "Channel rejected\n" if ($debug & 64); - next; - } - } - - if ($$rContext{blackchannel}[$counter]) { - print "In Channel Match Blacklist-Mode \"$$rContext{blackchannel}[$counter]\"\n" if ($debug & 64); - if ($channel =~ /$$rContext{blackchannel}[$counter]/) { - print "Channel rejected\n" if ($debug & 64); - next; - } - } - - print "Before Timeframe Match\n" if ($debug & 64); - if ($$rContext{timeframe}[$counter]) { - print "In Timeframe Match \"$$rContext{timeframe}[$counter]\"\n" if ($debug & 64); - my (@time, $time2, $ctime, $ctime2); - @time = GetTime($time); - $time2 = "$time[0]$time[1]"; - - ($ctime, $ctime2) = split (/\-/,$$rContext{timeframe}[$counter]); - - if (!$ctime) { - $ctime = "0"; - } - if (!$ctime2) { - $ctime2 = "2400"; - } - - if ($ctime < $ctime2) { - if (!($time2 >= $ctime && $time2 <= $ctime2)) { - print "Timeframe rejected 1\n" if ($debug & 64); - next; - } - } - else { - if (!(($time2 >= $ctime && $time2 <= "2400") || ($time2 >= "0" && $time2 <= $ctime2))) { - print "Timeframe rejected 2\n" if ($debug & 64); - next; - } - } - } - - print "Before Weekday Match\n" if ($debug & 64); - if ($$rContext{weekday}[$counter]) { - print "In Weekday Match \"$$rContext{weekday}\"\n" if ($debug & 64); - my ($wday); - $wday = getWDay($time); - $$rContext{weekday}[$counter] =~ /(.)(.)(.)(.)(.)(.)(.)/; - if ($$wday eq "-") { - print "Weekday rejected\n" if ($debug & 64); - next; - } - } - - print "Before Minlength Match\n" if ($debug & 64); - if ($$rContext{minlength}[$counter]) { - print "In Minlength Match \"$$rContext{minlength}[$counter]\"\n" if ($debug & 64); - if ($Program{$title}{$channel}{$time}{duration} < $$rContext{minlength}[$counter]) { - print "Minlength rejected\n" if ($debug & 64); - next; - } - } - - print "Before Maxlength Match\n" if ($debug & 64); - if ($$rContext{maxlength}[$counter]) { - print "In Maxlength Match \"$$rContext{maxlength}[$counter]\"\n" if ($debug & 64); - if ($Program{$title}{$channel}{$time}{duration} > $$rContext{maxlength}[$counter]) { - print "Maxlength rejected\n" if ($debug & 64); - next; - } - } - - # All test passed. Accept this timer - print "All Tests passed entry accepted/blacklisted\n" if ($debug & 64); - return ($counter); - } - # Foreach ran out without a hit - return "Nothing"; -} - -# Open the connection to VDR -sub initsocket { - my ($Dest, $Port) = split (/\:/,$Dest[$currentVDR - 1],2); - my $iaddr = inet_aton($Dest); - my $paddr = sockaddr_in($Port, $iaddr); - my $Timeout = 10; # max. seconds to wait for response - - $SIG{ALRM} = sub { die("Timeout while connecting to VDR"); }; - alarm($Timeout); - - socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp')); - connect(SOCKET, $paddr) or die ("Can't connect to VDR\n"); - select(SOCKET); $| = 1; - select(STDOUT); - - while (<SOCKET>) { - last if substr($_, 3, 1) ne "-"; - } - alarm(0); -} - -# Send a command to VDR and read back the result -sub GetSend { - my ($command, @retval); - - while ($command = shift) { - print SOCKET "$command\r\n"; - while (<SOCKET>) { - s/\x0d//g; - (@retval) = (@retval, $_); - last if substr($_, 3, 1) ne "-"; - } - } - return (@retval); -} - -# Close the socket to VDR -sub closesocket { - print SOCKET "Quit\r\n"; - close(SOCKET); -} - - -# Fetch the timers-List from VDR via SVDR and process it. -sub fetchVDRTimers { - my (@timers, $timer, $position, $active, $channel, $day, $start, $end, $prio, $lifetime, $title, $subtitle, $minute, $duration); - my ($utime, $utime2); - - # First fetch the timers-list from VDR - @timers = GetSend ("lstt"); - - foreach $timer (@timers) { - chomp $timer; - # a Valid Timer-line beginns with "250" - if ($timer =~ s/250-|250\s//) { - # Extract the Position in front of the line - ($position, $timer) = split (/\s/,$timer,2); - -# print "Position: \"$position\" Timer: \"$timer\"\n"; - # Split the : seperated values - ($active, $channel, $day, $start, $end, $prio, $lifetime, $title, $subtitle) = split (/\:/,$timer,9); - - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); - - # If the string is exactly 7 char wide, then its a "repeating"-timer - if ($active >= 1) { - if ($day =~ /(.)(.)(.)(.)(.)(.)(.)/) { - my (@days); - @days = ($1, $2, $3, $4, $5, $6, $7); - ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); - - $start =~ /(\d\d)(\d\d)/; - $hour = $1; - $minute = $2; - $utime = timelocal 0, $minute, $hour, $mday, $mon, $year; - $end =~ /(\d\d)(\d\d)/; - $hour = $1; - $minute = $2; - $utime2 = timelocal 0, $minute, $hour, $mday, $mon, $year; - if ($end < $start) { - $utime2 += 24*60*60; - } - $duration = $utime2 - $utime; - - # "Normalize" the timestamp to monday - $utime = $utime - ($wday * 24 * 60 *60); - - foreach my $num (0 .. $#days) { - if ($days[$num] ne "-") { - my $utime3; - # Days before today will be shifted in the next week - if (($num + 1) < $wday) { - $utime3 = $utime + (($num + 7 + 1) * 24 * 60 * 60); - } - else { - $utime3 = $utime + (($num + 1) * 24 * 60 * 60); - } - &addtimer ($title,$title,$subtitle,"",$channels[$channel],$utime3,$duration,$prio,$lifetime,"R$position",0,0); - } - } - } - - # When the Day-Value is between 1 and 31, then its a "One time" Timer - elsif (($day >= 1) && ($day <= 31)) { - if ($active == "2") { - $position += 1000000; - } - # When the Day is before the Current-Day, then the Timer is for the next month - if ($day < $mday) { - $mon++; - if ($mon == 12) { - $mon = 0; - $year ++; - } - } - $start =~ /(\d\d)(\d\d)/; - $hour = $1; - $minute = $2; - $utime = timelocal 0, $minute, $hour, $day, $mon, $year; - $end =~ /(\d\d)(\d\d)/; - $hour = $1; - $minute = $2; - $utime2 = timelocal 0, $minute, $hour, $day, $mon, $year; - if ($end < $start) { - $utime2 += 24*60*60; - } - $duration = $utime2 - $utime; - - &addtimer ($title,$title,$subtitle,"",$channels[$channel],$utime,$duration,$prio,$lifetime,$position,0,0); - } - } - } - } -} - -# Parse file "epg.data" -sub initepgdata { - open (FI,"epg.data") or die ("Can't open file \"epg.data\"\n"); - - while (<FI>) { - # Begin Channel - if (/^C\s(\d+)\s+(.+)/) { - $channel=$2; - while (<FI>) { - # End Channel - if (/^c$/) { - last; - } - # Begin Timer - elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/) { - # Undef this Variables because it is possibel that not every timer uses this values - undef $duration; - undef $subtitle; - undef $description; - undef $category; - - $time=$2; - $duration=$3; - } - # Title - elsif (/^T\s(.*)/) { - $title=$1; - } - # Subtitle - elsif (/^S\s(.*)/) { - $subtitle=$1; - } - # Description - elsif (/^D\s(.*)/) { - $description=$1; - } - elsif (/^K\s(.*)/) { - $category=$1; - } - # End Timer - elsif (/^e$/) { - # Only accept timers that are in the future - if ($time < time) { - next; - } - # Only accept timers that are at least 2 Seconds long - if ($duration <= 1) { - next; - } - - # Work around the different Bugs in the data - &correct_epg_data(); - - # Check if the Title & Subtitle is in the Done-List (Only if Subtitle exists) - if ($subtitle && $title =~ /$title_done/ && $subtitle =~ /$subtitle_done/) { - next; - } - - $Program{$title}{$channel}{$time}{duration}=$duration; - if ($subtitle) { - $Program{$title}{$channel}{$time}{subtitle}=$subtitle; - } - if ($description) { - $Program{$title}{$channel}{$time}{description}=$description; - } - if ($category) { - $Program{$title}{$channel}{$time}{category}=$category; - } - # Check if the title is in the DEEP-Blacklist - if (&testtimer("deepblack", $title, $channel, $time) ne "Nothing") { - print "Deepblack: \"$title\"" if ($debug & 64); - print " $subtitle" if ($debug & 64 && $subtitle); - print "\n" if ($debug & 64); - &delprogram ($title, $channel, $time); - } - } - } - } - } - close (FI); -} - -# What is a Movie (When correctly stored into Subtitle) -sub initmovie { - my (@list,$list); - open (FI,"${configdir}/subtitle-movie") or return; - @list = <FI>; - close(FI); - - foreach $list (@list) { - chomp $list; - } - $subtitle_movie = join ('|',@list); -} - -# What is already recorded/Should not be recorded -sub initdone { - my (@list,$list, %title_done, %subtitle_done, $title_temp, $subtitle_temp); - open (FI,"${configdir}/done") or return; - @list = <FI>; - close (FI); - - foreach $list (@list) { - chomp $list; - ($title_temp,$subtitle_temp) = split (/\|/,$list); - if ($title_temp) { - $title_done{"^\Q$title_temp\E\$"} = 1; - } - if ($subtitle_temp) { - $subtitle_done{"^\Q$subtitle_temp\E\$"} = 1; - } - } - $title_done = join ('|',sort keys %title_done); - $subtitle_done = join ('|',sort keys %subtitle_done); -} - -sub processdone { - # Now delete Timers in VDR that are already in the done-List - my ($list, @list, $position, $timer, $active, $g, $title, $subtitle, $counter, @todel); - $counter = 0; - @list = GetSend ("LSTT"); - - foreach $timer (@list) { - chomp $timer; - if ($timer =~ s/250-|250\s//) { - ($position, $timer) = split (/\s/,$timer,2); - # Split the : seperated values - ($active, $g, $g, $g, $g, $g, $g, $title, $subtitle) = split (/\:/,$timer,9); - if ($active == 2) { - # Title: "Shakespeare in Love"||Subtitle: "Romanze" - my ($ctitle, $csubtitle); - if ($subtitle && $subtitle =~ /^Title\:\s\"(.*)\"\|\|Subtitle\:\s\"(.*)\"/) { - $title = $1; - $subtitle = $2; - if ($subtitle) { - my (@titles, @subtitles, $num, $hit); - undef $hit; - @titles = split (/\~/,$title); - @subtitles = split (/\~/,$subtitle); - foreach $num (0 .. $#titles) { - if ($titles[$num] =~ /$title_done/ && $subtitles[$num] =~ /$subtitle_done/) { - $hit = 1; - } - else { - undef $hit; - last; - } - } - - if ($hit) { - my ($result); - print "Delete Timer: $title $subtitle\n" if ($debug & 4); - $position -= $counter; - ($result) = GetSend ("DELT $position"); - print "Result: $result" if ($debug & 4); - if ($result =~ /^250/) { - $counter++; - } - } - } - } - } - } - } -} - -# What should be recorded -sub inittorecord { - my ($context) = shift; - my ($rContext); - my (@title_list, @subtitle_list, @description_list, $line); - my (%Input); - my $counter = 0; - - if ($context eq "torecord") { - $rContext = \%torecord; - open (FI,"${configdir}/${context}") or die ("Can't open file \"$context\"\n"); - } elsif ($context eq "deepblack") { - $rContext = \%deepblack; - open (FI,"${configdir}/${context}") or return; - } else { - die ("Illegal Context"); - } - - - outer: while (<FI>) { - chomp if ($_); - if ($_ && !(/^\#/) && /^\[.*\]$/) { - $line = $.; - undef %Input; - while (<FI>) { - chomp; - if ($_ && !(/^\#/)) { - if (/^\[.*?\]$/) { - last; - } - - my ($key, $value); - ($key, $value) = split (/\s+=\s+/); - - if ($key =~ /^title$/i) { - if ($Input{title}) { - $Input{title} .= "|$value"; - } else { - $Input{title} = $value; - } - print "Titel = $value\n" if ($debug & 16); - } - elsif ($key =~ /^subtitle$/i) { - if ($Input{subtitle}) { - $Input{subtitle} .= "|$value"; - } else { - $Input{subtitle} = $value; - } - print "Subtitel = $value\n" if ($debug & 16); - } - elsif ($key =~ /^description$/i) { - if ($Input{description}) { - $Input{description} .= "|$value"; - } else { - $Input{description} = $value; - } - print "Description = $value\n" if ($debug & 16); - } - elsif ($key =~ /^category$/i) { - $Input{category} = $value; - print "Category = $value\n" if ($debug & 16); - } - elsif ($key =~ /^channel$/i) { - if ($Input{channel}) { - $Input{channel} .= "|^$value\$"; - } else { - $Input{channel} = $value; - } - print "Channel = $value\n" if ($debug & 16); - } - elsif ($key =~ /^timeframe$/i) { - $Input{timeframe} = $value; - print "Timeframe = $value\n" if ($debug & 16); - } - elsif ($key =~ /^weekday$/i) { - $Input{weekday} = $value; - print "Weekday = $value\n" if ($debug & 16); - } - elsif ($key =~ /^minlength$/i) { - $Input{minlength} = $value; - print "Minlength = $value\n" if ($debug & 16); - } - elsif ($key =~ /^maxlength$/i) { - $Input{maxlength} = $value; - print "Maxlength = $value\n" if ($debug & 16); - } - elsif ($key =~ /^prio$/i) { - $Input{prio} = $value; - print "Prio = $value\n" if ($debug & 16); - } - elsif ($key =~ /^lifetime$/i) { - $Input{lifetime} = $value; - print "Lifetime = $value\n" if ($debug & 16); - } - elsif ($key =~ /^timertitle$/i) { - $Input{timertitle} = $value; - print "Timertitel = $value\n" if ($debug & 16); - } - elsif ($key =~ /^margin$/i) { - $Input{margin} = $value; - print "Margin = $value\n" if ($debug & 16); - } - elsif ($key =~ /^instance$/i) { - $Input{instance} = $value; - print "Instance = $value\n" if ($debug & 16); - } else { - print "Unkown Key: \"$key\" with Value: \"$value\"\n"; - } - } - } - - # Accept entry only if it is for the current instance or for "no" instance - if (($Opts{s} && $Input{instance} && $Input{instance} eq "s") || !$Input{instance} || ($Input{instance} ne "s" && $Input{instance} == $currentVDR)) { - # Accept entry only if at least a Title/Subtitle/Description is provied - if (!$Input{title} && !$Input{subtitle} && !$Input{description}) { - print "No Title/Subtitle/Description Field. $context entry ignored. Block beginning at Line $line\n"; - redo outer; - } - - if ($Input{title}) { - $$rContext{title}[$counter] = $Input{title}; - $title_list[$#title_list + 1] = $Input{title}; - } - if ($Input{subtitle}) { - if ($Input{subtitle} =~ /^movie$/i || $Input{subtitle} =~ /^\!movie$/i) { - $test_subtitle_movie = 1; - } - $$rContext{subtitle}[$counter] = $Input{subtitle}; - $subtitle_list[$#subtitle_list + 1] = $Input{subtitle}; - } - if ($Input{description}) { - $$rContext{description}[$counter] = $Input{description}; - $description_list[$#description_list + 1] = $Input{description}; - } - if ($Input{category}) { - $$rContext{category}[$counter] = $Input{category}; - } - if ($Input{channel}) { - if ($Input{channel} =~ /\!/) { - $Input{channel} =~ s/\!//g; - $$rContext{blackchannel}[$counter] = $Input{channel}; - } else { - $$rContext{channel}[$counter] = $Input{channel}; - } - } - if ($Input{timeframe}) { - $$rContext{timeframe}[$counter] = $Input{timeframe}; - } - if ($Input{weekday}) { - $$rContext{weekday}[$counter] = $Input{weekday}; - } - if ($Input{minlength}) { - if ($Input{minlength} =~ /^(\d+)m$/) { - $Input{minlength} = $1 * 60 - } elsif ($Input{minlength} =~ /^(\d+)h$/) { - $Input{minlength} = $1 * 60 * 60 - } - $$rContext{minlength}[$counter] = $Input{minlength}; - } - if ($Input{maxlength}) { - if ($Input{maxlength} =~ /^(\d+)m$/) { - $Input{maxlength} = $1 * 60 - } elsif ($Input{maxlength} =~ /^(\d+)h$/) { - $Input{maxlength} = $1 * 60 * 60 - } - $$rContext{maxlength}[$counter] = $Input{maxlength}; - } - if ($Input{prio}) { - $$rContext{prio}[$counter] = $Input{prio}; - } - if ($Input{lifetime}) { - $$rContext{lifetime}[$counter] = $Input{lifetime}; - } - else { - $$rContext{prio}[$counter] = $default_prio; - } - if ($Input{timertitle}) { - $$rContext{timertitle}[$counter] = $Input{timertitle}; - } - if ($Input{margin}) { - my ($start, $stop); - ($start, $stop) = split (/;/,$Input{margin}, 2); - $$rContext{marginstart}[$counter] = $start if ($start); - $$rContext{marginstop}[$counter] = $stop if ($stop); - } - # Set Default-Margins if no margins defined - $$rContext{marginstart}[$counter] = $marginstart if (!$$rContext{marginstart}[$counter]); - $$rContext{marginstop}[$counter] = $marginstop if (!$$rContext{marginstop}[$counter]); - $counter++; - if ($Input{instance}) { - $$rContext{instance}[$counter] = $Input{instance}; - } - } - redo outer; - } - } - - $$rContext{timercount} = $counter - 1; - - $$rContext{titleRE} = join ('|',@title_list); - if ($$rContext{titleRE} && $$rContext{titleRE} =~ /\|.\|/) { - $$rContext{titleRE} = "."; - } - $$rContext{subtitleRE} = join ('|',@subtitle_list); - if ($$rContext{subtitleRE} && $$rContext{subtitleRE} =~ /\|.\|/) { - $$rContext{subtitleRE} = "."; - } - $$rContext{descriptionRE} = join ('|',@description_list); - if ($$rContext{descriptionRE} && $$rContext{descriptionRE} =~ /\|.\|/) { - $$rContext{descriptionRE} = "."; - } - - if (!$$rContext{titleRE}) { - $$rContext{titleRE} = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; - } - if (!$$rContext{subtitleRE}) { - $$rContext{subtitleRE} = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; - } - if (!$$rContext{descriptionRE}) { - $$rContext{descriptionRE} = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$"; - } -} - -# Parse "LSTC"-Command of VDR -sub initchannellist { - my ($counter, $chan, $garbage, $card, @temp_channels, $temp, $i); - - @temp_channels = GetSend ("LSTC"); - - foreach $i (0 .. $#temp_channels) { - $temp = $temp_channels[$i]; - chomp $temp; - - if ($temp =~ s/250-|250\s//) { - ($counter, $temp) = split (/\s/,$temp,2); - ($chan, $garbage,$garbage, $garbage, $garbage, $garbage, $garbage, $card, $garbage) = split (/\:/,$temp); - $channels[$counter] = $chan; - $channels{$chan}{number} = $counter; - $channels{$chan}{card} = $card; - $counter++; - } - } -} - -sub initconfigfile { - open (FI,"${configdir}/config") or return; - while (<FI>) { - s/\#.*//; - chomp; - if ($_) { - my ($key, $value); - ($key, $value) = split (/\s+=\s+/); - if ($key =~ /^debug$/i) { - $debug = $value; - print "Debug-Level = $value\n" if ($debug & 16); - } - elsif ($key =~ /^marginstart$/i) { - print "Marginstart = $value\n" if ($debug & 16); - $marginstart = $value; - } - elsif ($key =~ /^marginstop$/i) { - print "Marginstop = $value\n" if ($debug & 16); - $marginstop = $value; - } - elsif ($key =~ /^DVBCards$/i) { - print "DVB_Cards = $value\n" if ($debug & 16); - $DVB_cards = $value; - } - elsif ($key =~ /^defaultprio$/i) { - print "Default Priority = $value\n" if ($debug & 16); - $default_prio = $value; - } - elsif ($key =~ /^Dest$/i) { - print "Destination Host/IP:Port = $value\n" if ($debug & 16); - @Dest = split (/\s+/,$value); - } - elsif ($key =~ /^jointimers$/i) { - print "Join Timers = $value\n" if ($debug & 16); - $jointimers = $value; - } - elsif ($key =~ /^description$/i) { - print "Description = $value\n" if ($debug & 16); - $Description = $value; - } - else { - print "Unkown Key: \"$key\" with Value: \"$value\"\n"; - } - } - } - print "End Config\n" if ($debug & 16); -} - -sub initcommandline() { - my $Usage = qq{ -Usage: $0 [options] [Instance]... - -Options: -d hostname:Port hostname/ip:Port (localhost:2001) - -c configdir Directory where all config files are located - (~/.master-timer) - -i instance Which VDR-Instance, from the config-file, should be - used - -s Print all series from epg.data and exit - -v debuglevel Level of debug-messages to print - -h This Help-Page -}; - - # Only process commandline if not already processed - if (!$Opts{done}) { - die $Usage if (!getopts("d:p:c:i:sv:h",\%Opts)); - } - die $Usage if ($Opts{h}); - # Mark the options as already processed - $Opts{done} = 1; - - if ($Opts{v}) { - $debug = $Opts{v}; - } - if ($Opts{i}) { - $currentVDR = $Opts{i}; - } - if ($Opts{d}) { - @Dest = ($Opts{d}); - } - if ($Opts{c}) { - $configdir = $Opts{c}; - } -} - -sub init { - &initcommandline(); - &initconfigfile(); - # Process commandline a second time, so that configs from the config-file are overwritten - &initcommandline(); - &initsocket(); - &initmovie(); - &initdone(); - &initchannellist(); - &inittorecord("deepblack"); - &initepgdata(); - &inittorecord("torecord"); -} diff --git a/Tools/master-timer/process_summary.pl b/Tools/master-timer/process_summary.pl deleted file mode 100755 index ebe63009f..000000000 --- a/Tools/master-timer/process_summary.pl +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/perl -w - -$dir = "/home/ms/.master-timer"; - -open (FI,"$dir/done") or die "Can't open \"done\"\n"; -while (<FI>) - { - chomp; - if ($_) - { - ($title,$subtitle) = split (/\|/,$_,2); - $Done{$title}{$subtitle}=1; - } - } -close (FI); - -&traverse('/video'); - -if ($hit) - { - rename ("$dir/done","$dir/done.bak"); - open (FO,">$dir/done"); - foreach $title (sort keys %Done) - { - foreach $subtitle (sort keys %{%Done->{$title}}) - { - print FO "$title\|$subtitle\n"; - } - } - } - -sub traverse - { - local($dir) = shift; - local($path); - unless (opendir(DIR, $dir)) - { - warn "Can't open $dir\n"; - closedir(DIR); - return; - } - foreach (readdir(DIR)) - { - next if $_ eq '.' || $_ eq '..'; - $path = "$dir/$_"; - if (-d $path) # a directory - { - &traverse($path); - } - if ($_ eq "summary.vdr") - { - open (FI,"$path") or die "Can't open \"$path\"\n"; - @lines = <FI>; - close (FI); - if ($lines[0] =~ /^Title\:\s\"(.*)\"/) - { - @titles = split (/\~/,$1); - if ($lines[2] && $lines[2] =~ /^Subtitle\:\s\"(.*)\"/) - { - @subtitles = split (/\~/,$1); - foreach $num (0 .. $#titles) - { - if ($titles[$num] && $subtitles[$num]) - { - if (!$Done{$titles[$num]}{$subtitles[$num]}) - { - $Done{$titles[$num]}{$subtitles[$num]}=1; - $hit = 1; - } - } - } - } - } - } - } - closedir(DIR); - } - - diff --git a/Tools/master-timer/sample/channels-to-scan b/Tools/master-timer/sample/channels-to-scan deleted file mode 100644 index 22f473d57..000000000 --- a/Tools/master-timer/sample/channels-to-scan +++ /dev/null @@ -1,6 +0,0 @@ -1 -2 -3 -4 -5 -49 diff --git a/Tools/master-timer/sample/config b/Tools/master-timer/sample/config deleted file mode 100644 index 3180943f4..000000000 --- a/Tools/master-timer/sample/config +++ /dev/null @@ -1,32 +0,0 @@ -# Master-Timer config file. Values shown here are defaults. - -# How many seconds "too early" should the timer begin -marginstart = 600 - -# How many seconds "too long" should the timer end -marginstop = 600 - -# When the Prio isn't provided in the config file use this value -defaultprio = 50 - -# How many DVB cards are installed in the computer (not used yet) -DVBCards = 1 - -# IP/Hostname:Port of the destination (space is used for delimiter) -Dest = localhost:2001 - -# Should timers on the same channels be joined when they overlap (0 = off) -jointimers = 0 - -# Should the description be transfered to VDR? -description = 0 - -# Debug level -# 1 : Dump "torecord" -# 2 : Dump all timers -# 4 : Show when a timer will be deleted -# 8 : Dump the "Done" REs -# 16 : Verbose config reading -# 32 : Dump program variables -# 64 : Excessive deepblack/torecord debuging -debug = 0 diff --git a/Tools/master-timer/sample/convert-channel-list b/Tools/master-timer/sample/convert-channel-list deleted file mode 100644 index a97f3c531..000000000 --- a/Tools/master-timer/sample/convert-channel-list +++ /dev/null @@ -1,26 +0,0 @@ -Kabel 1|Kabel 1 -MTV|MTV Central -PRW 13TH Street|13th Street -PRW Discovery Channel|Discovery Channel -PRW Disney Channel|Disney Channel -PRW FOX KIDS|Fox Kids -PRW Junior|Junior -PRW K-Toon|K-Toon -PRW Krimi & Co|Krimi &Co -PRW Planet|Planet -PRW Sci-Fantasy|Premiere Sci-Fi -PRW Studio Universal|Studio Universal -PRW Sunset|Sunset -Premiere Action|Premiere Action -Premiere Comedy|Premiere Comedy -Premiere STAR|Premiere Star -Premiere World 1|Premiere 1 -Premiere World 2|Premiere 2 -Premiere World 3|premiere 3 -Pro Sieben|Pro-7 -RTL|RTL -RTL 2|RTL2 -Sat.1|Sat.1 -Super RTL|Super RTL -Viva|VIVA -Vox|VOX diff --git a/Tools/master-timer/sample/deepblack b/Tools/master-timer/sample/deepblack deleted file mode 100644 index 12884fe73..000000000 --- a/Tools/master-timer/sample/deepblack +++ /dev/null @@ -1,172 +0,0 @@ -# [<Anytext>] -# This marks the beginning of a deepblack-entry -# Title = <text> -# This matches a title -# Subtitle = <text> -# This matches a subtitle -# Description = <text> -# This matches a description -# Category = <left>/<right> -# This matches a DTV-Category -# Channel = <Channel> -# Restricts a deepblack-entry to a specific channel. -# A single "!" at start of channel list negates the selection. -# Timeframe = <begin>-<end> -# Restricts a deepblack-entry to a specific timeframe. -# No timers with start time in the timeframe will be programmed. -# minlength = <Number> -# Restricts a deepblack-entry to a specific minimum length -# (postfix "m" for minutes, "h" for hours.) -# maxlength = <Number> -# Restricts a deepblack-entry to a specific maximum length -# (postfix "m" for minutes, "h" for hours.) -# weekday = MTWTFSS -# Restricts a deepblack-entry to a specific weekday -# instance = <Number> -# Only apply this deepblack-entry for a specific Instance -# "s" is a special value used for "-s"-Mode -# -# The "Title", "Subtitle", "Description", "Channel"-Lines can be -# supplied any number of times for a specific entry -# -# To deepblack something at least one of the "Title", "Subtitle" or -# "Description" (If you don't have anything "better" use "Title = ." -# for this matches everything) fields has to be provided. -# These three fields are "include" and the rest are "exclude" fields. - -[Blacklist all Talkshows] -Title = . -Category = Talk - -[Blacklist all Lifestyles] -Title = . -Category = /Lifestyles - -[Blacklist Sport/Tennis] -Title = . -Category = Sport/Tennis - -[Record only ZDF and Pro7] -Title = . -Channel = !ZDF -Channel = ProSieben - -[Blacklist a timeframe] -Title = . -Timeframe = 1000-1400 - -[Blacklist everything with less than 5 minutes duration] -Title = . -maxlength = 5m - -[Sinnlose Serien] -Title = Fr alle Flle Stefanie -Title = Chicago Hope - Endstation Hoffnung -Title = Chicago Hope -Title = Doppelter Einsatz -Title = Dr. Stefan Frank - Der Arzt, dem die Frauen vertrauen -Title = Ehekriege -Title = Ein Bayer auf Rgen -Title = Emergency Room -Title = Gute Zeiten, schlechte Zeiten -Title = Hallo, Onkel Doc! -Title = Hercules -Title = Hinter Gittern - Der Frauenknast -Title = OP ruft Dr. Bruckner -Title = Wolffs Revier -Title = alphateam -Title = SK Klsch -Title = ^Becker$ -Title = Kommissar Rex -Title = Nur die Liebe zhlt -Title = Unsere kleine Farm -Title = Die Waltons -Title = ^Die Zwei$ - -[Glueckspiele] -Title = Die Quiz Show -Title = Glcksrad -Title = Jeder gegen Jeden -Title = Kochduell - -[Infotainment und Boulevardzeug] -Title = 'MAX' - Das ganze Leben! -Title = ^BIZZ$ -Title = Big Brother -Title = GIRLSCAMP -Title = Call TV -Title = DIE REDAKTION -Title = EXCLUSIV -Title = EXTRA -Title = Explosiv - Das Magazin -Title = K1 DIE REPORTAGE -Title = K1 Das Magazin -Title = PROSIEBEN REPORTAGE -Title = Fit For Fun TV -Title = peep! -Title = s.a.m. -Title = taff. -Title = ^blitz$ -Title = Die Harald Schmidt Show -Title = Spiegel TV-Reportage - -[Nachrichten] -Title = 10 vor 11 -Title = 17:30 live -Title = 18:30 -Title = 24 Stunden -Title = Punkt 12 -Title = Punkt 6 -Title = Punkt 9 -Title = RTL II News -Title = RTL aktuell -Title = RTL-Nachtjournal -Title = K1 Nachrichten -Title = Nachrichten - -[Talkshows] -Title = Andreas Trck -Title = Arabella -Title = Britt - Der Talk um Eins -Title = Brbel Schfer -Title = Die Oliver Geissen Show -Title = Peter Imhof -Title = Vera am Mittag -Title = Hans Meiser -Title = Nicole - Entscheidung am Nachmittag -Title = Franklin - -[So richtig Sinnloses] -Title = Dauerwerbesendungen -Title = Infomercials -Title = Kickers -Title = RTL SHOP -Title = SAT.1-FRHSTCKSFERNSEHEN -Title = Zapping - -[PREMIERE WORLD - Das Programm] -Title = PREMIERE WORLD - Das Programm -Title = Programm ab -Title = Programm von - -[Fussball] -Title = fussball -Title = fuball -Title = UEFA Champions - -#Sonstiges -[^Sieben$] -Title = ^Sieben$ - -[Starportrt Kevin Spacey] -Title = Starportrt Kevin Spacey - - -[All Movies for -s] -Subtitle = MOVIE -Instance = s - -[All >= 65m for -s] -Title = . -minlength = 65m -Instance = s diff --git a/Tools/master-timer/sample/done b/Tools/master-timer/sample/done deleted file mode 100644 index 76819c7be..000000000 --- a/Tools/master-timer/sample/done +++ /dev/null @@ -1 +0,0 @@ -Alles Routine|Komdie diff --git a/Tools/master-timer/sample/subtitle-movie b/Tools/master-timer/sample/subtitle-movie deleted file mode 100644 index 9bd357973..000000000 --- a/Tools/master-timer/sample/subtitle-movie +++ /dev/null @@ -1,52 +0,0 @@ -^Abenteuerfilm$ -^Actionfilm$ -^Actionkomdie$ -^Actionthriller$ -^Agentenfilm$ -^Beziehungskomdie$ -^Biografie$ -^Biographie$ -^Computeranimation$ -^Drama$ -^Episodenfilm$ -^Erotikfilm$ -^Familiendrama$ -^Fantasy$ -^Fantasykomdie$ -^Fantasy-Komdie$ -^Gangsterfilm$ -^Gerichtsfilm$ -^Gesellschaftsdrama$ -^Historiendrama$ -^Horrorfilm$ -^Horrorkomdie$ -^Jugenddrama$ -^Kinderfilm$ -^Komdie$ -^Kriegsfilm$ -^Krimikomdie$ -^Kriminalfilm$ -^Liebesfilm$ -^Liebeskomdie$ -^Melodram$ -^Melodrama$ -^Monumentalfilm$ -^Musical$ -^Politthriller$ -^Psychothriller$ -^Road Movie$ -^Romanze$ -^Satire$ -^Science-Fiction$ -^Science-Fiction-Komdie$ -^Spielfilm$ -^TV Movie$ -^TV-Drama$ -^Teil .$ -^Teil 0.$ -^Thriller$ -^Tragikomdie$ -^Western$ -^Westernkomdie$ -^Zeichentrick$ -^Zeichentrickkomdie$ diff --git a/Tools/master-timer/sample/torecord b/Tools/master-timer/sample/torecord deleted file mode 100644 index 0c97b9162..000000000 --- a/Tools/master-timer/sample/torecord +++ /dev/null @@ -1,90 +0,0 @@ -# [<Anytext>] -# This marks the beginning of a timer entry -# Title = <text> -# This matches a title -# Subtitle = <text> -# This matches a subtitle. -# You may use the magic "MOVIE" or "!MOVIE" which matches -# all entries from file "subtitle-movie". -# Description = <text> -# This matches a description -# Category = <left>/<right> -# This matches a DTV-Category -# Channel = <Channel> -# Restricts a time to a specific channel. -# A single "!" at start of channel list negates the selection. -# Timeframe = <begin>-<end> -# Restricts timer to a specific timeframe. -# Only timers with start time in the timeframe will be programmed. -# minlength = <Number> -# Restricts timer entry to a specific minimum length -# (postfix "m" for minutes, "h" for hours.) -# maxlength = <Number> -# Restricts a timer entry to a specific maximum length -# (postfix "m" for minutes, "h" for hours.) -# weekday = MTWTFSS -# Restricts a timer to a specific weekday -# Timertitle = <text> -# The title used for this timer. -# If this is not provided "Title" will be used. -# If "Title" is not provided the EPG title will be used. -# Margin = <Number>;<Number> -# Seconds added to the beginning and end of the timer. -# Positive numbers will lengthen the recording. -# instance = <Number> -# The instance of VDR for which this timer is. -# If this is not provided the timer is valid for ALL instances. -# -# The "Title", "Subtitle", "Description", "Channel"-Lines can be -# supplied any number of times for a specific entry -# -# To record something at least one of the "Title", "Subtitle" or "Description" -# fields has to be provided. These three fields are "include" and the rest are -# "exclude" fields! - -[Dies ist ein Test-Timer] -Title = Titel -Subtitle = Subtitel -Description = Description -Category = Serie/Krimi -Channel = Pro-7 -Channel = VIVA -Timeframe = 1230-1830 -Prio = 50 -Lifetime = 50 -minlength = 10m -maxlength = 3h -weekday = ---T--- -Timertitle = Test -Margin = 600;600 -instance = 2 - -# Record Babylon 5 only if NOT playing on Pro 7; -# recording starts one minute too early and ends -# one minute too early (to skip following ads). -[Babylon 5] -Title = Babylon 5 -Channel = !Pro-7 -Prio = 99 -Margin = 60;-60 - -[DS9] -Title = Deep Space Nine -Prio = 99 -Timertitle = DS9 -Margin = 60;-60 - -[Seven Days] -Title = Seven Days -Prio = 99 - -[Stargate] -Title = Stargate -Prio = 99 - -[Aniston] -Description = Aniston -Prio = 99 - -[Matrix] -Title = Matrix diff --git a/Tools/master-timer/scan-channels b/Tools/master-timer/scan-channels deleted file mode 100755 index 324181b98..000000000 --- a/Tools/master-timer/scan-channels +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -old=`svdrpsend.pl chan | grep 250 | cut -d " " -f2` -for dat in `cat $HOME/.master-timer/channels-to-scan` -do - svdrpsend.pl "chan $dat" - sleep 30s -done -svdrpsend.pl "chan $old" diff --git a/Tools/schnitt/README b/Tools/schnitt/README deleted file mode 100644 index 8e1cacc99..000000000 --- a/Tools/schnitt/README +++ /dev/null @@ -1,111 +0,0 @@ - Sammlung von "Hilfs"-Scripten - von Matthias Schniedermeyer - ms@citd.de - -Diese Sammlung an "Hilfs"-Scripten habe ich mir zum scheiden und anderen -Zwecken zusammengeschrieben. - -Das ganze unterliegt natuerlich der GPL. - -Ich bin nicht sonderlich gut im "Dokumentieren". Also gilt die Devise -"Hilf dir selbst". - -Ein paar Worte zu den "Hart"-Codierten Pfaden. - -/dvb/video -/dvb2/video - -Sind die 2 DVB-Rechner. - -/x1/video - -Ist das Verzeichniss in das die Video zum schneiden verschoben werden. - -/x1/temp -/x2/temp - -Sind die beim schneiden verwendeten Temporaer-Verzeichnisse - - -Enthalten sind folgende Scripte: - -cutall -> "Master"-Script zum starten des Scheide vorgangs. - Ist ein "find" nach "cut" -Dateien -cutt -> Das "eigentliche" Schnitt-Script - Bei einem einzelnen Block wird diese direkt - gesplitet und dann zu einem ISO-Image verarbeitet - Wenn mehrere Teile (=War mit Werbung) vorhanden - sind, dann werden zuerst die einzelnen Teile, - legt nummerierte Verzeichniss ein und kopiert bzw - splitet die einzelnen Dateien in die Verzeichniss - und macht dann daraus die ISO-Images - (Leider funktioniert das aus irgendwelche Gruenden - (noch) nicht mit Serien die nur eine CD gross sind - aber das wird noch) -index.php -> PHP-Script zum finden der Schnitt-Punkte, mit - Testmoeglichkeit ob erfolgreich an diesem Punkt - geschnitten werden kann -mv2 -> Zum Moven der Aufnahmen von meinen DVB-Rechnern - auf mein "Arbeitsrechner" -play -> Zum Abspielen einer Aufnahme von meinem Recher auf - dem "Frontend" DVB-Rechner -schnitt.pl -> Extraiert ein einzelnes Bild um es anzuzeigen - (Fuer index.php) -schnitt2.pl -> Gibt alles zwischen 2 Schnittpunkten auf STDOUT aus -schnitt3.pl -> Testet ob erfolgreich geschnitten werden kann. -schnitt3.pl.new -> Version fuer PES-Datenstroeme -schnitt4.pl -> "Beschleunigtes" Schnitt-Programm fuer VIVA - aufnahmen. 1 "VIDEO" pro Zeile erzeugt - "a", "b" ... Dateien -schnitt5.pl -> Gibt Datei-Nummern von einer Schnittmarke - +- 15000 Frames aus -schnitt6.pl -> Loescht alle Dateien die nicht von in einer von - schnitt5.pl abgedeckt ist. (Damit mv2 nicht so - lange braucht) -show -> Wird auf einem X-Display gestartet und zeigt das - aktuelle Bild von "schnitt.pl" an -vdr-remote.pl -> "Skeleton" um ueber SVDR-Kommandos zu schicken -vdr2 -> Start-Script -vmount -> Mounten aller zusammengehoeriger ISO-Images zum - abspielen - -Hilfsscripte: ------------- -cut.pl -> Entspricht weitestgehend "split" aber mit - "Nummer" anstatt Buchstaben -cut2 -> Entfernt escapende Backslashes -cut2.pl/cut3.pl -> Fuer Aufnehmen die aus mehreren Bloecken bestehen - (=Mit Werbung) -cutall2 -> Springt ins Schnitt-Verzeichniss und ruft das - "eigentliche" Schnitt-Script auf -cutall3.pl -> Wenn in einem Verzeichniss mehrere Aufnahmen sind - splitet dies Programm diese und ruft fuer jede - Aufnahme das "cutt"-Script auf -schnittcommon.pli -> Das "Common" Script fuer schnitt?.pl -getpreviframe.pl -> Findet das vorherige I-Frame. -unsort -> Macht das Gegenteil von sort. - -dump.c -> Muss in der "libmpeg3"-Verzeichniss des - "mpeg2-movie"-Packets kopiert werden und dann mit - "make" compilieren - Dieses C-Programm ist dafuer da um fuer das - PHP-Script das Bild anzuzeigen wo man gerade ist. - Da mir der "urspruengliche" Source-Code dafuer - abhanden gekommen ist und ich den Patch neumachen - musste (Wie immer mit "Verbesserungen") ist index.php - nocht nicht auf die neue Version angepasst. Die - Anpassung besteht aber nur darin eine "1" an die - Kommandozeile anzuhaengen. - - -Im Gegensatz zur "alten"-Version ist diese Version "vollstaendig" -einsatzfaehig! - - -Wenn jemand Fragen zum Einsatz hat dann "loechern Sie mich" - -ms@citd.de - - -Ich kann auch gerne die Einrichtung per "Fernwartung" (=ssh) uebernehmen. -(Wenn noetig compiliere ich auch auch apache mit PHP usw.) diff --git a/Tools/schnitt/cut.pl b/Tools/schnitt/cut.pl deleted file mode 100755 index e05507692..000000000 --- a/Tools/schnitt/cut.pl +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/perl - -chdir ($ARGV[0]) if ($ARGV[0]); - -$read = $size = 1024*1024; - -$filenum = "1"; -$count = 0; - -$fi = sprintf ("part%d",$filenum); -open (FI,">$fi"); - -while ($read == $size) - { - if ($count < 660*1024*1024) - { - $read = read (STDIN,$data,$size); - print FI $data; - $count += $size; - $a = $count /1024/1024; - if ($a % 10 == 0) { - print stderr "File: $filenum Size: ${a}MB\n"; - } - } - else - { - close (FI); - $filenum++; - $fi = sprintf ("part%d",$filenum); - open (FI,">$fi"); - $count = 0; - } - } - -close FI; diff --git a/Tools/schnitt/cut2 b/Tools/schnitt/cut2 deleted file mode 100755 index 09e9acbcc..000000000 --- a/Tools/schnitt/cut2 +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -cat cut2 | head -n 1 | tr -d [\\\\] diff --git a/Tools/schnitt/cut2.pl b/Tools/schnitt/cut2.pl deleted file mode 100755 index 6131e880a..000000000 --- a/Tools/schnitt/cut2.pl +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/perl - -$titel = $ARGV[0]; - -chdir ("/x2/temp"); - -@files=<teil*.mpg>; -$cd = 1; -mkdir "/x2/temp/$cd"; -open (FF,">/x2/temp/$cd/$titel\ CD\ $cd"); -close (FF); - -foreach $file (@files) - { - $size = -s $file; - $total += $size; - if ($total <= 660*1024*1024) - { - print "Moving $file\n"; - system ("mv /x2/temp/$file /x2/temp/$cd/$file"); - } - else - { - print "Splitting $file\n"; - $file =~ s/\.mpg$//; - $total -= $size; - $size = (660*1024*1024) - $total; - $cd = `cut3.pl /x2/temp $cd $file $size \'$titel\' < $file.mpg`; - chomp $cd; - $total = 0; - @files2=</x2/temp/$cd/teil*>; - foreach $file2 (@files2) - { - $total += -s $file2; - } - print "CD: $cd Total $total\n"; - unlink "$file.mpg"; - } - } diff --git a/Tools/schnitt/cut3.pl b/Tools/schnitt/cut3.pl deleted file mode 100755 index ddaf0d6f1..000000000 --- a/Tools/schnitt/cut3.pl +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/perl - -$read = $size = 1024*1024; - -$dir = $ARGV[0]; -$subdir = $ARGV[1]; -$teil = $ARGV[2]; -$count1 = $ARGV[3]; -$title = $ARGV[4]; - -$filenum = "1"; -$count = 0; - -open (FI,">$dir/$subdir/$teil.$filenum.mpg"); - -while ($read == $size) - { - if (($filenum == 1 && $count < $count1) || ($filenum > 1 && $count < 660*1024*1024)) - { - $read = read (STDIN,$data,$size); - print FI $data; - $count += $size; - $a = $count /1024/1024; - } - else - { - close (FI); - $filenum++; - $subdir++; - mkdir ("$dir/$subdir"); - open (FF,">$dir/$subdir/$title\ CD\ $subdir"); - close (FF); - open (FI,">$dir/$subdir/$teil.$filenum.mpg"); - $count = 0; - } - } - -close FI; - -print "$subdir\n"; diff --git a/Tools/schnitt/cutall b/Tools/schnitt/cutall deleted file mode 100755 index a6803e2b7..000000000 --- a/Tools/schnitt/cutall +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -find /x1/video/ -name "cut" -exec cutall2 {} \; diff --git a/Tools/schnitt/cutall2 b/Tools/schnitt/cutall2 deleted file mode 100755 index 962d57722..000000000 --- a/Tools/schnitt/cutall2 +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -a=`echo $1 | cut -d / -f1-5` -cd $a -cutall3.pl -mv cut cut.bak diff --git a/Tools/schnitt/cutall3.pl b/Tools/schnitt/cutall3.pl deleted file mode 100755 index 696166697..000000000 --- a/Tools/schnitt/cutall3.pl +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/perl - -open (FI,"cut") or die "Kann Cut-Datei nicht oeffnen\n"; - -outer: while (<FI>) - { - chomp; - if (! ($_ > 1 || $_ eq "0")) - { - open (FO,">cut2"); - print FO "$_\n"; - while (<FI>) - { - chomp; - if ($_ > 1 || $_ eq "0") - { - print FO "$_\n"; - } - else - { - system ("cutt"); - redo outer; - } - } - } - } -if ( -f "cut2") - { - system ("cutt"); - unlink "cut2"; - } diff --git a/Tools/schnitt/cutt b/Tools/schnitt/cutt deleted file mode 100755 index 1942437a0..000000000 --- a/Tools/schnitt/cutt +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/sh - -DIRA=/x2/temp -DIRB=/x1/temp - -if [ ! -f cut2 ]; then - echo Keine Beschreibungsdatei - exit 1 -else - name="`cut2`" - echo $name - count=`cat cut2 | wc -l` - let count=count-1 - let test=count%2 - if [ "$test" == "1" ]; then - echo Ungerade Anzahl von Markierungen - exit 1 - fi - - file=1 - - if [ "$count" == "2" ]; then - start=`cat cut2 | tail -n $count | head -n 1` - let count=count-1 - end=`cat cut2 | tail -n $count | head -n 1` - schnitt2.pl $start $end | avpes2mpeg | cut.pl $DIRA - secondway=2 - else - while [ "$count" != "0" ] - do - start=`cat cut2 | tail -n $count | head -n 1` - let count=count-1 - end=`cat cut2 | tail -n $count | head -n 1` - let count=count-1 - echo Cutting \& Converting from $start to $end - schnitt2.pl $start $end | avpes2mpeg > $DIRA/teil$file.mpg -# schnitt2.pl $start $end | pvademux $DIRA teil$file - let file=file+1 - done - fi -fi - -# Ab hier mkimg - -rm cut2 - -sync - -if [ "$secondway" != "2" ]; then - cd $DIRA - cut2.pl "$name" - if [ -d 2 ]; then - count=1 - cond=0 - - while [ "$cond" != "1" ] - do - echo mkisofs Teil $count - mkisofs -r -o $DIRB/image1.raw $count - rm -rf $count - mv -- $DIRB/image1.raw "$DIRB/${name} CD $count" - sync - let count=count+1 - if [ ! -d $count ]; then - cond=1 - fi - done - else - echo mkisofs - mkisofs -r -o $DIRB/image1.raw $count - rm -rf $count - mv -- $DIRB/image1.raw "$DIRB/${name}" - fi -else - - cd $DIRA - - if [ -f part2 ]; then - count=1 - cond=0 - - while [ "$cond" != "1" ] - do - mkdir a - mv "part$count" "a/${name} CD $count.mpg" - echo mkisofs Teil $count - mkisofs -r -o $DIRB/image1.raw a - rm -rf a - mv -- $DIRB/image1.raw "$DIRB/${name} CD $count" - sync - - let count=count+1 - if [ ! -f "part$count" ]; then - cond=1 - fi - done - else - mkdir a - mv part1 "a/${name}.mpg" - echo mkisofs - mkisofs -r -o $DIRB/image1.raw a - rm -rf a - mv -- $DIRB/image1.raw "$DIRB/${name}" - fi -fi - diff --git a/Tools/schnitt/dump.c b/Tools/schnitt/dump.c deleted file mode 100644 index a362f6892..000000000 --- a/Tools/schnitt/dump.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "libmpeg3.h" -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> - -int main(int argc, char *argv[]) -{ - mpeg3_t *file; - int x,y,ii,i,j,result,out; - int howmany; - unsigned char *output, **output_rows; - char filename[100]; - char header[100]; - char temp; - - howmany = atoi (argv[2]); - - if ((file = mpeg3_open(argv[1])) == NULL) - { - printf ("Open failed\n"); - return 1; - } - mpeg3_set_cpus(file,1); - mpeg3_set_mmx(file,0); - if (mpeg3_has_video == 0) - { - printf ("Stream has no Video\n"); - return 1; - } - x = mpeg3_video_width(file,0); - y = mpeg3_video_height(file, 0); - output = malloc (x*y*3 + 4); - output_rows = malloc (sizeof(unsigned char*) * y); - for(i = 0; i < y; i++) - output_rows[i] = &output[i * x * 3]; - - for (ii = 0; ii < howmany; ii++) - { - result = mpeg3_read_frame(file,output_rows,0,0,x,y,x,y,0,0); - - sprintf (filename,"/x2/temp/output%03i.ppm",ii); - sprintf (header,"P6\n%i %i\n255\n\r",x,y); - -/* printf ("Opening %s\n",filename); */ - - if ((out = open (filename,O_CREAT|O_WRONLY|O_TRUNC,0755)) == -1) - { - printf ("Can't open %s\n",filename); - return 1; - } - - write (out,header,strlen(header)); - - for (i = 0; i < y; i++) - for (j = 0; j < x; j++) - { - temp = output [(i*x+j)*3 + 1]; - output[(i*x+j)*3 + 1] = output [(i*x+j)*3 + 0]; - output[(i*x+j)*3 + 0] = temp; - } - write (out, output, x*y*3); - close (out); - } -} diff --git a/Tools/schnitt/getpreviframe.pl b/Tools/schnitt/getpreviframe.pl deleted file mode 100755 index 4829304c3..000000000 --- a/Tools/schnitt/getpreviframe.pl +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/perl - -require "/usr/local/bin/my/schnittcommon.pli"; - -if (!open (INDEX,"index.vdr")) - { - exit 1; - } -$index = $oindex = $ARGV[0]; -if ($index > 0) -{ - &prevI; - if ($oindex != $index) - { - print "$index\n"; - } - else - { - print "$oindex\n"; - } -} -else -{ - print "0\n"; -} diff --git a/Tools/schnitt/index.php b/Tools/schnitt/index.php deleted file mode 100644 index 58a288fec..000000000 --- a/Tools/schnitt/index.php +++ /dev/null @@ -1,215 +0,0 @@ -<html> -<head> - <title>Schneiden - - - -

Sender

-
- -\n"; - } - } - closedir($handle); -?> -
- -
- -

Filme/Serien fuer den Sender $dir

"; - $handle=opendir("/x1/video/$dir"); - while ($file = readdir($handle)) { - if ($file != "." && $file != "..") { - echo "
\n"; - } - } - closedir($handle); -?> -
-=10000) - $index -= 10000; - break; - case "-4000": - if ($index >=4000) - $index -= 4000; - break; - case "-2000": - if ($index >=2000) - $index -= 2000; - break; - case "-1000": - if ($index >=1000) - $index -= 1000; - break; - case "-500": - if ($index >=500) - $index -= 500; - break; - case "-100": - if ($index >=100) - $index -= 100; - break; - case "Vorheriges I-Frame": - $pindex = $index - 1; - $fp = popen ("/usr/local/bin/my/getpreviframe.pl $pindex","r"); - $i = fgets($fp,1000); - $index = chop ($i); - pclose ($fp); - break; - case "Naechstes I-Frame": - $index ++; - break; - case "+100": - $index += 100; - break; - case "+500": - $index += 500; - break; - case "+1000": - $index += 1000; - break; - case "+2000": - $index += 2000; - break; - case "+4000": - $index += 4000; - break; - case "+10000": - $index += 10000; - break; - } - -if ($test) - { - $fp = popen ("/usr/local/bin/my/schnitt3.pl $index","r"); - $i = fgets($fp,1000); - pclose ($fp); - $index = chop ($i); - } - -if ($name) - { - $fp = fopen ("cut","w"); - fputs ($fp,"$name\n"); - fclose ($fp); - } - -if ($cut) - { - $fp = fopen ("cut","a"); - fputs ($fp,"$index\n"); - fclose ($fp); - } - -$fp = popen ("/usr/local/bin/my/schnitt.pl $index","r"); -$i = fgets($fp,1000); -pclose ($fp); -$index = chop ($i); - -system ("/usr/local/bin/my/dumpframe /x2/temp/bild.m2v"); -system ("mv output.ppm /x2/temp"); -system ("touch /x2/temp/newpic"); -system ("killall sleep"); -?> -
- - -> - - - - - -

Index

Dir:

- - - - - - - - - - - - - - - - -
-
- - - - - - - - - -> - - - -
Absoluter Index:
Titel:
- - - diff --git a/Tools/schnitt/lmplex b/Tools/schnitt/lmplex deleted file mode 100755 index 8cbb50f20..000000000 --- a/Tools/schnitt/lmplex +++ /dev/null @@ -1,51 +0,0 @@ -#! /usr/bin/perl - -### Calculate the number of CPUs we want to keep busy -open IN, "/proc/cpuinfo"; -$cpus = grep /processor.*:/, ; -close IN; - -### This is a list of files to encode -@names = @ARGV; - -$dira = shift @names; -$dirb = shift @names; - -### This is the name of the encoder to use. -$coder = "/usr/local/bin/mplex "; -### - -### -### -### - -# Encode a single file -sub do_one { - my($m2v) = shift; - # Make mp3 from wav - $m2v =~ s/\.m2v$//; - - # In a subprocess, encode the file - printf "Multiplexing ${m2v}\n"; - unless($pid = fork) { - system ("$coder ${dira}/${m2v}.m2v ${dira}/${m2v}.mp2 ${dirb}/${m2v}.mpg"); - exit; - } -} - -# Go ahead and prefork $cpus encoders -foreach $i (0 .. $cpus-1) { - &do_one($names[0]) if ($names[0] ne ""); - shift @names; -} - -# Wait for the end of each encoder, start a new one... -foreach $i (@names) { - wait; - &do_one($i); -} - -# Wait for everything to close down. -while(wait > 0) { - ; -} diff --git a/Tools/schnitt/mv2 b/Tools/schnitt/mv2 deleted file mode 100755 index c27a9ffe6..000000000 --- a/Tools/schnitt/mv2 +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -# -# Move files from DVB-Computer(s) to localmachine into $LOCALDIR -# - -LOCALDIR=/x1/video - -if [ ! "$UID" = 0 ]; then - if [ -d "$1" ]; then - if [ -f "$1/index.vdr" ]; then - cd $LOCALDIR - recdir=`echo "$1" | cut -d / -f4-` - mkdir -p "$recdir" - cd "$recdir" - dvbcomp=`echo "$1" | cut -d / -f2` - (echo cd "/video/video0/$recdir"; echo mget \*)| ftp -i $dvbcomp - cd $LOCALDIR - ssh $dvbcomp ls -Ls /video/video0/$recdir > /tmp/dvb - ls -Ls $recdir > /tmp/local - diff -u /tmp/dvb /tmp/local &> /dev/null && rm -rfv /$dvbcomp/video?/$recdir - rm /tmp/dvb - rm /tmp/local - rmdir --ignore-fail-on-non-empty `find /$dvbcomp/video?/ -type d -mindepth 1 | cut -d \/ -f-4 | grep -v temp | sort | uniq` - fi - fi -else - echo Not as root -fi - -/usr/local/bin/my/process_summary.pl diff --git a/Tools/schnitt/play b/Tools/schnitt/play deleted file mode 100755 index 0c43bff5f..000000000 --- a/Tools/schnitt/play +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -if [ "$1" != "" ]; then - vmount "$1" -fi -ssh dvb2 /usr/local/bin/my/novdr -sleep 1s -cat /mnt/*/* | buffer -b 1000 -S 1024 | ssh dvb2 play2 -ssh dvb2 rm /tmp/novdr -umount /mnt/* - diff --git a/Tools/schnitt/schnitt.pl b/Tools/schnitt/schnitt.pl deleted file mode 100755 index ac72a144f..000000000 --- a/Tools/schnitt/schnitt.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl - -require "/usr/local/bin/my/schnittcommon.pli"; - -if (!open (INDEX,"index.vdr")) - { - exit 1; - } -$index = $ARGV[0]; -&nextI; -$offset1 = $offset; -&readnext; -$off = $offset - $offset1; -close (FI); -$fi = sprintf ("%03d.vdr",$file); -open (FI,$fi); -open (FO,">bild"); -sysseek (FI,$offset1,0); -sysread (FI,$temp,200000); -syswrite (FO,$temp,200000); -close (FI); -close (FO); - -`cat bild | /usr/local/bin/avpes2mpeg > avpes`; -`/usr/local/bin/my/dumpframe avpes 1`; -#`/usr/local/bin/pes2av_pes bild | /usr/local/bin/pvademux /x2/temp bild`; -print "$index\n"; diff --git a/Tools/schnitt/schnitt2.pl b/Tools/schnitt/schnitt2.pl deleted file mode 100755 index d81b5fd59..000000000 --- a/Tools/schnitt/schnitt2.pl +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/perl - -require "/usr/local/bin/my/schnittcommon.pli"; - -if (!open (INDEX,"index.vdr")) - { - print "Error opening index.vdr"; - exit 1; - } - -$index = $ARGV[0]; -&nextI; -#&readnext; -$file1 = $file; -$offset1 = $offset; -$index = $ARGV[1]; -&nextI; -#&readnext; -$file2 = $file; -$offset2 = $offset; - -if ($file1 == $file2) - { - $count = $offset2 - $offset1; - $cond = 0; - $size = 1024*1024; - $fi = sprintf ("%03d.vdr",$file); - open (FI,$fi); - sysseek (FI,$offset1,0); - while ($cond == 0) - { - if ($count > $size) - { - $read = sysread (FI,$data,$size); - print $data; - $count -= $size; - } - else - { - $read = sysread (FI,$data,$count); - print $data; - $cond = 1; - } - } - } -else - { - $count = $offset2; - $cond = 0; - $read = $size = 1024*1024; - $fi = sprintf ("%03d.vdr",$file1); - open (FI,$fi); - sysseek (FI,$offset1,0); - while ($read == $size) - { - $read = sysread (FI,$data,$size); - print $data; - } - close (FI); - - $file1++; - while ($file1 != $file2) - { - $fi = sprintf ("%03d.vdr",$file1); - open (FI,$fi); - $read = 1024*1024; - while ($read == $size) - { - $read = sysread (FI,$data,$size); - print $data; - } - close (FI); - $file1++; - } - - $fi = sprintf ("%03d.vdr",$file2); - open (FI,$fi); - while ($cond == 0) - { - if ($count > $size) - { - $read = sysread (FI,$data,$size); - print $data; - $count -= $size; - } - else - { - $read = sysread (FI,$data,$count); - print $data; - $cond = 1; - } - } - } diff --git a/Tools/schnitt/schnitt3.pl b/Tools/schnitt/schnitt3.pl deleted file mode 100755 index 7cc0f7f3e..000000000 --- a/Tools/schnitt/schnitt3.pl +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl - -require "/usr/local/bin/my/schnittcommon.pli"; - -open (INDEX,"index.vdr"); -$index = $ARGV[0]; -&nextI; - -$oldindex = $index; -$tempindex = $index; - -$add = -1; - -$fi = sprintf ("%03d.vdr",$file); -open (FI2,$fi); -open (FO,">test"); -sysseek (FI2,$offset,0); -sysread (FI2,$temp,3000000); -syswrite (FO,$temp,3000000); -close (FI2); -close (FO); -`/usr/local/bin/pvademux.old . test`; -if ( -s "test.mp2") - { - `rm test*`; - print "$index\n"; - exit 0; - } - -while (1) - { - if ($index == 0) - { - $add = 1; - } - if ($add = -1) - { - $index--; - &prevI; - } - else - { - nextI; - } - $fi = sprintf ("%03d.vdr",$file); - open (FI2,$fi); - open (FO,">test"); - sysseek (FI2,$offset,0); - sysread (FI2,$temp,3000000); - syswrite (FO,$temp,3000000); - close (FI2); - close (FO); - `/usr/local/bin/pvademux.old . test`; - if ( -s "test.mp2") - { - `rm test*`; - if ($index < 0) - { - $index *= -1; - } - print "$index\n"; - exit 0; - } - } diff --git a/Tools/schnitt/schnitt3.pl.new b/Tools/schnitt/schnitt3.pl.new deleted file mode 100755 index 04a6239be..000000000 --- a/Tools/schnitt/schnitt3.pl.new +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/perl - -require "/usr/local/bin/my/schnittcommon.pli"; - -open (INDEX,"index.vdr"); - -$index = $ARGV[0]; -&nextI; - -$oldindex = $index; -$tempindex = $index; - -$add = -1; - -$fi = sprintf ("%03d.vdr",$file); -open (FI2,$fi); -open (FO,">test2"); -sysseek (FI2,$offset,0); -sysread (FI2,$temp,3000000); -syswrite (FO,$temp,3000000); -close (FI2); -close (FO); - -system ("pes2av_pes test2 > test 2>/dev/null"); -open (PVA,"/usr/local/bin/pvademux.old . test 2>&1 |"); - -@a=; close PVA; -@b=split (/\s/,$a[2]); - -if (!($b[4] =~ /\-/) && $b[4] < 2000) - { - unlink ; - print "$index\n"; - exit 0; - } - -while (1) - { - if ($index == 0) - { - $add = 1; - } - if ($add = -1) - { - $index--; - &prevI; - } - else - { - nextI; - } - $fi = sprintf ("%03d.vdr",$file); - open (FI2,$fi); - open (FO,">test2"); - sysseek (FI2,$offset,0); - sysread (FI2,$temp,3000000); - syswrite (FO,$temp,3000000); - close (FI2); - close (FO); - -system ("/usr/local/bin/pes2av_pes test2 > test 2>/dev/null"); -open (PVA,"/usr/local/bin/pvademux.old . test 2>&1 |"); - -@a=; close PVA; -@b=split (/\s/,$a[2]); - -if (!($b[4] =~ /\-/) && $b[4] < 2000) - { - unlink ; - if ($index < 0) - { - $index *= -1; - } - print "$index\n"; - exit 0; - } -} diff --git a/Tools/schnitt/schnitt4.pl b/Tools/schnitt/schnitt4.pl deleted file mode 100755 index 75f2ad178..000000000 --- a/Tools/schnitt/schnitt4.pl +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl - -open (FI,$ARGV[0]) or die "Kann Input-Datei nicht oeffnen"; -$count = 1; - -while () - { - chomp; - $char = sprintf ("%c",$count + 96); - print "Cutting from/to $_ into /x2/clips/$char\n"; - system ("/usr/local/bin/my/schnitt2.pl $_ > /x2/clips/$char"); - $count++; - } diff --git a/Tools/schnitt/schnitt5.pl b/Tools/schnitt/schnitt5.pl deleted file mode 100755 index 7626ab51f..000000000 --- a/Tools/schnitt/schnitt5.pl +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/perl -require "/usr/local/bin/my/schnittcommon.pli"; - -open (INDEX,"index.vdr"); -$index = $ARGV[0] - 15000; -&nextI; - -$file1 = $file; - -$index += 30000; -&nextI; - -$file2 = $file; - -print "$file1 $file2\n"; - diff --git a/Tools/schnitt/schnitt6.pl b/Tools/schnitt/schnitt6.pl deleted file mode 100755 index 92d9eb49c..000000000 --- a/Tools/schnitt/schnitt6.pl +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl - -open (FI,"a"); - -while () -{ - open (SCH,"/usr/local/bin/my/schnitt5.pl $_|"); - $files = ; - chomp $files; - ($a,$b) = split (/\s/,$files); - $files[$a] = 1; - $files[$b] = 1; - close (SCH); -} - -while (<0*.vdr>) -{ - $_ =~ /\d(\d\d)\.vdr/; - if ($files[$1]) - { - print "Keeping $1\n"; - } - else - { - print "Deleting $_\n"; - unlink $_; - } -} - -close (FI); diff --git a/Tools/schnitt/schnittcommon.pli b/Tools/schnitt/schnittcommon.pli deleted file mode 100755 index f221f41af..000000000 --- a/Tools/schnitt/schnittcommon.pli +++ /dev/null @@ -1,64 +0,0 @@ -sub nextI - { - if (!$size) - { - $size = -s INDEX; - } - local ($a,$b,$c,$dummy); - $cond = 0; - seek (INDEX,$index * 8,0); - - while ($cond == 0) - { - &readnext; - if ($frame == 1) - { - $cond = 1; - } - else - { - $index++; - if ($index > ($size/8-1)) - { - $index = $size/8-1; - &prevI; - print "$index\n"; - exit 1; - } - } - } - } - -sub readnext - { - read (INDEX,$a,4); - read (INDEX,$b,1); - read (INDEX,$c,1); - read (INDEX,$dummy,2); - $offset = unpack ("L",$a); - $frame = unpack ("C",$b); - $file = unpack ("C",$c); - } - -sub prevI - { - local ($a,$b,$c,$dummy); - $cond = 0; - seek (INDEX,$index * 8,0); - - while ($cond == 0) - { - &readnext; - if ($frame == 1) - { - $cond = 1; - } - else - { - $index--; - seek (INDEX,$index * 8,0); - } - } - } - -1; diff --git a/Tools/schnitt/show b/Tools/schnitt/show deleted file mode 100755 index bfcc58a8f..000000000 --- a/Tools/schnitt/show +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -cd /x2/temp -while true -do - if [ -f newpic ]; then - killall xli - rm -f newpic - xli output000.ppm & - fi -sleep 24h -done diff --git a/Tools/schnitt/unsort b/Tools/schnitt/unsort deleted file mode 100755 index 83adfb6c6..000000000 --- a/Tools/schnitt/unsort +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/perl - -while (<>) -{ - $h{$_}=1; -} - -foreach $key (sort shuffle keys %h) -{ - print $key; -} - -sub shuffle { - $ran = rand(1); - - if ($ran > 0.5) - { - return -1; - } - else - { - return 1; - } -} - diff --git a/Tools/schnitt/vdr-remote.pl b/Tools/schnitt/vdr-remote.pl deleted file mode 100755 index 32d408e0d..000000000 --- a/Tools/schnitt/vdr-remote.pl +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/perl -w - -use strict; -use Socket; - -my ($dest, $port, $iaddr, $paddr, $proto, $line); - -$dest = "localhost"; -$port = "2001"; - -$iaddr = inet_aton($dest) || Error("no host: $dest"); -$paddr = sockaddr_in($port, $iaddr); - -$proto = getprotobyname('tcp'); -socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!"); -connect(SOCK, $paddr) || Error("connect: $!"); -select (SOCK); $| = 1; -$a=; - -for (;;) - { - open (FI,"/tmp/vdr-keys"); - while () - { - chomp; - print "$_\r\n"; - $a=; - } - close (FI); - } - -print "quit\r\n"; -$a=; -close (SOCK) || Error("close: $!"); - -sub Error -{ - print STDERR "@_\n"; - exit 0; -} diff --git a/Tools/schnitt/vdr2 b/Tools/schnitt/vdr2 deleted file mode 100755 index 96557bf2f..000000000 --- a/Tools/schnitt/vdr2 +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -irpty ~/.lircrc-vdr -- vdr -c /home/ms/.vdr -v /video/video0 diff --git a/Tools/schnitt/vmount b/Tools/schnitt/vmount deleted file mode 100755 index ab16e4579..000000000 --- a/Tools/schnitt/vmount +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -count=1 -cond=0 - -if [ -f "$1" ]; then - mount "$1" /mnt/1 -o loop - cond=1 -else - while [ "$cond" != "1" ] - do - if [ -f "$1$count" ]; then - mount "$1$count" /mnt/$count -o loop - else - cond=1 - fi - let count=count+1 - done -fi diff --git a/Tools/statdvb2vdr/ch.pl b/Tools/statdvb2vdr/ch.pl deleted file mode 100644 index 91e918d27..000000000 --- a/Tools/statdvb2vdr/ch.pl +++ /dev/null @@ -1,250 +0,0 @@ -#!/usr/bin/perl - -# Reads the file statdvb.dat produced by the Siemens windows -# software (1.50), which contains the scanned channels of an -# DVB-C (-S). The file ist located in the windows directory. -# -# Output is suitable for VDR (channels.conf). Only tested for -# the cable version. Should work with slight modifications for -# the sat version. -# -# 8. Mrz 2001 - Hans-Peter Raschke - - -# file structure derived from "DvbGlobalDef.h" of the Siemens -# DVB kit. - -# typedef int TABLETYPE; -# enum TunStandard -# { -# PAL_BG, //B/G stereo or mono -# PAL_I, //I mono (with Nicam stereo) -# PAL_DK, //D/K mono -# SECAM_L, //L mono (with Nicam stereo) -# SECAM_LI, //Secam L (with Nicam stereo) -# SECAM_DK, -# SECAM_BG, -# NTSC_M, -# DVB_C, -# DVB_S, -# DVB_T -# }; -# -# typedef struct TunProgDataTag //xx bytes+1string -# { -# int nNumber; //logical number of the program -# DWORD dwFrequency; //frequency in khz -# CString csName; //name of the program -# TunStandard eStandard; //standard of the program -# DWORD dwExtraInfo; //specific info, like teletext,reserved data -# //0x8 == external input 1-CVBS -# //0x10 == external input 2-Y/C -# //0x20 == scrambled Program stream -# //0x40 == ASTRA Sattable -# //0x80 == Eutelsat Sattable -# //0xC0 == Sattable from File -# //0x100 == Pulsed switch to other satellite dish -# //0x1000-0xF000 = Other Satellite Nr(if Sattable from File) -# //Digital only params beginning from here -# WORD ProgNr; //DVB Nr for the prog (PAS related) -# WORD wTS_ID; //Transport-Stream ID orig. -# WORD wNW_ID; //Network ID orig. -# WORD wService_ID; //Service /Programm Id -# BYTE nModulation; //Modulation-Type QAM,QPSK,other -# BYTE nFEC_outerinner; //outer(high nibble) and inner(low n.) -# DWORD dwSymbolrate; //in symbol/s -# BOOL b22kHz; //east or west(TRUE) position in Sat -# BOOL bVertical_pos; //horizontal or vertical(TRUE) position in SAT -# BYTE nProgtype; //type of service (e.g. tv, radio) -# WORD wVideo_PID; //video-pid of the channel -# WORD wAudio_PID; //audio-pid of the channel -# WORD wPMT_PID; //PID of the associated PMT -# WORD wTxt_PID; //teletext PID for the program -# WORD wSubtitling_PID; //subtitling PID for the program -# WORD wData_PID; //PID for data broadcast -# BYTE nIPFilter; //filter for different ip's -# DWORD dwReserved1; //Shows some extended Information LOWORD=DataBroadcast_Id, -# //MSB showing Databroadcast, (HIWORD & 0xFF)=ComponentTag from the stream ident desc -# DWORD dwReserved2; //reserved dword -# }DVBTunProgData; -# - -use strict; -use FileHandle; - -# for a full dump -my @varNames = ("nNumber", # logical number of the program - "dwFrequency", # frequency in khz - "csName", # name of the program - "eStandard", # standard of the program - "dwExtraInfo", # specific info, like teletext,reserved data - # 0x8 == external input 1-CVBS - # 0x10 == external input 2-Y/C - # 0x20 == scrambled Program stream - # 0x40 == ASTRA Sattable - # 0x80 == Eutelsat Sattable - # 0xC0 == Sattable from File - # 0x100 == Pulsed switch to other satellite dish - # 0x1000-0xF000 = Other Satellite Nr(if Sattable from File) - "ProgNr", # DVB Nr for the prog (PAS related) - "wTS_ID", # Transport-Stream ID orig. - "wNW_ID", # Network ID orig. - "wService_ID", # Service /Programm Id - "nModulation", # Modulation-Type QAM,QPSK,other - "nFEC_outerinner", # outer(high nibble) and inner(low n.) - "dwSymbolrate", # in symbol/s - "b22kHz", # east or west(TRUE) position in Sat - "bVertical_pos", # horizontal or vertical(TRUE) position in SAT - "nProgtype", # type of service (e.g. tv, radio) - "wVideo_PID", # video-pid of the channel - "wAudio_PID", # audio-pid of the channel - "wPMT_PID", # PID of the associated PMT - "wTxt_PID", # teletext PID for the program - "wSubtitling_PID", # subtitling PID for the program - "wData_PID"); # PID for data broadcast - -my @outVar = ("csName", - "dwFrequency", - "bVertical_pos", - "b22kHz", - "dwSymbolrate", - "wVideo_PID", - "wAudio_PID", - "wTxt_PID", - "dwExtraInfo", - "ProgNr"); - -# channels that need a valid smartcard -my @addCrypted = ("Extreme Sport", - "Bloomberg", - "Fashion TV", - "BET ON JAZZ", - "LANDSCAPE", - "Einstein", - "Single TV"); - -my @chNames = (); # list of scanned channels -my $camNo = 1; # number of CI/CAM to use -my %chData; # all channel data -my $buff; # input buffer -my $fh = new FileHandle("$ARGV[0]") or die "Datei $ARGV[0] nicht gefunden!"; - -binmode($fh); # could be run on windows -$fh->seek(4, 0); # skip id - -my $chCnt = 0; -while (!$fh->eof()) { - $chCnt++; - - last if ($fh->read($buff, 7) != 7); - my ($nNumber, - $dwFrequency, - $sLen - ) = unpack("SLC", $buff); - - last if ($fh->read($buff, $sLen) != $sLen); - my ($csName) = unpack("A$sLen", $buff); - $csName =~ s/:/./g; - $csName =~ s/^\s+//; - $csName =~ s/\s+$//; - - last if ($fh->read($buff, 54) != 54); - my ($eStandard, - $dwExtraInfo, - $ProgNr, - $wTS_ID, - $wNW_ID, - $wService_ID, - $nModulation, - $nFEC_outerinner, - $dwSymbolrate, - $b22kHz, - $bVertical_pos, - $nProgtype, - $wVideo_PID, - $wAudio_PID, - $wPMT_PID, - $wTxt_PID, - $wSubtitling_PID, - $wData_PID - ) = unpack("LLSSSSCCLLLCSSSSSS", $buff); - - # some modifications for VDR - $dwFrequency /= 1000; - $bVertical_pos = $bVertical_pos ? "v" : "h"; - $dwSymbolrate /= 1000; - $dwExtraInfo = ($dwExtraInfo == 32 || grep(($_ cmp $csName) == 0, @addCrypted)) ? $camNo : 0; - - my $x = 1; - my $orgName = $csName; - while (exists($chData{$csName})) { - $csName = "$orgName" . "_$x"; - $x++; - } - push(@chNames, $csName); - - my %tmp = ("nNumber" => $nNumber, - "dwFrequency" => $dwFrequency, - "csName" => $orgName, - "eStandard" => $eStandard, - "dwExtraInfo" => $dwExtraInfo, - "ProgNr" => $ProgNr, - "wTS_ID" => $wTS_ID, - "wNW_ID" => $wNW_ID, - "wService_ID" => $wService_ID, - "nModulation" => $nModulation, - "nFEC_outerinner" => $nFEC_outerinner, - "dwSymbolrate" => $dwSymbolrate, - "b22kHz" => $b22kHz, - "bVertical_pos" => $bVertical_pos, - "nProgtype" => $nProgtype, - "wVideo_PID" => $wVideo_PID, - "wAudio_PID" => $wAudio_PID, - "wPMT_PID" => $wPMT_PID, - "wTxt_PID" => $wTxt_PID, - "wSubtitling_PID" => $wSubtitling_PID, - "wData_PID" => $wData_PID); - $chData{$csName} = {%tmp}; -} - -print STDERR "$chCnt channels found!\n"; - -# now we print the channels.conf -# crypted TV -print ":verschlsselte Fernsehprogramme\n"; -for my $n (@chNames) { - my %tmp = %{$chData{$n}}; - printChannel($chData{$n}) if ($tmp{"nProgtype"} == 1 && $tmp{"dwExtraInfo"}); -} - -# TV -print ":Fernsehprogramme\n"; -for my $n (@chNames) { - my %tmp = %{$chData{$n}}; - printChannel($chData{$n}) if ($tmp{"nProgtype"} == 1 && !$tmp{"dwExtraInfo"}); -} - -# crypted radio -print ":verschlsselte Radioprogramme\n"; -for my $n (@chNames) { - my %tmp = %{$chData{$n}}; - printChannel($chData{$n}) if ($tmp{"nProgtype"} == 2 && $tmp{"dwExtraInfo"}); -} - -# radio -print ":Radioprogramme\n"; -for my $n (@chNames) { - my %tmp = %{$chData{$n}}; - printChannel($chData{$n}) if ($tmp{"nProgtype"} == 2 && !$tmp{"dwExtraInfo"}); -} - -sub printChannel { - my $p = shift; - my @tmp = (); - - for my $n (@outVar) { - push(@tmp, ${$p}{$n}); - } - - print join(":", @tmp), "\n"; -} diff --git a/Tools/xtvrc2vdr/Makefile b/Tools/xtvrc2vdr/Makefile deleted file mode 100644 index be5054152..000000000 --- a/Tools/xtvrc2vdr/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# -# Makefile for xtvrc2vdr utility -# - -OBJS = xtvrc2vdr.o - -%.o: %.c - gcc -g -O2 -Wall -c $(DEFINES) $< - -all: xtvrc2vdr - -xtvrc2vdr: $(OBJS) - gcc -g -O2 $(OBJS) -o xtvrc2vdr - -clean: - -rm -f $(OBJS) xtvrc2vdr diff --git a/Tools/xtvrc2vdr/hotbird.conf b/Tools/xtvrc2vdr/hotbird.conf deleted file mode 100644 index 3431d5c4d..000000000 --- a/Tools/xtvrc2vdr/hotbird.conf +++ /dev/null @@ -1,191 +0,0 @@ -TV Polonia:10719:v:1:27500:163:92:0:0 -Credit Agricole:10834:v:1:27500:5321:5333:0:0 -La Chaine Parlementaire:10873:v:1:27500:1020:1030:0:0 -TMT:10892:v:1:27500:163:92:0:0 -Multivision Accueil:10911:v:1:27500:320:330:0:0 -RTL:11054:v:1:27500:160:80:0:0 -VOX:11054:v:1:27500:500:501:0:0 -Sat 1 A:11054:v:1:27500:511:512:0:0 -RTL II Austria:11054:v:1:27500:520:521:0:0 -NBC Europe:11054:v:1:27500:550:551:0:0 -ZDF:11054:v:1:27500:570:571:0:0 -K-T9:11054:v:1:27500:580:581:0:0 -Sat 1 Schweiz:11604:v:1:27500:101:102:0:0 -MKT9:11623:v:1:27500:222:242:0:0 -Olisat TV Promo:11623:v:1:27500:226:246:0:0 -Bloomberg TV Germany:11642:v:1:27500:1460:1420:0:0 -Bloomberg TV UK:11642:v:1:27500:1560:1520:0:0 -SAT 7:11642:v:1:27500:1660:1620:0:0 -Multivision 1:11662:v:1:27500:120:130:0:0 -Dubai EDT9:11746:v:1:27500:4130:4131:0:0 -Dubai Sport Channel:11746:v:1:27500:4386:4387:0:0 -Dubai Business Channel:11746:v:1:27500:4642:4643:0:0 -Dubai EDT9:11746:v:1:27500:4898:4899:0:0 -RAI Uno:11766:v:1:27500:160:80:0:0 -RAI Due:11766:v:1:27500:161:84:0:0 -RAI Tre:11766:v:1:27500:162:88:0:0 -RAI Mosaico:11766:v:1:27500:518:8191:0:0 -RAI SportSat:11804:v:1:27500:512:650:0:0 -RAI Nettuno Sat 2:11804:v:1:27500:513:651:0:0 -RAI Educational:11804:v:1:27500:514:652:0:0 -TelePace :11804:v:1:27500:515:653:0:0 -RAI News24:11804:v:1:27500:516:654:0:0 -Camera dei Deputati:11804:v:1:27500:517:655:0:0 -SAT 2000:11804:v:1:27500:518:656:0:0 -RAI NettunoSat 1:11804:v:1:27500:519:657:0:0 -ERT Sat:11823:v:1:27500:521:740:0:0 -INT9:11843:v:1:27500:2324:2325:0:0 -TVL:11843:v:1:27500:2441:2442:0:0 -Team TV :11881:v:1:27500:2305:2306:0:0 -Ante Prima:11881:v:1:27500:2435:2436:0:0 -SNAI:11881:v:1:27500:2561:2562:0:0 -Italia 1 :11919:v:1:27500:512:650:0:0 -Canale 5:11919:v:1:27500:513:660:0:0 -Rete 4 :11919:v:1:27500:514:670:0:0 -ART Europe:12015:v:1:27500:164:96:0:0 -ESC 2:12015:v:1:27500:166:104:0:0 -ART Iqra:12015:v:1:27500:168:112:0:0 -Vetrina D+:12034:v:1:27500:166:105:0:0 -D+ Info:12073:v:1:27500:160:80:0:0 -Palco Promo:12073:v:1:27500:161:84:0:0 -Vacaciones T9:12092:v:1:27500:4112:4113:0:0 -TvL - TV Locale:12092:v:1:27500:4160:4161:0:0 -Satisfaction T9:12092:v:1:27500:4192:4193:0:0 -TVE Internacional:12092:v:1:27500:4208:4209:0:0 -TVG - TV de Galicia :12092:v:1:27500:4224:4225:0:0 -La Cadena Del Milagro:12092:v:1:27500:4368:4369:0:0 -Fiesta:12092:v:1:27500:4432:4433:0:0 -Visions Europe:12092:v:1:27500:4416:4417:0:0 -SateliTV/TV Sex Channel:12092:v:1:27500:4480:4481:0:0 -Krisma:12111:v:1:27500:200:201:0:0 -NT9:12111:v:1:27500:210:211:0:0 -Armenia TV 1:12111:v:1:27500:240:241:0:0 -SMAU Channel :12111:v:1:27500:260:261:0:0 -JSC - Al Jazeera Satellite Ch :12111:v:1:27500:270:271:0:0 -Il Tirreno Sat:12111:v:1:27500:280:301:0:0 -Coming Soon T9:12111:v:1:27500:310:311:0:0 -Alice:12149:v:1:27500:160:161:0:0 -Nuvolari Promo:12149:v:1:27500:176:177:0:0 -CCTV 4:12169:v:1:27500:516:690:0:0 -Kanali Vuolis:12169:v:1:27500:517:700:0:0 -Nova Promo:12169:v:1:27500:521:740:0:0 -ERT Sat :12188:v:1:27500:514:652:0:0 -Kanali Voulis:12188:v:1:27500:515:653:0:0 -OTE Promo:12188:v:1:27500:517:655:0:0 -TV 5 Europe:12245:v:1:27500:121:131:0:0 -Fashion T9:12245:v:1:27500:123:133:0:0 -TV Ajara:12245:v:1:27500:127:137:0:0 -Telekom T9:12265:v:1:27500:1460:1420:0:0 -SLO-TV1:12303:v:1:27500:200:201:0:0 -Polonia 1:12303:v:1:27500:205:206:0:0 -Super 1:12303:v:1:27500:207:208:0:0 -Sicilia Internacional:12303:v:1:27500:210:211:0:0 -SicilSat:12303:v:1:27500:225:226:0:0 -TBNE Italy:12303:v:1:27500:230:231:0:0 -Countdown T9:12303:v:1:27500:235:236:0:0 -Napoli International:12303:v:1:27500:240:241:0:0 -Magic T9:12303:v:1:27500:245:246:0:0 -TEST:12341:v:1:27500:165:108:0:0 -Colour Bars:12380:v:1:27500:3022:3032:0:0 -Tele 24 :12380:v:1:27500:3023:3033:0:0 -Abu Dhabi TV :12380:v:1:27500:3024:3034:0:0 -LCA:12380:v:1:27500:3025:3035:0:0 -RTV Montenegro:12380:v:1:27500:3026:3036:0:0 -SRG SSR Sat Access :12399:v:1:27500:165:98:0:0 -Jam-e-Jam Network 1 (IRIB 1):12437:v:1:27500:160:80:0:0 -Jam-e-Jam Network 2 (IRIB 2):12437:v:1:27500:161:82:0:0 -Sahar University Network:12437:v:1:27500:162:84:0:0 -Maharishi Open University:12476:v:1:27500:42:43:0:0 -Europe by Satellite:12476:v:1:27500:101:201:0:0 -Pink Backup:12476:v:1:27500:308:256:0:0 -Mizik Tropical:12476:v:1:27500:435:436:0:0 -TLI info card:12476:v:1:27500:771:768:0:0 -Liberty T9:12476:v:1:27500:941:942:0:0 -HRT TV 1:12520:v:1:27500:100:101:0:0 -HRT National:12520:v:1:27500:107:108:0:0 -BVN TV:12520:v:1:27500:210:211:0:0 -Sicilia International:12520:v:1:27500:501:502:0:0 -Sardegna Uno:12520:v:1:27500:503:504:0:0 -TGRT:12520:v:1:27500:505:506:0:0 -Euro Mediterraneo:12520:v:1:27500:510:511:0:0 -WWWTravel T9:12540:v:1:27500:1180:1183:0:0 -WWWTravel T9:12540:v:1:27500:1180:1184:0:0 -WWWTravel T9:12540:v:1:27500:1180:1185:0:0 -Bulgaria T9:12540:v:1:27500:4612:4613:0:0 -MC Sat Monte Carlo:12540:v:1:27500:5126:5122:0:0 -MBC:12597:v:1:27500:160:80:0:0 -SIMA-YEH-MOGHAVEMENT:12597:v:1:27500:161:84:0:0 -NITV (National Iran TV ):12597:v:1:27500:163:92:0:0 -BET International:12597:v:1:27500:167:108:0:0 -JSTV 2 Info Card:12597:v:1:27500:2011:2012:0:0 -EuroNews:12597:v:1:27500:2221:2231:0:0 -EuroNews:12597:v:1:27500:2221:2232:0:0 -EuroNews:12597:v:1:27500:2221:2233:0:0 -EuroNews:12597:v:1:27500:2221:2234:0:0 -EuroNews:12597:v:1:27500:2221:2235:0:0 -EuroNews:12597:v:1:27500:2221:2236:0:0 -EuroNews:12597:v:1:27500:2221:2237:0:0 -Canal Agro Rual:12597:v:1:27500:2321:2331:0:0 -MMO9:12616:v:1:27500:2561:2562:0:0 -Dubai Sport Channel:12654:v:1:27500:1060:1020:0:0 -Sharjah TV :12654:v:1:27500:1160:1120:0:0 -Qatar T9:12654:v:1:27500:1260:1220:0:0 -Saudi Channel 1 :12654:v:1:27500:1360:1320:0:0 -Kuwait Space Channel :12654:v:1:27500:1460:1420:0:0 -Libya T9:12654:v:1:27500:1560:1520:0:0 -Sudan T9:12654:v:1:27500:1660:1620:0:0 -Oman T9:12654:v:1:27500:1760:1720:0:0 -Jordan Satellite Channel:12654:v:1:27500:1860:1820:0:0 -Iraq Satellite Channel:12654:v:1:27500:1960:1920:0:0 -Thai TV 5 Global Network :12673:v:1:27500:200:201:0:0 -DigItaly:12673:v:1:27500:220:221:0:0 -Studio Europa:12673:v:1:27500:230:231:0:0 -Game Network:12673:v:1:27500:291:292:0:0 -Video Italia :12673:v:1:27500:340:341:0:0 -Telemarket:12673:v:1:27500:350:351:0:0 -Evision:12673:v:1:27500:360:361:0:0 -AB Passion:12692:v:1:27500:160:80:0:0 -Onyx T9:12692:v:1:27500:161:84:0:0 -EWTN:10723:v:1:29900:1001:1201:0:0 -Test (Newslynx):10723:v:1:29900:1002:1202:0:0 -MTA International:10723:v:1:29900:1004:1204:0:0 -J TV Test:10992:v:1:27500:2436:2437:0:0 -Bloomberg UK Test Card:11242:v:1:27500:162:88:0:0 -Channel SUN Test (KBT):11604:v:1:27500:111:112:0:0 -Racing Channel Test:11623:v:1:27500:223:243:0:0 -Test Card (pgm 4):11623:v:1:27500:224:244:0:0 -Olisat TLC test card:11623:v:1:27500:225:245:0:0 -Channel SUN Test (KBT):11623:v:1:27500:229:249:0:0 -Rai way 3 test card:11766:v:1:27500:164:96:0:0 -Rai way 1 test card:11766:v:1:27500:515:653:0:0 -Rai way 2 test card:11766:v:1:27500:516:654:0:0 -Test (Local Satellite):12092:v:1:27500:4176:4177:0:0 -Retelsat Test:12092:v:1:27500:4464:4465:0:0 -AIT Test Card:12111:v:1:27500:220:221:0:0 -Fucino Test Card:12111:v:1:27500:230:231:0:0 -Espresso(Antenna Hungaria Test Card):12149:v:1:27500:36:37:0:0 -Antenna Hungaria Test Card:12149:v:1:27500:96:97:0:0 -Antenna Hungaria Test Card:12149:v:1:27500:112:113:0:0 -Leonardo (Antenna Hungaria Test):12149:v:1:27500:128:129:0:0 -Test (Sahar):12437:v:1:27500:163:86:0:0 -Test 1:12437:v:1:27500:164:88:0:0 -Test 2:12437:v:1:27500:165:90:0:0 -CNES-Toulouse test:12558:v:1:27500:6143:6142:0:0 -Test Card:12597:v:1:27500:161:84:0:0 -FEED:11242:v:1:27500:167:108:0:0 -Feed :11623:v:1:27500:221:241:0:0 -Quantum 24 :10913:v:1:3998:1160:1120:0:0 -Quantum 24:10913:v:1:3998:1160:1220:0:0 -VIVA Polska:11131:v:1:4340:98:99:0:0 -Deutsche Welle T9:11196:v:1:9096:101:102:0:0 -Canal 24 Horas :11205:v:1:4000:4130:4131:0:0 -TV 5 Asie :11338:v:1:5632:512:640:0:0 -RAI4IFA:11548:v:1:4398:512:650:0:0 -Pro TV International:12201:v:1:5632:1160:1120:0:0 -TVN Polnoc:12211:v:1:5632:4194:4195:0:0 -WorldNet Europe:12484:v:1:8298:4260:4220:0:0 -WorldNet Europe:12484:v:1:8298:4360:4320:0:0 -WorldNet Europe:12484:v:1:8298:4460:4420:0:0 -WorldNet Europe:12484:v:1:8298:4560:4520:0:0 -TVN Polnoc:12573:v:1:5632:4194:4195:0:0 -APTN:12582:v:1:5632:308:256:0:0 diff --git a/Tools/xtvrc2vdr/xtvrc.hotbird b/Tools/xtvrc2vdr/xtvrc.hotbird deleted file mode 100644 index c809eeef5..000000000 --- a/Tools/xtvrc2vdr/xtvrc.hotbird +++ /dev/null @@ -1,1337 +0,0 @@ -* -Channel: TV Polonia -Frequency: 10719 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 163 92 0 10 - -* -Channel: Credit Agricole -Frequency: 10834 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 5321 5333 0 10 - -* -Channel: La Chaine Parlementaire -Frequency: 10873 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 1020 1030 0 10 - -* -Channel: TMT -Frequency: 10892 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 163 92 0 10 - -* -Channel: Multivision Accueil -Frequency: 10911 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 320 330 0 10 - -* -Channel: RTL -Frequency: 11054 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 4 160 80 0 10 - -* -Channel: VOX -Frequency: 11054 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 4 500 501 0 10 - -* -Channel: Sat 1 A -Frequency: 11054 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 4 511 512 0 10 - -* -Channel: RTL II Austria -Frequency: 11054 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 4 520 521 0 10 - -* -Channel: NBC Europe -Frequency: 11054 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 4 550 551 0 10 - -* -Channel: ZDF -Frequency: 11054 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 4 570 571 0 10 - -* -Channel: K-T9 -Frequency: 11054 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 4 580 581 0 10 - -* -Channel: Sat 1 Schweiz -Frequency: 11604 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 4 101 102 0 10 - -* -Channel: MKT9 -Frequency: 11623 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 222 242 0 10 - -* -Channel: Olisat TV Promo -Frequency: 11623 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 226 246 0 10 - -* -Channel: Bloomberg TV Germany -Frequency: 11642 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1460 1420 0 10 - -* -Channel: Bloomberg TV UK -Frequency: 11642 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1560 1520 0 10 - -* -Channel: SAT 7 -Frequency: 11642 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1660 1620 0 10 - -* -Channel: Multivision 1 -Frequency: 11662 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 120 130 0 10 - -* -Channel: Dubai EDT9 -Frequency: 11746 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4130 4131 0 10 - -* -Channel: Dubai Sport Channel -Frequency: 11746 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4386 4387 0 10 - -* -Channel: Dubai Business Channel -Frequency: 11746 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4642 4643 0 10 - -* -Channel: Dubai EDT9 -Frequency: 11746 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4898 4899 0 10 - -* -Channel: RAI Uno -Frequency: 11766 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 160 80 0 10 - -* -Channel: RAI Due -Frequency: 11766 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 161 84 0 10 - -* -Channel: RAI Tre -Frequency: 11766 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 162 88 0 10 - -* -Channel: RAI Mosaico -Frequency: 11766 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 518 8191 0 10 - -* -Channel: RAI SportSat -Frequency: 11804 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 512 650 0 10 - -* -Channel: RAI Nettuno Sat 2 -Frequency: 11804 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 513 651 0 10 - -* -Channel: RAI Educational -Frequency: 11804 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 514 652 0 10 - -* -Channel: TelePace -Frequency: 11804 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 515 653 0 10 - -* -Channel: RAI News24 -Frequency: 11804 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 516 654 0 10 - -* -Channel: Camera dei Deputati -Frequency: 11804 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 517 655 0 10 - -* -Channel: SAT 2000 -Frequency: 11804 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 518 656 0 10 - -* -Channel: RAI NettunoSat 1 -Frequency: 11804 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 519 657 0 10 - -* -Channel: ERT Sat -Frequency: 11823 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 521 740 0 10 - -* -Channel: INT9 -Frequency: 11843 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2324 2325 0 10 - -* -Channel: TVL -Frequency: 11843 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2441 2442 0 10 - -* -Channel: Team TV -Frequency: 11881 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2305 2306 0 10 - -* -Channel: Ante Prima -Frequency: 11881 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2435 2436 0 10 - -* -Channel: SNAI -Frequency: 11881 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2561 2562 0 10 - -* -Channel: Italia 1 -Frequency: 11919 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 512 650 0 10 - -* -Channel: Canale 5 -Frequency: 11919 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 513 660 0 10 - -* -Channel: Rete 4 -Frequency: 11919 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 514 670 0 10 - -* -Channel: ART Europe -Frequency: 12015 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 164 96 0 10 - -* -Channel: ESC 2 -Frequency: 12015 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 166 104 0 10 - -* -Channel: ART Iqra -Frequency: 12015 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 168 112 0 10 - -* -Channel: Vetrina D+ -Frequency: 12034 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 166 105 0 10 - -* -Channel: D+ Info -Frequency: 12073 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 160 80 0 10 - -* -Channel: Palco Promo -Frequency: 12073 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 161 84 0 10 - -* -Channel: Vacaciones T9 -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4112 4113 0 10 - -* -Channel: TvL - TV Locale -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4160 4161 0 10 - -* -Channel: Satisfaction T9 -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4192 4193 0 10 - -* -Channel: TVE Internacional -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4208 4209 0 10 - -* -Channel: TVG - TV de Galicia -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4224 4225 0 10 - -* -Channel: La Cadena Del Milagro -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4368 4369 0 10 - -* -Channel: Fiesta -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4432 4433 0 10 - -* -Channel: Visions Europe -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4416 4417 0 10 - -* -Channel: SateliTV/TV Sex Channel -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4480 4481 0 10 - -* -Channel: Krisma -Frequency: 12111 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 200 201 0 10 - -* -Channel: NT9 -Frequency: 12111 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 210 211 0 10 - -* -Channel: Armenia TV 1 -Frequency: 12111 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 240 241 0 10 - -* -Channel: SMAU Channel -Frequency: 12111 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 260 261 0 10 - -* -Channel: JSC - Al Jazeera Satellite Ch -Frequency: 12111 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 270 271 0 10 - -* -Channel: Il Tirreno Sat -Frequency: 12111 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 280 301 0 10 - -* -Channel: Coming Soon T9 -Frequency: 12111 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 310 311 0 10 - -* -Channel: Alice -Frequency: 12149 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 160 161 0 10 - -* -Channel: Nuvolari Promo -Frequency: 12149 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 176 177 0 10 - -* -Channel: CCTV 4 -Frequency: 12169 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 516 690 0 10 - -* -Channel: Kanali Vuolis -Frequency: 12169 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 517 700 0 10 - -* -Channel: Nova Promo -Frequency: 12169 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 521 740 0 10 - -* -Channel: ERT Sat -Frequency: 12188 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 514 652 0 10 - -* -Channel: Kanali Voulis -Frequency: 12188 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 515 653 0 10 - -* -Channel: OTE Promo -Frequency: 12188 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 517 655 0 10 - -* -Channel: TV 5 Europe -Frequency: 12245 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 121 131 0 10 - -* -Channel: Fashion T9 -Frequency: 12245 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 123 133 0 10 - -* -Channel: TV Ajara -Frequency: 12245 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 127 137 0 10 - -* -Channel: Telekom T9 -Frequency: 12265 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 1460 1420 0 10 - -* -Channel: SLO-TV1 -Frequency: 12303 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 200 201 0 10 - -* -Channel: Polonia 1 -Frequency: 12303 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 205 206 0 10 - -* -Channel: Super 1 -Frequency: 12303 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 207 208 0 10 - -* -Channel: Sicilia Internacional -Frequency: 12303 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 210 211 0 10 - -* -Channel: SicilSat -Frequency: 12303 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 225 226 0 10 - -* -Channel: TBNE Italy -Frequency: 12303 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 230 231 0 10 - -* -Channel: Countdown T9 -Frequency: 12303 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 235 236 0 10 - -* -Channel: Napoli International -Frequency: 12303 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 240 241 0 10 - -* -Channel: Magic T9 -Frequency: 12303 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 245 246 0 10 - -* -Channel: TEST -Frequency: 12341 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 165 108 0 10 - -* -Channel: Colour Bars -Frequency: 12380 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 3022 3032 0 10 - -* -Channel: Tele 24 -Frequency: 12380 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 3023 3033 0 10 - -* -Channel: Abu Dhabi TV -Frequency: 12380 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 3024 3034 0 10 - -* -Channel: LCA -Frequency: 12380 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 3025 3035 0 10 - -* -Channel: RTV Montenegro -Frequency: 12380 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 3026 3036 0 10 - -* -Channel: SRG SSR Sat Access -Frequency: 12399 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 165 98 0 10 - -* -Channel: Jam-e-Jam Network 1 (IRIB 1) -Frequency: 12437 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 160 80 0 10 - -* -Channel: Jam-e-Jam Network 2 (IRIB 2) -Frequency: 12437 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 161 82 0 10 - -* -Channel: Sahar University Network -Frequency: 12437 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 162 84 0 10 - -* -Channel: Maharishi Open University -Frequency: 12476 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 42 43 0 10 - -* -Channel: Europe by Satellite -Frequency: 12476 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 101 201 0 10 - -* -Channel: Pink Backup -Frequency: 12476 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 308 256 0 10 - -* -Channel: Mizik Tropical -Frequency: 12476 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 435 436 0 10 - -* -Channel: TLI info card -Frequency: 12476 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 771 768 0 10 - -* -Channel: Liberty T9 -Frequency: 12476 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 941 942 0 10 - -* -Channel: HRT TV 1 -Frequency: 12520 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 100 101 0 10 - -* -Channel: HRT National -Frequency: 12520 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 107 108 0 10 - -* -Channel: BVN TV -Frequency: 12520 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 210 211 0 10 - -* -Channel: Sicilia International -Frequency: 12520 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 501 502 0 10 - -* -Channel: Sardegna Uno -Frequency: 12520 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 503 504 0 10 - -* -Channel: TGRT -Frequency: 12520 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 505 506 0 10 - -* -Channel: Euro Mediterraneo -Frequency: 12520 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 510 511 0 10 - -* -Channel: WWWTravel T9 -Frequency: 12540 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1180 1183 0 10 - -* -Channel: WWWTravel T9 -Frequency: 12540 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1180 1184 0 10 - -* -Channel: WWWTravel T9 -Frequency: 12540 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1180 1185 0 10 - -* -Channel: Bulgaria T9 -Frequency: 12540 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4612 4613 0 10 - -* -Channel: MC Sat Monte Carlo -Frequency: 12540 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 5126 5122 0 10 - -* -Channel: MBC -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 160 80 0 10 - -* -Channel: SIMA-YEH-MOGHAVEMENT -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 161 84 0 10 - -* -Channel: NITV (National Iran TV ) -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 163 92 0 10 - -* -Channel: BET International -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 167 108 0 10 - -* -Channel: JSTV 2 Info Card -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2011 2012 0 10 - -* -Channel: EuroNews -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2221 2231 0 10 - -* -Channel: EuroNews -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2221 2232 0 10 - -* -Channel: EuroNews -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2221 2233 0 10 - -* -Channel: EuroNews -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2221 2234 0 10 - -* -Channel: EuroNews -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2221 2235 0 10 - -* -Channel: EuroNews -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2221 2236 0 10 - -* -Channel: EuroNews -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2221 2237 0 10 - -* -Channel: Canal Agro Rual -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2321 2331 0 10 - -* -Channel: MMO9 -Frequency: 12616 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 2561 2562 0 10 - -* -Channel: Dubai Sport Channel -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1060 1020 0 10 - -* -Channel: Sharjah TV -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1160 1120 0 10 - -* -Channel: Qatar T9 -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1260 1220 0 10 - -* -Channel: Saudi Channel 1 -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1360 1320 0 10 - -* -Channel: Kuwait Space Channel -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1460 1420 0 10 - -* -Channel: Libya T9 -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1560 1520 0 10 - -* -Channel: Sudan T9 -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1660 1620 0 10 - -* -Channel: Oman T9 -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1760 1720 0 10 - -* -Channel: Jordan Satellite Channel -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1860 1820 0 10 - -* -Channel: Iraq Satellite Channel -Frequency: 12654 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 1960 1920 0 10 - -* -Channel: Thai TV 5 Global Network -Frequency: 12673 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 200 201 0 10 - -* -Channel: DigItaly -Frequency: 12673 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 220 221 0 10 - -* -Channel: Studio Europa -Frequency: 12673 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 230 231 0 10 - -* -Channel: Game Network -Frequency: 12673 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 291 292 0 10 - -* -Channel: Video Italia -Frequency: 12673 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 340 341 0 10 - -* -Channel: Telemarket -Frequency: 12673 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 350 351 0 10 - -* -Channel: Evision -Frequency: 12673 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 360 361 0 10 - -* -Channel: AB Passion -Frequency: 12692 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 160 80 0 10 - -* -Channel: Onyx T9 -Frequency: 12692 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 161 84 0 10 - -* -Channel: EWTN -Frequency: 10723 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 29900 2 1001 1201 0 10 - -* -Channel: Test (Newslynx) -Frequency: 10723 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 29900 2 1002 1202 0 10 - -* -Channel: MTA International -Frequency: 10723 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 29900 2 1004 1204 0 10 - -* -Channel: J TV Test -Frequency: 10992 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 2436 2437 0 10 - -* -Channel: Bloomberg UK Test Card -Frequency: 11242 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 162 88 0 10 - -* -Channel: Channel SUN Test (KBT) -Frequency: 11604 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 4 111 112 0 10 - -* -Channel: Racing Channel Test -Frequency: 11623 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 223 243 0 10 - -* -Channel: Test Card (pgm 4) -Frequency: 11623 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 224 244 0 10 - -* -Channel: Olisat TLC test card -Frequency: 11623 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 225 245 0 10 - -* -Channel: Channel SUN Test (KBT) -Frequency: 11623 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 229 249 0 10 - -* -Channel: Rai way 3 test card -Frequency: 11766 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 164 96 0 10 - -* -Channel: Rai way 1 test card -Frequency: 11766 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 515 653 0 10 - -* -Channel: Rai way 2 test card -Frequency: 11766 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 1 516 654 0 10 - -* -Channel: Test (Local Satellite) -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4176 4177 0 10 - -* -Channel: Retelsat Test -Frequency: 12092 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 4464 4465 0 10 - -* -Channel: AIT Test Card -Frequency: 12111 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 220 221 0 10 - -* -Channel: Fucino Test Card -Frequency: 12111 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 230 231 0 10 - -* -Channel: Espresso(Antenna Hungaria Test Card) -Frequency: 12149 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 36 37 0 10 - -* -Channel: Antenna Hungaria Test Card -Frequency: 12149 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 96 97 0 10 - -* -Channel: Antenna Hungaria Test Card -Frequency: 12149 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 112 113 0 10 - -* -Channel: Leonardo (Antenna Hungaria Test) -Frequency: 12149 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 128 129 0 10 - -* -Channel: Test (Sahar) -Frequency: 12437 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 163 86 0 10 - -* -Channel: Test 1 -Frequency: 12437 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 164 88 0 10 - -* -Channel: Test 2 -Frequency: 12437 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 27500 2 165 90 0 10 - -* -Channel: CNES-Toulouse test -Frequency: 12558 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 6143 6142 0 10 - -* -Channel: Test Card -Frequency: 12597 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 161 84 0 10 - -* -Channel: FEED -Frequency: 11242 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 167 108 0 10 - -* -Channel: Feed -Frequency: 11623 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 27500 2 221 241 0 10 - -* -Channel: Quantum 24 -Frequency: 10913 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 3998 0 1160 1120 0 10 - -* -Channel: Quantum 24 -Frequency: 10913 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 3998 0 1160 1220 0 10 - -* -Channel: VIVA Polska -Frequency: 11131 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 4340 2 98 99 0 10 - -* -Channel: Deutsche Welle T9 -Frequency: 11196 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 9096 0 101 102 0 10 - -* -Channel: Canal 24 Horas -Frequency: 11205 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 4000 2 4130 4131 0 10 - -* -Channel: TV 5 Asie -Frequency: 11338 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 5632 2 512 640 0 10 - -* -Channel: RAI4IFA -Frequency: 11548 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 4398 6 512 650 0 10 - -* -Channel: Pro TV International -Frequency: 12201 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 5632 6 1160 1120 0 10 - -* -Channel: TVN Polnoc -Frequency: 12211 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 5632 2 4194 4195 0 10 - -* -Channel: WorldNet Europe -Frequency: 12484 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 8298 2 4260 4220 0 10 - -* -Channel: WorldNet Europe -Frequency: 12484 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 8298 2 4360 4320 0 10 - -* -Channel: WorldNet Europe -Frequency: 12484 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 8298 2 4460 4420 0 10 - -* -Channel: WorldNet Europe -Frequency: 12484 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 9 8298 2 4560 4520 0 10 - -* -Channel: TVN Polnoc -Frequency: 12573 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 5632 2 4194 4195 0 10 - -* -Channel: APTN -Frequency: 12582 -CBHC: 255 0 0 255 -NI: -1 0 -SAT: 10 5632 2 308 256 0 10 - diff --git a/Tools/xtvrc2vdr/xtvrc2vdr.c b/Tools/xtvrc2vdr/xtvrc2vdr.c deleted file mode 100644 index 772db66a9..000000000 --- a/Tools/xtvrc2vdr/xtvrc2vdr.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * * xtvrc2vdr.c: Converts 'xtvrc' files to 'vdr' channel format - * * - * * Copyright (C) 2000 Plamen Ganev - * * - * * This program is free software; you can redistribute it and/or - * * modify it under the terms of the GNU General Public License - * * as published by the Free Software Foundation; either version 2 - * * of the License, or (at your option) any later version. - * * - * * This program is distributed in the hope that it will be useful, - * * but WITHOUT ANY WARRANTY; without even the implied warranty of - * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * * GNU General Public License for more details. - * * - * * You should have received a copy of the GNU General Public License - * * along with this program; if not, write to the Free Software - * * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * * - * * The author can be reached at pganev@comm.it - * * - * */ - - -#include -#include -#include -#include - -#define MAX_LINE_LEN 1024 -#define MAX_NAME 100 -#define TOKS ": \n\r" -#define NAMETOKS ":\n\r" - -typedef struct { - char Name[MAX_NAME+1]; - int freq; - int color, hue, bright, saturation ; - int nitv, input ; - int pol, srate, fec, vpid, apid, lnbnum, type; -} CHANNEL_DATA ; - -void strlwr( char *s ){ - while ( s && *s ){ - *s = tolower(*s); - s++; - } -} - -int ReadChannel( FILE *f, CHANNEL_DATA *channel ) { - static char s[MAX_LINE_LEN+1]; - char *p; - - memset( channel, sizeof( CHANNEL_DATA ), 0 ) ; - - while ((p=fgets( s, MAX_LINE_LEN, f ))!=NULL){ -// printf("%s", s ) ; - if (s[0] == '*') - break ; - } - - if ( !p ) { /* EOF? */ -// printf("EOF\n"); - return 0 ; - } - - while (fgets( s, MAX_LINE_LEN, f )){ - if ( s[0] == '\n' ) - return channel->freq ? 1 : 0; - p = strtok( s, TOKS ) ; - if ( !p ) { - return 0; - } - strlwr( p ) ; - if ( !strcmp( p, "channel" )){ - p=strtok( NULL, NAMETOKS ); - while ( p && *p==' ') - p++; - strcpy( channel->Name, p ); -// printf("%d ", channel->freq ) ; - } else if ( !strcmp( p, "frequency")) { - channel->freq = atoi( p=strtok( NULL, TOKS )); -// printf("%d ", channel->freq ) ; - } else if ( !strcmp( p, "cbhc")) { - channel->color = atoi(p=strtok(NULL,TOKS)); - channel->hue = atoi(p=strtok(NULL,TOKS)); - channel->bright = atoi(p=strtok(NULL,TOKS)); - channel->saturation = atoi(p=strtok(NULL,TOKS)); - } else if ( !strcmp( p, "ni")) { - channel->nitv = atoi(p=strtok(NULL,TOKS)); - channel->input = atoi(p=strtok(NULL,TOKS)); - } else if ( !strcmp( p, "sat")) { - channel->pol = atoi(p=strtok(NULL,TOKS)); - channel->srate = atoi(p=strtok(NULL,TOKS)); - channel->fec = atoi(p=strtok(NULL,TOKS)); - channel->vpid = atoi(p=strtok(NULL,TOKS)); - channel->apid = atoi(p=strtok(NULL,TOKS)); - channel->lnbnum = atoi(p=strtok(NULL,TOKS)); - channel->type = atoi(p=strtok(NULL,TOKS)); - } else - printf("Unknown token %s\n", p ) ; - } - return 1 ; -} - -int main ( int argc, char *argv[] ){ - FILE *f, *fo ; - int cnt = 0; - CHANNEL_DATA channel ; - - if ( argc != 3 ){ - printf("USAGE: %s \n\n", argv[0] ) ; - return 0; - } - - if ( !(f=fopen(argv[1], "rt"))){ - printf("Can't open %s for reading\n\n", argv[1]); - return 0; - } - - if ( !(fo=fopen(argv[2], "wt"))){ - printf("Can't open %s for writing\n\n", argv[2]); - return 0; - } - - while ( ReadChannel( f, &channel ) ) { - cnt++; - fprintf(fo, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", - channel.Name , - channel.freq , - channel.pol ? 'v' : 'h' , - 1, //channel.lnbnum , - channel.srate , - channel.vpid , - channel.apid , - 0, //channel.type , - 0 ); //channel.fec ) ; - } - - printf( "%d channels read.\n\n", cnt ) ; - - fclose(f); - fclose(fo); - return 1; -} diff --git a/channels.conf b/channels.conf index 2cc3975f5..a2bd32fb1 100644 --- a/channels.conf +++ b/channels.conf @@ -22,7 +22,7 @@ ZDF.info:11954:h:0:27500:610:620:0:0:28011 CNN:12168:v:0:27500:165:100:0:0:28512 Super RTL:12188:h:0:27500:165:120:65:0:12040 VOX:12188:h:0:27500:167:136:0:0:12060 -DW TV:12363:v:0:27500:305:306:0:0:8905 +DW TV:10788:v:0:22000:305:306:0:0:8905 Kabel 1:12480:v:0:27500:511:512:33:0:899 Neun Live:12480:v:0:27500:767:768:0:0:897 DSF:12480:v:0:27500:1023:1024:0:0:900 @@ -80,7 +80,7 @@ Cinedom 1A:11758:h:0:27500:511:512,513:0:3:190 Cinedom 1B:12070:h:0:27500:1535:1536,1537:0:3:178 Cinedom 1C:11720:h:0:27500:511:512,513:0:3:180 Cinedom 1D:11720:h:0:27500:1535:1536,1537:0:3:176 -Cinedom 2A:11758:h:0:27500:1023:1024:0:3:193 +Cinedom 2A:11758:h:0:27500:1023:1024,1025:0:3:193 Cinedom 2B:11720:h:0:27500:1279:1280:0:3:183 Cinedom 2C:12070:h:0:27500:1791:1792:0:3:179 Cinedom 2D:12070:h:0:27500:511:512:0:3:184 diff --git a/channels.conf.cable b/channels.conf.cable index 6e0f43b70..b6d5c050a 100644 --- a/channels.conf.cable +++ b/channels.conf.cable @@ -1,6 +1,6 @@ :verschlsselte Fernsehprogramm PREMIERE ONE:378:h:0:6900:3071:3072:0:1:51 -PREMIERE MOVIE 1:370:h:0:6900:511:512:0:1:10 +PREMIERE MOVIE 1:370:h:0:6900:511:512;515:0:1:10 PREMIERE MOVIE 2:370:h:0:6900:1791:1792:0:1:11 PREMIERE MOVIE 3:370:h:0:6900:2303:2304:0:1:43 PREMIERE ACTION:370:h:0:6900:1023:1024,1025:0:1:20 diff --git a/config.c b/config.c index 6ebaaacb9..f93035142 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.76 2001/10/20 13:09:38 kls Exp $ + * $Id: config.c 1.77 2002/01/19 16:06:42 kls Exp $ */ #include "config.h" @@ -807,6 +807,7 @@ cSetup::cSetup(void) DefaultPriority = 50; DefaultLifetime = 50; UseSubtitle = 1; + RecordingDirs = 1; VideoFormat = VIDEO_FORMAT_4_3; ChannelInfoPos = 0; OSDwidth = 52; @@ -848,6 +849,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); + else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); @@ -924,6 +926,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "DefaultPriority = %d\n", DefaultPriority); fprintf(f, "DefaultLifetime = %d\n", DefaultLifetime); fprintf(f, "UseSubtitle = %d\n", UseSubtitle); + fprintf(f, "RecordingDirs = %d\n", RecordingDirs); fprintf(f, "VideoFormat = %d\n", VideoFormat); fprintf(f, "ChannelInfoPos = %d\n", ChannelInfoPos); fprintf(f, "OSDwidth = %d\n", OSDwidth); diff --git a/config.h b/config.h index 018d00ef2..960e51465 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.86 2001/11/25 15:57:08 kls Exp $ + * $Id: config.h 1.88 2002/01/19 16:06:53 kls Exp $ */ #ifndef __CONFIG_H @@ -18,7 +18,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.99" +#define VDRVERSION "0.99pre2" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -292,6 +292,7 @@ class cSetup { int PrimaryLimit; int DefaultPriority, DefaultLifetime; int UseSubtitle; + int RecordingDirs; int VideoFormat; int ChannelInfoPos; int OSDwidth, OSDheight; diff --git a/dvbapi.c b/dvbapi.c index 707db0d92..048639c66 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz * based on dvdplayer-0.5 by Matjaz Thaler * - * $Id: dvbapi.c 1.141 2001/11/25 16:38:09 kls Exp $ + * $Id: dvbapi.c 1.146 2002/01/26 15:39:48 kls Exp $ */ //#define DVDDEBUG 1 @@ -116,7 +116,7 @@ class cIndexFile { cIndexFile(const char *FileName, bool Record); ~cIndexFile(); bool Ok(void) { return index != NULL; } - void Write(uchar PictureType, uchar FileNumber, int FileOffset); + bool Write(uchar PictureType, uchar FileNumber, int FileOffset); bool Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType = NULL, int *Length = NULL); int GetNextIFrame(int Index, bool Forward, uchar *FileNumber = NULL, int *FileOffset = NULL, int *Length = NULL, bool StayOffEnd = false); int Get(uchar FileNumber, int FileOffset); @@ -146,7 +146,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) delta = buf.st_size % sizeof(tIndex); if (delta) { delta = sizeof(tIndex) - delta; - esyslog(LOG_ERR, "ERROR: invalid file size (%d) in '%s'", buf.st_size, fileName); + esyslog(LOG_ERR, "ERROR: invalid file size (%ld) in '%s'", buf.st_size, fileName); } last = (buf.st_size + delta) / sizeof(tIndex) - 1; if (!Record && last >= 0) { @@ -249,7 +249,7 @@ bool cIndexFile::CatchUp(int Index) return false; } -void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) +bool cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) { if (f >= 0) { tIndex i = { FileOffset, PictureType, FileNumber, 0 }; @@ -257,10 +257,11 @@ void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) esyslog(LOG_ERR, "ERROR: can't write to index file"); close(f); f = -1; - return; + return false; } last++; } + return f >= 0; } bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType, int *Length) @@ -506,7 +507,7 @@ cRecordBuffer::~cRecordBuffer() bool cRecordBuffer::RunningLowOnDiskSpace(void) { if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) { - uint Free = FreeDiskSpaceMB(fileName.Name()); + int Free = FreeDiskSpaceMB(fileName.Name()); lastDiskSpaceCheck = time(NULL); if (Free < MINFREEDISKSPACE) { dsyslog(LOG_INFO, "low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE); @@ -2305,6 +2306,7 @@ void cTransferBuffer::Output(void) class cCuttingBuffer : public cThread { private: + const char *error; bool active; int fromFile, toFile; cFileName *fromFileName, *toFileName; @@ -2315,10 +2317,12 @@ class cCuttingBuffer : public cThread { public: cCuttingBuffer(const char *FromFileName, const char *ToFileName); virtual ~cCuttingBuffer(); + const char *Error(void) { return error; } }; cCuttingBuffer::cCuttingBuffer(const char *FromFileName, const char *ToFileName) { + error = NULL; active = false; fromFile = toFile = -1; fromFileName = toFileName = NULL; @@ -2367,6 +2371,10 @@ void cCuttingBuffer::Action(void) int FileOffset, Length; uchar PictureType; + // Make sure there is enough disk space: + + AssertFreeDiskSpace(); + // Read one frame: if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { @@ -2376,11 +2384,15 @@ void cCuttingBuffer::Action(void) } if (fromFile >= 0) { Length = ReadFrame(fromFile, buffer, Length, sizeof(buffer)); - if (Length < 0) + if (Length < 0) { + error = "ReadFrame"; break; + } } - else + else { + error = "fromFile"; break; + } } else break; @@ -2392,14 +2404,22 @@ void cCuttingBuffer::Action(void) break; if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) { toFile = toFileName->NextFile(); - if (toFile < 0) + if (toFile < 0) { + error = "toFile 1"; break; + } FileSize = 0; } LastIFrame = 0; } - safe_write(toFile, buffer, Length); - toIndex->Write(PictureType, toFileName->Number(), FileSize); + if (safe_write(toFile, buffer, Length) != Length) { + error = "safe_write"; + break; + } + if (!toIndex->Write(PictureType, toFileName->Number(), FileSize)) { + error = "toIndex"; + break; + } FileSize += Length; if (!LastIFrame) LastIFrame = toIndex->Last(); @@ -2418,8 +2438,10 @@ void cCuttingBuffer::Action(void) CurrentFileNumber = 0; // triggers SetOffset before reading next frame if (Setup.SplitEditedFiles) { toFile = toFileName->NextFile(); - if (toFile < 0) + if (toFile < 0) { + error = "toFile 2"; break; + } FileSize = 0; } } @@ -2438,10 +2460,14 @@ void cCuttingBuffer::Action(void) char *cVideoCutter::editedVersionName = NULL; cCuttingBuffer *cVideoCutter::cuttingBuffer = NULL; +bool cVideoCutter::error = false; +bool cVideoCutter::ended = false; bool cVideoCutter::Start(const char *FileName) { if (!cuttingBuffer) { + error = false; + ended = false; cRecording Recording(FileName); const char *evn = Recording.PrefixFileName('%'); if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { @@ -2456,8 +2482,17 @@ bool cVideoCutter::Start(const char *FileName) void cVideoCutter::Stop(void) { + bool Interrupted = cuttingBuffer && cuttingBuffer->Active(); + const char *Error = cuttingBuffer ? cuttingBuffer->Error() : NULL; delete cuttingBuffer; cuttingBuffer = NULL; + if ((Interrupted || Error) && editedVersionName) { + if (Interrupted) + isyslog(LOG_INFO, "editing process has been interrupted"); + if (Error) + esyslog(LOG_ERR, "ERROR: '%s' during editing process", Error); + RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? + } } bool cVideoCutter::Active(void) @@ -2465,16 +2500,32 @@ bool cVideoCutter::Active(void) if (cuttingBuffer) { if (cuttingBuffer->Active()) return true; + error = cuttingBuffer->Error(); Stop(); - cRecordingUserCommand::InvokeCommand(RUC_EDITEDRECORDING, editedVersionName); + if (!error) + cRecordingUserCommand::InvokeCommand(RUC_EDITEDRECORDING, editedVersionName); delete editedVersionName; editedVersionName = NULL; + ended = true; } return false; } -// --- cDvbApi --------------------------------------------------------------- +bool cVideoCutter::Error(void) +{ + bool result = error; + error = false; + return result; +} +bool cVideoCutter::Ended(void) +{ + bool result = ended; + ended = false; + return result; +} + +// --- cDvbApi --------------------------------------------------------------- static const char *OstName(const char *Name, int n) { @@ -2842,7 +2893,11 @@ void cDvbApi::Open(int w, int h) } else if (d == 0) { //XXX full menu osd->Create(0, 0, w, lineHeight, 2); - osd->Create(0, lineHeight, w, (Setup.OSDheight - 3) * lineHeight, 2, true, clrBackground, clrCyan, clrWhite, clrBlack); + osd->Create(0, lineHeight, w, (Setup.OSDheight - 3) * lineHeight, 2); + osd->AddColor(clrBackground); + osd->AddColor(clrCyan); + osd->AddColor(clrWhite); + osd->AddColor(clrBlack); osd->Create(0, (Setup.OSDheight - 2) * lineHeight, w, 2 * lineHeight, 4); } else { //XXX progress display @@ -3197,7 +3252,7 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int Frequency, char Pol } } else - esyslog(LOG_ERR, "ERROR %d in frontend get event", res); + esyslog(LOG_ERR, "ERROR %d in frontend get event (channel %d, card %d)", res, ChannelNumber, CardIndex() + 1); } else esyslog(LOG_ERR, "ERROR: timeout while tuning"); diff --git a/dvbapi.h b/dvbapi.h index aa4a5feb2..733757195 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.59 2001/11/24 11:03:16 kls Exp $ + * $Id: dvbapi.h 1.60 2002/01/26 13:01:16 kls Exp $ */ #ifndef __DVBAPI_H @@ -69,10 +69,14 @@ class cVideoCutter { private: static char *editedVersionName; static cCuttingBuffer *cuttingBuffer; + static bool error; + static bool ended; public: static bool Start(const char *FileName); static void Stop(void); static bool Active(void); + static bool Error(void); + static bool Ended(void); }; class cDvbApi { diff --git a/dvbosd.c b/dvbosd.c index 90ac067dc..c34843005 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.10 2001/07/24 16:25:34 kls Exp $ + * $Id: dvbosd.c 1.12 2002/01/13 16:25:18 kls Exp $ */ #include "dvbosd.h" @@ -257,25 +257,35 @@ const char *cBitmap::Data(int x, int y) class cWindow : public cBitmap { private: + int handle; // the index within the OSD's window array (0...MAXNUMWINDOWS - 1) int x0, y0; + int bpp; + bool tiled; bool shown; public: - cWindow(int x, int y, int w, int h, int Bpp, bool ClearWithBackground = true); + cWindow(int Handle, int x, int y, int w, int h, int Bpp, bool ClearWithBackground, bool Tiled); int X0(void) { return x0; } int Y0(void) { return y0; } + int Bpp(void) { return bpp; } + bool Tiled(void) { return tiled; } bool Shown(void) { bool s = shown; shown = true; return s; } + int Handle(void) { return handle; } bool Contains(int x, int y); + void Relocate(int x, int y); void Fill(int x1, int y1, int x2, int y2, eDvbColor Color); void SetBitmap(int x, int y, const cBitmap &Bitmap); void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); const char *Data(int x, int y); }; -cWindow::cWindow(int x, int y, int w, int h, int Bpp, bool ClearWithBackground) +cWindow::cWindow(int Handle, int x, int y, int w, int h, int Bpp, bool ClearWithBackground, bool Tiled) :cBitmap(w, h, Bpp, ClearWithBackground) { + handle = Handle; x0 = x; y0 = y; + bpp = Bpp; + tiled = Tiled; shown = false; } @@ -286,19 +296,39 @@ bool cWindow::Contains(int x, int y) return x >= 0 && y >= 0 && x < width && y < height; } +void cWindow::Relocate(int x, int y) +{ + x0 = x; + y0 = y; +} + void cWindow::Fill(int x1, int y1, int x2, int y2, eDvbColor Color) { - cBitmap::Fill(x1 - x0, y1 - y0, x2 - x0, y2 - y0, Color); + if (tiled) { + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + } + cBitmap::Fill(x1, y1, x2, y2, Color); } void cWindow::SetBitmap(int x, int y, const cBitmap &Bitmap) { - cBitmap::SetBitmap(x - x0, y - y0, Bitmap); + if (tiled) { + x -= x0; + y -= y0; + } + cBitmap::SetBitmap(x, y, Bitmap); } void cWindow::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) { - cBitmap::Text(x - x0, y - y0, s, ColorFg, ColorBg); + if (tiled) { + x -= x0; + y -= y0; + } + cBitmap::Text(x, y, s, ColorFg, ColorBg); } const char *cWindow::Data(int x, int y) @@ -325,14 +355,28 @@ cDvbOsd::cDvbOsd(int VideoDev, int x, int y, int w, int h, int Bpp) cDvbOsd::~cDvbOsd() { if (videoDev >= 0) { - while (numWindows > 0) { - Cmd(OSD_SetWindow, 0, numWindows--); - Cmd(OSD_Close); - delete window[numWindows]; - } + for (int i = 0; i < numWindows; i++) { + SetWindow(window[i]); + Cmd(OSD_Close); + delete window[i]; + } + numWindows = 0; } } +bool cDvbOsd::SetWindow(cWindow *Window) +{ + // Window handles are counted 0...(MAXNUMWINDOWS - 1), but the actual window + // numbers in the driver are used from 1...MAXNUMWINDOWS. + int Handle = Window->Handle(); + if (0 <= Handle && Handle < MAXNUMWINDOWS) { + Cmd(OSD_SetWindow, 0, Handle + 1); + return true; + } + esyslog(LOG_ERR, "ERROR: illegal window handle: %d", Handle); + return -1; +} + void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) { if (videoDev >= 0) { @@ -347,62 +391,77 @@ void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co // must block all signals, otherwise the command might not be fully executed sigset_t set, oldset; sigfillset(&set); + sigdelset(&set, SIGALRM); sigprocmask(SIG_BLOCK, &set, &oldset); ioctl(videoDev, OSD_SEND_CMD, &dc); - usleep(5000); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places - // XXX and sometimes the OSD was no longer displayed). - // XXX Increase the value if the problem still persists on your particular system. - // TODO Check if this is still necessary with driver versions after 0.7. + if (cmd == OSD_SetBlock) // XXX this is the only command that takes longer + usleep(5000); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places + // XXX and sometimes the OSD was no longer displayed). + // XXX Increase the value if the problem still persists on your particular system. + // TODO Check if this is still necessary with driver versions after 0.7. sigprocmask(SIG_SETMASK, &oldset, NULL); } } -bool cDvbOsd::Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground, eDvbColor Color0, eDvbColor Color1, eDvbColor Color2, eDvbColor Color3) +tWindowHandle cDvbOsd::Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground, bool Tiled) { - /* TODO XXX - - check that no two windows overlap - */ if (numWindows < MAXNUMWINDOWS) { if (x >= 0 && y >= 0 && w > 0 && h > 0 && (Bpp == 1 || Bpp == 2 || Bpp == 4 || Bpp == 8)) { if ((w & 0x03) != 0) { w += 4 - (w & 0x03); esyslog(LOG_ERR, "ERROR: OSD window width must be a multiple of 4 - increasing to %d", w); } - cWindow *win = new cWindow(x, y, w, h, Bpp, ClearWithBackground); - if (Color0 != clrTransparent) { - win->Index(Color0); - win->Index(Color1); - win->Index(Color2); - win->Index(Color3); - win->Reset(); + cWindow *win = new cWindow(numWindows, x, y, w, h, Bpp, ClearWithBackground, Tiled); + if (SetWindow(win)) { + window[win->Handle()] = win; + Cmd(OSD_Open, Bpp, x0 + x, y0 + y, x0 + x + w - 1, y0 + y + h - 1, (void *)1); // initially hidden! + numWindows++; + return win->Handle(); } - window[numWindows++] = win; - Cmd(OSD_SetWindow, 0, numWindows); - Cmd(OSD_Open, Bpp, x0 + x, y0 + y, x0 + x + w - 1, y0 + y + h - 1, (void *)1); // initially hidden! + else + delete win; } else esyslog(LOG_ERR, "ERROR: illegal OSD parameters"); } else esyslog(LOG_ERR, "ERROR: too many OSD windows"); - return false; + return -1; +} + +void cDvbOsd::AddColor(eDvbColor Color, tWindowHandle Window) +{ + cWindow *w = GetWindow(Window); + if (w) { + w->Index(Color); + w->Reset(); + } } cWindow *cDvbOsd::GetWindow(int x, int y) { for (int i = 0; i < numWindows; i++) { - if (window[i]->Contains(x, y)) + if (window[i]->Tiled() && window[i]->Contains(x, y)) return window[i]; } return NULL; } +cWindow *cDvbOsd::GetWindow(tWindowHandle Window) +{ + if (0 <= Window && Window < numWindows) + return window[Window]; + if (Window == LAST_CREATED_WINDOW && numWindows > 0) + return window[numWindows - 1]; + return NULL; +} + void cDvbOsd::Flush(void) { for (int i = 0; i < numWindows; i++) { int x1 = 0, y1 = 0, x2 = 0, y2 = 0; if (window[i]->Dirty(x1, y1, x2, y2)) { - Cmd(OSD_SetWindow, 0, i + 1); + SetWindow(window[i]); int FirstColor = 0, LastColor = 0; const eDvbColor *pal; while ((pal = window[i]->Colors(FirstColor, LastColor)) != NULL) @@ -414,28 +473,36 @@ void cDvbOsd::Flush(void) // Showing the windows in a separate loop to avoid seeing them come up one after another for (int i = 0; i < numWindows; i++) { if (!window[i]->Shown()) { - Cmd(OSD_SetWindow, 0, i + 1); + SetWindow(window[i]); Cmd(OSD_MoveWindow, 0, x0 + window[i]->X0(), y0 + window[i]->Y0()); } } } -void cDvbOsd::Clear(void) +void cDvbOsd::Clear(tWindowHandle Window) { - for (int i = 0; i < numWindows; i++) - window[i]->Clear(); + if (Window == ALL_TILED_WINDOWS || Window == ALL_WINDOWS) { + for (int i = 0; i < numWindows; i++) + if (Window == ALL_WINDOWS || window[i]->Tiled()) + window[i]->Clear(); + } + else { + cWindow *w = GetWindow(Window); + if (w) + w->Clear(); + } } -void cDvbOsd::Fill(int x1, int y1, int x2, int y2, eDvbColor Color) +void cDvbOsd::Fill(int x1, int y1, int x2, int y2, eDvbColor Color, tWindowHandle Window) { - cWindow *w = GetWindow(x1, y1); + cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x1, y1) : GetWindow(Window); if (w) w->Fill(x1, y1, x2, y2, Color); } -void cDvbOsd::SetBitmap(int x, int y, const cBitmap &Bitmap) +void cDvbOsd::SetBitmap(int x, int y, const cBitmap &Bitmap, tWindowHandle Window) { - cWindow *w = GetWindow(x, y); + cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x, y) : GetWindow(Window); if (w) w->SetBitmap(x, y, Bitmap); } @@ -458,10 +525,44 @@ eDvbFont cDvbOsd::SetFont(eDvbFont Font) return oldFont; } -void cDvbOsd::Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground) +void cDvbOsd::Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground, tWindowHandle Window) { - cWindow *w = GetWindow(x, y); + cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x, y) : GetWindow(Window); if (w) w->Text(x, y, s, ColorFg, ColorBg); } +void cDvbOsd::Relocate(tWindowHandle Window, int x, int y, int NewWidth, int NewHeight) +{ + cWindow *w = GetWindow(Window); + if (w) { + SetWindow(w); + if (NewWidth > 0 && NewHeight > 0) { + if ((NewWidth & 0x03) != 0) { + NewWidth += 4 - (NewWidth & 0x03); + esyslog(LOG_ERR, "ERROR: OSD window width must be a multiple of 4 - increasing to %d", NewWidth); + } + Cmd(OSD_Close); + window[w->Handle()] = new cWindow(w->Handle(), x, y, NewWidth, NewHeight, w->Bpp(), w->ClearWithBackground(), w->Tiled()); + delete w; + Cmd(OSD_Open, 2, x0 + x, y0 + y, x0 + x + NewWidth - 1, y0 + y + NewHeight - 1, (void *)1); // initially hidden! + } + else { + w->Relocate(x, y); + Cmd(OSD_MoveWindow, 0, x0 + x, y0 + y); + } + } +} + +void cDvbOsd::Hide(tWindowHandle Window) +{ + if (SetWindow(GetWindow(Window))) + Cmd(OSD_Hide, 0); +} + +void cDvbOsd::Show(tWindowHandle Window) +{ + if (SetWindow(GetWindow(Window))) + Cmd(OSD_Show, 0); +} + diff --git a/dvbosd.h b/dvbosd.h index 5039a9159..ceac507d3 100644 --- a/dvbosd.h +++ b/dvbosd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.h 1.8 2001/07/28 16:22:32 kls Exp $ + * $Id: dvbosd.h 1.9 2001/12/09 15:11:05 kls Exp $ */ #ifndef __DVBOSD_H @@ -75,6 +75,7 @@ class cBitmap : public cPalette { public: cBitmap(int Width, int Height, int Bpp, bool ClearWithBackground = true); virtual ~cBitmap(); + bool ClearWithBackground(void) { return clearWithBackground; } eDvbFont SetFont(eDvbFont Font); bool Dirty(int &x1, int &y1, int &x2, int &y2); void SetPixel(int x, int y, eDvbColor Color); @@ -93,26 +94,84 @@ class cBitmap : public cPalette { class cWindow; +typedef int tWindowHandle; + +// '-1' is used as an error return value! +#define ALL_WINDOWS (-2) +#define ALL_TILED_WINDOWS (-3) +#define LAST_CREATED_WINDOW (-4) + class cDvbOsd { private: int videoDev; int numWindows; int x0, y0; cWindow *window[MAXNUMWINDOWS]; + bool SetWindow(cWindow *Window); void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL); cWindow *GetWindow(int x, int y); + cWindow *GetWindow(tWindowHandle Window); public: cDvbOsd(int VideoDev, int x, int y, int w = -1, int h = -1, int Bpp = -1); + // Initializes the OSD on the given VideoDev, starting at screen coordinates + // (x, y). If w, h and Bpp are given, one window with that width, height and + // color depth will be created - otherwise the actual windows will have to + // be created by separate calls to Create(). ~cDvbOsd(); - bool Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground = true, eDvbColor Color0 = clrTransparent, eDvbColor Color1 = clrTransparent, eDvbColor Color2 = clrTransparent, eDvbColor Color3 = clrTransparent); + // Destroys all windows and shuts down the OSD. + tWindowHandle Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground = true, bool Tiled = true); + // Creates a window at coordinates (x, y), which are relative to the OSD's + // origin given in the constructor, with the given width, height and color + // depth. ClearWithBackground controls whether the window will be filled with + // clrBackground when it is cleared. Setting this to 'false' may be useful + // for windows that don't need clrBackground but want to save this color + // palette entry for a different color. Tiled controls whether this will + // be part of a multi section OSD (with several windows that all have + // different color depths and palettes and form one large OSD area), or + // whether this is a "standalone" window that will be drawn "in front" + // of any windows defined *after* this one (this can be used for highlighting + // certain parts of the OSD, as would be done in a 'cursor'). + // Returns a handle that can be used to identify this window. + void AddColor(eDvbColor Color, tWindowHandle Window = LAST_CREATED_WINDOW); + // Adds the Color to the color palette of the given window if it is not + // already contained in the palette (and if the palette still has free + // slots for new colors). The default value LAST_CREATED_WINDOW will + // access the most recently created window, without the need of explicitly + // using a window handle. void Flush(void); - void Clear(void); - void Fill(int x1, int y1, int x2, int y2, eDvbColor Color); - void SetBitmap(int x, int y, const cBitmap &Bitmap); + // Actually commits all data of all windows to the OSD. + void Clear(tWindowHandle Window = ALL_TILED_WINDOWS); + // Clears the given window. If ALL_TILED_WINDOWS is given, only the tiled + // windows will be cleared, leaving the standalone windows untouched. If + // ALL_WINDOWS is given, the standalone windows will also be cleared. + void Fill(int x1, int y1, int x2, int y2, eDvbColor Color, tWindowHandle Window = ALL_TILED_WINDOWS); + // Fills the rectangle defined by the upper left (x1, y2) and lower right + // (x2, y2) corners with the given Color. If a specific window is given, + // the coordinates are relative to that window's upper left corner. + // Otherwise they are relative to the upper left corner of the entire OSD. + // If all tiled windows are selected, only that window which contains the + // point (x1, y1) will actually be filled. + void SetBitmap(int x, int y, const cBitmap &Bitmap, tWindowHandle Window = ALL_TILED_WINDOWS); + // Sets the pixels within the given window with the data from the given + // Bitmap. See Fill() for details about the coordinates. int Width(unsigned char c); + // Returns the width (in pixels) of the given character in the current font. int Width(const char *s); + // Returns the width (in pixels) of the given string in the current font. eDvbFont SetFont(eDvbFont Font); - void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); + // Sets the current font for subsequent Width() and Text() operations. + void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground, tWindowHandle Window = ALL_TILED_WINDOWS); + // Writes the given string at coordinates (x, y) with the given foreground + // and background color into the given window (see Fill() for details + // about the coordinates). + void Relocate(tWindowHandle Window, int x, int y, int NewWidth = -1, int NewHeight = -1); + // Moves the given window to the new location at (x, y). If NewWidth and + // NewHeight are also given, the window will also be resized to the new + // width and height. + void Hide(tWindowHandle Window); + // Hides the given window. + void Show(tWindowHandle Window); + // Shows the given window. }; #endif //__DVBOSD_H diff --git a/eit.c b/eit.c index 00792ab5f..ed757d2cc 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.29 2001/10/28 13:51:22 kls Exp $ + * $Id: eit.c 1.31 2002/01/13 16:14:31 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -473,22 +473,6 @@ void cEventInfo::FixEpgBugs(void) strreplace(pTitle, '`', '\''); strreplace(pSubtitle, '`', '\''); strreplace(pExtendedDescription, '`', '\''); - - if (Setup.EPGBugfixLevel <= 2) - return; - - // Pro7 and Kabel1 apparently are unable to use a calendar/clock, - // because all events between 00:00 and 06:00 have the date of the - // day before (sometimes even this correction doesn't help). - // Channels are recognized by their ServiceID, which may only work - // correctly on the ASTRA satellite system. - if (uServiceID == 898 // Pro-7 - || uServiceID == 899) { // Kabel 1 - struct tm tm_r; - tm *t = localtime_r(&tTime, &tm_r); - if (t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec <= 6 * 3600) - tTime += 24 * 3600; - } } } @@ -1013,8 +997,10 @@ void cSIProcessor::Action() break; } } + /*XXX this just fills up the log file - shouldn't we rather try to re-sync? else dsyslog(LOG_INFO, "read incomplete section - seclen = %d, n = %d", seclen, n); + XXX*/ } } } diff --git a/eit.h b/eit.h index 131419623..48ab91332 100644 --- a/eit.h +++ b/eit.h @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.12 2001/10/28 12:33:10 kls Exp $ + * $Id: eit.h 1.13 2002/01/13 16:18:23 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -25,6 +25,8 @@ #include "thread.h" #include "tools.h" +#define MAXEPGBUGFIXLEVEL 2 + class cEventInfo : public cListObject { friend class cSchedule; friend class cEIT; diff --git a/i18n.c b/i18n.c index 764dc3380..7977fcd44 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.45 2001/10/28 16:04:58 kls Exp $ + * $Id: i18n.c 1.50 2002/01/27 15:52:32 kls Exp $ * * Slovenian translations provided by Miha Setina * Italian translations provided by Alberto Carraro @@ -285,6 +285,15 @@ const tPhrase Phrases[] = { "Rsum", "Sammendrag", }, + { "Open", + "ffnen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Switch", "Umschalten", "Preklopi", @@ -631,6 +640,15 @@ const tPhrase Phrases[] = { "Enregistrement en cours!", "Timer gjr opptak!", }, + { "Error while accessing recording!", + "Fehler beim ansprechen der Aufzeichnung!", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Error while deleting recording!", "Fehler beim Lschen der Aufzeichnung!", "Napaka pri odstranjevanju posnetka!", @@ -703,6 +721,15 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO }, + { "Low disk space!", + "Platte beinahe voll!", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // Setup parameters: { "OSD-Language", "OSD-Sprache", @@ -884,6 +911,15 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO }, + { "RecordingDirs", + "Aufn. Verzeichnisse", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "VideoFormat", "Video Format", "", // TODO @@ -1293,6 +1329,14 @@ const tPhrase Phrases[] = { "bas", "", // TODO }, + { "free", + "frei", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Jump: ", // note the trailing blank "Springen: ", "", // TODO @@ -1355,6 +1399,30 @@ const tPhrase Phrases[] = { "Opration de montage lance", "Redigeringsprosess startet", }, + { "Editing process finished", + "Schnitt beendet", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Editing process failed!", + "Schnitt gescheitert!", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "scanning recordings...", + "Aufzeichnungen werden durchsucht...", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { NULL } }; diff --git a/interface.c b/interface.c index 8695a3670..b86fb141d 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.44 2001/09/01 15:18:46 kls Exp $ + * $Id: interface.c 1.47 2002/01/27 15:48:46 kls Exp $ */ #include "interface.h" @@ -292,8 +292,12 @@ void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor) { int Line = (abs(height) == 1) ? 0 : -2; ClearEol(0, Line, s ? BgColor : clrBackground); - if (s) - Write(0, Line, s, FgColor, BgColor); + if (s) { + int x = (Width() - strlen(s)) / 2; + if (x < 0) + x = 0; + Write(x, Line, s, FgColor, BgColor); + } } void cInterface::Info(const char *s) @@ -318,7 +322,7 @@ void cInterface::Error(const char *s) bool cInterface::Confirm(const char *s, int Seconds, bool WaitForTimeout) { - Open(); + Open(Setup.OSDwidth, -1); isyslog(LOG_INFO, "confirm: %s", s); Status(s, clrBlack, clrYellow); eKeys k = Wait(Seconds); @@ -331,13 +335,15 @@ bool cInterface::Confirm(const char *s, int Seconds, bool WaitForTimeout) void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor) { - if (open && Text) { + if (open) { const int w = Width() / 4; - int l = (w - int(strlen(Text))) / 2; - if (l < 0) - l = 0; - cDvbApi::PrimaryDvbApi->Fill(Index * w, -1, w, 1, BgColor); - cDvbApi::PrimaryDvbApi->Text(Index * w + l, -1, Text, FgColor, BgColor); + cDvbApi::PrimaryDvbApi->Fill(Index * w, -1, w, 1, Text ? BgColor : clrBackground); + if (Text) { + int l = (w - int(strlen(Text))) / 2; + if (l < 0) + l = 0; + cDvbApi::PrimaryDvbApi->Text(Index * w + l, -1, Text, FgColor, BgColor); + } } } diff --git a/menu.c b/menu.c index 45899b1ac..1cd549158 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.141 2001/11/24 13:20:37 kls Exp $ + * $Id: menu.c 1.146 2002/01/27 15:50:50 kls Exp $ */ #include "menu.h" @@ -15,6 +15,7 @@ #include "config.h" #include "eit.h" #include "i18n.h" +#include "videodir.h" #define MENUTIMEOUT 120 // seconds #define MAXWAIT4EPGINFO 10 // seconds @@ -1494,46 +1495,161 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) // --- cMenuRecordingItem ---------------------------------------------------- class cMenuRecordingItem : public cOsdItem { +private: + char *fileName; + char *name; + int totalEntries, newEntries; public: - cRecording *recording; - cMenuRecordingItem(cRecording *Recording); - virtual void Set(void); + cMenuRecordingItem(cRecording *Recording, int Level); + ~cMenuRecordingItem(); + void IncrementCounter(bool New); + const char *Name(void) { return name; } + const char *FileName(void) { return fileName; } + bool IsDirectory(void) { return name != NULL; } }; -cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording) +cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording, int Level) { - recording = Recording; - Set(); + fileName = strdup(Recording->FileName()); + name = NULL; + totalEntries = newEntries = 0; + SetText(Recording->Title('\t', true, Level)); + if (*Text() == '\t') + name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t' } -void cMenuRecordingItem::Set(void) +cMenuRecordingItem::~cMenuRecordingItem() { - SetText(recording->Title('\t', true)); + delete fileName; + delete name; +} + +void cMenuRecordingItem::IncrementCounter(bool New) +{ + totalEntries++; + if (New) + newEntries++; + char *buffer = NULL; + asprintf(&buffer, "%d\t%d\t%s", totalEntries, newEntries, name); + SetText(buffer, false); } // --- cMenuRecordings ------------------------------------------------------- -cMenuRecordings::cMenuRecordings(void) -:cOsdMenu(tr("Recordings"), 6, 6) +cRecordings cMenuRecordings::Recordings; +int cMenuRecordings::helpKeys = -1; + +cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus) +:cOsdMenu(Base ? Base : tr("Recordings"), 6, 6) { - if (Recordings.Load()) { - const char *lastReplayed = cReplayControl::LastReplayed(); - cRecording *recording = Recordings.First(); - while (recording) { - Add(new cMenuRecordingItem(recording), lastReplayed && strcmp(lastReplayed, recording->FileName()) == 0); - recording = Recordings.Next(recording); - } + base = Base ? strdup(Base) : NULL; + level = Setup.RecordingDirs ? Level : -1; + if (!Base) { + Interface->Status(tr("scanning recordings...")); + Interface->Flush(); } - SetHelp(tr("Play"), tr("Rewind"), tr("Delete"), tr("Summary")); - Display(); + if (Base || Recordings.Load()) { + const char *LastReplayed = cReplayControl::LastReplayed(); + cMenuRecordingItem *LastItem = NULL; + char *LastItemText = NULL; + for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { + if (!Base || strstr(recording->Name(), Base) == recording->Name()) { + cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); + if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { + Add(Item); + LastItem = Item; + delete LastItemText; + LastItemText = strdup(LastItem->Text()); // must use a copy because of the counters! + } + else + delete Item; + if (LastItem) { + if (LastReplayed && strcmp(LastReplayed, recording->FileName()) == 0) + SetCurrent(LastItem); + if (LastItem->IsDirectory()) + LastItem->IncrementCounter(recording->IsNew()); + } + } + } + delete LastItemText; + if (Current() < 0) + SetCurrent(First()); + else if (OpenSubMenus && Open(true)) + return; + } + Display(); // this keeps the higher level menus from showing up briefly when pressing 'Back' during replay + SetHelpKeys(); +} + +cMenuRecordings::~cMenuRecordings() +{ + helpKeys = -1; + delete base; +} + +void cMenuRecordings::SetHelpKeys(void) +{ + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + int NewHelpKeys = helpKeys; + if (ri) { + if (ri->IsDirectory()) + NewHelpKeys = 1; + else { + NewHelpKeys = 2; + cRecording *recording = GetRecording(ri); + if (recording && recording->Summary()) + NewHelpKeys = 3; + } + } + if (NewHelpKeys != helpKeys) { + switch (NewHelpKeys) { + case 0: SetHelp(NULL); break; + case 1: SetHelp(tr("Open")); break; + case 2: + case 3: SetHelp(tr("Play"), tr("Rewind"), tr("Delete"), NewHelpKeys == 3 ? tr("Summary") : NULL); + } + helpKeys = NewHelpKeys; + } +} + +cRecording *cMenuRecordings::GetRecording(cMenuRecordingItem *Item) +{ + cRecording *recording = Recordings.GetByName(Item->FileName()); + if (!recording) + Interface->Error(tr("Error while accessing recording!")); + return recording; +} + +bool cMenuRecordings::Open(bool OpenSubMenus) +{ + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri && ri->IsDirectory()) { + const char *t = ri->Name(); + char *buffer = NULL; + if (base) { + asprintf(&buffer, "%s~%s", base, t); + t = buffer; + } + AddSubMenu(new cMenuRecordings(t, level + 1, OpenSubMenus)); + delete buffer; + return true; + } + return false; } eOSState cMenuRecordings::Play(void) { cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); if (ri) { - cReplayControl::SetRecording(ri->recording->FileName(), ri->recording->Title()); - return osReplay; + if (ri->IsDirectory()) + Open(); + else { + cRecording *recording = GetRecording(ri); + if (recording) { + cReplayControl::SetRecording(recording->FileName(), recording->Title()); + return osReplay; + } + } } return osContinue; } @@ -1541,9 +1657,9 @@ eOSState cMenuRecordings::Play(void) eOSState cMenuRecordings::Rewind(void) { cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); - if (ri) { + if (ri && !ri->IsDirectory()) { cDvbApi::PrimaryDvbApi->StopReplay(); // must do this first to be able to rewind the currently replayed recording - cResumeFile ResumeFile(ri->recording->FileName()); + cResumeFile ResumeFile(ri->FileName()); ResumeFile.Delete(); return Play(); } @@ -1553,17 +1669,21 @@ eOSState cMenuRecordings::Rewind(void) eOSState cMenuRecordings::Del(void) { cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); - if (ri) { + if (ri && !ri->IsDirectory()) { //XXX what if this recording's file is currently in use??? //XXX if (!ti->recording) { if (Interface->Confirm(tr("Delete recording?"))) { - if (ri->recording->Delete()) { - cReplayControl::ClearLastReplayed(ri->recording->FileName()); - cOsdMenu::Del(Current()); - Display(); + cRecording *recording = GetRecording(ri); + if (recording) { + if (recording->Delete()) { + cReplayControl::ClearLastReplayed(ri->FileName()); + cOsdMenu::Del(Current()); + Recordings.Del(recording); + Display(); + } + else + Interface->Error(tr("Error while deleting recording!")); } - else - Interface->Error(tr("Error while deleting recording!")); } //XXX } //XXX else @@ -1577,8 +1697,11 @@ eOSState cMenuRecordings::Summary(void) if (HasSubMenu() || Count() == 0) return osContinue; cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); - if (ri && ri->recording->Summary() && *ri->recording->Summary()) - return AddSubMenu(new cMenuText(tr("Summary"), ri->recording->Summary())); + if (ri && !ri->IsDirectory()) { + cRecording *recording = GetRecording(ri); + if (recording && recording->Summary() && *recording->Summary()) + return AddSubMenu(new cMenuText(tr("Summary"), recording->Summary())); + } return osContinue; } @@ -1597,6 +1720,8 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) default: break; } } + if (!HasSubMenu() && Key != kNone) + SetHelpKeys(); return state; } @@ -1712,13 +1837,14 @@ void cMenuSetup::Set(void) Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart)); Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop)); Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout)); - Add(new cMenuEditIntItem( tr("EPGBugfixLevel"), &data.EPGBugfixLevel, 0, 3)); + Add(new cMenuEditIntItem( tr("EPGBugfixLevel"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); Add(new cMenuEditIntItem( tr("SVDRPTimeout"), &data.SVDRPTimeout)); Add(new cMenuEditBoolItem(tr("SortTimers"), &data.SortTimers)); Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("DefaultPriority"), &data.DefaultPriority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("DefaultLifetime"), &data.DefaultLifetime, 0, MAXLIFETIME)); Add(new cMenuEditBoolItem(tr("UseSubtitle"), &data.UseSubtitle)); + Add(new cMenuEditBoolItem(tr("RecordingDirs"), &data.RecordingDirs)); Add(new cMenuEditBoolItem(tr("VideoFormat"), &data.VideoFormat, "4:3", "16:9")); Add(new cMenuEditBoolItem(tr("ChannelInfoPos"), &data.ChannelInfoPos, tr("bottom"), tr("top"))); Add(new cMenuEditIntItem( tr("OSDwidth"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); @@ -1815,6 +1941,18 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) { digit = 0; + // Title with disk usage: + +#define MB_PER_MINUTE 30 // this is just an estimate! + + char buffer[40]; + int FreeMB; + int Percent = VideoDiskSpace(&FreeMB); + int Hours = int(double(FreeMB) / MB_PER_MINUTE / 60); + int Minutes = (FreeMB / MB_PER_MINUTE) % 60; + snprintf(buffer, sizeof(buffer), "%s - Disk %d%% - %2d:%02d %s", tr("Main"), Percent, Hours, Minutes, tr("free")); + SetTitle(buffer); + // Basic menu items: Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); @@ -1871,7 +2009,7 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) // Initial submenus: switch (State) { - case osRecordings: AddSubMenu(new cMenuRecordings); break; + case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break; #ifdef DVDSUPPORT case osDVD: AddSubMenu(new cMenuDVD); break; #endif //DVDSUPPORT diff --git a/menu.h b/menu.h index 250d2ff52..82fd64032 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.34 2001/10/28 15:21:04 kls Exp $ + * $Id: menu.h 1.35 2002/01/20 13:38:34 kls Exp $ */ #ifndef _MENU_H @@ -55,15 +55,24 @@ class cMenuDVD : public cOsdMenu { }; #endif //DVDSUPPORT +class cMenuRecordingItem; + class cMenuRecordings : public cOsdMenu { private: - cRecordings Recordings; + static cRecordings Recordings; + char *base; + int level; + static int helpKeys; + void SetHelpKeys(void); + cRecording *GetRecording(cMenuRecordingItem *Item); + bool Open(bool OpenSubMenus = false); eOSState Play(void); eOSState Rewind(void); eOSState Del(void); eOSState Summary(void); public: - cMenuRecordings(void); + cMenuRecordings(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false); + ~cMenuRecordings(); virtual eOSState ProcessKey(eKeys Key); }; diff --git a/osd.c b/osd.c index 02f437481..0a825d7da 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.18 2001/08/25 13:15:16 kls Exp $ + * $Id: osd.c 1.20 2002/01/26 11:09:58 kls Exp $ */ #include "osd.h" @@ -127,9 +127,7 @@ void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, c helpYellow = Yellow; helpBlue = Blue; if (visible) - Display(); - //XXX Interface->Help(helpRed, helpGreen, helpYellow, helpBlue); - //XXX must clear unused button areas! + Interface->Help(helpRed, helpGreen, helpYellow, helpBlue); } void cOsdMenu::Del(int Index) @@ -150,6 +148,10 @@ void cOsdMenu::Add(cOsdItem *Item, bool Current) void cOsdMenu::Display(void) { + if (subMenu) { + subMenu->Display(); + return; + } visible = true; Interface->Clear(); Interface->SetCols(cols); @@ -179,6 +181,11 @@ void cOsdMenu::Display(void) Interface->Status(status); } +void cOsdMenu::SetCurrent(cOsdItem *Item) +{ + current = Item ? Item->Index() : -1; +} + void cOsdMenu::RefreshCurrent(void) { cOsdItem *item = Get(current); diff --git a/osd.h b/osd.h index 2d243f166..21c931540 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.24 2001/08/25 12:56:46 kls Exp $ + * $Id: osd.h 1.25 2002/01/20 10:42:14 kls Exp $ */ #ifndef __OSD_H @@ -83,6 +83,7 @@ class cOsdMenu : public cOsdBase, public cList { bool visible; virtual void Clear(void); bool SpecialItem(int idx); + void SetCurrent(cOsdItem *Item); void RefreshCurrent(void); void DisplayCurrent(bool Current); void CursorUp(void); diff --git a/recording.c b/recording.c index fe56a6e69..acdf264cb 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.42 2001/10/20 10:28:28 kls Exp $ + * $Id: recording.c 1.48 2002/01/27 15:14:45 kls Exp $ */ #include "recording.h" @@ -14,6 +14,7 @@ #include #include #include +#include "i18n.h" #include "interface.h" #include "tools.h" #include "videodir.h" @@ -37,7 +38,7 @@ #define DELETEDLIFETIME 1 // hours after which a deleted recording will be actually removed #define REMOVECHECKDELTA 3600 // seconds between checks for removing deleted files -#define DISKCHECKDELTA 300 // seconds between checks for free disk space +#define DISKCHECKDELTA 100 // seconds between checks for free disk space #define REMOVELATENCY 10 // seconds to wait until next check after removing a file void RemoveDeletedRecordings(void) @@ -118,7 +119,7 @@ void AssertFreeDiskSpace(int Priority) return; } // Unable to free disk space, but there's nothing we can do about that... - esyslog(LOG_ERR, "low disk space, but no recordings to delete"); + Interface->Confirm(tr("Low disk space"), 30); } LastFreeDiskCheck = time(NULL); } @@ -184,6 +185,8 @@ void cResumeFile::Delete(void) // --- cRecording ------------------------------------------------------------ +#define RESUME_NOT_INITIALIZED (-2) + struct tCharExchange { char a; char b; }; tCharExchange CharExchange[] = { { '~', '/' }, @@ -213,6 +216,7 @@ char *ExchangeChars(char *s, bool ToFileSystem) cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary) { + resume = RESUME_NOT_INITIALIZED; titleBuffer = NULL; sortBuffer = NULL; fileName = NULL; @@ -242,6 +246,7 @@ cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary) cRecording::cRecording(const char *FileName) { + resume = RESUME_NOT_INITIALIZED; titleBuffer = NULL; sortBuffer = NULL; fileName = strdup(FileName); @@ -342,6 +347,15 @@ char *cRecording::SortName(void) return sortBuffer; } +int cRecording::GetResume(void) +{ + if (resume == RESUME_NOT_INITIALIZED) { + cResumeFile ResumeFile(FileName()); + resume = ResumeFile.Read(); + } + return resume; +} + bool cRecording::operator< (const cListObject &ListObject) { cRecording *r = (cRecording *)&ListObject; @@ -360,27 +374,47 @@ const char *cRecording::FileName(void) return fileName; } -const char *cRecording::Title(char Delimiter, bool NewIndicator) +const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) { - char New = ' '; - if (NewIndicator) { - cResumeFile ResumeFile(FileName()); - if (ResumeFile.Read() <= 0) - New = '*'; - } + char New = NewIndicator && IsNew() ? '*' : ' '; delete titleBuffer; titleBuffer = NULL; - struct tm tm_r; - struct tm *t = localtime_r(&start, &tm_r); - asprintf(&titleBuffer, "%02d.%02d%c%02d:%02d%c%c%s", - t->tm_mday, - t->tm_mon + 1, - Delimiter, - t->tm_hour, - t->tm_min, - New, - Delimiter, - name); + if (Level < 0 || Level == HierarchyLevels()) { + struct tm tm_r; + struct tm *t = localtime_r(&start, &tm_r); + const char *s; + if (Level > 0 && (s = strrchr(name, '~')) != NULL) + s++; + else + s = name; + asprintf(&titleBuffer, "%02d.%02d%c%02d:%02d%c%c%s", + t->tm_mday, + t->tm_mon + 1, + Delimiter, + t->tm_hour, + t->tm_min, + New, + Delimiter, + s); + } + else if (Level < HierarchyLevels()) { + const char *s = name; + const char *p = s; + while (*++s) { + if (*s == '~') { + if (Level--) + p = s + 1; + else + break; + } + } + titleBuffer = new char[s - p + 3]; + *titleBuffer = Delimiter; + *(titleBuffer + 1) = Delimiter; + strn0cpy(titleBuffer + 2, p, s - p + 1); + } + else + return ""; return titleBuffer; } @@ -395,6 +429,17 @@ const char *cRecording::PrefixFileName(char Prefix) return NULL; } +int cRecording::HierarchyLevels(void) +{ + const char *s = name; + int level = 0; + while (*++s) { + if (*s == '~') + level++; + } + return level; +} + bool cRecording::WriteSummary(void) { if (summary) { @@ -429,6 +474,11 @@ bool cRecording::Delete(void) bool cRecording::Remove(void) { + // let's do a final safety check here: + if (!endswith(FileName(), DELEXT)) { + esyslog(LOG_ERR, "attempt to remove recording %s", FileName()); + return false; + } isyslog(LOG_INFO, "removing recording %s", FileName()); return RemoveVideoFile(FileName()); } @@ -446,7 +496,7 @@ bool cRecordings::Load(bool Deleted) char *s; while ((s = readline(p)) != NULL) { cRecording *r = new cRecording(s); - if (r->name) + if (r->Name()) Add(r); else delete r; @@ -461,6 +511,15 @@ bool cRecordings::Load(bool Deleted) return result; } +cRecording *cRecordings::GetByName(const char *FileName) +{ + for (cRecording *recording = First(); recording; recording = Next(recording)) { + if (strcmp(recording->FileName(), FileName) == 0) + return recording; + } + return NULL; +} + // --- cMark ----------------------------------------------------------------- char *cMark::buffer = NULL; @@ -573,7 +632,7 @@ void cRecordingUserCommand::InvokeCommand(const char *State, const char *Recordi { if (command) { char *cmd; - asprintf(&cmd, "%s %s '%s'", command, State, RecordingFileName); + asprintf(&cmd, "%s %s \"%s\"", command, State, strescape(RecordingFileName, "\"$")); isyslog(LOG_INFO, "executing '%s'", cmd); SystemExec(cmd); delete cmd; diff --git a/recording.h b/recording.h index aead97e36..3aaa7e9e6 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.18 2001/10/07 10:38:56 kls Exp $ + * $Id: recording.h 1.21 2002/01/26 15:18:16 kls Exp $ */ #ifndef __RECORDING_H @@ -15,7 +15,7 @@ #include "tools.h" void RemoveDeletedRecordings(void); -void AssertFreeDiskSpace(int Priority); +void AssertFreeDiskSpace(int Priority = 0); class cResumeFile { private: @@ -29,8 +29,8 @@ class cResumeFile { }; class cRecording : public cListObject { - friend class cRecordings; private: + int resume; char *titleBuffer; char *sortBuffer; char *fileName; @@ -38,6 +38,7 @@ class cRecording : public cListObject { char *summary; char *StripEpisodeName(char *s); char *SortName(void); + int GetResume(void); public: time_t start; int priority; @@ -46,10 +47,13 @@ class cRecording : public cListObject { cRecording(const char *FileName); ~cRecording(); virtual bool operator< (const cListObject &ListObject); + const char *Name(void) { return name; } const char *FileName(void); - const char *Title(char Delimiter = ' ', bool NewIndicator = false); + const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1); const char *Summary(void) { return summary; } const char *PrefixFileName(char Prefix); + int HierarchyLevels(void); + bool IsNew(void) { return GetResume() <= 0; } bool WriteSummary(void); bool Delete(void); // Changes the file name so that it will no longer be visible in the "Recordings" menu @@ -62,6 +66,7 @@ class cRecording : public cListObject { class cRecordings : public cList { public: bool Load(bool Deleted = false); + cRecording *GetByName(const char *FileName); }; class cMark : public cListObject { diff --git a/svdrp.c b/svdrp.c index 48c956391..67de63c3b 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.27 2001/11/04 11:25:05 kls Exp $ + * $Id: svdrp.c 1.28 2002/01/13 16:07:42 kls Exp $ */ #include "svdrp.h" @@ -899,49 +899,49 @@ void cSVDRP::Process(void) } if (NewConnection) lastActivity = time(NULL); - if (file.Ready(false)) { - unsigned char c; - int r = safe_read(file, &c, 1); - if (r > 0) { - if (c == '\n' || c == 0x00) { - // strip trailing whitespace: - while (numChars > 0 && strchr(" \t\r\n", cmdLine[numChars - 1])) - cmdLine[--numChars] = 0; - // make sure the string is terminated: - cmdLine[numChars] = 0; - // showtime! - Execute(cmdLine); - numChars = 0; + while (file.Ready(false)) { + unsigned char c; + int r = safe_read(file, &c, 1); + if (r > 0) { + if (c == '\n' || c == 0x00) { + // strip trailing whitespace: + while (numChars > 0 && strchr(" \t\r\n", cmdLine[numChars - 1])) + cmdLine[--numChars] = 0; + // make sure the string is terminated: + cmdLine[numChars] = 0; + // showtime! + Execute(cmdLine); + numChars = 0; + } + else if (c == 0x04 && numChars == 0) { + // end of file (only at beginning of line) + Close(); + } + else if (c == 0x08 || c == 0x7F) { + // backspace or delete (last character) + if (numChars > 0) + numChars--; + } + else if (c <= 0x03 || c == 0x0D) { + // ignore control characters + } + else if (numChars < sizeof(cmdLine) - 1) { + cmdLine[numChars++] = c; + cmdLine[numChars] = 0; + } + else { + Reply(501, "Command line too long"); + esyslog(LOG_ERR, "SVDRP: command line too long: '%s'", cmdLine); + numChars = 0; + } + lastActivity = time(NULL); } - else if (c == 0x04 && numChars == 0) { - // end of file (only at beginning of line) + else if (r <= 0) { + isyslog(LOG_INFO, "lost connection to SVDRP client"); Close(); } - else if (c == 0x08 || c == 0x7F) { - // backspace or delete (last character) - if (numChars > 0) - numChars--; - } - else if (c <= 0x03 || c == 0x0D) { - // ignore control characters - } - else if (numChars < sizeof(cmdLine) - 1) { - cmdLine[numChars++] = c; - cmdLine[numChars] = 0; - } - else { - Reply(501, "Command line too long"); - esyslog(LOG_ERR, "SVDRP: command line too long: '%s'", cmdLine); - numChars = 0; - } - lastActivity = time(NULL); - } - else if (r <= 0) { - isyslog(LOG_INFO, "lost connection to SVDRP client"); - Close(); } - } - else if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) { + if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) { isyslog(LOG_INFO, "timeout on SVDRP connection"); Close(true); } diff --git a/tools.c b/tools.c index 472c50d73..dc579e55f 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.50 2001/10/19 13:12:45 kls Exp $ + * $Id: tools.c 1.53 2002/01/27 12:36:23 kls Exp $ */ #include "tools.h" @@ -136,6 +136,29 @@ char *compactspace(char *s) return s; } +const char *strescape(const char *s, const char *chars) +{ + static char *buffer = NULL; + const char *p = s; + char *t = NULL; + while (*p) { + if (strchr(chars, *p)) { + if (!t) { + buffer = (char *)realloc(buffer, 2 * strlen(s) + 1); + t = buffer + (p - s); + s = strcpy(buffer, s); + } + *t++ = '\\'; + } + if (t) + *t++ = *p; + p++; + } + if (t) + *t = 0; + return s; +} + bool startswith(const char *s, const char *p) { while (*p) { @@ -145,6 +168,17 @@ bool startswith(const char *s, const char *p) return true; } +bool endswith(const char *s, const char *p) +{ + const char *se = s + strlen(s) - 1; + const char *pe = p + strlen(p) - 1; + while (pe >= p) { + if (*pe-- != *se-- || (se < s && pe >= p)) + return false; + } + return true; +} + bool isempty(const char *s) { return !(s && *skipspace(s)); @@ -189,10 +223,12 @@ const char *AddDirectory(const char *DirName, const char *FileName) #define DFCMD "df -m -P '%s'" -uint FreeDiskSpaceMB(const char *Directory) +int FreeDiskSpaceMB(const char *Directory, int *UsedMB) { //TODO Find a simpler way to determine the amount of free disk space! - uint Free = 0; + if (UsedMB) + *UsedMB = 0; + int Free = 0; char *cmd = NULL; asprintf(&cmd, DFCMD, Directory); FILE *p = popen(cmd, "r"); @@ -200,8 +236,10 @@ uint FreeDiskSpaceMB(const char *Directory) char *s; while ((s = readline(p)) != NULL) { if (strchr(s, '/')) { - uint available; - sscanf(s, "%*s %*d %*d %u", &available); + int used, available; + sscanf(s, "%*s %*d %d %d", &used, &available); + if (UsedMB) + *UsedMB = used; Free = available; break; } diff --git a/tools.h b/tools.h index 843cbf1db..f9390185b 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.36 2001/09/30 10:20:59 kls Exp $ + * $Id: tools.h 1.39 2002/01/26 15:38:10 kls Exp $ */ #ifndef __TOOLS_H @@ -50,20 +50,22 @@ char *strreplace(char *s, char c1, char c2); char *skipspace(const char *s); char *stripspace(char *s); char *compactspace(char *s); +const char *strescape(const char *s, const char *chars); // returns a statically allocated string! bool startswith(const char *s, const char *p); +bool endswith(const char *s, const char *p); bool isempty(const char *s); int time_ms(void); void delay_ms(int ms); bool isnumber(const char *s); -const char *AddDirectory(const char *DirName, const char *FileName); -uint FreeDiskSpaceMB(const char *Directory); +const char *AddDirectory(const char *DirName, const char *FileName); // returns a statically allocated string! +int FreeDiskSpaceMB(const char *Directory, int *UsedMB = NULL); bool DirectoryOk(const char *DirName, bool LogErrors = false); bool MakeDirs(const char *FileName, bool IsDirectory = false); bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false); char *ReadLink(const char *FileName); bool SpinUpDisk(const char *FileName); -const char *DayDateTime(time_t t = 0); +const char *DayDateTime(time_t t = 0); // returns a statically allocated string! class cFile { private: diff --git a/vdr.c b/vdr.c index 886b09178..5351e4095 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.89 2001/11/03 12:23:45 kls Exp $ + * $Id: vdr.c 1.93 2002/01/26 14:07:01 kls Exp $ */ #include @@ -314,7 +314,6 @@ int main(int argc, char *argv[]) int LastChannel = -1; int PreviousChannel = cDvbApi::CurrentChannel(); time_t LastActivity = 0; - time_t LinearTime = time(NULL); int MaxLatencyTime = 0; bool ForceShutdown = false; @@ -324,14 +323,6 @@ int main(int argc, char *argv[]) } while (!Interrupted) { - // Test if we are running in the Einstein continuum: - time_t Now = time(NULL); - time_t LinearDelta = Now - LinearTime; - if (LinearDelta) { - if (LinearDelta < 0 || LinearDelta > 300) // assuming nothing will block for more than 5 minutes - esyslog(LOG_ERR, "ERROR: time warp detected (%d seconds)", LinearDelta); - LinearTime = Now; - } // Handle emergency exits: if (cThread::EmergencyExit()) { esyslog(LOG_ERR, "emergency exit requested - shutting down"); @@ -477,7 +468,12 @@ int main(int argc, char *argv[]) } if (!Menu) { EITScanner.Process(); - cVideoCutter::Active(); + if (!cVideoCutter::Active() && cVideoCutter::Ended()) { + if (cVideoCutter::Error()) + Interface->Error(tr("Editing process failed!")); + else + Interface->Info(tr("Editing process finished")); + } } if (!*Interact && (!cRecordControls::Active() || ForceShutdown)) { time_t Now = time(NULL); @@ -508,7 +504,7 @@ int main(int argc, char *argv[]) int Channel = timer ? timer->channel : 0; const char *File = timer ? timer->file : ""; char *cmd; - asprintf(&cmd, "%s %ld %ld %d '%s' %d", Shutdown, Next, Delta, Channel, File, UserShutdown); + asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", Shutdown, Next, Delta, Channel, strescape(File, "\"$"), UserShutdown); isyslog(LOG_INFO, "executing '%s'", cmd); SystemExec(cmd); delete cmd; @@ -518,7 +514,7 @@ int main(int argc, char *argv[]) if (signal(SIGALRM, Watchdog) == SIG_IGN) signal(SIGALRM, SIG_IGN); } - LastActivity = Now; // don't try again too soon + LastActivity = time(NULL); // don't try again too soon continue; // skip the rest of the housekeeping for now } } diff --git a/videodir.c b/videodir.c index d9d3f8524..dbb1bd197 100644 --- a/videodir.c +++ b/videodir.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: videodir.c 1.6 2001/09/02 14:55:15 kls Exp $ + * $Id: videodir.c 1.7 2002/01/27 12:37:26 kls Exp $ */ #include "videodir.h" @@ -27,7 +27,7 @@ class cVideoDirectory { public: cVideoDirectory(void); ~cVideoDirectory(); - uint FreeMB(void); + int FreeMB(int *UsedMB = NULL); const char *Name(void) { return name ? name : VideoDirectory; } const char *Stored(void) { return stored; } int Length(void) { return length; } @@ -53,9 +53,9 @@ cVideoDirectory::~cVideoDirectory() delete adjusted; } -uint cVideoDirectory::FreeMB(void) +int cVideoDirectory::FreeMB(int *UsedMB) { - return FreeDiskSpaceMB(name ? name : VideoDirectory); + return FreeDiskSpaceMB(name ? name : VideoDirectory, UsedMB); } bool cVideoDirectory::Next(void) @@ -117,9 +117,9 @@ int OpenVideoFile(const char *FileName, int Flags) cVideoDirectory Dir; if (Dir.IsDistributed()) { // Find the directory with the most free space: - uint MaxFree = Dir.FreeMB(); + int MaxFree = Dir.FreeMB(); while (Dir.Next()) { - uint Free = FreeDiskSpaceMB(Dir.Name()); + int Free = FreeDiskSpaceMB(Dir.Name()); if (Free > MaxFree) { Dir.Store(); MaxFree = Free; @@ -166,7 +166,7 @@ bool RemoveVideoFile(const char *FileName) return RemoveFileOrDir(FileName, true); } -bool VideoFileSpaceAvailable(unsigned int SizeMB) +bool VideoFileSpaceAvailable(int SizeMB) { cVideoDirectory Dir; if (Dir.IsDistributed()) { @@ -181,6 +181,22 @@ bool VideoFileSpaceAvailable(unsigned int SizeMB) return Dir.FreeMB() >= SizeMB; } +int VideoDiskSpace(int *FreeMB, int *UsedMB) +{ + int free = 0, used = 0; + cVideoDirectory Dir; + do { + int u; + free += Dir.FreeMB(&u); + used += u; + } while (Dir.Next()); + if (FreeMB) + *FreeMB = free; + if (UsedMB) + *UsedMB = used; + return (free + used) ? used * 100 / (free + used) : 0; +} + const char *PrefixVideoFileName(const char *FileName, char Prefix) { static char *PrefixedName = NULL; diff --git a/videodir.h b/videodir.h index 0197de303..a719c5e04 100644 --- a/videodir.h +++ b/videodir.h @@ -4,19 +4,22 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: videodir.h 1.3 2001/02/11 13:12:50 kls Exp $ + * $Id: videodir.h 1.4 2002/01/27 12:37:20 kls Exp $ */ #ifndef __VIDEODIR_H #define __VIDEODIR_H +#include + extern const char *VideoDirectory; int OpenVideoFile(const char *FileName, int Flags); int CloseVideoFile(int FileHandle); bool RenameVideoFile(const char *OldName, const char *NewName); bool RemoveVideoFile(const char *FileName); -bool VideoFileSpaceAvailable(unsigned int SizeMB); +bool VideoFileSpaceAvailable(int SizeMB); +int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent const char *PrefixVideoFileName(const char *FileName, char Prefix); void RemoveEmptyVideoDirectories(void); From 8184b809b250386bb27febeb15f1825f8e4b9013 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Tue, 29 Jan 2002 18:00:00 +0100 Subject: [PATCH 031/307] Version 0.99pre3 - Fixed handling improper buffer lengths in the EIT parser (thanks to Deti Fliegl). --- CONTRIBUTORS | 1 + HISTORY | 5 +++++ config.h | 4 ++-- libdtv/libsi/include/libsi.h | 4 ++-- libdtv/libsi/si_parser.c | 16 ++++++++-------- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 073e92719..1d06173f0 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -57,6 +57,7 @@ Alberto Carraro Deti Fliegl for implementing the 'CurrentChannel' setup parameter for fixing setting the OSD size in the 'Confirm' interface call + for fixing handling improper buffer lengths in the EIT parser Dave Chapman for implementing support for the teletext PID diff --git a/HISTORY b/HISTORY index 7a57c9848..819a9f47e 100644 --- a/HISTORY +++ b/HISTORY @@ -921,3 +921,8 @@ Video Disk Recorder Revision History - Status messages are now displayed centered. - Removed the 'Tools' subdirectory from the VDR archive. All contributed tools can now be found at ftp://ftp.cadsoft.de/pub/people/kls/vdr/Tools. + +2002-01-29: Version 0.99pre3 + +- Fixed handling improper buffer lengths in the EIT parser (thanks to Deti + Fliegl). diff --git a/config.h b/config.h index 960e51465..189390a3b 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.88 2002/01/19 16:06:53 kls Exp $ + * $Id: config.h 1.89 2002/01/29 21:53:32 kls Exp $ */ #ifndef __CONFIG_H @@ -18,7 +18,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.99pre2" +#define VDRVERSION "0.99pre3" #define MAXPRIORITY 99 #define MAXLIFETIME 99 diff --git a/libdtv/libsi/include/libsi.h b/libdtv/libsi/include/libsi.h index dda2b1e4e..29079b10d 100644 --- a/libdtv/libsi/include/libsi.h +++ b/libdtv/libsi/include/libsi.h @@ -946,9 +946,9 @@ struct Pid *siParsePMT (u_char *); struct LIST *siParseSDT (u_char *); struct LIST *siParseEIT (u_char *); time_t siParseTDT (u_char *); -void siParseDescriptors (struct LIST *, u_char *, u_int, u_char); +void siParseDescriptors (struct LIST *, u_char *, int, u_char); void siParseDescriptor (struct LIST *, u_char *); -char *siGetDescriptorText (u_char *, u_int); +char *siGetDescriptorText (u_char *, int); u_long crc32 (char *data, int len); /* si_debug_services.c */ diff --git a/libdtv/libsi/si_parser.c b/libdtv/libsi/si_parser.c index 76d72c8f1..e6ca52527 100644 --- a/libdtv/libsi/si_parser.c +++ b/libdtv/libsi/si_parser.c @@ -40,7 +40,7 @@ struct LIST *siParsePAT (u_char *Buffer) pat_t *Pat; pat_prog_t *PatProgram; u_char *Ptr; - u_int SectionLength; + int SectionLength; int TransportStreamID; int PatVersion; struct Program *Program; @@ -87,7 +87,7 @@ struct Pid *siParsePMT (u_char *Buffer) pmt_t *Pmt; pmt_info_t *PmtInfo; u_char *Ptr; - u_int SectionLength, ProgramInfoLength, + int SectionLength, ProgramInfoLength, StreamLength, LoopLength; int ProgramID; int PcrID; @@ -150,7 +150,7 @@ struct LIST *siParseSDT (u_char *Buffer) sdt_t *Sdt; sdt_descr_t *SdtDescriptor; u_char *Ptr; - u_int SectionLength, LoopLength; + int SectionLength, LoopLength; int TransportStreamID; int SdtVersion; int OriginalNetworkID; @@ -229,7 +229,7 @@ struct LIST *siParseEIT (u_char *Buffer) eit_t *Eit; eit_event_t *EitEvent; u_char *Ptr; - u_int SectionLength, LoopLength; + int SectionLength, LoopLength; int ServiceID; int EitVersion; int TransportStreamID; @@ -316,7 +316,7 @@ time_t siParseTDT (u_char *Buffer) { tdt_t *Tdt; u_char *Ptr; - u_int SectionLength; + int SectionLength; int TdtVersion; time_t CurrentTime; @@ -339,9 +339,9 @@ time_t siParseTDT (u_char *Buffer) void siParseDescriptors (struct LIST *Descriptors, u_char *Buffer, - u_int Length, u_char TableID) + int Length, u_char TableID) { - u_int DescriptorLength; + int DescriptorLength; u_char *Ptr; DescriptorLength = 0; @@ -838,7 +838,7 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) /* * ToDo: ETSI conformal text definition */ -char *siGetDescriptorText (u_char *Buffer, u_int Length) +char *siGetDescriptorText (u_char *Buffer, int Length) { char *tmp, *result; int i; From 3db2d636b2757326323418b5293ebc7307bf161d Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Wed, 30 Jan 2002 18:00:00 +0100 Subject: [PATCH 032/307] Version 0.99pre4 - Fixed handling improperly formatted EIT data (thanks to Rolf Hakenes). --- HISTORY | 4 ++++ config.h | 4 ++-- libdtv/libsi/include/libsi.h | 34 ++++++++++++++++++++++++---------- libdtv/libsi/si_parser.c | 28 +++++++++++++++------------- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/HISTORY b/HISTORY index 819a9f47e..a2c2e41b8 100644 --- a/HISTORY +++ b/HISTORY @@ -926,3 +926,7 @@ Video Disk Recorder Revision History - Fixed handling improper buffer lengths in the EIT parser (thanks to Deti Fliegl). + +2002-01-30: Version 0.99pre4 + +- Fixed handling improperly formatted EIT data (thanks to Rolf Hakenes). diff --git a/config.h b/config.h index 189390a3b..42f73378c 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.89 2002/01/29 21:53:32 kls Exp $ + * $Id: config.h 1.90 2002/01/30 18:30:03 kls Exp $ */ #ifndef __CONFIG_H @@ -18,7 +18,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.99pre3" +#define VDRVERSION "0.99pre4" #define MAXPRIORITY 99 #define MAXLIFETIME 99 diff --git a/libdtv/libsi/include/libsi.h b/libdtv/libsi/include/libsi.h index 29079b10d..366387a3f 100644 --- a/libdtv/libsi/include/libsi.h +++ b/libdtv/libsi/include/libsi.h @@ -4,8 +4,8 @@ /// /// ////////////////////////////////////////////////////////////// -// $Revision: 1.4 $ -// $Date: 2001/10/07 10:24:46 $ +// $Revision: 1.6 $ +// $Date: 2002/01/30 17:04:13 $ // $Author: hakenes $ // // (C) 2001 Rolf Hakenes , under the GNU GPL. @@ -32,6 +32,8 @@ #include #include +#define dvb_pid_t int + /* Program Identifier */ @@ -274,7 +276,7 @@ struct Pid { struct PidInfo { struct NODE Node; int StreamType; - int ElementaryPid; + dvb_pid_t ElementaryPid; struct LIST *Descriptors; }; @@ -283,7 +285,7 @@ struct PidInfo { { \ xCreateNode (pidinfo, NULL); \ pidinfo->StreamType = styp; \ - pidinfo->ElementaryPid = epid; \ + pidinfo->ElementaryPid = (dvb_pid_t) epid; \ pidinfo->Descriptors = xNewList (NULL); \ } while (0) @@ -418,7 +420,9 @@ struct BouquetNameDescriptor { #define CreateBouquetNameDescriptor(descr, text) \ do \ { \ - xCreateNode (((struct BouquetNameDescriptor *)descr), text); \ + xCreateNode (((struct BouquetNameDescriptor *)descr), NULL); \ + ((struct NODE *)descr)->Name = text; \ + ((struct NODE *)descr)->HashKey = xHashKey (text); \ ((struct BouquetNameDescriptor *)descr)->Tag = DESCR_BOUQUET_NAME; \ } while (0) @@ -613,7 +617,9 @@ struct ServiceDescriptor { #define CreateServiceDescriptor(descr, styp, prov, name) \ do \ { \ - xCreateNode (((struct ServiceDescriptor *)descr), name); \ + xCreateNode (((struct ServiceDescriptor *)descr), NULL); \ + ((struct NODE *)descr)->Name = name; \ + ((struct NODE *)descr)->HashKey = xHashKey (name); \ ((struct ServiceDescriptor *)descr)->Tag = DESCR_SERVICE; \ ((struct ServiceDescriptor *)descr)->ServiceType = styp; \ ((struct ServiceDescriptor *)descr)->ServiceProvider = prov; \ @@ -678,7 +684,9 @@ struct ComponentDescriptor { #define CreateComponentDescriptor(descr, scnt, ctyp, tag, lc1, lc2, lc3, txt) \ do \ { \ - xCreateNode (((struct ComponentDescriptor *)descr), txt); \ + xCreateNode (((struct ComponentDescriptor *)descr), NULL); \ + ((struct NODE *)descr)->Name = txt; \ + ((struct NODE *)descr)->HashKey = xHashKey (txt); \ ((struct ComponentDescriptor *)descr)->Tag = DESCR_COMPONENT; \ ((struct ComponentDescriptor *)descr)->StreamContent = scnt; \ ((struct ComponentDescriptor *)descr)->ComponentType = ctyp; \ @@ -735,7 +743,9 @@ struct ExtendedEventDescriptor { #define CreateExtendedEventDescriptor(descr, dnum, ldnb, lc1, lc2, lc3, text) \ do \ { \ - xCreateNode (((struct ExtendedEventDescriptor *)descr), text); \ + xCreateNode (((struct ExtendedEventDescriptor *)descr), NULL); \ + ((struct NODE *)descr)->Name = text; \ + ((struct NODE *)descr)->HashKey = xHashKey (text); \ ((struct ExtendedEventDescriptor *)descr)->Tag = DESCR_EXTENDED_EVENT; \ ((struct ExtendedEventDescriptor *)descr)->DescriptorNumber = dnum; \ ((struct ExtendedEventDescriptor *)descr)->LastDescriptorNumber = ldnb; \ @@ -754,7 +764,9 @@ struct ExtendedEventItem { #define CreateExtendedEventItem(itm, dtxt, text) \ do \ { \ - xCreateNode (itm, dtxt); \ + xCreateNode (itm, NULL); \ + ((struct NODE *)itm)->Name = dtxt; \ + ((struct NODE *)itm)->HashKey = xHashKey (dtxt); \ itm->Text = text; \ } while (0) @@ -822,7 +834,9 @@ struct ShortEventDescriptor { #define CreateShortEventDescriptor(descr, name, lc1, lc2, lc3, text) \ do \ { \ - xCreateNode (((struct ShortEventDescriptor *)descr), name); \ + xCreateNode (((struct ShortEventDescriptor *)descr), NULL); \ + ((struct NODE *)descr)->Name = name; \ + ((struct NODE *)descr)->HashKey = xHashKey (name); \ ((struct ShortEventDescriptor *)descr)->Tag = DESCR_SHORT_EVENT; \ ((struct ShortEventDescriptor *)descr)->LanguageCode[0] = lc1; \ ((struct ShortEventDescriptor *)descr)->LanguageCode[1] = lc2; \ diff --git a/libdtv/libsi/si_parser.c b/libdtv/libsi/si_parser.c index e6ca52527..063d93e6a 100644 --- a/libdtv/libsi/si_parser.c +++ b/libdtv/libsi/si_parser.c @@ -4,8 +4,8 @@ /// /// ////////////////////////////////////////////////////////////// -// $Revision: 1.4 $ -// $Date: 2001/10/07 10:24:46 $ +// $Revision: 1.6 $ +// $Date: 2002/01/30 17:04:13 $ // $Author: hakenes $ // // (C) 2001 Rolf Hakenes , under the GNU GPL. @@ -119,7 +119,8 @@ struct Pid *siParsePMT (u_char *Buffer) CreatePid (Pid, ProgramID, PcrID, PmtVersion); - siParseDescriptors (Pid->Descriptors, Ptr, ProgramInfoLength, Pmt->table_id); + if (StreamLength >= 0) siParseDescriptors (Pid->Descriptors, Ptr, + ProgramInfoLength, Pmt->table_id); Ptr += ProgramInfoLength; @@ -209,6 +210,8 @@ struct LIST *siParseSDT (u_char *Buffer) SetPresentFollowing (Service->Status); LoopLength = HILO (SdtDescriptor->descriptors_loop_length); + if (LoopLength > SectionLength - SDT_DESCR_LEN) + return (ServiceList); Ptr += SDT_DESCR_LEN; siParseDescriptors (Service->Descriptors, Ptr, LoopLength, Sdt->table_id); @@ -297,6 +300,8 @@ struct LIST *siParseEIT (u_char *Buffer) Event->Duration = BcdTimeToSeconds (EitEvent->duration); LoopLength = HILO (EitEvent->descriptors_loop_length); + if (LoopLength > SectionLength - EIT_EVENT_LEN) + return (EventList); Ptr += EIT_EVENT_LEN; siParseDescriptors (Event->Descriptors, Ptr, LoopLength, Eit->table_id); @@ -349,6 +354,8 @@ void siParseDescriptors (struct LIST *Descriptors, u_char *Buffer, while (DescriptorLength < Length) { + if ((GetDescriptorLength (Ptr) > Length - DescriptorLength) || + (GetDescriptorLength (Ptr) <= 0)) return; switch (TableID) { case TID_NIT_ACT: case TID_NIT_OTH: @@ -554,7 +561,6 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) Text = siGetDescriptorText (Buffer + DESCR_BOUQUET_NAME_LEN, GetDescriptorLength (Buffer) - DESCR_BOUQUET_NAME_LEN); CreateBouquetNameDescriptor (Descriptor, Text); -// xMemFree (Text); break; case DESCR_COMPONENT: @@ -567,7 +573,6 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) CastComponentDescriptor(Buffer)->lang_code1, CastComponentDescriptor(Buffer)->lang_code2, CastComponentDescriptor(Buffer)->lang_code3, Text); -// xMemFree (Text); break; case DESCR_SERVICE: @@ -579,7 +584,6 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) CastServiceDescriptor(Buffer)->provider_name_length))); CreateServiceDescriptor (Descriptor, CastServiceDescriptor(Buffer)->service_type, Text, Text2); -// xMemFree (Text2); break; case DESCR_COUNTRY_AVAIL: @@ -603,7 +607,6 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) CastShortEventDescriptor(Buffer)->lang_code1, CastShortEventDescriptor(Buffer)->lang_code2, CastShortEventDescriptor(Buffer)->lang_code3, Text2); -// xMemFree (Text); break; case DESCR_EXTENDED_EVENT: @@ -617,10 +620,9 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) CastExtendedEventDescriptor(Buffer)->lang_code1, CastExtendedEventDescriptor(Buffer)->lang_code2, CastExtendedEventDescriptor(Buffer)->lang_code3, Text); -// xMemFree (Text); Length = CastExtendedEventDescriptor(Buffer)->length_of_items; Ptr += DESCR_EXTENDED_EVENT_LEN; - while (Length > 0) + while ((Length > 0) && (Length < GetDescriptorLength (Buffer))) { Text = siGetDescriptorText (Ptr + ITEM_EXTENDED_EVENT_LEN, CastExtendedEventItem(Ptr)->item_description_length); @@ -629,7 +631,6 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) *((u_char *)(Ptr + ITEM_EXTENDED_EVENT_LEN + CastExtendedEventItem(Ptr)->item_description_length))); AddExtendedEventItem (Descriptor, Text2, Text); -// xMemFree (Text2); Length -= ITEM_EXTENDED_EVENT_LEN + CastExtendedEventItem(Ptr)->item_description_length + *((u_char *)(Ptr + ITEM_EXTENDED_EVENT_LEN + CastExtendedEventItem(Ptr)->item_description_length)) + 1; @@ -760,7 +761,7 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer) ASVC_FLAG, CastAc3Descriptor(Buffer)->asvc); } Length -= DESCR_AC3_LEN; Ptr += DESCR_AC3_LEN; - if (Length) AddAc3AdditionalData (Descriptor, Ptr, Length); + if (Length > 0) AddAc3AdditionalData (Descriptor, Ptr, Length); break; case DESCR_SUBTITLING: @@ -843,6 +844,8 @@ char *siGetDescriptorText (u_char *Buffer, int Length) char *tmp, *result; int i; + if ((Length < 0) || (Length > 4095)) + return (xSetText ("text error")); if (*Buffer == 0x05 || (*Buffer >= 0x20 && *Buffer <= 0xff)) { xMemAlloc (Length+1, &result); @@ -852,9 +855,8 @@ char *siGetDescriptorText (u_char *Buffer, int Length) if (*Buffer == 0) break; if ((*Buffer >= ' ' && *Buffer <= '~') || - (*Buffer == '\n') || (*Buffer >= 0xa0 && *Buffer <= 0xff)) *tmp++ = *Buffer; - if (*Buffer == 0x8A) *tmp++ = '\n'; + if (*Buffer == 0x8A || *Buffer == '\n') *tmp++ = '\n'; if (*Buffer == 0x86 || *Buffer == 0x87) *tmp++ = ' '; Buffer++; } From ef0a53af7282b14bd40f2087de28fc12a94e672b Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 3 Feb 2002 18:00:00 +0100 Subject: [PATCH 033/307] Version 0.99pre5 - Updated channel settings for 'N24' (thanks to Andreas Gebel). - Fixed handling hierarchical recordings menu in case of directories starting with the same sequence of characters. - Fixed handling timers on the 29th, 30th or 31st of a month in case the next month has less than 31 days. - Added a description of the sort order of individual episodes in the recordings menu to the MANUAL. - Removed the EPG bugfix for "Title / Subtitle" cleanup. Apparently Pro-7 has finally stopped this nasty habit. - Added some EPG bugfix statistics (printed to the log file every time the EPG data is cleaned up and when VDR is terminated). Maybe somebody in charge of the EPG data at the listed channels will read this and take the necessary actions to fix these things... - Changed the [dei]syslog macros in tools.h to use a variable number of args, thus making it safe to use them in nested 'if/else' statements. - Fixed error handling in establishing an SVDRP connection (thanks to Davide Achilli) for pointing this out). - The new configuration file 'svdrphosts.conf' is now used to define which hosts may access the SVDRP port (by default only 'localhost' has access). See FORMATS for details. - The special keywords TITLE and EPISODE can now be used in timer file names (see MANUAL and FORMATS for details). - The new setup parameter NameInstantRecord can be used to define how an instant recording will be named (see MANUAL for details). - When looking for the EPG record of the timer that starts a recording, now that record is taken which covers the time calculated as 'start + (Setup.MarginStart * 2) + 1)' in order to have a better chance of hitting the right record in case of an instant recording. Timers that start further in the future should always be programmed via the "Schedules" menu. - The special VPIDs '0' and '1' are now used to enable recording radio channels. Actually '0' should be enough, but '1' must be used with encrypted channels (driver bug?). Note, though, that since VDR is mainly a *video recorder*, some features like, e. g., the progress display, may not work as expected with radio recordings. Thanks to Michael Paar. - Fixed a problem with the ERR macro defined by ncurses.h (thanks to Artur Skawina). --- CONTRIBUTORS | 10 +++ FORMATS | 27 ++++++++- HISTORY | 39 ++++++++++++ INSTALL | 5 ++ MANUAL | 16 +++++ Makefile | 4 +- channels.conf | 2 +- config.c | 158 +++++++++++++++++++++++++++++++++--------------- config.h | 35 +++++++++-- dvbapi.c | 17 ++---- dvbapi.h | 3 +- dvbosd.h | 3 +- eit.c | 85 +++++++++++++++++++++----- gmon.out | Bin 0 -> 101224 bytes i18n.c | 11 +++- menu.c | 13 ++-- recording.c | 31 +++++++--- recording.h | 4 +- remux.c | 16 ++++- svdrp.c | 16 +++-- svdrphosts.conf | 13 ++++ tools.c | 23 ++++++- tools.h | 9 +-- vdr.c | 3 +- 24 files changed, 427 insertions(+), 116 deletions(-) create mode 100644 gmon.out create mode 100644 svdrphosts.conf diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1d06173f0..e0b9ee1c9 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -137,6 +137,7 @@ Matjaz Thaler Artur Skawina for improving the font file generation in the Makefile + for pointing out a problem with the ERR macro defined by ncurses.h Werner Fink for making I/O more robust by handling EINTR @@ -179,3 +180,12 @@ Lauri Pesonen Sergei Haller for fixing the LastActivity timestamp after a shutdown prompt + +Andreas Gebel + for his help in keeping 'channels.conf' up to date + +Davide Achilli + for pointing out a bug in error handling while establishing an SVDRP connection + +Michael Paar + for enabling recording of radio channels diff --git a/FORMATS b/FORMATS index 2a99e6efa..d7d4293c4 100644 --- a/FORMATS +++ b/FORMATS @@ -24,7 +24,7 @@ Video Disk Recorder File Formats - Polarization (one of 'h', 'H', 'v', 'V') ** - Diseqc number ** - Symbol rate *** - - Video PID + - Video PID (set to '0' for radio channels, '1' for encrypted radio channels) - Audio PID (either one number, or two, separated by a comma) If this channel also carries Dolby Digital sound, the Dolby PIDs follow the audio PIDs, separated by a semicolon, as in "...:101,102;103,104:..." @@ -72,6 +72,11 @@ Video Disk Recorder File Formats any ':' characters, these have to be replaced with '|'. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name). + The special keywords TITLE and EPISODE, if present, will be replaced + with the title and episode information from the EPG data at the time of + recording (if that data is available). If at the time of recording either + of these cannot be determined, TITLE will default to the channel name, and + EPISODE will default to a blank. - Summary (any newline characters in the summary have to be replaced with '|'; the summary may contain ':' characters) @@ -111,6 +116,26 @@ Video Disk Recorder File Formats 1..9, the command can be selected directly by pressing the respective numerical key on the remote control. +* svdrphosts.conf + + This file contains the IP numbers of all hosts that are allowed to access the + SVDRP port. + + Each line contains one IP number in the format + + IP-Address[/Netmask] + + where 'IP-Address' is the address of a host or a network in the usual dot + separated notation (as in 192.168.100.1). If the optional 'Netmask' is given + only the given number of bits of 'IP-Address' are taken into account. This + allows you to grant SVDRP access to all hosts of an entire network. 'Netmask' + can be any integer from 1 to 32. The special value of 0 is only accepted if + the 'IP-Address' is 0.0.0.0, because this will give access to any host (USE + THIS WITH CARE!). + + Everything following (and including) a '#' character is considered to be + comment. + * marks.vdr This file (if present in a recording directory) contains the editing marks diff --git a/HISTORY b/HISTORY index a2c2e41b8..bf8ce2c9c 100644 --- a/HISTORY +++ b/HISTORY @@ -930,3 +930,42 @@ Video Disk Recorder Revision History 2002-01-30: Version 0.99pre4 - Fixed handling improperly formatted EIT data (thanks to Rolf Hakenes). + +2002-02-03: Version 0.99pre5 + +- Updated channel settings for 'N24' (thanks to Andreas Gebel). +- Fixed handling hierarchical recordings menu in case of directories starting + with the same sequence of characters. +- Fixed handling timers on the 29th, 30th or 31st of a month in case the next + month has less than 31 days. +- Added a description of the sort order of individual episodes in the + recordings menu to the MANUAL. +- Removed the EPG bugfix for "Title / Subtitle" cleanup. Apparently Pro-7 has + finally stopped this nasty habit. +- Added some EPG bugfix statistics (printed to the log file every time the EPG + data is cleaned up and when VDR is terminated). Maybe somebody in charge of + the EPG data at the listed channels will read this and take the necessary + actions to fix these things... +- Changed the [dei]syslog macros in tools.h to use a variable number of args, + thus making it safe to use them in nested 'if/else' statements. +- Fixed error handling in establishing an SVDRP connection (thanks to Davide + Achilli) for pointing this out). +- The new configuration file 'svdrphosts.conf' is now used to define which + hosts may access the SVDRP port (by default only 'localhost' has access). + See FORMATS for details. +- The special keywords TITLE and EPISODE can now be used in timer file names + (see MANUAL and FORMATS for details). +- The new setup parameter NameInstantRecord can be used to define how an + instant recording will be named (see MANUAL for details). +- When looking for the EPG record of the timer that starts a recording, now + that record is taken which covers the time calculated as + 'start + (Setup.MarginStart * 2) + 1)' in order to have a better chance of + hitting the right record in case of an instant recording. Timers that start + further in the future should always be programmed via the "Schedules" menu. +- The special VPIDs '0' and '1' are now used to enable recording radio channels. + Actually '0' should be enough, but '1' must be used with encrypted channels + (driver bug?). Note, though, that since VDR is mainly a *video recorder*, some + features like, e. g., the progress display, may not work as expected with + radio recordings. Thanks to Michael Paar. +- Fixed a problem with the ERR macro defined by ncurses.h (thanks to Artur + Skawina). diff --git a/INSTALL b/INSTALL index d16509611..cf694890e 100644 --- a/INSTALL +++ b/INSTALL @@ -81,6 +81,11 @@ WARNING: DUE TO THE OPEN SVDRP PORT THIS PROGRAM MAY CONSTITUTE A A CONTROLLED ENVIRONMENT, YOU MAY WANT TO DISABLE SVDRP BY USING '--port=0'! +The file 'svdrphosts.conf' can be used to define which hosts are allowed +to access the SVDRP port. By default only localhost (127.0.0.1) is granted +access. If you want to give other hosts access to your SVDRP port you need to +add their IP numbers to 'svdrphosts.conf'. + If the program shall run as a daemon, use the --daemon option. This will completely detach it from the terminal and will continue as a background process. diff --git a/MANUAL b/MANUAL index 99d91be94..d0ce7a2cf 100644 --- a/MANUAL +++ b/MANUAL @@ -166,6 +166,14 @@ Video Disk Recorder User's Manual that directory (and any possible subdirectory thereof) as well as the total number of new recordings (as opposed to a recording's entry, which displays the date and time of the recording). + + If the setup parameter UseSubtitle was turned on when a recording took place, + VDR adds the "subtitle" (which is usually the name of the episode in case of + a series) to the recording's name. The "Recordings" menu then displays all + recordings of a periodic timer in chronological order, since these are + usually the individual episodes of a series, which you may want to view in + the order in which they were broadcast. + Playback can be stopped via the "Main" menu by selecting "Stop replaying", or by pressing the "Blue" button outside the menu. A previously stopped playback session can be resumed by pressing the "Blue" @@ -377,6 +385,14 @@ Video Disk Recorder User's Manual 0 = instant recordings will not be marked 1 = instant recordings will be marked. + NameInstantRecord = TITLE-EPISODE + Defines how to name an instant recording. If the keywords + TITLE and/or EPISODE are present, they will be replaced + with the title and episode information from the EPG data + at the time of recording (if that data is available). + If this parameter is empty, the channel name will be used + by default. + LnbSLOF = 11700 The switching frequency (in MHz) between low and high LOF LnbFrequLo = 9750 The LNB's low and high local oscillator frequencies (in MHz) LnbFrequHi = 10600 (these have no meaning for DVB-C receivers) diff --git a/Makefile b/Makefile index 38597e8d6..f74179d93 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.29 2002/01/13 16:57:27 kls Exp $ +# $Id: Makefile 1.30 2002/02/01 14:40:09 kls Exp $ .DELETE_ON_ERROR: @@ -105,7 +105,7 @@ $(DTVLIB) $(DTVDIR)/libdtv.h: clean: make -C $(AC3DIR) clean make -C $(DTVDIR) clean - -rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core *~ + -rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~ fontclean: -rm -f fontfix.c fontosd.c CLEAN: clean fontclean diff --git a/channels.conf b/channels.conf index a2bd32fb1..87796ae26 100644 --- a/channels.conf +++ b/channels.conf @@ -96,7 +96,7 @@ Cinedom 5A:11758:h:0:27500:1279:1280:0:3:194 Cinedom 5B:11720:h:0:27500:1791:1792:0:3:177 Cinedom 5C:12070:h:0:27500:1023:1024:0:3:186 :Beta Digital -N24:11914:H:0:27500:255:256:8191:3:52 +N24:12480:v:0:27500:2047:2048:0:0:47 CNBC:11954:h:0:27500:510:520:0:0:28010 Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199 :PW Erotic diff --git a/config.c b/config.c index f93035142..974aed0c2 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.77 2002/01/19 16:06:42 kls Exp $ + * $Id: config.c 1.82 2002/02/03 15:25:44 kls Exp $ */ #include "config.h" @@ -296,9 +296,8 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log) if (!DvbApi) DvbApi = cDvbApi::PrimaryDvbApi; if (!DvbApi->Recording() && !groupSep) { - if (Log) { + if (Log) isyslog(LOG_INFO, "switching to channel %d", number); - } for (int i = 3; i--;) { switch (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr)) { case scrOk: return true; @@ -341,7 +340,7 @@ cTimer::cTimer(bool Instant) *file = 0; summary = NULL; if (Instant && ch) - snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", ch->name); + snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : ch->name); } cTimer::cTimer(const cEventInfo *EventInfo) @@ -540,6 +539,13 @@ time_t cTimer::SetTime(time_t t, int SecondsFromMidnight) return mktime(&tm); } +char *cTimer::SetFile(const char *File) +{ + if (!isempty(File)) + strn0cpy(file, File, sizeof(file)); + return file; +} + bool cTimer::Matches(time_t t) { startTime = stopTime = 0; @@ -551,7 +557,7 @@ bool cTimer::Matches(time_t t) if (length < 0) length += SECSINDAY; - int DaysToCheck = IsSingleEvent() ? 31 : 7; + int DaysToCheck = IsSingleEvent() ? 61 : 7; // 61 to handle months with 31/30/31 for (int i = -1; i <= DaysToCheck; i++) { time_t t0 = IncDay(t, i); if (DayMatches(t0)) { @@ -647,6 +653,40 @@ const char *cCommand::Execute(void) return result; } +// -- cSVDRPhost ------------------------------------------------------------- + +cSVDRPhost::cSVDRPhost(void) +{ + addr.s_addr = 0; + mask = 0; +} + +bool cSVDRPhost::Parse(const char *s) +{ + mask = 0xFFFFFFFF; + const char *p = strchr(s, '/'); + if (p) { + char *error = NULL; + int m = strtoul(p + 1, &error, 10); + if (error && !isspace(*error) || m > 32) + return false; + *(char *)p = 0; // yes, we know it's 'const' - will be restored! + if (m == 0) + mask = 0; + else + mask >>= (32 - m); + } + int result = inet_aton(s, &addr); + if (p) + *(char *)p = '/'; // there it is again + return result != 0 && (mask != 0 || addr.s_addr == 0); +} + +bool cSVDRPhost::Accepts(in_addr_t Address) +{ + return (Address & mask) == addr.s_addr; +} + // -- cKeys ------------------------------------------------------------------ cKeys Keys; @@ -659,9 +699,9 @@ cCommands Commands; cChannels Channels; -bool cChannels::Load(const char *FileName) +bool cChannels::Load(const char *FileName, bool AllowComments) { - if (cConfig::Load(FileName)) { + if (cConfig::Load(FileName, AllowComments)) { ReNumber(); return true; } @@ -779,6 +819,21 @@ cTimer *cTimers::GetNextActiveTimer(void) return t0; } +// -- cSVDRPhosts ------------------------------------------------------------ + +cSVDRPhosts SVDRPhosts; + +bool cSVDRPhosts::Acceptable(in_addr_t Address) +{ + cSVDRPhost *h = First(); + while (h) { + if (h->Accepts(Address)) + return true; + h = (cSVDRPhost *)h->Next(); + } + return false; +} + // -- cSetup ----------------------------------------------------------------- cSetup Setup; @@ -792,6 +847,7 @@ cSetup::cSetup(void) ShowInfoOnChSwitch = 1; MenuScrollPage = 1; MarkInstantRecord = 1; + strcpy(NameInstantRecord, "TITLE-EPISODE"); LnbSLOF = 11700; LnbFrequLo = 9750; LnbFrequHi = 10600; @@ -825,47 +881,51 @@ cSetup::cSetup(void) bool cSetup::Parse(char *s) { - const char *Delimiters = " \t\n="; - char *Name = strtok(s, Delimiters); - char *Value = strtok(NULL, Delimiters); - if (Name && Value) { - if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value); - else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); - else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); - else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); - else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); - else if (!strcasecmp(Name, "LnbSLOF")) LnbSLOF = atoi(Value); - else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); - else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); - else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value); - else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); - else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); - else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); - else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); - else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); - else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); - else if (!strcasecmp(Name, "SortTimers")) SortTimers = atoi(Value); - else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); - else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); - else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); - else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); - else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); - else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); - else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); - else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); - else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); - else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); - else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); - else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); - else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); - else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); - else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); - else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); - else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); - else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); - else - return false; - return true; + char *p = strchr(s, '='); + if (p) { + *p = 0; + char *Name = compactspace(s); + char *Value = compactspace(p + 1); + if (*Name && *Value) { + if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value); + else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); + else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); + else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); + else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); + else if (!strcasecmp(Name, "NameInstantRecord")) strn0cpy(NameInstantRecord, Value, MaxFileName); + else if (!strcasecmp(Name, "LnbSLOF")) LnbSLOF = atoi(Value); + else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); + else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); + else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value); + else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); + else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); + else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); + else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); + else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); + else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); + else if (!strcasecmp(Name, "SortTimers")) SortTimers = atoi(Value); + else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); + else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); + else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); + else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); + else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); + else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); + else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); + else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); + else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); + else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); + else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); + else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); + else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); + else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); + else + return false; + return true; + } } return false; } @@ -882,6 +942,7 @@ bool cSetup::Load(const char *FileName) bool result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; + stripspace(buffer); if (!isempty(buffer)) { if (*buffer != '#' && !Parse(buffer)) { esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); @@ -911,6 +972,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch); fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage); fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord); + fprintf(f, "NameInstantRecord = %s\n", NameInstantRecord); fprintf(f, "LnbSLOF = %d\n", LnbSLOF); fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo); fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); diff --git a/config.h b/config.h index 42f73378c..325f4ef28 100644 --- a/config.h +++ b/config.h @@ -4,12 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.90 2002/01/30 18:30:03 kls Exp $ + * $Id: config.h 1.93 2002/02/03 15:16:21 kls Exp $ */ #ifndef __CONFIG_H #define __CONFIG_H +#include #include #include #include @@ -18,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.99pre4" +#define VDRVERSION "0.99pre5" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -65,6 +66,8 @@ enum eKeys { // "Up" and "Down" must be the first two keys! #define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) #define NORMALKEY(k) (eKeys((k) & ~k_Repeat)) +#define MaxFileName 256 + struct tKey { eKeys type; char *name; @@ -122,7 +125,6 @@ class cTimer : public cListObject { static char *buffer; static const char *ToText(cTimer *Timer); public: - enum { MaxFileName = 256 }; bool recording, pending; int active; int channel; @@ -148,6 +150,7 @@ class cTimer : public cListObject { bool DayMatches(time_t t); time_t IncDay(time_t t, int Days); time_t SetTime(time_t t, int SecondsFromMidnight); + char *SetFile(const char *File); bool Matches(time_t t = 0); time_t StartTime(void); time_t StopTime(void); @@ -171,6 +174,16 @@ class cCommand : public cListObject { const char *Execute(void); }; +class cSVDRPhost : public cListObject { +private: + struct in_addr addr; + in_addr_t mask; +public: + cSVDRPhost(void); + bool Parse(const char *s); + bool Accepts(in_addr_t Address); + }; + template class cConfig : public cList { private: char *fileName; @@ -182,7 +195,7 @@ template class cConfig : public cList { public: cConfig(void) { fileName = NULL; } virtual ~cConfig() { delete fileName; } - virtual bool Load(const char *FileName) + virtual bool Load(const char *FileName, bool AllowComments = false) { Clear(); fileName = strdup(FileName); @@ -196,6 +209,11 @@ template class cConfig : public cList { result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; + if (AllowComments) { + char *p = strchr(buffer, '#'); + if (p) + *p = 0; + } if (!isempty(buffer)) { T *l = new T; if (l->Parse(buffer)) @@ -242,7 +260,7 @@ class cChannels : public cConfig { int maxNumber; public: cChannels(void) { maxNumber = 0; } - virtual bool Load(const char *FileName); + virtual bool Load(const char *FileName, bool AllowComments = false); int GetNextGroup(int Idx); // Get next channel group int GetPrevGroup(int Idx); // Get previous channel group int GetNextNormal(int Idx); // Get next normal channel (not group) @@ -263,10 +281,16 @@ class cTimers : public cConfig { class cCommands : public cConfig {}; +class cSVDRPhosts : public cConfig { +public: + bool Acceptable(in_addr_t Address); + }; + extern cChannels Channels; extern cTimers Timers; extern cKeys Keys; extern cCommands Commands; +extern cSVDRPhosts SVDRPhosts; class cSetup { private: @@ -279,6 +303,7 @@ class cSetup { int ShowInfoOnChSwitch; int MenuScrollPage; int MarkInstantRecord; + char NameInstantRecord[MaxFileName]; int LnbSLOF; int LnbFrequLo; int LnbFrequHi; diff --git a/dvbapi.c b/dvbapi.c index 048639c66..314d91f6c 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz * based on dvdplayer-0.5 by Matjaz Thaler * - * $Id: dvbapi.c 1.146 2002/01/26 15:39:48 kls Exp $ + * $Id: dvbapi.c 1.147 2002/02/02 13:04:00 kls Exp $ */ //#define DVDDEBUG 1 @@ -548,9 +548,8 @@ void cRecordBuffer::Input(void) } else if (r < 0) { if (FATALERRNO) { - if (errno == EBUFFEROVERFLOW) { // this error code is not defined in the library + if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); - } else { LOG_ERROR; break; @@ -1064,9 +1063,8 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const return; // Create the index file: index = new cIndexFile(FileName, false); - if (!index) { + if (!index) esyslog(LOG_ERR, "ERROR: can't allocate index"); - } else if (!index->Ok()) { delete index; index = NULL; @@ -2251,9 +2249,8 @@ void cTransferBuffer::Input(void) } else if (r < 0) { if (FATALERRNO) { - if (errno == EBUFFEROVERFLOW) { // this error code is not defined in the library + if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); - } else { LOG_ERROR; break; @@ -2719,12 +2716,10 @@ bool cDvbApi::Init(void) } } PrimaryDvbApi = dvbApi[0]; - if (NumDvbApis > 0) { + if (NumDvbApis > 0) isyslog(LOG_INFO, "found %d video device%s", NumDvbApis, NumDvbApis > 1 ? "s" : ""); - } // need braces because of isyslog-macro - else { + else esyslog(LOG_ERR, "ERROR: no video device found, giving up!"); - } return NumDvbApis > 0; } diff --git a/dvbapi.h b/dvbapi.h index 733757195..fbc1e9d94 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.60 2002/01/26 13:01:16 kls Exp $ + * $Id: dvbapi.h 1.61 2002/02/03 16:43:38 kls Exp $ */ #ifndef __DVBAPI_H @@ -12,6 +12,7 @@ #if defined(DEBUG_OSD) || defined(REMOTE_KBD) #include +#undef ERR //XXX ncurses defines this - but this clashes with newer system header files #endif #include // FIXME: this is apparently necessary for the ost/... header files // FIXME: shouldn't every header file include ALL the other header diff --git a/dvbosd.h b/dvbosd.h index ceac507d3..0e90414cc 100644 --- a/dvbosd.h +++ b/dvbosd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.h 1.9 2001/12/09 15:11:05 kls Exp $ + * $Id: dvbosd.h 1.10 2002/02/03 16:43:50 kls Exp $ */ #ifndef __DVBOSD_H @@ -12,6 +12,7 @@ #if defined(DEBUG_OSD) || defined(REMOTE_KBD) #include +#undef ERR //XXX ncurses defines this - but this clashes with newer system header files #endif #include #include diff --git a/eit.c b/eit.c index ed757d2cc..2860fc4c6 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.31 2002/01/13 16:14:31 kls Exp $ + * $Id: eit.c 1.33 2002/02/02 12:12:26 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -352,6 +352,64 @@ void cEventInfo::Dump(FILE *f, const char *Prefix) const } } +#define MAXEPGBUGFIXSTATS 6 +#define MAXEPGBUGFIXCHANS 50 +struct tEpgBugFixStats { + int hits; + int n; + unsigned short serviceIDs[MAXEPGBUGFIXCHANS]; + tEpgBugFixStats(void) { hits = n = 0; } + }; + +tEpgBugFixStats EpgBugFixStats[MAXEPGBUGFIXSTATS]; + +static void EpgBugFixStat(int Number, unsigned int ServiceID) +{ + if (0 <= Number && Number < MAXEPGBUGFIXSTATS) { + tEpgBugFixStats *p = &EpgBugFixStats[Number]; + p->hits++; + int i = 0; + for (; i < p->n; i++) { + if (p->serviceIDs[i] == ServiceID) + break; + } + if (i == p->n && p->n < MAXEPGBUGFIXCHANS) + p->serviceIDs[p->n++] = ServiceID; + } +} + +static void ReportEpgBugFixStats(bool Reset = false) +{ + if (Setup.EPGBugfixLevel > 0) { + dsyslog(LOG_INFO, "====================="); + dsyslog(LOG_INFO, "EPG bugfix statistics"); + dsyslog(LOG_INFO, "====================="); + dsyslog(LOG_INFO, "IF SOMEBODY WHO IS IN CHARGE OF THE EPG DATA FOR ONE OF THE LISTED"); + dsyslog(LOG_INFO, "CHANNELS READS THIS: PLEASE TAKE A LOOK AT THE FUNCTION cEventInfo::FixEpgBugs()"); + dsyslog(LOG_INFO, "IN VDR/eit.c TO LEARN WHAT'S WRONG WITH YOUR DATA, AND FIX IT!"); + dsyslog(LOG_INFO, "====================="); + dsyslog(LOG_INFO, "Fix\tHits\tChannels"); + char buffer[1024]; + for (int i = 0; i < MAXEPGBUGFIXSTATS; i++) { + const char *delim = "\t"; + tEpgBugFixStats *p = &EpgBugFixStats[i]; + char *q = buffer; + q += snprintf(q, sizeof(buffer) - (q - buffer), "%d\t%d", i, p->hits); + for (int c = 0; c < p->n; c++) { + cChannel *channel = Channels.GetByServiceID(p->serviceIDs[c]); + if (channel) { + q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->name); + delim = ", "; + } + } + dsyslog(LOG_INFO, "%s", buffer); + if (Reset) + p->hits = p->n = 0; + } + dsyslog(LOG_INFO, "====================="); + } +} + void cEventInfo::FixEpgBugs(void) { // VDR can't usefully handle newline characters in the EPG data, so let's @@ -367,20 +425,6 @@ void cEventInfo::FixEpgBugs(void) // EPG data. Let's fix their bugs as good as we can: if (pTitle) { - // Pro7 preceeds the Subtitle with the Title: - // - // Title - // Title / Subtitle - // - if (pSubtitle && strstr(pSubtitle, pTitle) == pSubtitle) { - char *p = pSubtitle + strlen(pTitle); - const char *delim = " / "; - if (strstr(p, delim) == p) { - p += strlen(delim); - memmove(pSubtitle, p, strlen(p) + 1); - } - } - // VOX and VIVA put the Subtitle in quotes and use either the Subtitle // or the Extended Description field, depending on how long the string is: // @@ -400,6 +444,7 @@ void cEventInfo::FixEpgBugs(void) delete pExtendedDescription; pSubtitle = s; pExtendedDescription = d; + EpgBugFixStat(0, GetServiceID()); } } } @@ -416,6 +461,7 @@ void cEventInfo::FixEpgBugs(void) memmove(pSubtitle, pSubtitle + 1, strlen(pSubtitle)); pExtendedDescription = pSubtitle; pSubtitle = NULL; + EpgBugFixStat(1, GetServiceID()); } } @@ -427,6 +473,7 @@ void cEventInfo::FixEpgBugs(void) if (pSubtitle && strcmp(pTitle, pSubtitle) == 0) { delete pSubtitle; pSubtitle = NULL; + EpgBugFixStat(2, GetServiceID()); } // ZDF.info puts the Subtitle between double quotes, which is nothing @@ -442,6 +489,7 @@ void cEventInfo::FixEpgBugs(void) char *p = strrchr(pSubtitle, '"'); if (p) *p = 0; + EpgBugFixStat(3, GetServiceID()); } } @@ -460,8 +508,10 @@ void cEventInfo::FixEpgBugs(void) char *p = pExtendedDescription + 1; while (*p) { if (*p == '-' && *(p + 1) == ' ' && *(p + 2) && islower(*(p - 1)) && islower(*(p + 2))) { - if (!startswith(p + 2, "und ")) // special case in German, as in "Lach- und Sachgeschichten" + if (!startswith(p + 2, "und ")) { // special case in German, as in "Lach- und Sachgeschichten" memmove(p, p + 2, strlen(p + 2) + 1); + EpgBugFixStat(4, GetServiceID()); + } } p++; } @@ -845,6 +895,8 @@ cSIProcessor::cSIProcessor(const char *FileName) cSIProcessor::~cSIProcessor() { + if (masterSIProcessor) + ReportEpgBugFixStats(); active = false; Cancel(3); ShutDownFilters(); @@ -913,6 +965,7 @@ void cSIProcessor::Action() schedules->Cleanup(); schedulesMutex.Unlock(); lastCleanup = now; + ReportEpgBugFixStats(true); } if (epgDataFileName && now - lastDump > 600) { diff --git a/gmon.out b/gmon.out new file mode 100644 index 0000000000000000000000000000000000000000..ea79bc54bbd4e662e4d8c094175c3df7d5c3504b GIT binary patch literal 101224 zcmeI4@pGI-8OQJ1d+!#S!K6e88Zoq>(Fu5ML#Jwys|gy0IHa^wBMlhZD+CE8P}Hhn zOxuhE2ymqlgGRm5j>MUaUTKgb6^^!QWTKM-!(_(HaG}?lAA%kGcg}#e;zY?=i=r!+;7*n8FlbD<({#1bDN|PUF;XG3?*j z+0J7IWEON$OyR=@OqfD;EM^X4JUZ;wg5S<^8PC0dhLW zo+(}KnI$rWs!w@lCBD#NbuKiykanTRg+UiaT^M(v=t3mvG+OOK3Xp5G-5CK$N40M` zz$^V0<^dCrTbNwonYSOdPz0>M%EByQ-G-nJVE=jxk(Kyxy@j$Xopve#m(<%x6W~B# zC$-u$FCmF`X8>@^Oxz?FL1OP`J#+R}&){<;T87peZnuyI?77WC7I5}X3zeVq%r6Nscdv#QfGx67kxuzxJQ#_l2YF0{JP?LyXtS-{D^#Qhy<9w5Wk z?J4#}-;P4M$!VwCg+Ui`E{wTQa3OV_XMPq-`0bQ8duBQqLK+Z`=LBHG4{UelzT}w- z7}f5Wn>>@h(W+_(w6|O618lh2!T>%Tz)r5>^IPy?vz0jE!YrWc2^-nC6?Ks9>ARtK z3LtgjI&*1168T6h5^VjzHHd_BRC&5lYm|*A*Oyf30rA{B#&El`x zwKEKmMzsf10I8!;l42Nw4!aynGLOz`q#h6!YXXRPjr0S;Asn^Ev~P7-#_NKP4gq$c zODbdxa2$P8Sc?TN5w+6+xEqZs415#wgF~XB0z*jc^z_6~IPq;Pm%qi$pH?6;=fb7m zaU#WTJdHRp{9-Pc`g3TJ z1#}^zP__qy!xw8{Bw7oQI=5{COad~1`(9XrtA~xe_{T&fI@0Tz0!I7z5){i@m=@^% zp5Hg!YEA&cJ$@eW=KXd`s`23fhM}{N1jsq3kQTt7!aP1?(D3PhqS4+5{KzFM(as1! z5?m`n@)AJ;g*jVHq546;&Nb(v*jm70WIIow-GYiA0PMk3>dYOKI>@FlX^Sb$18Tly zi&Z`Z*MOO7WUFW5NCJfs zTSwt2paP3YhcFIE1uzL{51pg(3zhir7-mmrt^hcB%3d_rK8!_<3Darp z1$_Qd3mL#Ar)@Fw2sV@e$_0X>tr?ID5_ABz6m6XrWRh)NQ?~)u2aR?B!UR2l-QTy3 z_Pa3T!mtZRTo`j<5|9bnDFI}^)*e*t!_>bOHy2$di^7FjfOPbO5}5}`M-{3DaESML zKGXtMVa;h|4M5saXaPimNC!X~)kqpgM|iaL0!~4d?o~s8@GM!7VsF}xmJMRt2!^m0 zP(W0N(CNbD4?VN5&(^8=5q7>uEHna6J!4@8aQ=f9767mO%0kx=ihagDfLTE4Cl>Mm zxuNKzxd15q)H7FuqGdnEdV4V8LoMLe#TFU?%O8!KbyBPwAa$-4$N)a}M%;&kfQf1Q zLtqy0HqvYAc|d6dw^gYVL*>j>wg-KHmjJp&&jCtT2Um{+p4kh~ExPWPnBYv@@AVKs ze&rxpB-)k4EeMxqg)Cqt8db;vmanvRjsW(pvXBS7g1f&KE3Sx}y+NH6%9kU(My3Gm z=#s($pzx%HGGux(VmG@EKo}VT$fD4T*-=0bZfXh>fIPNB-J(r>{N4S!8X#NE1!yQ* z3y|L>3MqhWH44pcqz!O3*zmgmVS;YASOyR#7;+<%QYRQ((MEKnu`AJ0Y+MSJfN*eY zTxbSJN3~e53t2#zAm`S3&4r>{r+PKo3A$4Y2IXehpEzqS{K&3(BeYcg`F<+xsY`s=fVjWih%H^RRll%!y~i~Q22^{PTO2a-Vry) zOz?XSu;UyHX+W5*8_@7wo1m)GNu2~N3+ik{k=^In1l2v5tiReiDZmXMu#sj!O#oT! zImuw($>BqImb5((fA_?w$DR|O7%4z_E;Iw$g9LeiJPS)OC(&`hihc`)hx|D`S0au0 zR&MJT2($rYC&x7;5}g5P9f7`wZ8m{}fWwkaiveVXDAZx6jAZOcN3m&zP=#-Ipr~%q z?H2Tf$`C+0s!MqRumXP?soCo!r~^nlS}gf=+}wgcU2kopakC%rb?MIBGjUToWFrym z$SqOpx*QNrV-c|FSz9cI58(=_0^AeSsR1kt+8F}8dc@W_0XVtHrf$KvXWxqZyJhEd zaq|wMx~cZLkaeN?*Vr8XZpV{(K5jC>&X)s(o9Z|~UQOt*tB*R76hOM8k?f!2`VK{* z;6h|7ZdRc!jkMsjxBiN9bwk+eW;nS^Y2DgCZXCrT?&y z!~%R7F7*|$#Xm5~V&jTh9xp*nyAih0@w^{m%N+8*0Un&VaiI;f#3rt`UP7MDN z3|NLk;yTGzR*}%z)^y$Q>9W6Fki#HxP8x(SY9xP{Vr|uK5gZG2l(IjAf zo$Ylu;3O`N{ty7maa~cE0Z0OcHJ?nFcY!h$g * Italian translations provided by Alberto Carraro @@ -776,6 +776,15 @@ const tPhrase Phrases[] = { "Enregistrement immdiat", "Markere direkteopptak", }, + { "NameInstantRecord", + "Direktaufz. benennen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "LnbSLOF", "LnbSLOF", "LnbSLOF", diff --git a/menu.c b/menu.c index 1cd549158..40ac1859d 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.146 2002/01/27 15:50:50 kls Exp $ + * $Id: menu.c 1.148 2002/02/03 15:42:38 kls Exp $ */ #include "menu.h" @@ -1553,7 +1553,7 @@ cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus) cMenuRecordingItem *LastItem = NULL; char *LastItemText = NULL; for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { - if (!Base || strstr(recording->Name(), Base) == recording->Name()) { + if (!Base || (strstr(recording->Name(), Base) == recording->Name() && recording->Name()[strlen(Base)] == '~')) { cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { Add(Item); @@ -1829,6 +1829,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditBoolItem(tr("ShowInfoOnChSwitch"), &data.ShowInfoOnChSwitch)); Add(new cMenuEditBoolItem(tr("MenuScrollPage"), &data.MenuScrollPage)); Add(new cMenuEditBoolItem(tr("MarkInstantRecord"), &data.MarkInstantRecord)); + Add(new cMenuEditStrItem( tr("NameInstantRecord"), data.NameInstantRecord, sizeof(data.NameInstantRecord), FileNameChars)); Add(new cMenuEditIntItem( tr("LnbSLOF"), &data.LnbSLOF)); Add(new cMenuEditIntItem( tr("LnbFrequLo"), &data.LnbFrequLo)); Add(new cMenuEditIntItem( tr("LnbFrequHi"), &data.LnbFrequHi)); @@ -2309,14 +2310,16 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer->SetPending(true); timer->SetRecording(true); if (Channels.SwitchTo(timer->channel, dvbApi)) { + const char *Title = NULL; const char *Subtitle = NULL; const char *Summary = NULL; if (GetEventInfo()) { - dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", eventInfo->GetTitle(), eventInfo->GetSubtitle()); + Title = eventInfo->GetTitle(); Subtitle = eventInfo->GetSubtitle(); Summary = eventInfo->GetExtendedDescription(); + dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", Title, Subtitle); } - cRecording Recording(timer, Subtitle, Summary); + cRecording Recording(timer, Title, Subtitle, Summary); fileName = strdup(Recording.FileName()); cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); if (dvbApi->StartRecord(fileName, Channels.GetByNumber(timer->channel)->ca, timer->priority)) @@ -2337,7 +2340,7 @@ cRecordControl::~cRecordControl() bool cRecordControl::GetEventInfo(void) { cChannel *channel = Channels.GetByNumber(timer->channel); - time_t Time = timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2; + time_t Time = timer->StartTime() + ((Setup.MarginStart * 2) + 1) * 60; for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) { { cThreadLock ThreadLock; diff --git a/recording.c b/recording.c index acdf264cb..7a55e1a7d 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.48 2002/01/27 15:14:45 kls Exp $ + * $Id: recording.c 1.49 2002/02/03 15:46:42 kls Exp $ */ #include "recording.h" @@ -41,6 +41,9 @@ #define DISKCHECKDELTA 100 // seconds between checks for free disk space #define REMOVELATENCY 10 // seconds to wait until next check after removing a file +#define TIMERMACRO_TITLE "TITLE" +#define TIMERMACRO_EPISODE "EPISODE" + void RemoveDeletedRecordings(void) { static time_t LastRemoveCheck = 0; @@ -214,19 +217,33 @@ char *ExchangeChars(char *s, bool ToFileSystem) return s; } -cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary) +cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary) { resume = RESUME_NOT_INITIALIZED; titleBuffer = NULL; sortBuffer = NULL; fileName = NULL; - if (Timer->IsSingleEvent() || !Setup.UseSubtitle) + name = NULL; + // set up the actual name: + if (isempty(Title)) + Title = Channels.GetChannelNameByNumber(Timer->channel); + if (isempty(Subtitle)) + Subtitle = " "; + char *macroTITLE = strstr(Timer->file, TIMERMACRO_TITLE); + char *macroEPISODE = strstr(Timer->file, TIMERMACRO_EPISODE); + if (macroTITLE || macroEPISODE) { name = strdup(Timer->file); - else { - if (isempty(Subtitle)) - Subtitle = " "; - asprintf(&name, "%s~%s", Timer->file, Subtitle); + name = strreplace(name, TIMERMACRO_TITLE, Title); + name = strreplace(name, TIMERMACRO_EPISODE, Subtitle); + if (Timer->IsSingleEvent()) { + Timer->SetFile(name); // this was an instant recording, so let's set the actual data + Timers.Save(); + } } + else if (Timer->IsSingleEvent() || !Setup.UseSubtitle) + name = strdup(Timer->file); + else + asprintf(&name, "%s~%s", Timer->file, Subtitle); // substitute characters that would cause problems in file names: strreplace(name, '\n', ' '); start = Timer->StartTime(); diff --git a/recording.h b/recording.h index 3aaa7e9e6..38626f859 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.21 2002/01/26 15:18:16 kls Exp $ + * $Id: recording.h 1.22 2002/02/03 11:59:49 kls Exp $ */ #ifndef __RECORDING_H @@ -43,7 +43,7 @@ class cRecording : public cListObject { time_t start; int priority; int lifetime; - cRecording(cTimer *Timer, const char *Subtitle, const char *Summary); + cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary); cRecording(const char *FileName); ~cRecording(); virtual bool operator< (const cListObject &ListObject); diff --git a/remux.c b/remux.c index f89b897b6..99a644081 100644 --- a/remux.c +++ b/remux.c @@ -8,7 +8,7 @@ * the Linux DVB driver's 'tuxplayer' example and were rewritten to suit * VDR's needs. * - * $Id: remux.c 1.6 2001/08/19 11:52:05 kls Exp $ + * $Id: remux.c 1.8 2002/02/03 16:20:37 kls Exp $ */ /* The calling interface of the 'cRemux::Process()' function is defined @@ -555,6 +555,17 @@ XXX*/ return Result ? resultBuffer : NULL; XXX*/ + // Special VPID case to enable recording radio channels: + + if (vPid == 0 || vPid == 1 || vPid == 0x1FFF) { + // XXX actually '0' should be enough, but '1' must be used with encrypted channels (driver bug?) + // XXX also allowing 0x1FFF to not break Michael Paar's original patch, + // XXX but it would probably be best to only use '0' + *PictureType = I_FRAME; + Result = resultDelivered = resultCount; + return Result ? resultBuffer : NULL; + } + // Check if we're getting anywhere here: if (!synced && skipped >= 0) { @@ -583,9 +594,8 @@ XXX*/ if (l < 0) return NULL; // no useful data found, wait for more if (pt != NO_PICTURE) { - if (pt < I_FRAME || B_FRAME < pt) { + if (pt < I_FRAME || B_FRAME < pt) esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); - } else if (!synced) { if (pt == I_FRAME) { resultDelivered = i; // will drop everything before this position diff --git a/svdrp.c b/svdrp.c index 67de63c3b..4cdf2fbba 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.28 2002/01/13 16:07:42 kls Exp $ + * $Id: svdrp.c 1.30 2002/02/02 15:39:46 kls Exp $ */ #include "svdrp.h" @@ -101,9 +101,17 @@ int cSocket::Accept(void) struct sockaddr_in clientname; uint size = sizeof(clientname); int newsock = accept(sock, (struct sockaddr *)&clientname, &size); - if (newsock > 0) - isyslog(LOG_INFO, "connect from %s, port %hd", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port)); - else if (errno != EINTR) + if (newsock > 0) { + bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr); + if (!accepted) { + const char *s = "Access denied!\n"; + write(newsock, s, strlen(s)); + close(newsock); + newsock = -1; + } + isyslog(LOG_INFO, "connect from %s, port %hd - %s", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), accepted ? "accepted" : "DENIED"); + } + else if (errno != EINTR && errno != EAGAIN) LOG_ERROR; return newsock; } diff --git a/svdrphosts.conf b/svdrphosts.conf new file mode 100644 index 000000000..dec9c42a0 --- /dev/null +++ b/svdrphosts.conf @@ -0,0 +1,13 @@ +# +# svdrphosts This file describes a number of host addresses that +# are allowed to connect to the SVDRP port of the Video +# Disk Recorder (VDR) running on this system. +# Syntax: +# +# IP-Address[/Netmask] +# + +127.0.0.1 # always accept localhost +#192.168.100.0/24 # any host on the local net +#204.152.189.113 # a specific host +#0.0.0.0/0 # any host on any net (USE THIS WITH CARE!) diff --git a/tools.c b/tools.c index dc579e55f..441c5ce87 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.53 2002/01/27 12:36:23 kls Exp $ + * $Id: tools.c 1.56 2002/02/03 16:44:08 kls Exp $ */ #include "tools.h" @@ -13,6 +13,7 @@ #include #if defined(DEBUG_OSD) #include +#undef ERR //XXX ncurses defines this - but this clashes with newer system header files #endif #include #include @@ -100,6 +101,23 @@ char *strreplace(char *s, char c1, char c2) return s; } +char *strreplace(char *s, const char *s1, const char *s2) +{ + char *p = strstr(s, s1); + if (p) { + int of = p - s; + int l = strlen(s); + int l1 = strlen(s1); + int l2 = strlen(s2); + if (l2 > l1) + s = (char *)realloc(s, strlen(s) + l2 - l1 + 1); + if (l2 != l1) + memmove(s + of + l2, s + of + l1, l - of - l1 + 1); + strncpy(s + of, s2, l2); + } + return s; +} + char *skipspace(const char *s) { while (*s && isspace(*s)) @@ -404,9 +422,8 @@ char *ReadLink(const char *FileName) if (n < 0) { if (errno == ENOENT || errno == EINVAL) // file doesn't exist or is not a symlink TargetName = FileName; - else { // some other error occurred + else // some other error occurred LOG_ERROR_STR(FileName); - } } else if (n < int(sizeof(RealName))) { // got it! RealName[n] = 0; diff --git a/tools.h b/tools.h index f9390185b..9663a8edd 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.39 2002/01/26 15:38:10 kls Exp $ + * $Id: tools.h 1.41 2002/02/03 12:36:25 kls Exp $ */ #ifndef __TOOLS_H @@ -20,9 +20,9 @@ extern int SysLogLevel; -#define esyslog if (SysLogLevel > 0) syslog -#define isyslog if (SysLogLevel > 1) syslog -#define dsyslog if (SysLogLevel > 2) syslog +#define esyslog(a...) void( (SysLogLevel > 0) ? syslog(a) : void() ) +#define isyslog(a...) void( (SysLogLevel > 1) ? syslog(a) : void() ) +#define dsyslog(a...) void( (SysLogLevel > 2) ? syslog(a) : void() ) #define LOG_ERROR esyslog(LOG_ERR, "ERROR (%s,%d): %m", __FILE__, __LINE__) #define LOG_ERROR_STR(s) esyslog(LOG_ERR, "ERROR: %s: %m", s) @@ -47,6 +47,7 @@ char *readline(FILE *f); char *strcpyrealloc(char *dest, const char *src); char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); +char *strreplace(char *s, const char *s1, const char *s2); // re-allocates 's' and deletes the original string if necessary! char *skipspace(const char *s); char *stripspace(char *s); char *compactspace(char *s); diff --git a/vdr.c b/vdr.c index 5351e4095..670246a4b 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.93 2002/01/26 14:07:01 kls Exp $ + * $Id: vdr.c 1.94 2002/02/02 15:50:43 kls Exp $ */ #include @@ -272,6 +272,7 @@ int main(int argc, char *argv[]) Channels.Load(AddDirectory(ConfigDirectory, "channels.conf")); Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); Commands.Load(AddDirectory(ConfigDirectory, "commands.conf")); + SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true); #if defined(REMOTE_LIRC) Keys.SetDummyValues(); #elif !defined(REMOTE_NONE) From a1da0e5c5de55009716e2c327dda16c61c1dae83 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 10 Feb 2002 18:00:00 +0100 Subject: [PATCH 034/307] =?UTF-8?q?Version=200.99=20-=20Fixed=20a=20bug=20?= =?UTF-8?q?in=20moving=20timers=20or=20channels=20to=20the=20last=20positi?= =?UTF-8?q?on=20in=20the=20list=20=20=20(thanks=20to=20Matthias=20Schniede?= =?UTF-8?q?rmeyer=20for=20helping=20to=20debug=20this=20one).=20-=20Change?= =?UTF-8?q?d=20the=20estimated=20data=20rate=20for=20calculating=20the=20r?= =?UTF-8?q?emaining=20disk=20capacity=20=20=20to=2025.75=20MB/min.=20-=20O?= =?UTF-8?q?nly=20reporting=20the=20'EPG=20bugfix=20statistics'=20if=20ther?= =?UTF-8?q?e=20really=20were=20any=20fixes.=20-=20Added=20Finnish=20langua?= =?UTF-8?q?ge=20texts=20(thanks=20to=20Hannu=20Savolainen).=20-=20Reverted?= =?UTF-8?q?=20to=20the=20previous=20way=20of=20searching=20for=20the=20EPG?= =?UTF-8?q?=20record=20of=20the=20current=20=20=20recording=20in=20case=20?= =?UTF-8?q?of=20a=20periodic=20timer=20(i.e.=20taking=20the=20one=20that?= =?UTF-8?q?=20is=20in=20the=20=20=20middle=20between=20start=20and=20end?= =?UTF-8?q?=20time).=20-=20Added=20a=20typedef=20for=20'in=5Faddr=5Ft'=20t?= =?UTF-8?q?o=20make=20it=20work=20with=20glibc=20<=202.2=20(thanks=20to=20?= =?UTF-8?q?=20=20J=FCrgen=20Schmidt).=20-=20When=20the=20last=20entry=20in?= =?UTF-8?q?=20a=20"Recordings"=20menu=20page=20is=20deleted,=20that=20page?= =?UTF-8?q?=20is=20now=20=20=20automatically=20closed=20(suggested=20by=20?= =?UTF-8?q?Uwe=20Freese).=20-=20Changed=20the=20default=20name=20for=20ins?= =?UTF-8?q?tant=20recordings=20to=20"TITLE=20EPISODE"=20(avoiding=20=20=20?= =?UTF-8?q?the=20'-').=20-=20If=20Setup.ShowInfoOnChSwitch=20is=20set=20to?= =?UTF-8?q?=20"no",=20the=20box=20for=20the=20EPG=20display=20is=20no=20?= =?UTF-8?q?=20=20longer=20shown=20(thanks=20to=20Andy=20Grobb).=20-=20If?= =?UTF-8?q?=20compiled=20with=20VFAT=3D1,=20characters=20that=20can't=20be?= =?UTF-8?q?=20handled=20by=20a=20VFAT=20system=20are=20=20=20now=20encoded?= =?UTF-8?q?=20to=20'#XX'.=20-=20When=20the=20user=20presses=20the=20"Power?= =?UTF-8?q?"=20button=20and=20there=20is=20a=20timer=20about=20to=20start?= =?UTF-8?q?=20=20=20recording=20within=20Setup.MinEventTimeout=20minutes,?= =?UTF-8?q?=20there=20is=20now=20a=20confirmation=20=20=20prompt=20telling?= =?UTF-8?q?=20the=20user=20that=20there=20is=20an=20upcoming=20timer=20eve?= =?UTF-8?q?nt.=20-=20If=20a=20recording=20has=20no=20episode=20title,=20th?= =?UTF-8?q?e=20trailing=20'~'=20is=20no=20longer=20shown=20in=20=20=20the?= =?UTF-8?q?=20progress=20display.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTORS | 16 +++++ HISTORY | 27 ++++++++ channels.conf | 1 + config.c | 4 +- config.h | 6 +- eit.c | 47 +++++++------ gmon.out | Bin 101224 -> 0 bytes i18n.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++-- menu.c | 27 ++++++-- recording.c | 83 ++++++++++++++++++++--- tools.c | 6 +- vdr.c | 11 ++- 12 files changed, 359 insertions(+), 51 deletions(-) delete mode 100644 gmon.out diff --git a/CONTRIBUTORS b/CONTRIBUTORS index e0b9ee1c9..9ccf53db1 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -47,6 +47,7 @@ Matthias Schniedermeyer for implementing the 'MarkInstantRecord' setup option for his "schnitt" tools for his "master-timer" tool + for helping to debug the "move to last position in list" bug Miha Setina for translating the OSD texts to the Slovenian language @@ -161,6 +162,7 @@ Simon Bauschulte Andy Grobb for completing storing the current audio volume in the setup.conf file + for fixing the EPG display in case Setup.ShowInfoOnChSwitch is set to "no" Thomas Heiligenmann for implementing the SVDRP commands LSTR and DELR @@ -189,3 +191,17 @@ Davide Achilli Michael Paar for enabling recording of radio channels + +Hannu Savolainen + for translating the OSD texts to the Finnish language + +Jrgen Schmidt + for fixing a problem with 'in_addr_t' on systems with glibc < 2.2. + +Uwe Freese + for suggesting to automatically close an empty recordings page after deleting + an entry + +Rainer Zocholl + for suggesting a confirmation prompt when the user presses the "Power" button + and there is an upcoming timer event diff --git a/HISTORY b/HISTORY index bf8ce2c9c..b2b3a9e14 100644 --- a/HISTORY +++ b/HISTORY @@ -969,3 +969,30 @@ Video Disk Recorder Revision History radio recordings. Thanks to Michael Paar. - Fixed a problem with the ERR macro defined by ncurses.h (thanks to Artur Skawina). + +2002-02-10: Version 0.99 + +- Fixed a bug in moving timers or channels to the last position in the list + (thanks to Matthias Schniedermeyer for helping to debug this one). +- Changed the estimated data rate for calculating the remaining disk capacity + to 25.75 MB/min. +- Only reporting the 'EPG bugfix statistics' if there really were any fixes. +- Added Finnish language texts (thanks to Hannu Savolainen). +- Reverted to the previous way of searching for the EPG record of the current + recording in case of a periodic timer (i.e. taking the one that is in the + middle between start and end time). +- Added a typedef for 'in_addr_t' to make it work with glibc < 2.2 (thanks to + Jrgen Schmidt). +- When the last entry in a "Recordings" menu page is deleted, that page is now + automatically closed (suggested by Uwe Freese). +- Changed the default name for instant recordings to "TITLE EPISODE" (avoiding + the '-'). +- If Setup.ShowInfoOnChSwitch is set to "no", the box for the EPG display is no + longer shown (thanks to Andy Grobb). +- If compiled with VFAT=1, characters that can't be handled by a VFAT system are + now encoded to '#XX'. +- When the user presses the "Power" button and there is a timer about to start + recording within Setup.MinEventTimeout minutes, there is now a confirmation + prompt telling the user that there is an upcoming timer event. +- If a recording has no episode title, the trailing '~' is no longer shown in + the progress display. diff --git a/channels.conf b/channels.conf index 87796ae26..8d58e61d9 100644 --- a/channels.conf +++ b/channels.conf @@ -200,3 +200,4 @@ VIVA2:12552:v:0:22000:171:172:0:0:12120 MTV German:12699:v:0:22000:3031:3032:0:0:28643 IFA-TV:10832:h:0:22000:132:133:32:0:7251 QVC Germany:12552:v:0:22000:165:166:0:0:12100 +TANGOTV:10832:h:1:22000:61:62:0:0:61920 diff --git a/config.c b/config.c index 974aed0c2..8b5c454fe 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.82 2002/02/03 15:25:44 kls Exp $ + * $Id: config.c 1.83 2002/02/10 11:39:00 kls Exp $ */ #include "config.h" @@ -847,7 +847,7 @@ cSetup::cSetup(void) ShowInfoOnChSwitch = 1; MenuScrollPage = 1; MarkInstantRecord = 1; - strcpy(NameInstantRecord, "TITLE-EPISODE"); + strcpy(NameInstantRecord, "TITLE EPISODE"); LnbSLOF = 11700; LnbFrequLo = 9750; LnbFrequHi = 10600; diff --git a/config.h b/config.h index 325f4ef28..e2e2897fb 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.93 2002/02/03 15:16:21 kls Exp $ + * $Id: config.h 1.95 2002/02/10 15:44:40 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.99pre5" +#define VDRVERSION "0.99" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -174,6 +174,8 @@ class cCommand : public cListObject { const char *Execute(void); }; +typedef uint32_t in_addr_t; //XXX from /usr/include/netinet/in.h (apparently this is not defined on systems with glibc < 2.2) + class cSVDRPhost : public cListObject { private: struct in_addr addr; diff --git a/eit.c b/eit.c index 2860fc4c6..99bcdfff9 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.33 2002/02/02 12:12:26 kls Exp $ + * $Id: eit.c 1.34 2002/02/09 14:48:43 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -352,7 +352,7 @@ void cEventInfo::Dump(FILE *f, const char *Prefix) const } } -#define MAXEPGBUGFIXSTATS 6 +#define MAXEPGBUGFIXSTATS 5 #define MAXEPGBUGFIXCHANS 50 struct tEpgBugFixStats { int hits; @@ -381,32 +381,39 @@ static void EpgBugFixStat(int Number, unsigned int ServiceID) static void ReportEpgBugFixStats(bool Reset = false) { if (Setup.EPGBugfixLevel > 0) { - dsyslog(LOG_INFO, "====================="); - dsyslog(LOG_INFO, "EPG bugfix statistics"); - dsyslog(LOG_INFO, "====================="); - dsyslog(LOG_INFO, "IF SOMEBODY WHO IS IN CHARGE OF THE EPG DATA FOR ONE OF THE LISTED"); - dsyslog(LOG_INFO, "CHANNELS READS THIS: PLEASE TAKE A LOOK AT THE FUNCTION cEventInfo::FixEpgBugs()"); - dsyslog(LOG_INFO, "IN VDR/eit.c TO LEARN WHAT'S WRONG WITH YOUR DATA, AND FIX IT!"); - dsyslog(LOG_INFO, "====================="); - dsyslog(LOG_INFO, "Fix\tHits\tChannels"); + bool GotHits = false; char buffer[1024]; for (int i = 0; i < MAXEPGBUGFIXSTATS; i++) { const char *delim = "\t"; tEpgBugFixStats *p = &EpgBugFixStats[i]; - char *q = buffer; - q += snprintf(q, sizeof(buffer) - (q - buffer), "%d\t%d", i, p->hits); - for (int c = 0; c < p->n; c++) { - cChannel *channel = Channels.GetByServiceID(p->serviceIDs[c]); - if (channel) { - q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->name); - delim = ", "; + if (p->hits) { + if (!GotHits) { + dsyslog(LOG_INFO, "====================="); + dsyslog(LOG_INFO, "EPG bugfix statistics"); + dsyslog(LOG_INFO, "====================="); + dsyslog(LOG_INFO, "IF SOMEBODY WHO IS IN CHARGE OF THE EPG DATA FOR ONE OF THE LISTED"); + dsyslog(LOG_INFO, "CHANNELS READS THIS: PLEASE TAKE A LOOK AT THE FUNCTION cEventInfo::FixEpgBugs()"); + dsyslog(LOG_INFO, "IN VDR/eit.c TO LEARN WHAT'S WRONG WITH YOUR DATA, AND FIX IT!"); + dsyslog(LOG_INFO, "====================="); + dsyslog(LOG_INFO, "Fix\tHits\tChannels"); + GotHits = true; + } + char *q = buffer; + q += snprintf(q, sizeof(buffer) - (q - buffer), "%d\t%d", i, p->hits); + for (int c = 0; c < p->n; c++) { + cChannel *channel = Channels.GetByServiceID(p->serviceIDs[c]); + if (channel) { + q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->name); + delim = ", "; + } } - } - dsyslog(LOG_INFO, "%s", buffer); + dsyslog(LOG_INFO, "%s", buffer); + } if (Reset) p->hits = p->n = 0; } - dsyslog(LOG_INFO, "====================="); + if (GotHits) + dsyslog(LOG_INFO, "====================="); } } diff --git a/gmon.out b/gmon.out deleted file mode 100644 index ea79bc54bbd4e662e4d8c094175c3df7d5c3504b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101224 zcmeI4@pGI-8OQJ1d+!#S!K6e88Zoq>(Fu5ML#Jwys|gy0IHa^wBMlhZD+CE8P}Hhn zOxuhE2ymqlgGRm5j>MUaUTKgb6^^!QWTKM-!(_(HaG}?lAA%kGcg}#e;zY?=i=r!+;7*n8FlbD<({#1bDN|PUF;XG3?*j z+0J7IWEON$OyR=@OqfD;EM^X4JUZ;wg5S<^8PC0dhLW zo+(}KnI$rWs!w@lCBD#NbuKiykanTRg+UiaT^M(v=t3mvG+OOK3Xp5G-5CK$N40M` zz$^V0<^dCrTbNwonYSOdPz0>M%EByQ-G-nJVE=jxk(Kyxy@j$Xopve#m(<%x6W~B# zC$-u$FCmF`X8>@^Oxz?FL1OP`J#+R}&){<;T87peZnuyI?77WC7I5}X3zeVq%r6Nscdv#QfGx67kxuzxJQ#_l2YF0{JP?LyXtS-{D^#Qhy<9w5Wk z?J4#}-;P4M$!VwCg+Ui`E{wTQa3OV_XMPq-`0bQ8duBQqLK+Z`=LBHG4{UelzT}w- z7}f5Wn>>@h(W+_(w6|O618lh2!T>%Tz)r5>^IPy?vz0jE!YrWc2^-nC6?Ks9>ARtK z3LtgjI&*1168T6h5^VjzHHd_BRC&5lYm|*A*Oyf30rA{B#&El`x zwKEKmMzsf10I8!;l42Nw4!aynGLOz`q#h6!YXXRPjr0S;Asn^Ev~P7-#_NKP4gq$c zODbdxa2$P8Sc?TN5w+6+xEqZs415#wgF~XB0z*jc^z_6~IPq;Pm%qi$pH?6;=fb7m zaU#WTJdHRp{9-Pc`g3TJ z1#}^zP__qy!xw8{Bw7oQI=5{COad~1`(9XrtA~xe_{T&fI@0Tz0!I7z5){i@m=@^% zp5Hg!YEA&cJ$@eW=KXd`s`23fhM}{N1jsq3kQTt7!aP1?(D3PhqS4+5{KzFM(as1! z5?m`n@)AJ;g*jVHq546;&Nb(v*jm70WIIow-GYiA0PMk3>dYOKI>@FlX^Sb$18Tly zi&Z`Z*MOO7WUFW5NCJfs zTSwt2paP3YhcFIE1uzL{51pg(3zhir7-mmrt^hcB%3d_rK8!_<3Darp z1$_Qd3mL#Ar)@Fw2sV@e$_0X>tr?ID5_ABz6m6XrWRh)NQ?~)u2aR?B!UR2l-QTy3 z_Pa3T!mtZRTo`j<5|9bnDFI}^)*e*t!_>bOHy2$di^7FjfOPbO5}5}`M-{3DaESML zKGXtMVa;h|4M5saXaPimNC!X~)kqpgM|iaL0!~4d?o~s8@GM!7VsF}xmJMRt2!^m0 zP(W0N(CNbD4?VN5&(^8=5q7>uEHna6J!4@8aQ=f9767mO%0kx=ihagDfLTE4Cl>Mm zxuNKzxd15q)H7FuqGdnEdV4V8LoMLe#TFU?%O8!KbyBPwAa$-4$N)a}M%;&kfQf1Q zLtqy0HqvYAc|d6dw^gYVL*>j>wg-KHmjJp&&jCtT2Um{+p4kh~ExPWPnBYv@@AVKs ze&rxpB-)k4EeMxqg)Cqt8db;vmanvRjsW(pvXBS7g1f&KE3Sx}y+NH6%9kU(My3Gm z=#s($pzx%HGGux(VmG@EKo}VT$fD4T*-=0bZfXh>fIPNB-J(r>{N4S!8X#NE1!yQ* z3y|L>3MqhWH44pcqz!O3*zmgmVS;YASOyR#7;+<%QYRQ((MEKnu`AJ0Y+MSJfN*eY zTxbSJN3~e53t2#zAm`S3&4r>{r+PKo3A$4Y2IXehpEzqS{K&3(BeYcg`F<+xsY`s=fVjWih%H^RRll%!y~i~Q22^{PTO2a-Vry) zOz?XSu;UyHX+W5*8_@7wo1m)GNu2~N3+ik{k=^In1l2v5tiReiDZmXMu#sj!O#oT! zImuw($>BqImb5((fA_?w$DR|O7%4z_E;Iw$g9LeiJPS)OC(&`hihc`)hx|D`S0au0 zR&MJT2($rYC&x7;5}g5P9f7`wZ8m{}fWwkaiveVXDAZx6jAZOcN3m&zP=#-Ipr~%q z?H2Tf$`C+0s!MqRumXP?soCo!r~^nlS}gf=+}wgcU2kopakC%rb?MIBGjUToWFrym z$SqOpx*QNrV-c|FSz9cI58(=_0^AeSsR1kt+8F}8dc@W_0XVtHrf$KvXWxqZyJhEd zaq|wMx~cZLkaeN?*Vr8XZpV{(K5jC>&X)s(o9Z|~UQOt*tB*R76hOM8k?f!2`VK{* z;6h|7ZdRc!jkMsjxBiN9bwk+eW;nS^Y2DgCZXCrT?&y z!~%R7F7*|$#Xm5~V&jTh9xp*nyAih0@w^{m%N+8*0Un&VaiI;f#3rt`UP7MDN z3|NLk;yTGzR*}%z)^y$Q>9W6Fki#HxP8x(SY9xP{Vr|uK5gZG2l(IjAf zo$Ylu;3O`N{ty7maa~cE0Z0OcHJ?nFcY!h$g * Italian translations provided by Alberto Carraro @@ -12,6 +12,7 @@ * Portugese translations provided by Paulo Manuel Martins Lopes * French translations provided by Jean-Claude Repetto * Norwegian translations provided by Jrgen Tvedt + * Finnish translations provided by Hannu Savolainen * */ @@ -52,7 +53,7 @@ #include "config.h" #include "tools.h" -const int NumLanguages = 8; +const int NumLanguages = 9; typedef const char *tPhrase[NumLanguages]; @@ -66,6 +67,7 @@ const tPhrase Phrases[] = { "Portugues", "Franais", "Norsk", + "Suomi", }, // Menu titles: { "Main", @@ -76,6 +78,7 @@ const tPhrase Phrases[] = { "Principal", "Menu", "Hovedmeny", + "Valikko", }, { "Schedule", "Programm", @@ -85,6 +88,7 @@ const tPhrase Phrases[] = { "Programa", "Programmes", "Programmer", + "Ohjelmat", }, { "Channels", "Kanle", @@ -94,6 +98,7 @@ const tPhrase Phrases[] = { "Canal", "Chanes", "Kanaler", + "Kanavat", }, { "Timers", "Timer", @@ -103,6 +108,7 @@ const tPhrase Phrases[] = { "Alarmes", "Programmation", "Timer", + "Ajastin", }, { "Recordings", "Aufzeichnungen", @@ -112,6 +118,7 @@ const tPhrase Phrases[] = { "Gravacoes", "Enregistrements", "Opptak", + "Nauhoitteet", }, { "DVD", "DVD", @@ -121,6 +128,7 @@ const tPhrase Phrases[] = { "DVD", "DVD", "DVD", + "DVD", }, { "Setup", "Einstellungen", @@ -130,6 +138,7 @@ const tPhrase Phrases[] = { "Configurar", "Configuration", "Konfigurasjon", + "Asetukset", }, { "Commands", "Befehle", @@ -139,6 +148,7 @@ const tPhrase Phrases[] = { "Comandos", "Commandes", "Kommandoer", + "Komennot", }, { "Edit Channel", "Kanal Editieren", @@ -148,6 +158,7 @@ const tPhrase Phrases[] = { "Modificar Canal", "Modifier une chane", "Editer Kanal", + "Muokkaa kanavaa", }, { "Edit Timer", "Timer Editieren", @@ -157,6 +168,7 @@ const tPhrase Phrases[] = { "Modificar Alarme", "Changer la programmation", "Editer Timer", + "Muokkaa ajastusta", }, { "Event", "Sendung", @@ -165,7 +177,8 @@ const tPhrase Phrases[] = { "Uitzending", "Evento", "Evnement", - "Hendelse" + "Hendelse", + "Tapahtuma", }, { "Summary", "Inhalt", @@ -175,6 +188,7 @@ const tPhrase Phrases[] = { "Resumo", "Rsum", "Sammendrag", + "Yhteenveto", }, { "Schedule - %s", "Programm - %s", @@ -184,6 +198,7 @@ const tPhrase Phrases[] = { "Programa - %s", "Programmes - %s", "Program Guide - %s", + "Ohjelma - %s", }, { "What's on now?", "Was luft jetzt?", @@ -193,6 +208,7 @@ const tPhrase Phrases[] = { "O que ver agora?", "Programmes en cours", "Hvilket program sendes n?", + "Nykyinen ohjelma", }, { "What's on next?", "Was luft als nchstes?", @@ -202,6 +218,7 @@ const tPhrase Phrases[] = { "O que ver depois?", "Prochains programmes", "Hvilket program er neste?", + "Seuraava ohjelma", }, // Button texts (should not be more than 10 characters!): { "Edit", @@ -212,6 +229,7 @@ const tPhrase Phrases[] = { "Modificar", "Modifier", "Editer", + "Muuta", }, { "New", "Neu", @@ -221,6 +239,7 @@ const tPhrase Phrases[] = { "Novo", "Nouveau", "Ny", + "Uusi", }, { "Delete", "Lschen", @@ -230,6 +249,7 @@ const tPhrase Phrases[] = { "Apagar", "Supprimer", "Slett", + "Poista", }, { "Mark", "Markieren", @@ -239,6 +259,7 @@ const tPhrase Phrases[] = { "Marcar", "Marquer", "Marker", + "Merkitse", }, { "Record", "Aufnehmen", @@ -248,6 +269,7 @@ const tPhrase Phrases[] = { "Gravar", "Enregistre", "Ta opp", + "Nauhoita", }, { "Play", "Wiedergabe", @@ -257,6 +279,7 @@ const tPhrase Phrases[] = { "Play", "Lire", "Spill av", + "Toista", }, { "Rewind", "Anfang", @@ -266,6 +289,7 @@ const tPhrase Phrases[] = { "Rebobinar", "Retour", "Spol tilbake", + "Takaisinkel.", }, { "Resume", "Weiter", @@ -275,6 +299,7 @@ const tPhrase Phrases[] = { "Continuar", "Reprendre", "Fortsett", + "Jatka", }, { "Summary", "Inhalt", @@ -284,6 +309,7 @@ const tPhrase Phrases[] = { "Resumo", "Rsum", "Sammendrag", + "Yhteenveto", }, { "Open", "ffnen", @@ -293,6 +319,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Avaa", }, { "Switch", "Umschalten", @@ -302,6 +329,7 @@ const tPhrase Phrases[] = { "Seleccionar", "Regarder", "Skift til", + "Valitse", }, { "Now", "Jetzt", @@ -311,6 +339,7 @@ const tPhrase Phrases[] = { "Agora", "Maintenant", "N", + "Nyt", }, { "Next", "Nchste", @@ -320,6 +349,7 @@ const tPhrase Phrases[] = { "Proximo", "Aprs", "Neste", + "Seuraava", }, { "Schedule", "Programm", @@ -329,6 +359,7 @@ const tPhrase Phrases[] = { "Programa", "Programme", "Programmer", + "Ohjelmisto", }, { "Language", "Sprache", @@ -338,6 +369,7 @@ const tPhrase Phrases[] = { "", // TODO "Langue", "Sprk", + "Kieli", }, { "Eject", "Auswerfen", @@ -347,6 +379,7 @@ const tPhrase Phrases[] = { "", // TODO "Ejection", "", // TODO + "Avaa", }, // Confirmations: { "Delete channel?", @@ -357,6 +390,7 @@ const tPhrase Phrases[] = { "Apagar o Canal?", "Supprimer la chane?", "Slette kanal?", + "Poistetaanko kanava?", }, { "Delete timer?", "Timer lschen?", @@ -366,6 +400,7 @@ const tPhrase Phrases[] = { "Apagar o Alarme?", "Supprimer la programmation?", "Slette timer?", + "Poistetaanko ajastus?", }, { "Delete recording?", "Aufzeichnung lschen?", @@ -375,6 +410,7 @@ const tPhrase Phrases[] = { "Apagar Gravaco?", "Supprimer l'enregistrement?", "Slette opptak?", + "Poistetaanko nauhoitus?", }, { "Stop recording?", "Aufzeichnung beenden?", @@ -384,6 +420,7 @@ const tPhrase Phrases[] = { "Parar Gravaco?", "Arrter l'enregistrement?", "Stoppe opptak?", + "Pysytetnk nauhoitus?", }, { "on primary interface", "auf dem primren Interface", @@ -393,6 +430,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "pvastaanottimella", }, { "Cancel editing?", "Schneiden abbrechen?", @@ -401,7 +439,8 @@ const tPhrase Phrases[] = { "Bewerken afbreken?", "Cancelar Modificar?", "Annuler les modifications?", - "Avbryte redigering", + "Avbryte redigering?", + "Peruutetaanko muokkaus?", }, { "Recording - shut down anyway?", "Aufnahme luft - trotzdem ausschalten?", @@ -411,6 +450,17 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Nauhoitus kesken - lopetetaanko se?", + }, + { "Recording in %d minutes, shut down anyway?", + "Aufnahme in %d Minuten - trotzdem ausschalten?", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO }, { "Press any key to cancel shutdown", "Taste drcken um Shutdown abzubrechen", @@ -420,6 +470,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Peruuta pysytys painamalla jotakin nppint", }, // Channel parameters: { "Name", @@ -430,6 +481,7 @@ const tPhrase Phrases[] = { "Nome", "Nom", "Navn", + "Nimi", }, { "Frequency", "Frequenz", @@ -439,6 +491,7 @@ const tPhrase Phrases[] = { "Frequencia", "Frquence", "Frekvens", + "Taajuus", }, { "Polarization", "Polarisation", @@ -448,6 +501,7 @@ const tPhrase Phrases[] = { "Polarizacao", "Polarisation", "Polaritet", + "Polarisaatio", }, { "DiSEqC", "DiSEqC", @@ -457,6 +511,7 @@ const tPhrase Phrases[] = { "DiSEqC", "DiSEqC", "DiSEqC", + "DiSEqC", }, { "Srate", "Srate", @@ -466,6 +521,7 @@ const tPhrase Phrases[] = { "Srate", "Frq. Symbole", "Symbolrate", + "Srate", }, { "Vpid", "Vpid", @@ -475,6 +531,7 @@ const tPhrase Phrases[] = { "Vpid", "PID Vido", "Video pid", + "Kuva PID", }, { "Apid1", "Apid1", @@ -484,6 +541,7 @@ const tPhrase Phrases[] = { "Apid1", "PID Audio (1)", "Audio pid1", + "ni PID1", }, { "Apid2", "Apid2", @@ -493,6 +551,7 @@ const tPhrase Phrases[] = { "Apid2", "PID Audio (2)", "Audio pid2", + "ni PID2", }, { "Dpid1", "Dpid1", @@ -502,6 +561,7 @@ const tPhrase Phrases[] = { "Dpid1", "PID AC3 (1)", "AC3 pid1", + "AC3 PID1", }, { "Dpid2", "Dpid2", @@ -511,6 +571,7 @@ const tPhrase Phrases[] = { "Dpid2", "PID AC3 (2)", "AC3 pid2", + "AC3 PID2", }, { "Tpid", "Tpid", @@ -520,6 +581,7 @@ const tPhrase Phrases[] = { "Tpid", "PID Tltexte", "Teletext pid", + "TekstiTV PID", }, { "CA", "CA", @@ -529,6 +591,7 @@ const tPhrase Phrases[] = { "CA", "Cryptage", "Kortleser", + "Salauskortti", }, { "Pnr", "Pnr", @@ -538,6 +601,7 @@ const tPhrase Phrases[] = { "Pnr", "Num. Progr.", "Program Id", + "Ohjelmatunnus", }, // Timer parameters: { "Active", @@ -548,6 +612,7 @@ const tPhrase Phrases[] = { "Activo", "Actif", "Aktiv", + "Aktiivinen", }, { "Channel", "Kanal", @@ -557,6 +622,7 @@ const tPhrase Phrases[] = { "Canal", "Chane", "Kanal", + "Kanava", }, { "Day", "Tag", @@ -566,6 +632,7 @@ const tPhrase Phrases[] = { "Dia", "Jour", "Dag", + "Piv", }, { "Start", "Anfang", @@ -575,6 +642,7 @@ const tPhrase Phrases[] = { "Inicio", "Dbut", "Start", + "Aloitus", }, { "Stop", "Ende", @@ -584,6 +652,7 @@ const tPhrase Phrases[] = { "Fim", "Fin", "Slutt", + "Lopetus", }, { "Priority", "Prioritt", @@ -593,6 +662,7 @@ const tPhrase Phrases[] = { "Prioridade", "Priorit", "Prioritet", + "Prioriteetti", }, { "Lifetime", "Lebensdauer", @@ -602,6 +672,7 @@ const tPhrase Phrases[] = { "Duracao", "Dure de vie", "Levetid", + "Voimassaolo", }, { "File", "Datei", @@ -611,6 +682,7 @@ const tPhrase Phrases[] = { "Ficheiro", "Fichier", "Filnavn", + "Tiedosto", }, // Error messages: { "Channel is being used by a timer!", @@ -619,8 +691,9 @@ const tPhrase Phrases[] = { "Canale occupato da un timer!", "Kanaal wordt gebruikt door een timer!", "Canal a ser utilizador por um alarme!", - "Cette chane est en cours d'utilisation!" + "Cette chane est en cours d'utilisation!", "Kanalen er i bruk av en timer!", + "Kanava on ajastimen kytss!", }, { "Can't switch channel!", "Kanal kann nicht umgeschaltet werden!", @@ -630,6 +703,7 @@ const tPhrase Phrases[] = { "Nao pode mudar de canal!", "Impossible de changer de chane!", "Ikke mulig skifte kanal!", + "Kanavan vaihtaminen ei mahdollista!", }, { "Timer is recording!", "Timer zeichnet gerade auf!", @@ -639,6 +713,7 @@ const tPhrase Phrases[] = { "Alarme a gravar!", "Enregistrement en cours!", "Timer gjr opptak!", + "Ajastinnauhoitus kynniss!", }, { "Error while accessing recording!", "Fehler beim ansprechen der Aufzeichnung!", @@ -648,6 +723,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Nauhoituksen toistaminen eponnistui!", }, { "Error while deleting recording!", "Fehler beim Lschen der Aufzeichnung!", @@ -657,6 +733,7 @@ const tPhrase Phrases[] = { "Erro enquanto apagava uma gravacao!", "Erreur de suppression de l'enregistrement!", "Feil under sletting av opptak!", + "Nauhoituksen poistaminen eponnistui!", }, { "*** Invalid Channel ***", "*** Ungltiger Kanal ***", @@ -666,6 +743,7 @@ const tPhrase Phrases[] = { "*** Canal Invalido! ***", "*** Chane invalide! ***", "*** Ugyldig Kanal! ***", + "*** Virheellinen kanavavalinta! ***", }, { "No free DVB device to record!", "Keine freie DVB-Karte zum Aufnehmen!", @@ -674,7 +752,8 @@ const tPhrase Phrases[] = { "Geen vrije DVB kaart om op te nemen!", "Nenhuma placa DVB disponivel para gravar!", "Pas de carte DVB disponible pour l'enregistrement!", - "Ingen ledige DVB enheter for opptak!" + "Ingen ledige DVB enheter for opptak!", + "Ei vapaata vastaanotinta nauhoitusta varten!", }, { "Channel locked (recording)!", "Kanal blockiert (zeichnet auf)!", @@ -684,6 +763,7 @@ const tPhrase Phrases[] = { "Canal bloqueado (a gravar)!", "Chane verrouille (enregistrement en cours)!", "Kanalen er lst (opptak)!", + "Kanava lukittu (nauhoitusta varten)!", }, { "Can't start Transfer Mode!", "Transfer-Mode kann nicht gestartet werden!", @@ -693,6 +773,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Ksittmttmi teknisi ongelmia!", }, { "Can't start editing process!", "Schnitt kann nicht gestartet werden!", @@ -702,6 +783,7 @@ const tPhrase Phrases[] = { "Nao pode iniciar a modificacao!", "Impossible de commencer le montage!", "Kan ikke starte redigeringsprosessen!", + "Muokkauksen aloittaminen ei onnistu!", }, { "Editing process already active!", "Schnitt bereits aktiv!", @@ -711,6 +793,7 @@ const tPhrase Phrases[] = { "Processo de modificacao ja activo!", "Montage dj en cours!", "Redigeringsprosessen er allerede aktiv!", + "Muokkaus on jo kynniss!", }, { "Can't shutdown - option '-s' not given!", "Shutdown unmglich - Option '-s' fehlt!", @@ -720,6 +803,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Ei voida sammuttaa '-s' parametria ei annettu!", }, { "Low disk space!", "Platte beinahe voll!", @@ -729,6 +813,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Kovalevy lhes tynn!", }, // Setup parameters: { "OSD-Language", @@ -739,6 +824,7 @@ const tPhrase Phrases[] = { "Linguagem OSD", "Langue OSD", "OSD Sprk", + "Nytn kieli", }, { "PrimaryDVB", "Primres Interface", @@ -748,6 +834,7 @@ const tPhrase Phrases[] = { "DVB primario", "Premire carte DVB", "Hoved DVB-enhet", + "Ensisij. vast.otin", }, { "ShowInfoOnChSwitch", "Info zeigen", @@ -757,6 +844,7 @@ const tPhrase Phrases[] = { "Mostrar info ao mudar de Canal", "Affichage progr. en cours", "Info ved kanalskifte", + "Nyt kanavainfo", }, { "MenuScrollPage", "Seitenweise scrollen", @@ -766,6 +854,7 @@ const tPhrase Phrases[] = { "Scroll da pagina no menu", "Affichage progr. suivant", "Rask rulling i menyer", + "Valikkojen rullaus", }, { "MarkInstantRecord", "Direktaufz. markieren", @@ -775,6 +864,7 @@ const tPhrase Phrases[] = { "Marca de gravacao", "Enregistrement immdiat", "Markere direkteopptak", + "Merkitse vlitn nauh.", }, { "NameInstantRecord", "Direktaufz. benennen", @@ -784,6 +874,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Nime vlitn nauh.", }, { "LnbSLOF", "LnbSLOF", @@ -793,6 +884,7 @@ const tPhrase Phrases[] = { "LnbSLOF", "Limite de bandes LNB", "LO-grensefrekvens", + "LnbSLOF", }, { "LnbFrequLo", "Untere LNB-Frequenz", @@ -802,6 +894,7 @@ const tPhrase Phrases[] = { "Freq LO LNB", "Frquence basse LNB", "LO-frekvens i lavbndet", + "LO LNB taajuus", }, { "LnbFrequHi", "Obere LNB-Frequenz", @@ -811,6 +904,7 @@ const tPhrase Phrases[] = { "Freq HI LNB", "Frquence haute LNB", "LO-frekvens i hybndet", + "HI LNB taajuus", }, { "DiSEqC", "DiSEqC", @@ -820,6 +914,7 @@ const tPhrase Phrases[] = { "DiSEqC", "DiSEqC", "DiSEqC", + "DiSEqC", }, { "SetSystemTime", "Systemzeit stellen", @@ -829,6 +924,7 @@ const tPhrase Phrases[] = { "Ajustar relogio do sistema", "Ajuster l'heure du systme", "Juster system-klokken", + "Vastaanota kellonaika", }, { "MarginStart", "Zeitpuffer bei Anfang", @@ -838,6 +934,7 @@ const tPhrase Phrases[] = { "Margem de inicio", "Marge antrieure", "Opptaks margin (start)", + "Aloitusmarginaali", }, { "MarginStop", "Zeitpuffer bei Ende", @@ -847,6 +944,7 @@ const tPhrase Phrases[] = { "Margem de fim", "Marge postrieure", "Opptaks margin (slutt)", + "Lopetusmarginaali", }, { "EPGScanTimeout", "Zeit bis EPG Scan", @@ -856,6 +954,7 @@ const tPhrase Phrases[] = { "Timeout EPG", "Temps maxi EPG", "Ledig tid fr EPG-sk", + "Ohjelmatied. odotusaika", }, { "EPGBugfixLevel", "EPG Fehlerbereinigung", @@ -865,6 +964,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "EPGBugfixLevel", }, { "SVDRPTimeout", "SVDRP Timeout", @@ -874,6 +974,7 @@ const tPhrase Phrases[] = { "Timeout SVDRP", "Temps maxi SVDRP", "Ubrukt SVDRP-levetid", + "SVDRP odotusaika", }, { "SortTimers", "Timer sortieren", @@ -883,6 +984,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Jrjest ajastimet", }, { "PrimaryLimit", "Primr-Limit", @@ -892,6 +994,7 @@ const tPhrase Phrases[] = { "Limite Primario", "Premire limite", "Prioritets grense HovedDVB", + "PrimaryLimit", }, { "DefaultPriority", "Default Prioritt", @@ -901,6 +1004,7 @@ const tPhrase Phrases[] = { "Prioridade por defeito", "Priorit par dfaut", "Normal prioritet (Timer)", + "Oletusprioriteetti", }, { "DefaultLifetime", "Default Lebensdauer", @@ -910,6 +1014,7 @@ const tPhrase Phrases[] = { "Validade por defeito", "Dure de vie par dfaut", "Normal levetid (Timer)", + "Oletus voimassaoloaika", }, { "UseSubtitle", "Subtitle verwenden", @@ -919,6 +1024,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Tekstitys kytss", }, { "RecordingDirs", "Aufn. Verzeichnisse", @@ -928,6 +1034,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Nauhoitushakemistot", }, { "VideoFormat", "Video Format", @@ -937,6 +1044,7 @@ const tPhrase Phrases[] = { "", // TODO "Format vido", "TV Format", + "Kuvamuoto", }, { "ChannelInfoPos", "Kanal Info Position", @@ -946,6 +1054,7 @@ const tPhrase Phrases[] = { "", // TODO "Position infos chanes", "", // TODO + "Kanavainfon sijainti", }, { "OSDwidth", "OSD Breite", @@ -955,6 +1064,7 @@ const tPhrase Phrases[] = { "", // TODO "Largeur affichage", "", // TODO + "Tekstinytn leveys", }, { "OSDheight", "OSD Hhe", @@ -964,6 +1074,7 @@ const tPhrase Phrases[] = { "", // TODO "Hauteur affichage", "", // TODO + "Tekstinytn korkeus", }, { "OSDMessageTime", "OSD Nachricht Dauer", @@ -973,6 +1084,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Ilmoitusten nkymisaika", }, { "MaxVideoFileSize", "Max. Video Dateigre", @@ -982,6 +1094,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Maksimi tiedoston koko", }, { "SplitEditedFiles", "Editierte Dateien zerteilen", @@ -991,6 +1104,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Paloittele muokatut", }, { "MinEventTimeout", "Mindest Event Pause", @@ -1000,6 +1114,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Minimi tapahtuman odotus", }, { "MinUserInactivity", "Mindest User Inaktivitt", @@ -1009,6 +1124,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Minimi kyttjn odotus", }, { "MultiSpeedMode", "MultiSpeed Modus", @@ -1018,6 +1134,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Moninopeustila", }, { "ShowReplayMode", "Wiedergabe Status", @@ -1027,6 +1144,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Nyt toiston tila", }, // The days of the week: { "MTWTFSS", @@ -1037,6 +1155,7 @@ const tPhrase Phrases[] = { "STQQSSD", "LMMJVSD", "MTOTFLS", + "MTKTPLS", }, { "MonTueWedThuFriSatSun", // must all be 3 letters! "MonDieMitDonFreSamSon", @@ -1046,6 +1165,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "MaaTiiKesTorPerLauSun", }, // Learning keys: { "Learning Remote Control Keys", @@ -1056,6 +1176,7 @@ const tPhrase Phrases[] = { "Aprender as teclas do telecomando", "Apprentissage des codes de tlcommande", "Lre fjernkontrolltaster", + "Kaukostimen nppinten opettelu", }, { "Phase 1: Detecting RC code type", "Phase 1: FB Code feststellen", @@ -1065,6 +1186,7 @@ const tPhrase Phrases[] = { "Fase 1: detectar tipo de receptor", "Phase 1: Dtection du type de code", "Fase 1: Finne fjernkontroll-kodetype", + "Vaihe 1: Lhetystavan selvittminen", }, { "Press any key on the RC unit", "Eine Taste auf der FB drcken", @@ -1074,6 +1196,7 @@ const tPhrase Phrases[] = { "Pressione qualquer tecla do telecomando", "Appuyer sur une touche de la tlcommande", "Trykk en av tastene p fjernkontrollen", + "Paina mit tahansa kaukostimen nppint", }, { "RC code detected!", "FB Code erkannt!", @@ -1083,6 +1206,7 @@ const tPhrase Phrases[] = { "Codigo do telecomando detectado!", "Code de la tlcommande dtect!", "Fjernkontroll-kodetype funnet!", + "Nppinpainallus vastaanotettu!", }, { "Do not press any key...", "Keine Taste drcken...", @@ -1092,6 +1216,7 @@ const tPhrase Phrases[] = { "Nao pressione nada...", "Ne pas appuyer sur une touche ...", "Ikke trykk p noen av tastene...", + "l paina mitn nppint...", }, { "Phase 2: Learning specific key codes", "Phase 2: Einzelne Tastencodes lernen", @@ -1101,6 +1226,7 @@ const tPhrase Phrases[] = { "Fase 2: A aprender codigos especificos", "Phase 2: Apprentissage des codes des touches", "Fase 2: Lre spesifikke tastekoder", + "Vaihe 2: Nppinkoodien opettelu", }, { "Press key for '%s'", "Taste fr '%s' drcken", @@ -1110,6 +1236,7 @@ const tPhrase Phrases[] = { "Pressione tecla para '%s'", "Appuyer sur la touche '%s'", "Trykk tasten for '%s'", + "Paina nppint toiminnolle '%s'", }, { "Press 'Up' to confirm", "'Auf' drcken zum Besttigen", @@ -1119,6 +1246,7 @@ const tPhrase Phrases[] = { "Pressione 'Cima' para confirmar", "Appuyer sur 'Haut' pour confirmer", "Trykk 'Opp' for bekrefte", + "Paina 'Yls' hyvksyksesi", }, { "Press 'Down' to continue", "'Ab' drcken zum Weitermachen", @@ -1128,6 +1256,7 @@ const tPhrase Phrases[] = { "Pressione 'Baixo' para continuar", "Appuyer sur 'Bas' pour continuer", "Trykk Ned' for fortsette", + "Paina 'Alas' jatkaaksesi", }, { "(press 'Up' to go back)", "('Auf' drcken um zurckzugehen)", @@ -1137,6 +1266,7 @@ const tPhrase Phrases[] = { "(Pressione 'Cima' para voltar)", "(Appuyer sur 'Haut' pour revenir en arrire)", "(trykk 'Opp' for g tilbake)", + "(paina 'Yls' palataksesi takaisin)", }, { "(press 'Down' to end key definition)", "('Ab' drcken zum Beenden)", @@ -1146,6 +1276,7 @@ const tPhrase Phrases[] = { "(Pressione 'Baixo' para terminar a definicao)", "(Appuyer sur 'Bas' pour terminer)", "(trykk 'Ned' for avslutte innlring)", + "(paina 'Alas' lopettaaksesi nppinten opettelun)", }, { "Phase 3: Saving key codes", "Phase 3: Codes abspeichern", @@ -1155,6 +1286,7 @@ const tPhrase Phrases[] = { "Fase 3: A Salvar os codigos das teclas", "Phase 3: Sauvegarde des codes des touches", "Fase 3: Lagre tastekoder", + "Vaihe 3: Nppinkoodien tallettaminen", }, { "Press 'Up' to save, 'Down' to cancel", "'Auf' speichert, 'Ab' bricht ab", @@ -1164,6 +1296,7 @@ const tPhrase Phrases[] = { "'Cima' para Salvar, 'Baixo' para Cancelar", "Appuyer sur 'Haut' pour sauvegarder, 'Bas' pour annuler", "Trykk 'Opp' for lagre, 'Ned' for avbryte", + "Paina 'Yls' tallettaaksesi ja 'Alas' peruuttaaksesi", }, // Key names: { "Up", @@ -1174,6 +1307,7 @@ const tPhrase Phrases[] = { "Cima", "Haut", "Opp", + "Yls", }, { "Down", "Ab", @@ -1183,6 +1317,7 @@ const tPhrase Phrases[] = { "Baixo", "Bas", "Ned", + "Alas", }, { "Menu", "Men", @@ -1192,6 +1327,7 @@ const tPhrase Phrases[] = { "Menu", "Menu", "Meny", + "Valikko", }, { "Ok", "Ok", @@ -1201,6 +1337,7 @@ const tPhrase Phrases[] = { "Ok", "Ok", "Ok", + "Ok", }, { "Back", "Zurck", @@ -1210,6 +1347,7 @@ const tPhrase Phrases[] = { "Voltar", "Retour", "Tilbake", + "Takaisin", }, { "Left", "Links", @@ -1219,6 +1357,7 @@ const tPhrase Phrases[] = { "Esquerda", "Gauche", "Venstre", + "Vasemmalle", }, { "Right", "Rechts", @@ -1228,6 +1367,7 @@ const tPhrase Phrases[] = { "Direita", "Droite", "Hyre", + "Oikealle", }, { "Red", "Rot", @@ -1237,6 +1377,7 @@ const tPhrase Phrases[] = { "Vermelho", "Rouge", "Rd", + "Punainen", }, { "Green", "Grn", @@ -1246,6 +1387,7 @@ const tPhrase Phrases[] = { "Verde", "Vert", "Grnn", + "Vihre", }, { "Yellow", "Gelb", @@ -1255,6 +1397,7 @@ const tPhrase Phrases[] = { "Amarelo", "Jaune", "Gul", + "Keltainen", }, { "Blue", "Blau", @@ -1264,6 +1407,7 @@ const tPhrase Phrases[] = { "Azul", "Bleu", "Bl", + "Sininen", }, { "Power", "Ausschalten", @@ -1273,6 +1417,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Virtakytkin", }, { "Volume+", "Lautstrke+", @@ -1282,6 +1427,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "nenvoimakkuus+", }, { "Volume-", "Lautstrke-", @@ -1291,6 +1437,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "nenvoimakkuus-", }, { "Mute", "Stumm", @@ -1300,6 +1447,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "nen vaimennus", }, // Miscellaneous: { "yes", @@ -1310,6 +1458,7 @@ const tPhrase Phrases[] = { "sim", "oui", "ja", + "kyll", }, { "no", "nein", @@ -1319,6 +1468,7 @@ const tPhrase Phrases[] = { "nao", "non", "nei", + "ei", }, { "top", "oben", @@ -1328,6 +1478,7 @@ const tPhrase Phrases[] = { "", // TODO "haut", "", // TODO + "yl", }, { "bottom", "unten", @@ -1337,6 +1488,7 @@ const tPhrase Phrases[] = { "", // TODO "bas", "", // TODO + "ala", }, { "free", "frei", @@ -1345,6 +1497,8 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "", // TODO + "vapaa", }, { "Jump: ", // note the trailing blank "Springen: ", @@ -1353,6 +1507,8 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "", // TODO + "Hypp", }, { " Stop replaying", // note the leading blank! " Wiedergabe beenden", @@ -1362,6 +1518,7 @@ const tPhrase Phrases[] = { " Parar reproducao", " Arrter la lecture", " Stopp avspilling", + " Pysyt toisto", }, { " Stop recording ", // note the leading and trailing blanks! " Aufzeichnung beenden ", @@ -1371,6 +1528,7 @@ const tPhrase Phrases[] = { " Parar gravacao ", " Arrter l'enregistrement ", " Stopp opptak fra ", + " Pysyt nauhoitus ", }, { " Cancel editing", // note the leading blank! " Schneiden abbrechen", @@ -1380,6 +1538,7 @@ const tPhrase Phrases[] = { " Anular modificacao", " Annuler le montage", " Avbryt editering", + " Peruuta muokkaus", }, { "Switching primary DVB...", "Primres Interface wird umgeschaltet...", @@ -1388,7 +1547,8 @@ const tPhrase Phrases[] = { "Eerste DVB-kaart wordt omgeschakeld...", "A mudar placa DVB primaria...", "Changement de carte DVB principale...", - "Bytter hoved DVB-enhet... ", + "Bytter hoved DVB-enhet...", + "Vaihdetaan ensisijainen vastaanotin...", }, { "Up/Dn for new location - OK to move", "Auf/Ab fr neue Position - dann OK", @@ -1398,6 +1558,7 @@ const tPhrase Phrases[] = { "Cima/Baixo para nova localizacao - Ok para mudar", "Haut/Bas -> nouvelle place - OK -> dplacer", "Opp/Ned for ny plass - OK for flytte", + "Yls/Alas = liiku, OK = siirr", }, { "Editing process started", "Schnitt gestartet", @@ -1407,6 +1568,7 @@ const tPhrase Phrases[] = { "Processo de modificacao iniciado", "Opration de montage lance", "Redigeringsprosess startet", + "Muokkaus aloitettu", }, { "Editing process finished", "Schnitt beendet", @@ -1415,6 +1577,8 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "", // TODO + "Muokkaus lopetettu", }, { "Editing process failed!", "Schnitt gescheitert!", @@ -1423,6 +1587,8 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "", // TODO + "Muokkaus eponnistui", }, { "scanning recordings...", "Aufzeichnungen werden durchsucht...", @@ -1431,6 +1597,8 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "", // TODO + "haetaan nauhoituksia...", }, { NULL } }; diff --git a/menu.c b/menu.c index 40ac1859d..a7a98ec38 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.148 2002/02/03 15:42:38 kls Exp $ + * $Id: menu.c 1.152 2002/02/10 11:52:34 kls Exp $ */ #include "menu.h" @@ -1680,6 +1680,8 @@ eOSState cMenuRecordings::Del(void) cOsdMenu::Del(Current()); Recordings.Del(recording); Display(); + if (!Count()) + return osBack; } else Interface->Error(tr("Error while deleting recording!")); @@ -1707,6 +1709,7 @@ eOSState cMenuRecordings::Summary(void) eOSState cMenuRecordings::ProcessKey(eKeys Key) { + bool HadSubMenu = HasSubMenu(); eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { @@ -1720,6 +1723,13 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) default: break; } } + if (Key == kYellow && HadSubMenu && !HasSubMenu()) { + // the last recording in a subdirectory was deleted, so let's go back up + cOsdMenu::Del(Current()); + if (!Count()) + return osBack; + Display(); + } if (!HasSubMenu() && Key != kNone) SetHelpKeys(); return state; @@ -1944,13 +1954,14 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) // Title with disk usage: -#define MB_PER_MINUTE 30 // this is just an estimate! +#define MB_PER_MINUTE 25.75 // this is just an estimate! char buffer[40]; int FreeMB; int Percent = VideoDiskSpace(&FreeMB); - int Hours = int(double(FreeMB) / MB_PER_MINUTE / 60); - int Minutes = (FreeMB / MB_PER_MINUTE) % 60; + int Minutes = int(double(FreeMB) / MB_PER_MINUTE); + int Hours = Minutes / 60; + Minutes %= 60; snprintf(buffer, sizeof(buffer), "%s - Disk %d%% - %2d:%02d %s", tr("Main"), Percent, Hours, Minutes, tr("free")); SetTitle(buffer); @@ -2113,10 +2124,11 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched) { group = -1; withInfo = !Switched || Setup.ShowInfoOnChSwitch; + int EpgLines = withInfo ? 5 : 1; lines = 0; oldNumber = number = 0; cChannel *channel = Channels.GetByNumber(Number); - Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? 5 : -5); + Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? EpgLines : -EpgLines); if (channel) { DisplayChannel(channel); DisplayInfo(); @@ -2131,7 +2143,8 @@ cDisplayChannel::cDisplayChannel(eKeys FirstKey) oldNumber = cDvbApi::CurrentChannel(); number = 0; lastTime = time_ms(); - Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? 5 : -5); + int EpgLines = Setup.ShowInfoOnChSwitch ? 5 : 1; + Interface->Open(Setup.OSDwidth, Setup.ChannelInfoPos ? EpgLines : -EpgLines); ProcessKey(FirstKey); } @@ -2340,7 +2353,7 @@ cRecordControl::~cRecordControl() bool cRecordControl::GetEventInfo(void) { cChannel *channel = Channels.GetByNumber(timer->channel); - time_t Time = timer->StartTime() + ((Setup.MarginStart * 2) + 1) * 60; + time_t Time = timer->IsSingleEvent() ? timer->StartTime() + ((Setup.MarginStart * 2) + 1) * 60 : timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2; for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) { { cThreadLock ThreadLock; diff --git a/recording.c b/recording.c index 7a55e1a7d..d82288756 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.49 2002/02/03 15:46:42 kls Exp $ + * $Id: recording.c 1.51 2002/02/10 15:41:23 kls Exp $ */ #include "recording.h" @@ -196,22 +196,82 @@ tCharExchange CharExchange[] = { { ' ', '_' }, { '\'', '\x01' }, { '/', '\x02' }, -#ifdef VFAT - { ':', '\x03' }, -#endif { 0, 0 } }; -char *ExchangeChars(char *s, bool ToFileSystem) +static char *ExchangeChars(char *s, bool ToFileSystem) { char *p = s; while (*p) { +#define VFAT 1 +#ifdef VFAT + // The VFAT file system can't handle all characters, so we + // have to take extra efforts to encode/decode them: + if (ToFileSystem) { + switch (*p) { + // characters that can be used "as is": + case '!': + case '@': + case '$': + case '%': + case '&': + case '(': + case ')': + case '+': + case ',': + case '-': + case '.': + case ';': + case '=': + case '0' ... '9': + case 'a' ... 'z': + case 'A' ... 'Z': break; + // characters that can be mapped to other characters: + case ' ': *p = '_'; break; + case '~': *p = '/'; break; + // characters that have to be encoded: + default: { + int l = p - s; + s = (char *)realloc(s, strlen(s) + 10); + p = s + l; + char buf[4]; + sprintf(buf, "#%02X", (unsigned char)*p); + memmove(p + 2, p, strlen(p) + 1); + strncpy(p, buf, 3); + p += 2; + } + } + } + else { + switch (*p) { + // mapped characters: + case '_': *p = ' '; break; + case '/': *p = '~'; break; + // encodes characters: + case '#': { + if (strlen(p) > 2) { + char buf[3]; + sprintf(buf, "%c%c", *(p + 1), *(p + 2)); + unsigned char c = strtol(buf, NULL, 16); + *p = c; + memmove(p + 1, p + 3, strlen(p) - 2); + } + } + break; + // backwards compatibility: + case '\x01': *p = '\''; break; + case '\x02': *p = '/'; break; + case '\x03': *p = ':'; break; + } + } +#else for (struct tCharExchange *ce = CharExchange; ce->a && ce->b; ce++) { if (*p == (ToFileSystem ? ce->a : ce->b)) { *p = ToFileSystem ? ce->b : ce->a; break; } } +#endif p++; } return s; @@ -285,7 +345,7 @@ cRecording::cRecording(const char *FileName) name = new char[p - FileName + 1]; strncpy(name, FileName, p - FileName); name[p - FileName] = 0; - ExchangeChars(name, false); + name = ExchangeChars(name, false); } // read an optional summary file: char *SummaryFileName = NULL; @@ -384,9 +444,9 @@ const char *cRecording::FileName(void) if (!fileName) { struct tm tm_r; struct tm *t = localtime_r(&start, &tm_r); - ExchangeChars(name, true); + name = ExchangeChars(name, true); asprintf(&fileName, NAMEFORMAT, VideoDirectory, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, priority, lifetime); - ExchangeChars(name, false); + name = ExchangeChars(name, false); } return fileName; } @@ -399,7 +459,7 @@ const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) if (Level < 0 || Level == HierarchyLevels()) { struct tm tm_r; struct tm *t = localtime_r(&start, &tm_r); - const char *s; + char *s; if (Level > 0 && (s = strrchr(name, '~')) != NULL) s++; else @@ -413,6 +473,11 @@ const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) New, Delimiter, s); + // let's not display a trailing '~': + stripspace(titleBuffer); + s = &titleBuffer[strlen(titleBuffer) - 1]; + if (*s == '~') + *s = 0; } else if (Level < HierarchyLevels()) { const char *s = name; diff --git a/tools.c b/tools.c index 441c5ce87..e95bdf8d2 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.56 2002/02/03 16:44:08 kls Exp $ + * $Id: tools.c 1.57 2002/02/05 18:16:52 kls Exp $ */ #include "tools.h" @@ -804,8 +804,10 @@ void cListBase::Move(cListObject *From, cListObject *To) To->Prev()->Append(From); From->Append(To); } - else + else { lastObject->Append(From); + lastObject = From; + } if (!From->Prev()) objects = From; } diff --git a/vdr.c b/vdr.c index 670246a4b..9d5167b46 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.94 2002/02/02 15:50:43 kls Exp $ + * $Id: vdr.c 1.95 2002/02/10 15:12:43 kls Exp $ */ #include @@ -494,13 +494,20 @@ int main(int argc, char *argv[]) else LastActivity = 1; } + bool UserShutdown = key == kPower; + if (UserShutdown && Next && Delta <= Setup.MinEventTimeout * 60 && !ForceShutdown) { + char *buf; + asprintf(&buf, tr("Recording in %d minutes, shut down anyway?"), Delta / 60); + if (Interface->Confirm(buf)) + ForceShutdown = true; + delete buf; + } if (!Next || Delta > Setup.MinEventTimeout * 60 || ForceShutdown) { ForceShutdown = false; if (timer) dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next)); if (WatchdogTimeout > 0) signal(SIGALRM, SIG_IGN); - bool UserShutdown = key == kPower; if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) { int Channel = timer ? timer->channel : 0; const char *File = timer ? timer->file : ""; From fb8e7fa302ef8a73feb6958b0cb32cc54f76e677 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 24 Feb 2002 18:00:00 +0100 Subject: [PATCH 035/307] Version 1.0.0pre1 - Added scanning for EPG data for another 4 days on channels that support this (thanks to Oleg Assovski). - Removed '#define VFAT 1' from recording.c (was a leftover from testing). - Fixed the "Low disk space!" message (thanks to Sergei Haller). - Added the TPID to Hessen-3 in 'channels.conf' (thanks to Sergei Haller). - Fixed a crash when replaying with DEBUG_OSD=1 (thanks to Stefan Huelswitt). - Implemented the "First day" parameter for repeating timers. See FORMATS for information about the enhanced 'timers.conf' file format, and MANUAL for a description of the new item in the "Edit Timer" menu and the enhanced functionality of the "Blue" button in the "Timers" menu. - When deleting a recording that is currently still being recorded, the related timer will now automatically be terminated. If this is a repeating timer, it will receive a "First day" setting that skips the timer for this day. - Fixed closing all unused file descriptors when opening a pipe (thanks to Werner Fink). - Instant recordings now take the EPG data from the point in time at 5 minutes from the start time of the recording. In order for this to work the 'active' parameter of a timer now uses the second bit to indicate that this is an "instant" recording (see FORMATS for details). - Fixed the SVDRP GRAB command in case the video device can't be opened (thanks to Adrian Stabiszewski). - At startup the data written into 'epg.data' is now read into the EPG data structures. In order for this to work, the 'E' record has been extended to (optionally) contain the 'table ID' (see FORMATS for details). - The new SVDRP command PUTE can be used to put EPG data into the EPG list. See FORMATS for details about the required data format. - Taking the German umlauts 'as is' when compiled with VFAT. - The new Setup parameter RecordDolbyDigital can be used to generally turn off recording the Dolby Digital audio channels in case you want to save disk space or don't have the equipment to replay Dolby Digital audio. - Reading the 'setup.conf' file no longer terminates in case of an error, but rather attempts to read the rest of the file. - Removed DVD support from the core VDR source, since the current version from Andreas Schultz is already much further developed (DVD menu navigation) and the concept of "additional players" in VDR is going to change in version 1.1.0, where a new "plugin" interface shall allow the easy implementation of new players without having to patch the core VDR source. Until then, Andreas has agreed to provide his DVD support as a completely external patch. - The contents of the distribution archive now contains the directory name with the current version number, as in 'vdr-1.0.0pre1/...' in order to avoid inadvertently overwriting an existing VDR directory with a new version. - Added a missing error message in SVDRP command LSTC in case the given channel can't be found. --- CONTRIBUTORS | 10 + FORMATS | 55 ++- HISTORY | 48 ++- INSTALL | 30 -- MANUAL | 43 +- Makefile | 25 +- ac3dec/Makefile | 28 -- ac3dec/ac3.h | 64 --- ac3dec/ac3_internal.h | 353 ---------------- ac3dec/bit_allocate.c | 506 ----------------------- ac3dec/bit_allocate.h | 24 -- ac3dec/bitstream.c | 79 ---- ac3dec/bitstream.h | 44 -- ac3dec/bswap.h | 80 ---- ac3dec/cmplx.h | 29 -- ac3dec/coeff.c | 431 -------------------- ac3dec/coeff.h | 24 -- ac3dec/cpu_accel.c | 129 ------ ac3dec/crc.c | 96 ----- ac3dec/crc.h | 27 -- ac3dec/debug.c | 48 --- ac3dec/debug.h | 41 -- ac3dec/decode.c | 312 -------------- ac3dec/decode.h | 22 - ac3dec/dither.c | 114 ------ ac3dec/dither.h | 37 -- ac3dec/downmix.c | 89 ---- ac3dec/downmix.h | 34 -- ac3dec/downmix_c.c | 161 -------- ac3dec/downmix_c.h | 32 -- ac3dec/downmix_i386.S | 92 ----- ac3dec/downmix_i386.h | 27 -- ac3dec/downmix_kni.S | 396 ------------------ ac3dec/downmix_kni.h | 32 -- ac3dec/exponent.c | 132 ------ ac3dec/exponent.h | 28 -- ac3dec/imdct.c | 530 ------------------------ ac3dec/imdct.h | 26 -- ac3dec/imdct512_kni.S | 548 ------------------------- ac3dec/imdct_c.c | 218 ---------- ac3dec/imdct_c.h | 36 -- ac3dec/imdct_kni.c | 103 ----- ac3dec/imdct_kni.h | 36 -- ac3dec/mm_accel.h | 36 -- ac3dec/parse.c | 481 ---------------------- ac3dec/parse.h | 26 -- ac3dec/rematrix.c | 91 ----- ac3dec/rematrix.h | 25 -- ac3dec/sanity_check.c | 124 ------ ac3dec/sanity_check.h | 27 -- ac3dec/srfft.c | 305 -------------- ac3dec/srfft.h | 39 -- ac3dec/srfft_kni.S | 289 ------------- ac3dec/srfft_kni.h | 30 -- ac3dec/srfft_kni_c.c | 93 ----- ac3dec/srfftp.h | 305 -------------- ac3dec/stats.c | 178 -------- ac3dec/stats.h | 27 -- channels.conf | 2 +- config.c | 75 +++- config.h | 22 +- dvbapi.c | 925 +----------------------------------------- dvbapi.h | 19 +- dvd.c | 169 -------- dvd.h | 62 --- eit.c | 136 ++++++- eit.h | 15 +- i18n.c | 52 ++- menu.c | 323 +++++++-------- menu.h | 28 +- osd.h | 3 +- recording.c | 12 +- svdrp.c | 80 +++- svdrp.h | 17 +- thread.c | 35 +- thread.h | 18 +- tools.c | 35 +- tools.h | 3 +- vdr.c | 35 +- 79 files changed, 733 insertions(+), 8628 deletions(-) delete mode 100644 ac3dec/Makefile delete mode 100644 ac3dec/ac3.h delete mode 100644 ac3dec/ac3_internal.h delete mode 100644 ac3dec/bit_allocate.c delete mode 100644 ac3dec/bit_allocate.h delete mode 100644 ac3dec/bitstream.c delete mode 100644 ac3dec/bitstream.h delete mode 100644 ac3dec/bswap.h delete mode 100644 ac3dec/cmplx.h delete mode 100644 ac3dec/coeff.c delete mode 100644 ac3dec/coeff.h delete mode 100644 ac3dec/cpu_accel.c delete mode 100644 ac3dec/crc.c delete mode 100644 ac3dec/crc.h delete mode 100644 ac3dec/debug.c delete mode 100644 ac3dec/debug.h delete mode 100644 ac3dec/decode.c delete mode 100644 ac3dec/decode.h delete mode 100644 ac3dec/dither.c delete mode 100644 ac3dec/dither.h delete mode 100644 ac3dec/downmix.c delete mode 100644 ac3dec/downmix.h delete mode 100644 ac3dec/downmix_c.c delete mode 100644 ac3dec/downmix_c.h delete mode 100644 ac3dec/downmix_i386.S delete mode 100644 ac3dec/downmix_i386.h delete mode 100644 ac3dec/downmix_kni.S delete mode 100644 ac3dec/downmix_kni.h delete mode 100644 ac3dec/exponent.c delete mode 100644 ac3dec/exponent.h delete mode 100644 ac3dec/imdct.c delete mode 100644 ac3dec/imdct.h delete mode 100644 ac3dec/imdct512_kni.S delete mode 100644 ac3dec/imdct_c.c delete mode 100644 ac3dec/imdct_c.h delete mode 100644 ac3dec/imdct_kni.c delete mode 100644 ac3dec/imdct_kni.h delete mode 100644 ac3dec/mm_accel.h delete mode 100644 ac3dec/parse.c delete mode 100644 ac3dec/parse.h delete mode 100644 ac3dec/rematrix.c delete mode 100644 ac3dec/rematrix.h delete mode 100644 ac3dec/sanity_check.c delete mode 100644 ac3dec/sanity_check.h delete mode 100644 ac3dec/srfft.c delete mode 100644 ac3dec/srfft.h delete mode 100644 ac3dec/srfft_kni.S delete mode 100644 ac3dec/srfft_kni.h delete mode 100644 ac3dec/srfft_kni_c.c delete mode 100644 ac3dec/srfftp.h delete mode 100644 ac3dec/stats.c delete mode 100644 ac3dec/stats.h delete mode 100644 dvd.c delete mode 100644 dvd.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9ccf53db1..bbceff25e 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -110,6 +110,7 @@ Stefan Huelswitt for implementing "Multi Speed Mode" for implementing backtracing for fast forward/rewind for implementing the replay mode display + for fixing a crash when replaying with DEBUG_OSD=1 Ulrich Rder for pointing out that there are channels that have a symbol rate higher than @@ -142,6 +143,7 @@ Artur Skawina Werner Fink for making I/O more robust by handling EINTR + for fixing closing all unused file descriptors when opening a pipe Rolf Hakenes for providing 'libdtv' and adapting the EIT mechanisms to it @@ -182,6 +184,8 @@ Lauri Pesonen Sergei Haller for fixing the LastActivity timestamp after a shutdown prompt + for fixing the "Low disk space!" message + for adding the TPID to Hessen-3 in 'channels.conf' Andreas Gebel for his help in keeping 'channels.conf' up to date @@ -205,3 +209,9 @@ Uwe Freese Rainer Zocholl for suggesting a confirmation prompt when the user presses the "Power" button and there is an upcoming timer event + +Oleg Assovski + for adding EPG scanning for another 4 days + +Adrian Stabiszewski + for fixing the SVDRP GRAB command in case the video device can't be opened diff --git a/FORMATS b/FORMATS index d7d4293c4..0da293977 100644 --- a/FORMATS +++ b/FORMATS @@ -45,12 +45,16 @@ Video Disk Recorder File Formats The fields in a timer definition have the following meaning (from left to right): - - Timer active (0 = inactive, 1 = active) - Values larger than '1' can be used by external programs to mark active timers + - Timer active (0 = inactive, 1 = active, 3 = instant recording) + Values other than these can be used by external programs to mark active timers and recognize if the user has modified them. When a user modifes an active - timer the 'active' field will be explicitly set to '1'. + timer the 'active' field will be explicitly set to '1' (or '0', respectively, + if the user deactivates the timer). + Note: in order to allow future extensibility, external programs using the + 'active' parameter should only use the upper 16 bit of this 32 bit parameter + and leave the lower 16 bit untouched. - Program number of the channel to record - - Day of recording, either one or more of + - Day of recording (in case of a repeating timer), either one or more of M------ = Monday -T----- = Tuesday --W---- = Wednesday @@ -61,7 +65,14 @@ Video Disk Recorder File Formats (any combination is possible, for example MTWTF--, and the days may be indicated by any characters except '-', so for example ABC---- would set a timer that records on monday, tuesday and wednesday) or the "day of month" - (1..31) + (1..31) in case of a single shot timer. + The day definition of a repeating timer may be followed by the date when that + timer shall hit for the first time. The format for this is @YYYY-MM-DD, + so a complete definition could look like this: MTWTF--@2002-02-18. This + "first day" feature can be used to disable a repeating timer for a couple + of days, or for instance to define a new Mon...Fri timer on wednesday, which + actually starts "monday next week". The "first day" date given need not be + that of a day when the timer would actually hit. - Start time (first two digits for the hour, second two digits for the minutes) - End time (first two digits for the hour, second two digits for the minutes) - Priority (from 0 to 99, 0 = lowest prioity, 99 = highest priority) @@ -169,3 +180,37 @@ Video Disk Recorder File Formats for audio 2 (if available). Dolby Digital data is stored in packets with ids 0xBD. +* epg.data + + This file contains the EPG data in an easily parsable format. The first + character of each line defines what kind of data this line contains. + + The following tag characters are defined: + + C + E + T + S <subtitle> + D <description> + e + c + + Lowercase characters mark the end of a sequence that was started by the + corresponding uppercase character. The outer frame consists of a sequence + of one or more 'C'...'c' (Channel) entries. Inside these any number of + 'E'...'e' (Event) entries are allowed. The 'T', 'S' and 'D' entries are + optional (although every event should at least have a 'T' entry). + + <service id> is the "program number" as defined in 'channels.conf' + <channel name> is the "name" as in 'channels.conf' (for information only) + <start time> is the time (as a time_t integer) in UTC when this event starts + <duration> is the time (in seconds) that this event will take + <table id> is a hex number that indicates the table this event is contained + in (if this is left empty or 0 this event will not be overwritten + or modified by data that comes from the DVB stream) + <title> is the title of the event + <subtitle> is the subtitle (typically the name of the episode etc.) + <description> is the description of the event + + This file will be read at program startup in order to restore the results of + previous EPG scans. diff --git a/HISTORY b/HISTORY index b2b3a9e14..ea81172d8 100644 --- a/HISTORY +++ b/HISTORY @@ -979,7 +979,7 @@ Video Disk Recorder Revision History - Only reporting the 'EPG bugfix statistics' if there really were any fixes. - Added Finnish language texts (thanks to Hannu Savolainen). - Reverted to the previous way of searching for the EPG record of the current - recording in case of a periodic timer (i.e. taking the one that is in the + recording in case of a repeating timer (i.e. taking the one that is in the middle between start and end time). - Added a typedef for 'in_addr_t' to make it work with glibc < 2.2 (thanks to Jrgen Schmidt). @@ -996,3 +996,49 @@ Video Disk Recorder Revision History prompt telling the user that there is an upcoming timer event. - If a recording has no episode title, the trailing '~' is no longer shown in the progress display. + +2002-02-24: Version 1.0.0pre1 + +- Added scanning for EPG data for another 4 days on channels that support this + (thanks to Oleg Assovski). +- Removed '#define VFAT 1' from recording.c (was a leftover from testing). +- Fixed the "Low disk space!" message (thanks to Sergei Haller). +- Added the TPID to Hessen-3 in 'channels.conf' (thanks to Sergei Haller). +- Fixed a crash when replaying with DEBUG_OSD=1 (thanks to Stefan Huelswitt). +- Implemented the "First day" parameter for repeating timers. See FORMATS for + information about the enhanced 'timers.conf' file format, and MANUAL for + a description of the new item in the "Edit Timer" menu and the enhanced + functionality of the "Blue" button in the "Timers" menu. +- When deleting a recording that is currently still being recorded, the related + timer will now automatically be terminated. If this is a repeating timer, it + will receive a "First day" setting that skips the timer for this day. +- Fixed closing all unused file descriptors when opening a pipe (thanks to + Werner Fink). +- Instant recordings now take the EPG data from the point in time at 5 minutes + from the start time of the recording. In order for this to work the 'active' + parameter of a timer now uses the second bit to indicate that this is an + "instant" recording (see FORMATS for details). +- Fixed the SVDRP GRAB command in case the video device can't be opened (thanks + to Adrian Stabiszewski). +- At startup the data written into 'epg.data' is now read into the EPG data + structures. In order for this to work, the 'E' record has been extended to + (optionally) contain the 'table ID' (see FORMATS for details). +- The new SVDRP command PUTE can be used to put EPG data into the EPG list. + See FORMATS for details about the required data format. +- Taking the German umlauts 'as is' when compiled with VFAT. +- The new Setup parameter RecordDolbyDigital can be used to generally turn off + recording the Dolby Digital audio channels in case you want to save disk space + or don't have the equipment to replay Dolby Digital audio. +- Reading the 'setup.conf' file no longer terminates in case of an error, but + rather attempts to read the rest of the file. +- Removed DVD support from the core VDR source, since the current version from + Andreas Schultz is already much further developed (DVD menu navigation) and + the concept of "additional players" in VDR is going to change in version 1.1.0, + where a new "plugin" interface shall allow the easy implementation of new + players without having to patch the core VDR source. Until then, Andreas has + agreed to provide his DVD support as a completely external patch. +- The contents of the distribution archive now contains the directory name with + the current version number, as in 'vdr-1.0.0pre1/...' in order to avoid + inadvertently overwriting an existing VDR directory with a new version. +- Added a missing error message in SVDRP command LSTC in case the given channel + can't be found. diff --git a/INSTALL b/INSTALL index cf694890e..e87f7bea8 100644 --- a/INSTALL +++ b/INSTALL @@ -15,23 +15,6 @@ If you have the DVB driver source in a different location you will have to change the definition of DVBDIR in the Makefile. -If you want to use your DVD drive you will need to compile VDR with - - make DVD=1 - -to activate DVD support. VDR then also needs the package 'libdvdread' -in order to replay DVDs. This package is expected to be located in the -directory ../DVD (seen from the VDR directory). Adjust the definition -of DVDDIR in the Makefile if necessary. -You can find 'libdvdread' at - - http://www.dtek.chalmers.se/groups/dvd/downloads.shtml - -If you want to replay CSS encrypted DVDs you also need to get the 'libdvdcss' -library from - - http://www.videolan.org/libdvdcss/download.html - VDR requires the Linux-DVB card driver version dated 2001-09-14 or higher to work properly. @@ -250,19 +233,6 @@ This program must be given to VDR with the '-a' option, as in vdr -a ac3play -Accessing the DVD drive: ------------------------- - -By default VDR expects the DVD drive to be located at /dev/dvd (which -typically is a symbolic link to the actual device, for instance /dev/hdc). -You can use the '-V' option to overwrite this, as in - - vdr -V /media/dvd - -Note that the user id under which VDR runs needs to have write access to -the DVD device in order to replay CSS protected DVDs (which also requires -the presence of the 'libdvdcss' library). - The video data directory: ------------------------- diff --git a/MANUAL b/MANUAL index d0ce7a2cf..320d24dad 100644 --- a/MANUAL +++ b/MANUAL @@ -12,23 +12,25 @@ Video Disk Recorder User's Manual Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause - Left Prev group - Page up Disable Decrement Page up Search back - Right Next group - Page down Enable Increment Page down Search forward + Left Prev group - Page up Page up Decrement Page up Search back + Right Next group - Page down Page down Increment Page down Search forward Ok Ch display Select Switch Edit Accept Play Progress disp. Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on Back - Menu off Main menu Main menu Discard Main menu Recordings menu Red - Record Edit Edit - Play Jump Green - Language New New - Rewind Skip -60s - Yellow - Eject DVD Delete Delete - Delete Skip +60s - Blue - Resume Mark Mark(1) - Summary Stop + Yellow - - Delete Delete - Delete Skip +60s + Blue - Resume Mark On/Off(1) - Summary Stop 0..9 Ch select - - - Numeric inp. - Editing - Power Shutdown - - - - - - - Volume+ Volume up - - - - - - - Volume- Volume down - - - - - - - Mute Mute - - - - - - - (1) The "Mark" button in the "Timers" menu only works if sorting the timers - has been disabled in the "Setup" menu. + Power Shutdown + Volume+ Volume up + Volume- Volume down + Mute Mute + + (1) The "On/Off" button in the "Timers" menu only works if sorting the timers + has been enabled in the "Setup" menu. Otherwise the Blue button is used + to "mark" a timer for moving. * Navigating through the On Screen Menus @@ -41,8 +43,15 @@ Video Disk Recorder User's Manual any changes that might have been made in the current menu. In the "Timers" menu, the current timer can be enabled or disabled with - the "Right" or "Left" key, respectively (enabled timers are marked with '>', - timers that are currently recording are marked with '#'). + the "Blue" key (this is only possible if the "Timers" list is sorted, + otherwise the "Blue" key is used to mark a timer in order to move it to + another position in the list). Enabled timers are marked with '>', timers + that are currently recording are marked with '#'. If a timer has the + "First day" set so that it will start recording only on the given date, + it is marked with '!'. The "Blue" key toggles through the "enabled" and + "disabled" states, and for repeating timers that are currently recording + also a state that ends this recording prematurely and sets the "First day" + date so that it will record again the next time the timer hits. "Ok" here opens the "Edit timer" menu. Textual options, like channel names or recording file names, can be edited @@ -160,7 +169,7 @@ Video Disk Recorder User's Manual list with the "Up" and "Down" button and press "Ok" (or the "Red" button) to start playback. New recordings are marked with an '*'. If the Setup parameter RecordingDirs has been set and there are recordings - from periodic timers organized in a subdirectory structure, only the + from repeating timers organized in a subdirectory structure, only the directory is displayed and it can be opened by pressing "Ok" (or the "Red" button). A directory entry displays the total number of recordings within that directory (and any possible subdirectory thereof) as well as the total @@ -170,7 +179,7 @@ Video Disk Recorder User's Manual If the setup parameter UseSubtitle was turned on when a recording took place, VDR adds the "subtitle" (which is usually the name of the episode in case of a series) to the recording's name. The "Recordings" menu then displays all - recordings of a periodic timer in chronological order, since these are + recordings of a repeating timer in chronological order, since these are usually the individual episodes of a series, which you may want to view in the order in which they were broadcast. @@ -321,6 +330,8 @@ Video Disk Recorder User's Manual of this timer being collected in a common subdirectory. If this field is left blank, the channel name will be used to form the name of the recording. + First day: The date of the first day when this timer shall start recording + (only available for repeating timers). A timer can also be programmed by pressing the "Red" button on the "Schedule", "Now", "Next" or "Event" menus. @@ -469,6 +480,10 @@ Video Disk Recorder User's Manual 0 = 4:3 1 = 16:9 + RecordDolbyDigital = 1 Turns recording of the Dolby Digital audio channels on + or off. This may be useful if you don't have the equipment + to replay Dolby Digital audio and want to save disk space. + ChannelInfoPos = 0 The position of the channel info window in the OSD. 0 = bottom 1 = top diff --git a/Makefile b/Makefile index f74179d93..ecb8f81fa 100644 --- a/Makefile +++ b/Makefile @@ -4,29 +4,18 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.30 2002/02/01 14:40:09 kls Exp $ +# $Id: Makefile 1.31 2002/02/24 12:29:54 kls Exp $ .DELETE_ON_ERROR: DVBDIR = ../DVB -DVDDIR = ../DVD -AC3DIR = ./ac3dec DTVDIR = ./libdtv INCLUDES = -I$(DVBDIR)/ost/include DTVLIB = $(DTVDIR)/libdtv.a -ifdef DVD -INCLUDES += -I$(DVDDIR)/libdvdread -LIBDIRS += -L$(DVDDIR)/libdvdread/dvdread/.libs -DEFINES += -DDVDSUPPORT -DEFINES += -D_LARGEFILE64_SOURCE # needed by libdvdread -AC3LIB = $(AC3DIR)/libac3.a -DVDLIB = -ldvdread -endif - -OBJS = config.o dvbapi.o dvbosd.o dvd.o eit.o font.o i18n.o interface.o menu.o osd.o\ +OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o osd.o\ recording.o remote.o remux.o ringbuffer.o svdrp.o thread.o tools.o vdr.o\ videodir.o @@ -75,8 +64,8 @@ include $(DEPFILE) # The main program: -vdr: $(OBJS) $(AC3LIB) $(DTVLIB) - g++ -g -O2 $(OBJS) $(NCURSESLIB) -ljpeg -lpthread $(LIBDIRS) $(DVDLIB) $(AC3LIB) $(DTVLIB) -o vdr +vdr: $(OBJS) $(DTVLIB) + g++ -g -O2 $(OBJS) $(NCURSESLIB) -ljpeg -lpthread $(LIBDIRS) $(DTVLIB) -o vdr # The font files: @@ -90,11 +79,6 @@ fontosd.c: genfontfile: genfontfile.c gcc -o $@ -O2 -L/usr/X11R6/lib $< -lX11 -# The ac3dec library: - -$(AC3LIB): - make -C $(AC3DIR) all - # The libdtv library: $(DTVLIB) $(DTVDIR)/libdtv.h: @@ -103,7 +87,6 @@ $(DTVLIB) $(DTVDIR)/libdtv.h: # Housekeeping: clean: - make -C $(AC3DIR) clean make -C $(DTVDIR) clean -rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~ fontclean: diff --git a/ac3dec/Makefile b/ac3dec/Makefile deleted file mode 100644 index 7ab5ad028..000000000 --- a/ac3dec/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# -# Makefile for 'ac3dec' -# -# $Id: Makefile 1.2 2001/08/10 12:44:07 kls Exp $ - -#OBJS = coeff.o decode.o exponent.o rematrix.o bit_allocate.o crc.o dither.o\ -# imdct.o sanity_check.o bitstream.o debug.o downmix.o parse.o stats.o\ -# downmix_c.o imdct.o - -OBJS = bit_allocate.o bitstream.o coeff.o cpu_accel.o crc.o debug.o decode.o\ - dither.o downmix.o downmix_c.o exponent.o imdct.o imdct_c.o imdct_kni.o\ - parse.o rematrix.o sanity_check.o srfft.o srfft_kni_c.o stats.o - - -DEFINES += -DDOLBY_SURROUND - -all: libac3.a - -libac3.a: $(OBJS) - ar -rc libac3.a $(OBJS) - -# Implicit rules: - -%.o: %.c - gcc -g -O2 -Wall -m486 -I./ -c $(DEFINES) $< - -clean: - rm -f *~ libac3.a $(OBJS) diff --git a/ac3dec/ac3.h b/ac3dec/ac3.h deleted file mode 100644 index 8f268fbdb..000000000 --- a/ac3dec/ac3.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ac3.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - *------------------------------------------------------------ - * - * 24 Nov 2001 - * Andreas Schultz <aschultz@cs.uni-magdeburg.de> - * Added ac3_buffersize() - */ - -#define AC3_BUFFER_SIZE (6*1024*16) - -#ifndef __AC3_H__ -#define __AC3_H__ - -#ifdef __OMS__ -#include <oms/plugin/output_audio.h> -#else -//#include "audio_out.h" -#endif - -#include <inttypes.h> - -#define AC3_DOLBY_SURR_ENABLE (1<<0) -#define AC3_ALTIVEC_ENABLE (1<<1) - -typedef struct ac3_config_s { - // Bit flags that enable various things - uint32_t flags; - // Number of discrete channels in final output (for downmixing) - uint16_t num_output_ch; - // Which channel of a dual mono stream to select - uint16_t dual_mono_ch_sel; -} ac3_config_t; - -void ac3dec_init (void); - -#ifdef __OMS__ -size_t ac3dec_decode_data (plugin_output_audio_t *output, uint8_t *data_start, uint8_t *data_end); -#else -size_t ac3dec_decode_data (uint8_t *data_start ,uint8_t *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data); -#endif - -uint32_t ac3_buffersize(); - -#endif diff --git a/ac3dec/ac3_internal.h b/ac3dec/ac3_internal.h deleted file mode 100644 index 259396fdc..000000000 --- a/ac3dec/ac3_internal.h +++ /dev/null @@ -1,353 +0,0 @@ -/* - * ac3_internal.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef __GNUC__ -#define inline -#endif - -#include <setjmp.h> - -/* Exponent strategy constants */ -#define EXP_REUSE (0) -#define EXP_D15 (1) -#define EXP_D25 (2) -#define EXP_D45 (3) - -/* Delta bit allocation constants */ -#define DELTA_BIT_REUSE (0) -#define DELTA_BIT_NEW (1) -#define DELTA_BIT_NONE (2) -#define DELTA_BIT_RESERVED (3) - -/* samples work structure */ -typedef float stream_samples_t[6][256]; - -/* global config structure */ -extern ac3_config_t ac3_config; -/* global error flag */ -extern jmp_buf error_jmp_mark; -#define HANDLE_ERROR() longjmp (error_jmp_mark, -1) - -/* Everything you wanted to know about band structure */ -/* - * The entire frequency domain is represented by 256 real - * floating point fourier coefficients. Only the lower 253 - * coefficients are actually utilized however. We use arrays - * of 256 to be efficient in some cases. - * - * The 5 full bandwidth channels (fbw) can have their higher - * frequencies coupled together. These coupled channels then - * share their high frequency components. - * - * This coupling band is broken up into 18 sub-bands starting - * at mantissa number 37. Each sub-band is 12 bins wide. - * - * There are 50 bit allocation sub-bands which cover the entire - * frequency range. The sub-bands are of non-uniform width, and - * approximate a 1/6 octave scale. - */ - -/* The following structures are filled in by their corresponding parse_* - * functions. See http://www.atsc.org/Standards/A52/a_52.pdf for - * full details on each field. Indented fields are used to denote - * conditional fields. - */ - -typedef struct syncinfo_s -{ - uint32_t magic; - /* Sync word == 0x0B77 */ - uint16_t syncword; - /* crc for the first 5/8 of the sync block */ - /* uint16_t crc1; */ - /* Stream Sampling Rate (kHz) 0 = 48, 1 = 44.1, 2 = 32, 3 = reserved */ - uint16_t fscod; - /* Frame size code */ - uint16_t frmsizecod; - - /* Information not in the AC-3 bitstream, but derived */ - /* Frame size in 16 bit words */ - uint16_t frame_size; - /* Bit rate in kilobits */ - uint16_t bit_rate; - /* sampling rate in hertz */ - uint32_t sampling_rate; - -} syncinfo_t; - -typedef struct bsi_s -{ - uint32_t magic; - /* Bit stream identification == 0x8 */ - uint16_t bsid; - /* Bit stream mode */ - uint16_t bsmod; - /* Audio coding mode */ - uint16_t acmod; - /* If we're using the centre channel then */ - /* centre mix level */ - uint16_t cmixlev; - /* If we're using the surround channel then */ - /* surround mix level */ - uint16_t surmixlev; - /* If we're in 2/0 mode then */ - /* Dolby surround mix level - NOT USED - */ - uint16_t dsurmod; - /* Low frequency effects on */ - uint16_t lfeon; - /* Dialogue Normalization level */ - uint16_t dialnorm; - /* Compression exists */ - uint16_t compre; - /* Compression level */ - uint16_t compr; - /* Language code exists */ - uint16_t langcode; - /* Language code */ - uint16_t langcod; - /* Audio production info exists*/ - uint16_t audprodie; - uint16_t mixlevel; - uint16_t roomtyp; - /* If we're in dual mono mode (acmod == 0) then extra stuff */ - uint16_t dialnorm2; - uint16_t compr2e; - uint16_t compr2; - uint16_t langcod2e; - uint16_t langcod2; - uint16_t audprodi2e; - uint16_t mixlevel2; - uint16_t roomtyp2; - /* Copyright bit */ - uint16_t copyrightb; - /* Original bit */ - uint16_t origbs; - /* Timecode 1 exists */ - uint16_t timecod1e; - /* Timecode 1 */ - uint16_t timecod1; - /* Timecode 2 exists */ - uint16_t timecod2e; - /* Timecode 2 */ - uint16_t timecod2; - /* Additional bit stream info exists */ - uint16_t addbsie; - /* Additional bit stream length - 1 (in bytes) */ - uint16_t addbsil; - /* Additional bit stream information (max 64 bytes) */ - uint8_t addbsi[64]; - - /* Information not in the AC-3 bitstream, but derived */ - /* Number of channels (excluding LFE) - * Derived from acmod */ - uint16_t nfchans; -} bsi_t; - - -/* more pain */ -typedef struct audblk_s -{ - uint32_t magic1; - /* block switch bit indexed by channel num */ - uint16_t blksw[5]; - /* dither enable bit indexed by channel num */ - uint16_t dithflag[5]; - /* dynamic range gain exists */ - uint16_t dynrnge; - /* dynamic range gain */ - uint16_t dynrng; - /* if acmod==0 then */ - /* dynamic range 2 gain exists */ - uint16_t dynrng2e; - /* dynamic range 2 gain */ - uint16_t dynrng2; - /* coupling strategy exists */ - uint16_t cplstre; - /* coupling in use */ - uint16_t cplinu; - /* channel coupled */ - uint16_t chincpl[5]; - /* if acmod==2 then */ - /* Phase flags in use */ - uint16_t phsflginu; - /* coupling begin frequency code */ - uint16_t cplbegf; - /* coupling end frequency code */ - uint16_t cplendf; - /* coupling band structure bits */ - uint16_t cplbndstrc[18]; - /* Do coupling co-ords exist for this channel? */ - uint16_t cplcoe[5]; - /* Master coupling co-ordinate */ - uint16_t mstrcplco[5]; - /* Per coupling band coupling co-ordinates */ - uint16_t cplcoexp[5][18]; - uint16_t cplcomant[5][18]; - /* Phase flags for dual mono */ - uint16_t phsflg[18]; - /* Is there a rematrixing strategy */ - uint16_t rematstr; - /* Rematrixing bits */ - uint16_t rematflg[4]; - /* Coupling exponent strategy */ - uint16_t cplexpstr; - /* Exponent strategy for full bandwidth channels */ - uint16_t chexpstr[5]; - /* Exponent strategy for lfe channel */ - uint16_t lfeexpstr; - /* Channel bandwidth for independent channels */ - uint16_t chbwcod[5]; - /* The absolute coupling exponent */ - uint16_t cplabsexp; - /* Coupling channel exponents (D15 mode gives 18 * 12 /3 encoded exponents */ - uint16_t cplexps[18 * 12 / 3]; - /* Sanity checking constant */ - uint32_t magic2; - /* fbw channel exponents */ - uint16_t exps[5][252 / 3]; - /* channel gain range */ - uint16_t gainrng[5]; - /* low frequency exponents */ - uint16_t lfeexps[3]; - - /* Bit allocation info */ - uint16_t baie; - /* Slow decay code */ - uint16_t sdcycod; - /* Fast decay code */ - uint16_t fdcycod; - /* Slow gain code */ - uint16_t sgaincod; - /* dB per bit code */ - uint16_t dbpbcod; - /* masking floor code */ - uint16_t floorcod; - - /* SNR offset info */ - uint16_t snroffste; - /* coarse SNR offset */ - uint16_t csnroffst; - /* coupling fine SNR offset */ - uint16_t cplfsnroffst; - /* coupling fast gain code */ - uint16_t cplfgaincod; - /* fbw fine SNR offset */ - uint16_t fsnroffst[5]; - /* fbw fast gain code */ - uint16_t fgaincod[5]; - /* lfe fine SNR offset */ - uint16_t lfefsnroffst; - /* lfe fast gain code */ - uint16_t lfefgaincod; - - /* Coupling leak info */ - uint16_t cplleake; - /* coupling fast leak initialization */ - uint16_t cplfleak; - /* coupling slow leak initialization */ - uint16_t cplsleak; - - /* delta bit allocation info */ - uint16_t deltbaie; - /* coupling delta bit allocation exists */ - uint16_t cpldeltbae; - /* fbw delta bit allocation exists */ - uint16_t deltbae[5]; - /* number of cpl delta bit segments */ - uint16_t cpldeltnseg; - /* coupling delta bit allocation offset */ - uint16_t cpldeltoffst[8]; - /* coupling delta bit allocation length */ - uint16_t cpldeltlen[8]; - /* coupling delta bit allocation length */ - uint16_t cpldeltba[8]; - /* number of delta bit segments */ - uint16_t deltnseg[5]; - /* fbw delta bit allocation offset */ - uint16_t deltoffst[5][8]; - /* fbw delta bit allocation length */ - uint16_t deltlen[5][8]; - /* fbw delta bit allocation length */ - uint16_t deltba[5][8]; - - /* skip length exists */ - uint16_t skiple; - /* skip length */ - uint16_t skipl; - - //Removed Feb 2000 -ah - //added Jul 2000 ++dent - /* channel mantissas */ - uint16_t chmant[5][256]; - - /* coupling mantissas */ -// uint16_t cplmant[256]; - - //Added Jun 2000 -MaXX - /* coupling floats */ - float cpl_flt[ 256 ]; - - //Removed Feb 2000 -ah - //added Jul 2000 ++dent - /* coupling mantissas */ - uint16_t lfemant[7]; - - - /* -- Information not in the bitstream, but derived thereof -- */ - - /* Number of coupling sub-bands */ - uint16_t ncplsubnd; - - /* Number of combined coupling sub-bands - * Derived from ncplsubnd and cplbndstrc */ - uint16_t ncplbnd; - - /* Number of exponent groups by channel - * Derived from strmant, endmant */ - uint16_t nchgrps[5]; - - /* Number of coupling exponent groups - * Derived from cplbegf, cplendf, cplexpstr */ - uint16_t ncplgrps; - - /* End mantissa numbers of fbw channels */ - uint16_t endmant[5]; - - /* Start and end mantissa numbers for the coupling channel */ - uint16_t cplstrtmant; - uint16_t cplendmant; - - /* Decoded exponent info */ - uint16_t fbw_exp[5][256]; - uint16_t cpl_exp[256]; - uint16_t lfe_exp[7]; - - /* Bit allocation pointer results */ - uint16_t fbw_bap[5][256]; - uint16_t cpl_bap[256]; - uint16_t lfe_bap[7]; - - uint32_t magic3; -} audblk_t; - - diff --git a/ac3dec/bit_allocate.c b/ac3dec/bit_allocate.c deleted file mode 100644 index 008743402..000000000 --- a/ac3dec/bit_allocate.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * bit_allocate.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdlib.h> -#include <string.h> -#include "ac3.h" -#include "ac3_internal.h" - - - -static inline int16_t logadd(int16_t a,int16_t b); -static int16_t calc_lowcomp(int16_t a,int16_t b0,int16_t b1,int16_t bin); -static inline uint16_t min(int16_t a,int16_t b); -static inline uint16_t max(int16_t a,int16_t b); -static void ba_compute_psd(int16_t start, int16_t end, int16_t exps[], - int16_t psd[], int16_t bndpsd[]); - -static void ba_compute_excitation(int16_t start, int16_t end,int16_t fgain, - int16_t fastleak, int16_t slowleak, int16_t is_lfe, int16_t bndpsd[], - int16_t excite[]); -static void ba_compute_mask(int16_t start, int16_t end, uint16_t fscod, - uint16_t deltbae, uint16_t deltnseg, uint16_t deltoffst[], uint16_t deltba[], - uint16_t deltlen[], int16_t excite[], int16_t mask[]); -static void ba_compute_bap(int16_t start, int16_t end, int16_t snroffset, - int16_t psd[], int16_t mask[], int16_t bap[]); - -/* Misc LUTs for bit allocation process */ - -static int16_t slowdec[] = { 0x0f, 0x11, 0x13, 0x15 }; -static int16_t fastdec[] = { 0x3f, 0x53, 0x67, 0x7b }; -static int16_t slowgain[] = { 0x540, 0x4d8, 0x478, 0x410 }; -static int16_t dbpbtab[] = { 0x000, 0x700, 0x900, 0xb00 }; - -static uint16_t floortab[] = { 0x2f0, 0x2b0, 0x270, 0x230, 0x1f0, 0x170, 0x0f0, 0xf800 }; -static int16_t fastgain[] = { 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400 }; - - -static int16_t bndtab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, - 34, 37, 40, 43, 46, 49, 55, 61, 67, 73, - 79, 85, 97, 109, 121, 133, 157, 181, 205, 229 }; - -static int16_t bndsz[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, - 6, 12, 12, 12, 12, 24, 24, 24, 24, 24 }; - -static int16_t masktab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 28, 28, 29, - 29, 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, - 34, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 37, - 37, 37, 37, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 40, - 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, 0, 0 }; - - -static int16_t latab[] = { 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003b, 0x003a, 0x0039, - 0x0038, 0x0037, 0x0036, 0x0035, 0x0034, 0x0034, 0x0033, 0x0032, - 0x0031, 0x0030, 0x002f, 0x002f, 0x002e, 0x002d, 0x002c, 0x002c, - 0x002b, 0x002a, 0x0029, 0x0029, 0x0028, 0x0027, 0x0026, 0x0026, - 0x0025, 0x0024, 0x0024, 0x0023, 0x0023, 0x0022, 0x0021, 0x0021, - 0x0020, 0x0020, 0x001f, 0x001e, 0x001e, 0x001d, 0x001d, 0x001c, - 0x001c, 0x001b, 0x001b, 0x001a, 0x001a, 0x0019, 0x0019, 0x0018, - 0x0018, 0x0017, 0x0017, 0x0016, 0x0016, 0x0015, 0x0015, 0x0015, - 0x0014, 0x0014, 0x0013, 0x0013, 0x0013, 0x0012, 0x0012, 0x0012, - 0x0011, 0x0011, 0x0011, 0x0010, 0x0010, 0x0010, 0x000f, 0x000f, - 0x000f, 0x000e, 0x000e, 0x000e, 0x000d, 0x000d, 0x000d, 0x000d, - 0x000c, 0x000c, 0x000c, 0x000c, 0x000b, 0x000b, 0x000b, 0x000b, - 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0009, 0x0009, 0x0009, - 0x0009, 0x0009, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, - 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0006, 0x0006, - 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0005, 0x0005, - 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0004, 0x0004, - 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, - 0x0004, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, - 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0002, - 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, - 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, - 0x0002, 0x0002, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000}; - -static int16_t hth[][50] = {{ 0x04d0, 0x04d0, 0x0440, 0x0400, 0x03e0, 0x03c0, 0x03b0, 0x03b0, - 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390, - 0x0380, 0x0380, 0x0370, 0x0370, 0x0360, 0x0360, 0x0350, 0x0350, - 0x0340, 0x0340, 0x0330, 0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0, - 0x02f0, 0x02f0, 0x0300, 0x0310, 0x0340, 0x0390, 0x03e0, 0x0420, - 0x0460, 0x0490, 0x04a0, 0x0460, 0x0440, 0x0440, 0x0520, 0x0800, - 0x0840, 0x0840 }, - - { 0x04f0, 0x04f0, 0x0460, 0x0410, 0x03e0, 0x03d0, 0x03c0, 0x03b0, - 0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, - 0x0390, 0x0380, 0x0380, 0x0380, 0x0370, 0x0370, 0x0360, 0x0360, - 0x0350, 0x0350, 0x0340, 0x0340, 0x0320, 0x0310, 0x0300, 0x02f0, - 0x02f0, 0x02f0, 0x02f0, 0x0300, 0x0320, 0x0350, 0x0390, 0x03e0, - 0x0420, 0x0450, 0x04a0, 0x0490, 0x0460, 0x0440, 0x0480, 0x0630, - 0x0840, 0x0840 }, - - { 0x0580, 0x0580, 0x04b0, 0x0450, 0x0420, 0x03f0, 0x03e0, 0x03d0, - 0x03c0, 0x03b0, 0x03b0, 0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, - 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390, 0x0390, - 0x0380, 0x0380, 0x0380, 0x0370, 0x0360, 0x0350, 0x0340, 0x0330, - 0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0, 0x02f0, 0x0300, 0x0310, - 0x0330, 0x0350, 0x03c0, 0x0410, 0x0470, 0x04a0, 0x0460, 0x0440, - 0x0450, 0x04e0 }}; - - -static int16_t baptab[] = { 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, - 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, - 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, - 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; - -static int16_t sdecay; -static int16_t fdecay; -static int16_t sgain; -static int16_t dbknee; -static int16_t floor; -static int16_t psd[256]; -static int16_t bndpsd[256]; -static int16_t excite[256]; -static int16_t mask[256]; - - -/** - * - **/ - -static inline uint16_t max(int16_t a,int16_t b) -{ - return (a > b ? a : b); -} - - -/** - * - **/ - -static inline uint16_t min(int16_t a,int16_t b) -{ - return (a < b ? a : b); -} - - -/** - * - **/ - -static inline int16_t logadd(int16_t a,int16_t b) -{ - int16_t c; - int16_t address; - - c = a - b; - address = min((abs(c) >> 1), 255); - - if (c >= 0) - return(a + latab[address]); - else - return(b + latab[address]); -} - - -/** - * - **/ - -void bit_allocate(uint16_t fscod, bsi_t *bsi, audblk_t *audblk) -{ - uint16_t i; - int16_t fgain; - int16_t snroffset; - int16_t start; - int16_t end; - int16_t fastleak; - int16_t slowleak; - - /* Only perform bit_allocation if the exponents have changed or we - * have new sideband information */ - if (audblk->chexpstr[0] == 0 && audblk->chexpstr[1] == 0 && - audblk->chexpstr[2] == 0 && audblk->chexpstr[3] == 0 && - audblk->chexpstr[4] == 0 && audblk->cplexpstr == 0 && - audblk->lfeexpstr == 0 && audblk->baie == 0 && - audblk->snroffste == 0 && audblk->deltbaie == 0) - return; - - /* Do some setup before we do the bit alloc */ - sdecay = slowdec[audblk->sdcycod]; - fdecay = fastdec[audblk->fdcycod]; - sgain = slowgain[audblk->sgaincod]; - dbknee = dbpbtab[audblk->dbpbcod]; - floor = floortab[audblk->floorcod]; - - /* if all the SNR offset constants are zero then the whole block is zero */ - if(!audblk->csnroffst && !audblk->fsnroffst[0] && - !audblk->fsnroffst[1] && !audblk->fsnroffst[2] && - !audblk->fsnroffst[3] && !audblk->fsnroffst[4] && - !audblk->cplfsnroffst && !audblk->lfefsnroffst) { - memset(audblk->fbw_bap,0,sizeof(uint16_t) * 256 * 5); - memset(audblk->cpl_bap,0,sizeof(uint16_t) * 256); - memset(audblk->lfe_bap,0,sizeof(uint16_t) * 7); - return; - } - - - for(i = 0; i < bsi->nfchans; i++) - { - start = 0; - end = audblk->endmant[i] ; - fgain = fastgain[audblk->fgaincod[i]]; - snroffset = (((audblk->csnroffst - 15) << 4) + audblk->fsnroffst[i]) << 2 ; - fastleak = 0; - slowleak = 0; - - ba_compute_psd(start, end, audblk->fbw_exp[i], psd, bndpsd); - - ba_compute_excitation(start, end , fgain, fastleak, slowleak, 0, bndpsd, excite); - - ba_compute_mask(start, end, fscod, audblk->deltbae[i], audblk->deltnseg[i], - audblk->deltoffst[i], audblk->deltba[i], audblk->deltlen[i], excite, mask); - - ba_compute_bap(start, end, snroffset, psd, mask, audblk->fbw_bap[i]); - } - - if(audblk->cplinu) { - start = audblk->cplstrtmant; - end = audblk->cplendmant; - fgain = fastgain[audblk->cplfgaincod]; - snroffset = (((audblk->csnroffst - 15) << 4) + audblk->cplfsnroffst) << 2 ; - fastleak = (audblk->cplfleak << 8) + 768; - slowleak = (audblk->cplsleak << 8) + 768; - - ba_compute_psd(start, end, audblk->cpl_exp, psd, bndpsd); - - ba_compute_excitation(start, end , fgain, fastleak, slowleak, 0, bndpsd, excite); - - ba_compute_mask(start, end, fscod, audblk->cpldeltbae, audblk->cpldeltnseg, - audblk->cpldeltoffst, audblk->cpldeltba, audblk->cpldeltlen, excite, mask); - - ba_compute_bap(start, end, snroffset, psd, mask, audblk->cpl_bap); - } - - if(bsi->lfeon) { - start = 0; - end = 7; - fgain = fastgain[audblk->lfefgaincod]; - snroffset = (((audblk->csnroffst - 15) << 4) + audblk->lfefsnroffst) << 2 ; - fastleak = 0; - slowleak = 0; - - ba_compute_psd(start, end, audblk->lfe_exp, psd, bndpsd); - - ba_compute_excitation(start, end , fgain, fastleak, slowleak, 1, bndpsd, excite); - - /* Perform no delta bit allocation for lfe */ - ba_compute_mask(start, end, fscod, 2, 0, 0, 0, 0, excite, mask); - - ba_compute_bap(start, end, snroffset, psd, mask, audblk->lfe_bap); - } -} - - -/** - * - **/ - -static void ba_compute_psd(int16_t start, int16_t end, int16_t exps[], - int16_t psd[], int16_t bndpsd[]) -{ - int bin,i,j,k; - int16_t lastbin = 0; - - /* Map the exponents into dBs */ - for (bin=start; bin<end; bin++) { - psd[bin] = (3072 - (exps[bin] << 7)); - } - - /* Integrate the psd function over each bit allocation band */ - j = start; - k = masktab[start]; - - do { - lastbin = min(bndtab[k] + bndsz[k], end); - bndpsd[k] = psd[j]; - j++; - - for (i = j; i < lastbin; i++) { - bndpsd[k] = logadd(bndpsd[k], psd[j]); - j++; - } - - k++; - } while (end > lastbin); -} - - -/** - * - **/ - -static void ba_compute_excitation(int16_t start, int16_t end,int16_t fgain, - int16_t fastleak, int16_t slowleak, int16_t is_lfe, int16_t bndpsd[], - int16_t excite[]) -{ - int bin; - int16_t bndstrt; - int16_t bndend; - int16_t lowcomp = 0; - int16_t begin = 0; - - /* Compute excitation function */ - bndstrt = masktab[start]; - bndend = masktab[end - 1] + 1; - - if (bndstrt == 0) { /* For fbw and lfe channels */ - lowcomp = calc_lowcomp(lowcomp, bndpsd[0], bndpsd[1], 0); - excite[0] = bndpsd[0] - fgain - lowcomp; - lowcomp = calc_lowcomp(lowcomp, bndpsd[1], bndpsd[2], 1); - excite[1] = bndpsd[1] - fgain - lowcomp; - begin = 7 ; - -// Note: Do not call calc_lowcomp() for the last band of the lfe channel,(bin=6) - for (bin = 2; bin < 7; bin++) { - if (!(is_lfe && (bin == 6))) - lowcomp = calc_lowcomp(lowcomp, bndpsd[bin], bndpsd[bin+1], bin); - fastleak = bndpsd[bin] - fgain; - slowleak = bndpsd[bin] - sgain; - excite[bin] = fastleak - lowcomp; - - if (!(is_lfe && (bin == 6))) { - if (bndpsd[bin] <= bndpsd[bin+1]) { - begin = bin + 1 ; - break; - } - } - } - - for (bin = begin; bin < min(bndend, 22); bin++) { - if (!(is_lfe && (bin == 6))) - lowcomp = calc_lowcomp(lowcomp, bndpsd[bin], bndpsd[bin+1], bin); - fastleak -= fdecay ; - fastleak = max(fastleak, bndpsd[bin] - fgain); - slowleak -= sdecay ; - slowleak = max(slowleak, bndpsd[bin] - sgain); - excite[bin] = max(fastleak - lowcomp, slowleak); - } - begin = 22; - } - else /* For coupling channel */ - begin = bndstrt; - - for (bin = begin; bin < bndend; bin++) { - fastleak -= fdecay; - fastleak = max(fastleak, bndpsd[bin] - fgain); - slowleak -= sdecay; - slowleak = max(slowleak, bndpsd[bin] - sgain); - excite[bin] = max(fastleak, slowleak) ; - } -} - - -/** - * - **/ - -static void ba_compute_mask(int16_t start, int16_t end, uint16_t fscod, - uint16_t deltbae, uint16_t deltnseg, uint16_t deltoffst[], uint16_t deltba[], - uint16_t deltlen[], int16_t excite[], int16_t mask[]) -{ - int bin,k; - int16_t bndstrt; - int16_t bndend; - int16_t delta; - - bndstrt = masktab[start]; - bndend = masktab[end - 1] + 1; - - /* Compute the masking curve */ - - for (bin = bndstrt; bin < bndend; bin++) { - if (bndpsd[bin] < dbknee) { - excite[bin] += ((dbknee - bndpsd[bin]) >> 2); - } - mask[bin] = max(excite[bin], hth[fscod][bin]); - } - - /* Perform delta bit modulation if necessary */ - if ((deltbae == DELTA_BIT_REUSE) || (deltbae == DELTA_BIT_NEW)) { - int16_t band = 0; - int16_t seg = 0; - - for (seg = 0; seg < deltnseg+1; seg++) { - band += deltoffst[seg]; - - if (deltba[seg] >= 4) { - delta = (deltba[seg] - 3) << 7; - } else { - delta = (deltba[seg] - 4) << 7; - } - - for (k = 0; k < deltlen[seg]; k++) { - mask[band] += delta; - band++; - } - } - } -} - - -/** - * - **/ - -static void ba_compute_bap(int16_t start, int16_t end, int16_t snroffset, - int16_t psd[], int16_t mask[], int16_t bap[]) -{ - int i,j,k; - int16_t lastbin = 0; - int16_t address = 0; - - /* Compute the bit allocation pointer for each bin */ - i = start; - j = masktab[start]; - - do { - lastbin = min(bndtab[j] + bndsz[j], end); - mask[j] -= snroffset; - mask[j] -= floor; - - if (mask[j] < 0) - mask[j] = 0; - - mask[j] &= 0x1fe0; - mask[j] += floor; - for (k = i; k < lastbin; k++) { - address = (psd[i] - mask[j]) >> 5; - address = min(63, max(0, address)); - bap[i] = baptab[address]; - i++; - } - j++; - } while (end > lastbin); -} - - -/** - * - **/ - -static int16_t calc_lowcomp (int16_t a, int16_t b0, int16_t b1, int16_t bin) -{ - - if (bin < 7) { - if ((b0 + 256) == b1) - a = 384; - else if (b0 > b1) - a = max(0, a - 64); - } else if (bin < 20) { - if ((b0 + 256) == b1) - a = 320; - else if (b0 > b1) - a = max(0, a - 64) ; - } else - a = max(0, a - 128); - - return(a); -} - diff --git a/ac3dec/bit_allocate.h b/ac3dec/bit_allocate.h deleted file mode 100644 index a6a3c7703..000000000 --- a/ac3dec/bit_allocate.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * bit_allocate.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -void bit_allocate(uint16_t fscod, bsi_t *bsi, audblk_t *audblk); diff --git a/ac3dec/bitstream.c b/ac3dec/bitstream.c deleted file mode 100644 index f48d2408a..000000000 --- a/ac3dec/bitstream.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * bitstream.c - * - * Copyright (C) Aaron Holtzman - Dec 1999 - * - * This file is part of ac3dec, a free AC-3 audio decoder - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <inttypes.h> - -#include <bswap.h> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "ac3.h" -#include "ac3_internal.h" -#include "bitstream.h" - - -uint32_t bits_left = 0; -uint64_t current_word; -uint64_t *buffer_start = 0; - - -static inline uint64_t getdword (void) -{ - return be2me_64 (*buffer_start++); -} - - -static inline void bitstream_fill_current (void) -{ - //current_word = bswap_64 (*buffer_start++); - current_word = getdword (); -} - - -uint32_t bitstream_get_bh (uint32_t num_bits) -{ - uint32_t result; - - num_bits -= bits_left; - result = (current_word << (64 - bits_left)) >> (64 - bits_left); - - bitstream_fill_current(); - - if(num_bits != 0) - result = (result << num_bits) | (current_word >> (64 - num_bits)); - - bits_left = 64 - num_bits; - - return result; -} - - -void bitstream_init (uint8_t *start) -{ - //initialize the start of the buffer - buffer_start = (uint64_t *) start; - bits_left = 0; -} diff --git a/ac3dec/bitstream.h b/ac3dec/bitstream.h deleted file mode 100644 index f34726a77..000000000 --- a/ac3dec/bitstream.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * bitstream.h - * - * Copyright (C) Aaron Holtzman - Dec 1999 - * - * This file is part of ac3dec, a free AC-3 audio decoder - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - - -#include <inttypes.h> - -extern uint32_t bits_left; -extern uint64_t current_word; - -void bitstream_init(uint8_t *start); -inline uint32_t bitstream_get_bh(uint32_t num_bits); - -static inline uint32_t bitstream_get (uint32_t num_bits) -{ - uint32_t result; - - if (num_bits < bits_left) { - result = (current_word << (64 - bits_left)) >> (64 - num_bits); - bits_left -= num_bits; - return result; - } - - return bitstream_get_bh (num_bits); -} diff --git a/ac3dec/bswap.h b/ac3dec/bswap.h deleted file mode 100644 index 73d398aa1..000000000 --- a/ac3dec/bswap.h +++ /dev/null @@ -1,80 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#ifndef __BSWAP_H__ -#define __BSWAP_H__ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_BYTESWAP_H -#include <byteswap.h> -#else - -#include <inttypes.h> - -#ifdef WORDS_BIGENDIAN -// FIXME these need to actually swap ;) -#define bswap_16(x) (x) -#define bswap_32(x) (x) -#define bswap_64(x) (x) -#else -// This is wrong, 'cannot take address of ...' -#define bswap_16(x) ((((uint8_t*)&x)[2] << 8) \ - | (((uint8_t*)&x)[3])) - -// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. -#define bswap_32(x) \ - ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ - (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) - -#define bswap_64(x) \ - (__extension__ \ - ({ union { __extension__ unsigned long long int __ll; \ - unsigned long int __l[2]; } __w, __r; \ - __w.__ll = (x); \ - __r.__l[0] = bswap_32 (__w.__l[1]); \ - __r.__l[1] = bswap_32 (__w.__l[0]); \ - __r.__ll; })) -#endif - -#endif - -// be2me ... BigEndian to MachineEndian -// le2me ... LittleEndian to MachineEndian - -#ifdef WORDS_BIGENDIAN -#define be2me_16(x) (x) -#define be2me_32(x) (x) -#define be2me_64(x) (x) -#define le2me_16(x) bswap_16(x) -#define le2me_32(x) bswap_32(x) -#define le2me_64(x) bswap_64(x) -#else -#define be2me_16(x) bswap_16(x) -#define be2me_32(x) bswap_32(x) -#define be2me_64(x) bswap_64(x) -#define le2me_16(x) (x) -#define le2me_32(x) (x) -#define le2me_64(x) (x) -#endif - -#endif diff --git a/ac3dec/cmplx.h b/ac3dec/cmplx.h deleted file mode 100644 index 9f74721ec..000000000 --- a/ac3dec/cmplx.h +++ /dev/null @@ -1,29 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#ifndef __COMPLEX_H__ -#define __COMPLEX_H__ - -typedef struct complex { - float re; - float im; -} complex_t; - -#endif diff --git a/ac3dec/coeff.c b/ac3dec/coeff.c deleted file mode 100644 index 7d5579cae..000000000 --- a/ac3dec/coeff.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * coeff.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - - -#include <stdlib.h> -#include <stdio.h> -#include "ac3.h" -#include "ac3_internal.h" - - -#include "bitstream.h" -#include "dither.h" -#include "coeff.h" - - -// -//Lookup tables of 0.15 two's complement quantization values -// -#define Q0 ((-2 << 15) / 3.0) -#define Q1 (0) -#define Q2 ((2 << 15) / 3.0) - -static const float q_1_0[ 32 ] = -{ - Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, - Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, - Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, - 0,0,0,0,0 -}; - -static const float q_1_1[ 32 ] = -{ - Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, - Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, - Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, - 0,0,0,0,0 -}; - -static const float q_1_2[ 32 ] = -{ - Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, - Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, - Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, - 0,0,0,0,0 -}; - -#undef Q0 -#undef Q1 -#undef Q2 - -#define Q0 ((-4 << 15) / 5.0) -#define Q1 ((-2 << 15) / 5.0) -#define Q2 (0) -#define Q3 ((2 << 15) / 5.0) -#define Q4 ((4 << 15) / 5.0) - -static const float q_2_0[ 128 ] = -{ - Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, - Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, - Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, - Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, - Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, - Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, - Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3, - Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3, - Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4, - Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4, - 0,0,0 -}; - -static const float q_2_1[ 128 ] = -{ - Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1, - Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3, - Q4,Q4,Q4,Q4,Q4,Q0,Q0,Q0,Q0,Q0, - Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2, - Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, - Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1, - Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3, - Q4,Q4,Q4,Q4,Q4,Q0,Q0,Q0,Q0,Q0, - Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2, - Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, - Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1, - Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3, - Q4,Q4,Q4,Q4,Q4,0,0,0 - }; - -static const float q_2_2[ 128 ] = - { - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,0,0,0 -}; - -#undef Q0 -#undef Q1 -#undef Q2 -#undef Q3 -#undef Q4 - -static const float q_3[7] = -{ - (-6 << 15)/7.0, (-4 << 15)/7.0, (-2 << 15)/7.0, 0.0, - ( 2 << 15)/7.0, ( 4 << 15)/7.0, ( 6 << 15)/7.0 -}; - -#define Q0 ((-10 << 15) / 11.0) -#define Q1 ((-8 << 15) / 11.0) -#define Q2 ((-6 << 15) / 11.0) -#define Q3 ((-4 << 15) / 11.0) -#define Q4 ((-2 << 15) / 11.0) -#define Q5 (0) -#define Q6 ((2 << 15) / 11.0) -#define Q7 ((4 << 15) / 11.0) -#define Q8 ((6 << 15) / 11.0) -#define Q9 ((8 << 15) / 11.0) -#define QA ((10 << 15) / 11.0) - -static const float q_4_0[ 128 ] = -{ - Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, - Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, - Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, - Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, - Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, - Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, - Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, - Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, - Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, - Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, - QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, - 0, 0, 0, 0, 0, 0, 0 - }; - -static const float q_4_1[ 128 ] = -{ - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - 0, 0, 0, 0, 0, 0, 0 -}; - -#undef Q0 -#undef Q1 -#undef Q2 -#undef Q3 -#undef Q4 -#undef Q5 -#undef Q6 -#undef Q7 -#undef Q8 -#undef Q9 -#undef QA - -static const float q_5[15] = -{ - (-14 << 15)/15.0,(-12 << 15)/15.0,(-10 << 15)/15.0, - ( -8 << 15)/15.0,( -6 << 15)/15.0,( -4 << 15)/15.0, - ( -2 << 15)/15.0, 0.0 ,( 2 << 15)/15.0, - ( 4 << 15)/15.0,( 6 << 15)/15.0,( 8 << 15)/15.0, - ( 10 << 15)/15.0,( 12 << 15)/15.0,( 14 << 15)/15.0 -}; - -// -// Scale factors for convert_to_float -// - -static const uint32_t u32_scale_factors[25] = -{ - 0x38000000, //2 ^ -(0 + 15) - 0x37800000, //2 ^ -(1 + 15) - 0x37000000, //2 ^ -(2 + 15) - 0x36800000, //2 ^ -(3 + 15) - 0x36000000, //2 ^ -(4 + 15) - 0x35800000, //2 ^ -(5 + 15) - 0x35000000, //2 ^ -(6 + 15) - 0x34800000, //2 ^ -(7 + 15) - 0x34000000, //2 ^ -(8 + 15) - 0x33800000, //2 ^ -(9 + 15) - 0x33000000, //2 ^ -(10 + 15) - 0x32800000, //2 ^ -(11 + 15) - 0x32000000, //2 ^ -(12 + 15) - 0x31800000, //2 ^ -(13 + 15) - 0x31000000, //2 ^ -(14 + 15) - 0x30800000, //2 ^ -(15 + 15) - 0x30000000, //2 ^ -(16 + 15) - 0x2f800000, //2 ^ -(17 + 15) - 0x2f000000, //2 ^ -(18 + 15) - 0x2e800000, //2 ^ -(19 + 15) - 0x2e000000, //2 ^ -(20 + 15) - 0x2d800000, //2 ^ -(21 + 15) - 0x2d000000, //2 ^ -(22 + 15) - 0x2c800000, //2 ^ -(23 + 15) - 0x2c000000 //2 ^ -(24 + 15) -}; - -static float *scale_factor = (float*)u32_scale_factors; - -//These store the persistent state of the packed mantissas -static float q_1[2]; -static float q_2[2]; -static float q_4[1]; -static int32_t q_1_pointer; -static int32_t q_2_pointer; -static int32_t q_4_pointer; -static float __inline__ -coeff_get_float(uint16_t bap, uint16_t dithflag, uint16_t exp); - -//Conversion from bap to number of bits in the mantissas -//zeros account for cases 0,1,2,4 which are special cased -static uint16_t qnttztab[16] = -{ - 0, 0, 0, 3, - 0, 4, 5, 6, - 7, 8, 9, 10, - 11, 12, 14, 16 -}; - -static void coeff_reset(void); -static float coeff_get_float(uint16_t bap, uint16_t dithflag, uint16_t exp); -static void coeff_uncouple_ch(float samples[],bsi_t *bsi,audblk_t *audblk,uint32_t ch); - -void coeff_unpack(bsi_t *bsi, audblk_t *audblk, stream_samples_t samples) -{ - uint16_t i,j; - uint32_t done_cpl = 0; - - coeff_reset(); - - for(i=0; i< bsi->nfchans; i++) { - for(j=0; j < audblk->endmant[i]; j++) - samples[i][j] = coeff_get_float(audblk->fbw_bap[i][j], audblk->dithflag[i], audblk->fbw_exp[i][j]); - - if(audblk->cplinu && audblk->chincpl[i] && !(done_cpl)) { - // ncplmant is equal to 12 * ncplsubnd - // Don't dither coupling channel until channel - // separation so that interchannel noise is uncorrelated - for(j=audblk->cplstrtmant; j < audblk->cplendmant; j++) - audblk->cpl_flt[j] = coeff_get_float(audblk->cpl_bap[j],0, audblk->cpl_exp[j]); - done_cpl = 1; - } - } - - //uncouple the channel if necessary - if(audblk->cplinu) { - for(i=0; i< bsi->nfchans; i++) { - if(audblk->chincpl[i]) - coeff_uncouple_ch(samples[i],bsi,audblk,i); - } - - } - - if(bsi->lfeon) { - // There are always 7 mantissas for lfe, no dither for lfe - for(j=0; j < 7 ; j++) - samples[5][j] = coeff_get_float(audblk->lfe_bap[j], 0, audblk->lfe_exp[j]); - } -} - - -/** - * Fetch a float from the bitstream - **/ - -static float inline coeff_get_float (uint16_t bap, uint16_t dithflag, uint16_t exp) -{ - uint16_t dummy = 0; - - //If the bap is 0-5 then we have special cases to take care of - switch(bap) { - case 0: - if(dithflag) - return (dither_gen() * scale_factor[exp]); - - return 0.0; - - case 1: - if (q_1_pointer >= 0) - return(q_1[q_1_pointer--] * scale_factor[exp]); - - if ((dummy = bitstream_get (5)) > 26) - goto error; - - q_1[1] = q_1_1[dummy]; - q_1[0] = q_1_2[dummy]; - q_1_pointer = 1; - - return (q_1_0[dummy] * scale_factor[exp]); - - case 2: - if(q_2_pointer >= 0) - return (q_2[q_2_pointer--] * scale_factor[exp]); - - if ((dummy = bitstream_get (7)) > 124) - goto error; - - q_2[1] = q_2_1[dummy]; - q_2[0] = q_2_2[dummy]; - q_2_pointer = 1; - - return (q_2_0[dummy] * scale_factor[exp]); - - case 3: - if ((dummy = bitstream_get (3)) > 6) - goto error; - - return (q_3[dummy] * scale_factor[exp]); - - case 4: - if(q_4_pointer >= 0) - return (q_4[q_4_pointer--] * scale_factor[exp]); - - if ((dummy = bitstream_get (7)) > 120) - goto error; - - q_4[0] = q_4_1[dummy]; - q_4_pointer = 0; - - return (q_4_0[dummy] * scale_factor[exp]); - - case 5: - if ((dummy = bitstream_get (4)) > 14) - goto error; - - return (q_5[dummy] * scale_factor[exp]); - - default: - dummy = bitstream_get(qnttztab[bap]); - dummy <<= 16 - qnttztab[bap]; - return ((int16_t)dummy * scale_factor[exp]); - } - -error: -#ifdef DEBUG - fprintf(stderr,"** Invalid mantissa - skipping frame **\n"); -#endif - HANDLE_ERROR(); -} - - -/** - * Reset the mantissa state - **/ - -static void coeff_reset(void) -{ - q_1_pointer = q_2_pointer = q_4_pointer = -1; -} - - -/** - * Uncouple the coupling channel into a fbw channel - **/ - -static void coeff_uncouple_ch (float samples[],bsi_t *bsi,audblk_t *audblk,uint32_t ch) -{ - uint32_t bnd = 0; - uint32_t sub_bnd = 0; - uint32_t i,j; - float cpl_coord = 1.0; - uint32_t cpl_exp_tmp; - uint32_t cpl_mant_tmp; - - for (i=audblk->cplstrtmant;i<audblk->cplendmant;) { - if (!audblk->cplbndstrc[sub_bnd++]) { - cpl_exp_tmp = audblk->cplcoexp[ch][bnd] + 3 * audblk->mstrcplco[ch]; - if (audblk->cplcoexp[ch][bnd] == 15) - cpl_mant_tmp = (audblk->cplcomant[ch][bnd]) << 11; - else - cpl_mant_tmp = ((0x10) | audblk->cplcomant[ch][bnd]) << 10; - - cpl_coord = (cpl_mant_tmp * scale_factor[cpl_exp_tmp]) * 8.0f; - - //Invert the phase for the right channel if necessary - if(bsi->acmod == 0x2 && audblk->phsflginu && ch == 1 && audblk->phsflg[bnd]) - cpl_coord *= -1; - - bnd++; - } - - for(j=0;j < 12; j++) { - // Get new dither values for each channel if necessary, - // so the channels are uncorrelated - if(audblk->dithflag[ch] && !audblk->cpl_bap[i]) - samples[i] = cpl_coord * (dither_gen() * scale_factor[audblk->cpl_exp[i]]); - else - samples[i] = cpl_coord * audblk->cpl_flt[i]; - - i++; - } - } -} diff --git a/ac3dec/coeff.h b/ac3dec/coeff.h deleted file mode 100644 index dc822a9bd..000000000 --- a/ac3dec/coeff.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * coeff.h - * - * Copyright (C) Aaron Holtzman - Feb 2000 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -void coeff_unpack(bsi_t *bsi, audblk_t *audblk,stream_samples_t samples); diff --git a/ac3dec/cpu_accel.c b/ac3dec/cpu_accel.c deleted file mode 100644 index e01db83f6..000000000 --- a/ac3dec/cpu_accel.c +++ /dev/null @@ -1,129 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#include <inttypes.h> -#include "mm_accel.h" - -//#ifdef __i386__ -#if 0 - -#ifdef __PIC__ -#define cpuid(op, eax, ebx, ecx, edx) \ - __asm__ __volatile__ ("pushl %%ebx\n\t" \ - "cpuid\n\t" \ - "movl %%ebx, %%esi\n\t" \ - "popl %%ebx" \ - : "=a" (eax), \ - "=S" (ebx), \ - "=c" (ecx), \ - "=d" (edx) \ - : "a" (op) \ - : "cc") -#else -#define cpuid(op, eax, ebx, ecx, edx) \ - __asm__("cpuid" \ - : "=a" (eax), \ - "=b" (ebx), \ - "=c" (ecx), \ - "=d" (edx) \ - : "a" (op) \ - : "cc") -#endif - -static inline int has_cpuid () -{ - return 1; -/* - uint32_t eax, ebx; - - asm ("pushfl\n\t" - "popl %0\n\t" - "movl %0,%1\n\t" - "xorl $0x200000,%0\n\t" - "pushl %0\n\t" - "popfl\n\t" - "pushfl\n\t" - "popl %0" - : "=a" (eax), - "=b" (ebx) - : - : "cc"); - - return (eax != ebx); -*/ -} - - -static uint32_t x86_accel (void) -{ - uint32_t eax, ebx, ecx, edx; - int AMD; - uint32_t caps; - - if (!has_cpuid ()) // no cpuid - return 0; - - cpuid (0x00000000, eax, ebx, ecx, edx); - if (!eax) // vendor string only - return 0; - - AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65); - - cpuid (0x00000001, eax, ebx, ecx, edx); - if (! (edx & 0x00800000)) // no MMX - return 0; - - caps = OMS_ACCEL_X86_MMX; - if (edx & 0x02000000) // SSE - identical to AMD MMX extensions - caps = OMS_ACCEL_X86_MMX | OMS_ACCEL_X86_MMXEXT; - - cpuid (0x80000000, eax, ebx, ecx, edx); - if (eax < 0x80000001) // no extended capabilities - return caps; - - cpuid (0x80000001, eax, ebx, ecx, edx); - - if (edx & 0x80000000) - caps |= OMS_ACCEL_X86_3DNOW; - - if (AMD && (edx & 0x00400000)) // AMD MMX extensions - caps |= OMS_ACCEL_X86_MMXEXT; - - return caps; -} -#endif - -uint32_t mm_accel (void) -{ -//#ifdef __i386__ -#if 0 - static int got_accel = 0; - static uint32_t accel; - - if (!got_accel) { - got_accel = 1; - accel = x86_accel (); - } - - return accel; -#else - return 0; -#endif -} diff --git a/ac3dec/crc.c b/ac3dec/crc.c deleted file mode 100644 index 2d5ef8065..000000000 --- a/ac3dec/crc.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * crc.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include "ac3.h" -#include "ac3_internal.h" - -#include <sys/time.h> - -#include "crc.h" - -static const uint16_t crc_lut[256] = -{ - 0x0000,0x8005,0x800f,0x000a,0x801b,0x001e,0x0014,0x8011, - 0x8033,0x0036,0x003c,0x8039,0x0028,0x802d,0x8027,0x0022, - 0x8063,0x0066,0x006c,0x8069,0x0078,0x807d,0x8077,0x0072, - 0x0050,0x8055,0x805f,0x005a,0x804b,0x004e,0x0044,0x8041, - 0x80c3,0x00c6,0x00cc,0x80c9,0x00d8,0x80dd,0x80d7,0x00d2, - 0x00f0,0x80f5,0x80ff,0x00fa,0x80eb,0x00ee,0x00e4,0x80e1, - 0x00a0,0x80a5,0x80af,0x00aa,0x80bb,0x00be,0x00b4,0x80b1, - 0x8093,0x0096,0x009c,0x8099,0x0088,0x808d,0x8087,0x0082, - 0x8183,0x0186,0x018c,0x8189,0x0198,0x819d,0x8197,0x0192, - 0x01b0,0x81b5,0x81bf,0x01ba,0x81ab,0x01ae,0x01a4,0x81a1, - 0x01e0,0x81e5,0x81ef,0x01ea,0x81fb,0x01fe,0x01f4,0x81f1, - 0x81d3,0x01d6,0x01dc,0x81d9,0x01c8,0x81cd,0x81c7,0x01c2, - 0x0140,0x8145,0x814f,0x014a,0x815b,0x015e,0x0154,0x8151, - 0x8173,0x0176,0x017c,0x8179,0x0168,0x816d,0x8167,0x0162, - 0x8123,0x0126,0x012c,0x8129,0x0138,0x813d,0x8137,0x0132, - 0x0110,0x8115,0x811f,0x011a,0x810b,0x010e,0x0104,0x8101, - 0x8303,0x0306,0x030c,0x8309,0x0318,0x831d,0x8317,0x0312, - 0x0330,0x8335,0x833f,0x033a,0x832b,0x032e,0x0324,0x8321, - 0x0360,0x8365,0x836f,0x036a,0x837b,0x037e,0x0374,0x8371, - 0x8353,0x0356,0x035c,0x8359,0x0348,0x834d,0x8347,0x0342, - 0x03c0,0x83c5,0x83cf,0x03ca,0x83db,0x03de,0x03d4,0x83d1, - 0x83f3,0x03f6,0x03fc,0x83f9,0x03e8,0x83ed,0x83e7,0x03e2, - 0x83a3,0x03a6,0x03ac,0x83a9,0x03b8,0x83bd,0x83b7,0x03b2, - 0x0390,0x8395,0x839f,0x039a,0x838b,0x038e,0x0384,0x8381, - 0x0280,0x8285,0x828f,0x028a,0x829b,0x029e,0x0294,0x8291, - 0x82b3,0x02b6,0x02bc,0x82b9,0x02a8,0x82ad,0x82a7,0x02a2, - 0x82e3,0x02e6,0x02ec,0x82e9,0x02f8,0x82fd,0x82f7,0x02f2, - 0x02d0,0x82d5,0x82df,0x02da,0x82cb,0x02ce,0x02c4,0x82c1, - 0x8243,0x0246,0x024c,0x8249,0x0258,0x825d,0x8257,0x0252, - 0x0270,0x8275,0x827f,0x027a,0x826b,0x026e,0x0264,0x8261, - 0x0220,0x8225,0x822f,0x022a,0x823b,0x023e,0x0234,0x8231, - 0x8213,0x0216,0x021c,0x8219,0x0208,0x820d,0x8207,0x0202 -}; - -static uint16_t state; - - -void crc_init(void) -{ - state = 0; -} - - -inline void crc_process_byte (uint8_t data) -{ - state = crc_lut[data ^ (state>>8)] ^ (state<<8); -} - - -void crc_process_frame (uint8_t *data,uint32_t num_bytes) -{ - uint32_t i; - - for(i=0; i<num_bytes; i++) - crc_process_byte (data[i]); -} - - -int crc_validate(void) -{ - return (state == 0); -} diff --git a/ac3dec/crc.h b/ac3dec/crc.h deleted file mode 100644 index 16489656c..000000000 --- a/ac3dec/crc.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * crc.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -int crc_validate(void); -void crc_init(void); -void crc_process_byte(uint8_t data); -void crc_process_frame(uint8_t *data,uint32_t num_bytes); diff --git a/ac3dec/debug.c b/ac3dec/debug.c deleted file mode 100644 index b84511d7f..000000000 --- a/ac3dec/debug.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * debug.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdlib.h> -#include "debug.h" - -static int debug_level = -1; - -// Determine is debug output is required. -// We could potentially have multiple levels of debug info -int debug_is_on(void) -{ - if(debug_level < 0) { - debug_level = getenv ("AC3_DEBUG") ? 1 : 0; - } - - return debug_level; -} - -//If you don't have gcc, then ya don't get debug output -#ifndef __GNUC__ -void dprintf(char fmt[],...) -{ - return; -} -#endif - diff --git a/ac3dec/debug.h b/ac3dec/debug.h deleted file mode 100644 index 691d40329..000000000 --- a/ac3dec/debug.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * debug.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -int debug_is_on (void); - -#ifdef __GNUC__ -#ifdef DEBUG -#define dprintf(args...)\ -{\ - if (debug_is_on())\ - {\ - fprintf(stderr, args);\ - }\ -} -#else -#define dprintf(args...) { }; -#endif -#else -void dprintf(char fmt[],...); -#endif diff --git a/ac3dec/decode.c b/ac3dec/decode.c deleted file mode 100644 index 1ff517c41..000000000 --- a/ac3dec/decode.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * decode.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - *------------------------------------------------------------ - * - * Thomas Mirlacher <dent@cosy.sbg.ac.at> - * added OMS support - * 11 Jan 2001 - * Thomas Mirlacher <dent@cosy.sbg.ac.at> - * faster error response using jmp functions - * - * 9 Aug 2001 - * Matjaz Thaler <matjaz.thaler@rd.iskraemeco.si> - * Added support for DVB-s PCI card - * - * 24 Nov 2001 - * Andreas Schultz <aschultz@cs.uni-magdeburg.de> - * Added ac3_buffersize() - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include <sys/time.h> - -#ifdef __OMS__ -#include <oms/oms.h> -#include <oms/plugin/output_audio.h> -#endif - -#include "ac3.h" -#include "ac3_internal.h" -#include "bitstream.h" -#include "downmix.h" -#include "srfft.h" -#include "imdct.h" -#include "exponent.h" -#include "coeff.h" -#include "bit_allocate.h" -#include "parse.h" -#include "crc.h" -#include "stats.h" -#include "rematrix.h" -#include "sanity_check.h" -#include "debug.h" -#ifndef __OMS__ -//#include "audio_out.h" -#endif -//our global config structure -ac3_config_t ac3_config; - -static audblk_t audblk; -static bsi_t bsi; -static syncinfo_t syncinfo; -#ifndef __OMS__ -static uint32_t done_banner; -#endif -static uint32_t is_output_initialized = 0; - -//the floating point samples for one audblk -static stream_samples_t samples; - -//the integer samples for the entire frame (with enough space for 2 ch out) -//if this size change, be sure to change the size when muting -static int16_t s16_samples[2 * 6 * 256] __attribute__ ((aligned(16))); - -// downmix stuff -static float cmixlev_lut[4] = { 0.707, 0.595, 0.500, 0.707 }; -static float smixlev_lut[4] = { 0.707, 0.500, 0.0 , 0.500 }; -static dm_par_t dm_par; - -//Storage for the syncframe -#define BUFFER_MAX_SIZE 4096 -static uint8_t buffer[BUFFER_MAX_SIZE]; -static uint32_t buffer_size = 0;; -// for error handling -jmp_buf error_jmp_mark; - -uint32_t ac3_buffersize() -{ - return buffer_size; -} - -static uint32_t decode_buffer_syncframe (syncinfo_t *syncinfo, uint8_t **start, uint8_t *end) -{ - uint8_t *cur = *start; - uint16_t syncword = syncinfo->syncword; - uint32_t ret = 0; - - // Find an ac3 sync frame. - while (syncword != 0x0b77) { - if (cur >= end) - goto done; - syncword = (syncword << 8) + *cur++; - } - - //need the next 3 bytes to decide how big the frame is - while (buffer_size < 3) { - if(cur >= end) - goto done; - - buffer[buffer_size++] = *cur++; - } - - parse_syncinfo (syncinfo,buffer); - stats_print_syncinfo (syncinfo); - - while (buffer_size < syncinfo->frame_size * 2 - 2) { - if(cur >= end) - goto done; - - buffer[buffer_size++] = *cur++; - } - -#if 0 - // Check the crc over the entire frame - crc_init(); - crc_process_frame (buffer, syncinfo->frame_size * 2 - 2); - - if (!crc_validate()) { - fprintf(stderr,"** CRC failed - skipping frame **\n"); - goto done; - } -#endif - - //if we got to this point, we found a valid ac3 frame to decode - - bitstream_init (buffer); - //get rid of the syncinfo struct as we already parsed it - bitstream_get (24); - - //reset the syncword for next time - syncword = 0xffff; - buffer_size = 0; - ret = 1; - -done: - syncinfo->syncword = syncword; - *start = cur; - return ret; -} - - -void inline decode_mute (void) -{ - //mute the frame - memset (s16_samples, 0, sizeof(int16_t) * 256 * 2 * 6); -} - - -void ac3dec_init (void) -{ -// FIXME - don't do that statically here - ac3_config.num_output_ch = 2; - ac3_config.flags = 0; - - imdct_init (); - downmix_init (); - memset (&syncinfo, 0, sizeof (syncinfo)); - memset (&bsi, 0, sizeof (bsi)); - memset (&audblk, 0, sizeof (audblk)); - sanity_check_init (&syncinfo,&bsi,&audblk); -} - -#ifdef __OMS__ -size_t ac3dec_decode_data (plugin_output_audio_t *output, uint8_t *data_start, uint8_t *data_end) -#else -size_t ac3dec_decode_data (uint8_t *data_start ,uint8_t *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data) -#endif -{ - uint32_t i; - int datasize; - char *data; - - - if(ac3reset != 0){ - syncinfo.syncword = 0xffff; - buffer_size = 0; - } - - if (setjmp (error_jmp_mark) < 0) { - ac3dec_init (); - return 0; - } - - while (decode_buffer_syncframe (&syncinfo, &data_start, data_end)) { - parse_bsi (&bsi); - -#ifndef __OMS__ - if(!done_banner) { - // stats_print_banner(&syncinfo,&bsi); - done_banner = 1; - } -#endif - - // compute downmix parameters - // downmix to tow channels for now - dm_par.clev = 0.0; dm_par.slev = 0.0; dm_par.unit = 1.0; - if (bsi.acmod & 0x1) // have center - dm_par.clev = cmixlev_lut[bsi.cmixlev]; - - if (bsi.acmod & 0x4) // have surround channels - dm_par.slev = smixlev_lut[bsi.surmixlev]; - - dm_par.unit /= 1.0 + dm_par.clev + dm_par.slev; - dm_par.clev *= dm_par.unit; - dm_par.slev *= dm_par.unit; - - for(i=0; i < 6; i++) { - //Initialize freq/time sample storage - memset (samples, 0, sizeof(float) * 256 * (bsi.nfchans + bsi.lfeon)); - - // Extract most of the audblk info from the bitstream - // (minus the mantissas - parse_audblk (&bsi,&audblk); - - // Take the differential exponent data and turn it into - // absolute exponents - exponent_unpack (&bsi,&audblk); - - // Figure out how many bits per mantissa - bit_allocate (syncinfo.fscod,&bsi,&audblk); - - // Extract the mantissas from the stream and - // generate floating point frequency coefficients - coeff_unpack (&bsi,&audblk,samples); - - if (bsi.acmod == 0x2) - rematrix (&audblk,samples); - - // Convert the frequency samples into time samples - imdct (&bsi,&audblk,samples, &s16_samples[i * 2 * 256], &dm_par); - - // Downmix into the requested number of channels - // and convert floating point to int16_t - // downmix(&bsi,samples,&s16_samples[i * 2 * 256]); - - if (sanity_check(&syncinfo,&bsi,&audblk) < 0) { - HANDLE_ERROR (); - return 0; - } - - continue; - } - - if (!is_output_initialized) { -#ifdef __OMS__ - plugin_output_audio_attr_t attr; -#ifdef __sun__ - attr.format = 16; -#else - attr.format = AFMT_S16_NE; -#endif - attr.speed = syncinfo.sampling_rate; - attr.channels = 2; - - // output->setup (&attr); -#else - // ao_functions->open (16, syncinfo.sampling_rate, 2); -#endif - is_output_initialized = 1; - } - -#ifdef __OMS__ - output->write (s16_samples, 256 * 6 * 2 * 2); -#else - // ao_functions->play(s16_samples, 256 * 6 * 2); - data = (char *)s16_samples; - datasize = 0; - while(datasize < 6144){ - if(((*input_pointer+1) % AC3_BUFFER_SIZE) != *output_pointer){ // There is room in the sync_buffer - ac3_data[*input_pointer]=data[datasize]; - datasize++; - *input_pointer = (*input_pointer+1) % AC3_BUFFER_SIZE; - } - else{ - *input_pointer = *output_pointer = 0; - break; - } - } - -#endif - - } - - decode_mute (); - - return 0; -} diff --git a/ac3dec/decode.h b/ac3dec/decode.h deleted file mode 100644 index bb84a1105..000000000 --- a/ac3dec/decode.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * decode.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ diff --git a/ac3dec/dither.c b/ac3dec/dither.c deleted file mode 100644 index 079c04d6d..000000000 --- a/ac3dec/dither.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * dither.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - - -#include <stdlib.h> -#include <stdio.h> -#include "ac3.h" -#include "ac3_internal.h" - - -#include "dither.h" - - -const uint16_t dither_lut[256] = -{ - 0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055, - 0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb, - 0x21cd, 0x81dc, 0xc1fe, 0x61ef, 0x41ba, 0xe1ab, 0xa189, 0x0198, - 0xe123, 0x4132, 0x0110, 0xa101, 0x8154, 0x2145, 0x6167, 0xc176, - 0x439a, 0xe38b, 0xa3a9, 0x03b8, 0x23ed, 0x83fc, 0xc3de, 0x63cf, - 0x8374, 0x2365, 0x6347, 0xc356, 0xe303, 0x4312, 0x0330, 0xa321, - 0x6257, 0xc246, 0x8264, 0x2275, 0x0220, 0xa231, 0xe213, 0x4202, - 0xa2b9, 0x02a8, 0x428a, 0xe29b, 0xc2ce, 0x62df, 0x22fd, 0x82ec, - 0x8734, 0x2725, 0x6707, 0xc716, 0xe743, 0x4752, 0x0770, 0xa761, - 0x47da, 0xe7cb, 0xa7e9, 0x07f8, 0x27ad, 0x87bc, 0xc79e, 0x678f, - 0xa6f9, 0x06e8, 0x46ca, 0xe6db, 0xc68e, 0x669f, 0x26bd, 0x86ac, - 0x6617, 0xc606, 0x8624, 0x2635, 0x0660, 0xa671, 0xe653, 0x4642, - 0xc4ae, 0x64bf, 0x249d, 0x848c, 0xa4d9, 0x04c8, 0x44ea, 0xe4fb, - 0x0440, 0xa451, 0xe473, 0x4462, 0x6437, 0xc426, 0x8404, 0x2415, - 0xe563, 0x4572, 0x0550, 0xa541, 0x8514, 0x2505, 0x6527, 0xc536, - 0x258d, 0x859c, 0xc5be, 0x65af, 0x45fa, 0xe5eb, 0xa5c9, 0x05d8, - 0xae79, 0x0e68, 0x4e4a, 0xee5b, 0xce0e, 0x6e1f, 0x2e3d, 0x8e2c, - 0x6e97, 0xce86, 0x8ea4, 0x2eb5, 0x0ee0, 0xaef1, 0xeed3, 0x4ec2, - 0x8fb4, 0x2fa5, 0x6f87, 0xcf96, 0xefc3, 0x4fd2, 0x0ff0, 0xafe1, - 0x4f5a, 0xef4b, 0xaf69, 0x0f78, 0x2f2d, 0x8f3c, 0xcf1e, 0x6f0f, - 0xede3, 0x4df2, 0x0dd0, 0xadc1, 0x8d94, 0x2d85, 0x6da7, 0xcdb6, - 0x2d0d, 0x8d1c, 0xcd3e, 0x6d2f, 0x4d7a, 0xed6b, 0xad49, 0x0d58, - 0xcc2e, 0x6c3f, 0x2c1d, 0x8c0c, 0xac59, 0x0c48, 0x4c6a, 0xec7b, - 0x0cc0, 0xacd1, 0xecf3, 0x4ce2, 0x6cb7, 0xcca6, 0x8c84, 0x2c95, - 0x294d, 0x895c, 0xc97e, 0x696f, 0x493a, 0xe92b, 0xa909, 0x0918, - 0xe9a3, 0x49b2, 0x0990, 0xa981, 0x89d4, 0x29c5, 0x69e7, 0xc9f6, - 0x0880, 0xa891, 0xe8b3, 0x48a2, 0x68f7, 0xc8e6, 0x88c4, 0x28d5, - 0xc86e, 0x687f, 0x285d, 0x884c, 0xa819, 0x0808, 0x482a, 0xe83b, - 0x6ad7, 0xcac6, 0x8ae4, 0x2af5, 0x0aa0, 0xaab1, 0xea93, 0x4a82, - 0xaa39, 0x0a28, 0x4a0a, 0xea1b, 0xca4e, 0x6a5f, 0x2a7d, 0x8a6c, - 0x4b1a, 0xeb0b, 0xab29, 0x0b38, 0x2b6d, 0x8b7c, 0xcb5e, 0x6b4f, - 0x8bf4, 0x2be5, 0x6bc7, 0xcbd6, 0xeb83, 0x4b92, 0x0bb0, 0xaba1 -}; - -uint16_t lfsr_state = 1; - -// -// see dither_gen (inline-able) in dither.h -// - -#if 0 - -// -// this is the old dither_gen with is much slower than the new inlined -// lut version and is still here because it's easier to understand. -// - -/* - * Generate eight bits of pseudo-entropy using a 16 bit linear - * feedback shift register (LFSR). The primitive polynomial used - * is 1 + x^4 + x^14 + x^16. - * - * The distribution is uniform, over the range [-0.707,0.707] - * - */ - -uint16_t dither_gen(void) -{ - int i; - uint32_t state; - - //explicitly bring the state into a local var as gcc > 3.0? - //doesn't know how to optimize out the stores - state = lfsr_state; - - //Generate eight pseudo random bits - for(i=0;i<8;i++) { - state <<= 1; - - if(state & 0x10000) - state ^= 0xa011; - } - - lfsr_state = state; - - return (((((int32_t)state<<8)>>8) * (int32_t) (0.707106 * 256.0))>>16); -} - -#endif diff --git a/ac3dec/dither.h b/ac3dec/dither.h deleted file mode 100644 index abb9f518e..000000000 --- a/ac3dec/dither.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * dither.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - - -extern uint16_t lfsr_state; -extern const uint16_t dither_lut[256]; - -static inline uint16_t dither_gen(void) -{ - int16_t state; - - state = dither_lut[lfsr_state >> 8] ^ (lfsr_state << 8); - - lfsr_state = (uint16_t) state; - - return ((state * (int32_t) (0.707106 * 256.0))>>8); -} diff --git a/ac3dec/downmix.c b/ac3dec/downmix.c deleted file mode 100644 index 8eac3e21f..000000000 --- a/ac3dec/downmix.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * imdct.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <mm_accel.h> - -#include "ac3.h" -#include "ac3_internal.h" - -#include "debug.h" -#include "downmix.h" -#include "downmix_c.h" -#include "downmix_i386.h" -#ifdef HAVE_KNI -#include "downmix_kni.h" -#endif - -void (*downmix_3f_2r_to_2ch)(float *samples, dm_par_t * dm_par); -void (*downmix_3f_1r_to_2ch)(float *samples, dm_par_t * dm_par); -void (*downmix_2f_2r_to_2ch)(float *samples, dm_par_t * dm_par); -void (*downmix_2f_1r_to_2ch)(float *samples, dm_par_t * dm_par); -void (*downmix_3f_0r_to_2ch)(float *samples, dm_par_t * dm_par); -void (*stream_sample_2ch_to_s16)(int16_t *s16_samples, float *left, float *right); -void (*stream_sample_1ch_to_s16)(int16_t *s16_samples, float *center); - - -void downmix_init() -{ -#ifdef __i386__ -#ifdef HAVE_KNI - uint32_t accel = mm_accel (); - -// other dowmixing should go here too - if (accel & MM_ACCEL_X86_MMXEXT) { - dprintf("Using SSE for downmix\n"); - downmix_3f_2r_to_2ch = downmix_3f_2r_to_2ch_kni; - downmix_2f_2r_to_2ch = downmix_2f_2r_to_2ch_kni; - downmix_3f_1r_to_2ch = downmix_3f_1r_to_2ch_kni; - downmix_2f_1r_to_2ch = downmix_2f_1r_to_2ch_kni; - downmix_3f_0r_to_2ch = downmix_3f_0r_to_2ch_kni; - stream_sample_2ch_to_s16 = stream_sample_2ch_to_s16_kni; - stream_sample_1ch_to_s16 = stream_sample_1ch_to_s16_kni; - } else if (accel & MM_ACCEL_X86_3DNOW) { - } else -#endif -#endif - { - downmix_3f_2r_to_2ch = downmix_3f_2r_to_2ch_c; - downmix_2f_2r_to_2ch = downmix_2f_2r_to_2ch_c; - downmix_3f_1r_to_2ch = downmix_3f_1r_to_2ch_c; - downmix_2f_1r_to_2ch = downmix_2f_1r_to_2ch_c; - downmix_3f_0r_to_2ch = downmix_3f_0r_to_2ch_c; -#ifdef __i386__ -#if 1 - stream_sample_2ch_to_s16 = stream_sample_2ch_to_s16_c; - stream_sample_1ch_to_s16 = stream_sample_1ch_to_s16_c; -#else - stream_sample_2ch_to_s16 = stream_sample_2ch_to_s16_i386; - stream_sample_1ch_to_s16 = stream_sample_1ch_to_s16_i386; -#endif -#else - stream_sample_2ch_to_s16 = stream_sample_2ch_to_s16_c; - stream_sample_1ch_to_s16 = stream_sample_1ch_to_s16_c; -#endif - } -} diff --git a/ac3dec/downmix.h b/ac3dec/downmix.h deleted file mode 100644 index dcfe1e12e..000000000 --- a/ac3dec/downmix.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * downmix.h - * - * Copyright (C) Aaron Holtzman - Sept 1999 - * - * Originally based on code by Yeqing Deng. - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -typedef struct dm_par_s { - float unit; - float clev; - float slev; -} dm_par_t; - -void downmix_init(); diff --git a/ac3dec/downmix_c.c b/ac3dec/downmix_c.c deleted file mode 100644 index 875d785e4..000000000 --- a/ac3dec/downmix_c.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * downmix_c.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include "ac3.h" -#include "ac3_internal.h" - -#include "debug.h" -#include "downmix.h" -#include "downmix_c.h" - - -void downmix_3f_2r_to_2ch_c (float *samples, dm_par_t *dm_par) -{ - int i; - float *left, *right, *center, *left_sur, *right_sur; - float left_tmp, right_tmp; - - left = samples; - right = samples + 256 * 2; - center = samples + 256; - left_sur = samples + 256 * 3; - right_sur = samples + 256 * 4; - - for (i=0; i < 256; i++) { -#if defined DOLBY_SURROUND - left_tmp = dm_par->unit * *left + dm_par->clev * *center - dm_par->slev * (*left_sur + *right_sur); - right_tmp= dm_par->unit * *right++ + dm_par->clev * *center + dm_par->slev * (*left_sur++ + *right_sur++); -#else - left_tmp = dm_par->unit * *left + dm_par->clev * *center + dm_par->slev * *left_sur++; - right_tmp= dm_par->unit * *right++ + dm_par->clev * *center + dm_par->slev * *right_sur++; -#endif - *left++ = left_tmp; - *center++ = right_tmp; - - } -} - - -void downmix_2f_2r_to_2ch_c (float *samples, dm_par_t *dm_par) -{ - int i; - float *left, *right, *left_sur, *right_sur; - float left_tmp, right_tmp; - - left = &samples[0]; - right = &samples[256]; - left_sur = &samples[512]; - right_sur = &samples[768]; - - for (i = 0; i < 256; i++) { - left_tmp = dm_par->unit * *left + dm_par->slev * *left_sur++; - right_tmp= dm_par->unit * *right + dm_par->slev * *right_sur++; - *left++ = left_tmp; - *right++ = right_tmp; - } -} - - -void downmix_3f_1r_to_2ch_c (float *samples, dm_par_t *dm_par) -{ - int i; - float *left, *right, *center, *right_sur; - float left_tmp, right_tmp; - - left = &samples[0]; - right = &samples[512]; - center = &samples[256]; - right_sur = &samples[768]; - - for (i = 0; i < 256; i++) { - left_tmp = dm_par->unit * *left + dm_par->clev * *center - dm_par->slev * *right_sur; - right_tmp= dm_par->unit * *right++ + dm_par->clev * *center + dm_par->slev * *right_sur++; - *left++ = left_tmp; - *center++ = right_tmp; - } -} - - -void downmix_2f_1r_to_2ch_c (float *samples, dm_par_t *dm_par) -{ - int i; - float *left, *right, *right_sur; - float left_tmp, right_tmp; - - left = &samples[0]; - right = &samples[256]; - right_sur = &samples[512]; - - for (i = 0; i < 256; i++) { - left_tmp = dm_par->unit * *left - dm_par->slev * *right_sur; - right_tmp= dm_par->unit * *right + dm_par->slev * *right_sur++; - *left++ = left_tmp; - *right++ = right_tmp; - } -} - - -void downmix_3f_0r_to_2ch_c (float *samples, dm_par_t *dm_par) -{ - int i; - float *left, *right, *center; - float left_tmp, right_tmp; - - left = &samples[0]; - center = &samples[256]; - right = &samples[512]; - - for (i = 0; i < 256; i++) { - left_tmp = dm_par->unit * *left + dm_par->clev * *center; - right_tmp= dm_par->unit * *right++ + dm_par->clev * *center; - *left++ = left_tmp; - *center++ = right_tmp; - } -} - - -void stream_sample_2ch_to_s16_c (int16_t *s16_samples, float *left, float *right) -{ - int i; - - for (i=0; i < 256; i++) { - *s16_samples++ = (int16_t) *left++; - *s16_samples++ = (int16_t) *right++; - } -} - - -void stream_sample_1ch_to_s16_c (int16_t *s16_samples, float *center) -{ - int i; - float tmp; - - for (i=0; i < 256; i++) { - *s16_samples++ = tmp = (int16_t) (0.7071f * *center++); - *s16_samples++ = tmp; - } -} diff --git a/ac3dec/downmix_c.h b/ac3dec/downmix_c.h deleted file mode 100644 index 3643f65e8..000000000 --- a/ac3dec/downmix_c.h +++ /dev/null @@ -1,32 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#ifndef __DOWNMIX_C_H__ -#define __DOWNMIX_C_H__ - -void downmix_3f_2r_to_2ch_c(float *samples, dm_par_t * dm_par); -void downmix_3f_1r_to_2ch_c(float *samples, dm_par_t * dm_par); -void downmix_2f_2r_to_2ch_c(float *samples, dm_par_t * dm_par); -void downmix_2f_1r_to_2ch_c(float *samples, dm_par_t * dm_par); -void downmix_3f_0r_to_2ch_c(float *samples, dm_par_t * dm_par); -void stream_sample_2ch_to_s16_c(int16_t *s16_samples, float *left, float *right); -void stream_sample_1ch_to_s16_c(int16_t *s16_samples, float *center); - -#endif diff --git a/ac3dec/downmix_i386.S b/ac3dec/downmix_i386.S deleted file mode 100644 index 20f2e8c37..000000000 --- a/ac3dec/downmix_i386.S +++ /dev/null @@ -1,92 +0,0 @@ -/* This is basicly gcc generated. - * Only the floating point rounding mode loads and saves - * are removed in the stream_sample_to_s16 functions. - */ - -#ifdef __i386__ - - .file "downmix.c" - .version "01.01" -gcc2_compiled.: -.text - .align 4 -.globl stream_sample_2ch_to_s16_i386 - .type stream_sample_2ch_to_s16_i386,@function -stream_sample_2ch_to_s16_i386: - pushl %ebp - movl %esp,%ebp - subl $28,%esp - pushl %edi - pushl %esi - pushl %ebx - movl 8(%ebp),%edx - movl 12(%ebp),%ebx - movl 16(%ebp),%ecx - movl $255,%esi - .p2align 4,,7 -.L373: - flds (%ebx) - fistpl -8(%ebp) - movl -8(%ebp),%eax - movw %ax,(%edx) - addl $2,%edx - addl $4,%ebx - flds (%ecx) - fistpl -8(%ebp) - movl -8(%ebp),%eax - movw %ax,(%edx) - addl $4,%ecx - addl $2,%edx - decl %esi - jns .L373 - popl %ebx - popl %esi - popl %edi - leave - ret -.Lfe6: - .size stream_sample_2ch_to_s16_i386,.Lfe6-stream_sample_2ch_to_s16_i386 -.section .rodata - .align 4 -.LC46: - .long 0x3f350481 -.text - .align 4 -.globl stream_sample_1ch_to_s16_i386 - .type stream_sample_1ch_to_s16_i386,@function -stream_sample_1ch_to_s16_i386: - pushl %ebp - movl %esp,%ebp - subl $16,%esp - pushl %esi - pushl %ebx - movl 8(%ebp),%edx - movl 12(%ebp),%ecx - flds .LC46 - movl $255,%ebx - .p2align 4,,7 -.L379: - flds (%ecx) - fmul %st(1),%st - fistpl -8(%ebp) - movl -8(%ebp),%eax - movw %ax,-2(%ebp) - addl $4,%ecx - flds -2(%ebp) - fistpl -8(%ebp) - movl -8(%ebp),%eax - movw %ax,(%edx) - addl $2,%edx - movw %ax,(%edx) - addl $2,%edx - decl %ebx - jns .L379 - fstp %st(0) - popl %ebx - popl %esi - leave - ret -.Lfe7: - .size stream_sample_1ch_to_s16_i386,.Lfe7-stream_sample_1ch_to_s16_i386 - .ident "GCC: (GNU) 2.95.3 19991030 (prerelease)" -#endif diff --git a/ac3dec/downmix_i386.h b/ac3dec/downmix_i386.h deleted file mode 100644 index e34d7d6cf..000000000 --- a/ac3dec/downmix_i386.h +++ /dev/null @@ -1,27 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#ifndef __DOWNMIX_I386_H__ -#define __DOWNMIX_I386_H__ - -void stream_sample_2ch_to_s16_i386(int16_t *s16_samples, float *left, float *right); -void stream_sample_1ch_to_s16_i386(int16_t *s16_samples, float *center); - -#endif diff --git a/ac3dec/downmix_kni.S b/ac3dec/downmix_kni.S deleted file mode 100644 index 7df8c060f..000000000 --- a/ac3dec/downmix_kni.S +++ /dev/null @@ -1,396 +0,0 @@ -/* - * downmix_kni.S - * - * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - October 2000 - * - * - * downmix_kni.S is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * downmix_kni.S is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifdef __i386__ - -.section .rodata - .align 4 -sqrt2: .float 0f0.7071068 - .p2align 5,0, - - .section .text - - .align 4 - .global downmix_3f_2r_to_2ch_kni - .type downmix_3f_2r_to_2ch_kni, @function - -downmix_3f_2r_to_2ch_kni: - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %ecx - - movl 8(%ebp), %eax /* samples[] */ - movl 12(%ebp), %ebx /* &dm_par */ - movl $64, %ecx /* loop counter */ - - movss (%ebx), %xmm5 /* unit */ - shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ - - movss 4(%ebx), %xmm6 /* clev */ - shufps $0, %xmm6, %xmm6 /* clev | clev | clev | clev */ - - movss 8(%ebx), %xmm7 /* slev */ - shufps $0, %xmm7, %xmm7 /* slev | slev | slev | slev */ - -.loop: - movaps (%eax), %xmm0 /* left */ - movaps 2048(%eax), %xmm1 /* right */ - movaps 1024(%eax), %xmm2 /* center */ - mulps %xmm5, %xmm0 - mulps %xmm5, %xmm1 - - mulps %xmm6, %xmm2 - movaps 3072(%eax), %xmm3 /* leftsur */ - movaps 4096(%eax), %xmm4 /* rithgsur */ - addps %xmm2, %xmm0 - addps %xmm2, %xmm1 - - mulps %xmm7, %xmm3 - mulps %xmm7, %xmm4 - addps %xmm3, %xmm0 - addps %xmm4, %xmm1 - - movaps %xmm0, (%eax) - movaps %xmm1, 1024(%eax) - - addl $16, %eax - decl %ecx - jnz .loop - - popl %ecx - popl %ebx - popl %eax - - leave - ret - .p2align 4,,7 - - .global downmix_2f_2r_to_2ch_kni - .type downmix_2f_2r_to_2ch_kni, @function - -downmix_2f_2r_to_2ch_kni: - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %ecx - - movl 8(%ebp), %eax /* samples[] */ - movl 12(%ebp), %ebx /* &dm_par */ - movl $64, %ecx /* loop counter */ - - movss (%ebx), %xmm5 /* unit */ - shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ - - movss 8(%ebx), %xmm7 /* slev */ - shufps $0, %xmm7, %xmm7 /* slev | slev | slev | slev */ - -.loop3: - movaps (%eax), %xmm0 /* left */ - movaps 1024(%eax), %xmm1 /* right */ - movaps 2048(%eax), %xmm3 /* leftsur */ - mulps %xmm5, %xmm0 - mulps %xmm5, %xmm1 - - movaps 3072(%eax), %xmm4 /* rightsur */ - - mulps %xmm7, %xmm3 - mulps %xmm7, %xmm4 - addps %xmm3, %xmm0 - addps %xmm4, %xmm1 - - movaps %xmm0, (%eax) - movaps %xmm1, 1024(%eax) - - addl $16, %eax - decl %ecx - jnz .loop3 - - popl %ecx - popl %ebx - popl %eax - - leave - ret - .p2align 4,,7 - - .global downmix_3f_1r_to_2ch_kni - .type downmix_3f_1r_to_2ch_kni, @function - -downmix_3f_1r_to_2ch_kni: - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %ecx - - movl 8(%ebp), %eax /* samples[] */ - movl 12(%ebp), %ebx /* &dm_par */ - movl $64, %ecx /* loop counter */ - - movss (%ebx), %xmm5 /* unit */ - shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ - - movss 4(%ebx), %xmm6 /* clev */ - shufps $0, %xmm6, %xmm6 /* clev | clev | clev | clev */ - - movss 8(%ebx), %xmm7 /* slev */ - shufps $0, %xmm7, %xmm7 /* slev | slev | slev | slev */ - -.loop4: - movaps (%eax), %xmm0 /* left */ - movaps 2048(%eax), %xmm1 /* right */ - movaps 1024(%eax), %xmm2 /* center */ - mulps %xmm5, %xmm0 - mulps %xmm5, %xmm1 - - mulps %xmm6, %xmm2 - movaps 3072(%eax), %xmm3 /* sur */ - - addps %xmm2, %xmm0 - mulps %xmm7, %xmm3 - - addps %xmm2, %xmm1 - - subps %xmm3, %xmm0 - addps %xmm3, %xmm1 - - movaps %xmm0, (%eax) - movaps %xmm1, 1024(%eax) - - addl $16, %eax - decl %ecx - jnz .loop4 - - popl %ecx - popl %ebx - popl %eax - - leave - ret - .p2align 4,,7 - - .global downmix_2f_1r_to_2ch_kni - .type downmix_2f_1r_to_2ch_kni, @function - -downmix_2f_1r_to_2ch_kni: - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %ecx - - movl 8(%ebp), %eax /* samples[] */ - movl 12(%ebp), %ebx /* &dm_par */ - movl $64, %ecx /* loop counter */ - - movss (%ebx), %xmm5 /* unit */ - shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ - - movss 8(%ebx), %xmm7 /* slev */ - shufps $0, %xmm7, %xmm7 /* slev | slev | slev | slev */ - -.loop5: - movaps (%eax), %xmm0 /* left */ - movaps 1024(%eax), %xmm1 /* right */ - - mulps %xmm5, %xmm0 - mulps %xmm5, %xmm1 - - movaps 2048(%eax), %xmm3 /* sur */ - - mulps %xmm7, %xmm3 - - subps %xmm3, %xmm0 - addps %xmm3, %xmm1 - - movaps %xmm0, (%eax) - movaps %xmm1, 1024(%eax) - - addl $16, %eax - decl %ecx - jnz .loop5 - - popl %ecx - popl %ebx - popl %eax - - leave - ret - .p2align 4,,7 - - .global downmix_3f_0r_to_2ch_kni - .type downmix_3f_0r_to_2ch_kni, @function - -downmix_3f_0r_to_2ch_kni: - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %ecx - - movl 8(%ebp), %eax /* samples[] */ - movl 12(%ebp), %ebx /* &dm_par */ - movl $64, %ecx /* loop counter */ - - movss (%ebx), %xmm5 /* unit */ - shufps $0, %xmm5, %xmm5 /* unit | unit | unit | unit */ - - movss 4(%ebx), %xmm6 /* clev */ - shufps $0, %xmm6, %xmm6 /* clev | clev | clev | clev */ - - -.loop6: - movaps (%eax), %xmm0 /* left */ - movaps 2048(%eax), %xmm1 /* right */ - movaps 1024(%eax), %xmm2 /* center */ - mulps %xmm5, %xmm0 - mulps %xmm5, %xmm1 - - mulps %xmm6, %xmm2 - - addps %xmm2, %xmm0 - - addps %xmm2, %xmm1 - - movaps %xmm0, (%eax) - movaps %xmm1, 1024(%eax) - - addl $16, %eax - decl %ecx - jnz .loop6 - - popl %ecx - popl %ebx - popl %eax - - leave - ret - .p2align 4,,7 - - .global stream_sample_2ch_to_s16_kni - .type stream_sample_2ch_to_s16_kni, @function - -stream_sample_2ch_to_s16_kni: - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %edx - pushl %ecx - - movl 8(%ebp), %eax /* s16_samples */ - movl 12(%ebp), %ebx /* left */ - movl 16(%ebp), %edx /* right */ - movl $64, %ecx - -.loop1: - movaps (%ebx), %xmm0 /* l3 | l2 | l1 | l0 */ - movaps (%edx), %xmm1 /* r3 | r2 | r1 | r0 */ - movhlps %xmm0, %xmm2 /* l3 | l2 */ - movhlps %xmm1, %xmm3 /* r3 | r2 */ - unpcklps %xmm1, %xmm0 /* r1 | l1 | r0 | l0 */ - unpcklps %xmm3, %xmm2 /* r3 | l3 | r2 | l2 */ - - cvtps2pi %xmm0, %mm0 /* r0 l0 --> mm0, int_32 */ - movhlps %xmm0, %xmm0 - cvtps2pi %xmm0, %mm1 /* r1 l1 --> mm1, int_32 */ - - cvtps2pi %xmm2, %mm2 /* r2 l2 --> mm2, int_32 */ - movhlps %xmm2, %xmm2 - cvtps2pi %xmm2, %mm3 /* r3 l3 --> mm3, int_32 */ - packssdw %mm1, %mm0 /* r1 l1 r0 l0 --> mm0, int_16 */ - packssdw %mm3, %mm2 /* r3 l3 r2 l2 --> mm2, int_16 */ - - movq %mm0, (%eax) - movq %mm2, 8(%eax) - addl $16, %eax - addl $16, %ebx - addl $16, %edx - - decl %ecx - jnz .loop1 - - popl %ecx - popl %edx - popl %ebx - popl %eax - - emms - - leave - ret - .p2align 4,,7 - - .global stream_sample_1ch_to_s16_kni - .type stream_sample_1ch_to_s16_kni, @function - -stream_sample_1ch_to_s16_kni: - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %ecx - - movl $sqrt2, %eax - movss (%eax), %xmm7 - movl 8(%ebp), %eax /* s16_samples */ - movl 12(%ebp), %ebx /* left */ - shufps $0, %xmm7, %xmm7 - movl $64, %ecx - -.loop2: - movaps (%ebx), %xmm0 /* c3 | c2 | c1 | c0 */ - mulps %xmm7, %xmm0 - movhlps %xmm0, %xmm2 /* c3 | c2 */ - - cvtps2pi %xmm0, %mm0 /* c1 c0 --> mm0, int_32 */ - cvtps2pi %xmm2, %mm1 /* c3 c2 --> mm1, int_32 */ - - packssdw %mm0, %mm0 /* c1 c1 c0 c0 --> mm0, int_16 */ - packssdw %mm1, %mm1 /* c3 c3 c2 c2 --> mm1, int_16 */ - - movq %mm0, (%eax) - movq %mm1, 8(%eax) - addl $16, %eax - addl $16, %ebx - - decl %ecx - jnz .loop2 - - popl %ecx - popl %ebx - popl %eax - - emms - leave - ret -#endif diff --git a/ac3dec/downmix_kni.h b/ac3dec/downmix_kni.h deleted file mode 100644 index 323f2a754..000000000 --- a/ac3dec/downmix_kni.h +++ /dev/null @@ -1,32 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#ifndef __DOWNMIX_KNI_H__ -#define __DOWNMIX_KNI_H__ - -void downmix_3f_2r_to_2ch_kni(float *samples, dm_par_t * dm_par); -void downmix_3f_1r_to_2ch_kni(float *samples, dm_par_t * dm_par); -void downmix_2f_2r_to_2ch_kni(float *samples, dm_par_t * dm_par); -void downmix_2f_1r_to_2ch_kni(float *samples, dm_par_t * dm_par); -void downmix_3f_0r_to_2ch_kni(float *samples, dm_par_t * dm_par); -void stream_sample_2ch_to_s16_kni(int16_t *s16_samples, float *left, float *right); -void stream_sample_1ch_to_s16_kni(int16_t *s16_samples, float *center); - -#endif diff --git a/ac3dec/exponent.c b/ac3dec/exponent.c deleted file mode 100644 index 16fca4652..000000000 --- a/ac3dec/exponent.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * exponent.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - - -#include <stdlib.h> -#include <stdio.h> -#include "ac3.h" -#include "ac3_internal.h" - - -#include "exponent.h" - - -static inline void exp_unpack_ch(uint16_t type,uint16_t expstr,uint16_t ngrps,uint16_t initial_exp, uint16_t exps[], uint16_t *dest); - - -/** - * - **/ - -void exponent_unpack( bsi_t *bsi, audblk_t *audblk) -{ - uint16_t i; - - for(i=0; i< bsi->nfchans; i++) - exp_unpack_ch(UNPACK_FBW, audblk->chexpstr[i], audblk->nchgrps[i], audblk->exps[i][0], &audblk->exps[i][1], audblk->fbw_exp[i]); - - if(audblk->cplinu) - exp_unpack_ch(UNPACK_CPL, audblk->cplexpstr, audblk->ncplgrps, audblk->cplabsexp << 1, audblk->cplexps, &audblk->cpl_exp[audblk->cplstrtmant]); - - if(bsi->lfeon) - exp_unpack_ch(UNPACK_LFE, audblk->lfeexpstr, 2, audblk->lfeexps[0], &audblk->lfeexps[1], audblk->lfe_exp); -} - - -/** - * - **/ - -static inline void exp_unpack_ch(uint16_t type,uint16_t expstr,uint16_t ngrps,uint16_t initial_exp, - uint16_t exps[], uint16_t *dest) -{ - uint16_t i,j; - int16_t exp_acc; - int16_t exp_1,exp_2,exp_3; - - if (expstr == EXP_REUSE) - return; - - /* Handle the initial absolute exponent */ - exp_acc = initial_exp; - j = 0; - - /* In the case of a fbw channel then the initial absolute values is - * also an exponent */ - if(type != UNPACK_CPL) - dest[j++] = exp_acc; - - /* Loop through the groups and fill the dest array appropriately */ - for(i=0; i< ngrps; i++) { - if(exps[i] > 124) - goto error; - - exp_1 = exps[i] / 25; - exp_2 = (exps[i] - (exp_1 * 25)) / 5; - exp_3 = exps[i] - (exp_1 * 25) - (exp_2 * 5) ; - - exp_acc += (exp_1 - 2); - - switch(expstr) { - case EXP_D45: - dest[j++] = exp_acc; - dest[j++] = exp_acc; - case EXP_D25: - dest[j++] = exp_acc; - case EXP_D15: - dest[j++] = exp_acc; - } - - exp_acc += (exp_2 - 2); - - switch(expstr) { - case EXP_D45: - dest[j++] = exp_acc; - dest[j++] = exp_acc; - case EXP_D25: - dest[j++] = exp_acc; - case EXP_D15: - dest[j++] = exp_acc; - } - - exp_acc += (exp_3 - 2); - - switch(expstr) { - case EXP_D45: - dest[j++] = exp_acc; - dest[j++] = exp_acc; - case EXP_D25: - dest[j++] = exp_acc; - case EXP_D15: - dest[j++] = exp_acc; - } - } - - return; -error: -#ifdef DEBUG - fprintf (stderr,"** Invalid exponent - skipping frame **\n"); -#endif - HANDLE_ERROR (); -} - diff --git a/ac3dec/exponent.h b/ac3dec/exponent.h deleted file mode 100644 index 06c59db03..000000000 --- a/ac3dec/exponent.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * exponent.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#define UNPACK_FBW 1 -#define UNPACK_CPL 2 -#define UNPACK_LFE 4 - -void exponent_unpack( bsi_t *bsi, audblk_t *audblk); diff --git a/ac3dec/imdct.c b/ac3dec/imdct.c deleted file mode 100644 index c09ef4138..000000000 --- a/ac3dec/imdct.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * imdct.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include "ac3.h" -#include "ac3_internal.h" - -#include "downmix.h" -#include "imdct.h" -#include "imdct_c.h" -#ifdef HAVE_KNI -#include "imdct_kni.h" -#endif -#include "srfft.h" - - -extern void (*downmix_3f_2r_to_2ch)(float *samples, dm_par_t * dm_par); -extern void (*downmix_3f_1r_to_2ch)(float *samples, dm_par_t * dm_par); -extern void (*downmix_2f_2r_to_2ch)(float *samples, dm_par_t * dm_par); -extern void (*downmix_2f_1r_to_2ch)(float *samples, dm_par_t * dm_par); -extern void (*downmix_3f_0r_to_2ch)(float *samples, dm_par_t * dm_par); - - -extern void (*stream_sample_2ch_to_s16)(int16_t *s16_samples, float *left, float *right); -extern void (*stream_sample_1ch_to_s16)(int16_t *s16_samples, float *center); - -void (*fft_64p) (complex_t *); -void (*imdct_do_512) (float data[],float delay[]); -void (*imdct_do_512_nol) (float data[], float delay[]); - -void imdct_do_256 (float data[],float delay[]); - -#define N 512 - -/* static complex_t buf[128]; */ -//static complex_t buf[128] __attribute__((aligned(16))); -complex_t buf[128] __attribute__((aligned(16))); - -/* Delay buffer for time domain interleaving */ -static float delay[6][256]; -static float delay1[6][256]; - -/* Twiddle factors for IMDCT */ -static float xcos2[64]; -static float xsin2[64]; - -/* Windowing function for Modified DCT - Thank you acroread */ -//static float window[] = { -float window[] = { - 0.00014, 0.00024, 0.00037, 0.00051, 0.00067, 0.00086, 0.00107, 0.00130, - 0.00157, 0.00187, 0.00220, 0.00256, 0.00297, 0.00341, 0.00390, 0.00443, - 0.00501, 0.00564, 0.00632, 0.00706, 0.00785, 0.00871, 0.00962, 0.01061, - 0.01166, 0.01279, 0.01399, 0.01526, 0.01662, 0.01806, 0.01959, 0.02121, - 0.02292, 0.02472, 0.02662, 0.02863, 0.03073, 0.03294, 0.03527, 0.03770, - 0.04025, 0.04292, 0.04571, 0.04862, 0.05165, 0.05481, 0.05810, 0.06153, - 0.06508, 0.06878, 0.07261, 0.07658, 0.08069, 0.08495, 0.08935, 0.09389, - 0.09859, 0.10343, 0.10842, 0.11356, 0.11885, 0.12429, 0.12988, 0.13563, - 0.14152, 0.14757, 0.15376, 0.16011, 0.16661, 0.17325, 0.18005, 0.18699, - 0.19407, 0.20130, 0.20867, 0.21618, 0.22382, 0.23161, 0.23952, 0.24757, - 0.25574, 0.26404, 0.27246, 0.28100, 0.28965, 0.29841, 0.30729, 0.31626, - 0.32533, 0.33450, 0.34376, 0.35311, 0.36253, 0.37204, 0.38161, 0.39126, - 0.40096, 0.41072, 0.42054, 0.43040, 0.44030, 0.45023, 0.46020, 0.47019, - 0.48020, 0.49022, 0.50025, 0.51028, 0.52031, 0.53033, 0.54033, 0.55031, - 0.56026, 0.57019, 0.58007, 0.58991, 0.59970, 0.60944, 0.61912, 0.62873, - 0.63827, 0.64774, 0.65713, 0.66643, 0.67564, 0.68476, 0.69377, 0.70269, - 0.71150, 0.72019, 0.72877, 0.73723, 0.74557, 0.75378, 0.76186, 0.76981, - 0.77762, 0.78530, 0.79283, 0.80022, 0.80747, 0.81457, 0.82151, 0.82831, - 0.83496, 0.84145, 0.84779, 0.85398, 0.86001, 0.86588, 0.87160, 0.87716, - 0.88257, 0.88782, 0.89291, 0.89785, 0.90264, 0.90728, 0.91176, 0.91610, - 0.92028, 0.92432, 0.92822, 0.93197, 0.93558, 0.93906, 0.94240, 0.94560, - 0.94867, 0.95162, 0.95444, 0.95713, 0.95971, 0.96217, 0.96451, 0.96674, - 0.96887, 0.97089, 0.97281, 0.97463, 0.97635, 0.97799, 0.97953, 0.98099, - 0.98236, 0.98366, 0.98488, 0.98602, 0.98710, 0.98811, 0.98905, 0.98994, - 0.99076, 0.99153, 0.99225, 0.99291, 0.99353, 0.99411, 0.99464, 0.99513, - 0.99558, 0.99600, 0.99639, 0.99674, 0.99706, 0.99736, 0.99763, 0.99788, - 0.99811, 0.99831, 0.99850, 0.99867, 0.99882, 0.99895, 0.99908, 0.99919, - 0.99929, 0.99938, 0.99946, 0.99953, 0.99959, 0.99965, 0.99969, 0.99974, - 0.99978, 0.99981, 0.99984, 0.99986, 0.99988, 0.99990, 0.99992, 0.99993, - 0.99994, 0.99995, 0.99996, 0.99997, 0.99998, 0.99998, 0.99998, 0.99999, - 0.99999, 0.99999, 0.99999, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, - 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000 -}; - -//static const int pm128[128] = -const int pm128[128] = -{ - 0, 16, 32, 48, 64, 80, 96, 112, 8, 40, 72, 104, 24, 56, 88, 120, - 4, 20, 36, 52, 68, 84, 100, 116, 12, 28, 44, 60, 76, 92, 108, 124, - 2, 18, 34, 50, 66, 82, 98, 114, 10, 42, 74, 106, 26, 58, 90, 122, - 6, 22, 38, 54, 70, 86, 102, 118, 14, 46, 78, 110, 30, 62, 94, 126, - 1, 17, 33, 49, 65, 81, 97, 113, 9, 41, 73, 105, 25, 57, 89, 121, - 5, 21, 37, 53, 69, 85, 101, 117, 13, 29, 45, 61, 77, 93, 109, 125, - 3, 19, 35, 51, 67, 83, 99, 115, 11, 43, 75, 107, 27, 59, 91, 123, - 7, 23, 39, 55, 71, 87, 103, 119, 15, 31, 47, 63, 79, 95, 111, 127 -}; - -static const int pm64[64] = -{ - 0, 8, 16, 24, 32, 40, 48, 56, - 4, 20, 36, 52, 12, 28, 44, 60, - 2, 10, 18, 26, 34, 42, 50, 58, - 6, 14, 22, 30, 38, 46, 54, 62, - 1, 9, 17, 25, 33, 41, 49, 57, - 5, 21, 37, 53, 13, 29, 45, 61, - 3, 11, 19, 27, 35, 43, 51, 59, - 7, 23, 39, 55, 15, 31, 47, 63 -}; - - -void imdct_init (void) - { - int i; - float scale = 255.99609372; - -#ifdef __i386__ -#ifdef HAVE_KNI - if (!imdct_init_kni ()); - else -#endif -#endif - if (!imdct_init_c ()); - - // More twiddle factors to turn IFFT into IMDCT */ - for (i=0; i < 64; i++) { - xcos2[i] = cos(2.0f * M_PI * (8*i+1)/(4*N)) * scale; - xsin2[i] = sin(2.0f * M_PI * (8*i+1)/(4*N)) * scale; - } -} - - -void imdct_do_256 (float data[],float delay[]) -{ - int i, j, k; - int p, q; - - float tmp_a_i; - float tmp_a_r; - - float *data_ptr; - float *delay_ptr; - float *window_ptr; - - complex_t *buf1, *buf2; - - buf1 = &buf[0]; - buf2 = &buf[64]; - -// Pre IFFT complex multiply plus IFFT complex conjugate - for (k=0; k<64; k++) { - /* X1[k] = X[2*k] */ - /* X2[k] = X[2*k+1] */ - - j = pm64[k]; - p = 2 * (128-2*j-1); - q = 2 * (2 * j); - - /* Z1[k] = (X1[128-2*k-1] + j * X1[2*k]) * (xcos2[k] + j * xsin2[k]); */ - buf1[k].re = data[p] * xcos2[j] - data[q] * xsin2[j]; - buf1[k].im = -1.0f * (data[q] * xcos2[j] + data[p] * xsin2[j]); - /* Z2[k] = (X2[128-2*k-1] + j * X2[2*k]) * (xcos2[k] + j * xsin2[k]); */ - buf2[k].re = data[p + 1] * xcos2[j] - data[q + 1] * xsin2[j]; - buf2[k].im = -1.0f * ( data[q + 1] * xcos2[j] + data[p + 1] * xsin2[j]); - } - - fft_64p(&buf1[0]); - fft_64p(&buf2[0]); - -#ifdef DEBUG - //DEBUG FFT -#if 0 - printf ("Post FFT, buf1\n"); - for (i=0; i < 64; i++) - printf("%d %f %f\n", i, buf_1[i].re, buf_1[i].im); - printf ("Post FFT, buf2\n"); - for (i=0; i < 64; i++) - printf("%d %f %f\n", i, buf_2[i].re, buf_2[i].im); -#endif -#endif - - - // Post IFFT complex multiply - for( i=0; i < 64; i++) { - tmp_a_r = buf1[i].re; - tmp_a_i = -buf1[i].im; - buf1[i].re =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); - buf1[i].im =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); - tmp_a_r = buf2[i].re; - tmp_a_i = -buf2[i].im; - buf2[i].re =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); - buf2[i].im =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); - } - - data_ptr = data; - delay_ptr = delay; - window_ptr = window; - - /* Window and convert to real valued signal */ - for(i=0; i< 64; i++) { - *data_ptr++ = -buf1[i].im * *window_ptr++ + *delay_ptr++; - *data_ptr++ = buf1[64-i-1].re * *window_ptr++ + *delay_ptr++; - } - - for(i=0; i< 64; i++) { - *data_ptr++ = -buf1[i].re * *window_ptr++ + *delay_ptr++; - *data_ptr++ = buf1[64-i-1].im * *window_ptr++ + *delay_ptr++; - } - - delay_ptr = delay; - - for(i=0; i< 64; i++) { - *delay_ptr++ = -buf2[i].re * *--window_ptr; - *delay_ptr++ = buf2[64-i-1].im * *--window_ptr; - } - - for(i=0; i< 64; i++) { - *delay_ptr++ = buf2[i].im * *--window_ptr; - *delay_ptr++ = -buf2[64-i-1].re * *--window_ptr; - } -} - - -/** - * - **/ - -void imdct_do_256_nol (float data[], float delay[]) -{ - int i, j, k; - int p, q; - - float tmp_a_i; - float tmp_a_r; - - float *data_ptr; - float *delay_ptr; - float *window_ptr; - - complex_t *buf1, *buf2; - - buf1 = &buf[0]; - buf2 = &buf[64]; - - /* Pre IFFT complex multiply plus IFFT cmplx conjugate */ - for(k=0; k<64; k++) { - /* X1[k] = X[2*k] */ - /* X2[k] = X[2*k+1] */ - j = pm64[k]; - p = 2 * (128-2*j-1); - q = 2 * (2 * j); - - /* Z1[k] = (X1[128-2*k-1] + j * X1[2*k]) * (xcos2[k] + j * xsin2[k]); */ - buf1[k].re = data[p] * xcos2[j] - data[q] * xsin2[j]; - buf1[k].im = -1.0f * (data[q] * xcos2[j] + data[p] * xsin2[j]); - /* Z2[k] = (X2[128-2*k-1] + j * X2[2*k]) * (xcos2[k] + j * xsin2[k]); */ - buf2[k].re = data[p + 1] * xcos2[j] - data[q + 1] * xsin2[j]; - buf2[k].im = -1.0f * ( data[q + 1] * xcos2[j] + data[p + 1] * xsin2[j]); - } - - - fft_64p(&buf1[0]); - fft_64p(&buf2[0]); - -#ifdef DEBUG - //DEBUG FFT -#if 0 - printf("Post FFT, buf1\n"); - for (i=0; i < 64; i++) - printf("%d %f %f\n", i, buf_1[i].re, buf_1[i].im); - printf("Post FFT, buf2\n"); - for (i=0; i < 64; i++) - printf("%d %f %f\n", i, buf_2[i].re, buf_2[i].im); -#endif -#endif - - /* Post IFFT complex multiply */ - for( i=0; i < 64; i++) { - /* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */ - tmp_a_r = buf1[i].re; - tmp_a_i = -buf1[i].im; - buf1[i].re =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); - buf1[i].im =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); - /* y2[n] = z2[n] * (xcos2[n] + j * xsin2[n]) ; */ - tmp_a_r = buf2[i].re; - tmp_a_i = -buf2[i].im; - buf2[i].re =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); - buf2[i].im =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); - } - - data_ptr = data; - delay_ptr = delay; - window_ptr = window; - - /* Window and convert to real valued signal, no overlap */ - for(i=0; i< 64; i++) { - *data_ptr++ = -buf1[i].im * *window_ptr++; - *data_ptr++ = buf1[64-i-1].re * *window_ptr++; - } - - for(i=0; i< 64; i++) { - *data_ptr++ = -buf1[i].re * *window_ptr++ + *delay_ptr++; - *data_ptr++ = buf1[64-i-1].im * *window_ptr++ + *delay_ptr++; - } - - delay_ptr = delay; - - for(i=0; i< 64; i++) { - *delay_ptr++ = -buf2[i].re * *--window_ptr; - *delay_ptr++ = buf2[64-i-1].im * *--window_ptr; - } - - for(i=0; i< 64; i++) { - *delay_ptr++ = buf2[i].im * *--window_ptr; - *delay_ptr++ = -buf2[64-i-1].re * *--window_ptr; - } -} - -//FIXME remove - for timing code -///#include <sys/time.h> -//FIXME remove - -void imdct (bsi_t *bsi,audblk_t *audblk, stream_samples_t samples, int16_t *s16_samples, dm_par_t* dm_par) -{ - int i; - int doable = 0; - float *center=NULL, *left, *right, *left_sur, *right_sur; - float *delay_left, *delay_right; - float *delay1_left, *delay1_right, *delay1_center, *delay1_sr, *delay1_sl; - float right_tmp, left_tmp; - void (*do_imdct)(float data[], float deley[]); - - // test if dm in frequency is doable - if (!(doable = audblk->blksw[0])) - do_imdct = imdct_do_512; - else - do_imdct = imdct_do_256; - - // downmix in the frequency domain if all the channels - // use the same imdct - for (i=0; i < bsi->nfchans; i++) { - if (doable != audblk->blksw[i]) { - do_imdct = NULL; - break; - } - } - - if (do_imdct) { - //dowmix first and imdct - switch(bsi->acmod) { - case 7: // 3/2 - downmix_3f_2r_to_2ch (samples[0], dm_par); - break; - case 6: // 2/2 - downmix_2f_2r_to_2ch (samples[0], dm_par); - break; - case 5: // 3/1 - downmix_3f_1r_to_2ch (samples[0], dm_par); - break; - case 4: // 2/1 - downmix_2f_1r_to_2ch (samples[0], dm_par); - break; - case 3: // 3/0 - downmix_3f_0r_to_2ch (samples[0], dm_par); - break; - case 2: - break; - default: // 1/0 - if (bsi->acmod == 1) - center = samples[0]; - else if (bsi->acmod == 0) - center = samples[ac3_config.dual_mono_ch_sel]; - do_imdct(center, delay[0]); // no downmix - - stream_sample_1ch_to_s16 (s16_samples, center); - - return; - //goto done; - break; - } - - do_imdct (samples[0], delay[0]); - do_imdct (samples[1], delay[1]); - stream_sample_2ch_to_s16(s16_samples, samples[0], samples[1]); - - } else { //imdct and then dowmix - // delay and samples should be saved and mixed - //fprintf(stderr, "time domain downmix\n"); - for (i=0; i<bsi->nfchans; i++) { - if (audblk->blksw[i]) - imdct_do_256_nol (samples[i],delay1[i]); - else - imdct_do_512_nol (samples[i],delay1[i]); - } - - // mix the sample, overlap - switch(bsi->acmod) { - case 7: // 3/2 - left = samples[0]; - center = samples[1]; - right = samples[2]; - left_sur = samples[3]; - right_sur = samples[4]; - delay_left = delay[0]; - delay_right = delay[1]; - delay1_left = delay1[0]; - delay1_center = delay1[1]; - delay1_right = delay1[2]; - delay1_sl = delay1[3]; - delay1_sr = delay1[4]; - - for (i = 0; i < 256; i++) { - left_tmp = dm_par->unit * *left++ + dm_par->clev * *center + dm_par->slev * *left_sur++; - right_tmp= dm_par->unit * *right++ + dm_par->clev * *center++ + dm_par->slev * *right_sur++; - *s16_samples++ = (int16_t)(left_tmp + *delay_left); - *s16_samples++ = (int16_t)(right_tmp + *delay_right); - *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->clev * *delay1_center + dm_par->slev * *delay1_sl++; - *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *center++ + dm_par->slev * *delay1_sr++; - } - break; - case 6: // 2/2 - left = samples[0]; - right = samples[1]; - left_sur = samples[2]; - right_sur = samples[3]; - delay_left = delay[0]; - delay_right = delay[1]; - delay1_left = delay1[0]; - delay1_right = delay1[1]; - delay1_sl = delay1[2]; - delay1_sr = delay1[3]; - - for (i = 0; i < 256; i++) { - left_tmp = dm_par->unit * *left++ + dm_par->slev * *left_sur++; - right_tmp= dm_par->unit * *right++ + dm_par->slev * *right_sur++; - *s16_samples++ = (int16_t)(left_tmp + *delay_left); - *s16_samples++ = (int16_t)(right_tmp + *delay_right); - *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->slev * *delay1_sl++; - *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->slev * *delay1_sr++; - } - break; - case 5: // 3/1 - left = samples[0]; - center = samples[1]; - right = samples[2]; - right_sur = samples[3]; - delay_left = delay[0]; - delay_right = delay[1]; - delay1_left = delay1[0]; - delay1_center = delay1[1]; - delay1_right = delay1[2]; - delay1_sl = delay1[3]; - - for (i = 0; i < 256; i++) { - left_tmp = dm_par->unit * *left++ + dm_par->clev * *center - dm_par->slev * *right_sur; - right_tmp= dm_par->unit * *right++ + dm_par->clev * *center++ + dm_par->slev * *right_sur++; - *s16_samples++ = (int16_t)(left_tmp + *delay_left); - *s16_samples++ = (int16_t)(right_tmp + *delay_right); - *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->clev * *delay1_center + dm_par->slev * *delay1_sl; - *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *center++ + dm_par->slev * *delay1_sl++; - } - break; - case 4: // 2/1 - left = samples[0]; - right = samples[1]; - right_sur = samples[2]; - delay_left = delay[0]; - delay_right = delay[1]; - delay1_left = delay1[0]; - delay1_right = delay1[1]; - delay1_sl = delay1[2]; - - for (i = 0; i < 256; i++) { - left_tmp = dm_par->unit * *left++ - dm_par->slev * *right_sur; - right_tmp= dm_par->unit * *right++ + dm_par->slev * *right_sur++; - *s16_samples++ = (int16_t)(left_tmp + *delay_left); - *s16_samples++ = (int16_t)(right_tmp + *delay_right); - *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->slev * *delay1_sl; - *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->slev * *delay1_sl++; - } - break; - case 3: // 3/0 - left = samples[0]; - center = samples[1]; - right = samples[2]; - delay_left = delay[0]; - delay_right = delay[1]; - delay1_left = delay1[0]; - delay1_center = delay1[1]; - delay1_right = delay1[2]; - - for (i = 0; i < 256; i++) { - left_tmp = dm_par->unit * *left++ + dm_par->clev * *center; - right_tmp= dm_par->unit * *right++ + dm_par->clev * *center++; - *s16_samples++ = (int16_t)(left_tmp + *delay_left); - *s16_samples++ = (int16_t)(right_tmp + *delay_right); - *delay_left++ = dm_par->unit * *delay1_left++ + dm_par->clev * *delay1_center; - *delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *center++; - } - break; - case 2: // copy to output - for (i = 0; i < 256; i++) { - *s16_samples++ = (int16_t)samples[0][i]; - *s16_samples++ = (int16_t)samples[1][i]; - } - break; - } - } -} diff --git a/ac3dec/imdct.h b/ac3dec/imdct.h deleted file mode 100644 index 8f10af00b..000000000 --- a/ac3dec/imdct.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * imdct.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -void imdct (bsi_t *bsi,audblk_t *audblk, stream_samples_t samples, int16_t *s16_samples, dm_par_t *dm_par); -void imdct_init(void); diff --git a/ac3dec/imdct512_kni.S b/ac3dec/imdct512_kni.S deleted file mode 100644 index 10b8de6fe..000000000 --- a/ac3dec/imdct512_kni.S +++ /dev/null @@ -1,548 +0,0 @@ -/* - * imdct512_kni.S - * - * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - October 2000 - * - * - * imdct512_kni.S is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * imdct512_kni.S is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifdef __i386__ - -.text - .align 4 -.global imdct512_pre_ifft_twiddle_kni - .type imdct512_pre_ifft_twiddle_kni, @function -imdct512_pre_ifft_twiddle_kni: - - pushl %ebp - movl %esp, %ebp - addl $-4, %esp /* local variable, loop counter */ - - pushl %eax - pushl %ebx - pushl %ecx - pushl %edx - pushl %edi - pushl %esi - - movl 8(%ebp), %eax /* pmt */ - movl 12(%ebp), %ebx /* buf */ - movl 16(%ebp), %ecx /* data */ - movl 20(%ebp), %edx /* xcos_sin_sse */ - movl $64, -4(%ebp) - - -.loop: - movl (%eax), %esi - movl 4(%eax), %edi - movss (%ecx, %esi, 8), %xmm1 /* 2j */ - movss (%ecx, %edi, 8), %xmm3 /* 2(j+1) */ - - shll $1, %esi - shll $1, %edi - - movaps (%edx, %esi, 8), %xmm0; /* -c_j | -s_j | -s_j | c_j */ - movaps (%edx, %edi, 8), %xmm2; /* -c_j+1 | -s_j+1 | -s_j+1 | c_j+1 */ - - negl %esi - negl %edi - - movss 1020(%ecx, %esi, 4), %xmm4 /* 255-2j */ - addl $8, %eax - movss 1020(%ecx, %edi, 4), %xmm5 /* 255-2(j+1) */ - - shufps $0, %xmm1, %xmm4 /* 2j | 2j | 255-2j | 255-2j */ - shufps $0, %xmm3, %xmm5 /* 2(j+1) | 2(j+1) | 255-2(j+1) | 255-2(j+1) */ - mulps %xmm4, %xmm0 - mulps %xmm5, %xmm2 - movhlps %xmm0, %xmm1 - movhlps %xmm2, %xmm3 - addl $16, %ebx - addps %xmm1, %xmm0 - addps %xmm3, %xmm2 - movlhps %xmm2, %xmm0 - movaps %xmm0, -16(%ebx) - decl -4(%ebp) - jnz .loop - - popl %esi - popl %edi - popl %edx - popl %ecx - popl %ebx - popl %eax - - addl $4, %esp - popl %ebp - - ret - .p2align 4,0 - -.global imdct512_post_ifft_twiddle_kni - .type imdct512_post_ifft_twiddle_kni, @function -imdct512_post_ifft_twiddle_kni: - - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %ecx - - movl 8(%ebp), %eax /* buf[] */ - movl 12(%ebp), %ebx /* xcos_sin_sse[] */ - movl $32, %ecx /* loop counter */ - -.loop1: - movaps (%eax), %xmm0 /* im1 | re1 | im0 | re0 */ - - movaps (%ebx), %xmm2 /* -c | -s | -s | c */ - movhlps %xmm0, %xmm1 /* im1 | re1 */ - movaps 16(%ebx), %xmm3 /* -c1 | -s1 | -s1 | c1 */ - - shufps $0x50, %xmm0, %xmm0 /* im0 | im0 | re0 | re0 */ - shufps $0x50, %xmm1, %xmm1 /* im1 | im1 | re1 | re1 */ - - movaps 16(%eax), %xmm4 /* im3 | re3 | im2 | re2 */ - - shufps $0x27, %xmm2, %xmm2 /* c | -s | -s | -c */ - movhlps %xmm4, %xmm5 /* im3 | re3 */ - shufps $0x27, %xmm3, %xmm3 /* c1 | -s1 | -s1 | -c1 */ - - movaps 32(%ebx), %xmm6 /* -c2 | -s2 | -s2 | c2 */ - movaps 48(%ebx), %xmm7 /* -c3 | -s3 | -s3 | c3 */ - - shufps $0x50, %xmm4, %xmm4 /* im2 | im2 | re2 | re2 */ - shufps $0x50, %xmm5, %xmm5 /* im3 | im3 | re3 | re3 */ - - mulps %xmm2, %xmm0 - mulps %xmm3, %xmm1 - - shufps $0x27, %xmm6, %xmm6 /* c2 | -s2 | -s2 | -c2 */ - shufps $0x27, %xmm7, %xmm7 /* c3 | -s3 | -s3 | -c3 */ - - movhlps %xmm0, %xmm2 - movhlps %xmm1, %xmm3 - - mulps %xmm6, %xmm4 - mulps %xmm7, %xmm5 - - addps %xmm2, %xmm0 - addps %xmm3, %xmm1 - - movhlps %xmm4, %xmm6 - movhlps %xmm5, %xmm7 - - addps %xmm6, %xmm4 - addps %xmm7, %xmm5 - - movlhps %xmm1, %xmm0 - movlhps %xmm5, %xmm4 - - movaps %xmm0, (%eax) - movaps %xmm4, 16(%eax) - addl $64, %ebx - addl $32, %eax - decl %ecx - jnz .loop1 - - popl %ecx - popl %ebx - popl %eax - - leave - ret - .p2align 4,0 - -.global imdct512_window_delay_kni - .type imdct512_window_delay_kni, @function -imdct512_window_delay_kni: - - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %ecx - pushl %edx - pushl %esi - pushl %edi - - movl 20(%ebp), %ebx /* delay */ - movl 16(%ebp), %edx /* window */ - - movl 8(%ebp), %eax /* buf */ - movl $16, %ecx /* loop count */ - leal 516(%eax), %esi /* buf[64].im */ - leal 504(%eax), %edi /* buf[63].re */ - movl 12(%ebp), %eax /* data */ -.first_128_samples: - - movss (%esi), %xmm0 - movss 8(%esi), %xmm2 - movss (%edi), %xmm1 - movss -8(%edi), %xmm3 - - movlhps %xmm2, %xmm0 /* 0.0 | im1 | 0.0 | im0 */ - movlhps %xmm3, %xmm1 /* 0.0 | re1 | 0.0 | re0 */ - - movaps (%edx), %xmm4 /* w3 | w2 | w1 | w0 */ - movaps (%ebx), %xmm5 /* d3 | d2 | d1 | d0 */ - shufps $0xb1, %xmm1, %xmm1 /* re1 | 0.0 | re0 | 0.0 */ - - movss 16(%esi), %xmm6 /* im2 */ - movss 24(%esi), %xmm7 /* im3 */ - subps %xmm1, %xmm0 /* -re1 | im1 | -re0 | im0 */ - movss -16(%edi), %xmm2 /* re2 */ - movss -24(%edi), %xmm3 /* re3 */ - mulps %xmm4, %xmm0 - movlhps %xmm7, %xmm6 /* 0.0 | im3 | 0.0 | im2 */ - movlhps %xmm3, %xmm2 /* 0.0 | re3 | 0.0 | re2 */ - addps %xmm5, %xmm0 - shufps $0xb1, %xmm2, %xmm2 /* re3 | 0.0 | re2 | 0.0 */ - movaps 16(%edx), %xmm4 /* w7 | w6 | w5 | w4 */ - movaps 16(%ebx), %xmm5 /* d7 | d6 | d5 | d4 */ - subps %xmm2, %xmm6 /* -re3 | im3 | -re2 | im2 */ - addl $32, %edx - movaps %xmm0, (%eax) - addl $32, %ebx - mulps %xmm4, %xmm6 - addl $32, %esi - addl $32, %eax - addps %xmm5, %xmm6 - addl $-32, %edi - movaps %xmm6, -16(%eax) - decl %ecx - jnz .first_128_samples - - movl 8(%ebp), %esi /* buf[0].re */ - leal 1020(%esi), %edi /* buf[127].im */ - movl $16, %ecx /* loop count */ -.second_128_samples: - - movss (%esi), %xmm0 /* buf[i].re */ - movss 8(%esi), %xmm2 /* re1 */ - movss (%edi), %xmm1 /* buf[127-i].im */ - movss -8(%edi), %xmm3 /* im1 */ - - movlhps %xmm2, %xmm0 /* 0.0 | re1 | 0.0 | re0 */ - movlhps %xmm3, %xmm1 /* 0.0 | im1 | 0.0 | im1 */ - - movaps (%edx), %xmm4 /* w3 | w2 | w1 | w0 */ - movaps (%ebx), %xmm5 /* d3 | d2 | d1 | d0 */ - - shufps $0xb1, %xmm1, %xmm1 /* im1 | 0.0 | im0 | 0.0 */ - movss 16(%esi), %xmm6 /* re2 */ - movss 24(%esi), %xmm7 /* re3 */ - movss -16(%edi), %xmm2 /* im2 */ - movss -24(%edi), %xmm3 /* im3 */ - subps %xmm1, %xmm0 /* -im1 | re1 | -im0 | re0 */ - movlhps %xmm7, %xmm6 /* 0.0 | re3 | 0.0 | re2 */ - movlhps %xmm3, %xmm2 /* 0.0 | im3 | 0.0 | im2 */ - mulps %xmm4, %xmm0 - shufps $0xb1, %xmm2, %xmm2 /* im3 | 0.0 | im2 | 0.0 */ - movaps 16(%edx), %xmm4 /* w7 | w6 | w5 | w4 */ - addl $32, %esi - subps %xmm2, %xmm6 /* -im3 | re3 | -im2 | re2 */ - addps %xmm5, %xmm0 - mulps %xmm4, %xmm6 - addl $-32, %edi - movaps 16(%ebx), %xmm5 /* d7 | d6 | d5 | d4 */ - movaps %xmm0, (%eax) - addps %xmm5, %xmm6 - addl $32, %edx - addl $32, %eax - addl $32, %ebx - movaps %xmm6, -16(%eax) - decl %ecx - jnz .second_128_samples - - movl 8(%ebp), %eax - leal 512(%eax), %esi /* buf[64].re */ - leal 508(%eax), %edi /* buf[63].im */ - movl $16, %ecx /* loop count */ - movl 20(%ebp), %eax /* delay */ -.first_128_delay: - - movss (%esi), %xmm0 - movss 8(%esi), %xmm2 - movss (%edi), %xmm1 - movss -8(%edi), %xmm3 - - movlhps %xmm2, %xmm0 /* 0.0 | re1 | 0.0 | re0 */ - movlhps %xmm3, %xmm1 /* 0.0 | im1 | 0.0 | im0 */ - - movaps -16(%edx), %xmm4 /* w3 | w2 | w1 | w0 */ - shufps $0xb1, %xmm1, %xmm1 /* im1 | 0.0 | im0 | 0.0 */ - movss 16(%esi), %xmm6 /* re2 */ - movss 24(%esi), %xmm7 /* re3 */ - movss -16(%edi), %xmm2 /* im2 */ - movss -24(%edi), %xmm3 /* im3 */ - subps %xmm1, %xmm0 /* -im1 | re1 | -im0 | re0 */ - addl $-32, %edx - movlhps %xmm7, %xmm6 /* 0.0 | re3 | 0.0 | re2 */ - movlhps %xmm3, %xmm2 /* 0.0 | im3 | 0.0 | im2 */ - mulps %xmm4, %xmm0 - movaps (%edx), %xmm5 /* w7 | w6 | w5 | w4 */ - shufps $0xb1, %xmm2, %xmm2 /* im3 | 0.0 | im2 | 0.0 */ - movaps %xmm0, (%eax) - addl $32, %esi - subps %xmm2, %xmm6 /* -im3 | re3 | -im2 | re2 */ - addl $-32, %edi - mulps %xmm5, %xmm6 - addl $32, %eax - movaps %xmm6, -16(%eax) - decl %ecx - jnz .first_128_delay - - movl 8(%ebp), %ebx - leal 4(%ebx), %esi /* buf[0].im */ - leal 1016(%ebx), %edi /* buf[127].re */ - movl $16, %ecx /* loop count */ -.second_128_delay: - - movss (%esi), %xmm0 - movss 8(%esi), %xmm2 - movss (%edi), %xmm1 - movss -8(%edi), %xmm3 - - movlhps %xmm2, %xmm0 /* 0.0 | im1 | 0.0 | im0 */ - movlhps %xmm3, %xmm1 /* 0.0 | re1 | 0.0 | re0 */ - - movaps -16(%edx), %xmm4 /* w3 | w2 | w1 | w0 */ - shufps $0xb1, %xmm1, %xmm1 /* re1 | 0.0 | re0 | 0.0 */ - movss 16(%esi), %xmm6 /* im2 */ - movss 24(%esi), %xmm7 /* im3 */ - movss -16(%edi), %xmm2 /* re2 */ - movss -24(%edi), %xmm3 /* re3 */ - subps %xmm0, %xmm1 /* re1 | -im1 | re0 | -im0 */ - addl $-32, %edx - movlhps %xmm7, %xmm6 /* 0.0 | im3 | 0.0 | im2 */ - movlhps %xmm3, %xmm2 /* 0.0 | re3 | 0.0 | re2 */ - mulps %xmm4, %xmm1 - movaps (%edx), %xmm5 /* w7 | w6 | w5 | w4 */ - shufps $0xb1, %xmm2, %xmm2 /* re3 | 0.0 | re2 | 0.0 */ - movaps %xmm1, (%eax) - addl $32, %esi - subps %xmm6, %xmm2 /* re | -im3 | re | -im2 */ - addl $-32, %edi - mulps %xmm5, %xmm2 - addl $32, %eax - movaps %xmm2, -16(%eax) - decl %ecx - jnz .second_128_delay - - popl %edi - popl %esi - popl %edx - popl %ecx - popl %ebx - popl %eax - - leave - ret - .p2align 4,0 - -.global imdct512_window_delay_nol_kni - .type imdct512_window_delay_nol_kni, @function -imdct512_window_delay_nol_kni: - - pushl %ebp - movl %esp, %ebp - - pushl %eax - pushl %ebx - pushl %ecx - pushl %edx - pushl %esi - pushl %edi - - /* movl 20(%ebp), %ebx delay */ - movl 16(%ebp), %edx /* window */ - - movl 8(%ebp), %eax /* buf */ - movl $16, %ecx /* loop count */ - leal 516(%eax), %esi /* buf[64].im */ - leal 504(%eax), %edi /* buf[63].re */ - movl 12(%ebp), %eax /* data */ -.first_128_sample: - - movss (%esi), %xmm0 - movss 8(%esi), %xmm2 - movss (%edi), %xmm1 - movss -8(%edi), %xmm3 - - movlhps %xmm2, %xmm0 /* 0.0 | im1 | 0.0 | im0 */ - movlhps %xmm3, %xmm1 /* 0.0 | re1 | 0.0 | re0 */ - - movaps (%edx), %xmm4 /* w3 | w2 | w1 | w0 */ - /* movaps (%ebx), %xmm5 d3 | d2 | d1 | d0 */ - shufps $0xb1, %xmm1, %xmm1 /* re1 | 0.0 | re0 | 0.0 */ - - movss 16(%esi), %xmm6 /* im2 */ - movss 24(%esi), %xmm7 /* im3 */ - subps %xmm1, %xmm0 /* -re1 | im1 | -re0 | im0 */ - movss -16(%edi), %xmm2 /* re2 */ - movss -24(%edi), %xmm3 /* re3 */ - mulps %xmm4, %xmm0 - movlhps %xmm7, %xmm6 /* 0.0 | im3 | 0.0 | im2 */ - movlhps %xmm3, %xmm2 /* 0.0 | re3 | 0.0 | re2 */ - /* addps %xmm5, %xmm0 */ - shufps $0xb1, %xmm2, %xmm2 /* re3 | 0.0 | re2 | 0.0 */ - movaps 16(%edx), %xmm4 /* w7 | w6 | w5 | w4 */ - /* movaps 16(%ebx), %xmm5 d7 | d6 | d5 | d4 */ - subps %xmm2, %xmm6 /* -re3 | im3 | -re2 | im2 */ - addl $32, %edx - movaps %xmm0, (%eax) - /* addl $32, %ebx */ - mulps %xmm4, %xmm6 - addl $32, %esi - addl $32, %eax - /* addps %xmm5, %xmm6 */ - addl $-32, %edi - movaps %xmm6, -16(%eax) - decl %ecx - jnz .first_128_sample - - movl 8(%ebp), %esi /* buf[0].re */ - leal 1020(%esi), %edi /* buf[127].im */ - movl $16, %ecx /* loop count */ -.second_128_sample: - - movss (%esi), %xmm0 /* buf[i].re */ - movss 8(%esi), %xmm2 /* re1 */ - movss (%edi), %xmm1 /* buf[127-i].im */ - movss -8(%edi), %xmm3 /* im1 */ - - movlhps %xmm2, %xmm0 /* 0.0 | re1 | 0.0 | re0 */ - movlhps %xmm3, %xmm1 /* 0.0 | im1 | 0.0 | im1 */ - - movaps (%edx), %xmm4 /* w3 | w2 | w1 | w0 */ - /* movaps (%ebx), %xmm5 d3 | d2 | d1 | d0 */ - - shufps $0xb1, %xmm1, %xmm1 /* im1 | 0.0 | im0 | 0.0 */ - movss 16(%esi), %xmm6 /* re2 */ - movss 24(%esi), %xmm7 /* re3 */ - movss -16(%edi), %xmm2 /* im2 */ - movss -24(%edi), %xmm3 /* im3 */ - subps %xmm1, %xmm0 /* -im1 | re1 | -im0 | re0 */ - movlhps %xmm7, %xmm6 /* 0.0 | re3 | 0.0 | re2 */ - movlhps %xmm3, %xmm2 /* 0.0 | im3 | 0.0 | im2 */ - mulps %xmm4, %xmm0 - shufps $0xb1, %xmm2, %xmm2 /* im3 | 0.0 | im2 | 0.0 */ - movaps 16(%edx), %xmm4 /* w7 | w6 | w5 | w4 */ - addl $32, %esi - subps %xmm2, %xmm6 /* -im3 | re3 | -im2 | re2 */ - /* addps %xmm5, %xmm0 */ - mulps %xmm4, %xmm6 - addl $-32, %edi - /* movaps 16(%ebx), %xmm5 d7 | d6 | d5 | d4 */ - movaps %xmm0, (%eax) - /* addps %xmm5, %xmm6 */ - addl $32, %edx - addl $32, %eax - /* addl $32, %ebx */ - movaps %xmm6, -16(%eax) - decl %ecx - jnz .second_128_sample - - movl 8(%ebp), %eax - leal 512(%eax), %esi /* buf[64].re */ - leal 508(%eax), %edi /* buf[63].im */ - movl $16, %ecx /* loop count */ - movl 20(%ebp), %eax /* delay */ -.first_128_delays: - - movss (%esi), %xmm0 - movss 8(%esi), %xmm2 - movss (%edi), %xmm1 - movss -8(%edi), %xmm3 - - movlhps %xmm2, %xmm0 /* 0.0 | re1 | 0.0 | re0 */ - movlhps %xmm3, %xmm1 /* 0.0 | im1 | 0.0 | im0 */ - - movaps -16(%edx), %xmm4 /* w3 | w2 | w1 | w0 */ - shufps $0xb1, %xmm1, %xmm1 /* im1 | 0.0 | im0 | 0.0 */ - movss 16(%esi), %xmm6 /* re2 */ - movss 24(%esi), %xmm7 /* re3 */ - movss -16(%edi), %xmm2 /* im2 */ - movss -24(%edi), %xmm3 /* im3 */ - subps %xmm1, %xmm0 /* -im1 | re1 | -im0 | re0 */ - addl $-32, %edx - movlhps %xmm7, %xmm6 /* 0.0 | re3 | 0.0 | re2 */ - movlhps %xmm3, %xmm2 /* 0.0 | im3 | 0.0 | im2 */ - mulps %xmm4, %xmm0 - movaps (%edx), %xmm5 /* w7 | w6 | w5 | w4 */ - shufps $0xb1, %xmm2, %xmm2 /* im3 | 0.0 | im2 | 0.0 */ - movaps %xmm0, (%eax) - addl $32, %esi - subps %xmm2, %xmm6 /* -im3 | re3 | -im2 | re2 */ - addl $-32, %edi - mulps %xmm5, %xmm6 - addl $32, %eax - movaps %xmm6, -16(%eax) - decl %ecx - jnz .first_128_delays - - movl 8(%ebp), %ebx - leal 4(%ebx), %esi /* buf[0].im */ - leal 1016(%ebx), %edi /* buf[127].re */ - movl $16, %ecx /* loop count */ -.second_128_delays: - - movss (%esi), %xmm0 - movss 8(%esi), %xmm2 - movss (%edi), %xmm1 - movss -8(%edi), %xmm3 - - movlhps %xmm2, %xmm0 /* 0.0 | im1 | 0.0 | im0 */ - movlhps %xmm3, %xmm1 /* 0.0 | re1 | 0.0 | re0 */ - - movaps -16(%edx), %xmm4 /* w3 | w2 | w1 | w0 */ - shufps $0xb1, %xmm1, %xmm1 /* re1 | 0.0 | re0 | 0.0 */ - movss 16(%esi), %xmm6 /* im2 */ - movss 24(%esi), %xmm7 /* im3 */ - movss -16(%edi), %xmm2 /* re2 */ - movss -24(%edi), %xmm3 /* re3 */ - subps %xmm0, %xmm1 /* re1 | -im1 | re0 | -im0 */ - addl $-32, %edx - movlhps %xmm7, %xmm6 /* 0.0 | im3 | 0.0 | im2 */ - movlhps %xmm3, %xmm2 /* 0.0 | re3 | 0.0 | re2 */ - mulps %xmm4, %xmm1 - movaps (%edx), %xmm5 /* w7 | w6 | w5 | w4 */ - shufps $0xb1, %xmm2, %xmm2 /* re3 | 0.0 | re2 | 0.0 */ - movaps %xmm1, (%eax) - addl $32, %esi - subps %xmm6, %xmm2 /* re | -im3 | re | -im2 */ - addl $-32, %edi - mulps %xmm5, %xmm2 - addl $32, %eax - movaps %xmm2, -16(%eax) - decl %ecx - jnz .second_128_delays - - popl %edi - popl %esi - popl %edx - popl %ecx - popl %ebx - popl %eax - - leave - ret - .p2align 4,0 -#endif diff --git a/ac3dec/imdct_c.c b/ac3dec/imdct_c.c deleted file mode 100644 index 1f2bfe849..000000000 --- a/ac3dec/imdct_c.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * imdct.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include "ac3.h" -#include "ac3_internal.h" - -#include "downmix.h" -#include "imdct_c.h" -#include "srfft.h" - - -#define N 512 - -extern void (*imdct_do_512) (float data[],float delay[]); -extern void (*imdct_do_512_nol) (float data[], float delay[]); -extern void (*fft_64p) (complex_t *); - -extern const int pm128[]; -extern float window[]; -extern complex_t buf[128]; - -extern void fft_64p_c (complex_t *); -extern void fft_128p_c (complex_t *); - -static void imdct_do_512_c (float data[],float delay[]); -static void imdct_do_512_nol_c (float data[], float delay[]); - -/* Twiddle factors for IMDCT */ -static float xcos1[128] __attribute__((aligned(16))); -static float xsin1[128] __attribute__((aligned(16))); - - -int imdct_init_c (void) -{ - int i; - float scale = 255.99609372; - - imdct_do_512 = imdct_do_512_c; - imdct_do_512_nol = imdct_do_512_nol_c; - fft_64p = fft_64p_c; - - /* Twiddle factors to turn IFFT into IMDCT */ - - for (i=0; i < 128; i++) { - xcos1[i] = cos(2.0f * M_PI * (8*i+1)/(8*N)) * scale; - xsin1[i] = sin(2.0f * M_PI * (8*i+1)/(8*N)) * scale; - } - - return 0; -} - - -static void imdct_do_512_c (float data[], float delay[]) -{ - int i, j; - float tmp_a_r, tmp_a_i; - float *data_ptr; - float *delay_ptr; - float *window_ptr; - -// 512 IMDCT with source and dest data in 'data' -// Pre IFFT complex multiply plus IFFT complex conjugate - - for( i=0; i < 128; i++) { - j = pm128[i]; - //a = (data[256-2*j-1] - data[2*j]) * (xcos1[j] + xsin1[j]); - //c = data[2*j] * xcos1[j]; - //b = data[256-2*j-1] * xsin1[j]; - //buf1[i].re = a - b + c; - //buf1[i].im = b + c; - buf[i].re = (data[256-2*j-1] * xcos1[j]) - (data[2*j] * xsin1[j]); - buf[i].im = -1.0 * (data[2*j] * xcos1[j] + data[256-2*j-1] * xsin1[j]); - } - - fft_128p_c (&buf[0]); - -// Post IFFT complex multiply plus IFFT complex conjugate - for (i=0; i < 128; i++) { - tmp_a_r = buf[i].re; - tmp_a_i = buf[i].im; - //a = (tmp_a_r - tmp_a_i) * (xcos1[j] + xsin1[j]); - //b = tmp_a_r * xsin1[j]; - //c = tmp_a_i * xcos1[j]; - //buf[j].re = a - b + c; - //buf[j].im = b + c; - buf[i].re =(tmp_a_r * xcos1[i]) + (tmp_a_i * xsin1[i]); - buf[i].im =(tmp_a_r * xsin1[i]) - (tmp_a_i * xcos1[i]); - } - - data_ptr = data; - delay_ptr = delay; - window_ptr = window; - -// Window and convert to real valued signal - for (i=0; i< 64; i++) { - *data_ptr++ = -buf[64+i].im * *window_ptr++ + *delay_ptr++; - *data_ptr++ = buf[64-i-1].re * *window_ptr++ + *delay_ptr++; - } - - for(i=0; i< 64; i++) { - *data_ptr++ = -buf[i].re * *window_ptr++ + *delay_ptr++; - *data_ptr++ = buf[128-i-1].im * *window_ptr++ + *delay_ptr++; - } - -// The trailing edge of the window goes into the delay line - delay_ptr = delay; - - for(i=0; i< 64; i++) { - *delay_ptr++ = -buf[64+i].re * *--window_ptr; - *delay_ptr++ = buf[64-i-1].im * *--window_ptr; - } - - for(i=0; i<64; i++) { - *delay_ptr++ = buf[i].im * *--window_ptr; - *delay_ptr++ = -buf[128-i-1].re * *--window_ptr; - } -} - - -static void imdct_do_512_nol_c (float data[], float delay[]) -{ - int i, j; - - float tmp_a_i; - float tmp_a_r; - - float *data_ptr; - float *delay_ptr; - float *window_ptr; - - // - // 512 IMDCT with source and dest data in 'data' - // - - // Pre IFFT complex multiply plus IFFT cmplx conjugate - - for( i=0; i < 128; i++) { - /* z[i] = (X[256-2*i-1] + j * X[2*i]) * (xcos1[i] + j * xsin1[i]) */ - j = pm128[i]; - //a = (data[256-2*j-1] - data[2*j]) * (xcos1[j] + xsin1[j]); - //c = data[2*j] * xcos1[j]; - //b = data[256-2*j-1] * xsin1[j]; - //buf1[i].re = a - b + c; - - //buf1[i].im = b + c; - buf[i].re = (data[256-2*j-1] * xcos1[j]) - (data[2*j] * xsin1[j]); - buf[i].im = -1.0 * (data[2*j] * xcos1[j] + data[256-2*j-1] * xsin1[j]); - } - - fft_128p_c (&buf[0]); - - /* Post IFFT complex multiply plus IFFT complex conjugate*/ - for (i=0; i < 128; i++) { - /* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; */ - /* int j1 = i; */ - tmp_a_r = buf[i].re; - tmp_a_i = buf[i].im; - //a = (tmp_a_r - tmp_a_i) * (xcos1[j] + xsin1[j]); - //b = tmp_a_r * xsin1[j]; - //c = tmp_a_i * xcos1[j]; - //buf[j].re = a - b + c; - //buf[j].im = b + c; - buf[i].re =(tmp_a_r * xcos1[i]) + (tmp_a_i * xsin1[i]); - buf[i].im =(tmp_a_r * xsin1[i]) - (tmp_a_i * xcos1[i]); - } - - data_ptr = data; - delay_ptr = delay; - window_ptr = window; - - /* Window and convert to real valued signal, no overlap here*/ - for (i=0; i< 64; i++) { - *data_ptr++ = -buf[64+i].im * *window_ptr++; - *data_ptr++ = buf[64-i-1].re * *window_ptr++; - } - - for(i=0; i< 64; i++) { - *data_ptr++ = -buf[i].re * *window_ptr++; - *data_ptr++ = buf[128-i-1].im * *window_ptr++; - } - - /* The trailing edge of the window goes into the delay line */ - delay_ptr = delay; - - for(i=0; i< 64; i++) { - *delay_ptr++ = -buf[64+i].re * *--window_ptr; - *delay_ptr++ = buf[64-i-1].im * *--window_ptr; - } - - for(i=0; i<64; i++) { - *delay_ptr++ = buf[i].im * *--window_ptr; - *delay_ptr++ = -buf[128-i-1].re * *--window_ptr; - } -} diff --git a/ac3dec/imdct_c.h b/ac3dec/imdct_c.h deleted file mode 100644 index d2c31b54b..000000000 --- a/ac3dec/imdct_c.h +++ /dev/null @@ -1,36 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#ifndef __IMDCT_C_H__ -#define __IMDCT_C_H__ - -#include "cmplx.h" - -int imdct_init_c (void); - -void fft_128p_c (complex_t *); -void fft_64p_c (complex_t *); - -void imdct512_pre_ifft_twiddle_c (const int *pmt, complex_t *buf, float *data, float *xcos_sin_sse); -void imdct512_post_ifft_twiddle_c (complex_t *buf, float *xcos_sin_sse); -void imdct512_window_delay_c (complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); -void imdct512_window_delay_nol_c (complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); - -#endif diff --git a/ac3dec/imdct_kni.c b/ac3dec/imdct_kni.c deleted file mode 100644 index b44547a95..000000000 --- a/ac3dec/imdct_kni.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * imdct_kni.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -#ifdef __i386__ - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <mm_accel.h> -#include "ac3.h" -#include "ac3_internal.h" - -#include "downmix.h" -#include "imdct_kni.h" -#include "srfft.h" - -#define N 512 - -/* Delay buffer for time domain interleaving */ -static float xcos_sin_sse[128 * 4] __attribute__((aligned(16))); - -extern void (*imdct_do_512) (float data[],float delay[]); -extern void (*imdct_do_512_nol) (float data[], float delay[]); -extern void (*fft_64p) (complex_t *); - -extern const int pm128[]; -extern float window[]; -extern complex_t buf[128]; - -extern void fft_64p_kni (complex_t *); -extern void fft_128p_kni (complex_t *); - -static void imdct_do_512_kni (float data[], float delay[]); -static void imdct_do_512_nol_kni (float data[], float delay[]); - - -int imdct_init_kni (void) -{ - uint32_t accel = mm_accel (); - - if (accel & MM_ACCEL_X86_MMXEXT) { - int i; - float scale = 255.99609372; - - fprintf (stderr, "Using SSE for IMDCT\n"); - imdct_do_512 = imdct_do_512_kni; - imdct_do_512_nol = imdct_do_512_nol_kni; - fft_64p = fft_64p_kni; - - for (i=0; i < 128; i++) { - float xcos_i = cos(2.0f * M_PI * (8*i+1)/(8*N)) * scale; - float xsin_i = sin(2.0f * M_PI * (8*i+1)/(8*N)) * scale; - xcos_sin_sse[i * 4] = xcos_i; - xcos_sin_sse[i * 4 + 1] = -xsin_i; - xcos_sin_sse[i * 4 + 2] = -xsin_i; - xcos_sin_sse[i * 4 + 3] = -xcos_i; - } - - return 0; - } else - return -1; -} - - -static void imdct_do_512_kni (float data[], float delay[]) -{ - imdct512_pre_ifft_twiddle_kni (pm128, buf, data, xcos_sin_sse); - fft_128p_kni (buf); - imdct512_post_ifft_twiddle_kni (buf, xcos_sin_sse); - imdct512_window_delay_kni (buf, data, window, delay); -} - - -static void imdct_do_512_nol_kni (float data[], float delay[]) -{ - imdct512_pre_ifft_twiddle_kni (pm128, buf, data, xcos_sin_sse); - fft_128p_kni (buf); - imdct512_post_ifft_twiddle_kni (buf, xcos_sin_sse); - imdct512_window_delay_nol_kni (buf, data, window, delay); -} - -#endif diff --git a/ac3dec/imdct_kni.h b/ac3dec/imdct_kni.h deleted file mode 100644 index 2193c0753..000000000 --- a/ac3dec/imdct_kni.h +++ /dev/null @@ -1,36 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#ifndef __IMDCT_KNI_H__ -#define __IMDCT_KNI_H__ - -#include "cmplx.h" - -int imdct_init_kni (void); - -void fft_128p_kni(complex_t *); -void fft_64p_kni(complex_t *); - -void imdct512_pre_ifft_twiddle_kni(const int *pmt, complex_t *buf, float *data, float *xcos_sin_sse); -void imdct512_post_ifft_twiddle_kni(complex_t *buf, float *xcos_sin_sse); -void imdct512_window_delay_kni(complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); -void imdct512_window_delay_nol_kni(complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); - -#endif diff --git a/ac3dec/mm_accel.h b/ac3dec/mm_accel.h deleted file mode 100644 index 82dc5837f..000000000 --- a/ac3dec/mm_accel.h +++ /dev/null @@ -1,36 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#ifndef __MM_ACCEL_H__ -#define __MM_ACCEL_H__ - -#include <inttypes.h> - -// generic accelerations -#define MM_ACCEL_MLIB 0x00000001 - -// x86 accelerations -#define MM_ACCEL_X86_MMX 0x80000000 -#define MM_ACCEL_X86_3DNOW 0x40000000 -#define MM_ACCEL_X86_MMXEXT 0x20000000 - -uint32_t mm_accel (void); - -#endif diff --git a/ac3dec/parse.c b/ac3dec/parse.c deleted file mode 100644 index 49ea57c67..000000000 --- a/ac3dec/parse.c +++ /dev/null @@ -1,481 +0,0 @@ -/* - * parse.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include "ac3.h" -#include "ac3_internal.h" - - -#include "bitstream.h" -#include "stats.h" -#include "debug.h" -#include "crc.h" -#include "parse.h" - -/* Misc LUT */ -static const uint16_t nfchans[8] = {2,1,2,3,3,4,4,5}; - -struct frmsize_s -{ - uint16_t bit_rate; - uint16_t frm_size[3]; -}; - -static const struct frmsize_s frmsizecod_tbl[64] = -{ - { 32 ,{64 ,69 ,96 } }, - { 32 ,{64 ,70 ,96 } }, - { 40 ,{80 ,87 ,120 } }, - { 40 ,{80 ,88 ,120 } }, - { 48 ,{96 ,104 ,144 } }, - { 48 ,{96 ,105 ,144 } }, - { 56 ,{112 ,121 ,168 } }, - { 56 ,{112 ,122 ,168 } }, - { 64 ,{128 ,139 ,192 } }, - { 64 ,{128 ,140 ,192 } }, - { 80 ,{160 ,174 ,240 } }, - { 80 ,{160 ,175 ,240 } }, - { 96 ,{192 ,208 ,288 } }, - { 96 ,{192 ,209 ,288 } }, - { 112 ,{224 ,243 ,336 } }, - { 112 ,{224 ,244 ,336 } }, - { 128 ,{256 ,278 ,384 } }, - { 128 ,{256 ,279 ,384 } }, - { 160 ,{320 ,348 ,480 } }, - { 160 ,{320 ,349 ,480 } }, - { 192 ,{384 ,417 ,576 } }, - { 192 ,{384 ,418 ,576 } }, - { 224 ,{448 ,487 ,672 } }, - { 224 ,{448 ,488 ,672 } }, - { 256 ,{512 ,557 ,768 } }, - { 256 ,{512 ,558 ,768 } }, - { 320 ,{640 ,696 ,960 } }, - { 320 ,{640 ,697 ,960 } }, - { 384 ,{768 ,835 ,1152 } }, - { 384 ,{768 ,836 ,1152 } }, - { 448 ,{896 ,975 ,1344 } }, - { 448 ,{896 ,976 ,1344 } }, - { 512 ,{1024 ,1114 ,1536 } }, - { 512 ,{1024 ,1115 ,1536 } }, - { 576 ,{1152 ,1253 ,1728 } }, - { 576 ,{1152 ,1254 ,1728 } }, - { 640 ,{1280 ,1393 ,1920 } }, - { 640 ,{1280 ,1394 ,1920 } } -}; - -/* Parse a syncinfo structure, minus the sync word */ -void parse_syncinfo(syncinfo_t *syncinfo, uint8_t *data) -{ - // - // We need to read in the entire syncinfo struct (0x0b77 + 24 bits) - // in order to determine how big the frame is - // - - // Get the sampling rate - syncinfo->fscod = (data[2] >> 6) & 0x3; - - if(syncinfo->fscod == 3) { - //invalid sampling rate code - return; - } - else if(syncinfo->fscod == 2) - syncinfo->sampling_rate = 32000; - else if(syncinfo->fscod == 1) - syncinfo->sampling_rate = 44100; - else - syncinfo->sampling_rate = 48000; - - // Get the frame size code - syncinfo->frmsizecod = data[2] & 0x3f; - - // Calculate the frame size and bitrate - syncinfo->frame_size = - frmsizecod_tbl[syncinfo->frmsizecod].frm_size[syncinfo->fscod]; - syncinfo->bit_rate = frmsizecod_tbl[syncinfo->frmsizecod].bit_rate; - -} - - -/** - * This routine fills a bsi struct from the AC3 stream - **/ - -void parse_bsi(bsi_t *bsi) -{ - /* Check the AC-3 version number */ - bsi->bsid = bitstream_get(5); - - /* Get the audio service provided by the steram */ - bsi->bsmod = bitstream_get(3); - - /* Get the audio coding mode (ie how many channels)*/ - bsi->acmod = bitstream_get(3); - /* Predecode the number of full bandwidth channels as we use this - * number a lot */ - bsi->nfchans = nfchans[bsi->acmod]; - - /* If it is in use, get the centre channel mix level */ - if ((bsi->acmod & 0x1) && (bsi->acmod != 0x1)) - bsi->cmixlev = bitstream_get(2); - - /* If it is in use, get the surround channel mix level */ - if (bsi->acmod & 0x4) - bsi->surmixlev = bitstream_get(2); - - /* Get the dolby surround mode if in 2/0 mode */ - if(bsi->acmod == 0x2) - bsi->dsurmod= bitstream_get(2); - - /* Is the low frequency effects channel on? */ - bsi->lfeon = bitstream_get(1); - - /* Get the dialogue normalization level */ - bsi->dialnorm = bitstream_get(5); - - /* Does compression gain exist? */ - if ((bsi->compre = bitstream_get(1))) { - /* Get compression gain */ - bsi->compr = bitstream_get(8); - } - - /* Does language code exist? */ - if ((bsi->langcode = bitstream_get(1))) { - /* Get langauge code */ - bsi->langcod = bitstream_get(8); - } - - /* Does audio production info exist? */ - if ((bsi->audprodie = bitstream_get(1))) { - /* Get mix level */ - bsi->mixlevel = bitstream_get(5); - - /* Get room type */ - bsi->roomtyp = bitstream_get(2); - } - - /* If we're in dual mono mode then get some extra info */ - if (!bsi->acmod) { - /* Get the dialogue normalization level two */ - bsi->dialnorm2 = bitstream_get(5); - - /* Does compression gain two exist? */ - if ((bsi->compr2e = bitstream_get(1))) { - /* Get compression gain two */ - bsi->compr2 = bitstream_get(8); - } - - /* Does language code two exist? */ - if ((bsi->langcod2e = bitstream_get(1))) { - /* Get langauge code two */ - bsi->langcod2 = bitstream_get(8); - } - - /* Does audio production info two exist? */ - if ((bsi->audprodi2e = bitstream_get(1))) { - /* Get mix level two */ - bsi->mixlevel2 = bitstream_get(5); - - /* Get room type two */ - bsi->roomtyp2 = bitstream_get(2); - } - } - - /* Get the copyright bit */ - bsi->copyrightb = bitstream_get(1); - - /* Get the original bit */ - bsi->origbs = bitstream_get(1); - - /* Does timecode one exist? */ - if ((bsi->timecod1e = bitstream_get(1))) - bsi->timecod1 = bitstream_get(14); - - /* Does timecode two exist? */ - if ((bsi->timecod2e = bitstream_get(1))) - bsi->timecod2 = bitstream_get(14); - - /* Does addition info exist? */ - if ((bsi->addbsie = bitstream_get(1))) { - uint32_t i; - - /* Get how much info is there */ - bsi->addbsil = bitstream_get(6); - - /* Get the additional info */ - for(i=0;i<(bsi->addbsil + 1);i++) - bsi->addbsi[i] = bitstream_get(8); - } - - stats_print_bsi(bsi); -} - - -/* More pain inducing parsing */ -void parse_audblk(bsi_t *bsi,audblk_t *audblk) -{ - int i,j; - - for (i=0; i < bsi->nfchans; i++) { - /* Is this channel an interleaved 256 + 256 block ? */ - audblk->blksw[i] = bitstream_get(1); - } - - for (i=0;i < bsi->nfchans; i++) { - /* Should we dither this channel? */ - audblk->dithflag[i] = bitstream_get(1); - } - - /* Does dynamic range control exist? */ - if ((audblk->dynrnge = bitstream_get(1))) { - /* Get dynamic range info */ - audblk->dynrng = bitstream_get(8); - } - - /* If we're in dual mono mode then get the second channel DR info */ - if (bsi->acmod == 0) { - /* Does dynamic range control two exist? */ - if ((audblk->dynrng2e = bitstream_get(1))) { - /* Get dynamic range info */ - audblk->dynrng2 = bitstream_get(8); - } - } - - /* Does coupling strategy exist? */ - if ((audblk->cplstre = bitstream_get(1))) { - /* Is coupling turned on? */ - if ((audblk->cplinu = bitstream_get(1))) { - for(i=0;i < bsi->nfchans; i++) - audblk->chincpl[i] = bitstream_get(1); - if(bsi->acmod == 0x2) - audblk->phsflginu = bitstream_get(1); - audblk->cplbegf = bitstream_get(4); - audblk->cplendf = bitstream_get(4); - audblk->ncplsubnd = (audblk->cplendf + 2) - audblk->cplbegf + 1; - - /* Calculate the start and end bins of the coupling channel */ - audblk->cplstrtmant = (audblk->cplbegf * 12) + 37 ; - audblk->cplendmant = ((audblk->cplendf + 3) * 12) + 37; - - /* The number of combined subbands is ncplsubnd minus each combined - * band */ - audblk->ncplbnd = audblk->ncplsubnd; - - for(i=1; i< audblk->ncplsubnd; i++) { - audblk->cplbndstrc[i] = bitstream_get(1); - audblk->ncplbnd -= audblk->cplbndstrc[i]; - } - } - } - - if(audblk->cplinu) { - /* Loop through all the channels and get their coupling co-ords */ - for(i=0;i < bsi->nfchans;i++) { - if(!audblk->chincpl[i]) - continue; - - /* Is there new coupling co-ordinate info? */ - if ((audblk->cplcoe[i] = bitstream_get(1))) { - audblk->mstrcplco[i] = bitstream_get(2); - for(j=0;j < audblk->ncplbnd; j++) { - audblk->cplcoexp[i][j] = bitstream_get(4); - audblk->cplcomant[i][j] = bitstream_get(4); - } - } - } - - /* If we're in dual mono mode, there's going to be some phase info */ - if( (bsi->acmod == 0x2) && audblk->phsflginu && - (audblk->cplcoe[0] || audblk->cplcoe[1])) { - for(j=0;j < audblk->ncplbnd; j++) - audblk->phsflg[j] = bitstream_get(1); - - } - } - - /* If we're in dual mono mode, there may be a rematrix strategy */ - if(bsi->acmod == 0x2) { - if ((audblk->rematstr = bitstream_get(1))) { - if (!audblk->cplinu) { - for(i = 0; i < 4; i++) - audblk->rematflg[i] = bitstream_get(1); - } - if((audblk->cplbegf > 2) && audblk->cplinu) { - for(i = 0; i < 4; i++) - audblk->rematflg[i] = bitstream_get(1); - } - if((audblk->cplbegf <= 2) && audblk->cplinu) { - for(i = 0; i < 3; i++) - audblk->rematflg[i] = bitstream_get(1); - } - if((audblk->cplbegf == 0) && audblk->cplinu) - for(i = 0; i < 2; i++) - audblk->rematflg[i] = bitstream_get(1); - - } - } - - if (audblk->cplinu) { - /* Get the coupling channel exponent strategy */ - audblk->cplexpstr = bitstream_get(2); - audblk->ncplgrps = (audblk->cplendmant - audblk->cplstrtmant) / - (3 << (audblk->cplexpstr-1)); - } - - for(i = 0; i < bsi->nfchans; i++) - audblk->chexpstr[i] = bitstream_get(2); - - /* Get the exponent strategy for lfe channel */ - if(bsi->lfeon) - audblk->lfeexpstr = bitstream_get(1); - - /* Determine the bandwidths of all the fbw channels */ - for(i = 0; i < bsi->nfchans; i++) { - uint16_t grp_size; - - if(audblk->chexpstr[i] != EXP_REUSE) { - if (audblk->cplinu && audblk->chincpl[i]) { - audblk->endmant[i] = audblk->cplstrtmant; - } else { - audblk->chbwcod[i] = bitstream_get(6); - audblk->endmant[i] = ((audblk->chbwcod[i] + 12) * 3) + 37; - } - - /* Calculate the number of exponent groups to fetch */ - grp_size = 3 * (1 << (audblk->chexpstr[i] - 1)); - audblk->nchgrps[i] = (audblk->endmant[i] - 1 + (grp_size - 3)) / grp_size; - } - } - - /* Get the coupling exponents if they exist */ - if(audblk->cplinu && (audblk->cplexpstr != EXP_REUSE)) { - audblk->cplabsexp = bitstream_get(4); - for(i=0;i< audblk->ncplgrps;i++) - audblk->cplexps[i] = bitstream_get(7); - } - - /* Get the fwb channel exponents */ - for(i=0;i < bsi->nfchans; i++) { - if(audblk->chexpstr[i] != EXP_REUSE) { - audblk->exps[i][0] = bitstream_get(4); - for(j=1;j<=audblk->nchgrps[i];j++) - audblk->exps[i][j] = bitstream_get(7); - audblk->gainrng[i] = bitstream_get(2); - } - } - - /* Get the lfe channel exponents */ - if(bsi->lfeon && (audblk->lfeexpstr != EXP_REUSE)) { - audblk->lfeexps[0] = bitstream_get(4); - audblk->lfeexps[1] = bitstream_get(7); - audblk->lfeexps[2] = bitstream_get(7); - } - - /* Get the parametric bit allocation parameters */ - audblk->baie = bitstream_get(1); - - if(audblk->baie) { - audblk->sdcycod = bitstream_get(2); - audblk->fdcycod = bitstream_get(2); - audblk->sgaincod = bitstream_get(2); - audblk->dbpbcod = bitstream_get(2); - audblk->floorcod = bitstream_get(3); - } - - /* Get the SNR off set info if it exists */ - audblk->snroffste = bitstream_get(1); - - if(audblk->snroffste) { - audblk->csnroffst = bitstream_get(6); - - if(audblk->cplinu) { - audblk->cplfsnroffst = bitstream_get(4); - audblk->cplfgaincod = bitstream_get(3); - } - - for(i = 0;i < bsi->nfchans; i++) { - audblk->fsnroffst[i] = bitstream_get(4); - audblk->fgaincod[i] = bitstream_get(3); - } - if(bsi->lfeon) { - - audblk->lfefsnroffst = bitstream_get(4); - audblk->lfefgaincod = bitstream_get(3); - } - } - - /* Get coupling leakage info if it exists */ - if(audblk->cplinu) { - audblk->cplleake = bitstream_get(1); - - if(audblk->cplleake) { - audblk->cplfleak = bitstream_get(3); - audblk->cplsleak = bitstream_get(3); - } - } - - /* Get the delta bit alloaction info */ - audblk->deltbaie = bitstream_get(1); - - if(audblk->deltbaie) { - if(audblk->cplinu) - audblk->cpldeltbae = bitstream_get(2); - - for(i = 0;i < bsi->nfchans; i++) - audblk->deltbae[i] = bitstream_get(2); - - if (audblk->cplinu && (audblk->cpldeltbae == DELTA_BIT_NEW)) { - audblk->cpldeltnseg = bitstream_get(3); - for(i = 0;i < audblk->cpldeltnseg + 1; i++) { - audblk->cpldeltoffst[i] = bitstream_get(5); - audblk->cpldeltlen[i] = bitstream_get(4); - audblk->cpldeltba[i] = bitstream_get(3); - } - } - - for(i = 0;i < bsi->nfchans; i++) { - if (audblk->deltbae[i] == DELTA_BIT_NEW) { - audblk->deltnseg[i] = bitstream_get(3); - for(j = 0; j < audblk->deltnseg[i] + 1; j++) { - audblk->deltoffst[i][j] = bitstream_get(5); - audblk->deltlen[i][j] = bitstream_get(4); - audblk->deltba[i][j] = bitstream_get(3); - } - } - } - } - - /* Check to see if there's any dummy info to get */ - if((audblk->skiple = bitstream_get(1))) { - uint16_t skip_data; - - audblk->skipl = bitstream_get(9); - - for (i = 0; i < audblk->skipl; i++) { - skip_data = bitstream_get(8); - } - } - - stats_print_audblk(bsi,audblk); -} diff --git a/ac3dec/parse.h b/ac3dec/parse.h deleted file mode 100644 index 6264fea1d..000000000 --- a/ac3dec/parse.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * parse.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -void parse_syncinfo(syncinfo_t *syncinfo,uint8_t *data); -void parse_audblk(bsi_t *bsi,audblk_t *audblk); -void parse_bsi(bsi_t *bsi); diff --git a/ac3dec/rematrix.c b/ac3dec/rematrix.c deleted file mode 100644 index f1df19b19..000000000 --- a/ac3dec/rematrix.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * rematrix.c - * - * Copyright (C) Aaron Holtzman - July 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include "ac3.h" -#include "ac3_internal.h" - - -#include "rematrix.h" - - -struct rematrix_band_s -{ - uint32_t start; - uint32_t end; -} rematrix_band[] = { - {13, 24}, - {25, 36}, - {37, 60}, - {61, 252} -}; - - -/** - * - **/ - -inline uint32_t min (uint32_t a, uint32_t b) -{ - return (a < b) ? a : b; -} - - -/** - * This routine simply does stereo remartixing for the 2 channel - * stereo mode - **/ - -void rematrix (audblk_t *audblk, stream_samples_t samples) -{ - uint32_t num_bands; - uint32_t start; - uint32_t end; - int i,j; - - if (!audblk->cplinu || audblk->cplbegf > 2) - num_bands = 4; - else if (audblk->cplbegf > 0) - num_bands = 3; - else - num_bands = 2; - - for (i=0; i < num_bands; i++) { - if (!audblk->rematflg[i]) - continue; - - start = rematrix_band[i].start; - end = min (rematrix_band[i].end ,12 * audblk->cplbegf + 36); - - for (j=start;j < end; j++) { - float left,right; - - left = samples[0][j] + samples[1][j]; - right = samples[0][j] - samples[1][j]; - samples[0][j] = left; - samples[1][j] = right; - } - } -} diff --git a/ac3dec/rematrix.h b/ac3dec/rematrix.h deleted file mode 100644 index 0be6528f6..000000000 --- a/ac3dec/rematrix.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * rematrix.h - * - * Copyright (C) Aaron Holtzman - July 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -void rematrix(audblk_t *audblk, stream_samples_t samples); diff --git a/ac3dec/sanity_check.c b/ac3dec/sanity_check.c deleted file mode 100644 index d475de14f..000000000 --- a/ac3dec/sanity_check.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * sanity_check.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include "ac3.h" -#include "ac3_internal.h" -#include "sanity_check.h" - - -/** - * - **/ - -void sanity_check_init(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk) -{ - syncinfo->magic = AC3_MAGIC_NUMBER; - bsi->magic = AC3_MAGIC_NUMBER; - audblk->magic1 = AC3_MAGIC_NUMBER; - audblk->magic2 = AC3_MAGIC_NUMBER; - audblk->magic3 = AC3_MAGIC_NUMBER; -} - - -/** - * - **/ - -int sanity_check(syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk) -{ - int i; - - if(syncinfo->magic != AC3_MAGIC_NUMBER) { - fprintf(stderr,"\n** Sanity check failed -- syncinfo magic number **"); - return -1; - } - - if(bsi->magic != AC3_MAGIC_NUMBER) { - fprintf(stderr,"\n** Sanity check failed -- bsi magic number **"); - return -1; - } - - if(audblk->magic1 != AC3_MAGIC_NUMBER) { - fprintf(stderr,"\n** Sanity check failed -- audblk magic number 1 **"); - return -1; - } - - if(audblk->magic2 != AC3_MAGIC_NUMBER) { - fprintf(stderr,"\n** Sanity check failed -- audblk magic number 2 **"); - return -1; - } - - if(audblk->magic3 != AC3_MAGIC_NUMBER) { - fprintf(stderr,"\n** Sanity check failed -- audblk magic number 3 **"); - return -1; - } - - for(i = 0;i < 5 ; i++) { - if (audblk->fbw_exp[i][255] !=0 || audblk->fbw_exp[i][254] !=0 || - audblk->fbw_exp[i][253] !=0) { - fprintf(stderr,"\n** Sanity check failed -- fbw_exp out of bounds **"); - return -1; - } - - if (audblk->fbw_bap[i][255] !=0 || audblk->fbw_bap[i][254] !=0 || - audblk->fbw_bap[i][253] !=0) { - fprintf(stderr,"\n** Sanity check failed -- fbw_bap out of bounds **"); - return -1; - } - - } - - if (audblk->cpl_exp[255] !=0 || audblk->cpl_exp[254] !=0 || - audblk->cpl_exp[253] !=0) { - fprintf(stderr,"\n** Sanity check failed -- cpl_exp out of bounds **"); - return -1; - } - - if (audblk->cpl_bap[255] !=0 || audblk->cpl_bap[254] !=0 || - audblk->cpl_bap[253] !=0) { - fprintf(stderr,"\n** Sanity check failed -- cpl_bap out of bounds **"); - return -1; - } - - if (audblk->cpl_flt[255] !=0 || audblk->cpl_flt[254] !=0 || - audblk->cpl_flt[253] !=0) { - fprintf(stderr,"\n** Sanity check failed -- cpl_mant out of bounds **"); - return -1; - } - - if ((audblk->cplinu == 1) && (audblk->cplbegf > (audblk->cplendf+2))) { - fprintf(stderr,"\n** Sanity check failed -- cpl params inconsistent **"); - return -1; - } - - for(i=0; i < bsi->nfchans; i++) { - if((audblk->chincpl[i] == 0) && (audblk->chbwcod[i] > 60)) { - fprintf(stderr,"\n** Sanity check failed -- chbwcod too big **"); - return -1; - } - } - - return 0; -} diff --git a/ac3dec/sanity_check.h b/ac3dec/sanity_check.h deleted file mode 100644 index ead9399c9..000000000 --- a/ac3dec/sanity_check.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * sanity_check.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#define AC3_MAGIC_NUMBER 0xdeadbeef - -void sanity_check_init (syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk); -int sanity_check (syncinfo_t *syncinfo, bsi_t *bsi, audblk_t *audblk); diff --git a/ac3dec/srfft.c b/ac3dec/srfft.c deleted file mode 100644 index 4cbb62954..000000000 --- a/ac3dec/srfft.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * srfft.c - * - * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - April 2000 - * - * 64 and 128 point split radix fft for ac3dec - * - * The algorithm is desribed in the book: - * "Computational Frameworks of the Fast Fourier Transform". - * - * The ideas and the the organization of code borrowed from djbfft written by - * D. J. Bernstein <djb@cr.py.to>. djbff can be found at - * http://cr.yp.to/djbfft.html. - * - * srfft.c is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * srfft.c is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdio.h> - -#include "srfft.h" -#include "srfftp.h" - -void fft_8 (complex_t *x); - -void fft_4(complex_t *x) -{ - /* delta_p = 1 here */ - /* x[k] = sum_{i=0..3} x[i] * w^{i*k}, w=e^{-2*pi/4} - */ - - register float yt_r, yt_i, yb_r, yb_i, u_r, u_i, vi_r, vi_i; - - yt_r = x[0].re; - yb_r = yt_r - x[2].re; - yt_r += x[2].re; - - u_r = x[1].re; - vi_i = x[3].re - u_r; - u_r += x[3].re; - - u_i = x[1].im; - vi_r = u_i - x[3].im; - u_i += x[3].im; - - yt_i = yt_r; - yt_i += u_r; - x[0].re = yt_i; - yt_r -= u_r; - x[2].re = yt_r; - yt_i = yb_r; - yt_i += vi_r; - x[1].re = yt_i; - yb_r -= vi_r; - x[3].re = yb_r; - - yt_i = x[0].im; - yb_i = yt_i - x[2].im; - yt_i += x[2].im; - - yt_r = yt_i; - yt_r += u_i; - x[0].im = yt_r; - yt_i -= u_i; - x[2].im = yt_i; - yt_r = yb_i; - yt_r += vi_i; - x[1].im = yt_r; - yb_i -= vi_i; - x[3].im = yb_i; -} - - -void fft_8 (complex_t *x) -{ - /* delta_p = diag{1, sqrt(i)} here */ - /* x[k] = sum_{i=0..7} x[i] * w^{i*k}, w=e^{-2*pi/8} - */ - register float wT1_r, wT1_i, wB1_r, wB1_i, wT2_r, wT2_i, wB2_r, wB2_i; - - wT1_r = x[1].re; - wT1_i = x[1].im; - wB1_r = x[3].re; - wB1_i = x[3].im; - - x[1] = x[2]; - x[2] = x[4]; - x[3] = x[6]; - fft_4(&x[0]); - - - /* x[0] x[4] */ - wT2_r = x[5].re; - wT2_r += x[7].re; - wT2_r += wT1_r; - wT2_r += wB1_r; - wT2_i = wT2_r; - wT2_r += x[0].re; - wT2_i = x[0].re - wT2_i; - x[0].re = wT2_r; - x[4].re = wT2_i; - - wT2_i = x[5].im; - wT2_i += x[7].im; - wT2_i += wT1_i; - wT2_i += wB1_i; - wT2_r = wT2_i; - wT2_r += x[0].im; - wT2_i = x[0].im - wT2_i; - x[0].im = wT2_r; - x[4].im = wT2_i; - - /* x[2] x[6] */ - wT2_r = x[5].im; - wT2_r -= x[7].im; - wT2_r += wT1_i; - wT2_r -= wB1_i; - wT2_i = wT2_r; - wT2_r += x[2].re; - wT2_i = x[2].re - wT2_i; - x[2].re = wT2_r; - x[6].re = wT2_i; - - wT2_i = x[5].re; - wT2_i -= x[7].re; - wT2_i += wT1_r; - wT2_i -= wB1_r; - wT2_r = wT2_i; - wT2_r += x[2].im; - wT2_i = x[2].im - wT2_i; - x[2].im = wT2_i; - x[6].im = wT2_r; - - - /* x[1] x[5] */ - wT2_r = wT1_r; - wT2_r += wB1_i; - wT2_r -= x[5].re; - wT2_r -= x[7].im; - wT2_i = wT1_i; - wT2_i -= wB1_r; - wT2_i -= x[5].im; - wT2_i += x[7].re; - - wB2_r = wT2_r; - wB2_r += wT2_i; - wT2_i -= wT2_r; - wB2_r *= HSQRT2; - wT2_i *= HSQRT2; - wT2_r = wB2_r; - wB2_r += x[1].re; - wT2_r = x[1].re - wT2_r; - - wB2_i = x[5].re; - x[1].re = wB2_r; - x[5].re = wT2_r; - - wT2_r = wT2_i; - wT2_r += x[1].im; - wT2_i = x[1].im - wT2_i; - wB2_r = x[5].im; - x[1].im = wT2_r; - x[5].im = wT2_i; - - /* x[3] x[7] */ - wT1_r -= wB1_i; - wT1_i += wB1_r; - wB1_r = wB2_i - x[7].im; - wB1_i = wB2_r + x[7].re; - wT1_r -= wB1_r; - wT1_i -= wB1_i; - wB1_r = wT1_r + wT1_i; - wB1_r *= HSQRT2; - wT1_i -= wT1_r; - wT1_i *= HSQRT2; - wB2_r = x[3].re; - wB2_i = wB2_r + wT1_i; - wB2_r -= wT1_i; - x[3].re = wB2_i; - x[7].re = wB2_r; - wB2_i = x[3].im; - wB2_r = wB2_i + wB1_r; - wB2_i -= wB1_r; - x[3].im = wB2_i; - x[7].im = wB2_r; -} - - -void fft_asmb(int k, complex_t *x, complex_t *wTB, - const complex_t *d, const complex_t *d_3) -{ - register complex_t *x2k, *x3k, *x4k, *wB; - register float a_r, a_i, a1_r, a1_i, u_r, u_i, v_r, v_i; - - x2k = x + 2 * k; - x3k = x2k + 2 * k; - x4k = x3k + 2 * k; - wB = wTB + 2 * k; - - TRANSZERO(x[0],x2k[0],x3k[0],x4k[0]); - TRANS(x[1],x2k[1],x3k[1],x4k[1],wTB[1],wB[1],d[1],d_3[1]); - - --k; - for(;;) { - TRANS(x[2],x2k[2],x3k[2],x4k[2],wTB[2],wB[2],d[2],d_3[2]); - TRANS(x[3],x2k[3],x3k[3],x4k[3],wTB[3],wB[3],d[3],d_3[3]); - if (!--k) break; - x += 2; - x2k += 2; - x3k += 2; - x4k += 2; - d += 2; - d_3 += 2; - wTB += 2; - wB += 2; - } - -} - -void fft_asmb16(complex_t *x, complex_t *wTB) -{ - register float a_r, a_i, a1_r, a1_i, u_r, u_i, v_r, v_i; - int k = 2; - - /* transform x[0], x[8], x[4], x[12] */ - TRANSZERO(x[0],x[4],x[8],x[12]); - - /* transform x[1], x[9], x[5], x[13] */ - TRANS(x[1],x[5],x[9],x[13],wTB[1],wTB[5],delta16[1],delta16_3[1]); - - /* transform x[2], x[10], x[6], x[14] */ - TRANSHALF_16(x[2],x[6],x[10],x[14]); - - /* transform x[3], x[11], x[7], x[15] */ - TRANS(x[3],x[7],x[11],x[15],wTB[3],wTB[7],delta16[3],delta16_3[3]); - -} - - -void fft_64p_c (complex_t *a) -{ - fft_8(&a[0]); fft_4(&a[8]); fft_4(&a[12]); - fft_asmb16(&a[0], &a[8]); - - fft_8(&a[16]), fft_8(&a[24]); - fft_asmb(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); - - fft_8(&a[32]); fft_4(&a[40]); fft_4(&a[44]); - fft_asmb16(&a[32], &a[40]); - - fft_8(&a[48]); fft_4(&a[56]); fft_4(&a[60]); - fft_asmb16(&a[48], &a[56]); - - fft_asmb(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); -} - - -void fft_128p_c (complex_t *a) -{ - fft_8(&a[0]); fft_4(&a[8]); fft_4(&a[12]); - fft_asmb16(&a[0], &a[8]); - - fft_8(&a[16]), fft_8(&a[24]); - fft_asmb(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); - - fft_8(&a[32]); fft_4(&a[40]); fft_4(&a[44]); - fft_asmb16(&a[32], &a[40]); - - fft_8(&a[48]); fft_4(&a[56]); fft_4(&a[60]); - fft_asmb16(&a[48], &a[56]); - - fft_asmb(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); - - fft_8(&a[64]); fft_4(&a[72]); fft_4(&a[76]); - /* fft_16(&a[64]); */ - fft_asmb16(&a[64], &a[72]); - - fft_8(&a[80]); fft_8(&a[88]); - - /* fft_32(&a[64]); */ - fft_asmb(4, &a[64], &a[80],&delta32[0], &delta32_3[0]); - - fft_8(&a[96]); fft_4(&a[104]), fft_4(&a[108]); - /* fft_16(&a[96]); */ - fft_asmb16(&a[96], &a[104]); - - fft_8(&a[112]), fft_8(&a[120]); - /* fft_32(&a[96]); */ - fft_asmb(4, &a[96], &a[112], &delta32[0], &delta32_3[0]); - - /* fft_128(&a[0]); */ - fft_asmb(16, &a[0], &a[64], &delta128[0], &delta128_3[0]); -} diff --git a/ac3dec/srfft.h b/ac3dec/srfft.h deleted file mode 100644 index 7916092a4..000000000 --- a/ac3dec/srfft.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * srfft.h - * - * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - April 2000 - * - * 64 and 128 point split radix fft for ac3dec - * - * The algorithm is desribed in the book: - * "Computational Frameworks of the Fast Fourier Transform". - * - * The ideas and the the organization of code borrowed from djbfft written by - * D. J. Bernstein <djb@cr.py.to>. djbff can be found at - * http://cr.yp.to/djbfft.html. - * - * srfft.h is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * srfft.h is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef SRFFT_H__ -#define SRFFT_H__ - -#include "cmplx.h" - -void fft_64p_c (complex_t *x); -void fft_128p_c (complex_t *x); - -#endif /* SRFFT_H__ */ diff --git a/ac3dec/srfft_kni.S b/ac3dec/srfft_kni.S deleted file mode 100644 index a42a41b14..000000000 --- a/ac3dec/srfft_kni.S +++ /dev/null @@ -1,289 +0,0 @@ -/* - * srfft_kni.S - * - * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - October 2000 - * - * - * srfft_kni.S is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * srfft_kni.S is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifdef __i386__ - -.section .rodata - .align 16 -hsqrt2: .float 0f0.707106781188 - .float 0f0.707106781188 - .float 0f-0.707106781188 - .float 0f-0.707106781188 -C_1: .float 0f-1.0 - .float 0f1.0 - .float 0f-1.0 - .float 0f1.0 - -.text - .align 4 -.global fft_4_kni - .type fft_4_kni, @function -fft_4_kni: - pushl %ebp - movl %esp, %ebp - movl 8(%ebp), %eax /* complex_t * */ - - movaps (%eax), %xmm0 /* x[1] | x[0] */ - movaps 16(%eax), %xmm2 /* x[3] | x[2] */ - movaps %xmm0, %xmm1 /* x[1] | x[0] */ - addps %xmm2, %xmm0 /* x[1] + x[3] | x[0] + x[2] */ - subps %xmm2, %xmm1 /* x[1] - x[3] | x[0] - x[2] */ - xorps %xmm6, %xmm6 - movhlps %xmm1, %xmm4 /* x[1] - x[3] */ - movhlps %xmm0, %xmm3 /* x[1] + x[3] */ - subss %xmm4, %xmm6 /* -(x[1] - x[3]).re */ - movlhps %xmm1, %xmm0 /* x[0] - x[2] | x[0] + x[2] */ - movss %xmm6, %xmm4 /* (x[1] - x[3]).im | (x[3]-x[1]).re */ - movaps %xmm0, %xmm2 /* x[0] - x[2] | x[0] + x[2] */ - shufps $0x14, %xmm4, %xmm3 /* -i*(x[2] - x[3] | x[2] + x[3] */ - addps %xmm3, %xmm0 - subps %xmm3, %xmm2 - movaps %xmm0, (%eax) - movaps %xmm2, 16(%eax) - - leave - ret - - - .align 4 -.global fft_8_kni - .type fft_8_kni, @function -fft_8_kni: - pushl %ebp - movl %esp, %ebp - movl 8(%ebp), %eax /* complext_t */ - - pushl %ebx - movlps (%eax), %xmm0 /* x[0] */ - movlps 32(%eax), %xmm1 /* x[4] */ - movhps 16(%eax), %xmm0 /* x[2] | x[0] */ - movhps 48(%eax), %xmm1 /* x[6] | x[4] */ - movaps %xmm0, %xmm2 /* x[2] | x[0] */ - xorps %xmm3, %xmm3 - addps %xmm1, %xmm0 /* x[2] + x[6] | x[0] + x[4] */ - subps %xmm1, %xmm2 /* x[2] - x[6] | x[0] - x[4] */ - movhlps %xmm0, %xmm5 /* x[2] + x[6] */ - movhlps %xmm2, %xmm4 - movlhps %xmm2, %xmm0 /* x[0] - x[4] | x[0] + x[4] */ - subss %xmm4, %xmm3 /* -(x[2]-x[6]).re */ - movaps %xmm0, %xmm7 /* x[0] - x[4] | x[0] + x[4] */ - movss %xmm3, %xmm4 /* (x[2]-x[6]).im | -(x[2]-x[6]).re */ - movlps 8(%eax), %xmm1 /* x[1] */ - shufps $0x14, %xmm4, %xmm5 /* -i*(x[2] - x[6]) | x[2] + x[6] */ - - addps %xmm5, %xmm0 /* yt */ - subps %xmm5, %xmm7 /* yb */ - - movhps 24(%eax), %xmm1 /* x[3] | x[1] */ - movl $hsqrt2, %ebx - movlps 40(%eax), %xmm2 /* x[5] */ - movhps 56(%eax), %xmm2 /* /x[7] | x[5] */ - movaps %xmm1, %xmm3 /* x[3] | x[1] */ - addps %xmm2, %xmm1 /* x[3] + x[7] | x[1] + x[5] */ - subps %xmm2, %xmm3 /* x[3] - x[7] | x[1] - x[5] */ - movaps (%ebx), %xmm4 /* -1/sqrt2 | -1/sqrt2 | 1/sqrt2 | 1/sqrt2 */ - movaps %xmm3, %xmm6 /* x[3] - x[7] | x[1] - x[5] */ - mulps %xmm4, %xmm3 - shufps $0xc8, %xmm4, %xmm4 /* -1/sqrt2 | 1/sqrt2 | -1/sqrt2 | 1/sqrt2 */ - shufps $0xb1, %xmm6, %xmm6 - mulps %xmm4, %xmm6 - addps %xmm3, %xmm6 /* (-1-i)/sqrt2 * (x[3]-x[7]) | (1-i)/sqrt2 * (x[1] - x[5] */ - movhlps %xmm1, %xmm5 /* x[3] + x[7] */ - movlhps %xmm6, %xmm1 /* (1+i)/sqrt2 * (x[1]-x[5]) | x[1]+x[5] */ - shufps $0xe4, %xmm6, %xmm5 /* (-1-i)/sqrt2 * (x[3]-x[7]) | x[3]+x[7] */ - movaps %xmm1, %xmm3 /* (1-i)/sqrt2 * (x[1]-x[5]) | x[1]+x[5] */ - movl $C_1, %ebx - addps %xmm5, %xmm1 /* u */ - subps %xmm5, %xmm3 /* v */ - movaps %xmm0, %xmm2 /* yb */ - movaps %xmm7, %xmm4 /* yt */ - movaps (%ebx), %xmm5 - mulps %xmm5, %xmm3 - addps %xmm1, %xmm0 /* yt + u */ - subps %xmm1, %xmm2 /* yt - u */ - shufps $0xb1, %xmm3, %xmm3 /* -i * v */ - movaps %xmm0, (%eax) - movaps %xmm2, 32(%eax) - addps %xmm3, %xmm4 /* yb - i*v */ - subps %xmm3, %xmm7 /* yb + i*v */ - movaps %xmm4, 16(%eax) - movaps %xmm7, 48(%eax) - - popl %ebx - leave - ret - - .align 4 -.global fft_asmb_kni - .type fft_asmb, @function -fft_asmb_kni: - pushl %ebp - movl %esp, %ebp - - subl $4, %esp - - pushl %eax - pushl %ebx - pushl %ecx - pushl %edx - pushl %esi - pushl %edi - - movl 8(%ebp), %ecx /* k */ - movl 12(%ebp), %eax /* x */ - movl %ecx, -4(%ebp) /* k */ - movl 16(%ebp), %ebx /* wT */ - movl 20(%ebp), %edx /* d */ - movl 24(%ebp), %esi /* d3 */ - shll $4, %ecx /* 16k */ - addl $8, %edx - leal (%eax, %ecx, 2), %edi - addl $8, %esi - - /* TRANSZERO and TRANS */ - movaps (%eax), %xmm0 /* x[1] | x[0] */ - movaps (%ebx), %xmm1 /* wT[1] | wT[0] */ - movaps (%ebx, %ecx), %xmm2 /* wB[1] | wB[0] */ - movlps (%edx), %xmm3 /* d */ - movlps (%esi), %xmm4 /* d3 */ - movhlps %xmm1, %xmm5 /* wT[1] */ - movhlps %xmm2, %xmm6 /* wB[1] */ - shufps $0x50, %xmm3, %xmm3 /* d[1].im | d[1].im | d[1].re | d[1].re */ - shufps $0x50, %xmm4, %xmm4 /* d3[1].im | d3[1].im | d3[i].re | d3[i].re */ - movlhps %xmm5, %xmm5 /* wT[1] | wT[1] */ - movlhps %xmm6, %xmm6 /* wB[1] | wB[1] */ - mulps %xmm3, %xmm5 - mulps %xmm4, %xmm6 - movhlps %xmm5, %xmm7 /* wT[1].im * d[1].im | wT[1].re * d[1].im */ - movlhps %xmm6, %xmm5 /* wB[1].im * d3[1].re | wB[1].re * d3[1].re | wT[1].im * d[1].re | wT[1].re * d[1].re */ - shufps $0xb1, %xmm6, %xmm7 /* wB[1].re * d3[1].im | wB[i].im * d3[1].im | wT[1].re * d[1].im | wT[1].im * d[1].im */ - movl $C_1, %edi - movaps (%edi), %xmm4 - mulps %xmm4, %xmm7 - addps %xmm7, %xmm5 /* wB[1] * d3[1] | wT[1] * d[1] */ - movlhps %xmm5, %xmm1 /* d[1] * wT[1] | wT[0] */ - shufps $0xe4, %xmm5, %xmm2 /* d3[1] * wB[1] | wB[0] */ - movaps %xmm1, %xmm3 /* d[1] * wT[1] | wT[0] */ - leal (%eax, %ecx, 2), %edi - addps %xmm2, %xmm1 /* u */ - subps %xmm2, %xmm3 /* v */ - mulps %xmm4, %xmm3 - movaps (%eax, %ecx), %xmm5 /* xk[1] | xk[0] */ - shufps $0xb1, %xmm3, %xmm3 /* -i * v */ - movaps %xmm0, %xmm2 /* x[1] | x[0] */ - movaps %xmm5, %xmm6 /* xk[1] | xk[0] */ - addps %xmm1, %xmm0 - subps %xmm1, %xmm2 - addps %xmm3, %xmm5 - subps %xmm3, %xmm6 - movaps %xmm0, (%eax) - movaps %xmm2, (%edi) - movaps %xmm5, (%eax, %ecx) - movaps %xmm6, (%edi, %ecx) - addl $16, %eax - addl $16, %ebx - addl $8, %edx - addl $8, %esi - decl -4(%ebp) - -.loop: - movaps (%ebx), %xmm0 /* wT[1] | wT[0] */ - movaps (%edx), %xmm1 /* d[1] | d[0] */ - - movaps (%ebx, %ecx), %xmm4 /* wB[1] | wB[0] */ - movaps (%esi), %xmm5 /* d3[1] | d3[0] */ - - movhlps %xmm0, %xmm2 /* wT[1] */ - movhlps %xmm1, %xmm3 /* d[1] */ - - movhlps %xmm4, %xmm6 /* wB[1] */ - movhlps %xmm5, %xmm7 /* d3[1] */ - - shufps $0x50, %xmm1, %xmm1 /* d[0].im | d[0].im | d[0].re | d[0].re */ - shufps $0x50, %xmm3, %xmm3 /* d[1].im | d[1].im | d[1].re | d[1].re */ - - movlhps %xmm0, %xmm0 /* wT[0] | wT[0] */ - shufps $0x50, %xmm5, %xmm5 /* d3[0].im | d3[0].im | d3[0].re | d3[0].re */ - movlhps %xmm2, %xmm2 /* wT[1] | wT[1] */ - shufps $0x50, %xmm7, %xmm7 /* d3[1].im | d3[1].im | d3[1].re | d3[1].re */ - - mulps %xmm1, %xmm0 /* d[0].im * wT[0].im | d[0].im * wT[0].re | d[0].re * wT[0].im | d[0].re * wT[0].re */ - mulps %xmm3, %xmm2 /* d[1].im * wT[1].im | d[1].im * wT[1].re | d[1].re * wT[1].im | d[1].re * wT[1].re */ - movlhps %xmm4, %xmm4 /* wB[0] | wB[0] */ - movlhps %xmm6, %xmm6 /* wB[1] | wB[1] */ - - movhlps %xmm0, %xmm1 /* d[0].im * wT[0].im | d[0].im * wT[0].re */ - movlhps %xmm2, %xmm0 /* d[1].re * wT[1].im | d[1].re * wT[1].re | d[0].re * wT[0].im | d[0].re * wT[0].re */ - mulps %xmm5, %xmm4 /* wB[0].im * d3[0].im | wB[0].re * d3[0].im | wB[0].im * d3[0].re | wB[0].re * d3[0].re */ - mulps %xmm7, %xmm6 /* wB[1].im * d3[1].im | wB[1].re * d3[1].im | wB[1].im * d3[1].re | wB[1].re * d3[1].re */ - shufps $0xb1, %xmm2, %xmm1 /* d[1].im * wT[1].re | d[1].im * wT[1].im | d[0].im * wT[0].re | d[0].im * wT[0].im */ - movl $C_1, %edi - movaps (%edi), %xmm3 /* 1.0 | -1.0 | 1.0 | -1.0 */ - - movhlps %xmm4, %xmm5 /* wB[0].im * d3[0].im | wB[0].re * d3[0].im */ - mulps %xmm3, %xmm1 /* d[1].im * wT[1].re | -d[1].im * wT[1].im | d[0].im * wT[0].re | -d[0].im * wT[0].im */ - movlhps %xmm6, %xmm4 /* wB[1].im * d3[1].re | wB[1].re * d3[1].re | wB[0].im * d3[0].re | wB[0].im * d3[0].re */ - addps %xmm1, %xmm0 /* wT[1] * d[1] | wT[0] * d[0] */ - - shufps $0xb1, %xmm6, %xmm5 /* wB[1].re * d3[1].im | wB[1].im * d3[1].im | wB[0].re * d3[0].im | wB[0].im * d3[0].im */ - mulps %xmm3, %xmm5 /* wB[1].re * d3[1].im | -wB[1].im * d3[1].im | wB[0].re * d3[0].im | -wB[0].im * d3[0].im */ - addps %xmm5, %xmm4 /* wB[1] * d3[1] | wB[0] * d3[0] */ - - movaps %xmm0, %xmm1 /* wT[1] * d[1] | wT[0] * d[0] */ - addps %xmm4, %xmm0 /* u */ - subps %xmm4, %xmm1 /* v */ - movaps (%eax), %xmm6 /* x[1] | x[0] */ - leal (%eax, %ecx, 2), %edi - mulps %xmm3, %xmm1 - addl $16, %ebx - addl $16, %esi - shufps $0xb1, %xmm1, %xmm1 /* -i * v */ - movaps (%eax, %ecx), %xmm7 /* xk[1] | xk[0] */ - movaps %xmm6, %xmm2 - movaps %xmm7, %xmm4 - addps %xmm0, %xmm6 - subps %xmm0, %xmm2 - movaps %xmm6, (%eax) - movaps %xmm2, (%edi) - addps %xmm1, %xmm7 - subps %xmm1, %xmm4 - addl $16, %edx - movaps %xmm7, (%eax, %ecx) - movaps %xmm4, (%edi, %ecx) - - addl $16, %eax - decl -4(%ebp) - jnz .loop - -.end: - popl %edi - popl %esi - popl %edx - popl %ecx - popl %ebx - popl %eax - - addl $4, %esp - - leave - ret -#endif diff --git a/ac3dec/srfft_kni.h b/ac3dec/srfft_kni.h deleted file mode 100644 index 6dc468e34..000000000 --- a/ac3dec/srfft_kni.h +++ /dev/null @@ -1,30 +0,0 @@ -/***** -* -* This file is part of the OMS program. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* -*****/ - -#ifndef __SRFF_KNI__ -#define __SRFF_KNI__ - -#include "cmplx.h" - -void fft_4_kni (complex_t *a); -void fft_8_kni (complex_t *a); -void fft_asmb_kni (int, complex_t*, complex_t *, complex_t *, complex_t*); - -#endif diff --git a/ac3dec/srfft_kni_c.c b/ac3dec/srfft_kni_c.c deleted file mode 100644 index d461110fc..000000000 --- a/ac3dec/srfft_kni_c.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * srfft_kni.c - * - * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - April 2000 - * - * 64 and 128 point split radix fft for ac3dec - * - * The algorithm is desribed in the book: - * "Computational Frameworks of the Fast Fourier Transform". - * - * The ideas and the the organization of code borrowed from djbfft written by - * D. J. Bernstein <djb@cr.py.to>. djbff can be found at - * http://cr.yp.to/djbfft.html. - * - * srfft.c is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * srfft.c is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifdef __i386__ - -#include <stdio.h> - -#include "srfft_kni.h" -#include "srfftp.h" - -void fft_64p_kni(complex_t *a) -{ - fft_8_kni(&a[0]); fft_4_kni(&a[8]); fft_4_kni(&a[12]); - fft_asmb_kni(2, &a[0], &a[8], &delta16[0], &delta16_3[0]); - - fft_8_kni(&a[16]), fft_8_kni(&a[24]); - fft_asmb_kni(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); - - fft_8_kni(&a[32]); fft_4_kni(&a[40]); fft_4_kni(&a[44]); - fft_asmb_kni(2, &a[32], &a[40], &delta16[0], &delta16_3[0]); - - fft_8_kni(&a[48]); fft_4_kni(&a[56]); fft_4_kni(&a[60]); - fft_asmb_kni(2, &a[48], &a[56], &delta16[0], &delta16_3[0]); - - fft_asmb_kni(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); -} - - -void fft_128p_kni(complex_t *a) -{ - fft_8_kni(&a[0]); fft_4_kni(&a[8]); fft_4_kni(&a[12]); - fft_asmb_kni(2, &a[0], &a[8], &delta16[0], &delta16_3[0]); - - fft_8_kni(&a[16]), fft_8_kni(&a[24]); - fft_asmb_kni(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); - - fft_8_kni(&a[32]); fft_4_kni(&a[40]); fft_4_kni(&a[44]); - fft_asmb_kni(2, &a[32], &a[40], &delta16[0], &delta16_3[0]); - - fft_8_kni(&a[48]); fft_4_kni(&a[56]); fft_4_kni(&a[60]); - fft_asmb_kni(2, &a[48], &a[56], &delta16[0], &delta16_3[0]); - - fft_asmb_kni(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); - - fft_8_kni(&a[64]); fft_4_kni(&a[72]); fft_4_kni(&a[76]); - /* fft_16(&a[64]); */ - fft_asmb_kni(2, &a[64], &a[72], &delta16[0], &delta16_3[0]); - - fft_8_kni(&a[80]); fft_8_kni(&a[88]); - - /* fft_32(&a[64]); */ - fft_asmb_kni(4, &a[64], &a[80],&delta32[0], &delta32_3[0]); - - fft_8_kni(&a[96]); fft_4_kni(&a[104]), fft_4_kni(&a[108]); - /* fft_16(&a[96]); */ - fft_asmb_kni(2, &a[96], &a[104], &delta16[0], &delta16_3[0]); - - fft_8_kni(&a[112]), fft_8_kni(&a[120]); - /* fft_32(&a[96]); */ - fft_asmb_kni(4, &a[96], &a[112], &delta32[0], &delta32_3[0]); - - /* fft_128(&a[0]); */ - fft_asmb_kni(16, &a[0], &a[64], &delta128[0], &delta128_3[0]); -} - -#endif diff --git a/ac3dec/srfftp.h b/ac3dec/srfftp.h deleted file mode 100644 index 6f4471530..000000000 --- a/ac3dec/srfftp.h +++ /dev/null @@ -1,305 +0,0 @@ - -/* - * srfftp.h - * - * Copyright (C) Yuqing Deng <Yuqing_Deng@brown.edu> - April 2000 - * - * 64 and 128 point split radix fft for ac3dec - * - * The algorithm is desribed in the book: - * "Computational Frameworks of the Fast Fourier Transform". - * - * The ideas and the the organization of code borrowed from djbfft written by - * D. J. Bernstein <djb@cr.py.to>. djbff can be found at - * http://cr.yp.to/djbfft.html. - * - * srfftp.h is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * srfftp.h is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef SRFFTP_H__ -#define SRFFTP_H__ - -#include "cmplx.h" - -static complex_t delta16[4] = - { {1.00000000000000, 0.00000000000000}, - {0.92387953251129, -0.38268343236509}, - {0.70710678118655, -0.70710678118655}, - {0.38268343236509, -0.92387953251129}}; - -static complex_t delta16_3[4] = - { {1.00000000000000, 0.00000000000000}, - {0.38268343236509, -0.92387953251129}, - {-0.70710678118655, -0.70710678118655}, - {-0.92387953251129, 0.38268343236509}}; - -static complex_t delta32[8] = - { {1.00000000000000, 0.00000000000000}, - {0.98078528040323, -0.19509032201613}, - {0.92387953251129, -0.38268343236509}, - {0.83146961230255, -0.55557023301960}, - {0.70710678118655, -0.70710678118655}, - {0.55557023301960, -0.83146961230255}, - {0.38268343236509, -0.92387953251129}, - {0.19509032201613, -0.98078528040323}}; - -static complex_t delta32_3[8] = - { {1.00000000000000, 0.00000000000000}, - {0.83146961230255, -0.55557023301960}, - {0.38268343236509, -0.92387953251129}, - {-0.19509032201613, -0.98078528040323}, - {-0.70710678118655, -0.70710678118655}, - {-0.98078528040323, -0.19509032201613}, - {-0.92387953251129, 0.38268343236509}, - {-0.55557023301960, 0.83146961230255}}; - -static complex_t delta64[16] = - { {1.00000000000000, 0.00000000000000}, - {0.99518472667220, -0.09801714032956}, - {0.98078528040323, -0.19509032201613}, - {0.95694033573221, -0.29028467725446}, - {0.92387953251129, -0.38268343236509}, - {0.88192126434836, -0.47139673682600}, - {0.83146961230255, -0.55557023301960}, - {0.77301045336274, -0.63439328416365}, - {0.70710678118655, -0.70710678118655}, - {0.63439328416365, -0.77301045336274}, - {0.55557023301960, -0.83146961230255}, - {0.47139673682600, -0.88192126434835}, - {0.38268343236509, -0.92387953251129}, - {0.29028467725446, -0.95694033573221}, - {0.19509032201613, -0.98078528040323}, - {0.09801714032956, -0.99518472667220}}; - -static complex_t delta64_3[16] = - { {1.00000000000000, 0.00000000000000}, - {0.95694033573221, -0.29028467725446}, - {0.83146961230255, -0.55557023301960}, - {0.63439328416365, -0.77301045336274}, - {0.38268343236509, -0.92387953251129}, - {0.09801714032956, -0.99518472667220}, - {-0.19509032201613, -0.98078528040323}, - {-0.47139673682600, -0.88192126434836}, - {-0.70710678118655, -0.70710678118655}, - {-0.88192126434835, -0.47139673682600}, - {-0.98078528040323, -0.19509032201613}, - {-0.99518472667220, 0.09801714032956}, - {-0.92387953251129, 0.38268343236509}, - {-0.77301045336274, 0.63439328416365}, - {-0.55557023301960, 0.83146961230255}, - {-0.29028467725446, 0.95694033573221}}; - -static complex_t delta128[32] = - { {1.00000000000000, 0.00000000000000}, - {0.99879545620517, -0.04906767432742}, - {0.99518472667220, -0.09801714032956}, - {0.98917650996478, -0.14673047445536}, - {0.98078528040323, -0.19509032201613}, - {0.97003125319454, -0.24298017990326}, - {0.95694033573221, -0.29028467725446}, - {0.94154406518302, -0.33688985339222}, - {0.92387953251129, -0.38268343236509}, - {0.90398929312344, -0.42755509343028}, - {0.88192126434836, -0.47139673682600}, - {0.85772861000027, -0.51410274419322}, - {0.83146961230255, -0.55557023301960}, - {0.80320753148064, -0.59569930449243}, - {0.77301045336274, -0.63439328416365}, - {0.74095112535496, -0.67155895484702}, - {0.70710678118655, -0.70710678118655}, - {0.67155895484702, -0.74095112535496}, - {0.63439328416365, -0.77301045336274}, - {0.59569930449243, -0.80320753148064}, - {0.55557023301960, -0.83146961230255}, - {0.51410274419322, -0.85772861000027}, - {0.47139673682600, -0.88192126434835}, - {0.42755509343028, -0.90398929312344}, - {0.38268343236509, -0.92387953251129}, - {0.33688985339222, -0.94154406518302}, - {0.29028467725446, -0.95694033573221}, - {0.24298017990326, -0.97003125319454}, - {0.19509032201613, -0.98078528040323}, - {0.14673047445536, -0.98917650996478}, - {0.09801714032956, -0.99518472667220}, - {0.04906767432742, -0.99879545620517}}; - -static complex_t delta128_3[32] = - { {1.00000000000000, 0.00000000000000}, - {0.98917650996478, -0.14673047445536}, - {0.95694033573221, -0.29028467725446}, - {0.90398929312344, -0.42755509343028}, - {0.83146961230255, -0.55557023301960}, - {0.74095112535496, -0.67155895484702}, - {0.63439328416365, -0.77301045336274}, - {0.51410274419322, -0.85772861000027}, - {0.38268343236509, -0.92387953251129}, - {0.24298017990326, -0.97003125319454}, - {0.09801714032956, -0.99518472667220}, - {-0.04906767432742, -0.99879545620517}, - {-0.19509032201613, -0.98078528040323}, - {-0.33688985339222, -0.94154406518302}, - {-0.47139673682600, -0.88192126434836}, - {-0.59569930449243, -0.80320753148065}, - {-0.70710678118655, -0.70710678118655}, - {-0.80320753148065, -0.59569930449243}, - {-0.88192126434835, -0.47139673682600}, - {-0.94154406518302, -0.33688985339222}, - {-0.98078528040323, -0.19509032201613}, - {-0.99879545620517, -0.04906767432742}, - {-0.99518472667220, 0.09801714032956}, - {-0.97003125319454, 0.24298017990326}, - {-0.92387953251129, 0.38268343236509}, - {-0.85772861000027, 0.51410274419322}, - {-0.77301045336274, 0.63439328416365}, - {-0.67155895484702, 0.74095112535496}, - {-0.55557023301960, 0.83146961230255}, - {-0.42755509343028, 0.90398929312344}, - {-0.29028467725446, 0.95694033573221}, - {-0.14673047445536, 0.98917650996478}}; - -#define HSQRT2 0.707106781188; - -#define TRANSZERO(A0,A4,A8,A12) { \ - u_r = wTB[0].re; \ - v_i = u_r - wTB[k*2].re; \ - u_r += wTB[k*2].re; \ - u_i = wTB[0].im; \ - v_r = wTB[k*2].im - u_i; \ - u_i += wTB[k*2].im; \ - a_r = A0.re; \ - a_i = A0.im; \ - a1_r = a_r; \ - a1_r += u_r; \ - A0.re = a1_r; \ - a_r -= u_r; \ - A8.re = a_r; \ - a1_i = a_i; \ - a1_i += u_i; \ - A0.im = a1_i; \ - a_i -= u_i; \ - A8.im = a_i; \ - a1_r = A4.re; \ - a1_i = A4.im; \ - a_r = a1_r; \ - a_r -= v_r; \ - A4.re = a_r; \ - a1_r += v_r; \ - A12.re = a1_r; \ - a_i = a1_i; \ - a_i -= v_i; \ - A4.im = a_i; \ - a1_i += v_i; \ - A12.im = a1_i; \ - } - -#define TRANSHALF_16(A2,A6,A10,A14) {\ - u_r = wTB[2].re; \ - a_r = u_r; \ - u_i = wTB[2].im; \ - u_r += u_i; \ - u_i -= a_r; \ - a_r = wTB[6].re; \ - a1_r = a_r; \ - a_i = wTB[6].im; \ - a_r = a_i - a_r; \ - a_i += a1_r; \ - v_i = u_r - a_r; \ - u_r += a_r; \ - v_r = u_i + a_i; \ - u_i -= a_i; \ - v_i *= HSQRT2; \ - v_r *= HSQRT2; \ - u_r *= HSQRT2; \ - u_i *= HSQRT2; \ - a_r = A2.re; \ - a_i = A2.im; \ - a1_r = a_r; \ - a1_r += u_r; \ - A2.re = a1_r; \ - a_r -= u_r; \ - A10.re = a_r; \ - a1_i = a_i; \ - a1_i += u_i; \ - A2.im = a1_i; \ - a_i -= u_i; \ - A10.im = a_i; \ - a1_r = A6.re; \ - a1_i = A6.im; \ - a_r = a1_r; \ - a1_r += v_r; \ - A6.re = a1_r; \ - a_r -= v_r; \ - A14.re = a_r; \ - a_i = a1_i; \ - a1_i -= v_i; \ - A6.im = a1_i; \ - a_i += v_i; \ - A14.im = a_i; \ - } - -#define TRANS(A1,A5,A9,A13,WT,WB,D,D3) { \ - u_r = WT.re; \ - a_r = u_r; \ - a_r *= D.im; \ - u_r *= D.re; \ - a_i = WT.im; \ - a1_i = a_i; \ - a1_i *= D.re; \ - a_i *= D.im; \ - u_r -= a_i; \ - u_i = a_r; \ - u_i += a1_i; \ - a_r = WB.re; \ - a1_r = a_r; \ - a1_r *= D3.re; \ - a_r *= D3.im; \ - a_i = WB.im; \ - a1_i = a_i; \ - a_i *= D3.re; \ - a1_i *= D3.im; \ - a1_r -= a1_i; \ - a_r += a_i; \ - v_i = u_r - a1_r; \ - u_r += a1_r; \ - v_r = a_r - u_i; \ - u_i += a_r; \ - a_r = A1.re; \ - a_i = A1.im; \ - a1_r = a_r; \ - a1_r += u_r; \ - A1.re = a1_r; \ - a_r -= u_r; \ - A9.re = a_r; \ - a1_i = a_i; \ - a1_i += u_i; \ - A1.im = a1_i; \ - a_i -= u_i; \ - A9.im = a_i; \ - a1_r = A5.re; \ - a1_i = A5.im; \ - a_r = a1_r; \ - a1_r -= v_r; \ - A5.re = a1_r; \ - a_r += v_r; \ - A13.re = a_r; \ - a_i = a1_i; \ - a1_i -= v_i; \ - A5.im = a1_i; \ - a_i += v_i; \ - A13.im = a_i; \ - } - -#endif diff --git a/ac3dec/stats.c b/ac3dec/stats.c deleted file mode 100644 index 4bdad09a1..000000000 --- a/ac3dec/stats.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * stats.c - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <stdlib.h> -#include <stdio.h> -//#include "config.h" -#include "ac3.h" -#include "ac3_internal.h" - - -#include "stats.h" -#include "debug.h" - -#if !defined (__GNUC__) || defined (DEBUG) -static const char *service_ids[8] = -{ - "CM","ME","VI","HI", - "D", "C","E", "VO" -}; -#endif - -struct mixlev_s -{ - float clev; - char *desc; -}; - -static const struct mixlev_s cmixlev_tbl[4] = -{ - {0.707, "(-3.0 dB)"}, {0.595, "(-4.5 dB)"}, - {0.500, "(-6.0 dB)"}, {1.0, "Invalid"} -}; - -static const struct mixlev_s smixlev_tbl[4] = -{ - {0.707, "(-3.0 dB)"}, {0.500, "(-6.0 dB)"}, - { 0.0, "off "}, { 1.0, "Invalid"} -}; - -static const char *language[128] = -{ - "unknown", "Albanian", "Breton", "Catalan", "Croatian", "Welsh", "Czech", "Danish", - "German", "English", "Spanish", "Esperanto", "Estonian", "Basque", "Faroese", "French", - "Frisian", "Irish", "Gaelic", "Galician", "Icelandic", "Italian", "Lappish", "Latin", - "Latvian", "Luxembourgian", "Lithuanian", "Hungarian", "Maltese", "Dutch", "Norwegian", "Occitan", - "Polish", "Portugese", "Romanian", "Romansh", "Serbian", "Slovak", "Slovene", "Finnish", - "Swedish", "Turkish", "Flemish", "Walloon", "0x2c", "0x2d", "0x2e", "0x2f", - "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", - "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "0x3f", - "background", "0x41", "0x42", "0x43", "0x44", "Zulu", "Vietnamese", "Uzbek", - "Urdu", "Ukrainian", "Thai", "Telugu", "Tatar", "Tamil", "Tadzhik", "Swahili", - "Sranan Tongo", "Somali", "Sinhalese", "Shona", "Serbo-Croat", "Ruthenian", "Russian", "Quechua", - "Pustu", "Punjabi", "Persian", "Papamiento", "Oriya", "Nepali", "Ndebele", "Marathi", - "Moldavian", "Malaysian", "Malagasay", "Macedonian", "Laotian", "Korean", "Khmer", "Kazakh", - "Kannada", "Japanese", "Indonesian", "Hindi", "Hebrew", "Hausa", "Gurani", "Gujurati", - "Greek", "Georgian", "Fulani", "Dari", "Churash", "Chinese", "Burmese", "Bulgarian", - "Bengali", "Belorussian", "Bambora", "Azerbijani", "Assamese", "Armenian", "Arabic", "Amharic" -}; - - -void stats_print_banner(syncinfo_t *syncinfo,bsi_t *bsi) -{ - // fprintf(stdout,PACKAGE"-"VERSION" (C) 2000 Aaron Holtzman (aholtzma@ess.engr.uvic.ca)\n"); - - fprintf(stdout,"%d.%d Mode ",bsi->nfchans,bsi->lfeon); - fprintf(stdout,"%2.1f KHz",syncinfo->sampling_rate * 1e-3); - fprintf(stdout,"%4d kbps ",syncinfo->bit_rate); - if (bsi->langcode && (bsi->langcod < 128)) - fprintf(stdout,"%s ", language[bsi->langcod]); - - switch(bsi->bsmod) { - case 0: - fprintf(stdout,"Complete Main Audio Service"); - break; - case 1: - fprintf(stdout,"Music and Effects Audio Service"); - case 2: - fprintf(stdout,"Visually Impaired Audio Service"); - break; - case 3: - fprintf(stdout,"Hearing Impaired Audio Service"); - break; - case 4: - fprintf(stdout,"Dialogue Audio Service"); - break; - case 5: - fprintf(stdout,"Commentary Audio Service"); - break; - case 6: - fprintf(stdout,"Emergency Audio Service"); - break; - case 7: - fprintf(stdout,"Voice Over Audio Service"); - break; - } - fprintf(stdout,"\n"); -} - - -void stats_print_syncinfo (syncinfo_t *syncinfo) -{ - dprintf("(syncinfo) "); - - switch (syncinfo->fscod) { - case 2: - dprintf("32 KHz "); - break; - case 1: - dprintf("44.1 KHz "); - break; - case 0: - dprintf("48 KHz "); - break; - default: - dprintf("Invalid sampling rate "); - break; - } - - dprintf("%4d kbps %4d words per frame\n",syncinfo->bit_rate, - syncinfo->frame_size); - -} - - -void stats_print_bsi(bsi_t *bsi) { - dprintf("(bsi) "); - dprintf("%s",service_ids[bsi->bsmod]); - dprintf(" %d.%d Mode ",bsi->nfchans,bsi->lfeon); - if ((bsi->acmod & 0x1) && (bsi->acmod != 0x1)) - dprintf(" Centre Mix Level %s ",cmixlev_tbl[bsi->cmixlev].desc); - if (bsi->acmod & 0x4) - dprintf(" Sur Mix Level %s ",smixlev_tbl[bsi->cmixlev].desc); - dprintf("\n"); - -} - - -char *exp_strat_tbl[4] = {"R ","D15 ","D25 ","D45 "}; - -void stats_print_audblk(bsi_t *bsi,audblk_t *audblk) { - uint32_t i; - - dprintf("(audblk) "); - dprintf("%s ",audblk->cplinu ? "cpl on " : "cpl off"); - dprintf("%s ",audblk->baie? "bai " : " "); - dprintf("%s ",audblk->snroffste? "snroffst " : " "); - dprintf("%s ",audblk->deltbaie? "deltba " : " "); - dprintf("%s ",audblk->phsflginu? "phsflg " : " "); - dprintf("(%s %s %s %s %s) ",exp_strat_tbl[audblk->chexpstr[0]], - exp_strat_tbl[audblk->chexpstr[1]],exp_strat_tbl[audblk->chexpstr[2]], - exp_strat_tbl[audblk->chexpstr[3]],exp_strat_tbl[audblk->chexpstr[4]]); - dprintf("["); - for(i=0;i<bsi->nfchans;i++) - dprintf("%1d",audblk->blksw[i]); - dprintf("]"); - - dprintf("\n"); -} diff --git a/ac3dec/stats.h b/ac3dec/stats.h deleted file mode 100644 index 8a9ecb69b..000000000 --- a/ac3dec/stats.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * stats.h - * - * Copyright (C) Aaron Holtzman - May 1999 - * - * This file is part of ac3dec, a free Dolby AC-3 stream decoder. - * - * ac3dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * ac3dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -void stats_print_syncinfo(syncinfo_t *syncinfo); -void stats_print_bsi(bsi_t *bsi); -void stats_print_audblk(bsi_t *bsi,audblk_t *audblk); -void stats_print_banner(syncinfo_t *syncinfo,bsi_t *bsi); diff --git a/channels.conf b/channels.conf index 8d58e61d9..4642edc51 100644 --- a/channels.conf +++ b/channels.conf @@ -4,7 +4,7 @@ Pro-7:12480:v:0:27500:255:256;257:32:0:898 RTL2:12188:h:0:27500:166:128:68:0:12020 ARD:11837:h:0:27500:101:102:104:0:28106 BR3:11837:h:0:27500:201:202:204:0:28107 -Hessen-3:11837:h:0:27500:301:302:0:0:28108 +Hessen-3:11837:h:0:27500:301:302:304:0:28108 N3:12110:h:0:27500:2401:2402:2404:0:28224 SR3:11837:h:0:27500:501:502:504:0:28110 WDR:11837:h:0:27500:601:602:0:0:28111 diff --git a/config.c b/config.c index 8b5c454fe..213fe2cfe 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.83 2002/02/10 11:39:00 kls Exp $ + * $Id: config.c 1.87 2002/02/24 11:59:14 kls Exp $ */ #include "config.h" @@ -323,7 +323,7 @@ cTimer::cTimer(bool Instant) { startTime = stopTime = 0; recording = pending = false; - active = Instant; + active = Instant ? taActInst : taInactive; cChannel *ch = Channels.GetByNumber(cDvbApi::CurrentChannel()); channel = ch ? ch->number : 0; time_t t = time(NULL); @@ -338,6 +338,7 @@ cTimer::cTimer(bool Instant) priority = Setup.DefaultPriority; lifetime = Setup.DefaultLifetime; *file = 0; + firstday = 0; summary = NULL; if (Instant && ch) snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : ch->name); @@ -367,6 +368,7 @@ cTimer::cTimer(const cEventInfo *EventInfo) const char *Title = EventInfo->GetTitle(); if (!isempty(Title)) strn0cpy(file, EventInfo->GetTitle(), sizeof(file)); + firstday = 0; summary = NULL; } @@ -395,7 +397,7 @@ const char *cTimer::ToText(cTimer *Timer) delete buffer; strreplace(Timer->file, ':', '|'); strreplace(Timer->summary, '\n', '|'); - asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); + asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day, Timer->firstday), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); strreplace(Timer->summary, '|', '\n'); strreplace(Timer->file, '|', ':'); return buffer; @@ -411,20 +413,38 @@ int cTimer::TimeToInt(int t) return (t / 100 * 60 + t % 100) * 60; } -int cTimer::ParseDay(const char *s) +int cTimer::ParseDay(const char *s, time_t *FirstDay) { char *tail; int d = strtol(s, &tail, 10); + if (FirstDay) + *FirstDay = 0; if (tail && *tail) { d = 0; if (tail == s) { - if (strlen(s) == 7) { + const char *first = strchr(s, '@'); + int l = first ? first - s : strlen(s); + if (l == 7) { for (const char *p = s + 6; p >= s; p--) { - d <<= 1; - d |= (*p != '-'); - } + d <<= 1; + d |= (*p != '-'); + } d |= 0x80000000; } + if (FirstDay && first) { + ++first; + if (strlen(first) == 10) { + struct tm tm_r; + if (3 == sscanf(first, "%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) { + tm_r.tm_year -= 1900; + tm_r.tm_mon--; + tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0; + *FirstDay = mktime(&tm_r); + } + } + else + d = 0; + } } } else if (d < 1 || d > 31) @@ -432,24 +452,40 @@ int cTimer::ParseDay(const char *s) return d; } -const char *cTimer::PrintDay(int d) +const char *cTimer::PrintDay(int d, time_t FirstDay) { - static char buffer[8]; +#define DAYBUFFERSIZE 32 + static char buffer[DAYBUFFERSIZE]; if ((d & 0x80000000) != 0) { char *b = buffer; const char *w = tr("MTWTFSS"); - *b = 0; while (*w) { *b++ = (d & 1) ? *w : '-'; d >>= 1; w++; } + if (FirstDay) { + struct tm tm_r; + localtime_r(&FirstDay, &tm_r); + b += strftime(b, DAYBUFFERSIZE - (b - buffer), "@%Y-%m-%d", &tm_r); + } + *b = 0; } else sprintf(buffer, "%d", d); return buffer; } +const char *cTimer::PrintFirstDay(void) +{ + if (firstday) { + const char *s = PrintDay(day, firstday); + if (strlen(s) == 18) + return s + 8; + } + return ""; // not NULL, so the caller can always use the result +} + bool cTimer::Parse(const char *s) { char *buffer1 = NULL; @@ -477,7 +513,7 @@ bool cTimer::Parse(const char *s) summary = NULL; } //TODO add more plausibility checks - day = ParseDay(buffer1); + day = ParseDay(buffer1, &firstday); strn0cpy(file, buffer2, MaxFileName); strreplace(file, '|', ':'); strreplace(summary, '|', '\n'); @@ -563,13 +599,17 @@ bool cTimer::Matches(time_t t) if (DayMatches(t0)) { time_t a = SetTime(t0, begin); time_t b = a + length; - if (t <= b) { + if ((!firstday || a >= firstday) && t <= b) { startTime = a; stopTime = b; + if (t >= firstday) + firstday = 0; break; } } } + if (!startTime) + startTime = firstday; // just to have something that's more than a week in the future return active && startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers } @@ -598,6 +638,11 @@ void cTimer::SetPending(bool Pending) pending = Pending; } +void cTimer::SkipToday(void) +{ + firstday = IncDay(SetTime(recording ? StartTime() : time(NULL), 0), 1); +} + // --- cCommand ------------------------------------------------------------- char *cCommand::result = NULL; @@ -865,6 +910,7 @@ cSetup::cSetup(void) UseSubtitle = 1; RecordingDirs = 1; VideoFormat = VIDEO_FORMAT_4_3; + RecordDolbyDigital = 1; ChannelInfoPos = 0; OSDwidth = 52; OSDheight = 18; @@ -910,6 +956,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "RecordDolbyDigital")) RecordDolbyDigital = atoi(Value); else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); @@ -947,7 +994,6 @@ bool cSetup::Load(const char *FileName) if (*buffer != '#' && !Parse(buffer)) { esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); result = false; - break; } } } @@ -990,6 +1036,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "UseSubtitle = %d\n", UseSubtitle); fprintf(f, "RecordingDirs = %d\n", RecordingDirs); fprintf(f, "VideoFormat = %d\n", VideoFormat); + fprintf(f, "RecordDolbyDigital = %d\n", RecordDolbyDigital); fprintf(f, "ChannelInfoPos = %d\n", ChannelInfoPos); fprintf(f, "OSDwidth = %d\n", OSDwidth); fprintf(f, "OSDheight = %d\n", OSDheight); diff --git a/config.h b/config.h index e2e2897fb..35f1590c0 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.95 2002/02/10 15:44:40 kls Exp $ + * $Id: config.h 1.99 2002/02/24 13:39:47 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.99" +#define VDRVERSION "1.0.0pre1" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -119,6 +119,12 @@ class cChannel : public cListObject { bool Switch(cDvbApi *DvbApi = NULL, bool Log = true); }; +enum eTimerActive { taInactive = 0, + taActive = 1, + taInstant = 2, + taActInst = (taActive | taInstant) + }; + class cTimer : public cListObject { private: time_t startTime, stopTime; @@ -135,6 +141,7 @@ class cTimer : public cListObject { int priority; int lifetime; char file[MaxFileName]; + time_t firstday; char *summary; cTimer(bool Instant = false); cTimer(const cEventInfo *EventInfo); @@ -148,17 +155,19 @@ class cTimer : public cListObject { int GetMDay(time_t t); int GetWDay(time_t t); bool DayMatches(time_t t); - time_t IncDay(time_t t, int Days); - time_t SetTime(time_t t, int SecondsFromMidnight); + static time_t IncDay(time_t t, int Days); + static time_t SetTime(time_t t, int SecondsFromMidnight); char *SetFile(const char *File); bool Matches(time_t t = 0); time_t StartTime(void); time_t StopTime(void); void SetRecording(bool Recording); void SetPending(bool Pending); + void SkipToday(void); + const char *PrintFirstDay(void); static int TimeToInt(int t); - static int ParseDay(const char *s); - static const char *PrintDay(int d); + static int ParseDay(const char *s, time_t *FirstDay = NULL); + static const char *PrintDay(int d, time_t FirstDay = 0); }; class cCommand : public cListObject { @@ -321,6 +330,7 @@ class cSetup { int UseSubtitle; int RecordingDirs; int VideoFormat; + int RecordDolbyDigital; int ChannelInfoPos; int OSDwidth, OSDheight; int OSDMessageTime; diff --git a/dvbapi.c b/dvbapi.c index 314d91f6c..55bc5731d 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,14 +4,9 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * DVD support initially written by Andreas Schultz <aschultz@warp10.net> - * based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si> - * - * $Id: dvbapi.c 1.147 2002/02/02 13:04:00 kls Exp $ + * $Id: dvbapi.c 1.152 2002/02/24 12:53:51 kls Exp $ */ -//#define DVDDEBUG 1 - #include "dvbapi.h" #include <dirent.h> #include <errno.h> @@ -26,13 +21,6 @@ extern "C" { #include <sys/stat.h> #include <sys/time.h> #include <unistd.h> - -#ifdef DVDSUPPORT -extern "C" { -#include "ac3dec/ac3.h" -} -#endif //DVDSUPPORT - #include "config.h" #include "recording.h" #include "remux.h" @@ -1320,865 +1308,6 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) return replayFile >= 0; } -#ifdef DVDSUPPORT - -#define SYSTEM_HEADER 0xBB -#define PROG_STREAM_MAP 0xBC -#ifndef PRIVATE_STREAM1 -#define PRIVATE_STREAM1 0xBD -#endif -#define PADDING_STREAM 0xBE -#ifndef PRIVATE_STREAM2 -#define PRIVATE_STREAM2 0xBF -#endif -#define AUDIO_STREAM_S 0xC0 -#define AUDIO_STREAM_E 0xDF -#define VIDEO_STREAM_S 0xE0 -#define VIDEO_STREAM_E 0xEF -#define ECM_STREAM 0xF0 -#define EMM_STREAM 0xF1 -#define DSM_CC_STREAM 0xF2 -#define ISO13522_STREAM 0xF3 -#define PROG_STREAM_DIR 0xFF - -#define cOPENDVD 0 -#define cOPENTITLE 1 -#define cOPENCHAPTER 2 -#define cOUTCELL 3 -#define cREADFRAME 4 -#define cOUTPACK 5 -#define cOUTFRAMES 6 - -// --- cAC3toPCM ------------------------------------------------------------- - -class cAC3toPCM { -private: - enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat; - uchar *ac3data; - int ac3inp; - int ac3outp; -public: - cAC3toPCM(void); - ~cAC3toPCM(); - void Clear(void); - void Put(unsigned char *sector, int length); - cFrame *Get(int size, uchar PTSflags = 0, uchar *PTSdata = 0); - }; - -cAC3toPCM::cAC3toPCM(void) -{ - ac3dec_init(); - ac3data = new uchar[AC3_BUFFER_SIZE]; - Clear(); -} - -cAC3toPCM::~cAC3toPCM() -{ - delete ac3data; -} - -void cAC3toPCM::Clear(void) -{ - ac3stat = AC3_START; - ac3outp = ac3inp = 0; -} - -void cAC3toPCM::Put(unsigned char *sector, int length) -{ - ac3dec_decode_data(sector, sector + length, ac3stat == AC3_START, &ac3inp, &ac3outp, (char *)ac3data); - ac3stat = AC3_PLAY; -} - -// data=PCM samples, 16 bit, LSB first, 48kHz, stereo -cFrame *cAC3toPCM::Get(int size, uchar PTSflags, uchar *PTSdata) -{ - if (ac3inp == ac3outp) - return NULL; - -#define MAXSIZE 2022 - - uchar buffer[2048]; - uchar *data; - - if (size > 0) { - int p_size = (size > MAXSIZE) ? MAXSIZE : size; - int length = 10; // default header bytes - int header = 0; - - switch (PTSflags) { - case 2: header = 5; // additional header bytes - break; - case 3: header = 10; - break; - default: header = 0; - } - - length += header; - - buffer[0] = 0x00; - buffer[1] = 0x00; - buffer[2] = 0x01; - buffer[3] = PRIVATE_STREAM1; - - buffer[6] = 0x80; - buffer[7] = PTSflags << 6; - buffer[8] = header; - - if (header) - memcpy(&buffer[9], (void *)PTSdata, header); - - // add data - data = buffer + 9 + header + 7; - int cnt = 0; - while (p_size) { - if (ac3outp != ac3inp) { // data in the buffer - data[cnt ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder (the "xor" (^) is a swab!) - p_size--; - cnt++; - length++; - ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE; - } - else - break; - } - - data = buffer + 9 + header; - data[0] = aLPCM; // substream ID - data[1] = 0x00; // other stuff (see DVB specs), ignored by driver - data[2] = 0x00; - data[3] = 0x00; - data[4] = 0x00; - data[5] = 0x00; - data[6] = 0x00; - - buffer[4] = (length >> 8) & 0xff; - buffer[5] = length & 0xff; - - length += 6; - - return new cFrame(buffer, length); - } - return NULL; -} - -// --- cDVDplayBuffer -------------------------------------------------------- - -class cDVDplayBuffer : public cPlayBuffer { -private: - cAC3toPCM AC3toPCM; - uchar audioTrack; - - cDVD *dvd;//XXX necessary??? - - int titleid; - int chapid; - int angle; - dvd_file_t *title; - ifo_handle_t *vmg_file; - ifo_handle_t *vts_file; - - int doplay; - int cyclestate; - int prevcycle; - int skipCnt; - - tt_srpt_t *tt_srpt; - vts_ptt_srpt_t *vts_ptt_srpt; - pgc_t *cur_pgc; - dsi_t dsi_pack; - unsigned int next_vobu; - unsigned int prev_vobu; - unsigned int next_ilvu_start; - unsigned int cur_output_size; - unsigned int min_output_size; - unsigned int pktcnt; - int pgc_id; - int start_cell; - int next_cell; - int prev_cell; - int cur_cell; - unsigned int cur_pack; - int ttn; - int pgn; - - uchar *data; - - int logAudioTrack; - int maxAudioTrack; - - int is_nav_pack(unsigned char *buffer); - void Close(void); - virtual void Empty(bool Block = false); - int decode_packet(unsigned char *sector, bool trickmode); - int ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType); - bool PacketStart(uchar **Data, int len); - int GetPacketType(const uchar *Data); - int GetStuffingLen(const uchar *Data); - int GetPacketLength(const uchar *Data); - int GetPESHeaderLength(const uchar *Data); - void handleAC3(unsigned char *sector, int length, uchar PTSflags, uchar *PTSdata); - unsigned int getAudioStream(unsigned int StreamId); - void setChapid(void); - void NextState(int State) { prevcycle = cyclestate; cyclestate = State; } -protected: - virtual void Input(void); -public: - cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title); - virtual ~cDVDplayBuffer(); - virtual int SkipFrames(int Frames); - virtual void SkipSeconds(int Seconds); - virtual void Goto(int Position, bool Still = false); - virtual void GetIndex(int &Current, int &Total, bool SnapToIFrame = false); - virtual void ToggleAudioTrack(void); - }; - -cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title) -:cPlayBuffer(DvbApi, VideoDev, AudioDev) -{ - dvd = DvD; - titleid = title; - chapid = 0; - angle = 0; - cyclestate = cOPENDVD; - prevcycle = 0; - skipCnt = 0; - logAudioTrack = 0; - canToggleAudioTrack = true;//XXX determine from cDVD! - data = new uchar[1024 * DVD_VIDEO_LB_LEN]; - canDoTrickMode = true; - skipAC3bytes = true; - dvbApi->SetModeReplay(); - Start(); -} - -cDVDplayBuffer::~cDVDplayBuffer() -{ - Stop(); - Close(); - dvbApi->SetModeNormal(false); - delete data; -} - -unsigned int cDVDplayBuffer::getAudioStream(unsigned int StreamId) -{ - if (cyclestate < cOPENCHAPTER || StreamId > 7) - return 0; - if (!(cur_pgc->audio_control[StreamId] & 0x8000)) - return 0; - int track = (cur_pgc->audio_control[StreamId] >> 8) & 0x07; - return dvd->getAudioTrack(track) | track; -} - -void cDVDplayBuffer::ToggleAudioTrack(void) -{ - unsigned int newTrack; - - if (CanToggleAudioTrack() && maxAudioTrack != 0) { - logAudioTrack = (logAudioTrack + 1) % maxAudioTrack; - if ((newTrack = getAudioStream(logAudioTrack)) != 0) - audioTrack = newTrack; -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVB: Audio Stream ID changed to: %x", audioTrack); -#endif - AC3toPCM.Clear(); - } -} - -/** - * Returns true if the pack is a NAV pack. This check is clearly insufficient, - * and sometimes we incorrectly think that valid other packs are NAV packs. I - * need to make this stronger. - */ -inline int cDVDplayBuffer::is_nav_pack(unsigned char *buffer) -{ - return buffer[41] == 0xbf && buffer[1027] == 0xbf; -} - -void cDVDplayBuffer::Input(void) -{ - dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid()); - - doplay = true; - while (Busy() && doplay) { - if (blockInput) { - if (blockInput > 1) - blockInput = 1; - continue; - } - - //BEGIN: ripped from play_title - - /** - * Playback by cell in this pgc, starting at the cell for our chapter. - */ - - //dsyslog(LOG_INFO, "DVD: cyclestate: %d", cyclestate); - switch (cyclestate) { - - case cOPENDVD: // open the DVD and get all the basic information - { - if (!dvd->isValid()) { - doplay = false; - break; - } - - /** - * Load the video manager to find out the information about the titles on - * this disc. - */ - vmg_file = dvd->openVMG(); - if (!vmg_file) { - esyslog(LOG_ERR, "ERROR: can't open VMG info"); - doplay = false; - break; - } - tt_srpt = vmg_file->tt_srpt; - - NextState(cOPENTITLE); - break; - } - - case cOPENTITLE: // open the selected title - { - /** - * Make sure our title number is valid. - */ - isyslog(LOG_INFO, "DVD: there are %d titles on this DVD", tt_srpt->nr_of_srpts); - if (titleid < 0 || titleid >= tt_srpt->nr_of_srpts) { - esyslog(LOG_ERR, "ERROR: invalid title %d", titleid + 1); - doplay = false; - break; - } - - /** - * Load the VTS information for the title set our title is in. - */ - vts_file = dvd->openVTS(tt_srpt->title[titleid].title_set_nr); - if (!vts_file) { - esyslog(LOG_ERR, "ERROR: can't open the title %d info file", tt_srpt->title[titleid].title_set_nr); - doplay = false; - break; - } - - NextState(cOPENCHAPTER); - break; - } - - case cOPENCHAPTER: - { - /** - * Make sure the chapter number is valid for this title. - */ - isyslog(LOG_INFO, "DVD: there are %d chapters in this title", tt_srpt->title[titleid].nr_of_ptts); - if (chapid < 0 || chapid >= tt_srpt->title[titleid].nr_of_ptts) { - esyslog(LOG_ERR, "ERROR: invalid chapter %d", chapid + 1); - doplay = false; - break; - } - - /** - * Determine which program chain we want to watch. This is based on the - * chapter number. - */ - ttn = tt_srpt->title[titleid].vts_ttn; - vts_ptt_srpt = vts_file->vts_ptt_srpt; - pgc_id = vts_ptt_srpt->title[ttn - 1].ptt[chapid].pgcn; - pgn = vts_ptt_srpt->title[ttn - 1].ptt[chapid].pgn; - cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_id - 1].pgc; - start_cell = cur_pgc->program_map[pgn - 1] - 1; - - /** - * setup Audio information - **/ - for (maxAudioTrack = 0; maxAudioTrack < 8; maxAudioTrack++) { - if (!(cur_pgc->audio_control[maxAudioTrack] & 0x8000)) - break; - } - canToggleAudioTrack = (maxAudioTrack > 0); - // init the AudioInformation - audioTrack = getAudioStream(logAudioTrack); -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVD: max: %d, track: %x", maxAudioTrack, audioTrack); -#endif - - /** - * We've got enough info, time to open the title set data. - */ - title = dvd->openTitle(tt_srpt->title[titleid].title_set_nr, DVD_READ_TITLE_VOBS); - if (!title) { - esyslog(LOG_ERR, "ERROR: can't open title VOBS (VTS_%02d_1.VOB).", tt_srpt->title[titleid].title_set_nr); - doplay = false; - break; - } - - /** - * Playback by cell in this pgc, starting at the cell for our chapter. - */ - next_cell = start_cell; - prev_cell = start_cell; - cur_cell = start_cell; - - NextState(cOUTCELL); - break; - } - - case cOUTCELL: - { -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVD: new cell: %d", cur_cell); - dsyslog(LOG_INFO, "DVD: vob_id: %x, cell_nr: %x", cur_pgc->cell_position[cur_cell].vob_id_nr, cur_pgc->cell_position[cur_cell].cell_nr); -#endif - - if (cur_cell < 0) { - cur_cell = 0; - Backward(); - } - doplay = (cur_cell < cur_pgc->nr_of_cells); - if (!doplay) - break; - - /* Check if we're entering an angle block. */ - if (cur_pgc->cell_playback[cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK) { - cur_cell += angle; - for (int i = 0; ; ++i) { - if (cur_pgc->cell_playback[cur_cell + i].block_mode == BLOCK_MODE_LAST_CELL) { - next_cell = cur_cell + i + 1; - break; - } - } - } - else { - next_cell = cur_cell + 1; - prev_cell = cur_cell - 1; - } - - // init settings for next state - if (playDir == pdForward) - cur_pack = cur_pgc->cell_playback[cur_cell].first_sector; - else - cur_pack = cur_pgc->cell_playback[cur_cell].last_vobu_start_sector; - - NextState(cOUTPACK); - break; - } - - case cOUTPACK: - { -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVD: new pack: %d", cur_pack); -#endif - /** - * We loop until we're out of this cell. - */ - - if (playDir == pdForward) { - if (cur_pack >= cur_pgc->cell_playback[cur_cell].last_sector) { - cur_cell = next_cell; -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVD: end of pack"); -#endif - NextState(cOUTCELL); - break; - } - } - else { -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVD: prev: %d, curr: %x, next: %x, prev: %x", prevcycle, cur_pack, next_vobu, prev_vobu); -#endif - if ((cur_pack & 0x80000000) != 0) { - cur_cell = prev_cell; -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVD: start of pack"); -#endif - NextState(cOUTCELL); - break; - } - } - - /** - * Read NAV packet. - */ - int len = DVDReadBlocks(title, cur_pack, 1, data); - if (len == 0) { - esyslog(LOG_ERR, "ERROR: read failed for block %d", cur_pack); - doplay = false; - break; - } - if (!is_nav_pack(data)) { - esyslog(LOG_ERR, "ERROR: no nav_pack"); - return; - } - - /** - * Parse the contained dsi packet. - */ - navRead_DSI(&dsi_pack, &(data[DSI_START_BYTE])); - if (cur_pack != dsi_pack.dsi_gi.nv_pck_lbn) { - esyslog(LOG_ERR, "ERROR: cur_pack != dsi_pack.dsi_gi.nv_pck_lbn"); - return; - } - // navPrint_DSI(&dsi_pack); - - /** - * Determine where we go next. These values are the ones we mostly - * care about. - */ - next_ilvu_start = cur_pack + dsi_pack.sml_agli.data[angle].address; - cur_output_size = dsi_pack.dsi_gi.vobu_ea; - min_output_size = dsi_pack.dsi_gi.vobu_1stref_ea; - - /** - * If we're not at the end of this cell, we can determine the next - * VOBU to display using the VOBU_SRI information section of the - * DSI. Using this value correctly follows the current angle, - * avoiding the doubled scenes in The Matrix, and makes our life - * really happy. - * - * Otherwise, we set our next address past the end of this cell to - * force the code above to go to the next cell in the program. - */ - if (dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) - next_vobu = cur_pack + (dsi_pack.vobu_sri.next_vobu & 0x7fffffff); - else - next_vobu = cur_pack + cur_output_size + 1; - - if (dsi_pack.vobu_sri.prev_vobu != SRI_END_OF_CELL) - prev_vobu = cur_pack - (dsi_pack.vobu_sri.prev_vobu & 0x7fffffff); - else { -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVD: cur: %x, prev: %x", cur_pack, dsi_pack.vobu_sri.prev_vobu); -#endif - prev_vobu = 0x80000000; - } - -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVD: curr: %x, next: %x, prev: %x", cur_pack, next_vobu, prev_vobu); -#endif - if (cur_output_size >= 1024) { - esyslog(LOG_ERR, "ERROR: cur_output_size >= 1024"); - return; - } - cur_pack++; - - NextState(cREADFRAME); - break; - } - - case cREADFRAME: - { - bool trickMode = (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)); - - /* FIXME: - * the entire trickMode code relies on the assumtion - * that there is only one I-FRAME per PACK - * - * I have no clue wether that is correct or not !!! - */ - if (trickMode && (skipCnt++ % 4 != 0)) { - cur_pack = (playDir == pdForward) ? next_vobu : prev_vobu; - NextState(cOUTPACK); - break; - } - - if (trickMode) - cur_output_size = min_output_size; - - /** - * Read in cursize packs. - */ -#ifdef DVDDEBUG - dsyslog(LOG_INFO, "DVD: read pack: %d", cur_pack); -#endif - int len = DVDReadBlocks(title, cur_pack, cur_output_size, data); - if (len != (int)cur_output_size) { - esyslog(LOG_ERR, "ERROR: read failed for %d blocks at %d", cur_output_size, cur_pack); - doplay = false; - break; - } - pktcnt = 0; - NextState(cOUTFRAMES); - break; - } - - case cOUTFRAMES: - { - bool trickMode = (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)); - - /** - * Output cursize packs. - */ - if (pktcnt >= cur_output_size) { - cur_pack = next_vobu; - NextState(cOUTPACK); - break; - } - //dsyslog(LOG_INFO, "DVD: pack: %d, frame: %d", cur_pack, pktcnt); - - if (decode_packet(&data[pktcnt * DVD_VIDEO_LB_LEN], trickMode) != 1) { //we've got a video packet - if (trickMode) { - //dsyslog(LOG_INFO, "DVD: did pack: %d", pktcnt); - cur_pack = (playDir == pdForward) ? next_vobu : prev_vobu; - NextState(cOUTPACK); - break; - } - } - - pktcnt++; - - if (pktcnt >= cur_output_size) { - cur_pack = next_vobu; - NextState(cOUTPACK); - break; - } - break; - } - - default: - { - esyslog(LOG_ERR, "ERROR: cyclestate %d not known", cyclestate); - return; - } - } - - // dsyslog(LOG_INF, "DVD: new cyclestate: %d, pktcnt: %d, cur: %d", cyclestate, pktcnt, cur_output_size); - } - - dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid()); -} - -#define NO_PICTURE 0 -#define SC_PICTURE 0x00 - -inline bool cDVDplayBuffer::PacketStart(uchar **Data, int len) -{ - while (len > 6 && !((*Data)[0] == 0x00 && (*Data)[1] == 0x00 && (*Data)[2] == 0x01)) - (*Data)++; - return ((*Data)[0] == 0x00 && (*Data)[1] == 0x00 && (*Data)[2] == 0x01); -} - -inline int cDVDplayBuffer::GetPacketType(const uchar *Data) -{ - return Data[3]; -} - -inline int cDVDplayBuffer::GetStuffingLen(const uchar *Data) -{ - return Data[13] & 0x07; -} - -inline int cDVDplayBuffer::GetPacketLength(const uchar *Data) -{ - return (Data[4] << 8) + Data[5] + 6; -} - -inline int cDVDplayBuffer::GetPESHeaderLength(const uchar *Data) -{ - return (Data[8]); -} - -int cDVDplayBuffer::ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType) -{ - // Scans the video packet starting at Offset and returns its length. - // If the return value is -1 the packet was not completely in the buffer. - - int Length = GetPacketLength(Data); - if (Length > 0 && Length <= Count) { - int i = 8; // the minimum length of the video packet header - i += Data[i] + 1; // possible additional header bytes - for (; i < Length; i++) { - if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { - switch (Data[i + 3]) { - case SC_PICTURE: *PictureType = (uchar)(Data[i + 5] >> 3) & 0x07; - return Length; - } - } - } - PictureType = NO_PICTURE; - return Length; - } - return -1; -} - -void cDVDplayBuffer::handleAC3(unsigned char *sector, int length, uchar PTSflags, uchar *PTSdata) -{ -#define PCM_FRAME_SIZE 1536 - AC3toPCM.Put(sector, length); - cFrame *frame; - if (ac3_buffersize() <= 100) { - if ((frame = AC3toPCM.Get(PCM_FRAME_SIZE, PTSflags, PTSdata)) != NULL) - putFrame(frame); - } - while ((frame = AC3toPCM.Get(PCM_FRAME_SIZE)) != NULL) - putFrame(frame); -} - -int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode) -{ - //XXX kls 2001-11-03: do we really need all these different return values? - uchar pt = 1; - - //make sure we got a PS packet header - if (!PacketStart(§or, DVD_VIDEO_LB_LEN) && GetPacketType(sector) != 0xBA) { - esyslog(LOG_ERR, "ERROR: got unexpected packet: %x %x %x %x", sector[0], sector[1], sector[2], sector[3]); - return -1; - } - - int offset = 14 + GetStuffingLen(sector); - sector += offset; - int r = DVD_VIDEO_LB_LEN - offset; - int datalen = r; - - sector[6] &= 0x8f; - uchar PTSflags = sector[7] >> 6; - uchar *PTSdata = sector + 9; - uchar *data = sector; - - switch (GetPacketType(sector)) { - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - { - ScanVideoPacket(sector, r, &pt); - if (trickMode && pt != 1) - return pt; - putFrame(sector, r, ftVideo); - break; - } - case AUDIO_STREAM_S ... AUDIO_STREAM_E: { - // no sound in trick mode - if (trickMode) - return 1; - if (audioTrack != GetPacketType(sector)) - return 5; - putFrame(sector, r, ftAudio); - break; - } - case PRIVATE_STREAM1: - { - datalen = GetPacketLength(sector); - //skip optional Header bytes - datalen -= GetPESHeaderLength(sector); - data += GetPESHeaderLength(sector); - //skip mandatory header bytes - data += 3; - //fallthrough is intended - } - case PRIVATE_STREAM2: - { - //FIXME: Stream1 + Stream2 is ok, but is Stream2 alone also? - - // no sound in trick mode - if (trickMode) - return 1; - - // skip PS header bytes - data += 6; - // data now points to the beginning of the payload - - if (audioTrack == *data) { - switch (audioTrack & 0xF8) { - case aAC3: - if (dolbyDev) - putFrame(sector, r, ftDolby); - data += 4; - datalen -= 13; // 3 (mandatory header) + 6 (PS header) + 4 (AC3 header) = 13 - handleAC3(data, datalen, PTSflags, PTSdata); - break; - case aLPCM: - // write(audio, sector+14 , sector[19]+(sector[18]<<8)+6); - putFrame(sector, GetPacketLength(sector), ftAudio); - break; - default: - break; - } - } - return pt; - } - default: - case SYSTEM_HEADER: - case PROG_STREAM_MAP: - { - esyslog(LOG_ERR, "ERROR: don't know what to do - packetType: %x", GetPacketType(sector)); - // just skip them for now,l but try to debug it - dsyslog(LOG_INFO, "DVD: curr cell: %8x, Nr of cells: %8x", cur_cell, cur_pgc->nr_of_cells); - dsyslog(LOG_INFO, "DVD: curr pack: %8x, last sector: %8x", cur_pack, cur_pgc->cell_playback[cur_cell].last_sector); - dsyslog(LOG_INFO, "DVD: curr pkt: %8x, output size: %8x", pktcnt, cur_output_size); -#if 0 - // looks like my DVD is/was brocken ....... - for (int n = 0; n <= 255; n++) { - dsyslog(LOG_INFO, "%4x %2x %2x %2x %2x %2x %2x %2x %2x", n * 8, - osect[n * 8 + 0], osect[n * 8 + 1], osect[n * 8 + 2], osect[n * 8 + 3], - osect[n * 8 + 4], osect[n * 8 + 5], osect[n * 8 + 6], osect[n * 8 + 7]); - } - return 0; -#endif - return pt; - } - } - return pt; -} - -void cDVDplayBuffer::Empty(bool Block) -{ - if (!(blockInput || blockOutput)) { - cPlayBuffer::Empty(true); - AC3toPCM.Clear(); - } - if (!Block) - cPlayBuffer::Empty(false); -} - -void cDVDplayBuffer::Close(void) -{ - dvd->Close(); -} - -int cDVDplayBuffer::SkipFrames(int Frames) -{ - return -1; -} - -/* Figure out the correct pgN from the cell and update state. */ -void cDVDplayBuffer::setChapid(void) -{ - int new_pgN = 0; - - while (new_pgN < cur_pgc->nr_of_programs && cur_cell >= cur_pgc->program_map[new_pgN]) - new_pgN++; - - if (new_pgN == cur_pgc->nr_of_programs) { /* We are at the last program */ - if (cur_cell > cur_pgc->nr_of_cells) - chapid = 1; /* We are past the last cell */ - } - - chapid = new_pgN; -} - -void cDVDplayBuffer::SkipSeconds(int Seconds) -{ - if (Seconds) { - setChapid(); - int newchapid = Seconds > 0 ? chapid + 1 : chapid - 1; - - if (newchapid >= 0 && newchapid < tt_srpt->title[titleid].nr_of_ptts) { - Empty(true); - chapid = newchapid; - NextState(cOPENCHAPTER); - AC3toPCM.Clear(); - Empty(false); - Play(); - } - } -} - -void cDVDplayBuffer::Goto(int Index, bool Still) -{ -} - -void cDVDplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame) -{ - Current = Total = -1; -} -#endif //DVDSUPPORT - // --- cTransferBuffer ------------------------------------------------------- class cTransferBuffer : public cRingBufferLinear { @@ -2732,18 +1861,11 @@ void cDvbApi::Cleanup(void) PrimaryDvbApi = NULL; } -const cSchedules *cDvbApi::Schedules(cThreadLock *ThreadLock) const -{ - if (siProcessor && ThreadLock->Lock(siProcessor)) - return siProcessor->Schedules(); - return NULL; -} - bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY) { - int result = 0; - int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR); + int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR, true); if (videoDev >= 0) { + int result = 0; struct video_mbuf mbuf; result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf); if (result == 0) { @@ -2827,8 +1949,9 @@ bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, result |= 1; } close(videoDev); + return result == 0; } - return result == 0; + return false; } #ifdef DEBUG_OSD @@ -3017,7 +2140,9 @@ void cDvbApi::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor col void cDvbApi::Flush(void) { -#ifndef DEBUG_OSD +#ifdef DEBUG_OSD + refresh(); +#else if (osd) osd->Flush(); #endif @@ -3106,9 +2231,9 @@ bool cDvbApi::SetPids(bool ForRecording) { return SetVpid(vPid, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && SetApid1(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && - SetApid2(ForRecording ? aPid2 : 0, DMX_OUT_TS_TAP) && + SetApid2(ForRecording ? aPid2 : 0, DMX_OUT_TS_TAP) && (!Setup.RecordDolbyDigital || SetDpid1(ForRecording ? dPid1 : 0, DMX_OUT_TS_TAP) && - SetDpid2(ForRecording ? dPid2 : 0, DMX_OUT_TS_TAP); + SetDpid2(ForRecording ? dPid2 : 0, DMX_OUT_TS_TAP)); } eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr) @@ -3416,36 +2541,6 @@ bool cDvbApi::StartReplay(const char *FileName) return false; } -#ifdef DVDSUPPORT -bool cDvbApi::StartDVDplay(cDVD *dvd, int TitleID) -{ - if (Recording()) { - esyslog(LOG_ERR, "ERROR: StartDVDplay() called while recording - ignored!"); - return false; - } - StopTransfer(); - StopReplay(); - if (fd_video >= 0 && fd_audio >= 0) { - - // Check DeviceName: - - if (!dvd) { - esyslog(LOG_ERR, "ERROR: StartDVDplay: DVD device is (null)"); - return false; - } - - // Create replay buffer: - - replayBuffer = new cDVDplayBuffer(this, fd_video, fd_audio, dvd, TitleID); - if (replayBuffer) - return true; - else - esyslog(LOG_ERR, "ERROR: can't allocate replaying buffer"); - } - return false; -} -#endif //DVDSUPPORT - void cDvbApi::StopReplay(void) { if (replayBuffer) { diff --git a/dvbapi.h b/dvbapi.h index fbc1e9d94..06028f0bd 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.61 2002/02/03 16:43:38 kls Exp $ + * $Id: dvbapi.h 1.63 2002/02/24 12:38:08 kls Exp $ */ #ifndef __DVBAPI_H @@ -29,9 +29,6 @@ #include <stdio.h> #include "dvbosd.h" -#ifdef DVDSUPPORT -#include "dvd.h" -#endif //DVDSUPPORT #include "eit.h" #include "thread.h" @@ -60,9 +57,6 @@ class cChannel; class cRecordBuffer; class cPlayBuffer; class cReplayBuffer; -#ifdef DVDSUPPORT -class cDVDplayBuffer; -#endif //DVDSUPPORT class cTransferBuffer; class cCuttingBuffer; @@ -83,9 +77,6 @@ class cVideoCutter { class cDvbApi { friend class cRecordBuffer; friend class cReplayBuffer; -#ifdef DVDSUPPORT - friend class cDVDplayBuffer; -#endif //DVDSUPPORT friend class cTransferBuffer; private: FrontendType frontendType; @@ -143,10 +134,6 @@ class cDvbApi { private: cSIProcessor *siProcessor; public: - const cSchedules *Schedules(cThreadLock *ThreadLock) const; - // Caller must provide a cThreadLock which has to survive the entire - // time the returned cSchedules is accessed. Once the cSchedules is no - // longer used, the cThreadLock must be destroyed. void SetUseTSTime(bool On) { if (siProcessor) siProcessor->SetUseTSTime(On); } // Image Grab facilities @@ -250,10 +237,6 @@ class cDvbApi { // 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. -#ifdef DVDSUPPORT - bool StartDVDplay(cDVD *dvd, int TitleID);//XXX dvd parameter necessary??? - // Starts replaying the given TitleID on the DVD. -#endif //DVDSUPPORT void StopReplay(void); // Stops the current replay session (if any). void Pause(void); diff --git a/dvd.c b/dvd.c deleted file mode 100644 index e061b1414..000000000 --- a/dvd.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * dvd.c: Functions for handling DVDs - * - * See the main source file 'vdr.c' for copyright information and - * how to reach the author. - * - * Initially written by Andreas Schultz <aschultz@warp10.net> - * - * $Id: dvd.c 1.4 2001/11/10 13:38:50 kls Exp $ - */ - -#ifdef DVDSUPPORT - -//#define DVDSUPPORTDEBUG 1 -//#define DEBUG_BUFFER 1 - -#include <fcntl.h> -#include <linux/cdrom.h> -#include <string.h> -#include <sys/ioctl.h> -#include <unistd.h> - -#include "dvd.h" -#include "tools.h" - -// --- cDVD ---------------------------------------------------------------------------- - -const char *cDVD::deviceName = "/dev/dvd"; -cDVD *cDVD::dvdInstance = NULL; - -cDVD *cDVD::getDVD(void) -{ - if (!dvdInstance) - new cDVD; - return dvdInstance; -} - -cDVD::cDVD(void) -{ - dvd = NULL; - title = NULL; - vmg_file = NULL; - vts_file = NULL; - dvdInstance = this; -} - -cDVD::~cDVD() -{ - Close(); -} - -int cDVD::Command(int Cmd) -{ - int result = -1; - int f; - if ((f = open(deviceName, O_RDONLY | O_NONBLOCK)) > 0) { - result = ioctl(f, Cmd, 0); - close(f); - } - return result; -} - -void cDVD::SetDeviceName(const char *DeviceName) -{ - deviceName = strdup(DeviceName); -} - -const char *cDVD::DeviceName(void) -{ - return deviceName; -} - -bool cDVD::DriveExists(void) -{ - return access(deviceName, F_OK) == 0; -} - -bool cDVD::DiscOk(void) -{ - return Command(CDROM_DRIVE_STATUS) == CDS_DISC_OK; -} - -void cDVD::Eject(void) -{ - if (dvdInstance) - dvdInstance->Close(); - Command(CDROMEJECT); -} - -void cDVD::Open(void) -{ - if (!dvd) - dvd = DVDOpen(deviceName); -} - -void cDVD::Close(void) -{ -#ifdef DVDSUPPORTDEBUG - dsyslog(LOG_INFO, "DVD: cDVD::Close(%p): vts: %p, vmg: %p, title: %p, dvd: %p", this, vts_file, vmg_file, title, dvd); -#endif - if (vts_file) - ifoClose(vts_file); - if (vmg_file) - ifoClose(vmg_file); - if (title) - DVDCloseFile(title); - if (dvd) - DVDClose(dvd); - vts_file = NULL; - vmg_file = NULL; - title = NULL; - dvd = NULL; -} - -ifo_handle_t *cDVD::openVMG(void) -{ - if (!isValid()) - return NULL; - if (!vmg_file) - vmg_file = ifoOpen(dvd, 0); - return vmg_file; -} - -ifo_handle_t *cDVD::openVTS(int TitleSet) -{ - if (!isValid()) - return NULL; - if (vts_file && (titleset != TitleSet)) { - ifoClose(vts_file); - vts_file = NULL; - } - if (!vts_file) { - titleset = TitleSet; - vts_file = ifoOpen(dvd, TitleSet); - } - return vts_file; -} - -dvd_file_t *cDVD::openTitle(int Title, dvd_read_domain_t domain) -{ - if (!isValid()) - return NULL; - if (title) - DVDCloseFile(title); - title = DVDOpenFile(dvd, Title, domain); - return title; -} - -int cDVD::getAudioTrack(int stream) -{ - if (getVTS()) { - switch (getVTS()->vtsi_mat->vts_audio_attr[stream].audio_format) { - case 0: // ac3 - return aAC3; - case 2: // mpeg1 - case 3: // mpeg2ext - return aMPEG; - case 4: // lpcm - return aLPCM; - case 6: // dts - return aDTS; - default: - esyslog(LOG_ERR, "ERROR: unknown Audio stream info"); - } - } - return 0; -} - -#endif //DVDSUPPORT diff --git a/dvd.h b/dvd.h deleted file mode 100644 index 5ac145489..000000000 --- a/dvd.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * dvd.h: Functions for handling DVDs - * - * See the main source file 'vdr.c' for copyright information and - * how to reach the author. - * - * Initially written by Andreas Schultz <aschultz@warp10.net> - * - * $Id: dvd.h 1.4 2001/11/10 13:38:25 kls Exp $ - */ - -#ifndef __DVD_H -#define __DVD_H - -#ifdef DVDSUPPORT - -#include <dvdread/dvd_reader.h> -#include <dvdread/ifo_types.h> -#include <dvdread/ifo_read.h> -#include <dvdread/dvd_udf.h> -#include <dvdread/nav_read.h> -#include <dvdread/nav_print.h> - -#define aAC3 0x80 -#define aDTS 0x88 -#define aLPCM 0xA0 -#define aMPEG 0xC0 - -class cDVD { -private: - static cDVD *dvdInstance; - static const char *deviceName; - dvd_reader_t *dvd; - dvd_file_t *title; - ifo_handle_t *vmg_file; - ifo_handle_t *vts_file; - int titleset; - static int Command(int Cmd); -public: - cDVD(void); - ~cDVD(); - static void SetDeviceName(const char *DeviceName); - static const char *DeviceName(void); - static bool DriveExists(void); - static bool DiscOk(void); - static void Eject(void); - void Open(void); - void Close(void); - bool isValid(void) { return (dvd != NULL); } - ifo_handle_t *openVMG(void); - ifo_handle_t *openVTS(int TitleSet); - ifo_handle_t *getVTS() { return vts_file; } - dvd_file_t *openTitle(int Title, dvd_read_domain_t domain); - static cDVD *getDVD(void); - int getAudioNrOfTracks() { return getVTS() ? getVTS()->vtsi_mat->nr_of_vts_audio_streams : 0; } - int getAudioLanguage(int stream) { return getVTS() ? getVTS()->vtsi_mat->vts_audio_attr[stream].lang_code : 0; } - int getAudioTrack(int stream); - }; - -#endif //DVDSUPPORT - -#endif //__DVD_H diff --git a/eit.c b/eit.c index 99bcdfff9..bd43fe925 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.34 2002/02/09 14:48:43 kls Exp $ + * $Id: eit.c 1.37 2002/02/23 17:11:19 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -341,7 +341,7 @@ unsigned short cEventInfo::GetServiceID() const void cEventInfo::Dump(FILE *f, const char *Prefix) const { if (tTime + lDuration >= time(NULL)) { - fprintf(f, "%sE %u %ld %ld\n", Prefix, uEventID, tTime, lDuration); + fprintf(f, "%sE %u %ld %ld %X\n", Prefix, uEventID, tTime, lDuration, uTableID); if (!isempty(pTitle)) fprintf(f, "%sT %s\n", Prefix, pTitle); if (!isempty(pSubtitle)) @@ -352,6 +352,54 @@ void cEventInfo::Dump(FILE *f, const char *Prefix) const } } +bool cEventInfo::Read(FILE *f, cSchedule *Schedule) +{ + if (Schedule) { + cEventInfo *pEvent = NULL; + char *s; + while ((s = readline(f)) != NULL) { + char *t = skipspace(s + 1); + switch (*s) { + case 'E': if (!pEvent) { + unsigned int uEventID; + time_t tTime; + long lDuration; + unsigned int uTableID = 0; + int n = sscanf(t, "%u %ld %ld %X", &uEventID, &tTime, &lDuration, &uTableID); + if (n == 3 || n == 4) { + pEvent = (cEventInfo *)Schedule->GetEvent(uEventID, tTime); + if (!pEvent) + pEvent = Schedule->AddEvent(new cEventInfo(Schedule->GetServiceID(), uEventID)); + if (pEvent) { + pEvent->SetTableID(uTableID); + pEvent->SetTime(tTime); + pEvent->SetDuration(lDuration); + } + } + } + break; + case 'T': if (pEvent) + pEvent->SetTitle(t); + break; + case 'S': if (pEvent) + pEvent->SetSubtitle(t); + break; + case 'D': if (pEvent) + pEvent->SetExtendedDescription(t); + break; + case 'e': pEvent = NULL; + break; + case 'c': // to keep things simple we react on 'c' here + return false; + default: esyslog(LOG_ERR, "ERROR: unexpected tag while reading EPG data: %s", s); + return false; + } + } + return true; + } + return false; +} + #define MAXEPGBUGFIXSTATS 5 #define MAXEPGBUGFIXCHANS 50 struct tEpgBugFixStats { @@ -545,6 +593,13 @@ cSchedule::cSchedule(unsigned short servid) cSchedule::~cSchedule() { } + +cEventInfo *cSchedule::AddEvent(cEventInfo *EventInfo) +{ + Events.Add(EventInfo); + return EventInfo; +} + /** */ const cEventInfo * cSchedule::GetPresentEvent() const { @@ -689,6 +744,31 @@ void cSchedule::Dump(FILE *f, const char *Prefix) const } } +bool cSchedule::Read(FILE *f, cSchedules *Schedules) +{ + if (Schedules) { + char *s; + while ((s = readline(f)) != NULL) { + if (*s == 'C') { + unsigned int uServiceID; + if (1 == sscanf(s + 1, "%u", &uServiceID)) { + cSchedule *p = (cSchedule *)Schedules->SetCurrentServiceID(uServiceID); + if (p) { + while (cEventInfo::Read(f, p)) + ; // loop stops after having read the closing 'c' + } + } + } + else { + esyslog(LOG_ERR, "ERROR: unexpected tag while reading EPG data: %s", s); + return false; + } + } + return true; + } + return false; +} + // --- cSchedules ------------------------------------------------------------ cSchedules::cSchedules() @@ -701,7 +781,7 @@ cSchedules::~cSchedules() { } /** */ -bool cSchedules::SetCurrentServiceID(unsigned short servid) +const cSchedule *cSchedules::SetCurrentServiceID(unsigned short servid) { pCurrentSchedule = GetSchedule(servid); if (pCurrentSchedule == NULL) @@ -709,12 +789,12 @@ bool cSchedules::SetCurrentServiceID(unsigned short servid) Add(new cSchedule(servid)); pCurrentSchedule = GetSchedule(servid); if (pCurrentSchedule == NULL) - return false; + return NULL; } uCurrentServiceID = servid; - return true; + return pCurrentSchedule; } /** */ const cSchedule * cSchedules::GetSchedule() const @@ -757,6 +837,13 @@ void cSchedules::Dump(FILE *f, const char *Prefix) const p->Dump(f, Prefix); } +/** */ +bool cSchedules::Read(FILE *f) +{ + cMutexLock MutexLock; + return cSchedule::Read(f, (cSchedules *)cSIProcessor::Schedules(MutexLock)); +} + // --- cEIT ------------------------------------------------------------------ class cEIT { @@ -822,17 +909,20 @@ int cEIT::ProcessEIT(unsigned char *buffer) if (!pEvent) { // If we don't have that event ID yet, we create a new one. // Otherwise we copy the information into the existing event anyway, because the data might have changed. - pSchedule->Events.Add(new cEventInfo(VdrProgramInfo->ServiceID, VdrProgramInfo->EventID)); - pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID); + pEvent = pSchedule->AddEvent(new cEventInfo(VdrProgramInfo->ServiceID, VdrProgramInfo->EventID)); if (!pEvent) break; pEvent->SetTableID(tid); } else { // We have found an existing event, either through its event ID or its start time. + // If the existing event has a zero table ID it was defined externally and shall + // not be overwritten. + if (pEvent->GetTableID() == 0x00) + continue; // If the new event comes from a table that belongs to an "other TS" and the existing - // one comes from a "actual TS" table, lets skip it. - if ((tid == 0x4F || tid == 0x60) && (pEvent->GetTableID() == 0x4E || pEvent->GetTableID() == 0x50)) + // one comes from an "actual TS" table, lets skip it. + if ((tid == 0x4F || tid == 0x60 || tid == 0x61) && (pEvent->GetTableID() == 0x4E || pEvent->GetTableID() == 0x50 || pEvent->GetTableID() == 0x51)) continue; } if (rEvent) { @@ -913,6 +1003,32 @@ cSIProcessor::~cSIProcessor() delete fileName; } +const cSchedules *cSIProcessor::Schedules(cMutexLock &MutexLock) +{ + if (MutexLock.Lock(&schedulesMutex)) + return schedules; + return NULL; +} + +bool cSIProcessor::Read(FILE *f) +{ + bool OwnFile = f == NULL; + if (OwnFile) { + const char *FileName = GetEpgDataFileName(); + if (access(FileName, R_OK) == 0) { + dsyslog(LOG_INFO, "reading EPG data from %s", FileName); + if ((f = fopen(FileName, "r")) == NULL) { + LOG_ERROR; + return false; + } + } + } + bool result = cSchedules::Read(f); + if (OwnFile) + fclose(f); + return result; +} + void cSIProcessor::SetEpgDataFileName(const char *FileName) { epgDataFileName = NULL; @@ -940,6 +1056,8 @@ void cSIProcessor::SetStatus(bool On) AddFilter(0x12, 0x4f); // event info, other TS, present/following AddFilter(0x12, 0x50); // event info, actual TS, schedule AddFilter(0x12, 0x60); // event info, other TS, schedule + AddFilter(0x12, 0x51); // event info, actual TS, schedule for another 4 days + AddFilter(0x12, 0x61); // event info, other TS, schedule for another 4 days } schedulesMutex.Unlock(); } diff --git a/eit.h b/eit.h index 48ab91332..55c0f4e05 100644 --- a/eit.h +++ b/eit.h @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.13 2002/01/13 16:18:23 kls Exp $ + * $Id: eit.h 1.15 2002/02/23 15:30:25 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -72,6 +72,7 @@ class cEventInfo : public cListObject { int GetChannelNumber(void) const { return nChannelNumber; } void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' void Dump(FILE *f, const char *Prefix = "") const; + static bool Read(FILE *f, cSchedule *Schedule); void FixEpgBugs(void); }; @@ -92,6 +93,7 @@ class cSchedule : public cListObject { cSchedule(unsigned short servid = 0); public: ~cSchedule(); + cEventInfo *AddEvent(cEventInfo *EventInfo); const cEventInfo *GetPresentEvent(void) const; const cEventInfo *GetFollowingEvent(void) const; unsigned short GetServiceID(void) const; @@ -100,15 +102,17 @@ class cSchedule : public cListObject { const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); } int NumEvents(void) const { return Events.Count(); } void Dump(FILE *f, const char *Prefix = "") const; + static bool Read(FILE *f, cSchedules *Schedules); }; class cSchedules : public cList<cSchedule> { + friend class cSchedule; friend class cSIProcessor; private: const cSchedule *pCurrentSchedule; unsigned short uCurrentServiceID; protected: - bool SetCurrentServiceID(unsigned short servid); + const cSchedule *SetCurrentServiceID(unsigned short servid); void Cleanup(); public: cSchedules(void); @@ -116,6 +120,7 @@ class cSchedules : public cList<cSchedule> { const cSchedule *GetSchedule(unsigned short servid) const; const cSchedule *GetSchedule(void) const; void Dump(FILE *f, const char *Prefix = "") const; + static bool Read(FILE *f); }; typedef struct sip_filter { @@ -146,10 +151,14 @@ class cSIProcessor : public cThread { ~cSIProcessor(); static void SetEpgDataFileName(const char *FileName); static const char *GetEpgDataFileName(void); + static const cSchedules *Schedules(cMutexLock &MutexLock); + // Caller must provide a cMutexLock which has to survive the entire + // time the returned cSchedules is accessed. Once the cSchedules is no + // longer used, the cMutexLock must be destroyed. + static bool Read(FILE *f = NULL); void SetStatus(bool On); bool SetUseTSTime(bool use); bool SetCurrentServiceID(unsigned short servid); - const cSchedules *Schedules(void) { return schedules; } }; #endif diff --git a/i18n.c b/i18n.c index f2c414f00..083971573 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.53 2002/02/10 15:07:46 kls Exp $ + * $Id: i18n.c 1.57 2002/02/24 12:54:12 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -120,16 +120,6 @@ const tPhrase Phrases[] = { "Opptak", "Nauhoitteet", }, - { "DVD", - "DVD", - "DVD", - "DVD", - "DVD", - "DVD", - "DVD", - "DVD", - "DVD", - }, { "Setup", "Einstellungen", "Nastavitve", @@ -261,6 +251,16 @@ const tPhrase Phrases[] = { "Marker", "Merkitse", }, + { "On/Off", + "Ein/Aus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Record", "Aufnehmen", "Posnemi", @@ -412,6 +412,16 @@ const tPhrase Phrases[] = { "Slette opptak?", "Poistetaanko nauhoitus?", }, + { "Timer still recording - really delete?", + "Timer zeichnet auf - trotzdem lschen?", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Stop recording?", "Aufzeichnung beenden?", "Koncaj snemanje?", @@ -684,6 +694,16 @@ const tPhrase Phrases[] = { "Filnavn", "Tiedosto", }, + { "First day", + "Erster Tag", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // Error messages: { "Channel is being used by a timer!", "Kanal wird von einem Timer benutzt!", @@ -1046,6 +1066,16 @@ const tPhrase Phrases[] = { "TV Format", "Kuvamuoto", }, + { "RecordDolbyDigital", + "Dolby Digital Ton aufz.", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "ChannelInfoPos", "Kanal Info Position", "", // TODO diff --git a/menu.c b/menu.c index a7a98ec38..28e5d4d86 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.152 2002/02/10 11:52:34 kls Exp $ + * $Id: menu.c 1.159 2002/02/24 12:55:49 kls Exp $ */ #include "menu.h" @@ -254,6 +254,62 @@ eOSState cMenuEditDayItem::ProcessKey(eKeys Key) return osContinue; } +// --- cMenuEditDateItem ----------------------------------------------------- + +class cMenuEditDateItem : public cMenuEditItem { +protected: + time_t *value; + virtual void Set(void); +public: + cMenuEditDateItem(const char *Name, time_t *Value); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value) +:cMenuEditItem(Name) +{ + value = Value; + Set(); +} + +void cMenuEditDateItem::Set(void) +{ +#define DATEBUFFERSIZE 32 + char buf[DATEBUFFERSIZE]; + if (*value) { + struct tm tm_r; + localtime_r(value, &tm_r); + strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r); + strcat(buf, WeekDayName(tm_r.tm_wday)); + } + else + *buf = 0; + SetValue(buf); +} + +eOSState cMenuEditDateItem::ProcessKey(eKeys Key) +{ + eOSState state = cMenuEditItem::ProcessKey(Key); + + if (state == osUnknown) { + if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? + *value -= SECSINDAY; + if (*value < time(NULL)) + *value = 0; + } + else if (NORMALKEY(Key) == kRight) { + if (!*value) + *value = cTimer::SetTime(time(NULL), 0); + *value += SECSINDAY; + } + else + return state; + Set(); + state = osContinue; + } + return state; +} + // --- cMenuEditTimeItem ----------------------------------------------------- class cMenuEditTimeItem : public cMenuEditItem { @@ -905,6 +961,8 @@ class cMenuEditTimer : public cOsdMenu { private: cTimer *timer; cTimer data; + cMenuEditDateItem *firstday; + void SetFirstDayItem(void); public: cMenuEditTimer(int Index, bool New = false); virtual eOSState ProcessKey(eKeys Key); @@ -913,6 +971,7 @@ class cMenuEditTimer : public cOsdMenu { cMenuEditTimer::cMenuEditTimer(int Index, bool New) :cOsdMenu(tr("Edit Timer"), 12) { + firstday = NULL; timer = Timers.Get(Index); if (timer) { data = *timer; @@ -927,6 +986,21 @@ cMenuEditTimer::cMenuEditTimer(int Index, bool New) Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), FileNameChars)); + SetFirstDayItem(); + } +} + +void cMenuEditTimer::SetFirstDayItem(void) +{ + if (!firstday && !data.IsSingleEvent()) { + Add(firstday = new cMenuEditDateItem(tr("First day"), &data.firstday)); + Display(); + } + else if (firstday && data.IsSingleEvent()) { + Del(firstday->Index()); + firstday = NULL; + data.firstday = 0; + Display(); } } @@ -953,6 +1027,8 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key) default: break; } } + if (Key != kNone) + SetFirstDayItem(); return state; } @@ -983,7 +1059,7 @@ void cMenuTimerItem::Set(void) { char *buffer = NULL; asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s", - timer->active ? timer->recording ? '#' : '>' : ' ', + !timer->active ? ' ' : timer->firstday ? '!' : timer->recording ? '#' : '>', timer->channel, timer->PrintDay(timer->day), timer->start / 100, @@ -998,10 +1074,10 @@ void cMenuTimerItem::Set(void) class cMenuTimers : public cOsdMenu { private: - eOSState Activate(bool On); eOSState Edit(void); eOSState New(void); eOSState Del(void); + eOSState OnOff(void); virtual void Move(int From, int To); eOSState Summary(void); cTimer *CurrentTimer(void); @@ -1022,7 +1098,7 @@ cMenuTimers::cMenuTimers(void) } if (Setup.SortTimers) Sort(); - SetHelp(tr("Edit"), tr("New"), tr("Delete"), Setup.SortTimers ? NULL : tr("Mark")); + SetHelp(tr("Edit"), tr("New"), tr("Delete"), Setup.SortTimers ? tr("On/Off") : tr("Mark")); } cTimer *cMenuTimers::CurrentTimer(void) @@ -1031,14 +1107,27 @@ cTimer *cMenuTimers::CurrentTimer(void) return item ? item->Timer() : NULL; } -eOSState cMenuTimers::Activate(bool On) +eOSState cMenuTimers::OnOff(void) { cTimer *timer = CurrentTimer(); - if (timer && timer->active != On) { - timer->active = On; + if (timer) { + if (timer->IsSingleEvent()) + timer->active = !timer->active; + else if (timer->firstday) { + timer->firstday = 0; + timer->active = false; + } + else if (timer->active) + timer->SkipToday(); + else + timer->active = true; + timer->Matches(); // refresh start and end time RefreshCurrent(); DisplayCurrent(true); - isyslog(LOG_INFO, "timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de"); + if (timer->firstday) + isyslog(LOG_INFO, "timer %d first day set to %s", timer->Index() + 1, timer->PrintFirstDay()); + else + isyslog(LOG_INFO, "timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de"); Timers.Save(); } return osContinue; @@ -1106,27 +1195,17 @@ eOSState cMenuTimers::Summary(void) eOSState cMenuTimers::ProcessKey(eKeys Key) { - // Must do these before calling cOsdMenu::ProcessKey() because cOsdMenu - // uses them to page up/down: - if (!HasSubMenu()) { - switch (Key) { - case kLeft: - case kRight: return Activate(Key == kRight); - default: break; - } - } - eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch (Key) { - case kLeft: - case kRight: return Activate(Key == kRight); case kOk: return Summary(); case kRed: return Edit(); case kGreen: return New(); case kYellow: return Del(); - case kBlue: if (!Setup.SortTimers) + case kBlue: if (Setup.SortTimers) + OnOff(); + else Mark(); break; default: break; @@ -1350,7 +1429,7 @@ cMenuScheduleItem::cMenuScheduleItem(const cEventInfo *EventInfo) class cMenuSchedule : public cOsdMenu { private: - cThreadLock threadLock; + cMutexLock mutexLock; const cSchedules *schedules; bool now, next; int otherChannel; @@ -1370,7 +1449,7 @@ cMenuSchedule::cMenuSchedule(void) cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel()); if (channel) { cMenuWhatsOn::SetCurrentChannel(channel->number); - schedules = cDvbApi::PrimaryDvbApi->Schedules(&threadLock); + schedules = cSIProcessor::Schedules(mutexLock); PrepareSchedule(channel); SetHelp(tr("Record"), tr("Now"), tr("Next")); } @@ -1670,26 +1749,34 @@ eOSState cMenuRecordings::Del(void) { cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); if (ri && !ri->IsDirectory()) { -//XXX what if this recording's file is currently in use??? -//XXX if (!ti->recording) { - if (Interface->Confirm(tr("Delete recording?"))) { - cRecording *recording = GetRecording(ri); - if (recording) { - if (recording->Delete()) { - cReplayControl::ClearLastReplayed(ri->FileName()); - cOsdMenu::Del(Current()); - Recordings.Del(recording); - Display(); - if (!Count()) - return osBack; + if (Interface->Confirm(tr("Delete recording?"))) { + cRecordControl *rc = cRecordControls::GetRecordControl(ri->FileName()); + if (rc) { + if (Interface->Confirm(tr("Timer still recording - really delete?"))) { + cTimer *timer = rc->Timer(); + if (timer) { + timer->SkipToday(); + cRecordControls::Process(time(NULL)); + Timers.Save(); } - else - Interface->Error(tr("Error while deleting recording!")); } + else + return osContinue; } -//XXX } -//XXX else -//XXX Interface->Error(tr("Timer is recording!")); + cRecording *recording = GetRecording(ri); + if (recording) { + if (recording->Delete()) { + cReplayControl::ClearLastReplayed(ri->FileName()); + cOsdMenu::Del(Current()); + Recordings.Del(recording); + Display(); + if (!Count()) + return osBack; + } + else + Interface->Error(tr("Error while deleting recording!")); + } + } } return osContinue; } @@ -1735,81 +1822,6 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) return state; } -#ifdef DVDSUPPORT -// --- cMenuDVDItem ---------------------------------------------------------- - -class cMenuDVDItem : public cOsdItem { - private: - int title; - int chapters; - virtual void Set(void); -public: - cMenuDVDItem(int Title, int Chapters); - int Title(void) { return title; } - }; - -cMenuDVDItem::cMenuDVDItem(int Title, int Chapters) -{ - title = Title; - chapters = Chapters; - Set(); -} - -void cMenuDVDItem::Set(void) -{ - char *buffer = NULL; - asprintf(&buffer, " %2d.\tTitle - \t%2d\tChapters", title + 1, chapters); - SetText(buffer, false); -} - -// --- cMenuDVD -------------------------------------------------------------- - -cMenuDVD::cMenuDVD(void) -:cOsdMenu(tr("DVD"), 5, 8, 3) -{ - if ((dvd = cDVD::getDVD())) { - dvd->Open(); - ifo_handle_t *vmg = dvd->openVMG(); - if (vmg) { - int lastTitleID = cReplayControl::LastTitleID(); - dsyslog(LOG_INFO, "DVD: vmg: %p", vmg);//XXX - tt_srpt_t *tt_srpt = vmg->tt_srpt; - dsyslog(LOG_INFO, "DVD: tt_srpt: %p", tt_srpt);//XXX - for (int i = 0; i < tt_srpt->nr_of_srpts; i++) - Add(new cMenuDVDItem(i, tt_srpt->title[i].nr_of_ptts), i == lastTitleID); - } - } - SetHelp(tr("Play"), NULL, NULL, NULL); - Display(); -} - -eOSState cMenuDVD::Play(void) -{ - cMenuDVDItem *ri = (cMenuDVDItem *)Get(Current()); - if (ri) { - cReplayControl::SetDVD(dvd, ri->Title()); - isyslog(LOG_INFO, "DVD: playing title %d", ri->Title()); - return osReplay; - } - return osContinue; -} - -eOSState cMenuDVD::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - - if (state == osUnknown) { - switch (Key) { - case kOk: - case kRed: return Play(); - case kMenu: return osEnd; - default: break; - } - } - return state; -} -#endif //DVDSUPPORT - // --- cMenuSetup ------------------------------------------------------------ class cMenuSetup : public cOsdMenu { @@ -1857,6 +1869,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditBoolItem(tr("UseSubtitle"), &data.UseSubtitle)); Add(new cMenuEditBoolItem(tr("RecordingDirs"), &data.RecordingDirs)); Add(new cMenuEditBoolItem(tr("VideoFormat"), &data.VideoFormat, "4:3", "16:9")); + Add(new cMenuEditBoolItem(tr("RecordDolbyDigital"), &data.RecordDolbyDigital)); Add(new cMenuEditBoolItem(tr("ChannelInfoPos"), &data.ChannelInfoPos, tr("bottom"), tr("top"))); Add(new cMenuEditIntItem( tr("OSDwidth"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); Add(new cMenuEditIntItem( tr("OSDheight"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); @@ -1971,10 +1984,6 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) Add(new cOsdItem(hk(tr("Channels")), osChannels)); Add(new cOsdItem(hk(tr("Timers")), osTimers)); Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); -#ifdef DVDSUPPORT - if (cDVD::DriveExists()) - Add(new cOsdItem(hk(tr("DVD")), osDVD)); -#endif //DVDSUPPORT Add(new cOsdItem(hk(tr("Setup")), osSetup)); if (Commands.Count()) Add(new cOsdItem(hk(tr("Commands")), osCommands)); @@ -2007,13 +2016,7 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) // Color buttons: - const char *DVDbutton = -#ifdef DVDSUPPORT - cDVD::DiscOk() ? tr("Eject") : NULL; -#else - NULL; -#endif //DVDSUPPORT - SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, DVDbutton, cReplayControl::LastReplayed() ? tr("Resume") : NULL); + SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); Display(); lastActivity = time(NULL); SetHasHotkeys(); @@ -2022,9 +2025,6 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) switch (State) { case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break; -#ifdef DVDSUPPORT - case osDVD: AddSubMenu(new cMenuDVD); break; -#endif //DVDSUPPORT default: break; } } @@ -2049,9 +2049,6 @@ eOSState cMenuMain::ProcessKey(eKeys Key) case osChannels: return AddSubMenu(new cMenuChannels); case osTimers: return AddSubMenu(new cMenuTimers); case osRecordings: return AddSubMenu(new cMenuRecordings); -#ifdef DVDSUPPORT - case osDVD: return AddSubMenu(new cMenuDVD); -#endif //DVDSUPPORT case osSetup: return AddSubMenu(new cMenuSetup); case osCommands: return AddSubMenu(new cMenuCommands); case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { @@ -2084,23 +2081,6 @@ eOSState cMenuMain::ProcessKey(eKeys Key) } } break; -#ifdef DVDSUPPORT - case kYellow: if (!HasSubMenu()) { - if (cDVD::DiscOk()) { - // We need to stop replaying a DVD before ejecting, - // otherwise the replay thread crashes. Currently - // checking LastReplayed() is pretty much the only way - // of finding out whether we are currently replaying a DVD - // (i.e. if LastReplayed() returns non-NULL, we are either - // replaying a normal recording, or nothing at all): - if (!cReplayControl::LastReplayed()) - cDvbApi::PrimaryDvbApi->StopReplay(); - cDVD::Eject(); - state = osEnd; - } - } - break; -#endif //DVDSUPPORT case kBlue: if (!HasSubMenu()) state = osReplay; break; @@ -2175,8 +2155,8 @@ void cDisplayChannel::DisplayInfo(void) { if (withInfo) { const cEventInfo *Present = NULL, *Following = NULL; - cThreadLock ThreadLock; - const cSchedules *Schedules = cDvbApi::PrimaryDvbApi->Schedules(&ThreadLock); + cMutexLock MutexLock; + const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock); if (Schedules) { const cSchedule *Schedule = Schedules->GetSchedule(); if (Schedule) { @@ -2350,14 +2330,16 @@ cRecordControl::~cRecordControl() delete fileName; } +#define INSTANT_REC_EPG_LOOKAHEAD 300 // seconds to look into the EPG data for an instant recording + bool cRecordControl::GetEventInfo(void) { cChannel *channel = Channels.GetByNumber(timer->channel); - time_t Time = timer->IsSingleEvent() ? timer->StartTime() + ((Setup.MarginStart * 2) + 1) * 60 : timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2; + time_t Time = timer->active == taActInst ? timer->StartTime() + INSTANT_REC_EPG_LOOKAHEAD : timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2; for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) { { - cThreadLock ThreadLock; - const cSchedules *Schedules = dvbApi->Schedules(&ThreadLock); + cMutexLock MutexLock; + const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock); if (Schedules) { const cSchedule *Schedule = Schedules->GetSchedule(channel->pnr); if (Schedule) { @@ -2481,6 +2463,15 @@ const char *cRecordControls::GetInstantId(const char *LastInstantId) return NULL; } +cRecordControl *cRecordControls::GetRecordControl(const char *FileName) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0) + return RecordControls[i]; + } + return NULL; +} + void cRecordControls::Process(time_t t) { for (int i = 0; i < MAXDVBAPI; i++) { @@ -2548,10 +2539,6 @@ void cProgressBar::Mark(int x, bool Start, bool Current) char *cReplayControl::fileName = NULL; char *cReplayControl::title = NULL; -#ifdef DVDSUPPORT -cDVD *cReplayControl::dvd = NULL;//XXX -int cReplayControl::titleid = 0;//XXX -#endif //DVDSUPPORT cReplayControl::cReplayControl(void) { @@ -2565,10 +2552,6 @@ cReplayControl::cReplayControl(void) if (!dvbApi->StartReplay(fileName)) Interface->Error(tr("Channel locked (recording)!")); } -#ifdef DVDSUPPORT - else if (dvd) - dvbApi->StartDVDplay(dvd, titleid);//XXX -#endif //DVDSUPPORT } cReplayControl::~cReplayControl() @@ -2585,20 +2568,6 @@ void cReplayControl::SetRecording(const char *FileName, const char *Title) title = Title ? strdup(Title) : NULL; } -#ifdef DVDSUPPORT -void cReplayControl::SetDVD(cDVD *DVD, int Title)//XXX -{ - SetRecording(NULL, NULL); - dvd = DVD; - titleid = Title; -} - -int cReplayControl::LastTitleID(void) -{ - return titleid; -} -#endif //DVDSUPPORT - const char *cReplayControl::LastReplayed(void) { return fileName; @@ -2966,7 +2935,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key) else Show(); break; - case kBack: return fileName ? osRecordings : osDVD; + case kBack: return osRecordings; default: return osUnknown; } } diff --git a/menu.h b/menu.h index 82fd64032..9e49bf65e 100644 --- a/menu.h +++ b/menu.h @@ -4,16 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.35 2002/01/20 13:38:34 kls Exp $ + * $Id: menu.h 1.37 2002/02/24 12:40:37 kls Exp $ */ #ifndef _MENU_H #define _MENU_H #include "dvbapi.h" -#ifdef DVDSUPPORT -#include "dvd.h" -#endif //DVDSUPPORT #include "osd.h" #include "recording.h" @@ -43,18 +40,6 @@ class cDisplayChannel : public cOsdBase { virtual eOSState ProcessKey(eKeys Key); }; -#ifdef DVDSUPPORT -class cMenuDVD : public cOsdMenu { -private: - cDVD *dvd;//XXX member really necessary??? - eOSState Play(void); - eOSState Eject(void); -public: - cMenuDVD(void); - virtual eOSState ProcessKey(eKeys Key); - }; -#endif //DVDSUPPORT - class cMenuRecordingItem; class cMenuRecordings : public cOsdMenu { @@ -92,6 +77,8 @@ class cRecordControl { void Stop(bool KeepInstant = false); bool IsInstant(void) { return instantId; } const char *InstantId(void) { return instantId; } + const char *FileName(void) { return fileName; } + cTimer *Timer(void) { return timer; } }; class cRecordControls { @@ -103,6 +90,7 @@ class cRecordControls { static void Stop(cDvbApi *DvbApi); static bool StopPrimary(bool DoIt = false); static const char *GetInstantId(const char *LastInstantId); + static cRecordControl *GetRecordControl(const char *FileName); static void Process(time_t t); static bool Active(void); }; @@ -122,10 +110,6 @@ class cReplayControl : public cOsdBase { void Show(int Seconds = 0); void Hide(void); static char *fileName; -#ifdef DVDSUPPORT - static cDVD *dvd;//XXX member really necessary??? - static int titleid;//XXX -#endif //DVDSUPPORT static char *title; void DisplayAtBottom(const char *s = NULL); void ShowMode(void); @@ -141,10 +125,6 @@ class cReplayControl : public cOsdBase { virtual eOSState ProcessKey(eKeys Key); bool Visible(void) { return visible; } static void SetRecording(const char *FileName, const char *Title); -#ifdef DVDSUPPORT - static void SetDVD(cDVD *DVD, int Title);//XXX - static int LastTitleID(void); -#endif //DVDSUPPORT static const char *LastReplayed(void); static void ClearLastReplayed(const char *FileName); }; diff --git a/osd.h b/osd.h index 21c931540..4eb2a22dd 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.25 2002/01/20 10:42:14 kls Exp $ + * $Id: osd.h 1.26 2002/02/24 12:55:16 kls Exp $ */ #ifndef __OSD_H @@ -27,7 +27,6 @@ enum eOSState { osUnknown, osCommands, osRecord, osReplay, - osDVD, osStopRecord, osStopReplay, osCancelEdit, diff --git a/recording.c b/recording.c index d82288756..4d07434a0 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.51 2002/02/10 15:41:23 kls Exp $ + * $Id: recording.c 1.54 2002/02/24 11:21:42 kls Exp $ */ #include "recording.h" @@ -122,7 +122,7 @@ void AssertFreeDiskSpace(int Priority) return; } // Unable to free disk space, but there's nothing we can do about that... - Interface->Confirm(tr("Low disk space"), 30); + Interface->Confirm(tr("Low disk space!"), 30); } LastFreeDiskCheck = time(NULL); } @@ -203,7 +203,6 @@ static char *ExchangeChars(char *s, bool ToFileSystem) { char *p = s; while (*p) { -#define VFAT 1 #ifdef VFAT // The VFAT file system can't handle all characters, so we // have to take extra efforts to encode/decode them: @@ -225,7 +224,12 @@ static char *ExchangeChars(char *s, bool ToFileSystem) case '=': case '0' ... '9': case 'a' ... 'z': - case 'A' ... 'Z': break; + case 'A' ... 'Z': + case '': case '': + case '': case '': + case '': case '': + case '': + break; // characters that can be mapped to other characters: case ' ': *p = '_'; break; case '~': *p = '/'; break; diff --git a/svdrp.c b/svdrp.c index 4cdf2fbba..228003ea0 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.30 2002/02/02 15:39:46 kls Exp $ + * $Id: svdrp.c 1.33 2002/02/24 14:16:03 kls Exp $ */ #include "svdrp.h" @@ -118,6 +118,52 @@ int cSocket::Accept(void) return -1; } +// --- cPUTEhandler ---------------------------------------------------------- + +cPUTEhandler::cPUTEhandler(void) +{ + if ((f = tmpfile()) != NULL) { + status = 354; + message = "Enter EPG data, end with \".\" on a line by itself"; + } + else { + LOG_ERROR; + status = 554; + message = "Error while opening temporary file"; + } +} + +cPUTEhandler::~cPUTEhandler() +{ + if (f) + fclose(f); +} + +bool cPUTEhandler::Process(const char *s) +{ + if (f) { + if (strcmp(s, ".") != 0) { + fputs(s, f); + fputc('\n', f); + return true; + } + else { + rewind(f); + if (cSchedules::Read(f)) { + status = 250; + message = "EPG data processed"; + } + else { + status = 451; + message = "Error while processing EPG data"; + } + fclose(f); + f = NULL; + } + } + return false; +} + // --- cSVDRP ---------------------------------------------------------------- #define MAXHELPTOPIC 10 @@ -192,6 +238,11 @@ const char *HelpPages[] = { " zero, this means that the timer is currently recording and has started\n" " at the given time. The first value in the resulting line is the number\n" " of the timer.", + "PUTE\n" + " Put data into the EPG list. The data entered has to strictly follow the\n" + " format defined in VDR/FORMATS for the 'epg.data' file. A '.' on a line\n" + " by itself terminates the input and starts processing of the data (all\n" + " entered data is buffered until the terminating '.' is seen).", "UPDT <settings>\n" " Updates a timer. Settings must be in the same format as returned\n" " by the LSTT command. If a timer with the same channel, day, start\n" @@ -209,6 +260,7 @@ const char *HelpPages[] = { 220 VDR service ready 221 VDR service closing transmission channel 250 Requested VDR action okay, completed + 354 Start sending EPG data 451 Requested action aborted: local error in processing 500 Syntax error, command unrecognized 501 Syntax error in parameters or arguments @@ -252,6 +304,7 @@ const char *GetHelpPage(const char *Cmd) cSVDRP::cSVDRP(int Port) :socket(Port) { + PUTEhandler = NULL; numChars = 0; message = NULL; lastActivity = 0; @@ -273,6 +326,7 @@ void cSVDRP::Close(bool Timeout) Reply(221, "%s closing connection%s", buffer, Timeout ? " (timeout)" : ""); isyslog(LOG_INFO, "closing SVDRP connection"); //TODO store IP#??? file.Close(); + DELETENULL(PUTEhandler); } } @@ -583,6 +637,8 @@ void cSVDRP::CmdLSTC(const char *Option) } if (next) Reply(250, "%d %s", next->number, next->ToText()); + else + Reply(501, "Channel \"%s\" not defined", Option); } } else if (Channels.MaxNumber() >= 1) { @@ -600,8 +656,8 @@ void cSVDRP::CmdLSTC(const char *Option) void cSVDRP::CmdLSTE(const char *Option) { - cThreadLock ThreadLock; - const cSchedules *Schedules = cDvbApi::PrimaryDvbApi->Schedules(&ThreadLock); + cMutexLock MutexLock; + const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock); if (Schedules) { FILE *f = fdopen(file, "w"); if (f) { @@ -827,6 +883,15 @@ void cSVDRP::CmdNEXT(const char *Option) Reply(550, "No active timers"); } +void cSVDRP::CmdPUTE(const char *Option) +{ + delete PUTEhandler; + PUTEhandler = new cPUTEhandler; + Reply(PUTEhandler->Status(), PUTEhandler->Message()); + if (PUTEhandler->Status() != 354) + DELETENULL(PUTEhandler); +} + void cSVDRP::CmdUPDT(const char *Option) { if (*Option) { @@ -859,6 +924,14 @@ void cSVDRP::CmdUPDT(const char *Option) void cSVDRP::Execute(char *Cmd) { + // handle PUTE data: + if (PUTEhandler) { + if (!PUTEhandler->Process(Cmd)) { + Reply(PUTEhandler->Status(), PUTEhandler->Message()); + DELETENULL(PUTEhandler); + } + return; + } // skip leading whitespace: Cmd = skipspace(Cmd); // find the end of the command word: @@ -888,6 +961,7 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("NEWT")) CmdNEWT(s); else if (CMD("NEXT")) CmdNEXT(s); else if (CMD("UPDT")) CmdUPDT(s); + else if (CMD("PUTE")) CmdPUTE(s); else if (CMD("QUIT")) Close(); else Reply(500, "Command unrecognized: \"%s\"", Cmd); } diff --git a/svdrp.h b/svdrp.h index e68a92e43..42e5b6911 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.13 2001/11/04 11:20:46 kls Exp $ + * $Id: svdrp.h 1.14 2002/02/24 10:48:21 kls Exp $ */ #ifndef __SVDRP_H @@ -26,11 +26,25 @@ class cSocket { int Accept(void); }; +class cPUTEhandler { +private: + FILE *f; + int status; + const char *message; +public: + cPUTEhandler(void); + ~cPUTEhandler(); + bool Process(const char *s); + int Status(void) { return status; } + const char *Message(void) { return message; } + }; + class cSVDRP { private: cSocket socket; cFile file; cRecordings Recordings; + cPUTEhandler *PUTEhandler; uint numChars; char cmdLine[MAXPARSEBUFFER]; char *message; @@ -57,6 +71,7 @@ class cSVDRP { void CmdNEWC(const char *Option); void CmdNEWT(const char *Option); void CmdNEXT(const char *Option); + void CmdPUTE(const char *Option); void CmdUPDT(const char *Option); void Execute(char *Cmd); public: diff --git a/thread.c b/thread.c index 7e5b0ea7f..94ba86057 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.16 2001/10/27 13:23:06 kls Exp $ + * $Id: thread.c 1.18 2002/02/23 13:49:06 kls Exp $ */ #include "thread.h" @@ -190,6 +190,32 @@ bool cThread::EmergencyExit(bool Request) return emergencyExitRequested = true; // yes, it's an assignment, not a comparison! } +// --- cMutexLock ------------------------------------------------------------ + +cMutexLock::cMutexLock(cMutex *Mutex) +{ + mutex = NULL; + locked = false; + Lock(Mutex); +} + +cMutexLock::~cMutexLock() +{ + if (mutex && locked) + mutex->Unlock(); +} + +bool cMutexLock::Lock(cMutex *Mutex) +{ + if (Mutex && !mutex) { + mutex = Mutex; + Mutex->Lock(); + locked = true; + return true; + } + return false; +} + // --- cThreadLock ----------------------------------------------------------- cThreadLock::cThreadLock(cThread *Thread) @@ -277,8 +303,11 @@ bool cPipe::Open(const char *Command, const char *Mode) _exit(-1); } else { - for (int i = STDERR_FILENO + 1; i < fd[1 - iopipe]; i++) - close(i); //close all dup'ed filedescriptors + for (int i = 0; i <= fd[1]; i++) { + if (i == STDIN_FILENO || i == STDOUT_FILENO || i == STDERR_FILENO) + continue; + close(i); // close all dup'ed filedescriptors + } if (execl("/bin/sh", "sh", "-c", Command, NULL) == -1) { LOG_ERROR_STR(Command); close(fd[1 - iopipe]); diff --git a/thread.h b/thread.h index 4547addeb..3ac398a2c 100644 --- a/thread.h +++ b/thread.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.11 2001/10/27 13:22:20 kls Exp $ + * $Id: thread.h 1.12 2002/02/23 13:53:38 kls Exp $ */ #ifndef __THREAD_H @@ -69,6 +69,22 @@ class cThread { static bool EmergencyExit(bool Request = false); }; +// cMutexLock can be used to easily set a lock on mutex and make absolutely +// sure that it will be unlocked when the block will be left. Several locks can +// be stacked, so a function that makes many calls to another function which uses +// cMutexLock may itself use a cMutexLock to make one longer lock instead of many +// short ones. + +class cMutexLock { +private: + cMutex *mutex; + bool locked; +public: + cMutexLock(cMutex *Mutex = NULL); + ~cMutexLock(); + bool Lock(cMutex *Mutex); + }; + // cThreadLock can be used to easily set a lock in a thread and make absolutely // sure that it will be unlocked when the block will be left. Several locks can // be stacked, so a function that makes many calls to another function which uses diff --git a/tools.c b/tools.c index e95bdf8d2..3764a6441 100644 --- a/tools.c +++ b/tools.c @@ -4,17 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.57 2002/02/05 18:16:52 kls Exp $ + * $Id: tools.c 1.59 2002/02/17 12:57:23 kls Exp $ */ #include "tools.h" #include <ctype.h> #include <dirent.h> #include <errno.h> -#if defined(DEBUG_OSD) -#include <ncurses.h> -#undef ERR //XXX ncurses defines this - but this clashes with newer system header files -#endif #include <stdlib.h> #include <sys/time.h> #include <time.h> @@ -466,6 +462,20 @@ bool SpinUpDisk(const char *FileName) return false; } +const char *WeekDayName(int WeekDay) +{ + static char buffer[4]; + WeekDay = WeekDay == 0 ? 6 : WeekDay - 1; // we start with monday==0! + if (0 <= WeekDay && WeekDay <= 6) { + const char *day = tr("MonTueWedThuFriSatSun"); + day += WeekDay * 3; + strncpy(buffer, day, 3); + return buffer; + } + else + return "???"; +} + const char *DayDateTime(time_t t) { static char buffer[32]; @@ -473,11 +483,7 @@ const char *DayDateTime(time_t t) time(&t); struct tm tm_r; tm *tm = localtime_r(&t, &tm_r); - int weekday = tm->tm_wday == 0 ? 6 : tm->tm_wday - 1; // we start with monday==0! - const char *day = tr("MonTueWedThuFriSatSun"); - day += weekday * 3; - strncpy(buffer, day, 3); - snprintf(buffer + 3, sizeof(buffer) - 3, " %2d.%02d %02d:%02d", tm->tm_mday, tm->tm_mon + 1, tm->tm_hour, tm->tm_min); + snprintf(buffer, sizeof(buffer), "%s %2d.%02d %02d:%02d", WeekDayName(tm->tm_wday), tm->tm_mday, tm->tm_mon + 1, tm->tm_hour, tm->tm_min); return buffer; } @@ -545,9 +551,6 @@ bool cFile::Ready(bool Wait) bool cFile::AnyFileReady(int FileDes, int TimeoutMs) { -#ifdef DEBUG_OSD - refresh(); -#endif fd_set set; FD_ZERO(&set); for (int i = 0; i < maxFiles; i++) { @@ -566,9 +569,6 @@ bool cFile::AnyFileReady(int FileDes, int TimeoutMs) bool cFile::FileReady(int FileDes, int TimeoutMs) { -#ifdef DEBUG_OSD - refresh(); -#endif fd_set set; struct timeval timeout; FD_ZERO(&set); @@ -582,9 +582,6 @@ bool cFile::FileReady(int FileDes, int TimeoutMs) bool cFile::FileReadyForWriting(int FileDes, int TimeoutMs) { -#ifdef DEBUG_OSD - refresh(); -#endif fd_set set; struct timeval timeout; FD_ZERO(&set); diff --git a/tools.h b/tools.h index 9663a8edd..08a567234 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.41 2002/02/03 12:36:25 kls Exp $ + * $Id: tools.h 1.42 2002/02/17 12:57:44 kls Exp $ */ #ifndef __TOOLS_H @@ -66,6 +66,7 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false); bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false); char *ReadLink(const char *FileName); bool SpinUpDisk(const char *FileName); +const char *WeekDayName(int WeekDay); // returns a statically allocated string! const char *DayDateTime(time_t t = 0); // returns a statically allocated string! class cFile { diff --git a/vdr.c b/vdr.c index 9d5167b46..90c1d8433 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.95 2002/02/10 15:12:43 kls Exp $ + * $Id: vdr.c 1.97 2002/02/24 12:55:10 kls Exp $ */ #include <getopt.h> @@ -32,9 +32,7 @@ #include <unistd.h> #include "config.h" #include "dvbapi.h" -#ifdef DVDSUPPORT -#include "dvd.h" -#endif //DVDSUPPORT +#include "eit.h" #include "i18n.h" #include "interface.h" #include "menu.h" @@ -104,14 +102,13 @@ int main(int argc, char *argv[]) { "shutdown", required_argument, NULL, 's' }, { "terminal", required_argument, NULL, 't' }, { "video", required_argument, NULL, 'v' }, - { "dvd", required_argument, NULL, 'V' }, { "watchdog", required_argument, NULL, 'w' }, { NULL } }; int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:r:s:t:v:V:w:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:r:s:t:v:w:", long_options, &option_index)) != -1) { switch (c) { case 'a': cDvbApi::SetAudioCommand(optarg); break; @@ -152,7 +149,6 @@ int main(int argc, char *argv[]) " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" " -t TTY, --terminal=TTY controlling tty\n" " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" - " -V DEV, --dvd=DEV use DEV as the DVD device (default: %s)\n" " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n" " seconds (default: %d); '0' disables the watchdog\n" "\n" @@ -160,11 +156,6 @@ int main(int argc, char *argv[]) cSIProcessor::GetEpgDataFileName() ? cSIProcessor::GetEpgDataFileName() : "'-'", DEFAULTSVDRPPORT, VideoDirectory, -#ifdef DVDSUPPORT - cDVD::DeviceName(), -#else - "no DVD support", -#endif //DVDSUPPORT DEFAULTWATCHDOG ); return 0; @@ -196,18 +187,6 @@ int main(int argc, char *argv[]) while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') optarg[strlen(optarg) - 1] = 0; break; - case 'V': -#ifdef DVDSUPPORT - cDVD::SetDeviceName(optarg); - if (!cDVD::DriveExists()) { - fprintf(stderr, "vdr: DVD drive not found: %s\n", optarg); - return 2; - } -#else - fprintf(stderr, "vdr: DVD support has not been compiled in!"); - return 2; -#endif //DVDSUPPORT - break; case 'w': if (isnumber(optarg)) { int t = atoi(optarg); if (t >= 0) { @@ -286,6 +265,8 @@ int main(int argc, char *argv[]) cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB); + cSIProcessor::Read(); + Channels.SwitchTo(Setup.CurrentChannel); cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true); @@ -406,12 +387,6 @@ int main(int argc, char *argv[]) DELETENULL(ReplayControl); ReplayControl = new cReplayControl; break; -#ifdef DVDSUPPORT - case osDVD: DELETENULL(Menu); - DELETENULL(ReplayControl); - Menu = new cMenuMain(ReplayControl, osDVD); - break; -#endif //DVDSUPPORT case osStopReplay: DELETENULL(*Interact); DELETENULL(ReplayControl); From 0bad88704ba7e0346c49bb28be28e709473d9244 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Mon, 25 Feb 2002 18:00:00 +0100 Subject: [PATCH 036/307] Version 1.0.0pre2 - Fixed a crash in case there is no 'epg.data' at program start (thanks to Andreas Schultz). --- CONTRIBUTORS | 1 + HISTORY | 5 +++++ config.h | 4 ++-- eit.c | 4 +++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index bbceff25e..1acaafcb9 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -124,6 +124,7 @@ Andreas Schultz <aschultz@warp10.net> for adding support for replaying DVDs (much of this was derived from dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>) for adding PTS to the converted PCM audio when replaying a DVD + for fixing a crash in case there is no 'epg.data' at program start Aaron Holtzman for writing 'ac3dec' diff --git a/HISTORY b/HISTORY index ea81172d8..2b0093e0f 100644 --- a/HISTORY +++ b/HISTORY @@ -1042,3 +1042,8 @@ Video Disk Recorder Revision History inadvertently overwriting an existing VDR directory with a new version. - Added a missing error message in SVDRP command LSTC in case the given channel can't be found. + +2002-02-25: Version 1.0.0pre2 + +- Fixed a crash in case there is no 'epg.data' at program start (thanks to + Andreas Schultz). diff --git a/config.h b/config.h index 35f1590c0..b5860d18b 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.99 2002/02/24 13:39:47 kls Exp $ + * $Id: config.h 1.100 2002/02/25 16:29:09 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "1.0.0pre1" +#define VDRVERSION "1.0.0pre2" #define MAXPRIORITY 99 #define MAXLIFETIME 99 diff --git a/eit.c b/eit.c index bd43fe925..8f4c03724 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.37 2002/02/23 17:11:19 kls Exp $ + * $Id: eit.c 1.38 2002/02/25 16:30:42 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -1022,6 +1022,8 @@ bool cSIProcessor::Read(FILE *f) return false; } } + else + return false; } bool result = cSchedules::Read(f); if (OwnFile) From a001a4bf97715d62b387d1da9fd1e48382508428 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 3 Mar 2002 18:00:00 +0100 Subject: [PATCH 037/307] Version 1.0.0pre3 - Fixed parsing 'E' records in epg2html.pl. - Fixed a deadlock when switching channels via Schedule/Now|Next/Switch (reported by Martin Hammerschmid). - Changed the meaning of the 'Ca' parameter in 'channels.conf'. Each channel can now define which decryption method it needs in order to be accessed. The new configuration file 'ca.conf' contains the defined values, and the default 'channels.conf' has been modifed to contain the new values for 'Premiere World' and 'ORF'. If you use the default 'channels.conf' and have the conditional access hardware to receive encrypted channels, please make sure you copy the file 'ca.conf' into your /video directory (or wherever your configuration files are located) and go into the "Setup" menu and set the CICAM values according to your hardware setup. Currently there are two possible CICAM entries per DVB card, so any card can implement up to two different conditional access modes (besides the default "Free To Air" mode, which is always assumed to be available on any DVB card). - Updated French language texts (thanks to Jean-Claude Repetto). --- CONTRIBUTORS | 1 + FORMATS | 19 ++++++- HISTORY | 19 +++++++ MANUAL | 8 +++ ca.conf | 22 ++++++++ channels.conf | 138 +++++++++++++++++++++++++------------------------- config.c | 73 +++++++++++++++++++++++++- config.h | 25 ++++++++- dvbapi.c | 127 +++++++++++++++++++++++++++++++++------------- dvbapi.h | 31 +++++++++--- eit.c | 22 ++------ epg2html.pl | 4 +- i18n.c | 76 +++++++++++++-------------- menu.c | 65 +++++++++++++++++++++++- vdr.c | 3 +- 15 files changed, 457 insertions(+), 176 deletions(-) create mode 100644 ca.conf diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1acaafcb9..ed63a4bb1 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -39,6 +39,7 @@ Martin Hammerschmid <martin@hammerschmid.com> for suggesting to display the direct channel select input on the OSD for suggesting to use the "Blue" button in the main menu to resume replay for implementing pege up/down with the "Left" and "Right" keys + for detecting a deadlock when switching channels via Schedule/Now|Next/Switch Bastian Guse <bastian@nocopy.de> for writing the FORMATS entry for timers.conf diff --git a/FORMATS b/FORMATS index 0da293977..91903384e 100644 --- a/FORMATS +++ b/FORMATS @@ -29,8 +29,9 @@ Video Disk Recorder File Formats If this channel also carries Dolby Digital sound, the Dolby PIDs follow the audio PIDs, separated by a semicolon, as in "...:101,102;103,104:..." - Teletext PID - - Conditional Access (0 = Free To Air, 1 = can be decrypted by the first - DVB card, 2 = can be decrypted by the second DVB card) + - Conditional Access (0 = Free To Air, 1..4 = explicitly requires the DVB card + with the given number, >=100 = requires a specific decryption method defined + in 'ca.conf'). - Program Number Fields marked with ** are only meaningful for DVB-S receivers. @@ -38,6 +39,20 @@ Video Disk Recorder File Formats Fields marked with *** are only meaningful for DVB-S and DVB-C receivers. DVB-T receivers simply ignore these. +* ca.conf + + This file contains the definitions of the various conditional access code + numbers. Anything after (and including) a '#' character is comment. + Value lines consist of an integer number, followed by a text describing + this decryption method (typically the name of the pay tv service using this + decryption method). + The special value 0 means "Free To Air", i.e. can be used for channels that + don't require additional decryption hardware. + The values 1..4 can be used for channels that for some reason explicitly + need a given DVB card (for backward compatibility). + The values defined in this file are the ones used in the 'Ca' parameter of + 'channels.conf'. + * timers.conf This file contains the timer setup. diff --git a/HISTORY b/HISTORY index 2b0093e0f..84c1460e1 100644 --- a/HISTORY +++ b/HISTORY @@ -1047,3 +1047,22 @@ Video Disk Recorder Revision History - Fixed a crash in case there is no 'epg.data' at program start (thanks to Andreas Schultz). + +2002-03-03: Version 1.0.0pre3 + +- Fixed parsing 'E' records in epg2html.pl. +- Fixed a deadlock when switching channels via Schedule/Now|Next/Switch (reported + by Martin Hammerschmid). +- Changed the meaning of the 'Ca' parameter in 'channels.conf'. Each channel can + now define which decryption method it needs in order to be accessed. The new + configuration file 'ca.conf' contains the defined values, and the default + 'channels.conf' has been modifed to contain the new values for 'Premiere World' + and 'ORF'. If you use the default 'channels.conf' and have the conditional + access hardware to receive encrypted channels, please make sure you copy the + file 'ca.conf' into your /video directory (or wherever your configuration files + are located) and go into the "Setup" menu and set the CICAM values according + to your hardware setup. Currently there are two possible CICAM entries per + DVB card, so any card can implement up to two different conditional access + modes (besides the default "Free To Air" mode, which is always assumed to be + available on any DVB card). +- Updated French language texts (thanks to Jean-Claude Repetto). diff --git a/MANUAL b/MANUAL index 320d24dad..c4cda08a5 100644 --- a/MANUAL +++ b/MANUAL @@ -526,6 +526,14 @@ Video Disk Recorder User's Manual 0 = off 1 = on + CaCaps (no default) Defines the "Conditional Access Capabilities" of a DVB + card. The value consists of the card number, followed by + a list of decryption method values (defined in 'ca.conf'). + For instance + CaCaps = 3 101 102 + would define that card number 3 is able to decrypt + "Premiere World" and the "ORF". + * Executing system commands The "Main" menu option "Commands" allows you to execute any system commands diff --git a/ca.conf b/ca.conf new file mode 100644 index 000000000..7024ee427 --- /dev/null +++ b/ca.conf @@ -0,0 +1,22 @@ +# Conditional Access configuration for VDR +# +# Format: +# +# number description +# +# Please contact kls@cadsoft.de before assigning a new number +# to a description, in order to keep them unique. + +0 Free To Air + +# BetaCrypt + +101 Premiere World +102 ORF + +# Special values to "hard code" a channel to a specific DVB card: + +1 DVB 1 +2 DVB 2 +3 DVB 3 +4 DVB 4 diff --git a/channels.conf b/channels.conf index 4642edc51..db1cbf41b 100644 --- a/channels.conf +++ b/channels.conf @@ -15,8 +15,8 @@ ZDF:11954:h:0:27500:110:120:130:0:28006 3sat:11954:h:0:27500:210:220:230:0:28007 KiKa:11954:h:0:27500:310:320:330:0:28008 arte:11836:h:0:27500:401:402:404:0:28109 -ORF1:12692:h:0:22000:160:161:165:3:13001 -ORF2:12692:h:0:22000:500:501:505:3:13002 +ORF1:12692:h:0:22000:160:161:165:102:13001 +ORF2:12692:h:0:22000:500:501:505:102:13002 ORF Sat:11954:h:0:27500:506:507:0:0:28010 ZDF.info:11954:h:0:27500:610:620:0:0:28011 CNN:12168:v:0:27500:165:100:0:0:28512 @@ -49,82 +49,82 @@ B1:12110:h:0:27500:601:602:604:0:28206 ARD Online-Kanal:12722:h:0:22000:0:701:0:0:0 :Premiere World Premiere World:11797:h:0:27500:255:256:32:0:8 -Premiere 1:11797:h:0:27500:511:512:0:3:10 -Premiere 2:11797:h:0:27500:1791:1792:0:3:11 -Premiere 3:11797:h:0:27500:2303:2304:0:3:43 -Premiere One:12032:h:0:27500:3071:3072:0:3:51 -Premiere Star:11797:h:0:27500:767:768:0:3:9 -Premiere Sci-Fi:11797:h:0:27500:1535:1536:0:3:41 -Premiere Action:11797:h:0:27500:1023:1024:0:3:20 -Premiere X-Action:11798:h:0:27500:2047:2048:0:3:50 -Premiere Comedy:11797:h:0:27500:1279:1280:0:3:29 -13th Street:12031:h:0:27500:2303:2304:0:3:42 -Studio Universal:12090:V:0:27500:255:256:0:3:36 -Filmpalast:12031:h:0:27500:2559:2560:0:3:516 -Heimatkanal:12031:h:0:27500:2815:2816:0:3:517 -Discovery Channel:12031:h:0:27500:1791:1792:0:3:14 -Planet:12090:V:0:27500:1279:1280:0:3:13 -Fox Kids:12031:h:0:27500:1279:1280:0:3:28 -Fox Kids Trkce:11914:H:0:27500:767:768:8191:3:54 -Junior:12031:h:0:27500:255:256:0:3:19 -K-Toon:12031:h:0:27500:511:512:0:3:12 -Disney Channel:12090:V:0:27500:767:768:0:3:34 -Sunset:12031:h:0:27500:1023:1024:0:3:16 -Krimi&Co:12031:h:0:27500:1535:1536:0:3:23 -Goldstar TV:12031:h:0:27500:3839:3840:0:3:518 -Classica:12031:h:0:27500:767:768:0:3:15 -Seasons:12090:V:0:27500:511:512:0:3:33 +Premiere 1:11797:h:0:27500:511:512:0:101:10 +Premiere 2:11797:h:0:27500:1791:1792:0:101:11 +Premiere 3:11797:h:0:27500:2303:2304:0:101:43 +Premiere One:12032:h:0:27500:3071:3072:0:101:51 +Premiere Star:11797:h:0:27500:767:768:0:101:9 +Premiere Sci-Fi:11797:h:0:27500:1535:1536:0:101:41 +Premiere Action:11797:h:0:27500:1023:1024:0:101:20 +Premiere X-Action:11798:h:0:27500:2047:2048:0:101:50 +Premiere Comedy:11797:h:0:27500:1279:1280:0:101:29 +13th Street:12031:h:0:27500:2303:2304:0:101:42 +Studio Universal:12090:V:0:27500:255:256:0:101:36 +Filmpalast:12031:h:0:27500:2559:2560:0:101:516 +Heimatkanal:12031:h:0:27500:2815:2816:0:101:517 +Discovery Channel:12031:h:0:27500:1791:1792:0:101:14 +Planet:12090:V:0:27500:1279:1280:0:101:13 +Fox Kids:12031:h:0:27500:1279:1280:0:101:28 +Fox Kids Trkce:11914:H:0:27500:767:768:8191:101:54 +Junior:12031:h:0:27500:255:256:0:101:19 +K-Toon:12031:h:0:27500:511:512:0:101:12 +Disney Channel:12090:V:0:27500:767:768:0:101:34 +Sunset:12031:h:0:27500:1023:1024:0:101:16 +Krimi&Co:12031:h:0:27500:1535:1536:0:101:23 +Goldstar TV:12031:h:0:27500:3839:3840:0:101:518 +Classica:12031:h:0:27500:767:768:0:101:15 +Seasons:12090:V:0:27500:511:512:0:101:33 :Cinedom -Cinedom Deluxe:11758:h:0:27500:255:256,257;259:0:3:189 -Cinedom 1A:11758:h:0:27500:511:512,513:0:3:190 -Cinedom 1B:12070:h:0:27500:1535:1536,1537:0:3:178 -Cinedom 1C:11720:h:0:27500:511:512,513:0:3:180 -Cinedom 1D:11720:h:0:27500:1535:1536,1537:0:3:176 -Cinedom 2A:11758:h:0:27500:1023:1024,1025:0:3:193 -Cinedom 2B:11720:h:0:27500:1279:1280:0:3:183 -Cinedom 2C:12070:h:0:27500:1791:1792:0:3:179 -Cinedom 2D:12070:h:0:27500:511:512:0:3:184 -Cinedom 2E:12070:h:0:27500:1279:1280:0:3:188 -Cinedom 3A:11758:h:0:27500:2559:2560:0:3:192 -Cinedom 3B:11758:h:0:27500:1535:1536:0:3:195 -Cinedom 3C:12070:h:0:27500:767:768:0:3:185 -Cinedom 3D:11720:h:0:27500:1023:1024:0:3:182 -Cinedom 4A:11758:h:0:27500:767:768:0:3:191 -Cinedom 4B:11720:h:0:27500:767:768:0:3:181 -Cinedom 4C:12070:h:0:27500:2047:2048:0:3:187 -Cinedom 5A:11758:h:0:27500:1279:1280:0:3:194 -Cinedom 5B:11720:h:0:27500:1791:1792:0:3:177 -Cinedom 5C:12070:h:0:27500:1023:1024:0:3:186 +Cinedom Deluxe:11758:h:0:27500:255:256,257;259:0:101:189 +Cinedom 1A:11758:h:0:27500:511:512,513:0:101:190 +Cinedom 1B:12070:h:0:27500:1535:1536,1537:0:101:178 +Cinedom 1C:11720:h:0:27500:511:512,513:0:101:180 +Cinedom 1D:11720:h:0:27500:1535:1536,1537:0:101:176 +Cinedom 2A:11758:h:0:27500:1023:1024,1025:0:101:193 +Cinedom 2B:11720:h:0:27500:1279:1280:0:101:183 +Cinedom 2C:12070:h:0:27500:1791:1792:0:101:179 +Cinedom 2D:12070:h:0:27500:511:512:0:101:184 +Cinedom 2E:12070:h:0:27500:1279:1280:0:101:188 +Cinedom 3A:11758:h:0:27500:2559:2560:0:101:192 +Cinedom 3B:11758:h:0:27500:1535:1536:0:101:195 +Cinedom 3C:12070:h:0:27500:767:768:0:101:185 +Cinedom 3D:11720:h:0:27500:1023:1024:0:101:182 +Cinedom 4A:11758:h:0:27500:767:768:0:101:191 +Cinedom 4B:11720:h:0:27500:767:768:0:101:181 +Cinedom 4C:12070:h:0:27500:2047:2048:0:101:187 +Cinedom 5A:11758:h:0:27500:1279:1280:0:101:194 +Cinedom 5B:11720:h:0:27500:1791:1792:0:101:177 +Cinedom 5C:12070:h:0:27500:1023:1024:0:101:186 :Beta Digital N24:12480:v:0:27500:2047:2048:0:0:47 CNBC:11954:h:0:27500:510:520:0:0:28010 Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199 :PW Erotic -Beate-Uhse.TV:11758:h:0:27500:3839:3840:0:3:21 -Blue Movie 1:11758:h:0:27500:1791:1792:0:3:513 -Blue Movie 2:11758:h:0:27500:2047:2048:0:3:514 -Blue Movie 3:11758:h:0:27500:2303:2304:0:3:515 +Beate-Uhse.TV:11758:h:0:27500:3839:3840:0:101:21 +Blue Movie 1:11758:h:0:27500:1791:1792:0:101:513 +Blue Movie 2:11758:h:0:27500:2047:2048:0:101:514 +Blue Movie 3:11758:h:0:27500:2303:2304:0:101:515 :Sportsworld -Premiere Sport 1:11720:h:0:27500:255:256,257:0:3:17 -Premiere Sport 2:12070:h:0:27500:3839:3840:0:3:27 -Premiere Sport 3:12070:h:0:27500:255:256:0:3:26 +Premiere Sport 1:11720:h:0:27500:255:256,257:0:101:17 +Premiere Sport 2:12070:h:0:27500:3839:3840:0:101:27 +Premiere Sport 3:12070:h:0:27500:255:256:0:101:26 :Formel 1 -Infokanal:11720:h:0:27500:3071:3072:0:3:244 -Multikanal:11720:h:0:27500:2815:2816:0:3:243 -Supersignal:11720:h:0:27500:255:256:0:3:17 -Verfolgerfeld:11720:h:0:27500:2303:2304:0:3:241 -Cockpitkanal:11720:h:0:27500:2559:2560:0:3:242 -Boxengasse:11720:h:0:27500:2047:2048:0:3:240 +Infokanal:11720:h:0:27500:3071:3072:0:101:244 +Multikanal:11720:h:0:27500:2815:2816:0:101:243 +Supersignal:11720:h:0:27500:255:256:0:101:17 +Verfolgerfeld:11720:h:0:27500:2303:2304:0:101:241 +Cockpitkanal:11720:h:0:27500:2559:2560:0:101:242 +Boxengasse:11720:h:0:27500:2047:2048:0:101:240 :Premiere World Bundesliga -Superdom:11758:h:0:27500:2815:8192:0:3:18 -BuLi-Konferenz:11758:h:0:27500:3327:3328,3329:0:3:215 -BuLi-Spiel 1:11720:h:0:27500:255:256,257:0:3:17 -BuLi-Spiel 2:11720:h:0:27500:2047:2048,2049:0:3:240 -BuLi-Spiel 3:11720:h:0:27500:2303:2304,2305:0:3:241 -BuLi-Spiel 4:11720:h:0:27500:2559:2560,2561:0:3:242 -BuLi-Spiel 5:11720:h:0:27500:2815:2816,2817:0:3:243 -BuLi-Spiel 6:11720:h:0:27500:3071:3072,3073:0:3:244 -BuLi-Spiel 7:11758:h:0:27500:3071:3072,3073:0:3:214 +Superdom:11758:h:0:27500:2815:8192:0:101:18 +BuLi-Konferenz:11758:h:0:27500:3327:3328,3329:0:101:215 +BuLi-Spiel 1:11720:h:0:27500:255:256,257:0:101:17 +BuLi-Spiel 2:11720:h:0:27500:2047:2048,2049:0:101:240 +BuLi-Spiel 3:11720:h:0:27500:2303:2304,2305:0:101:241 +BuLi-Spiel 4:11720:h:0:27500:2559:2560,2561:0:101:242 +BuLi-Spiel 5:11720:h:0:27500:2815:2816,2817:0:101:243 +BuLi-Spiel 6:11720:h:0:27500:3071:3072,3073:0:101:244 +BuLi-Spiel 7:11758:h:0:27500:3071:3072,3073:0:101:214 : TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601 Mosaico:11934:v:0:27500:165:100:0:0:29010 diff --git a/config.c b/config.c index 213fe2cfe..a91cb8ac2 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.87 2002/02/24 11:59:14 kls Exp $ + * $Id: config.c 1.88 2002/03/03 16:04:21 kls Exp $ */ #include "config.h" @@ -732,6 +732,24 @@ bool cSVDRPhost::Accepts(in_addr_t Address) return (Address & mask) == addr.s_addr; } +// -- cCaDefinition ---------------------------------------------------------- + +cCaDefinition::cCaDefinition(void) +{ + number = 0; + description = NULL; +} + +cCaDefinition::~cCaDefinition() +{ + delete description; +} + +bool cCaDefinition::Parse(const char *s) +{ + return 2 == sscanf(s, "%d %a[^\n]", &number, &description) && description && *description; +} + // -- cKeys ------------------------------------------------------------------ cKeys Keys; @@ -879,6 +897,21 @@ bool cSVDRPhosts::Acceptable(in_addr_t Address) return false; } +// -- cCaDefinitions --------------------------------------------------------- + +cCaDefinitions CaDefinitions; + +const cCaDefinition *cCaDefinitions::Get(int Number) +{ + cCaDefinition *p = First(); + while (p) { + if (p->Number() == Number) + return p; + p = (cCaDefinition *)p->Next(); + } + return NULL; +} + // -- cSetup ----------------------------------------------------------------- cSetup Setup; @@ -921,10 +954,46 @@ cSetup::cSetup(void) MinUserInactivity = 120; MultiSpeedMode = 0; ShowReplayMode = 0; + memset(CaCaps, sizeof(CaCaps), 0); CurrentChannel = -1; CurrentVolume = MAXVOLUME; } +void cSetup::PrintCaCaps(FILE *f, const char *Name) +{ + for (int d = 0; d < MAXDVBAPI; d++) { + if (CaCaps[d][0]) { + fprintf(f, "CaCaps = %d", d + 1); + for (int i = 0; i < MAXCACAPS && CaCaps[d][i]; i++) + fprintf(f, " %d", CaCaps[d][i]); + fprintf(f, "\n"); + } + } +} + +bool cSetup::ParseCaCaps(const char *Value) +{ + char *p; + int d = strtol(Value, &p, 10); + if (d > 0 && d < MAXDVBAPI) { + d--; + int i = 0; + while (p != Value && p && *p) { + if (i < MAXCACAPS) { + int c = strtol(p, &p, 10); + if (c > 0) + CaCaps[d][i++] = c; + else + return false; + } + else + return false; + } + return true; + } + return false; +} + bool cSetup::Parse(char *s) { char *p = strchr(s, '='); @@ -967,6 +1036,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); + else if (!strcasecmp(Name, "CaCaps")) return ParseCaCaps(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); else @@ -1047,6 +1117,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "MinUserInactivity = %d\n", MinUserInactivity); fprintf(f, "MultiSpeedMode = %d\n", MultiSpeedMode); fprintf(f, "ShowReplayMode = %d\n", ShowReplayMode); + PrintCaCaps(f, "CaCaps"); fprintf(f, "CurrentChannel = %d\n", CurrentChannel); fprintf(f, "CurrentVolume = %d\n", CurrentVolume); if (f.Close()) { diff --git a/config.h b/config.h index b5860d18b..f5e834351 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.100 2002/02/25 16:29:09 kls Exp $ + * $Id: config.h 1.102 2002/03/03 16:04:43 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "1.0.0pre2" +#define VDRVERSION "1.0.0pre3" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -195,6 +195,18 @@ class cSVDRPhost : public cListObject { bool Accepts(in_addr_t Address); }; +class cCaDefinition : public cListObject { +private: + int number; + char *description; +public: + cCaDefinition(void); + ~cCaDefinition(); + bool Parse(const char *s); + int Number(void) const { return number; } + const char *Description(void) const { return description; } + }; + template<class T> class cConfig : public cList<T> { private: char *fileName; @@ -297,15 +309,23 @@ class cSVDRPhosts : public cConfig<cSVDRPhost> { bool Acceptable(in_addr_t Address); }; +class cCaDefinitions : public cConfig<cCaDefinition> { +public: + const cCaDefinition *Get(int Number); + }; + extern cChannels Channels; extern cTimers Timers; extern cKeys Keys; extern cCommands Commands; extern cSVDRPhosts SVDRPhosts; +extern cCaDefinitions CaDefinitions; class cSetup { private: static char *fileName; + void PrintCaCaps(FILE *f, const char *Name); + bool ParseCaCaps(const char *Value); bool Parse(char *s); public: // Also adjust cMenuSetup (menu.c) when adding parameters here! @@ -339,6 +359,7 @@ class cSetup { int MinEventTimeout, MinUserInactivity; int MultiSpeedMode; int ShowReplayMode; + int CaCaps[MAXDVBAPI][MAXCACAPS]; int CurrentChannel; int CurrentVolume; cSetup(void); diff --git a/dvbapi.c b/dvbapi.c index 55bc5731d..2f1ca1453 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.152 2002/02/24 12:53:51 kls Exp $ + * $Id: dvbapi.c 1.154 2002/03/03 15:43:24 kls Exp $ */ #include "dvbapi.h" @@ -1684,9 +1684,10 @@ cDvbApi::cDvbApi(int n) replayBuffer = NULL; transferBuffer = NULL; transferringFromDvbApi = NULL; - ca = 0; + ca = -1; priority = -1; cardIndex = n; + SetCaCaps(); // Devices that are only present on DVB-C or DVB-S cards: @@ -1783,37 +1784,93 @@ bool cDvbApi::SetPrimaryDvbApi(int n) return false; } +int cDvbApi::CanShift(int Ca, int Priority) +{ + // Test whether a recording on this DVB device can be shifted to another one + // in order to perform a new recording with the given Ca and Priority on this device: + int ShiftLevel = -1; // default means this device can't be shifted + if (Recording()) { + if (ProvidesCa(Ca) // this device provides the requested Ca + && (Ca != this->Ca() // the requested Ca is different from the one currently used... + || Priority > this->Priority())) { // ...or the request comes from a higher priority + cDvbApi *d = NULL; + int Provides[MAXDVBAPI]; + for (int i = 0; i < NumDvbApis; i++) { + if ((Provides[i] = dvbApi[i]->ProvidesCa(this->Ca())) != 0) { // this device is basicly able to do the job + if (dvbApi[i] != this) { // it is not _this_ device + int sl = dvbApi[i]->CanShift(this->Ca(), Priority); // this is the original Priority! + if (sl >= 0 && (ShiftLevel < 0 || sl < ShiftLevel)) { + d = dvbApi[i]; + ShiftLevel = sl; + } + } + } + } + if (ShiftLevel >= 0) + ShiftLevel++; // adds the device's own shift + } + } + else if (Priority > this->Priority()) + ShiftLevel = 0; // no shifting necessary, this device can do the job + return ShiftLevel; +} + cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) { - cDvbApi *d = NULL, *dMinPriority = NULL; - int index = Ca - 1; - for (int i = 0; i < MAXDVBAPI; i++) { - if (dvbApi[i]) { - if (dvbApi[i]->CardIndex() == index) { // means we need exactly _this_ device + cDvbApi *d = NULL; + int Provides[MAXDVBAPI]; + // Check which devices provide Ca: + for (int i = 0; i < NumDvbApis; i++) { + if ((Provides[i] = dvbApi[i]->ProvidesCa(Ca)) != 0) { // this device is basicly able to do the job + if (Priority > dvbApi[i]->Priority() // Priority is high enough to use this device + && (!d // we don't have a device yet, or... + || dvbApi[i]->Priority() < d->Priority() // ...this one has an even lower Priority + || (dvbApi[i]->Priority() == d->Priority() // ...same Priority... + && Provides[i] < Provides[d->CardIndex()]))) // ...but this one provides fewer Ca values d = dvbApi[i]; - break; - } - else if (Ca == 0) { // means any device would be acceptable - if (!d || !dvbApi[i]->Recording() || (d->Recording() && d->Priority() > dvbApi[i]->Priority())) - d = dvbApi[i]; // this is one that is either not currently recording or has the lowest priority - if (d && d != PrimaryDvbApi && !d->Recording()) // avoids the PrimaryDvbApi if possible - break; - if (d && d->Recording() && d->Priority() < Setup.PrimaryLimit && (!dMinPriority || d->Priority() < dMinPriority->Priority())) - dMinPriority = d; // this is the one with the lowest priority below Setup.PrimaryLimit - } } } - if (d == PrimaryDvbApi) { // the PrimaryDvbApi was the only one that was free - if (Priority < Setup.PrimaryLimit) - return NULL; // not enough priority to use the PrimaryDvbApi - if (dMinPriority) // there's one that must not use the PrimaryDvbApi... - d = dMinPriority; // ...so let's kick out that one + if (!d && Ca > MAXDVBAPI) { + // We didn't find one the easy way, so now we have to try harder: + int ShiftLevel = -1; + for (int i = 0; i < NumDvbApis; i++) { + if (Provides[i]) { // this device is basicly able to do the job, but for some reason we didn't get it above + int sl = dvbApi[i]->CanShift(Ca, Priority); // asks this device to shift its job to another device + if (sl >= 0 && (ShiftLevel < 0 || sl < ShiftLevel)) { + d = dvbApi[i]; // found one that can be shifted with the fewest number of subsequent shifts + ShiftLevel = sl; + } + } + } } - return (d // we found one... - && (!d->Recording() // ...that's either not currently recording... - || d->Priority() < Priority // ...or has a lower priority... - || (!d->Ca() && Ca))) // ...or doesn't need this card - ? d : NULL; + return d; +} + +void cDvbApi::SetCaCaps(void) +{ + for (int i = 0; i < MAXCACAPS; i++) + caCaps[i] = Setup.CaCaps[CardIndex()][i]; +} + +int cDvbApi::ProvidesCa(int Ca) +{ + if (Ca == CardIndex() + 1) + return 1; // exactly _this_ card was requested + if (Ca && Ca <= MAXDVBAPI) + return 0; // a specific card was requested, but not _this_ one + int result = Ca ? 0 : 1; // by default every card can provide FTA + int others = Ca ? 1 : 0; + for (int i = 0; i < MAXCACAPS; i++) { + if (caCaps[i]) { + if (caCaps[i] == Ca) + result = 1; + else + others++; + } + else + break; + } + return result ? result + others : 0; } bool cDvbApi::Probe(const char *FileName) @@ -1854,7 +1911,7 @@ bool cDvbApi::Init(void) void cDvbApi::Cleanup(void) { - for (int i = 0; i < MAXDVBAPI; i++) { + for (int i = 0; i < NumDvbApis; i++) { delete dvbApi[i]; dvbApi[i] = NULL; } @@ -2148,6 +2205,11 @@ void cDvbApi::Flush(void) #endif } +int cDvbApi::Priority(void) +{ + return (this == PrimaryDvbApi && !Recording()) ? Setup.PrimaryLimit - 1 : priority; +} + int cDvbApi::SetModeRecord(void) { // Sets up the DVB device for recording @@ -2238,9 +2300,6 @@ bool cDvbApi::SetPids(bool ForRecording) eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr) { - // Make sure the siProcessor won't access the device while switching - cThreadLock ThreadLock(siProcessor); - StopTransfer(); StopReplay(); @@ -2265,7 +2324,7 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int Frequency, char Pol // If this card can't receive this channel, we must not actually switch // the channel here, because that would irritate the driver when we // start replaying in Transfer Mode immediately after switching the channel: - bool NeedsTransferMode = (this == PrimaryDvbApi && Ca && Ca != CardIndex() + 1); + bool NeedsTransferMode = (this == PrimaryDvbApi && !ProvidesCa(Ca)); if (!NeedsTransferMode) { @@ -2507,7 +2566,7 @@ void cDvbApi::StopRecord(void) if (recordBuffer) { delete recordBuffer; recordBuffer = NULL; - ca = 0; + ca = -1; priority = -1; } } @@ -2706,7 +2765,7 @@ void cEITScanner::Process(void) time_t now = time(NULL); if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) { for (int i = 0; i < MAXDVBAPI; i++) { - cDvbApi *DvbApi = cDvbApi::GetDvbApi(i + 1, MAXPRIORITY); + cDvbApi *DvbApi = cDvbApi::GetDvbApi(i + 1, MAXPRIORITY + 1); if (DvbApi) { if (DvbApi != cDvbApi::PrimaryDvbApi || (cDvbApi::NumDvbApis == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) { if (!(DvbApi->Recording() || DvbApi->Replaying() || DvbApi->Transferring())) { diff --git a/dvbapi.h b/dvbapi.h index 06028f0bd..396b5c217 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.63 2002/02/24 12:38:08 kls Exp $ + * $Id: dvbapi.h 1.64 2002/03/03 14:51:20 kls Exp $ */ #ifndef __DVBAPI_H @@ -94,12 +94,16 @@ class cDvbApi { public: ~cDvbApi(); -#define MAXDVBAPI 4 +#define MAXDVBAPI 4 // the maximum number of DVB cards in the system +#define MAXCACAPS 16 // the maximum number of different CA values per DVB card + static int NumDvbApis; private: static cDvbApi *dvbApi[MAXDVBAPI]; static int useDvbApi; int cardIndex; + int caCaps[MAXCACAPS]; + int CanShift(int Ca, int Priority); public: static cDvbApi *PrimaryDvbApi; static void SetUseDvbApi(int n); @@ -110,9 +114,10 @@ class cDvbApi { // Sets the primary DVB device to 'n' (which must be in the range // 1...NumDvbApis) and returns true if this was possible. static cDvbApi *GetDvbApi(int Ca, int Priority); - // Selects a free DVB device, starting with the highest device number - // (but avoiding, if possible, the PrimaryDvbApi). - // If Ca is not 0, the device with the given number will be returned. + // Selects a free DVB device, avoiding the PrimaryDvbApi if possible. + // If Ca is not 0, the device with the given number will be returned + // in case Ca is <= MAXDVBAPI, or the device that provides the given + // value in its caCaps. // If all DVB devices are currently recording, the one recording the // lowest priority timer (if any) that is lower than the given Priority // will be returned. @@ -120,6 +125,15 @@ class cDvbApi { // recording and stop recording if necessary. int CardIndex(void) { return cardIndex; } // Returns the card index of this DvbApi (0 ... MAXDVBAPI - 1). + void SetCaCaps(void); + // Sets the CaCaps of this DVB device according to the Setup data. + int ProvidesCa(int Ca); + // Checks whether this DVB device provides the given value in its + // caCaps. Returns 0 if the value is not provided, 1 if only this + // value is provided, and > 1 if this and other values are provided. + // If the given value is equal to the number of this DVB device, + // 1 is returned. If it is 0 (FTA), 1 plus the number of other values + // in caCaps is returned. static bool Probe(const char *FileName); // Probes for existing DVB devices. static bool Init(void); @@ -204,16 +218,17 @@ class cDvbApi { cPlayBuffer *replayBuffer; int ca; int priority; - int Priority(void) { return priority; } + int Priority(void); // Returns the priority of the current recording session (0..MAXPRIORITY), - // or -1 if no recording is currently active. + // or -1 if no recording is currently active. The primary DVB device will + // always return at least Setup.PrimaryLimit-1. int SetModeRecord(void); // Initiates recording mode and returns the file handle to read from. void SetModeReplay(void); void SetModeNormal(bool FromRecording); public: int Ca(void) { return ca; } - // Returns the ca of the current recording session (0..MAXDVBAPI). + // Returns the ca of the current recording session. int SecondsToFrames(int Seconds); // Returns the number of frames corresponding to the given number of seconds. bool Recording(void); diff --git a/eit.c b/eit.c index 8f4c03724..9985fbbd8 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.38 2002/02/25 16:30:42 kls Exp $ + * $Id: eit.c 1.39 2002/03/01 16:32:11 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -1047,8 +1047,6 @@ const char *cSIProcessor::GetEpgDataFileName(void) void cSIProcessor::SetStatus(bool On) { - LOCK_THREAD; - schedulesMutex.Lock(); ShutDownFilters(); if (On) { @@ -1061,7 +1059,6 @@ void cSIProcessor::SetStatus(bool On) AddFilter(0x12, 0x51); // event info, actual TS, schedule for another 4 days AddFilter(0x12, 0x61); // event info, other TS, schedule for another 4 days } - schedulesMutex.Unlock(); } /** use the vbi device to parse all relevant SI @@ -1085,20 +1082,15 @@ void cSIProcessor::Action() struct tm *ptm = localtime_r(&now, &tm_r); if (now - lastCleanup > 3600 && ptm->tm_hour == 5) { - LOCK_THREAD; - - schedulesMutex.Lock(); + cMutexLock MutexLock(&schedulesMutex); isyslog(LOG_INFO, "cleaning up schedules data"); schedules->Cleanup(); - schedulesMutex.Unlock(); lastCleanup = now; ReportEpgBugFixStats(true); } if (epgDataFileName && now - lastDump > 600) { - LOCK_THREAD; - - schedulesMutex.Lock(); + cMutexLock MutexLock(&schedulesMutex); FILE *f = fopen(GetEpgDataFileName(), "w"); if (f) { schedules->Dump(f); @@ -1107,7 +1099,6 @@ void cSIProcessor::Action() else LOG_ERROR; lastDump = now; - schedulesMutex.Unlock(); } } @@ -1162,12 +1153,9 @@ void cSIProcessor::Action() case 0x12: if (buf[0] != 0x72) { - LOCK_THREAD; - - schedulesMutex.Lock(); + cMutexLock MutexLock(&schedulesMutex); cEIT ceit(buf, seclen, schedules); ceit.ProcessEIT(buf); - schedulesMutex.Unlock(); } else dsyslog(LOG_INFO, "Received stuffing section in EIT\n"); @@ -1261,6 +1249,6 @@ bool cSIProcessor::ShutDownFilters(void) /** */ bool cSIProcessor::SetCurrentServiceID(unsigned short servid) { - LOCK_THREAD; + cMutexLock MutexLock(&schedulesMutex); return schedules ? schedules->SetCurrentServiceID(servid) : false; } diff --git a/epg2html.pl b/epg2html.pl index 215eb7356..cdeb63841 100755 --- a/epg2html.pl +++ b/epg2html.pl @@ -12,7 +12,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: epg2html.pl 1.2 2000/12/01 18:37:46 kls Exp $ +# $Id: epg2html.pl 1.3 2002/02/26 22:10:47 kls Exp $ @Index = (); @@ -45,7 +45,7 @@ sub Tags push(@Index, qq{<a href="$Page">$Channel</a><br>\n}); my %Events = (); while (<>) { - if (/^E (.*) (.*) (.*)/) { + if (/^E (.*?) (.*?) (.*?)/) { (my $Time, $Duration) = ($2, $3); my $Title = "", $Subtitle = "", $Description = ""; while (<>) { diff --git a/i18n.c b/i18n.c index 083971573..2b52c68e4 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.57 2002/02/24 12:54:12 kls Exp $ + * $Id: i18n.c 1.59 2002/03/03 16:38:57 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -257,7 +257,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Marche/Arr", "", // TODO "", // TODO }, @@ -317,7 +317,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Ouvrir", "", // TODO "Avaa", }, @@ -418,7 +418,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Enregistrement en cours - confirmez la suppression", "", // TODO "", // TODO }, @@ -438,7 +438,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "sur la carte principale", "", // TODO "pvastaanottimella", }, @@ -458,7 +458,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Enregistrement en cours - confirmez l'arrt", "", // TODO "Nauhoitus kesken - lopetetaanko se?", }, @@ -468,7 +468,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Enregistrement dans %d minutes - confirmez l'arrt", // TODO "", // TODO "", // TODO }, @@ -478,7 +478,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Appuyez sur une touche pour annuler l'arrt", "", // TODO "Peruuta pysytys painamalla jotakin nppint", }, @@ -700,7 +700,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Premier jour", "", // TODO "", // TODO }, @@ -741,7 +741,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Impossible d'accder l'enregistrement", "", // TODO "Nauhoituksen toistaminen eponnistui!", }, @@ -791,7 +791,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Impossible d'utiliser le mode transfert!", "", // TODO "Ksittmttmi teknisi ongelmia!", }, @@ -821,7 +821,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Arrt impossible - option '-s' absente!", "", // TODO "Ei voida sammuttaa '-s' parametria ei annettu!", }, @@ -831,7 +831,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Disque presque plein!", "", // TODO "Kovalevy lhes tynn!", }, @@ -892,7 +892,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Noms enregistr. immdiats", "", // TODO "Nime vlitn nauh.", }, @@ -982,7 +982,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Niveau de correction EPG", "", // TODO "EPGBugfixLevel", }, @@ -1002,7 +1002,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Trier les programmations", "", // TODO "Jrjest ajastimet", }, @@ -1042,7 +1042,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Utiliser les sous-titres", "", // TODO "Tekstitys kytss", }, @@ -1052,7 +1052,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Dossiers d'enregistrements", "", // TODO "Nauhoitushakemistot", }, @@ -1072,7 +1072,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Enregistrer en Dolby Digital", "", // TODO "", // TODO }, @@ -1112,7 +1112,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Dure affichage cran", "", // TODO "Ilmoitusten nkymisaika", }, @@ -1122,7 +1122,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Taille maxi des fichiers", "", // TODO "Maksimi tiedoston koko", }, @@ -1132,7 +1132,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Sparer les squences", "", // TODO "Paloittele muokatut", }, @@ -1141,8 +1141,8 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO - "", // TODO + "", // TODO + "MinEventTimeout", // Too difficult to translate - read the manual! "", // TODO "Minimi tapahtuman odotus", }, @@ -1152,7 +1152,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Dure minimale d'inactivit", "", // TODO "Minimi kyttjn odotus", }, @@ -1162,7 +1162,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Mode multi-vitesses", "", // TODO "Moninopeustila", }, @@ -1172,7 +1172,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Affichage mode de lecture", "", // TODO "Nyt toiston tila", }, @@ -1193,7 +1193,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "LunMarMerJeuVenSamDim", "", // TODO "MaaTiiKesTorPerLauSun", }, @@ -1445,7 +1445,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Arrt", "", // TODO "Virtakytkin", }, @@ -1455,7 +1455,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Volume+", "", // TODO "nenvoimakkuus+", }, @@ -1465,7 +1465,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Volume-", "", // TODO "nenvoimakkuus-", }, @@ -1475,7 +1475,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Coupure du son", "", // TODO "nen vaimennus", }, @@ -1526,7 +1526,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "restant", "", // TODO "vapaa", }, @@ -1536,9 +1536,9 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO + "Accs direct: ", "", // TODO - "", // TODO - "Hypp", + "Hypp:", }, { " Stop replaying", // note the leading blank! " Wiedergabe beenden", @@ -1606,7 +1606,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Montage termin", "", // TODO "Muokkaus lopetettu", }, @@ -1616,7 +1616,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Echec du montage", "", // TODO "Muokkaus eponnistui", }, @@ -1626,7 +1626,7 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO "", // TODO - "", // TODO + "Recherche des enregistrements...", "", // TODO "haetaan nauhoituksia...", }, diff --git a/menu.c b/menu.c index 28e5d4d86..b1e7e49e3 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.159 2002/02/24 12:55:49 kls Exp $ + * $Id: menu.c 1.160 2002/03/03 16:12:29 kls Exp $ */ #include "menu.h" @@ -585,6 +585,60 @@ void cMenuEditStraItem::Set(void) SetValue(strings[*value]); } +// --- cMenuEditCaItem ------------------------------------------------------- + +class cMenuEditCaItem : public cMenuEditIntItem { +private: + const cCaDefinition *ca; + bool allowCardNr; +protected: + virtual void Set(void); +public: + cMenuEditCaItem(const char *Name, int *Value, bool AllowCardNr = false); + eOSState ProcessKey(eKeys Key); + }; + +cMenuEditCaItem::cMenuEditCaItem(const char *Name, int *Value, bool AllowCardNr) +:cMenuEditIntItem(Name, Value, 0) +{ + ca = CaDefinitions.Get(*Value); + allowCardNr = AllowCardNr; + Set(); +} + +void cMenuEditCaItem::Set(void) +{ + if (ca) + SetValue(ca->Description()); + else + cMenuEditIntItem::Set(); +} + +eOSState cMenuEditCaItem::ProcessKey(eKeys Key) +{ + eOSState state = cMenuEditItem::ProcessKey(Key); + + if (state == osUnknown) { + if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? + if (ca && ca->Prev()) { + ca = (cCaDefinition *)ca->Prev(); + *value = ca->Number(); + } + } + else if (NORMALKEY(Key) == kRight) { + if (ca && ca->Next() && (allowCardNr || ((cCaDefinition *)ca->Next())->Number() > MAXDVBAPI)) { + ca = (cCaDefinition *)ca->Next(); + *value = ca->Number(); + } + } + else + return cMenuEditIntItem::ProcessKey(Key); + Set(); + state = osContinue; + } + return state; +} + // --- cMenuEditChannel ------------------------------------------------------ class cMenuEditChannel : public cOsdMenu { @@ -613,7 +667,7 @@ cMenuEditChannel::cMenuEditChannel(int Index) Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF)); - Add(new cMenuEditIntItem( tr("CA"), &data.ca, 0, cDvbApi::NumDvbApis)); + Add(new cMenuEditCaItem( tr("CA"), &data.ca, true)); Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0)); } } @@ -1880,6 +1934,13 @@ void cMenuSetup::Set(void) Add(new cMenuEditIntItem( tr("MinUserInactivity"), &data.MinUserInactivity)); Add(new cMenuEditBoolItem(tr("MultiSpeedMode"), &data.MultiSpeedMode)); Add(new cMenuEditBoolItem(tr("ShowReplayMode"), &data.ShowReplayMode)); + for (int d = 0; d < cDvbApi::NumDvbApis; d++) { + for (int i = 0; i < 2; i++) { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%s%d %d", tr("CICAM DVB"), d + 1, i + 1); + Add(new cMenuEditCaItem(buffer, &data.CaCaps[d][i])); + } + } } eOSState cMenuSetup::ProcessKey(eKeys Key) diff --git a/vdr.c b/vdr.c index 90c1d8433..a246be11c 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.97 2002/02/24 12:55:10 kls Exp $ + * $Id: vdr.c 1.98 2002/03/03 14:56:03 kls Exp $ */ #include <getopt.h> @@ -252,6 +252,7 @@ int main(int argc, char *argv[]) Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); Commands.Load(AddDirectory(ConfigDirectory, "commands.conf")); SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true); + CaDefinitions.Load(AddDirectory(ConfigDirectory, "ca.conf"), true); #if defined(REMOTE_LIRC) Keys.SetDummyValues(); #elif !defined(REMOTE_NONE) From 217fcb26808f74c9de81b4c653757f75ba13852f Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 17 Mar 2002 18:00:00 +0100 Subject: [PATCH 038/307] =?UTF-8?q?Version=201.0.0pre4=20-=20Added=20'Ca'?= =?UTF-8?q?=20code=20201=20for=20'Cryptoworks,=20GOD-DIGITAL'=20to=20'ca.c?= =?UTF-8?q?onf'=20(thanks=20to=20=20=20Bernd=20Schweikert).=20-=20Fixed=20?= =?UTF-8?q?avoiding=20the=20primary=20DVB=20interface=20in=20case=20Setup.?= =?UTF-8?q?PrimaryLimit=20is=200.=20-=20Fixed=20handling=20CICAM=20setting?= =?UTF-8?q?s=20if=20the=20first=20one=20of=20a=20DVB=20card=20was=20FTA.?= =?UTF-8?q?=20-=20Fixed=20reacting=20on=20changes=20in=20CICAM=20settings?= =?UTF-8?q?=20(needed=20to=20restart=20VDR=20before).=20-=20The=20"Blue"?= =?UTF-8?q?=20button=20in=20the=20"Main"=20menu=20now=20works=20as=20"Stop?= =?UTF-8?q?"=20button=20if=20a=20recording=20=20=20is=20currently=20being?= =?UTF-8?q?=20replayed.=20-=20New=20command=20line=20option=20'-m'=20to=20?= =?UTF-8?q?mute=20audio=20of=20the=20primary=20DVB=20device=20at=20=20=20s?= =?UTF-8?q?tartup=20(suggested=20by=20Mirko=20G=FCnther).=20-=20The=20new?= =?UTF-8?q?=20SVDRP=20command=20VOLU=20can=20be=20used=20to=20control=20th?= =?UTF-8?q?e=20audio=20volume=20(suggested=20=20=20by=20Mirko=20G=FCnther)?= =?UTF-8?q?.=20-=20Fixed=20resetting=20'mute'=20state=20when=20setting=20t?= =?UTF-8?q?he=20volume=20to=20a=20non-zero=20value.=20-=20Added=20log=20me?= =?UTF-8?q?ssages=20when=20deleting=20recordings=20in=20case=20the=20disk?= =?UTF-8?q?=20runs=20full=20while=20=20=20recording.=20-=20Fixed=20closing?= =?UTF-8?q?=20a=20pipe=20(used=20for=20replaying=20Dolby=20Digital=20audio?= =?UTF-8?q?),=20which=20=20=20sometimes=20left=20'zombie'=20processes=20be?= =?UTF-8?q?hind=20(thanks=20to=20Werner=20Fink=20for=20helping=20=20=20to?= =?UTF-8?q?=20debug=20this=20one).=20-=20Now=20starting=20the=20Dolby=20Di?= =?UTF-8?q?gital=20output=20thread=20only=20if=20the=20recording=20actuall?= =?UTF-8?q?y=20=20=20contains=20Dolby=20Digital=20audio=20data=20(thanks?= =?UTF-8?q?=20to=20Werner=20Fink).=20-=20Implemented=20OSD=20for=20Volume?= =?UTF-8?q?=20and=20Mute=20(works=20only=20if=20there=20is=20no=20other=20?= =?UTF-8?q?OSD=20=20=20activity,=20but=20this=20should=20be=20no=20problem?= =?UTF-8?q?=20for=20normal=20use).=20-=20Changed=20the=20MANUAL=20descript?= =?UTF-8?q?ion=20of=20the=20"Conditional=20Access"=20setup=20parameters=20?= =?UTF-8?q?=20=20to=20reflect=20the=20actual=20"CICAM=20DVBn=20m"=20notati?= =?UTF-8?q?on=20in=20the=20"Setup"=20menu.=20-=20The=20new=20Setup=20param?= =?UTF-8?q?eter=20"Use=20time=20from=20transponder"=20can=20be=20used=20to?= =?UTF-8?q?=20define=20which=20=20=20transponder=20shall=20be=20used=20to?= =?UTF-8?q?=20set=20the=20system=20time=20(see=20MANUAL=20for=20details).?= =?UTF-8?q?=20=20=20If=20you=20have=20been=20using=20the=20SetSystemTime?= =?UTF-8?q?=20option=20previously,=20you=20now=20MUST=20=20=20select=20a?= =?UTF-8?q?=20channel=20that=20you=20trust=20to=20have=20a=20reliable=20ti?= =?UTF-8?q?me=20base.=20-=20Grouped=20the=20Setup=20parameters=20into=20se?= =?UTF-8?q?veral=20sub-menus,=20so=20that=20each=20group=20of=20=20=20para?= =?UTF-8?q?meters=20fits=20on=20a=20single=20screen=20-=20unless=20the=20h?= =?UTF-8?q?eight=20of=20the=20OSD=20has=20been=20=20=20set=20to=20a=20smal?= =?UTF-8?q?l=20value=20(based=20on=20code=20from=20Markus=20Lang).=20-=20C?= =?UTF-8?q?hanged=20the=20title=20of=20the=20"Main"=20menu=20to=20"VDR".?= =?UTF-8?q?=20-=20Fixed=20displaying=20a=20system=20message=20while=20the?= =?UTF-8?q?=20replay=20mode=20is=20being=20shown.=20-=20Physically=20remov?= =?UTF-8?q?ing=20a=20deleted=20recording=20if=20one=20with=20the=20same=20?= =?UTF-8?q?name=20shall=20be=20=20=20deleted=20again.=20-=20The=20"Left"?= =?UTF-8?q?=20and=20"Right"=20keys=20are=20now=20used=20to=20page=20up=20a?= =?UTF-8?q?nd=20down=20in=20text=20displays=20=20=20(like=20the=20EPG=20de?= =?UTF-8?q?scriptions=20or=20the=20results=20of=20commands=20executed=20fr?= =?UTF-8?q?om=20the=20=20=20"Commands"=20menu).=20-=20Fixed=20high=20CPU?= =?UTF-8?q?=20usage=20in=20transfer=20mode.=20-=20Replaced=20'killproc'=20?= =?UTF-8?q?with=20'killall'=20in=20'runvdr',=20since=20apparently=20'killp?= =?UTF-8?q?roc'=20=20=20is=20not=20available=20by=20default=20on=20some=20?= =?UTF-8?q?Linux=20distributions,=20whereas=20'killall'=20is.=20=20=20Plea?= =?UTF-8?q?se=20check=20if=20your=20system=20provides=20'killall'=20-=20if?= =?UTF-8?q?=20it=20doesn't,=20please=20change=20=20=20this=20back=20in=20'?= =?UTF-8?q?runvdr'=20and=20report=20this=20(thanks=20to=20Achim=20Lange).?= =?UTF-8?q?=20-=20The=20"Commands"=20menu=20now=20automatically=20assigns?= =?UTF-8?q?=20number=20keys=20as=20hotkeys=20to=20the=20=20=20commands.=20?= =?UTF-8?q?If=20you=20have=20preceeded=20your=20commands=20with=20digits?= =?UTF-8?q?=20you=20may=20want=20to=20=20=20remove=20these=20from=20your?= =?UTF-8?q?=20'commands.conf'=20file.=20-=20The=20new=20Setup=20item=20"Re?= =?UTF-8?q?start"=20can=20be=20used=20to=20force=20a=20complete=20restart?= =?UTF-8?q?=20of=20VDR,=20=20=20including=20reloading=20the=20driver.=20No?= =?UTF-8?q?te=20that=20this=20can=20only=20work=20if=20VDR=20and=20the=20?= =?UTF-8?q?=20=20driver=20are=20wrapped=20into=20a=20mechanism=20that=20ac?= =?UTF-8?q?tually=20performs=20this=20action=20if=20VDR=20=20=20exits.=20T?= =?UTF-8?q?he=20'runvdr'=20script=20can=20be=20used=20for=20this=20purpose?= =?UTF-8?q?.=20-=20Refined=20texts=20of=20the=20"Setup"=20menu.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTORS | 18 +- COPYING | 340 +++++++++++++++++++++++++++++++ FORMATS | 12 +- HISTORY | 61 +++++- MANUAL | 313 ++++++++++++++++------------- ca.conf | 4 + config.c | 21 +- config.h | 7 +- dvbapi.c | 52 +++-- dvbapi.h | 16 +- eit.c | 19 +- eit.h | 6 +- i18n.c | 558 +++++++++++++++++++++++++++++++++------------------ menu.c | 532 +++++++++++++++++++++++++++++++++++++++--------- menu.h | 19 +- osd.c | 19 +- osd.h | 16 +- recording.c | 12 +- runvdr | 6 +- svdrp.c | 33 ++- svdrp.h | 3 +- thread.c | 19 +- vdr.c | 28 ++- 23 files changed, 1589 insertions(+), 525 deletions(-) create mode 100644 COPYING diff --git a/CONTRIBUTORS b/CONTRIBUTORS index ed63a4bb1..3adfbd961 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -91,9 +91,12 @@ Henning Holtschneider <hh@holtschneider.com> Paulo Manuel Martins Lopes <pmml@netvita.pt> for translating the OSD texts to the Portugese language -Markus Lang <markus.lang@nissan-db.de> and Ulrich Rder <dynamite@efr-net.de> +Markus Lang <pretender@gaze.de> and Ulrich Rder <dynamite@efr-net.de> for making DiSEqC support configurable +Markus Lang <pretender@gaze.de> + for some initial code for grouping the Setup menu into several sub-menus + Jean-Claude Repetto <jc@repetto.org> for translating the OSD texts to the French language @@ -146,6 +149,9 @@ Artur Skawina <skawina@geocities.com> Werner Fink <werner@suse.de> for making I/O more robust by handling EINTR for fixing closing all unused file descriptors when opening a pipe + for helping to debug leftover 'zombie' processes when closing a pipe + for making the Dolby Digital thread start only if the recording actually + contains Dolby Digital data Rolf Hakenes <hakenes@hippomi.de> for providing 'libdtv' and adapting the EIT mechanisms to it @@ -217,3 +223,13 @@ Oleg Assovski <assen@bitcom.msk.ru> Adrian Stabiszewski <as@nitegate.de> for fixing the SVDRP GRAB command in case the video device can't be opened + +Bernd Schweikert <bernd.schweikert@dit-gmbh.de> + for adding 'Ca' code 201 for 'Cryptoworks, GOD-DIGITAL' to 'ca.conf' + +Mirko Gnther <mi.guenther@ib-helms.de> + for suggesting the -m command line option + for suggesting the SVDRP command VOLU + +Achim Lange <Achim_Lange@t-online.de> + for replacing 'killproc' with 'killall' in 'runvdr' to make it work on Debian diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..5b6e7c66c --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/FORMATS b/FORMATS index 91903384e..63ae7e1dd 100644 --- a/FORMATS +++ b/FORMATS @@ -117,7 +117,7 @@ Video Disk Recorder File Formats * commands.conf This file contains the definitions of commands that can be executed from - the "Main" menus "Commands" option. + the "VDR" menu's "Commands" option. Each line contains one command definition in the following format: @@ -134,13 +134,9 @@ Video Disk Recorder File Formats Examples: - 1 Check for new mail: /usr/local/bin/checkmail 2>&1 - 2 CPU status : /usr/local/bin/cpustatus 2>&1 - 3 Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' - - If the first non-blank character of the 'title' is a digit in the range - 1..9, the command can be selected directly by pressing the respective numerical - key on the remote control. + Check for new mail: /usr/local/bin/checkmail 2>&1 + CPU status : /usr/local/bin/cpustatus 2>&1 + Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' * svdrphosts.conf diff --git a/HISTORY b/HISTORY index 84c1460e1..708f6d9da 100644 --- a/HISTORY +++ b/HISTORY @@ -41,14 +41,14 @@ Video Disk Recorder Revision History of the channel, with a prepended '@' character. - Timers that are not given an explicit Name now use the channel name with a prepended '@' character. -- If an instant recording is currently active, the Main menu now contains +- If an instant recording is currently active, the "Main" menu now contains an option to stop that recording. - Timers are now only processed when the Menu is not active. So after editing a timer the effect will take place only after the menu has been closed. In order to avoid missing a timer event by inadvertently leaving the menu open, the menu will be closed automatically after about two minutes of inactivity. -- If a recording is currently being replayed, the Main menu now contains an +- If a recording is currently being replayed, the "Main" menu now contains an option to stop replaying. - Displaying the recording DVB interface status in the decimal points of the RCU display. @@ -424,7 +424,7 @@ Video Disk Recorder Revision History - Fixed a memory leak in the EIT processor that happened when the system time was set. - Removed some redundant code from the cListBase destructor. -- Fixed internationalization of some Main menu texts. +- Fixed internationalization of some "Main" menu texts. - Updated 'channels.conf' after the recent changes of Premiere World (thanks to Axel Gruber). - Redesigned the ring buffer to make it work with two separate threads for @@ -480,7 +480,7 @@ Video Disk Recorder Revision History items the amount of visible information remained the same as before, though. If your DVB card has even less memory (which would result in only the channel switching display and the replay progress display being visible, but - no Main menu), try reducing the constant 'MenuLines' in dvbapi.h (currently + no "Main" menu), try reducing the constant 'MenuLines' in dvbapi.h (currently '13') even further. - There are two new setup parameters to define the "Default Priority" and "Default Lifetime" when creating a new timer event. @@ -1066,3 +1066,56 @@ Video Disk Recorder Revision History modes (besides the default "Free To Air" mode, which is always assumed to be available on any DVB card). - Updated French language texts (thanks to Jean-Claude Repetto). + +2002-03-17: Version 1.0.0pre4 + +- Added 'Ca' code 201 for 'Cryptoworks, GOD-DIGITAL' to 'ca.conf' (thanks to + Bernd Schweikert). +- Fixed avoiding the primary DVB interface in case Setup.PrimaryLimit is 0. +- Fixed handling CICAM settings if the first one of a DVB card was FTA. +- Fixed reacting on changes in CICAM settings (needed to restart VDR before). +- The "Blue" button in the "Main" menu now works as "Stop" button if a recording + is currently being replayed. +- New command line option '-m' to mute audio of the primary DVB device at + startup (suggested by Mirko Gnther). +- The new SVDRP command VOLU can be used to control the audio volume (suggested + by Mirko Gnther). +- Fixed resetting 'mute' state when setting the volume to a non-zero value. +- Added log messages when deleting recordings in case the disk runs full while + recording. +- Fixed closing a pipe (used for replaying Dolby Digital audio), which + sometimes left 'zombie' processes behind (thanks to Werner Fink for helping + to debug this one). +- Now starting the Dolby Digital output thread only if the recording actually + contains Dolby Digital audio data (thanks to Werner Fink). +- Implemented OSD for Volume and Mute (works only if there is no other OSD + activity, but this should be no problem for normal use). +- Changed the MANUAL description of the "Conditional Access" setup parameters + to reflect the actual "CICAM DVBn m" notation in the "Setup" menu. +- The new Setup parameter "Use time from transponder" can be used to define which + transponder shall be used to set the system time (see MANUAL for details). + If you have been using the SetSystemTime option previously, you now MUST + select a channel that you trust to have a reliable time base. +- Grouped the Setup parameters into several sub-menus, so that each group of + parameters fits on a single screen - unless the height of the OSD has been + set to a small value (based on code from Markus Lang). +- Changed the title of the "Main" menu to "VDR". +- Fixed displaying a system message while the replay mode is being shown. +- Physically removing a deleted recording if one with the same name shall be + deleted again. +- The "Left" and "Right" keys are now used to page up and down in text displays + (like the EPG descriptions or the results of commands executed from the + "Commands" menu). +- Fixed high CPU usage in transfer mode. +- Replaced 'killproc' with 'killall' in 'runvdr', since apparently 'killproc' + is not available by default on some Linux distributions, whereas 'killall' is. + Please check if your system provides 'killall' - if it doesn't, please change + this back in 'runvdr' and report this (thanks to Achim Lange). +- The "Commands" menu now automatically assigns number keys as hotkeys to the + commands. If you have preceeded your commands with digits you may want to + remove these from your 'commands.conf' file. +- The new Setup item "Restart" can be used to force a complete restart of VDR, + including reloading the driver. Note that this can only work if VDR and the + driver are wrapped into a mechanism that actually performs this action if VDR + exits. The 'runvdr' script can be used for this purpose. +- Refined texts of the "Setup" menu. diff --git a/MANUAL b/MANUAL index c4cda08a5..b94050512 100644 --- a/MANUAL +++ b/MANUAL @@ -8,20 +8,20 @@ Video Disk Recorder User's Manual possible, several keys have different meanings in the various modes: - Key Normal Main Channels Timers Edit/New Recordings Replay - - Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play - Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause - Left Prev group - Page up Page up Decrement Page up Search back - Right Next group - Page down Page down Increment Page down Search forward - Ok Ch display Select Switch Edit Accept Play Progress disp. - Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on - Back - Menu off Main menu Main menu Discard Main menu Recordings menu - Red - Record Edit Edit - Play Jump - Green - Language New New - Rewind Skip -60s - Yellow - - Delete Delete - Delete Skip +60s - Blue - Resume Mark On/Off(1) - Summary Stop - 0..9 Ch select - - - Numeric inp. - Editing + Key Normal VDR Channels Timers Edit/New Recordings Replay + + Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play + Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause + Left Prev group - Page up Page up Decrement Page up Search back + Right Next group - Page down Page down Increment Page down Search forward + Ok Ch display Select Switch Edit Accept Play Progress disp. + Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on + Back - Menu off VDR menu VDR menu Discard VDR menu Recordings menu + Red - Record Edit Edit - Play Jump + Green - Language New New - Rewind Skip -60s + Yellow - - Delete Delete - Delete Skip +60s + Blue - Stop/Resume Mark On/Off(1) - Summary Stop + 0..9 Ch select - - - Numeric inp. - Editing Power Shutdown Volume+ Volume up @@ -34,7 +34,7 @@ Video Disk Recorder User's Manual * Navigating through the On Screen Menus - The "Main" menu can be called up with the "Menu" key of your remote + The "VDR" menu can be called up with the "Menu" key of your remote control unit. The "Up" and "Down" keys are used to select a specific item. The "Left" and "Right" keys can be used to change options, and the numeric keys allow direct input of numeric data. The "Ok" key @@ -74,7 +74,7 @@ Video Disk Recorder User's Manual The "Schedule" menu implements VDR's "Electronic Program Guide" (EPG). - Select "Schedule" from the "Main" menu and you get a list of all upcoming + Select "Schedule" from the "VDR" menu and you get a list of all upcoming broadcasts on the current channel. "Up" and "Down" can be used to scroll through this list, and pressing "Ok" @@ -135,7 +135,7 @@ Video Disk Recorder User's Manual * Selecting language specific audio track If the current channel provides different audio tracks (typically for - different languages), the "Green" button in the "Main" menu can be pressed + different languages), the "Green" button in the "VDR" menu can be pressed to toggle between these. There can be two different audio PIDs per channel, assuming that typically a channel broadcasts a country specific language plus the movie's original soundtrack. @@ -157,7 +157,7 @@ Video Disk Recorder User's Manual * Instant Recording You can start recording the current channel by pressing the "Red" button - in the "Main" menu. This will create a timer event named "@channelname" that + in the "VDR" menu. This will create a timer event named "@channelname" that starts 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 pressing the "Menu" button and selecting @@ -176,17 +176,17 @@ Video Disk Recorder User's Manual number of new recordings (as opposed to a recording's entry, which displays the date and time of the recording). - If the setup parameter UseSubtitle was turned on when a recording took place, - VDR adds the "subtitle" (which is usually the name of the episode in case of + If the setup parameter "Use episode name" was turned on when a recording took place, + VDR adds the "Episode name" (which is usually the name of the episode in case of a series) to the recording's name. The "Recordings" menu then displays all recordings of a repeating timer in chronological order, since these are usually the individual episodes of a series, which you may want to view in the order in which they were broadcast. - Playback can be stopped via the "Main" menu by selecting "Stop replaying", + Playback can be stopped via the "VDR" menu by selecting "Stop replaying", or by pressing the "Blue" button outside the menu. A previously stopped playback session can be resumed by pressing the "Blue" - button in the "Main" menu. + button in the "VDR" menu. * Replay Control @@ -322,10 +322,10 @@ Video Disk Recorder User's Manual structure "/video/Sci-Fi/Star_Trek/Voyager". The '~' character has been chosen for this since the file system's directory delimiter '/' may be part of a regular programme name. - Repeating timers create recordings that contain the 'Subtitle' + Repeating timers create recordings that contain the 'Episode name' information from the EPG data in their file name. Typically (on tv stations that care about their viewers) this contains the episode - title of a series. The subtitle is appended to the timer's file name, + title of a series. The episode name is appended to the timer's file name, separated by a '~' character, so that it results in all recordings of this timer being collected in a common subdirectory. If this field is left blank, the channel name will be used to form @@ -342,7 +342,7 @@ Video Disk Recorder User's Manual the channel or replay another recording on that interface. However, if there is an other DVB interface that is currently not recording and provides the necessary conditional access facilities to continue the recording that is - currently being performed on the primary DVB interface, the Main menu will + currently being performed on the primary DVB interface, the "VDR" menu will contain an option that allows you to stop recording on the primary DVB interface. Select that option to stop the ongoing recording and thus free the primary DVB interface to allow channel switching or replaying. The interrupted @@ -352,87 +352,60 @@ Video Disk Recorder User's Manual * Parameters in the "Setup" menu - Select "Setup" from the "Main" menu to enter the setup menu. From there you can + Select "Setup" from the "VDR" menu to enter the setup menu. From there you can modify the following system parameters (note that "boolean" values will be displayed as "no" and "yes" in the "Setup" menu, while in the setup file they are stored as '0' and '1', respectively): - OSDLanguage = 0 Defines the language used to display the OSD texts. - 0 = Englisch - 1 = Deutsch - 2 = Slovenian - 3 = Italian - 4 = Dutch - 5 = Portugese - 6 = French - 7 = Norwegian - - PrimaryDVB = 1 Defines the primary DVB interface (i.e. the one that - will display the menus and will react on input through - the remote control). Valid values range from '1' to the - number of installed DVB cards. If more than one DVB card - is installed and a recording is to be started, the - program will try to use a free DVB card that is different - from the primary DVB interface, so that the viewer will - be disturbed as little as possible. + OSD: - ShowInfoOnChSwitch = 1 Turns the display of the current/next information on - or off when switching the channel. The information is - always displayed when pressing the "Ok" button in - normal viewing mode. + Language = English Defines the language used to display the OSD texts. - MenuScrollPage = 1 0 = when pressing the "Down" ("Up") key while the cursor - is on the last (first) line of a list page, the - list is advanced by a full page and the cursor will - be at the top (bottom) of that page - 1 = dto., but the cursor remains at the bottom (top) of - the page (this mode allows for faster scrolling - through long lists). + Width = 52 The width and height of the OSD . + Height = 18 The valid ranges are width=40...56, height=12...21. - MarkInstantRecord = 1 Defines whether an "instant recording" (started by - pressing the "Red" button in the "Main" menu) will be - marked with a '@' character to make it distinguishable - from timer recordings in the "Recordings" menu. - 0 = instant recordings will not be marked - 1 = instant recordings will be marked. + Message time = 1 The time (in seconds) how long an informational + message shall be displayed on the OSD. The valid range + is 1...60. - NameInstantRecord = TITLE-EPISODE - Defines how to name an instant recording. If the keywords - TITLE and/or EPISODE are present, they will be replaced - with the title and episode information from the EPG data - at the time of recording (if that data is available). - If this parameter is empty, the channel name will be used - by default. + Channel info position = bottom + The position of the channel info window in the OSD + (either 'bottom' or 'top'). - LnbSLOF = 11700 The switching frequency (in MHz) between low and high LOF - LnbFrequLo = 9750 The LNB's low and high local oscillator frequencies (in MHz) - LnbFrequHi = 10600 (these have no meaning for DVB-C receivers) + Info on channel switch = yes + Turns the display of the current/next information on + or off when switching the channel. The information is + always displayed when pressing the "Ok" button in + normal viewing mode. - DiSEqC = 1 Generally turns DiSEqC support on or off. - 0 = disabled - 1 = enabled + Scroll pages = yes yes = when pressing the "Down" ("Up") key while the cursor + is on the last (first) line of a list page, the + list is advanced by a full page and the cursor will + be at the top (bottom) of that page + no = dto., but the cursor remains at the bottom (top) of + the page (this mode allows for faster scrolling + through long lists). - SetSystemTime = 0 Defines whether the system time will be set according to - the time received from the DVB data stream. - 0 = system time will not be set - 1 = system time wil be set - Note that this works only if VDR is running under a user - id that has permisson to set the system time. + Sort timers = yes Turns sorting the timers in the "Timers" menu on/off. + Timers are sorted by ascending start times, with the + first one being the next timer that will start. - MarginStart = 2 Defines how many minutes before the official start time - MarginStop = 10 of a broadcast VDR shall start recording, and how long - after the official end time it shall stop recording. + Recording directories = yes + Turns displaying the Recordings menu as a hierarchical + directory structure on or off. + + EPG: - EPGScanTimeout = 5 The time (in hours) of user inactivity after which the + EPG scan timeout = 5 The time (in hours) of user inactivity after which the DVB card in a single card system starts scanning channels to keep the EPG up-to-date. A value of '0' completely turns off scanning on both single and multiple card systems. - EPGBugfixLevel = 2 Some tv stations transmit weirdly formatted EPG data. + EPG bugfix level = 2 Some tv stations transmit weirdly formatted EPG data. VDR attempts to fix these bugs up to the given level: 0 = no EPG fixing - 1 = basic fixing of text location (Title, Subtitle and + 1 = basic fixing of text location (Title, Episode and Extended Description) 2 = removal of excess whitespace and hyphens, mapping of wrongly used characters @@ -443,15 +416,74 @@ Video Disk Recorder User's Manual be fixed accordingly. Restart VDR if you want to make sure all data is fixed. - SVDRPTimeout = 300 The time (in seconds) of inactivity on an open SVDRP - connection after which the connection is automatically - closed. Default is 300, a value of 0 means no timeout. + Set system time = no Defines whether the system time will be set according to + the time received from the DVB data stream. + Note that this works only if VDR is running under a user + id that has permisson to set the system time. You also + need to set the option "Use time from transponder" to a + channel that you trust to transmit a reliable time base + (not all channels seem to have access to a correct time + base...). + + Use time from transponder = 0 + The frequency of the transponder that shall be used to + set the system time. The Setup menu will offer the full + list of channels, even if several of them are on the + same transponder. Also, when selecting a channel, saving + the Setup and opening the Setup menu again, there may be + a different channel listed here, since the first one + in 'channels.conf' that is on the given transponder will + be taken. Note that in order to set the system time from + the transponder data the option "Set system time" must also + be enabled. + + DVB: + + Primary DVB interface = 1 + Defines the primary DVB interface (i.e. the one that + will display the menus and will react on input through + the remote control). Valid values range from '1' to the + number of installed DVB cards. If more than one DVB card + is installed and a recording is to be started, the + program will try to use a free DVB card that is different + from the primary DVB interface, so that the viewer will + be disturbed as little as possible. - SortTimers = 1 Turns sorting the timers in the "Timers" menu on/off. - Timers are sorted by ascending start times, with the - first one being the next timer that will start. + Video format = 4:3 The video format (or aspect ratio) of the tv set in use + (4:3 or 16:9). - PrimaryLimit = 0 The minimum priority a timer must have to be allowed to + LNB: + + SLOF = 11700 The switching frequency (in MHz) between low and + high LOF + Low LNB frequency = 9750 The LNB's low and high local oscillator frequencies + High LNB frequency = 10600 (in MHz, these have no meaning for DVB-C receivers) + + Use DiSEqC = no Generally turns DiSEqC support on or off. + + CICAM: + + CICAM DVBn m Defines the "Conditional Access" capabilities of the DVB + card 'n'. Each DVB card can provide up to two CICAM + methods ('m' = [1, 2]). + + In the 'setup.conf' file the value consists of the card + number, followed by a list of decryption method values + (defined in 'ca.conf'). + For instance + CaCaps = 3 101 102 + would define that card number 3 is able to decrypt + "Premiere World" and the "ORF". + + Recording: + + Margin at start = 2 Defines how many minutes before the official start time + Margin at stop = 10 of a broadcast VDR shall start recording, and how long + after the official end time it shall stop recording. + These margins are added automatically to timers that + are created from the EPG data. + + Primary limit = 0 The minimum priority a timer must have to be allowed to use the primary DVB interface, or to force another timer with higher priority to use the primary DVB interface. This is mainly useful for recordings that should take @@ -459,55 +491,67 @@ Video Disk Recorder User's Manual never keep the user from viewing stuff on the primary interface. On systems with only one DVB card, timers with a priority below PrimaryLimit will never execute. - - DefaultPriority = 50 The default Priority and Lifetime values used when - DefaultLifetime = 50 creating a new timer event. A Lifetime value of 99 + + Default priority = 50 The default Priority and Lifetime values used when + Default lifetime = 50 creating a new timer event. A Lifetime value of 99 means that this recording will never be deleted automatically. - UseSubtitle = 1 Repeating timers use the EPG's 'Subtitle' information to - create recording file names in a hierarchical structure + Use episode name = yes Repeating timers use the EPG's 'Episode name' information + to create recording file names in a hierarchical structure (for instance to gather all episodes of a series in a common subdirectory). This parameter can be used to control this. - 0 = don't use the 'Subtitle' - 1 = use it (and create subdirectories) + no = don't use the 'Episode name' + yes = use it (and create subdirectories) - RecordingDirs = 1 Turns displaying the Recordings menu as a hierarchical - directory structure on or off. + Mark instant recording = yes + Defines whether an "instant recording" (started by + pressing the "Red" button in the "VDR" menu) will be + marked with a '@' character to make it distinguishable + from timer recordings in the "Recordings" menu. - VideoFormat = 0 The video format (or aspect ratio) of the tv set in use. - 0 = 4:3 - 1 = 16:9 + Name instant recording = TITLE EPISODE + Defines how to name an instant recording. If the keywords + TITLE and/or EPISODE are present, they will be replaced + with the title and episode information from the EPG data + at the time of recording (if that data is available). + If this parameter is empty, the channel name will be used + by default. - RecordDolbyDigital = 1 Turns recording of the Dolby Digital audio channels on + Record Dolby Digital = yes + Turns recording of the Dolby Digital audio channels on or off. This may be useful if you don't have the equipment to replay Dolby Digital audio and want to save disk space. - ChannelInfoPos = 0 The position of the channel info window in the OSD. - 0 = bottom - 1 = top - - OSDwidth = 52 The width and height of the OSD . - OSDheight = 18 The valid ranges are width=40...56, height=12...21. - - OSDMessageTime = 1 The time (in seconds) how long an informational - message shall be displayed on the OSD. The valid range - is 1...60. - - MaxVideoFileSize=2000 The maximum size of a single recorded video file in MB. + Max. video file size = 2000 + The maximum size of a single recorded video file in MB. The valid range is 100...2000. Default is 2000, but you may want to use smaller values if you are planning on archiving a recording to CD. - SplitEditedFiles = 0 During the actual editing process VDR writes the result + Split edited files = no + During the actual editing process VDR writes the result into files that may grow up to MaxVideoFileSize. If you prefer to have each marked sequence stored in a separate file (named 001.vdr, 002.vdr, ...) you can set this - option to 1. + option to 'yes'. + + Replay: + + Multi speed mode = no Defines the function of the "Left" and "Right" keys in + replay mode. If set to 'no', one speed will be used, while + if set to 'yes' there will be three speeds for fast and slow + search, respectively. + + Show replay mode = no Turns displaying the current replay mode on or off. - MinEventTimeout=30 If the command line option '-s' has been set, VDR will - MinUserInactivity=120 automatically shutdown the computer if the next timer + Miscellaneous: + + Min. event timeout = 30 + Min. user inactivity = 120 + If the command line option '-s' has been set, VDR will + automatically shutdown the computer if the next timer event is at least MinEventTimeout minutes in the future, and the user has been inactive for at least MinUserInactivity minutes. Setting MinUserInactivity @@ -515,30 +559,15 @@ Video Disk Recorder User's Manual retaining the possibility to manually shutdown the computer. - MultiSpeedMode = 0 Defines the function of the "Left" and "Right" keys in - replay mode. If set to 0, one speed will be used, while - if set to 1 there will be three speeds for fast and slow - search, respectively. - 0 = off - 1 = on - - ShowReplayMode = 0 Turns displaying the current replay mode on or off. - 0 = off - 1 = on - - CaCaps (no default) Defines the "Conditional Access Capabilities" of a DVB - card. The value consists of the card number, followed by - a list of decryption method values (defined in 'ca.conf'). - For instance - CaCaps = 3 101 102 - would define that card number 3 is able to decrypt - "Premiere World" and the "ORF". + SVDRP timeout = 300 The time (in seconds) of inactivity on an open SVDRP + connection after which the connection is automatically + closed. Default is 300, a value of 0 means no timeout. * Executing system commands - The "Main" menu option "Commands" allows you to execute any system commands + The "VDR" menu option "Commands" allows you to execute any system commands defined in the configuration file 'commands.conf' (see FORMATS for details). - The "Commands" option will only be present in the "Main" menu if a valid + The "Commands" option will only be present in the "VDR" menu if a valid 'commands.conf' file containing at least one command definition has been found at program start. diff --git a/ca.conf b/ca.conf index 7024ee427..ee2c9c53c 100644 --- a/ca.conf +++ b/ca.conf @@ -14,6 +14,10 @@ 101 Premiere World 102 ORF +# Cryptoworks + +201 GOD-DIGITAL + # Special values to "hard code" a channel to a specific DVB card: 1 DVB 1 diff --git a/config.c b/config.c index a91cb8ac2..b89fe748d 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.88 2002/03/03 16:04:21 kls Exp $ + * $Id: config.c 1.91 2002/03/17 14:24:09 kls Exp $ */ #include "config.h" @@ -811,7 +811,7 @@ cChannel *cChannels::GetByNumber(int Number) { cChannel *channel = (cChannel *)First(); while (channel) { - if (channel->number == Number) + if (!channel->groupSep && channel->number == Number) return channel; channel = (cChannel *)channel->Next(); } @@ -822,7 +822,7 @@ cChannel *cChannels::GetByServiceID(unsigned short ServiceId) { cChannel *channel = (cChannel *)First(); while (channel) { - if (channel->pnr == ServiceId) + if (!channel->groupSep && channel->pnr == ServiceId) return channel; channel = (cChannel *)channel->Next(); } @@ -931,6 +931,7 @@ cSetup::cSetup(void) LnbFrequHi = 10600; DiSEqC = 0; SetSystemTime = 0; + TimeTransponder = 0; MarginStart = 2; MarginStop = 10; EPGScanTimeout = 5; @@ -962,12 +963,16 @@ cSetup::cSetup(void) void cSetup::PrintCaCaps(FILE *f, const char *Name) { for (int d = 0; d < MAXDVBAPI; d++) { - if (CaCaps[d][0]) { - fprintf(f, "CaCaps = %d", d + 1); - for (int i = 0; i < MAXCACAPS && CaCaps[d][i]; i++) + int written = 0; + for (int i = 0; i < MAXCACAPS; i++) { + if (CaCaps[d][i]) { + if (!written++) + fprintf(f, "CaCaps = %d", d + 1); fprintf(f, " %d", CaCaps[d][i]); + } + } + if (written) fprintf(f, "\n"); - } } } @@ -1013,6 +1018,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value); else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); + else if (!strcasecmp(Name, "TimeTransponder")) TimeTransponder = atoi(Value); else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); @@ -1094,6 +1100,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); fprintf(f, "DiSEqC = %d\n", DiSEqC); fprintf(f, "SetSystemTime = %d\n", SetSystemTime); + fprintf(f, "TimeTransponder = %d\n", TimeTransponder); fprintf(f, "MarginStart = %d\n", MarginStart); fprintf(f, "MarginStop = %d\n", MarginStop); fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout); diff --git a/config.h b/config.h index f5e834351..4a216f139 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.102 2002/03/03 16:04:43 kls Exp $ + * $Id: config.h 1.105 2002/03/17 14:24:11 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "1.0.0pre3" +#define VDRVERSION "1.0.0pre4" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -92,6 +92,8 @@ class cKeys { void Set(eKeys Key, unsigned int Code); }; +#define ISTRANSPONDER(f1, f2) (abs((f1) - (f2)) < 4) + class cChannel : public cListObject { private: static char *buffer; @@ -340,6 +342,7 @@ class cSetup { int LnbFrequHi; int DiSEqC; int SetSystemTime; + int TimeTransponder; int MarginStart, MarginStop; int EPGScanTimeout; int EPGBugfixLevel; diff --git a/dvbapi.c b/dvbapi.c index 2f1ca1453..1ade142b0 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.154 2002/03/03 15:43:24 kls Exp $ + * $Id: dvbapi.c 1.163 2002/03/16 14:20:47 kls Exp $ */ #include "dvbapi.h" @@ -63,6 +63,9 @@ extern "C" { // The maximum time to wait before giving up while catching up on an index file: #define MAXINDEXCATCHUP 2 // seconds +// The default priority for non-primary DVB cards: +#define DEFAULTPRIORITY -2 + #define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls #define FATALERRNO (errno != EAGAIN && errno != EINTR) @@ -743,10 +746,6 @@ cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev) canToggleAudioTrack = false; skipAC3bytes = false; audioTrack = 0xC0; - if (cDvbApi::AudioCommand()) { - if (!dolbyDev.Open(cDvbApi::AudioCommand(), "w")) - esyslog(LOG_ERR, "ERROR: can't open pipe to audio command '%s'", cDvbApi::AudioCommand()); - } } cPlayBuffer::~cPlayBuffer() @@ -755,7 +754,11 @@ cPlayBuffer::~cPlayBuffer() void cPlayBuffer::PlayExternalDolby(const uchar *b, int MaxLength) { - if (dolbyDev) { + if (cDvbApi::AudioCommand()) { + if (!dolbyDev && !dolbyDev.Open(cDvbApi::AudioCommand(), "w")) { + esyslog(LOG_ERR, "ERROR: can't open pipe to audio command '%s'", cDvbApi::AudioCommand()); + return; + } if (b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01) { if (b[3] == 0xBD) { // dolby int l = b[4] * 256 + b[5] + 6; @@ -1147,7 +1150,7 @@ void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except) int l = b[i + 4] * 256 + b[i + 5] + 6; switch (c) { case 0xBD: // dolby - if (Except && dolbyDev) + if (Except) PlayExternalDolby(&b[i], Length - i); // continue with deleting the data - otherwise it disturbs DVB replay case 0xC0 ... 0xC1: // audio @@ -1408,7 +1411,7 @@ void cTransferBuffer::Output(void) int r = Get(b, sizeof(b)); if (r > 0) { uchar *p = b; - while (r > 0 && Busy()) { + while (r > 0 && Busy() && cFile::FileReadyForWriting(toDevice, 100)) { int w = write(toDevice, p, r); if (w > 0) { p += w; @@ -1685,9 +1688,8 @@ cDvbApi::cDvbApi(int n) transferBuffer = NULL; transferringFromDvbApi = NULL; ca = -1; - priority = -1; + priority = DEFAULTPRIORITY; cardIndex = n; - SetCaCaps(); // Devices that are only present on DVB-C or DVB-S cards: @@ -1721,8 +1723,6 @@ cDvbApi::cDvbApi(int n) if (fd_frontend >= 0 && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxd1 >= 0 && fd_demuxd2 >= 0 && fd_demuxt >= 0) { siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n)); - if (!dvbApi[0]) // only the first one shall set the system time - siProcessor->SetUseTSTime(Setup.SetSystemTime); FrontendInfo feinfo; CHECK(ioctl(fd_frontend, FE_GET_INFO, &feinfo)); frontendType = feinfo.type; @@ -1749,7 +1749,7 @@ cDvbApi::cDvbApi(int n) #endif currentChannel = 1; mute = false; - volume = MAXVOLUME; + volume = Setup.CurrentVolume; } cDvbApi::~cDvbApi() @@ -1848,8 +1848,10 @@ cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) void cDvbApi::SetCaCaps(void) { - for (int i = 0; i < MAXCACAPS; i++) - caCaps[i] = Setup.CaCaps[CardIndex()][i]; + for (int d = 0; d < NumDvbApis; d++) { + for (int i = 0; i < MAXCACAPS; i++) + dvbApi[d]->caCaps[i] = Setup.CaCaps[dvbApi[d]->CardIndex()][i]; + } } int cDvbApi::ProvidesCa(int Ca) @@ -1867,8 +1869,6 @@ int cDvbApi::ProvidesCa(int Ca) else others++; } - else - break; } return result ? result + others : 0; } @@ -1906,6 +1906,7 @@ bool cDvbApi::Init(void) isyslog(LOG_INFO, "found %d video device%s", NumDvbApis, NumDvbApis > 1 ? "s" : ""); else esyslog(LOG_ERR, "ERROR: no video device found, giving up!"); + SetCaCaps(); return NumDvbApis > 0; } @@ -2321,6 +2322,11 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int Frequency, char Pol CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); } + // Stop setting system time: + + if (siProcessor) + siProcessor->SetCurrentTransponder(0); + // If this card can't receive this channel, we must not actually switch // the channel here, because that would irritate the driver when we // start replaying in Transfer Mode immediately after switching the channel: @@ -2472,6 +2478,11 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int Frequency, char Pol CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); } + // Start setting system time: + + if (Result == scrOk && siProcessor) + siProcessor->SetCurrentTransponder(Frequency); + return Result; } @@ -2567,7 +2578,7 @@ void cDvbApi::StopRecord(void) delete recordBuffer; recordBuffer = NULL; ca = -1; - priority = -1; + priority = DEFAULTPRIORITY; } } @@ -2699,12 +2710,13 @@ bool cDvbApi::ToggleAudioTrack(void) return false; } -void cDvbApi::ToggleMute(void) +bool cDvbApi::ToggleMute(void) { int OldVolume = volume; mute = !mute; SetVolume(0, mute); volume = OldVolume; + return mute; } void cDvbApi::SetVolume(int Volume, bool Absolute) @@ -2714,6 +2726,8 @@ void cDvbApi::SetVolume(int Volume, bool Absolute) audioMixer_t am; am.volume_left = am.volume_right = volume; CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am)); + if (volume > 0) + mute = false; } } diff --git a/dvbapi.h b/dvbapi.h index 396b5c217..e9cf8c83a 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.64 2002/03/03 14:51:20 kls Exp $ + * $Id: dvbapi.h 1.68 2002/03/10 10:50:00 kls Exp $ */ #ifndef __DVBAPI_H @@ -43,7 +43,8 @@ #define MAXVIDEOFILESIZE 2000 // MB #define MINVIDEOFILESIZE 100 // MB -#define MAXVOLUME 255 +#define MAXVOLUME 255 +#define VOLUMEDELTA 5 // used to increase/decrease the volume const char *IndexToHMSF(int Index, bool WithFrame = false); // Converts the given index to a string, optionally containing the frame number. @@ -125,8 +126,8 @@ class cDvbApi { // recording and stop recording if necessary. int CardIndex(void) { return cardIndex; } // Returns the card index of this DvbApi (0 ... MAXDVBAPI - 1). - void SetCaCaps(void); - // Sets the CaCaps of this DVB device according to the Setup data. + static void SetCaCaps(void); + // Sets the CaCaps of all DVB devices according to the Setup data. int ProvidesCa(int Ca); // Checks whether this DVB device provides the given value in its // caCaps. Returns 0 if the value is not provided, 1 if only this @@ -148,8 +149,6 @@ class cDvbApi { private: cSIProcessor *siProcessor; public: - void SetUseTSTime(bool On) { if (siProcessor) siProcessor->SetUseTSTime(On); } - // Image Grab facilities bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); @@ -307,8 +306,9 @@ class cDvbApi { bool mute; int volume; public: - void ToggleMute(void); - // Turns the volume off or on. + bool IsMute(void) { return mute; } + bool ToggleMute(void); + // Turns the volume off or on and returns the new mute state. void SetVolume(int Volume, bool Absolute = false); // Sets the volume to the given value, either absolutely or relative to // the current volume. diff --git a/eit.c b/eit.c index 9985fbbd8..011000b70 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.39 2002/03/01 16:32:11 kls Exp $ + * $Id: eit.c 1.41 2002/03/17 14:23:41 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -981,7 +981,6 @@ cSIProcessor::cSIProcessor(const char *FileName) { fileName = strdup(FileName); masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master' - useTStime = false; filters = NULL; if (!numSIProcessors++) // the first one creates it schedules = new cSchedules; @@ -1138,7 +1137,7 @@ void cSIProcessor::Action() case 0x14: if (buf[0] == 0x70) { - if (useTStime) + if (Setup.SetSystemTime && Setup.TimeTransponder && ISTRANSPONDER(currentTransponder, Setup.TimeTransponder)) { cTDT ctdt((tdt_t *)buf); ctdt.SetSystemTime(); @@ -1222,14 +1221,6 @@ bool cSIProcessor::AddFilter(u_char pid, u_char tid) return false; } -/** set whether local systems time should be -set by the received TDT or TOT packets */ -bool cSIProcessor::SetUseTSTime(bool use) -{ - useTStime = use; - return useTStime; -} - /** */ bool cSIProcessor::ShutDownFilters(void) { @@ -1246,6 +1237,12 @@ bool cSIProcessor::ShutDownFilters(void) return true; // there's no real 'boolean' to return here... } +/** */ +void cSIProcessor::SetCurrentTransponder(int CurrentTransponder) +{ + currentTransponder = CurrentTransponder; +} + /** */ bool cSIProcessor::SetCurrentServiceID(unsigned short servid) { diff --git a/eit.h b/eit.h index 55c0f4e05..5221c403d 100644 --- a/eit.h +++ b/eit.h @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.h 1.15 2002/02/23 15:30:25 kls Exp $ + * $Id: eit.h 1.16 2002/03/10 10:56:57 kls Exp $ ***************************************************************************/ #ifndef __EIT_H @@ -139,7 +139,7 @@ class cSIProcessor : public cThread { static cMutex schedulesMutex; static const char *epgDataFileName; bool masterSIProcessor; - bool useTStime; + int currentTransponder; SIP_FILTER *filters; char *fileName; bool active; @@ -157,7 +157,7 @@ class cSIProcessor : public cThread { // longer used, the cMutexLock must be destroyed. static bool Read(FILE *f = NULL); void SetStatus(bool On); - bool SetUseTSTime(bool use); + void SetCurrentTransponder(int CurrentTransponder); bool SetCurrentServiceID(unsigned short servid); }; diff --git a/i18n.c b/i18n.c index 2b52c68e4..a7d63059b 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.59 2002/03/03 16:38:57 kls Exp $ + * $Id: i18n.c 1.66 2002/03/17 13:50:43 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -46,6 +46,14 @@ * in the "Setup" menu. * 5. Send the modified 'i18n.c' file to <kls@cadsoft.de> to have * it included in the next version of VDR. + * + * In case an English phrase is used in more than one context (and might need + * different translations in other languages) it can be preceeded with an + * arbitrary string to describe its context, separated from the actual phrase + * by a '$' character (see for instance "Button$Stop" vs. "Stop"). + * Of course this means that no English phrase may contain the '$' character! + * If this should ever become necessary, the existing '$' would have to be + * replaced with something different... */ #include "i18n.h" @@ -70,15 +78,15 @@ const tPhrase Phrases[] = { "Suomi", }, // Menu titles: - { "Main", - "Hauptmen", - "Glavni meni", - "Principale", - "Hoofdmenu", - "Principal", - "Menu", - "Hovedmeny", - "Valikko", + { "VDR", + "VDR", + "VDR", + "VDR", + "VDR", + "VDR", + "VDR", + "VDR", + "VDR", }, { "Schedule", "Programm", @@ -291,6 +299,16 @@ const tPhrase Phrases[] = { "Spol tilbake", "Takaisinkel.", }, + { "Button$Stop", + "Beenden", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Resume", "Weiter", "Nadaljuj", @@ -351,7 +369,7 @@ const tPhrase Phrases[] = { "Neste", "Seuraava", }, - { "Schedule", + { "Button$Schedule", "Programm", "Urnik", "Programma", @@ -366,7 +384,7 @@ const tPhrase Phrases[] = { "Jezik", "Linguaggio", "Taal", - "", // TODO + "Linguagem", // TODO (correct?) "Langue", "Sprk", "Kieli", @@ -452,6 +470,26 @@ const tPhrase Phrases[] = { "Avbryte redigering?", "Peruutetaanko muokkaus?", }, + { "Really restart?", + "Wirklich neu starten?", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Recording - restart anyway?", + "Aufnahme luft - trotzdem neu starten?", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Recording - shut down anyway?", "Aufnahme luft - trotzdem ausschalten?", "", // TODO @@ -835,29 +873,150 @@ const tPhrase Phrases[] = { "", // TODO "Kovalevy lhes tynn!", }, + // Setup pages: + { "OSD", + "OSD", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "EPG", + "EPG", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "DVB", + "DVB", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "LNB", + "LNB", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "CICAM", + "CICAM", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Recording", + "Aufnahme", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Replay", + "Wiedergabe", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Miscellaneous", + "Sonstiges", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Restart", + "Neustart", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // Setup parameters: - { "OSD-Language", - "OSD-Sprache", - "OSD-jezik", - "Linguaggio OSD", - "OSD-taal", - "Linguagem OSD", - "Langue OSD", - "OSD Sprk", - "Nytn kieli", - }, - { "PrimaryDVB", - "Primres Interface", - "Primarna naprava", - "Scheda DVB primaria", - "Eerste DVB kaart", - "DVB primario", - "Premire carte DVB", - "Hoved DVB-enhet", - "Ensisij. vast.otin", + { "Setup.OSD$Language", + "Sprache", + "Jezik", + "Linguaggio", + "Taal", + "Linguagem", // TODO (correct?) + "Langue", + "Sprk", + "Kieli", + }, + { "Setup.OSD$Width", + "Breite", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "Largeur", //TODO (correct?) + "", // TODO + "Leveys", //TODO (correct?) }, - { "ShowInfoOnChSwitch", - "Info zeigen", + { "Setup.OSD$Height", + "Hhe", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "Hauteur", //TODO (correct?) + "", // TODO + "Korkeus", //TODO (correct?) + }, + { "Setup.OSD$Message time", + "Anzeigedauer fr Nachrichten", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "Dure affichage cran", + "", // TODO + "Ilmoitusten nkymisaika", + }, + { "Setup.OSD$Channel info position", + "Kanal-Info Position", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "Position infos chanes", + "", // TODO + "Kanavainfon sijainti", + }, + { "Setup.OSD$Info on channel switch", + "Info beim Kanalwechsel", "Pokazi naziv kanala", "Vis info nel cambio canale", "Kanaal info tonen", @@ -866,7 +1025,7 @@ const tPhrase Phrases[] = { "Info ved kanalskifte", "Nyt kanavainfo", }, - { "MenuScrollPage", + { "Setup.OSD$Scroll pages", "Seitenweise scrollen", "Drsni meni", "Scrolla pagina nel menu", @@ -876,37 +1035,97 @@ const tPhrase Phrases[] = { "Rask rulling i menyer", "Valikkojen rullaus", }, - { "MarkInstantRecord", - "Direktaufz. markieren", - "Oznaci direktno snemanje", - "Marca la registrazione", - "Direkte opnamen markeren", - "Marca de gravacao", - "Enregistrement immdiat", - "Markere direkteopptak", - "Merkitse vlitn nauh.", + { "Setup.OSD$Sort timers", + "Timer sortieren", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "Trier les programmations", + "", // TODO + "Jrjest ajastimet", }, - { "NameInstantRecord", - "Direktaufz. benennen", + { "Setup.OSD$Recording directories", + "Aufnahme Verzeichnisse", "", // TODO "", // TODO "", // TODO "", // TODO - "Noms enregistr. immdiats", + "Dossiers d'enregistrements", "", // TODO - "Nime vlitn nauh.", + "Nauhoitushakemistot", + }, + { "Setup.EPG$EPG scan timeout", + "Zeit bis EPG Scan", + "Cas do EPG pregleda", + "Timeout EPG", + "EPG-scan Timeout", + "Timeout EPG", + "Temps maxi EPG", + "Ledig tid fr EPG-sk", + "Ohjelmatied. odotusaika", + }, + { "Setup.EPG$EPG bugfix level", + "EPG Fehlerbereinigung", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "Niveau de correction EPG", + "", // TODO + "EPG Bugfix Level", + }, + { "Setup.EPG$Set system time", + "Systemzeit stellen", + "Sistemski cas", + "Setta orario auto", + "Systeem klok instellen", + "Ajustar relogio do sistema", + "Ajuster l'heure du systme", + "Juster system-klokken", + "Vastaanota kellonaika", + }, + { "Setup.EPG$Use time from transponder", + "Transponder fr Systemzeit", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, + { "Setup.DVB$Primary DVB interface", + "Primres DVB Interface", + "Primarna naprava", + "Scheda DVB primaria", + "Eerste DVB kaart", + "DVB primario", + "Premire carte DVB", + "Hoved DVB-enhet", + "Ensisij. vast.otin", + }, + { "Setup.DVB$Video format", + "Video Format", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "Format vido", + "TV Format", + "Kuvamuoto", }, - { "LnbSLOF", - "LnbSLOF", - "LnbSLOF", - "LnbSLOF", - "LnbSLOF", - "LnbSLOF", + { "Setup.LNB$SLOF", + "SLOF", + "SLOF", + "SLOF", + "SLOF", + "SLOF", "Limite de bandes LNB", "LO-grensefrekvens", - "LnbSLOF", + "SLOF", }, - { "LnbFrequLo", + { "Setup.LNB$Low LNB frequency", "Untere LNB-Frequenz", "Spodnja LNB-frek.", "Freq LO LNB", @@ -916,7 +1135,7 @@ const tPhrase Phrases[] = { "LO-frekvens i lavbndet", "LO LNB taajuus", }, - { "LnbFrequHi", + { "Setup.LNB$High LNB frequency", "Obere LNB-Frequenz", "Zgornja LNB-frek.", "Freq HI LNB", @@ -926,27 +1145,27 @@ const tPhrase Phrases[] = { "LO-frekvens i hybndet", "HI LNB taajuus", }, - { "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - }, - { "SetSystemTime", - "Systemzeit stellen", - "Sistemski cas", - "Setta orario auto", - "Systeem klok instellen", - "Ajustar relogio do sistema", - "Ajuster l'heure du systme", - "Juster system-klokken", - "Vastaanota kellonaika", - }, - { "MarginStart", + { "Setup.LNB$Use DiSEqC", + "DiSEqC benutzen", + "DiSEqC", // TODO + "DiSEqC", // TODO + "DiSEqC", // TODO + "DiSEqC", // TODO + "DiSEqC", // TODO + "DiSEqC", // TODO + "DiSEqC", // TODO + }, + { "Setup.CICAM$CICAM DVB", + "CICAM DVB", + "CICAM DVB", + "CICAM DVB", + "CICAM DVB", + "CICAM DVB", + "CICAM DVB", + "CICAM DVB", + "CICAM DVB", + }, + { "Setup.Recording$Margin at start", "Zeitpuffer bei Anfang", "Premor pred zacetkom", "Min margine inizio", @@ -956,7 +1175,7 @@ const tPhrase Phrases[] = { "Opptaks margin (start)", "Aloitusmarginaali", }, - { "MarginStop", + { "Setup.Recording$Margin at stop", "Zeitpuffer bei Ende", "Premor za koncem", "Min margine fine", @@ -966,47 +1185,7 @@ const tPhrase Phrases[] = { "Opptaks margin (slutt)", "Lopetusmarginaali", }, - { "EPGScanTimeout", - "Zeit bis EPG Scan", - "Cas do EPG pregleda", - "Timeout EPG", - "EPG-scan Timeout", - "Timeout EPG", - "Temps maxi EPG", - "Ledig tid fr EPG-sk", - "Ohjelmatied. odotusaika", - }, - { "EPGBugfixLevel", - "EPG Fehlerbereinigung", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Niveau de correction EPG", - "", // TODO - "EPGBugfixLevel", - }, - { "SVDRPTimeout", - "SVDRP Timeout", - "", // TODO - "Timeout SVDRP", - "SVDRP Timeout", - "Timeout SVDRP", - "Temps maxi SVDRP", - "Ubrukt SVDRP-levetid", - "SVDRP odotusaika", - }, - { "SortTimers", - "Timer sortieren", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Trier les programmations", - "", // TODO - "Jrjest ajastimet", - }, - { "PrimaryLimit", + { "Setup.Recording$Primary limit", "Primr-Limit", "", // TODO "", // TODO @@ -1016,7 +1195,7 @@ const tPhrase Phrases[] = { "Prioritets grense HovedDVB", "PrimaryLimit", }, - { "DefaultPriority", + { "Setup.Recording$Default priority", "Default Prioritt", "", // TODO "", // TODO @@ -1026,7 +1205,7 @@ const tPhrase Phrases[] = { "Normal prioritet (Timer)", "Oletusprioriteetti", }, - { "DefaultLifetime", + { "Setup.Recording$Default lifetime", "Default Lebensdauer", "", // TODO "", // TODO @@ -1036,107 +1215,87 @@ const tPhrase Phrases[] = { "Normal levetid (Timer)", "Oletus voimassaoloaika", }, - { "UseSubtitle", - "Subtitle verwenden", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Utiliser les sous-titres", - "", // TODO - "Tekstitys kytss", - }, - { "RecordingDirs", - "Aufn. Verzeichnisse", + { "Setup.Recording$Use episode name", + "Episodenname verwenden", "", // TODO "", // TODO "", // TODO "", // TODO - "Dossiers d'enregistrements", + "Utiliser les sous-titres", // TODO (episode name!) "", // TODO - "Nauhoitushakemistot", + "Tekstitys kytss", // TODO (episode name!) }, - { "VideoFormat", - "Video Format", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Format vido", - "TV Format", - "Kuvamuoto", + { "Setup.Recording$Mark instant recording", + "Direktaufzeichnung markieren", + "Oznaci direktno snemanje", + "Marca la registrazione", + "Direkte opnamen markeren", + "Marca de gravacao", + "Enregistrement immdiat", + "Markere direkteopptak", + "Merkitse vlitn nauh.", }, - { "RecordDolbyDigital", - "Dolby Digital Ton aufz.", + { "Setup.Recording$Name instant recording", + "Direktaufzeichnung benennen", "", // TODO "", // TODO "", // TODO "", // TODO - "Enregistrer en Dolby Digital", - "", // TODO + "Noms enregistr. immdiats", "", // TODO + "Nime vlitn nauh.", }, - { "ChannelInfoPos", - "Kanal Info Position", - "", // TODO - "", // TODO + { "Setup.Recording$Record Dolby Digital", + "Dolby Digital Ton aufzeichnen", "", // TODO "", // TODO - "Position infos chanes", - "", // TODO - "Kanavainfon sijainti", - }, - { "OSDwidth", - "OSD Breite", - "", // TODO "", // TODO "", // TODO + "Enregistrer en Dolby Digital", "", // TODO - "Largeur affichage", "", // TODO - "Tekstinytn leveys", }, - { "OSDheight", - "OSD Hhe", + { "Setup.Recording$Max. video file size", + "Max. Video Dateigre", "", // TODO "", // TODO "", // TODO "", // TODO - "Hauteur affichage", + "Taille maxi des fichiers", "", // TODO - "Tekstinytn korkeus", + "Maksimi tiedoston koko", }, - { "OSDMessageTime", - "OSD Nachricht Dauer", + { "Setup.Recording$Split edited files", + "Editierte Dateien aufteilen", "", // TODO "", // TODO "", // TODO "", // TODO - "Dure affichage cran", + "Sparer les squences", "", // TODO - "Ilmoitusten nkymisaika", + "Paloittele muokatut", }, - { "MaxVideoFileSize", - "Max. Video Dateigre", + { "Setup.Replay$Multi speed mode", + "MultiSpeed Modus", "", // TODO "", // TODO "", // TODO "", // TODO - "Taille maxi des fichiers", + "Mode multi-vitesses", "", // TODO - "Maksimi tiedoston koko", + "Moninopeustila", }, - { "SplitEditedFiles", - "Editierte Dateien zerteilen", + { "Setup.Replay$Show replay mode", + "Wiedergabestatus anzeigen", "", // TODO "", // TODO "", // TODO "", // TODO - "Sparer les squences", + "Affichage mode de lecture", "", // TODO - "Paloittele muokatut", + "Nyt toiston tila", }, - { "MinEventTimeout", + { "Setup.Miscellaneous$Min. event timeout", "Mindest Event Pause", "", // TODO "", // TODO @@ -1146,8 +1305,8 @@ const tPhrase Phrases[] = { "", // TODO "Minimi tapahtuman odotus", }, - { "MinUserInactivity", - "Mindest User Inaktivitt", + { "Setup.Miscellaneous$Min. user inactivity", + "Mindest Benutzer-Inaktivitt", "", // TODO "", // TODO "", // TODO @@ -1156,25 +1315,15 @@ const tPhrase Phrases[] = { "", // TODO "Minimi kyttjn odotus", }, - { "MultiSpeedMode", - "MultiSpeed Modus", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Mode multi-vitesses", - "", // TODO - "Moninopeustila", - }, - { "ShowReplayMode", - "Wiedergabe Status", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Affichage mode de lecture", + { "Setup.Miscellaneous$SVDRP timeout", + "SVDRP Timeout", "", // TODO - "Nyt toiston tila", + "Timeout SVDRP", + "SVDRP Timeout", + "Timeout SVDRP", + "Temps maxi SVDRP", + "Ubrukt SVDRP-levetid", + "SVDRP odotusaika", }, // The days of the week: { "MTWTFSS", @@ -1540,6 +1689,16 @@ const tPhrase Phrases[] = { "", // TODO "Hypp:", }, + { "Volume ", // note the trailing blank + "Lautstrke ", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "Volume ", + "", // TODO + "nenvoimakkuus ", + }, { " Stop replaying", // note the leading blank! " Wiedergabe beenden", " Prekini ponavljanje", @@ -1645,7 +1804,8 @@ const char *tr(const char *s) } esyslog(LOG_ERR, "no translation found for '%s' in language %d (%s)\n", s, Setup.OSDLanguage, Phrases[0][Setup.OSDLanguage]); } - return s; + const char *p = strchr(s, '$'); + return p ? p + 1 : s; } const char * const * Languages(void) diff --git a/menu.c b/menu.c index b1e7e49e3..93f1ff7d4 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.160 2002/03/03 16:12:29 kls Exp $ + * $Id: menu.c 1.172 2002/03/17 14:23:44 kls Exp $ */ #include "menu.h" @@ -168,6 +168,47 @@ void cMenuEditChanItem::Set(void) SetValue(buf); } +// --- cMenuEditTranItem ----------------------------------------------------- + +class cMenuEditTranItem : public cMenuEditChanItem { +private: + int number; + int transponder; +public: + cMenuEditTranItem(const char *Name, int *Value); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuEditTranItem::cMenuEditTranItem(const char *Name, int *Value) +:cMenuEditChanItem(Name, Value) +{ + number = 0; + transponder = *Value; + cChannel *channel = Channels.First(); + while (channel) { + if (!channel->groupSep && ISTRANSPONDER(channel->frequency, *Value)) { + number = channel->number; + break; + } + channel = (cChannel *)channel->Next(); + } + *Value = number; + Set(); + *Value = transponder; +} + +eOSState cMenuEditTranItem::ProcessKey(eKeys Key) +{ + *value = number; + eOSState state = cMenuEditChanItem::ProcessKey(Key); + number = *value; + cChannel *channel = Channels.GetByNumber(*value); + if (channel) + transponder = channel->frequency; + *value = transponder; + return state; +} + // --- cMenuEditDayItem ------------------------------------------------------ class cMenuEditDayItem : public cMenuEditIntItem { @@ -892,8 +933,8 @@ class cMenuTextItem : public cOsdItem { virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); bool CanScrollUp(void) { return offset > 0; } bool CanScrollDown(void) { return h + offset < lines; } - void ScrollUp(void); - void ScrollDown(void); + void ScrollUp(bool Page); + void ScrollDown(bool Page); virtual eOSState ProcessKey(eKeys Key); }; @@ -952,20 +993,20 @@ void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor); } -void cMenuTextItem::ScrollUp(void) +void cMenuTextItem::ScrollUp(bool Page) { if (CanScrollUp()) { Clear(); - offset--; + offset = max(offset - (Page ? h : 1), 0); Display(); } } -void cMenuTextItem::ScrollDown(void) +void cMenuTextItem::ScrollDown(bool Page) { if (CanScrollDown()) { Clear(); - offset++; + offset = min(offset + (Page ? h : 1), lines - h); Display(); } } @@ -973,10 +1014,14 @@ void cMenuTextItem::ScrollDown(void) eOSState cMenuTextItem::ProcessKey(eKeys Key) { switch (Key) { + case kLeft|k_Repeat: + case kLeft: case kUp|k_Repeat: - case kUp: ScrollUp(); break; + case kUp: ScrollUp(NORMALKEY(Key) == kLeft); break; + case kRight|k_Repeat: + case kRight: case kDown|k_Repeat: - case kDown: ScrollDown(); break; + case kDown: ScrollDown(NORMALKEY(Key) == kRight); break; default: return osUnknown; } return osContinue; @@ -1394,7 +1439,7 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentCha currentChannel = CurrentChannelNr; delete pArray; - SetHelp(tr("Record"), Now ? tr("Next") : tr("Now"), tr("Schedule"), tr("Switch")); + SetHelp(tr("Record"), Now ? tr("Next") : tr("Now"), tr("Button$Schedule"), tr("Switch")); } const cEventInfo *cMenuWhatsOn::ScheduleEventInfo(void) @@ -1876,84 +1921,45 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) return state; } -// --- cMenuSetup ------------------------------------------------------------ +// --- cMenuSetupPage -------------------------------------------------------- -class cMenuSetup : public cOsdMenu { -private: +class cMenuSetupPage : public cOsdMenu { +protected: cSetup data; int osdLanguage; - void Set(void); + void SetupTitle(const char *s); + virtual void Set(void) = 0; public: - cMenuSetup(void); + cMenuSetupPage(void); virtual eOSState ProcessKey(eKeys Key); }; -cMenuSetup::cMenuSetup(void) -:cOsdMenu("", 25) +cMenuSetupPage::cMenuSetupPage(void) +:cOsdMenu("", 30) { data = Setup; osdLanguage = Setup.OSDLanguage; - Set(); } -void cMenuSetup::Set(void) +void cMenuSetupPage::SetupTitle(const char *s) { - Clear(); - SetTitle(tr("Setup")); - Add(new cMenuEditStraItem(tr("OSD-Language"), &data.OSDLanguage, NumLanguages, Languages())); - Add(new cMenuEditIntItem( tr("PrimaryDVB"), &data.PrimaryDVB, 1, cDvbApi::NumDvbApis)); - Add(new cMenuEditBoolItem(tr("ShowInfoOnChSwitch"), &data.ShowInfoOnChSwitch)); - Add(new cMenuEditBoolItem(tr("MenuScrollPage"), &data.MenuScrollPage)); - Add(new cMenuEditBoolItem(tr("MarkInstantRecord"), &data.MarkInstantRecord)); - Add(new cMenuEditStrItem( tr("NameInstantRecord"), data.NameInstantRecord, sizeof(data.NameInstantRecord), FileNameChars)); - Add(new cMenuEditIntItem( tr("LnbSLOF"), &data.LnbSLOF)); - Add(new cMenuEditIntItem( tr("LnbFrequLo"), &data.LnbFrequLo)); - Add(new cMenuEditIntItem( tr("LnbFrequHi"), &data.LnbFrequHi)); - Add(new cMenuEditBoolItem(tr("DiSEqC"), &data.DiSEqC)); - Add(new cMenuEditBoolItem(tr("SetSystemTime"), &data.SetSystemTime)); - Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart)); - Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop)); - Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout)); - Add(new cMenuEditIntItem( tr("EPGBugfixLevel"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); - Add(new cMenuEditIntItem( tr("SVDRPTimeout"), &data.SVDRPTimeout)); - Add(new cMenuEditBoolItem(tr("SortTimers"), &data.SortTimers)); - Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit, 0, MAXPRIORITY)); - Add(new cMenuEditIntItem( tr("DefaultPriority"), &data.DefaultPriority, 0, MAXPRIORITY)); - Add(new cMenuEditIntItem( tr("DefaultLifetime"), &data.DefaultLifetime, 0, MAXLIFETIME)); - Add(new cMenuEditBoolItem(tr("UseSubtitle"), &data.UseSubtitle)); - Add(new cMenuEditBoolItem(tr("RecordingDirs"), &data.RecordingDirs)); - Add(new cMenuEditBoolItem(tr("VideoFormat"), &data.VideoFormat, "4:3", "16:9")); - Add(new cMenuEditBoolItem(tr("RecordDolbyDigital"), &data.RecordDolbyDigital)); - Add(new cMenuEditBoolItem(tr("ChannelInfoPos"), &data.ChannelInfoPos, tr("bottom"), tr("top"))); - Add(new cMenuEditIntItem( tr("OSDwidth"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); - Add(new cMenuEditIntItem( tr("OSDheight"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); - Add(new cMenuEditIntItem( tr("OSDMessageTime"), &data.OSDMessageTime, 1, 60)); - Add(new cMenuEditIntItem( tr("MaxVideoFileSize"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); - Add(new cMenuEditBoolItem(tr("SplitEditedFiles"), &data.SplitEditedFiles)); - Add(new cMenuEditIntItem( tr("MinEventTimeout"), &data.MinEventTimeout)); - Add(new cMenuEditIntItem( tr("MinUserInactivity"), &data.MinUserInactivity)); - Add(new cMenuEditBoolItem(tr("MultiSpeedMode"), &data.MultiSpeedMode)); - Add(new cMenuEditBoolItem(tr("ShowReplayMode"), &data.ShowReplayMode)); - for (int d = 0; d < cDvbApi::NumDvbApis; d++) { - for (int i = 0; i < 2; i++) { - char buffer[32]; - snprintf(buffer, sizeof(buffer), "%s%d %d", tr("CICAM DVB"), d + 1, i + 1); - Add(new cMenuEditCaItem(buffer, &data.CaCaps[d][i])); - } - } + char buf[40]; // can't call tr() for more than one string at a time! + char *q = buf + snprintf(buf, sizeof(buf), "%s - ", tr("Setup")); + snprintf(q, sizeof(buf) - strlen(buf), "%s", tr(s)); + SetTitle(buf); } -eOSState cMenuSetup::ProcessKey(eKeys Key) +eOSState cMenuSetupPage::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch (Key) { - case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osEnd; - cDvbApi::PrimaryDvbApi->SetUseTSTime(data.SetSystemTime); + case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack; cDvbApi::PrimaryDvbApi->SetVideoFormat(data.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3); Setup = data; Setup.Save(); + cDvbApi::SetCaCaps(); break; default: break; } @@ -1969,6 +1975,235 @@ eOSState cMenuSetup::ProcessKey(eKeys Key) return state; } +// --- cMenuSetupOSD --------------------------------------------------------- + +class cMenuSetupOSD : public cMenuSetupPage { +private: + virtual void Set(void); +public: + cMenuSetupOSD(void) { Set(); } + }; + +void cMenuSetupOSD::Set(void) +{ + Clear(); + SetupTitle("OSD"); + Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &data.OSDLanguage, NumLanguages, Languages())); + Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); + Add(new cMenuEditIntItem( tr("Setup.OSD$Height"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); + Add(new cMenuEditIntItem( tr("Setup.OSD$Message time"), &data.OSDMessageTime, 1, 60)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"), &data.ChannelInfoPos, tr("bottom"), tr("top"))); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll pages"), &data.MenuScrollPage)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Sort timers"), &data.SortTimers)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs)); +} + +// --- cMenuSetupEPG --------------------------------------------------------- + +class cMenuSetupEPG : public cMenuSetupPage { +private: + virtual void Set(void); +public: + cMenuSetupEPG(void) { Set(); } + }; + +void cMenuSetupEPG::Set(void) +{ + Clear(); + SetupTitle("EPG"); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout"), &data.EPGScanTimeout)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); + Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime)); + Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder)); +} + +// --- cMenuSetupDVB --------------------------------------------------------- + +class cMenuSetupDVB : public cMenuSetupPage { +private: + virtual void Set(void); +public: + cMenuSetupDVB(void) { Set(); } + }; + +void cMenuSetupDVB::Set(void) +{ + Clear(); + SetupTitle("DVB"); + Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDvbApi::NumDvbApis)); + Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9")); +} + +// --- cMenuSetupLNB --------------------------------------------------------- + +class cMenuSetupLNB : public cMenuSetupPage { +private: + virtual void Set(void); +public: + cMenuSetupLNB(void) { Set(); } + }; + +void cMenuSetupLNB::Set(void) +{ + Clear(); + SetupTitle("LNB"); + Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF"), &data.LnbSLOF)); + Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency"), &data.LnbFrequLo)); + Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency"), &data.LnbFrequHi)); + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); +} + +// --- cMenuSetupCICAM ------------------------------------------------------- + +class cMenuSetupCICAM : public cMenuSetupPage { +private: + virtual void Set(void); +public: + cMenuSetupCICAM(void) { Set(); } + }; + +void cMenuSetupCICAM::Set(void) +{ + Clear(); + SetupTitle("CICAM"); + for (int d = 0; d < cDvbApi::NumDvbApis; d++) { + for (int i = 0; i < 2; i++) { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%s%d %d", tr("Setup.CICAM$CICAM DVB"), d + 1, i + 1); + Add(new cMenuEditCaItem(buffer, &data.CaCaps[d][i])); + } + } +} + +// --- cMenuSetupRecord ------------------------------------------------------ + +class cMenuSetupRecord : public cMenuSetupPage { +private: + virtual void Set(void); +public: + cMenuSetupRecord(void) { Set(); } + }; + +void cMenuSetupRecord::Set(void) +{ + Clear(); + SetupTitle("Recording"); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start"), &data.MarginStart)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop"), &data.MarginStop)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Primary limit"), &data.PrimaryLimit, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Default priority"), &data.DefaultPriority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime"), &data.DefaultLifetime, 0, MAXLIFETIME)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); + Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord), FileNameChars)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Record Dolby Digital"), &data.RecordDolbyDigital)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); +} + +// --- cMenuSetupReplay ------------------------------------------------------ + +class cMenuSetupReplay : public cMenuSetupPage { +private: + virtual void Set(void); +public: + cMenuSetupReplay(void) { Set(); } + }; + +void cMenuSetupReplay::Set(void) +{ + Clear(); + SetupTitle("Replay"); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode)); +} + +// --- cMenuSetupMisc -------------------------------------------------------- + +class cMenuSetupMisc : public cMenuSetupPage { +private: + virtual void Set(void); +public: + cMenuSetupMisc(void) { Set(); } + }; + +void cMenuSetupMisc::Set(void) +{ + Clear(); + SetupTitle("Miscellaneous"); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout"), &data.MinEventTimeout)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity"), &data.MinUserInactivity)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout"), &data.SVDRPTimeout)); +} + +// --- cMenuSetup ------------------------------------------------------------ + +class cMenuSetup : public cOsdMenu { +private: + virtual void Set(void); + eOSState Restart(void); +public: + cMenuSetup(void); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuSetup::cMenuSetup(void) +:cOsdMenu("") +{ + Set(); +} + +void cMenuSetup::Set(void) +{ + Clear(); + SetTitle(tr("Setup")); + SetHasHotkeys(); + Add(new cOsdItem(hk(tr("OSD")), osUser1)); + Add(new cOsdItem(hk(tr("EPG")), osUser2)); + Add(new cOsdItem(hk(tr("DVB")), osUser3)); + Add(new cOsdItem(hk(tr("LNB")), osUser4)); + Add(new cOsdItem(hk(tr("CICAM")), osUser5)); + Add(new cOsdItem(hk(tr("Recording")), osUser6)); + Add(new cOsdItem(hk(tr("Replay")), osUser7)); + Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8)); + Add(new cOsdItem(hk(tr("Restart")), osUser9)); +} + +eOSState cMenuSetup::Restart(void) +{ + if (Interface->Confirm(cRecordControls::Active() ? tr("Recording - restart anyway?") : tr("Really restart?"))) { + cThread::EmergencyExit(true); + return osEnd; + } + return osContinue; +} + +eOSState cMenuSetup::ProcessKey(eKeys Key) +{ + int osdLanguage = Setup.OSDLanguage; + eOSState state = cOsdMenu::ProcessKey(Key); + + switch (state) { + case osUser1: return AddSubMenu(new cMenuSetupOSD); + case osUser2: return AddSubMenu(new cMenuSetupEPG); + case osUser3: return AddSubMenu(new cMenuSetupDVB); + case osUser4: return AddSubMenu(new cMenuSetupLNB); + case osUser5: return AddSubMenu(new cMenuSetupCICAM); + case osUser6: return AddSubMenu(new cMenuSetupRecord); + case osUser7: return AddSubMenu(new cMenuSetupReplay); + case osUser8: return AddSubMenu(new cMenuSetupMisc); + case osUser9: return Restart(); + default: ; + } + if (Setup.OSDLanguage != osdLanguage) { + Set(); + if (!HasSubMenu()) + Display(); + } + return state; +} + // --- cMenuCommands --------------------------------------------------------- class cMenuCommands : public cOsdMenu { @@ -1982,14 +2217,14 @@ class cMenuCommands : public cOsdMenu { cMenuCommands::cMenuCommands(void) :cOsdMenu(tr("Commands")) { + SetHasHotkeys(); int i = 0; cCommand *command; while ((command = Commands.Get(i)) != NULL) { - Add(new cOsdItem(command->Title())); + Add(new cOsdItem(hk(command->Title()))); i++; } - SetHasHotkeys(); } eOSState cMenuCommands::Execute(void) @@ -2022,9 +2257,24 @@ eOSState cMenuCommands::ProcessKey(eKeys Key) #define ON_PRIMARY_INTERFACE tr("on primary interface") cMenuMain::cMenuMain(bool Replaying, eOSState State) -:cOsdMenu(tr("Main")) +:cOsdMenu("") { - digit = 0; + replaying = Replaying; + Set(); + + // Initial submenus: + + switch (State) { + case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break; + default: break; + } +} + +void cMenuMain::Set(void) +{ + Clear(); + //SetTitle("VDR"); // this is done below, including disk usage + SetHasHotkeys(); // Title with disk usage: @@ -2036,7 +2286,7 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) int Minutes = int(double(FreeMB) / MB_PER_MINUTE); int Hours = Minutes / 60; Minutes %= 60; - snprintf(buffer, sizeof(buffer), "%s - Disk %d%% - %2d:%02d %s", tr("Main"), Percent, Hours, Minutes, tr("free")); + snprintf(buffer, sizeof(buffer), "%s - Disk %d%% - %2d:%02d %s", tr("VDR"), Percent, Hours, Minutes, tr("free")); SetTitle(buffer); // Basic menu items: @@ -2051,7 +2301,7 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) // Replay control: - if (Replaying) + if (replaying) Add(new cOsdItem(tr(" Stop replaying"), osStopReplay)); // Record control: @@ -2077,32 +2327,14 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State) // Color buttons: - SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); + SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, NULL, replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL); Display(); lastActivity = time(NULL); - SetHasHotkeys(); - - // Initial submenus: - - switch (State) { - case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break; - default: break; - } -} - -const char *cMenuMain::hk(const char *s) -{ - static char buffer[32]; - if (digit < 9) { - snprintf(buffer, sizeof(buffer), " %d %s", ++digit, s); - return buffer; - } - else - return s; } eOSState cMenuMain::ProcessKey(eKeys Key) { + int osdLanguage = Setup.OSDLanguage; eOSState state = cOsdMenu::ProcessKey(Key); switch (state) { @@ -2143,13 +2375,19 @@ eOSState cMenuMain::ProcessKey(eKeys Key) } break; case kBlue: if (!HasSubMenu()) - state = osReplay; + state = replaying ? osStopReplay : osReplay; break; default: break; } } - if (Key != kNone) + if (Key != kNone) { lastActivity = time(NULL); + if (Setup.OSDLanguage != osdLanguage) { + Set(); + if (!HasSubMenu()) + Display(); + } + } else if (time(NULL) - lastActivity > MENUTIMEOUT) state = osEnd; return state; @@ -2345,6 +2583,109 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) return osEnd; } +// --- cVolumeBar ------------------------------------------------------------ + +class cVolumeBar : public cBitmap { +public: + cVolumeBar(int Width, int Height, int Current, int Total, const char *Prompt = NULL); + }; + +cVolumeBar::cVolumeBar(int Width, int Height, int Current, int Total, const char *Prompt) +:cBitmap(Width, Height, 2) +{ + int l = Prompt ? cBitmap::Width(Prompt) : 0; + int p = (Width - l) * Current / Total; + Text(0, 0, Prompt, clrGreen); + Fill(l, 0, p, Height - 1, clrGreen); + Fill(l + p, 0, Width - 1, Height - 1, clrWhite); +} + +// --- cDisplayVolume -------------------------------------------------------- + +#define VOLUMETIMEOUT 1000 //ms +#define MUTETIMEOUT 5000 //ms + +cDisplayVolume *cDisplayVolume::displayVolume = NULL; + +cDisplayVolume::cDisplayVolume(void) +:cOsdBase(true) +{ + displayVolume = this; + timeout = time_ms() + (cDvbApi::PrimaryDvbApi->IsMute() ? MUTETIMEOUT : VOLUMETIMEOUT); + Interface->Open(Setup.OSDwidth, -1); + Show(); +} + +cDisplayVolume::~cDisplayVolume() +{ + Interface->Close(); + displayVolume = NULL; +} + +void cDisplayVolume::Show(void) +{ + cDvbApi *dvbApi = cDvbApi::PrimaryDvbApi; + if (dvbApi->IsMute()) { + Interface->Fill(0, 0, Width(), 1, clrTransparent); + Interface->Write(0, 0, tr("Mute"), clrGreen); + } + else { + int Current = cDvbApi::CurrentVolume(); + int Total = MAXVOLUME; + const char *Prompt = tr("Volume "); +#ifdef DEBUG_OSD + int l = strlen(Prompt); + int p = int(double(Width() - l) * Current / Total + 0.5); + Interface->Write(0, 0, Prompt, clrGreen); + Interface->Fill(l, 0, p, 1, clrGreen); + Interface->Fill(l + p, 0, Width() - l - p, 1, clrWhite); +#else + cVolumeBar VolumeBar(Width() * dvbApi->CellWidth(), dvbApi->LineHeight(), Current, Total, Prompt); + Interface->SetBitmap(0, 0, VolumeBar); +#endif + } +} + +cDisplayVolume *cDisplayVolume::Create(void) +{ + if (!displayVolume) + new cDisplayVolume; + return displayVolume; +} + +void cDisplayVolume::Process(eKeys Key) +{ + if (displayVolume) + displayVolume->ProcessKey(Key); +} + +eOSState cDisplayVolume::ProcessKey(eKeys Key) +{ + switch (Key) { + case kVolUp|k_Repeat: + case kVolUp: + case kVolDn|k_Repeat: + case kVolDn: + Show(); + timeout = time_ms() + VOLUMETIMEOUT; + break; + case kMute: + if (cDvbApi::PrimaryDvbApi->IsMute()) { + Show(); + timeout = time_ms() + MUTETIMEOUT; + } + else + timeout = 0; + break; + case kNone: break; + default: if ((Key & k_Release) == 0) { + Interface->PutKey(Key); + return osEnd; + } + } + return time_ms() < timeout ? osContinue : osEnd; +} + // --- cRecordControl -------------------------------------------------------- cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) @@ -2666,6 +3007,8 @@ void cReplayControl::DisplayAtBottom(const char *s) if (s) { int w = dvbApi->WidthInCells(s); int d = max(Width() - w, 0) / 2; + if (modeOnly) //XXX remove when displaying replay mode differently + Interface->Fill(0, -1, Interface->Width(), 1, clrTransparent); //XXX remove when displaying replay mode differently Interface->Write(d, -1, s); Interface->Flush(); } @@ -2685,8 +3028,11 @@ void cReplayControl::ShowMode(void) if (NormalPlay) return; // no need to do indicate ">" unless there was a different mode displayed before // open small display + /*XXX change when displaying replay mode differently Interface->Open(9, -1); Interface->Clear(); + XXX*/ + Interface->Open(0, -1); //XXX remove when displaying replay mode differently visible = modeOnly = true; } diff --git a/menu.h b/menu.h index 9e49bf65e..ae46d02f2 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.37 2002/02/24 12:40:37 kls Exp $ + * $Id: menu.h 1.40 2002/03/16 09:51:10 kls Exp $ */ #ifndef _MENU_H @@ -17,8 +17,8 @@ class cMenuMain : public cOsdMenu { private: time_t lastActivity; - int digit; - const char *hk(const char *s); + bool replaying; + void Set(void); public: cMenuMain(bool Replaying, eOSState State = osUnknown); virtual eOSState ProcessKey(eKeys Key); @@ -40,6 +40,19 @@ class cDisplayChannel : public cOsdBase { virtual eOSState ProcessKey(eKeys Key); }; +class cDisplayVolume : public cOsdBase { +private: + int timeout; + static cDisplayVolume *displayVolume; + void Show(void); + cDisplayVolume(void); +public: + virtual ~cDisplayVolume(); + static cDisplayVolume *Create(void); + static void Process(eKeys Key); + eOSState ProcessKey(eKeys Key); + }; + class cMenuRecordingItem; class cMenuRecordings : public cOsdMenu { diff --git a/osd.c b/osd.c index 0a825d7da..e404a6f8a 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.20 2002/01/26 11:09:58 kls Exp $ + * $Id: osd.c 1.21 2002/03/10 16:18:06 kls Exp $ */ #include "osd.h" @@ -102,6 +102,23 @@ cOsdMenu::~cOsdMenu() Interface->Close(); } +const char *cOsdMenu::hk(const char *s) +{ + static char buffer[32]; + if (digit < 9) { + snprintf(buffer, sizeof(buffer), " %d %s", ++digit, s); + return buffer; + } + else + return s; +} + +void cOsdMenu::SetHasHotkeys(void) +{ + hasHotkeys = true; + digit = 0; +} + void cOsdMenu::SetStatus(const char *s) { delete status; diff --git a/osd.h b/osd.h index 4eb2a22dd..8e825869d 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.26 2002/02/24 12:55:16 kls Exp $ + * $Id: osd.h 1.27 2002/03/10 16:18:11 kls Exp $ */ #ifndef __OSD_H @@ -33,6 +33,16 @@ enum eOSState { osUnknown, osSwitchDvb, osBack, osEnd, + os_User, // the following values can be used locally + osUser1, + osUser2, + osUser3, + osUser4, + osUser5, + osUser6, + osUser7, + osUser8, + osUser9, }; class cOsdItem : public cListObject { @@ -77,9 +87,12 @@ class cOsdMenu : public cOsdBase, public cList<cOsdItem> { cOsdMenu *subMenu; const char *helpRed, *helpGreen, *helpYellow, *helpBlue; const char *status; + int digit; bool hasHotkeys; protected: bool visible; + const char *hk(const char *s); + void SetHasHotkeys(void); virtual void Clear(void); bool SpecialItem(int idx); void SetCurrent(cOsdItem *Item); @@ -100,7 +113,6 @@ class cOsdMenu : public cOsdBase, public cList<cOsdItem> { public: cOsdMenu(const char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0); virtual ~cOsdMenu(); - void SetHasHotkeys(void) { hasHotkeys = true; } int Current(void) { return current; } void Add(cOsdItem *Item, bool Current = false); void Display(void); diff --git a/recording.c b/recording.c index 4d07434a0..56ea05653 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.54 2002/02/24 11:21:42 kls Exp $ + * $Id: recording.c 1.57 2002/03/16 12:17:44 kls Exp $ */ #include "recording.h" @@ -86,6 +86,7 @@ void AssertFreeDiskSpace(int Priority) if (!LockFile.Lock()) return; // Remove the oldest file that has been "deleted": + isyslog(LOG_INFO, "low disk space while recording, trying to remove a deleted recording..."); cRecordings Recordings; if (Recordings.Load(true)) { cRecording *r = Recordings.First(); @@ -101,12 +102,13 @@ void AssertFreeDiskSpace(int Priority) } } // No "deleted" files to remove, so let's see if we can delete a recording: + isyslog(LOG_INFO, "...no deleted recording found, trying to delete an old recording..."); if (Recordings.Load(false)) { cRecording *r = Recordings.First(); cRecording *r0 = NULL; while (r) { if (r->lifetime < MAXLIFETIME) { // recordings with MAXLIFETIME live forever - if ((r->lifetime == 0 && Priority > r->priority) || // the recording has guaranteed lifetime and the new recording has higher priority + if ((r->lifetime == 0 && Priority > r->priority) || // the recording has no guaranteed lifetime and the new recording has higher priority (time(NULL) - r->start) / SECSINDAY > r->lifetime) { // the recording's guaranteed lifetime has expired if (r0) { if (r->priority < r0->priority || (r->priority == r0->priority && r->start < r0->start)) @@ -122,6 +124,7 @@ void AssertFreeDiskSpace(int Priority) return; } // Unable to free disk space, but there's nothing we can do about that... + isyslog(LOG_INFO, "...no old recording found, giving up"); Interface->Confirm(tr("Low disk space!"), 30); } LastFreeDiskCheck = time(NULL); @@ -551,6 +554,11 @@ bool cRecording::Delete(void) char *ext = strrchr(NewName, '.'); if (strcmp(ext, RECEXT) == 0) { strncpy(ext, DELEXT, strlen(ext)); + if (access(NewName, F_OK) == 0) { + // the new name already exists, so let's remove that one first: + isyslog(LOG_INFO, "removing recording %s", NewName); + RemoveVideoFile(NewName); + } isyslog(LOG_INFO, "deleting recording %s", FileName()); result = RenameVideoFile(FileName(), NewName); } diff --git a/runvdr b/runvdr index afd645fc4..13ee73294 100755 --- a/runvdr +++ b/runvdr @@ -18,14 +18,14 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: runvdr 1.8 2001/07/27 07:35:19 kls Exp $ +# $Id: runvdr 1.9 2002/03/16 16:22:12 kls Exp $ DVBDIR="../DVB/driver" VDRPRG="./vdr" VDRCMD="$VDRPRG -w 60 $*" LSMOD="`/sbin/lsmod | grep -w '^dvb' | wc -l`" -KILLPROC="/sbin/killproc -TERM" +KILL="/usr/bin/killall -q -TERM" # Load driver if it hasn't been loaded already: if [ $LSMOD -eq 0 ] ; then @@ -37,7 +37,7 @@ while (true) do if test $? -eq 0; then exit; fi date echo "restarting VDR" - $KILLPROC $VDRPRG + $KILL $VDRPRG sleep 10 (cd $DVBDIR; make rmmod; make insmod) date diff --git a/svdrp.c b/svdrp.c index 228003ea0..06f8ebbc5 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.33 2002/02/24 14:16:03 kls Exp $ + * $Id: svdrp.c 1.34 2002/03/08 17:17:05 kls Exp $ */ #include "svdrp.h" @@ -247,6 +247,12 @@ const char *HelpPages[] = { " Updates a timer. Settings must be in the same format as returned\n" " by the LSTT command. If a timer with the same channel, day, start\n" " and stop time does not yet exists, it will be created.", + "VOLU [ <number> | + | - | mute ]\n" + " Set the audio volume to the given number (which is limited to the range\n" + " 0...255). If the special options '+' or '-' are given, the volume will\n" + " be turned up or down, respectively. The option 'mute' will toggle the\n" + " audio muting. If no option is given, the current audio volume level will\n" + " be returned.", "QUIT\n" " Exit vdr (SVDRP).\n" " You can also hit Ctrl-D to exit.", @@ -920,6 +926,28 @@ void cSVDRP::CmdUPDT(const char *Option) Reply(501, "Missing timer settings"); } +void cSVDRP::CmdVOLU(const char *Option) +{ + if (*Option) { + if (isnumber(Option)) + cDvbApi::PrimaryDvbApi->SetVolume(strtol(Option, NULL, 10), true); + else if (strcmp(Option, "+") == 0) + cDvbApi::PrimaryDvbApi->SetVolume(VOLUMEDELTA); + else if (strcmp(Option, "-") == 0) + cDvbApi::PrimaryDvbApi->SetVolume(-VOLUMEDELTA); + else if (strcasecmp(Option, "MUTE") == 0) + cDvbApi::PrimaryDvbApi->ToggleMute(); + else { + Reply(501, "Unknown option: \"%s\"", Option); + return; + } + } + if (cDvbApi::PrimaryDvbApi->IsMute()) + Reply(250, "Audio is mute"); + else + Reply(250, "Audio volume is %d", cDvbApi::CurrentVolume()); +} + #define CMD(c) (strcasecmp(Cmd, c) == 0) void cSVDRP::Execute(char *Cmd) @@ -960,8 +988,9 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("NEWC")) CmdNEWC(s); else if (CMD("NEWT")) CmdNEWT(s); else if (CMD("NEXT")) CmdNEXT(s); - else if (CMD("UPDT")) CmdUPDT(s); else if (CMD("PUTE")) CmdPUTE(s); + else if (CMD("UPDT")) CmdUPDT(s); + else if (CMD("VOLU")) CmdVOLU(s); else if (CMD("QUIT")) Close(); else Reply(500, "Command unrecognized: \"%s\"", Cmd); } diff --git a/svdrp.h b/svdrp.h index 42e5b6911..29ef83cd6 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.14 2002/02/24 10:48:21 kls Exp $ + * $Id: svdrp.h 1.15 2002/03/08 16:40:23 kls Exp $ */ #ifndef __SVDRP_H @@ -73,6 +73,7 @@ class cSVDRP { void CmdNEXT(const char *Option); void CmdPUTE(const char *Option); void CmdUPDT(const char *Option); + void CmdVOLU(const char *Option); void Execute(char *Cmd); public: cSVDRP(int Port); diff --git a/thread.c b/thread.c index 94ba86057..a7e77f1b4 100644 --- a/thread.c +++ b/thread.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.18 2002/02/23 13:49:06 kls Exp $ + * $Id: thread.c 1.19 2002/03/09 12:05:44 kls Exp $ */ #include "thread.h" @@ -327,14 +327,21 @@ int cPipe::Close(void) f = NULL; } - if (pid >= 0) { + if (pid > 0) { int status = 0; - struct rusage ru; int i = 5; - while (ret == -1 && i > 0) { - usleep(1000); - ret = wait4(pid, &status, WNOHANG, &ru); + while (i > 0) { + ret = waitpid(pid, &status, WNOHANG); + if (ret < 0) { + if (errno != EINTR && errno != ECHILD) { + LOG_ERROR; + break; + } + } + else if (ret == pid) + break; i--; + usleep(100000); } if (!i) { diff --git a/vdr.c b/vdr.c index a246be11c..17ae1488e 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.98 2002/03/03 14:56:03 kls Exp $ + * $Id: vdr.c 1.101 2002/03/09 17:10:16 kls Exp $ */ #include <getopt.h> @@ -50,8 +50,6 @@ #define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown #define MANUALSTART 600 // seconds the next timer must be in the future to assume manual start -#define VOLUMEDELTA 5 // used to increase/decrease the volume - static int Interrupted = 0; static void SignalHandler(int signum) @@ -85,6 +83,7 @@ int main(int argc, char *argv[]) int SVDRPport = DEFAULTSVDRPPORT; const char *ConfigDirectory = NULL; bool DaemonMode = false; + bool MuteAudio = false; int WatchdogTimeout = DEFAULTWATCHDOG; const char *Terminal = NULL; const char *Shutdown = NULL; @@ -97,6 +96,7 @@ int main(int argc, char *argv[]) { "epgfile", required_argument, NULL, 'E' }, { "help", no_argument, NULL, 'h' }, { "log", required_argument, NULL, 'l' }, + { "mute", no_argument, NULL, 'm' }, { "port", required_argument, NULL, 'p' }, { "record", required_argument, NULL, 'r' }, { "shutdown", required_argument, NULL, 's' }, @@ -108,7 +108,7 @@ int main(int argc, char *argv[]) int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:r:s:t:v:w:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:mp:r:s:t:v:w:", long_options, &option_index)) != -1) { switch (c) { case 'a': cDvbApi::SetAudioCommand(optarg); break; @@ -143,6 +143,7 @@ int main(int argc, char *argv[]) " -l LEVEL, --log=LEVEL set log level (default: 3)\n" " 0 = no logging, 1 = errors only,\n" " 2 = errors and info, 3 = errors, info and debug\n" + " -m, --mute mute audio of the primary DVB device at startup\n" " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" " 0 turns off SVDRP\n" " -r CMD, --record=CMD call CMD before and after a recording\n" @@ -170,6 +171,8 @@ int main(int argc, char *argv[]) fprintf(stderr, "vdr: invalid log level: %s\n", optarg); return 2; break; + case 'm': MuteAudio = true; + break; case 'p': if (isnumber(optarg)) SVDRPport = atoi(optarg); else { @@ -269,7 +272,10 @@ int main(int argc, char *argv[]) cSIProcessor::Read(); Channels.SwitchTo(Setup.CurrentChannel); - cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true); + if (MuteAudio) + cDvbApi::PrimaryDvbApi->ToggleMute(); + else + cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true); cEITScanner EITScanner; @@ -351,10 +357,16 @@ int main(int argc, char *argv[]) case kVolUp: case kVolDn|k_Repeat: case kVolDn: - cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA); - break; case kMute: - cDvbApi::PrimaryDvbApi->ToggleMute(); + if (key == kMute) { + if (!cDvbApi::PrimaryDvbApi->ToggleMute() && !Menu) + break; // no need to display "mute off" + } + else + cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA); + if (!Menu && (!ReplayControl || !ReplayControl->Visible())) + Menu = cDisplayVolume::Create(); + cDisplayVolume::Process(key); break; // Power off: case kPower: isyslog(LOG_INFO, "Power button pressed"); From 262327908d329a8c292d8ae71fe9d135390a3cde Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Mon, 1 Apr 2002 18:00:00 +0200 Subject: [PATCH 039/307] Version 1.0.0pre5 - Fixed restoring CICAM setup values for a fourth DVB card (thanks to Klaus Wolf). - Completed internationalization of OSD texts (thanks to Hannu Savolainen, Arnold Niessen, Paulo Lopes, Jean-Claude Repetto, Alberto Carraro, Matjaz Thaler and Truls Slevigen). - Improved file I/O in case of EINTR, which may occur e.g. with heavy system load (thanks to Werner Fink). - Now writing the title of a recording into the 'summary.vdr' file. - Workaround for displaying still frames with the unpatched LinuxDVB driver (if anybody ever finds out why the unpatched driver doesn't display VDR's still frames, please let me know). - When executing a command from the "Commands" menu, the title of that command is now immediately shown in the status line (followed by "...") to give the user some feedback that the command is being executed, which is especially important if this takes some time. - Fixed scrolling the "Channels" menu in case the cursor ends up on a group delimiter (thanks to Bernd Zierath for helping to debug this one). - Added manual pages vdr(1) and vdr(5) (which made the FORMATS file obsolete). - New command command line option '-V' to display the VDR version. - Adjusting column width for channel numbers in case there are more than 999 channels. - Checking the return value of '...FileRady...' calls in dvbapi.c for better performance under heavy system load. - New 'make' target 'install', which copies the manual pages and executables to their appropriate system locations and creates the /video directory if it doesn't exist yet. - Automatic hotkey assignment is now suppressed if the first entry in commands.conf starts with a digit in the range '1'...'9', followed by a blank. - Fixed a bug in switching back the replay mode display in time shift mode (thanks to Achim Lange for reporting this one). - Fixed a bug in the 'First day' timer parameter for timers that record over midnight. - Added units to Setup parameters. - Changed time entry in the 'Jump' command during replay, so that it is filled up from right to left. - Now using statfs() to determine the amount of free disk space, which avoids the use of an external 'df' command (thanks to Ruben Nunez Francisco). - Fixed skipping the next hit of a repeating timer (thanks to Rainer Zocholl for reporting this one). - Fixed a bug when a timer records over midnight of a day that had a change in Daylight Saving Time. - Added Polish language texts (thanks to Michael Rakowski). - Fixed a bug in parsing group separators in channels.conf (thanks to Henning Holtschneider for reporting this one). - Changed the default 'Ok' key when using the PC keyboard from '5' (in the numeric block) to 'Enter', because the '5' key didn't work on keyboards with the F-keys on top. - Fixed a bug in the EPG bugfix mechanism if the extended description is shorter than 3 characters (thanks to Andreas Schultz). --- CONTRIBUTORS | 40 +- FORMATS | 227 ---------- HISTORY | 53 ++- INSTALL | 12 +- Makefile | 17 +- README | 8 - config.c | 14 +- config.h | 6 +- dvbapi.c | 162 +++---- eit.c | 6 +- eit.diff | 25 ++ i18n.c | 1211 +++++++++++++++++++++++++++++--------------------- keys-pc.conf | 2 +- menu.c | 141 +++--- menu.h | 4 +- mpatrol.diff | 56 +++ osd.c | 24 +- recording.c | 8 +- svdrp.c | 12 +- tools.c | 55 ++- vdr.1 | 164 +++++++ vdr.5 | 382 ++++++++++++++++ vdr.c | 11 +- 23 files changed, 1660 insertions(+), 980 deletions(-) delete mode 100644 FORMATS create mode 100644 eit.diff create mode 100644 mpatrol.diff create mode 100644 vdr.1 create mode 100644 vdr.5 diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 3adfbd961..6a126c9fb 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -51,10 +51,10 @@ Matthias Schniedermeyer <ms@citd.de> for helping to debug the "move to last position in list" bug Miha Setina <mihasetina@softhome.net> - for translating the OSD texts to the Slovenian language + for translating OSD texts to the Slovenian language Alberto Carraro <bertocar@tin.it> - for translating the OSD texts to the Italian language + for translating OSD texts to the Italian language Deti Fliegl <deti@fliegl.de> for implementing the 'CurrentChannel' setup parameter @@ -77,7 +77,7 @@ Axel Gruber <axel@agm.de> for his support in keeping the Premiere World channels up to date in 'channels.conf' Arnold Niessen <niessen@iae.nl> <arnold.niessen@philips.com> - for translating the OSD texts to the Dutch language + for translating OSD texts to the Dutch language Jrgen Sauer <jojo@automatix.de> for implementing the -t option to set the controlling terminal @@ -87,9 +87,10 @@ Benjamin Reichardt <reichard@math.uni-goettingen.de> Henning Holtschneider <hh@holtschneider.com> for patching 'runvdr' to check whether the driver is already loaded + for reporting a bug in parsing group separators in channels.conf -Paulo Manuel Martins Lopes <pmml@netvita.pt> - for translating the OSD texts to the Portugese language +Paulo Lopes <pmml@netvita.pt> + for translating OSD texts to the Portugese language Markus Lang <pretender@gaze.de> and Ulrich Rder <dynamite@efr-net.de> for making DiSEqC support configurable @@ -98,13 +99,13 @@ Markus Lang <pretender@gaze.de> for some initial code for grouping the Setup menu into several sub-menus Jean-Claude Repetto <jc@repetto.org> - for translating the OSD texts to the French language + for translating OSD texts to the French language Andre Valentin <av2000@topmail.de> for increasing the key name buffer size for LIRC Jrgen Tvedt <pjtvedt@online.no> - for translating the OSD texts to the Norwegian language + for translating OSD texts to the Norwegian language Stefan Huelswitt <huels@iname.com> for fixing the repeat function with LIRC @@ -129,6 +130,8 @@ Andreas Schultz <aschultz@warp10.net> dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>) for adding PTS to the converted PCM audio when replaying a DVD for fixing a crash in case there is no 'epg.data' at program start + for fixing a bug in the EPG bugfix mechanism if the extended description is shorter + than 3 characters Aaron Holtzman for writing 'ac3dec' @@ -141,6 +144,7 @@ Uwe Scheffler <UweScheffler@t-online.de> Matjaz Thaler <matjaz.thaler@guest.arnes.si> for improving AC3 decoding when replaying DVDs + for translating OSD texts to the Slovenian language Artur Skawina <skawina@geocities.com> for improving the font file generation in the Makefile @@ -205,7 +209,7 @@ Michael Paar <mpaar@uumail.de> for enabling recording of radio channels Hannu Savolainen <hannu@opensound.com> - for translating the OSD texts to the Finnish language + for translating OSD texts to the Finnish language Jrgen Schmidt <ju@ct.heise.de> for fixing a problem with 'in_addr_t' on systems with glibc < 2.2. @@ -214,9 +218,10 @@ Uwe Freese <mail@uwe-freese.de> for suggesting to automatically close an empty recordings page after deleting an entry -Rainer Zocholl <Usenet-372114@zocki.toppoint.de> +Rainer Zocholl <vdrcontrib@zocki.toppoint.de> for suggesting a confirmation prompt when the user presses the "Power" button and there is an upcoming timer event + for reporting a bug in skipping the next hit of a repeating timer Oleg Assovski <assen@bitcom.msk.ru> for adding EPG scanning for another 4 days @@ -233,3 +238,20 @@ Mirko G Achim Lange <Achim_Lange@t-online.de> for replacing 'killproc' with 'killall' in 'runvdr' to make it work on Debian + for reporting a bug in switching back the replay mode display in time shift mode + +Klaus Wolf <klaus@wolfsoft.de> + for reporting a bug in restoring the CICAM values for a fourth DVB card + +Bernd Zierath <b.zierath@ebv.com> + for helping to debug scrolling the "Channels" menu in case the cursor ends up on + a group separator + +Truls Slevigen <truls@slevigen.no> + for translating OSD texts to the Norwegian language + +Ruben Nunez Francisco <ruben.nunez@tang-it.com> + for implementing FreeDiskSpaceMB() without external 'df' command + +Michael Rakowski <mrak@gmx.de> + for translating OSD texts to the Polish language diff --git a/FORMATS b/FORMATS deleted file mode 100644 index 63ae7e1dd..000000000 --- a/FORMATS +++ /dev/null @@ -1,227 +0,0 @@ -Video Disk Recorder File Formats --------------------------------- - -* channels.conf - - This file contains the channel setup. - It consists of two types of lines: "group delimiters" and "channel - definitions". - - A "group delimiter" is a line starting with a ':' as the very first - character, followed by arbitrary text. - Example: ":First group" - - A "channel definition" is a line with channel data, where the fields - are separated by ':' characters: - Example: "RTL:12188:h:1:27500:163:104:105:0:12003" - - The fields in a channel definition have the following meaning (from left - to right): - - - Name: the channel's name (if the name originally contains a ':' character - it has to be replaced by '|') - - Frequency in MHz for DVB-S and DVB-C, kHz for DVB-T (as an integer) - - Polarization (one of 'h', 'H', 'v', 'V') ** - - Diseqc number ** - - Symbol rate *** - - Video PID (set to '0' for radio channels, '1' for encrypted radio channels) - - Audio PID (either one number, or two, separated by a comma) - If this channel also carries Dolby Digital sound, the Dolby PIDs follow - the audio PIDs, separated by a semicolon, as in "...:101,102;103,104:..." - - Teletext PID - - Conditional Access (0 = Free To Air, 1..4 = explicitly requires the DVB card - with the given number, >=100 = requires a specific decryption method defined - in 'ca.conf'). - - Program Number - - Fields marked with ** are only meaningful for DVB-S receivers. - DVB-C and DVB-T receivers simply ignore these. - Fields marked with *** are only meaningful for DVB-S and DVB-C receivers. - DVB-T receivers simply ignore these. - -* ca.conf - - This file contains the definitions of the various conditional access code - numbers. Anything after (and including) a '#' character is comment. - Value lines consist of an integer number, followed by a text describing - this decryption method (typically the name of the pay tv service using this - decryption method). - The special value 0 means "Free To Air", i.e. can be used for channels that - don't require additional decryption hardware. - The values 1..4 can be used for channels that for some reason explicitly - need a given DVB card (for backward compatibility). - The values defined in this file are the ones used in the 'Ca' parameter of - 'channels.conf'. - -* timers.conf - - This file contains the timer setup. - - The fields in a timer definition have the following meaning (from left - to right): - - - Timer active (0 = inactive, 1 = active, 3 = instant recording) - Values other than these can be used by external programs to mark active timers - and recognize if the user has modified them. When a user modifes an active - timer the 'active' field will be explicitly set to '1' (or '0', respectively, - if the user deactivates the timer). - Note: in order to allow future extensibility, external programs using the - 'active' parameter should only use the upper 16 bit of this 32 bit parameter - and leave the lower 16 bit untouched. - - Program number of the channel to record - - Day of recording (in case of a repeating timer), either one or more of - M------ = Monday - -T----- = Tuesday - --W---- = Wednesday - ---T--- = Thrusday - ----F-- = Friday - -----S- = Saturday - ------S = Sunday - (any combination is possible, for example MTWTF--, and the days may be - indicated by any characters except '-', so for example ABC---- would set - a timer that records on monday, tuesday and wednesday) or the "day of month" - (1..31) in case of a single shot timer. - The day definition of a repeating timer may be followed by the date when that - timer shall hit for the first time. The format for this is @YYYY-MM-DD, - so a complete definition could look like this: MTWTF--@2002-02-18. This - "first day" feature can be used to disable a repeating timer for a couple - of days, or for instance to define a new Mon...Fri timer on wednesday, which - actually starts "monday next week". The "first day" date given need not be - that of a day when the timer would actually hit. - - Start time (first two digits for the hour, second two digits for the minutes) - - End time (first two digits for the hour, second two digits for the minutes) - - Priority (from 0 to 99, 0 = lowest prioity, 99 = highest priority) - - Guaranteed lifetime of recording (in days); 0 means that this recording may - be automatically deleted by a new recording with higher priority, 99 means - that this recording will never be automatically deleted - - Name of timer (will be used to name the recording); if the name contains - any ':' characters, these have to be replaced with '|'. If the name shall - contain subdirectories, these have to be delimited by '~' (since the '/' - character may be part of a regular programme name). - The special keywords TITLE and EPISODE, if present, will be replaced - with the title and episode information from the EPG data at the time of - recording (if that data is available). If at the time of recording either - of these cannot be determined, TITLE will default to the channel name, and - EPISODE will default to a blank. - - Summary (any newline characters in the summary have to be replaced with '|'; - the summary may contain ':' characters) - -* setup.conf - - This file contains the basic configuration options for VDR. - - Each line contains one option in the format "Name = Value". - - See the MANUAL file for a description of the available options. - -* commands.conf - - This file contains the definitions of commands that can be executed from - the "VDR" menu's "Commands" option. - - Each line contains one command definition in the following format: - - title : command - - where 'title' is the string the will be displayed in the "Commands" menu, - and 'command' is the actual command string that will be executed when this - option is selected. The delimiting ':' may be surrounded by any number of - white space characters. - - In order to avoid error messages to stderr, every command should have - stderr redirected to stdout. Everything the command prints to stdout will - be displayed in a result window, with 'title' as its title. - - Examples: - - Check for new mail: /usr/local/bin/checkmail 2>&1 - CPU status : /usr/local/bin/cpustatus 2>&1 - Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' - -* svdrphosts.conf - - This file contains the IP numbers of all hosts that are allowed to access the - SVDRP port. - - Each line contains one IP number in the format - - IP-Address[/Netmask] - - where 'IP-Address' is the address of a host or a network in the usual dot - separated notation (as in 192.168.100.1). If the optional 'Netmask' is given - only the given number of bits of 'IP-Address' are taken into account. This - allows you to grant SVDRP access to all hosts of an entire network. 'Netmask' - can be any integer from 1 to 32. The special value of 0 is only accepted if - the 'IP-Address' is 0.0.0.0, because this will give access to any host (USE - THIS WITH CARE!). - - Everything following (and including) a '#' character is considered to be - comment. - -* marks.vdr - - This file (if present in a recording directory) contains the editing marks - defined for this recording. - - Each line contains the definition of one mark in the following format: - - hh:mm:ss.ff comment - - where 'hh:mm:ss.ff' is a frame position within the recording, given as "hours, - minutes, seconds and (optional) frame number". 'comment' can be any string - and may be used to describe this mark. If present, 'comment' must be separated - from the frame position by at least one blank. - - The lines in this file need not necessarily appear in the correct temporal - sequence, they will be automatically sorted by time index. - - CURRENT RESTRICTIONS: - - - the 'comment' is currently not used by VDR - - marks must have a frame number, and that frame MUST be an I-frame (this - means that only marks generated by VDR itself can be used, since they - will always be guaranteed to mark I-frames). - -* 001.vdr ... 255.vdr - - These are the actual recorded MPEG data files. In order to keep the size of - an individual file below a given limit, a recording is split into several - files. The contents of these files is "Packetized Elementary Stream" (PES) - and contains ES packets with ids 0xE0 for video, 0xC0 for audio 1 and 0xC1 - for audio 2 (if available). Dolby Digital data is stored in packets with - ids 0xBD. - -* epg.data - - This file contains the EPG data in an easily parsable format. The first - character of each line defines what kind of data this line contains. - - The following tag characters are defined: - - C <service id> <channel name> - E <event id> <start time> <duration> <table id> - T <title> - S <subtitle> - D <description> - e - c - - Lowercase characters mark the end of a sequence that was started by the - corresponding uppercase character. The outer frame consists of a sequence - of one or more 'C'...'c' (Channel) entries. Inside these any number of - 'E'...'e' (Event) entries are allowed. The 'T', 'S' and 'D' entries are - optional (although every event should at least have a 'T' entry). - - <service id> is the "program number" as defined in 'channels.conf' - <channel name> is the "name" as in 'channels.conf' (for information only) - <start time> is the time (as a time_t integer) in UTC when this event starts - <duration> is the time (in seconds) that this event will take - <table id> is a hex number that indicates the table this event is contained - in (if this is left empty or 0 this event will not be overwritten - or modified by data that comes from the DVB stream) - <title> is the title of the event - <subtitle> is the subtitle (typically the name of the episode etc.) - <description> is the description of the event - - This file will be read at program startup in order to restore the results of - previous EPG scans. diff --git a/HISTORY b/HISTORY index 708f6d9da..cafa4c1dd 100644 --- a/HISTORY +++ b/HISTORY @@ -529,7 +529,7 @@ Video Disk Recorder Revision History 2001-06-26: Version 0.83 - Avoiding "Device or resource busy" error message when setting PIDs. -- Added Portugese language texts (thanks to Paulo Manuel Martins Lopes). +- Added Portugese language texts (thanks to Paulo Lopes). - Recording and replaying Dolby Digital (AC3) sound. - No longer getting stuck when a channel doesn't sync while switching with the 'Up' and 'Down' keys. @@ -1119,3 +1119,54 @@ Video Disk Recorder Revision History driver are wrapped into a mechanism that actually performs this action if VDR exits. The 'runvdr' script can be used for this purpose. - Refined texts of the "Setup" menu. + +2002-04-01: Version 1.0.0pre5 + +- Fixed restoring CICAM setup values for a fourth DVB card (thanks to Klaus Wolf). +- Completed internationalization of OSD texts (thanks to Hannu Savolainen, + Arnold Niessen, Paulo Lopes, Jean-Claude Repetto, Alberto Carraro, Matjaz + Thaler and Truls Slevigen). +- Improved file I/O in case of EINTR, which may occur e.g. with heavy system + load (thanks to Werner Fink). +- Now writing the title of a recording into the 'summary.vdr' file. +- Workaround for displaying still frames with the unpatched LinuxDVB driver + (if anybody ever finds out why the unpatched driver doesn't display VDR's + still frames, please let me know). +- When executing a command from the "Commands" menu, the title of that command + is now immediately shown in the status line (followed by "...") to give the + user some feedback that the command is being executed, which is especially + important if this takes some time. +- Fixed scrolling the "Channels" menu in case the cursor ends up on a group + delimiter (thanks to Bernd Zierath for helping to debug this one). +- Added manual pages vdr(1) and vdr(5) (which made the FORMATS file obsolete). +- New command command line option '-V' to display the VDR version. +- Adjusting column width for channel numbers in case there are more than 999 + channels. +- Checking the return value of '...FileRady...' calls in dvbapi.c for better + performance under heavy system load. +- New 'make' target 'install', which copies the manual pages and executables + to their appropriate system locations and creates the /video directory if + it doesn't exist yet. +- Automatic hotkey assignment is now suppressed if the first entry in + commands.conf starts with a digit in the range '1'...'9', followed by a blank. +- Fixed a bug in switching back the replay mode display in time shift mode + (thanks to Achim Lange for reporting this one). +- Fixed a bug in the 'First day' timer parameter for timers that record over + midnight. +- Added units to Setup parameters. +- Changed time entry in the 'Jump' command during replay, so that it is filled + up from right to left. +- Now using statfs() to determine the amount of free disk space, which avoids + the use of an external 'df' command (thanks to Ruben Nunez Francisco). +- Fixed skipping the next hit of a repeating timer (thanks to Rainer Zocholl + for reporting this one). +- Fixed a bug when a timer records over midnight of a day that had a change in + Daylight Saving Time. +- Added Polish language texts (thanks to Michael Rakowski). +- Fixed a bug in parsing group separators in channels.conf (thanks to Henning + Holtschneider for reporting this one). +- Changed the default 'Ok' key when using the PC keyboard from '5' (in the + numeric block) to 'Enter', because the '5' key didn't work on keyboards with + the F-keys on top. +- Fixed a bug in the EPG bugfix mechanism if the extended description is shorter + than 3 characters (thanks to Andreas Schultz). diff --git a/INSTALL b/INSTALL index e87f7bea8..911285cee 100644 --- a/INSTALL +++ b/INSTALL @@ -78,6 +78,8 @@ option to set the controlling terminal, as in vdr:123:respawn:/usr/local/bin/vdr --terminal=/dev/tty8 -w 60 +See the man page vdr(1) for complete information about all command line options. + Locale ------ @@ -279,17 +281,15 @@ with the name of the basic directory when running 'vdr': Configuration files: -------------------- -There are three configuration files that hold information about -channels, remote control keys and timers. By default these files are +There are several configuration files that hold information about +channels, remote control keys, timers etc. By default these files are assumed to be located in the video directory, but a different directory can be used with the '-c' option. For starters just copy all *.conf files from the VDR directory into your video directory. The configuration files can be edited with any text editor, or will be written by the 'vdr' program if any changes are made inside the on-screen menus. -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. +Take a look at man page vdr(5) for information about the file formats. The files that come with this package contain the author's selections, so please make sure you adapt these to your personal taste. Also make sure @@ -350,7 +350,7 @@ The default PC key assignments are: Up, Down, Left, Right Crsr keys in numeric block Menu 'Home' in numeric block - Ok '5' in numeric block + Ok 'Enter' Back 'End' in numeric block Red, Green, Yellow, Blue 'F1'..'F4' 0..9 '0'..'9' in top row diff --git a/Makefile b/Makefile index ecb8f81fa..62fd8973b 100644 --- a/Makefile +++ b/Makefile @@ -4,12 +4,16 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.31 2002/02/24 12:29:54 kls Exp $ +# $Id: Makefile 1.33 2002/04/01 12:50:48 kls Exp $ .DELETE_ON_ERROR: DVBDIR = ../DVB DTVDIR = ./libdtv +MANDIR = /usr/local/man +BINDIR = /usr/local/bin + +VIDEODIR = /video INCLUDES = -I$(DVBDIR)/ost/include @@ -84,6 +88,17 @@ genfontfile: genfontfile.c $(DTVLIB) $(DTVDIR)/libdtv.h: make -C $(DTVDIR) all +# Install the files: + +install: + @cp vdr runvdr $(BINDIR) + @gzip -c vdr.1 > $(MANDIR)/man1/vdr.1.gz + @gzip -c vdr.5 > $(MANDIR)/man5/vdr.5.gz + @if [ ! -d $(VIDEODIR) ]; then\ + mkdir $(VIDEODIR);\ + cp *.conf $(VIDEODIR);\ + fi + # Housekeeping: clean: diff --git a/README b/README index 0dfc875ef..6b6e33e6d 100644 --- a/README +++ b/README @@ -31,11 +31,3 @@ file management and even "on disk editing". The menus of commercial set-top-boxes usually are a lot more fancy than the ones in this system, but here we have the full source code and can modify the menus in whatever way desired. - -What do you think? ------------------- - -So, what do you think about this project? Does it make sense? Were you -able to use it? Do you have suggestions on how to improve it? -Please send email to kls@cadsoft.de if you'd like to comment on this. - diff --git a/config.c b/config.c index b89fe748d..7104dcc27 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.91 2002/03/17 14:24:09 kls Exp $ + * $Id: config.c 1.96 2002/04/01 11:54:05 kls Exp $ */ #include "config.h" @@ -248,6 +248,7 @@ bool cChannel::Parse(const char *s) strn0cpy(name, s, MaxChannelName); name[strlen(name) - 1] = 0; // strip the '\n' groupSep = true; + number = 0; } else return false; @@ -439,6 +440,7 @@ int cTimer::ParseDay(const char *s, time_t *FirstDay) tm_r.tm_year -= 1900; tm_r.tm_mon--; tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0; + tm_r.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting *FirstDay = mktime(&tm_r); } } @@ -560,6 +562,7 @@ time_t cTimer::IncDay(time_t t, int Days) tm tm = *localtime_r(&t, &tm_r); tm.tm_mday += Days; // now tm_mday may be out of its valid range int h = tm.tm_hour; // save original hour to compensate for DST change + tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting t = mktime(&tm); // normalize all values tm.tm_hour = h; // compensate for DST change return mktime(&tm); // calculate final result @@ -572,6 +575,7 @@ time_t cTimer::SetTime(time_t t, int SecondsFromMidnight) tm.tm_hour = SecondsFromMidnight / 3600; tm.tm_min = (SecondsFromMidnight % 3600) / 60; tm.tm_sec = SecondsFromMidnight % 60; + tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting return mktime(&tm); } @@ -602,7 +606,7 @@ bool cTimer::Matches(time_t t) if ((!firstday || a >= firstday) && t <= b) { startTime = a; stopTime = b; - if (t >= firstday) + if (t >= firstday + SECSINDAY) firstday = 0; break; } @@ -638,9 +642,9 @@ void cTimer::SetPending(bool Pending) pending = Pending; } -void cTimer::SkipToday(void) +void cTimer::Skip(void) { - firstday = IncDay(SetTime(recording ? StartTime() : time(NULL), 0), 1); + firstday = IncDay(SetTime(StartTime(), 0), 1); } // --- cCommand ------------------------------------------------------------- @@ -980,7 +984,7 @@ bool cSetup::ParseCaCaps(const char *Value) { char *p; int d = strtol(Value, &p, 10); - if (d > 0 && d < MAXDVBAPI) { + if (d > 0 && d <= MAXDVBAPI) { d--; int i = 0; while (p != Value && p && *p) { diff --git a/config.h b/config.h index 4a216f139..e7c01eb2b 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.105 2002/03/17 14:24:11 kls Exp $ + * $Id: config.h 1.107 2002/03/31 21:17:30 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "1.0.0pre4" +#define VDRVERSION "1.0.0pre5" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -165,7 +165,7 @@ class cTimer : public cListObject { time_t StopTime(void); void SetRecording(bool Recording); void SetPending(bool Pending); - void SkipToday(void); + void Skip(void); const char *PrintFirstDay(void); static int TimeToInt(int t); static int ParseDay(const char *s, time_t *FirstDay = NULL); diff --git a/dvbapi.c b/dvbapi.c index 1ade142b0..d9906189d 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.163 2002/03/16 14:20:47 kls Exp $ + * $Id: dvbapi.c 1.166 2002/03/29 11:32:47 kls Exp $ */ #include "dvbapi.h" @@ -98,7 +98,7 @@ class cIndexFile { private: struct tIndex { int offset; uchar type; uchar number; short reserved; }; int f; - char *fileName, *pFileExt; + char *fileName; int size, last; tIndex *index; cResumeFile resumeFile; @@ -120,7 +120,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) :resumeFile(FileName) { f = -1; - fileName = pFileExt = NULL; + fileName = NULL; size = 0; last = -1; index = NULL; @@ -128,7 +128,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) fileName = new char[strlen(FileName) + strlen(INDEXFILESUFFIX) + 1]; if (fileName) { strcpy(fileName, FileName); - pFileExt = fileName + strlen(fileName); + char *pFileExt = fileName + strlen(fileName); strcpy(pFileExt, INDEXFILESUFFIX); int delta = 0; if (access(fileName, R_OK) == 0) { @@ -177,8 +177,6 @@ cIndexFile::cIndexFile(const char *FileName, bool Record) } else LOG_ERROR_STR(fileName); - delete fileName; - fileName = pFileExt = NULL; } } else @@ -223,14 +221,14 @@ bool cIndexFile::CatchUp(int Index) last = newLast; } else - LOG_ERROR; + LOG_ERROR_STR(fileName); } else esyslog(LOG_ERR, "ERROR: can't realloc() index"); } } else - LOG_ERROR; + LOG_ERROR_STR(fileName); if (Index >= last) sleep(1); else @@ -244,8 +242,8 @@ bool cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset) { if (f >= 0) { tIndex i = { FileOffset, PictureType, FileNumber, 0 }; - if (safe_write(f, &i, sizeof(i)) != sizeof(i)) { - esyslog(LOG_ERR, "ERROR: can't write to index file"); + if (safe_write(f, &i, sizeof(i)) < 0) { + LOG_ERROR_STR(fileName); close(f); f = -1; return false; @@ -527,23 +525,25 @@ void cRecordBuffer::Input(void) time_t t = time(NULL); recording = true; for (;;) { - int r = read(videoDev, b, sizeof(b)); - if (r > 0) { - uchar *p = b; - while (r > 0) { - int w = Put(p, r); - p += w; - r -= w; - } - t = time(NULL); - } - else if (r < 0) { - if (FATALERRNO) { - if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library - esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); - else { - LOG_ERROR; - break; + if (cFile::FileReady(videoDev, 100)) { + int r = read(videoDev, b, sizeof(b)); + if (r > 0) { + uchar *p = b; + while (r > 0) { + int w = Put(p, r); + p += w; + r -= w; + } + t = time(NULL); + } + else if (r < 0) { + if (FATALERRNO) { + if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library + esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); + else { + LOG_ERROR; + break; + } } } } @@ -552,7 +552,6 @@ void cRecordBuffer::Input(void) cThread::EmergencyExit(true); t = time(NULL); } - cFile::FileReady(videoDev, 100); if (!recording) break; } @@ -579,17 +578,12 @@ void cRecordBuffer::Output(void) if (NextFile()) { if (index && pictureType != NO_PICTURE) index->Write(pictureType, fileName.Number(), fileSize); - while (Result > 0) { - int w = safe_write(recordFile, p, Result); - if (w < 0) { - LOG_ERROR_STR(fileName.Name()); - recording = false; - return; - } - p += w; - Result -= w; - fileSize += w; - } + if (safe_write(recordFile, p, Result) < 0) { + LOG_ERROR_STR(fileName.Name()); + recording = false; + return; + } + fileSize += Result; } else break; @@ -797,16 +791,17 @@ void cPlayBuffer::Output(void) const uchar *p = frame->Data(); int r = frame->Count(); while (r > 0 && Busy() && !blockOutput) { - cFile::FileReadyForWriting(videoDev, 100); - int w = write(videoDev, p, r); - if (w > 0) { - p += w; - r -= w; - } - else if (w < 0 && FATALERRNO) { - LOG_ERROR; - Stop(); - return; + if (cFile::FileReadyForWriting(videoDev, 100)) { + int w = write(videoDev, p, r); + if (w > 0) { + p += w; + r -= w; + } + else if (w < 0 && FATALERRNO) { + LOG_ERROR; + Stop(); + return; + } } } writeIndex = frame->Index(); @@ -1182,10 +1177,26 @@ void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except) void cReplayBuffer::DisplayFrame(uchar *b, int Length) { StripAudioPackets(b, Length); - videoDisplayStillPicture sp = { (char *)b, Length }; CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, false)); CHECK(ioctl(audioDev, AUDIO_SET_MUTE, true)); +/* Using the VIDEO_STILLPICTURE ioctl call would be the + correct way to display a still frame, but unfortunately this + doesn't work with frames from VDR. So let's do pretty much the + same here as in DVB/driver/dvb.c's play_iframe() - I have absolutely + no idea why it works this way, but doesn't work with VIDEO_STILLPICTURE. + If anybody ever finds out what could be changed so that VIDEO_STILLPICTURE + could be used, please let me know! + kls 2002-03-23 +*/ +//#define VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES +#ifdef VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES + videoDisplayStillPicture sp = { (char *)b, Length }; CHECK(ioctl(videoDev, VIDEO_STILLPICTURE, &sp)); +#else +#define MIN_IFRAME 400000 + for (int i = MIN_IFRAME / Length + 1; i > 0; i--) + safe_write(videoDev, b, Length); +#endif } void cReplayBuffer::Close(void) @@ -1361,31 +1372,32 @@ void cTransferBuffer::Input(void) uchar b[MINVIDEODATA]; int n = 0; while (Busy()) { - cFile::FileReady(fromDevice, 100); - int r = read(fromDevice, b + n, sizeof(b) - n); - if (r > 0) { - n += r; - int Count = n, Result; - const uchar *p = remux.Process(b, Count, Result); - if (p) { - while (Result > 0 && Busy()) { - int w = Put(p, Result); - p += w; - Result -= w; - } - } - if (Count > 0) { - n -= Count; - memmove(b, b + Count, n); + if (cFile::FileReady(fromDevice, 100)) { + int r = read(fromDevice, b + n, sizeof(b) - n); + if (r > 0) { + n += r; + int Count = n, Result; + const uchar *p = remux.Process(b, Count, Result); + if (p) { + while (Result > 0 && Busy()) { + int w = Put(p, Result); + p += w; + Result -= w; + } + } + if (Count > 0) { + n -= Count; + memmove(b, b + Count, n); + } } - } - else if (r < 0) { - if (FATALERRNO) { - if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library - esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); - else { - LOG_ERROR; - break; + else if (r < 0) { + if (FATALERRNO) { + if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library + esyslog(LOG_ERR, "ERROR (%s,%d): DVB driver buffer overflow", __FILE__, __LINE__); + else { + LOG_ERROR; + break; + } } } } @@ -1541,7 +1553,7 @@ void cCuttingBuffer::Action(void) } LastIFrame = 0; } - if (safe_write(toFile, buffer, Length) != Length) { + if (safe_write(toFile, buffer, Length) < 0) { error = "safe_write"; break; } diff --git a/eit.c b/eit.c index 011000b70..4fc749bfa 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.41 2002/03/17 14:23:41 kls Exp $ + * $Id: eit.c 1.42 2002/04/01 12:58:20 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -560,8 +560,8 @@ void cEventInfo::FixEpgBugs(void) pExtendedDescription = compactspace(pExtendedDescription); // Remove superfluous hyphens: if (pExtendedDescription) { - char *p = pExtendedDescription + 1; - while (*p) { + char *p = pExtendedDescription; + while (*p && *(p + 1) && *(p + 2)) { if (*p == '-' && *(p + 1) == ' ' && *(p + 2) && islower(*(p - 1)) && islower(*(p + 2))) { if (!startswith(p + 2, "und ")) { // special case in German, as in "Lach- und Sachgeschichten" memmove(p, p + 2, strlen(p + 2) + 1); diff --git a/eit.diff b/eit.diff new file mode 100644 index 000000000..57584b966 --- /dev/null +++ b/eit.diff @@ -0,0 +1,25 @@ +# This is a BitKeeper generated patch for the following project: +# Project Name: Linux VDR +# This patch format is intended for GNU patch command version 2.5 or higher. +# This patch includes the following deltas: +# ChangeSet 1.21 -> 1.22 +# eit.c 1.6 -> 1.7 +# +# The following is the BitKeeper ChangeSet Log +# -------------------------------------------- +# 02/04/01 aschultz@warp10.net 1.22 +# fix segfault in eit.c +# -------------------------------------------- +# +diff -Nru a/eit.c b/eit.c +--- a/eit.c Mon Apr 1 14:38:00 2002 ++++ b/eit.c Mon Apr 1 14:38:00 2002 +@@ -559,7 +559,7 @@ + pSubtitle = compactspace(pSubtitle); + pExtendedDescription = compactspace(pExtendedDescription); + // Remove superfluous hyphens: +- if (pExtendedDescription) { ++ if (pExtendedDescription && strlen(pExtendedDescription) >= 3) { + char *p = pExtendedDescription + 1; + while (*p) { + if (*p == '-' && *(p + 1) == ' ' && *(p + 2) && islower(*(p - 1)) && islower(*(p + 2))) { diff --git a/i18n.c b/i18n.c index a7d63059b..0ffbf4528 100644 --- a/i18n.c +++ b/i18n.c @@ -4,15 +4,16 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.66 2002/03/17 13:50:43 kls Exp $ + * $Id: i18n.c 1.78 2002/04/01 11:37:08 kls Exp $ * - * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> - * Italian translations provided by Alberto Carraro <bertocar@tin.it> - * Dutch translations provided by Arnold Niessen <niessen@iae.nl> <arnold.niessen@philips.com> - * Portugese translations provided by Paulo Manuel Martins Lopes <pmml@netvita.pt> - * French translations provided by Jean-Claude Repetto <jc@repetto.org> - * Norwegian translations provided by Jrgen Tvedt <pjtvedt@online.no> - * Finnish translations provided by Hannu Savolainen <hannu@opensound.com> + * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> and Matjaz Thaler <matjaz.thaler@guest.arnes.si> + * Italian translations provided by Alberto Carraro <bertocar@tin.it> + * Dutch translations provided by Arnold Niessen <niessen@iae.nl> <arnold.niessen@philips.com> + * Portuguese translations provided by Paulo Lopes <pmml@netvita.pt> + * French translations provided by Jean-Claude Repetto <jc@repetto.org> + * Norwegian translations provided by Jrgen Tvedt <pjtvedt@online.no> and Truls Slevigen <truls@slevigen.no> + * Finnish translations provided by Hannu Savolainen <hannu@opensound.com> + * Polish translations provided by Michael Rakowski <mrak@gmx.de> * */ @@ -61,7 +62,7 @@ #include "config.h" #include "tools.h" -const int NumLanguages = 9; +const int NumLanguages = 10; typedef const char *tPhrase[NumLanguages]; @@ -72,10 +73,11 @@ const tPhrase Phrases[] = { "Slovenski", "Italiano", "Nederlands", - "Portugues", + "Portugus", "Franais", "Norsk", "Suomi", + "Polski", }, // Menu titles: { "VDR", @@ -87,46 +89,51 @@ const tPhrase Phrases[] = { "VDR", "VDR", "VDR", + "VDR", }, { "Schedule", "Programm", "Urnik", "Programmi", "Gids", - "Programa", + "Programao", "Programmes", "Programmer", "Ohjelmat", + "Program", }, { "Channels", "Kanle", "Kanali", "Canali", "Kanalen", - "Canal", + "Canais", "Chanes", "Kanaler", "Kanavat", + "Kanaly", }, { "Timers", "Timer", "Termini", "Timer", "Timers", - "Alarmes", + "Timers", "Programmation", - "Timer", + "Timere", "Ajastin", + "Timery", }, { "Recordings", "Aufzeichnungen", "Posnetki", "Registrazioni", "Opnames", - "Gravacoes", + "Gravaes", "Enregistrements", "Opptak", "Nauhoitteet", + "Nagrania", }, { "Setup", "Einstellungen", @@ -137,6 +144,7 @@ const tPhrase Phrases[] = { "Configuration", "Konfigurasjon", "Asetukset", + "Nastawy", }, { "Commands", "Befehle", @@ -147,6 +155,7 @@ const tPhrase Phrases[] = { "Commandes", "Kommandoer", "Komennot", + "Rozkazy", }, { "Edit Channel", "Kanal Editieren", @@ -157,16 +166,18 @@ const tPhrase Phrases[] = { "Modifier une chane", "Editer Kanal", "Muokkaa kanavaa", + "Ustawienie Kanalu", }, { "Edit Timer", "Timer Editieren", "Uredi termin", "Modifica Timer", "Timer veranderen", - "Modificar Alarme", + "Modificar Timer", "Changer la programmation", "Editer Timer", "Muokkaa ajastusta", + "Ustawienie Timerow", }, { "Event", "Sendung", @@ -177,6 +188,7 @@ const tPhrase Phrases[] = { "Evnement", "Hendelse", "Tapahtuma", + "Audycja", }, { "Summary", "Inhalt", @@ -187,6 +199,7 @@ const tPhrase Phrases[] = { "Rsum", "Sammendrag", "Yhteenveto", + "Zawartosc", }, { "Schedule - %s", "Programm - %s", @@ -197,26 +210,29 @@ const tPhrase Phrases[] = { "Programmes - %s", "Program Guide - %s", "Ohjelma - %s", + "Program - %s", }, { "What's on now?", "Was luft jetzt?", "Kaj je na sporedu?", "In programmazione", "Wat is er nu?", - "O que ver agora?", + "Programa actual?", "Programmes en cours", "Hvilket program sendes n?", "Nykyinen ohjelma", + "Program biezacy", }, { "What's on next?", "Was luft als nchstes?", "Kaj sledi?", "Prossimi programmi", "Wat komt er hierna?", - "O que ver depois?", + "Prximo Programa?", "Prochains programmes", "Hvilket program er neste?", "Seuraava ohjelma", + "Program nastepny", }, // Button texts (should not be more than 10 characters!): { "Edit", @@ -228,6 +244,7 @@ const tPhrase Phrases[] = { "Modifier", "Editer", "Muuta", + "Edycja", }, { "New", "Neu", @@ -238,6 +255,7 @@ const tPhrase Phrases[] = { "Nouveau", "Ny", "Uusi", + "Nowy", }, { "Delete", "Lschen", @@ -248,6 +266,7 @@ const tPhrase Phrases[] = { "Supprimer", "Slett", "Poista", + "Usunac", }, { "Mark", "Markieren", @@ -258,16 +277,18 @@ const tPhrase Phrases[] = { "Marquer", "Marker", "Merkitse", + "Zaznaczyc", }, { "On/Off", "Ein/Aus", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Vklop/Izklop", + "On/Off", + "Aan/Uit", + "On/Off", "Marche/Arr", - "", // TODO - "", // TODO + "Av/P", + "Pll/Pois", + "Zal./ Wyl.", }, { "Record", "Aufnehmen", @@ -278,6 +299,7 @@ const tPhrase Phrases[] = { "Enregistre", "Ta opp", "Nauhoita", + "Nagrywac", }, { "Play", "Wiedergabe", @@ -288,26 +310,29 @@ const tPhrase Phrases[] = { "Lire", "Spill av", "Toista", + "Odtwarzac", }, { "Rewind", "Anfang", "Zacetek", "Da inizio", - "Spoel terug", + "Naar begin", "Rebobinar", "Retour", "Spol tilbake", "Takaisinkel.", + "Poczatek", }, { "Button$Stop", "Beenden", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Ustavi", + "Stop", + "Eindigen", + "Parar", + "Arrt", + "Stopp", + "Pysyt", + "Zakonczyc", }, { "Resume", "Weiter", @@ -318,6 +343,7 @@ const tPhrase Phrases[] = { "Reprendre", "Fortsett", "Jatka", + "Dalej", }, { "Summary", "Inhalt", @@ -328,16 +354,18 @@ const tPhrase Phrases[] = { "Rsum", "Sammendrag", "Yhteenveto", + "Zawartosc", }, { "Open", "ffnen", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Odpri", + "Apri", + "Openen", + "Abrir", "Ouvrir", - "", // TODO + "pne", "Avaa", + "Otworzyc", }, { "Switch", "Umschalten", @@ -348,6 +376,7 @@ const tPhrase Phrases[] = { "Regarder", "Skift til", "Valitse", + "Przelaczyc", }, { "Now", "Jetzt", @@ -358,6 +387,7 @@ const tPhrase Phrases[] = { "Maintenant", "N", "Nyt", + "Teraz", }, { "Next", "Nchste", @@ -368,36 +398,40 @@ const tPhrase Phrases[] = { "Aprs", "Neste", "Seuraava", + "Nastepny", }, { "Button$Schedule", "Programm", "Urnik", "Programma", "Programma", - "Programa", + "Programao", "Programme", "Programmer", "Ohjelmisto", + "Program", }, { "Language", "Sprache", "Jezik", "Linguaggio", "Taal", - "Linguagem", // TODO (correct?) + "Linguagem", "Langue", "Sprk", "Kieli", + "Jezyk", }, { "Eject", "Auswerfen", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Izvrzi", + "Eject", + "Eject", + "Ejectar", "Ejection", - "", // TODO + "Eject", "Avaa", + "Wyrzucenie", }, // Confirmations: { "Delete channel?", @@ -405,120 +439,132 @@ const tPhrase Phrases[] = { "Odstrani kanal?", "Cancello il canale?", "Kanaal verwijderen?", - "Apagar o Canal?", + "Apagar o canal?", "Supprimer la chane?", "Slette kanal?", "Poistetaanko kanava?", + "Usunac kanal?", }, { "Delete timer?", "Timer lschen?", "Odstani termin?", "Cancello il timer?", "Timer verwijderen?", - "Apagar o Alarme?", + "Apagar o timer?", "Supprimer la programmation?", "Slette timer?", "Poistetaanko ajastus?", + "Usunac timer?", }, { "Delete recording?", "Aufzeichnung lschen?", "Odstrani posnetek?", "Cancello la registrazione?", "Opname verwijderen?", - "Apagar Gravaco?", + "Apagar a gravao?", "Supprimer l'enregistrement?", "Slette opptak?", "Poistetaanko nauhoitus?", + "Usunac nagranie?", }, { "Timer still recording - really delete?", "Timer zeichnet auf - trotzdem lschen?", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Snemanje po terminu - zares odstrani?", + "Timer in regestazione - cancello?", + "Timer neemt nog op - toch verwijderen?" + "Timer activo - tm a certeza que quer apagar?", "Enregistrement en cours - confirmez la suppression", - "", // TODO - "", // TODO + "Timer gjr opptak - vil du slette likevel?", + "Ajastin nauhoittaa - poistetaanko silti?", + "Nagrywanie w trakcie - napewno usunac?", }, { "Stop recording?", "Aufzeichnung beenden?", "Koncaj snemanje?", "Fermo la registrazione?", "Opname stoppen?", - "Parar Gravaco?", + "Parar Gravao?", "Arrter l'enregistrement?", "Stoppe opptak?", "Pysytetnk nauhoitus?", + "Zakonczyc nagranie?", }, { "on primary interface", "auf dem primren Interface", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "sur la carte principale", - "", // TODO + "na primarni napravi", + "su interfaccia primaria", + "op eerste interface", + "no interface primrio", + "sur la carte primaire", + "p frste enhet", "pvastaanottimella", + "na pierwszym interfejsie", }, { "Cancel editing?", "Schneiden abbrechen?", "Zelite prekiniti urejanje?", "Annullo la modifica?", "Bewerken afbreken?", - "Cancelar Modificar?", + "Cancelar Modificaes?", "Annuler les modifications?", "Avbryte redigering?", "Peruutetaanko muokkaus?", + "Zakonczyc montaz?", }, { "Really restart?", "Wirklich neu starten?", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Zares ponoven zagon", + "Eseguo un restart?", + "Werkelijk opnieuw starten?", + "Tem a certeza que quer reiniciar?", + "Redmarrer?", + "Vil du virkelig starte p nytt?", + "Aloitetaanko varmasti alusta?", + "Rzeczywiscie nowy start?", }, { "Recording - restart anyway?", "Aufnahme luft - trotzdem neu starten?", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Snemanje - zares ponoven zagon", + "In registrazione - restart comunque?", + "Opname loopt - toch opnieuw starten?", + "Em gravao - quer mesmo reiniciar?", + "Enregistrement en cours - redmarrer?", + "Gjr opptak - starte p nytt likevel?", + "Nauhoitus kynniss - aloitetaanko alusta?", + "Nagrywanie w trakcie - rzeczywiscie nowy start?", }, { "Recording - shut down anyway?", "Aufnahme luft - trotzdem ausschalten?", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Snemanje - zares izklopi?", + "In registrazione - spengo comunque?", + "Opname loopt - toch uitschakelen?", + "Em gravao - quer mesmo desligar?", "Enregistrement en cours - confirmez l'arrt", - "", // TODO + "Gjr opptak - sl av likevel?", "Nauhoitus kesken - lopetetaanko se?", + "Nagrywanie w trakcie - mimo to wylaczyc?", }, { "Recording in %d minutes, shut down anyway?", "Aufnahme in %d Minuten - trotzdem ausschalten?", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Enregistrement dans %d minutes - confirmez l'arrt", // TODO - "", // TODO - "", // TODO + "Snemanje cez %d minut, zares izklopi?", + "Registrazione fra %d minuti - spengo comunque?", + "Opname in %d minuten - toch uitschakelen?", + "Em gravao dentro de %d minutos - quer mesmo desligar?", + "Enregistrement dans %d minutes - confirmez l'arrt", + "Skal gjre opptak om %d minutter - sl av likevel?", + "Nauhoitus alkaisi %d min. kuluttua - sammutetaanko silti?", + "Nagrywanie za %d minut - mimo to wylaczyc?", }, { "Press any key to cancel shutdown", "Taste drcken um Shutdown abzubrechen", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Pritisni katerikoli gumb za preklic izklopa", + "Un tasto per annullare lo spegnimento", + "Druk een toets om shutdown af te breken", + "Pressione qualquer tecla para cancelar", "Appuyez sur une touche pour annuler l'arrt", - "", // TODO + "Trykk en tast for ikke sl av", "Peruuta pysytys painamalla jotakin nppint", + "Dowolny przycisk zatrzyma wylaczanie", }, // Channel parameters: { "Name", @@ -530,26 +576,29 @@ const tPhrase Phrases[] = { "Nom", "Navn", "Nimi", + "Nazwa", }, { "Frequency", "Frequenz", "Frekvenca", "Frequenza", "Frequentie", - "Frequencia", + "Frequncia", "Frquence", "Frekvens", "Taajuus", + "Czestotliwosc", }, { "Polarization", "Polarisation", "Polarizacija", "Polarizzazione", "Polarisatie", - "Polarizacao", + "Polarizao", "Polarisation", - "Polaritet", + "Polarisasjon", "Polarisaatio", + "Polaryzacja", }, { "DiSEqC", "DiSEqC", @@ -560,6 +609,7 @@ const tPhrase Phrases[] = { "DiSEqC", "DiSEqC", "DiSEqC", + "DiSEqC", }, { "Srate", "Srate", @@ -568,7 +618,8 @@ const tPhrase Phrases[] = { "Srate", "Srate", "Frq. Symbole", - "Symbolrate", + "Srate", + "Srate", "Srate", }, { "Vpid", @@ -576,20 +627,22 @@ const tPhrase Phrases[] = { "Vpid", "Vpid", "Vpid", - "Vpid", + "PID de Vdeo", "PID Vido", - "Video pid", + "Vpid", "Kuva PID", + "Vpid", }, { "Apid1", "Apid1", "Apid1", "Apid1", "Apid1", - "Apid1", + "PID udio (1)", "PID Audio (1)", - "Audio pid1", + "Apid1", "ni PID1", + "Apid1", }, { "Apid2", "Apid2", @@ -597,59 +650,65 @@ const tPhrase Phrases[] = { "Apid2", "Apid2", "Apid2", - "PID Audio (2)", - "Audio pid2", + "PID udio (2)", + "Apid2", "ni PID2", + "Apid2", }, { "Dpid1", "Dpid1", "Dpid1", "Dpid1", "Dpid1", - "Dpid1", "PID AC3 (1)", - "AC3 pid1", + "PID AC3 (1)", + "AC3pid1", "AC3 PID1", + "Dpid1", }, { "Dpid2", "Dpid2", "Dpid2", "Dpid2", "Dpid2", - "Dpid2", "PID AC3 (2)", - "AC3 pid2", + "PID AC3 (2)", + "AC3pid2", "AC3 PID2", + "Dpid2", }, { "Tpid", "Tpid", "Tpid", "Tpid", "Tpid", - "Tpid", + "PID Teletexto", "PID Tltexte", - "Teletext pid", + "Tekst-TV pid", "TekstiTV PID", + "Tpid", }, { "CA", "CA", "CA", "CA", "CA", - "CA", + "Encriptao", "Cryptage", "Kortleser", "Salauskortti", + "CA", }, { "Pnr", "Pnr", "Pnr", "Pnr", "Pnr", - "Pnr", + "Nm. Progr.", "Num. Progr.", "Program Id", "Ohjelmatunnus", + "Pnr", }, // Timer parameters: { "Active", @@ -661,6 +720,7 @@ const tPhrase Phrases[] = { "Actif", "Aktiv", "Aktiivinen", + "Aktywny", }, { "Channel", "Kanal", @@ -671,6 +731,7 @@ const tPhrase Phrases[] = { "Chane", "Kanal", "Kanava", + "Kanal", }, { "Day", "Tag", @@ -681,6 +742,7 @@ const tPhrase Phrases[] = { "Jour", "Dag", "Piv", + "Dzien", }, { "Start", "Anfang", @@ -691,6 +753,7 @@ const tPhrase Phrases[] = { "Dbut", "Start", "Aloitus", + "Poczatek", }, { "Stop", "Ende", @@ -701,6 +764,7 @@ const tPhrase Phrases[] = { "Fin", "Slutt", "Lopetus", + "Koniec", }, { "Priority", "Prioritt", @@ -711,16 +775,18 @@ const tPhrase Phrases[] = { "Priorit", "Prioritet", "Prioriteetti", + "Priorytet", }, { "Lifetime", "Lebensdauer", "Veljavnost", "Durata", "Bewaarduur", - "Duracao", + "Durao", "Dure de vie", "Levetid", "Voimassaolo", + "Trwalosc dni", }, { "File", "Datei", @@ -731,16 +797,18 @@ const tPhrase Phrases[] = { "Fichier", "Filnavn", "Tiedosto", + "Plik", }, { "First day", "Erster Tag", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Prvi dan", + "Primo giorno", + "Eerste dag", + "Primeiro dia", "Premier jour", - "", // TODO - "", // TODO + "Frste dag", + "1. piv", + "Pierwszy dzien", }, // Error messages: { "Channel is being used by a timer!", @@ -748,60 +816,66 @@ const tPhrase Phrases[] = { "Urnik zaseda kanal!", "Canale occupato da un timer!", "Kanaal wordt gebruikt door een timer!", - "Canal a ser utilizador por um alarme!", + "Canal a ser utilizador por um timer!", "Cette chane est en cours d'utilisation!", "Kanalen er i bruk av en timer!", "Kanava on ajastimen kytss!", + "Kanal jest zajety przez timer nagran", }, { "Can't switch channel!", "Kanal kann nicht umgeschaltet werden!", "Ne morem preklopiti kanala!", "Impossibile cambiare canale!", "Kan geen kanaal wisselen!", - "Nao pode mudar de canal!", + "No pode mudar de canal!", "Impossible de changer de chane!", "Ikke mulig skifte kanal!", "Kanavan vaihtaminen ei mahdollista!", + "Kanal nie moze byc teraz przelaczony!", }, { "Timer is recording!", "Timer zeichnet gerade auf!", "Snemanje po urniku!", "Registrazione di un timer in corso!", "Timer is aan het opnemen!", - "Alarme a gravar!", + "Timer a gravar!", "Enregistrement en cours!", "Timer gjr opptak!", "Ajastinnauhoitus kynniss!", + "Timer nagrywa!", }, { "Error while accessing recording!", "Fehler beim ansprechen der Aufzeichnung!", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Napaka pri dostopu do posnetka", + "Errore nel tentativo di acc alla registrazione", + "Fout bij lezen opname!", + "Erro ao aceder gravao", "Impossible d'accder l'enregistrement", - "", // TODO + "Feil under lesing av opptak!", "Nauhoituksen toistaminen eponnistui!", + "Blad - brak dostepu do nagrania!", }, { "Error while deleting recording!", "Fehler beim Lschen der Aufzeichnung!", "Napaka pri odstranjevanju posnetka!", "Errore durante la canc del filmato!", "Fout bij verwijderen opname!", - "Erro enquanto apagava uma gravacao!", + "Erro enquanto apagava uma gravao!", "Erreur de suppression de l'enregistrement!", "Feil under sletting av opptak!", "Nauhoituksen poistaminen eponnistui!", + "Blad przy usuwaniu nagrania!", }, { "*** Invalid Channel ***", "*** Ungltiger Kanal ***", "*** Neznan kanal ***", "*** CANALE INVALIDO ***", "*** Ongeldig kanaal ***", - "*** Canal Invalido! ***", + "*** Canal Invlido! ***", "*** Chane invalide! ***", "*** Ugyldig Kanal! ***", "*** Virheellinen kanavavalinta! ***", + "*** Niewazny kanal ***", }, { "No free DVB device to record!", "Keine freie DVB-Karte zum Aufnehmen!", @@ -812,6 +886,7 @@ const tPhrase Phrases[] = { "Pas de carte DVB disponible pour l'enregistrement!", "Ingen ledige DVB enheter for opptak!", "Ei vapaata vastaanotinta nauhoitusta varten!", + "Brak wolnej karty DVB do nagrywania!", }, { "Channel locked (recording)!", "Kanal blockiert (zeichnet auf)!", @@ -822,147 +897,162 @@ const tPhrase Phrases[] = { "Chane verrouille (enregistrement en cours)!", "Kanalen er lst (opptak)!", "Kanava lukittu (nauhoitusta varten)!", + "Kanal zablokowany (nagrywanie w toku)!", }, { "Can't start Transfer Mode!", "Transfer-Mode kann nicht gestartet werden!", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Ne morem zaceti z prenosnim nacinom", + "Impossibile iniziare la modalita' di trasferimento!", + "Kan Transfer-Mode niet starten", + "Impossvel iniciar modo de transferncia!", "Impossible d'utiliser le mode transfert!", - "", // TODO + "Kan ikke starte transfer modus!", "Ksittmttmi teknisi ongelmia!", + "Tryb transferowy jest niemozliwy!", }, { "Can't start editing process!", "Schnitt kann nicht gestartet werden!", "Ne morem zaceti urejanja!", "Imposs iniziare processo di modifica", "Kan niet beginnen met bewerken!", - "Nao pode iniciar a modificacao!", + "No pode iniciar a modificao!", "Impossible de commencer le montage!", "Kan ikke starte redigeringsprosessen!", "Muokkauksen aloittaminen ei onnistu!", + "Uruchamianie montazu jest niemozliwe!", }, { "Editing process already active!", "Schnitt bereits aktiv!", "Urejanje je ze aktivno!", "Processo di modifica gia` attivo", "Bewerken is al actief!", - "Processo de modificacao ja activo!", + "Processo de modificao j activo!", "Montage dj en cours!", "Redigeringsprosessen er allerede aktiv!", "Muokkaus on jo kynniss!", + "Montaz w toku!", }, { "Can't shutdown - option '-s' not given!", "Shutdown unmglich - Option '-s' fehlt!", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Zaustavitev ni mogoca - opcija '-s' ni podana!", + "Impossibile spegnere - parametro '-s' non passato", + "Shutdown onmogelijk - Optie '-s' ontbreekt!", + "Impossvel desligar - falta a opo '-s'!", "Arrt impossible - option '-s' absente!", - "", // TODO + "Kan ikke sl av - startet uten parameteret '-s'!", "Ei voida sammuttaa '-s' parametria ei annettu!", + "Wylaczenie niemozliwe - brak opcji '-s' !", }, { "Low disk space!", "Platte beinahe voll!", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Zmanjkuje prostora na disku", + "Poco spazio su disco!", + "Disk bijna vol!", + "Espao em disco reduzido!", "Disque presque plein!", - "", // TODO + "Lite ledig diskplass!", "Kovalevy lhes tynn!", + "Dysk wkrotce pelny!", }, // Setup pages: { "OSD", "OSD", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "OSD", + "OSD", + "OSD", + "OSD", + "Affichage des menus", + "OSD", + "Tekstinytt", + "OSD", }, { "EPG", "EPG", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "EPG", + "EPG", + "EPG", + "EPG", + "Guide des programmes", + "Programoversikt", + "Ohjelmaopas", + "EPG", }, { "DVB", "DVB", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "DVB", + "Scheda DVB", + "DVB", + "DVB", + "Cartes DVB", + "DVB-enheter", + "DVB", + "DVB", }, { "LNB", "LNB", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "LNB", + "LNB", + "LNB", + "LNB", + "LNB", + "LNB", + "LNB", + "LNB", }, { "CICAM", "CICAM", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "CICAM", + "CICAM", + "CICAM", + "CICAM", + "Accs conditionnel", + "CICAM", + "CICAM", + "CICAM", }, { "Recording", "Aufnahme", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Snemanje", + "Registrazione", + "Opname", + "A gravar", + "Enregistrement", + "Opptak", + "Nauhoita", + "Nagranie", }, { "Replay", "Wiedergabe", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Predvajanje", + "Replay", + "Afspelen", + "Replay", + "Lecture", + "Spill av", + "Toista", + "Odtwarzanie", }, { "Miscellaneous", "Sonstiges", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Ostalo", + "Generici", + "Overig", + "Outros", + "Divers", + "Forskjellig", + "Sekalaista", + "Pozostale", }, { "Restart", "Neustart", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Ponoven zagon", + "Restart", + "Herstart", + "Reiniciar", + "Redmarrer", + "Start p nytt", + "Aloita uudelleen", + "Zastartowac", }, // Setup parameters: { "Setup.OSD$Language", @@ -970,50 +1060,55 @@ const tPhrase Phrases[] = { "Jezik", "Linguaggio", "Taal", - "Linguagem", // TODO (correct?) + "Linguagem", "Langue", "Sprk", "Kieli", + "Jezyk", }, { "Setup.OSD$Width", "Breite", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Largeur", //TODO (correct?) - "", // TODO - "Leveys", //TODO (correct?) + "Sirina", + "Largh OSD", + "Breedte", + "Largura", + "Largeur", + "Bredde", + "Leveys", + "Szerokosc", }, { "Setup.OSD$Height", "Hhe", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Hauteur", //TODO (correct?) - "", // TODO - "Korkeus", //TODO (correct?) - }, - { "Setup.OSD$Message time", - "Anzeigedauer fr Nachrichten", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Dure affichage cran", - "", // TODO - "Ilmoitusten nkymisaika", + "Visina", + "Altezz OSD", + "Hoogte", + "Altura", + "Hauteur", + "Hyde", + "Korkeus", + "Wysokosc", + }, + { "Setup.OSD$Message time (s)", + "Anzeigedauer fr Nachrichten (s)", + "Cas sporocila (s)", + "Tempo del messaggio (s)", + "Weergave duur van berichten (s)", + "Mostrar contador (s)", + "Dure affichage cran (s)", + "Tid meldinger skal vises (s)", + "Ilmoitusten nkymisaika (s)", + "Czas wyswietlania wiadomosci (s)", }, { "Setup.OSD$Channel info position", "Kanal-Info Position", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Pozicija informacije o kanalu", + "Posizione info canale", + "Kanaal info positie", + "Posio de info dos canais", "Position infos chanes", - "", // TODO + "Posisjon p kanalinformasjon", "Kanavainfon sijainti", + "Lokalizacja informacji o kanale", }, { "Setup.OSD$Info on channel switch", "Info beim Kanalwechsel", @@ -1024,136 +1119,150 @@ const tPhrase Phrases[] = { "Affichage progr. en cours", "Info ved kanalskifte", "Nyt kanavainfo", + "Informacja przy zmianie kanalu", }, { "Setup.OSD$Scroll pages", "Seitenweise scrollen", "Drsni meni", "Scrolla pagina nel menu", "Scrollen per pagina", - "Scroll da pagina no menu", + "Scroll da pgina no menu", "Affichage progr. suivant", "Rask rulling i menyer", "Valikkojen rullaus", + "Przesuwac stronami", }, { "Setup.OSD$Sort timers", "Timer sortieren", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Sortiraj termine", + "Ordinamento timer", + "Timers sorteren", + "Ordenar os timers", "Trier les programmations", - "", // TODO + "Sorter timere", "Jrjest ajastimet", + "Sortowanie timerow", }, { "Setup.OSD$Recording directories", "Aufnahme Verzeichnisse", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Direktoriji za posnetke", + "Directory di registrazione", + "Opname directories", + "Directorias de gravao", "Dossiers d'enregistrements", - "", // TODO + "Kataloger til opptak", "Nauhoitushakemistot", - }, - { "Setup.EPG$EPG scan timeout", - "Zeit bis EPG Scan", - "Cas do EPG pregleda", - "Timeout EPG", - "EPG-scan Timeout", - "Timeout EPG", - "Temps maxi EPG", - "Ledig tid fr EPG-sk", - "Ohjelmatied. odotusaika", + "Wykaz nagran", + }, + { "Setup.EPG$EPG scan timeout (h)", + "Zeit bis EPG Scan (h)", + "Cas do EPG pregleda (h)", + "Timeout EPG (h)", + "EPG-scan Timeout (h)", + "Expirou o EPG (h)", + "Temps maxi EPG (h)", + "Ledig tid fr EPG-sk (h)", + "Ohjelmatied. odotusaika (h)", + "Czas do skanu EPG (h)", }, { "Setup.EPG$EPG bugfix level", "EPG Fehlerbereinigung", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Nivo za popravilo EPG napak", + "EPG livello corr", + "EPG foutcorrectieniveau", + "Nvel de correcto EPG", "Niveau de correction EPG", - "", // TODO + "Niv for EPG-feilretting", "EPG Bugfix Level", + "Poziom bledow EPG", }, { "Setup.EPG$Set system time", "Systemzeit stellen", - "Sistemski cas", - "Setta orario auto", + "Nastavi sistemski cas", + "Settaggio orario auto", "Systeem klok instellen", - "Ajustar relogio do sistema", + "Ajustar relgio do sistema", "Ajuster l'heure du systme", "Juster system-klokken", "Vastaanota kellonaika", + "Ustawianie czasu", }, { "Setup.EPG$Use time from transponder", "Transponder fr Systemzeit", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Transponder za nastavitev casa", + "Utilizza orario da transponder", + "Gebruik transponder tijd voor systeem", + "Usar relgio do transponder", + "Utiliser l'heure de la chane", + "Bruk klokke fra transponder", + "Vastaanota kellonaika lhettimelt", + "Transponder do ustawiania czasu", }, { "Setup.DVB$Primary DVB interface", "Primres DVB Interface", "Primarna naprava", "Scheda DVB primaria", "Eerste DVB kaart", - "DVB primario", - "Premire carte DVB", + "Interface DVB primrio", + "Carte DVB primaire", "Hoved DVB-enhet", "Ensisij. vast.otin", + "Pierwotny interfejs DVB", }, { "Setup.DVB$Video format", "Video Format", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Video format", + "Formato video", + "Videoformaat", + "Formato vdeo", "Format vido", - "TV Format", + "TV-Format", "Kuvamuoto", - }, - { "Setup.LNB$SLOF", - "SLOF", - "SLOF", - "SLOF", - "SLOF", - "SLOF", - "Limite de bandes LNB", - "LO-grensefrekvens", - "SLOF", - }, - { "Setup.LNB$Low LNB frequency", - "Untere LNB-Frequenz", - "Spodnja LNB-frek.", - "Freq LO LNB", - "Laagste LNB frequentie", - "Freq LO LNB", - "Frquence basse LNB", - "LO-frekvens i lavbndet", - "LO LNB taajuus", - }, - { "Setup.LNB$High LNB frequency", - "Obere LNB-Frequenz", - "Zgornja LNB-frek.", - "Freq HI LNB", - "Hoogste LNB frequentie", - "Freq HI LNB", - "Frquence haute LNB", - "LO-frekvens i hybndet", - "HI LNB taajuus", + "Format telewizyjny", + }, + { "Setup.LNB$SLOF (MHz)", + "SLOF (MHz)", + "Frekvenca preklopa (MHz)", + "SLOF (MHz)", + "SLOF (MHz)", + "Limite de bandas LNB (MHz)", + "Limite de bandes LNB (MHz)", + "LO-grensefrekvens (MHz)", + "SLOF (MHz)", + "SLOF (MHz)", + }, + { "Setup.LNB$Low LNB frequency (MHz)", + "Untere LNB-Frequenz (MHz)", + "Spodnja LNB-frek. (MHz)", + "Freq LO LNB (MHz)", + "Laagste LNB frequentie (MHz)", + "Frequncia base LNB (MHz)", + "Frquence basse LNB (MHz)", + "LO-frekvens i lavbndet (MHz)", + "LO LNB taajuus (MHz)", + "Dolna czestotliwosc LNB (MHz)", + }, + { "Setup.LNB$High LNB frequency (MHz)", + "Obere LNB-Frequenz (MHz)", + "Zgornja LNB-frek. (MHz)", + "Freq HI LNB (MHz)", + "Hoogste LNB frequentie (MHz)", + "Frequncia alta LNB (MHz)", + "Frquence haute LNB (MHz)", + "LO-frekvens i hybndet (MHz)", + "HI LNB taajuus (MHz)", + "Gorna czestotliwosc LNB (MHz)", }, { "Setup.LNB$Use DiSEqC", "DiSEqC benutzen", - "DiSEqC", // TODO - "DiSEqC", // TODO - "DiSEqC", // TODO - "DiSEqC", // TODO - "DiSEqC", // TODO - "DiSEqC", // TODO - "DiSEqC", // TODO + "Uporabi DiSEqC", + "Utilizza DiSEqC", + "DiSEqC gebruiken", + "Utilizar DiSEqC", + "Utiliser le DiSEqC", + "Bruk DiSEqC", + "Kyt DiSEqC", + "Uzywac DiSEqC", }, { "Setup.CICAM$CICAM DVB", "CICAM DVB", @@ -1161,169 +1270,186 @@ const tPhrase Phrases[] = { "CICAM DVB", "CICAM DVB", "CICAM DVB", + "Accs conditionnel", "CICAM DVB", "CICAM DVB", "CICAM DVB", }, - { "Setup.Recording$Margin at start", - "Zeitpuffer bei Anfang", - "Premor pred zacetkom", - "Min margine inizio", - "Tijd marge (begin)", - "Margem de inicio", - "Marge antrieure", - "Opptaks margin (start)", - "Aloitusmarginaali", - }, - { "Setup.Recording$Margin at stop", - "Zeitpuffer bei Ende", - "Premor za koncem", - "Min margine fine", - "Tijd marge (eind)", - "Margem de fim", - "Marge postrieure", - "Opptaks margin (slutt)", - "Lopetusmarginaali", + { "Setup.Recording$Margin at start (min)", + "Zeitpuffer bei Anfang (min)", + "Premor pred zacetkom (min)", + "Min margine inizio (min)", + "Tijd marge begin (min)", + "Margem inicial (min)", + "Marge antrieure (min)", + "Opptaksmargin start (min)", + "Aloitusmarginaali (min)", + "Poczatkowy czas buforowy (min)", + }, + { "Setup.Recording$Margin at stop (min)", + "Zeitpuffer bei Ende (min)", + "Premor za koncem (min)", + "Min margine fine (min)", + "Tijd marge eind (min)", + "Margem final (min)", + "Marge postrieure (min)", + "Opptaksmargin slutt (min)", + "Lopetusmarginaali (min)", + "Koncowy czas buforowy (min)", }, { "Setup.Recording$Primary limit", "Primr-Limit", - "", // TODO - "", // TODO - "", // TODO - "Limite Primario", + "Osnovna meja", + "Limite primario", + "Eerste grens", + "Limite Primrio", "Premire limite", - "Prioritets grense HovedDVB", + "Prioritetsgrense HovedDVB", "PrimaryLimit", + "Pierwotny limit", }, { "Setup.Recording$Default priority", "Default Prioritt", - "", // TODO - "", // TODO - "", // TODO + "Osnovna prioriteta", + "Priorita' predefinita", + "Standaard prioriteit", "Prioridade por defeito", "Priorit par dfaut", "Normal prioritet (Timer)", "Oletusprioriteetti", - }, - { "Setup.Recording$Default lifetime", - "Default Lebensdauer", - "", // TODO - "", // TODO - "", // TODO - "Validade por defeito", - "Dure de vie par dfaut", - "Normal levetid (Timer)", - "Oletus voimassaoloaika", + "Priorytet pierwotny", + }, + { "Setup.Recording$Default lifetime (d)", + "Default Lebensdauer (d)", + "Osnovni zivljenski cas (d)", + "Durata predefinita (d)", + "Standaard levensduur (d)", + "Validade por defeito (d)", + "Dure de vie par dfaut (d)", + "Normal levetid timer (d)", + "Oletus voimassaoloaika (d)", + "Pierwotna trwalosc (d)", }, { "Setup.Recording$Use episode name", "Episodenname verwenden", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Utiliser les sous-titres", // TODO (episode name!) - "", // TODO - "Tekstitys kytss", // TODO (episode name!) + "Uporabi ime epizode", + "Utilizza il nome dell'episodio", + "Gebruik episode naam", + "Utilizar o nome do episdio", + "Utiliser le nom de l'pisode", + "Bruk episodenavn", + "Kyt jakson nime", + "Czy uzywac nazwe epizodu", }, { "Setup.Recording$Mark instant recording", "Direktaufzeichnung markieren", "Oznaci direktno snemanje", "Marca la registrazione", "Direkte opnamen markeren", - "Marca de gravacao", + "Marca de gravao rpida", "Enregistrement immdiat", "Markere direkteopptak", "Merkitse vlitn nauh.", + "Zaznaczyc natychm. nagranie", }, { "Setup.Recording$Name instant recording", "Direktaufzeichnung benennen", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Ime za direktno snemanje", + "Nome registrazione istantanea", + "Naam direkt-opname", + "Nome de gravao rpida", "Noms enregistr. immdiats", - "", // TODO + "Navngi direkteopptak", "Nime vlitn nauh.", + "Nazwac natychm. nagranie", }, { "Setup.Recording$Record Dolby Digital", "Dolby Digital Ton aufzeichnen", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Enregistrer en Dolby Digital", - "", // TODO - "", // TODO - }, - { "Setup.Recording$Max. video file size", - "Max. Video Dateigre", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Taille maxi des fichiers", - "", // TODO - "Maksimi tiedoston koko", + "Posnemi dolby digital", + "Registra dolby digital", + "Dolby Digital geluid opnamen", + "Gravar em Dolby Digital", + "Enregistrer en Dolby Digital", + "Ta opp Dolby Digital lyd", + "Dolby Digital nauhoitus", + "Nagrywac Dolby Digital", + }, + { "Setup.Recording$Max. video file size (MB)", + "Max. Video Dateigre (MB)", + "Najvecja velikost datoteke (MB)", + "Dimensione massima file video (MB)", + "Maximale omvang video file (MB)", + "Tamanho mximo dos ficheiros (MB)", + "Taille maxi des fichiers (MB)", + "Maksimal strrelse p videofiler (MB)", + "Maksimi tiedoston koko (MB)", + "Maks. wielkosc pliku (MB)", }, { "Setup.Recording$Split edited files", "Editierte Dateien aufteilen", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Razdeli urejene datoteke", + "Dividi i file modificati", + "Bewerkte files opdelen", + "Quebrar ficheiros", "Sparer les squences", - "", // TODO + "Splitt redigerte filer", "Paloittele muokatut", + "Dzielic montowane pliki", }, { "Setup.Replay$Multi speed mode", "MultiSpeed Modus", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Rezim z vec hitrostmi", + "Modalita' multispeed", + "Multi-speed mode", + "Modo de multi-speed", "Mode multi-vitesses", - "", // TODO + "Multispeed modus", "Moninopeustila", + "Tryb wielopredkosciowy", }, { "Setup.Replay$Show replay mode", "Wiedergabestatus anzeigen", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Prikazi rezim predvajanja", + "Modalita' di visualizz su replay", + "Weergave mode aangeven", + "Mostrar modo de replay", "Affichage mode de lecture", - "", // TODO + "Vis avspillingsmodus", "Nyt toiston tila", - }, - { "Setup.Miscellaneous$Min. event timeout", - "Mindest Event Pause", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "MinEventTimeout", // Too difficult to translate - read the manual! - "", // TODO - "Minimi tapahtuman odotus", - }, - { "Setup.Miscellaneous$Min. user inactivity", - "Mindest Benutzer-Inaktivitt", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Dure minimale d'inactivit", - "", // TODO - "Minimi kyttjn odotus", - }, - { "Setup.Miscellaneous$SVDRP timeout", - "SVDRP Timeout", - "", // TODO - "Timeout SVDRP", - "SVDRP Timeout", - "Timeout SVDRP", - "Temps maxi SVDRP", - "Ubrukt SVDRP-levetid", - "SVDRP odotusaika", + "Wyswietlac status odtwarzania", + }, + { "Setup.Miscellaneous$Min. event timeout (min)", + "Mindest Event Pause (min)", + "Najmanjsi cas dogodka (min)", + "Tempo minimo di pausa (min)", // ??? i don't know... + "Minimale event time-out (min)", + "Perodo mnimo de pausa (min)", + "MinEventTimeout (min)", // Too difficult to translate - read the manual! + "Minste hendelsespause (min)", + "Minimi tapahtuman odotus (min)", + "Min. czas do nast. akcji (Event) (min)", + }, + { "Setup.Miscellaneous$Min. user inactivity (min)", + "Mindest Benutzer-Inaktivitt (min)", + "Najmanjsi cas neaktivnosti (min)", + "Tempo minimo di inattivita' (min)", + "Minimum gebruikers inactiviteit (min)", + "Perodo mnimo de inactividade (min)", + "Dure minimale d'inactivit (min)", + "Minimumstid med inaktivitet (min)", + "Minimi kyttjn odotus (min)", + "Min. brak aktywnosci uzytkownika (min)", + }, + { "Setup.Miscellaneous$SVDRP timeout (min)", + "SVDRP Timeout (min)", + "SVDRP Timeout (min)", + "Timeout SVDRP (min)", + "SVDRP Timeout (min)", + "Timeout SVDRP (min)", + "Temps maxi SVDRP (min)", + "Ubrukt SVDRP-levetid (min)", + "SVDRP odotusaika (min)", + "Min. brak aktywnosci SVDRP (min)", }, // The days of the week: { "MTWTFSS", @@ -1335,16 +1461,18 @@ const tPhrase Phrases[] = { "LMMJVSD", "MTOTFLS", "MTKTPLS", + "PWSCPSN", }, { "MonTueWedThuFriSatSun", // must all be 3 letters! "MonDieMitDonFreSamSon", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "PonTorSreCetPetSobNed", + "LunMarMerGioVenSabDom", + "MaaDinWoeDonVryZatZon", + "SegTerQuaQuiSexSabDom", "LunMarMerJeuVenSamDim", - "", // TODO + "ManTirOnsTorFreLrSn", "MaaTiiKesTorPerLauSun", + "PonWtoSroCzwPiaSobNie", }, // Learning keys: { "Learning Remote Control Keys", @@ -1356,6 +1484,7 @@ const tPhrase Phrases[] = { "Apprentissage des codes de tlcommande", "Lre fjernkontrolltaster", "Kaukostimen nppinten opettelu", + "Nauka kodu pilota", }, { "Phase 1: Detecting RC code type", "Phase 1: FB Code feststellen", @@ -1366,46 +1495,51 @@ const tPhrase Phrases[] = { "Phase 1: Dtection du type de code", "Fase 1: Finne fjernkontroll-kodetype", "Vaihe 1: Lhetystavan selvittminen", + "Faza 1: Detekcja typu kodu", }, { "Press any key on the RC unit", "Eine Taste auf der FB drcken", "Pritisnite tipko na upravljalcu", "Premere un tasto nell'unita` RC", "Druk op een willekeurige knop", - "Pressione qualquer tecla do telecomando", + "Pressione qualquer tecla do telecomando", "Appuyer sur une touche de la tlcommande", "Trykk en av tastene p fjernkontrollen", "Paina mit tahansa kaukostimen nppint", + "Nacisnac klawisz pilota", }, { "RC code detected!", "FB Code erkannt!", "IR koda sprejeta!", "Codice RC rilevato!", "Afstandsbediening code herkend!", - "Codigo do telecomando detectado!", + "Cdigo do telecomando detectado!", "Code de la tlcommande dtect!", "Fjernkontroll-kodetype funnet!", "Nppinpainallus vastaanotettu!", + "Kod pilota zostal poznany!", }, { "Do not press any key...", "Keine Taste drcken...", "Ne pritiskajte tipk...", "Non premere alcun tasto...", "Druk niet op een knop...", - "Nao pressione nada...", - "Ne pas appuyer sur une touche ...", + "No pressione nada...", + "N'appuyer sur aucune touche ...", "Ikke trykk p noen av tastene...", "l paina mitn nppint...", + "Nie naciskac klawiszy...", }, { "Phase 2: Learning specific key codes", "Phase 2: Einzelne Tastencodes lernen", "Faza 2: Ucenje posebnih kod", "Fase 2: Codici specifici dei tasti", "Fase 2: Leren specifieke toets-codes", - "Fase 2: A aprender codigos especificos", + "Fase 2: A aprender cdigos especificos", "Phase 2: Apprentissage des codes des touches", "Fase 2: Lre spesifikke tastekoder", "Vaihe 2: Nppinkoodien opettelu", + "Faza 2: Nauka pojedynczych klawiszy", }, { "Press key for '%s'", "Taste fr '%s' drcken", @@ -1416,6 +1550,7 @@ const tPhrase Phrases[] = { "Appuyer sur la touche '%s'", "Trykk tasten for '%s'", "Paina nppint toiminnolle '%s'", + "Nacisnac klawisz dla '%s'", }, { "Press 'Up' to confirm", "'Auf' drcken zum Besttigen", @@ -1426,6 +1561,7 @@ const tPhrase Phrases[] = { "Appuyer sur 'Haut' pour confirmer", "Trykk 'Opp' for bekrefte", "Paina 'Yls' hyvksyksesi", + "Nacisnac 'Gora' do potwierdzenia", }, { "Press 'Down' to continue", "'Ab' drcken zum Weitermachen", @@ -1436,6 +1572,7 @@ const tPhrase Phrases[] = { "Appuyer sur 'Bas' pour continuer", "Trykk Ned' for fortsette", "Paina 'Alas' jatkaaksesi", + "Nacisnac 'Dol' zeby kontynuowac", }, { "(press 'Up' to go back)", "('Auf' drcken um zurckzugehen)", @@ -1446,26 +1583,29 @@ const tPhrase Phrases[] = { "(Appuyer sur 'Haut' pour revenir en arrire)", "(trykk 'Opp' for g tilbake)", "(paina 'Yls' palataksesi takaisin)", + "(Nacisnac 'Gora' cofa)", }, { "(press 'Down' to end key definition)", "('Ab' drcken zum Beenden)", "(pritisnite 'Dol' za konec)", "('Giu' per finire la definiz tasti)", "(Druk 'Omlaag' om te beeindigen)", - "(Pressione 'Baixo' para terminar a definicao)", + "(Pressione 'Baixo' para terminar a definio)", "(Appuyer sur 'Bas' pour terminer)", "(trykk 'Ned' for avslutte innlring)", "(paina 'Alas' lopettaaksesi nppinten opettelun)", + "(Nacisnac 'Dol' by zakonczyc)", }, { "Phase 3: Saving key codes", "Phase 3: Codes abspeichern", "Faza 3: Shranjujem kodo", "Fase 3: Salvataggio key codes", "Fase 3: Opslaan toets codes", - "Fase 3: A Salvar os codigos das teclas", + "Fase 3: A salvar os cdigos das teclas", "Phase 3: Sauvegarde des codes des touches", "Fase 3: Lagre tastekoder", "Vaihe 3: Nppinkoodien tallettaminen", + "Faza 3: Zapamietac Kod", }, { "Press 'Up' to save, 'Down' to cancel", "'Auf' speichert, 'Ab' bricht ab", @@ -1476,6 +1616,7 @@ const tPhrase Phrases[] = { "Appuyer sur 'Haut' pour sauvegarder, 'Bas' pour annuler", "Trykk 'Opp' for lagre, 'Ned' for avbryte", "Paina 'Yls' tallettaaksesi ja 'Alas' peruuttaaksesi", + "'Gora' zapamietuje, 'Dol' przerywa", }, // Key names: { "Up", @@ -1487,6 +1628,7 @@ const tPhrase Phrases[] = { "Haut", "Opp", "Yls", + "Gora", }, { "Down", "Ab", @@ -1497,6 +1639,7 @@ const tPhrase Phrases[] = { "Bas", "Ned", "Alas", + "Dol", }, { "Menu", "Men", @@ -1507,6 +1650,7 @@ const tPhrase Phrases[] = { "Menu", "Meny", "Valikko", + "Menu", }, { "Ok", "Ok", @@ -1517,6 +1661,7 @@ const tPhrase Phrases[] = { "Ok", "Ok", "Ok", + "Ok", }, { "Back", "Zurck", @@ -1527,6 +1672,7 @@ const tPhrase Phrases[] = { "Retour", "Tilbake", "Takaisin", + "Wstecz", }, { "Left", "Links", @@ -1537,6 +1683,7 @@ const tPhrase Phrases[] = { "Gauche", "Venstre", "Vasemmalle", + "Lewo", }, { "Right", "Rechts", @@ -1547,6 +1694,7 @@ const tPhrase Phrases[] = { "Droite", "Hyre", "Oikealle", + "Prawo", }, { "Red", "Rot", @@ -1557,6 +1705,7 @@ const tPhrase Phrases[] = { "Rouge", "Rd", "Punainen", + "Czerwony", }, { "Green", "Grn", @@ -1567,6 +1716,7 @@ const tPhrase Phrases[] = { "Vert", "Grnn", "Vihre", + "Zielony", }, { "Yellow", "Gelb", @@ -1577,6 +1727,7 @@ const tPhrase Phrases[] = { "Jaune", "Gul", "Keltainen", + "Zolty", }, { "Blue", "Blau", @@ -1587,46 +1738,51 @@ const tPhrase Phrases[] = { "Bleu", "Bl", "Sininen", + "Niebieski", }, { "Power", "Ausschalten", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Izklop", + "Power", + "Uitschakelen", + "Ligar", "Arrt", - "", // TODO + "Power", "Virtakytkin", + "Wylaczyc", }, { "Volume+", "Lautstrke+", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Glasnost+", "Volume+", - "", // TODO + "Volume+", + "Volume+", + "Volume+", + "Volum+", "nenvoimakkuus+", + "Glosnej", }, { "Volume-", "Lautstrke-", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Glasnost-", + "Volume-", + "Volume-", "Volume-", - "", // TODO + "Volume-", + "Volum-", "nenvoimakkuus-", + "Ciszej", }, { "Mute", "Stumm", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Izklop zvoka", + "Mute", + "Geluid onderbreken", + "Sem som", "Coupure du son", - "", // TODO + "Lyd av", "nen vaimennus", + "Cisza", }, // Miscellaneous: { "yes", @@ -1638,156 +1794,183 @@ const tPhrase Phrases[] = { "oui", "ja", "kyll", + "tak", }, { "no", "nein", "ne", "no", "nee", - "nao", + "no", "non", "nei", "ei", + "nie", }, { "top", "oben", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "zgoraj", + "limite sup", + "boven", + "topo", "haut", - "", // TODO + "vre", "yl", + "gora", }, { "bottom", "unten", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "spodaj", + "limite inf", + "onder", + "fundo", "bas", - "", // TODO + "nedre", "ala", + "dol", + }, + { "Disk", + "Disk", + "Disk", + "Disk", + "Disk", + "Disk", + "Disque", + "Disk", + "Disk", + "Disk", }, { "free", "frei", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "prosto", + "liberi", + "vrij", + "livre", "restant", - "", // TODO + "ledig", "vapaa", + "pozostalo", }, { "Jump: ", // note the trailing blank "Springen: ", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Skoci: ", + "Vai a: ", + "Springen: ", + "Saltar: ", "Accs direct: ", - "", // TODO - "Hypp:", + "Hopp: ", + "Hypp: ", + "Skok: ", }, { "Volume ", // note the trailing blank "Lautstrke ", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Glasnost ", + "Volume ", + "Volume ", + "Volume ", "Volume ", - "", // TODO + "Volum ", "nenvoimakkuus ", + "Glosnosc ", }, { " Stop replaying", // note the leading blank! " Wiedergabe beenden", " Prekini ponavljanje", " Interrompi riproduzione", " Stop afspelen", - " Parar reproducao", + " Parar reproduo", " Arrter la lecture", " Stopp avspilling", " Pysyt toisto", + " Zatrzymac odtwarzanie", }, { " Stop recording ", // note the leading and trailing blanks! " Aufzeichnung beenden ", " Prekini shranjevanje ", " Interrompi registrazione ", " Stop opnemen ", - " Parar gravacao ", + " Parar gravao ", " Arrter l'enregistrement ", " Stopp opptak fra ", " Pysyt nauhoitus ", + " Zatrzymac nagrywanie ", }, { " Cancel editing", // note the leading blank! " Schneiden abbrechen", " Prekini urejanje", " Annulla modifiche", " Bewerken afbreken", - " Anular modificacao", + " Anular modificao", " Annuler le montage", - " Avbryt editering", + " Avbryt redigering", " Peruuta muokkaus", + " Przerwac montaz ", }, { "Switching primary DVB...", "Primres Interface wird umgeschaltet...", "Preklapljanje primarne naprave...", "Cambio su card DVB primaria...", "Eerste DVB-kaart wordt omgeschakeld...", - "A mudar placa DVB primaria...", - "Changement de carte DVB principale...", - "Bytter hoved DVB-enhet...", + "A mudar interface DVB primrio...", + "Changement de carte DVB primaire...", + "Bytter frste DVB-enhet..." "Vaihdetaan ensisijainen vastaanotin...", + "Pierwszy interfejs DVB przelacza...", }, { "Up/Dn for new location - OK to move", "Auf/Ab fr neue Position - dann OK", "Gor/Dol za novo poz. - Ok za premik", "Su/Giu per nuova posizione - OK per muovere", "Gebruik Omhoog/Omlaag - daarna Ok", - "Cima/Baixo para nova localizacao - Ok para mudar", + "Cima/Baixo para nova localizao - Ok para mover", "Haut/Bas -> nouvelle place - OK -> dplacer", "Opp/Ned for ny plass - OK for flytte", "Yls/Alas = liiku, OK = siirr", + "Gora/Dol na nowa pozycje - Ok zmienia", }, { "Editing process started", "Schnitt gestartet", "Urejanje se je zacelo", "Processo di modifica iniziato", "Bewerken is gestart", - "Processo de modificacao iniciado", + "Processo de modificao iniciado", "Opration de montage lance", "Redigeringsprosess startet", "Muokkaus aloitettu", + "Uruchomiony proces montazu", }, { "Editing process finished", "Schnitt beendet", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "Proces urejanja koncan", + "Processo di modifica terminato", + "Bewerken is klaar", + "Processo de modificao terminado", "Montage termin", - "", // TODO + "Redigeringsprosess avsluttet", "Muokkaus lopetettu", + "Proces montazu zakonczony", }, { "Editing process failed!", "Schnitt gescheitert!", - "", // TODO - "", // TODO - "", // TODO - "", // TODO - "Echec du montage", - "", // TODO - "Muokkaus eponnistui", + "Napaka pri procesu urejenja!", + "Processo di modifica fallito!", + "Bewerken is mislukt!", + "Falha no processo de modificao", + "Echec du montage!", + "Feil under redigering!", + "Muokkaus eponnistui!", + "Bledny proces montazu!", }, { "scanning recordings...", "Aufzeichnungen werden durchsucht...", - "", // TODO - "", // TODO - "", // TODO - "", // TODO + "iskanje posnetkov...", + "scansione registrazioni...", + "Doorzoeken opnames...", + "A pesquisar gravaes...", "Recherche des enregistrements...", - "", // TODO + "Gr igjennom opptakene...", "haetaan nauhoituksia...", + "Skan nagran...", }, { NULL } }; diff --git a/keys-pc.conf b/keys-pc.conf index d727712d3..d9a390f7c 100644 --- a/keys-pc.conf +++ b/keys-pc.conf @@ -3,7 +3,7 @@ Address 0000 Up 00000103 Down 00000102 Menu 00000106 -Ok 0000015E +Ok 0000000D Back 00000168 Left 00000104 Right 00000105 diff --git a/menu.c b/menu.c index 93f1ff7d4..03dbcea34 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.172 2002/03/17 14:23:44 kls Exp $ + * $Id: menu.c 1.180 2002/03/31 21:17:42 kls Exp $ */ #include "menu.h" @@ -21,6 +21,8 @@ #define MAXWAIT4EPGINFO 10 // seconds #define MODETIMEOUT 3 // seconds +#define CHNUMWIDTH (Channels.Count() > 999 ? 5 : 4) // there are people with more than 999 channels... + const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#~^"; // --- cMenuEditItem --------------------------------------------------------- @@ -780,7 +782,7 @@ class cMenuChannels : public cOsdMenu { }; cMenuChannels::cMenuChannels(void) -:cOsdMenu(tr("Channels"), 4) +:cOsdMenu(tr("Channels"), CHNUMWIDTH) { //TODO int i = 0; @@ -1186,7 +1188,7 @@ class cMenuTimers : public cOsdMenu { }; cMenuTimers::cMenuTimers(void) -:cOsdMenu(tr("Timers"), 2, 4, 10, 6, 6) +:cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6) { int i = 0; cTimer *timer; @@ -1217,7 +1219,7 @@ eOSState cMenuTimers::OnOff(void) timer->active = false; } else if (timer->active) - timer->SkipToday(); + timer->Skip(); else timer->active = true; timer->Matches(); // refresh start and end time @@ -1412,7 +1414,7 @@ static int CompareEventChannel(const void *p1, const void *p2) } cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr) -:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), 4, 7, 6) +:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6) { const cSchedule *Schedule = Schedules->First(); const cEventInfo **pArray = NULL; @@ -1854,7 +1856,7 @@ eOSState cMenuRecordings::Del(void) if (Interface->Confirm(tr("Timer still recording - really delete?"))) { cTimer *timer = rc->Timer(); if (timer) { - timer->SkipToday(); + timer->Skip(); cRecordControls::Process(time(NULL)); Timers.Save(); } @@ -1935,7 +1937,7 @@ class cMenuSetupPage : public cOsdMenu { }; cMenuSetupPage::cMenuSetupPage(void) -:cOsdMenu("", 30) +:cOsdMenu("", 33) { data = Setup; osdLanguage = Setup.OSDLanguage; @@ -1991,7 +1993,7 @@ void cMenuSetupOSD::Set(void) Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &data.OSDLanguage, NumLanguages, Languages())); Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); Add(new cMenuEditIntItem( tr("Setup.OSD$Height"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); - Add(new cMenuEditIntItem( tr("Setup.OSD$Message time"), &data.OSDMessageTime, 1, 60)); + Add(new cMenuEditIntItem( tr("Setup.OSD$Message time (s)"), &data.OSDMessageTime, 1, 60)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"), &data.ChannelInfoPos, tr("bottom"), tr("top"))); Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll pages"), &data.MenuScrollPage)); @@ -2012,7 +2014,7 @@ void cMenuSetupEPG::Set(void) { Clear(); SetupTitle("EPG"); - Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout"), &data.EPGScanTimeout)); + Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout)); Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime)); Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder)); @@ -2048,10 +2050,10 @@ void cMenuSetupLNB::Set(void) { Clear(); SetupTitle("LNB"); - Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF"), &data.LnbSLOF)); - Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency"), &data.LnbFrequLo)); - Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency"), &data.LnbFrequHi)); - Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); + Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); + Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo)); + Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi)); + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); } // --- cMenuSetupCICAM ------------------------------------------------------- @@ -2089,17 +2091,17 @@ void cMenuSetupRecord::Set(void) { Clear(); SetupTitle("Recording"); - Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start"), &data.MarginStart)); - Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop"), &data.MarginStop)); - Add(new cMenuEditIntItem( tr("Setup.Recording$Primary limit"), &data.PrimaryLimit, 0, MAXPRIORITY)); - Add(new cMenuEditIntItem( tr("Setup.Recording$Default priority"), &data.DefaultPriority, 0, MAXPRIORITY)); - Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime"), &data.DefaultLifetime, 0, MAXLIFETIME)); - Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); - Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); - Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord), FileNameChars)); - Add(new cMenuEditBoolItem(tr("Setup.Recording$Record Dolby Digital"), &data.RecordDolbyDigital)); - Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); - Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Primary limit"), &data.PrimaryLimit, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Default priority"), &data.DefaultPriority, 0, MAXPRIORITY)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); + Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord), FileNameChars)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Record Dolby Digital"), &data.RecordDolbyDigital)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); } // --- cMenuSetupReplay ------------------------------------------------------ @@ -2132,9 +2134,9 @@ void cMenuSetupMisc::Set(void) { Clear(); SetupTitle("Miscellaneous"); - Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout"), &data.MinEventTimeout)); - Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity"), &data.MinUserInactivity)); - Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout"), &data.SVDRPTimeout)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (min)"), &data.SVDRPTimeout)); } // --- cMenuSetup ------------------------------------------------------------ @@ -2231,6 +2233,11 @@ eOSState cMenuCommands::Execute(void) { cCommand *command = Commands.Get(Current()); if (command) { + char *buffer = NULL; + asprintf(&buffer, "%s...", command->Title()); + Interface->Status(buffer); + Interface->Flush(); + delete buffer; const char *Result = command->Execute(); if (Result) return AddSubMenu(new cMenuText(command->Title(), Result, fontFix)); @@ -2286,7 +2293,7 @@ void cMenuMain::Set(void) int Minutes = int(double(FreeMB) / MB_PER_MINUTE); int Hours = Minutes / 60; Minutes %= 60; - snprintf(buffer, sizeof(buffer), "%s - Disk %d%% - %2d:%02d %s", tr("VDR"), Percent, Hours, Minutes, tr("free")); + snprintf(buffer, sizeof(buffer), "%s - %s %d%% - %2d:%02d %s", tr("VDR"), tr("Disk"), Percent, Hours, Minutes, tr("free")); SetTitle(buffer); // Basic menu items: @@ -2310,6 +2317,7 @@ void cMenuMain::Set(void) char *buffer = NULL; asprintf(&buffer, "%s%s", STOP_RECORDING, ON_PRIMARY_INTERFACE); Add(new cOsdItem(buffer, osStopRecord)); + delete buffer; } const char *s = NULL; @@ -3100,64 +3108,47 @@ bool cReplayControl::ShowProgress(bool Initial) void cReplayControl::TimeSearchDisplay(void) { char buf[64]; - int len; - strcpy(buf, tr("Jump: ")); - len = strlen(buf); - - switch (timeSearchPos) { - case 1: sprintf(buf + len, "%01d-:--", timeSearchHH / 10); break; - case 2: sprintf(buf + len, "%02d:--", timeSearchHH); break; - case 3: sprintf(buf + len, "%02d:%01d-", timeSearchHH, timeSearchMM / 10); break; - case 4: sprintf(buf + len, "%02d:%02d", timeSearchHH, timeSearchMM); break; - default: sprintf(buf + len, "--:--"); break; - } - + int len = strlen(buf); + char h10 = '0' + (timeSearchTime >> 24); + char h1 = '0' + ((timeSearchTime & 0x00FF0000) >> 16); + char m10 = '0' + ((timeSearchTime & 0x0000FF00) >> 8); + char m1 = '0' + (timeSearchTime & 0x000000FF); + char ch10 = timeSearchPos > 3 ? h10 : '-'; + char ch1 = timeSearchPos > 2 ? h1 : '-'; + char cm10 = timeSearchPos > 1 ? m10 : '-'; + char cm1 = timeSearchPos > 0 ? m1 : '-'; + sprintf(buf + len, "%c%c:%c%c", ch10, ch1, cm10, cm1); DisplayAtBottom(buf); } void cReplayControl::TimeSearchProcess(eKeys Key) { - int Seconds = timeSearchHH * 3600 + timeSearchMM * 60; +#define STAY_SECONDS_OFF_END 10 + int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60; + int Current = (lastCurrent / FRAMESPERSEC); + int Total = (lastTotal / FRAMESPERSEC); switch (Key) { case k0 ... k9: - { - int n = Key - k0; - int s = (lastTotal / FRAMESPERSEC); - int m = s / 60 % 60; - int h = s / 3600; - switch (timeSearchPos) { - case 0: if (n * 10 <= h) { - timeSearchHH = n * 10; - timeSearchPos++; - } - break; - case 1: if (timeSearchHH + n <= h) { - timeSearchHH += n; - timeSearchPos++; - } - break; - case 2: if (n <= 5 && timeSearchHH * 60 + n * 10 <= h * 60 + m) { - timeSearchMM += n * 10; - timeSearchPos++; - } - break; - case 3: if (timeSearchHH * 60 + timeSearchMM + n <= h * 60 + m) { - timeSearchMM += n; - timeSearchPos++; - } - break; - } - TimeSearchDisplay(); - } + if (timeSearchPos < 4) { + timeSearchTime <<= 8; + timeSearchTime |= Key - k0; + timeSearchPos++; + TimeSearchDisplay(); + } break; case kLeft: - case kRight: - dvbApi->SkipSeconds(Seconds * (Key == kRight ? 1 : -1)); + case kRight: { + int dir = (Key == kRight ? 1 : -1); + if (dir > 0) + Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds); + dvbApi->SkipSeconds(Seconds * dir); timeSearchActive = false; + } break; case kUp: case kDown: + Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds); dvbApi->Goto(Seconds * FRAMESPERSEC, Key == kDown); timeSearchActive = false; break; @@ -3177,7 +3168,7 @@ void cReplayControl::TimeSearchProcess(eKeys Key) void cReplayControl::TimeSearch(void) { - timeSearchHH = timeSearchMM = timeSearchPos = 0; + timeSearchTime = timeSearchPos = 0; timeSearchHide = false; if (modeOnly) Hide(); @@ -3288,7 +3279,9 @@ eOSState cReplayControl::ProcessKey(eKeys Key) ShowMode(); timeoutShow = 0; } - else if (!modeOnly) + else if (modeOnly) + ShowMode(); + else shown = ShowProgress(!shown) || shown; } bool DisplayedFrames = displayFrames; diff --git a/menu.h b/menu.h index ae46d02f2..88930167e 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.40 2002/03/16 09:51:10 kls Exp $ + * $Id: menu.h 1.41 2002/03/31 13:53:23 kls Exp $ */ #ifndef _MENU_H @@ -116,7 +116,7 @@ class cReplayControl : public cOsdBase { int lastCurrent, lastTotal; time_t timeoutShow; bool timeSearchActive, timeSearchHide; - int timeSearchHH, timeSearchMM, timeSearchPos; + int timeSearchTime, timeSearchPos; void TimeSearchDisplay(void); void TimeSearchProcess(eKeys Key); void TimeSearch(void); diff --git a/mpatrol.diff b/mpatrol.diff new file mode 100644 index 000000000..59497c44c --- /dev/null +++ b/mpatrol.diff @@ -0,0 +1,56 @@ +# This is a BitKeeper generated patch for the following project: +# Project Name: Linux VDR +# This patch format is intended for GNU patch command version 2.5 or higher. +# This patch includes the following deltas: +# ChangeSet 1.20 -> 1.21 +# config.c 1.4 -> 1.5 +# tools.c 1.2 -> 1.3 +# +# The following is the BitKeeper ChangeSet Log +# -------------------------------------------- +# 02/04/01 aschultz@warp10.net 1.21 +# fix memory management due to MPatrol +# -------------------------------------------- +# +diff -Nru a/config.c b/config.c +--- a/config.c Mon Apr 1 14:37:48 2002 ++++ b/config.c Mon Apr 1 14:37:48 2002 +@@ -265,7 +265,7 @@ + sscanf(apidbuf, "%d ,%d ", &apid1, &apid2); + if (p) + sscanf(p, "%d ,%d ", &dpid1, &dpid2); +- delete apidbuf; ++ free(apidbuf); + } + else + return false; +@@ -277,7 +277,7 @@ + tpid = 0; + } + strn0cpy(name, buffer, MaxChannelName); +- delete buffer; ++ free(buffer); + } + else + return false; +diff -Nru a/tools.c b/tools.c +--- a/tools.c Mon Apr 1 14:37:48 2002 ++++ b/tools.c Mon Apr 1 14:37:48 2002 +@@ -71,7 +71,7 @@ + esyslog(LOG_ERR, "ERROR: out of memory"); + } + else { +- delete dest; ++ free(dest); + dest = NULL; + } + return dest; +@@ -230,7 +230,7 @@ + const char *AddDirectory(const char *DirName, const char *FileName) + { + static char *buf = NULL; +- delete buf; ++ free(buf); + asprintf(&buf, "%s/%s", DirName && *DirName ? DirName : ".", FileName); + return buf; + } diff --git a/osd.c b/osd.c index e404a6f8a..56ba9b5c1 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.21 2002/03/10 16:18:06 kls Exp $ + * $Id: osd.c 1.23 2002/03/29 16:34:03 kls Exp $ */ #include "osd.h" @@ -76,6 +76,7 @@ eOSState cOsdItem::ProcessKey(eKeys Key) cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4) { + digit = 0; hasHotkeys = false; visible = false; title = NULL; @@ -105,12 +106,15 @@ cOsdMenu::~cOsdMenu() const char *cOsdMenu::hk(const char *s) { static char buffer[32]; - if (digit < 9) { - snprintf(buffer, sizeof(buffer), " %d %s", ++digit, s); - return buffer; + if (s && hasHotkeys) { + if (digit == 0 && '1' <= *s && *s <= '9' && *(s + 1) == ' ') + digit = 10; // prevents automatic hotkeys - input already has them + if (digit < 9) { + snprintf(buffer, sizeof(buffer), " %d %s", ++digit, s); + s = buffer; + } } - else - return s; + return s; } void cOsdMenu::SetHasHotkeys(void) @@ -288,6 +292,10 @@ void cOsdMenu::PageUp(void) first -= MAXOSDITEMS; if (first < 0) first = current = 0; + if (SpecialItem(current)) { + current -= (current > 0) ? 1 : -1; + first = min(first, current - 1); + } Display(); DisplayCurrent(true); } @@ -302,6 +310,10 @@ void cOsdMenu::PageDown(void) current = Count() - 1; first = Count() - MAXOSDITEMS; } + if (SpecialItem(current)) { + current += (current < Count() - 1) ? 1 : -1; + first = max(first, current - MAXOSDITEMS); + } Display(); DisplayCurrent(true); } diff --git a/recording.c b/recording.c index 56ea05653..b19e8b73f 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.57 2002/03/16 12:17:44 kls Exp $ + * $Id: recording.c 1.60 2002/04/01 10:51:23 kls Exp $ */ #include "recording.h" @@ -172,7 +172,7 @@ bool cResumeFile::Save(int Index) if (fileName) { int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (f >= 0) { - if (safe_write(f, &Index, sizeof(Index)) != sizeof(Index)) + if (safe_write(f, &Index, sizeof(Index)) < 0) LOG_ERROR_STR(fileName); close(f); return true; @@ -324,7 +324,7 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c if (isempty(Summary)) Summary = ""; if (*Subtitle || *Summary) - asprintf(&summary, "%s%s%s", Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary); + asprintf(&summary, "%s\n\n%s%s%s", Title, Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary); } } @@ -343,7 +343,7 @@ cRecording::cRecording(const char *FileName) time_t now = time(NULL); struct tm tm_r; struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't' - t.tm_isdst = -1; // makes sure mktime() will determine the correct dst setting + t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting 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--; diff --git a/svdrp.c b/svdrp.c index 06f8ebbc5..751a5c54c 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.34 2002/03/08 17:17:05 kls Exp $ + * $Id: svdrp.c 1.35 2002/03/23 16:17:39 kls Exp $ */ #include "svdrp.h" @@ -340,16 +340,12 @@ bool cSVDRP::Send(const char *s, int length) { if (length < 0) length = strlen(s); - int wbytes = safe_write(file, s, length); - if (wbytes == length) - return true; - if (wbytes < 0) { + if (safe_write(file, s, length) < 0) { LOG_ERROR; file.Close(); + return false; } - else //XXX while...??? - esyslog(LOG_ERR, "Wrote %d bytes to client while expecting %d\n", wbytes, length); - return false; + return true; } void cSVDRP::Reply(int Code, const char *fmt, ...) diff --git a/tools.c b/tools.c index 3764a6441..099fb7d94 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.59 2002/02/17 12:57:23 kls Exp $ + * $Id: tools.c 1.62 2002/03/31 20:51:06 kls Exp $ */ #include "tools.h" @@ -13,6 +13,7 @@ #include <errno.h> #include <stdlib.h> #include <sys/time.h> +#include <sys/vfs.h> #include <time.h> #include <unistd.h> #include "i18n.h" @@ -33,14 +34,22 @@ ssize_t safe_read(int filedes, void *buffer, size_t size) ssize_t safe_write(int filedes, const void *buffer, size_t size) { - for (;;) { - ssize_t p = write(filedes, buffer, size); - if (p < 0 && errno == EINTR) { - dsyslog(LOG_INFO, "EINTR while writing to file handle %d - retrying", filedes); - continue; - } - return p; - } + ssize_t p = 0; + ssize_t written = size; + const unsigned char *ptr = (const unsigned char *)buffer; + while (size > 0) { + p = write(filedes, ptr, size); + if (p < 0) { + if (errno == EINTR) { + dsyslog(LOG_INFO, "EINTR while writing to file handle %d - retrying", filedes); + continue; + } + break; + } + ptr += p; + size -= p; + } + return p < 0 ? p : written; } void writechar(int filedes, char c) @@ -235,34 +244,20 @@ const char *AddDirectory(const char *DirName, const char *FileName) return buf; } -#define DFCMD "df -m -P '%s'" - int FreeDiskSpaceMB(const char *Directory, int *UsedMB) { - //TODO Find a simpler way to determine the amount of free disk space! if (UsedMB) *UsedMB = 0; int Free = 0; - char *cmd = NULL; - asprintf(&cmd, DFCMD, Directory); - FILE *p = popen(cmd, "r"); - if (p) { - char *s; - while ((s = readline(p)) != NULL) { - if (strchr(s, '/')) { - int used, available; - sscanf(s, "%*s %*d %d %d", &used, &available); - if (UsedMB) - *UsedMB = used; - Free = available; - break; - } - } - pclose(p); + struct statfs statFs; + if (statfs(Directory, &statFs) == 0) { + int blocksPerMeg = 1024 * 1024 / statFs.f_bsize; + if (UsedMB) + *UsedMB = (statFs.f_blocks - statFs.f_bfree) / blocksPerMeg; + Free = statFs.f_bavail / blocksPerMeg; } else - esyslog(LOG_ERR, "ERROR: can't open pipe for cmd '%s'", cmd); - delete cmd; + LOG_ERROR_STR(Directory); return Free; } diff --git a/vdr.1 b/vdr.1 new file mode 100644 index 000000000..1fd39df6e --- /dev/null +++ b/vdr.1 @@ -0,0 +1,164 @@ +'\" t +.\" ** The above line should force tbl to be a preprocessor ** +.\" Man page for vdr +.\" +.\" Copyright (C) 2002 Klaus Schmidinger +.\" +.\" You may distribute under the terms of the GNU General Public +.\" License as specified in the file COPYING that comes with the +.\" vdr distribution. +.\" +.\" $Id: vdr.1 1.2 2002/03/29 10:10:04 kls Exp $ +.\" +.TH vdr 1 "29 Mar 2002" "1.0.0" "Video Disk Recorder" +.SH NAME +vdr - the Video Disk Recorder +.SH SYNOPSIS +.B vdr +[options] +.SH DESCRIPTION +.B vdr +implements a complete digital Set-Top-Box and Video Recorder. +It can work with signals received from satellites (DVB-S) as +well as cable (DVB-C) and terrestrial (DVB-T) signals. + +At least one DVB card is required to run \fBvdr\fR, but in order +to watch one broadcast while recording another, or to start watching +a recorded programme before the live broadcast has ended (\fBtime shifting\fR), +two DVB cards are necessary. By default \fBvdr\fR can support up to four +DVB cards. The primary DVB card (the one your tv set is connected to) has +to be a "full featured" card, which means it must contain an MPEG decoder +and provide audio and video signal outputs. + +\fBvdr\fR uses the On Screen Display of the DVB card to display its menus. +It can be controlled by the PC keyboard, a home built "Remote Control Unit" +(RCU) or the "Linux Infrared Remote Control" (LIRC). + +Remote access is possible via the "Simple Video Disk Recorder Protocol" (SVDRP), +which can be accessed on port 2001, for instance by \fBtelnet\fR. +.SH OPTIONS +.TP +.BI -a\ cmd ,\ --audio= cmd +Send Dolby Digital audio to stdin of command \fIcmd\fR. +.TP +.BI -c\ dir ,\ --config= dir +Read config files from directory \fIdir\fR +(default is to read them from the video directory). +.TP +.B -d, --daemon +Run in daemon mode. +.TP +.BI -D\ num ,\ --device= num +Use only the given DVB device (\fInum\fR = 0, 1, 2...). +There may be several \fB-D\fR options (by default all DVB devices will be used). +.TP +.BI -E\ file ,\ --epgfile= file +Write the EPG data into the given \fIfile\fR +(default is \fI/video/epg.data\fR). +Use \fB-E-\fR to disable this. +If \fIfile\fR is a directory, the file \fIepg.data\fR +will be created in that directory. +.TP +.B -h, --help +Print a help message and exit. +.TP +.BI -l\ level ,\ --log= level +Set logging to \fIlevel\fR. +\fB0\fR\ =\ no logging, \fB1\fR\ =\ errors only, +\fB2\fR\ =\ errors and info, \fB3\fR\ =\ errors, info and debug. +The default logging level is \fB3\fR. +.TP +.B -m, --mute +Mute audio of the primary DVB device at startup. +.TP +.BI -p\ port ,\ --port= port +Use \fIport\fR for SVDRP. A value of \fB0\fR turns off SVDRP. +The default SVDRP port is \fB2001\fR. +You need to edit the file \fIsvdrphosts.conf\fR in order to enable +access to the SVDRP port. +.TP +.BI -r\ cmd ,\ --record= cmd +Call \fIcmd\fR before and after a recording. +.TP +.BI -s\ cmd ,\ --shutdown= cmd +Call \fIcmd\fR to shutdown the computer. +.TP +.BI -t\ tty ,\ --terminal= tty +Set the controlling terminal. +.TP +.BI -v\ dir ,\ --video= dir +Use \fIdir\fR as video directory. +The default is \fI/video\fR. +.TP +.B -V, --version +Print version information and exit. +.TP +.BI -w\ sec ,\ --watchdog= sec +Activate the watchdog timer with a timeout of \fIsec\fR seconds. +A value of \fB0\fR (default) disables the watchdog. +.SH EXIT STATUS +.TP +.B 0 +Successful program execution. +.TP +.B 1 +An error has been detected which requires the DVB driver and \fBvdr\fR +to be re-loaded. +.SH FILES +.TP +.I channels.conf +Channel configuration. +.TP +.I ca.conf +Conditional access configuration. +.TP +.I timers.conf +Timer configuration. +.TP +.I setup.conf +User definable setup. +.TP +.I commands.conf +User definable commands (executed from the \fBCommands\fR menu). +.TP +.I svdrphosts.conf +SVDRP host configuration, defining which hosts or networks are given +access to the SVDRP port. +.TP +.I marks.vdr +Contains the editing marks defined for a recording. +.TP +.I summary.vdr +Contains a description of the recording. +.TP +.I resume.vdr +Contains the index into the recording where the last replay session left off. +.TP +.I index.vdr +Contains the file number, offset and type of each frame of the recording. +.TP +.I keys.conf +Contains the key assignments for the remote control. +.TP +.I keys-pc.conf +Contains the key assignments for the PC keyboard (used if the program +was compiled with DEBUG_OSD=1). +.TP +.IR 001.vdr\ ...\ 255.vdr +The actual data files of a recording. +.TP +.I epg.data +Contains all current EPG data. Can be used for external processing and will +also be read at program startup to have the full EPG data available immediately. +.SH SEE ALSO +.BR vdr (5) +.SH AUTHOR +Written by Klaus Schmidinger, with contributions from many others. +See the file \fICONTRIBUTORS\fR in the \fBvdr\fR source distribution. +.SH REPORTING BUGS +Report bugs to <vdr-bugs@cadsoft.de>. +.SH COPYRIGHT +Copyright \(co 2002 Klaus Schmidinger. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/vdr.5 b/vdr.5 new file mode 100644 index 000000000..483e15ffe --- /dev/null +++ b/vdr.5 @@ -0,0 +1,382 @@ +'\" t +.\" ** The above line should force tbl to be a preprocessor ** +.\" Man page for vdr file formats +.\" +.\" Copyright (C) 2002 Klaus Schmidinger +.\" +.\" You may distribute under the terms of the GNU General Public +.\" License as specified in the file COPYING that comes with the +.\" vdr distribution. +.\" +.\" $Id: vdr.5 1.3 2002/04/01 12:32:59 kls Exp $ +.\" +.TH vdr 5 "29 Mar 2002" "1.0.0" "Video Disk Recorder Files" +.SH NAME +vdr file formats - the Video Disk Recorder Files +.SH DESCRIPTION +This page describes the formats of the various files \fBvdr\fR uses to +store configuration data and recordings. +.SH SYNTAX +.SS CHANNELS +The file \fIchannels.conf\fR contains the channel configuration. +Each line defines either a \fBgroup delimiter\fR or a \fBchannel\fR. + +A \fBgroup delimiter\fR is a line starting with a ':' as the very first +character, followed by arbitrary text. Example: + +\fB:First group\fR + +A \fBchannel definition\fR is a line with channel data, where the fields +are separated by ':' characters. Example: + +\fBRTL:12188:h:1:27500:163:104:105:0:12003\fR + +The line number of a channel definition (not counting group separators!) +defines the channel's number in OSD menus and the \fItimers.conf\fR file. + +The fields in a channel definition have the following meaning (from left +to right): +.TP +.B Name +The channel's name (if the name originally contains a ':' character +it has to be replaced by '|'). +.TP +.B Frequency +The transponder frequency in MHz for DVB-S and DVB-C, kHz for DVB-T (as an integer). +.TP +.B Polarization +The polarization of the satellite signal. 'h' or 'H' for horizontal, 'v' or 'V' +for vertical (DVB-S only). +.TP +.B +DiSEqC +The DiSEqC code to use for this channel (integer, DVB-S only). +.TP +.B +Srate +The symbol rate of this channel (DVB-S and DVB-C only). +.TP +.B VPID +The video PID (set to '0' for radio channels, '1' for encrypted radio channels). +.TP +.B APID +The audio PID (either one number, or two, separated by a comma). +If this channel also carries Dolby Digital sound, the Dolby PIDs follow +the audio PIDs, separated by a semicolon, as in +.B ...:101,102;103,104:... +.TP +.B TPID +The teletext PID. +.TP +.B Conditional access +An integer defining how this channel can be accessed: +.TS +tab (@); +l l. +\fB0\fR@Free To Air +\fB1...4\fR@explicitly requires the DVB card with the given number +\fB>=100\fR@requires a specific decryption method defined in \fIca.conf\fR +.TE +.TP +.B PNR +The program number (aka service ID) of this channel. +.SS TIMERS +The file \fItimers.conf\fR contains the timer setup. +Each line contains one timer definition, with individual fields +separated by ':' characters. Example: + +\fB1:10:-T-----:2058:2150:50:5:Quarks & Co:\fR + +The fields in a timer definition have the following meaning (from left +to right): +.TP +.B Status +Defines whether this timer is \fBinactive\fR (0) or \fBactive\fR (1). +The value 3 is used for instant recordings. +Values other than these can be used by external programs to mark active timers +and recognize if the user has modified them. When a user modifes an active +timer the \fBstatus\fR field will be explicitly set to '1' (or '0', respectively, +if the user deactivates the timer). + +Note: in order to allow future extensibility, external programs using the +\fBstatus\fR parameter should only use the upper 16 bit of this 32 bit parameter +and leave the lower 16 bit untouched. +.TP +.B Channel +The number of the channel to record. +.TP +.B Day +The day when this timer shall record. + +If this is a `single-shot' timer, this is the day of month on which this +timer shall record. This must be in the range \fB1...31\fR. + +In case of a `repeating' timer this is a string consisting of exactly seven +characters, where each character position corresponds to one day of the week +(with Monday being the first day). The character '-' at a certain position +means that the timer shall not record on that day. Any other character will +cause the timer to record on that day. Example: + +.B MTWTF-- + +will define a timer that records on Monday thru Friday and does not record +on weekends. The same result could be achieved with \fBABCDE--\fR (this is +used to allow setting the days with language specific characters). + +The day definition of a `repeating' timer may be followed by the date when that +timer shall hit for the first time. The format for this is \fB@YYYY-MM-DD\fR, +so a complete definition could look like this: + +\fBMTWTF--@2002-02-18\fR + +which would implement a timer that records Moday thru Friday, and will hit +for the first time on or after February 18, 2002. +This \fBfirst day\fR feature can be used to disable a repeating timer for a couple +of days, or for instance to define a new Mon...Fri timer on wednesday, which +actually starts "monday next week". The \fBfirst day\fR date given need not be +that of a day when the timer would actually hit. +.TP +.B Start +A four digit integer defining when this timer shall \fBstart\fR recording. +The format is \fBhhmm\fR, so \fB1430\fR would mean "half past two" in the +afternoon. +.TP +.B Stop +A four digit integer defining when this timer shall \fBstop\fR recording. +The format is the same as for the \fBstart\fR time. +.TP +.B Priority +An integer in the range \fB0...99\fR, defining the \fBpriority\fR +of this timer and of recordings created by this timer. +\fB0\fR represents the lowest value, \fB99\fR the highest. +The priority is used to decide which timer shall be +started in case there are two or more timers with the exact same +\fBstart\fR time. The first timer in the list with the highest priority +will be used. + +This value is also stored with the recording and is +later used to decide which recording to remove from disk in order +to free space for a new recording. If the disk runs full and a new +recording needs more space, an existing recording with the lowest +priority (and which has exceeded its guaranteed \fBlifetime\fR) will be +removed. + +If all available DVB cards are currently occupied, a +timer with a higher priority will interrupt the timer with the +lowest priority in order to start recording. +.TP +.B Lifetime +The \fBguaranteed lifetime\fR (in days) of a recording created by this timer. +\fB0\fR means that this recording may be automatically deleted at any time +by a new recording with higher priority. \fB99\fR means that this recording +will never be automatically deleted. Any number in the range \fB1...98\fR +means that this recording may not be automatically deleted in favour of a +new recording, until the given number of days since the \fBstart\fR time of +the recording has passed by. +.TP +.B File +The \fBfile name\fR this timer will give to a recording. +If the name contains any ':' characters, these have to be replaced by '|'. +If the name shall contain subdirectories, these have to be delimited by '~' +(since the '/' character may be part of a regular programme name). + +The special keywords \fBTITLE\fR and \fBEPISODE\fR, if present, will be replaced +by the title and episode information from the EPG data at the time of +recording (if that data is available). If at the time of recording either +of these cannot be determined, \fBTITLE\fR will default to the channel name, and +\fBEPISODE\fR will default to a blank. +.TP +.B Summary +Arbitrary text that describes the recording made by this timer. +Any newline characters in the summary have to be replaced by '|', and +the summary may contain ':' characters. If this field is not empty, its +contents will be written into the \fIsummary.vdr\fR file of the recording. +.SS CONDITIONAL ACCESS +The file \fIca.conf\fR defines the numbers to be used in the \fBConditional access\fR +field of channels in \fIchannels.conf\fR and assigns descriptive texts to them. +Example: + +\fB101 Premiere World\fR + +Anything after (and including) a '#' character is comment. + +Value lines consist of an integer number, followed by a text describing +this decryption method (typically the name of the pay tv service using this +decryption method). + +The special value \fB0\fR means \fBFree To Air\fR, which can be used for +channels that don't require additional decryption hardware. + +The values \fB1...4\fR can be used for channels that for some reason explicitly +need a given DVB card (for backward compatibility). +.SS KEYS +The file \fIkeys.conf\fR contains the key assignments for the remote control +unit (RCU). If \fBvdr\fR has been built with REMOTE=KBD, the file \fIkeys-pc.conf\fR +will be used instead. If you are using \fBvdr\fR together with \fBLIRC\fR, no +such file will be used. In that case you need to consult the \fBLIRC\fR +documentation to see how to set up the remote control key assignments there. +.SS COMMANDS +The file \fIcommands.conf\fR contains the definitions of commands that can +be executed from the \fBvdr\fR main menu's "Commands" option. +Each line contains one command definition in the following format: + +\fBtitle : command\fR + +where \fBtitle\fR is the string that will be displayed in the "Commands" menu, +and \fBcommand\fR is the actual command string that will be executed when this +option is selected. The delimiting ':' may be surrounded by any number of +white space characters. + +By default the menu entries in the "Commands" menu will be numbered '1'...'9' +to make them selectable by pressing the corresponding number key. If you want +to use your own numbering scheme (maybe to skip certain numbers), just precede +the \fBtitle\fRs with the numbers of your choice. \fBvdr\fR will suppress its +automatic numbering if the first entry in \fIcommands.conf\fR starts with a +digit in the range '1'...'9', followed by a blank. + +In order to avoid error messages to the console, every command should have +\fIstderr\fR redirected to \fIstdout\fR. Everything the command prints to +\fIstdout\fR will be displayed in a result window, with \fBtitle\fR as its title. + +Examples: + +Check for new mail: /usr/local/bin/checkmail 2>&1 +.br +CPU status : /usr/local/bin/cpustatus 2>&1 +.br +Disk space : df -h | grep '/video' | awk '{ print 100 - $5 "% free"; }' +.br +Calendar : date;echo;cal + +Note that the commands 'checkmail' and 'cpustatus' are only \fBexamples\fR! +Don't send emails to the author asking where to find these ;-) +.SS SVDRP HOSTS +The file \fIsvdrphosts.conf\fR contains the IP numbers of all hosts that are +allowed to access the SVDRP port. +Each line contains one IP number in the format + +\fBIP-Address[/Netmask]\fR + +where \fBIP-Address\fR is the address of a host or a network in the usual dot +separated notation (as in 192.168.100.1). If the optional \fBNetmask\fR is given +only the given number of bits of \fBIP-Address\fR are taken into account. This +allows you to grant SVDRP access to all hosts of an entire network. \fBNetmask\fR +can be any integer from 1 to 32. The special value of 0 is only accepted if +the \fBIP-Address\fR is 0.0.0.0, because this will give access to any host +(\fBUSE THIS WITH CARE!\fR). + +Everything following (and including) a '#' character is considered to be comment. + +Examples: + +127.0.0.1 # always accept localhost +.br +192.168.100.0/24 # any host on the local net +.br +204.152.189.113 # a specific host +.br +0.0.0.0/0 # any host on any net (\fBUSE WITH CARE!\fR) +.SS SETUP +The file \fIsetup.conf\fR contains the basic configuration options for \fBvdr\fR. +Each line contains one option in the format "Name = Value". +See the MANUAL file for a description of the available options. +.SS AUDIO/VIDEO DATA +The files \fI001.vdr\fR...\fI255.vdr\fR are the actual recorded MPEG data +files. In order to keep the size of an individual file below a given limit, +a recording is split into several files. The contents of these files is +\fBPacketized Elementary Stream\fR (PES) and contains ES packets with ids +0xE0 for video, 0xC0 for audio 1 and 0xC1 for audio 2 (if available). +Dolby Digital data is stored in packets with ids 0xBD. +.SS INDEX +The file \fIindex.vdr\fR (if present in a recording directory) contains +the (binary) index data into each of the the recording files +\fI001.vdr\fR...\fI255.vdr\fR. It is used during replay to determine +the current position within the recording, and to implement skipping +and fast forward/back functions. +See the definition of the \fBcIndexFile\fR class for details about the +actual contents of this file. +.SS SUMMARY +The file \fIsummary.vdr\fR (if present in a recording directory) contains +a description of the recording, derived from the EPG data at recording time +(if such data was available) or the \fBSummary\fR field of the corresponding +timer. This is a plain ASCII file and can contain arbitrary text. +.SS RESUME +The file \fIresume.vdr\fR (if present in a recording directory) contains +the position within the recording where the last replay session left off. +The data is a four byte (binary) integer value and defines an offset into +the file \fIindex.vdr\fR. +.SS MARKS +The file \fImarks.vdr\fR (if present in a recording directory) contains +the editing marks defined for this recording. +Each line contains the definition of one mark in the following format: + +\fBhh:mm:ss.ff comment\fR + +where \fBhh:mm:ss.ff\fR is a frame position within the recording, given as +"hours, minutes, seconds and (optional) frame number". +\fBcomment\fR can be any string and may be used to describe this mark. +If present, \fBcomment\fR must be separated from the frame position by at +least one blank. + +The lines in this file need not necessarily appear in the correct temporal +sequence, they will be automatically sorted by time index. + +\fBCURRENT RESTRICTIONS:\fR + +-\ the comment is currently not used by VDR +.br +-\ marks must have a frame number, and that frame MUST be an I-frame (this +means that only marks generated by VDR itself can be used, since they +will always be guaranteed to mark I-frames). +.SS EPG DATA +The file \fIepg.data\fR contains the EPG data in an easily parsable format. +The first character of each line defines what kind of data this line contains. + +The following tag characters are defined: +.TS +tab (@); +l l. +\fBC\fR@<service id> <channel name> +\fBE\fR@<event id> <start time> <duration> <table id> +\fBT\fR@<title> +\fBS\fR@<subtitle> +\fBD\fR@<description> +\fBe\fR@ +\fBc\fR@ +.TE + +Lowercase characters mark the end of a sequence that was started by the +corresponding uppercase character. The outer frame consists of a sequence +of one or more \fBC\fR...\fBc\fR (Channel) entries. Inside these any number of +\fBE\fR...\fBe\fR (Event) entries are allowed. +The \fBT\fR, \fBS\fR and \fBD\fR entries are optional (although every event +should at least have a \fBT\fR entry). + +.TS +tab (@); +l l. +<service id> @is the "program number" as defined in 'channels.conf' +<channel name> @is the "name" as in 'channels.conf' (for information only) +<start time> @is the time (as a time_t integer) in UTC when this event starts +<duration> @is the time (in seconds) that this event will take +<table id> @is a hex number that indicates the table this event is contained\ +in (if this is left empty or 0 this event will not be overwritten\ +or modified by data that comes from the DVB stream) +<title> @is the title of the event +<subtitle> @is the subtitle (typically the name of the episode etc.) +<description> @is the description of the event +.TE + +This file will be read at program startup in order to restore the results of +previous EPG scans. +.SH SEE ALSO +.BR vdr (1) +.SH AUTHOR +Written by Klaus Schmidinger. +.SH REPORTING BUGS +Report bugs to <vdr-bugs@cadsoft.de>. +.SH COPYRIGHT +Copyright \(co 2002 Klaus Schmidinger. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/vdr.c b/vdr.c index 17ae1488e..874e8264b 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.101 2002/03/09 17:10:16 kls Exp $ + * $Id: vdr.c 1.102 2002/03/29 10:09:20 kls Exp $ */ #include <getopt.h> @@ -101,6 +101,7 @@ int main(int argc, char *argv[]) { "record", required_argument, NULL, 'r' }, { "shutdown", required_argument, NULL, 's' }, { "terminal", required_argument, NULL, 't' }, + { "version", no_argument, NULL, 'V' }, { "video", required_argument, NULL, 'v' }, { "watchdog", required_argument, NULL, 'w' }, { NULL } @@ -108,7 +109,7 @@ int main(int argc, char *argv[]) int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:mp:r:s:t:v:w:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:mp:r:s:t:v:Vw:", long_options, &option_index)) != -1) { switch (c) { case 'a': cDvbApi::SetAudioCommand(optarg); break; @@ -139,7 +140,7 @@ int main(int argc, char *argv[]) " %s); use '-E-' to disable this\n" " if FILE is a directory, the default EPG file will be\n" " created in that directory\n" - " -h, --help display this help and exit\n" + " -h, --help print this help and exit\n" " -l LEVEL, --log=LEVEL set log level (default: 3)\n" " 0 = no logging, 1 = errors only,\n" " 2 = errors and info, 3 = errors, info and debug\n" @@ -149,6 +150,7 @@ int main(int argc, char *argv[]) " -r CMD, --record=CMD call CMD before and after a recording\n" " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" " -t TTY, --terminal=TTY controlling tty\n" + " -V, --version print version information and exit\n" " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n" " seconds (default: %d); '0' disables the watchdog\n" @@ -186,6 +188,9 @@ int main(int argc, char *argv[]) break; case 't': Terminal = optarg; break; + case 'V': printf("vdr, version %s\n", VDRVERSION); + return 0; + break; case 'v': VideoDirectory = optarg; while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') optarg[strlen(optarg) - 1] = 0; From c9a5d8ea5328e4a8bcb0c3423b825c02cb0c3b27 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Sun, 7 Apr 2002 18:00:00 +0200 Subject: [PATCH 040/307] Version 1.0.0 - Fixed a problem with wrong EPG data in the Schedules menu (thanks to Tobias Kerner, problem was initially reported by Michel Moster, but somehow I had misplaced his message...). - Added Spanish language texts (thanks to Ruben Nunez Francisco). - Fixed resetting the "First day" timer parameter once the timer actually starts recording. - Fixed the still picture workaround in case the progress display is active (thanks to Gerald Raaf). - Fixed a problem with accessing the epg.data file before it is fully written (thanks to Thilo Wunderlich for reporting this one). - Now the EPG scan skips channels that have their 'Ca' parameter explicitly set to an other DVB card (suggested by Sergei Haller). - Fixed a possible hangup when reading a broken epg.data file (thanks to Henning Holtschneider for pointing this one out). - Fixed a bug in the editing process in case a previously edited file with the same name was manually deleted on a system with more than one video directory (thanks to Dirk Wiebel for reporting this one). --- CONTRIBUTORS | 25 +++++++ HISTORY | 24 +++++- config.c | 6 +- config.h | 4 +- dvbapi.c | 34 +++++++-- eit.c | 16 ++-- eit.diff | 25 ------- i18n.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++---- menu.c | 12 ++- mpatrol.diff | 56 -------------- vdr.1 | 4 +- vdr.5 | 4 +- 12 files changed, 287 insertions(+), 126 deletions(-) delete mode 100644 eit.diff delete mode 100644 mpatrol.diff diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 6a126c9fb..ec742b188 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -88,6 +88,7 @@ Benjamin Reichardt <reichard@math.uni-goettingen.de> Henning Holtschneider <hh@holtschneider.com> for patching 'runvdr' to check whether the driver is already loaded for reporting a bug in parsing group separators in channels.conf + for pointing out a possible hangup when reading a broken epg.data file Paulo Lopes <pmml@netvita.pt> for translating OSD texts to the Portugese language @@ -186,6 +187,7 @@ Norbert Schmidt <nschmidt-nrw@t-online.de> Thilo Wunderlich <tw@ubcom.net> for his help in keeping 'channels.conf' up to date + for reporting a problem with accessing the epg.data file before it is fully written Stephan Schreiber <stephan@sschreiber.de> for his support in keeping the Premiere World channels up to date in 'channels.conf.cable' @@ -198,6 +200,8 @@ Sergei Haller <Sergei.Haller@math.uni-giessen.de> for fixing the LastActivity timestamp after a shutdown prompt for fixing the "Low disk space!" message for adding the TPID to Hessen-3 in 'channels.conf' + for suggesting that the EPG scan should skip channels with their 'Ca' parameter + explicitly set to an other DVB card Andreas Gebel <andreas@xcapenet.de> for his help in keeping 'channels.conf' up to date @@ -252,6 +256,27 @@ Truls Slevigen <truls@slevigen.no> Ruben Nunez Francisco <ruben.nunez@tang-it.com> for implementing FreeDiskSpaceMB() without external 'df' command + for translating OSD texts to the Spanish language + +Mirko Dlle <mdoelle@linux-user.de> + for reporting a bug when a timer records over midnight of a day that had a + change in Daylight Saving Time Michael Rakowski <mrak@gmx.de> for translating OSD texts to the Polish language + +Michael Moster <dvb@juelich-gmbh.de> + for initally reporting the problem with wrong EPG data in the Schedules menu + (somehow I had misplaced his message...) + +Tobias Kerner <tobschle@gmx.de> + for helping to debug a problem with wrong EPG data in the Schedules menu + +Dirk Wiebel <dirk@wiebel.de> + for reporting a bug in the editing process in case a previously edited file + with the same name was manually deleted on a system with more than one video + directory + +Gerald Raaf <graaf@attglobal.net> + for helping to fix the still picture workaround in case the progress display + is active diff --git a/HISTORY b/HISTORY index cafa4c1dd..af15667af 100644 --- a/HISTORY +++ b/HISTORY @@ -1151,7 +1151,7 @@ Video Disk Recorder Revision History commands.conf starts with a digit in the range '1'...'9', followed by a blank. - Fixed a bug in switching back the replay mode display in time shift mode (thanks to Achim Lange for reporting this one). -- Fixed a bug in the 'First day' timer parameter for timers that record over +- Fixed a bug in the "First day" timer parameter for timers that record over midnight. - Added units to Setup parameters. - Changed time entry in the 'Jump' command during replay, so that it is filled @@ -1161,7 +1161,7 @@ Video Disk Recorder Revision History - Fixed skipping the next hit of a repeating timer (thanks to Rainer Zocholl for reporting this one). - Fixed a bug when a timer records over midnight of a day that had a change in - Daylight Saving Time. + Daylight Saving Time (thanks to Mirko Dlle for reporting this one). - Added Polish language texts (thanks to Michael Rakowski). - Fixed a bug in parsing group separators in channels.conf (thanks to Henning Holtschneider for reporting this one). @@ -1170,3 +1170,23 @@ Video Disk Recorder Revision History the F-keys on top. - Fixed a bug in the EPG bugfix mechanism if the extended description is shorter than 3 characters (thanks to Andreas Schultz). + +2002-04-07: Version 1.0.0 + +- Fixed a problem with wrong EPG data in the Schedules menu (thanks to Tobias + Kerner, problem was initially reported by Michel Moster, but somehow I had + misplaced his message...). +- Added Spanish language texts (thanks to Ruben Nunez Francisco). +- Fixed resetting the "First day" timer parameter once the timer actually starts + recording. +- Fixed the still picture workaround in case the progress display is active + (thanks to Gerald Raaf). +- Fixed a problem with accessing the epg.data file before it is fully written + (thanks to Thilo Wunderlich for reporting this one). +- Now the EPG scan skips channels that have their 'Ca' parameter explicitly set + to an other DVB card (suggested by Sergei Haller). +- Fixed a possible hangup when reading a broken epg.data file (thanks to Henning + Holtschneider for pointing this one out). +- Fixed a bug in the editing process in case a previously edited file with the + same name was manually deleted on a system with more than one video directory + (thanks to Dirk Wiebel for reporting this one). diff --git a/config.c b/config.c index 7104dcc27..76e138b7e 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.96 2002/04/01 11:54:05 kls Exp $ + * $Id: config.c 1.97 2002/04/02 21:56:51 kls Exp $ */ #include "config.h" @@ -606,14 +606,14 @@ bool cTimer::Matches(time_t t) if ((!firstday || a >= firstday) && t <= b) { startTime = a; stopTime = b; - if (t >= firstday + SECSINDAY) - firstday = 0; break; } } } if (!startTime) startTime = firstday; // just to have something that's more than a week in the future + else if (t > startTime || t > firstday + SECSINDAY + 3600) // +3600 in case of DST change + firstday = 0; return active && startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers } diff --git a/config.h b/config.h index e7c01eb2b..00774b08f 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.107 2002/03/31 21:17:30 kls Exp $ + * $Id: config.h 1.109 2002/04/07 13:08:12 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "1.0.0pre5" +#define VDRVERSION "1.0.0" #define MAXPRIORITY 99 #define MAXLIFETIME 99 diff --git a/dvbapi.c b/dvbapi.c index d9906189d..9d59d900e 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.166 2002/03/29 11:32:47 kls Exp $ + * $Id: dvbapi.c 1.170 2002/04/07 09:35:51 kls Exp $ */ #include "dvbapi.h" @@ -1194,8 +1194,10 @@ void cReplayBuffer::DisplayFrame(uchar *b, int Length) CHECK(ioctl(videoDev, VIDEO_STILLPICTURE, &sp)); #else #define MIN_IFRAME 400000 - for (int i = MIN_IFRAME / Length + 1; i > 0; i--) + for (int i = MIN_IFRAME / Length + 1; i > 0; i--) { safe_write(videoDev, b, Length); + usleep(1); // allows the buffer to be displayed in case the progress display is active + } #endif } @@ -1612,6 +1614,18 @@ bool cVideoCutter::Start(const char *FileName) cRecording Recording(FileName); const char *evn = Recording.PrefixFileName('%'); if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { + // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c) + // remove a possible deleted recording with the same name to avoid symlink mixups: + char *s = strdup(evn); + char *e = strrchr(s, '.'); + if (e) { + if (strcmp(e, ".rec") == 0) { + strcpy(e, ".del"); + RemoveVideoFile(s); + } + } + delete s; + // XXX editedVersionName = strdup(evn); Recording.WriteSummary(); cuttingBuffer = new cCuttingBuffer(FileName, editedVersionName); @@ -2803,12 +2817,16 @@ void cEITScanner::Process(void) numTransponders = 0; } cChannel *Channel = Channels.GetByNumber(ch); - if (Channel && Channel->pnr && !TransponderScanned(Channel)) { - if (DvbApi == cDvbApi::PrimaryDvbApi && !currentChannel) - currentChannel = DvbApi->Channel(); - Channel->Switch(DvbApi, false); - lastChannel = ch; - break; + if (Channel) { + if (Channel->ca <= MAXDVBAPI && !DvbApi->ProvidesCa(Channel->ca)) + break; // the channel says it explicitly needs a different card + if (Channel->pnr && !TransponderScanned(Channel)) { + if (DvbApi == cDvbApi::PrimaryDvbApi && !currentChannel) + currentChannel = DvbApi->Channel(); + Channel->Switch(DvbApi, false); + lastChannel = ch; + break; + } } ch++; } diff --git a/eit.c b/eit.c index 4fc749bfa..b27fbc7a1 100644 --- a/eit.c +++ b/eit.c @@ -16,7 +16,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: eit.c 1.42 2002/04/01 12:58:20 kls Exp $ + * $Id: eit.c 1.44 2002/04/06 13:58:59 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -390,12 +390,12 @@ bool cEventInfo::Read(FILE *f, cSchedule *Schedule) case 'e': pEvent = NULL; break; case 'c': // to keep things simple we react on 'c' here - return false; + return true; default: esyslog(LOG_ERR, "ERROR: unexpected tag while reading EPG data: %s", s); return false; } } - return true; + esyslog(LOG_ERR, "ERROR: unexpected end of file while reading EPG data"); } return false; } @@ -754,8 +754,8 @@ bool cSchedule::Read(FILE *f, cSchedules *Schedules) if (1 == sscanf(s + 1, "%u", &uServiceID)) { cSchedule *p = (cSchedule *)Schedules->SetCurrentServiceID(uServiceID); if (p) { - while (cEventInfo::Read(f, p)) - ; // loop stops after having read the closing 'c' + if (!cEventInfo::Read(f, p)) + return false; } } } @@ -1090,10 +1090,10 @@ void cSIProcessor::Action() if (epgDataFileName && now - lastDump > 600) { cMutexLock MutexLock(&schedulesMutex); - FILE *f = fopen(GetEpgDataFileName(), "w"); - if (f) { + cSafeFile f(GetEpgDataFileName()); + if (f.Open()) { schedules->Dump(f); - fclose(f); + f.Close(); } else LOG_ERROR; diff --git a/eit.diff b/eit.diff deleted file mode 100644 index 57584b966..000000000 --- a/eit.diff +++ /dev/null @@ -1,25 +0,0 @@ -# This is a BitKeeper generated patch for the following project: -# Project Name: Linux VDR -# This patch format is intended for GNU patch command version 2.5 or higher. -# This patch includes the following deltas: -# ChangeSet 1.21 -> 1.22 -# eit.c 1.6 -> 1.7 -# -# The following is the BitKeeper ChangeSet Log -# -------------------------------------------- -# 02/04/01 aschultz@warp10.net 1.22 -# fix segfault in eit.c -# -------------------------------------------- -# -diff -Nru a/eit.c b/eit.c ---- a/eit.c Mon Apr 1 14:38:00 2002 -+++ b/eit.c Mon Apr 1 14:38:00 2002 -@@ -559,7 +559,7 @@ - pSubtitle = compactspace(pSubtitle); - pExtendedDescription = compactspace(pExtendedDescription); - // Remove superfluous hyphens: -- if (pExtendedDescription) { -+ if (pExtendedDescription && strlen(pExtendedDescription) >= 3) { - char *p = pExtendedDescription + 1; - while (*p) { - if (*p == '-' && *(p + 1) == ' ' && *(p + 2) && islower(*(p - 1)) && islower(*(p + 2))) { diff --git a/i18n.c b/i18n.c index 0ffbf4528..0b22f1ddc 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.78 2002/04/01 11:37:08 kls Exp $ + * $Id: i18n.c 1.79 2002/04/06 09:49:19 kls Exp $ * * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> and Matjaz Thaler <matjaz.thaler@guest.arnes.si> * Italian translations provided by Alberto Carraro <bertocar@tin.it> @@ -14,6 +14,7 @@ * Norwegian translations provided by Jrgen Tvedt <pjtvedt@online.no> and Truls Slevigen <truls@slevigen.no> * Finnish translations provided by Hannu Savolainen <hannu@opensound.com> * Polish translations provided by Michael Rakowski <mrak@gmx.de> + * Spanish translations provided by Ruben Nunez Francisco <ruben.nunez@tang-it.com> * */ @@ -62,7 +63,7 @@ #include "config.h" #include "tools.h" -const int NumLanguages = 10; +const int NumLanguages = 11; typedef const char *tPhrase[NumLanguages]; @@ -78,6 +79,7 @@ const tPhrase Phrases[] = { "Norsk", "Suomi", "Polski", + "Espaol", }, // Menu titles: { "VDR", @@ -90,6 +92,7 @@ const tPhrase Phrases[] = { "VDR", "VDR", "VDR", + "VDR", }, { "Schedule", "Programm", @@ -101,6 +104,7 @@ const tPhrase Phrases[] = { "Programmer", "Ohjelmat", "Program", + "Programa", }, { "Channels", "Kanle", @@ -112,6 +116,7 @@ const tPhrase Phrases[] = { "Kanaler", "Kanavat", "Kanaly", + "Canales", }, { "Timers", "Timer", @@ -123,6 +128,7 @@ const tPhrase Phrases[] = { "Timere", "Ajastin", "Timery", + "Timer", }, { "Recordings", "Aufzeichnungen", @@ -134,6 +140,7 @@ const tPhrase Phrases[] = { "Opptak", "Nauhoitteet", "Nagrania", + "Grabaciones", }, { "Setup", "Einstellungen", @@ -145,6 +152,7 @@ const tPhrase Phrases[] = { "Konfigurasjon", "Asetukset", "Nastawy", + "Configuracin", }, { "Commands", "Befehle", @@ -156,28 +164,31 @@ const tPhrase Phrases[] = { "Kommandoer", "Komennot", "Rozkazy", + "rdenes", }, - { "Edit Channel", - "Kanal Editieren", + { "Edit channel", + "Kanal editieren", "Uredi kanal", "Modifica canale", "Kanaal aanpassen", - "Modificar Canal", + "Modificar canal", "Modifier une chane", - "Editer Kanal", + "Editer kanal", "Muokkaa kanavaa", - "Ustawienie Kanalu", + "Ustawienie kanalu", + "Modificar canal", }, - { "Edit Timer", - "Timer Editieren", + { "Edit timer", + "Timer editieren", "Uredi termin", - "Modifica Timer", + "Modifica timer", "Timer veranderen", - "Modificar Timer", + "Modificar timer", "Changer la programmation", - "Editer Timer", + "Editer timer", "Muokkaa ajastusta", - "Ustawienie Timerow", + "Ustawienie timerow", + "Modificar timer", }, { "Event", "Sendung", @@ -189,6 +200,7 @@ const tPhrase Phrases[] = { "Hendelse", "Tapahtuma", "Audycja", + "Evento", }, { "Summary", "Inhalt", @@ -200,6 +212,7 @@ const tPhrase Phrases[] = { "Sammendrag", "Yhteenveto", "Zawartosc", + "Resmen", }, { "Schedule - %s", "Programm - %s", @@ -211,6 +224,7 @@ const tPhrase Phrases[] = { "Program Guide - %s", "Ohjelma - %s", "Program - %s", + "Programa - %s", }, { "What's on now?", "Was luft jetzt?", @@ -222,6 +236,7 @@ const tPhrase Phrases[] = { "Hvilket program sendes n?", "Nykyinen ohjelma", "Program biezacy", + "Qu hay ahora?", }, { "What's on next?", "Was luft als nchstes?", @@ -233,6 +248,7 @@ const tPhrase Phrases[] = { "Hvilket program er neste?", "Seuraava ohjelma", "Program nastepny", + "Qu hay proximo?", }, // Button texts (should not be more than 10 characters!): { "Edit", @@ -245,6 +261,7 @@ const tPhrase Phrases[] = { "Editer", "Muuta", "Edycja", + "Modificar", }, { "New", "Neu", @@ -256,6 +273,7 @@ const tPhrase Phrases[] = { "Ny", "Uusi", "Nowy", + "Nuevo", }, { "Delete", "Lschen", @@ -267,6 +285,7 @@ const tPhrase Phrases[] = { "Slett", "Poista", "Usunac", + "Borrar", }, { "Mark", "Markieren", @@ -278,6 +297,7 @@ const tPhrase Phrases[] = { "Marker", "Merkitse", "Zaznaczyc", + "Marcar", }, { "On/Off", "Ein/Aus", @@ -289,6 +309,7 @@ const tPhrase Phrases[] = { "Av/P", "Pll/Pois", "Zal./ Wyl.", + "On/Off", }, { "Record", "Aufnehmen", @@ -300,6 +321,7 @@ const tPhrase Phrases[] = { "Ta opp", "Nauhoita", "Nagrywac", + "Grabar", }, { "Play", "Wiedergabe", @@ -311,6 +333,7 @@ const tPhrase Phrases[] = { "Spill av", "Toista", "Odtwarzac", + "Play", }, { "Rewind", "Anfang", @@ -322,6 +345,7 @@ const tPhrase Phrases[] = { "Spol tilbake", "Takaisinkel.", "Poczatek", + "Rebobinar", }, { "Button$Stop", "Beenden", @@ -333,6 +357,7 @@ const tPhrase Phrases[] = { "Stopp", "Pysyt", "Zakonczyc", + "Parar", }, { "Resume", "Weiter", @@ -344,6 +369,7 @@ const tPhrase Phrases[] = { "Fortsett", "Jatka", "Dalej", + "Continuar", }, { "Summary", "Inhalt", @@ -355,6 +381,7 @@ const tPhrase Phrases[] = { "Sammendrag", "Yhteenveto", "Zawartosc", + "Resumen", }, { "Open", "ffnen", @@ -366,6 +393,7 @@ const tPhrase Phrases[] = { "pne", "Avaa", "Otworzyc", + "Abrir", }, { "Switch", "Umschalten", @@ -377,6 +405,7 @@ const tPhrase Phrases[] = { "Skift til", "Valitse", "Przelaczyc", + "Cambiar", }, { "Now", "Jetzt", @@ -388,6 +417,7 @@ const tPhrase Phrases[] = { "N", "Nyt", "Teraz", + "Ahora", }, { "Next", "Nchste", @@ -399,6 +429,7 @@ const tPhrase Phrases[] = { "Neste", "Seuraava", "Nastepny", + "Siguiente", }, { "Button$Schedule", "Programm", @@ -410,6 +441,7 @@ const tPhrase Phrases[] = { "Programmer", "Ohjelmisto", "Program", + "Programa", }, { "Language", "Sprache", @@ -421,6 +453,7 @@ const tPhrase Phrases[] = { "Sprk", "Kieli", "Jezyk", + "Lengua", }, { "Eject", "Auswerfen", @@ -432,6 +465,7 @@ const tPhrase Phrases[] = { "Eject", "Avaa", "Wyrzucenie", + "Eyectar", }, // Confirmations: { "Delete channel?", @@ -444,6 +478,7 @@ const tPhrase Phrases[] = { "Slette kanal?", "Poistetaanko kanava?", "Usunac kanal?", + "Eliminar canal?", }, { "Delete timer?", "Timer lschen?", @@ -455,6 +490,7 @@ const tPhrase Phrases[] = { "Slette timer?", "Poistetaanko ajastus?", "Usunac timer?", + "Eliminar timer?", }, { "Delete recording?", "Aufzeichnung lschen?", @@ -466,6 +502,7 @@ const tPhrase Phrases[] = { "Slette opptak?", "Poistetaanko nauhoitus?", "Usunac nagranie?", + "Eliminar grabacion?", }, { "Timer still recording - really delete?", "Timer zeichnet auf - trotzdem lschen?", @@ -477,6 +514,7 @@ const tPhrase Phrases[] = { "Timer gjr opptak - vil du slette likevel?", "Ajastin nauhoittaa - poistetaanko silti?", "Nagrywanie w trakcie - napewno usunac?", + "Timer activo - de verdad eliminarlo?", }, { "Stop recording?", "Aufzeichnung beenden?", @@ -488,6 +526,7 @@ const tPhrase Phrases[] = { "Stoppe opptak?", "Pysytetnk nauhoitus?", "Zakonczyc nagranie?", + "Parar grabacin?", }, { "on primary interface", "auf dem primren Interface", @@ -499,6 +538,7 @@ const tPhrase Phrases[] = { "p frste enhet", "pvastaanottimella", "na pierwszym interfejsie", + "en interface primario", }, { "Cancel editing?", "Schneiden abbrechen?", @@ -510,6 +550,7 @@ const tPhrase Phrases[] = { "Avbryte redigering?", "Peruutetaanko muokkaus?", "Zakonczyc montaz?", + "Cancelar modificacin?", }, { "Really restart?", "Wirklich neu starten?", @@ -521,6 +562,7 @@ const tPhrase Phrases[] = { "Vil du virkelig starte p nytt?", "Aloitetaanko varmasti alusta?", "Rzeczywiscie nowy start?", + "De verdad reiniciar?", }, { "Recording - restart anyway?", "Aufnahme luft - trotzdem neu starten?", @@ -532,6 +574,7 @@ const tPhrase Phrases[] = { "Gjr opptak - starte p nytt likevel?", "Nauhoitus kynniss - aloitetaanko alusta?", "Nagrywanie w trakcie - rzeczywiscie nowy start?", + "Grabando - reiniciar?", }, { "Recording - shut down anyway?", "Aufnahme luft - trotzdem ausschalten?", @@ -543,6 +586,7 @@ const tPhrase Phrases[] = { "Gjr opptak - sl av likevel?", "Nauhoitus kesken - lopetetaanko se?", "Nagrywanie w trakcie - mimo to wylaczyc?", + "Grabando - apagar?", }, { "Recording in %d minutes, shut down anyway?", "Aufnahme in %d Minuten - trotzdem ausschalten?", @@ -554,6 +598,7 @@ const tPhrase Phrases[] = { "Skal gjre opptak om %d minutter - sl av likevel?", "Nauhoitus alkaisi %d min. kuluttua - sammutetaanko silti?", "Nagrywanie za %d minut - mimo to wylaczyc?", + "Grabando en %d minutos, de verdad cortar?", }, { "Press any key to cancel shutdown", "Taste drcken um Shutdown abzubrechen", @@ -565,6 +610,7 @@ const tPhrase Phrases[] = { "Trykk en tast for ikke sl av", "Peruuta pysytys painamalla jotakin nppint", "Dowolny przycisk zatrzyma wylaczanie", + "Pulse una tecla para interrumpir corte", }, // Channel parameters: { "Name", @@ -577,6 +623,7 @@ const tPhrase Phrases[] = { "Navn", "Nimi", "Nazwa", + "Nombre", }, { "Frequency", "Frequenz", @@ -588,6 +635,7 @@ const tPhrase Phrases[] = { "Frekvens", "Taajuus", "Czestotliwosc", + "Frecuencia", }, { "Polarization", "Polarisation", @@ -599,6 +647,7 @@ const tPhrase Phrases[] = { "Polarisasjon", "Polarisaatio", "Polaryzacja", + "Polarizacin", }, { "DiSEqC", "DiSEqC", @@ -610,6 +659,7 @@ const tPhrase Phrases[] = { "DiSEqC", "DiSEqC", "DiSEqC", + "DiSEqC", }, { "Srate", "Srate", @@ -621,6 +671,7 @@ const tPhrase Phrases[] = { "Srate", "Srate", "Srate", + "Srate", }, { "Vpid", "Vpid", @@ -632,6 +683,7 @@ const tPhrase Phrases[] = { "Vpid", "Kuva PID", "Vpid", + "Vpid", }, { "Apid1", "Apid1", @@ -643,6 +695,7 @@ const tPhrase Phrases[] = { "Apid1", "ni PID1", "Apid1", + "Apid1", }, { "Apid2", "Apid2", @@ -654,6 +707,7 @@ const tPhrase Phrases[] = { "Apid2", "ni PID2", "Apid2", + "Apid2", }, { "Dpid1", "Dpid1", @@ -665,6 +719,7 @@ const tPhrase Phrases[] = { "AC3pid1", "AC3 PID1", "Dpid1", + "Dpid1", }, { "Dpid2", "Dpid2", @@ -676,6 +731,7 @@ const tPhrase Phrases[] = { "AC3pid2", "AC3 PID2", "Dpid2", + "Dpid2", }, { "Tpid", "Tpid", @@ -687,6 +743,7 @@ const tPhrase Phrases[] = { "Tekst-TV pid", "TekstiTV PID", "Tpid", + "Tpid", }, { "CA", "CA", @@ -698,6 +755,7 @@ const tPhrase Phrases[] = { "Kortleser", "Salauskortti", "CA", + "CA", }, { "Pnr", "Pnr", @@ -709,6 +767,7 @@ const tPhrase Phrases[] = { "Program Id", "Ohjelmatunnus", "Pnr", + "Pnr", }, // Timer parameters: { "Active", @@ -721,6 +780,7 @@ const tPhrase Phrases[] = { "Aktiv", "Aktiivinen", "Aktywny", + "Activo", }, { "Channel", "Kanal", @@ -732,6 +792,7 @@ const tPhrase Phrases[] = { "Kanal", "Kanava", "Kanal", + "Canal", }, { "Day", "Tag", @@ -743,6 +804,7 @@ const tPhrase Phrases[] = { "Dag", "Piv", "Dzien", + "Da", }, { "Start", "Anfang", @@ -754,6 +816,7 @@ const tPhrase Phrases[] = { "Start", "Aloitus", "Poczatek", + "Comienzo", }, { "Stop", "Ende", @@ -765,6 +828,7 @@ const tPhrase Phrases[] = { "Slutt", "Lopetus", "Koniec", + "Fin", }, { "Priority", "Prioritt", @@ -776,6 +840,7 @@ const tPhrase Phrases[] = { "Prioritet", "Prioriteetti", "Priorytet", + "Prioridad", }, { "Lifetime", "Lebensdauer", @@ -787,6 +852,7 @@ const tPhrase Phrases[] = { "Levetid", "Voimassaolo", "Trwalosc dni", + "Durabilidad", }, { "File", "Datei", @@ -798,6 +864,7 @@ const tPhrase Phrases[] = { "Filnavn", "Tiedosto", "Plik", + "Fichero", }, { "First day", "Erster Tag", @@ -809,6 +876,7 @@ const tPhrase Phrases[] = { "Frste dag", "1. piv", "Pierwszy dzien", + "Primer da", }, // Error messages: { "Channel is being used by a timer!", @@ -821,6 +889,7 @@ const tPhrase Phrases[] = { "Kanalen er i bruk av en timer!", "Kanava on ajastimen kytss!", "Kanal jest zajety przez timer nagran", + "Canal est ocupado por un timer!", }, { "Can't switch channel!", "Kanal kann nicht umgeschaltet werden!", @@ -832,6 +901,7 @@ const tPhrase Phrases[] = { "Ikke mulig skifte kanal!", "Kanavan vaihtaminen ei mahdollista!", "Kanal nie moze byc teraz przelaczony!", + "No puedo cambiar canal!", }, { "Timer is recording!", "Timer zeichnet gerade auf!", @@ -843,9 +913,10 @@ const tPhrase Phrases[] = { "Timer gjr opptak!", "Ajastinnauhoitus kynniss!", "Timer nagrywa!", + "Timer esta grabando!", }, { "Error while accessing recording!", - "Fehler beim ansprechen der Aufzeichnung!", + "Fehler beim Ansprechen der Aufzeichnung!", "Napaka pri dostopu do posnetka", "Errore nel tentativo di acc alla registrazione", "Fout bij lezen opname!", @@ -854,6 +925,7 @@ const tPhrase Phrases[] = { "Feil under lesing av opptak!", "Nauhoituksen toistaminen eponnistui!", "Blad - brak dostepu do nagrania!", + "Error al accesar la grabacin!", }, { "Error while deleting recording!", "Fehler beim Lschen der Aufzeichnung!", @@ -865,6 +937,7 @@ const tPhrase Phrases[] = { "Feil under sletting av opptak!", "Nauhoituksen poistaminen eponnistui!", "Blad przy usuwaniu nagrania!", + "Error al borrar la grabacin!", }, { "*** Invalid Channel ***", "*** Ungltiger Kanal ***", @@ -876,6 +949,7 @@ const tPhrase Phrases[] = { "*** Ugyldig Kanal! ***", "*** Virheellinen kanavavalinta! ***", "*** Niewazny kanal ***", + "*** Canal invlido ***", }, { "No free DVB device to record!", "Keine freie DVB-Karte zum Aufnehmen!", @@ -887,6 +961,7 @@ const tPhrase Phrases[] = { "Ingen ledige DVB enheter for opptak!", "Ei vapaata vastaanotinta nauhoitusta varten!", "Brak wolnej karty DVB do nagrywania!", + "No hay dispositivo DVB disponible para grabar!", }, { "Channel locked (recording)!", "Kanal blockiert (zeichnet auf)!", @@ -898,6 +973,7 @@ const tPhrase Phrases[] = { "Kanalen er lst (opptak)!", "Kanava lukittu (nauhoitusta varten)!", "Kanal zablokowany (nagrywanie w toku)!", + "Canal bloqueado (grabando)!", }, { "Can't start Transfer Mode!", "Transfer-Mode kann nicht gestartet werden!", @@ -909,6 +985,7 @@ const tPhrase Phrases[] = { "Kan ikke starte transfer modus!", "Ksittmttmi teknisi ongelmia!", "Tryb transferowy jest niemozliwy!", + "No puedo iniciar modo de transferencia!", }, { "Can't start editing process!", "Schnitt kann nicht gestartet werden!", @@ -920,6 +997,7 @@ const tPhrase Phrases[] = { "Kan ikke starte redigeringsprosessen!", "Muokkauksen aloittaminen ei onnistu!", "Uruchamianie montazu jest niemozliwe!", + "No puedo iniciar proceso de modificacin!", }, { "Editing process already active!", "Schnitt bereits aktiv!", @@ -931,6 +1009,7 @@ const tPhrase Phrases[] = { "Redigeringsprosessen er allerede aktiv!", "Muokkaus on jo kynniss!", "Montaz w toku!", + "Proceso de modificacin ya fue iniciado!", }, { "Can't shutdown - option '-s' not given!", "Shutdown unmglich - Option '-s' fehlt!", @@ -942,6 +1021,7 @@ const tPhrase Phrases[] = { "Kan ikke sl av - startet uten parameteret '-s'!", "Ei voida sammuttaa '-s' parametria ei annettu!", "Wylaczenie niemozliwe - brak opcji '-s' !", + "No puedo cortar - opcin '-s' absente!", }, { "Low disk space!", "Platte beinahe voll!", @@ -953,6 +1033,7 @@ const tPhrase Phrases[] = { "Lite ledig diskplass!", "Kovalevy lhes tynn!", "Dysk wkrotce pelny!", + "Disco casi lleno", }, // Setup pages: { "OSD", @@ -965,6 +1046,7 @@ const tPhrase Phrases[] = { "OSD", "Tekstinytt", "OSD", + "OSD", }, { "EPG", "EPG", @@ -976,6 +1058,7 @@ const tPhrase Phrases[] = { "Programoversikt", "Ohjelmaopas", "EPG", + "EPG", }, { "DVB", "DVB", @@ -987,6 +1070,7 @@ const tPhrase Phrases[] = { "DVB-enheter", "DVB", "DVB", + "DVB", }, { "LNB", "LNB", @@ -998,6 +1082,7 @@ const tPhrase Phrases[] = { "LNB", "LNB", "LNB", + "LNB", }, { "CICAM", "CICAM", @@ -1009,6 +1094,7 @@ const tPhrase Phrases[] = { "CICAM", "CICAM", "CICAM", + "CICAM", }, { "Recording", "Aufnahme", @@ -1020,6 +1106,7 @@ const tPhrase Phrases[] = { "Opptak", "Nauhoita", "Nagranie", + "Grabacin", }, { "Replay", "Wiedergabe", @@ -1031,6 +1118,7 @@ const tPhrase Phrases[] = { "Spill av", "Toista", "Odtwarzanie", + "Poner", }, { "Miscellaneous", "Sonstiges", @@ -1042,6 +1130,7 @@ const tPhrase Phrases[] = { "Forskjellig", "Sekalaista", "Pozostale", + "Varios", }, { "Restart", "Neustart", @@ -1053,6 +1142,7 @@ const tPhrase Phrases[] = { "Start p nytt", "Aloita uudelleen", "Zastartowac", + "Reiniciar", }, // Setup parameters: { "Setup.OSD$Language", @@ -1065,6 +1155,7 @@ const tPhrase Phrases[] = { "Sprk", "Kieli", "Jezyk", + "Lengua", }, { "Setup.OSD$Width", "Breite", @@ -1076,6 +1167,7 @@ const tPhrase Phrases[] = { "Bredde", "Leveys", "Szerokosc", + "Anchura", }, { "Setup.OSD$Height", "Hhe", @@ -1087,6 +1179,7 @@ const tPhrase Phrases[] = { "Hyde", "Korkeus", "Wysokosc", + "Altura", }, { "Setup.OSD$Message time (s)", "Anzeigedauer fr Nachrichten (s)", @@ -1098,6 +1191,7 @@ const tPhrase Phrases[] = { "Tid meldinger skal vises (s)", "Ilmoitusten nkymisaika (s)", "Czas wyswietlania wiadomosci (s)", + "Duracin muestra mensajes (s)", }, { "Setup.OSD$Channel info position", "Kanal-Info Position", @@ -1109,6 +1203,7 @@ const tPhrase Phrases[] = { "Posisjon p kanalinformasjon", "Kanavainfon sijainti", "Lokalizacja informacji o kanale", + "Posicin para informacin canal", }, { "Setup.OSD$Info on channel switch", "Info beim Kanalwechsel", @@ -1120,6 +1215,7 @@ const tPhrase Phrases[] = { "Info ved kanalskifte", "Nyt kanavainfo", "Informacja przy zmianie kanalu", + "Informacin para cambio de canal", }, { "Setup.OSD$Scroll pages", "Seitenweise scrollen", @@ -1131,6 +1227,7 @@ const tPhrase Phrases[] = { "Rask rulling i menyer", "Valikkojen rullaus", "Przesuwac stronami", + "Desplazar pgina entera", }, { "Setup.OSD$Sort timers", "Timer sortieren", @@ -1142,9 +1239,10 @@ const tPhrase Phrases[] = { "Sorter timere", "Jrjest ajastimet", "Sortowanie timerow", + "Ordenar timer", }, { "Setup.OSD$Recording directories", - "Aufnahme Verzeichnisse", + "Aufnahmeverzeichnisse", "Direktoriji za posnetke", "Directory di registrazione", "Opname directories", @@ -1153,6 +1251,7 @@ const tPhrase Phrases[] = { "Kataloger til opptak", "Nauhoitushakemistot", "Wykaz nagran", + "Directorios para grabacin", }, { "Setup.EPG$EPG scan timeout (h)", "Zeit bis EPG Scan (h)", @@ -1164,6 +1263,7 @@ const tPhrase Phrases[] = { "Ledig tid fr EPG-sk (h)", "Ohjelmatied. odotusaika (h)", "Czas do skanu EPG (h)", + "Tiempo hasta exploracin EPG (h)", }, { "Setup.EPG$EPG bugfix level", "EPG Fehlerbereinigung", @@ -1175,6 +1275,7 @@ const tPhrase Phrases[] = { "Niv for EPG-feilretting", "EPG Bugfix Level", "Poziom bledow EPG", + "Nivel para arreglar EPG", }, { "Setup.EPG$Set system time", "Systemzeit stellen", @@ -1186,6 +1287,7 @@ const tPhrase Phrases[] = { "Juster system-klokken", "Vastaanota kellonaika", "Ustawianie czasu", + "Ajustar reloj de sistema", }, { "Setup.EPG$Use time from transponder", "Transponder fr Systemzeit", @@ -1197,6 +1299,7 @@ const tPhrase Phrases[] = { "Bruk klokke fra transponder", "Vastaanota kellonaika lhettimelt", "Transponder do ustawiania czasu", + "Transponder para reloj de sistema", }, { "Setup.DVB$Primary DVB interface", "Primres DVB Interface", @@ -1208,6 +1311,7 @@ const tPhrase Phrases[] = { "Hoved DVB-enhet", "Ensisij. vast.otin", "Pierwotny interfejs DVB", + "Primer interface DVB", }, { "Setup.DVB$Video format", "Video Format", @@ -1219,6 +1323,7 @@ const tPhrase Phrases[] = { "TV-Format", "Kuvamuoto", "Format telewizyjny", + "Formato Vdeo", }, { "Setup.LNB$SLOF (MHz)", "SLOF (MHz)", @@ -1230,6 +1335,7 @@ const tPhrase Phrases[] = { "LO-grensefrekvens (MHz)", "SLOF (MHz)", "SLOF (MHz)", + "SLOF (MHz)", }, { "Setup.LNB$Low LNB frequency (MHz)", "Untere LNB-Frequenz (MHz)", @@ -1241,6 +1347,7 @@ const tPhrase Phrases[] = { "LO-frekvens i lavbndet (MHz)", "LO LNB taajuus (MHz)", "Dolna czestotliwosc LNB (MHz)", + "Frecuencia baja LNB (MHz)", }, { "Setup.LNB$High LNB frequency (MHz)", "Obere LNB-Frequenz (MHz)", @@ -1252,6 +1359,7 @@ const tPhrase Phrases[] = { "LO-frekvens i hybndet (MHz)", "HI LNB taajuus (MHz)", "Gorna czestotliwosc LNB (MHz)", + "Frecuencia alta LNB (MHz)", }, { "Setup.LNB$Use DiSEqC", "DiSEqC benutzen", @@ -1263,6 +1371,7 @@ const tPhrase Phrases[] = { "Bruk DiSEqC", "Kyt DiSEqC", "Uzywac DiSEqC", + "Utilizar DiSEqC", }, { "Setup.CICAM$CICAM DVB", "CICAM DVB", @@ -1274,6 +1383,7 @@ const tPhrase Phrases[] = { "CICAM DVB", "CICAM DVB", "CICAM DVB", + "CICAM DVB", }, { "Setup.Recording$Margin at start (min)", "Zeitpuffer bei Anfang (min)", @@ -1285,6 +1395,7 @@ const tPhrase Phrases[] = { "Opptaksmargin start (min)", "Aloitusmarginaali (min)", "Poczatkowy czas buforowy (min)", + "Comenzar grabacin antes (min)", }, { "Setup.Recording$Margin at stop (min)", "Zeitpuffer bei Ende (min)", @@ -1296,6 +1407,7 @@ const tPhrase Phrases[] = { "Opptaksmargin slutt (min)", "Lopetusmarginaali (min)", "Koncowy czas buforowy (min)", + "Cortar grabacin despus (min)", }, { "Setup.Recording$Primary limit", "Primr-Limit", @@ -1307,6 +1419,7 @@ const tPhrase Phrases[] = { "Prioritetsgrense HovedDVB", "PrimaryLimit", "Pierwotny limit", + "L'mite primario", }, { "Setup.Recording$Default priority", "Default Prioritt", @@ -1318,6 +1431,7 @@ const tPhrase Phrases[] = { "Normal prioritet (Timer)", "Oletusprioriteetti", "Priorytet pierwotny", + "Prioridad predefinida", }, { "Setup.Recording$Default lifetime (d)", "Default Lebensdauer (d)", @@ -1329,6 +1443,7 @@ const tPhrase Phrases[] = { "Normal levetid timer (d)", "Oletus voimassaoloaika (d)", "Pierwotna trwalosc (d)", + "Duracin predefinida", }, { "Setup.Recording$Use episode name", "Episodenname verwenden", @@ -1340,6 +1455,7 @@ const tPhrase Phrases[] = { "Bruk episodenavn", "Kyt jakson nime", "Czy uzywac nazwe epizodu", + "Utilizar nombre de episodo", }, { "Setup.Recording$Mark instant recording", "Direktaufzeichnung markieren", @@ -1351,6 +1467,7 @@ const tPhrase Phrases[] = { "Markere direkteopptak", "Merkitse vlitn nauh.", "Zaznaczyc natychm. nagranie", + "Marcar grabaciones instantneas", }, { "Setup.Recording$Name instant recording", "Direktaufzeichnung benennen", @@ -1362,6 +1479,7 @@ const tPhrase Phrases[] = { "Navngi direkteopptak", "Nime vlitn nauh.", "Nazwac natychm. nagranie", + "Nombrar grabaciones instantneas", }, { "Setup.Recording$Record Dolby Digital", "Dolby Digital Ton aufzeichnen", @@ -1373,6 +1491,7 @@ const tPhrase Phrases[] = { "Ta opp Dolby Digital lyd", "Dolby Digital nauhoitus", "Nagrywac Dolby Digital", + "Grabar sonido Dolby Digital", }, { "Setup.Recording$Max. video file size (MB)", "Max. Video Dateigre (MB)", @@ -1384,6 +1503,7 @@ const tPhrase Phrases[] = { "Maksimal strrelse p videofiler (MB)", "Maksimi tiedoston koko (MB)", "Maks. wielkosc pliku (MB)", + "Tamao mx. ficheros (MB)", }, { "Setup.Recording$Split edited files", "Editierte Dateien aufteilen", @@ -1395,6 +1515,7 @@ const tPhrase Phrases[] = { "Splitt redigerte filer", "Paloittele muokatut", "Dzielic montowane pliki", + "Quebrar ficheros", }, { "Setup.Replay$Multi speed mode", "MultiSpeed Modus", @@ -1406,6 +1527,7 @@ const tPhrase Phrases[] = { "Multispeed modus", "Moninopeustila", "Tryb wielopredkosciowy", + "Modo multi-velocidad", }, { "Setup.Replay$Show replay mode", "Wiedergabestatus anzeigen", @@ -1417,6 +1539,7 @@ const tPhrase Phrases[] = { "Vis avspillingsmodus", "Nyt toiston tila", "Wyswietlac status odtwarzania", + "Mostrar modo de replay", }, { "Setup.Miscellaneous$Min. event timeout (min)", "Mindest Event Pause (min)", @@ -1428,6 +1551,7 @@ const tPhrase Phrases[] = { "Minste hendelsespause (min)", "Minimi tapahtuman odotus (min)", "Min. czas do nast. akcji (Event) (min)", + "Tiempo mnimo pausa (min)", }, { "Setup.Miscellaneous$Min. user inactivity (min)", "Mindest Benutzer-Inaktivitt (min)", @@ -1439,6 +1563,7 @@ const tPhrase Phrases[] = { "Minimumstid med inaktivitet (min)", "Minimi kyttjn odotus (min)", "Min. brak aktywnosci uzytkownika (min)", + "Tiempo mnimo inactividad (min)", }, { "Setup.Miscellaneous$SVDRP timeout (min)", "SVDRP Timeout (min)", @@ -1450,6 +1575,7 @@ const tPhrase Phrases[] = { "Ubrukt SVDRP-levetid (min)", "SVDRP odotusaika (min)", "Min. brak aktywnosci SVDRP (min)", + "SVDRP interrupcin (min)", }, // The days of the week: { "MTWTFSS", @@ -1462,6 +1588,7 @@ const tPhrase Phrases[] = { "MTOTFLS", "MTKTPLS", "PWSCPSN", + "LMMJVSD", }, { "MonTueWedThuFriSatSun", // must all be 3 letters! "MonDieMitDonFreSamSon", @@ -1473,6 +1600,7 @@ const tPhrase Phrases[] = { "ManTirOnsTorFreLrSn", "MaaTiiKesTorPerLauSun", "PonWtoSroCzwPiaSobNie", + "LunMarMieJueVieSabDom", }, // Learning keys: { "Learning Remote Control Keys", @@ -1485,6 +1613,7 @@ const tPhrase Phrases[] = { "Lre fjernkontrolltaster", "Kaukostimen nppinten opettelu", "Nauka kodu pilota", + "Aprendiendo teclas del telemando", }, { "Phase 1: Detecting RC code type", "Phase 1: FB Code feststellen", @@ -1496,6 +1625,7 @@ const tPhrase Phrases[] = { "Fase 1: Finne fjernkontroll-kodetype", "Vaihe 1: Lhetystavan selvittminen", "Faza 1: Detekcja typu kodu", + "Fase 1: Detectando tipo de receptor", }, { "Press any key on the RC unit", "Eine Taste auf der FB drcken", @@ -1507,6 +1637,7 @@ const tPhrase Phrases[] = { "Trykk en av tastene p fjernkontrollen", "Paina mit tahansa kaukostimen nppint", "Nacisnac klawisz pilota", + "Pulse una tecla en el telemando", }, { "RC code detected!", "FB Code erkannt!", @@ -1518,6 +1649,7 @@ const tPhrase Phrases[] = { "Fjernkontroll-kodetype funnet!", "Nppinpainallus vastaanotettu!", "Kod pilota zostal poznany!", + "Cdigo detectado!", }, { "Do not press any key...", "Keine Taste drcken...", @@ -1529,6 +1661,7 @@ const tPhrase Phrases[] = { "Ikke trykk p noen av tastene...", "l paina mitn nppint...", "Nie naciskac klawiszy...", + "No pulse tecla...", }, { "Phase 2: Learning specific key codes", "Phase 2: Einzelne Tastencodes lernen", @@ -1540,6 +1673,7 @@ const tPhrase Phrases[] = { "Fase 2: Lre spesifikke tastekoder", "Vaihe 2: Nppinkoodien opettelu", "Faza 2: Nauka pojedynczych klawiszy", + "Fase 2: Aprendiendo cdigos especficos", }, { "Press key for '%s'", "Taste fr '%s' drcken", @@ -1551,6 +1685,7 @@ const tPhrase Phrases[] = { "Trykk tasten for '%s'", "Paina nppint toiminnolle '%s'", "Nacisnac klawisz dla '%s'", + "Pulsar tecla para '%s'", }, { "Press 'Up' to confirm", "'Auf' drcken zum Besttigen", @@ -1562,6 +1697,7 @@ const tPhrase Phrases[] = { "Trykk 'Opp' for bekrefte", "Paina 'Yls' hyvksyksesi", "Nacisnac 'Gora' do potwierdzenia", + "Pulse 'Arriba' para confirmar", }, { "Press 'Down' to continue", "'Ab' drcken zum Weitermachen", @@ -1573,6 +1709,7 @@ const tPhrase Phrases[] = { "Trykk Ned' for fortsette", "Paina 'Alas' jatkaaksesi", "Nacisnac 'Dol' zeby kontynuowac", + "Pulse 'Abajo' para confirmar", }, { "(press 'Up' to go back)", "('Auf' drcken um zurckzugehen)", @@ -1584,6 +1721,7 @@ const tPhrase Phrases[] = { "(trykk 'Opp' for g tilbake)", "(paina 'Yls' palataksesi takaisin)", "(Nacisnac 'Gora' cofa)", + "(Pulse 'Arriba' para retornar)", }, { "(press 'Down' to end key definition)", "('Ab' drcken zum Beenden)", @@ -1595,6 +1733,7 @@ const tPhrase Phrases[] = { "(trykk 'Ned' for avslutte innlring)", "(paina 'Alas' lopettaaksesi nppinten opettelun)", "(Nacisnac 'Dol' by zakonczyc)", + "(Pulse 'Abajo' para terminar programacin teclas)", }, { "Phase 3: Saving key codes", "Phase 3: Codes abspeichern", @@ -1606,6 +1745,7 @@ const tPhrase Phrases[] = { "Fase 3: Lagre tastekoder", "Vaihe 3: Nppinkoodien tallettaminen", "Faza 3: Zapamietac Kod", + "Fase 3: Guardar cdigos de teclas", }, { "Press 'Up' to save, 'Down' to cancel", "'Auf' speichert, 'Ab' bricht ab", @@ -1617,6 +1757,7 @@ const tPhrase Phrases[] = { "Trykk 'Opp' for lagre, 'Ned' for avbryte", "Paina 'Yls' tallettaaksesi ja 'Alas' peruuttaaksesi", "'Gora' zapamietuje, 'Dol' przerywa", + "Pulse 'Arriba' para guarder, 'Abajo' para anular", }, // Key names: { "Up", @@ -1629,6 +1770,7 @@ const tPhrase Phrases[] = { "Opp", "Yls", "Gora", + "Arriba", }, { "Down", "Ab", @@ -1640,6 +1782,7 @@ const tPhrase Phrases[] = { "Ned", "Alas", "Dol", + "Abajo", }, { "Menu", "Men", @@ -1651,6 +1794,7 @@ const tPhrase Phrases[] = { "Meny", "Valikko", "Menu", + "Menu", }, { "Ok", "Ok", @@ -1662,6 +1806,7 @@ const tPhrase Phrases[] = { "Ok", "Ok", "Ok", + "Ok", }, { "Back", "Zurck", @@ -1673,6 +1818,7 @@ const tPhrase Phrases[] = { "Tilbake", "Takaisin", "Wstecz", + "Retornar", }, { "Left", "Links", @@ -1684,6 +1830,7 @@ const tPhrase Phrases[] = { "Venstre", "Vasemmalle", "Lewo", + "Izquierda", }, { "Right", "Rechts", @@ -1695,6 +1842,7 @@ const tPhrase Phrases[] = { "Hyre", "Oikealle", "Prawo", + "Derecha", }, { "Red", "Rot", @@ -1706,6 +1854,7 @@ const tPhrase Phrases[] = { "Rd", "Punainen", "Czerwony", + "Rojo", }, { "Green", "Grn", @@ -1717,6 +1866,7 @@ const tPhrase Phrases[] = { "Grnn", "Vihre", "Zielony", + "Verde", }, { "Yellow", "Gelb", @@ -1728,6 +1878,7 @@ const tPhrase Phrases[] = { "Gul", "Keltainen", "Zolty", + "Amarillo", }, { "Blue", "Blau", @@ -1739,6 +1890,7 @@ const tPhrase Phrases[] = { "Bl", "Sininen", "Niebieski", + "Azul", }, { "Power", "Ausschalten", @@ -1750,6 +1902,7 @@ const tPhrase Phrases[] = { "Power", "Virtakytkin", "Wylaczyc", + "Corriente", }, { "Volume+", "Lautstrke+", @@ -1761,6 +1914,7 @@ const tPhrase Phrases[] = { "Volum+", "nenvoimakkuus+", "Glosnej", + "Volumen+", }, { "Volume-", "Lautstrke-", @@ -1772,6 +1926,7 @@ const tPhrase Phrases[] = { "Volum-", "nenvoimakkuus-", "Ciszej", + "Volumen-", }, { "Mute", "Stumm", @@ -1783,6 +1938,7 @@ const tPhrase Phrases[] = { "Lyd av", "nen vaimennus", "Cisza", + "Mudo", }, // Miscellaneous: { "yes", @@ -1795,6 +1951,7 @@ const tPhrase Phrases[] = { "ja", "kyll", "tak", + "s", }, { "no", "nein", @@ -1806,6 +1963,7 @@ const tPhrase Phrases[] = { "nei", "ei", "nie", + "no", }, { "top", "oben", @@ -1817,6 +1975,7 @@ const tPhrase Phrases[] = { "vre", "yl", "gora", + "parte sup.", }, { "bottom", "unten", @@ -1828,6 +1987,7 @@ const tPhrase Phrases[] = { "nedre", "ala", "dol", + "fondo", }, { "Disk", "Disk", @@ -1839,6 +1999,7 @@ const tPhrase Phrases[] = { "Disk", "Disk", "Disk", + "Disco", }, { "free", "frei", @@ -1850,6 +2011,7 @@ const tPhrase Phrases[] = { "ledig", "vapaa", "pozostalo", + "libre", }, { "Jump: ", // note the trailing blank "Springen: ", @@ -1861,6 +2023,7 @@ const tPhrase Phrases[] = { "Hopp: ", "Hypp: ", "Skok: ", + "Saltar: ", }, { "Volume ", // note the trailing blank "Lautstrke ", @@ -1872,6 +2035,7 @@ const tPhrase Phrases[] = { "Volum ", "nenvoimakkuus ", "Glosnosc ", + "Volumen ", }, { " Stop replaying", // note the leading blank! " Wiedergabe beenden", @@ -1883,6 +2047,7 @@ const tPhrase Phrases[] = { " Stopp avspilling", " Pysyt toisto", " Zatrzymac odtwarzanie", + " Parar reproducin", }, { " Stop recording ", // note the leading and trailing blanks! " Aufzeichnung beenden ", @@ -1894,6 +2059,7 @@ const tPhrase Phrases[] = { " Stopp opptak fra ", " Pysyt nauhoitus ", " Zatrzymac nagrywanie ", + " Parar grabacin ", }, { " Cancel editing", // note the leading blank! " Schneiden abbrechen", @@ -1905,6 +2071,7 @@ const tPhrase Phrases[] = { " Avbryt redigering", " Peruuta muokkaus", " Przerwac montaz ", + " Anular modificacin ", }, { "Switching primary DVB...", "Primres Interface wird umgeschaltet...", @@ -1916,6 +2083,7 @@ const tPhrase Phrases[] = { "Bytter frste DVB-enhet..." "Vaihdetaan ensisijainen vastaanotin...", "Pierwszy interfejs DVB przelacza...", + "Cambio interface primario...", }, { "Up/Dn for new location - OK to move", "Auf/Ab fr neue Position - dann OK", @@ -1927,6 +2095,7 @@ const tPhrase Phrases[] = { "Opp/Ned for ny plass - OK for flytte", "Yls/Alas = liiku, OK = siirr", "Gora/Dol na nowa pozycje - Ok zmienia", + "Arriba/Abajo para nuevo lugar - OK para mover", }, { "Editing process started", "Schnitt gestartet", @@ -1938,6 +2107,7 @@ const tPhrase Phrases[] = { "Redigeringsprosess startet", "Muokkaus aloitettu", "Uruchomiony proces montazu", + "Proceso modificacin iniciado", }, { "Editing process finished", "Schnitt beendet", @@ -1949,6 +2119,7 @@ const tPhrase Phrases[] = { "Redigeringsprosess avsluttet", "Muokkaus lopetettu", "Proces montazu zakonczony", + "Proceso modificacion terminado", }, { "Editing process failed!", "Schnitt gescheitert!", @@ -1960,6 +2131,7 @@ const tPhrase Phrases[] = { "Feil under redigering!", "Muokkaus eponnistui!", "Bledny proces montazu!", + "Modificacin ha fallado!", }, { "scanning recordings...", "Aufzeichnungen werden durchsucht...", @@ -1971,6 +2143,7 @@ const tPhrase Phrases[] = { "Gr igjennom opptakene...", "haetaan nauhoituksia...", "Skan nagran...", + "buscando grabaciones...", }, { NULL } }; diff --git a/menu.c b/menu.c index 03dbcea34..bc3aeb6e5 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.180 2002/03/31 21:17:42 kls Exp $ + * $Id: menu.c 1.182 2002/04/06 09:41:59 kls Exp $ */ #include "menu.h" @@ -694,7 +694,7 @@ class cMenuEditChannel : public cOsdMenu { }; cMenuEditChannel::cMenuEditChannel(int Index) -:cOsdMenu(tr("Edit Channel"), 14) +:cOsdMenu(tr("Edit channel"), 14) { channel = Channels.Get(Index); if (channel) { @@ -1070,7 +1070,7 @@ class cMenuEditTimer : public cOsdMenu { }; cMenuEditTimer::cMenuEditTimer(int Index, bool New) -:cOsdMenu(tr("Edit Timer"), 12) +:cOsdMenu(tr("Edit timer"), 12) { firstday = NULL; timer = Timers.Get(Index); @@ -1539,6 +1539,7 @@ class cMenuSchedule : public cOsdMenu { void PrepareSchedule(cChannel *Channel); public: cMenuSchedule(void); + virtual ~cMenuSchedule(); virtual eOSState ProcessKey(eKeys Key); }; @@ -1556,6 +1557,11 @@ cMenuSchedule::cMenuSchedule(void) } } +cMenuSchedule::~cMenuSchedule() +{ + cMenuWhatsOn::ScheduleEventInfo(); // makes sure any posted data is cleared +} + static int CompareEventTime(const void *p1, const void *p2) { return (int)((*(cEventInfo **)p1)->GetTime() - (*(cEventInfo **)p2)->GetTime()); diff --git a/mpatrol.diff b/mpatrol.diff deleted file mode 100644 index 59497c44c..000000000 --- a/mpatrol.diff +++ /dev/null @@ -1,56 +0,0 @@ -# This is a BitKeeper generated patch for the following project: -# Project Name: Linux VDR -# This patch format is intended for GNU patch command version 2.5 or higher. -# This patch includes the following deltas: -# ChangeSet 1.20 -> 1.21 -# config.c 1.4 -> 1.5 -# tools.c 1.2 -> 1.3 -# -# The following is the BitKeeper ChangeSet Log -# -------------------------------------------- -# 02/04/01 aschultz@warp10.net 1.21 -# fix memory management due to MPatrol -# -------------------------------------------- -# -diff -Nru a/config.c b/config.c ---- a/config.c Mon Apr 1 14:37:48 2002 -+++ b/config.c Mon Apr 1 14:37:48 2002 -@@ -265,7 +265,7 @@ - sscanf(apidbuf, "%d ,%d ", &apid1, &apid2); - if (p) - sscanf(p, "%d ,%d ", &dpid1, &dpid2); -- delete apidbuf; -+ free(apidbuf); - } - else - return false; -@@ -277,7 +277,7 @@ - tpid = 0; - } - strn0cpy(name, buffer, MaxChannelName); -- delete buffer; -+ free(buffer); - } - else - return false; -diff -Nru a/tools.c b/tools.c ---- a/tools.c Mon Apr 1 14:37:48 2002 -+++ b/tools.c Mon Apr 1 14:37:48 2002 -@@ -71,7 +71,7 @@ - esyslog(LOG_ERR, "ERROR: out of memory"); - } - else { -- delete dest; -+ free(dest); - dest = NULL; - } - return dest; -@@ -230,7 +230,7 @@ - const char *AddDirectory(const char *DirName, const char *FileName) - { - static char *buf = NULL; -- delete buf; -+ free(buf); - asprintf(&buf, "%s/%s", DirName && *DirName ? DirName : ".", FileName); - return buf; - } diff --git a/vdr.1 b/vdr.1 index 1fd39df6e..b26a9dff5 100644 --- a/vdr.1 +++ b/vdr.1 @@ -8,9 +8,9 @@ .\" License as specified in the file COPYING that comes with the .\" vdr distribution. .\" -.\" $Id: vdr.1 1.2 2002/03/29 10:10:04 kls Exp $ +.\" $Id: vdr.1 1.3 2002/04/07 13:11:43 kls Exp $ .\" -.TH vdr 1 "29 Mar 2002" "1.0.0" "Video Disk Recorder" +.TH vdr 1 "7 Apr 2002" "1.0.0" "Video Disk Recorder" .SH NAME vdr - the Video Disk Recorder .SH SYNOPSIS diff --git a/vdr.5 b/vdr.5 index 483e15ffe..b440f12be 100644 --- a/vdr.5 +++ b/vdr.5 @@ -8,9 +8,9 @@ .\" License as specified in the file COPYING that comes with the .\" vdr distribution. .\" -.\" $Id: vdr.5 1.3 2002/04/01 12:32:59 kls Exp $ +.\" $Id: vdr.5 1.4 2002/04/07 13:12:04 kls Exp $ .\" -.TH vdr 5 "29 Mar 2002" "1.0.0" "Video Disk Recorder Files" +.TH vdr 5 "7 Apr 2002" "1.0.0" "Video Disk Recorder Files" .SH NAME vdr file formats - the Video Disk Recorder Files .SH DESCRIPTION From ae8a947367b4be57c9b0ca7bbf0032de0e2018d3 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger <kls (at) cadsoft (dot) de> Date: Thu, 9 May 2002 18:00:00 +0200 Subject: [PATCH 041/307] Version 1.1.0 - Begin of the 1.1 development branch. THIS IS NOT A STABLE VERSION! The current stable version for every day use is still the 1.0 branch. - First step towards a universal plugin interface. See the file PLUGINS.html for a detailed description. The man page vdr(1) describes the new options '-L' and '-P' used to load plugins. This first step implements the complete "outer" shell for plugins. The "inner" access to VDR data structures will follow. - The VDR version number is now displayed in the title line of the "Setup" menu. --- CONTRIBUTORS | 55 +++- HISTORY | 66 +++- MANUAL | 21 +- Makefile | 28 +- PLUGINS.html | 620 +++++++++++++++++++++++++++++++++++++ PLUGINS/SRC/hello/COPYING | 340 ++++++++++++++++++++ PLUGINS/SRC/hello/HISTORY | 6 + PLUGINS/SRC/hello/Makefile | 78 +++++ PLUGINS/SRC/hello/README | 11 + PLUGINS/SRC/hello/hello.c | 105 +++++++ PLUGINS/SRC/hello/i18n.c | 52 ++++ PLUGINS/SRC/hello/i18n.h | 11 + channels.conf | 125 ++++---- channels.conf.cable | 291 ++++++++--------- channels.conf.terr | 9 + config.c | 377 +++++++++++++--------- config.h | 43 ++- dvbapi.c | 33 +- dvbapi.h | 4 +- dvbosd.c | 5 +- i18n.c | 414 ++++++++++++++++++++++--- i18n.h | 20 +- interface.h | 3 +- menu.c | 611 ++++++++---------------------------- menu.h | 8 +- menuitems.c | 476 ++++++++++++++++++++++++++++ menuitems.h | 110 +++++++ newplugin | 250 +++++++++++++++ osd.c | 11 +- osd.h | 4 +- plugin.c | 319 +++++++++++++++++++ plugin.h | 81 +++++ recording.c | 6 +- remote.h | 4 +- ringbuffer.c | 66 ++-- tools.c | 8 +- vdr.1 | 24 +- vdr.c | 133 +++++--- 38 files changed, 3797 insertions(+), 1031 deletions(-) create mode 100644 PLUGINS.html create mode 100644 PLUGINS/SRC/hello/COPYING create mode 100644 PLUGINS/SRC/hello/HISTORY create mode 100644 PLUGINS/SRC/hello/Makefile create mode 100644 PLUGINS/SRC/hello/README create mode 100644 PLUGINS/SRC/hello/hello.c create mode 100644 PLUGINS/SRC/hello/i18n.c create mode 100644 PLUGINS/SRC/hello/i18n.h create mode 100644 menuitems.c create mode 100644 menuitems.h create mode 100755 newplugin create mode 100644 plugin.c create mode 100644 plugin.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index ec742b188..b6bd60ae0 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,4 +1,7 @@ -Thanks go to the following people for patches and contributions: +Tons of suggestions, bugreports, patches and other contributions have been +provided by the people on the 'linux-dvb' and 'vdr' mailing lists. +Special thanks go to the following individuals (if your name is missing here, +please send an email to kls@cadsoft.de): Carsten Koch <Carsten.Koch@icem.de> for adding LIRC support @@ -9,6 +12,7 @@ Carsten Koch <Carsten.Koch@icem.de> for implementing the 'new recording' indicator for suggesting that the "Back" button in replay mode should bring up the "Recordings" menu for fixing the watchdog timer if the program hangs in OSD activities + for his support in keeping the Premiere World channels up to date in 'channels.conf' Plamen Ganev <pganev@com-it.net> for fixing the frequency offset for Hotbird channels @@ -28,7 +32,7 @@ Guido Fiala <gfiala@s.netic.de> now does these things itself) for making the replay progress display avoid unnecessary code execution -Robert Schneider <Robert.Schneider@lotus.com> +Robert Schneider <Robert.Schneider@de.ibm.com> for implementing EIT support for displaying the current/next info for extending EIT support to implement a complete EPG @@ -117,6 +121,13 @@ Stefan Huelswitt <huels@iname.com> for implementing backtracing for fast forward/rewind for implementing the replay mode display for fixing a crash when replaying with DEBUG_OSD=1 + for fixing a crash when selecting the "Jump" function directly after setting + an editing mark + for reporting a possible endless loop in shifting recordings between DVB cards + for making it no longer setting PIDs 0x1FFF, which apparently fixes problems + with CAMs and AC3 sound only working the first time + for making the main loop take an active video cutting process into account when + doing shutdown or housekeeping Ulrich Rder <roeder@efr-net.de> for pointing out that there are channels that have a symbol rate higher than @@ -157,6 +168,8 @@ Werner Fink <werner@suse.de> for helping to debug leftover 'zombie' processes when closing a pipe for making the Dolby Digital thread start only if the recording actually contains Dolby Digital data + for improving thread locking in the ring buffer to avoid possible race conditions + under heavy load Rolf Hakenes <hakenes@hippomi.de> for providing 'libdtv' and adapting the EIT mechanisms to it @@ -185,7 +198,7 @@ Thomas Heiligenmann <thomas@heiligenmann.de> Norbert Schmidt <nschmidt-nrw@t-online.de> for filling in some missing teletext PIDs -Thilo Wunderlich <tw@ubcom.net> +Thilo Wunderlich <wunderlich@speedway.org> for his help in keeping 'channels.conf' up to date for reporting a problem with accessing the epg.data file before it is fully written @@ -202,6 +215,8 @@ Sergei Haller <Sergei.Haller@math.uni-giessen.de> for adding the TPID to Hessen-3 in 'channels.conf' for suggesting that the EPG scan should skip channels with their 'Ca' parameter explicitly set to an other DVB card + for implementing enhanced string editing with upper-/lowercase, insert/overwrite + and delete Andreas Gebel <andreas@xcapenet.de> for his help in keeping 'channels.conf' up to date @@ -280,3 +295,37 @@ Dirk Wiebel <dirk@wiebel.de> Gerald Raaf <graaf@attglobal.net> for helping to fix the still picture workaround in case the progress display is active + for his support in keeping the Premiere World channels up to date in 'channels.conf' + +Andreas Roedl <flood@flood-net.de> + for adding some DVB-T channels for Berlin (Germany) to channels.conf.terr + +Jean Martin <mac_j_fr@hotmail.com> + for pointing out a problem with OSD color palette handling on "big endian" systems + +Steffen Koch <Steffen.Koch@koch-enterprises.de> + for reporting a crash when selecting the "Jump" function directly after setting + an editing mark + +Matthias Hilbig <hilbig@upb.de> + for fixing some missing ',' in i18n.c + +Simon Dean <linux-dvb@sickhack.com> + for reporting a problem with '.' at the end of a directory name in case of VFAT=1 + (Windows can't handle these) + +Dimitrios Dimitrakos <mail@dimitrios.de> + for translating OSD texts to the Greek language + +Marcus Kuba <marcus@kuba4u.de> + for reporting a bug in the unit of the "SVDRP timeout" setup parameter + +Ulrich Petri <ulope@gmx.de> + for his help in debugging a crash on systems with disks that have a block size + larger than 1MB + +Oliver Lorei <oliverlorei@cityweb.de> + for his support in keeping the Premiere World channels up to date in 'channels.conf.cable' + +Andreas Bttger <fboettger@t-online.de> + for reporting a bug in skipping forward in time shift mode near the end of the recording diff --git a/HISTORY b/HISTORY index af15667af..6599534e8 100644 --- a/HISTORY +++ b/HISTORY @@ -1,7 +1,9 @@ Video Disk Recorder Revision History ------------------------------------ -2000-02-19: Version 0.01 (Initial revision). +2000-02-19: Version 0.01 + +- Initial revision. 2000-03-11: Version 0.02 @@ -1190,3 +1192,65 @@ Video Disk Recorder Revision History - Fixed a bug in the editing process in case a previously edited file with the same name was manually deleted on a system with more than one video directory (thanks to Dirk Wiebel for reporting this one). + +2002-04-21: Version 1.0.1 + +- Added some DVB-T channels for Berlin (Germany) to channels.conf.terr (thanks to + Andreas Roedl). +- Implemented enhanced string editing with upper-/lowercase, insert/overwrite + and delete (thanks to Sergei Haller). +- Fixed color palette handling on "big endian" systems (thanks to Jean Martin + for pointing out this one). +- Updated the "Blue Movie" channels to the new "Premiere Erotik" (thanks to + Thilo Wunderlich). NOTE: this adds a new channel to 'channels.conf', so that + any timers referencing a channel with a number higher than 102 should be + checked and adapted if necessary (this only applies if you are using the default + 'channels.conf'). +- Improved thread locking in the ring buffer to avoid possible race conditions + under heavy load (thanks to Werner Fink). +- Fixed a crash when selecting the "Jump" function directly after setting an + editing mark (thanks to Steffen Koch for reporting and Stefan Huelswitt for + fixing this one). +- Fixed some missing ',' in i18n.c (thanks to Matthias Hilbig). +- Fixed a possible endless loop in shifting recordings between DVB cards (thanks + to Stefan Huelswitt for reporting this one). +- Updated the Premiere World Formula 1 channels in 'channels.conf' (thanks to Mel + Schchner). +- No longer setting PIDs 0x1FFF, which apparently fixes problems with CAMs and + AC3 sound only working the first time (thanks to Stefan Huelswitt). +- Now encoding '.' at the end of a directory name in case of VFAT=1, since Windows + can't handle these (thanks to Simon Dean for reporting this one). + +2002-05-05: Version 1.0.2 + +- Now taking an active video cutting process into account when doing shutdown or + housekeeping (thanks to Stefan Huelswitt). +- The default duration of an instant recording has been increased to 3 hours and + is now configurable in the "Setup/Recording" menu. +- Added Greek language texts (thanks to Dimitrios Dimitrakos). +- Fixed the unit of the "SVDRP timeout" setup parameter (thanks to Marcus Kuba + for reporting this one). +- Fixed a crash on systems with disks that have a block size larger than 1MB + (thanks to Ulrich Petri for helping to debug this one). +- Updated 'channels.conf' for the new PW settings (thanks to Andreas Share, + Carsten Koch, Gerald Raaf and Mel Schchner). Note that all channels with numbers + over 50 may have moved, so you should carefully check any timers you have set! +- Updated 'channels.conf.cable' for the new PW settings (thanks to Oliver Lorei + Stephan Schreiber and Uwe Scheffler). Note that all channels may have moved, so + you should carefully check any timers you have set! + For future updates of this file somebody with digital cable should take the role + of the "maintainer" and send me updated versions based on the file that comes + with the most recent version of VDR. I will then simply replace the entire file + 'channels.conf.cable' whenever a new version is sent to me. +- Fixed skipping forward in time shift mode near the end of the recording (thanks + to Andreas Bttger for reporting this one). + +2002-05-09: Version 1.1.0 + +- Begin of the 1.1 development branch. THIS IS NOT A STABLE VERSION! + The current stable version for every day use is still the 1.0 branch. +- First step towards a universal plugin interface. See the file PLUGINS.html + for a detailed description. The man page vdr(1) describes the new options '-L' + and '-P' used to load plugins. This first step implements the complete "outer" + shell for plugins. The "inner" access to VDR data structures will follow. +- The VDR version number is now displayed in the title line of the "Setup" menu. diff --git a/MANUAL b/MANUAL index b94050512..978713180 100644 --- a/MANUAL +++ b/MANUAL @@ -17,9 +17,9 @@ Video Disk Recorder User's Manual Ok Ch display Select Switch Edit Accept Play Progress disp. Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on Back - Menu off VDR menu VDR menu Discard VDR menu Recordings menu - Red - Record Edit Edit - Play Jump - Green - Language New New - Rewind Skip -60s - Yellow - - Delete Delete - Delete Skip +60s + Red - Record Edit Edit ABC/abc Play Jump + Green - Language New New Ins/Ovr Rewind Skip -60s + Yellow - - Delete Delete Delete Delete Skip +60s Blue - Stop/Resume Mark On/Off(1) - Summary Stop 0..9 Ch select - - - Numeric inp. - Editing @@ -58,11 +58,10 @@ Video Disk Recorder User's Manual by pressing the "Right" button (which puts brackets around the current character as in "[R]TL"), selecting the desired character position with "Left" and "Right", and changing the character with the "Up" and "Down" - keys. "Ok" then confirms the changes. The special character '^' can be used - to "cut off" a string at this position. When this character is visible in the - brackets (as in abc[^]), the next press to the "Left" or "Ok" button will - actually cut off the string. Using "Up" and/or "Down" brings back the - original rest of the string (unless you have pressed "Left" or "Ok"). + keys. "Ok" then confirms the changes. The "Red" key toggles between + upper- and lowercase characters, while the "Green" key switches between + insert and overwrite mode. The "Yellow" key deletes the current character + (or the one to the right of the cursor in insert mode). The "Red", "Green", "Yellow" and "Blue" buttons have special meanings in various menus and are listed at the bottom of the on-screen-display. @@ -519,6 +518,12 @@ Video Disk Recorder User's Manual If this parameter is empty, the channel name will be used by default. + Instant rec. time = 180 + Defines the duration of an instant recording in minutes. + Default is 180 minutes (3 hours). The stop time of an + instant recording can be modified at any time by editing + the respective timer in the "Timers" menu. + Record Dolby Digital = yes Turns recording of the Dolby Digital audio channels on or off. This may be useful if you don't have the equipment diff --git a/Makefile b/Makefile index 62fd8973b..55a01e875 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.33 2002/04/01 12:50:48 kls Exp $ +# $Id: Makefile 1.34 2002/05/09 09:35:05 kls Exp $ .DELETE_ON_ERROR: @@ -13,15 +13,17 @@ DTVDIR = ./libdtv MANDIR = /usr/local/man BINDIR = /usr/local/bin +PLUGINDIR= ./PLUGINS + VIDEODIR = /video INCLUDES = -I$(DVBDIR)/ost/include DTVLIB = $(DTVDIR)/libdtv.a -OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o osd.o\ - recording.o remote.o remux.o ringbuffer.o svdrp.o thread.o tools.o vdr.o\ - videodir.o +OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o\ + menuitems.o osd.o plugin.o recording.o remote.o remux.o ringbuffer.o\ + svdrp.o thread.o tools.o vdr.o videodir.o OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1 @@ -69,7 +71,7 @@ include $(DEPFILE) # The main program: vdr: $(OBJS) $(DTVLIB) - g++ -g -O2 $(OBJS) $(NCURSESLIB) -ljpeg -lpthread $(LIBDIRS) $(DTVLIB) -o vdr + g++ -g -O2 -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(DTVLIB) -o vdr # The font files: @@ -88,6 +90,21 @@ genfontfile: genfontfile.c $(DTVLIB) $(DTVDIR)/libdtv.h: make -C $(DTVDIR) all +# The 'include' directory (for plugins): + +include-dir: + @mkdir -p include/vdr + @(cd include/vdr; for i in ../../*.h; do ln -fs $$i .; done) + +# Plugins: + +plugins: include-dir + @for i in `ls $(PLUGINDIR)/SRC | grep -v '[^a-z0-9]'`; do make -C "$(PLUGINDIR)/SRC/$$i" all; done + +plugins-clean: + @for i in `ls $(PLUGINDIR)/SRC | grep -v '[^a-z0-9]'`; do make -C "$(PLUGINDIR)/SRC/$$i" clean; done + @-rm -f $(PLUGINDIR)/lib/* + # Install the files: install: @@ -104,6 +121,7 @@ install: clean: make -C $(DTVDIR) clean -rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~ + -rm -rf include fontclean: -rm -f fontfix.c fontosd.c CLEAN: clean fontclean diff --git a/PLUGINS.html b/PLUGINS.html new file mode 100644 index 000000000..b903f040d --- /dev/null +++ b/PLUGINS.html @@ -0,0 +1,620 @@ +<html> +<head> +<title>The VDR Plugin System + + + +

The VDR Plugin System

+ +VDR provides an easy to use plugin interface that allows additional functionality +to be added to the program by implementing a dynamically loadable library file. +This interface allows programmers to develop additional functionality for VDR completely +separate from the core VDR source, without the need of patching the original +VDR code (and all the problems of correlating various patches). +

+This document describes the "outside" interface of the plugin system. +It handles everything necessary for a plugin to get hooked into the core +VDR program and present itself to the user. + + + +


Quick start

+ +
Can't wait, can't wait!

+ +Actually you should read this entire document before starting to work with VDR plugins, +but you probably want to see something happening right away ;-) +

+So, for a quick demonstration of the plugin system, there is a demo plugin called +"hello" that comes with the VDR source. To test drive this one, do the following: +

    +
  • change into the VDR source directory +
  • make the VDR program with your usual REMOTE=... (and maybe other) options +
  • do make plugins to build the demo plugin +
  • run VDR with vdr -V to see the version information +
  • run VDR with vdr -h to see the command line options +
  • run VDR with vdr -Phello +
  • open VDR's main menu and select the Hello item +
  • open the Setup menu from VDR's main menu and select Plugins +
+If you enjoyed this brief glimpse into VDR plugin handling, read through the rest of +this document and eventually write your own VDR plugin. + +

The name of the plugin

+ +
Give me some I.D.!

+ +One of the first things to consider when writing a VDR plugin is giving the thing +a proper name. This name will be used in the VDR command line in order to load +the plugin, and will also be the name of the plugin's source directory, as well +as part of the final library name. +

+The plugin's name should typically be as short as possible. Three letter +abbreviations like dvd (for a DVD player) or mp3 +(for an MP3 player) would be good choices. It is also recommended that the name +consists of only lowercase letters and digits. +No other characters should be used here. +

+A plugin can access its name through the (non virtual) member function + +


+const char *Name(void); +

+ +The actual name is derived from the plugin's library file name, as defined in the +next chapter. + +


The plugin directory structure

+ +
Where is everybody?

+ +By default plugins are located in a directory named PLUGINS below the +VDR source directory. Inside this directory the following subdirectory structure +is used: + +


+VDR/PLUGINS/SRC +VDR/PLUGINS/SRC/demo +VDR/PLUGINS/SRC/hello +VDR/PLUGINS/lib +VDR/PLUGINS/lib/libvdr-demo.so.1.1.0 +VDR/PLUGINS/lib/libvdr-hello.so.1.1.0 +

+ +The SRC directory contains one subdirectory for each plugin, which carries +the name of that plugin (in the above example that would be demo and +hello, respectively). What's inside the individual source directory of a +plugin is entirely up to the author of that plugin. The only prerequisites are +that there is a Makefile that provides the targets all and +clean, and that a call to make all actually produces a dynamically +loadable library file for that plugin (we'll get to the details later). +

+The lib directory contains the dynamically loadable libraries of all +available plugins. Note that the names of these files are created by concatenating +

+ + + +
libvdr-demo.so.1.1.0
VDR plugin
library prefix
name of
the plugin
shared object
indicator
VDR version number
this plugin was
compiled for
+

+The plugin library files can be stored in any directory. If the default organization +is not used, the path to the plugin directory has be be given to VDR through the +-L option. +

+The VDR Makefile contains the target plugins, which calls +make all in every directory found under VDR/PLUGINS/SRC, +plus the target plugins-clean, which calls make clean in +each of these directories. +

+If you download a plugin package +from the web, it will typically have a name like +

+vdr-demo-0.0.1.tgz +

+and will unpack into a directory named +

+vdr-demo-0.0.1 +

+To use the plugins and plugins-clean targets from the VDR Makefile +you need to unpack such an archive into the VDR/PLUGINS/SRC directory and +create a symbolic link with the basic plugin name, as in + +


+ln -s vdr-demo-0.0.1 demo +

+ +Since the VDR Makefile only searches for directories with names consisting +of only lowercase characters and digits, it will only follow the symbolic links, which +should lead to the current version of the plugin you want to use. This way you can +have several different versions of a plugin source (like vdr-demo-0.0.1 and +vdr-demo-0.0.2) and define which one to actually use through the symbolic link. + +


Initializing a new plugin directory

+ +
A room with a view

+ +Call the Perl script newplugin from the VDR source directory to create +a new plugin directory with a Makefile and a main source file implementing +the basic derived plugin class. +You will also find a README file there with some inital text, where you +should fill in actual information about your project. +A HISTORY file is set up with an "Initial revision" entry. As your project +evolves, you should add the changes here with date and version number. +

+newplugin also creates a copy of the GPL license file COPYING, +assuming that you will release your work under that license. Change this if you +have other plans. +

+Add further files and maybe subdirectories to your plugin source directory as +necessary. Don't forget to adapt the Makefile appropriately. + +


The actual implementation

+ +
Use the source, Luke!

+ +A newly initialized plugin doesn't really do very much yet. +If you load it into VDR you will find a new +entry in the main menu, with the same name as your plugin (where the first character +has been converted to uppercase). There will also be a new entry named "Plugins" in +the "Setup" menu, which will bring up a list of all loaded plugins, through which you +can access each plugin's own setup parameters (if it provides any). +

+To implement actual functionality into your plugin you need to edit the source file +that was generated as PLUGINS/SRC/name.c. Read the comments in that file +to see where you can bring in your own code. The following sections of this document +will walk you through the individual member functions of the plugin class. +

+Depending on what your plugin shall do, you may or may not need all of the given +member functions. Except for the MainMenuEntry() function they all by default +return values that will result in no actual functionality. You can either completely +delete unused functions from your source file, or just leave them as they are. +If your plugin shall not be accessible through VDR's main menu, simply remove +(or comment out) the line implementing the MainMenuEntry() function. +

+At the end of the plugin's source file you will find a line that looks like this: + +


+VDRPLUGINCREATOR(cPluginDemo); +

+ +This is the "magic" hook that allows VDR to actually load the plugin into +its memory. You don't need to worry about the details behind all this. +

+If your plugin requires additional source files, simply add them to your plugin's +source directory and adjust the Makefile accordingly. + +


Construction and Destruction

+ +
What goes up, must come down...

+ +The constructor and destructor of a plugin are defined as + +


+cPlugin(void); +virtual ~cPlugin(); +

+ +The constructor shall initialize any member variables the plugin defines, but +must not access any global structures of VDR. +It also must not create any threads or other large data structures. These things +are done in the Start() function later. +Constructing a plugin object shall not have any side effects or produce any output, +since VDR, for instance, has to create the plugin objects in order to get their +command line help - and after that immediately destroys them again. +

+The destructor has to clean up any data created by the plugin, and has to +take care that any threads the plugin may have created will be stopped. +

+Of course, if your plugin doesn't define any member variables that need to be +initialized (and deleted), you don't need to implement either of these functions. + +


Version number

+ +
Which incarnation is this?

+ +Every plugin must have a version number of its own, which does not necessarily +have to be in any way related to the VDR version number. +VDR requests a plugin's version number through a call to the function + +


+virtual const char *Version(void) = 0; +

+ +Since this is a "pure" virtual function, any derived plugin class must +implement it. The returned string should identify this version of the plugin. +Typically this would be something like "0.0.1", but it may also contain other +information, like for instance "0.0.1pre2" or the like. The string should only +be as long as really necessary, and shall not contain the plugin's name itself. +Here's an example: + +


+static const char *VERSION = "0.0.1"; + +... + +const char *cPluginDemo::Version(void) +{ + return VERSION; +} +

+ +Note that the definition of the version number is expected to be located in the +main source file, and must be written as +

+static const char *VERSION = ...
+
+just like shown in the above example. This is a convention that allows the Makefile +to extract the version number when generating the file name for the distribution archive. +

+A new plugin project should start with version number 0.0.1 and should reach +version 1.0.0 once it is completely operative and well tested. Following the +Linux kernel version numbering scheme, versions with even release numbers +(like 1.0.x, 1.2.x, 1.4.x...) should be stable releases, +while those with odd release numbers (like 1.1.x, 1.3.x, +1.5.x...) are usually considered "under development". The three parts of +a version number are not limited to single digits, so a version number of 1.2.15 +would be acceptable. + +


Description

+ +
What is it that you do?

+ +In order to tell the user what exactly a plugin does, it must implement the function + +


+virtual const char *Description(void) = 0; +

+ +which returns a short, one line description of the plugin's purpose. + +


+virtual const char *Description(void) +{ + return "A simple demo plugin"; +} +

+ +


Command line arguments

+ +
Taking orders

+ +A VDR plugin can have command line arguments just like any normal program. +If a plugin wants to react on command line arguments, it needs to implement +the function + +


+virtual bool ProcessArgs(int argc, char *argv[]); +

+ +The parameters argc and argv have exactly the same meaning +as in a normal C program's main() function. +argv[0] contains the name of the plugin (as given in the -P +option of the vdr call). +

+Each plugin has its own set of command line options, which are totally independent +from those of any other plugin or VDR itself. +

+You can use the getopt() or getopt_long() function to process +these arguments. As with any normal C program, the strings pointed to by argv +will survive the entire lifetime of the plugin, so it is safe to store pointers to +these values inside the plugin. Here's an example: + +


+bool cPluginDemo::ProcessArgs(int argc, char *argv[]) +{ + static struct option long_options[] = { + { "aaa", required_argument, NULL, 'a' }, + { "bbb", no_argument, NULL, 'b' }, + { NULL } + }; + + int c; + while ((c = getopt_long(argc, argv, "a:b", long_options, NULL)) != -1) { + switch (c) { + case 'a': fprintf(stderr, "option -a = %s\n", optarg); + break; + case 'b': fprintf(stderr, "option -b\n"); + break; + default: return false; + } + } + return true; +} +

+ +The return value must be true if all options have been processed +correctly, or false in case of an error. The first plugin that returns +false from a call to its ProcessArgs() function will cause VDR +to exit. + +


Command line help

+ +
Tell me about it...

+ +If a plugin accepts command line options, it should implement the function + +


+virtual const char *CommandLineHelp(void); +

+ +which will be called if the user enters the -h option when starting VDR. +The returned string should contain the command line help for this plugin, formatted +in the same way as done by VDR itself: + +


+const char *cPluginDemo::CommandLineHelp(void) +{ + return " -a ABC, --aaa=ABC do something nice with ABC\n" + " -b, --bbb activate 'plan B'\n"; +} +

+ +This command line help will be printed directly below VDR's help texts (separated +by a line indicating the plugin's name, version and description), so if you use the +same formatting as shown here it will line up nicely. +Note that all lines should be terminated with a newline character, and should +be shorter than 80 characters. + +


Getting started

+ +
Let's get ready to rumble!

+ +If a plugin implements a function that runs in the background (presumably in a +thread of its own), or wants to make use of internationalization, +it needs to implement the function + +


+virtual void Start(void); +

+ +which is called once for each plugin at program startup. +Inside this function the plugin must set up everything necessary to perform +its task. This may, for instance, be a thread that collects data from the DVB +stream, which is later presented to the user via a function that is available +from the main menu. +

+If the plugin doesn't implement any background functionality or internationalized +texts, it doesn't need to implement this function. + +


Main menu entry

+ +
Today's special is...

+ +If the plugin implements a feature that the user shall be able to access +from VDR's main menu, it needs to implement the function + +


+virtual const char *MainMenuEntry(void); +

+ +The default implementation returns a NULL pointer, which means that +this plugin will not have an item in the main menu. Here's an example of a +plugin that will have a main menu item: + +


+const char *cPluginDemo::MainMenuEntry(void) +{ + return "Demo"; +} +

+ +The menu entries of all plugins will be inserted into VDR's main menu right +after the Recordings item, in the same sequence as they were given +in the call to VDR. + +


User interaction

+ +
It's showtime!

+ +If the user selects the main menu entry of a plugin, VDR calls the function + +


+virtual cOsdMenu *MainMenuAction(void); +

+ +which can do one of two things: +

    +
  • Return a pointer to a cOsdMenu object which will be displayed + as a submenu of the main menu (just like the Recordings menu, for instance). + That menu can then implement further functionality and, for instance, could + eventually start a custom player to replay a file other than a VDR recording. +
  • Perform a specific action and return NULL. In that case the main menu + will be closed after calling MainMenuAction(). +
+ +It is very important that a call to MainMenuAction() returns as soon +as possible! As long as the program stays inside this function, no other user +interaction is possible. If a specific action takes longer than a few seconds, +the plugin should launch a separate thread to do this. + + +

Setup parameters

+ +
Remember me...

+ +If a plugin requires its own setup parameters, it needs to implement the following +functions to handle these parameters: + +


+virtual cMenuSetupPage *SetupMenu(void); +virtual bool SetupParse(const char *Name, const char *Value); +

+ +The SetupMenu() function shall return the plugin's "Setup" menu +page, where the user can adjust all the parameters known to this plugin. +

+SetupParse() will be called for each parameter the plugin has +previously stored in the global setup data (see below). It shall return +true if the parameter was parsed correctly, false in case of +an error. If false is returned, an error message will be written to +the log file (and program execution will continue). +

+The plugin's setup parameters are stored in the same file as VDR's parameters. +In order to allow each plugin (and VDR itself) to have its own set of parameters, +the Name of each parameter will be preceeded with the plugin's +name, as in +

+demo.SomeParameter = 123 +

+The prefix will be handled by the core VDR setup code, so the individual +plugins need not worry about this. +

+To store its values in the global setup, a plugin has to call the function + +


+void SetupStore(const char *Name, type Value); +

+ +where Name is the name of the parameter ("SomeParameter" in the above +example, without the prefix "demo.") and Value is a simple data type (like +char *, int etc). +Note that this is not a function that the individual plugin class needs to implement! +SetupStore() is a non-virtual member function of the cPlugin class. +

+To remove a parameter from the setup data, call SetupStore() with the appropriate +name and without any value, as in +

+SetupStore("SomeParameter"); +

+The VDR menu "Setup/Plugins" will list all loaded plugins with their name, +version number and description. Selecting an item in this list will bring up +the plugin's "Setup" menu if that plugin has implemented the SetupMenu() +function. +

+Finally, a plugin doesn't have to implement the SetupMenu() if it only +needs setup parameters that are not directly user adjustable. It can use +SetupStore() and SetupParse() without presenting these +parameters to the user. + +


Internationalization

+ +
Welcome to Babylon!

+ +If a plugin displays texts to the user, it should implement internationalized +versions of these texts and call the function + +


+void RegisterI18n(const tI18nPhrase * const Phrases); +

+ +to register them with VDR's internationalization mechanism. +

+The call to this function must be done in the Start() function of the plugin: + +


+const tI18nPhrase Phrases[] = { + { "Hello world!", + "Hallo Welt!", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + }, + { NULL } + }; + +void cPluginDemo::Start(void) +{ + RegisterI18n(Phrases); +} +

+ +Each entry of type tI18nPhrase must have exactly as many members as defined +by the constant I18nNumLanguages in the file VDR/i18n.h, and the +sequence of the various languages must be the same as defined in VDR/i18n.c.
+It is very important that the array is terminated with a { NULL } +entry!. +

+Usually you won't be able to fill in all the different translations by yourself, so +you may want to contact the maintainers of these languages (listed in the file +VDR/i18n.c) and ask them to provide the additional translations. +

+The actual runtime selection of the texts corresponding to the selected language +is done by wrapping each internationalized text with the tr() macro: + +


+const char *s = tr("Hello world!"); +

+ +The text given here must be the first one defined in the related Phrases +entry (which is the English version), and the returned pointer is either a translated +version (if available) or the original string. In the latter case a message will be +written to the log file, indicating that a translation is missing. +Texts are first searched for in the Phrases registered for this plugin (if any) +and then in the global VDR texts. So a plugin can make use of texts defined by the +core VDR code. + +


Loading plugins into VDR

+ +
Saddling up!

+ +Plugins are loaded into VDR using the command line option -P, as in + +


+vdr -Pdemo +

+ +If the plugin accepts command line options, they are given as part of the argument +to the -P option, which then has to be enclosed in quotes: + +


+vdr -P"demo -a abc -b" +

+ +Any number of plugins can be loaded this way, each with its own -P option: + +


+vdr -P"demo -a abc -b" -Pdvd -Pmp3 +

+ +If you are not starting VDR from the VDR source directory (and thus your plugins +cannot be found at their default location) you need to tell VDR the location of +the plugins through the -L option: + +


+vdr -L/usr/lib/vdr -Pdemo +

+ +There can be any number of -L options, and each of them will apply to the +-P options following it. +

+When started with the -h or -V option (for help +or version information, respectively), VDR will automatically load all plugins +in the default or given directory that match the VDR plugin +naming convention, +and display their help and/or version information in addition to its own output. + +


Building the distribution package

+ +
Let's get this show on the road!

+ +If you want to make your plugin available to other VDR users, you'll need to +make a package that can be easily distributed. +The Makefile that has been created by the call to +newplugin +provides the target package, which does this for you. +

+Simply change into your source directory and execute make package: + +


+cd VDR/PLUGINS/SRC/demo +make package +

+ +After this you should find a file named like + +


+vdr-demo-0.0.1.tgz +

+ +in your source directory, where demo will be replaced with your actual +plugin's name, and 0.0.1 will be your plugin's current version number. + + + diff --git a/PLUGINS/SRC/hello/COPYING b/PLUGINS/SRC/hello/COPYING new file mode 100644 index 000000000..5b6e7c66c --- /dev/null +++ b/PLUGINS/SRC/hello/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/PLUGINS/SRC/hello/HISTORY b/PLUGINS/SRC/hello/HISTORY new file mode 100644 index 000000000..b35760cac --- /dev/null +++ b/PLUGINS/SRC/hello/HISTORY @@ -0,0 +1,6 @@ +VDR Plugin 'hello' Revision History +----------------------------------- + +2002-05-09: Version 0.0.1 + +- Initial revision. diff --git a/PLUGINS/SRC/hello/Makefile b/PLUGINS/SRC/hello/Makefile new file mode 100644 index 000000000..fb764cdca --- /dev/null +++ b/PLUGINS/SRC/hello/Makefile @@ -0,0 +1,78 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile 1.1 2002/05/09 15:17:44 kls Exp $ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# +PLUGIN = hello + +### The version number of this plugin (taken from the main source file): + +VERSION = `grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g'` + +### The directory environment: + +DVBDIR = ../../../../DVB/ost/include +VDRDIR = ../../.. +VDRINC = $(VDRDIR)/include +LIBDIR = ../../lib +TMPDIR = /tmp + +### The version number of VDR (taken from VDR's "config.h"): + +VDRVERSION = `grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g'` + +### The name of the distribution archive: + +ARCHIVE = vdr-$(PLUGIN)-$(VERSION) + +### Includes and Defines (add further entries here): + +INCLUDES = -I$(VDRINC) -I$(DVBDIR) + +DEFINES = -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o i18n.o + +### The C++ compiler and options: + +CXX = g++ +CXXFLAGS = -O2 -Wall -Woverloaded-virtual -m486 + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +# Dependencies: + +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +include $(DEPFILE) + +### Targets: + +all: libvdr-$(PLUGIN).so + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@ + @cp $@ $(LIBDIR)/$@.$(VDRVERSION) + +package: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(ARCHIVE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution archive created as $(ARCHIVE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ diff --git a/PLUGINS/SRC/hello/README b/PLUGINS/SRC/hello/README new file mode 100644 index 000000000..fd844ca61 --- /dev/null +++ b/PLUGINS/SRC/hello/README @@ -0,0 +1,11 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Klaus Schmidinger + +Project's homepage: www.cadsoft.de/people/kls/vdr + +Latest version available at: www.cadsoft.de/people/kls/vdr/software.htm + +See the file COPYING for license information. + +Description: This is a small demo of the VDR plugin interface. diff --git a/PLUGINS/SRC/hello/hello.c b/PLUGINS/SRC/hello/hello.c new file mode 100644 index 000000000..5db4f2a27 --- /dev/null +++ b/PLUGINS/SRC/hello/hello.c @@ -0,0 +1,105 @@ +/* + * hello.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: hello.c 1.1 2002/05/09 15:28:51 kls Exp $ + */ + +#include +#include +#include +#include "i18n.h" + +static const char *VERSION = "0.0.1"; +static const char *DESCRIPTION = "A friendly greeting"; +static const char *MAINMENUENTRY = "Hello"; + +class cPluginHello : public cPlugin { +private: + // Add any member variables or functions you may need here. + const char *option_a; + bool option_b; +public: + cPluginHello(void); + virtual ~cPluginHello(); + virtual const char *Version(void) { return VERSION; } + virtual const char *Description(void) { return tr(DESCRIPTION); } + virtual const char *CommandLineHelp(void); + virtual bool ProcessArgs(int argc, char *argv[]); + virtual void Start(void); + virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); } + virtual cOsdMenu *MainMenuAction(void); + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *Name, const char *Value); + }; + +cPluginHello::cPluginHello(void) +{ + // Initialize any member varaiables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! + option_a = NULL; + option_b = false; +} + +cPluginHello::~cPluginHello() +{ + // Clean up after yourself! +} + +const char *cPluginHello::CommandLineHelp(void) +{ + // Return a string that describes all known command line options. + return " -a ABC, --aaa=ABC do something nice with ABC\n" + " -b, --bbb activate 'plan B'\n"; +} + +bool cPluginHello::ProcessArgs(int argc, char *argv[]) +{ + // Implement command line argument processing here if applicable. + static struct option long_options[] = { + { "aaa", required_argument, NULL, 'a' }, + { "bbb", no_argument, NULL, 'b' }, + { NULL } + }; + + int c; + while ((c = getopt_long(argc, argv, "a:b", long_options, NULL)) != -1) { + switch (c) { + case 'a': option_a = optarg; + break; + case 'b': option_b = true; + break; + default: return false; + } + } + return true; +} + +void cPluginHello::Start(void) +{ + // Start any background activities the plugin shall perform. + RegisterI18n(Phrases); +} + +cOsdMenu *cPluginHello::MainMenuAction(void) +{ + // Perform the action when selected from the main VDR menu. + Interface->Info(tr("Hello world!")); + return NULL; +} + +cMenuSetupPage *cPluginHello::SetupMenu(void) +{ + // Return a setup menu in case the plugin supports one. + return NULL; +} + +bool cPluginHello::SetupParse(const char *Name, const char *Value) +{ + // Parse your own setup parameters and store their values. + return false; +} + +VDRPLUGINCREATOR(cPluginHello); // Don't touch this! diff --git a/PLUGINS/SRC/hello/i18n.c b/PLUGINS/SRC/hello/i18n.c new file mode 100644 index 000000000..70617421b --- /dev/null +++ b/PLUGINS/SRC/hello/i18n.c @@ -0,0 +1,52 @@ +/* + * i18n.c: Internationalization + * + * See the README file for copyright information and how to reach the author. + * + * $Id: i18n.c 1.1 2002/05/09 15:13:31 kls Exp $ + */ + +#include "i18n.h" + +const tI18nPhrase Phrases[] = { + { "Hello", + "Hallo", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + }, + { "Hello world!", + "Hallo Welt!", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + }, + { "A friendly greeting", + "Ein freundlicher Gru", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + }, + { NULL } + }; diff --git a/PLUGINS/SRC/hello/i18n.h b/PLUGINS/SRC/hello/i18n.h new file mode 100644 index 000000000..2976fe888 --- /dev/null +++ b/PLUGINS/SRC/hello/i18n.h @@ -0,0 +1,11 @@ +/* + * i18n.h: Internationalization + * + * See the README file for copyright information and how to reach the author. + * + * $Id: i18n.h 1.1 2002/05/09 15:15:49 kls Exp $ + */ + +#include + +extern const tI18nPhrase Phrases[]; diff --git a/channels.conf b/channels.conf index db1cbf41b..fef477489 100644 --- a/channels.conf +++ b/channels.conf @@ -48,83 +48,68 @@ ORB:12110:h:0:27500:501:502:504:0:28205 B1:12110:h:0:27500:601:602:604:0:28206 ARD Online-Kanal:12722:h:0:22000:0:701:0:0:0 :Premiere World -Premiere World:11797:h:0:27500:255:256:32:0:8 -Premiere 1:11797:h:0:27500:511:512:0:101:10 -Premiere 2:11797:h:0:27500:1791:1792:0:101:11 +Premiere Start:11797:h:0:27500:255:256:0:101:8 +Premiere 1:11797:h:0:27500:511:512,513;515:0:101:10 +Premiere 2:11797:h:0:27500:1791:1792,1793;1795:0:101:11 Premiere 3:11797:h:0:27500:2303:2304:0:101:43 -Premiere One:12032:h:0:27500:3071:3072:0:101:51 -Premiere Star:11797:h:0:27500:767:768:0:101:9 -Premiere Sci-Fi:11797:h:0:27500:1535:1536:0:101:41 -Premiere Action:11797:h:0:27500:1023:1024:0:101:20 -Premiere X-Action:11798:h:0:27500:2047:2048:0:101:50 -Premiere Comedy:11797:h:0:27500:1279:1280:0:101:29 -13th Street:12031:h:0:27500:2303:2304:0:101:42 +Premiere 4:11797:h:0:27500:767:768:0:101:9 +Premiere 5:11797:h:0:27500:1279:1280:0:101:29 +Premiere 6:11797:h:0:27500:1535:1536:0:101:41 +Premiere 7:11797:h:0:27500:1023:1024:0:101:20 +13th Street:11758:h:0:27500:2303:2304:0:101:42 Studio Universal:12090:V:0:27500:255:256:0:101:36 -Filmpalast:12031:h:0:27500:2559:2560:0:101:516 -Heimatkanal:12031:h:0:27500:2815:2816:0:101:517 -Discovery Channel:12031:h:0:27500:1791:1792:0:101:14 -Planet:12090:V:0:27500:1279:1280:0:101:13 -Fox Kids:12031:h:0:27500:1279:1280:0:101:28 -Fox Kids Trkce:11914:H:0:27500:767:768:8191:101:54 -Junior:12031:h:0:27500:255:256:0:101:19 -K-Toon:12031:h:0:27500:511:512:0:101:12 +Premiere Serie:12031:h:0:27500:1023:1024:0:101:16 Disney Channel:12090:V:0:27500:767:768:0:101:34 -Sunset:12031:h:0:27500:1023:1024:0:101:16 +Premiere Nostalgie:12031:h:0:27500:2559:2560:0:101:516 +Discovery Channel:12031:h:0:27500:1791:1792:0:101:14 +Planet:12090:v:0:27500:1279:1280:0:101:13 +Fox Kids:11758:h:0:27500:1279:1280:0:101:28 +Junior:11758:h:0:27500:255:256:0:101:19 +K-Toon:11758:h:0:27500:511:512:0:101:12 Krimi&Co:12031:h:0:27500:1535:1536:0:101:23 -Goldstar TV:12031:h:0:27500:3839:3840:0:101:518 -Classica:12031:h:0:27500:767:768:0:101:15 -Seasons:12090:V:0:27500:511:512:0:101:33 -:Cinedom -Cinedom Deluxe:11758:h:0:27500:255:256,257;259:0:101:189 -Cinedom 1A:11758:h:0:27500:511:512,513:0:101:190 -Cinedom 1B:12070:h:0:27500:1535:1536,1537:0:101:178 -Cinedom 1C:11720:h:0:27500:511:512,513:0:101:180 -Cinedom 1D:11720:h:0:27500:1535:1536,1537:0:101:176 -Cinedom 2A:11758:h:0:27500:1023:1024,1025:0:101:193 -Cinedom 2B:11720:h:0:27500:1279:1280:0:101:183 -Cinedom 2C:12070:h:0:27500:1791:1792:0:101:179 -Cinedom 2D:12070:h:0:27500:511:512:0:101:184 -Cinedom 2E:12070:h:0:27500:1279:1280:0:101:188 -Cinedom 3A:11758:h:0:27500:2559:2560:0:101:192 -Cinedom 3B:11758:h:0:27500:1535:1536:0:101:195 -Cinedom 3C:12070:h:0:27500:767:768:0:101:185 -Cinedom 3D:11720:h:0:27500:1023:1024:0:101:182 -Cinedom 4A:11758:h:0:27500:767:768:0:101:191 -Cinedom 4B:11720:h:0:27500:767:768:0:101:181 -Cinedom 4C:12070:h:0:27500:2047:2048:0:101:187 -Cinedom 5A:11758:h:0:27500:1279:1280:0:101:194 -Cinedom 5B:11720:h:0:27500:1791:1792:0:101:177 -Cinedom 5C:12070:h:0:27500:1023:1024:0:101:186 -:Beta Digital -N24:12480:v:0:27500:2047:2048:0:0:47 -CNBC:11954:h:0:27500:510:520:0:0:28010 -Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199 +Goldstar TV:11758:h:0:27500:3839:3840:0:101:518 +Classica:11758:h:0:27500:767:768:0:101:15 +Sonnenklar TV:12090:V:0:27500:1023:1024:0:0:32 +:Premiere Direkt +Premiere Direkt 1A:12031:h:0:27500:511:512,513;515:0:101:177 +Premiere Direkt 1B:11719:h:0:27500:1023:1024,1025;1027:0:101:182 +Premiere Direkt 2A:12031:h:0:27500:255:256;259:0:101:176 +Premiere Direkt 2B:11719:h:0:27500:767:768;769:0:101:181 +Premiere Direkt 3A:11719:h:0:27500:511:512;515:0:101:180 +Premiere Direkt 3B:11719:h:0:27500:1279:1280;1283:0:101:183 +Premiere Direkt 4A:12031:h:0:27500:2815:2816:0:101:18 +Premiere Direkt 4B:12070:h:0:27500:1535:1536:0:101:216 :PW Erotic -Beate-Uhse.TV:11758:h:0:27500:3839:3840:0:101:21 -Blue Movie 1:11758:h:0:27500:1791:1792:0:101:513 -Blue Movie 2:11758:h:0:27500:2047:2048:0:101:514 -Blue Movie 3:11758:h:0:27500:2303:2304:0:101:515 +Beate-Uhse.TV:11758:h:0:27500:1023:1024:0:101:21 +Premiere Erotik 1:12031:h:0:27500:1279:1280:0:101:513 +Premiere Erotik 2:11719:h:0:27500:1535:1536:0:101:778 +Premiere Erotik 3:11719:h:0:27500:1791:1792:0:101:779 +Premiere Erotik 4:11719:h:0:27500:3583:3584:0:101:780 :Sportsworld Premiere Sport 1:11720:h:0:27500:255:256,257:0:101:17 -Premiere Sport 2:12070:h:0:27500:3839:3840:0:101:27 -Premiere Sport 3:12070:h:0:27500:255:256:0:101:26 +Premiere Sport 2:12031:h:0:27500:3839:3840:0:101:27 :Formel 1 -Infokanal:11720:h:0:27500:3071:3072:0:101:244 -Multikanal:11720:h:0:27500:2815:2816:0:101:243 -Supersignal:11720:h:0:27500:255:256:0:101:17 -Verfolgerfeld:11720:h:0:27500:2303:2304:0:101:241 -Cockpitkanal:11720:h:0:27500:2559:2560:0:101:242 -Boxengasse:11720:h:0:27500:2047:2048:0:101:240 -:Premiere World Bundesliga -Superdom:11758:h:0:27500:2815:8192:0:101:18 -BuLi-Konferenz:11758:h:0:27500:3327:3328,3329:0:101:215 -BuLi-Spiel 1:11720:h:0:27500:255:256,257:0:101:17 -BuLi-Spiel 2:11720:h:0:27500:2047:2048,2049:0:101:240 -BuLi-Spiel 3:11720:h:0:27500:2303:2304,2305:0:101:241 -BuLi-Spiel 4:11720:h:0:27500:2559:2560,2561:0:101:242 -BuLi-Spiel 5:11720:h:0:27500:2815:2816,2817:0:101:243 -BuLi-Spiel 6:11720:h:0:27500:3071:3072,3073:0:101:244 -BuLi-Spiel 7:11758:h:0:27500:3071:3072,3073:0:101:214 +Supersignal:12070:h:0:27500:255:256:0:101:211 +Cockpitkanal:12070:h:0:27500:511:512:0:101:212 +Boxengasse:12070:h:0:27500:767:768:0:101:213 +Verfolgerfeld:12070:h:0:27500:1023:1024:0:101:214 +Infokanal:12070:h:0:27500:1279:1280:0:101:215 +Multikanal:11720:h:0:27500:255:256:0:101:17 +:Beta Digital +N24:12480:v:0:27500:2047:2048:0:0:47 +CNBC:11954:h:0:27500:510:520:0:0:28010 +Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199 +:Premiere Bundesliga +BL-Konferenz:12031:h:0:27500:2303:2304,2305:0:101:210 +BuLi 1:11719:h:0:27500:255:256,257:0:101:17 +BuLi 2:11719:h:0:27500:2047:2048,2049:0:101:240 +BuLi 3:11719:h:0:27500:2303:2304,2305:0:101:241 +BuLi 4:11719:h:0:27500:2559:2560,2561:0:101:242 +BuLi 5:11719:h:0:27500:2815:2816,2817:0:101:243 +BuLi 6:11719:h:0:27500:3071:3072,3073:0:101:244 +BuLi 7:11719:h:0:27500:3327:3328,3329:0:101:245 +BuLi 8:12031:h:0:27500:3071:3072,3073:0:101:208 +BuLi 9:12031:h:0:27500:3327:3328,3329:0:101:209 : TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601 Mosaico:11934:v:0:27500:165:100:0:0:29010 @@ -168,7 +153,7 @@ ESC 1:12363:v:0:27500:163:104:0:0:0 TV5 Europe:12363:v:0:27500:164:112:0:0:0 TV7 Tunisia:12363:v:0:27500:166:128:0:0:0 ARTE:12363:v:0:27500:167:137:0:0:0 -RAI Uno:12363:v:0:27500:289:290:0:0:8904 +RAI Uno:10788:v:0:22000:289:290:0:0:9004 RTP International:12363:v:0:27500:300:301:0:0:0 Fashion TV:12402:v:0:27500:163:92:0:0:0 VideoService:12422:h:0:27500:255:256:0:0:0 diff --git a/channels.conf.cable b/channels.conf.cable index b6d5c050a..3987fd82e 100644 --- a/channels.conf.cable +++ b/channels.conf.cable @@ -1,184 +1,165 @@ -:verschlsselte Fernsehprogramm -PREMIERE ONE:378:h:0:6900:3071:3072:0:1:51 -PREMIERE MOVIE 1:370:h:0:6900:511:512;515:0:1:10 -PREMIERE MOVIE 2:370:h:0:6900:1791:1792:0:1:11 -PREMIERE MOVIE 3:370:h:0:6900:2303:2304:0:1:43 -PREMIERE ACTION:370:h:0:6900:1023:1024,1025:0:1:20 -PREMIERE X-ACTION:370:h:0:6900:2047:2048,2049:0:1:50 -PREMIERE SCI-FI:370:h:0:6900:1535:1536:0:1:41 -PREMIERE STAR:370:h:0:6900:767:768:0:1:9 -PREMIERE COMEDY:370:h:0:6900:1279:1280:0:1:29 -13 TH STREET:378:h:0:6900:2303:2304,2305:0:1:42 -KRIMI &CO:378:h:0:6900:1535:1536:0:1:23 -STUDIO UNIVERSAL:402:h:0:6900:1050:1054:0:1:36 -DISCOVERY CHANNEL:378:h:0:6900:1791:1792:0:1:14 -FILMPALAST:378:h:0:6900:2559:2560:0:1:516 -DISNEY CHANNEL:402:h:0:6900:1030:1034:0:1:34 -SUNSET:378:h:0:6900:1023:1024:0:1:16 -PLANET:402:h:0:6900:1100:1104:0:1:13 -CLASSICA:378:h:0:6900:767:768:0:1:15 -GOLDSTAR TV:378:h:0:6900:3839:3840:0:1:518 -HEIMATKANAL:378:h:0:6900:2815:2816:0:1:517 -K-TOON:378:h:0:6900:511:512:0:1:12 -FOX KIDS:378:h:0:6900:1279:1280:0:1:28 -KiKa:394:h:0:6900:310:320:330:0:28008 -JUNIOR:378:h:0:6900:255:256:0:1:19 :Fernsehprogramme -Das Erste:410:h:0:6900:101:102,88:104:0:28106 -ZDF:394:h:0:6900:110:120,121:130:0:28006 +Das Erste:410:h:0:6900:101:102:111:0:28106 +ZDF:394:h:0:6900:110:120:130:0:28006 +3sat:394:h:0:6900:210:220:230:0:28007 +arte:410:h:0:6900:401:402:404:0:28109 +EuroNews:394:h:0:6900:2221:2233:768:0:28015 ZDF.info:394:h:0:6900:610:620:0:0:28011 ZDF.doku:394:h:0:6900:660:670:0:0:28014 ZDF Theaterkanal:394:h:0:6900:1110:1120:130:0:28016 EinsExtra:426:h:0:6900:101:102:0:0:28201 EinsFestival:426:h:0:6900:201:202:0:0:28202 EinsMuXx:426:h:0:6900:301:302:0:0:28203 -3sat:394:h:0:6900:210:220:230:0:28007 -arte:410:h:0:6900:401:402:404:0:28109 -EuroNews:394:h:0:6900:2221:2233:768:0:28015 Phoenix:410:h:0:6900:901:902:0:0:28114 Eurosport:394:h:0:6900:410:420:430:0:28009 DW-tv:610:h:0:6900:634:632:0:0:6101 CNBC:394:h:0:6900:510:520:530:0:28010 +:Regionalprogramme WDR FERNSEHEN:410:h:0:6900:601:602:604:0:28111 +B1 Berlin:426:h:0:6900:601:602,603:604:0:28206 +ORB-Fernsehen:426:h:0:6900:501:502:504:0:28205 MDR FERNSEHEN:426:h:0:6900:401:402:404:0:28204 SR Fernsehen Suedwest:410:h:0:6900:501:502:504:0:28110 SuedWest BW:410:h:0:6900:801:802:804:0:28113 SuedWest RP:426:h:0:6900:3101:3102:3104:0:28231 BR-alpha:410:h:0:6900:701:702:704:0:28112 -B1 Berlin:426:h:0:6900:601:602:604:0:28206 N3:426:h:0:6900:2401:2402:2404:0:28224 -ORB-Fernsehen:426:h:0:6900:501:502:504:0:28205 hessen fernsehen:410:h:0:6900:301:302:304:0:28108 Bayerisches FS:410:h:0:6900:201:202:204:0:28107 Test-R:410:h:0:6900:901:902:104:0:28130 +:Premiere Hauptprogramme +Premiere START:370:C:0:6900:255:256:32:101:8 +Premiere 1:370:C:0:6900:511:512:0:101:10 +Premiere 2:370:C:0:6900:1791:1792:0:101:11 +Premiere 3:370:C:0:6900:2303:2304:0:101:43 +Premiere 4:370:C:0:6900:767:768:0:101:9 +Premiere 5:370:C:0:6900:1279:1280:0:101:29 +Premiere 6:370:C:0:6900:1535:1536:0:101:41 +Premiere 7:370:C:0:6900:1023:1024:0:101:20 +Premiere SERIE:378:C:0:6900:1023:1024:0:101:16 +Premiere Nostalgie:378:C:0:6900:2559:2560:0:101:516 +13 TH STREET:354:C:0:6900:2303:2304:0:101:42 +Stundio Universal:402:C:0:6900:1050:1054:0:101:36 +Krimi &Co:378:C:0:6900:1535:1536:0:101:23 +Disney Channel:402:C:0:6900:1030:1034:0:101:34 +Discovery Channel:378:C:0:6900:1791:1792:0:101:14 +Fox Kids:354:C:0:6900:1279:1280:0:101:28 +Junior:354:C:0:6900:255:256:0:101:19 +K-TOON:354:C:0:6900:0:0:0:101:12 +GOLDSTAR TV:354:C:0:6900:3839:3840:0:101:518 +CLASSICA:354:C:0:6900:767:768:0:101:15 :Mediavision -Extreme Sport:346:h:0:6900:801:802:0:1:50700 -Bloomberg:346:h:0:6900:811:812:0:1:50701 -Single TV:346:h:0:6900:621:622:0:1:50706 -Fashion TV:346:h:0:6900:821:822:0:1:50702 -BET ON JAZZ:346:h:0:6900:841:842:0:1:50704 -LANDSCAPE:346:h:0:6900:831:832:0:1:50703 -Einstein:346:h:0:6900:623:624:0:1:50719 +Bloomberg:346:h:0:6900:811:812:0:101:50701 +Fashion TV:346:h:0:6900:821:822:0:101:50702 +Einstein:346:h:0:6900:623:624:0:101:50719 +Extreme Sport:346:h:0:6900:801:802:0:101:50700 +LANDSCAPE:346:h:0:6900:831:832:0:101:50703 +Single TV:346:h:0:6900:621:622:0:101:50706 Leitseite:346:h:0:6900:2254:0:0:0:5004 -Via 1 - Schner Reisen:346:h:0:6900:611:612:0:0:50705 -Parlamentsfernsehen:610:h:0:6900:33:36:47:0:6100 -Vh1 - Classic:610:h:0:6900:604:603:0:0:6106 +BET ON JAZZ:346:h:0:6900:841:842:0:101:50704 +:Digit. Bouquet"Kabel Berlin" +Parlamentsfernsehen:610:C:0:6900:33:36:47:0:6100 +DW-tv:610:C:0:6900:634:632:0:0:6101 +Kanal 7:610:C:0:6900:49:52:0:101:6103 +Euronews:610:C:0:6900:597:592,591:0:101:6104 +Vh1 - Classic:610:h:0:6900:604:603:0:101:6106 +Travel:610:C:0:6900:595:594:0:101:6105 +Nuvolari:618:C:0:6900:1011:1012:0:101:50101 +Marco Polo:618:C:0:6900:1021:1022:0:101:50102 +Alice:618:C:0:6900:1031:1032:0:101:50103 +Leonardo:618:C:0:6900:1041:1042:0:101:50104 +Club:618:C:0:6900:1051:1052:0:101:50105 +Avante:618:C:0:6900:1061:1062:0:101:50106 +Expo 24*7:618:C:0:6900:1071:1072:0:101:50107 +Innergy:618:C:0:6900:0:0:0:101:50108 +BBC Prime:618:C:0:6900:1091:1092:0:101:50109 +Eurosport News:618:C:0:6900:1101:1102:0:101:50110 :Diverse TV-Sender -TV Polonia:434:h:0:6900:641:642:0:1:53204 -Kanal D:434:h:0:6900:651:652:0:1:53205 -RTP international:434:h:0:6900:661:662:0:1:53206 -ERT-Sat:434:h:0:6900:691:692:0:1:53209 -CNE:434:h:0:6900:4056:4057:0:1:53208 -ZEE TV:442:h:0:6900:517:773:0:1:53301 -NTV i:442:h:0:6900:514:515:0:1:53302 +TV Polonia:434:h:0:6900:641:642:0:101:53204 +Kanal D:434:h:0:6900:651:652:0:101:53205 +RTP international:434:h:0:6900:661:662:0:101:53206 +ERT-Sat:434:h:0:6900:691:692:0:101:53209 +CNE:434:h:0:6900:4056:4057:0:101:53208 +ZEE TV:442:h:0:6900:517:773:0:101:53301 +NTV i:442:h:0:6900:514:515:0:101:53302 ATV:434:h:0:6900:631:632:0:0:53203 TW1:610:h:0:6900:6106:6107:0:0:6106 -PREMIERE WORLD:370:h:0:6900:255:256:32:0:8 -:Premiere World Bundesliga -Superdom:362:h:0:6900:255:256:0:1:26 -Spiel 1:362:h:0:6900:255:256,257:0:1:17 -Spiel 2:362:h:0:6900:2047:2048,2049:0:1:240 -BuLi-Konferenz:362:h:0:6900:3071:3072,3073:0:1:208 -BuLi-Spiel 1:362:h:0:6900:3327:3328,3329:0:1:209 -BuLi-Spiel 2:362:h:0:6900:2303:2304,2305:0:1:210 -BuLi-Spiel 3:362:h:0:6900:3583:3584,3585:0:1:211 -BuLi-Spiel 4:362:h:0:6900:2559:2560,2561:0:1:212 -BuLi-Spiel 5:362:h:0:6900:2815:2816,2817:0:1:213 :Premiere Sport -PREMIERE SPORT 1:362:h:0:6900:255:256:0:1:17 -PREMIERE SPORT 2:362:h:0:6900:3327:3328:0:1:27 -PREMIERE SPORT 3:354:h:0:6900:2815:2816:0:1:18 -:Premiere Formel 1 -F1 Studio:362:h:0:6900:255:256:0:1:17 -F1 Box:362:h:0:6900:2047:2048:0:1:240 -F1 Verfolger:362:h:0:6900:2303:2304:0:1:241 -F1 Cockpit:362:h:0:6900:2559:2560:0:1:242 -F1 Multi:362:h:0:6900:2815:2816:0:1:243 -F1 Info:362:h:0:6900:3071:3072:0:1:244 -:Premiere Cinedom 1 -Cinedom 1A:362:h:0:6900:1535:1536,1537:0:1:176 -Cinedom 1B:386:h:0:6900:1535:1536,1537:0:1:178 -Cinedom 1C:362:h:0:6900:511:512,513:0:1:180 -Cinedom 1D:354:h:0:6900:511:512,513:0:1:190 -:Premiere Cinedom 2 -Cinedom 2A:386:h:0:6900:1791:1792,1793:0:1:179 -Cinedom 2B:362:h:0:6900:1279:1280,1281:0:1:183 -Cinedom 2C:386:h:0:6900:511:512:0:1:184 -Cinedom 2D:386:h:0:6900:1279:1280:0:1:188 -Cinedom 2E:354:h:0:6900:1023:1024:0:1:193 -: Premiere Cinedom 3 -Cinedom 3A:362:h:0:6900:1023:1024,1025:0:1:182 -Cinedom 3B:386:h:0:6900:767:768:0:1:185 -Cinedom 3C:354:h:0:6900:2559:2560:0:1:192 -Cinedom 3D:354:h:0:6900:1535:1536:0:1:195 -: Premiere Cinedom 4 -Cinedom 4A:362:h:0:6900:767:768,769:0:1:181 -Cinedom 4B:386:h:0:6900:2047:2048:0:1:187 -Cinedom 4C:354:h:0:6900:767:768:0:1:191 -: Premiere Cinedom 5 -Cinedom 5A:386:h:0:6900:1023:1024,1025:0:1:186 -Cinedom 5B:354:h:0:6900:1279:1280,1281:0:1:194 -: Premiere Cinedom Deluxe -CINEDOM DELUXE:354:h:0:6900:255:256,257:0:1:189 -:Premiere Erotic -BEATE-UHSE.TV:354:h:0:6900:3839:3840:0:1:21 -BLUE MOVIE 1:354:h:0:6900:1791:1792:0:1:513 -BLUE MOVIE 2:354:h:0:6900:2047:2048:0:1:514 -BLUE MOVIE 3:354:h:0:6900:2303:2304:0:1:515 +PREMIERE SPORT 1:362:C:0:6900:255:256,257:0:101:17 +PREMIERE SPORT 2:378:C:0:6900:3839:3840,3841:0:101:27 +:Premiere Direkt 1 +PREMIERE DIREKT 1A:362:C:0:6900:1023:1024,1025:0:101:182 +PREMIERE DIREKT 1B:378:C:0:6900:511:512,513:0:101:177 +:Premiere Direkt 2 +PREMIERE DIREKT 2A:378:C:0:6900:255:256,257:0:101:176 +PREMIERE DIREKT 2B:362:C:0:6900:767:768,769:0:101:181 +:Premiere Direkt 3 +PREMIERE DIREKT 3A:362:C:0:6900:511:512,513:0:101:180 +PREMIERE DIREKT 3B:362:C:0:6900:1279:1280,1281:0:101:183 +:Premiere Direkt 4 +PREMIERE DIREKT 4A:378:C:0:6900:2815:2816,2817:0:101:18 +PREMIERE DIREKT 4B:386:C:0:6900:1535:1536,1537:0:101:216 +:Premiere Erotik +BEATE-UHSE.TV:354:C:0:6900:1023:1024:0:101:21 +PREMIERE EROTIK 1:378:C:0:6900:1279:1280:0:101:513 +PREMIERE EROTIK 2:362:C:0:6900:1535:1536:0:101:778 +PREMIERE EROTIK 3:362:C:0:6900:1791:1792:0:101:779 +PREMIERE EROTIK 4:362:C:0:6900:3583:3584:0:101:780 :Radioprogramme -Fritz:426:h:0:6900:0:901:0:0:28209 -HR XXL:410:h:0:6900:0:3501:0:0:28125 -JUMP:426:h:0:6900:0:1001:0:0:28210 -SPUTNIK:426:h:0:6900:0:1201:0:0:28212 -RADIOmultikulti:426:h:0:6900:0:1301:0:0:28213 -DLR-Berlin:394:h:0:6900:0:710:0:0:28012 -DLF-Kln:394:h:0:6900:0:810:0:0:28013 -sterreich 1:394:h:0:6900:0:169:0:0:28017 -100,6:354:h:0:6900:0:1312:0:0:161 -Bayern 4 Klassik:410:h:0:6900:0:3001:0:0:28120 -B5 aktuell:410:h:0:6900:0:3101:0:0:28121 -Bremen 2:410:h:0:6900:0:3801:0:0:28128 -Bayern 1:410:h:0:6900:0:3601:0:0:28126 -NDR 4 Info:410:h:0:6900:0:3701:0:0:28127 -SR 1:410:h:0:6900:0:3901:0:0:28129 -hr-klassik:410:h:0:6900:0:3401:0:0:28124 -hr2:410:h:0:6900:0:3301:0:0:28123 -hr-chronos:410:h:0:6900:0:3201:0:0:28122 -Radio 3:426:h:0:6900:0:701:0:0:28207 -MDR KULTUR:426:h:0:6900:0:801:0:0:28208 -MDR info:426:h:0:6900:0:1101:0:0:28211 -SWR-2:426:h:0:6900:0:1401:0:0:28214 -WDR3:426:h:0:6900:0:1501:0:0:28215 -WDR Radio 5:426:h:0:6900:0:1601:0:0:28216 +Fritz:426:h:0:6900:1:901:0:0:28209 +HR XXL:410:h:0:6900:1:3501:0:0:28125 +JUMP:426:h:0:6900:1:1001:0:0:28210 +SPUTNIK:426:h:0:6900:1:1201:0:0:28212 +RADIOmultikulti:426:h:0:6900:1:1301:0:0:28213 +DLR-Berlin:394:h:0:6900:1:710:0:0:28012 +DLF-Kln:394:h:0:6900:1:810:0:0:28013 +sterreich 1:394:h:0:6900:1:169:0:0:28017 +100,6:354:h:0:6900:1:1312:0:0:161 +Bayern 4 Klassik:410:h:0:6900:1:3001:0:0:28120 +B5 aktuell:410:h:0:6900:1:3101:0:0:28121 +Bremen 2:410:h:0:6900:1:3801:0:0:28128 +Bayern 1:410:h:0:6900:1:3601:0:0:28126 +NDR 4 Info:410:h:0:6900:1:3701:0:0:28127 +SR 1:410:h:0:6900:1:3901:0:0:28129 +hr-klassik:410:h:0:6900:1:3401:0:0:28124 +hr2:410:h:0:6900:1:3301:0:0:28123 +hr-chronos:410:h:0:6900:1:3201:0:0:28122 +Radio 3:426:h:0:6900:1:701:0:0:28207 +MDR KULTUR:426:h:0:6900:1:801:0:0:28208 +MDR info:426:h:0:6900:1:1101:0:0:28211 +SWR-2:426:h:0:6900:1:1401:0:0:28214 +WDR3:426:h:0:6900:1:1501:0:0:28215 +WDR Radio 5:426:h:0:6900:1:1601:0:0:28216 :verschlsselte Radioprogramme -ALTERNATIVE ROCK:378:h:0:6900:1:800:0:1:151 -HITLISTE:378:h:0:6900:1:784:0:1:150 -DANCE:378:h:0:6900:1:816:0:1:152 -EASY LISTENING:402:h:0:6900:1:1201:0:1:162 -CLASSIC ROCK:378:h:0:6900:1:544:0:1:154 -Cristal New Age:442:h:0:6900:1:536:0:0:53351 -Movie Sounds:442:h:0:6900:1:537:0:1:53352 -LOVE SONGS:402:h:0:6900:1:1191:0:1:163 -KLASSIK POPULR:378:h:0:6900:1:592:0:1:145 -KLASS. SYMPHONIEN:378:h:0:6900:1:608:0:1:146 -OPER & VOKALMUSIK:378:h:0:6900:1:624:0:1:147 -BAROCKMUSIK:378:h:0:6900:1:640:0:1:148 -JAZZ:378:h:0:6900:1:656:0:1:149 -COUNTRY:378:h:0:6900:1:352:0:1:153 -FILMMUSIK:378:h:0:6900:1:368:0:1:155 -DEUTSCHE HITS:402:h:0:6900:1:1156:0:1:156 -SOUL CLASSICS:402:h:0:6900:1:1161:0:1:157 -TRK MZIGI:402:h:0:6900:1:1166:0:1:158 -GOLD:402:h:0:6900:1:1171:0:1:159 -MUSICALS:402:h:0:6900:1:1196:0:1:164 -OLD GOLD:402:h:0:6900:1:1186:0:1:165 -SCHLAGER:402:h:0:6900:1:1176:0:1:166 -VOLKSMUSIK:402:h:0:6900:1:1181:0:1:167 -All Jazz:442:h:0:6900:1:535:0:1:53350 -Sinfonica:442:h:0:6900:1:538:0:1:53353 -Opernfestival:442:h:0:6900:1:539:0:1:53354 -Barock Fantasie:442:h:0:6900:1:540:0:1:53355 -Musica Camerata:442:h:0:6900:1:541:0:1:53356 -Musica Antica:442:h:0:6900:1:542:0:1:53357 -Adagio:442:h:0:6900:1:543:0:1:53358 -Jazz Legends:442:h:0:6900:1:544:0:1:53359 +ALTERNATIVE ROCK:370:C:0:6900:1:800:0:101:151 +CLASSIC ROCK:370:C:0:6900:1:544:0:101:154 +DANCE:370:C:0:6900:1:816:0:101:152 +LOVE SONGS:370:C:0:6900:1:352:0:101:163 +GOLD:370:C:0:6900:1:576:0:101:159 +OLD GOLD:370:C:0:6900:1:304:0:101:165 +SOUL CLASSICS:370:C:0:6900:1:400:0:101:157 +EASY LISTENING:370:C:0:6900:1:384:0:101:162 +DEUTSCHE HITS:370:C:0:6900:1:592:0:101:156 +SCHLAGER:370:C:0:6900:1:320:0:101:166 +VOLKSMUSIK:362:C:0:6900:1:336:0:101:167 +COUNTRY:362:C:0:6900:1:352:0:101:153 +FILMMUSIK:362:C:0:6900:1:368:0:101:155 +MUSICALS:362:C:0:6900:1:384:0:101:164 +JAZZ:362:C:0:6900:1:656:0:101:149 +KLASSIK POPUL04R:378:C:0:6900:1:592:0:101:145 +ORCHESTRALE WERKE:378:C:0:6900:1:608:0:101:146 +BAROCK:378:C:0:6900:1:640:0:101:148 +OPER:378:C:0:6900:1:624:0:101:147 +TRK MZIGI:378:C:0:6900:1:560:0:101:158 +HITLISTE:370:C:0:6900:1:784:0:101:150 +Radio GoldStar:354:C:0:6900:1:368:0:101:171 +All Jazz:442:C:0:6900:1:535:0:101:53350 +Cristal New Age:442:C:0:6900:1:536:0:101:53351 +Movie Sounds:442:C:0:6900:1:537:0:101:53352 +Sinfonica:442:C:0:6900:1:538:0:101:53353 +Opernfestival:442:C:0:6900:1:539:0:101:53354 +Barock Fantasie:442:C:0:6900:1:540:0:101:53355 +Musica Camerata:442:C:0:6900:1:541:0:101:53356 +Musica Antica:442:C:0:6900:1:542:0:101:53357 +Adagio:442:C:0:6900:1:543:0:101:53358 +Jazz legends:442:C:0:6900:1:544:0:101:53359 diff --git a/channels.conf.terr b/channels.conf.terr index bed1be8c4..81c058168 100644 --- a/channels.conf.terr +++ b/channels.conf.terr @@ -9,3 +9,12 @@ BBC CHOICE:505833:0:0:0:620:621:0:0:4351 BBC NEWS 24:505833:0:0:0:640:641:0:0:4415 BBC Knowledge:505833:0:0:0:630:631:0:0:4607 Shop!:561833:0:0:0:6049:6050:0:0:13120 +: DVB-T Berlin Germany +RTL 1:778000:V:0:27500:160:80:0:1:1 +RTL 2:778000:V:0:27500:161:82:0:1:2 +Super RTL:778000:V:0:27500:162:84:0:1:3 +VOX:778000:V:0:27500:165:81:0:1:4 +SAT 1:714000:V:0:27500:160:80:0:1:18 +PRO 7:714000:V:0:27500:161:82:0:1:19 +KABEL 1:714000:V:0:27500:162:84:0:1:20 +N24:714000:V:0:27500:163:86:0:1:21 diff --git a/config.c b/config.c index 76e138b7e..8290e735e 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.97 2002/04/02 21:56:51 kls Exp $ + * $Id: config.c 1.99 2002/05/05 09:10:00 kls Exp $ */ #include "config.h" @@ -13,6 +13,7 @@ #include "dvbapi.h" #include "i18n.h" #include "interface.h" +#include "plugin.h" // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' // format characters in order to allow any number of blanks after a numeric @@ -332,7 +333,8 @@ cTimer::cTimer(bool Instant) struct tm *now = localtime_r(&t, &tm_r); day = now->tm_mday; start = now->tm_hour * 100 + now->tm_min; - stop = start + 200; // "instant recording" records 2 hours by default + stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime; + stop = (stop / 60) * 100 + (stop % 60); if (stop >= 2400) stop -= 2400; //TODO VPS??? @@ -386,11 +388,12 @@ cTimer& cTimer::operator= (const cTimer &Timer) return *this; } -bool cTimer::operator< (const cTimer &Timer) +bool cTimer::operator< (const cListObject &ListObject) { + cTimer *ti = (cTimer *)&ListObject; time_t t1 = StartTime(); - time_t t2 = (*(cTimer *)&Timer).StartTime(); - return t1 < t2 || (t1 == t2 && priority > Timer.priority); + time_t t2 = ti->StartTime(); + return t1 < t2 || (t1 == t2 && priority > ti->priority); } const char *cTimer::ToText(cTimer *Timer) @@ -916,12 +919,76 @@ const cCaDefinition *cCaDefinitions::Get(int Number) return NULL; } +// -- cSetupLine ------------------------------------------------------------- + +cSetupLine::cSetupLine(void) +{ + plugin = name = value = NULL; +} + +cSetupLine::cSetupLine(const char *Name, const char *Value, const char *Plugin) +{ + name = strdup(Name); + value = strdup(Value); + plugin = Plugin ? strdup(Plugin) : NULL; +} + +cSetupLine::~cSetupLine() +{ + delete plugin; + delete name; + delete value; +} + +bool cSetupLine::operator< (const cListObject &ListObject) +{ + const cSetupLine *sl = (cSetupLine *)&ListObject; + if (!plugin && !sl->plugin) + return strcasecmp(name, sl->name) < 0; + if (!plugin) + return true; + if (!sl->plugin) + return false; + int result = strcasecmp(plugin, sl->plugin); + if (result == 0) + result = strcasecmp(name, sl->name); + return result < 0; +} + +bool cSetupLine::Parse(char *s) +{ + char *p = strchr(s, '='); + if (p) { + *p = 0; + char *Name = compactspace(s); + char *Value = compactspace(p + 1); + if (*Name && *Value) { + p = strchr(Name, '.'); + if (p) { + *p = 0; + char *Plugin = compactspace(Name); + Name = compactspace(p + 1); + if (!(*Plugin && *Name)) + return false; + plugin = strdup(Plugin); + } + name = strdup(Name); + value = strdup(Value); + return true; + } + } + return false; +} + +bool cSetupLine::Save(FILE *f) +{ + return fprintf(f, "%s%s%s = %s\n", plugin ? plugin : "", plugin ? "." : "", name, value) > 0; +} + // -- cSetup ----------------------------------------------------------------- cSetup Setup; -char *cSetup::fileName = NULL; - cSetup::cSetup(void) { OSDLanguage = 0; @@ -930,6 +997,7 @@ cSetup::cSetup(void) MenuScrollPage = 1; MarkInstantRecord = 1; strcpy(NameInstantRecord, "TITLE EPISODE"); + InstantRecordTime = 180; LnbSLOF = 11700; LnbFrequLo = 9750; LnbFrequHi = 10600; @@ -964,19 +1032,77 @@ cSetup::cSetup(void) CurrentVolume = MAXVOLUME; } -void cSetup::PrintCaCaps(FILE *f, const char *Name) +cSetup& cSetup::operator= (const cSetup &s) +{ + memcpy(&__BeginData__, &s.__BeginData__, (char *)&s.__EndData__ - (char *)&s.__BeginData__); + return *this; +} + +cSetupLine *cSetup::Get(const char *Name, const char *Plugin) +{ + for (cSetupLine *l = First(); l; l = Next(l)) { + if ((l->Plugin() == NULL) == (Plugin == NULL)) { + if ((!Plugin || strcasecmp(l->Plugin(), Plugin) == 0) && strcasecmp(l->Name(), Name) == 0) + return l; + } + } + return NULL; +} + +void cSetup::Store(const char *Name, const char *Value, const char *Plugin) +{ + if (Name && *Name) { + cSetupLine *l = Get(Name, Plugin); + if (l) + Del(l); + if (Value) + Add(new cSetupLine(Name, Value, Plugin)); + } +} + +void cSetup::Store(const char *Name, int Value, const char *Plugin) +{ + char *buffer = NULL; + asprintf(&buffer, "%d", Value); + Store(Name, buffer, Plugin); + delete buffer; +} + +bool cSetup::Load(const char *FileName) +{ + if (cConfig::Load(FileName, true)) { + bool result = true; + for (cSetupLine *l = First(); l; l = Next(l)) { + if (l->Plugin()) { + cPlugin *p = cPluginManager::GetPlugin(l->Plugin()); + if (p && !p->SetupParse(l->Name(), l->Value())) + result = false; + } + else { + if (!Parse(l->Name(), l->Value())) + result = false; + } + } + return result; + } + return false; +} + +void cSetup::StoreCaCaps(const char *Name) { for (int d = 0; d < MAXDVBAPI; d++) { - int written = 0; + char buffer[MAXPARSEBUFFER]; + char *q = buffer; + *buffer = 0; for (int i = 0; i < MAXCACAPS; i++) { if (CaCaps[d][i]) { - if (!written++) - fprintf(f, "CaCaps = %d", d + 1); - fprintf(f, " %d", CaCaps[d][i]); + if (!*buffer) + q += snprintf(buffer, sizeof(buffer), "%d", d + 1); + q += snprintf(q, sizeof(buffer) - (q - buffer), " %d", CaCaps[d][i]); } } - if (written) - fprintf(f, "\n"); + if (*buffer) + Store(Name, buffer); } } @@ -1003,142 +1129,99 @@ bool cSetup::ParseCaCaps(const char *Value) return false; } -bool cSetup::Parse(char *s) -{ - char *p = strchr(s, '='); - if (p) { - *p = 0; - char *Name = compactspace(s); - char *Value = compactspace(p + 1); - if (*Name && *Value) { - if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value); - else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); - else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); - else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); - else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); - else if (!strcasecmp(Name, "NameInstantRecord")) strn0cpy(NameInstantRecord, Value, MaxFileName); - else if (!strcasecmp(Name, "LnbSLOF")) LnbSLOF = atoi(Value); - else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); - else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); - else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value); - else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); - else if (!strcasecmp(Name, "TimeTransponder")) TimeTransponder = atoi(Value); - else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); - else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); - else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); - else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); - else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); - else if (!strcasecmp(Name, "SortTimers")) SortTimers = atoi(Value); - else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); - else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); - else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); - else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); - else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); - else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); - else if (!strcasecmp(Name, "RecordDolbyDigital")) RecordDolbyDigital = atoi(Value); - else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); - else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); - else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); - else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); - else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); - else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); - else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); - else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); - else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); - else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); - else if (!strcasecmp(Name, "CaCaps")) return ParseCaCaps(Value); - else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); - else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); - else - return false; - return true; - } - } - return false; -} - -bool cSetup::Load(const char *FileName) -{ - isyslog(LOG_INFO, "loading %s", FileName); - delete fileName; - fileName = strdup(FileName); - FILE *f = fopen(fileName, "r"); - if (f) { - int line = 0; - char buffer[MAXPARSEBUFFER]; - bool result = true; - while (fgets(buffer, sizeof(buffer), f) > 0) { - line++; - stripspace(buffer); - if (!isempty(buffer)) { - if (*buffer != '#' && !Parse(buffer)) { - esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); - result = false; - } - } - } - fclose(f); - return result; - } +bool cSetup::Parse(const char *Name, const char *Value) +{ + if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value); + else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); + else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); + else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); + else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); + else if (!strcasecmp(Name, "NameInstantRecord")) strn0cpy(NameInstantRecord, Value, MaxFileName); + else if (!strcasecmp(Name, "InstantRecordTime")) InstantRecordTime = atoi(Value); + else if (!strcasecmp(Name, "LnbSLOF")) LnbSLOF = atoi(Value); + else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); + else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); + else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value); + else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); + else if (!strcasecmp(Name, "TimeTransponder")) TimeTransponder = atoi(Value); + else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); + else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); + else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); + else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); + else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); + else if (!strcasecmp(Name, "SortTimers")) SortTimers = atoi(Value); + else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); + else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); + else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); + else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); + else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); + else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "RecordDolbyDigital")) RecordDolbyDigital = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); + else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); + else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); + else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); + else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); + else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); + else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); + else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); + else if (!strcasecmp(Name, "CaCaps")) return ParseCaCaps(Value); + else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); else - LOG_ERROR_STR(FileName); - return false; + return false; + return true; } -bool cSetup::Save(const char *FileName) -{ - if (!FileName) - FileName = fileName; - if (FileName) { - cSafeFile f(FileName); - if (f.Open()) { - fprintf(f, "# VDR Setup\n"); - fprintf(f, "OSDLanguage = %d\n", OSDLanguage); - fprintf(f, "PrimaryDVB = %d\n", PrimaryDVB); - fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch); - fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage); - fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord); - fprintf(f, "NameInstantRecord = %s\n", NameInstantRecord); - fprintf(f, "LnbSLOF = %d\n", LnbSLOF); - fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo); - fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); - fprintf(f, "DiSEqC = %d\n", DiSEqC); - fprintf(f, "SetSystemTime = %d\n", SetSystemTime); - fprintf(f, "TimeTransponder = %d\n", TimeTransponder); - fprintf(f, "MarginStart = %d\n", MarginStart); - fprintf(f, "MarginStop = %d\n", MarginStop); - fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout); - fprintf(f, "EPGBugfixLevel = %d\n", EPGBugfixLevel); - fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout); - fprintf(f, "SortTimers = %d\n", SortTimers); - fprintf(f, "PrimaryLimit = %d\n", PrimaryLimit); - fprintf(f, "DefaultPriority = %d\n", DefaultPriority); - fprintf(f, "DefaultLifetime = %d\n", DefaultLifetime); - fprintf(f, "UseSubtitle = %d\n", UseSubtitle); - fprintf(f, "RecordingDirs = %d\n", RecordingDirs); - fprintf(f, "VideoFormat = %d\n", VideoFormat); - fprintf(f, "RecordDolbyDigital = %d\n", RecordDolbyDigital); - fprintf(f, "ChannelInfoPos = %d\n", ChannelInfoPos); - fprintf(f, "OSDwidth = %d\n", OSDwidth); - fprintf(f, "OSDheight = %d\n", OSDheight); - fprintf(f, "OSDMessageTime = %d\n", OSDMessageTime); - fprintf(f, "MaxVideoFileSize = %d\n", MaxVideoFileSize); - fprintf(f, "SplitEditedFiles = %d\n", SplitEditedFiles); - fprintf(f, "MinEventTimeout = %d\n", MinEventTimeout); - fprintf(f, "MinUserInactivity = %d\n", MinUserInactivity); - fprintf(f, "MultiSpeedMode = %d\n", MultiSpeedMode); - fprintf(f, "ShowReplayMode = %d\n", ShowReplayMode); - PrintCaCaps(f, "CaCaps"); - fprintf(f, "CurrentChannel = %d\n", CurrentChannel); - fprintf(f, "CurrentVolume = %d\n", CurrentVolume); - if (f.Close()) { - isyslog(LOG_INFO, "saved setup to %s", FileName); - return true; - } - } +bool cSetup::Save(void) +{ + Store("OSDLanguage", OSDLanguage); + Store("PrimaryDVB", PrimaryDVB); + Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch); + Store("MenuScrollPage", MenuScrollPage); + Store("MarkInstantRecord", MarkInstantRecord); + Store("NameInstantRecord", NameInstantRecord); + Store("InstantRecordTime", InstantRecordTime); + Store("LnbSLOF", LnbSLOF); + Store("LnbFrequLo", LnbFrequLo); + Store("LnbFrequHi", LnbFrequHi); + Store("DiSEqC", DiSEqC); + Store("SetSystemTime", SetSystemTime); + Store("TimeTransponder", TimeTransponder); + Store("MarginStart", MarginStart); + Store("MarginStop", MarginStop); + Store("EPGScanTimeout", EPGScanTimeout); + Store("EPGBugfixLevel", EPGBugfixLevel); + Store("SVDRPTimeout", SVDRPTimeout); + Store("SortTimers", SortTimers); + Store("PrimaryLimit", PrimaryLimit); + Store("DefaultPriority", DefaultPriority); + Store("DefaultLifetime", DefaultLifetime); + Store("UseSubtitle", UseSubtitle); + Store("RecordingDirs", RecordingDirs); + Store("VideoFormat", VideoFormat); + Store("RecordDolbyDigital", RecordDolbyDigital); + Store("ChannelInfoPos", ChannelInfoPos); + Store("OSDwidth", OSDwidth); + Store("OSDheight", OSDheight); + Store("OSDMessageTime", OSDMessageTime); + Store("MaxVideoFileSize", MaxVideoFileSize); + Store("SplitEditedFiles", SplitEditedFiles); + Store("MinEventTimeout", MinEventTimeout); + Store("MinUserInactivity", MinUserInactivity); + Store("MultiSpeedMode", MultiSpeedMode); + Store("ShowReplayMode", ShowReplayMode); + StoreCaCaps("CaCaps"); + Store("CurrentChannel", CurrentChannel); + Store("CurrentVolume", CurrentVolume); + + Sort(); + + if (cConfig::Save()) { + isyslog(LOG_INFO, "saved setup to %s", FileName()); + return true; } - else - esyslog(LOG_ERR, "attempt to save setup without file name"); return false; } - diff --git a/config.h b/config.h index 00774b08f..3949dde7e 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.109 2002/04/07 13:08:12 kls Exp $ + * $Id: config.h 1.113 2002/05/04 14:29:29 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "1.0.0" +#define VDRVERSION "1.1.0" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -149,7 +149,7 @@ class cTimer : public cListObject { cTimer(const cEventInfo *EventInfo); virtual ~cTimer(); cTimer& operator= (const cTimer &Timer); - bool operator< (const cTimer &Timer); + virtual bool operator< (const cListObject &ListObject); const char *ToText(void); bool Parse(const char *s); bool Save(FILE *f); @@ -220,7 +220,8 @@ template class cConfig : public cList { public: cConfig(void) { fileName = NULL; } virtual ~cConfig() { delete fileName; } - virtual bool Load(const char *FileName, bool AllowComments = false) + const char *FileName(void) { return fileName; } + bool Load(const char *FileName, bool AllowComments = false) { Clear(); fileName = strdup(FileName); @@ -323,20 +324,42 @@ extern cCommands Commands; extern cSVDRPhosts SVDRPhosts; extern cCaDefinitions CaDefinitions; -class cSetup { +class cSetupLine : public cListObject { private: - static char *fileName; - void PrintCaCaps(FILE *f, const char *Name); - bool ParseCaCaps(const char *Value); + char *plugin; + char *name; + char *value; +public: + cSetupLine(void); + cSetupLine(const char *Name, const char *Value, const char *Plugin = NULL); + virtual ~cSetupLine(); + virtual bool operator< (const cListObject &ListObject); + const char *Plugin(void) { return plugin; } + const char *Name(void) { return name; } + const char *Value(void) { return value; } bool Parse(char *s); + bool Save(FILE *f); + }; + +class cSetup : public cConfig { + friend class cPlugin; // needs to be able to call Store() +private: + void StoreCaCaps(const char *Name); + bool ParseCaCaps(const char *Value); + bool Parse(const char *Name, const char *Value); + cSetupLine *Get(const char *Name, const char *Plugin = NULL); + void Store(const char *Name, const char *Value, const char *Plugin = NULL); + void Store(const char *Name, int Value, const char *Plugin = NULL); public: // Also adjust cMenuSetup (menu.c) when adding parameters here! + int __BeginData__; int OSDLanguage; int PrimaryDVB; int ShowInfoOnChSwitch; int MenuScrollPage; int MarkInstantRecord; char NameInstantRecord[MaxFileName]; + int InstantRecordTime; int LnbSLOF; int LnbFrequLo; int LnbFrequHi; @@ -365,9 +388,11 @@ class cSetup { int CaCaps[MAXDVBAPI][MAXCACAPS]; int CurrentChannel; int CurrentVolume; + int __EndData__; cSetup(void); + cSetup& operator= (const cSetup &s); bool Load(const char *FileName); - bool Save(const char *FileName = NULL); + bool Save(void); }; extern cSetup Setup; diff --git a/dvbapi.c b/dvbapi.c index 9d59d900e..77e537269 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.170 2002/04/07 09:35:51 kls Exp $ + * $Id: dvbapi.c 1.174 2002/05/03 15:59:32 kls Exp $ */ #include "dvbapi.h" @@ -279,8 +279,7 @@ bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *Pictu int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length, bool StayOffEnd) { if (index) { - if (Forward) - CatchUp(); + CatchUp(); int d = Forward ? 1 : -1; for (;;) { Index += d; @@ -533,6 +532,8 @@ void cRecordBuffer::Input(void) int w = Put(p, r); p += w; r -= w; + if (r > 0) + usleep(1); // this keeps the CPU load low } t = time(NULL); } @@ -1810,21 +1811,24 @@ bool cDvbApi::SetPrimaryDvbApi(int n) return false; } -int cDvbApi::CanShift(int Ca, int Priority) +int cDvbApi::CanShift(int Ca, int Priority, int UsedCards) { // Test whether a recording on this DVB device can be shifted to another one // in order to perform a new recording with the given Ca and Priority on this device: int ShiftLevel = -1; // default means this device can't be shifted + if (UsedCards & (1 << CardIndex()) != 0) + return ShiftLevel; // otherwise we would get into a loop if (Recording()) { if (ProvidesCa(Ca) // this device provides the requested Ca && (Ca != this->Ca() // the requested Ca is different from the one currently used... || Priority > this->Priority())) { // ...or the request comes from a higher priority cDvbApi *d = NULL; int Provides[MAXDVBAPI]; + UsedCards |= (1 << CardIndex()); for (int i = 0; i < NumDvbApis; i++) { if ((Provides[i] = dvbApi[i]->ProvidesCa(this->Ca())) != 0) { // this device is basicly able to do the job if (dvbApi[i] != this) { // it is not _this_ device - int sl = dvbApi[i]->CanShift(this->Ca(), Priority); // this is the original Priority! + int sl = dvbApi[i]->CanShift(this->Ca(), Priority, UsedCards); // this is the original Priority! if (sl >= 0 && (ShiftLevel < 0 || sl < ShiftLevel)) { d = dvbApi[i]; ShiftLevel = sl; @@ -2301,16 +2305,17 @@ bool cDvbApi::SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output) { if (Pid) { CHECK(ioctl(fd, DMX_STOP)); - dmxPesFilterParams pesFilterParams; - pesFilterParams.pid = Pid; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = Output; - pesFilterParams.pesType = PesType; - pesFilterParams.flags = DMX_IMMEDIATE_START; - if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { - if (Pid != 0x1FFF) + if (Pid != 0x1FFF) { + dmxPesFilterParams pesFilterParams; + pesFilterParams.pid = Pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = Output; + pesFilterParams.pesType = PesType; + pesFilterParams.flags = DMX_IMMEDIATE_START; + if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { LOG_ERROR; - return false; + return false; + } } } return true; diff --git a/dvbapi.h b/dvbapi.h index e9cf8c83a..7e638786b 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.68 2002/03/10 10:50:00 kls Exp $ + * $Id: dvbapi.h 1.69 2002/04/21 09:49:22 kls Exp $ */ #ifndef __DVBAPI_H @@ -104,7 +104,7 @@ class cDvbApi { static int useDvbApi; int cardIndex; int caCaps[MAXCACAPS]; - int CanShift(int Ca, int Priority); + int CanShift(int Ca, int Priority, int UsedCards = 0); public: static cDvbApi *PrimaryDvbApi; static void SetUseDvbApi(int n); diff --git a/dvbosd.c b/dvbosd.c index c34843005..eb962613b 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.12 2002/01/13 16:25:18 kls Exp $ + * $Id: dvbosd.c 1.13 2002/04/13 11:34:48 kls Exp $ */ #include "dvbosd.h" @@ -25,6 +25,9 @@ cPalette::cPalette(int Bpp) int cPalette::Index(eDvbColor Color) { +#if __BYTE_ORDER == __BIG_ENDIAN + Color = eDvbColor(((Color & 0xFF) << 24) | ((Color & 0xFF00) << 8) | ((Color & 0xFF0000) >> 8) | ((Color & 0xFF000000) >> 24)); +#endif for (int i = 0; i < numColors; i++) { if (color[i] == Color) { used[i] = true; diff --git a/i18n.c b/i18n.c index 0b22f1ddc..4129cf7ae 100644 --- a/i18n.c +++ b/i18n.c @@ -4,26 +4,29 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.79 2002/04/06 09:49:19 kls Exp $ + * $Id: i18n.c 1.87 2002/05/09 13:40:51 kls Exp $ * - * Slovenian translations provided by Miha Setina and Matjaz Thaler - * Italian translations provided by Alberto Carraro - * Dutch translations provided by Arnold Niessen - * Portuguese translations provided by Paulo Lopes - * French translations provided by Jean-Claude Repetto - * Norwegian translations provided by Jrgen Tvedt and Truls Slevigen - * Finnish translations provided by Hannu Savolainen - * Polish translations provided by Michael Rakowski - * Spanish translations provided by Ruben Nunez Francisco + * Translations provided by: + * + * Slovenian Miha Setina and Matjaz Thaler + * Italian Alberto Carraro + * Dutch Arnold Niessen + * Portuguese Paulo Lopes + * French Jean-Claude Repetto + * Norwegian Jrgen Tvedt and Truls Slevigen + * Finnish Hannu Savolainen + * Polish Michael Rakowski + * Spanish Ruben Nunez Francisco + * Greek Dimitrios Dimitrakos * */ /* * How to add a new language: * - * 1. Announce your translation action on the Linux-DVB mailing + * 1. Announce your translation action on the VDR mailing * list to avoid duplicate work. - * 2. Increase the value of 'NumLanguages'. + * 2. Increase the value of 'I18nNumLanguages' in 'i18n.h'. * 3. Insert a new line in every member of the 'Phrases[]' array, * containing the translated text for the new language. * For example, assuming you want to add the Italian language, @@ -45,7 +48,7 @@ * Note that only the characters defined in 'fontosd.c' will * be available! * 4. Compile VDR and test the new language by switching to it - * in the "Setup" menu. + * in the "Setup/OSD" menu. * 5. Send the modified 'i18n.c' file to to have * it included in the next version of VDR. * @@ -59,15 +62,10 @@ */ #include "i18n.h" -#include #include "config.h" #include "tools.h" -const int NumLanguages = 11; - -typedef const char *tPhrase[NumLanguages]; - -const tPhrase Phrases[] = { +const tI18nPhrase Phrases[] = { // The name of the language (this MUST be the first phrase!): { "English", "Deutsch", @@ -80,6 +78,7 @@ const tPhrase Phrases[] = { "Suomi", "Polski", "Espaol", + "Ellinika", }, // Menu titles: { "VDR", @@ -93,6 +92,7 @@ const tPhrase Phrases[] = { "VDR", "VDR", "VDR", + "VDR", }, { "Schedule", "Programm", @@ -105,6 +105,7 @@ const tPhrase Phrases[] = { "Ohjelmat", "Program", "Programa", + "Programma", }, { "Channels", "Kanle", @@ -117,6 +118,7 @@ const tPhrase Phrases[] = { "Kanavat", "Kanaly", "Canales", + "Kanalia", }, { "Timers", "Timer", @@ -129,6 +131,7 @@ const tPhrase Phrases[] = { "Ajastin", "Timery", "Timer", + "Programmatismos", }, { "Recordings", "Aufzeichnungen", @@ -141,6 +144,7 @@ const tPhrase Phrases[] = { "Nauhoitteet", "Nagrania", "Grabaciones", + "Egrafes", }, { "Setup", "Einstellungen", @@ -153,6 +157,7 @@ const tPhrase Phrases[] = { "Asetukset", "Nastawy", "Configuracin", + "Rithmisis", }, { "Commands", "Befehle", @@ -165,6 +170,7 @@ const tPhrase Phrases[] = { "Komennot", "Rozkazy", "rdenes", + "Entoles", }, { "Edit channel", "Kanal editieren", @@ -177,6 +183,7 @@ const tPhrase Phrases[] = { "Muokkaa kanavaa", "Ustawienie kanalu", "Modificar canal", + "Prosarmoges kanaliou", }, { "Edit timer", "Timer editieren", @@ -189,6 +196,7 @@ const tPhrase Phrases[] = { "Muokkaa ajastusta", "Ustawienie timerow", "Modificar timer", + "Prosarmoges programmatismou", }, { "Event", "Sendung", @@ -201,6 +209,7 @@ const tPhrase Phrases[] = { "Tapahtuma", "Audycja", "Evento", + "Ekpompi", }, { "Summary", "Inhalt", @@ -213,6 +222,7 @@ const tPhrase Phrases[] = { "Yhteenveto", "Zawartosc", "Resmen", + "Periexomeno", }, { "Schedule - %s", "Programm - %s", @@ -225,6 +235,7 @@ const tPhrase Phrases[] = { "Ohjelma - %s", "Program - %s", "Programa - %s", + "Programma - %s", }, { "What's on now?", "Was luft jetzt?", @@ -237,6 +248,7 @@ const tPhrase Phrases[] = { "Nykyinen ohjelma", "Program biezacy", "Qu hay ahora?", + "Ti pezi tora", }, { "What's on next?", "Was luft als nchstes?", @@ -249,6 +261,7 @@ const tPhrase Phrases[] = { "Seuraava ohjelma", "Program nastepny", "Qu hay proximo?", + "Ti tha peksi meta", }, // Button texts (should not be more than 10 characters!): { "Edit", @@ -262,6 +275,7 @@ const tPhrase Phrases[] = { "Muuta", "Edycja", "Modificar", + "Prosarmogi", }, { "New", "Neu", @@ -274,6 +288,7 @@ const tPhrase Phrases[] = { "Uusi", "Nowy", "Nuevo", + "Neo", }, { "Delete", "Lschen", @@ -286,6 +301,7 @@ const tPhrase Phrases[] = { "Poista", "Usunac", "Borrar", + "Swisimo", }, { "Mark", "Markieren", @@ -298,6 +314,7 @@ const tPhrase Phrases[] = { "Merkitse", "Zaznaczyc", "Marcar", + "Markarisma", }, { "On/Off", "Ein/Aus", @@ -310,6 +327,7 @@ const tPhrase Phrases[] = { "Pll/Pois", "Zal./ Wyl.", "On/Off", + "Energo/Klisto", }, { "Record", "Aufnehmen", @@ -322,6 +340,7 @@ const tPhrase Phrases[] = { "Nauhoita", "Nagrywac", "Grabar", + "Egrafi", }, { "Play", "Wiedergabe", @@ -334,6 +353,7 @@ const tPhrase Phrases[] = { "Toista", "Odtwarzac", "Play", + "Anametadosi", }, { "Rewind", "Anfang", @@ -346,6 +366,7 @@ const tPhrase Phrases[] = { "Takaisinkel.", "Poczatek", "Rebobinar", + "Arxi", }, { "Button$Stop", "Beenden", @@ -358,6 +379,7 @@ const tPhrase Phrases[] = { "Pysyt", "Zakonczyc", "Parar", + "Terma", }, { "Resume", "Weiter", @@ -370,6 +392,7 @@ const tPhrase Phrases[] = { "Jatka", "Dalej", "Continuar", + "Sinexia", }, { "Summary", "Inhalt", @@ -382,6 +405,7 @@ const tPhrase Phrases[] = { "Yhteenveto", "Zawartosc", "Resumen", + "Periexomeno", }, { "Open", "ffnen", @@ -394,6 +418,7 @@ const tPhrase Phrases[] = { "Avaa", "Otworzyc", "Abrir", + "Anigma", }, { "Switch", "Umschalten", @@ -406,6 +431,7 @@ const tPhrase Phrases[] = { "Valitse", "Przelaczyc", "Cambiar", + "Alagi", }, { "Now", "Jetzt", @@ -418,6 +444,7 @@ const tPhrase Phrases[] = { "Nyt", "Teraz", "Ahora", + "Tora", }, { "Next", "Nchste", @@ -430,6 +457,7 @@ const tPhrase Phrases[] = { "Seuraava", "Nastepny", "Siguiente", + "Epomeno", }, { "Button$Schedule", "Programm", @@ -442,6 +470,7 @@ const tPhrase Phrases[] = { "Ohjelmisto", "Program", "Programa", + "Programma", }, { "Language", "Sprache", @@ -454,6 +483,7 @@ const tPhrase Phrases[] = { "Kieli", "Jezyk", "Lengua", + "Glosa", }, { "Eject", "Auswerfen", @@ -466,6 +496,46 @@ const tPhrase Phrases[] = { "Avaa", "Wyrzucenie", "Eyectar", + "Apovoli", + }, + { "ABC/abc", + "ABC/abc", + "ABC/abc", + "ABC/abc", + "ABC/abc", + "ABC/abc", + "ABC/abc", + "ABC/abc", + "ABC/abc", + "ABC/abc", + "ABC/abc", + "ABC/abc", + }, + { "Insert", + "Einfgen", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "Isodos", + }, + { "Overwrite", + "berschreiben", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "Epanagrafi", }, // Confirmations: { "Delete channel?", @@ -479,6 +549,7 @@ const tPhrase Phrases[] = { "Poistetaanko kanava?", "Usunac kanal?", "Eliminar canal?", + "Na sviso to kanali?", }, { "Delete timer?", "Timer lschen?", @@ -491,6 +562,7 @@ const tPhrase Phrases[] = { "Poistetaanko ajastus?", "Usunac timer?", "Eliminar timer?", + "Svisimo tou programmitismou?", }, { "Delete recording?", "Aufzeichnung lschen?", @@ -503,18 +575,20 @@ const tPhrase Phrases[] = { "Poistetaanko nauhoitus?", "Usunac nagranie?", "Eliminar grabacion?", + "Svisimo tis egrafis?", }, { "Timer still recording - really delete?", "Timer zeichnet auf - trotzdem lschen?", "Snemanje po terminu - zares odstrani?", "Timer in regestazione - cancello?", - "Timer neemt nog op - toch verwijderen?" + "Timer neemt nog op - toch verwijderen?", "Timer activo - tm a certeza que quer apagar?", "Enregistrement en cours - confirmez la suppression", "Timer gjr opptak - vil du slette likevel?", "Ajastin nauhoittaa - poistetaanko silti?", "Nagrywanie w trakcie - napewno usunac?", "Timer activo - de verdad eliminarlo?", + "Ginete akoma programmatismeni egrafi - na svisti sigoura?", }, { "Stop recording?", "Aufzeichnung beenden?", @@ -527,6 +601,7 @@ const tPhrase Phrases[] = { "Pysytetnk nauhoitus?", "Zakonczyc nagranie?", "Parar grabacin?", + "Akirosi egrafis?", }, { "on primary interface", "auf dem primren Interface", @@ -539,6 +614,7 @@ const tPhrase Phrases[] = { "pvastaanottimella", "na pierwszym interfejsie", "en interface primario", + "stin protevon karta", }, { "Cancel editing?", "Schneiden abbrechen?", @@ -551,6 +627,7 @@ const tPhrase Phrases[] = { "Peruutetaanko muokkaus?", "Zakonczyc montaz?", "Cancelar modificacin?", + "Akirosi alagon?", }, { "Really restart?", "Wirklich neu starten?", @@ -563,6 +640,7 @@ const tPhrase Phrases[] = { "Aloitetaanko varmasti alusta?", "Rzeczywiscie nowy start?", "De verdad reiniciar?", + "Na gini sigoura epanekinisi?", }, { "Recording - restart anyway?", "Aufnahme luft - trotzdem neu starten?", @@ -575,6 +653,7 @@ const tPhrase Phrases[] = { "Nauhoitus kynniss - aloitetaanko alusta?", "Nagrywanie w trakcie - rzeczywiscie nowy start?", "Grabando - reiniciar?", + "Ginete egrafi - na gini epanekinisi sigoura?", }, { "Recording - shut down anyway?", "Aufnahme luft - trotzdem ausschalten?", @@ -587,6 +666,7 @@ const tPhrase Phrases[] = { "Nauhoitus kesken - lopetetaanko se?", "Nagrywanie w trakcie - mimo to wylaczyc?", "Grabando - apagar?", + "Ginete egrafi - na stamatisi i litourgia sigoura?", }, { "Recording in %d minutes, shut down anyway?", "Aufnahme in %d Minuten - trotzdem ausschalten?", @@ -599,6 +679,7 @@ const tPhrase Phrases[] = { "Nauhoitus alkaisi %d min. kuluttua - sammutetaanko silti?", "Nagrywanie za %d minut - mimo to wylaczyc?", "Grabando en %d minutos, de verdad cortar?", + "Anamenete egrafi se %d lepta - na stamatisi i litourgia sigoura?", }, { "Press any key to cancel shutdown", "Taste drcken um Shutdown abzubrechen", @@ -611,6 +692,7 @@ const tPhrase Phrases[] = { "Peruuta pysytys painamalla jotakin nppint", "Dowolny przycisk zatrzyma wylaczanie", "Pulse una tecla para interrumpir corte", + "Piese ena pliktro na stamatisi to katevasma", }, // Channel parameters: { "Name", @@ -624,6 +706,7 @@ const tPhrase Phrases[] = { "Nimi", "Nazwa", "Nombre", + "Onoma", }, { "Frequency", "Frequenz", @@ -636,6 +719,7 @@ const tPhrase Phrases[] = { "Taajuus", "Czestotliwosc", "Frecuencia", + "Sixnotita", }, { "Polarization", "Polarisation", @@ -648,6 +732,7 @@ const tPhrase Phrases[] = { "Polarisaatio", "Polaryzacja", "Polarizacin", + "Polosi", }, { "DiSEqC", "DiSEqC", @@ -660,6 +745,7 @@ const tPhrase Phrases[] = { "DiSEqC", "DiSEqC", "DiSEqC", + "DiSEqC", }, { "Srate", "Srate", @@ -672,6 +758,7 @@ const tPhrase Phrases[] = { "Srate", "Srate", "Srate", + "Srate", }, { "Vpid", "Vpid", @@ -684,6 +771,7 @@ const tPhrase Phrases[] = { "Kuva PID", "Vpid", "Vpid", + "Vpid", }, { "Apid1", "Apid1", @@ -696,6 +784,7 @@ const tPhrase Phrases[] = { "ni PID1", "Apid1", "Apid1", + "Apid1", }, { "Apid2", "Apid2", @@ -708,6 +797,7 @@ const tPhrase Phrases[] = { "ni PID2", "Apid2", "Apid2", + "Apid2", }, { "Dpid1", "Dpid1", @@ -720,6 +810,7 @@ const tPhrase Phrases[] = { "AC3 PID1", "Dpid1", "Dpid1", + "Dpid1", }, { "Dpid2", "Dpid2", @@ -732,6 +823,7 @@ const tPhrase Phrases[] = { "AC3 PID2", "Dpid2", "Dpid2", + "Dpid2", }, { "Tpid", "Tpid", @@ -744,6 +836,7 @@ const tPhrase Phrases[] = { "TekstiTV PID", "Tpid", "Tpid", + "Tpid", }, { "CA", "CA", @@ -756,6 +849,7 @@ const tPhrase Phrases[] = { "Salauskortti", "CA", "CA", + "CA", }, { "Pnr", "Pnr", @@ -768,6 +862,7 @@ const tPhrase Phrases[] = { "Ohjelmatunnus", "Pnr", "Pnr", + "Pnr", }, // Timer parameters: { "Active", @@ -781,6 +876,7 @@ const tPhrase Phrases[] = { "Aktiivinen", "Aktywny", "Activo", + "Energo", }, { "Channel", "Kanal", @@ -793,6 +889,7 @@ const tPhrase Phrases[] = { "Kanava", "Kanal", "Canal", + "Kanali", }, { "Day", "Tag", @@ -805,6 +902,7 @@ const tPhrase Phrases[] = { "Piv", "Dzien", "Da", + "Imera", }, { "Start", "Anfang", @@ -817,6 +915,7 @@ const tPhrase Phrases[] = { "Aloitus", "Poczatek", "Comienzo", + "Arxi", }, { "Stop", "Ende", @@ -829,6 +928,7 @@ const tPhrase Phrases[] = { "Lopetus", "Koniec", "Fin", + "Telos", }, { "Priority", "Prioritt", @@ -841,6 +941,7 @@ const tPhrase Phrases[] = { "Prioriteetti", "Priorytet", "Prioridad", + "Protereotita", }, { "Lifetime", "Lebensdauer", @@ -853,6 +954,7 @@ const tPhrase Phrases[] = { "Voimassaolo", "Trwalosc dni", "Durabilidad", + "Xronos Zois", }, { "File", "Datei", @@ -865,6 +967,7 @@ const tPhrase Phrases[] = { "Tiedosto", "Plik", "Fichero", + "Arxeio", }, { "First day", "Erster Tag", @@ -877,6 +980,7 @@ const tPhrase Phrases[] = { "1. piv", "Pierwszy dzien", "Primer da", + "Proti mera", }, // Error messages: { "Channel is being used by a timer!", @@ -890,6 +994,7 @@ const tPhrase Phrases[] = { "Kanava on ajastimen kytss!", "Kanal jest zajety przez timer nagran", "Canal est ocupado por un timer!", + "To kanali xrisimopiite apo programmatismeni thesi", }, { "Can't switch channel!", "Kanal kann nicht umgeschaltet werden!", @@ -902,6 +1007,7 @@ const tPhrase Phrases[] = { "Kanavan vaihtaminen ei mahdollista!", "Kanal nie moze byc teraz przelaczony!", "No puedo cambiar canal!", + "Den mporo na pao sto kanali!", }, { "Timer is recording!", "Timer zeichnet gerade auf!", @@ -914,6 +1020,7 @@ const tPhrase Phrases[] = { "Ajastinnauhoitus kynniss!", "Timer nagrywa!", "Timer esta grabando!", + "Ginete progrmamatismeni egrafi!", }, { "Error while accessing recording!", "Fehler beim Ansprechen der Aufzeichnung!", @@ -926,6 +1033,7 @@ const tPhrase Phrases[] = { "Nauhoituksen toistaminen eponnistui!", "Blad - brak dostepu do nagrania!", "Error al accesar la grabacin!", + "Lathos stin evresi tis egrafis!", }, { "Error while deleting recording!", "Fehler beim Lschen der Aufzeichnung!", @@ -938,6 +1046,7 @@ const tPhrase Phrases[] = { "Nauhoituksen poistaminen eponnistui!", "Blad przy usuwaniu nagrania!", "Error al borrar la grabacin!", + "Lathos stin prospathia na svisti i egrafi!", }, { "*** Invalid Channel ***", "*** Ungltiger Kanal ***", @@ -950,6 +1059,7 @@ const tPhrase Phrases[] = { "*** Virheellinen kanavavalinta! ***", "*** Niewazny kanal ***", "*** Canal invlido ***", + "*** Kanali akiro ***", }, { "No free DVB device to record!", "Keine freie DVB-Karte zum Aufnehmen!", @@ -962,6 +1072,7 @@ const tPhrase Phrases[] = { "Ei vapaata vastaanotinta nauhoitusta varten!", "Brak wolnej karty DVB do nagrywania!", "No hay dispositivo DVB disponible para grabar!", + "Den iparxi elevteri DVB Karta gia egrafi!", }, { "Channel locked (recording)!", "Kanal blockiert (zeichnet auf)!", @@ -974,6 +1085,7 @@ const tPhrase Phrases[] = { "Kanava lukittu (nauhoitusta varten)!", "Kanal zablokowany (nagrywanie w toku)!", "Canal bloqueado (grabando)!", + "To kanali ine mplokarismeno (Ginete egrafi)!", }, { "Can't start Transfer Mode!", "Transfer-Mode kann nicht gestartet werden!", @@ -986,6 +1098,7 @@ const tPhrase Phrases[] = { "Ksittmttmi teknisi ongelmia!", "Tryb transferowy jest niemozliwy!", "No puedo iniciar modo de transferencia!", + "Den mpori na arxisi to Transfer-Mode!", }, { "Can't start editing process!", "Schnitt kann nicht gestartet werden!", @@ -998,6 +1111,7 @@ const tPhrase Phrases[] = { "Muokkauksen aloittaminen ei onnistu!", "Uruchamianie montazu jest niemozliwe!", "No puedo iniciar proceso de modificacin!", + "Den mpori na arxisi to kopsimo tis tenias!", }, { "Editing process already active!", "Schnitt bereits aktiv!", @@ -1010,6 +1124,7 @@ const tPhrase Phrases[] = { "Muokkaus on jo kynniss!", "Montaz w toku!", "Proceso de modificacin ya fue iniciado!", + "To kopsimo ti tenias ini idi se litourgia!", }, { "Can't shutdown - option '-s' not given!", "Shutdown unmglich - Option '-s' fehlt!", @@ -1020,8 +1135,9 @@ const tPhrase Phrases[] = { "Arrt impossible - option '-s' absente!", "Kan ikke sl av - startet uten parameteret '-s'!", "Ei voida sammuttaa '-s' parametria ei annettu!", - "Wylaczenie niemozliwe - brak opcji '-s' !", + "Wylaczenie niemozliwe - brak opcji '-s'!", "No puedo cortar - opcin '-s' absente!", + "Den mporo na kliso ton ipologisti. Lipi i parametros '-s'!", }, { "Low disk space!", "Platte beinahe voll!", @@ -1034,6 +1150,7 @@ const tPhrase Phrases[] = { "Kovalevy lhes tynn!", "Dysk wkrotce pelny!", "Disco casi lleno", + "O Skliros kontevi na gemisi!", }, // Setup pages: { "OSD", @@ -1047,6 +1164,7 @@ const tPhrase Phrases[] = { "Tekstinytt", "OSD", "OSD", + "OSD", }, { "EPG", "EPG", @@ -1059,6 +1177,7 @@ const tPhrase Phrases[] = { "Ohjelmaopas", "EPG", "EPG", + "EPG", }, { "DVB", "DVB", @@ -1071,6 +1190,7 @@ const tPhrase Phrases[] = { "DVB", "DVB", "DVB", + "DVB", }, { "LNB", "LNB", @@ -1083,6 +1203,7 @@ const tPhrase Phrases[] = { "LNB", "LNB", "LNB", + "LNB", }, { "CICAM", "CICAM", @@ -1095,6 +1216,7 @@ const tPhrase Phrases[] = { "CICAM", "CICAM", "CICAM", + "CICAM", }, { "Recording", "Aufnahme", @@ -1107,6 +1229,7 @@ const tPhrase Phrases[] = { "Nauhoita", "Nagranie", "Grabacin", + "Egrafi", }, { "Replay", "Wiedergabe", @@ -1119,6 +1242,7 @@ const tPhrase Phrases[] = { "Toista", "Odtwarzanie", "Poner", + "Anametadosi", }, { "Miscellaneous", "Sonstiges", @@ -1131,6 +1255,20 @@ const tPhrase Phrases[] = { "Sekalaista", "Pozostale", "Varios", + "Diafora", + }, + { "Plugins", + "Plugins", + "Plugins", + "Plugins", + "Plugins", + "Plugins", + "Plugins", + "Plugins", + "Plugins", + "Plugins", + "Plugins", + "Plugins", }, { "Restart", "Neustart", @@ -1143,6 +1281,7 @@ const tPhrase Phrases[] = { "Aloita uudelleen", "Zastartowac", "Reiniciar", + "Epanekinisi", }, // Setup parameters: { "Setup.OSD$Language", @@ -1156,6 +1295,7 @@ const tPhrase Phrases[] = { "Kieli", "Jezyk", "Lengua", + "Glosa", }, { "Setup.OSD$Width", "Breite", @@ -1168,6 +1308,7 @@ const tPhrase Phrases[] = { "Leveys", "Szerokosc", "Anchura", + "Makros", }, { "Setup.OSD$Height", "Hhe", @@ -1180,6 +1321,7 @@ const tPhrase Phrases[] = { "Korkeus", "Wysokosc", "Altura", + "Ipsos", }, { "Setup.OSD$Message time (s)", "Anzeigedauer fr Nachrichten (s)", @@ -1192,6 +1334,7 @@ const tPhrase Phrases[] = { "Ilmoitusten nkymisaika (s)", "Czas wyswietlania wiadomosci (s)", "Duracin muestra mensajes (s)", + "Xronos endiksis minimaton (d)", }, { "Setup.OSD$Channel info position", "Kanal-Info Position", @@ -1204,6 +1347,7 @@ const tPhrase Phrases[] = { "Kanavainfon sijainti", "Lokalizacja informacji o kanale", "Posicin para informacin canal", + "Thesi Pliroforias kanalion", }, { "Setup.OSD$Info on channel switch", "Info beim Kanalwechsel", @@ -1216,6 +1360,7 @@ const tPhrase Phrases[] = { "Nyt kanavainfo", "Informacja przy zmianie kanalu", "Informacin para cambio de canal", + "Plirofories stin alagi kanaliou", }, { "Setup.OSD$Scroll pages", "Seitenweise scrollen", @@ -1228,6 +1373,7 @@ const tPhrase Phrases[] = { "Valikkojen rullaus", "Przesuwac stronami", "Desplazar pgina entera", + "Scroll selidas", }, { "Setup.OSD$Sort timers", "Timer sortieren", @@ -1240,6 +1386,7 @@ const tPhrase Phrases[] = { "Jrjest ajastimet", "Sortowanie timerow", "Ordenar timer", + "Organosi programmatismenon", }, { "Setup.OSD$Recording directories", "Aufnahmeverzeichnisse", @@ -1252,6 +1399,7 @@ const tPhrase Phrases[] = { "Nauhoitushakemistot", "Wykaz nagran", "Directorios para grabacin", + "Fakeli egrafon", }, { "Setup.EPG$EPG scan timeout (h)", "Zeit bis EPG Scan (h)", @@ -1264,6 +1412,7 @@ const tPhrase Phrases[] = { "Ohjelmatied. odotusaika (h)", "Czas do skanu EPG (h)", "Tiempo hasta exploracin EPG (h)", + "Xronos mexri sarosi EPG se Ores", }, { "Setup.EPG$EPG bugfix level", "EPG Fehlerbereinigung", @@ -1276,6 +1425,7 @@ const tPhrase Phrases[] = { "EPG Bugfix Level", "Poziom bledow EPG", "Nivel para arreglar EPG", + "EPG Bugfix Vathmos", }, { "Setup.EPG$Set system time", "Systemzeit stellen", @@ -1288,6 +1438,7 @@ const tPhrase Phrases[] = { "Vastaanota kellonaika", "Ustawianie czasu", "Ajustar reloj de sistema", + "Sintonismos Oras ipologosti", }, { "Setup.EPG$Use time from transponder", "Transponder fr Systemzeit", @@ -1300,6 +1451,7 @@ const tPhrase Phrases[] = { "Vastaanota kellonaika lhettimelt", "Transponder do ustawiania czasu", "Transponder para reloj de sistema", + "Transponder gia sintonismo tis oras", }, { "Setup.DVB$Primary DVB interface", "Primres DVB Interface", @@ -1312,6 +1464,7 @@ const tPhrase Phrases[] = { "Ensisij. vast.otin", "Pierwotny interfejs DVB", "Primer interface DVB", + "Protevon DVB karta", }, { "Setup.DVB$Video format", "Video Format", @@ -1324,6 +1477,7 @@ const tPhrase Phrases[] = { "Kuvamuoto", "Format telewizyjny", "Formato Vdeo", + "Video Format", }, { "Setup.LNB$SLOF (MHz)", "SLOF (MHz)", @@ -1336,6 +1490,7 @@ const tPhrase Phrases[] = { "SLOF (MHz)", "SLOF (MHz)", "SLOF (MHz)", + "SLOF (MHz)", }, { "Setup.LNB$Low LNB frequency (MHz)", "Untere LNB-Frequenz (MHz)", @@ -1348,6 +1503,7 @@ const tPhrase Phrases[] = { "LO LNB taajuus (MHz)", "Dolna czestotliwosc LNB (MHz)", "Frecuencia baja LNB (MHz)", + "Kato LNB-Sixnotita (MHz)", }, { "Setup.LNB$High LNB frequency (MHz)", "Obere LNB-Frequenz (MHz)", @@ -1360,6 +1516,7 @@ const tPhrase Phrases[] = { "HI LNB taajuus (MHz)", "Gorna czestotliwosc LNB (MHz)", "Frecuencia alta LNB (MHz)", + "Ano LNB-Sixnotita (MHz)", }, { "Setup.LNB$Use DiSEqC", "DiSEqC benutzen", @@ -1372,6 +1529,7 @@ const tPhrase Phrases[] = { "Kyt DiSEqC", "Uzywac DiSEqC", "Utilizar DiSEqC", + "Energopiisi DiSEqC", }, { "Setup.CICAM$CICAM DVB", "CICAM DVB", @@ -1384,6 +1542,7 @@ const tPhrase Phrases[] = { "CICAM DVB", "CICAM DVB", "CICAM DVB", + "CICAM DVB", }, { "Setup.Recording$Margin at start (min)", "Zeitpuffer bei Anfang (min)", @@ -1396,6 +1555,7 @@ const tPhrase Phrases[] = { "Aloitusmarginaali (min)", "Poczatkowy czas buforowy (min)", "Comenzar grabacin antes (min)", + "Prosthetos xronos prin arxi (lepta)", }, { "Setup.Recording$Margin at stop (min)", "Zeitpuffer bei Ende (min)", @@ -1408,6 +1568,7 @@ const tPhrase Phrases[] = { "Lopetusmarginaali (min)", "Koncowy czas buforowy (min)", "Cortar grabacin despus (min)", + "Prosthetos xronos sto telos (lepta)", }, { "Setup.Recording$Primary limit", "Primr-Limit", @@ -1420,6 +1581,7 @@ const tPhrase Phrases[] = { "PrimaryLimit", "Pierwotny limit", "L'mite primario", + "Protevon limit", }, { "Setup.Recording$Default priority", "Default Prioritt", @@ -1432,6 +1594,7 @@ const tPhrase Phrases[] = { "Oletusprioriteetti", "Priorytet pierwotny", "Prioridad predefinida", + "Protereotita", }, { "Setup.Recording$Default lifetime (d)", "Default Lebensdauer (d)", @@ -1444,6 +1607,7 @@ const tPhrase Phrases[] = { "Oletus voimassaoloaika (d)", "Pierwotna trwalosc (d)", "Duracin predefinida", + "Xronos zois", }, { "Setup.Recording$Use episode name", "Episodenname verwenden", @@ -1456,6 +1620,7 @@ const tPhrase Phrases[] = { "Kyt jakson nime", "Czy uzywac nazwe epizodu", "Utilizar nombre de episodo", + "Xrisimopiisi onomatos episodiou", }, { "Setup.Recording$Mark instant recording", "Direktaufzeichnung markieren", @@ -1468,6 +1633,7 @@ const tPhrase Phrases[] = { "Merkitse vlitn nauh.", "Zaznaczyc natychm. nagranie", "Marcar grabaciones instantneas", + "Markarisma apevthias egrafis", }, { "Setup.Recording$Name instant recording", "Direktaufzeichnung benennen", @@ -1480,6 +1646,20 @@ const tPhrase Phrases[] = { "Nime vlitn nauh.", "Nazwac natychm. nagranie", "Nombrar grabaciones instantneas", + "eponomasi apevthias egrafis", + }, + { "Setup.Recording$Instant rec. time (min)", + "Dauer der Direktaufzeichnung (min)", + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO }, { "Setup.Recording$Record Dolby Digital", "Dolby Digital Ton aufzeichnen", @@ -1492,6 +1672,7 @@ const tPhrase Phrases[] = { "Dolby Digital nauhoitus", "Nagrywac Dolby Digital", "Grabar sonido Dolby Digital", + "Egrafi tou Dolby Digital ixou", }, { "Setup.Recording$Max. video file size (MB)", "Max. Video Dateigre (MB)", @@ -1504,6 +1685,7 @@ const tPhrase Phrases[] = { "Maksimi tiedoston koko (MB)", "Maks. wielkosc pliku (MB)", "Tamao mx. ficheros (MB)", + "Megisto megethos arxeiou (MB)", }, { "Setup.Recording$Split edited files", "Editierte Dateien aufteilen", @@ -1516,6 +1698,7 @@ const tPhrase Phrases[] = { "Paloittele muokatut", "Dzielic montowane pliki", "Quebrar ficheros", + "Diamelisma epeksergasm. arxeion", }, { "Setup.Replay$Multi speed mode", "MultiSpeed Modus", @@ -1528,6 +1711,7 @@ const tPhrase Phrases[] = { "Moninopeustila", "Tryb wielopredkosciowy", "Modo multi-velocidad", + "Multispeed modus", }, { "Setup.Replay$Show replay mode", "Wiedergabestatus anzeigen", @@ -1540,6 +1724,7 @@ const tPhrase Phrases[] = { "Nyt toiston tila", "Wyswietlac status odtwarzania", "Mostrar modo de replay", + "Endiksi status anametadosis", }, { "Setup.Miscellaneous$Min. event timeout (min)", "Mindest Event Pause (min)", @@ -1552,6 +1737,7 @@ const tPhrase Phrases[] = { "Minimi tapahtuman odotus (min)", "Min. czas do nast. akcji (Event) (min)", "Tiempo mnimo pausa (min)", + "Elaxistos Xronos paremvolis (lepta)", }, { "Setup.Miscellaneous$Min. user inactivity (min)", "Mindest Benutzer-Inaktivitt (min)", @@ -1564,18 +1750,20 @@ const tPhrase Phrases[] = { "Minimi kyttjn odotus (min)", "Min. brak aktywnosci uzytkownika (min)", "Tiempo mnimo inactividad (min)", - }, - { "Setup.Miscellaneous$SVDRP timeout (min)", - "SVDRP Timeout (min)", - "SVDRP Timeout (min)", - "Timeout SVDRP (min)", - "SVDRP Timeout (min)", - "Timeout SVDRP (min)", - "Temps maxi SVDRP (min)", - "Ubrukt SVDRP-levetid (min)", - "SVDRP odotusaika (min)", - "Min. brak aktywnosci SVDRP (min)", - "SVDRP interrupcin (min)", + "Elaxistos xronos mi xrisis (lepta)", + }, + { "Setup.Miscellaneous$SVDRP timeout (s)", + "SVDRP Timeout (s)", + "SVDRP Timeout (s)", + "Timeout SVDRP (s)", + "SVDRP Timeout (s)", + "Timeout SVDRP (s)", + "Temps maxi SVDRP (s)", + "Ubrukt SVDRP-levetid (s)", + "SVDRP odotusaika (s)", + "Min. brak aktywnosci SVDRP (s)", + "SVDRP interrupcin (s)", + "SVDRP Timeout (d)", }, // The days of the week: { "MTWTFSS", @@ -1589,6 +1777,7 @@ const tPhrase Phrases[] = { "MTKTPLS", "PWSCPSN", "LMMJVSD", + "DTTPPSK", }, { "MonTueWedThuFriSatSun", // must all be 3 letters! "MonDieMitDonFreSamSon", @@ -1601,6 +1790,21 @@ const tPhrase Phrases[] = { "MaaTiiKesTorPerLauSun", "PonWtoSroCzwPiaSobNie", "LunMarMieJueVieSabDom", + "DevTriTetPemParSavKir", + }, + // The allowed characters in strings: + { " abcdefghijklmnopqrstuvwxyz0123456789-.#~", + " abcdefghijklmnopqrstuvwxyz0123456789-.#~", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + " abcdefghijklmnopqrstuvwxyz0123456789-.#~", + "",// TODO }, // Learning keys: { "Learning Remote Control Keys", @@ -1614,6 +1818,7 @@ const tPhrase Phrases[] = { "Kaukostimen nppinten opettelu", "Nauka kodu pilota", "Aprendiendo teclas del telemando", + "Ekmathisi Remote Control", }, { "Phase 1: Detecting RC code type", "Phase 1: FB Code feststellen", @@ -1626,6 +1831,7 @@ const tPhrase Phrases[] = { "Vaihe 1: Lhetystavan selvittminen", "Faza 1: Detekcja typu kodu", "Fase 1: Detectando tipo de receptor", + "Phasi 1: Dilosi RC Code", }, { "Press any key on the RC unit", "Eine Taste auf der FB drcken", @@ -1638,6 +1844,7 @@ const tPhrase Phrases[] = { "Paina mit tahansa kaukostimen nppint", "Nacisnac klawisz pilota", "Pulse una tecla en el telemando", + "Pata ena pliktro sto RC", }, { "RC code detected!", "FB Code erkannt!", @@ -1650,6 +1857,7 @@ const tPhrase Phrases[] = { "Nppinpainallus vastaanotettu!", "Kod pilota zostal poznany!", "Cdigo detectado!", + "Evresi RC Code!", }, { "Do not press any key...", "Keine Taste drcken...", @@ -1662,6 +1870,7 @@ const tPhrase Phrases[] = { "l paina mitn nppint...", "Nie naciskac klawiszy...", "No pulse tecla...", + "Min patas Pliktra...", }, { "Phase 2: Learning specific key codes", "Phase 2: Einzelne Tastencodes lernen", @@ -1674,6 +1883,7 @@ const tPhrase Phrases[] = { "Vaihe 2: Nppinkoodien opettelu", "Faza 2: Nauka pojedynczych klawiszy", "Fase 2: Aprendiendo cdigos especficos", + "Fasi 2: Ekmathisi memonomenon kodikon pliktron", }, { "Press key for '%s'", "Taste fr '%s' drcken", @@ -1686,6 +1896,7 @@ const tPhrase Phrases[] = { "Paina nppint toiminnolle '%s'", "Nacisnac klawisz dla '%s'", "Pulsar tecla para '%s'", + "Pata to pliktro gia '%s'", }, { "Press 'Up' to confirm", "'Auf' drcken zum Besttigen", @@ -1698,6 +1909,7 @@ const tPhrase Phrases[] = { "Paina 'Yls' hyvksyksesi", "Nacisnac 'Gora' do potwierdzenia", "Pulse 'Arriba' para confirmar", + "Pata 'pano' gia apodoxi", }, { "Press 'Down' to continue", "'Ab' drcken zum Weitermachen", @@ -1710,6 +1922,7 @@ const tPhrase Phrases[] = { "Paina 'Alas' jatkaaksesi", "Nacisnac 'Dol' zeby kontynuowac", "Pulse 'Abajo' para confirmar", + "Pata 'kato' gia sinexia", }, { "(press 'Up' to go back)", "('Auf' drcken um zurckzugehen)", @@ -1722,6 +1935,7 @@ const tPhrase Phrases[] = { "(paina 'Yls' palataksesi takaisin)", "(Nacisnac 'Gora' cofa)", "(Pulse 'Arriba' para retornar)", + "(Pata 'pano' gia na pas piso)", }, { "(press 'Down' to end key definition)", "('Ab' drcken zum Beenden)", @@ -1734,6 +1948,7 @@ const tPhrase Phrases[] = { "(paina 'Alas' lopettaaksesi nppinten opettelun)", "(Nacisnac 'Dol' by zakonczyc)", "(Pulse 'Abajo' para terminar programacin teclas)", + "(Pata 'Kato' gia termatismo)", }, { "Phase 3: Saving key codes", "Phase 3: Codes abspeichern", @@ -1746,6 +1961,7 @@ const tPhrase Phrases[] = { "Vaihe 3: Nppinkoodien tallettaminen", "Faza 3: Zapamietac Kod", "Fase 3: Guardar cdigos de teclas", + "Fasi 3: Apothikevsi kodikon", }, { "Press 'Up' to save, 'Down' to cancel", "'Auf' speichert, 'Ab' bricht ab", @@ -1758,6 +1974,7 @@ const tPhrase Phrases[] = { "Paina 'Yls' tallettaaksesi ja 'Alas' peruuttaaksesi", "'Gora' zapamietuje, 'Dol' przerywa", "Pulse 'Arriba' para guarder, 'Abajo' para anular", + "'kato' apothikevsi, 'Pano' akirosi", }, // Key names: { "Up", @@ -1771,6 +1988,7 @@ const tPhrase Phrases[] = { "Yls", "Gora", "Arriba", + "Pano", }, { "Down", "Ab", @@ -1783,6 +2001,7 @@ const tPhrase Phrases[] = { "Alas", "Dol", "Abajo", + "Kato", }, { "Menu", "Men", @@ -1795,6 +2014,7 @@ const tPhrase Phrases[] = { "Valikko", "Menu", "Menu", + "Menou", }, { "Ok", "Ok", @@ -1807,6 +2027,7 @@ const tPhrase Phrases[] = { "Ok", "Ok", "Ok", + "Ok", }, { "Back", "Zurck", @@ -1819,6 +2040,7 @@ const tPhrase Phrases[] = { "Takaisin", "Wstecz", "Retornar", + "Piso", }, { "Left", "Links", @@ -1831,6 +2053,7 @@ const tPhrase Phrases[] = { "Vasemmalle", "Lewo", "Izquierda", + "Aristera", }, { "Right", "Rechts", @@ -1843,6 +2066,7 @@ const tPhrase Phrases[] = { "Oikealle", "Prawo", "Derecha", + "Deksia", }, { "Red", "Rot", @@ -1855,6 +2079,7 @@ const tPhrase Phrases[] = { "Punainen", "Czerwony", "Rojo", + "Kokino", }, { "Green", "Grn", @@ -1867,6 +2092,7 @@ const tPhrase Phrases[] = { "Vihre", "Zielony", "Verde", + "Prasino", }, { "Yellow", "Gelb", @@ -1879,6 +2105,7 @@ const tPhrase Phrases[] = { "Keltainen", "Zolty", "Amarillo", + "Kitrino", }, { "Blue", "Blau", @@ -1891,6 +2118,7 @@ const tPhrase Phrases[] = { "Sininen", "Niebieski", "Azul", + "Mple", }, { "Power", "Ausschalten", @@ -1903,6 +2131,7 @@ const tPhrase Phrases[] = { "Virtakytkin", "Wylaczyc", "Corriente", + "Klisimo", }, { "Volume+", "Lautstrke+", @@ -1915,6 +2144,7 @@ const tPhrase Phrases[] = { "nenvoimakkuus+", "Glosnej", "Volumen+", + "Entasi+", }, { "Volume-", "Lautstrke-", @@ -1927,6 +2157,7 @@ const tPhrase Phrases[] = { "nenvoimakkuus-", "Ciszej", "Volumen-", + "Entasi-", }, { "Mute", "Stumm", @@ -1939,6 +2170,7 @@ const tPhrase Phrases[] = { "nen vaimennus", "Cisza", "Mudo", + "Mougko", }, // Miscellaneous: { "yes", @@ -1952,6 +2184,7 @@ const tPhrase Phrases[] = { "kyll", "tak", "s", + "nai", }, { "no", "nein", @@ -1964,6 +2197,7 @@ const tPhrase Phrases[] = { "ei", "nie", "no", + "oxi", }, { "top", "oben", @@ -1976,6 +2210,7 @@ const tPhrase Phrases[] = { "yl", "gora", "parte sup.", + "pano", }, { "bottom", "unten", @@ -1988,6 +2223,7 @@ const tPhrase Phrases[] = { "ala", "dol", "fondo", + "kato", }, { "Disk", "Disk", @@ -2000,6 +2236,7 @@ const tPhrase Phrases[] = { "Disk", "Disk", "Disco", + "Disk", }, { "free", "frei", @@ -2012,6 +2249,7 @@ const tPhrase Phrases[] = { "vapaa", "pozostalo", "libre", + "akoma", }, { "Jump: ", // note the trailing blank "Springen: ", @@ -2024,6 +2262,7 @@ const tPhrase Phrases[] = { "Hypp: ", "Skok: ", "Saltar: ", + "Pidima: ", }, { "Volume ", // note the trailing blank "Lautstrke ", @@ -2036,6 +2275,7 @@ const tPhrase Phrases[] = { "nenvoimakkuus ", "Glosnosc ", "Volumen ", + "Entasi ", }, { " Stop replaying", // note the leading blank! " Wiedergabe beenden", @@ -2048,6 +2288,7 @@ const tPhrase Phrases[] = { " Pysyt toisto", " Zatrzymac odtwarzanie", " Parar reproducin", + " Telos anametadosis", }, { " Stop recording ", // note the leading and trailing blanks! " Aufzeichnung beenden ", @@ -2060,6 +2301,7 @@ const tPhrase Phrases[] = { " Pysyt nauhoitus ", " Zatrzymac nagrywanie ", " Parar grabacin ", + " Telos egrafis ", }, { " Cancel editing", // note the leading blank! " Schneiden abbrechen", @@ -2070,8 +2312,9 @@ const tPhrase Phrases[] = { " Annuler le montage", " Avbryt redigering", " Peruuta muokkaus", - " Przerwac montaz ", - " Anular modificacin ", + " Przerwac montaz", + " Anular modificacin", + " Diakopi kopsimatos", }, { "Switching primary DVB...", "Primres Interface wird umgeschaltet...", @@ -2080,10 +2323,11 @@ const tPhrase Phrases[] = { "Eerste DVB-kaart wordt omgeschakeld...", "A mudar interface DVB primrio...", "Changement de carte DVB primaire...", - "Bytter frste DVB-enhet..." + "Bytter frste DVB-enhet...", "Vaihdetaan ensisijainen vastaanotin...", "Pierwszy interfejs DVB przelacza...", "Cambio interface primario...", + "I protevon DVB Karta alazi...", }, { "Up/Dn for new location - OK to move", "Auf/Ab fr neue Position - dann OK", @@ -2096,6 +2340,7 @@ const tPhrase Phrases[] = { "Yls/Alas = liiku, OK = siirr", "Gora/Dol na nowa pozycje - Ok zmienia", "Arriba/Abajo para nuevo lugar - OK para mover", + "Pano/Kato gia nea thesi. meta OK", }, { "Editing process started", "Schnitt gestartet", @@ -2108,6 +2353,7 @@ const tPhrase Phrases[] = { "Muokkaus aloitettu", "Uruchomiony proces montazu", "Proceso modificacin iniciado", + "Arxi kopsimatos", }, { "Editing process finished", "Schnitt beendet", @@ -2120,6 +2366,7 @@ const tPhrase Phrases[] = { "Muokkaus lopetettu", "Proces montazu zakonczony", "Proceso modificacion terminado", + "To kopsimo termatistike", }, { "Editing process failed!", "Schnitt gescheitert!", @@ -2132,6 +2379,7 @@ const tPhrase Phrases[] = { "Muokkaus eponnistui!", "Bledny proces montazu!", "Modificacin ha fallado!", + "Kopsimo apetixe!", }, { "scanning recordings...", "Aufzeichnungen werden durchsucht...", @@ -2144,27 +2392,103 @@ const tPhrase Phrases[] = { "haetaan nauhoituksia...", "Skan nagran...", "buscando grabaciones...", + "Ginete sarosi egrafon...", + }, + { "This plugin has no setup parameters!", + "Dieses Plugin hat keine Setup-Parameter!", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO }, { NULL } }; -const char *tr(const char *s) +// --- cI18nEntry ------------------------------------------------------------ + +class cI18nEntry : public cListObject { +private: + const tI18nPhrase *phrases; + const char *plugin; +public: + cI18nEntry(const tI18nPhrase * const Phrases, const char *Plugin); + const tI18nPhrase *Phrases(void) { return phrases; } + const char *Plugin(void) { return plugin; } + }; + +cI18nEntry::cI18nEntry(const tI18nPhrase * const Phrases, const char *Plugin) +{ + phrases = Phrases; + plugin = Plugin; +} + +// --- cI18nList ------------------------------------------------------------- + +class cI18nList : public cList { +public: + cI18nEntry *Get(const char *Plugin); + const tI18nPhrase *GetPhrases(const char *Plugin); + }; + +cI18nEntry *cI18nList::Get(const char *Plugin) +{ + if (Plugin) { + for (cI18nEntry *p = First(); p; p = Next(p)) { + if (strcmp(p->Plugin(), Plugin) == 0) + return p; + } + } + return NULL; +} + +const tI18nPhrase *cI18nList::GetPhrases(const char *Plugin) +{ + cI18nEntry *p = Get(Plugin); + return p ? p->Phrases() : NULL; +} + +cI18nList I18nList; + +// --- + +void I18nRegister(const tI18nPhrase * const Phrases, const char *Plugin) +{ + cI18nEntry *p = I18nList.Get(Plugin); + if (p) + I18nList.Del(p); + if (Phrases) + I18nList.Add(new cI18nEntry(Phrases, Plugin)); +} + +const char *I18nTranslate(const char *s, const char *Plugin) { if (Setup.OSDLanguage) { - for (const tPhrase *p = Phrases; **p; p++) { - if (strcmp(s, **p) == 0) { - const char *t = (*p)[Setup.OSDLanguage]; - if (t && *t) - return t; - } + const tI18nPhrase *p = Plugin ? I18nList.GetPhrases(Plugin) : Phrases; + if (!p) + p = Phrases; + for (int i = ((p == Phrases) ? 1 : 2); i--; ) { + for (; **p; p++) { + if (strcmp(s, **p) == 0) { + const char *t = (*p)[Setup.OSDLanguage]; + if (t && *t) + return t; + } + } + p = Phrases; } - esyslog(LOG_ERR, "no translation found for '%s' in language %d (%s)\n", s, Setup.OSDLanguage, Phrases[0][Setup.OSDLanguage]); + esyslog(LOG_ERR, "%s%sno translation found for '%s' in language %d (%s)\n", Plugin ? Plugin : "", Plugin ? ": " : "", s, Setup.OSDLanguage, Phrases[0][Setup.OSDLanguage]); } const char *p = strchr(s, '$'); return p ? p + 1 : s; } -const char * const * Languages(void) +const char * const * I18nLanguages(void) { return &Phrases[0][0]; } diff --git a/i18n.h b/i18n.h index c94241a54..68fe7364c 100644 --- a/i18n.h +++ b/i18n.h @@ -4,16 +4,28 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.h 1.1 2000/11/11 09:27:25 kls Exp $ + * $Id: i18n.h 1.2 2002/05/05 13:42:31 kls Exp $ */ #ifndef __I18N_H #define __I18N_H -extern const int NumLanguages; +#include -const char *tr(const char *s); +const int I18nNumLanguages = 12; -const char * const * Languages(void); +typedef const char *tI18nPhrase[I18nNumLanguages]; + +void I18nRegister(const tI18nPhrase * const Phrases, const char *Plugin); + +const char *I18nTranslate(const char *s, const char *Plugin = NULL); + +const char * const * I18nLanguages(void); + +#ifdef PLUGIN_NAME_I18N +#define tr(s) I18nTranslate(s, PLUGIN_NAME_I18N) +#else +#define tr(s) I18nTranslate(s) +#endif #endif //__I18N_H diff --git a/interface.h b/interface.h index dbfa1bca7..914a38346 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.24 2001/09/01 15:14:50 kls Exp $ + * $Id: interface.h 1.25 2002/04/19 13:17:15 kls Exp $ */ #ifndef __INTERFACE_H @@ -46,6 +46,7 @@ class cInterface { void SetBitmap(int x, int y, const cBitmap &Bitmap); void Flush(void); void SetCols(int *c); + const int *GetCols(void) { return cols; } eDvbFont SetFont(eDvbFont Font); char *WrapText(const char *Text, int Width, int *Height); void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); diff --git a/menu.c b/menu.c index bc3aeb6e5..ef7581957 100644 --- a/menu.c +++ b/menu.c @@ -4,10 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.182 2002/04/06 09:41:59 kls Exp $ + * $Id: menu.c 1.190 2002/05/09 10:13:47 kls Exp $ */ #include "menu.h" +#include #include #include #include @@ -15,134 +16,19 @@ #include "config.h" #include "eit.h" #include "i18n.h" +#include "menuitems.h" +#include "plugin.h" #include "videodir.h" #define MENUTIMEOUT 120 // seconds #define MAXWAIT4EPGINFO 10 // seconds #define MODETIMEOUT 3 // seconds -#define CHNUMWIDTH (Channels.Count() > 999 ? 5 : 4) // there are people with more than 999 channels... - -const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#~^"; - -// --- cMenuEditItem --------------------------------------------------------- - -class cMenuEditItem : public cOsdItem { -private: - const char *name; - const char *value; -public: - cMenuEditItem(const char *Name); - ~cMenuEditItem(); - void SetValue(const char *Value); - }; - -cMenuEditItem::cMenuEditItem(const char *Name) -{ - name = strdup(Name); - value = NULL; -} - -cMenuEditItem::~cMenuEditItem() -{ - delete name; - delete value; -} - -void cMenuEditItem::SetValue(const char *Value) -{ - delete value; - value = strdup(Value); - char *buffer = NULL; - asprintf(&buffer, "%s:\t%s", name, value); - SetText(buffer, false); - Display(); -} - -// --- cMenuEditIntItem ------------------------------------------------------ - -class cMenuEditIntItem : public cMenuEditItem { -protected: - int *value; - int min, max; - virtual void Set(void); -public: - cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX); - virtual eOSState ProcessKey(eKeys Key); - }; - -cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max) -:cMenuEditItem(Name) -{ - value = Value; - min = Min; - max = Max; - Set(); -} - -void cMenuEditIntItem::Set(void) -{ - char buf[16]; - snprintf(buf, sizeof(buf), "%d", *value); - SetValue(buf); -} +#define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours -eOSState cMenuEditIntItem::ProcessKey(eKeys Key) -{ - eOSState state = cMenuEditItem::ProcessKey(Key); - - if (state == osUnknown) { - int newValue; - if (k0 <= Key && Key <= k9) { - if (fresh) { - *value = 0; - fresh = false; - } - newValue = *value * 10 + (Key - k0); - } - else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? - newValue = *value - 1; - fresh = true; - } - else if (NORMALKEY(Key) == kRight) { - newValue = *value + 1; - fresh = true; - } - else - return state; - if ((!fresh || min <= newValue) && newValue <= max) { - *value = newValue; - Set(); - } - state = osContinue; - } - return state; -} - -// --- cMenuEditBoolItem ----------------------------------------------------- - -class cMenuEditBoolItem : public cMenuEditIntItem { -protected: - const char *falseString, *trueString; - virtual void Set(void); -public: - cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString = NULL, const char *TrueString = NULL); - }; +#define CHNUMWIDTH (Channels.Count() > 999 ? 5 : 4) // there are people with more than 999 channels... -cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString) -:cMenuEditIntItem(Name, Value, 0, 1) -{ - falseString = FalseString ? FalseString : tr("no"); - trueString = TrueString ? TrueString : tr("yes"); - Set(); -} - -void cMenuEditBoolItem::Set(void) -{ - char buf[16]; - snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString); - SetValue(buf); -} +const char *FileNameChars = " abcdefghijklmnopqrstuvwxyz0123456789-.#~"; // --- cMenuEditChanItem ----------------------------------------------------- @@ -448,186 +334,6 @@ eOSState cMenuEditTimeItem::ProcessKey(eKeys Key) return state; } -// --- cMenuEditChrItem ------------------------------------------------------ - -class cMenuEditChrItem : public cMenuEditItem { -private: - char *value; - const char *allowed; - const char *current; - virtual void Set(void); -public: - cMenuEditChrItem(const char *Name, char *Value, const char *Allowed); - ~cMenuEditChrItem(); - virtual eOSState ProcessKey(eKeys Key); - }; - -cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed) -:cMenuEditItem(Name) -{ - value = Value; - allowed = strdup(Allowed); - current = strchr(allowed, *Value); - if (!current) - current = allowed; - Set(); -} - -cMenuEditChrItem::~cMenuEditChrItem() -{ - delete allowed; -} - -void cMenuEditChrItem::Set(void) -{ - char buf[2]; - snprintf(buf, sizeof(buf), "%c", *value); - SetValue(buf); -} - -eOSState cMenuEditChrItem::ProcessKey(eKeys Key) -{ - eOSState state = cMenuEditItem::ProcessKey(Key); - - if (state == osUnknown) { - if (NORMALKEY(Key) == kLeft) { - if (current > allowed) - current--; - } - else if (NORMALKEY(Key) == kRight) { - if (*(current + 1)) - current++; - } - else - return state; - *value = *current; - Set(); - state = osContinue; - } - return state; -} - -// --- cMenuEditStrItem ------------------------------------------------------ - -class cMenuEditStrItem : public cMenuEditItem { -private: - char *value; - int length; - const char *allowed; - int pos; - virtual void Set(void); - char Inc(char c, bool Up); -public: - cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed); - ~cMenuEditStrItem(); - virtual eOSState ProcessKey(eKeys Key); - }; - -cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed) -:cMenuEditItem(Name) -{ - value = Value; - length = Length; - allowed = strdup(Allowed); - pos = -1; - Set(); -} - -cMenuEditStrItem::~cMenuEditStrItem() -{ - delete allowed; -} - -void cMenuEditStrItem::Set(void) -{ - char buf[1000]; - if (pos >= 0) { - strncpy(buf, value, pos); - const char *s = value[pos] != '^' ? value + pos + 1 : ""; - snprintf(buf + pos, sizeof(buf) - pos - 2, "[%c]%s", *(value + pos), s); - SetValue(buf); - } - else - SetValue(value); -} - -char cMenuEditStrItem::Inc(char c, bool Up) -{ - const char *p = strchr(allowed, c); - if (!p) - p = allowed; - if (Up) { - if (!*++p) - p = allowed; - } - else if (--p < allowed) - p = allowed + strlen(allowed) - 1; - return *p; -} - -eOSState cMenuEditStrItem::ProcessKey(eKeys Key) -{ - switch (Key) { - case kLeft|k_Repeat: - case kLeft: if (pos > 0) { - if (value[pos] == '^') - value[pos] = 0; - pos--; - } - break; - case kRight|k_Repeat: - case kRight: if (pos < length && value[pos] != '^' && (pos < int(strlen(value) - 1) || value[pos] != ' ')) { - if (++pos >= int(strlen(value))) { - value[pos] = ' '; - value[pos + 1] = 0; - } - } - break; - case kUp|k_Repeat: - case kUp: - case kDown|k_Repeat: - case kDown: if (pos >= 0) - value[pos] = Inc(value[pos], NORMALKEY(Key) == kUp); - else - return cMenuEditItem::ProcessKey(Key); - break; - case kOk: if (pos >= 0) { - if (value[pos] == '^') - value[pos] = 0; - pos = -1; - stripspace(value); - break; - } - // run into default - default: return cMenuEditItem::ProcessKey(Key); - } - Set(); - return osContinue; -} - -// --- cMenuEditStraItem ----------------------------------------------------- - -class cMenuEditStraItem : public cMenuEditIntItem { -private: - const char * const *strings; -protected: - virtual void Set(void); -public: - cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings); - }; - -cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings) -:cMenuEditIntItem(Name, Value, 0, NumStrings - 1) -{ - strings = Strings; - Set(); -} - -void cMenuEditStraItem::Set(void) -{ - SetValue(strings[*value]); -} - // --- cMenuEditCaItem ------------------------------------------------------- class cMenuEditCaItem : public cMenuEditIntItem { @@ -699,7 +405,7 @@ cMenuEditChannel::cMenuEditChannel(int Index) channel = Channels.Get(Index); if (channel) { data = *channel; - Add(new cMenuEditStrItem( tr("Name"), data.name, sizeof(data.name), FileNameChars)); + Add(new cMenuEditStrItem( tr("Name"), data.name, sizeof(data.name), tr(FileNameChars))); Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency)); Add(new cMenuEditChrItem( tr("Polarization"), &data.polarization, "hv")); Add(new cMenuEditIntItem( tr("DiSEqC"), &data.diseqc, 0, 10)); //TODO exact limits??? @@ -919,116 +625,6 @@ eOSState cMenuChannels::ProcessKey(eKeys Key) return state; } -// --- cMenuTextItem --------------------------------------------------------- - -class cMenuTextItem : public cOsdItem { -private: - char *text; - int x, y, w, h, lines, offset; - eDvbColor fgColor, bgColor; - eDvbFont font; -public: - cMenuTextItem(const char *Text, int X, int Y, int W, int H = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground, eDvbFont Font = fontOsd); - ~cMenuTextItem(); - int Height(void) { return h; } - void Clear(void); - virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); - bool CanScrollUp(void) { return offset > 0; } - bool CanScrollDown(void) { return h + offset < lines; } - void ScrollUp(bool Page); - void ScrollDown(bool Page); - virtual eOSState ProcessKey(eKeys Key); - }; - -cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbColor FgColor, eDvbColor BgColor, eDvbFont Font) -{ - x = X; - y = Y; - w = W; - h = H; - fgColor = FgColor; - bgColor = BgColor; - font = Font; - offset = 0; - eDvbFont oldFont = Interface->SetFont(font); - text = Interface->WrapText(Text, w - 1, &lines); - Interface->SetFont(oldFont); - if (h < 0) - h = lines; -} - -cMenuTextItem::~cMenuTextItem() -{ - delete text; -} - -void cMenuTextItem::Clear(void) -{ - Interface->Fill(x, y, w, h, bgColor); -} - -void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) -{ - int l = 0; - char *t = text; - eDvbFont oldFont = Interface->SetFont(font); - while (*t) { - char *n = strchr(t, '\n'); - if (l >= offset) { - if (n) - *n = 0; - Interface->Write(x, y + l - offset, t, fgColor, bgColor); - if (n) - *n = '\n'; - else - break; - } - if (!n) - break; - t = n + 1; - if (++l >= h + offset) - break; - } - Interface->SetFont(oldFont); - // scroll indicators use inverted color scheme! - if (CanScrollUp()) Interface->Write(x + w - 1, y, "^", bgColor, fgColor); - if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor); -} - -void cMenuTextItem::ScrollUp(bool Page) -{ - if (CanScrollUp()) { - Clear(); - offset = max(offset - (Page ? h : 1), 0); - Display(); - } -} - -void cMenuTextItem::ScrollDown(bool Page) -{ - if (CanScrollDown()) { - Clear(); - offset = min(offset + (Page ? h : 1), lines - h); - Display(); - } -} - -eOSState cMenuTextItem::ProcessKey(eKeys Key) -{ - switch (Key) { - case kLeft|k_Repeat: - case kLeft: - case kUp|k_Repeat: - case kUp: ScrollUp(NORMALKEY(Key) == kLeft); break; - case kRight|k_Repeat: - case kRight: - case kDown|k_Repeat: - case kDown: ScrollDown(NORMALKEY(Key) == kRight); break; - default: return osUnknown; - } - return osContinue; -} - // --- cMenuText ------------------------------------------------------------- class cMenuText : public cOsdMenu { @@ -1086,7 +682,7 @@ cMenuEditTimer::cMenuEditTimer(int Index, bool New) //TODO VPS??? Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); - Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), FileNameChars)); + Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), tr(FileNameChars))); SetFirstDayItem(); } } @@ -1929,60 +1525,6 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) return state; } -// --- cMenuSetupPage -------------------------------------------------------- - -class cMenuSetupPage : public cOsdMenu { -protected: - cSetup data; - int osdLanguage; - void SetupTitle(const char *s); - virtual void Set(void) = 0; -public: - cMenuSetupPage(void); - virtual eOSState ProcessKey(eKeys Key); - }; - -cMenuSetupPage::cMenuSetupPage(void) -:cOsdMenu("", 33) -{ - data = Setup; - osdLanguage = Setup.OSDLanguage; -} - -void cMenuSetupPage::SetupTitle(const char *s) -{ - char buf[40]; // can't call tr() for more than one string at a time! - char *q = buf + snprintf(buf, sizeof(buf), "%s - ", tr("Setup")); - snprintf(q, sizeof(buf) - strlen(buf), "%s", tr(s)); - SetTitle(buf); -} - -eOSState cMenuSetupPage::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - - if (state == osUnknown) { - switch (Key) { - case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack; - cDvbApi::PrimaryDvbApi->SetVideoFormat(data.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3); - Setup = data; - Setup.Save(); - cDvbApi::SetCaCaps(); - break; - default: break; - } - } - if (data.OSDLanguage != osdLanguage) { - int OriginalOSDLanguage = Setup.OSDLanguage; - Setup.OSDLanguage = data.OSDLanguage; - Set(); - Display(); - osdLanguage = data.OSDLanguage; - Setup.OSDLanguage = OriginalOSDLanguage; - } - return state; -} - // --- cMenuSetupOSD --------------------------------------------------------- class cMenuSetupOSD : public cMenuSetupPage { @@ -1996,7 +1538,7 @@ void cMenuSetupOSD::Set(void) { Clear(); SetupTitle("OSD"); - Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &data.OSDLanguage, NumLanguages, Languages())); + Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &data.OSDLanguage, I18nNumLanguages, I18nLanguages())); Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); Add(new cMenuEditIntItem( tr("Setup.OSD$Height"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); Add(new cMenuEditIntItem( tr("Setup.OSD$Message time (s)"), &data.OSDMessageTime, 1, 60)); @@ -2104,7 +1646,8 @@ void cMenuSetupRecord::Set(void) Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME)); Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); - Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord), FileNameChars)); + Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord), tr(FileNameChars))); + Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME)); Add(new cMenuEditBoolItem(tr("Setup.Recording$Record Dolby Digital"), &data.RecordDolbyDigital)); Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); @@ -2142,7 +1685,76 @@ void cMenuSetupMisc::Set(void) SetupTitle("Miscellaneous"); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout)); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity)); - Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (min)"), &data.SVDRPTimeout)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout)); +} + +// --- cMenuSetupPluginItem -------------------------------------------------- + +class cMenuSetupPluginItem : public cOsdItem { +private: + int pluginIndex; +public: + cMenuSetupPluginItem(const char *Name, int Index); + int PluginIndex(void) { return pluginIndex; } + }; + +cMenuSetupPluginItem::cMenuSetupPluginItem(const char *Name, int Index) +:cOsdItem(Name) +{ + pluginIndex = Index; +} + +// --- cMenuSetupPlugins ----------------------------------------------------- + +class cMenuSetupPlugins : public cMenuSetupPage { +private: + virtual void Set(void); +public: + cMenuSetupPlugins(void) { Set(); } + virtual eOSState ProcessKey(eKeys Key); + }; + +void cMenuSetupPlugins::Set(void) +{ + Clear(); + SetupTitle("Plugins"); + SetHasHotkeys(); + for (int i = 0; ; i++) { + cPlugin *p = cPluginManager::GetPlugin(i); + if (p) { + char *buffer = NULL; + asprintf(&buffer, "%s (%s) - %s", p->Name(), p->Version(), p->Description()); + Add(new cMenuSetupPluginItem(hk(buffer), i)); + delete buffer; + } + else + break; + } +} + +eOSState cMenuSetupPlugins::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); // not cMenuSetupPage::ProcessKey()! + + if (state == osUnknown) { + switch (Key) { + case kOk: { + cMenuSetupPluginItem *item = (cMenuSetupPluginItem *)Get(Current()); + if (item) { + cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); + if (p) { + cOsdMenu *menu = p->SetupMenu(); + if (menu) + return AddSubMenu(menu); + Interface->Info(tr("This plugin has no setup parameters!")); + } + } + } + break; + default: break; + } + } + return state; } // --- cMenuSetup ------------------------------------------------------------ @@ -2165,7 +1777,9 @@ cMenuSetup::cMenuSetup(void) void cMenuSetup::Set(void) { Clear(); - SetTitle(tr("Setup")); + char buffer[64]; + snprintf(buffer, sizeof(buffer), "%s - VDR %s", tr("Setup"), VDRVERSION); + SetTitle(buffer); SetHasHotkeys(); Add(new cOsdItem(hk(tr("OSD")), osUser1)); Add(new cOsdItem(hk(tr("EPG")), osUser2)); @@ -2175,7 +1789,9 @@ void cMenuSetup::Set(void) Add(new cOsdItem(hk(tr("Recording")), osUser6)); Add(new cOsdItem(hk(tr("Replay")), osUser7)); Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8)); - Add(new cOsdItem(hk(tr("Restart")), osUser9)); + if (cPluginManager::HasPlugins()) + Add(new cOsdItem(hk(tr("Plugins")), osUser9)); + Add(new cOsdItem(hk(tr("Restart")), osUser10)); } eOSState cMenuSetup::Restart(void) @@ -2201,7 +1817,8 @@ eOSState cMenuSetup::ProcessKey(eKeys Key) case osUser6: return AddSubMenu(new cMenuSetupRecord); case osUser7: return AddSubMenu(new cMenuSetupReplay); case osUser8: return AddSubMenu(new cMenuSetupMisc); - case osUser9: return Restart(); + case osUser9: return AddSubMenu(new cMenuSetupPlugins); + case osUser10: return Restart(); default: ; } if (Setup.OSDLanguage != osdLanguage) { @@ -2264,6 +1881,22 @@ eOSState cMenuCommands::ProcessKey(eKeys Key) return state; } +// --- cMenuPluginItem ------------------------------------------------------- + +class cMenuPluginItem : public cOsdItem { +private: + int pluginIndex; +public: + cMenuPluginItem(const char *Name, int Index); + int PluginIndex(void) { return pluginIndex; } + }; + +cMenuPluginItem::cMenuPluginItem(const char *Name, int Index) +:cOsdItem(Name, osPlugin) +{ + pluginIndex = Index; +} + // --- cMenuMain ------------------------------------------------------------- #define STOP_RECORDING tr(" Stop recording ") @@ -2308,6 +1941,22 @@ void cMenuMain::Set(void) Add(new cOsdItem(hk(tr("Channels")), osChannels)); Add(new cOsdItem(hk(tr("Timers")), osTimers)); Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); + + // Plugins: + + for (int i = 0; ; i++) { + cPlugin *p = cPluginManager::GetPlugin(i); + if (p) { + const char *item = p->MainMenuEntry(); + if (item) + Add(new cMenuPluginItem(hk(item), i)); + } + else + break; + } + + // More basic menu items: + Add(new cOsdItem(hk(tr("Setup")), osSetup)); if (Commands.Count()) Add(new cOsdItem(hk(tr("Commands")), osCommands)); @@ -2375,6 +2024,19 @@ eOSState cMenuMain::ProcessKey(eKeys Key) return osEnd; } break; + case osPlugin: { + cMenuPluginItem *item = (cMenuPluginItem *)Get(Current()); + if (item) { + cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); + if (p) { + cOsdMenu *menu = p->MainMenuAction(); + if (menu) + return AddSubMenu(menu); + } + } + state = osEnd; + } + break; default: switch (Key) { case kMenu: state = osEnd; break; case kRed: if (!HasSubMenu()) @@ -3185,6 +2847,7 @@ void cReplayControl::TimeSearch(void) else return; } + timeoutShow = 0; TimeSearchDisplay(); timeSearchActive = true; } @@ -3287,7 +2950,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key) } else if (modeOnly) ShowMode(); - else + else shown = ShowProgress(!shown) || shown; } bool DisplayedFrames = displayFrames; diff --git a/menu.h b/menu.h index 88930167e..a0e0851e2 100644 --- a/menu.h +++ b/menu.h @@ -4,11 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.41 2002/03/31 13:53:23 kls Exp $ + * $Id: menu.h 1.42 2002/04/13 15:31:41 kls Exp $ */ -#ifndef _MENU_H -#define _MENU_H +#ifndef __MENU_H +#define __MENU_H #include "dvbapi.h" #include "osd.h" @@ -142,4 +142,4 @@ class cReplayControl : public cOsdBase { static void ClearLastReplayed(const char *FileName); }; -#endif //_MENU_H +#endif //__MENU_H diff --git a/menuitems.c b/menuitems.c new file mode 100644 index 000000000..d09f5b703 --- /dev/null +++ b/menuitems.c @@ -0,0 +1,476 @@ +/* + * menuitems.c: General purpose menu items + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: menuitems.c 1.1 2002/05/09 10:10:12 kls Exp $ + */ + +#include "menuitems.h" +#include +#include "i18n.h" + +// --- cMenuEditItem --------------------------------------------------------- + +cMenuEditItem::cMenuEditItem(const char *Name) +{ + name = strdup(Name); + value = NULL; +} + +cMenuEditItem::~cMenuEditItem() +{ + delete name; + delete value; +} + +void cMenuEditItem::SetValue(const char *Value) +{ + delete value; + value = strdup(Value); + char *buffer = NULL; + asprintf(&buffer, "%s:\t%s", name, value); + SetText(buffer, false); + Display(); +} + +// --- cMenuEditIntItem ------------------------------------------------------ + +cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max) +:cMenuEditItem(Name) +{ + value = Value; + min = Min; + max = Max; + Set(); +} + +void cMenuEditIntItem::Set(void) +{ + char buf[16]; + snprintf(buf, sizeof(buf), "%d", *value); + SetValue(buf); +} + +eOSState cMenuEditIntItem::ProcessKey(eKeys Key) +{ + eOSState state = cMenuEditItem::ProcessKey(Key); + + if (state == osUnknown) { + int newValue; + if (k0 <= Key && Key <= k9) { + if (fresh) { + *value = 0; + fresh = false; + } + newValue = *value * 10 + (Key - k0); + } + else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? + newValue = *value - 1; + fresh = true; + } + else if (NORMALKEY(Key) == kRight) { + newValue = *value + 1; + fresh = true; + } + else + return state; + if ((!fresh || min <= newValue) && newValue <= max) { + *value = newValue; + Set(); + } + state = osContinue; + } + return state; +} + +// --- cMenuEditBoolItem ----------------------------------------------------- + +cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString) +:cMenuEditIntItem(Name, Value, 0, 1) +{ + falseString = FalseString ? FalseString : tr("no"); + trueString = TrueString ? TrueString : tr("yes"); + Set(); +} + +void cMenuEditBoolItem::Set(void) +{ + char buf[16]; + snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString); + SetValue(buf); +} + +// --- cMenuEditChrItem ------------------------------------------------------ + +cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed) +:cMenuEditItem(Name) +{ + value = Value; + allowed = strdup(Allowed); + current = strchr(allowed, *Value); + if (!current) + current = allowed; + Set(); +} + +cMenuEditChrItem::~cMenuEditChrItem() +{ + delete allowed; +} + +void cMenuEditChrItem::Set(void) +{ + char buf[2]; + snprintf(buf, sizeof(buf), "%c", *value); + SetValue(buf); +} + +eOSState cMenuEditChrItem::ProcessKey(eKeys Key) +{ + eOSState state = cMenuEditItem::ProcessKey(Key); + + if (state == osUnknown) { + if (NORMALKEY(Key) == kLeft) { + if (current > allowed) + current--; + } + else if (NORMALKEY(Key) == kRight) { + if (*(current + 1)) + current++; + } + else + return state; + *value = *current; + Set(); + state = osContinue; + } + return state; +} + +// --- cMenuEditStrItem ------------------------------------------------------ + +cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed) +:cMenuEditItem(Name) +{ + value = Value; + length = Length; + allowed = strdup(Allowed); + pos = -1; + insert = uppercase = false; + newchar = true; + Set(); +} + +cMenuEditStrItem::~cMenuEditStrItem() +{ + delete allowed; +} + +void cMenuEditStrItem::SetHelpKeys(void) +{ + if (pos >= 0) + Interface->Help(tr("ABC/abc"), tr(insert ? "Overwrite" : "Insert"), tr("Delete")); + else + Interface->Help(NULL); +} + +void cMenuEditStrItem::Set(void) +{ + char buf[1000]; + const char *fmt = insert && newchar ? "[]%c%s" : "[%c]%s"; + + if (pos >= 0) { + strncpy(buf, value, pos); + snprintf(buf + pos, sizeof(buf) - pos - 2, fmt, *(value + pos), value + pos + 1); + int width = Interface->Width() - Interface->GetCols()[0]; + if (cDvbApi::PrimaryDvbApi->WidthInCells(buf) <= width) { + // the whole buffer fits on the screen + SetValue(buf); + return; + } + width *= cDvbApi::PrimaryDvbApi->CellWidth(); + width -= cDvbApi::PrimaryDvbApi->Width('>'); // assuming '<' and '>' have the same with + int w = 0; + int i = 0; + int l = strlen(buf); + while (i < l && w <= width) + w += cDvbApi::PrimaryDvbApi->Width(buf[i++]); + if (i >= pos + 4) { + // the cursor fits on the screen + buf[i - 1] = '>'; + buf[i] = 0; + SetValue(buf); + return; + } + // the cursor doesn't fit on the screen + w = 0; + if (buf[i = pos + 3]) { + buf[i] = '>'; + buf[i + 1] = 0; + } + else + i--; + while (i >= 0 && w <= width) + w += cDvbApi::PrimaryDvbApi->Width(buf[i--]); + buf[++i] = '<'; + SetValue(buf + i); + } + else + SetValue(value); +} + +char cMenuEditStrItem::Inc(char c, bool Up) +{ + const char *p = strchr(allowed, c); + if (!p) + p = allowed; + if (Up) { + if (!*++p) + p = allowed; + } + else if (--p < allowed) + p = allowed + strlen(allowed) - 1; + return *p; +} + +eOSState cMenuEditStrItem::ProcessKey(eKeys Key) +{ + switch (Key) { + case kRed: // Switch between upper- and lowercase characters + if (pos >= 0 && (!insert || !newchar)) { + uppercase = !uppercase; + value[pos] = uppercase ? toupper(value[pos]) : tolower(value[pos]); + } + break; + case kGreen: // Toggle insert/overwrite modes + if (pos >= 0) { + insert = !insert; + newchar = true; + } + SetHelpKeys(); + break; + case kYellow|k_Repeat: + case kYellow: // Remove the character at current position; in insert mode it is the character to the right of cursor + if (pos >= 0) { + if (strlen(value) > 1) { + memmove(value + pos, value + pos + 1, strlen(value) - pos); + // reduce position, if we removed the last character + if (pos == int(strlen(value))) + pos--; + } + else if (strlen(value) == 1) + value[0] = ' '; // This is the last character in the string, replace it with a blank + if (isalpha(value[pos])) + uppercase = isupper(value[pos]); + newchar = true; + } + break; + case kLeft|k_Repeat: + case kLeft: if (pos > 0) { + if (!insert || newchar) + pos--; + newchar = true; + } + if (!insert && isalpha(value[pos])) + uppercase = isupper(value[pos]); + break; + case kRight|k_Repeat: + case kRight: if (pos < length && pos < int(strlen(value)) ) { + if (++pos >= int(strlen(value))) { + if (pos >= 2 && value[pos - 1] == ' ' && value[pos - 2] == ' ') + pos--; // allow only two blanks at the end + else { + value[pos] = ' '; + value[pos + 1] = 0; + } + } + } + newchar = true; + if (!insert && isalpha(value[pos])) + uppercase = isupper(value[pos]); + if (pos == 0) + SetHelpKeys(); + break; + case kUp|k_Repeat: + case kUp: + case kDown|k_Repeat: + case kDown: if (pos >= 0) { + if (insert && newchar) { + // create a new character in insert mode + if (int(strlen(value)) < length) { + memmove(value + pos + 1, value + pos, strlen(value) - pos + 1); + value[pos] = ' '; + } + } + if (uppercase) + value[pos] = toupper(Inc(tolower(value[pos]), NORMALKEY(Key) == kUp)); + else + value[pos] = Inc( value[pos], NORMALKEY(Key) == kUp); + newchar = false; + } + else + return cMenuEditItem::ProcessKey(Key); + break; + case kOk: if (pos >= 0) { + pos = -1; + newchar = true; + stripspace(value); + SetHelpKeys(); + break; + } + // run into default + default: return cMenuEditItem::ProcessKey(Key); + } + Set(); + return osContinue; +} + +// --- cMenuEditStraItem ----------------------------------------------------- + +cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings) +:cMenuEditIntItem(Name, Value, 0, NumStrings - 1) +{ + strings = Strings; + Set(); +} + +void cMenuEditStraItem::Set(void) +{ + SetValue(strings[*value]); +} + +// --- cMenuTextItem --------------------------------------------------------- + +cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbColor FgColor, eDvbColor BgColor, eDvbFont Font) +{ + x = X; + y = Y; + w = W; + h = H; + fgColor = FgColor; + bgColor = BgColor; + font = Font; + offset = 0; + eDvbFont oldFont = Interface->SetFont(font); + text = Interface->WrapText(Text, w - 1, &lines); + Interface->SetFont(oldFont); + if (h < 0) + h = lines; +} + +cMenuTextItem::~cMenuTextItem() +{ + delete text; +} + +void cMenuTextItem::Clear(void) +{ + Interface->Fill(x, y, w, h, bgColor); +} + +void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) +{ + int l = 0; + char *t = text; + eDvbFont oldFont = Interface->SetFont(font); + while (*t) { + char *n = strchr(t, '\n'); + if (l >= offset) { + if (n) + *n = 0; + Interface->Write(x, y + l - offset, t, fgColor, bgColor); + if (n) + *n = '\n'; + else + break; + } + if (!n) + break; + t = n + 1; + if (++l >= h + offset) + break; + } + Interface->SetFont(oldFont); + // scroll indicators use inverted color scheme! + if (CanScrollUp()) Interface->Write(x + w - 1, y, "^", bgColor, fgColor); + if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor); +} + +void cMenuTextItem::ScrollUp(bool Page) +{ + if (CanScrollUp()) { + Clear(); + offset = max(offset - (Page ? h : 1), 0); + Display(); + } +} + +void cMenuTextItem::ScrollDown(bool Page) +{ + if (CanScrollDown()) { + Clear(); + offset = min(offset + (Page ? h : 1), lines - h); + Display(); + } +} + +eOSState cMenuTextItem::ProcessKey(eKeys Key) +{ + switch (Key) { + case kLeft|k_Repeat: + case kLeft: + case kUp|k_Repeat: + case kUp: ScrollUp(NORMALKEY(Key) == kLeft); break; + case kRight|k_Repeat: + case kRight: + case kDown|k_Repeat: + case kDown: ScrollDown(NORMALKEY(Key) == kRight); break; + default: return osUnknown; + } + return osContinue; +} + +// --- cMenuSetupPage -------------------------------------------------------- + +cMenuSetupPage::cMenuSetupPage(void) +:cOsdMenu("", 33) +{ + data = Setup; + osdLanguage = Setup.OSDLanguage; +} + +void cMenuSetupPage::SetupTitle(const char *s) +{ + char buf[40]; // can't call tr() for more than one string at a time! + char *q = buf + snprintf(buf, sizeof(buf), "%s - ", tr("Setup")); + snprintf(q, sizeof(buf) - strlen(buf), "%s", tr(s)); + SetTitle(buf); +} + +eOSState cMenuSetupPage::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack; + cDvbApi::PrimaryDvbApi->SetVideoFormat(data.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3); + Setup = data; + Setup.Save(); + cDvbApi::SetCaCaps(); + break; + default: break; + } + } + if (data.OSDLanguage != osdLanguage) { + int OriginalOSDLanguage = Setup.OSDLanguage; + Setup.OSDLanguage = data.OSDLanguage; + Set(); + Display(); + osdLanguage = data.OSDLanguage; + Setup.OSDLanguage = OriginalOSDLanguage; + } + return state; +} diff --git a/menuitems.h b/menuitems.h new file mode 100644 index 000000000..a08a71488 --- /dev/null +++ b/menuitems.h @@ -0,0 +1,110 @@ +/* + * menuitems.h: General purpose menu items + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: menuitems.h 1.1 2002/05/09 09:41:06 kls Exp $ + */ + +#ifndef __MENUITEMS_H +#define __MENUITEMS_H + +#include "osd.h" + +class cMenuEditItem : public cOsdItem { +private: + const char *name; + const char *value; +public: + cMenuEditItem(const char *Name); + ~cMenuEditItem(); + void SetValue(const char *Value); + }; + +class cMenuEditIntItem : public cMenuEditItem { +protected: + int *value; + int min, max; + virtual void Set(void); +public: + cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX); + virtual eOSState ProcessKey(eKeys Key); + }; + +class cMenuEditBoolItem : public cMenuEditIntItem { +protected: + const char *falseString, *trueString; + virtual void Set(void); +public: + cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString = NULL, const char *TrueString = NULL); + }; + +class cMenuEditChrItem : public cMenuEditItem { +private: + char *value; + const char *allowed; + const char *current; + virtual void Set(void); +public: + cMenuEditChrItem(const char *Name, char *Value, const char *Allowed); + ~cMenuEditChrItem(); + virtual eOSState ProcessKey(eKeys Key); + }; + +class cMenuEditStrItem : public cMenuEditItem { +private: + char *value; + int length; + const char *allowed; + int pos; + bool insert, newchar, uppercase; + void SetHelpKeys(void); + virtual void Set(void); + char Inc(char c, bool Up); +public: + cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed); + ~cMenuEditStrItem(); + virtual eOSState ProcessKey(eKeys Key); + }; + +class cMenuEditStraItem : public cMenuEditIntItem { +private: + const char * const *strings; +protected: + virtual void Set(void); +public: + cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings); + }; + +class cMenuTextItem : public cOsdItem { +private: + char *text; + int x, y, w, h, lines, offset; + eDvbColor fgColor, bgColor; + eDvbFont font; +public: + cMenuTextItem(const char *Text, int X, int Y, int W, int H = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground, eDvbFont Font = fontOsd); + ~cMenuTextItem(); + int Height(void) { return h; } + void Clear(void); + virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); + bool CanScrollUp(void) { return offset > 0; } + bool CanScrollDown(void) { return h + offset < lines; } + void ScrollUp(bool Page); + void ScrollDown(bool Page); + virtual eOSState ProcessKey(eKeys Key); + }; + +class cMenuSetupPage : public cOsdMenu { +protected: + cSetup data; + int osdLanguage; + void SetupTitle(const char *s); + virtual void Set(void) = 0; +public: + cMenuSetupPage(void); + virtual eOSState ProcessKey(eKeys Key); + }; + +#endif //__MENUITEMS_H diff --git a/newplugin b/newplugin new file mode 100755 index 000000000..22d18f418 --- /dev/null +++ b/newplugin @@ -0,0 +1,250 @@ +#!/usr/bin/perl -w + +# newplugin: Initializing a new plugin source directory +# +# Creates a new plugin source directory from which to start implementing +# a plugin for VDR. +# See the file PLUGINS.html for detailed instructions on how to +# write a plugin. +# +# Usage: newplugin +# +# See the main source file 'vdr.c' for copyright information and +# how to reach the author. +# +# $Id: newplugin 1.1 2002/05/09 15:12:26 kls Exp $ + +$PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin \n"; + +die "Please use only lowercase letters and digits in the plugin name\n" if ($PLUGIN_NAME =~ tr/a-z0-9//c); + +$PLUGIN_CLASS = ucfirst($PLUGIN_NAME); + +$PLUGIN_VERSION = "0.0.1"; +$PLUGIN_DESCRIPTION = "Enter description for '$PLUGIN_NAME' plugin"; +$PLUGIN_MAINENTRY = $PLUGIN_CLASS; + +$PLUGINS_SRC = "PLUGINS/SRC"; + +$README = qq +{This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Your Name + +Project's homepage: URL + +Latest version available at: URL + +See the file COPYING for license information. + +Description: +}; + +$HISTORY_TITLE = "VDR Plugin '$PLUGIN_NAME' Revision History"; +$HISTORY_LINE = '-' x length($HISTORY_TITLE); +$HISTORY_DATE = sprintf("%4d-%02d-%02d", (localtime)[5] + 1900, (localtime)[4] + 1, (localtime)[3]); +$HISTORY = qq +{$HISTORY_TITLE +$HISTORY_LINE + +$HISTORY_DATE: Version $PLUGIN_VERSION + +- Initial revision. +}; + +$MAKEFILE = qq +{# +# Makefile for a Video Disk Recorder plugin +# +# \$Id\$ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# +PLUGIN = $PLUGIN_NAME + +### The version number of this plugin (taken from the main source file): + +VERSION = `grep 'static const char \\*VERSION *=' \$(PLUGIN).c | awk '{ print \$\$6 }' | sed -e 's/[";]//g'` + +### The directory environment: + +DVBDIR = ../../../../DVB/ost/include +VDRDIR = ../../.. +VDRINC = \$(VDRDIR)/include +LIBDIR = ../../lib +TMPDIR = /tmp + +### The version number of VDR (taken from VDR's "config.h"): + +VDRVERSION = `grep 'define VDRVERSION ' \$(VDRDIR)/config.h | awk '{ print \$\$3 }' | sed -e 's/"//g'` + +### The name of the distribution archive: + +ARCHIVE = vdr-\$(PLUGIN)-\$(VERSION) + +### Includes and Defines (add further entries here): + +INCLUDES = -I\$(VDRINC) -I\$(DVBDIR) + +DEFINES = -DPLUGIN_NAME_I18N='"\$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = \$(PLUGIN).o + +### The C++ compiler and options: + +CXX = g++ +CXXFLAGS = -O2 -Wall -Woverloaded-virtual -m486 + +### Implicit rules: + +%.o: %.c + \$(CXX) \$(CXXFLAGS) -c \$(DEFINES) \$(INCLUDES) \$< + +# Dependencies: + +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +\$(DEPFILE): Makefile + \@\$(MAKEDEP) \$(DEFINES) \$(INCLUDES) \$(OBJS:%.o=%.c) > \$\@ + +include \$(DEPFILE) + +### Targets: + +all: libvdr-\$(PLUGIN).so + +libvdr-\$(PLUGIN).so: \$(OBJS) + \$(CXX) \$(CXXFLAGS) -shared \$(OBJS) -o \$\@ + \@cp \$\@ \$(LIBDIR)/\$\@.\$(VDRVERSION) + +package: clean + \@-rm -rf \$(TMPDIR)/\$(ARCHIVE) + \@mkdir \$(TMPDIR)/\$(ARCHIVE) + \@cp -a * \$(TMPDIR)/\$(ARCHIVE) + \@tar czf \$(ARCHIVE).tgz -C \$(TMPDIR) \$(ARCHIVE) + \@-rm -rf \$(TMPDIR)/\$(ARCHIVE) + \@echo Distribution archive created as \$(ARCHIVE).tgz + +clean: + \@-rm -f \$(OBJS) \$(DEPFILE) *.so *.tgz core* *~ +}; + +$MAIN = qq +{/* + * $PLUGIN_NAME.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * \$Id\$ + */ + +#include + +static const char *VERSION = "$PLUGIN_VERSION"; +static const char *DESCRIPTION = "$PLUGIN_DESCRIPTION"; +static const char *MAINMENUENTRY = "$PLUGIN_MAINENTRY"; + +class cPlugin$PLUGIN_CLASS : public cPlugin { +private: + // Add any member variables or functions you may need here. +public: + cPlugin$PLUGIN_CLASS(void); + virtual ~cPlugin$PLUGIN_CLASS(); + virtual const char *Version(void) { return VERSION; } + virtual const char *Description(void) { return DESCRIPTION; } + virtual const char *CommandLineHelp(void); + virtual bool ProcessArgs(int argc, char *argv[]); + virtual void Start(void); + virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; } + virtual cOsdMenu *MainMenuAction(void); + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *Name, const char *Value); + }; + +cPlugin${PLUGIN_CLASS}::cPlugin$PLUGIN_CLASS(void) +{ + // Initialize any member varaiables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! +} + +cPlugin${PLUGIN_CLASS}::~cPlugin$PLUGIN_CLASS() +{ + // Clean up after yourself! +} + +const char *cPlugin${PLUGIN_CLASS}::CommandLineHelp(void) +{ + // Return a string that describes all known command line options. + return NULL; +} + +bool cPlugin${PLUGIN_CLASS}::ProcessArgs(int argc, char *argv[]) +{ + // Implement command line argument processing here if applicable. + return true; +} + +void cPlugin${PLUGIN_CLASS}::Start(void) +{ + // Start any background activities the plugin shall perform. +} + +cOsdMenu *cPlugin${PLUGIN_CLASS}::MainMenuAction(void) +{ + // Perform the action when selected from the main VDR menu. + return NULL; +} + +cMenuSetupPage *cPlugin${PLUGIN_CLASS}::SetupMenu(void) +{ + // Return a setup menu in case the plugin supports one. + return NULL; +} + +bool cPlugin${PLUGIN_CLASS}::SetupParse(const char *Name, const char *Value) +{ + // Parse your own setup parameters and store their values. + return false; +} + +VDRPLUGINCREATOR(cPlugin$PLUGIN_CLASS); // Don't touch this! +}; + +$PLUGINDIR = "$PLUGINS_SRC/$PLUGIN_NAME"; + +die "The directory $PLUGINS_SRC doesn't exist!\n" unless (-d "$PLUGINS_SRC"); +die "A plugin named '$PLUGIN_NAME' already exists in $PLUGINS_SRC!\n" if (-e "$PLUGINDIR"); +mkdir("$PLUGINDIR") || die "$!"; + +CreateFile("README", $README); +CreateFile("HISTORY", $HISTORY); +CreateFile("Makefile", $MAKEFILE); +CreateFile("$PLUGIN_NAME.c", $MAIN); +`cp COPYING "$PLUGINDIR"` if (-e "COPYING"); + +print qq{ +The new plugin source directory has been created in "$PLUGINDIR". + +The next steps you should perform now are: + +* edit the file "README" to adjust it to your specific implementation +* fill in the code skeleton in "$PLUGIN_NAME.c" to implement your plugin function +* add further source files if necessary +* adapt the "Makefile" if necessary +* do "make plugins" from the VDR source directory to build your plugin + +}; + +sub CreateFile +{ + my ($Name, $Content) = @_; + open(FILE, ">$PLUGINDIR/$Name") || die "$Name: $!\n"; + print FILE $Content; + close(FILE); +} + diff --git a/osd.c b/osd.c index 56ba9b5c1..111678471 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.23 2002/03/29 16:34:03 kls Exp $ + * $Id: osd.c 1.24 2002/05/01 11:53:24 kls Exp $ */ #include "osd.h" @@ -105,12 +105,13 @@ cOsdMenu::~cOsdMenu() const char *cOsdMenu::hk(const char *s) { - static char buffer[32]; + static char buffer[64]; if (s && hasHotkeys) { if (digit == 0 && '1' <= *s && *s <= '9' && *(s + 1) == ' ') - digit = 10; // prevents automatic hotkeys - input already has them - if (digit < 9) { - snprintf(buffer, sizeof(buffer), " %d %s", ++digit, s); + digit = -1; // prevents automatic hotkeys - input already has them + if (digit >= 0) { + digit++; + snprintf(buffer, sizeof(buffer), " %c %s", (digit < 10) ? '0' + digit : ' ' , s); s = buffer; } } diff --git a/osd.h b/osd.h index 8e825869d..6f0532972 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.27 2002/03/10 16:18:11 kls Exp $ + * $Id: osd.h 1.28 2002/05/01 11:17:42 kls Exp $ */ #ifndef __OSD_H @@ -23,6 +23,7 @@ enum eOSState { osUnknown, osChannels, osTimers, osRecordings, + osPlugin, osSetup, osCommands, osRecord, @@ -43,6 +44,7 @@ enum eOSState { osUnknown, osUser7, osUser8, osUser9, + osUser10, }; class cOsdItem : public cListObject { diff --git a/plugin.c b/plugin.c new file mode 100644 index 000000000..ecae317e4 --- /dev/null +++ b/plugin.c @@ -0,0 +1,319 @@ +/* + * plugin.c: The VDR plugin interface + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: plugin.c 1.1 2002/05/09 16:26:56 kls Exp $ + */ + +#include "plugin.h" +#include +#include +#include +#include "config.h" + +#define LIBVDR_PREFIX "libvdr-" +#define SO_INDICATOR ".so." + +#define MAXPLUGINARGS 1024 + +// --- cPlugin --------------------------------------------------------------- + +cPlugin::cPlugin(void) +{ + name = NULL; +} + +cPlugin::~cPlugin() +{ + I18nRegister(NULL, Name()); +} + +void cPlugin::SetName(const char *s) +{ + name = s; +} + +const char *cPlugin::CommandLineHelp(void) +{ + return NULL; +} + +bool cPlugin::ProcessArgs(int argc, char *argv[]) +{ + return true; +} + +void cPlugin::Start(void) +{ +} + +const char *cPlugin::MainMenuEntry(void) +{ + return NULL; +} + +cOsdMenu *cPlugin::MainMenuAction(void) +{ + return NULL; +} + +cMenuSetupPage *cPlugin::SetupMenu(void) +{ + return NULL; +} + +bool cPlugin::SetupParse(const char *Name, const char *Value) +{ + return false; +} + +void cPlugin::SetupStore(const char *Name, const char *Value) +{ + Setup.Store(Name, Value, this->Name()); +} + +void cPlugin::SetupStore(const char *Name, int Value) +{ + Setup.Store(Name, Value, this->Name()); +} + +void cPlugin::RegisterI18n(const tI18nPhrase * const Phrases) +{ + I18nRegister(Phrases, Name()); +} + +// --- cDll ------------------------------------------------------------------ + +cDll::cDll(const char *FileName, const char *Args) +{ + fileName = strdup(FileName); + args = Args ? strdup(Args) : NULL; + handle = NULL; + plugin = NULL; +} + +cDll::~cDll() +{ + delete plugin; + if (handle) + dlclose(handle); + delete args; + delete fileName; +} + +static char *SkipQuote(char *s) +{ + char c = *s; + strcpy(s, s + 1); + while (*s && *s != c) { + if (*s == '\\') + strcpy(s, s + 1); + if (*s) + s++; + } + if (*s) { + strcpy(s, s + 1); + return s; + } + esyslog(LOG_ERR, "ERROR: missing closing %c", c); + fprintf(stderr, "vdr: missing closing %c\n", c); + return NULL; +} + +bool cDll::Load(bool Log) +{ + if (Log) + isyslog(LOG_INFO, "loading plugin: %s", fileName); + if (handle) { + esyslog(LOG_ERR, "attempt to load plugin '%s' twice!", fileName); + return false; + } + handle = dlopen(fileName, RTLD_NOW); + const char *error = dlerror(); + if (!error) { + void *(*creator)(void); + (void *)creator = dlsym(handle, "VDRPluginCreator"); + if (!(error = dlerror())) + plugin = (cPlugin *)creator(); + } + if (!error) { + if (plugin && args) { + int argc = 0; + char *argv[MAXPLUGINARGS]; + char *p = args; + char *q = NULL; + bool done = false; + while (!done) { + if (!q) + q = p; + switch (*p) { + case '\\': strcpy(p, p + 1); + if (*p) + p++; + else { + esyslog(LOG_ERR, "ERROR: missing character after \\"); + fprintf(stderr, "vdr: missing character after \\\n"); + return false; + } + break; + case '"': + case '\'': if ((p = SkipQuote(p)) == NULL) + return false; + break; + default: if (!*p || isspace(*p)) { + done = !*p; + *p = 0; + if (q) { + if (argc < MAXPLUGINARGS - 1) + argv[argc++] = q; + else { + esyslog(LOG_ERR, "ERROR: plugin argument list too long"); + fprintf(stderr, "vdr: plugin argument list too long\n"); + return false; + } + q = NULL; + } + } + if (!done) + p++; + } + } + argv[argc] = NULL; + if (argc) + plugin->SetName(argv[0]); + optind = 0; // to reset the getopt() data + return !argc || plugin->ProcessArgs(argc, argv); + } + } + else { + esyslog(LOG_ERR, "ERROR: %s", error); + fprintf(stderr, "vdr: %s\n", error); + } + return !error && plugin; +} + +// --- cPluginManager -------------------------------------------------------- + +cPluginManager *cPluginManager::pluginManager = NULL; + +cPluginManager::cPluginManager(const char *Directory) +{ + directory = NULL; + if (pluginManager) { + fprintf(stderr, "vdr: attempt to create more than one plugin manager - exiting!\n"); + exit(2); + } + SetDirectory(Directory); + pluginManager = this; +} + +cPluginManager::~cPluginManager() +{ + Shutdown(); + delete directory; + if (pluginManager == this) + pluginManager = NULL; +} + +void cPluginManager::SetDirectory(const char *Directory) +{ + delete directory; + directory = Directory ? strdup(Directory) : NULL; +} + +void cPluginManager::AddPlugin(const char *Args) +{ + if (strcmp(Args, "*") == 0) { + DIR *d = opendir(directory); + if (d) { + struct dirent *e; + while ((e = readdir(d)) != NULL) { + if (strstr(e->d_name, LIBVDR_PREFIX) == e->d_name) { + char *p = strstr(e->d_name, SO_INDICATOR); + if (p) { + *p = 0; + p += strlen(SO_INDICATOR); + if (strcmp(p, VDRVERSION) == 0) { + char *name = e->d_name + strlen(LIBVDR_PREFIX); + if (strcmp(name, "*") != 0) { // let's not get into a loop! + AddPlugin(e->d_name + strlen(LIBVDR_PREFIX)); + } + } + } + } + } + closedir(d); + } + return; + } + char *s = strdup(Args); + char *p = strchr(s, ' '); + if (p) + *p = 0; + char *buffer = NULL; + asprintf(&buffer, "%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, VDRVERSION); + dlls.Add(new cDll(buffer, Args)); + delete buffer; + delete s; +} + +bool cPluginManager::LoadPlugins(bool Log) +{ + for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) { + if (!dll->Load(Log)) + return false; + } + return true; +} + +void cPluginManager::StartPlugins(void) +{ + for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) { + cPlugin *p = dll->Plugin(); + if (p) { + int Language = Setup.OSDLanguage; + Setup.OSDLanguage = 0; // the i18n texts are only available _after_ Start() + isyslog(LOG_INFO, "starting plugin: %s (%s): %s", p->Name(), p->Version(), p->Description()); + Setup.OSDLanguage = Language; + dll->Plugin()->Start(); + } + } +} + +bool cPluginManager::HasPlugins(void) +{ + return pluginManager && pluginManager->dlls.Count(); +} + +cPlugin *cPluginManager::GetPlugin(int Index) +{ + cDll *dll = pluginManager ? pluginManager->dlls.Get(Index) : NULL; + return dll ? dll->Plugin() : NULL; +} + +cPlugin *cPluginManager::GetPlugin(const char *Name) +{ + if (pluginManager) { + for (cDll *dll = pluginManager->dlls.First(); dll; dll = pluginManager->dlls.Next(dll)) { + cPlugin *p = dll->Plugin(); + if (p && strcmp(p->Name(), Name) == 0) + return p; + } + } + return NULL; +} + +void cPluginManager::Shutdown(bool Log) +{ + cDll *dll; + while ((dll = dlls.Last()) != NULL) { + if (Log) { + cPlugin *p = dll->Plugin(); + if (p) + isyslog(LOG_INFO, "stopping plugin: %s", p->Name()); + } + dlls.Del(dll); + } +} diff --git a/plugin.h b/plugin.h new file mode 100644 index 000000000..99f330d4f --- /dev/null +++ b/plugin.h @@ -0,0 +1,81 @@ +/* + * plugin.h: The VDR plugin interface + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: plugin.h 1.1 2002/05/09 10:16:09 kls Exp $ + */ + +#ifndef __PLUGIN_H +#define __PLUGIN_H + +#include "i18n.h" +#include "menuitems.h" +#include "osd.h" +#include "tools.h" + +#define VDRPLUGINCREATOR(PluginClass) extern "C" void *VDRPluginCreator(void) { return new PluginClass; } + +class cPlugin { + friend class cDll; +private: + const char *name; + void SetName(const char *s); +public: + cPlugin(void); + virtual ~cPlugin(); + + const char *Name(void) { return name; } + virtual const char *Version(void) = 0; + virtual const char *Description(void) = 0; + virtual const char *CommandLineHelp(void); + + virtual bool ProcessArgs(int argc, char *argv[]); + virtual void Start(void); + + virtual const char *MainMenuEntry(void); + virtual cOsdMenu *MainMenuAction(void); + + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *Name, const char *Value); + void SetupStore(const char *Name, const char *Value = NULL); + void SetupStore(const char *Name, int Value); + + void RegisterI18n(const tI18nPhrase * const Phrases); + }; + +class cDll : public cListObject { +private: + char *fileName; + char *args; + void *handle; + cPlugin *plugin; +public: + cDll(const char *FileName, const char *Args); + virtual ~cDll(); + bool Load(bool Log = false); + cPlugin *Plugin(void) { return plugin; } + }; + +class cDlls : public cList {}; + +class cPluginManager { +private: + static cPluginManager *pluginManager; + char *directory; + cDlls dlls; +public: + cPluginManager(const char *Directory); + virtual ~cPluginManager(); + void SetDirectory(const char *Directory); + void AddPlugin(const char *Args); + bool LoadPlugins(bool Log = false); + void StartPlugins(void); + static bool HasPlugins(void); + static cPlugin *GetPlugin(int Index); + static cPlugin *GetPlugin(const char *Name); + void Shutdown(bool Log = false); + }; + +#endif //__PLUGIN_H diff --git a/recording.c b/recording.c index b19e8b73f..e63704535 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.60 2002/04/01 10:51:23 kls Exp $ + * $Id: recording.c 1.61 2002/04/21 14:02:55 kls Exp $ */ #include "recording.h" @@ -222,7 +222,6 @@ static char *ExchangeChars(char *s, bool ToFileSystem) case '+': case ',': case '-': - case '.': case ';': case '=': case '0' ... '9': @@ -237,7 +236,8 @@ static char *ExchangeChars(char *s, bool ToFileSystem) case ' ': *p = '_'; break; case '~': *p = '/'; break; // characters that have to be encoded: - default: { + default: + if (*p != '.' || !*(p + 1) || *(p + 1) == '~') { // Windows can't handle '.' at the end of directory names int l = p - s; s = (char *)realloc(s, strlen(s) + 10); p = s + l; diff --git a/remote.h b/remote.h index bbdf2facc..184a42e9c 100644 --- a/remote.h +++ b/remote.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remote.h 1.15 2001/07/22 14:42:59 kls Exp $ + * $Id: remote.h 1.16 2002/05/09 11:43:04 kls Exp $ */ #ifndef __REMOTE_H @@ -95,7 +95,7 @@ class cRcIoLIRC : public cRcIoBase, private cThread { #elif !defined REMOTE_NONE -#error Please define a remote control mode! +// #error Please define a remote control mode! #endif diff --git a/ringbuffer.c b/ringbuffer.c index 8b8420c16..a52683d53 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -7,7 +7,7 @@ * Parts of this file were inspired by the 'ringbuffy.c' from the * LinuxDVB driver (see linuxtv.org). * - * $Id: ringbuffer.c 1.5 2001/11/03 09:50:46 kls Exp $ + * $Id: ringbuffer.c 1.6 2002/04/18 15:46:36 kls Exp $ */ #include "ringbuffer.h" @@ -154,7 +154,6 @@ int cRingBufferLinear::Put(const uchar *Data, int Count) Lock(); int rest = Size() - head; int diff = tail - head; - Unlock(); int free = (diff > 0) ? diff - 1 : Size() + diff - 1; if (statistics) { int fill = Size() - free - 1 + Count; @@ -167,22 +166,25 @@ int cRingBufferLinear::Put(const uchar *Data, int Count) dsyslog(LOG_INFO, "buffer usage: %d%%", percent); } } - if (free <= 0) - return 0; - if (free < Count) - Count = free; - if (Count > maxFill) - maxFill = Count; - if (Count >= rest) { - memcpy(buffer + head, Data, rest); - if (Count - rest) - memcpy(buffer, Data + rest, Count - rest); - head = Count - rest; - } - else { - memcpy(buffer + head, Data, Count); - head += Count; + if (free > 0) { + if (free < Count) + Count = free; + if (Count > maxFill) + maxFill = Count; + if (Count >= rest) { + memcpy(buffer + head, Data, rest); + if (Count - rest) + memcpy(buffer, Data + rest, Count - rest); + head = Count - rest; + } + else { + memcpy(buffer + head, Data, Count); + head += Count; + } } + else + Count = 0; + Unlock(); } return Count; } @@ -193,22 +195,24 @@ int cRingBufferLinear::Get(uchar *Data, int Count) Lock(); int rest = Size() - tail; int diff = head - tail; - Unlock(); int cont = (diff >= 0) ? diff : Size() + diff; - if (rest <= 0) - return 0; - if (cont < Count) - Count = cont; - if (Count >= rest) { - memcpy(Data, buffer + tail, rest); - if (Count - rest) - memcpy(Data + rest, buffer, Count - rest); - tail = Count - rest; - } - else { - memcpy(Data, buffer + tail, Count); - tail += Count; + if (rest > 0) { + if (cont < Count) + Count = cont; + if (Count >= rest) { + memcpy(Data, buffer + tail, rest); + if (Count - rest) + memcpy(Data + rest, buffer, Count - rest); + tail = Count - rest; + } + else { + memcpy(Data, buffer + tail, Count); + tail += Count; + } } + else + Count = 0; + Unlock(); } return Count; } diff --git a/tools.c b/tools.c index 099fb7d94..6f99ef095 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.62 2002/03/31 20:51:06 kls Exp $ + * $Id: tools.c 1.63 2002/05/01 16:20:30 kls Exp $ */ #include "tools.h" @@ -251,10 +251,10 @@ int FreeDiskSpaceMB(const char *Directory, int *UsedMB) int Free = 0; struct statfs statFs; if (statfs(Directory, &statFs) == 0) { - int blocksPerMeg = 1024 * 1024 / statFs.f_bsize; + double blocksPerMeg = 1024.0 * 1024.0 / statFs.f_bsize; if (UsedMB) - *UsedMB = (statFs.f_blocks - statFs.f_bfree) / blocksPerMeg; - Free = statFs.f_bavail / blocksPerMeg; + *UsedMB = int((statFs.f_blocks - statFs.f_bfree) / blocksPerMeg); + Free = int(statFs.f_bavail / blocksPerMeg); } else LOG_ERROR_STR(Directory); diff --git a/vdr.1 b/vdr.1 index b26a9dff5..06c0b84d3 100644 --- a/vdr.1 +++ b/vdr.1 @@ -8,9 +8,9 @@ .\" License as specified in the file COPYING that comes with the .\" vdr distribution. .\" -.\" $Id: vdr.1 1.3 2002/04/07 13:11:43 kls Exp $ +.\" $Id: vdr.1 1.4 2002/05/09 16:04:17 kls Exp $ .\" -.TH vdr 1 "7 Apr 2002" "1.0.0" "Video Disk Recorder" +.TH vdr 1 "9 May 2002" "1.1.0" "Video Disk Recorder" .SH NAME vdr - the Video Disk Recorder .SH SYNOPSIS @@ -68,6 +68,11 @@ Set logging to \fIlevel\fR. \fB2\fR\ =\ errors and info, \fB3\fR\ =\ errors, info and debug. The default logging level is \fB3\fR. .TP +.BI -L\ dir ,\ --lib= dir +Search for plugins in directory \fIdir\fR (default is ./PLUGINS/lib). +There can be several \fB-L\fR options with different \fIdir\fR values. +Each of them will apply to the \fB-P\fR options following it. +.TP .B -m, --mute Mute audio of the primary DVB device at startup. .TP @@ -77,6 +82,18 @@ The default SVDRP port is \fB2001\fR. You need to edit the file \fIsvdrphosts.conf\fR in order to enable access to the SVDRP port. .TP +.BI -P\ options ,\ --plugin= options +Load a plugin, defined by the given \fIoptions\fR. +The first word in \fIoptions\fR must be the name of an existing \fBvdr\fR +plugin, optionally followed by a blank separated list of command line options +for that plugin. If \fIoptions\fR contains any blanks, you need to enclose it +in quotes, like for example + +\fBvdr -P "abc -a -b xyz"\fR + +which would load a plugin named \fBabc\fR, giving it the command line options +\fB-a\ -b\ xyz\fR. +.TP .BI -r\ cmd ,\ --record= cmd Call \fIcmd\fR before and after a recording. .TP @@ -104,6 +121,9 @@ Successful program execution. .B 1 An error has been detected which requires the DVB driver and \fBvdr\fR to be re-loaded. +.TP +.B 2 +An non-recoverable error has been detected, \fBvdr\fR has given up. .SH FILES .TP .I channels.conf diff --git a/vdr.c b/vdr.c index 874e8264b..7bb1f9bb5 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.102 2002/03/29 10:09:20 kls Exp $ + * $Id: vdr.c 1.104 2002/05/05 10:34:31 kls Exp $ */ #include @@ -36,6 +36,7 @@ #include "i18n.h" #include "interface.h" #include "menu.h" +#include "plugin.h" #include "recording.h" #include "tools.h" #include "videodir.h" @@ -79,14 +80,18 @@ int main(int argc, char *argv[]) #define DEFAULTSVDRPPORT 2001 #define DEFAULTWATCHDOG 0 // seconds +#define DEFAULTPLUGINDIR "./PLUGINS/lib" int SVDRPport = DEFAULTSVDRPPORT; const char *ConfigDirectory = NULL; + bool DisplayHelp = false; + bool DisplayVersion = false; bool DaemonMode = false; bool MuteAudio = false; int WatchdogTimeout = DEFAULTWATCHDOG; const char *Terminal = NULL; const char *Shutdown = NULL; + cPluginManager PluginManager(DEFAULTPLUGINDIR); static struct option long_options[] = { { "audio", required_argument, NULL, 'a' }, @@ -95,8 +100,10 @@ int main(int argc, char *argv[]) { "device", required_argument, NULL, 'D' }, { "epgfile", required_argument, NULL, 'E' }, { "help", no_argument, NULL, 'h' }, + { "lib", required_argument, NULL, 'L' }, { "log", required_argument, NULL, 'l' }, { "mute", no_argument, NULL, 'm' }, + { "plugin", required_argument, NULL, 'P' }, { "port", required_argument, NULL, 'p' }, { "record", required_argument, NULL, 'r' }, { "shutdown", required_argument, NULL, 's' }, @@ -108,8 +115,7 @@ int main(int argc, char *argv[]) }; int c; - int option_index = 0; - while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:mp:r:s:t:v:Vw:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:L:mp:P:r:s:t:v:Vw:", long_options, NULL)) != -1) { switch (c) { case 'a': cDvbApi::SetAudioCommand(optarg); break; @@ -128,40 +134,7 @@ int main(int argc, char *argv[]) break; case 'E': cSIProcessor::SetEpgDataFileName(*optarg != '-' ? optarg : NULL); break; - case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80| - " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n" - " -c DIR, --config=DIR read config files from DIR (default is to read them\n" - " from the video directory)\n" - " -d, --daemon run in daemon mode\n" - " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n" - " there may be several -D options (default: all DVB\n" - " devices will be used)\n" - " -E FILE --epgfile=FILE write the EPG data into the given FILE (default is\n" - " %s); use '-E-' to disable this\n" - " if FILE is a directory, the default EPG file will be\n" - " created in that directory\n" - " -h, --help print this help and exit\n" - " -l LEVEL, --log=LEVEL set log level (default: 3)\n" - " 0 = no logging, 1 = errors only,\n" - " 2 = errors and info, 3 = errors, info and debug\n" - " -m, --mute mute audio of the primary DVB device at startup\n" - " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" - " 0 turns off SVDRP\n" - " -r CMD, --record=CMD call CMD before and after a recording\n" - " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" - " -t TTY, --terminal=TTY controlling tty\n" - " -V, --version print version information and exit\n" - " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" - " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n" - " seconds (default: %d); '0' disables the watchdog\n" - "\n" - "Report bugs to \n", - cSIProcessor::GetEpgDataFileName() ? cSIProcessor::GetEpgDataFileName() : "'-'", - DEFAULTSVDRPPORT, - VideoDirectory, - DEFAULTWATCHDOG - ); - return 0; + case 'h': DisplayHelp = true; break; case 'l': if (isnumber(optarg)) { int l = atoi(optarg); @@ -173,6 +146,8 @@ int main(int argc, char *argv[]) fprintf(stderr, "vdr: invalid log level: %s\n", optarg); return 2; break; + case 'L': PluginManager.SetDirectory(optarg); + break; case 'm': MuteAudio = true; break; case 'p': if (isnumber(optarg)) @@ -182,14 +157,15 @@ int main(int argc, char *argv[]) return 2; } break; + case 'P': PluginManager.AddPlugin(optarg); + break; case 'r': cRecordingUserCommand::SetCommand(optarg); break; case 's': Shutdown = optarg; break; case 't': Terminal = optarg; break; - case 'V': printf("vdr, version %s\n", VDRVERSION); - return 0; + case 'V': DisplayVersion = true; break; case 'v': VideoDirectory = optarg; while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/') @@ -209,6 +185,71 @@ int main(int argc, char *argv[]) } } + // Help and version info: + + if (DisplayHelp || DisplayVersion) { + if (!PluginManager.HasPlugins()) + PluginManager.AddPlugin("*"); // adds all available plugins + PluginManager.LoadPlugins(); + if (DisplayHelp) { + printf("Usage: vdr [OPTIONS]\n\n" // for easier orientation, this is column 80| + " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n" + " -c DIR, --config=DIR read config files from DIR (default is to read them\n" + " from the video directory)\n" + " -d, --daemon run in daemon mode\n" + " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n" + " there may be several -D options (default: all DVB\n" + " devices will be used)\n" + " -E FILE --epgfile=FILE write the EPG data into the given FILE (default is\n" + " %s); use '-E-' to disable this\n" + " if FILE is a directory, the default EPG file will be\n" + " created in that directory\n" + " -h, --help print this help and exit\n" + " -l LEVEL, --log=LEVEL set log level (default: 3)\n" + " 0 = no logging, 1 = errors only,\n" + " 2 = errors and info, 3 = errors, info and debug\n" + " -L DIR, --lib=DIR search for plugins in DIR (default is %s)\n" + " -m, --mute mute audio of the primary DVB device at startup\n" + " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n" + " 0 turns off SVDRP\n" + " -P OPT, --plugin=OPT load a plugin defined by the given options\n" + " -r CMD, --record=CMD call CMD before and after a recording\n" + " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n" + " -t TTY, --terminal=TTY controlling tty\n" + " -v DIR, --video=DIR use DIR as video directory (default: %s)\n" + " -V, --version print version information and exit\n" + " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n" + " seconds (default: %d); '0' disables the watchdog\n" + "\n", + cSIProcessor::GetEpgDataFileName() ? cSIProcessor::GetEpgDataFileName() : "'-'", + DEFAULTPLUGINDIR, + DEFAULTSVDRPPORT, + VideoDirectory, + DEFAULTWATCHDOG + ); + } + if (DisplayVersion) + printf("vdr (%s) - The Video Disk Recorder\n", VDRVERSION); + if (PluginManager.HasPlugins()) { + if (DisplayHelp) + printf("Plugins: vdr -P\"name [OPTIONS]\"\n\n"); + for (int i = 0; ; i++) { + cPlugin *p = PluginManager.GetPlugin(i); + if (p) { + const char *help = p->CommandLineHelp(); + printf("%s (%s) - %s\n", p->Name(), p->Version(), p->Description()); + if (DisplayHelp && help) { + printf("\n"); + puts(help); + } + } + else + break; + } + } + return 0; + } + // Log file: if (SysLogLevel > 0) @@ -250,6 +291,11 @@ int main(int argc, char *argv[]) isyslog(LOG_INFO, "VDR version %s started", VDRVERSION); + // Load plugins: + + if (!PluginManager.LoadPlugins(true)) + return 2; + // Configuration data: if (!ConfigDirectory) @@ -276,6 +322,12 @@ int main(int argc, char *argv[]) cSIProcessor::Read(); + // Start plugins: + + PluginManager.StartPlugins(); + + // Channel: + Channels.SwitchTo(Setup.CurrentChannel); if (MuteAudio) cDvbApi::PrimaryDvbApi->ToggleMute(); @@ -469,7 +521,7 @@ int main(int argc, char *argv[]) Interface->Info(tr("Editing process finished")); } } - if (!*Interact && (!cRecordControls::Active() || ForceShutdown)) { + if (!*Interact && ((!cRecordControls::Active() && !cVideoCutter::Active()) || ForceShutdown)) { time_t Now = time(NULL); if (Now - LastActivity > ACTIVITYTIMEOUT) { // Shutdown: @@ -529,6 +581,7 @@ int main(int argc, char *argv[]) Setup.CurrentChannel = cDvbApi::CurrentChannel(); Setup.CurrentVolume = cDvbApi::CurrentVolume(); Setup.Save(); + PluginManager.Shutdown(true); cVideoCutter::Stop(); delete Menu; delete ReplayControl; From 803c6c6bf6340302f78171892bef599aa272c266 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 11 May 2002 18:00:00 +0200 Subject: [PATCH 042/307] Version 1.1.1 - Separated the actual DVB hardware OSD implementation from the abstract OSD interface. 'osdbase.c/.h' now implements the abstract OSD, while 'dvbosd.c/.h' is the actual implementation for the DVB hardware. This is in preparation for allowing additional kinds of OSD hardware implementations. - Fixed leftover references to the file FORMATS in MANUAL and svdrp.c. - Avoiding ambiguities in the cList template class in case one defines a "list of lists" (thanks to Stefan Huelswitt). - Simplified the basic cMenuSetupPage class for easier use in plugins. - Added setup parameters and a Setup menu to the 'hello' plugin example. - Fixed logging error message for unknown config parameters in plugins. - Rearranged cleanup sequence at the end of the main program. - Adapted PLUGINS.html to use the actual code examples from the 'hello' plugin. --- CONTRIBUTORS | 2 + HISTORY | 15 ++ MANUAL | 4 +- Makefile | 4 +- PLUGINS.html | 207 ++++++++++++--- PLUGINS/SRC/hello/HISTORY | 4 + PLUGINS/SRC/hello/hello.c | 47 +++- PLUGINS/SRC/hello/i18n.c | 41 ++- PLUGINS/SRC/hello/i18n.h | 7 +- config.c | 11 +- config.h | 4 +- dvbosd.c | 545 ++++---------------------------------- dvbosd.h | 171 +----------- i18n.c | 15 +- menu.c | 194 ++++++++------ menuitems.c | 48 ++-- menuitems.h | 15 +- osdbase.c | 482 +++++++++++++++++++++++++++++++++ osdbase.h | 211 +++++++++++++++ svdrp.c | 4 +- tools.h | 6 +- vdr.c | 10 +- 22 files changed, 1216 insertions(+), 831 deletions(-) create mode 100644 osdbase.c create mode 100644 osdbase.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b6bd60ae0..ce0ffaa51 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -128,6 +128,8 @@ Stefan Huelswitt with CAMs and AC3 sound only working the first time for making the main loop take an active video cutting process into account when doing shutdown or housekeeping + for making the cList template class avoid ambiguities in case one defines a "list of + lists" Ulrich Rder for pointing out that there are channels that have a symbol rate higher than diff --git a/HISTORY b/HISTORY index 6599534e8..1da14fdb6 100644 --- a/HISTORY +++ b/HISTORY @@ -1254,3 +1254,18 @@ Video Disk Recorder Revision History and '-P' used to load plugins. This first step implements the complete "outer" shell for plugins. The "inner" access to VDR data structures will follow. - The VDR version number is now displayed in the title line of the "Setup" menu. + +2002-05-11: Version 1.1.1 + +- Separated the actual DVB hardware OSD implementation from the abstract OSD + interface. 'osdbase.c/.h' now implements the abstract OSD, while 'dvbosd.c/.h' + is the actual implementation for the DVB hardware. This is in preparation for + allowing additional kinds of OSD hardware implementations. +- Fixed leftover references to the file FORMATS in MANUAL and svdrp.c. +- Avoiding ambiguities in the cList template class in case one defines a "list of + lists" (thanks to Stefan Huelswitt). +- Simplified the basic cMenuSetupPage class for easier use in plugins. +- Added setup parameters and a Setup menu to the 'hello' plugin example. +- Fixed logging error message for unknown config parameters in plugins. +- Rearranged cleanup sequence at the end of the main program. +- Adapted PLUGINS.html to use the actual code examples from the 'hello' plugin. diff --git a/MANUAL b/MANUAL index 978713180..2dc75a34b 100644 --- a/MANUAL +++ b/MANUAL @@ -571,7 +571,7 @@ Video Disk Recorder User's Manual * Executing system commands The "VDR" menu option "Commands" allows you to execute any system commands - defined in the configuration file 'commands.conf' (see FORMATS for details). + defined in the configuration file 'commands.conf' (see vdr(5) for details). The "Commands" option will only be present in the "VDR" menu if a valid 'commands.conf' file containing at least one command definition has been found at program start. @@ -584,7 +584,7 @@ Video Disk Recorder User's Manual be displayed on a result screen after executing the command. This screen will use a 'fixed' font so that you can generate formatted output. In order to avoid error messages going to stderr, command definitions should redirect - stderr to stdout (see FORMATS). + stderr to stdout (see vdr(5)). WARNING: THE COMMANDS DEFINED IN 'commands.conf' WILL BE EXECUTED UNDER THE ======= SAME USER ID THAT VDR IS RUNNING WITH. BE VERY CAREFUL WHEN diff --git a/Makefile b/Makefile index 55a01e875..d6f788729 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.34 2002/05/09 09:35:05 kls Exp $ +# $Id: Makefile 1.35 2002/05/10 10:24:46 kls Exp $ .DELETE_ON_ERROR: @@ -22,7 +22,7 @@ INCLUDES = -I$(DVBDIR)/ost/include DTVLIB = $(DTVDIR)/libdtv.a OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o\ - menuitems.o osd.o plugin.o recording.o remote.o remux.o ringbuffer.o\ + menuitems.o osdbase.o osd.o plugin.o recording.o remote.o remux.o ringbuffer.o\ svdrp.o thread.o tools.o vdr.o videodir.o OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 diff --git a/PLUGINS.html b/PLUGINS.html index b903f040d..70d6f468a 100644 --- a/PLUGINS.html +++ b/PLUGINS.html @@ -15,7 +15,10 @@

The VDR Plugin System

This document describes the "outside" interface of the plugin system. It handles everything necessary for a plugin to get hooked into the core VDR program and present itself to the user. - +

+
  +Important modifications introduced in version 1.1.1 are marked like this. +


Quick start

@@ -25,12 +28,12 @@

The VDR Plugin System

Actually you should read this entire document before starting to work with VDR plugins, but you probably want to see something happening right away ;-)

-So, for a quick demonstration of the plugin system, there is a demo plugin called +So, for a quick demonstration of the plugin system, there is a sample plugin called "hello" that comes with the VDR source. To test drive this one, do the following: