diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2001-03-31 08:42:27 +0200 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2001-03-31 08:42:27 +0200 |
commit | 5c68fc100c87bf677932852fbcd446199c03fecb (patch) | |
tree | d8257dcf6457b0f38124606fb0419912ffc71bfc /remux.c | |
parent | 191fb910bf8f908266dd512a9c649cc906cb72d0 (diff) | |
download | vdr-5c68fc100c87bf677932852fbcd446199c03fecb.tar.gz vdr-5c68fc100c87bf677932852fbcd446199c03fecb.tar.bz2 |
Redesigned the ring buffer; prepared for remultiplexing
Diffstat (limited to 'remux.c')
-rw-r--r-- | remux.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/remux.c b/remux.c new file mode 100644 index 00000000..e48296d8 --- /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 + |