diff options
author | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2001-11-04 18:00:00 +0100 |
---|---|---|
committer | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2001-11-04 18:00:00 +0100 |
commit | 6e1fd835558b4e70ad94a280a209f050ec0f7a75 (patch) | |
tree | c7807d423152fecf6e7fd98aaa6fb69324238431 | |
parent | 8465398c6d2a57bc30a07fb61353a7c8ba6db574 (diff) | |
download | vdr-patch-lnbsharing-6e1fd835558b4e70ad94a280a209f050ec0f7a75.tar.gz vdr-patch-lnbsharing-6e1fd835558b4e70ad94a280a209f050ec0f7a75.tar.bz2 |
Version 0.98vdr-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 Schächner).
- 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.
-rw-r--r-- | CONTRIBUTORS | 14 | ||||
-rw-r--r-- | HISTORY | 39 | ||||
-rw-r--r-- | INSTALL | 10 | ||||
-rw-r--r-- | MANUAL | 14 | ||||
-rw-r--r-- | channels.conf | 36 | ||||
-rw-r--r-- | config.h | 4 | ||||
-rw-r--r-- | dvbapi.c | 941 | ||||
-rw-r--r-- | dvbapi.h | 30 | ||||
-rw-r--r-- | eit.c | 37 | ||||
-rw-r--r-- | eit.h | 9 | ||||
-rw-r--r-- | i18n.c | 11 | ||||
-rw-r--r-- | menu.c | 96 | ||||
-rw-r--r-- | menu.h | 3 | ||||
-rw-r--r-- | ringbuffer.c | 5 | ||||
-rw-r--r-- | ringbuffer.h | 8 | ||||
-rw-r--r-- | svdrp.c | 183 | ||||
-rw-r--r-- | svdrp.h | 13 | ||||
-rw-r--r-- | thread.c | 33 | ||||
-rw-r--r-- | thread.h | 12 | ||||
-rw-r--r-- | vdr.c | 10 |
20 files changed, 732 insertions, 776 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 3a04af1..2fdfcc1 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öder <roeder@efr-net.de> 27500 for his support in keeping the Premiere World channels up to date in 'channels.conf' -Helmut Schächner <schaechner@yahoo.com> +Mel Schächner <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 @@ -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 Schächner). +- Updated 'channels.conf' for Premiere World (thanks to Mel Schächner). 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 Schächner). + (thanks to Mel Schächner). - 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 Schächner). +- 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. @@ -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 @@ -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 200fbfe..c9bf996 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 @@ -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 @@ -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 @@ protected: 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 @@ private: int doplay; int cyclestate; int prevcycle; - int brakeCounter; int skipCnt; tt_srpt_t *tt_srpt; @@ -1335,11 +1520,6 @@ private: 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 @@ private: 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 @@ public: 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); @@ -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 @@ public: 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 @@ private: 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 @@ private: 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 @@ public: 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 { @@ -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); @@ -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 @@ private: 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 @@ protected: 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 @@ public: 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; @@ -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[] = { "Arrêter l'enregistrement?", "Stoppe opptak?", }, + { "on primary interface", + "auf dem primären Interface", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "Cancel editing?", "Schneiden abbrechen?", "Zelite prekiniti urejanje?", @@ -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; @@ -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 @@ public: 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 7e09b2a..8b8420c 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 f61d9e0..7e1025b 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 @@ public: 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; } }; @@ -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); @@ -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 @@ private: 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 @@ private: 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: @@ -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 @@ -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 @@ private: 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 @@ public: cThreadLock(cThread *Thread = NULL); ~cThreadLock(); bool Lock(cThread *Thread); - bool Locked(void); }; #define LOCK_THREAD cThreadLock ThreadLock(this) @@ -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; |