Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[vdr] vdrcutter2 1.2.5.2 (+destdir +split)



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

revision 1.2.5.2 means:
	based upon plain vanilla vdr 1.2.5
	vdrcutter version 2 ;-)

NEW:
	- no more free space check
	- optional dest-dir
		- this dest-dir can be wherever you wantto
		- optional split into many files ..

the old stdout behavior is still active, if none 
optional options are set ..

@klaus: any chance to make this std alone thingy offcial ?

have fun, cheers sven
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQE/hCfUHdOA30NoFAARAvM9AJoCKyjbIEs4ccOm4Z338yNJvNY6yACglOBT
AlQnEOwEHViZWp/yZhMQsH4=
=j5wq
-----END PGP SIGNATURE-----
diff -Nur vdr-1.2.5/Makefile vdr-1.2.5-vdrcutter2/Makefile
--- vdr-1.2.5/Makefile	2003-08-09 13:09:45.000000000 +0200
+++ vdr-1.2.5-vdrcutter2/Makefile	2003-10-08 16:54:12.000000000 +0200
@@ -33,11 +33,13 @@
 
 DTVLIB   = $(DTVDIR)/libdtv.a
 
-OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd.o\
+OBJSBASE = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd.o\
        dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o interface.o keys.o\
        lirc.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o rcu.o\
        receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sources.o\
-       spu.o status.o svdrp.o thread.o timers.o tools.o transfer.o vdr.o videodir.o
+       spu.o status.o svdrp.o thread.o timers.o tools.o transfer.o videodir.o
+
+OBJS = $(OBJSBASE) vdr.o
 
 OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
 FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
@@ -63,7 +65,7 @@
 DEFINES += -DVFAT
 endif
 
-all: vdr
+all: vdr vdrcutter2
 font: genfontfile fontfix.c fontosd.c
 	@echo "font files created."
 
