From 7ade39597ac83a03395e86a8276fbb6dec6a6a2f Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 22 Jun 2002 10:11:59 +0200 Subject: Activated cutting --- HISTORY | 1 + Makefile | 4 +- cutter.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cutter.h | 29 +++++++ dvbplayer.c | 21 +---- menu.c | 15 ++-- recording.c | 22 +++++- recording.h | 7 +- vdr.c | 13 ++-- 9 files changed, 325 insertions(+), 40 deletions(-) create mode 100644 cutter.c create mode 100644 cutter.h diff --git a/HISTORY b/HISTORY index 0df6b8a1..00a64394 100644 --- a/HISTORY +++ b/HISTORY @@ -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. diff --git a/Makefile b/Makefile index 09654b21..f3b37504 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/menu.c b/menu.c index ff63fbcd..29703da1 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.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 #include #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 diff --git a/vdr.c b/vdr.c index bef3919f..9423219f 100644 --- a/vdr.c +++ b/vdr.c @@ -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 @@ -31,6 +31,7 @@ #include #include #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; -- cgit v1.2.3