From patchwork Tue Mar 13 22:33:13 2007 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reinhard Nissl X-Patchwork-Id: 12444 Received: from mail.gmx.net ([213.165.64.20]) by www.linuxtv.org with smtp (Exim 4.50) id 1HRFZ0-0001PC-23 for vdr@linuxtv.org; Tue, 13 Mar 2007 23:33:50 +0100 Received: (qmail invoked by alias); 13 Mar 2007 22:33:19 -0000 Received: from p54933386.dip0.t-ipconnect.de (EHLO [192.168.101.15]) [84.147.51.134] by mail.gmx.net (mp012) with SMTP; 13 Mar 2007 23:33:19 +0100 X-Authenticated: #527675 X-Provags-ID: V01U2FsdGVkX1+e+uAlmgWeAt1AUpXSqlz0fO/L/BG1GyfWSH5VQ7 FWtCtszFzqt5af Message-ID: <45F726A9.60604@gmx.de> Date: Tue, 13 Mar 2007 23:33:13 +0100 From: Reinhard Nissl User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20060911 SUSE/1.5.0.9-0.1 Thunderbird/1.5.0.9 Mnenhy/0.7.4.666 MIME-Version: 1.0 To: VDR Mailing List Subject: Re: [vdr] TV Standards option for vdr-1.5.x References: <2d842fa80703121303r1aaa79d8x9dc594ff5fb3f74e@mail.gmail.com> <45F65B3A.3030602@web.de> <2d842fa80703130136ie7b2472qd36afa032d0ce9d5@mail.gmail.com> <45F6655D.30202@web.de> <2d842fa80703130157y5f85f74ei62746d8d2384d000@mail.gmail.com> <45F66D97.2090308@web.de> <2d842fa80703130230k58dbd903tfa7898f378363016@mail.gmail.com> <2d842fa80703130325n65f22beex53f08543ccfca6d4@mail.gmail.com> <2d842fa80703131251l4a5e3614v5e44baed61a046fc@mail.gmail.com> In-Reply-To: <2d842fa80703131251l4a5e3614v5e44baed61a046fc@mail.gmail.com> X-Y-GMX-Trusted: 0 X-BeenThere: vdr@linuxtv.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: VDR Mailing List List-Id: VDR Mailing List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 13 Mar 2007 22:33:50 -0000 Status: O X-Status: X-Keywords: X-UID: 12456 Hi, Stone wrote: > That plugin is only beneficial if you have a dual PAL/NTSC environment. > It does not help with the frames per second calculatons at all. You may want to try the attached patch. It determines FramesPerSec by having a look at the first picture of the recording and falls back to the FRAMESPERSEC macro otherwise. The current implementation requires that the recording was taken with cVideoRepacker enabled. Furthermore it must be MPEG2. The file marks.vdr still uses FRAMEPERSEC for compatibility. Plugins like dvd, burn, mp3, mplayer, etc. still use FRAMESPERSEC. Although this patch is against VDR-1.4.6, it applies with some offset also against VDR-1.5.1. Bye. diff -Nurp ../vdr-1.4.6-orig/dvbplayer.c ./dvbplayer.c --- ../vdr-1.4.6-orig/dvbplayer.c 2006-04-17 14:45:48.000000000 +0200 +++ ./dvbplayer.c 2007-03-13 23:19:51.000000000 +0100 @@ -182,8 +182,8 @@ bool cNonBlockingFileReader::WaitForData #define PLAYERBUFSIZE MEGABYTE(1) -// The number of frames to back up when resuming an interrupted replay session: -#define RESUMEBACKUP (10 * FRAMESPERSEC) +// The number of seconds to back up when resuming an interrupted replay session: +#define RESUMEBACKUP 10 class cDvbPlayer : public cPlayer, cThread { private: @@ -196,6 +196,7 @@ private: cFileName *fileName; cIndexFile *index; cUnbufferedFile *replayFile; + int framesPerSec; bool eof; bool firstPacket; ePlayModes playMode; @@ -225,6 +226,7 @@ public: void Goto(int Position, bool Still = false); virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); + int GetFramesPerSec(void) { return framesPerSec; } }; #define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct? @@ -253,6 +255,7 @@ cDvbPlayer::cDvbPlayer(const char *FileN replayFile = fileName->Open(); if (!replayFile) return; + framesPerSec = replayFile->GetFramesPerSec(); ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE); // Create the index file: index = new cIndexFile(FileName, false); @@ -341,7 +344,7 @@ bool cDvbPlayer::Save(void) if (index) { int Index = writeIndex; if (Index >= 0) { - Index -= RESUMEBACKUP; + Index -= RESUMEBACKUP * GetFramesPerSec(); if (Index > 0) Index = index->GetNextIFrame(Index, false); else @@ -371,7 +374,7 @@ void cDvbPlayer::Action(void) readIndex = Resume(); if (readIndex >= 0) - isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true)); + isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true, GetFramesPerSec())); nonBlockingFileReader = new cNonBlockingFileReader; int Length = 0; @@ -665,7 +668,7 @@ void cDvbPlayer::SkipSeconds(int Seconds Empty(); int Index = writeIndex; if (Index >= 0) { - Index = max(Index + Seconds * FRAMESPERSEC, 0); + Index = max(Index + Seconds * GetFramesPerSec(), 0); if (Index > 0) Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true); if (Index >= 0) @@ -832,3 +835,10 @@ void cDvbPlayerControl::Goto(int Positio if (player) player->Goto(Position, Still); } + +int cDvbPlayerControl::GetFramesPerSec() +{ + if (player) + return player->GetFramesPerSec(); + return FRAMESPERSEC; +} diff -Nurp ../vdr-1.4.6-orig/dvbplayer.h ./dvbplayer.h --- ../vdr-1.4.6-orig/dvbplayer.h 2002-06-23 12:13:51.000000000 +0200 +++ ./dvbplayer.h 2007-03-13 23:19:51.000000000 +0100 @@ -54,6 +54,8 @@ public: void Goto(int Index, bool Still = false); // Positions to the given index and displays that frame as a still picture // if Still is true. + int GetFramesPerSec(); + // Returns the number of frames per second for the current recording. }; #endif //__DVBPLAYER_H diff -Nurp ../vdr-1.4.6-orig/menu.c ./menu.c --- ../vdr-1.4.6-orig/menu.c 2006-12-02 12:12:02.000000000 +0100 +++ ./menu.c 2007-03-13 23:19:51.000000000 +0100 @@ -3931,7 +3931,7 @@ bool cReplayControl::ShowProgress(bool I lastCurrent = lastTotal = -1; } if (Total != lastTotal) { - displayReplay->SetTotal(IndexToHMSF(Total)); + displayReplay->SetTotal(IndexToHMSF(Total, false, GetFramesPerSec())); if (!Initial) displayReplay->Flush(); } @@ -3939,7 +3939,7 @@ bool cReplayControl::ShowProgress(bool I displayReplay->SetProgress(Current, Total); if (!Initial) displayReplay->Flush(); - displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames)); + displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames, GetFramesPerSec())); displayReplay->Flush(); lastCurrent = Current; } @@ -3971,8 +3971,8 @@ void cReplayControl::TimeSearchProcess(e { #define STAY_SECONDS_OFF_END 10 int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60; - int Current = (lastCurrent / FRAMESPERSEC); - int Total = (lastTotal / FRAMESPERSEC); + int Current = (lastCurrent / GetFramesPerSec()); + int Total = (lastTotal / GetFramesPerSec()); switch (Key) { case k0 ... k9: if (timeSearchPos < 4) { @@ -3999,7 +3999,7 @@ void cReplayControl::TimeSearchProcess(e case kDown: case kOk: Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds); - Goto(Seconds * FRAMESPERSEC, Key == kDown || Key == kPause || Key == kOk); + Goto(Seconds * GetFramesPerSec(), Key == kDown || Key == kPause || Key == kOk); timeSearchActive = false; break; default: @@ -4120,7 +4120,7 @@ void cReplayControl::EditTest(void) if ((m->Index() & 0x01) != 0) m = marks.Next(m); if (m) { - Goto(m->position - SecondsToFrames(3)); + Goto(m->position - SecondsToFrames(3, GetFramesPerSec())); Play(); } } diff -Nurp ../vdr-1.4.6-orig/recording.c ./recording.c --- ../vdr-1.4.6-orig/recording.c 2006-10-07 14:46:22.000000000 +0200 +++ ./recording.c 2007-03-13 23:19:51.000000000 +0100 @@ -1496,11 +1496,11 @@ cUnbufferedFile *cFileName::NextFile(voi // --- Index stuff ----------------------------------------------------------- -cString IndexToHMSF(int Index, bool WithFrame) +cString IndexToHMSF(int Index, bool WithFrame, int FramesPerSec) { char buffer[16]; - int f = (Index % FRAMESPERSEC) + 1; - int s = (Index / FRAMESPERSEC); + int f = (Index % FramesPerSec) + 1; + int s = (Index / FramesPerSec); int m = s / 60 % 60; int h = s / 3600; s %= 60; @@ -1508,17 +1508,17 @@ cString IndexToHMSF(int Index, bool With return buffer; } -int HMSFToIndex(const char *HMSF) +int HMSFToIndex(const char *HMSF, int FramesPerSec) { int h, m, s, f = 0; if (3 <= sscanf(HMSF, "%d:%d:%d.%d", &h, &m, &s, &f)) - return (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1; + return (h * 3600 + m * 60 + s) * FramesPerSec + f - 1; return 0; } -int SecondsToFrames(int Seconds) +int SecondsToFrames(int Seconds, int FramesPerSec) { - return Seconds * FRAMESPERSEC; + return Seconds * FramesPerSec; } // --- ReadFrame ------------------------------------------------------------- diff -Nurp ../vdr-1.4.6-orig/recording.h ./recording.h --- ../vdr-1.4.6-orig/recording.h 2006-12-01 16:06:07.000000000 +0100 +++ ./recording.h 2007-03-13 23:19:51.000000000 +0100 @@ -231,11 +231,11 @@ public: cUnbufferedFile *NextFile(void); }; -cString IndexToHMSF(int Index, bool WithFrame = false); +cString IndexToHMSF(int Index, bool WithFrame = false, int FramesPerSec = FRAMESPERSEC); // Converts the given index to a string, optionally containing the frame number. -int HMSFToIndex(const char *HMSF); +int HMSFToIndex(const char *HMSF, int FramesPerSec = FRAMESPERSEC); // Converts the given string (format: "hh:mm:ss.ff") to an index. -int SecondsToFrames(int Seconds); //XXX+ ->player??? +int SecondsToFrames(int Seconds, int FramesPerSec = FRAMESPERSEC); //XXX+ ->player??? // Returns the number of frames corresponding to the given number of seconds. int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max); diff -Nurp ../vdr-1.4.6-orig/svdrp.c ./svdrp.c --- ../vdr-1.4.6-orig/svdrp.c 2006-08-12 11:09:55.000000000 +0200 +++ ./svdrp.c 2007-03-13 23:19:51.000000000 +0100 @@ -1301,8 +1301,10 @@ void cSVDRP::CmdPLAY(const char *Option) int x = sscanf(option, "%d:%d:%d.%d", &h, &m, &s, &f); if (x == 1) pos = h; - else if (x >= 3) - pos = (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1; + else if (x >= 3) { + int FramesPerSec = cUnbufferedFile::GetFramesPerSec(recording->FileName()); + pos = (h * 3600 + m * 60 + s) * FramesPerSec + f - 1; + } } cResumeFile resume(recording->FileName()); if (pos <= 0) diff -Nurp ../vdr-1.4.6-orig/tools.c ./tools.c --- ../vdr-1.4.6-orig/tools.c 2006-12-02 12:12:59.000000000 +0100 +++ ./tools.c 2007-03-13 23:19:51.000000000 +0100 @@ -27,6 +27,8 @@ extern "C" { #include #include "i18n.h" #include "thread.h" +#include "remux.h" +#include "recording.h" int SysLogLevel = 3; @@ -1244,6 +1246,77 @@ cUnbufferedFile *cUnbufferedFile::Create return File; } +int cUnbufferedFile::GetFramesPerSec(const char *FileName) +{ + // use this constant as a fallback value + int FramesPerSec = FRAMESPERSEC; + // open the file an determine frames per second + cFileName fn(FileName, false); + cUnbufferedFile *f = fn.Open(); + if (f) { + FramesPerSec = f->GetFramesPerSec(); + fn.Close(); + } + return FramesPerSec; +} + +int cUnbufferedFile::GetFramesPerSec(void) +{ + // use this constant as a fallback value + int FramesPerSec = FRAMESPERSEC; + // rember current file position to restore later + off_t OrigPos = curpos; + // seek to the beginning and read a chunk of data + if (0 == Seek(0, SEEK_SET)) { + uchar Data[2048]; + ssize_t Count = Read(Data, sizeof(Data)); + if (Count > 0) { + // this chunk of data should actually be a PES packet + uchar *Limit = Data + Count; + int PesPayloadOffset = 0; + if (AnalyzePesHeader(Data, Count, PesPayloadOffset) == phMPEG2) { + // we need a video stream -- radio recordings use the default + if ((Data[3] & 0xF0) == 0xE0) { + // thanks to cVideoRepacker, the payload starts with a sequence header + uchar *p = Data + PesPayloadOffset; + if (p + 12 <= Limit) { + if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && p[3] == 0xB3) { + uint32_t frame_rate_code = p[7] & 0x0F; + uint32_t frame_rate_extension_n = 0; + uint32_t frame_rate_extension_d = 0; + // now we need to have a look at the next startcode, + // as it might be a sequence extension + p = (uchar *)memmem(p + 12, Limit - (p + 12), "\x00\x00\x01", 3); + if (p && p + 4 < Limit && p[3] == 0xB5) { // extension start code + if (p + 5 < Limit && (p[4] >> 4) == 0x1) { // sequence extension + if (p + 10 < Limit) { + frame_rate_extension_n = (p[9] & 0x60) >> 5; + frame_rate_extension_d = (p[9] & 0x1F); + } + } + } + // calculate frame rate and round it for compatibility + if (0x1 <= frame_rate_code && frame_rate_code <= 0x8) { + static const int n[] = { -1, 24000, 24, 25, 30000, 30, 50, 60000, 60 }; + static const int d[] = { -1, 1001, 1, 1, 1001, 1, 1, 1001, 1 }; + double frame_rate = n[frame_rate_code] * (frame_rate_extension_n + 1) + / (double)(d[frame_rate_code] * (frame_rate_extension_d + 1)); + FramesPerSec = (int)frame_rate; + if (frame_rate - FramesPerSec > 0.5) + FramesPerSec++; +fprintf(stderr, "FramesPerSec: %d\n", FramesPerSec); + } + } + } + } + } + } + } + // restore original position + Seek(OrigPos, SEEK_SET); + return FramesPerSec; +} + // --- cLockFile ------------------------------------------------------------- #define LOCKFILENAME ".lock-vdr" diff -Nurp ../vdr-1.4.6-orig/tools.h ./tools.h --- ../vdr-1.4.6-orig/tools.h 2006-12-03 18:38:38.000000000 +0100 +++ ./tools.h 2007-03-13 23:19:51.000000000 +0100 @@ -263,6 +263,8 @@ public: ssize_t Read(void *Data, size_t Size); ssize_t Write(const void *Data, size_t Size); static cUnbufferedFile *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE); + static int GetFramesPerSec(const char *FileName); + int GetFramesPerSec(void); }; class cLockFile {