summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2002-06-22 10:11:59 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2002-06-22 10:11:59 +0200
commit7ade39597ac83a03395e86a8276fbb6dec6a6a2f (patch)
tree11cb4137aee8c97844a03efcaea242f5983d333d
parent8a9898ea4f5d1ad71d3ab13b08484bd6ef3a72c8 (diff)
downloadvdr-7ade39597ac83a03395e86a8276fbb6dec6a6a2f.tar.gz
vdr-7ade39597ac83a03395e86a8276fbb6dec6a6a2f.tar.bz2
Activated cutting
-rw-r--r--HISTORY1
-rw-r--r--Makefile4
-rw-r--r--cutter.c253
-rw-r--r--cutter.h29
-rw-r--r--dvbplayer.c21
-rw-r--r--menu.c15
-rw-r--r--recording.c22
-rw-r--r--recording.h7
-rw-r--r--vdr.c13
9 files changed, 325 insertions, 40 deletions
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 <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
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 <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;