mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Improved editing TS recordings
This commit is contained in:
parent
5b4e1fa793
commit
cca2cd35ad
17
HISTORY
17
HISTORY
@ -7272,7 +7272,7 @@ Video Disk Recorder Revision History
|
|||||||
".keep" to prevent a directory from being deleted when it is empty. Currently the
|
".keep" to prevent a directory from being deleted when it is empty. Currently the
|
||||||
only file name that is ignored is ".sort".
|
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
|
- 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).
|
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
|
- 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
|
of the list of marks the returned pointer might have pointed to a totally different
|
||||||
mark. Besides, the return value was never actually used.
|
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
|
||||||
|
20
MANUAL
20
MANUAL
@ -367,13 +367,13 @@ Version 1.6
|
|||||||
- 7, 9 Jump back and forward between editing marks. Replay goes into still
|
- 7, 9 Jump back and forward between editing marks. Replay goes into still
|
||||||
mode after jumping to a mark.
|
mode after jumping to a mark.
|
||||||
- 8 Positions replay at a point 3 seconds before the current or next
|
- 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.
|
- 2 Start the actual cutting process.
|
||||||
|
|
||||||
Editing marks are represented by black, vertical lines in the progress display.
|
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.
|
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
|
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
|
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
|
(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
|
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.
|
"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
|
6,...) is an "end" mark. Inserting or toggling a mark on or off automatically
|
||||||
adjusts the sequence to the right side of that mark.
|
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
|
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.
|
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
|
Currently editing marks can only be set at I-frames, which typically appear
|
||||||
every 12th frame. So editing can be done with a resolution of roughly half
|
every half of a second to a second. A "begin" mark marks the first frame of
|
||||||
a second. A "start" mark marks the first frame of a resulting video
|
a resulting video sequence, and an "end" mark marks the last frame of that
|
||||||
sequence, and an "end" mark marks the last frame of that sequence.
|
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
|
An edited recording (indicated by the '%' character) will never be deleted
|
||||||
automatically in case the disk runs full (no matter what "lifetime" it has).
|
automatically in case the disk runs full (no matter what "lifetime" it has).
|
||||||
|
|
||||||
|
654
cutter.c
654
cutter.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "cutter.h"
|
||||||
@ -13,17 +13,261 @@
|
|||||||
#include "remux.h"
|
#include "remux.h"
|
||||||
#include "videodir.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 --------------------------------------------------------
|
// --- cCuttingThread --------------------------------------------------------
|
||||||
|
|
||||||
class cCuttingThread : public cThread {
|
class cCuttingThread : public cThread {
|
||||||
private:
|
private:
|
||||||
const char *error;
|
const char *error;
|
||||||
bool isPesRecording;
|
bool isPesRecording;
|
||||||
|
double framesPerSecond;
|
||||||
cUnbufferedFile *fromFile, *toFile;
|
cUnbufferedFile *fromFile, *toFile;
|
||||||
cFileName *fromFileName, *toFileName;
|
cFileName *fromFileName, *toFileName;
|
||||||
cIndexFile *fromIndex, *toIndex;
|
cIndexFile *fromIndex, *toIndex;
|
||||||
cMarks fromMarks, toMarks;
|
cMarks fromMarks, toMarks;
|
||||||
|
int numSequences;
|
||||||
off_t maxVideoFileSize;
|
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:
|
protected:
|
||||||
virtual void Action(void);
|
virtual void Action(void);
|
||||||
public:
|
public:
|
||||||
@ -41,16 +285,25 @@ cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName)
|
|||||||
fromIndex = toIndex = NULL;
|
fromIndex = toIndex = NULL;
|
||||||
cRecording Recording(FromFileName);
|
cRecording Recording(FromFileName);
|
||||||
isPesRecording = Recording.IsPesRecording();
|
isPesRecording = Recording.IsPesRecording();
|
||||||
if (fromMarks.Load(FromFileName, Recording.FramesPerSecond(), isPesRecording) && fromMarks.Count()) {
|
framesPerSecond = Recording.FramesPerSecond();
|
||||||
fromFileName = new cFileName(FromFileName, false, true, isPesRecording);
|
suspensionLogged = false;
|
||||||
toFileName = new cFileName(ToFileName, true, true, isPesRecording);
|
fileSize = 0;
|
||||||
fromIndex = new cIndexFile(FromFileName, false, isPesRecording);
|
ptsFixer.Setup(framesPerSecond);
|
||||||
toIndex = new cIndexFile(ToFileName, true, isPesRecording);
|
if (fromMarks.Load(FromFileName, framesPerSecond, isPesRecording) && fromMarks.Count()) {
|
||||||
toMarks.Load(ToFileName, Recording.FramesPerSecond(), isPesRecording); // doesn't actually load marks, just sets the file name
|
numSequences = fromMarks.GetNumSequences();
|
||||||
maxVideoFileSize = MEGABYTE(Setup.MaxVideoFileSize);
|
if (numSequences > 0) {
|
||||||
if (isPesRecording && maxVideoFileSize > MEGABYTE(MAXVIDEOFILESIZEPES))
|
fromFileName = new cFileName(FromFileName, false, true, isPesRecording);
|
||||||
maxVideoFileSize = MEGABYTE(MAXVIDEOFILESIZEPES);
|
toFileName = new cFileName(ToFileName, true, true, isPesRecording);
|
||||||
Start();
|
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
|
else
|
||||||
esyslog("no editing marks found for %s", FromFileName);
|
esyslog("no editing marks found for %s", FromFileName);
|
||||||
@ -65,168 +318,235 @@ cCuttingThread::~cCuttingThread()
|
|||||||
delete toIndex;
|
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)
|
void cCuttingThread::Action(void)
|
||||||
{
|
{
|
||||||
cMark *Mark = fromMarks.First();
|
if (cMark *BeginMark = fromMarks.GetNextBegin()) {
|
||||||
if (Mark) {
|
|
||||||
fromFile = fromFileName->Open();
|
fromFile = fromFileName->Open();
|
||||||
toFile = toFileName->Open();
|
toFile = toFileName->Open();
|
||||||
if (!fromFile || !toFile)
|
if (!fromFile || !toFile)
|
||||||
return;
|
return;
|
||||||
fromFile->SetReadAhead(MEGABYTE(20));
|
int LastEndIndex = -1;
|
||||||
int Index = Mark->Position();
|
while (BeginMark && Running()) {
|
||||||
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;
|
|
||||||
|
|
||||||
// Suspend cutting if we have severe throughput problems:
|
// Suspend cutting if we have severe throughput problems:
|
||||||
|
if (Throttled()) {
|
||||||
if (cIoThrottle::Engaged()) {
|
|
||||||
if (!suspensionLogged) {
|
|
||||||
dsyslog("suspending cutter thread");
|
|
||||||
suspensionLogged = true;
|
|
||||||
}
|
|
||||||
cCondWait::SleepMs(100);
|
cCondWait::SleepMs(100);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (suspensionLogged) {
|
|
||||||
dsyslog("resuming cutter thread");
|
|
||||||
suspensionLogged = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure there is enough disk space:
|
// Make sure there is enough disk space:
|
||||||
|
|
||||||
AssertFreeDiskSpace(-1);
|
AssertFreeDiskSpace(-1);
|
||||||
|
// Determine the actual begin and end marks, skipping any marks at the same position:
|
||||||
// Read one frame:
|
cMark *EndMark = fromMarks.GetNextEnd(BeginMark);
|
||||||
|
// Process the current sequence:
|
||||||
if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) {
|
int EndIndex = EndMark ? EndMark->Position() : fromIndex->Last() + 1;
|
||||||
if (FileNumber != CurrentFileNumber) {
|
int NextBeginIndex = -1;
|
||||||
fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
|
if (EndMark) {
|
||||||
if (fromFile)
|
if (cMark *NextBeginMark = fromMarks.GetNextBegin(EndMark))
|
||||||
fromFile->SetReadAhead(MEGABYTE(20));
|
NextBeginIndex = NextBeginMark->Position();
|
||||||
CurrentFileNumber = FileNumber;
|
}
|
||||||
}
|
if (!ProcessSequence(LastEndIndex, BeginMark->Position(), EndIndex, NextBeginIndex))
|
||||||
if (fromFile) {
|
break;
|
||||||
int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer));
|
if (!EndMark)
|
||||||
if (len < 0) {
|
break; // reached EOF
|
||||||
error = "ReadFrame";
|
LastEndIndex = EndIndex;
|
||||||
|
// Switch to the next sequence:
|
||||||
|
BeginMark = fromMarks.GetNextBegin(EndMark);
|
||||||
|
if (BeginMark) {
|
||||||
|
// Split edited files:
|
||||||
|
if (Setup.SplitEditedFiles) {
|
||||||
|
if (!SwitchFile(true))
|
||||||
break;
|
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 {
|
|
||||||
// Error, unless we're past the last cut-in and there's no cut-out
|
|
||||||
if (Mark || LastMark)
|
|
||||||
error = "index";
|
|
||||||
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";
|
|
||||||
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();
|
Recordings.TouchUpdate();
|
||||||
@ -255,7 +575,7 @@ bool cCutter::Start(const char *FileName)
|
|||||||
|
|
||||||
cMarks FromMarks;
|
cMarks FromMarks;
|
||||||
FromMarks.Load(FileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
|
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);
|
Recording.SetStartTime(Recording.Start() + (int(First->Position() / Recording.FramesPerSecond() + 30) / 60) * 60);
|
||||||
|
|
||||||
const char *evn = Recording.PrefixFileName('%');
|
const char *evn = Recording.PrefixFileName('%');
|
||||||
@ -343,13 +663,17 @@ bool CutRecording(const char *FileName)
|
|||||||
if (Recording.Name()) {
|
if (Recording.Name()) {
|
||||||
cMarks Marks;
|
cMarks Marks;
|
||||||
if (Marks.Load(FileName, Recording.FramesPerSecond(), Recording.IsPesRecording()) && Marks.Count()) {
|
if (Marks.Load(FileName, Recording.FramesPerSecond(), Recording.IsPesRecording()) && Marks.Count()) {
|
||||||
if (cCutter::Start(FileName)) {
|
if (Marks.GetNumSequences()) {
|
||||||
while (cCutter::Active())
|
if (cCutter::Start(FileName)) {
|
||||||
cCondWait::SleepMs(CUTTINGCHECKINTERVAL);
|
while (cCutter::Active())
|
||||||
return true;
|
cCondWait::SleepMs(CUTTINGCHECKINTERVAL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "can't start editing process\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fprintf(stderr, "can't start editing process\n");
|
fprintf(stderr, "'%s' has no editing sequences\n", FileName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fprintf(stderr, "'%s' has no editing marks\n", FileName);
|
fprintf(stderr, "'%s' has no editing marks\n", FileName);
|
||||||
|
4
menu.c
4
menu.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "menu.h"
|
||||||
@ -4796,6 +4796,8 @@ void cReplayControl::EditCut(void)
|
|||||||
if (!cCutter::Active()) {
|
if (!cCutter::Active()) {
|
||||||
if (!marks.Count())
|
if (!marks.Count())
|
||||||
Skins.Message(mtError, tr("No editing marks defined!"));
|
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))
|
else if (!cCutter::Start(fileName))
|
||||||
Skins.Message(mtError, tr("Can't start editing process!"));
|
Skins.Message(mtError, tr("Can't start editing process!"));
|
||||||
else
|
else
|
||||||
|
5
po/ar.po
5
po/ar.po
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.7.0\n"
|
"Project-Id-Version: VDR 1.7.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-10-16 11:16-0400\n"
|
||||||
"Last-Translator: Osama Alrawab <alrawab@hotmail.com>\n"
|
"Last-Translator: Osama Alrawab <alrawab@hotmail.com>\n"
|
||||||
"Language-Team: Arabic <ar@li.org>\n"
|
"Language-Team: Arabic <ar@li.org>\n"
|
||||||
@ -1241,6 +1241,9 @@ msgstr "اقفز الى "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "لاتوجد علامات تعديل معرفة"
|
msgstr "لاتوجد علامات تعديل معرفة"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "لا يمكن البدء فى عملية التعديل"
|
msgstr "لا يمكن البدء فى عملية التعديل"
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-03-02 19:02+0100\n"
|
||||||
"Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
|
"Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
|
||||||
"Language-Team: Catalan <vdr@linuxtv.org>\n"
|
"Language-Team: Catalan <vdr@linuxtv.org>\n"
|
||||||
@ -1216,6 +1216,9 @@ msgstr "Salta a:"
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "No hi ha marques d'edició definides"
|
msgstr "No hi ha marques d'edició definides"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "No puc iniciar el procés d'edició!"
|
msgstr "No puc iniciar el procés d'edició!"
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.7.14\n"
|
"Project-Id-Version: VDR 1.7.14\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2010-05-06 11:00+0200\n"
|
||||||
"Last-Translator: Radek Šťastný <dedkus@gmail.com>\n"
|
"Last-Translator: Radek Šťastný <dedkus@gmail.com>\n"
|
||||||
"Language-Team: Czech <vdr@linuxtv.org>\n"
|
"Language-Team: Czech <vdr@linuxtv.org>\n"
|
||||||
@ -1215,6 +1215,9 @@ msgstr "Skok: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nejsou definovány editační značky!"
|
msgstr "Nejsou definovány editační značky!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Nelze začít editační proces!"
|
msgstr "Nelze začít editační proces!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
|
||||||
"Last-Translator: Mogens Elneff <mogens@elneff.dk>\n"
|
"Last-Translator: Mogens Elneff <mogens@elneff.dk>\n"
|
||||||
"Language-Team: Danish <vdr@linuxtv.org>\n"
|
"Language-Team: Danish <vdr@linuxtv.org>\n"
|
||||||
@ -1213,6 +1213,9 @@ msgstr "Hop: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Der er ikke sat nogen redigeringsmærker!"
|
msgstr "Der er ikke sat nogen redigeringsmærker!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Kan ikke starte redigeringsprocessen!"
|
msgstr "Kan ikke starte redigeringsprocessen!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2010-01-16 16:46+0100\n"
|
||||||
"Last-Translator: Klaus Schmidinger <kls@tvdr.de>\n"
|
"Last-Translator: Klaus Schmidinger <kls@tvdr.de>\n"
|
||||||
"Language-Team: German <vdr@linuxtv.org>\n"
|
"Language-Team: German <vdr@linuxtv.org>\n"
|
||||||
@ -1213,6 +1213,9 @@ msgstr "Springen: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Keine Schnittmarken gesetzt!"
|
msgstr "Keine Schnittmarken gesetzt!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr "Keine Schnittsequenzen definiert!"
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Schnitt kann nicht gestartet werden!"
|
msgstr "Schnitt kann nicht gestartet werden!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
|
||||||
"Last-Translator: Dimitrios Dimitrakos <mail@dimitrios.de>\n"
|
"Last-Translator: Dimitrios Dimitrakos <mail@dimitrios.de>\n"
|
||||||
"Language-Team: Greek <vdr@linuxtv.org>\n"
|
"Language-Team: Greek <vdr@linuxtv.org>\n"
|
||||||
@ -1213,6 +1213,9 @@ msgstr "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "ÄÝí Ý÷ïõí ïñéóôåß óçìåßá åðåîåñãáóßáò"
|
msgstr "ÄÝí Ý÷ïõí ïñéóôåß óçìåßá åðåîåñãáóßáò"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Áäõíáìßá åêêßíçóçò ôçò åðåîåñãáóßáò!"
|
msgstr "Áäõíáìßá åêêßíçóçò ôçò åðåîåñãáóßáò!"
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-03-02 19:02+0100\n"
|
||||||
"Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
|
"Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
|
||||||
"Language-Team: Spanish <vdr@linuxtv.org>\n"
|
"Language-Team: Spanish <vdr@linuxtv.org>\n"
|
||||||
@ -1214,6 +1214,9 @@ msgstr "Saltar: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "¡No se definieron marcas de edición!"
|
msgstr "¡No se definieron marcas de edición!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "¡No se puede iniciar el proceso de edición!"
|
msgstr "¡No se puede iniciar el proceso de edición!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
|
||||||
"Last-Translator: Arthur Konovalov <artlov@gmail.com>\n"
|
"Last-Translator: Arthur Konovalov <artlov@gmail.com>\n"
|
||||||
"Language-Team: Estonian <vdr@linuxtv.org>\n"
|
"Language-Team: Estonian <vdr@linuxtv.org>\n"
|
||||||
@ -1213,6 +1213,9 @@ msgstr "Hüpe: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Redigeerimise markerid puuduvad!"
|
msgstr "Redigeerimise markerid puuduvad!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Redigeerimise start nurjus!"
|
msgstr "Redigeerimise start nurjus!"
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2007-08-15 15:52+0200\n"
|
||||||
"Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n"
|
"Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n"
|
||||||
"Language-Team: Finnish <vdr@linuxtv.org>\n"
|
"Language-Team: Finnish <vdr@linuxtv.org>\n"
|
||||||
@ -1216,6 +1216,9 @@ msgstr "Siirry: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Muokkausmerkinnät puuttuvat!"
|
msgstr "Muokkausmerkinnät puuttuvat!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Muokkauksen aloitus epäonnistui!"
|
msgstr "Muokkauksen aloitus epäonnistui!"
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-02-27 18:14+0100\n"
|
||||||
"Last-Translator: Jean-Claude Repetto <jc@repetto.org>\n"
|
"Last-Translator: Jean-Claude Repetto <jc@repetto.org>\n"
|
||||||
"Language-Team: French <vdr@linuxtv.org>\n"
|
"Language-Team: French <vdr@linuxtv.org>\n"
|
||||||
@ -1219,6 +1219,9 @@ msgstr "Acc
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Pas de marques d'édition définies !"
|
msgstr "Pas de marques d'édition définies !"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Impossible de commencer le montage !"
|
msgstr "Impossible de commencer le montage !"
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-03-17 19:00+0100\n"
|
||||||
"Last-Translator: Adrian Caval <anrxc@sysphere.org>\n"
|
"Last-Translator: Adrian Caval <anrxc@sysphere.org>\n"
|
||||||
"Language-Team: Croatian <vdr@linuxtv.org>\n"
|
"Language-Team: Croatian <vdr@linuxtv.org>\n"
|
||||||
@ -1215,6 +1215,9 @@ msgstr "Sko
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nijedna toèka rezanja nije odreðena!"
|
msgstr "Nijedna toèka rezanja nije odreðena!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Ne mogu zapoèeti ureðivanje!"
|
msgstr "Ne mogu zapoèeti ureðivanje!"
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2012-01-02 11:54+0200\n"
|
||||||
"Last-Translator: István Füley <ifuley@tigercomp.ro>\n"
|
"Last-Translator: István Füley <ifuley@tigercomp.ro>\n"
|
||||||
"Language-Team: Hungarian <vdr@linuxtv.org>\n"
|
"Language-Team: Hungarian <vdr@linuxtv.org>\n"
|
||||||
@ -1217,6 +1217,9 @@ msgstr "Ugr
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nincs vágópont kijelölve"
|
msgstr "Nincs vágópont kijelölve"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "A vágás nem indítható!"
|
msgstr "A vágás nem indítható!"
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2012-06-06 22:50+0100\n"
|
||||||
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
||||||
"Language-Team: Italian <vdr@linuxtv.org>\n"
|
"Language-Team: Italian <vdr@linuxtv.org>\n"
|
||||||
@ -1220,6 +1220,9 @@ msgstr "Vai a: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nessun marcatore di modifica definito!"
|
msgstr "Nessun marcatore di modifica definito!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Impossibile avviare il processo di modifica!"
|
msgstr "Impossibile avviare il processo di modifica!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.7.16\n"
|
"Project-Id-Version: VDR 1.7.16\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2010-10-30 11:55+0200\n"
|
||||||
"Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
|
"Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
|
||||||
"Language-Team: Lithuanian <vdr@linuxtv.org>\n"
|
"Language-Team: Lithuanian <vdr@linuxtv.org>\n"
|
||||||
@ -1213,6 +1213,9 @@ msgstr "Peršokti: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nenustatytos koregavimo žymės!"
|
msgstr "Nenustatytos koregavimo žymės!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Negali pradėti koregavimo!"
|
msgstr "Negali pradėti koregavimo!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR-1.7.14\n"
|
"Project-Id-Version: VDR-1.7.14\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2010-03-11 00:54+0100\n"
|
||||||
"Last-Translator: Dimitar Petrovski <dimeptr@gmail.com>\n"
|
"Last-Translator: Dimitar Petrovski <dimeptr@gmail.com>\n"
|
||||||
"Language-Team: Macedonian <en@li.org>\n"
|
"Language-Team: Macedonian <en@li.org>\n"
|
||||||
@ -1214,6 +1214,9 @@ msgstr "Скокни:"
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Нема одредено ознаки за сечење!"
|
msgstr "Нема одредено ознаки за сечење!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Не може да почне уредување!"
|
msgstr "Не може да почне уредување!"
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-02-26 17:20+0100\n"
|
||||||
"Last-Translator: Johan Schuring <johan.schuring@vetteblei.nl>\n"
|
"Last-Translator: Johan Schuring <johan.schuring@vetteblei.nl>\n"
|
||||||
"Language-Team: Dutch <vdr@linuxtv.org>\n"
|
"Language-Team: Dutch <vdr@linuxtv.org>\n"
|
||||||
@ -1217,6 +1217,9 @@ msgstr "Springen: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Geen bewerkingsmarkeringen gedefinieerd!"
|
msgstr "Geen bewerkingsmarkeringen gedefinieerd!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Kan niet beginnen met bewerken!"
|
msgstr "Kan niet beginnen met bewerken!"
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
|
||||||
"Last-Translator: Truls Slevigen <truls@slevigen.no>\n"
|
"Last-Translator: Truls Slevigen <truls@slevigen.no>\n"
|
||||||
"Language-Team: Norwegian Nynorsk <vdr@linuxtv.org>\n"
|
"Language-Team: Norwegian Nynorsk <vdr@linuxtv.org>\n"
|
||||||
@ -1214,6 +1214,9 @@ msgstr "Hopp: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Kan ikke starte redigeringsprosessen!"
|
msgstr "Kan ikke starte redigeringsprosessen!"
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-03-09 12:59+0100\n"
|
||||||
"Last-Translator: Michael Rakowski <mrak@gmx.de>\n"
|
"Last-Translator: Michael Rakowski <mrak@gmx.de>\n"
|
||||||
"Language-Team: Polish <vdr@linuxtv.org>\n"
|
"Language-Team: Polish <vdr@linuxtv.org>\n"
|
||||||
@ -1214,6 +1214,9 @@ msgstr "Skok: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nie zdefiniowano znaczników monta¿u!"
|
msgstr "Nie zdefiniowano znaczników monta¿u!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Nie mo¿na uruchomiæ procesu edycji!"
|
msgstr "Nie mo¿na uruchomiæ procesu edycji!"
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.7.15\n"
|
"Project-Id-Version: VDR 1.7.15\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2010-03-28 22:49+0100\n"
|
||||||
"Last-Translator: Cris Silva <hudokkow@gmail.com>\n"
|
"Last-Translator: Cris Silva <hudokkow@gmail.com>\n"
|
||||||
"Language-Team: Portuguese <vdr@linuxtv.org>\n"
|
"Language-Team: Portuguese <vdr@linuxtv.org>\n"
|
||||||
@ -1214,6 +1214,9 @@ msgstr "Saltar: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Marcas de edição não foram definidas!"
|
msgstr "Marcas de edição não foram definidas!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Impossível iniciar processo de edição!"
|
msgstr "Impossível iniciar processo de edição!"
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.7.12\n"
|
"Project-Id-Version: VDR 1.7.12\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2012-11-05 01:28+0100\n"
|
||||||
"Last-Translator: Lucian Muresan <lucianm@users.sourceforge.net>\n"
|
"Last-Translator: Lucian Muresan <lucianm@users.sourceforge.net>\n"
|
||||||
"Language-Team: Romanian <vdr@linuxtv.org>\n"
|
"Language-Team: Romanian <vdr@linuxtv.org>\n"
|
||||||
@ -1216,6 +1216,9 @@ msgstr "Salt la: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nu s-au pus marcaje de montaj pentru această înregistrare"
|
msgstr "Nu s-au pus marcaje de montaj pentru această înregistrare"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Nu pot porni montajul înregistrării!"
|
msgstr "Nu pot porni montajul înregistrării!"
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-12-15 14:37+0100\n"
|
||||||
"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
|
"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
|
||||||
"Language-Team: Russian <vdr@linuxtv.org>\n"
|
"Language-Team: Russian <vdr@linuxtv.org>\n"
|
||||||
@ -1214,6 +1214,9 @@ msgstr "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "½Õ ×ÐÔÐÝë ÜÕâÚØ ÔÛï ÜÞÝâÐÖÐ!"
|
msgstr "½Õ ×ÐÔÐÝë ÜÕâÚØ ÔÛï ÜÞÝâÐÖÐ!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "½ÕÒÞ×ÜÞÖÝÞ ÝÐçÐâì ÜÞÝâÐÖ ×ÐßØáØ!"
|
msgstr "½ÕÒÞ×ÜÞÖÝÞ ÝÐçÐâì ÜÞÝâÐÖ ×ÐßØáØ!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.7.16\n"
|
"Project-Id-Version: VDR 1.7.16\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2011-02-15 16:29+0100\n"
|
||||||
"Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
|
"Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
|
||||||
"Language-Team: Slovak <vdr@linuxtv.org>\n"
|
"Language-Team: Slovak <vdr@linuxtv.org>\n"
|
||||||
@ -1213,6 +1213,9 @@ msgstr "Skok: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nie sú urèené znaèky úprav!"
|
msgstr "Nie sú urèené znaèky úprav!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Nemô¾e zaèa» spracovanie úprav!"
|
msgstr "Nemô¾e zaèa» spracovanie úprav!"
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-02-28 19:44+0100\n"
|
||||||
"Last-Translator: Matjaz Thaler <matjaz.thaler@guest.arnes.si>\n"
|
"Last-Translator: Matjaz Thaler <matjaz.thaler@guest.arnes.si>\n"
|
||||||
"Language-Team: Slovenian <vdr@linuxtv.org>\n"
|
"Language-Team: Slovenian <vdr@linuxtv.org>\n"
|
||||||
@ -1214,6 +1214,9 @@ msgstr "Sko
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nobena prekinitvena toèka ni definirana!"
|
msgstr "Nobena prekinitvena toèka ni definirana!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Ne morem zaèeti urejanja!"
|
msgstr "Ne morem zaèeti urejanja!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.7.1\n"
|
"Project-Id-Version: VDR 1.7.1\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2011-01-09 15:57+0100\n"
|
||||||
"Last-Translator: Milan Cvijanoviæ <elcom_cvijo@hotmail.com>\n"
|
"Last-Translator: Milan Cvijanoviæ <elcom_cvijo@hotmail.com>\n"
|
||||||
"Language-Team: Serbian <vdr@linuxtv.org>\n"
|
"Language-Team: Serbian <vdr@linuxtv.org>\n"
|
||||||
@ -1239,6 +1239,9 @@ msgstr "Sko
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Nijedna taèka rezanja nije odreðena!"
|
msgstr "Nijedna taèka rezanja nije odreðena!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Ne mogu zapoèeti ureðivanje!"
|
msgstr "Ne mogu zapoèeti ureðivanje!"
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-03-12 18:25+0100\n"
|
||||||
"Last-Translator: Magnus Andersson <svankan@bahnhof.se>\n"
|
"Last-Translator: Magnus Andersson <svankan@bahnhof.se>\n"
|
||||||
"Language-Team: Swedish <vdr@linuxtv.org>\n"
|
"Language-Team: Swedish <vdr@linuxtv.org>\n"
|
||||||
@ -1216,6 +1216,9 @@ msgstr "Hopp: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Det finns inga redigeringsmärken"
|
msgstr "Det finns inga redigeringsmärken"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Kan inte starta redigering!"
|
msgstr "Kan inte starta redigering!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2008-02-28 00:33+0100\n"
|
||||||
"Last-Translator: Oktay Yolgeçen <oktay_73@yahoo.de>\n"
|
"Last-Translator: Oktay Yolgeçen <oktay_73@yahoo.de>\n"
|
||||||
"Language-Team: Turkish <vdr@linuxtv.org>\n"
|
"Language-Team: Turkish <vdr@linuxtv.org>\n"
|
||||||
@ -1213,6 +1213,9 @@ msgstr "Atla: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Kesim iþaretleri belirtilmemiþ!"
|
msgstr "Kesim iþaretleri belirtilmemiþ!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Kesim baþlatýlamýyor!"
|
msgstr "Kesim baþlatýlamýyor!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.7.7\n"
|
"Project-Id-Version: VDR 1.7.7\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2010-04-25 16:35+0200\n"
|
||||||
"Last-Translator: Yarema aka Knedlyk <yupadmin@gmail.com>\n"
|
"Last-Translator: Yarema aka Knedlyk <yupadmin@gmail.com>\n"
|
||||||
"Language-Team: Ukrainian <vdr@linuxtv.org>\n"
|
"Language-Team: Ukrainian <vdr@linuxtv.org>\n"
|
||||||
@ -1213,6 +1213,9 @@ msgstr "Перейти: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "Не задано міток для монтажу!"
|
msgstr "Не задано міток для монтажу!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "Неможливо почати монтаж запису!"
|
msgstr "Неможливо почати монтаж запису!"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\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"
|
"PO-Revision-Date: 2009-09-23 23:50+0800\n"
|
||||||
"Last-Translator: Nan Feng <nfgx@21cn.com>\n"
|
"Last-Translator: Nan Feng <nfgx@21cn.com>\n"
|
||||||
"Language-Team: Chinese (simplified) <vdr@linuxtv.org>\n"
|
"Language-Team: Chinese (simplified) <vdr@linuxtv.org>\n"
|
||||||
@ -1216,6 +1216,9 @@ msgstr "跳过: "
|
|||||||
msgid "No editing marks defined!"
|
msgid "No editing marks defined!"
|
||||||
msgstr "无编辑标记定义!"
|
msgstr "无编辑标记定义!"
|
||||||
|
|
||||||
|
msgid "No editing sequences defined!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Can't start editing process!"
|
msgid "Can't start editing process!"
|
||||||
msgstr "不能开始编辑处理"
|
msgstr "不能开始编辑处理"
|
||||||
|
|
||||||
|
50
recording.c
50
recording.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "recording.h"
|
||||||
@ -1456,6 +1456,54 @@ cMark *cMarks::GetNext(int Position)
|
|||||||
return NULL;
|
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 -------------------------------------------------
|
// --- cRecordingUserCommand -------------------------------------------------
|
||||||
|
|
||||||
const char *cRecordingUserCommand::command = NULL;
|
const char *cRecordingUserCommand::command = NULL;
|
||||||
|
15
recording.h
15
recording.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __RECORDING_H
|
||||||
@ -238,6 +238,19 @@ public:
|
|||||||
cMark *Get(int Position);
|
cMark *Get(int Position);
|
||||||
cMark *GetPrev(int Position);
|
cMark *GetPrev(int Position);
|
||||||
cMark *GetNext(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"
|
#define RUC_BEFORERECORDING "before"
|
||||||
|
112
remux.c
112
remux.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "remux.h"
|
||||||
@ -114,6 +114,32 @@ void cRemux::SetBrokenLink(uchar *Data, int Length)
|
|||||||
|
|
||||||
// --- Some TS handling tools ------------------------------------------------
|
// --- 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)
|
int64_t TsGetPts(const uchar *p, int l)
|
||||||
{
|
{
|
||||||
// Find the first packet with a PTS and use it:
|
// Find the first packet with a PTS and use it:
|
||||||
@ -127,25 +153,75 @@ int64_t TsGetPts(const uchar *p, int l)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TsSetTeiOnBrokenPackets(uchar *p, int l)
|
int64_t TsGetDts(const uchar *p, int l)
|
||||||
{
|
{
|
||||||
bool Processed[MAXPID] = { false };
|
// Find the first packet with a DTS and use it:
|
||||||
while (l >= TS_SIZE) {
|
while (l > 0) {
|
||||||
if (*p != TS_SYNC_BYTE)
|
const uchar *d = p;
|
||||||
break;
|
if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d))
|
||||||
int Pid = TsPid(p);
|
return PesGetDts(d);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l -= TS_SIZE;
|
|
||||||
p += TS_SIZE;
|
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 ------------------------------------------------------------
|
||||||
@ -1395,7 +1471,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // audio
|
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);
|
dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1);
|
||||||
synced = true;
|
synced = true;
|
||||||
parser->SetDebug(false);
|
parser->SetDebug(false);
|
||||||
|
66
remux.h
66
remux.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __REMUX_H
|
||||||
@ -52,6 +52,11 @@ public:
|
|||||||
#define PATPID 0x0000 // PAT PID (constant 0)
|
#define PATPID 0x0000 // PAT PID (constant 0)
|
||||||
#define MAXPID 0x2000 // for arrays that use a PID as the index
|
#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)
|
inline bool TsHasPayload(const uchar *p)
|
||||||
{
|
{
|
||||||
return p[3] & TS_PAYLOAD_EXISTS;
|
return p[3] & TS_PAYLOAD_EXISTS;
|
||||||
@ -82,6 +87,16 @@ inline bool TsIsScrambled(const uchar *p)
|
|||||||
return p[3] & TS_SCRAMBLING_CONTROL;
|
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)
|
inline int TsPayloadOffset(const uchar *p)
|
||||||
{
|
{
|
||||||
int o = TsHasAdaptationField(p) ? p[4] + 5 : 4;
|
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;
|
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.
|
// The following functions all take a pointer to a sequence of complete TS packets.
|
||||||
|
|
||||||
int64_t TsGetPts(const uchar *p, int l);
|
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:
|
// Some PES handling tools:
|
||||||
// The following functions that take a pointer to PES data all assume that
|
// 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;
|
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)
|
inline int64_t PesGetPts(const uchar *p)
|
||||||
{
|
{
|
||||||
return ((((int64_t)p[ 9]) & 0x0E) << 29) |
|
return ((((int64_t)p[ 9]) & 0x0E) << 29) |
|
||||||
@ -151,6 +187,28 @@ inline int64_t PesGetPts(const uchar *p)
|
|||||||
((((int64_t)p[13]) & 0xFE) >> 1);
|
((((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:
|
// A transprent TS payload handler:
|
||||||
|
|
||||||
class cTsPayload {
|
class cTsPayload {
|
||||||
|
Loading…
Reference in New Issue
Block a user