@@ -86,6 +88,9 @@
 vdr: $(OBJS) $(DTVLIB)
 	$(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(DTVLIB) -o vdr
 
+vdrcutter2: cutter2.o $(OBJSBASE)
+	$(CXX) $(CXXFLAGS) -rdynamic $^ -ljpeg -lpthread -ldl $(LIBDIRS) $(DTVLIB) -o $@
+
 # The font files:
 
 fontfix.c:
@@ -142,6 +147,7 @@
 clean:
 	$(MAKE) -C $(DTVDIR) clean
 	-rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~
+	-rm -f cutter2.o vdrcutter2
 	-rm -rf include
 	-rm -rf srcdoc
 fontclean:
diff -Nur vdr-1.2.5/cutter2.c vdr-1.2.5-vdrcutter2/cutter2.c
--- vdr-1.2.5/cutter2.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.2.5-vdrcutter2/cutter2.c	2003-10-08 16:51:58.000000000 +0200
@@ -0,0 +1,444 @@
+/*
+ * cutter.c: The video cutting facilities
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+
+#include "cutter2.h"
+#include "recording.h"
+#include "remux.h"
+#include "thread.h"
+#include "videodir.h"
+
+// --- cFileNameLoose -------------------------------------------------------------
+
+#include <errno.h>
+#include <unistd.h>
+#include "videodir.h"
+
+#define MAXFILESPERRECORDING 255
+#define RECORDFILESUFFIX    "/%03d.vdr"
+#define RECORDFILESUFFIXLEN 20 // some additional bytes for safety...
+
+class cFileNameLoose {
+private:
+  int file;
+  int fileNumber;
+  char *fileName, *pFileNumber;
+  bool record;
+  bool blocking;
+public:
+  cFileNameLoose(const char *FileName, bool Record, bool Blocking = false);
+  ~cFileNameLoose();
+  const char *Name(void) { return fileName; }
+  int Number(void) { return fileNumber; }
+  int Open(void);
+  void Close(void);
+  int SetOffset(int Number, int Offset = 0);
+  int NextFile(void);
+  };
+
+cFileNameLoose::cFileNameLoose(const char *FileName, bool Record, bool Blocking)
+{
+  file = -1;
+  fileNumber = 0;
+  record = Record;
+  blocking = Blocking;
+  // Prepare the file name:
+  fileName = MALLOC(char, strlen(FileName) + RECORDFILESUFFIXLEN);
+  if (!fileName) {
+     esyslog("ERROR: can't copy file name '%s'", fileName);
+     return;
+     }
+  strcpy(fileName, FileName);
+  pFileNumber = fileName + strlen(fileName);
+  SetOffset(1);
+}
+
+cFileNameLoose::~cFileNameLoose()
+{
+  Close();
+  free(fileName);
+}
+
+int cFileNameLoose::Open(void)
+{
+  if (file < 0) {
+     int BlockingFlag = blocking ? 0 : O_NONBLOCK;
+     if (record) {
+        dsyslog("recording to '%s'", fileName);
+        file = open(fileName, O_RDWR | O_CREAT | BlockingFlag, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+        if (file < 0)
+           LOG_ERROR_STR(fileName);
+        }
+     else {
+        if (access(fileName, R_OK) == 0) {
+           dsyslog("playing '%s'", fileName);
+           file = open(fileName, O_RDONLY | BlockingFlag);
+           if (file < 0)
+              LOG_ERROR_STR(fileName);
+           }
+        else if (errno != ENOENT)
+           LOG_ERROR_STR(fileName);
+        }
+     }
+  return file;
+}
+
+
+void cFileNameLoose::Close(void)
+{
+  if (file >= 0) {
+     if ((record && CloseVideoFile(file) < 0) || (!record && close(file) < 0))
+        LOG_ERROR_STR(fileName);
+     file = -1;
+     }
+}
+
+int cFileNameLoose::SetOffset(int Number, int Offset)
+{
+  if (fileNumber != Number)
+     Close();
+  if (0 < Number && Number <= MAXFILESPERRECORDING) {
+     fileNumber = Number;
+     sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber);
+     if (record) {
+        if (access(fileName, F_OK) == 0) // file exists, let's try next suffix
+           return SetOffset(Number + 1);
+        else if (errno != ENOENT) { // something serious has happened
+           LOG_ERROR_STR(fileName);
+           return -1;
+           }
+        // found a non existing file suffix
+        }
+     if (Open() >= 0) {
+        if (!record && Offset >= 0 && lseek(file, Offset, SEEK_SET) != Offset) {
+           LOG_ERROR_STR(fileName);
+           return -1;
+           }
+        }
+     return file;
+     }
+  esyslog("ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING);
+  return -1;
+}
+
+int cFileNameLoose::NextFile(void)
+{
+  return SetOffset(fileNumber + 1);
+}
+
+// --- cCutting2Thread --------------------------------------------------------
+
+class cCutting2Thread : public cThread {
+private:
+  const char *error;
+  bool active;
+  bool splitFiles;
+  int fromFile, toFile;
+  cFileNameLoose *fromFileName, *toFileName;
+  cIndexFile *fromIndex, *toIndex;
+  cMarks fromMarks, toMarks;
+protected:
+  virtual void Action(void);
+public:
+  cCutting2Thread(const char *FromFileName, int foutdesc);
+  cCutting2Thread(const char *FromFileName, const char *ToFileName, bool splitFiles=false);
+  virtual ~cCutting2Thread();
+  const char *Error(void) { return error; }
+  };
+
+cCutting2Thread::cCutting2Thread(const char *FromFileName, int foutdesc)
+{
+  error = NULL;
+  active = false;
+  splitFiles=false;
+  fromFile = -1;
+  toFile   = foutdesc;
+  fromFileName = toFileName = NULL;
+  fromIndex = toIndex = NULL;
+  if (fromMarks.Load(FromFileName) && fromMarks.Count()) {
+     fromFileName = new cFileNameLoose(FromFileName, false, true);
+     fromIndex = new cIndexFile(FromFileName, false);
+     Start();
+     }
+  else
+     esyslog("no editing marks found for %s", FromFileName);
+}
+
+cCutting2Thread::cCutting2Thread(const char *FromFileName, const char *ToFileName, bool splitFiles)
+{
+  error = NULL;
+  active = false;
+  this->splitFiles=splitFiles;
+  fromFile = toFile = -1;
+  fromFileName = toFileName = NULL;
+  fromIndex = toIndex = NULL;
+  if (fromMarks.Load(FromFileName) && fromMarks.Count()) {
+     fromFileName = new cFileNameLoose(FromFileName, false, true);
+     toFileName = new cFileNameLoose(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);
+}
+
+
+cCutting2Thread::~cCutting2Thread()
+{
+  active = false;
+  Cancel(3);
+  delete fromFileName;
+  delete fromIndex;
+}
+
+void cCutting2Thread::Action(void)
+{
+  dsyslog("video cutting thread started (pid=%d)", getpid());
+
+  cMark *Mark = fromMarks.First();
+  if (Mark) {
+     fromFile = fromFileName->Open();
+     if(toFileName!=NULL)
+	     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;
+     if(toFileName!=NULL)
+     {
+	     toMarks.Add(0);
+	     toMarks.Save();
+     }
+     uchar buffer[MAXFRAMESIZE];
+     bool LastMark = false;
+     bool cutIn = true;
+     while (active) {
+           uchar FileNumber;
+           int FileOffset, Length;
+           uchar PictureType;
+
+           // Make sure there is enough disk space:
+	   //
+	   // well .. this cannot be done here, 'cause we use a different 
+	   // output directory ..
+           // AssertFreeDiskSpace(-1);
+
+           // 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 (LastMark) // edited version shall end before next I-frame
+                 break;
+              if (toFileName!=NULL && FileSize > MEGABYTE(Setup.MaxVideoFileSize)) {
+                 toFile = toFileName->NextFile();
+                 if (toFile < 0) {
+                    error = "toFile 1";
+                    break;
+                    }
+                 FileSize = 0;
+                 }
+              LastIFrame = 0;
+
+              if (cutIn) {
+                 cRemux::SetBrokenLink(buffer, Length);
+                 cutIn = false;
+                 }
+              }
+           if (safe_write(toFile, buffer, Length) < 0) {
+              error = "safe_write";
+              break;
+              }
+           if (toFileName!=NULL && !toIndex->Write(PictureType, toFileName->Number(), FileSize)) {
+              error = "toIndex";
+              break;
+              }
+           FileSize += Length;
+           if (toFileName!=NULL && !LastIFrame)
+              LastIFrame = toIndex->Last();
+
+           // Check editing marks:
+
+           if (Mark && Index >= Mark->position) {
+              Mark = fromMarks.Next(Mark);
+	      if(toFileName!=NULL) {
+		      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
+                 cutIn = true;
+                 if (toFileName!=NULL && splitFiles ) {
+                    toFile = toFileName->NextFile();
+                    if (toFile < 0) {
+                       error = "toFile 2";
+                       break;
+                       }
+                    FileSize = 0;
+                    }
+                 }
+              else
+                 LastMark = true;
+              }
+           }
+     }
+  else
+     esyslog("no editing marks found!");
+  dsyslog("end video cutting thread");
+}
+
+// --- cCutter2 ---------------------------------------------------------------
+
+cCutting2Thread *cCutter2::cuttingThread = NULL;
+bool cCutter2::error = false;
+bool cCutter2::ended = false;
+
+bool cCutter2::Start(const char *FileName, const char *destdir, bool splitFiles)
+{
+  if (!cuttingThread) {
+     error = false;
+     ended = false;
+     if( destdir==NULL )
+	     cuttingThread = new cCutting2Thread(FileName, fileno(stdout));
+     else
+	     cuttingThread = new cCutting2Thread(FileName, destdir, splitFiles);
+     return true;
+     }
+  return false;
+}
+
+void cCutter2::Stop(void)
+{
+  bool Interrupted = cuttingThread && cuttingThread->Active();
+  const char *Error = cuttingThread ? cuttingThread->Error() : NULL;
+  delete cuttingThread;
+  cuttingThread = NULL;
+  if ((Interrupted || Error)) {
+     if (Interrupted)
+        fprintf(stderr, "editing process has been interrupted");
+     if (Error)
+        fprintf(stderr, "ERROR: '%s' during editing process", Error);
+     }
+}
+
+bool cCutter2::Active(void)
+{
+  if (cuttingThread) {
+     if (cuttingThread->Active())
+        return true;
+     error = cuttingThread->Error();
+     Stop();
+     ended = true;
+     }
+  return false;
+}
+
+bool cCutter2::Error(void)
+{
+  bool result = error;
+  error = false;
+  return result;
+}
+
+bool cCutter2::Ended(void)
+{
+  bool result = ended;
+  ended = false;
+  return result;
+}
+
+void printUsage()
+{
+	printf ("usage: vdrcutter2 [-d <dest-directory> [-s]] <recording directory>\n");
+	printf ("\t -d <dest-directory>: optional destination directory for optionally split files, marks, index ..\n");
+	printf ("\t -s: optional split files, only allowed with destination directory \n");
+	printf ("\t if just the recording directory is given, the result is written to stdout\n\n");
+}
+
+int main (int argc, char * argv[])
+{
+  const char * destdir = NULL;
+  const char * recdir = NULL;
+  bool splitFiles=false;
+     
+  fprintf(stderr, "vdrcutter version 1.2.5.2\n");
+
+  int c;
+  while ((c = getopt(argc, argv, "d:s")) != -1) {
+     switch (c) {
+	case 'd': destdir = optarg; break;
+	case 's': splitFiles = true; break;
+	default: printUsage(); exit(1);
+     }
+  }
+
+  if( argc-optind < 1 ) { printUsage(); exit(1); }
+
+  if(splitFiles && !destdir) { printUsage(); exit(1); }
+
+  recdir = argv[optind++];
+
+  fprintf(stderr, "Cutting recording at <%s>\n", recdir);
+
+  if( !destdir )
+	  fprintf(stderr, "Writing result to stdout\n");
+  else 
+	  fprintf(stderr, "Writing result to dir <%s> split=%d\n", destdir, splitFiles);
+
+     cMarks marks;
+
+     marks.Load(recdir);
+
+     if (!cCutter2::Active()) {
+        if (!marks.Count())
+           fprintf(stderr, "No editing marks defined!\n");
+        else if (!cCutter2::Start(recdir, destdir, splitFiles))
+           fprintf(stderr, "Can't start editing process!\n");
+        else {
+           fprintf(stderr, "Editing process started\n");
+	   while ( cCutter2::Active() ) sleep (1);
+          }
+        }
+     else
+        fprintf(stderr, "Editing process already active!\n");
+}
+
diff -Nur vdr-1.2.5/cutter2.h vdr-1.2.5-vdrcutter2/cutter2.h
--- vdr-1.2.5/cutter2.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.2.5-vdrcutter2/cutter2.h	2003-10-08 15:53:28.000000000 +0200
@@ -0,0 +1,28 @@
+/*
+ * 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 __CUTTER2_H
+#define __CUTTER2_H
+
+class cCutting2Thread;
+
+class cCutter2 {
+private:
+  static cCutting2Thread *cuttingThread;
+  static bool error;
+  static bool ended;
+public:
+  static bool Start(const char *FileName, const char *destdir=NULL, bool splitFiles=false);
+  static void Stop(void);
+  static bool Active(void);
+  static bool Error(void);
+  static bool Ended(void);
+  };
+
+#endif //__CUTTER2_H

Home | Main Index | Thread Index