diff options
| author | Klaus Schmidinger <vdr@tvdr.de> | 2002-06-22 10:11:59 +0200 | 
|---|---|---|
| committer | Klaus Schmidinger <vdr@tvdr.de> | 2002-06-22 10:11:59 +0200 | 
| commit | 7ade39597ac83a03395e86a8276fbb6dec6a6a2f (patch) | |
| tree | 11cb4137aee8c97844a03efcaea242f5983d333d | |
| parent | 8a9898ea4f5d1ad71d3ab13b08484bd6ef3a72c8 (diff) | |
| download | vdr-7ade39597ac83a03395e86a8276fbb6dec6a6a2f.tar.gz vdr-7ade39597ac83a03395e86a8276fbb6dec6a6a2f.tar.bz2 | |
Activated cutting
| -rw-r--r-- | HISTORY | 1 | ||||
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | cutter.c | 253 | ||||
| -rw-r--r-- | cutter.h | 29 | ||||
| -rw-r--r-- | dvbplayer.c | 21 | ||||
| -rw-r--r-- | menu.c | 15 | ||||
| -rw-r--r-- | recording.c | 22 | ||||
| -rw-r--r-- | recording.h | 7 | ||||
| -rw-r--r-- | vdr.c | 13 | 
9 files changed, 325 insertions, 40 deletions
| @@ -1351,3 +1351,4 @@ Video Disk Recorder Revision History  2002-06-22: Version 1.1.4  - Added Hungarian language texts (thanks to Istvan Koenigsberger and Guido Josten). +- Activated cutting. @@ -4,7 +4,7 @@  # See the main source file 'vdr.c' for copyright information and  # how to reach the author.  # -# $Id: Makefile 1.40 2002/06/10 16:31:34 kls Exp $ +# $Id: Makefile 1.41 2002/06/22 09:49:29 kls Exp $  .DELETE_ON_ERROR: @@ -21,7 +21,7 @@ INCLUDES = -I$(DVBDIR)/ost/include  DTVLIB   = $(DTVDIR)/libdtv.a -OBJS = audio.o config.o device.o dvbplayer.o dvbosd.o eit.o eitscan.o font.o i18n.o\ +OBJS = audio.o config.o cutter.o device.o dvbplayer.o dvbosd.o eit.o eitscan.o font.o i18n.o\         interface.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o receiver.o\         recorder.o recording.o remote.o remux.o ringbuffer.o status.o svdrp.o thread.o\         tools.o vdr.o videodir.o diff --git a/cutter.c b/cutter.c new file mode 100644 index 00000000..2b623ed8 --- /dev/null +++ b/cutter.c @@ -0,0 +1,253 @@ +/* + * cutter.c: The video cutting facilities + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: cutter.c 1.1 2002/06/22 10:09:34 kls Exp $ + */ + +#include "cutter.h" +#include "recording.h" +#include "remux.h" +#include "thread.h" +#include "videodir.h" + +// --- cCuttingThread -------------------------------------------------------- + +class cCuttingThread : public cThread { +private: +  const char *error; +  bool active; +  int fromFile, toFile; +  cFileName *fromFileName, *toFileName; +  cIndexFile *fromIndex, *toIndex; +  cMarks fromMarks, toMarks; +protected: +  virtual void Action(void); +public: +  cCuttingThread(const char *FromFileName, const char *ToFileName); +  virtual ~cCuttingThread(); +  const char *Error(void) { return error; } +  }; + +cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName) +{ +  error = NULL; +  active = false; +  fromFile = toFile = -1; +  fromFileName = toFileName = NULL; +  fromIndex = toIndex = NULL; +  if (fromMarks.Load(FromFileName) && fromMarks.Count()) { +     fromFileName = new cFileName(FromFileName, false, true); +     toFileName = new cFileName(ToFileName, true, true); +     fromIndex = new cIndexFile(FromFileName, false); +     toIndex = new cIndexFile(ToFileName, true); +     toMarks.Load(ToFileName); // doesn't actually load marks, just sets the file name +     Start(); +     } +  else +     esyslog("no editing marks found for %s", FromFileName); +} + +cCuttingThread::~cCuttingThread() +{ +  active = false; +  Cancel(3); +  delete fromFileName; +  delete toFileName; +  delete fromIndex; +  delete toIndex; +} + +void cCuttingThread::Action(void) +{ +  dsyslog("video cutting thread started (pid=%d)", getpid()); + +  cMark *Mark = fromMarks.First(); +  if (Mark) { +     fromFile = fromFileName->Open(); +     toFile = toFileName->Open(); +     active = fromFile >= 0 && toFile >= 0; +     int Index = Mark->position; +     Mark = fromMarks.Next(Mark); +     int FileSize = 0; +     int CurrentFileNumber = 0; +     int LastIFrame = 0; +     toMarks.Add(0); +     toMarks.Save(); +     uchar buffer[MAXFRAMESIZE]; +     while (active) { +           uchar FileNumber; +           int FileOffset, Length; +           uchar PictureType; + +           // Make sure there is enough disk space: + +           AssertFreeDiskSpace(); + +           // Read one frame: + +           if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { +              if (FileNumber != CurrentFileNumber) { +                 fromFile = fromFileName->SetOffset(FileNumber, FileOffset); +                 CurrentFileNumber = FileNumber; +                 } +              if (fromFile >= 0) { +                 int len = ReadFrame(fromFile, buffer,  Length, sizeof(buffer)); +                 if (len < 0) { +                    error = "ReadFrame"; +                    break; +                    } +                 if (len != Length) { +                    CurrentFileNumber = 0; // this re-syncs in case the frame was larger than the buffer +                    Length = len; +                    } +                 } +              else { +                 error = "fromFile"; +                 break; +                 } +              } +           else +              break; + +           // 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) { +                    error = "toFile 1"; +                    break; +                    } +                 FileSize = 0; +                 } +              LastIFrame = 0; +              } +           if (safe_write(toFile, buffer, Length) < 0) { +              error = "safe_write"; +              break; +              } +           if (!toIndex->Write(PictureType, toFileName->Number(), FileSize)) { +              error = "toIndex"; +              break; +              } +           FileSize += Length; +           if (!LastIFrame) +              LastIFrame = toIndex->Last(); + +           // Check editing marks: + +           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 +                 if (Setup.SplitEditedFiles) { +                    toFile = toFileName->NextFile(); +                    if (toFile < 0) { +                       error = "toFile 2"; +                       break; +                       } +                    FileSize = 0; +                    } +                 } +              // 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. +              } +           } +     } +  else +     esyslog("no editing marks found!"); +  dsyslog("end video cutting thread"); +} + +// --- cCutter --------------------------------------------------------------- + +char *cCutter::editedVersionName = NULL; +cCuttingThread *cCutter::cuttingThread = NULL; +bool cCutter::error = false; +bool cCutter::ended = false; + +bool cCutter::Start(const char *FileName) +{ +  if (!cuttingThread) { +     error = false; +     ended = false; +     cRecording Recording(FileName); +     const char *evn = Recording.PrefixFileName('%'); +     if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { +        // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c) +        // remove a possible deleted recording with the same name to avoid symlink mixups: +        char *s = strdup(evn); +        char *e = strrchr(s, '.'); +        if (e) { +           if (strcmp(e, ".rec") == 0) { +              strcpy(e, ".del"); +              RemoveVideoFile(s); +              } +           } +        delete s; +        // XXX +        editedVersionName = strdup(evn); +        Recording.WriteSummary(); +        cuttingThread = new cCuttingThread(FileName, editedVersionName); +        return true; +        } +     } +  return false; +} + +void cCutter::Stop(void) +{ +  bool Interrupted = cuttingThread && cuttingThread->Active(); +  const char *Error = cuttingThread ? cuttingThread->Error() : NULL; +  delete cuttingThread; +  cuttingThread = NULL; +  if ((Interrupted || Error) && editedVersionName) { +     if (Interrupted) +        isyslog("editing process has been interrupted"); +     if (Error) +        esyslog("ERROR: '%s' during editing process", Error); +     RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? +     } +} + +bool cCutter::Active(void) +{ +  if (cuttingThread) { +     if (cuttingThread->Active()) +        return true; +     error = cuttingThread->Error(); +     Stop(); +     if (!error) +        cRecordingUserCommand::InvokeCommand(RUC_EDITEDRECORDING, editedVersionName); +     delete editedVersionName; +     editedVersionName = NULL; +     ended = true; +     } +  return false; +} + +bool cCutter::Error(void) +{ +  bool result = error; +  error = false; +  return result; +} + +bool cCutter::Ended(void) +{ +  bool result = ended; +  ended = false; +  return result; +} diff --git a/cutter.h b/cutter.h new file mode 100644 index 00000000..8275281f --- /dev/null +++ b/cutter.h @@ -0,0 +1,29 @@ +/* + * cutter.h: The video cutting facilities + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: cutter.h 1.1 2002/06/22 10:03:15 kls Exp $ + */ + +#ifndef __CUTTER_H +#define __CUTTER_H + +class cCuttingThread; + +class cCutter { +private: +  static char *editedVersionName; +  static cCuttingThread *cuttingThread; +  static bool error; +  static bool ended; +public: +  static bool Start(const char *FileName); +  static void Stop(void); +  static bool Active(void); +  static bool Error(void); +  static bool Ended(void); +  }; + +#endif //__CUTTER_H diff --git a/dvbplayer.c b/dvbplayer.c index 10fdf4b5..f18eb84e 100644 --- a/dvbplayer.c +++ b/dvbplayer.c @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: dvbplayer.c 1.1 2002/06/16 10:59:45 kls Exp $ + * $Id: dvbplayer.c 1.2 2002/06/22 10:11:59 kls Exp $   */  #include "dvbplayer.h" @@ -13,22 +13,6 @@  #include "ringbuffer.h"  #include "thread.h" -// --- ReadFrame ------------------------------------------------------------- - -int ReadFrame(int f, uchar *b, int Length, int Max) -{ -  if (Length == -1) -     Length = Max; // this means we read up to EOF (see cIndex) -  else if (Length > Max) { -     esyslog("ERROR: frame larger than buffer (%d > %d)", Length, Max); -     Length = Max; -     } -  int r = safe_read(f, b, Length); -  if (r < 0) -     LOG_ERROR; -  return r; -} -  // --- cBackTrace ----------------------------------------------------------  #define AVG_FRAME_SIZE 15000         // an assumption about the average frame size @@ -91,9 +75,6 @@ int cBackTrace::Get(bool Forward)  // (must be larger than MINVIDEODATA - see remux.h)  #define VIDEOBUFSIZE  MEGABYTE(1) -// The maximum size of a single frame: -#define MAXFRAMESIZE  KILOBYTE(192) -  // The number of frames to back up when resuming an interrupted replay session:  #define RESUMEBACKUP (10 * FRAMESPERSEC) @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: menu.c 1.197 2002/06/16 13:23:51 kls Exp $ + * $Id: menu.c 1.198 2002/06/22 09:55:58 kls Exp $   */  #include "menu.h" @@ -14,6 +14,7 @@  #include <stdlib.h>  #include <string.h>  #include "config.h" +#include "cutter.h"  #include "eit.h"  #include "i18n.h"  #include "menuitems.h" @@ -2026,10 +2027,8 @@ void cMenuMain::Set(void)    // Editing control: -  /*XXX+ -  if (cVideoCutter::Active()) +  if (cCutter::Active())       Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit)); -     XXX*/    // Color buttons: @@ -2063,7 +2062,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)                            }                         break;      case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) { -                          //XXX+cVideoCutter::Stop(); +                          cCutter::Stop();                            return osEnd;                            }                         break; @@ -2973,11 +2972,10 @@ void cReplayControl::MarkMove(bool Forward)  void cReplayControl::EditCut(void)  { -  /*XXX+    if (fileName) {       Hide(); -     if (!cVideoCutter::Active()) { -        if (!cVideoCutter::Start(fileName)) +     if (!cCutter::Active()) { +        if (!cCutter::Start(fileName))             Interface->Error(tr("Can't start editing process!"));          else             Interface->Info(tr("Editing process started")); @@ -2986,7 +2984,6 @@ void cReplayControl::EditCut(void)          Interface->Error(tr("Editing process already active!"));       ShowMode();       } -     XXX*/  }  void cReplayControl::EditTest(void) diff --git a/recording.c b/recording.c index 7bc896c5..7ebec5c9 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: recording.c 1.63 2002/06/16 11:29:27 kls Exp $ + * $Id: recording.c 1.64 2002/06/22 10:11:49 kls Exp $   */  #include "recording.h" @@ -1056,6 +1056,8 @@ int cFileName::NextFile(void)    return SetOffset(fileNumber + 1);  } +// --- Index stuff ----------------------------------------------------------- +  const char *IndexToHMSF(int Index, bool WithFrame)  {    static char buffer[16]; @@ -1080,3 +1082,21 @@ int SecondsToFrames(int Seconds)  {    return Seconds * FRAMESPERSEC;  } + +// --- ReadFrame ------------------------------------------------------------- + +int ReadFrame(int f, uchar *b, int Length, int Max) +{ +  if (Length == -1) +     Length = Max; // this means we read up to EOF (see cIndex) +  else if (Length > Max) { +     esyslog("ERROR: frame larger than buffer (%d > %d)", Length, Max); +     Length = Max; +     } +  int r = safe_read(f, b, Length); +  if (r < 0) +     LOG_ERROR; +  return r; +} + + diff --git a/recording.h b/recording.h index 16c6506f..2fae49ee 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: recording.h 1.23 2002/06/16 11:29:47 kls Exp $ + * $Id: recording.h 1.24 2002/06/22 10:09:27 kls Exp $   */  #ifndef __RECORDING_H @@ -107,6 +107,9 @@ public:  //XXX+  #define FRAMESPERSEC 25 +// The maximum size of a single frame: +#define MAXFRAMESIZE  KILOBYTE(192) +  // The maximum file size is limited by the range that can be covered  // with 'int'. 4GB might be possible (if the range is considered  // 'unsigned'), 2GB should be possible (even if the range is considered @@ -163,4 +166,6 @@ int HMSFToIndex(const char *HMSF);  int SecondsToFrames(int Seconds); //XXX+ ->player???        // Returns the number of frames corresponding to the given number of seconds. +int ReadFrame(int f, uchar *b, int Length, int Max); +  #endif //__RECORDING_H @@ -22,7 +22,7 @@   *   * The project's page is at http://www.cadsoft.de/people/kls/vdr   * - * $Id: vdr.c 1.114 2002/06/16 11:30:28 kls Exp $ + * $Id: vdr.c 1.115 2002/06/22 09:56:12 kls Exp $   */  #include <getopt.h> @@ -31,6 +31,7 @@  #include <stdlib.h>  #include <unistd.h>  #include "config.h" +#include "cutter.h"  #include "device.h"  #include "eitscan.h"  #include "i18n.h" @@ -529,16 +530,14 @@ int main(int argc, char *argv[])            }          if (!Menu) {             EITScanner.Process(); -           /*XXX+ -           if (!cVideoCutter::Active() && cVideoCutter::Ended()) { -              if (cVideoCutter::Error()) +           if (!cCutter::Active() && cCutter::Ended()) { +              if (cCutter::Error())                   Interface->Error(tr("Editing process failed!"));                else                   Interface->Info(tr("Editing process finished"));                } -              XXX*/             } -        if (!*Interact && ((!cRecordControls::Active() /*XXX+&& !cVideoCutter::Active()XXX*/) || ForceShutdown)) { +        if (!*Interact && ((!cRecordControls::Active() && !cCutter::Active()) || ForceShutdown)) {             time_t Now = time(NULL);             if (Now - LastActivity > ACTIVITYTIMEOUT) {                // Shutdown: @@ -598,7 +597,7 @@ int main(int argc, char *argv[])    if (Interrupted)       isyslog("caught signal %d", Interrupted);    cRecordControls::Shutdown(); -  //XXX+cVideoCutter::Stop(); +  cCutter::Stop();    delete Menu;    delete ReplayControl;    delete Interface; | 
