summaryrefslogtreecommitdiff
path: root/remux.c
diff options
context:
space:
mode:
Diffstat (limited to 'remux.c')
-rw-r--r--remux.c286
1 files changed, 157 insertions, 129 deletions
diff --git a/remux.c b/remux.c
index 98f404f2..c5055b69 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.28 2009/11/01 15:33:32 kls Exp $
+ * $Id: remux.c 2.29 2009/11/22 11:23:27 kls Exp $
*/
#include "remux.h"
@@ -264,8 +264,8 @@ void cPatPmtGenerator::GeneratePat(void)
uchar *p = pat;
int i = 0;
p[i++] = TS_SYNC_BYTE; // TS indicator
- p[i++] = TS_PAYLOAD_START; // flags (3), pid hi (5)
- p[i++] = 0x00; // pid lo
+ p[i++] = TS_PAYLOAD_START | (PATPID >> 8); // flags (3), pid hi (5)
+ p[i++] = PATPID & 0xFF; // pid lo
p[i++] = 0x10; // flags (4), continuity counter (4)
p[i++] = 0x00; // pointer field (payload unit start indicator is set)
int PayloadStart = i;
@@ -733,20 +733,20 @@ void PesDump(const char *Name, const u_char *Data, int Length)
// --- cFrameDetector --------------------------------------------------------
+#define EMPTY_SCANNER (0xFFFFFFFF)
+
cFrameDetector::cFrameDetector(int Pid, int Type)
{
- pid = Pid;
- type = Type;
+ SetPid(Pid, Type);
synced = false;
newFrame = independentFrame = false;
numPtsValues = 0;
numIFrames = 0;
- isVideo = type == 0x01 || type == 0x02 || type == 0x1B; // MPEG 1, 2 or 4
frameDuration = 0;
framesInPayloadUnit = framesPerPayloadUnit = 0;
payloadUnitOfFrame = 0;
scanning = false;
- scanner = 0;
+ scanner = EMPTY_SCANNER;
}
static int CmpUint32(const void *p1, const void *p2)
@@ -756,8 +756,24 @@ static int CmpUint32(const void *p1, const void *p2)
return 0;
}
+void cFrameDetector::SetPid(int Pid, int Type)
+{
+ pid = Pid;
+ type = Type;
+ isVideo = type == 0x01 || type == 0x02 || type == 0x1B; // MPEG 1, 2 or 4
+}
+
+void cFrameDetector::Reset(void)
+{
+ newFrame = independentFrame = false;
+ payloadUnitOfFrame = 0;
+ scanning = false;
+ scanner = EMPTY_SCANNER;
+}
+
int cFrameDetector::Analyze(const uchar *Data, int Length)
{
+ int SeenPayloadStart = false;
int Processed = 0;
newFrame = independentFrame = false;
while (Length >= TS_SIZE) {
@@ -768,144 +784,156 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
return Processed + Skipped;
}
- if (TsHasPayload(Data) && !TsIsScrambled(Data) && TsPid(Data) == pid) {
- if (TsPayloadStart(Data)) {
- if (synced && Processed)
- return Processed;
- if (Length < 2 * TS_SIZE)
- return 0; // need more data, in case the frame type is stored in the second TS packet
- if (!frameDuration) {
- // frame duration unknown, so collect a sequence of PTS values:
- if (numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
- const uchar *Pes = Data + TsPayloadOffset(Data);
- if (PesHasPts(Pes)) {
- ptsValues[numPtsValues] = PesGetPts(Pes);
- // check for rollover:
- if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
- dbgframes("#");
- numPtsValues = 0;
- numIFrames = 0;
+ if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
+ int Pid = TsPid(Data);
+ if (Pid == pid) {
+ if (TsPayloadStart(Data)) {
+ SeenPayloadStart = true;
+ if (synced && Processed)
+ return Processed;
+ if (Length < MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE)
+ return 0; // need more data, in case the frame type is not stored in the first TS packet
+ if (!frameDuration) {
+ // frame duration unknown, so collect a sequence of PTS values:
+ if (numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
+ const uchar *Pes = Data + TsPayloadOffset(Data);
+ if (PesHasPts(Pes)) {
+ ptsValues[numPtsValues] = PesGetPts(Pes);
+ // check for rollover:
+ if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
+ dbgframes("#");
+ numPtsValues = 0;
+ numIFrames = 0;
+ }
+ else
+ numPtsValues++;
}
- else
- numPtsValues++;
}
- }
- else {
- // find the smallest PTS delta:
- qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
- numPtsValues--;
- for (int i = 0; i < numPtsValues; i++)
- ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
- qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
- uint32_t Delta = ptsValues[0];
- // determine frame info:
- if (isVideo) {
- if (Delta % 3600 == 0)
- frameDuration = 3600; // PAL, 25 fps
- else if (Delta % 3003 == 0)
- frameDuration = 3003; // NTSC, 29.97 fps
- else if (Delta == 1800) {
- frameDuration = 3600; // PAL, 25 fps
- framesPerPayloadUnit = -2;
- }
- else if (Delta == 1501) {
- frameDuration = 3003; // NTSC, 29.97 fps
- framesPerPayloadUnit = -2;
- }
- else {
- frameDuration = 3600; // unknown, assuming 25 fps
- dsyslog("unknown frame duration (%d), assuming 25 fps", Delta);
+ else {
+ // find the smallest PTS delta:
+ qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
+ numPtsValues--;
+ for (int i = 0; i < numPtsValues; i++)
+ ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
+ qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
+ uint32_t Delta = ptsValues[0];
+ // determine frame info:
+ if (isVideo) {
+ if (Delta % 3600 == 0)
+ frameDuration = 3600; // PAL, 25 fps
+ else if (Delta % 3003 == 0)
+ frameDuration = 3003; // NTSC, 29.97 fps
+ else if (Delta == 1800) {
+ frameDuration = 3600; // PAL, 25 fps
+ framesPerPayloadUnit = -2;
+ }
+ else if (Delta == 1501) {
+ frameDuration = 3003; // NTSC, 29.97 fps
+ framesPerPayloadUnit = -2;
+ }
+ else {
+ frameDuration = 3600; // unknown, assuming 25 fps
+ dsyslog("unknown frame duration (%d), assuming 25 fps", Delta);
+ }
}
+ else // audio
+ frameDuration = Delta; // PTS of audio frames is always increasing
+ dbgframes("\nframe duration = %d FPS = %5.2f FPPU = %d\n", frameDuration, 90000.0 / frameDuration, framesPerPayloadUnit);
}
- else // audio
- frameDuration = Delta; // PTS of audio frames is always increasing
- dbgframes("\nframe duration = %d FPS = %5.2f FPPU = %d\n", frameDuration, 90000.0 / frameDuration, framesPerPayloadUnit);
}
+ scanner = EMPTY_SCANNER;
+ scanning = true;
}
- scanner = 0;
- scanning = true;
- }
- if (scanning) {
- int PayloadOffset = TsPayloadOffset(Data);
- if (TsPayloadStart(Data)) {
- PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
- if (!framesPerPayloadUnit)
- framesPerPayloadUnit = framesInPayloadUnit;
- if (DebugFrames && !synced)
- dbgframes("/");
- }
- for (int i = PayloadOffset; scanning && i < TS_SIZE; i++) {
- scanner <<= 8;
- scanner |= Data[i];
- switch (type) {
- case 0x01: // MPEG 1 video
- case 0x02: // MPEG 2 video
- if (scanner == 0x00000100) { // Picture Start Code
- newFrame = true;
- independentFrame = ((Data[i + 2] >> 3) & 0x07) == 1; // I-Frame
- if (synced) {
- if (framesPerPayloadUnit <= 1)
- scanning = false;
+ if (scanning) {
+ int PayloadOffset = TsPayloadOffset(Data);
+ if (TsPayloadStart(Data)) {
+ PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
+ if (!framesPerPayloadUnit)
+ framesPerPayloadUnit = framesInPayloadUnit;
+ if (DebugFrames && !synced)
+ dbgframes("/");
+ }
+ for (int i = PayloadOffset; scanning && i < TS_SIZE; i++) {
+ scanner <<= 8;
+ scanner |= Data[i];
+ switch (type) {
+ case 0x01: // MPEG 1 video
+ case 0x02: // MPEG 2 video
+ if (scanner == 0x00000100) { // Picture Start Code
+ scanner = EMPTY_SCANNER;
+ if (synced && !SeenPayloadStart && Processed)
+ return Processed; // flush everything before this new frame
+ newFrame = true;
+ independentFrame = ((Data[i + 2] >> 3) & 0x07) == 1; // I-Frame
+ if (synced) {
+ if (framesPerPayloadUnit <= 1)
+ scanning = false;
+ }
+ else {
+ framesInPayloadUnit++;
+ if (independentFrame)
+ numIFrames++;
+ dbgframes("%d ", (Data[i + 2] >> 3) & 0x07);
+ }
+ if (synced)
+ return Processed + TS_SIZE; // flag this new frame
}
- else {
- framesInPayloadUnit++;
- if (independentFrame)
- numIFrames++;
- dbgframes("%d ", (Data[i + 2] >> 3) & 0x07);
+ break;
+ case 0x1B: // MPEG 4 video
+ if (scanner == 0x00000109) { // Access Unit Delimiter
+ scanner = EMPTY_SCANNER;
+ if (synced && !SeenPayloadStart && Processed)
+ return Processed; // flush everything before this new frame
+ newFrame = true;
+ independentFrame = Data[i + 1] == 0x10;
+ if (synced) {
+ if (framesPerPayloadUnit < 0) {
+ payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
+ if (payloadUnitOfFrame != 0 && independentFrame)
+ payloadUnitOfFrame = 0;
+ if (payloadUnitOfFrame)
+ newFrame = false;
+ }
+ if (framesPerPayloadUnit <= 1)
+ scanning = false;
+ }
+ else {
+ framesInPayloadUnit++;
+ if (independentFrame)
+ numIFrames++;
+ dbgframes("%02X ", Data[i + 1]);
+ }
+ if (synced)
+ return Processed + TS_SIZE; // flag this new frame
}
- scanner = 0;
+ break;
+ case 0x04: // MPEG audio
+ case 0x06: // AC3 audio
if (synced && Processed)
return Processed;
- }
- break;
- case 0x1B: // MPEG 4 video
- if (scanner == 0x00000109) { // Access Unit Delimiter
newFrame = true;
- independentFrame = Data[i + 1] == 0x10;
- if (synced) {
- if (framesPerPayloadUnit < 0) {
- payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
- if (payloadUnitOfFrame != 0 && independentFrame)
- payloadUnitOfFrame = 0;
- if (payloadUnitOfFrame)
- newFrame = false;
- }
- if (framesPerPayloadUnit <= 1)
- scanning = false;
- }
- else {
- framesInPayloadUnit++;
- if (independentFrame)
+ independentFrame = true;
+ if (!synced) {
+ framesInPayloadUnit = 1;
+ if (TsPayloadStart(Data))
numIFrames++;
- dbgframes("%02X ", Data[i + 1]);
}
- if (synced && Processed)
- return Processed;
- scanner = 0;
- }
- break;
- case 0x04: // MPEG audio
- case 0x06: // AC3 audio
- newFrame = true;
- independentFrame = true;
- if (!synced) {
- framesInPayloadUnit = 1;
- if (TsPayloadStart(Data))
- numIFrames++;
- }
- scanning = false;
- if (synced && Processed)
- return Processed;
- break;
- default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
- pid = 0; // let's just ignore any further data
+ scanning = false;
+ break;
+ default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
+ pid = 0; // let's just ignore any further data
+ }
+ }
+ if (!synced && frameDuration && independentFrame) {
+ synced = true;
+ dbgframes("*");
+ Reset();
+ return Processed + TS_SIZE;
}
- }
- if (!synced && frameDuration && independentFrame) {
- synced = true;
- dbgframes("*");
}
}
+ else if (Pid == PATPID && synced && Processed)
+ return Processed; // allow the caller to see any PAT packets
}
Data += TS_SIZE;
Length -= TS_SIZE;