Go to the documentation of this file.
28 void Flush(
uchar *Data,
int &Length,
int MaxLength);
49 int NewSize = (
length + Length) * 3 / 2;
63 if (Data &&
length > 0 && Length +
length <= MaxLength) {
79 void Flush(
int Pid,
uchar *Data,
int &Length,
int MaxLength);
84 for (
int i = 0; i <
MAXPID; i++)
90 for (
int i = 0; i <
MAXPID; i++)
111 bool FindHeader(uint32_t Code,
const char *Header);
117 void AdjGopTime(
int Offset,
int FramesPerSecond);
125 if (
TsPid(Data) == Vpid) {
126 Setup(Data, Length, Vpid);
137 esyslog(
"ERROR: %s header not found!", Header);
184 uchar Frame = ((Byte3 & 0x1F) << 1) | (Byte4 >> 7);
185 uchar Sec = ((Byte2 & 0x07) << 3) | (Byte3 >> 5);
186 uchar Min = ((Byte1 & 0x03) << 4) | (Byte2 >> 4);
187 uchar Hour = ((Byte1 & 0x7C) >> 2);
188 int GopTime = ((Hour * 60 + Min) * 60 + Sec) * FramesPerSecond + Frame;
192 GopTime += 24 * 60 * 60 * FramesPerSecond;
193 Frame = GopTime % FramesPerSecond;
194 GopTime = GopTime / FramesPerSecond;
196 GopTime = GopTime / 60;
198 GopTime = GopTime / 60;
200 SetByte((Byte1 & 0x80) | (Hour << 2) | (Min >> 4), Index1);
201 SetByte(((Min & 0x0F) << 4) | 0x08 | (Sec >> 3), Index2);
202 SetByte(((Sec & 0x07) << 3) | (Frame >> 1), Index3);
203 SetByte((Byte4 & 0x7F) | ((Frame & 0x01) << 7), Index4);
218 SetByte((Tref << 6) | (Byte2 & 0x3F), Index2);
249 bool LoadFrame(
int Index,
uchar *Buffer,
bool &Independent,
int &Length);
255 bool FixFrame(
uchar *Data,
int &Length,
bool Independent,
int Index,
bool CutIn,
bool CutOut);
256 bool ProcessSequence(
int LastEndIndex,
int BeginIndex,
int EndIndex,
int NextBeginIndex);
258 virtual void Action(
void);
266 :
cThread(
"video cutting", true)
300 esyslog(
"no editing sequences found for %s", FromFileName);
303 esyslog(
"no editing marks found for %s", FromFileName);
319 dsyslog(
"suspending cutter thread");
325 dsyslog(
"resuming cutter thread");
335 if (
fromIndex->
Get(Index, &FileNumber, &FileOffset, &Independent, &Length)) {
342 else if (len != Length)
344 return error == NULL;
378 if (!Buffer1 || !Buffer2)
383 if (
LoadFrame(Index1, Buffer1, Independent, Length1) &&
LoadFrame(Index2, Buffer2, Independent, Length2)) {
384 if (Length1 == Length2) {
386 for (
int i = 0; i < Length1; i++) {
387 if (Buffer1[i] != Buffer2[i]) {
403 bool Processed[
MAXPID] = {
false };
407 for (
int NumIndependentFrames = 0; NumIndependentFrames < 2; Index++) {
410 if (
LoadFrame(Index, Buffer, Independent, len)) {
412 NumIndependentFrames++;
418 int64_t d =
PtsDiff(LastPts, Pts);
422 NumIndependentFrames = 0;
423 Processed[Pid] =
true;
475 bool DeletedFrame =
false;
476 bool GotVidPts =
false;
508 Pts = PtsAdd(Pts,
offset);
522 Dts = PtsAdd(Dts,
offset);
536 if (!DeletedFrame && !GotVidPts) {
547 bool SeamlessBegin = LastEndIndex >= 0 &&
FramesAreEqual(LastEndIndex, BeginIndex);
548 bool SeamlessEnd = NextBeginIndex >= 0 &&
FramesAreEqual(EndIndex, NextBeginIndex);
555 for (
int Index = BeginIndex; Running() && Index < EndIndex; Index++) {
558 if (
LoadFrame(Index, Buffer, Independent, Length)) {
561 bool CutIn = !SeamlessBegin && Index == BeginIndex;
562 bool CutOut = !SeamlessEnd && Index == EndIndex - 1;
563 bool DeletedFrame =
false;
565 DeletedFrame =
FixFrame(Buffer, Length, Independent, Index, CutIn, CutOut);
581 error =
"safe_write";
606 int LastEndIndex = -1;
607 while (BeginMark && Running()) {
617 int NextBeginIndex = -1;
620 NextBeginIndex = NextBeginMark->Position();
622 if (!
ProcessSequence(LastEndIndex, BeginMark->Position(), EndIndex, NextBeginIndex))
626 LastEndIndex = EndIndex;
639 esyslog(
"no editing marks found!");
698 isyslog(
"editing process has been interrupted");
724 #define CUTTINGCHECKINTERVAL 500 // ms between checks for the active cutting process
730 if (Recording.Name()) {
735 if (Cutter.
Start()) {
740 fprintf(stderr,
"error while cutting\n");
743 fprintf(stderr,
"can't start editing process\n");
746 fprintf(stderr,
"'%s' has no editing sequences\n", FileName);
749 fprintf(stderr,
"'%s' has no editing marks\n", FileName);
752 fprintf(stderr,
"'%s' is not a recording\n", FileName);
755 fprintf(stderr,
"'%s' is not a directory\n", FileName);
void Flush(int Pid, uchar *Data, int &Length, int MaxLength)
int64_t TsGetDts(const uchar *p, int l)
bool FixFrame(uchar *Data, int &Length, bool Independent, int Index, bool CutIn, bool CutOut)
int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max)
void AssertFreeDiskSpace(int Priority, bool Force)
The special Priority value -1 means that we shall get rid of any deleted recordings faster than norma...
bool IsPesRecording(void) const
#define RUC_EDITEDRECORDING
static const char * NowReplaying(void)
cUnbufferedFile * SetOffset(int Number, off_t Offset=0)
void Setup(uchar *Data, int Length, int Pid=-1)
Sets up this TS payload handler with the given Data, which points to a sequence of Length bytes of co...
void TsHidePayload(uchar *p)
#define MAXVIDEOFILESIZEPES
cCutter(const char *FileName)
Sets up a new cutter for the given FileName, which must be the full path name of an existing recordin...
void GetPendingPackets(uchar *Buffer, int &Length, int Index)
static cString EditedFileName(const char *FileName)
Returns the full path name of the edited version of the recording with the given FileName.
void TsSetPts(uchar *p, int l, int64_t Pts)
cUnbufferedFile * NextFile(void)
cUnbufferedFile * Open(void)
#define CUTTINGCHECKINTERVAL
cPatPmtParser patPmtParser
void AdjTref(int TrefOffset)
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 Add(int Position)
If this cMarks object is used by multiple threads, the caller must Lock() it before calling Add() and...
bool ParsePatPmt(const uchar *Data, int Length)
Parses the given Data (which may consist of several TS packets, typically an entire frame) and extrac...
cUnbufferedFile is used for large files that are mainly written or read in a streaming manner,...
int TsPid(const uchar *p)
cUnbufferedFile * fromFile
int64_t TsGetPcr(const uchar *p)
static void InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName=NULL)
uchar GetByte(void)
Gets the next byte of the TS payload, skipping any intermediate TS header data.
void AdjGopTime(int Offset, int FramesPerSecond)
void Append(uchar *Data, int Length)
Appends Length bytes of Data to this packet buffer.
cMpeg2Fixer(uchar *Data, int Length, int Vpid)
bool Find(uint32_t Code)
Searches for the four byte sequence given in Code and returns true if it was found within the payload...
double FramesPerSecond(void) const
const char * PrefixFileName(char Prefix)
bool CutRecording(const char *FileName)
const cMark * GetNextEnd(const cMark *BeginMark) const
Returns the next "end" mark after BeginMark, skipping any marks at the same position as BeginMark.
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 Active(void)
Returns true if the cutter is currently active.
void Flush(uchar *Data, int &Length, int MaxLength)
Flushes the content of this packet buffer into the given Data, starting at position Length,...
bool TsHasPayload(const uchar *p)
static void SetBrokenLink(uchar *Data, int Length)
static bool RemoveVideoFile(const char *FileName)
bool SwitchFile(bool Force=false)
int GetLastIndex(void)
Returns the index into the TS data of the payload byte that has most recently been read.
void Append(int Pid, uchar *Data, int Length)
cString originalVersionName
virtual ~cCuttingThread()
bool FindHeader(uint32_t Code, const char *Header)
uchar TsContinuityCounter(const uchar *p)
cPacketBuffer * buffers[MAXPID]
bool FramesAreEqual(int Index1, int Index2)
bool Load(const char *RecordingFileName, double FramesPerSecond=DEFAULTFRAMESPERSECOND, bool IsPesRecording=false)
int GetNumSequences(void) const
Returns the actual number of sequences to be cut from the recording.
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
bool Write(bool Independent, uint16_t FileNumber, off_t FileOffset)
ssize_t Write(const void *Data, size_t Size)
void SetByte(uchar Byte, int Index)
Sets the TS data byte at the given Index to the value Byte.
bool Error(void)
Returns true if an error occurred while cutting the recording.
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
bool Active(void)
Checks whether the thread is still alive.
cString editedVersionName
void TsSetPcr(uchar *p, int64_t Pcr)
void TsSetContinuityCounter(uchar *p, uchar Counter)
int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
Returns the difference between two PTS values.
void SetReadAhead(size_t ra)
void Stop(void)
Stops an ongoing cutting process.
bool SkipBytes(int Bytes)
Skips the given number of bytes in the payload and returns true if there is still data left to read.
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
#define RUC_EDITINGRECORDING
bool Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent=NULL, int *Length=NULL)
bool LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length)
cCuttingThread(const char *FromFileName, const char *ToFileName)
int64_t TsGetPts(const uchar *p, int l)
bool Start(void)
Starts the actual cutting process.
static bool Engaged(void)
Returns true if any I/O throttling object is currently active.
void TsSetDts(uchar *p, int l, int64_t Dts)
cCuttingThread * cuttingThread
bool ProcessSequence(int LastEndIndex, int BeginIndex, int EndIndex, int NextBeginIndex)
static void Shutdown(void)
bool WriteInfo(const char *OtherFileName=NULL)
Writes in info file of this recording.
void SetStartTime(time_t Start)
Sets the start time of this recording to the given value.