27 void Flush(
uchar *Data,
int &Length,
int MaxLength);
48 int NewSize = (
length + Length) * 3 / 2;
62 if (Data &&
length > 0 && Length +
length <= MaxLength) {
78 void Flush(
int Pid,
uchar *Data,
int &Length,
int MaxLength);
83 for (
int i = 0; i <
MAXPID; i++)
89 for (
int i = 0; i <
MAXPID; i++)
97 buffers[Pid]->Append(Data, Length);
103 buffers[Pid]->Flush(Data, Length, MaxLength);
110 bool FindHeader(uint32_t Code,
const char *Header);
116 void AdjGopTime(
int Offset,
int FramesPerSecond);
124 if (
TsPid(Data) == Vpid) {
125 Setup(Data, Length, Vpid);
136 esyslog(
"ERROR: %s header not found!", Header);
183 uchar Frame = ((Byte3 & 0x1F) << 1) | (Byte4 >> 7);
184 uchar Sec = ((Byte2 & 0x07) << 3) | (Byte3 >> 5);
185 uchar Min = ((Byte1 & 0x03) << 4) | (Byte2 >> 4);
186 uchar Hour = ((Byte1 & 0x7C) >> 2);
187 int GopTime = ((Hour * 60 + Min) * 60 + Sec) * FramesPerSecond + Frame;
191 GopTime += 24 * 60 * 60 * FramesPerSecond;
192 Frame = GopTime % FramesPerSecond;
193 GopTime = GopTime / FramesPerSecond;
195 GopTime = GopTime / 60;
197 GopTime = GopTime / 60;
199 SetByte((Byte1 & 0x80) | (Hour << 2) | (Min >> 4), Index1);
200 SetByte(((Min & 0x0F) << 4) | 0x08 | (Sec >> 3), Index2);
201 SetByte(((Sec & 0x07) << 3) | (Frame >> 1), Index3);
202 SetByte((Byte4 & 0x7F) | ((Frame & 0x01) << 7), Index4);
217 SetByte((Tref << 6) | (Byte2 & 0x3F), Index2);
252 bool LoadFrame(
int Index,
uchar *Buffer,
bool &Independent,
int &Length,
bool *Errors = NULL,
bool *Missing = NULL);
258 bool FixFrame(
uchar *Data,
int &Length,
bool Independent,
int Index,
bool CutIn,
bool CutOut);
259 bool ProcessSequence(
int LastEndIndex,
int BeginIndex,
int EndIndex,
int NextBeginIndex);
262 virtual void Action(
void);
305 if (
fromIndex->GetErrors()->Size() > 0) {
312 esyslog(
"no editing sequences found for %s", FromFileName);
315 esyslog(
"no editing marks found for %s", FromFileName);
331 dsyslog(
"suspending cutter thread");
337 dsyslog(
"resuming cutter thread");
347 if (
fromIndex->Get(Index, &FileNumber, &FileOffset, &Independent, &Length, Errors, Missing)) {
354 else if (len != Length)
356 return error == NULL;
390 if (!Buffer1 || !Buffer2)
395 if (
LoadFrame(Index1, Buffer1, Independent, Length1) &&
LoadFrame(Index2, Buffer2, Independent, Length2)) {
396 if (Length1 == Length2) {
398 for (
int i = 0; i < Length1; i++) {
399 if (Buffer1[i] != Buffer2[i]) {
415 bool Processed[
MAXPID] = {
false };
419 for (
int NumIndependentFrames = 0; NumIndependentFrames < 2; Index++) {
422 if (
LoadFrame(Index, Buffer, Independent, len)) {
424 NumIndependentFrames++;
430 int64_t d =
PtsDiff(LastPts, Pts);
434 NumIndependentFrames = 0;
435 Processed[Pid] =
true;
487 bool DeletedFrame =
false;
488 bool GotVidPts =
false;
548 if (!DeletedFrame && !GotVidPts) {
559 bool SeamlessBegin = LastEndIndex >= 0 &&
FramesAreEqual(LastEndIndex, BeginIndex);
560 bool SeamlessEnd = NextBeginIndex >= 0 &&
FramesAreEqual(EndIndex, NextBeginIndex);
567 for (
int Index = BeginIndex;
Running() && Index < EndIndex; Index++) {
572 if (
LoadFrame(Index, Buffer, Independent, Length, &Errors, &Missing)) {
575 bool CutIn = !SeamlessBegin && Index == BeginIndex;
576 bool CutOut = !SeamlessEnd && Index == EndIndex - 1;
577 bool DeletedFrame =
false;
579 DeletedFrame =
FixFrame(Buffer, Length, Independent, Index, CutIn, CutOut);
596 if (
toFile->Write(Buffer, Length) < 0) {
597 error =
"safe_write";
615#define ERROR_HANDLING_DELTA 1
640 int LastEndIndex = -1;
642 while (BeginMark &&
Running()) {
652 int NextBeginIndex = -1;
655 NextBeginIndex = NextBeginMark->Position();
657 if (!
ProcessSequence(LastEndIndex, BeginMark->Position(), EndIndex, NextBeginIndex))
661 LastEndIndex = EndIndex;
663 BeginMark =
fromMarks.GetNextBegin(EndMark);
666 if (
Setup.SplitEditedFiles) {
675 esyslog(
"no editing marks found!");
739 isyslog(
"editing process has been interrupted");
765#define CUTTINGCHECKINTERVAL 500
771 if (Recording.
Name()) {
776 if (Cutter.
Start()) {
781 fprintf(stderr,
"error while cutting\n");
784 fprintf(stderr,
"can't start editing process\n");
787 fprintf(stderr,
"'%s' has no editing sequences\n", FileName);
790 fprintf(stderr,
"'%s' has no editing marks\n", FileName);
793 fprintf(stderr,
"'%s' is not a recording\n", FileName);
796 fprintf(stderr,
"'%s' is not a directory\n", FileName);
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
static void Shutdown(void)
cCuttingThread * cuttingThread
bool Start(void)
Starts the actual cutting process.
cString editedVersionName
cCutter(const char *FileName)
Sets up a new cutter for the given FileName, which must be the full path name of an existing recordin...
cRecordingInfo recordingInfo
void Stop(void)
Stops an ongoing cutting process.
bool Error(void)
Returns true if an error occurred while cutting the recording.
cString originalVersionName
bool Active(void)
Returns true if the cutter is currently active.
static cString EditedFileName(const char *FileName)
Returns the full path name of the edited version of the recording with the given FileName.
void HandleErrors(bool Force=false)
cPatPmtParser patPmtParser
cString editedRecordingName
virtual ~cCuttingThread()
cUnbufferedFile * fromFile
bool SwitchFile(bool Force=false)
cRecordingInfo * recordingInfo
cCuttingThread(const char *FromFileName, const char *ToFileName, cRecordingInfo *RecordingInfo)
bool FixFrame(uchar *Data, int &Length, bool Independent, int Index, bool CutIn, bool CutOut)
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
bool FramesAreEqual(int Index1, int Index2)
bool ProcessSequence(int LastEndIndex, int BeginIndex, int EndIndex, int NextBeginIndex)
bool LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length, bool *Errors=NULL, bool *Missing=NULL)
void GetPendingPackets(uchar *Buffer, int &Length, int Index)
static bool Engaged(void)
Returns true if any I/O throttling object is currently active.
int GetNumSequences(void) const
Returns the actual number of sequences to be cut from the recording.
const cMark * GetNextBegin(const cMark *EndMark=NULL) const
Returns the next "begin" mark after EndMark, skipping any marks at the same position as EndMark.
bool Load(const char *RecordingFileName, double FramesPerSecond=DEFAULTFRAMESPERSECOND, bool IsPesRecording=false)
bool FindHeader(uint32_t Code, const char *Header)
void AdjTref(int TrefOffset)
void AdjGopTime(int Offset, int FramesPerSecond)
cMpeg2Fixer(uchar *Data, int Length, int Vpid)
void Append(uchar *Data, int Length)
Appends Length bytes of Data to this packet buffer.
void Flush(uchar *Data, int &Length, int MaxLength)
Flushes the content of this packet buffer into the given Data, starting at position Length,...
cPacketBuffer * buffers[MAXPID]
void Append(int Pid, uchar *Data, int Length)
void Flush(int Pid, uchar *Data, int &Length, int MaxLength)
static void InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName=NULL)
void SetStartTime(time_t Start)
Sets the start time of this recording to the given value.
const char * Name(void) const
Returns the full name of the recording (without the video directory).
const char * PrefixFileName(char Prefix)
double FramesPerSecond(void) const
bool IsPesRecording(void) const
static void SetBrokenLink(uchar *Data, int Length)
static const char * NowReplaying(void)
static cString sprintf(const char *fmt,...) __attribute__((format(printf
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
cThread(const char *Description=NULL, bool LowPriority=false)
Creates a new thread.
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
void SetByte(uchar Byte, int Index)
Sets the TS data byte at the given Index to the value Byte.
uchar GetByte(void)
Gets the next byte of the TS payload, skipping any intermediate TS header data.
int GetLastIndex(void)
Returns the index into the TS data of the payload byte that has most recently been read.
bool Find(uint32_t Code)
Searches for the four byte sequence given in Code and returns true if it was found within the payload...
bool SkipBytes(int Bytes)
Skips the given number of bytes in the payload and returns true if there is still data left to read.
cUnbufferedFile is used for large files that are mainly written or read in a streaming manner,...
static bool RemoveVideoFile(const char *FileName)
#define ERROR_HANDLING_DELTA
#define CUTTINGCHECKINTERVAL
bool CutRecording(const char *FileName)
void AssertFreeDiskSpace(int Priority, bool Force)
The special Priority value -1 means that we shall get rid of any deleted recordings faster than norma...
int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max)
void SetRecordingTimerId(const char *Directory, const char *TimerId)
#define MAXVIDEOFILESIZEPES
#define RUC_EDITINGRECORDING
#define RUC_EDITEDRECORDING
#define LOCK_RECORDINGS_WRITE
void TsSetPcr(uchar *p, int64_t Pcr)
int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
Returns the difference between two PTS values.
void TsHidePayload(uchar *p)
int64_t TsGetDts(const uchar *p, int l)
void TsSetDts(uchar *p, int l, int64_t Dts)
void TsSetPts(uchar *p, int l, int64_t Pts)
int64_t TsGetPts(const uchar *p, int l)
int TsPid(const uchar *p)
bool TsHasPayload(const uchar *p)
void TsSetContinuityCounter(uchar *p, uchar Counter)
uchar TsContinuityCounter(const uchar *p)
int64_t TsGetPcr(const uchar *p)
int64_t PtsAdd(int64_t Pts1, int64_t Pts2)
Adds the given PTS values, taking into account the 33bit wrap around.