diff options
Diffstat (limited to 'src/demuxers/demux_ts.c')
-rw-r--r-- | src/demuxers/demux_ts.c | 270 |
1 files changed, 115 insertions, 155 deletions
diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c index 38eca0bbb..ef1a7a6ea 100644 --- a/src/demuxers/demux_ts.c +++ b/src/demuxers/demux_ts.c @@ -146,6 +146,13 @@ #include <fcntl.h> #include <unistd.h> #include <string.h> +#include <arpa/inet.h> + +#ifdef HAVE_FFMPEG_AVUTIL_H +# include <crc.h> +#else +# include <libavutil/crc.h> +#endif #define LOG_MODULE "demux_ts" #define LOG_VERBOSE @@ -153,9 +160,9 @@ #define LOG */ -#include "xine_internal.h" -#include "xineutils.h" -#include "demux.h" +#include <xine/xine_internal.h> +#include <xine/xineutils.h> +#include <xine/demux.h> /* #define TS_LOG @@ -174,7 +181,10 @@ #define BODY_SIZE (188 - 4) /* more PIDS are needed due "auto-detection". 40 spare media entries */ #define MAX_PIDS ((BODY_SIZE - 1 - 13) / 4) + 40 -#define MAX_PMTS ((BODY_SIZE - 1 - 13) / 4) + 10 + +#define MAX_PMTS 128 +#define PAT_BUF_SIZE (4 * MAX_PMTS + 20) + #define SYNC_BYTE 0x47 #define MIN_SYNCS 3 @@ -319,6 +329,18 @@ typedef struct { } demux_ts_audio_track; typedef struct { + + demux_class_t demux_class; + + /* class-wide, global variables here */ + + xine_t *xine; + config_values_t *config; + + const AVCRC *av_crc; +} demux_ts_class_t; + +typedef struct { /* * The first field must be the "base class" for the plugin! */ @@ -334,17 +356,22 @@ typedef struct { input_plugin_t *input; unsigned int read_retries; + demux_ts_class_t *class; + int status; int hdmv; /* -1 = unknown, 0 = mpeg-ts, 1 = hdmv/m2ts */ int pkt_size; /* TS packet size */ int pkt_offset; /* TS packet offset */ + int blockSize; int rate; unsigned int media_num; demux_ts_media media[MAX_PIDS]; /* PAT */ + uint8_t pat[PAT_BUF_SIZE]; + int pat_write_pos; uint32_t last_pat_crc; uint32_t transport_stream_id; /* programs */ @@ -352,7 +379,6 @@ typedef struct { uint32_t pmt_pid[MAX_PMTS]; uint8_t *pmt[MAX_PMTS]; uint8_t *pmt_write_ptr[MAX_PMTS]; - uint32_t crc32_table[256]; uint32_t last_pmt_crc; /* * Stuff to do with the transport header. As well as the video @@ -402,15 +428,6 @@ typedef struct { } demux_ts_t; -typedef struct { - - demux_class_t demux_class; - - /* class-wide, global variables here */ - - xine_t *xine; - config_values_t *config; -} demux_ts_class_t; static void reset_track_map(fifo_buffer_t *fifo) { @@ -443,7 +460,7 @@ static int demux_ts_dynamic_pmt_find (demux_ts_t *this, if (i < MAX_PIDS) { /* prepare new media descriptor */ #ifdef LOG_DYNAMIC_PMT - char *name = ""; + const char *name = ""; if (type == BUF_VIDEO_BASE) name = "video"; else if (type == BUF_AUDIO_BASE) name = "audio"; else if (type == BUF_SPU_BASE) name = "subtitle"; @@ -523,7 +540,7 @@ static void demux_ts_dynamic_pmt_clean (demux_ts_t *this) { } else { /* drop this no longer needed media descriptor */ #ifdef LOG_DYNAMIC_PMT - char *name = ""; + const char *name = ""; if (type == BUF_VIDEO_BASE) name = "video"; else if (type == BUF_AUDIO_BASE) name = "audio"; else if (type == BUF_SPU_BASE) name = "subtitle"; @@ -611,28 +628,6 @@ static void demux_ts_tbre_update (demux_ts_t *this, unsigned int mode, int64_t n this->tbre_lasttime = now; } -static void demux_ts_build_crc32_table(demux_ts_t*this) { - uint32_t i, j, k; - - for( i = 0 ; i < 256 ; i++ ) { - k = 0; - for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) { - k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); - } - this->crc32_table[i] = k; - } -} - -static uint32_t demux_ts_compute_crc32(demux_ts_t*this, uint8_t *data, - int32_t length, uint32_t crc32) { - int32_t i; - - for(i = 0; i < length; i++) { - crc32 = (crc32 << 8) ^ this->crc32_table[(crc32 >> 24) ^ data[i]]; - } - return crc32; -} - /* redefine abs as macro to handle 64-bit diffs. i guess llabs may not be available everywhere */ #define abs(x) ( ((x)<0) ? -(x) : (x) ) @@ -808,14 +803,12 @@ static void demux_ts_flush(demux_ts_t *this) * demux_ts_parse_pat * * Parse a program association table (PAT). - * The PAT is expected to be exactly one section long, - * and that section is expected to be contained in a single TS packet. + * The PAT is expected to be exactly one section long. * - * The PAT is assumed to contain a single program definition, though - * we can cope with the stupidity of SPTSs which contain NITs. + * We can cope with the stupidity of SPTSs which contain NITs. */ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, - unsigned char *pkt, unsigned int pusi) { + unsigned char *pkt, unsigned int pusi, int len) { #ifdef TS_PAT_LOG uint32_t table_id; uint32_t version_number; @@ -834,47 +827,67 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, unsigned int pmt_pid; unsigned int program_count; - /* - * A PAT in a single section should start with a payload unit start - * indicator set. - */ - if (!pusi) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: demux error! PAT without payload unit start indicator\n"); - return; + /* reassemble the section */ + if (pusi) { + this->pat_write_pos = 0; + /* offset the section by n + 1 bytes. this is sometimes used to let it end + at an exact TS packet boundary */ + len -= (unsigned int)pkt[0] + 1; + pkt += (unsigned int)pkt[0] + 1; + if (len < 1) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_ts: demux error! PAT with invalid pointer\n"); + return; + } + } else { + if (!this->pat_write_pos) + return; } + if (len > PAT_BUF_SIZE - this->pat_write_pos) + len = PAT_BUF_SIZE - this->pat_write_pos; + memcpy (this->pat + this->pat_write_pos, pkt, len); + this->pat_write_pos +=len; - /* - * sections start with a pointer. Skip it! - */ - pkt += pkt[4]; - if (pkt - original_pkt > PKT_SIZE) { + /* lets see if we got the section length already */ + pkt = this->pat; + if (this->pat_write_pos < 3) + return; + section_length = ((((uint32_t)pkt[1] << 8) | pkt[2]) & 0x03ff) + 3; + /* this should be at least the head plus crc */ + if (section_length < 8 + 4) { + this->pat_write_pos = 0; + return; + } + /* and it should fit into buf */ + if (section_length > PAT_BUF_SIZE) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: demux error! PAT with invalid pointer\n"); + "demux_ts: PAT too large (%d bytes)\n", section_length); + this->pat_write_pos = 0; return; } + + /* lets see if we got the section complete */ + if (this->pat_write_pos < section_length) + return; + + /* OK now parse it */ + this->pat_write_pos = 0; #ifdef TS_PAT_LOG - table_id = (unsigned int)pkt[5] ; + table_id = (unsigned int)pkt[0]; #endif - section_syntax_indicator = (((unsigned int)pkt[6] >> 7) & 1) ; - section_length = (((unsigned int)pkt[6] & 0x03) << 8) | pkt[7]; - transport_stream_id = ((uint32_t)pkt[8] << 8) | pkt[9]; + section_syntax_indicator = (pkt[1] >> 7) & 0x01; + transport_stream_id = ((uint32_t)pkt[3] << 8) | pkt[4]; #ifdef TS_PAT_LOG - version_number = ((uint32_t)pkt[10] >> 1) & 0x1f; + version_number = ((uint32_t)pkt[5] >> 1) & 0x1f; #endif - current_next_indicator = ((uint32_t)pkt[10] & 0x01); - section_number = (uint32_t)pkt[11]; - last_section_number = (uint32_t)pkt[12]; - crc32 = (uint32_t)pkt[4+section_length] << 24; - crc32 |= (uint32_t)pkt[5+section_length] << 16; - crc32 |= (uint32_t)pkt[6+section_length] << 8; - crc32 |= (uint32_t)pkt[7+section_length] ; + current_next_indicator = pkt[5] & 0x01; + section_number = pkt[6]; + last_section_number = pkt[7]; #ifdef TS_PAT_LOG printf ("demux_ts: PAT table_id: %.2x\n", table_id); printf (" section_syntax: %d\n", section_syntax_indicator); - printf (" section_length: %d (%#.3x)\n", - section_length, section_length); + printf (" section_length: %d (%#.3x)\n", section_length, section_length); printf (" transport_stream_id: %#.4x\n", transport_stream_id); printf (" version_number: %d\n", version_number); printf (" c/n indicator: %d\n", current_next_indicator); @@ -882,25 +895,22 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, printf (" last_section_number: %d\n", last_section_number); #endif - if ((section_syntax_indicator != 1) || !(current_next_indicator)) { - return; - } - - if (pkt - original_pkt > BODY_SIZE - 1 - 3 - section_length) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: FIXME: (unsupported )PAT spans multiple TS packets\n"); + if ((section_syntax_indicator != 1) || !current_next_indicator) return; - } if ((section_number != 0) || (last_section_number != 0)) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ts: FIXME: (unsupported) PAT consists of multiple (%d) sections\n", last_section_number); + "demux_ts: FIXME (unsupported) PAT consists of multiple (%d) sections\n", last_section_number); return; } /* Check CRC. */ - calc_crc32 = demux_ts_compute_crc32 (this, pkt+5, section_length+3-4, - 0xffffffff); + crc32 = (uint32_t) pkt[section_length - 4] << 24; + crc32 |= (uint32_t) pkt[section_length - 3] << 16; + crc32 |= (uint32_t) pkt[section_length - 2] << 8; + crc32 |= (uint32_t) pkt[section_length - 1]; + + calc_crc32 = htonl (av_crc (this->class->av_crc, 0xffffffff, pkt, section_length - 4)); if (crc32 != calc_crc32) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: demux error! PAT with invalid CRC32: packet_crc32: %.8x calc_crc32: %.8x\n", @@ -931,8 +941,8 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt, * Process all programs in the program loop. */ program_count = 0; - for (program = pkt + 13; - (program < pkt + 13 + section_length - 9) && (program_count < MAX_PMTS); + for (program = pkt + 8; + (program < pkt + section_length - 4) && (program_count < MAX_PMTS); program += 4) { program_number = ((unsigned int)program[0] << 8) | program[1]; pmt_pid = (((unsigned int)program[2] & 0x1f) << 8) | program[3]; @@ -1434,7 +1444,7 @@ static void demux_ts_parse_pmt (demux_ts_t *this, unsigned char *stream; unsigned int i; int count; - char *ptr = NULL; + uint8_t *ptr = NULL; unsigned char len; unsigned int offset=0; int mi; @@ -1555,9 +1565,9 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num crc32 |= (uint32_t) this->pmt[program_count][section_length+3-1] ; /* Check CRC. */ - calc_crc32 = demux_ts_compute_crc32 (this, - this->pmt[program_count], - section_length+3-4, 0xffffffff); + calc_crc32 = htonl(av_crc(this->class->av_crc, 0xffffffff, + this->pmt[program_count], section_length+3-4)); + if (crc32 != calc_crc32) { xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_ts: demux error! PMT with invalid CRC32: packet_crc32: %#.8x calc_crc32: %#.8x\n", @@ -2238,8 +2248,8 @@ static void demux_ts_parse_packet (demux_ts_t*this) { /* PAT */ if (pid == 0) { - demux_ts_parse_pat(this, originalPkt, originalPkt+data_offset-4, - payload_unit_start_indicator); + demux_ts_parse_pat(this, originalPkt, originalPkt + data_offset, + payload_unit_start_indicator, PKT_SIZE - data_offset); return; } @@ -2421,8 +2431,6 @@ static void demux_ts_send_headers (demux_plugin_t *this_gen) { this->send_newpts = 1; - demux_ts_build_crc32_table (this); - this->status = DEMUX_OK ; this->scrambled_npids = 0; @@ -2613,39 +2621,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, } break; - case METHOD_BY_EXTENSION: { - const char *const mrl = input->get_mrl (input); - - if (_x_demux_check_extension (mrl, "m2ts mts")) - hdmv = 1; - else - hdmv = 0; - - /* check extension */ - const char *const extensions = class_gen->get_extensions (class_gen); - - if (_x_demux_check_extension (mrl, extensions)) - break; - - /* accept dvb streams */ - /* - * Also handle the special dvbs,dvbt and dvbc mrl formats: - * the content is exactly the same but the input plugin - * uses a different tuning algorithm [Pragma] - */ - - if (!strncasecmp (mrl, "dvb://", 6)) - break; - if (!strncasecmp (mrl, "dvbs://", 7)) - break; - if (!strncasecmp (mrl, "dvbc://", 7)) - break; - if (!strncasecmp (mrl, "dvbt://", 7)) - break; - - return NULL; - } - + case METHOD_BY_MRL: case METHOD_EXPLICIT: break; @@ -2660,6 +2636,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, this = calloc(1, sizeof(*this)); this->stream = stream; this->input = input; + this->class = (demux_ts_class_t*)class_gen; this->demux_plugin.send_headers = demux_ts_send_headers; this->demux_plugin.send_chunk = demux_ts_send_chunk; @@ -2720,30 +2697,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, /* * ts demuxer class */ - -static const char *get_description (demux_class_t *this_gen) { - return "MPEG Transport Stream demuxer"; -} - -static const char *get_identifier (demux_class_t *this_gen) { - return "MPEG_TS"; -} - -static const char *get_extensions (demux_class_t *this_gen) { - return "ts m2t trp m2ts mts"; -} - -static const char *get_mimetypes (demux_class_t *this_gen) { - return "video/mp2t: m2t: MPEG2 transport stream;"; -} - -static void class_dispose (demux_class_t *this_gen) { - - demux_ts_class_t *this = (demux_ts_class_t *) this_gen; - - free (this); -} - static void *init_class (xine_t *xine, void *data) { demux_ts_class_t *this; @@ -2753,11 +2706,18 @@ static void *init_class (xine_t *xine, void *data) { this->xine = xine; this->demux_class.open_plugin = open_plugin; - this->demux_class.get_description = get_description; - this->demux_class.get_identifier = get_identifier; - this->demux_class.get_mimetypes = get_mimetypes; - this->demux_class.get_extensions = get_extensions; - this->demux_class.dispose = class_dispose; + this->demux_class.description = N_("MPEG Transport Stream demuxer"); + this->demux_class.identifier = "MPEG_TS"; + this->demux_class.mimetypes = "video/mp2t: m2t: MPEG2 transport stream;"; + + /* accept dvb streams; also handle the special dvbs,dvbt and dvbc + * mrl formats: the content is exactly the same but the input plugin + * uses a different tuning algorithm [Pragma] + */ + this->demux_class.extensions = "ts m2t trp m2ts mts dvb:// dvbs:// dvbc:// dvbt://"; + this->demux_class.dispose = default_demux_class_dispose; + + this->av_crc = av_crc_get_table(AV_CRC_32_IEEE); return this; } @@ -2772,7 +2732,7 @@ static const demuxer_info_t demux_info_ts = { const plugin_info_t xine_plugin_info[] EXPORTED = { /* type, API, "name", version, special_info, init_function */ - { PLUGIN_DEMUX, 26, "mpeg-ts", XINE_VERSION_CODE, &demux_info_ts, init_class }, + { PLUGIN_DEMUX, 27, "mpeg-ts", XINE_VERSION_CODE, &demux_info_ts, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; |