From 1c5e9ecedd9b3f63ba9f98729039f35724a83380 Mon Sep 17 00:00:00 2001 From: Guenter Bartsch Date: Sun, 29 Jul 2001 22:21:52 +0000 Subject: ...of course I forgot to add the file itself #-)) CVS patchset: 364 CVS date: 2001/07/29 22:21:52 --- src/demuxers/demux_ts.c | 1054 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1054 insertions(+) create mode 100644 src/demuxers/demux_ts.c diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c new file mode 100644 index 000000000..79d2fed3f --- /dev/null +++ b/src/demuxers/demux_ts.c @@ -0,0 +1,1054 @@ +/* + * Copyright (C) 2000 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: demux_ts.c,v 1.1 2001/07/29 22:21:52 guenter Exp $ + * + * Demultiplexer for MPEG2 Transport Streams. + * + * For the purposes of playing video, we make some assumptions about the + * kinds of TS we have to process. The most important simplification is to + * assume that the TS contains a single program (SPTS) because this then + * allows significant simplifications to be made in processing PATs. + * + * The next simplification is to assume that the program has a reasonable + * number of video, audio and other streams. This allows PMT processing to + * be simplified. + * + * MODIFICATION HISTORY + * + * Date Author + * ---- ------ + * 30-Jul-2001 shaheedhaque Reviewed by: n/a + * PATs and PMTs seem to work. + * + * 29-Jul-2001 shaheedhaque Reviewed by: n/a + * Compiles! + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "xine_internal.h" +#include "monitor.h" +#include "demux.h" + +/* + * The maximum number of PIDs we are prepared to handle in a single program is the + * number that fits in a single-packet PMT. + */ +#define PKT_SIZE 188 +#define BODY_SIZE (188 - 4) +#define MAX_PIDS ((BODY_SIZE - 1 - 13) / 4) + +#define NULL_PID 8191 +#define INVALID_PID ((unsigned int)(-1)) +#define INVALID_PROGRAM ((unsigned int)(-1)) +#define INVALID_CC ((unsigned int)(-1)) + +/* +** +** DATA STRUCTURES +** +*/ + +/* + * Describe a single elementary stream. + */ +typedef struct { + unsigned int pid; + fifo_buffer_t *fifo; + int type; + buf_element_t *buf; + int pes_buf_next; + int pes_len; + unsigned int counter; +} demux_ts_media; + +typedef struct { + /* + * The first field must be the "base class" for the plugin! + */ + demux_plugin_t plugin; + + fifo_buffer_t *fifoAudio; + fifo_buffer_t *fifoVideo; + fifo_buffer_t *fifoSPU; + + input_plugin_t *input; + + pthread_t thread; + + int mnAudioChannel; + int mnSPUChannel; + int status; + + int blockSize; + demux_ts_media media[MAX_PIDS]; + int mSeqHdrSeen; + + /* + * Stuff to do with the transport header. As well as the video + * and audio PIDs, we keep the index of the corresponding entry + * inthe media[] array. + */ + unsigned int programNumber; + unsigned int pmtPid; + unsigned int pcrPid; + unsigned int videoPid; + unsigned int audioPid; + unsigned int videoMedia; + unsigned int audioMedia; +} demux_ts; + +/* +** +** PRIVATE FUNCTIONS +** +*/ +static void *demux_ts_loop( + void *gen_this); +static void demux_ts_pat_parse( + demux_ts *this, + unsigned char *originalPkt, + unsigned char *pkt, + unsigned int pus); +static void demux_ts_pes_buffer( + demux_ts *this, + unsigned char *ts, + unsigned int mediaIndex, + unsigned int pus, + unsigned int cc, + unsigned int len); +static void demux_ts_pes_new( + demux_ts *this, + unsigned int mediaIndex, + unsigned int pid, + fifo_buffer_t *fifo); +static void demux_ts_pmt_parse( + demux_ts *this, + unsigned char *originalPkt, + unsigned char *pkt, + unsigned int pus); +static void demux_ts_parse_ts( + demux_ts *this); +static void demux_ts_queue_pes( + demux_ts *this, + buf_element_t *buf); +static void demux_ts_close( + demux_plugin_t *gen_this); +static char *demux_ts_get_id( + void); +static int demux_ts_get_status( + demux_plugin_t *this_gen); +static int demux_ts_open( + demux_plugin_t *this_gen, + input_plugin_t *input, + int stage); +static void demux_ts_start( + demux_plugin_t *this_gen, + fifo_buffer_t *fifoVideo, + fifo_buffer_t *fifoAudio, + off_t pos, + gui_get_next_mrl_cb_t next_mrl_cb, + gui_branched_cb_t branched_cb); +static void demux_ts_stop( + demux_plugin_t *this_gen); + +/* +** +** DATA +** +*/ +static uint32_t xine_debug; + +/* + * Sit in a loop eating data. + */ +static void *demux_ts_loop( + void *gen_this) +{ + demux_ts *this = (demux_ts *)gen_this; + buf_element_t *buf; + + /* + * TBD: why do we not appear at the beginning of the file? + */ +this->input->seek(this->input, 0, SEEK_SET); +fprintf (stderr, "demux %u demux_ts_loop seeking back to start of file! \n", __LINE__); + this->mSeqHdrSeen = 0; + + do { + demux_ts_parse_ts(this); + } while (this->status == DEMUX_OK) ; + + xprintf(VERBOSE|DEMUX, "demux loop finished (status: %d)\n", this->status); + + this->status = DEMUX_FINISHED; + buf = this->fifoVideo->buffer_pool_alloc(this->fifoVideo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 0; /* stream finished */ + this->fifoVideo->put(this->fifoVideo, buf); + + if (this->fifoAudio) { + buf = this->fifoAudio->buffer_pool_alloc(this->fifoAudio); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 0; /* stream finished */ + this->fifoAudio->put(this->fifoAudio, buf); + } + pthread_exit(NULL); + return NULL; +} + +/* + * NAME demux_ts_pat_parse + * + * Parse a 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 assumed to contain a single program definition, though + * we can cope with the stupidity of SPTSs which contain NITs. + */ +static void demux_ts_pat_parse( + demux_ts *this, + unsigned char *originalPkt, + unsigned char *pkt, + unsigned int pus) +{ + unsigned int length; + unsigned char *program; + unsigned int programNumber; + unsigned int pmtPid; + unsigned int programCount; + + /* + * A PAT in a single section should start with a payload unit start + * indicator set. + */ + if (!pus) { + fprintf (stderr, "demux error! PAT without payload unit start\n"); + return; + } + + /* + * PAT packets with a pus start with a pointer. Skip it! + */ + pkt += pkt[4]; + if (pkt - originalPkt > PKT_SIZE) { + fprintf (stderr, "demux error! PAT with invalid pointer\n"); + return; + } + if (!(pkt[10] & 0x01)) { + /* + * Not current! + */ + return; + } + length = (((unsigned int)pkt[6] & 0x3) << 8) | pkt[7]; + if (pkt - originalPkt > BODY_SIZE - 1 - 3 - (int)length) { + fprintf (stderr, "demux error! PAT with invalid section length\n"); + return; + } + if ((pkt[11]) || (pkt[12])) { + fprintf (stderr, "demux error! PAT with invalid section %02x of %02x\n", pkt[11], pkt[12]); + return; + } + + /* + * TBD: at this point, we should check the CRC. Its not that expensive, and + * the consequences of getting it wrong are dire! + */ + + /* + * Process all programs in the program loop. + */ + programCount = 0; + for (program = pkt + 13; program < pkt + 13 + length - 9; program += 4) { + programNumber = ((unsigned int)program[0] << 8) | program[1]; + + /* + * Skip NITs completely. + */ + if (!programNumber) + continue; + programCount++; + pmtPid = (((unsigned int)program[2] & 0x1f) << 8) | program[3]; + + /* + * If we have yet to learn our program number, then learn it. + */ + if (this->programNumber == INVALID_PROGRAM) { + xprintf(VERBOSE|DEMUX, "acquiring programNumber=%u pmtPid=%04x\n", programNumber, pmtPid); + this->programNumber = programNumber; + this->pmtPid = pmtPid; + } else { + if (this->programNumber != programNumber) { + fprintf(stderr, "demux error! MPTS: programNumber=%u pmtPid=%04x\n", programNumber, pmtPid); + } else { + if (this->pmtPid != pmtPid) { + xprintf(VERBOSE|DEMUX, "pmtPid changed %04x\n", pmtPid); + this->pmtPid = pmtPid; + } + } + } + } +} + +/* + * Manage a buffer for a PES stream. + */ +static void demux_ts_pes_buffer( + demux_ts *this, + unsigned char *ts, + unsigned int mediaIndex, + unsigned int pus, + unsigned int cc, + unsigned int len) +{ + demux_ts_media *m = &this->media[mediaIndex]; + + /* + * By checking the CC here, we avoid the need to check for the no-payload + * case (i.e. adaptation field only) when it does not get bumped. + */ + if (m->counter != INVALID_CC) { + if ((m->counter & 0x0f) != cc) { + fprintf(stderr, "dropped input packet cc = %d expected = %d\n", cc, m->counter); + } + } + m->counter = cc; + m->counter++; + if (pus) { + /* new PES packet */ + if (ts[0] || ts[1] || ts[2] != 1) { + fprintf(stderr, "PUS set but no PES header (corrupt stream?)\n"); + m->buf->free_buffer(m->buf); + m->buf = 0; + return; + } + if (m->buf) { + fprintf(stderr, "PUS set but last PES not complete (corrupt stream?) %d %d\n", + m->pes_buf_next, m->pes_len); + m->buf->free_buffer(m->buf); + m->buf = 0; + return; + + } + + m->pes_len = ((ts[4] << 8) | ts[5]) + 6; + // printf("starting new pes, len = %d\n", m->pes_len); + m->buf = m->fifo->buffer_pool_alloc(m->fifo); + memcpy(m->buf->mem, ts, len); + m->pes_buf_next = len; + } else if (m->buf) { + memcpy(m->buf->mem+m->pes_buf_next, ts, len); + m->pes_buf_next += len; + if (m->pes_buf_next == m->pes_len) { + if (!this->mSeqHdrSeen) { + /* Wait until we have seen a sequence header as + we may have started to listen to a stream in mid-play*/ + + unsigned char *p = m->buf->mem + 4; + + if (p[-1] != 0xe0) { + m->buf->free_buffer(m->buf); + m->buf = 0; + return; + } + + while (p - m->buf->mem < m->pes_len) { + if (p[0] == 0 && p[1] == 0 && p[2] == 1 && p[3] == 0xb3) + break; + else + ++p; + } + if (p - m->buf->mem >= m->pes_len) { + m->buf->free_buffer(m->buf); + m->buf = 0; + return; + } + this->mSeqHdrSeen = 1; + fprintf(stderr, "found sequence header\n"); + // TBD: metronom_start_clock(0); + } + + // printf("Queuing PES - len = %d\n", m->pes_len); + demux_ts_queue_pes(this, m->buf); + m->buf = 0; + } else if (m->pes_buf_next > m->pes_len) { + fprintf(stderr, "too much data read for PES (corrupt stream?)\n"); + m->buf->free_buffer(m->buf); + m->buf = 0; + } + } else { + fprintf(stderr, "nowhere to buffer input (corrupt stream?)\n"); + } +} + +/* + * Create a buffer for a PES stream. + */ +static void demux_ts_pes_new( + demux_ts *this, + unsigned int mediaIndex, + unsigned int pid, + fifo_buffer_t *fifo) +{ + demux_ts_media *m = &this->media[mediaIndex]; + + /* new PID seen - initialise stuff */ + m->pid = pid; + m->fifo = fifo; + m->buf = 0; + m->pes_buf_next = 0; + m->pes_len = 0; + m->counter = INVALID_CC; +} + +/* + * NAME demux_ts_pmt_parse + * + * Parse a PMT. The PMT is expected to be exactly one section long, + * and that section is expected to be contained in a single TS packet. + * + * In other words, the PMT is assumed to describe a reasonable number of + * video, audio and other streams (with descriptors). + */ +static void demux_ts_pmt_parse( + demux_ts *this, + unsigned char *originalPkt, + unsigned char *pkt, + unsigned int pus) +{ + typedef enum + { + ISO_11172_VIDEO = 1, // 1 + ISO_13818_VIDEO = 2, // 2 + ISO_11172_AUDIO = 3, // 3 + ISO_13818_AUDIO = 4, // 4 + ISO_13818_PRIVATE = 5, // 5 + ISO_13818_PES_PRIVATE = 6, // 6 + ISO_13522_MHEG = 7, // 7 + ISO_13818_DSMCC = 8, // 8 + ISO_13818_TYPE_A = 9, // 9 + ISO_13818_TYPE_B = 10, // a + ISO_13818_TYPE_C = 11, // b + ISO_13818_TYPE_D = 12, // c + ISO_13818_TYPE_E = 13, // d + ISO_13818_AUX = 14 + } streamType; + unsigned int length; + unsigned int programInfoLength; + unsigned int codedLength; + unsigned int mediaIndex; + unsigned int pid; + unsigned char *stream; + + /* + * A PMT in a single section should start with a payload unit start + * indicator set. + */ + if (!pus) { + fprintf (stderr, "demux error! PMT without payload unit start\n"); + return; + } + + /* + * PMT packets with a pus start with a pointer. Skip it! + */ + pkt += pkt[4]; + if (pkt - originalPkt > PKT_SIZE) { + fprintf (stderr, "demux error! PMT with invalid pointer\n"); + return; + } + if (!(pkt[10] & 0x01)) { + /* + * Not current! + */ + return; + } + length = (((unsigned int)pkt[6] & 0x3) << 8) | pkt[7]; + if (pkt - originalPkt > BODY_SIZE - 1 - 3 - (int)length) { + fprintf (stderr, "demux error! PMT with invalid section length\n"); + return; + } + if ((pkt[11]) || (pkt[12])) { + fprintf (stderr, "demux error! PMT with invalid section %02x of %02x\n", pkt[11], pkt[12]); + return; + } + + /* + * TBD: at this point, we should check the CRC. Its not that expensive, and + * the consequences of getting it wrong are dire! + */ + + /* + * ES definitions start here...we are going to learn upto one video + * PID and one audio PID. + */ + + programInfoLength = (((unsigned int)pkt[15] & 0x0f) << 8) | pkt[16]; + stream = &pkt[17] + programInfoLength; + codedLength = 13 + programInfoLength; + if (codedLength > length) { + fprintf (stderr, "demux error! PMT with inconsistent progInfo length\n"); + return; + } + length -= codedLength; + + /* + * Extract the elementary streams. + */ + mediaIndex = 0; + while (length > 0) { + unsigned int streamInfoLength; + + pid = (((unsigned int)stream[1] & 0x1f) << 8) | stream[2]; + streamInfoLength = (((unsigned int)stream[3] & 0xf) << 8) | stream[4]; + codedLength = 5 + streamInfoLength; + if (codedLength > length) { + fprintf (stderr, "demux error! PMT with inconsistent streamInfo length\n"); + return; + } + + /* + * Squirrel away the first audio and the first video stream. TBD: there + * should really be a way to select the stream of interest. + */ + switch (stream[0]) { + case ISO_11172_VIDEO: + case ISO_13818_VIDEO: + if (this->videoPid == INVALID_PID) { + xprintf(VERBOSE|DEMUX, "video pid %04x\n", pid); + demux_ts_pes_new(this, mediaIndex, pid, this->fifoVideo); + } + this->videoPid = pid; + this->videoMedia = mediaIndex; + break; + case ISO_11172_AUDIO: + case ISO_13818_AUDIO: + if (this->audioPid == INVALID_PID) { + xprintf(VERBOSE|DEMUX, "audio pid %04x\n", pid); + demux_ts_pes_new(this, mediaIndex, pid, this->fifoAudio); + } + this->audioPid = pid; + this->audioMedia = mediaIndex; + break; + default: + break; + } + mediaIndex++; + stream += codedLength; + length -= codedLength; + } + + /* + * Get the current PCR PID. + */ + pid = (((unsigned int)pkt[13] & 0x1f) << 8) | + pkt[14]; + if (this->pcrPid != pid) { + if (this->pcrPid == INVALID_PID) { + xprintf(VERBOSE|DEMUX, "pcr pid %04x\n", pid); + } else { + xprintf(VERBOSE|DEMUX, "pcr pid changed %04x\n", pid); + } + this->pcrPid = pid; + } +} + +static void demux_ts_parse_ts( + demux_ts *this) +{ + unsigned char originalPkt[PKT_SIZE]; + unsigned int pid; + unsigned int pus; + unsigned int afc; + unsigned int cc; + + /* + * TBD: implement some sync checking WITH recovery. + */ + if (this->input->read(this->input, originalPkt, PKT_SIZE) != PKT_SIZE) { + this->status = DEMUX_FINISHED; + return; + } + + /* + * Discard packets that are obviously bad. + */ + if (originalPkt[0] != 0x47) { + fprintf (stderr, "demux error! invalid ts sync byte %02x\n",originalPkt[0]); + return; + } + if (originalPkt[1] & 0x80) { + fprintf (stderr, "demux error! transport error\n"); + return; + } + + pid = ((originalPkt[1] << 8) | originalPkt[2]) & 0x1fff; + pus = originalPkt[1] & 0x40; + afc = originalPkt[3] & 0x30; + cc = originalPkt[3] & 0x0f; + + if (afc & 0x10) { + unsigned char *pkt; + unsigned len; + + /* + * Has a payload! Calculate & check payload length. + */ + pkt = originalPkt; + if (afc & 0x20) { + /* + * Skip adaptation header. + */ + if (pkt[4]) + pkt += pkt[4]; + pkt++; + } + len = originalPkt + PKT_SIZE - pkt; + if (len > PKT_SIZE) { + fprintf (stderr, "demux error! invalid payload size %d\n",len); + } else { + + /* + * Do the demuxing in descending order of packet frequency! + */ + if (pid == this->videoPid) { + demux_ts_pes_buffer(this, pkt + 4, this->videoMedia, pus, cc, len); + } else if (pid == this->audioPid) { + demux_ts_pes_buffer(this, pkt + 4, this->audioMedia, pus, cc, len); + } else if (pid == this->pmtPid) { + demux_ts_pmt_parse(this, originalPkt, pkt, pus); + } else if (pid == 0) { + demux_ts_pat_parse(this, originalPkt, pkt, pus); + }; + } + } + + /* + * Now check for PCRs. First test for an adaptation header, since + * that is the most likely test to fail. + */ +} + +static void demux_ts_queue_pes( + demux_ts *this, + buf_element_t *buf) +{ + unsigned char *p; + int bMpeg1=0; + uint32_t nHeaderLen; + uint32_t nPTS; + uint32_t nDTS; + uint32_t nPacketLen; + uint32_t nStreamID; + + p = buf->mem; /* len = this->blockSize; */ + + /* we should have a PES packet here */ + + if (p[0] || p[1] || (p[2] != 1)) { + fprintf (stderr, "demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]); + buf->free_buffer(buf); + return ; + } + + nPacketLen = p[4] << 8 | p[5]; + nStreamID = p[3]; + + xprintf(VERBOSE|DEMUX, "packet id = %02x len = %d\n",nStreamID, nPacketLen); + + if (bMpeg1) { + + if (nStreamID == 0xBF) { + buf->free_buffer(buf); + return ; + } + + p += 6; /* nPacketLen -= 6; */ + + while ((p[0] & 0x80) == 0x80) { + p++; + nPacketLen--; + /* printf ("stuffing\n");*/ + } + + if ((p[0] & 0xc0) == 0x40) { + /* STD_buffer_scale, STD_buffer_size */ + p += 2; + nPacketLen -=2; + } + + nPTS = 0; + nDTS = 0; + if ((p[0] & 0xf0) == 0x20) { + nPTS = (p[ 0] & 0x0E) << 29 ; + nPTS |= p[ 1] << 22 ; + nPTS |= (p[ 2] & 0xFE) << 14 ; + nPTS |= p[ 3] << 7 ; + nPTS |= (p[ 4] & 0xFE) >> 1 ; + p += 5; + nPacketLen -=5; + } else if ((p[0] & 0xf0) == 0x30) { + nPTS = (p[ 0] & 0x0E) << 29 ; + nPTS |= p[ 1] << 22 ; + nPTS |= (p[ 2] & 0xFE) << 14 ; + nPTS |= p[ 3] << 7 ; + nPTS |= (p[ 4] & 0xFE) >> 1 ; + nDTS = (p[ 5] & 0x0E) << 29 ; + nDTS |= p[ 6] << 22 ; + nDTS |= (p[ 7] & 0xFE) << 14 ; + nDTS |= p[ 8] << 7 ; + nDTS |= (p[ 9] & 0xFE) >> 1 ; + p += 10; + nPacketLen -= 10; + } else { + p++; + nPacketLen --; + } + + } else { /* mpeg 2 */ + + if (p[7] & 0x80) { /* PTS avail */ + + nPTS = (p[ 9] & 0x0E) << 29 ; + nPTS |= p[10] << 22 ; + nPTS |= (p[11] & 0xFE) << 14 ; + nPTS |= p[12] << 7 ; + nPTS |= (p[13] & 0xFE) >> 1 ; + + } else + nPTS = 0; + + if (p[7] & 0x40) { /* PTS avail */ + + nDTS = (p[14] & 0x0E) << 29 ; + nDTS |= p[15] << 22 ; + nDTS |= (p[16] & 0xFE) << 14 ; + nDTS |= p[17] << 7 ; + nDTS |= (p[18] & 0xFE) >> 1 ; + + } else + nDTS = 0; + + + nHeaderLen = p[8]; + + p += nHeaderLen + 9; + nPacketLen -= nHeaderLen + 3; + } + + xprintf(VERBOSE|DEMUX, "stream_id=%x len=%d pts=%d dts=%d\n", nStreamID, nPacketLen, nPTS, nDTS); + + if (nStreamID == 0xbd) { + + int nTrack,nSPUID; + + nTrack = p[0] & 0x0F; /* hack : ac3 track */ + + if((p[0] & 0xE0) == 0x20) { + nSPUID = (p[0] & 0x1f); + + xprintf(VERBOSE|DEMUX, "SPU PES packet, id 0x%03x\n",p[0] & 0x1f); + + if((this->mnSPUChannel >= 0) + && (this->fifoSPU != NULL) + && (nSPUID == this->mnSPUChannel)) { + buf->content = p+1; + buf->size = nPacketLen-1; + buf->type = BUF_SPU_PACKAGE; + buf->PTS = nPTS; + buf->DTS = nDTS ; + buf->input_pos = this->input->seek(this->input, 0, SEEK_CUR); + + this->fifoSPU->put(this->fifoSPU, buf); + return; + } + } + + if (((p[0]&0xF0) == 0x80) && (nTrack == this->mnAudioChannel)) { + + xprintf(VERBOSE|DEMUX|AC3, "ac3 PES packet, track %02x\n",nTrack); + /* printf ( "ac3 PES packet, track %02x\n",nTrack); */ + + buf->content = p+4; + buf->size = nPacketLen-4; + buf->type = BUF_AUDIO_AC3; + buf->PTS = nPTS; + buf->DTS = nDTS ; + buf->input_pos = this->input->seek(this->input, 0, SEEK_CUR); + + this->fifoAudio->put(this->fifoAudio, buf); + return ; + } else if (((p[0]&0xf0) == 0xa0) || (nTrack == (this->mnAudioChannel-16))) { + + int pcm_offset; + + xprintf(VERBOSE|DEMUX,"LPCMacket, len : %d %02x\n",nPacketLen-4, p[0]); + + /* printf ("PCM!!!!!!!!!!!!!!!!!!!!!!!\n"); */ + + for( pcm_offset=0; ++pcm_offset < nPacketLen-1 ; ){ + if ( p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80 ) { /* START */ + pcm_offset += 2; + break; + } + } + + buf->content = p+pcm_offset; + buf->size = nPacketLen-pcm_offset; + buf->type = BUF_AUDIO_LPCM; + buf->PTS = nPTS; + buf->DTS = nDTS ; + buf->input_pos = this->input->seek(this->input, 0, SEEK_CUR); + + this->fifoAudio->put(this->fifoAudio, buf); + return ; + } + + } else if ((nStreamID >= 0xbc) && ((nStreamID & 0xf0) == 0xe0)) { + + xprintf(VERBOSE|DEMUX, "video %d\n", nStreamID); + + buf->content = p; + buf->size = nPacketLen; + buf->type = BUF_VIDEO_MPEG; + buf->PTS = nPTS; + buf->DTS = nDTS; + + this->fifoVideo->put(this->fifoVideo, buf); + return ; + + } else if ((nStreamID & 0xe0) == 0xc0) { + int nTrack; + + nTrack = nStreamID & 0x1f; + + xprintf(VERBOSE|DEMUX|MPEG, "mpg audio #%d", nTrack); + + if ((bMpeg1 && (nTrack == this->mnAudioChannel)) + || (!bMpeg1 && (nTrack == (this->mnAudioChannel-8)))) { + + buf->content = p; + buf->size = nPacketLen; + buf->type = BUF_AUDIO_MPEG; + buf->PTS = nPTS; + buf->DTS = nDTS; + buf->input_pos = this->input->seek(this->input, 0, SEEK_CUR); + + this->fifoAudio->put(this->fifoAudio, buf); + return ; + } + + } else { + xprintf(VERBOSE | DEMUX, "unknown packet, id = %x\n",nStreamID); + } + + buf->free_buffer(buf); + return ; +} + +static void demux_ts_close( + demux_plugin_t *gen_this) +{ + /* nothing */ +} + +static char *demux_ts_get_id( + void) +{ + return "MPEG_TS"; +} + +static int demux_ts_get_status( + demux_plugin_t *this_gen) +{ + demux_ts *this = (demux_ts *)this_gen; + return this->status; +} + +static int demux_ts_open( + demux_plugin_t *this_gen, + input_plugin_t *input, + int stage) +{ + demux_ts *this = (demux_ts *) this_gen; + char *mrl; + char *media; + char *ending; + + switch (stage) { + case STAGE_BY_EXTENSION: + mrl = input->get_mrl(input); + media = strstr(mrl, "://"); + if (media) { +fprintf (stderr, "demux %u ts_open! \n", __LINE__); + if ((!(strncasecmp(mrl, "stdin", 5))) || (!(strncasecmp(mrl, "fifo", 4)))) { + if(!(strncasecmp(media+3, "ts", 3))) { + break; + } + return DEMUX_CANNOT_HANDLE; + } + else if (strncasecmp(mrl, "file", 4)) { + return DEMUX_CANNOT_HANDLE; + } + } + ending = strrchr(mrl, '.'); + if (ending) { + xprintf(VERBOSE|DEMUX, "demux_ts_open: ending %s of %s\n", ending, mrl); + if ((!strcasecmp(ending, ".m2t")) || (!strcasecmp(ending, ".ts"))) { + break; + } + } + return DEMUX_CANNOT_HANDLE; + default: + return DEMUX_CANNOT_HANDLE; + } + + this->input = input; + this->blockSize = PKT_SIZE; + return DEMUX_CAN_HANDLE; +} + +static void demux_ts_start( + demux_plugin_t *this_gen, + fifo_buffer_t *fifoVideo, + fifo_buffer_t *fifoAudio, + off_t pos, + gui_get_next_mrl_cb_t next_mrl_cb, + gui_branched_cb_t branched_cb) +{ + demux_ts *this = (demux_ts *)this_gen; + buf_element_t *buf; + + this->fifoVideo = fifoVideo; + this->fifoAudio = fifoAudio; + + /* + * Send reset buffer. + */ + buf = this->fifoVideo->buffer_pool_alloc(this->fifoVideo); + buf->type = BUF_CONTROL_START; + this->fifoVideo->put(this->fifoVideo, buf); + if (this->fifoAudio) { + buf = this->fifoAudio->buffer_pool_alloc(this->fifoAudio); + buf->type = BUF_CONTROL_START; + this->fifoAudio->put(this->fifoAudio, buf); + } + + this->status = DEMUX_OK ; + if (this->input->get_blocksize(this->input)) + this->blockSize = this->input->get_blocksize(this->input); + pos /= (off_t)this->blockSize; + pos *= (off_t)this->blockSize; + + /* + * Now start demuxing. + */ + pthread_create(&this->thread, NULL, demux_ts_loop, this); +} + +static void demux_ts_stop( + demux_plugin_t *this_gen) +{ + demux_ts *this = (demux_ts *)this_gen; + void *p; + buf_element_t *buf; + + printf ("demux_ts: stop...\n"); + + if (this->status != DEMUX_OK) { + + this->fifoVideo->clear(this->fifoVideo); + if(this->fifoAudio) + this->fifoAudio->clear(this->fifoAudio); + return; + } + + this->status = DEMUX_FINISHED; + + pthread_join (this->thread, &p); + + this->fifoVideo->clear(this->fifoVideo); + if(this->fifoAudio) + this->fifoAudio->clear(this->fifoAudio); + + buf = this->fifoVideo->buffer_pool_alloc (this->fifoVideo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 1; /* forced */ + this->fifoVideo->put (this->fifoVideo, buf); + + if (this->fifoAudio) { + buf = this->fifoAudio->buffer_pool_alloc (this->fifoAudio); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 1; /* forced */ + this->fifoAudio->put (this->fifoAudio, buf); + } +} + +demux_plugin_t *init_demuxer_plugin( + int iface, + config_values_t *config) +{ + demux_ts *this; + int i; + + if (iface != 2) { + printf( + "demux_ts: plugin doesn't support plugin API version %d.\n" + "demux_ts: this means there's a version mismatch between xine and this " + "demux_ts: demuxer plugin.\nInstalling current input plugins should help.\n", + iface); + return NULL; + } + + /* + * Initialise the generic plugin. + */ + this = xmalloc(sizeof(*this)); + xine_debug = config->lookup_int(config, "xine_debug", 0); + this->plugin.interface_version = DEMUXER_PLUGIN_IFACE_VERSION; + this->plugin.open = demux_ts_open; + this->plugin.start = demux_ts_start; + this->plugin.stop = demux_ts_stop; + this->plugin.close = demux_ts_close; + this->plugin.get_status = demux_ts_get_status; + this->plugin.get_identifier = demux_ts_get_id; + + /* + * Initialise our specialised data. + */ + this->mnSPUChannel = -1; /* Turn off SPU by default */ + for (i = 0; i < MAX_PIDS; i++) + this->media[i].pid = INVALID_PID; + this->programNumber = INVALID_PROGRAM; + this->pmtPid = INVALID_PID; + this->pcrPid = INVALID_PID; + this->videoPid = INVALID_PID; + this->audioPid = INVALID_PID; + return (demux_plugin_t *)this; +} -- cgit v1.2.3