1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Implemented 'Multi Speed Mode'

This commit is contained in:
Klaus Schmidinger 2001-09-09 12:52:41 +02:00
parent 9d509c37e7
commit de45b51473
8 changed files with 194 additions and 90 deletions

View File

@ -100,6 +100,7 @@ Stefan Huelswitt <huels@iname.com>
for making the position of the channel display configurable
for making the width and height of the OSD configurable
for implementing the "Jump" function in replay mode
for implementing "Multi Speed Mode"
Ulrich Röder <dynamite@efr-net.de>
for pointing out that there are channels that have a symbol rate higher than

View File

@ -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).

11
MANUAL
View File

@ -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

View File

@ -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);

View File

@ -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);

245
dvbapi.c
View File

@ -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.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

11
i18n.c
View File

@ -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 <mihasetina@softhome.net>
* Italian translations provided by Alberto Carraro <bertocar@tin.it>
@ -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",

5
menu.c
View File

@ -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: