PID Filter - Demultiplexer

From LinuxTVWiki
Jump to navigation Jump to search

Introduction

A raw MPEG-2 Transport Stream consists data of all the services transmitted on a particular transponder. The task on the receiver side is to filter out the interesting packets and schedule them to their target decoders: Audio packets to the audio-decoder, video packets to the video decoder, subtitle packets to the subtitle decoder etc...

MPEG-2 TS packets are identified by the Packet ID, the PID. This is a 13-bit number located in the 2nd and 3rd byte of a TS packet.

PID Filter Algorithm

The algorithm is easy: we simply check the 13 PID bits and look whether this PID is enabled in our PID filter list.

PID Filter Sample Code (the easy way)

This implementation uses a trivial PID table of 2^13 (=8192) bits where every bit is set to '1' if this particular PID is enabled and cleared to '0' if the PID is disabled. The entire table has a size of 8kbit (1kByte). pid_is_enabled() simply tests if the bit on position '<pid>' is set.

You can also organize you filters in a linked list and traverse this every time, but you don't need to do it that complicated unless you really want...

Here the code:

static unsigned char pid_table [1024] = { 0 };


static inline
void enable_pid (unsigned short pid)
{
        unsigned int index = pid / 8;
        unsigned int bit = pid % 8;
        pid_table[index] |= 1 << bit;
}


static inline
void disable_pid (unsigned short pid)
{
        unsigned int index = pid / 8;
        unsigned int bit = pid % 8;
        pid_table[index] &= ~(1 << bit);
}


static inline
int pid_is_enabled (unsigned short pid)
{
        unsigned int index = pid / 8;
        unsigned int bit = pid % 8;
        return (pid_table[index] & (1 << bit)) ? 1 : 0;
}


static inline
unsigned short ts_pid (const unsigned char *ts_packet)
{
        return ((ts_packet[1] & 0x1f) << 8) + ts_packet[2];
}


static
void pidfilter_process_ts_packet (const unsigned char ts_packet[188])
{
        unsigned short pid = ts_pid(ts_packet);

        if (pid_is_enabled(pid))
               pass_packet_to_decoder(ts_packet);
}

PID Filter Sample Code (with sanity checks)

This slightly extended version of the above code contains additional sanity checks that have been useful in the past:

static
void pidfilter_process_ts_packet (const unsigned char ts_packet[188])
{
        unsigned short pid = ts_pid(ts_packet);
        unsigned char scrambling_control;

        /**
         *  check TS error indicator bit and discard broken packets...
         */
        if (ts_packet[1] & 0x80) {
                bad_packet_counter++;
                return;
        }

        /**
         *  this makes no sense - however, some transponders like to send
         *  packets with scrambling bits set which contain gaga data (??).
         *
         *  In any case no scrambled packets should arrive in the demux,
         *  CSA descramblers are located before this stage of the pipeline,
         *  so simply discard this garbage...
         */
        scrambling_control = (ts_packet[3] >> 6) & 0x03;

        if (scrambling_control != 0)
                return;

        if (pid_is_enabled(pid))
               pass_packet_to_decoder(ts_packet);
}

Section Filtering

Most DVB Hardware decoders provide so called Section Filters, these allow to specify which MPEG and DVB section tables we want to receive in a particular queue.

But in practice these tables are organized in a way that we want to update our clock, EPG state and DSM-CC caroussels continously and enable all section filters on a particular PID in most cases. So it's questionable whether it makes sense to implement a similiar solution in future designs, simple PID filtering is usually sufficient.

The MPEG table decoder receives now all tables of an enabled PID, these are usually related anyways.