summaryrefslogtreecommitdiff
path: root/remux.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-04-01 18:00:00 +0200
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-04-01 18:00:00 +0200
commit610c5600df98b35226536ffe92b1fd231128c7d4 (patch)
treef0df8ce83dd3e4829be7def61126871f425e2f23 /remux.c
parentf2937af95ceaf3a52c327e96571367ef5475b3a1 (diff)
downloadvdr-patch-lnbsharing-610c5600df98b35226536ffe92b1fd231128c7d4.tar.gz
vdr-patch-lnbsharing-610c5600df98b35226536ffe92b1fd231128c7d4.tar.bz2
Version 0.72vdr-0.72
- Fixed SVDRP commands LSTC and LSTT to make them return an error message if no channels or timers are defined. - Enhanced 'channels.conf.cable' (thanks to Hans-Peter Raschke). - Fixed switching to another channel via the EPG while a recording is being replayed. - Fixed a memory leak in the EIT processor that happened when the system time was set. - Removed some redundant code from the cListBase destructor. - Fixed internationalization of some Main menu texts. - Updated 'channels.conf' after the recent changes of Premiere World (thanks to Axel Gruber). - Redesigned the ring buffer to make it work with two separate threads for input and output (also prepared for using a remultiplexer). - Fixed setting system time from transponders. - Fixed a segfault in the Schedule menu in case there is no EPG information. - The 'runvdr' script now kills any leftover vdr threads before restarting it. - Fixed a problem with Daylight Saving Time when displaying the times of recordings. - Added Dutch language texts (thanks to Arnold Niessen). - The new command line option -t can be used to set the controlling terminal (thanks to Jürgen Sauer). This is especially useful when starting VDR through an entry in /etc/inittab (see INSTALL). - Since the CAM module only works if it is installed in the "highest" DVB card, recordings now search for a free DVB card from lowest to highest index (as opposed to the previous "highest to lowest" search) in order to not use the CAM card for FTA recordings unless necessary. This is only important for systems with three or more DVB cards. - Added the "statdvb2vdr" tool from Hans-Peter Raschke. - Fixed a segfault that sometimes happened when killing VDR. - VDR now returns an exit status of '2' in case of an error at startup, instead of terminating with 'abort()' (which caused a core dump). - SVDRP now also works with clients that don't do line buffering (like the Windows 'telnet'). - Empty lines in config files no longer cause error messages. - New SVDRP command LSTE to list the EPG data. - The SVDRP HELP command now prints the topics in several columns.
Diffstat (limited to 'remux.c')
-rw-r--r--remux.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/remux.c b/remux.c
new file mode 100644
index 0000000..e48296d
--- /dev/null
+++ b/remux.c
@@ -0,0 +1,173 @@
+/*
+ * remux.c: A streaming MPEG2 remultiplexer
+ *
+ * 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 calling interface of the 'cRemux::Process()' function is defined
+ as follows:
+
+ 'Data' points to a chunk of data that consists of 'Count' bytes.
+ The 'Process' function shall try to remultiplex as much of the
+ data as possible and return a pointer to the resulting buffer.
+ That buffer typically is different from the incoming 'Data',
+ but in the simplest case (when 'Process' does nothing) might
+ as well point to the original 'Data'. When returning, 'Count'
+ shall be set to the number of bytes that have been processed
+ (i.e. have been taken from 'Data'), while 'Result' indicates
+ how many bytes the returned buffer contains. 'PictureType' shall
+ be set to NO_PICTURE if the returned data does not start a new
+ picture, or one of I_FRAME, P_FRAME or B_FRAME if a new picture
+ starting point has been found. This also means that the returned
+ data buffer may contain at most one entire video frame, because
+ the next frame must be returned with its own value for 'PictureType'.
+
+ 'Process' shall do it's best to keep the latency time as short
+ as possible in order to allow a quick start of VDR's "Transfer
+ mode" (displaying the signal of one DVB card on another card).
+ In order to do that, this function may decide to first pass
+ through the incoming data (almost) unprocessed, and make
+ actual processing kick in after a few seconds (if that is at
+ all possible for the algorithm). This may result in a non-
+ optimal stream at the beginning, which won't matter for normal
+ recordings but may make switching through encrypted channels
+ in "Transfer mode" faster.
+
+ In the resulting data stream, a new packet shall always be started
+ when a frame border is encountered. VDR needs this in order to
+ be able to detect and store the frame indexes, and to easily
+ display single frames in fast forward/back mode. The very first
+ data block returned shall be the starting point of an I_FRAME.
+ Everything before that shall be silently dropped.
+
+ If the incoming data is not enough to do remultiplexing, a value
+ of NULL shall be returned ('Result' has no meaning then). This
+ will tell the caller to wait for more data to be presented in
+ the next call. If NULL is returned and 'Count' is not 0, the
+ caller shall remove 'Count' bytes from the beginning of 'Data'
+ before the next call. This is the way 'Process' indicates that
+ it must skip that data.
+
+ Any data that is not used during this call will appear at the
+ beginning of the incoming 'Data' buffer at the next call, plus
+ any new data that has become available.
+
+ It is guaranteed that the caller will completely process any
+ returned data before the next call to 'Process'. That way, 'Process'
+ can dynamically allocate its return buffer and be sure the caller
+ doesn't keep any pointers into that buffer.
+*/
+
+#include "remux.h"
+#include "tools.h"
+
+#if defined(REMUX_NONE)
+
+cRemux::cRemux(void)
+{
+ synced = false;
+}
+
+cRemux::~cRemux()
+{
+}
+
+int cRemux::GetPacketLength(const uchar *Data, int Count, int Offset)
+{
+ // Returns the entire length of the packet starting at offset, or -1 in case of error.
+ return (Offset + 5 < Count) ? (Data[Offset + 4] << 8) + Data[Offset + 5] + 6 : -1;
+}
+
+int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType)
+{
+ // Scans the video packet starting at Offset and returns its length.
+ // If the return value is -1 the packet was not completely in the buffer.
+
+ int Length = GetPacketLength(Data, Count, Offset);
+ if (Length > 0 && Offset + Length <= Count) {
+ int i = Offset + 8; // the minimum length of the video packet header
+ i += Data[i] + 1; // possible additional header bytes
+ for (; i < Offset + Length; i++) {
+ if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) {
+ switch (Data[i + 3]) {
+ case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07;
+ return Length;
+ }
+ }
+ }
+ PictureType = NO_PICTURE;
+ return Length;
+ }
+ return -1;
+}
+
+const uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar &PictureType)
+{
+ int Skip = 0;
+
+ PictureType = NO_PICTURE;
+
+ 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:
+ {
+ uchar pt = NO_PICTURE;
+ int l = ScanVideoPacket(Data, Count, i, pt);
+ if (l < 0) {
+ if (Skip < Count)
+ Count = Skip;
+ 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;
+ }
+ }
+ if (synced)
+ PictureType = pt;
+ }
+ else {
+ Count = i;
+ Result = i - Skip;
+ return Data + Skip;
+ }
+ }
+ else if (!synced) {
+ i += l;
+ Skip = i;
+ break;
+ }
+ 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!
+ break;
+ }
+ }
+ }
+ }
+ if (Skip < Count)
+ Count = Skip;
+ return NULL; // no useful data found, wait for more
+}
+
+#elif defined(REMUX_TEST)
+#endif
+