diff options
author | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2001-09-16 18:00:00 +0200 |
---|---|---|
committer | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2001-09-16 18:00:00 +0200 |
commit | 156831036e9b0fcbfc719033cc89e08c1985cad6 (patch) | |
tree | dede3254f8982f36fe40a11f7ce333b13f2297d6 /dvbapi.c | |
parent | bb18b9e0b449afff418f010c1b2e255acd3fbad3 (diff) | |
download | vdr-patch-lnbsharing-156831036e9b0fcbfc719033cc89e08c1985cad6.tar.gz vdr-patch-lnbsharing-156831036e9b0fcbfc719033cc89e08c1985cad6.tar.bz2 |
Version 0.95vdr-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).
Diffstat (limited to 'dvbapi.c')
-rw-r--r-- | dvbapi.c | 486 |
1 files changed, 336 insertions, 150 deletions
@@ -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 @@ public: 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 @@ private: 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; |