MPEG-2 Frame Aligner

From LinuxTVWiki
Jump to navigation Jump to search

Introduction

Most hardware does not provides aligned MPEG-2 data streams, also the linux-dvb API's DVR device can get out of sync if the MPEG-2 TS data stream is interrupted, e.g. due to DMA buffer overflows or if the demod delivers partial packets in case of uncorrectable block errors.

MPEG-2 TS packets can be 188 (without FEC data) or 204 bytes long (including 16 FEC bytes).

Algorithm

The MPEG-2 Frame Aligner can get implemented as simple state machine, whenever we are in an "out-of-sync"-state we check all followig bytes until we encounter a MPEG-2 TS Sync Byte (0x47). From then on we check every 188 or 204 bytes if the next 0x47-sync-byte is present. If so the packet is passed to the PID filter

Sample Code

The following sample code works for 188-byte packets. This code is taken from the LinuxDVB kernel driver (originally written by Florian Schirmer) and thus GPL'd.

A more generic and robust version based on a state machine should not be too hard to implement and would be able to synchronize both 188- and 204-byte-packets. Please let us know when you feel in the mood to implement+test this, we'll be happy to help whereever possible.

struct framealigner {
        char tsbuf[188];
        int tsbufp;
};


void framealigner_process_ts_data (struct framealigner *fa,
                                   const char *buf,
                                   unsigned int count)
{
        unsigned int p = 0, i, j;

        if ((i = fa->tsbufp)) {
                if (count < (j=188-i)) {
                        memcpy(&fa->tsbuf[i], buf, count);
                        fa->tsbufp += count;
                        return;
                }
                memcpy(&fa->tsbuf[i], buf, j);
                pidfilter_ts_packet(fa->tsbuf);
                fa->tsbufp = 0;
                p += j;
        }

        while (p < count) {
                if (buf[p] == 0x47) {
                        if (count-p >= 188) {
                                pidfilter_process_ts_packet(buf+p);
                                p += 188;
                        } else {
                                i = count - p;
                                memcpy(fa->tsbuf, buf+p, i);
                                fa->tsbufp = i;
                                return;
                        }
                } else
                        p++;
        }
}