summaryrefslogtreecommitdiff
path: root/remux.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-07-29 18:00:00 +0200
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-07-29 18:00:00 +0200
commit8f9cc68f76c4fd0960f919a77fb16a6455922deb (patch)
tree83f607160a07966e97069397580acfb0d9b1be7a /remux.c
parent610c5600df98b35226536ffe92b1fd231128c7d4 (diff)
downloadvdr-patch-lnbsharing-8f9cc68f76c4fd0960f919a77fb16a6455922deb.tar.gz
vdr-patch-lnbsharing-8f9cc68f76c4fd0960f919a77fb16a6455922deb.tar.bz2
Version 0.85vdr-0.85
- Added Norwegian language texts (thanks to Jørgen Tvedt). - Increased the usleep value in cDvbOsd::Cmd() to 5000 in order to work on systems with the KURT/utime-patch (thanks to Guido Fiala). - Changed the check whether the driver is loaded in runvdr to check for the 'dvb' module (the last one loaded). - Fixed repeat function with LIRC (thanks to Stefan Huelswitt). - Increased the upper limit for the symbol rate to 30000 (thanks to Ulrich Röder). - Made the position of the channel display configurable (thanks to Stefan Huelswitt). - Made the width and height of the OSD configurable (thanks to Stefan Huelswitt). - DiSEqC support can now be generally enabled/disabled in the Setup menu. This may be necessary if your multiswitch gets irritated by the default DiSEqC codes '0' (thanks to Markus Lang). - Fixed replaying in case there is no index file. - Fixed jumping to an editing mark when replay has been paused. - Avoiding unnecessary code execution in the replay progress display (thanks to Guido Fiala). - When entering time values the digits that still have to be entered are now shown as '-' (as in "1-:--"). - When setting an editing mark while the progress display is not active, the display will now be turned on for a short while to indicate the successful setting of the mark. - Updated 'channels.conf' for Premiere World (thanks to Helmut Schächner). Check your timers if you use this channels.conf file, since the sequence of several PW channels has been changed. - Changed the color of "Info" messages to "black on green" and that of the confirmation messages (like "Delete...") to "black on yellow". - Fixed display with DEBUG_OSD (it still crashes sometimes, esp. when replaying, but I can't seem to find what causes this... any ideas anybody?). - Avoiding audio/video distortions in 'Transfer Mode' by no longer actually tuning the primary interface (which can't receive this channel, anyway). Apparently the driver gets irritated when the channel is switched and a replay session is started immediately after that. - Increased timeout until reporting "video data stream broken" when recording. - Explicitly switching back to the previously active channel after ending a replay session (to have it shown correctly in case it was in 'Transfer Mode').
Diffstat (limited to 'remux.c')
-rw-r--r--remux.c539
1 files changed, 493 insertions, 46 deletions
diff --git a/remux.c b/remux.c
index e48296d..3c7ec6e 100644
--- a/remux.c
+++ b/remux.c
@@ -4,7 +4,11 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remux.c 1.1 2001/03/31 08:42:17 kls Exp $
+ * The parts of this code that implement cTS2PES have been taken from
+ * the Linux DVB driver's 'tuxplayer' example and were rewritten to suit
+ * VDR's needs.
+ *
+ * $Id: remux.c 1.5 2001/06/24 16:37:23 kls Exp $
*/
/* The calling interface of the 'cRemux::Process()' function is defined
@@ -62,17 +66,390 @@
*/
#include "remux.h"
+#include "thread.h"
#include "tools.h"
-#if defined(REMUX_NONE)
+// --- cTS2PES ---------------------------------------------------------------
+
+#include <netinet/in.h>
+
+//XXX TODO: these should really be available in some driver header file!
+#define PROG_STREAM_MAP 0xBC
+#ifndef PRIVATE_STREAM1
+#define PRIVATE_STREAM1 0xBD
+#endif
+#define PADDING_STREAM 0xBE
+#ifndef PRIVATE_STREAM2
+#define PRIVATE_STREAM2 0xBF
+#endif
+#define AUDIO_STREAM_S 0xC0
+#define AUDIO_STREAM_E 0xDF
+#define VIDEO_STREAM_S 0xE0
+#define VIDEO_STREAM_E 0xEF
+#define ECM_STREAM 0xF0
+#define EMM_STREAM 0xF1
+#define DSM_CC_STREAM 0xF2
+#define ISO13522_STREAM 0xF3
+#define PROG_STREAM_DIR 0xFF
+
+//pts_dts flags
+#define PTS_ONLY 0x80
+
+#define TS_SIZE 188
+#define PAY_START 0x40
+#define PID_MASK_HI 0x1F
+//flags
+#define ADAPT_FIELD 0x20
+//XXX TODO
+
+#define MAX_PLENGTH 0xFFFF
+#define MMAX_PLENGTH (4*MAX_PLENGTH)
+
+#define IPACKS 2048
+
+// Start codes:
+#define SC_PICTURE 0x00 // "picture header"
+
+#define MAXNONUSEFULDATA (10*1024*1024)
+
+class cTS2PES {
+private:
+ int size;
+ int found;
+ int count;
+ uint8_t *buf;
+ uint8_t cid;
+ uint8_t audioCid;
+ int plength;
+ uint8_t plen[2];
+ uint8_t flag1;
+ uint8_t flag2;
+ uint8_t hlength;
+ int mpeg;
+ uint8_t check;
+ int which;
+ bool done;
+ uint8_t *resultBuffer;
+ int *resultCount;
+ static uint8_t headr[];
+ void store(uint8_t *Data, int Count);
+ void reset_ipack(void);
+ void send_ipack(void);
+ void write_ipack(const uint8_t *Data, int Count);
+ void instant_repack(const uint8_t *Buf, int Count);
+public:
+ cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid = 0x00);
+ ~cTS2PES();
+ void ts_to_pes(const uint8_t *Buf); // don't need count (=188)
+ void Clear(void);
+ };
+
+uint8_t cTS2PES::headr[] = { 0x00, 0x00, 0x01 };
-cRemux::cRemux(void)
+cTS2PES::cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid)
{
+ resultBuffer = ResultBuffer;
+ resultCount = ResultCount;
+ size = Size;
+ audioCid = AudioCid;
+
+ if (!(buf = new uint8_t[size]))
+ esyslog(LOG_ERR, "Not enough memory for ts_transform");
+
+ reset_ipack();
+}
+
+cTS2PES::~cTS2PES()
+{
+ delete buf;
+}
+
+void cTS2PES::Clear(void)
+{
+ reset_ipack();
+}
+
+void cTS2PES::store(uint8_t *Data, int Count)
+{
+ if (*resultCount + Count > RESULTBUFFERSIZE) {
+ esyslog(LOG_ERR, "ERROR: result buffer overflow (%d + %d > %d)", *resultCount, Count, RESULTBUFFERSIZE);
+ Count = RESULTBUFFERSIZE - *resultCount;
+ }
+ memcpy(resultBuffer + *resultCount, Data, Count);
+ *resultCount += Count;
+}
+
+void cTS2PES::reset_ipack(void)
+{
+ found = 0;
+ cid = 0;
+ plength = 0;
+ flag1 = 0;
+ flag2 = 0;
+ hlength = 0;
+ mpeg = 0;
+ check = 0;
+ which = 0;
+ done = false;
+ count = 0;
+}
+
+void cTS2PES::send_ipack(void)
+{
+ if (count < 10)
+ return;
+ buf[3] = (AUDIO_STREAM_S <= cid && cid <= AUDIO_STREAM_E && audioCid) ? audioCid : cid;
+ buf[4] = (uint8_t)(((count - 6) & 0xFF00) >> 8);
+ buf[5] = (uint8_t)((count - 6) & 0x00FF);
+ store(buf, count);
+
+ switch (mpeg) {
+ case 2:
+ buf[6] = 0x80;
+ buf[7] = 0x00;
+ buf[8] = 0x00;
+ count = 9;
+ break;
+ case 1:
+ buf[6] = 0x0F;
+ count = 7;
+ break;
+ }
+}
+
+void cTS2PES::write_ipack(const uint8_t *Data, int Count)
+{
+ if (count < 6) {
+ memcpy(buf, headr, 3);
+ count = 6;
+ }
+
+ if (count + Count < size) {
+ memcpy(buf + count, Data, Count);
+ count += Count;
+ }
+ else {
+ int rest = size - count;
+ memcpy(buf + count, Data, rest);
+ count += rest;
+ send_ipack();
+ if (Count - rest > 0)
+ write_ipack(Data + rest, Count - rest);
+ }
+}
+
+void cTS2PES::instant_repack(const uint8_t *Buf, int Count)
+{
+ int c = 0;
+
+ while (c < Count && (mpeg == 0 || (mpeg == 1 && found < 7) || (mpeg == 2 && found < 9)) && (found < 5 || !done)) {
+ switch (found ) {
+ case 0:
+ case 1:
+ if (Buf[c] == 0x00)
+ found++;
+ else
+ found = 0;
+ c++;
+ break;
+ case 2:
+ if (Buf[c] == 0x01)
+ found++;
+ else if (Buf[c] != 0)
+ found = 0;
+ c++;
+ break;
+ case 3:
+ cid = 0;
+ switch (Buf[c]) {
+ case PROG_STREAM_MAP:
+ case PRIVATE_STREAM2:
+ case PROG_STREAM_DIR:
+ case ECM_STREAM :
+ case EMM_STREAM :
+ case PADDING_STREAM :
+ case DSM_CC_STREAM :
+ case ISO13522_STREAM:
+ done = true;
+ case PRIVATE_STREAM1:
+ case VIDEO_STREAM_S ... VIDEO_STREAM_E:
+ case AUDIO_STREAM_S ... AUDIO_STREAM_E:
+ found++;
+ cid = Buf[c++];
+ break;
+ default:
+ found = 0;
+ break;
+ }
+ break;
+ case 4:
+ if (Count - c > 1) {
+ unsigned short *pl = (unsigned short *)(Buf + c);
+ plength = ntohs(*pl);
+ c += 2;
+ found += 2;
+ }
+ else {
+ plen[0] = Buf[c];
+ found++;
+ return;
+ }
+ break;
+ case 5: {
+ plen[1] = Buf[c++];
+ unsigned short *pl = (unsigned short *)plen;
+ plength = ntohs(*pl);
+ found++;
+ }
+ break;
+ case 6:
+ if (!done) {
+ flag1 = Buf[c++];
+ found++;
+ if ((flag1 & 0xC0) == 0x80 )
+ mpeg = 2;
+ else {
+ esyslog(LOG_INFO, "ERROR: can't record MPEG1!");
+ hlength = 0;
+ which = 0;
+ mpeg = 1;
+ flag2 = 0;
+ }
+ }
+ break;
+ case 7:
+ if (!done && mpeg == 2) {
+ flag2 = Buf[c++];
+ found++;
+ }
+ break;
+ case 8:
+ if (!done && mpeg == 2) {
+ hlength = Buf[c++];
+ found++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!plength)
+ plength = MMAX_PLENGTH - 6;
+
+ if (done || ((mpeg == 2 && found >= 9) || (mpeg == 1 && found >= 7))) {
+ switch (cid) {
+ case AUDIO_STREAM_S ... AUDIO_STREAM_E:
+ case VIDEO_STREAM_S ... VIDEO_STREAM_E:
+ case PRIVATE_STREAM1:
+
+ if (mpeg == 2 && found == 9) {
+ write_ipack(&flag1, 1);
+ write_ipack(&flag2, 1);
+ write_ipack(&hlength, 1);
+ }
+
+ if (mpeg == 2 && (flag2 & PTS_ONLY) && found < 14) {
+ while (c < Count && found < 14) {
+ write_ipack(Buf + c, 1);
+ c++;
+ found++;
+ }
+ if (c == Count)
+ return;
+ }
+
+ while (c < Count && found < plength + 6) {
+ int l = Count - c;
+ if (l + found > plength + 6)
+ l = plength + 6 - found;
+ write_ipack(Buf + c, l);
+ found += l;
+ c += l;
+ }
+
+ break;
+ }
+
+ if (done) {
+ if (found + Count - c < plength + 6) {
+ found += Count - c;
+ c = Count;
+ }
+ else {
+ c += plength + 6 - found;
+ found = plength + 6;
+ }
+ }
+
+ if (plength && found == plength + 6) {
+ send_ipack();
+ reset_ipack();
+ if (c < Count)
+ instant_repack(Buf + c, Count - c);
+ }
+ }
+ return;
+}
+
+void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
+{
+ if (!Buf)
+ return;
+
+ if (Buf[1] & PAY_START) {
+ if (plength == MMAX_PLENGTH - 6 && found > 6) {
+ plength = found - 6;
+ found = 0;
+ send_ipack();
+ reset_ipack();
+ }
+ }
+
+ uint8_t off = 0;
+
+ if (Buf[3] & ADAPT_FIELD) { // adaptation field?
+ off = Buf[4] + 1;
+ if (off + 4 > 187)
+ return;
+ }
+
+ instant_repack(Buf + 4 + off, TS_SIZE - 4 - off);
+}
+
+// --- cRemux ----------------------------------------------------------------
+
+cRemux::cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure)
+{
+ vPid = VPid;
+ aPid1 = APid1;
+ aPid2 = APid2;
+ dPid1 = DPid1;
+ dPid2 = DPid2;
+ exitOnFailure = ExitOnFailure;
synced = false;
+ skipped = 0;
+ resultCount = resultDelivered = 0;
+ vTS2PES = new cTS2PES(resultBuffer, &resultCount, IPACKS);
+ aTS2PES1 = new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC0);
+ aTS2PES2 = aPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC1) : NULL;
+ dTS2PES1 = dPid1 ? new cTS2PES(resultBuffer, &resultCount, IPACKS) : NULL;
+ //XXX don't yet know how to tell apart primary and secondary DD data...
+ dTS2PES2 = /*XXX dPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS) : XXX*/ NULL;
}
cRemux::~cRemux()
{
+ delete vTS2PES;
+ delete aTS2PES1;
+ delete aTS2PES2;
+ delete dTS2PES1;
+ delete dTS2PES2;
+}
+
+int cRemux::GetPid(const uchar *Data)
+{
+ return (((uint16_t)Data[0] & PID_MASK_HI) << 8) | (Data[1] & 0xFF);
}
int cRemux::GetPacketLength(const uchar *Data, int Count, int Offset)
@@ -104,70 +481,140 @@ int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &Pic
return -1;
}
-const uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar &PictureType)
+void cRemux::SetAudioPid(int APid)
{
- int Skip = 0;
+ aPid1 = APid;
+ vTS2PES->Clear();
+ aTS2PES1->Clear();
+ resultCount = resultDelivered = 0;
+}
- PictureType = NO_PICTURE;
+const uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar *PictureType)
+{
+ uchar dummyPictureType;
+ if (!PictureType)
+ PictureType = &dummyPictureType;
- if (Count >= MINVIDEODATA) {
- for (int i = 0; i < Count; i++) {
- if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) {
- switch (Data[i + 3]) {
- case SC_VIDEO:
+/*XXX
+ // test recording the raw TS:
+ Result = Count;
+ *PictureType = I_FRAME;
+ return Data;
+XXX*/
+
+ // Remove any previously delivered data from the result buffer:
+
+ if (resultDelivered) {
+ if (resultDelivered < resultCount)
+ memmove(resultBuffer, resultBuffer + resultDelivered, resultCount - resultDelivered);
+ resultCount -= resultDelivered;
+ resultDelivered = 0;
+ }
+
+ // Convert incoming TS data into multiplexed PES:
+
+ int used = 0;
+ for (int i = 0; i < Count; i += TS_SIZE) {
+ if (Count - i < TS_SIZE)
+ break;
+ int pid = GetPid(Data + i + 1);
+ if (Data[i + 3] & 0x10) { // got payload
+ if (pid == vPid) vTS2PES->ts_to_pes(Data + i);
+ else if (pid == aPid1) aTS2PES1->ts_to_pes(Data + i);
+ else if (pid == aPid2 && aTS2PES2) aTS2PES2->ts_to_pes(Data + i);
+ else if (pid == dPid1 && dTS2PES1) dTS2PES1->ts_to_pes(Data + i);
+ else if (pid == dPid2 && dTS2PES2) dTS2PES2->ts_to_pes(Data + i);
+ }
+ used += TS_SIZE;
+ if (resultCount > (int)sizeof(resultBuffer) / 2)
+ break;
+ }
+ Count = used;
+
+/*XXX
+ // test recording without determining the real frame borders:
+ *PictureType = I_FRAME;
+ Result = resultDelivered = resultCount;
+ return Result ? resultBuffer : NULL;
+XXX*/
+
+ // Check if we're getting anywhere here:
+
+ if (!synced && skipped >= 0) {
+ if (skipped > MAXNONUSEFULDATA) {
+ esyslog(LOG_ERR, "ERROR: no useful data seen within %d byte of video stream", skipped);
+ skipped = -1;
+ if (exitOnFailure)
+ cThread::EmergencyExit(true);
+ }
+ else
+ skipped += Count;
+ }
+
+ // Check for frame borders:
+
+ *PictureType = NO_PICTURE;
+
+ if (resultCount >= MINVIDEODATA) {
+ for (int i = 0; i < resultCount; i++) {
+ if (resultBuffer[i] == 0 && resultBuffer[i + 1] == 0 && resultBuffer[i + 2] == 1) {
+ switch (resultBuffer[i + 3]) {
+ case VIDEO_STREAM_S ... VIDEO_STREAM_E:
{
uchar pt = NO_PICTURE;
- int l = ScanVideoPacket(Data, Count, i, pt);
- if (l < 0) {
- if (Skip < Count)
- Count = Skip;
+ int l = ScanVideoPacket(resultBuffer, resultCount, i, pt);
+ if (l < 0)
return NULL; // no useful data found, wait for more
- }
if (pt != NO_PICTURE) {
if (pt < I_FRAME || B_FRAME < pt) {
esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt);
}
- else if (PictureType == NO_PICTURE) {
- if (!synced) {
- if (pt == I_FRAME) {
- Skip = i;
- synced = true;
- }
- else {
- i += l;
- Skip = i;
- break;
- }
+ else if (!synced) {
+ if (pt == I_FRAME) {
+ resultDelivered = i; // will drop everything before this position
+ synced = true;
+ }
+ else {
+ resultDelivered = i + l; // will drop everything before and including this packet
+ return NULL;
}
- if (synced)
- PictureType = pt;
- }
- else {
- Count = i;
- Result = i - Skip;
- return Data + Skip;
}
}
- else if (!synced) {
- i += l;
- Skip = i;
- break;
+ if (synced) {
+ *PictureType = pt;
+ Result = l;
+ const uchar *p = resultBuffer + resultDelivered;
+ resultDelivered += l;
+ return p;
+ }
+ else {
+ resultDelivered = i + l; // will drop everything before and including this packet
+ return NULL;
}
- i += l - 1; // -1 to compensate for i++ in the loop!
}
break;
- case SC_AUDIO:
- i += GetPacketLength(Data, Count, i) - 1; // -1 to compensate for i++ in the loop!
+ case PRIVATE_STREAM1:
+ case AUDIO_STREAM_S ... AUDIO_STREAM_E:
+ {
+ int l = GetPacketLength(resultBuffer, resultCount, i);
+ if (l < 0)
+ return NULL; // no useful data found, wait for more
+ if (synced) {
+ Result = l;
+ const uchar *p = resultBuffer + resultDelivered;
+ resultDelivered += l;
+ return p;
+ }
+ else {
+ resultDelivered = i + l; // will drop everything before and including this packet
+ return NULL;
+ }
+ }
break;
}
}
}
}
- if (Skip < Count)
- Count = Skip;
return NULL; // no useful data found, wait for more
}
-#elif defined(REMUX_TEST)
-#endif
-