From de45b51473daaa313dda61d4d86c3fb970d51cd8 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 9 Sep 2001 12:52:41 +0200 Subject: [PATCH] Implemented 'Multi Speed Mode' --- CONTRIBUTORS | 1 + HISTORY | 3 +- MANUAL | 11 +++ config.c | 5 +- config.h | 3 +- dvbapi.c | 245 +++++++++++++++++++++++++++++++++------------------ i18n.c | 11 ++- menu.c | 5 +- 8 files changed, 194 insertions(+), 90 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index c055c175..4d5dee50 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -100,6 +100,7 @@ Stefan Huelswitt for making the position of the channel display configurable for making the width and height of the OSD configurable for implementing the "Jump" function in replay mode + for implementing "Multi Speed Mode" Ulrich Röder for pointing out that there are channels that have a symbol rate higher than diff --git a/HISTORY b/HISTORY index 0c2b0554..be38534c 100644 --- a/HISTORY +++ b/HISTORY @@ -716,7 +716,7 @@ Video Disk Recorder Revision History That way every recording will store the actual summary data at the time of the recording. -2001-09-08: Version 0.95 +2001-09-09: Version 0.95 - Fixed behaviour in case the shutdown didn't take place (there were many "next timer event at..." messages in that case). @@ -734,3 +734,4 @@ Video Disk Recorder Revision History 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). diff --git a/MANUAL b/MANUAL index ab1d9b3a..d7bf23af 100644 --- a/MANUAL +++ b/MANUAL @@ -177,6 +177,10 @@ Video Disk Recorder User's Manual backward at a slower speed; press again to return to pause mode. Pressing and holding down the button performs the function until the button is released again. + If "Multi Speed Mode" has been enabled in the "Setup" menu, the + function of these buttons changes in a way that gives you three + fast and slow speeds, through which you can switch by pressing + the respective button several times. - Red Jump to a specific location. Enter the time you want to jump to and then press "Left" or "Right" to jump relative to the current position, "Up" to jump to an absolute position, and "Down" to @@ -451,6 +455,13 @@ Video Disk Recorder User's Manual retaining the possibility to manually shutdown the computer. + MultiSpeedMode = 0 Defines the function of the "Left" and "Right" keys in + replay mode. If set to 0, one speed will be used, while + if set to 1 there will be three speeds for fast and slow + search, respectively. + 0 = off + 1 = on + * Executing system commands The "Main" menu option "Commands" allows you to execute any system commands diff --git a/config.c b/config.c index e3957ac9..171400b6 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.67 2001/09/08 14:12:43 kls Exp $ + * $Id: config.c 1.68 2001/09/08 14:59:38 kls Exp $ */ #include "config.h" @@ -812,6 +812,7 @@ cSetup::cSetup(void) MaxVideoFileSize = MAXVIDEOFILESIZE; MinEventTimeout = 30; MinUserInactivity = 120; + MultiSpeedMode = 0; CurrentChannel = -1; } @@ -849,6 +850,7 @@ bool cSetup::Parse(char *s) else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else return false; @@ -921,6 +923,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "MaxVideoFileSize = %d\n", MaxVideoFileSize); fprintf(f, "MinEventTimeout = %d\n", MinEventTimeout); fprintf(f, "MinUserInactivity = %d\n", MinUserInactivity); + fprintf(f, "MultiSpeedMode = %d\n", MultiSpeedMode); fprintf(f, "CurrentChannel = %d\n", CurrentChannel); f.Close(); isyslog(LOG_INFO, "saved setup to %s", FileName); diff --git a/config.h b/config.h index 2c31a60e..8af48869 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.74 2001/09/08 14:12:30 kls Exp $ + * $Id: config.h 1.75 2001/09/08 14:58:16 kls Exp $ */ #ifndef __CONFIG_H @@ -297,6 +297,7 @@ public: int OSDMessageTime; int MaxVideoFileSize; int MinEventTimeout, MinUserInactivity; + int MultiSpeedMode; int CurrentChannel; cSetup(void); bool Load(const char *FileName); diff --git a/dvbapi.c b/dvbapi.c index 991fb193..69ee8ec2 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -7,7 +7,7 @@ * DVD support initially written by Andreas Schultz * based on dvdplayer-0.5 by Matjaz Thaler * - * $Id: dvbapi.c 1.112 2001/09/08 11:36:12 kls Exp $ + * $Id: dvbapi.c 1.113 2001/09/09 12:52:41 kls Exp $ */ //#define DVDDEBUG 1 @@ -630,17 +630,25 @@ int ReadFrame(int f, uchar *b, int Length, int Max) // --- cPlayBuffer --------------------------------------------------------- +#define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct? + class cPlayBuffer : public cRingBufferFrame { protected: + enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill }; + enum ePlayDirs { pdForward, pdBackward }; + static int Speeds[]; cDvbApi *dvbApi; int videoDev, audioDev; FILE *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); @@ -659,6 +667,11 @@ public: 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) { @@ -667,7 +680,9 @@ cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev) 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; @@ -697,25 +712,23 @@ 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(); Drop(frame); } } @@ -723,6 +736,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)) { @@ -746,67 +779,112 @@ void cPlayBuffer::Empty(bool Block) 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 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 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; + case pmFast: + //XXX + if (playDir == pdForward) + readIndex -= 150; // this about compensates for the buffered data, so that we don't get too far ahead + //XXX + if (Setup.MultiSpeedMode) + TrickSpeed(playDir == pdForward ? 1 : -1); + else if (playDir == pdForward) + Play(); + break; + case pmSlow: + if (Setup.MultiSpeedMode) + TrickSpeed(playDir == pdForward ? -1 : 1); + else if (playDir == pdForward) + Pause(); + 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 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 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; + case pmFast: + if (Setup.MultiSpeedMode) + TrickSpeed(playDir == pdBackward ? 1 : -1); + else if (playDir == pdBackward) + Play(); + break; + case pmSlow: + if (Setup.MultiSpeedMode) + TrickSpeed(playDir == pdBackward ? -1 : 1); + else if (playDir == pdBackward) + Pause(); + break; + } } } @@ -890,18 +968,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 +1150,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 +1173,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 +1255,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 +1535,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 +1553,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 +1648,7 @@ void cDVDplayBuffer::Input(void) case cREADFRAME: { - int trickMode = (fastForward && !paused || fastRewind); + bool trickMode = (playMode != pmPlay); /* FIXME: * the entire trickMode code relies on the assumtion @@ -1582,7 +1657,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 +1684,7 @@ void cDVDplayBuffer::Input(void) case cOUTFRAMES: { - int trickMode = (fastForward && !paused || fastRewind); + bool trickMode = (playMode != pmPlay); /** * Output cursize packs. @@ -1624,7 +1699,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 +1910,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 diff --git a/i18n.c b/i18n.c index c722a787..9fee5055 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.40 2001/09/08 11:43:28 kls Exp $ + * $Id: i18n.c 1.41 2001/09/08 15:01:12 kls Exp $ * * Slovenian translations provided by Miha Setina * Italian translations provided by Alberto Carraro @@ -947,6 +947,15 @@ const tPhrase Phrases[] = { "", // TODO "", // TODO }, + { "MultiSpeedMode", + "MultiSpeed Modus", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, // The days of the week: { "MTWTFSS", "MDMDFSS", diff --git a/menu.c b/menu.c index 7036249b..5e582777 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.116 2001/09/08 14:39:09 kls Exp $ + * $Id: menu.c 1.117 2001/09/08 15:05:16 kls Exp $ */ #include "menu.h" @@ -1725,6 +1725,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditIntItem( tr("MaxVideoFileSize"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); Add(new cMenuEditIntItem( tr("MinEventTimeout"), &data.MinEventTimeout)); Add(new cMenuEditIntItem( tr("MinUserInactivity"), &data.MinUserInactivity)); + Add(new cMenuEditBoolItem(tr("MultiSpeedMode"), &data.MultiSpeedMode)); } eOSState cMenuSetup::ProcessKey(eKeys Key) @@ -2637,8 +2638,10 @@ eOSState cReplayControl::ProcessKey(eKeys Key) case kUp: dvbApi->Play(); break; case kDown: dvbApi->Pause(); break; case kLeft|k_Release: + if (Setup.MultiSpeedMode) break; case kLeft: dvbApi->Backward(); break; case kRight|k_Release: + if (Setup.MultiSpeedMode) break; case kRight: dvbApi->Forward(); break; case kRed: TimeSearch(); break; case kGreen|k_Repeat: