PID Filter - Demultiplexer
From LinuxTVWiki
m (fixed links) |
|||
| (8 intermediate revisions not shown) | |||
| Line 1: | Line 1: | ||
== Introduction == | == Introduction == | ||
| - | A raw [[ | + | 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 == | == PID Filter Algorithm == | ||
| Line 10: | Line 10: | ||
== PID Filter Sample Code (the easy way) == | == 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). <tt>pid_is_enabled()</tt> 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: | ||
<tt> | <tt> | ||
| + | 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 | static inline | ||
unsigned short ts_pid (const unsigned char *ts_packet) | unsigned short ts_pid (const unsigned char *ts_packet) | ||
| Line 20: | Line 56: | ||
static | static | ||
| - | void | + | void pidfilter_process_ts_packet (const unsigned char ts_packet[188]) |
{ | { | ||
unsigned short pid = ts_pid(ts_packet); | unsigned short pid = ts_pid(ts_packet); | ||
| Line 34: | Line 70: | ||
<tt> | <tt> | ||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
| - | |||
static | static | ||
| - | void | + | void pidfilter_process_ts_packet (const unsigned char ts_packet[188]) |
{ | { | ||
unsigned short pid = ts_pid(ts_packet); | unsigned short pid = ts_pid(ts_packet); | ||
| Line 60: | Line 89: | ||
* | * | ||
* In any case no scrambled packets should arrive in the demux, | * In any case no scrambled packets should arrive in the demux, | ||
| - | * CSA descramblers are located before this stage of the pipeline. | + | * CSA descramblers are located before this stage of the pipeline, |
| + | * so simply discard this garbage... | ||
*/ | */ | ||
scrambling_control = (ts_packet[3] >> 6) & 0x03; | scrambling_control = (ts_packet[3] >> 6) & 0x03; | ||
if (scrambling_control != 0) | if (scrambling_control != 0) | ||
| - | return | + | return; |
if (pid_is_enabled(pid)) | if (pid_is_enabled(pid)) | ||
| Line 71: | Line 101: | ||
} | } | ||
</tt> | </tt> | ||
| + | |||
| + | == 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. | ||
| + | |||
| + | [[Category:Technology]] | ||
Latest revision as of 22:11, 6 January 2008
Contents |
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.