mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Version 1.1.4
- Added Hungarian language texts (thanks to Istvan Koenigsberger and Guido Josten). - Activated cutting. - Activated 'Transfer Mode'. - Moved handling of the Menu key entirely into vdr.c. - Switched VDR's own player to the new cPlayer/cControl structures. - Switched handling 'Transfer Mode' to the new cPlayer/cControl structures. - The following limitations apply to this version: + The '-a' option (for Dolby Digital audio) doesn't work yet. + Switching between different language tracks doesn't work yet.
This commit is contained in:
		
							
								
								
									
										253
									
								
								cutter.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								cutter.c
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user