Hello all, here's a proposal for speed control for vdr-dvd. It uses SG_IO and GPCMD_SET_STREAMING so there's no need for VDR to run as root. The user needs rw permissions on the drive, though. When the plug-in is terminated the drive will be set to its initial speed (vacuum cleaner mode). The code is heavily based on mplayer (thank you). I tested it with vdr-1.4.6 and a vdr-dvd snapshot on a NEC ND-3500 and it works just fine. The user can set the speed between 1x and 4x - I figure that's enough - in the OSD plug-in setup. If set to 0 the patch won't kick in. In case the users sets it to zero _while_ he/she is watching a dvd the speed will still be reset because of a DvdSetSpeedActive flag. Kernel and headers have to support the commands for the patch to work but the plug-in should compile and work even on older kernels. All feedback is very welcome. Regards Sebastian
diff -Nur dvd.old/i18n.c dvd/i18n.c --- dvd.old/i18n.c 2007-09-16 18:36:41.000000000 +0200 +++ dvd/i18n.c 2007-11-10 14:43:11.000000000 +0100 @@ -280,6 +280,32 @@ #endif }, { + "Setup.DVD$DVD-ROM Speed", + "DVD-ROM-Geschwindigkeit", // Deutsch + "DVD-ROM Speed", // Slovenski + "DVD-ROM Speed", // Italiano + "DVD-ROM Speed", // Nederlands + "DVD-ROM Speed", // Português + "DVD-ROM Speed", // Français + "DVD-ROM Speed", // Norsk + "DVD-ROM Speed", // suomi + "DVD-ROM Speed", // Polski + "DVD-ROM Speed", // Español + "DVD-ROM Speed", // ÅëëçíéêÜ (Greek) + "DVD-ROM Speed", // Svenska + "DVD-ROM Speed", // Romaneste + "DVD-ROM Speed", // Magyar + "DVD-ROM Speed", // Català + "DVD-ROM Speed", // ÀãááÚØÙ (Russian) + "DVD-ROM Speed", // Hrvatski (Croatian) + "DVD-ROM Speed", // Eesti + "DVD-ROM Speed", // Dansk + "DVD-ROM Speed", // Czech +#if VDRVERSNUM >= 10502 + "DVD-ROM Speed" // Türkçe +#endif + }, + { "Setup.DVD$Gain (analog)", "Verstärkung (analog)", // Deutsch "Ojaèanje (analogno)", // Slovenski diff -Nur dvd.old/player-dvd.c dvd/player-dvd.c --- dvd.old/player-dvd.c 2007-09-17 21:04:43.000000000 +0200 +++ dvd/player-dvd.c 2007-11-10 17:40:57.000000000 +0100 @@ -35,6 +35,11 @@ #include "control-dvd.h" #include "dvd.h" +/* Needed for DvdSetSpeed() */ +#include <linux/cdrom.h> +#include <scsi/sg.h> +#include <sys/ioctl.h> + /** * this was "weak"'s solution of a forced * SPU only stream choice, @@ -252,6 +257,7 @@ bool cDvdPlayer::HasBitStreamOut = false; bool cDvdPlayer::HasSoftDeviceOut = false; bool cDvdPlayer::SoftDeviceOutActive = false; +bool cDvdPlayer::DvdSetSpeedActive = false; const int cDvdPlayer::MaxAudioTracks = 0x20; const int cDvdPlayer::AudioTrackMask = 0x1F; @@ -565,6 +571,93 @@ #endif } +/* This function was ripped off of mplayer without remorse ;-) */ +void cDvdPlayer::DvdSetSpeed(const char *device, int speed) +{ +#if defined(SG_IO) && defined(GPCMD_SET_STREAMING) + int fd; + unsigned char buffer[28]; + unsigned char cmd[16]; + unsigned char sense[16]; + struct sg_io_hdr sghdr; + struct stat st; + + memset(&sghdr, 0, sizeof(sghdr)); + memset(buffer, 0, sizeof(buffer)); + memset(sense, 0, sizeof(sense)); + memset(cmd, 0, sizeof(cmd)); + memset(&st, 0, sizeof(st)); + + if (stat(device, &st) == -1) { + esyslog("ERROR: dvd-plugin: DVD device %s doesn't exist", device); + return; + } + + if (!S_ISBLK(st.st_mode)) { + esyslog("ERROR: dvd-plugin: DVD device %s is not a block device", device); + return; + } + + if ((fd = open(device, O_RDWR | O_NONBLOCK)) == -1) { + esyslog("ERROR: dvd-plugin: Failed to open DVD device %s O_RDWR | O_NONBLOCK", device); + return; + } + + if (speed < 100 && speed > 0) { /* speed times 1350KB/s (DVD single speed) */ + speed *= 1350; + } + + switch (speed) { + case 0: /* don't touch speed setting */ + close(fd); + return; + case -1: /* restore default value */ + speed = 0; + buffer[0] = 4; /* restore default */ + isyslog("dvd-plugin: Restoring initial DVD drive speed"); + break; + default: /* limit to <speed> KB/s */ + isyslog("dvd-plugin: Limiting speed to %d KB/s", speed); + break; + } + + sghdr.interface_id = 'S'; + sghdr.timeout = 5000; + sghdr.dxfer_direction = SG_DXFER_TO_DEV; + sghdr.mx_sb_len = sizeof(sense); + sghdr.dxfer_len = sizeof(buffer); + sghdr.cmd_len = sizeof(cmd); + sghdr.sbp = sense; + sghdr.dxferp = buffer; + sghdr.cmdp = cmd; + + cmd[0] = GPCMD_SET_STREAMING; + cmd[10] = sizeof(buffer); + + buffer[8] = 0xff; /* first sector 0, last sector 0xffffffff */ + buffer[9] = 0xff; + buffer[10] = 0xff; + buffer[11] = 0xff; + + buffer[12] = buffer[20] = (speed >> 24) & 0xff; /* <speed> kilobyte */ + buffer[13] = buffer[21] = (speed >> 16) & 0xff; + buffer[14] = buffer[22] = (speed >> 8) & 0xff; + buffer[15] = buffer[23] = speed & 0xff; + + buffer[18] = buffer[26] = 0x03; /* 1 second */ + buffer[19] = buffer[27] = 0xe8; + + if (ioctl(fd, SG_IO, &sghdr) < 0) { + esyslog("ERROR: dvd-plugin: DVD speed limiting failed"); + close(fd); + return; + } + isyslog("dvd-plugin: DVD speed limiting successful"); + DvdSetSpeedActive = true; + close(fd); +#endif +} + void cDvdPlayer::Action(void) { memset(event_buf, 0, sizeof(uint8_t)*4096); @@ -598,6 +691,11 @@ fflush(NULL); return; } + + /* Try to reduce drive speed if the user wants us to */ + if (DVDSetup.Speed) + DvdSetSpeed(const_cast<char *>(cDVD::getDVD()->DeviceName()), DVDSetup.Speed); + dvdnav_set_readahead_flag(nav, DVDSetup.ReadAHead); if (DVDSetup.PlayerRCE != 0) dvdnav_set_region_mask(nav, 1 << (DVDSetup.PlayerRCE - 1)); @@ -1203,6 +1301,12 @@ dvdnav_close(nav); nav=NULL; + /* Try to restore drive speed if it was previously changed */ + if (DvdSetSpeedActive) { + DvdSetSpeed(const_cast<char *>(cDVD::getDVD()->DeviceName()), -1); + DvdSetSpeedActive = false; + } + DEBUGDVD("%s:%d: input thread ended (pid=%d)\n", __FILE__, __LINE__, getpid()); fflush(NULL); } diff -Nur dvd.old/player-dvd.h dvd/player-dvd.h --- dvd.old/player-dvd.h 2007-09-17 21:04:43.000000000 +0200 +++ dvd/player-dvd.h 2007-11-10 14:50:09.000000000 +0100 @@ -168,6 +168,7 @@ static bool HasBitStreamOut; static bool SoftDeviceOutActive; // currently used to switch for xine static bool HasSoftDeviceOut; // currently used to switch for xine + static bool DvdSetSpeedActive; //dvd stuff int currButtonN; @@ -229,6 +230,7 @@ void DrawSPU(); void HideSPU(); void EmptySPU(); + void DvdSetSpeed(const char*, int); void Pause(void); void Play(void); diff -Nur dvd.old/setup-dvd.c dvd/setup-dvd.c --- dvd.old/setup-dvd.c 2007-08-12 18:57:22.000000000 +0200 +++ dvd/setup-dvd.c 2007-11-10 14:52:06.000000000 +0100 @@ -35,6 +35,7 @@ Gain = 4; AC3dynrng = 0; + Speed = 0; } bool cDVDSetup::SetupParse(const char *Name, const char *Value) @@ -47,6 +48,7 @@ else if (!strcasecmp(Name, "ShowSubtitles")) ShowSubtitles = atoi(Value); else if (!strcasecmp(Name, "HideMainMenu")) HideMainMenu = atoi(Value); else if (!strcasecmp(Name, "ReadAHead")) ReadAHead = atoi(Value); + else if (!strcasecmp(Name, "Speed")) Speed = atoi(Value); else if (!strcasecmp(Name, "Gain")) Gain = atoi(Value); else return false; @@ -72,6 +74,7 @@ Add(new cMenuEditBoolItem(tr("Setup.DVD$Display subtitles"), &data.ShowSubtitles)); Add(new cMenuEditBoolItem(tr("Setup.DVD$Hide Mainmenu Entry"), &data.HideMainMenu)); Add(new cMenuEditBoolItem(tr("Setup.DVD$ReadAHead"), &data.ReadAHead)); + Add(new cMenuEditIntItem( tr("Setup.DVD$DVD-ROM Speed"), &data.Speed, 0, 4)); Add(new cMenuEditIntItem( tr("Setup.DVD$Gain (analog)"), &data.Gain, 0, 10)); } @@ -85,6 +88,7 @@ SetupStore("ShowSubtitles", DVDSetup.ShowSubtitles ); SetupStore("HideMainMenu", DVDSetup.HideMainMenu ); SetupStore("ReadAHead", DVDSetup.ReadAHead ); + SetupStore("Speed", DVDSetup.Speed ); SetupStore("Gain", DVDSetup.Gain ); } diff -Nur dvd.old/setup-dvd.h dvd/setup-dvd.h --- dvd.old/setup-dvd.h 2005-01-05 17:32:21.000000000 +0100 +++ dvd/setup-dvd.h 2007-11-10 14:52:51.000000000 +0100 @@ -23,6 +23,7 @@ int HideMainMenu; int ReadAHead; int Gain; + int Speed; // AC3 stuff int AC3dynrng;
_______________________________________________ vdr mailing list vdr@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr