summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY17
-rw-r--r--MANUAL20
-rw-r--r--cutter.c650
-rw-r--r--menu.c4
-rw-r--r--po/ar.po5
-rw-r--r--po/ca_ES.po5
-rw-r--r--po/cs_CZ.po5
-rw-r--r--po/da_DK.po5
-rw-r--r--po/de_DE.po5
-rw-r--r--po/el_GR.po5
-rw-r--r--po/es_ES.po5
-rw-r--r--po/et_EE.po5
-rw-r--r--po/fi_FI.po5
-rw-r--r--po/fr_FR.po5
-rw-r--r--po/hr_HR.po5
-rw-r--r--po/hu_HU.po5
-rw-r--r--po/it_IT.po5
-rw-r--r--po/lt_LT.po5
-rw-r--r--po/mk_MK.po5
-rw-r--r--po/nl_NL.po5
-rw-r--r--po/nn_NO.po5
-rw-r--r--po/pl_PL.po5
-rw-r--r--po/pt_PT.po5
-rw-r--r--po/ro_RO.po5
-rw-r--r--po/ru_RU.po5
-rw-r--r--po/sk_SK.po5
-rw-r--r--po/sl_SI.po5
-rw-r--r--po/sr_SR.po5
-rw-r--r--po/sv_SE.po5
-rw-r--r--po/tr_TR.po5
-rw-r--r--po/uk_UA.po5
-rw-r--r--po/zh_CN.po5
-rw-r--r--recording.c50
-rw-r--r--recording.h15
-rw-r--r--remux.c108
-rw-r--r--remux.h66
36 files changed, 846 insertions, 224 deletions
diff --git a/HISTORY b/HISTORY
index 50470824..93e5fd09 100644
--- a/HISTORY
+++ b/HISTORY
@@ -7272,7 +7272,7 @@ Video Disk Recorder Revision History
".keep" to prevent a directory from being deleted when it is empty. Currently the
only file name that is ignored is ".sort".
-2012-11-12: Version 1.7.32
+2012-11-18: Version 1.7.32
- Pressing the Play key during normal live viewing mode now opens the Recordings menu
if there is no "last viewed" recording (thanks to Alexander Wenzel).
@@ -7315,3 +7315,18 @@ Video Disk Recorder Revision History
- The return type of cMarks::Add() has been changed to void, since due to the sorting
of the list of marks the returned pointer might have pointed to a totally different
mark. Besides, the return value was never actually used.
+- Improved editing TS recordings by
+ + stripping dangling TS packets from the beginning of a sequence
+ + including pending TS packets at the end of a sequence
+ + fixing all timestamps and continuity counters
+ + generating editing marks for the edited version in such a way that each cutting
+ point is marked by an "end" and "begin" mark with the same offset
+ + no longer generating an editing mark at the "end" of the edited recording (this
+ was actually generated at the beginning of the last GOP, so that a subsequent
+ edit would have cut off the last GOP)
+ + no longer generating any editing marks if the edited recording results on just
+ one single sequence
+ + ignoring pairs of editing marks that are placed at exactly the same position of
+ a recording when actually cutting the recording
+ + not doing anything if the editing marks in place would result in the edited
+ version being the same as the original recording
diff --git a/MANUAL b/MANUAL
index fb28462b..272659cc 100644
--- a/MANUAL
+++ b/MANUAL
@@ -367,13 +367,13 @@ Version 1.6
- 7, 9 Jump back and forward between editing marks. Replay goes into still
mode after jumping to a mark.
- 8 Positions replay at a point 3 seconds before the current or next
- "start" mark and starts replay.
+ "begin" mark and starts replay.
- 2 Start the actual cutting process.
Editing marks are represented by black, vertical lines in the progress display.
- A small black triangle at the top of the mark means that this is a "start"
+ A small black triangle at the top of the mark means that this is a "begin"
mark, and a triangle at the bottom means that this is an "end" mark.
- The cutting process will save all video data between "start" and "end" marks
+ The cutting process will save all video data between "begin" and "end" marks
into a new file (the original recording remains untouched). The new file will
have the same name as the original recording, preceded with a '%' character
(imagine the '%' somehow looking like a pair of scissors ;-). Red bars in the
@@ -382,7 +382,7 @@ Version 1.6
The video sequences to be saved by the cutting process are determined by an
"even/odd" algorithm. This means that every odd numbered editing mark (i.e.
- 1, 3, 5,...) represents a "start" mark, while every even numbered mark (2, 4,
+ 1, 3, 5,...) represents a "begin" mark, while every even numbered mark (2, 4,
6,...) is an "end" mark. Inserting or toggling a mark on or off automatically
adjusts the sequence to the right side of that mark.
@@ -395,11 +395,13 @@ Version 1.6
version of the recording you can use the '8' key to jump to a point just
before the next cut and have a look at the resulting sequence.
- Currently editing marks can only be set at I-frames, which typically is
- every 12th frame. So editing can be done with a resolution of roughly half
- a second. A "start" mark marks the first frame of a resulting video
- sequence, and an "end" mark marks the last frame of that sequence.
-
+ Currently editing marks can only be set at I-frames, which typically appear
+ every half of a second to a second. A "begin" mark marks the first frame of
+ a resulting video sequence, and an "end" mark marks the last frame of that
+ sequence. Note that the actual frame indicated by the an "end" mark will
+ not be included in the edited version of the recording. That's because every
+ recording (and every sequence of an edited recording) begins with an I-frame
+ and ends right before the next I-frame.
An edited recording (indicated by the '%' character) will never be deleted
automatically in case the disk runs full (no matter what "lifetime" it has).
diff --git a/cutter.c b/cutter.c
index a0e2b477..ace1893b 100644
--- a/cutter.c
+++ b/cutter.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: cutter.c 2.15 2012/10/04 12:19:37 kls Exp $
+ * $Id: cutter.c 2.16 2012/11/18 12:09:00 kls Exp $
*/
#include "cutter.h"
@@ -13,17 +13,261 @@
#include "remux.h"
#include "videodir.h"
+// --- cPacketBuffer ---------------------------------------------------------
+
+class cPacketBuffer {
+private:
+ uchar *data;
+ int size;
+ int length;
+public:
+ cPacketBuffer(void);
+ ~cPacketBuffer();
+ 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, and clears the buffer afterwards. Length will be
+ ///< incremented accordingly. If Length plus the total length of the stored
+ ///< packets would exceed MaxLength, nothing is copied.
+ };
+
+cPacketBuffer::cPacketBuffer(void)
+{
+ data = NULL;
+ size = length = 0;
+}
+
+cPacketBuffer::~cPacketBuffer()
+{
+ free(data);
+}
+
+void cPacketBuffer::Append(uchar *Data, int Length)
+{
+ if (length + Length >= size) {
+ int NewSize = (length + Length) * 3 / 2;
+ if (uchar *p = (uchar *)realloc(data, NewSize)) {
+ data = p;
+ size = NewSize;
+ }
+ else
+ return; // out of memory
+ }
+ memcpy(data + length, Data, Length);
+ length += Length;
+}
+
+void cPacketBuffer::Flush(uchar *Data, int &Length, int MaxLength)
+{
+ if (Data && length > 0 && Length + length <= MaxLength) {
+ memcpy(Data + Length, data, length);
+ Length += length;
+ }
+ length = 0;
+}
+
+// --- cPacketStorage --------------------------------------------------------
+
+class cPacketStorage {
+private:
+ cPacketBuffer *buffers[MAXPID];
+public:
+ cPacketStorage(void);
+ ~cPacketStorage();
+ void Append(int Pid, uchar *Data, int Length);
+ void Flush(int Pid, uchar *Data, int &Length, int MaxLength);
+ };
+
+cPacketStorage::cPacketStorage(void)
+{
+ for (int i = 0; i < MAXPID; i++)
+ buffers[i] = NULL;
+}
+
+cPacketStorage::~cPacketStorage()
+{
+ for (int i = 0; i < MAXPID; i++)
+ delete buffers[i];
+}
+
+void cPacketStorage::Append(int Pid, uchar *Data, int Length)
+{
+ if (!buffers[Pid])
+ buffers[Pid] = new cPacketBuffer;
+ buffers[Pid]->Append(Data, Length);
+}
+
+void cPacketStorage::Flush(int Pid, uchar *Data, int &Length, int MaxLength)
+{
+ if (buffers[Pid])
+ buffers[Pid]->Flush(Data, Length, MaxLength);
+}
+
+// --- cDanglingPacketStripper -----------------------------------------------
+
+class cDanglingPacketStripper {
+private:
+ bool processed[MAXPID];
+ cPatPmtParser patPmtParser;
+public:
+ cDanglingPacketStripper(void);
+ bool Process(uchar *Data, int Length, int64_t FirstPts);
+ ///< Scans the frame given in Data and hides the payloads of any TS packets
+ ///< that either didn't start within this frame, or have a PTS that is
+ ///< before FirstPts. The TS packets in question are not physically removed
+ ///< from Data in order to keep any frame counts and PCR timestamps intact.
+ ///< Returns true if any dangling packets have been found.
+ };
+
+cDanglingPacketStripper::cDanglingPacketStripper(void)
+{
+ memset(processed, 0x00, sizeof(processed));
+}
+
+bool cDanglingPacketStripper::Process(uchar *Data, int Length, int64_t FirstPts)
+{
+ bool Found = false;
+ while (Length >= TS_SIZE && *Data == TS_SYNC_BYTE) {
+ int Pid = TsPid(Data);
+ if (Pid == PATPID)
+ patPmtParser.ParsePat(Data, TS_SIZE);
+ else if (Pid == patPmtParser.PmtPid())
+ patPmtParser.ParsePmt(Data, TS_SIZE);
+ else {
+ int64_t Pts = TsGetPts(Data, TS_SIZE);
+ if (Pts >= 0)
+ processed[Pid] = PtsDiff(FirstPts, Pts) >= 0; // Pts is at or after FirstPts
+ if (!processed[Pid]) {
+ TsHidePayload(Data);
+ Found = true;
+ }
+ }
+ Length -= TS_SIZE;
+ Data += TS_SIZE;
+ }
+ return Found;
+}
+
+// --- cPtsFixer -------------------------------------------------------------
+
+class cPtsFixer {
+private:
+ int delta; // time between two frames
+ int64_t last; // the last (i.e. highest) video PTS value seen
+ int64_t offset; // offset to add to PTS values
+ bool fixCounters; // controls fixing the TS continuity counters (only from the second CutIn up)
+ uchar counter[MAXPID]; // the TS continuity counter for each PID
+ cPatPmtParser patPmtParser;
+public:
+ cPtsFixer(void);
+ void Setup(double FramesPerSecond);
+ void Fix(uchar *Data, int Length, bool CutIn);
+ };
+
+cPtsFixer::cPtsFixer(void)
+{
+ delta = 0;
+ last = -1;
+ offset = -1;
+ fixCounters = false;
+ memset(counter, 0x00, sizeof(counter));
+}
+
+void cPtsFixer::Setup(double FramesPerSecond)
+{
+ delta = int(round(PTSTICKS / FramesPerSecond));
+}
+
+void cPtsFixer::Fix(uchar *Data, int Length, bool CutIn)
+{
+ if (!patPmtParser.Vpid()) {
+ if (!patPmtParser.ParsePatPmt(Data, Length))
+ return;
+ }
+ // Determine the PTS offset at the beginning of each sequence (except the first one):
+ if (CutIn && last >= 0) {
+ int64_t Pts = TsGetPts(Data, Length);
+ if (Pts >= 0) {
+ // offset is calculated so that Pts + offset results in last + delta:
+ offset = Pts - PtsAdd(last, delta);
+ if (offset <= 0)
+ offset = -offset;
+ else
+ offset = MAX33BIT + 1 - offset;
+ }
+ fixCounters = true;
+ }
+ // Keep track of the highest video PTS:
+ uchar *p = Data;
+ int len = Length;
+ while (len >= TS_SIZE && *p == TS_SYNC_BYTE) {
+ int Pid = TsPid(p);
+ if (Pid == patPmtParser.Vpid()) {
+ int64_t Pts = PtsAdd(TsGetPts(p, TS_SIZE), offset); // offset is taken into account here, to make last have the "new" value already!
+ if (Pts >= 0 && (last < 0 || PtsDiff(last, Pts) > 0))
+ last = Pts;
+ }
+ // Adjust the TS continuity counter:
+ if (fixCounters) {
+ counter[Pid] = (counter[Pid] + 1) & TS_CONT_CNT_MASK;
+ TsSetContinuityCounter(p, counter[Pid]);
+ }
+ else
+ counter[Pid] = TsGetContinuityCounter(p); // collect initial counters
+ p += TS_SIZE;
+ len -= TS_SIZE;
+ }
+ // Apply the PTS offset:
+ if (offset > 0) {
+ uchar *p = Data;
+ int len = Length;
+ while (len >= TS_SIZE && *p == TS_SYNC_BYTE) {
+ // Adjust the various timestamps:
+ int64_t Pts = TsGetPts(p, TS_SIZE);
+ if (Pts >= 0)
+ TsSetPts(p, TS_SIZE, PtsAdd(Pts, offset));
+ int64_t Dts = TsGetDts(p, TS_SIZE);
+ if (Dts >= 0)
+ TsSetDts(p, TS_SIZE, PtsAdd(Dts, offset));
+ int64_t Pcr = TsGetPcr(p);
+ if (Pcr >= 0) {
+ int64_t NewPcr = Pcr + offset * PCRFACTOR;
+ if (NewPcr >= MAX27MHZ)
+ NewPcr -= MAX27MHZ + 1;
+ TsSetPcr(p, NewPcr);
+ }
+ p += TS_SIZE;
+ len -= TS_SIZE;
+ }
+ }
+}
+
// --- cCuttingThread --------------------------------------------------------
class cCuttingThread : public cThread {
private:
const char *error;
bool isPesRecording;
+ double framesPerSecond;
cUnbufferedFile *fromFile, *toFile;
cFileName *fromFileName, *toFileName;
cIndexFile *fromIndex, *toIndex;
cMarks fromMarks, toMarks;
+ int numSequences;
off_t maxVideoFileSize;
+ off_t fileSize;
+ cPtsFixer ptsFixer;
+ bool suspensionLogged;
+ bool Throttled(void);
+ bool SwitchFile(bool Force = false);
+ bool LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length);
+ bool FramesAreEqual(int Index1, int Index2);
+ void GetPendingPackets(uchar *Buffer, int &Length, int Index, int64_t LastPts);
+ // Gather all non-video TS packets from Index upward that either belong to
+ // payloads that started before Index, or have a PTS that is before LastPts,
+ // and add them to the end of the given Data.
+ bool ProcessSequence(int LastEndIndex, int BeginIndex, int EndIndex, int NextBeginIndex);
protected:
virtual void Action(void);
public:
@@ -41,16 +285,25 @@ cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName)
fromIndex = toIndex = NULL;
cRecording Recording(FromFileName);
isPesRecording = Recording.IsPesRecording();
- if (fromMarks.Load(FromFileName, Recording.FramesPerSecond(), isPesRecording) && fromMarks.Count()) {
- fromFileName = new cFileName(FromFileName, false, true, isPesRecording);
- toFileName = new cFileName(ToFileName, true, true, isPesRecording);
- fromIndex = new cIndexFile(FromFileName, false, isPesRecording);
- toIndex = new cIndexFile(ToFileName, true, isPesRecording);
- toMarks.Load(ToFileName, Recording.FramesPerSecond(), isPesRecording); // doesn't actually load marks, just sets the file name
- maxVideoFileSize = MEGABYTE(Setup.MaxVideoFileSize);
- if (isPesRecording && maxVideoFileSize > MEGABYTE(MAXVIDEOFILESIZEPES))
- maxVideoFileSize = MEGABYTE(MAXVIDEOFILESIZEPES);
- Start();
+ framesPerSecond = Recording.FramesPerSecond();
+ suspensionLogged = false;
+ fileSize = 0;
+ ptsFixer.Setup(framesPerSecond);
+ if (fromMarks.Load(FromFileName, framesPerSecond, isPesRecording) && fromMarks.Count()) {
+ numSequences = fromMarks.GetNumSequences();
+ if (numSequences > 0) {
+ fromFileName = new cFileName(FromFileName, false, true, isPesRecording);
+ toFileName = new cFileName(ToFileName, true, true, isPesRecording);
+ fromIndex = new cIndexFile(FromFileName, false, isPesRecording);
+ toIndex = new cIndexFile(ToFileName, true, isPesRecording);
+ toMarks.Load(ToFileName, framesPerSecond, isPesRecording); // doesn't actually load marks, just sets the file name
+ maxVideoFileSize = MEGABYTE(Setup.MaxVideoFileSize);
+ if (isPesRecording && maxVideoFileSize > MEGABYTE(MAXVIDEOFILESIZEPES))
+ maxVideoFileSize = MEGABYTE(MAXVIDEOFILESIZEPES);
+ Start();
+ }
+ else
+ esyslog("no editing sequences found for %s", FromFileName);
}
else
esyslog("no editing marks found for %s", FromFileName);
@@ -65,169 +318,236 @@ cCuttingThread::~cCuttingThread()
delete toIndex;
}
+bool cCuttingThread::Throttled(void)
+{
+ if (cIoThrottle::Engaged()) {
+ if (!suspensionLogged) {
+ dsyslog("suspending cutter thread");
+ suspensionLogged = true;
+ }
+ return true;
+ }
+ else if (suspensionLogged) {
+ dsyslog("resuming cutter thread");
+ suspensionLogged = false;
+ }
+ return false;
+}
+
+bool cCuttingThread::LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length)
+{
+ uint16_t FileNumber;
+ off_t FileOffset;
+ if (fromIndex->Get(Index, &FileNumber, &FileOffset, &Independent, &Length)) {
+ fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
+ if (fromFile) {
+ fromFile->SetReadAhead(MEGABYTE(20));
+ int len = ReadFrame(fromFile, Buffer, Length, MAXFRAMESIZE);
+ if (len < 0)
+ error = "ReadFrame";
+ else if (len != Length)
+ Length = len;
+ return error == NULL;
+ }
+ else
+ error = "fromFile";
+ }
+ return false;
+}
+
+bool cCuttingThread::SwitchFile(bool Force)
+{
+ if (fileSize > maxVideoFileSize || Force) {
+ toFile = toFileName->NextFile();
+ if (!toFile) {
+ error = "toFile";
+ return false;
+ }
+ fileSize = 0;
+ }
+ return true;
+}
+
+bool cCuttingThread::FramesAreEqual(int Index1, int Index2)
+{
+ bool Independent;
+ uchar Buffer1[MAXFRAMESIZE];
+ uchar Buffer2[MAXFRAMESIZE];
+ int Length1;
+ int Length2;
+ if (LoadFrame(Index1, Buffer1, Independent, Length1) && LoadFrame(Index2, Buffer2, Independent, Length2)) {
+ if (Length1 == Length2) {
+ int Diffs = 0;
+ for (int i = 0; i < Length1; i++) {
+ if (Buffer1[i] != Buffer2[i]) {
+ if (Diffs++ > 10) // the continuity counters of the PAT/PMT packets may differ
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void cCuttingThread::GetPendingPackets(uchar *Data, int &Length, int Index, int64_t LastPts)
+{
+ bool Processed[MAXPID] = { false };
+ int NumIndependentFrames = 0;
+ cPatPmtParser PatPmtParser;
+ cPacketStorage PacketStorage;
+ for (; NumIndependentFrames < 2; Index++) {
+ uchar Buffer[MAXFRAMESIZE];
+ bool Independent;
+ int len;
+ if (LoadFrame(Index, Buffer, Independent, len)) {
+ if (Independent)
+ NumIndependentFrames++;
+ uchar *p = Buffer;
+ while (len >= TS_SIZE && *p == TS_SYNC_BYTE) {
+ int Pid = TsPid(p);
+ if (Pid == PATPID)
+ PatPmtParser.ParsePat(p, TS_SIZE);
+ else if (Pid == PatPmtParser.PmtPid())
+ PatPmtParser.ParsePmt(p, TS_SIZE);
+ else if (!Processed[Pid]) {
+ int64_t Pts = TsGetPts(p, TS_SIZE);
+ if (Pts >= 0) {
+ int64_t d = PtsDiff(LastPts, Pts);
+ if (d <= 0) // Pts is before or at LastPts
+ PacketStorage.Flush(Pid, Data, Length, MAXFRAMESIZE);
+ if (d >= 0) { // Pts is at or after LastPts
+ NumIndependentFrames = 0; // we search until we find two consecutive I-frames without any more pending packets
+ Processed[Pid] = true;
+ }
+ }
+ if (!Processed[Pid])
+ PacketStorage.Append(Pid, p, TS_SIZE);
+ }
+ len -= TS_SIZE;
+ p += TS_SIZE;
+ }
+ }
+ else
+ break;
+ }
+}
+
+bool cCuttingThread::ProcessSequence(int LastEndIndex, int BeginIndex, int EndIndex, int NextBeginIndex)
+{
+ // Check for seamless connections:
+ bool SeamlessBegin = LastEndIndex >= 0 && FramesAreEqual(LastEndIndex, BeginIndex);
+ bool SeamlessEnd = NextBeginIndex >= 0 && FramesAreEqual(EndIndex, NextBeginIndex);
+ // Process all frames from BeginIndex (included) to EndIndex (excluded):
+ cDanglingPacketStripper DanglingPacketStripper;
+ int NumIndependentFrames = 0;
+ int64_t FirstPts = -1;
+ int64_t LastPts = -1;
+ for (int Index = BeginIndex; Running() && Index < EndIndex; Index++) {
+ uchar Buffer[MAXFRAMESIZE];
+ bool Independent;
+ int Length;
+ if (LoadFrame(Index, Buffer, Independent, Length)) {
+ if (!isPesRecording) {
+ int64_t Pts = TsGetPts(Buffer, Length);
+ if (FirstPts < 0)
+ FirstPts = Pts; // the PTS of the first frame in the sequence
+ else if (LastPts < 0 || PtsDiff(LastPts, Pts) > 0)
+ LastPts = Pts; // the PTS of the frame that is displayed as the very last one of the sequence
+ }
+ // Fixup data at the beginning of the sequence:
+ if (!SeamlessBegin) {
+ if (isPesRecording) {
+ if (Index == BeginIndex)
+ cRemux::SetBrokenLink(Buffer, Length);
+ }
+ else if (NumIndependentFrames < 2) {
+ if (DanglingPacketStripper.Process(Buffer, Length, FirstPts))
+ NumIndependentFrames = 0; // we search until we find two consecutive I-frames without any more dangling packets
+ }
+ }
+ // Fixup data at the end of the sequence:
+ if (!SeamlessEnd) {
+ if (Index == EndIndex - 1) {
+ if (!isPesRecording)
+ GetPendingPackets(Buffer, Length, EndIndex, LastPts + int(round(PTSTICKS / framesPerSecond))); // adding one frame length to fully cover the very last frame
+ }
+ }
+ // Fixup timestamps and continuity counters:
+ if (!isPesRecording) {
+ if (numSequences > 1)
+ ptsFixer.Fix(Buffer, Length, !SeamlessBegin && Index == BeginIndex);
+ }
+ // Every file shall start with an independent frame:
+ if (Independent) {
+ NumIndependentFrames++;
+ if (!SwitchFile())
+ return false;
+ }
+ // Write index:
+ if (!toIndex->Write(Independent, toFileName->Number(), fileSize)) {
+ error = "toIndex";
+ return false;
+ }
+ // Write data:
+ if (toFile->Write(Buffer, Length) < 0) {
+ error = "safe_write";
+ return false;
+ }
+ fileSize += Length;
+ // Generate marks at the editing points in the edited recording:
+ if (numSequences > 0 && Index == BeginIndex) {
+ if (toMarks.Count() > 0)
+ toMarks.Add(toIndex->Last());
+ toMarks.Add(toIndex->Last());
+ toMarks.Save();
+ }
+ }
+ else
+ return false;
+ }
+ return true;
+}
+
void cCuttingThread::Action(void)
{
- cMark *Mark = fromMarks.First();
- if (Mark) {
+ if (cMark *BeginMark = fromMarks.GetNextBegin()) {
fromFile = fromFileName->Open();
toFile = toFileName->Open();
if (!fromFile || !toFile)
return;
- fromFile->SetReadAhead(MEGABYTE(20));
- int Index = Mark->Position();
- Mark = fromMarks.Next(Mark);
- off_t FileSize = 0;
- int CurrentFileNumber = 0;
- int LastIFrame = 0;
- toMarks.Add(0);
- toMarks.Save();
- uchar buffer[MAXFRAMESIZE], buffer2[MAXFRAMESIZE];
- int Length2;
- bool CheckForSeamlessStream = false;
- bool LastMark = false;
- bool cutIn = true;
- bool suspensionLogged = false;
- while (Running()) {
- uint16_t FileNumber;
- off_t FileOffset;
- int Length;
- bool Independent;
-
+ int LastEndIndex = -1;
+ while (BeginMark && Running()) {
// Suspend cutting if we have severe throughput problems:
-
- if (cIoThrottle::Engaged()) {
- if (!suspensionLogged) {
- dsyslog("suspending cutter thread");
- suspensionLogged = true;
- }
+ if (Throttled()) {
cCondWait::SleepMs(100);
continue;
}
- else if (suspensionLogged) {
- dsyslog("resuming cutter thread");
- suspensionLogged = false;
- }
-
// Make sure there is enough disk space:
-
AssertFreeDiskSpace(-1);
-
- // Read one frame:
-
- if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) {
- if (FileNumber != CurrentFileNumber) {
- fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
- if (fromFile)
- fromFile->SetReadAhead(MEGABYTE(20));
- CurrentFileNumber = FileNumber;
- }
- if (fromFile) {
- 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;
- }
+ // Determine the actual begin and end marks, skipping any marks at the same position:
+ cMark *EndMark = fromMarks.GetNextEnd(BeginMark);
+ // Process the current sequence:
+ int EndIndex = EndMark ? EndMark->Position() : fromIndex->Last() + 1;
+ int NextBeginIndex = -1;
+ if (EndMark) {
+ if (cMark *NextBeginMark = fromMarks.GetNextBegin(EndMark))
+ NextBeginIndex = NextBeginMark->Position();
}
- else {
- // Error, unless we're past the last cut-in and there's no cut-out
- if (Mark || LastMark)
- error = "index";
+ if (!ProcessSequence(LastEndIndex, BeginMark->Position(), EndIndex, NextBeginIndex))
break;
- }
-
- // Write one frame:
-
- if (Independent) { // every file shall start with an independent frame
- if (LastMark) // edited version shall end before next I-frame
- break;
- if (FileSize > maxVideoFileSize) {
- toFile = toFileName->NextFile();
- if (!toFile) {
- error = "toFile 1";
+ if (!EndMark)
+ break; // reached EOF
+ LastEndIndex = EndIndex;
+ // Switch to the next sequence:
+ BeginMark = fromMarks.GetNextBegin(EndMark);
+ if (BeginMark) {
+ // Split edited files:
+ if (Setup.SplitEditedFiles) {
+ if (!SwitchFile(true))
break;
- }
- FileSize = 0;
- }
- LastIFrame = 0;
- // Compare the current frame with the previously stored one, to see if this is a seamlessly merged recording of the same stream:
- if (CheckForSeamlessStream) {
- if (Length == Length2) {
- int diffs = 0;
- for (int i = 0; i < Length; i++) {
- if (buffer[i] != buffer2[i]) {
- if (diffs++ > 10)
- break;
- }
- }
- if (diffs < 10) // the continuity counters of the PAT/PMT packets may differ
- cutIn = false; // it's apparently a seamless stream, so no need for "broken" handling
- }
- CheckForSeamlessStream = false;
- }
- if (cutIn) {
- if (isPesRecording)
- cRemux::SetBrokenLink(buffer, Length);
- else
- TsSetTeiOnBrokenPackets(buffer, Length);
- cutIn = false;
}
}
- if (toFile->Write(buffer, Length) < 0) {
- error = "safe_write";
- break;
- }
- if (!toIndex->Write(Independent, 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) {
- // Read the next frame, for later comparison with the first frame at this mark:
- if (fromIndex->Get(Index, &FileNumber, &FileOffset, &Independent, &Length2)) {
- if (FileNumber != CurrentFileNumber)
- fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
- if (fromFile) {
- int len = ReadFrame(fromFile, buffer2, Length2, sizeof(buffer2));
- if (len >= 0 && len == Length2)
- CheckForSeamlessStream = true;
- }
- }
- Index = Mark->Position();
- Mark = fromMarks.Next(Mark);
- CurrentFileNumber = 0; // triggers SetOffset before reading next frame
- cutIn = true;
- if (Setup.SplitEditedFiles) {
- toFile = toFileName->NextFile();
- if (!toFile) {
- error = "toFile 2";
- break;
- }
- FileSize = 0;
- }
- }
- else
- LastMark = true;
- }
}
Recordings.TouchUpdate();
}
@@ -255,7 +575,7 @@ bool cCutter::Start(const char *FileName)
cMarks FromMarks;
FromMarks.Load(FileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
- if (cMark *First = FromMarks.First())
+ if (cMark *First = FromMarks.GetNextBegin())
Recording.SetStartTime(Recording.Start() + (int(First->Position() / Recording.FramesPerSecond() + 30) / 60) * 60);
const char *evn = Recording.PrefixFileName('%');
@@ -343,13 +663,17 @@ bool CutRecording(const char *FileName)
if (Recording.Name()) {
cMarks Marks;
if (Marks.Load(FileName, Recording.FramesPerSecond(), Recording.IsPesRecording()) && Marks.Count()) {
- if (cCutter::Start(FileName)) {
- while (cCutter::Active())
- cCondWait::SleepMs(CUTTINGCHECKINTERVAL);
- return true;
+ if (Marks.GetNumSequences()) {
+ if (cCutter::Start(FileName)) {
+ while (cCutter::Active())
+ cCondWait::SleepMs(CUTTINGCHECKINTERVAL);
+ return true;
+ }
+ else
+ fprintf(stderr, "can't start editing process\n");
}
else
- fprintf(stderr, "can't start editing process\n");
+ fprintf(stderr, "'%s' has no editing sequences\n", FileName);
}
else
fprintf(stderr, "'%s' has no editing marks\n", FileName);
diff --git a/menu.c b/menu.c
index d50be124..7837922f 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 2.62 2012/10/03 10:14:53 kls Exp $
+ * $Id: menu.c 2.63 2012/11/13 11:23:25 kls Exp $
*/
#include "menu.h"
@@ -4796,6 +4796,8 @@ void cReplayControl::EditCut(void)
if (!cCutter::Active()) {
if (!marks.Count())
Skins.Message(mtError, tr("No editing marks defined!"));
+ else if (!marks.GetNumSequences())
+ Skins.Message(mtError, tr("No editing sequences defined!"));
else if (!cCutter::Start(fileName))
Skins.Message(mtError, tr("Can't start editing process!"));
else
diff --git a/po/ar.po b/po/ar.po
index 14e8126b..c0fb31f4 100644
--- a/po/ar.po
+++ b/po/ar.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-10-16 11:16-0400\n"
"Last-Translator: Osama Alrawab <alrawab@hotmail.com>\n"
"Language-Team: Arabic <ar@li.org>\n"
@@ -1241,6 +1241,9 @@ msgstr "اقفز الى "
msgid "No editing marks defined!"
msgstr "لاتوجد علامات تعديل معرفة"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "لا يمكن البدء فى عملية التعديل"
diff --git a/po/ca_ES.po b/po/ca_ES.po
index c67265b1..f08cd57b 100644
--- a/po/ca_ES.po
+++ b/po/ca_ES.po
@@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-02 19:02+0100\n"
"Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
"Language-Team: Catalan <vdr@linuxtv.org>\n"
@@ -1216,6 +1216,9 @@ msgstr "Salta a:"
msgid "No editing marks defined!"
msgstr "No hi ha marques d'edici definides"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "No puc iniciar el procs d'edici!"
diff --git a/po/cs_CZ.po b/po/cs_CZ.po
index 55053f95..1a621026 100644
--- a/po/cs_CZ.po
+++ b/po/cs_CZ.po
@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.14\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-05-06 11:00+0200\n"
"Last-Translator: Radek Šťastný <dedkus@gmail.com>\n"
"Language-Team: Czech <vdr@linuxtv.org>\n"
@@ -1215,6 +1215,9 @@ msgstr "Skok: "
msgid "No editing marks defined!"
msgstr "Nejsou definovány editační značky!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Nelze začít editační proces!"
diff --git a/po/da_DK.po b/po/da_DK.po
index fac58003..597539ff 100644
--- a/po/da_DK.po
+++ b/po/da_DK.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
"Last-Translator: Mogens Elneff <mogens@elneff.dk>\n"
"Language-Team: Danish <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Hop: "
msgid "No editing marks defined!"
msgstr "Der er ikke sat nogen redigeringsmrker!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kan ikke starte redigeringsprocessen!"
diff --git a/po/de_DE.po b/po/de_DE.po
index a321b501..c958758c 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-01-16 16:46+0100\n"
"Last-Translator: Klaus Schmidinger <kls@tvdr.de>\n"
"Language-Team: German <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Springen: "
msgid "No editing marks defined!"
msgstr "Keine Schnittmarken gesetzt!"
+msgid "No editing sequences defined!"
+msgstr "Keine Schnittsequenzen definiert!"
+
msgid "Can't start editing process!"
msgstr "Schnitt kann nicht gestartet werden!"
diff --git a/po/el_GR.po b/po/el_GR.po
index 8936408c..1347812d 100644
--- a/po/el_GR.po
+++ b/po/el_GR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
"Last-Translator: Dimitrios Dimitrakos <mail@dimitrios.de>\n"
"Language-Team: Greek <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr ": "
msgid "No editing marks defined!"
msgstr " "
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr " !"
diff --git a/po/es_ES.po b/po/es_ES.po
index bc80a117..8e76063d 100644
--- a/po/es_ES.po
+++ b/po/es_ES.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-02 19:02+0100\n"
"Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
"Language-Team: Spanish <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Saltar: "
msgid "No editing marks defined!"
msgstr "No se definieron marcas de edicin!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "No se puede iniciar el proceso de edicin!"
diff --git a/po/et_EE.po b/po/et_EE.po
index 0dea9992..12c1f259 100644
--- a/po/et_EE.po
+++ b/po/et_EE.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
"Last-Translator: Arthur Konovalov <artlov@gmail.com>\n"
"Language-Team: Estonian <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Hüpe: "
msgid "No editing marks defined!"
msgstr "Redigeerimise markerid puuduvad!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Redigeerimise start nurjus!"
diff --git a/po/fi_FI.po b/po/fi_FI.po
index daad22ae..901328ae 100644
--- a/po/fi_FI.po
+++ b/po/fi_FI.po
@@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-13 13:15+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-15 15:52+0200\n"
"Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
@@ -1216,6 +1216,9 @@ msgstr "Siirry: "
msgid "No editing marks defined!"
msgstr "Muokkausmerkinnät puuttuvat!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Muokkauksen aloitus epäonnistui!"
diff --git a/po/fr_FR.po b/po/fr_FR.po
index 3ca3c06f..a0995aeb 100644
--- a/po/fr_FR.po
+++ b/po/fr_FR.po
@@ -13,7 +13,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-02-27 18:14+0100\n"
"Last-Translator: Jean-Claude Repetto <jc@repetto.org>\n"
"Language-Team: French <vdr@linuxtv.org>\n"
@@ -1219,6 +1219,9 @@ msgstr "Accs direct : "
msgid "No editing marks defined!"
msgstr "Pas de marques d'dition dfinies !"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Impossible de commencer le montage !"
diff --git a/po/hr_HR.po b/po/hr_HR.po
index dcb1a217..44cfd09f 100644
--- a/po/hr_HR.po
+++ b/po/hr_HR.po
@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-17 19:00+0100\n"
"Last-Translator: Adrian Caval <anrxc@sysphere.org>\n"
"Language-Team: Croatian <vdr@linuxtv.org>\n"
@@ -1215,6 +1215,9 @@ msgstr "Skoi: "
msgid "No editing marks defined!"
msgstr "Nijedna toka rezanja nije odreena!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Ne mogu zapoeti ureivanje!"
diff --git a/po/hu_HU.po b/po/hu_HU.po
index c391b67e..30ab8ab6 100644
--- a/po/hu_HU.po
+++ b/po/hu_HU.po
@@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2012-01-02 11:54+0200\n"
"Last-Translator: Istvn Fley <ifuley@tigercomp.ro>\n"
"Language-Team: Hungarian <vdr@linuxtv.org>\n"
@@ -1217,6 +1217,9 @@ msgstr "Ugrs ide: "
msgid "No editing marks defined!"
msgstr "Nincs vgpont kijellve"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "A vgs nem indthat!"
diff --git a/po/it_IT.po b/po/it_IT.po
index b63d93d8..1258f23f 100644
--- a/po/it_IT.po
+++ b/po/it_IT.po
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2012-06-06 22:50+0100\n"
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
"Language-Team: Italian <vdr@linuxtv.org>\n"
@@ -1220,6 +1220,9 @@ msgstr "Vai a: "
msgid "No editing marks defined!"
msgstr "Nessun marcatore di modifica definito!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Impossibile avviare il processo di modifica!"
diff --git a/po/lt_LT.po b/po/lt_LT.po
index 95f8e831..b53c7627 100644
--- a/po/lt_LT.po
+++ b/po/lt_LT.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.16\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-10-30 11:55+0200\n"
"Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
"Language-Team: Lithuanian <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Peršokti: "
msgid "No editing marks defined!"
msgstr "Nenustatytos koregavimo žymės!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Negali pradėti koregavimo!"
diff --git a/po/mk_MK.po b/po/mk_MK.po
index fd16ec88..89e8b739 100644
--- a/po/mk_MK.po
+++ b/po/mk_MK.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR-1.7.14\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-03-11 00:54+0100\n"
"Last-Translator: Dimitar Petrovski <dimeptr@gmail.com>\n"
"Language-Team: Macedonian <en@li.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Скокни:"
msgid "No editing marks defined!"
msgstr "Нема одредено ознаки за сечење!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Не може да почне уредување!"
diff --git a/po/nl_NL.po b/po/nl_NL.po
index 6c3825d9..5e515c36 100644
--- a/po/nl_NL.po
+++ b/po/nl_NL.po
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-02-26 17:20+0100\n"
"Last-Translator: Johan Schuring <johan.schuring@vetteblei.nl>\n"
"Language-Team: Dutch <vdr@linuxtv.org>\n"
@@ -1217,6 +1217,9 @@ msgstr "Springen: "
msgid "No editing marks defined!"
msgstr "Geen bewerkingsmarkeringen gedefinieerd!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kan niet beginnen met bewerken!"
diff --git a/po/nn_NO.po b/po/nn_NO.po
index 41ce5c30..f3662605 100644
--- a/po/nn_NO.po
+++ b/po/nn_NO.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
"Last-Translator: Truls Slevigen <truls@slevigen.no>\n"
"Language-Team: Norwegian Nynorsk <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Hopp: "
msgid "No editing marks defined!"
msgstr ""
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kan ikke starte redigeringsprosessen!"
diff --git a/po/pl_PL.po b/po/pl_PL.po
index f4c18761..fbe8a860 100644
--- a/po/pl_PL.po
+++ b/po/pl_PL.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-09 12:59+0100\n"
"Last-Translator: Michael Rakowski <mrak@gmx.de>\n"
"Language-Team: Polish <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Skok: "
msgid "No editing marks defined!"
msgstr "Nie zdefiniowano znacznikw montau!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Nie mona uruchomi procesu edycji!"
diff --git a/po/pt_PT.po b/po/pt_PT.po
index 5cfc2037..d69e0690 100644
--- a/po/pt_PT.po
+++ b/po/pt_PT.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.15\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-03-28 22:49+0100\n"
"Last-Translator: Cris Silva <hudokkow@gmail.com>\n"
"Language-Team: Portuguese <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Saltar: "
msgid "No editing marks defined!"
msgstr "Marcas de edio no foram definidas!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Impossvel iniciar processo de edio!"
diff --git a/po/ro_RO.po b/po/ro_RO.po
index 7db9a15a..03ae8f02 100644
--- a/po/ro_RO.po
+++ b/po/ro_RO.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.12\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2012-11-05 01:28+0100\n"
"Last-Translator: Lucian Muresan <lucianm@users.sourceforge.net>\n"
"Language-Team: Romanian <vdr@linuxtv.org>\n"
@@ -1216,6 +1216,9 @@ msgstr "Salt la: "
msgid "No editing marks defined!"
msgstr "Nu s-au pus marcaje de montaj pentru această înregistrare"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Nu pot porni montajul înregistrării!"
diff --git a/po/ru_RU.po b/po/ru_RU.po
index d8e1e8e1..b58fd9a1 100644
--- a/po/ru_RU.po
+++ b/po/ru_RU.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-12-15 14:37+0100\n"
"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
"Language-Team: Russian <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr ": "
msgid "No editing marks defined!"
msgstr " !"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr " !"
diff --git a/po/sk_SK.po b/po/sk_SK.po
index 0de2d061..ab5035e8 100644
--- a/po/sk_SK.po
+++ b/po/sk_SK.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.16\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2011-02-15 16:29+0100\n"
"Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
"Language-Team: Slovak <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Skok: "
msgid "No editing marks defined!"
msgstr "Nie s uren znaky prav!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Neme zaa spracovanie prav!"
diff --git a/po/sl_SI.po b/po/sl_SI.po
index 95568682..9326d858 100644
--- a/po/sl_SI.po
+++ b/po/sl_SI.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-02-28 19:44+0100\n"
"Last-Translator: Matjaz Thaler <matjaz.thaler@guest.arnes.si>\n"
"Language-Team: Slovenian <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Skoi: "
msgid "No editing marks defined!"
msgstr "Nobena prekinitvena toka ni definirana!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Ne morem zaeti urejanja!"
diff --git a/po/sr_SR.po b/po/sr_SR.po
index c4149dda..c7b97d57 100644
--- a/po/sr_SR.po
+++ b/po/sr_SR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.1\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2011-01-09 15:57+0100\n"
"Last-Translator: Milan Cvijanovi <elcom_cvijo@hotmail.com>\n"
"Language-Team: Serbian <vdr@linuxtv.org>\n"
@@ -1239,6 +1239,9 @@ msgstr "Skoi: "
msgid "No editing marks defined!"
msgstr "Nijedna taka rezanja nije odreena!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Ne mogu zapoeti ureivanje!"
diff --git a/po/sv_SE.po b/po/sv_SE.po
index 951dd044..dc4d6208 100644
--- a/po/sv_SE.po
+++ b/po/sv_SE.po
@@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-12 18:25+0100\n"
"Last-Translator: Magnus Andersson <svankan@bahnhof.se>\n"
"Language-Team: Swedish <vdr@linuxtv.org>\n"
@@ -1216,6 +1216,9 @@ msgstr "Hopp: "
msgid "No editing marks defined!"
msgstr "Det finns inga redigeringsmrken"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kan inte starta redigering!"
diff --git a/po/tr_TR.po b/po/tr_TR.po
index 8b161b3f..1f619441 100644
--- a/po/tr_TR.po
+++ b/po/tr_TR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-02-28 00:33+0100\n"
"Last-Translator: Oktay Yolgeen <oktay_73@yahoo.de>\n"
"Language-Team: Turkish <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Atla: "
msgid "No editing marks defined!"
msgstr "Kesim iaretleri belirtilmemi!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kesim balatlamyor!"
diff --git a/po/uk_UA.po b/po/uk_UA.po
index 45e57ee5..72fe84c5 100644
--- a/po/uk_UA.po
+++ b/po/uk_UA.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.7\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-04-25 16:35+0200\n"
"Last-Translator: Yarema aka Knedlyk <yupadmin@gmail.com>\n"
"Language-Team: Ukrainian <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Перейти: "
msgid "No editing marks defined!"
msgstr "Не задано міток для монтажу!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Неможливо почати монтаж запису!"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 4e2b951f..56b2de0d 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2009-09-23 23:50+0800\n"
"Last-Translator: Nan Feng <nfgx@21cn.com>\n"
"Language-Team: Chinese (simplified) <vdr@linuxtv.org>\n"
@@ -1216,6 +1216,9 @@ msgstr "跳过: "
msgid "No editing marks defined!"
msgstr "无编辑标记定义!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "不能开始编辑处理"
diff --git a/recording.c b/recording.c
index 79db1c74..497bf2dd 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 2.72 2012/11/12 14:51:09 kls Exp $
+ * $Id: recording.c 2.73 2012/11/13 13:46:49 kls Exp $
*/
#include "recording.h"
@@ -1456,6 +1456,54 @@ cMark *cMarks::GetNext(int Position)
return NULL;
}
+cMark *cMarks::GetNextBegin(cMark *EndMark)
+{
+ cMark *BeginMark = EndMark ? Next(EndMark) : First();
+ if (BeginMark) {
+ while (cMark *NextMark = Next(BeginMark)) {
+ if (BeginMark->Position() == NextMark->Position()) { // skip Begin/End at the same position
+ if (!(BeginMark = Next(NextMark)))
+ break;
+ }
+ else
+ break;
+ }
+ }
+ return BeginMark;
+}
+
+cMark *cMarks::GetNextEnd(cMark *BeginMark)
+{
+ if (!BeginMark)
+ return NULL;
+ cMark *EndMark = Next(BeginMark);
+ if (EndMark) {
+ while (cMark *NextMark = Next(EndMark)) {
+ if (EndMark->Position() == NextMark->Position()) { // skip End/Begin at the same position
+ if (!(EndMark = Next(NextMark)))
+ break;
+ }
+ else
+ break;
+ }
+ }
+ return EndMark;
+}
+
+int cMarks::GetNumSequences(void)
+{
+ int NumSequences = 0;
+ if (cMark *BeginMark = GetNextBegin()) {
+ while (cMark *EndMark = GetNextEnd(BeginMark)) {
+ NumSequences++;
+ BeginMark = GetNextBegin(EndMark);
+ }
+ if (NumSequences == 0 && BeginMark->Position() > 0)
+ NumSequences = 1; // there is only one actual "begin" mark at a non-zero offset, and no actual "end" mark
+ }
+ return NumSequences;
+}
+
// --- cRecordingUserCommand -------------------------------------------------
const char *cRecordingUserCommand::command = NULL;
diff --git a/recording.h b/recording.h
index 7118e783..9ae9b1ec 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 2.39 2012/11/12 14:51:09 kls Exp $
+ * $Id: recording.h 2.40 2012/11/13 11:43:59 kls Exp $
*/
#ifndef __RECORDING_H
@@ -238,6 +238,19 @@ public:
cMark *Get(int Position);
cMark *GetPrev(int Position);
cMark *GetNext(int Position);
+ cMark *GetNextBegin(cMark *EndMark = NULL);
+ ///< Returns the next "begin" mark after EndMark, skipping any marks at the
+ ///< same position as EndMark. If EndMark is NULL, the first actual "begin"
+ ///< will be returned (if any).
+ cMark *GetNextEnd(cMark *BeginMark);
+ ///< Returns the next "end" mark after BeginMark, skipping any marks at the
+ ///< same position as BeginMark.
+ int GetNumSequences(void);
+ ///< Returns the actual number of sequences to be cut from the recording.
+ ///< If there is only one actual "begin" mark, and it is positioned at index
+ ///< 0 (the beginning of the recording), and there is no "end" mark, the
+ ///< return value is 0, which means that the result is the same as the original
+ ///< recording.
};
#define RUC_BEFORERECORDING "before"
diff --git a/remux.c b/remux.c
index bc7cd0de..e3b34c66 100644
--- a/remux.c
+++ b/remux.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remux.c 2.70 2012/11/13 10:00:00 kls Exp $
+ * $Id: remux.c 2.71 2012/11/18 12:18:08 kls Exp $
*/
#include "remux.h"
@@ -114,6 +114,32 @@ void cRemux::SetBrokenLink(uchar *Data, int Length)
// --- Some TS handling tools ------------------------------------------------
+void TsHidePayload(uchar *p)
+{
+ p[1] &= ~TS_PAYLOAD_START;
+ p[3] |= TS_ADAPT_FIELD_EXISTS;
+ p[3] &= ~TS_PAYLOAD_EXISTS;
+ p[4] = TS_SIZE - 5;
+ p[5] = 0x00;
+ memset(p + 6, 0xFF, TS_SIZE - 6);
+}
+
+void TsSetPcr(uchar *p, int64_t Pcr)
+{
+ if (TsHasAdaptationField(p)) {
+ if (p[4] >= 7 && (p[5] & TS_ADAPT_PCR)) {
+ int64_t b = Pcr / PCRFACTOR;
+ int e = Pcr % PCRFACTOR;
+ p[ 6] = b >> 25;
+ p[ 7] = b >> 17;
+ p[ 8] = b >> 9;
+ p[ 9] = b >> 1;
+ p[10] = (b << 7) | (p[10] & 0x7E) | ((e >> 8) & 0x01);
+ p[11] = e;
+ }
+ }
+}
+
int64_t TsGetPts(const uchar *p, int l)
{
// Find the first packet with a PTS and use it:
@@ -127,27 +153,77 @@ int64_t TsGetPts(const uchar *p, int l)
return -1;
}
-void TsSetTeiOnBrokenPackets(uchar *p, int l)
+int64_t TsGetDts(const uchar *p, int l)
{
- bool Processed[MAXPID] = { false };
- while (l >= TS_SIZE) {
- if (*p != TS_SYNC_BYTE)
- break;
- int Pid = TsPid(p);
- if (!Processed[Pid]) {
- if (!TsPayloadStart(p))
- p[1] |= TS_ERROR;
- else {
- Processed[Pid] = true;
- int offs = TsPayloadOffset(p);
- cRemux::SetBrokenLink(p + offs, TS_SIZE - offs);
- }
+ // Find the first packet with a DTS and use it:
+ while (l > 0) {
+ const uchar *d = p;
+ if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d))
+ return PesGetDts(d);
+ p += TS_SIZE;
+ l -= TS_SIZE;
+ }
+ return -1;
+}
+
+void TsSetPts(uchar *p, int l, int64_t Pts)
+{
+ // Find the first packet with a PTS and use it:
+ while (l > 0) {
+ const uchar *d = p;
+ if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d)) {
+ PesSetPts(const_cast<uchar *>(d), Pts);
+ return;
}
+ p += TS_SIZE;
l -= TS_SIZE;
+ }
+}
+
+void TsSetDts(uchar *p, int l, int64_t Dts)
+{
+ // Find the first packet with a DTS and use it:
+ while (l > 0) {
+ const uchar *d = p;
+ if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d)) {
+ PesSetDts(const_cast<uchar *>(d), Dts);
+ return;
+ }
p += TS_SIZE;
+ l -= TS_SIZE;
}
}
+// --- Some PES handling tools -----------------------------------------------
+
+void PesSetPts(uchar *p, int64_t Pts)
+{
+ p[ 9] = ((Pts >> 29) & 0x0E) | (p[9] & 0xF1);
+ p[10] = Pts >> 22;
+ p[11] = ((Pts >> 14) & 0xFE) | 0x01;
+ p[12] = Pts >> 7;
+ p[13] = ((Pts << 1) & 0xFE) | 0x01;
+}
+
+void PesSetDts(uchar *p, int64_t Dts)
+{
+ p[14] = ((Dts >> 29) & 0x0E) | (p[14] & 0xF1);
+ p[15] = Dts >> 22;
+ p[16] = ((Dts >> 14) & 0xFE) | 0x01;
+ p[17] = Dts >> 7;
+ p[18] = ((Dts << 1) & 0xFE) | 0x01;
+}
+
+int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
+{
+ int64_t d = Pts2 - Pts1;
+ if (d > MAX33BIT / 2)
+ return d - (MAX33BIT + 1);
+ if (d < -MAX33BIT / 2)
+ return d + (MAX33BIT + 1);
+ return d;
+}
+
// --- cTsPayload ------------------------------------------------------------
cTsPayload::cTsPayload(void)
@@ -1395,7 +1471,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
}
}
else // audio
- framesPerSecond = 90000.0 / Delta; // PTS of audio frames is always increasing
+ framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1);
synced = true;
parser->SetDebug(false);
diff --git a/remux.h b/remux.h
index 9b156a69..dd17e0d9 100644
--- a/remux.h
+++ b/remux.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remux.h 2.34 2012/11/06 11:03:06 kls Exp $
+ * $Id: remux.h 2.35 2012/11/18 12:17:23 kls Exp $
*/
#ifndef __REMUX_H
@@ -52,6 +52,11 @@ public:
#define PATPID 0x0000 // PAT PID (constant 0)
#define MAXPID 0x2000 // for arrays that use a PID as the index
+#define PTSTICKS 90000 // number of PTS ticks per second
+#define PCRFACTOR 300 // conversion from 27MHz PCR extension to 90kHz PCR base
+#define MAX33BIT 0x00000001FFFFFFFFLL // max. possible value with 33 bit
+#define MAX27MHZ ((MAX33BIT + 1) * PCRFACTOR - 1) // max. possible PCR value
+
inline bool TsHasPayload(const uchar *p)
{
return p[3] & TS_PAYLOAD_EXISTS;
@@ -82,6 +87,16 @@ inline bool TsIsScrambled(const uchar *p)
return p[3] & TS_SCRAMBLING_CONTROL;
}
+inline uchar TsGetContinuityCounter(const uchar *p)
+{
+ return p[3] & TS_CONT_CNT_MASK;
+}
+
+inline void TsSetContinuityCounter(uchar *p, uchar Counter)
+{
+ p[3] = (p[3] & ~TS_CONT_CNT_MASK) | (Counter & TS_CONT_CNT_MASK);
+}
+
inline int TsPayloadOffset(const uchar *p)
{
int o = TsHasAdaptationField(p) ? p[4] + 5 : 4;
@@ -103,15 +118,31 @@ inline int TsContinuityCounter(const uchar *p)
return p[3] & TS_CONT_CNT_MASK;
}
-inline int TsGetAdaptationField(const uchar *p)
+inline int64_t TsGetPcr(const uchar *p)
{
- return TsHasAdaptationField(p) ? p[5] : 0x00;
+ if (TsHasAdaptationField(p)) {
+ if (p[4] >= 7 && (p[5] & TS_ADAPT_PCR)) {
+ return ((((int64_t)p[ 6]) << 25) |
+ (((int64_t)p[ 7]) << 17) |
+ (((int64_t)p[ 8]) << 9) |
+ (((int64_t)p[ 9]) << 1) |
+ (((int64_t)p[10]) >> 7)) * PCRFACTOR +
+ (((((int)p[10]) & 0x01) << 8) |
+ ( ((int)p[11])));
+ }
+ }
+ return -1;
}
+void TsHidePayload(uchar *p);
+void TsSetPcr(uchar *p, int64_t Pcr);
+
// The following functions all take a pointer to a sequence of complete TS packets.
int64_t TsGetPts(const uchar *p, int l);
-void TsSetTeiOnBrokenPackets(uchar *p, int l);
+int64_t TsGetDts(const uchar *p, int l);
+void TsSetPts(uchar *p, int l, int64_t Pts);
+void TsSetDts(uchar *p, int l, int64_t Dts);
// Some PES handling tools:
// The following functions that take a pointer to PES data all assume that
@@ -142,6 +173,11 @@ inline bool PesHasPts(const uchar *p)
return (p[7] & 0x80) && p[8] >= 5;
}
+inline bool PesHasDts(const uchar *p)
+{
+ return (p[7] & 0x40) && p[8] >= 10;
+}
+
inline int64_t PesGetPts(const uchar *p)
{
return ((((int64_t)p[ 9]) & 0x0E) << 29) |
@@ -151,6 +187,28 @@ inline int64_t PesGetPts(const uchar *p)
((((int64_t)p[13]) & 0xFE) >> 1);
}
+inline int64_t PesGetDts(const uchar *p)
+{
+ return ((((int64_t)p[14]) & 0x0E) << 29) |
+ (( (int64_t)p[15]) << 22) |
+ ((((int64_t)p[16]) & 0xFE) << 14) |
+ (( (int64_t)p[17]) << 7) |
+ ((((int64_t)p[18]) & 0xFE) >> 1);
+}
+
+void PesSetPts(uchar *p, int64_t Pts);
+void PesSetDts(uchar *p, int64_t Dts);
+
+// PTS handling:
+
+inline int64_t PtsAdd(int64_t Pts1, int64_t Pts2) { return (Pts1 + Pts2) & MAX33BIT; }
+ ///< Adds the given PTS values, taking into account the 33bit wrap around.
+int64_t PtsDiff(int64_t Pts1, int64_t Pts2);
+ ///< Returns the difference between two PTS values. The result of Pts2 - Pts1
+ ///< is the actual number of 90kHz time ticks that pass from Pts1 to Pts2,
+ ///< properly taking into account the 33bit wrap around. If Pts2 is "before"
+ ///< Pts1, the result is negative.
+
// A transprent TS payload handler:
class cTsPayload {