view libmpdemux/demux_ts.c @ 9894:3933e0ef000c

10l noticed by Joey Parrish <joey at nicewarrior.org>
author faust3
date Wed, 09 Apr 2003 18:55:49 +0000
parents 872b8d422a05
children 01a9af06319a
line wrap: on
line source

/*
 * Copyright (C) 2000-2002 the xine project
 *
 * This file is part of xine, a free 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$
 *
 * 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.



 /* 
 * WARNING: Quite a hack was required in order to get files by MultiDec played back correctly.
 * If it breaks anything else, just comment out the "#define DEMUX_PVA_MULTIDEC_HACK" below
 * and it will not be compiled in.
 *
 * Feedback is appreciated.
 *
 * written by Matteo Giani
 */
 
 
/*
 * MPEG2 transport stream (aka DVB) demux
 * Copyright (c) 2002 Fabrice Bellard.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "config.h"
#include "mp_msg.h"
#include "help_mp.h"

#include "stream.h"
#include "demuxer.h"
#include "stheader.h"

#include "bswap.h"


typedef struct {
	off_t offset;
	long size;
	uint8_t type;
	uint8_t is_packet_start;
	float pts;
	uint8_t packet_size;
} ts_payload_t;


typedef struct {
	float last_audio_pts;
	float last_video_pts;
	uint8_t just_synced;
	uint8_t synced_stream_id;
	char *buffer;		
	int buffer_size;
	int buffer_offset;
	int packet_size;
} ts_priv_t;

#define TS_FEC_PACKET_SIZE 204
#define TS_PACKET_SIZE 188
#define NB_PID_MAX 8192
    
#define MAX_HEADER_SIZE 6			/* enough for PES header + length */
#define MAX_PROBE_SIZE	1000000
#define NUM_CONSECUTIVE_TS_PACKETS 5


enum MpegTSState {
    MPEGTS_HEADER = 0,
    MPEGTS_PESHEADER_FILL,
    MPEGTS_PESHEADER_FLAGS,
    MPEGTS_PESHEADER_SIZE,
    MPEGTS_PESHEADER_READ,
    MPEGTS_PAYLOAD,
    MPEGTS_SKIP,
};


int ts_fastparse = 0;

typedef enum  
{
	UNKNOWN		= -1,
	VIDEO_MPEG2 	= 0x10000002,
	AUDIO_MP2   	= 0x50,
	AUDIO_A52   	= 0x2000,
	AUDIO_LPCM_BE  	= 0x2000000,
	SPU_DVD		= 0x3000000,
	SPU_DVB		= 0x3000001,
} es_stream_type_t;    

typedef struct MpegTSStream 		// IT'S AN ES
{
    int pid;
    enum MpegTSState state;
    int last_cc; /* last cc code (-1 if first packet) */
    /* used to get the format */
    int header_size;
    int payload_size;
    int pes_header_size;
    //AVStream *st;
    es_stream_type_t type;    
    unsigned char header[MAX_HEADER_SIZE];
    char *pes_buffer;
    int offset;
    float pts;
    float last_pts;
} MpegTSStream;


typedef struct MpegTSContext {
    int raw_packet_size; 	/* raw packet size, including FEC if present */
    MpegTSStream *pids[NB_PID_MAX];
    demuxer_t *demuxer;
} MpegTSContext;


typedef struct {
    int size;
    unsigned char *start;
    es_stream_type_t type;    
    float pts;
    int pid;
} ES_info_t;

MpegTSContext ts;

//FILE *outfile;


static uint8_t get_packet_size(const unsigned char *buf, int size)
{
    int i;

    if (size < (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS))
        return 0;
	
    for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) 
    {
        if (buf[i * TS_PACKET_SIZE] != 0x47)
	{
	    mp_msg(MSGT_DEMUX, MSGL_DBG2, "GET_PACKET_SIZE, pos %d, char: %2x\n", i, buf[i * TS_PACKET_SIZE]);	
            goto try_fec;
	}
    }
    return TS_PACKET_SIZE;
    
 try_fec:
    for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) 
    {
        if (buf[i * TS_FEC_PACKET_SIZE] != 0x47)
            return 0;
    }
    return TS_FEC_PACKET_SIZE;
}




int ts_check_file(demuxer_t * demuxer)
{
	const int buf_size = (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS);
	char buf[buf_size], c, done = 0;
	uint32_t _read, i=1;
	uint8_t size = 0;
	off_t pos = 0;
	
	mp_msg(MSGT_DEMUX, MSGL_V, "************Checking for TS************\n");
	
	while(! done)
	{	
	    while(((c=stream_read_char(demuxer->stream)) != 0x47) 
		&& (i < MAX_PROBE_SIZE)
		&& ! demuxer->stream->eof
		) i++; 
	    
	    if(c != 0x47)
	    {
		mp_msg(MSGT_DEMUX, MSGL_V, "NOT A TS FILE1\n");
		done = 1;
		continue;
	    }
	
	    pos = stream_tell(demuxer->stream) - 1;
	    buf[0] = c;
	    _read = stream_read(demuxer->stream, &buf[1], buf_size-1);
	
	    if(_read < buf_size-1)
	    {
		mp_msg(MSGT_DEMUX, MSGL_V, "COULDN'T READ ENOUGH DATA, EXITING TS_CHECK\n");
		stream_reset(demuxer->stream);
		return 0;
	    }
	    
	    size = get_packet_size(buf, buf_size);
	    if(size)
		done = 1;
	}
	
	mp_msg(MSGT_DEMUX, MSGL_V, "TRIED UP TO POSITION %u, FUOND %x, packet_size= %d\n", i, c, size);
	stream_seek(demuxer->stream, pos);
	return size;
}





demuxer_t *demux_open_ts(demuxer_t * demuxer)
{
	uint8_t packet_size;
	//demuxer_t *vd, *ad;
	//stream_t *s;
	sh_video_t *sh_video;
	sh_audio_t *sh_audio;
	ts_priv_t * priv;
	int i;
	
	
	mp_msg(MSGT_DEMUX, MSGL_V, "DEMUX OPEN, AUDIO_ID: %d, VIDEO_ID: %d, SUBTITLE_ID: %d,\n", 
	    demuxer->audio->id, demuxer->video->id, demuxer->sub->id);
	
	for(i=0; i < 8192; i++)
	    ts.pids[i] = NULL;
	
	demuxer->type= DEMUXER_TYPE_MPEG_TS;
	
	stream_reset(demuxer->stream);
	stream_seek(demuxer->stream, 0);
	
	packet_size = ts_check_file(demuxer);
	if(!packet_size)
	    return NULL;
	
	priv = malloc(sizeof(ts_priv_t));
	priv->last_video_pts=-1;
    	priv->last_audio_pts=-1;
	priv->packet_size = packet_size;
	demuxer->priv = priv;
	
	if(demuxer->stream->type != STREAMTYPE_FILE) demuxer->seekable=0;
	else demuxer->seekable = 1;
		
	
	sh_video = new_sh_video(demuxer, 0);
	sh_video->ds = demuxer->video;
	demuxer->video->sh = sh_video;
	
        
	
	sh_audio = new_sh_audio(demuxer, 0);		
	sh_audio->ds = demuxer->audio;
	demuxer->audio->sh = sh_audio;
	
	
	mp_msg(MSGT_DEMUXER,MSGL_INFO, "Opened TS demuxer...");

	if(! ts_fastparse)	
	    ts_detect_streams(demuxer);
	
	
	/*
	demuxer->movi_start = 0;
	demuxer->movi_end = demuxer->stream->end_pos;
	*/
	    
	
	/*    
	s= new_ds_stream(demuxer->video);
	return demux_open_stream(s, DEMUXER_TYPE_MPEG_ES, demuxer->audio->id, demuxer->video->id, demuxer->sub->id, NULL); 
	*/
	
	stream_seek(demuxer->stream, 0);		//IF IT'S FROM A PIPE IT WILL FAIL, BUT WHO CARES?
	return demuxer;	
}



void ts_detect_streams(demuxer_t *demuxer)
{
	int video_found = 0, audio_found = 0;
	off_t pos=0;
	ES_info_t es;
	int *apid, *vpid, *spid;
	unsigned char tmp[TS_FEC_PACKET_SIZE];
	sh_video_t *sh_video = demuxer->video->sh;
	sh_audio_t *sh_audio = demuxer->audio->sh;
	
	apid = &(demuxer->audio->id);
	vpid = &(demuxer->video->id);
	spid = &(demuxer->sub->id);
	
	
	mp_msg(MSGT_DEMUXER, MSGL_INFO, "PROBING UP TO %u\n", MAX_PROBE_SIZE);
	while(pos <= MAX_PROBE_SIZE)
	{
	    if(ts_parse(demuxer, &es, tmp))
	    {
		mp_msg(MSGT_DEMUXER, MSGL_V, "TYPE: %x, PID: %d\n", es.type, es.pid);
		if(es.type == VIDEO_MPEG2)
		{
		    sh_video->format = VIDEO_MPEG2;	//MPEG2 video
		    if(*vpid == -1)
			*vpid = es.pid;
		    video_found = 1;
		}
		    
		if(es.type == AUDIO_MP2)
		{
		    sh_audio->format = AUDIO_MP2;	//MPEG1L2 audio
		    if(*apid == -1)
			*apid = es.pid;
		    audio_found = 1;
		}
		    
		if(es.type == AUDIO_A52)
		{
		    sh_audio->format = AUDIO_A52;	//AC3 audio
		    if(*apid == -1)
			*apid = es.pid;
		    audio_found = 1;
		}
		
		pos = stream_tell(demuxer->stream);
		if(video_found && audio_found)
		    break;
	    }
	}
	
	if(video_found)
	    mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG2...");
	else
	{
	    *vpid = -2;		//WE DIDN'T MATCH ANY VIDEO STREAM, SO WE FORCE THE DEMUXER TO IGNORE VIDEO
	    mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO VIDEO!\n");
	}
	    
	if(sh_audio->format == AUDIO_MP2)
	    mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO MP2\n");
	else if(sh_audio->format == AUDIO_A52)
	    mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO A52\n");
	else    
	{
	    *apid = -2;		//WE DIDN'T MATCH ANY AUDIO STREAM, SO WE FORCE THE DEMUXER TO IGNORE AUDIO
	    mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO AUDIO!\n");
	}
}


void demux_close_ts(demuxer_t * demuxer)
{
	if(demuxer->priv)
	{
		free(demuxer->priv);
		demuxer->priv=NULL;
	}
}
			



//MpegTSStream *tss,  const unsigned char *buf, int buf_size, int is_start, ES_info_t *es
static int pes_parse2(MpegTSStream *tss, unsigned char *buf, uint16_t packet_len, int is_start, ES_info_t *es) 
{
    unsigned char *p;
    uint32_t       header_len;
    int64_t        pts;
    uint32_t       stream_id;
    uint32_t       pkt_len;

    mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2(%X, %X, %d, %d, ): \n", tss, buf, packet_len, is_start);

    if(packet_len == 0)
    {
	mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2(,PACKET_LEN = 0, EXIT\n");
        return 0;
    }
    
    if(packet_len > 184)
    {
	mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2, BUFFER LEN IS TOO BIG: %d, EXIT\n", packet_len);
        return 0;
    }
    
    
    p = buf;
    pkt_len = packet_len;

    if(! is_start)
    {
	tss->pts = tss->last_pts;
	es->start = p;
	es->size = packet_len;
	return es->size;
    }
  
    /* we should have a PES packet here */

    if (p[0] || p[1] || (p[2] != 1)) 
    {
        mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: error HEADER %02x %02x %02x (should be 0x000001) \n", p[0], p[1], p[2]);
	return 0 ;
    }

    packet_len -= 6;
  
    tss->payload_size = p[4] << 8 | p[5];
    if (tss->payload_size == 0)
        tss->payload_size = 65536;
		
    stream_id  = p[3];

    if(packet_len==0)
	return 0;

  //mp_msg(MSGT_DEMUX, MSGL_V, "pes_parse2: packet stream id: %.2X (%d) len: %d (%x)\n", stream_id, stream_id, packet_len, packet_len);

    if (p[7] & 0x80) 
    { /* pts avail */
	pts  = (int64_t)(p[9] & 0x0E) << 29 ;
	pts |=  p[10]         << 22 ;
	pts |= (p[11] & 0xFE) << 14 ;
	pts |=  p[12]         <<  7 ;
	pts |= (p[13] & 0xFE) >>  1 ;
    
	tss->pts = tss->last_pts = pts / 90000.0f;
    } 
    else
	tss->pts = tss->last_pts;

    header_len = p[8];

    /* sometimes corruption on header_len causes segfault in memcpy below */
    if (header_len + 9 > pkt_len) 
    {
	mp_msg(MSGT_DEMUX, MSGL_DBG2, "demux_ts: illegal value for PES_header_data_length (0x%02x)\n", header_len);
	return 0;
    }

    p += header_len + 9;
    packet_len -= header_len + 3;

    if (stream_id == 0xbd) 
    {
	int track, spu_id;
    
	mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: audio buf = %02X %02X %02X %02X %02X %02X %02X %02X\n",
	    p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
    
	track = p[0] & 0x0F; /* hack : ac3 track */
	/*
        * we check the descriptor tag first because some stations
        * do not include any of the ac3 header info in their audio tracks
        * these "raw" streams may begin with a byte that looks like a stream type.
        */
	if(		//(m->descriptor_tag == 0x81) ||    /* ac3 - raw */ 
    	    (p[0] == 0x0B && p[1] == 0x77))   /* ac3 - syncword */
	{ 						
    	    es->start = p;
    	    es->size = packet_len;
    	    tss->type = AUDIO_A52;
    	    return es->size;
	} 
	else if (//m->descriptor_tag == 0x06 && 
	    p[0] == 0x20 && p[1] == 0x00) 
	{
    	    /* DVBSUB */
    	    long payload_len = ((buf[4] << 8) | buf[5]) - header_len - 3;
    	    es->start = p;
    	    es->size  = packet_len;
    	    tss->type = SPU_DVB + payload_len;
      
    	    return es->size;
	} 
	else if ((p[0] & 0xE0) == 0x20) 
	{
    	    spu_id      = (p[0] & 0x1f);
            es->start   = p+1;
    	    es->size    = packet_len-1;
    	    tss->type   = SPU_DVD + spu_id;
    	    return es->size;
	} 
	else if ((p[0] & 0xF0) == 0x80) 
	{
    	    es->start   = p+4;
    	    es->size    = packet_len - 4;
    	    tss->type   = AUDIO_A52; // + track;
    	    return es->size;
	} 
	else if ((p[0]&0xf0) == 0xa0) 
	{
    	    int pcm_offset;

    	    for (pcm_offset=0; ++pcm_offset < packet_len-1 ; )
    	    {
    		if (p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80) 
		{ 	/* START */
        	    pcm_offset += 2;
        	    break;
    		}
    	    }

    	    es->start   = p + pcm_offset;
    	    es->size    = packet_len - pcm_offset;
    	    tss->type   = AUDIO_LPCM_BE; // + track;
    	    return es->size;
	}
    } 
    else if ((stream_id >= 0xbc) && ((stream_id & 0xf0) == 0xe0)) 
    {
	es->start   = p;
	es->size    = packet_len;
	tss->type   = VIDEO_MPEG2;
	return es->size;
    } 
    else if ((stream_id & 0xe0) == 0xc0) 
    {
	int track;
	track 	    = stream_id & 0x1f;
	es->start   = p;
	es->size    = packet_len;
	tss->type   = AUDIO_MP2; // + track;
	return es->size;
    } 
    else 
    {
	mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: unknown packet, id: %x\n", stream_id);
    }

    return 0;
}




int ts_sync(demuxer_t *demuxer)
{
    uint8_t c=0;
    
    mp_msg(MSGT_DEMUX, MSGL_DBG2, "TS_SYNC \n");
    
    while(((c=stream_read_char(demuxer->stream)) != 0x47) && ! demuxer->stream->eof);
    
    if(c == 0x47)
	return c;
    else
	return 0;
}






// 0 = EOF or no stream found
// 1 = successfully read a packet
int ts_parse(demuxer_t * demuxer , ES_info_t *es, unsigned char *packet)
{
    MpegTSStream *tss;
    uint8_t done = 0;
    ts_priv_t *priv = demuxer->priv;
    uint16_t buf_size, is_start; 
    int len, pid, cc, cc_ok, afc;
    unsigned char *p;
    
    while(! done)
    {
	if(! ts_sync(demuxer))
	{	
	    mp_msg(MSGT_DEMUX, MSGL_V, "TS_FILL_BUFFER: COULDN'T SYNC\n");        
	    return 0;
        }
	
	len = stream_read(demuxer->stream, &packet[1], priv->packet_size-1);
        if (len != priv->packet_size-1)
            return 0;
        
	
	
        pid = ((packet[1] & 0x1f) << 8) | packet[2];
	tss = ts.pids[pid];	//an ES stream
        if(tss == NULL) 
	{
            /* if no pid found, then add a pid context */
	    tss = malloc(sizeof(MpegTSStream));
	    if (!tss)
    		continue;
	    memset(tss, 0, sizeof(MpegTSStream));
            ts.pids[pid] = tss;
            tss->pid = pid;
            tss->last_cc = -1;
	    tss->type = UNKNOWN;
            mp_msg(MSGT_DEMUX, MSGL_DBG2, "new TS pid=%u\n", pid);
        }
	
	cc = (packet[3] & 0xf);
        cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc));
	if(! cc_ok)
	{
	    mp_msg(MSGT_DEMUX, MSGL_V, "ts_parse: CCCheck NOT OK: %d -> %d\n", tss->last_cc, cc);	
	}
        tss->last_cc = cc;        
    
	
        
        /* skip adaptation field */
        afc = (packet[3] >> 4) & 3;
        p = packet + 4;
        if (afc == 0) /* reserved value */
            continue;
        if (afc == 2) /* adaptation field only */
            continue;
        if (afc == 3) 
	{
            /* skip adapation field */
            p += p[0] + 1;
        }
        /* if past the end of packet, ignore */
        if (p >= packet + TS_PACKET_SIZE)
            continue;
    
	// PES CONTENT STARTS HERE
	
	buf_size = TS_PACKET_SIZE - (p - packet);
	
	is_start = packet[1] & 0x40;
	if((len = pes_parse2(tss, p, buf_size, is_start, es)))
	{
	    tss->offset += es->size;
	    es->pid = tss->pid;
	    es->pts = tss->pts;
	    es->type = tss->type;
            
	    mp_msg(MSGT_DEMUX, MSGL_DBG2, "ts_parse, type=%X, start=%X, len=%d\n", tss->type, es->start, es->size);
	
	    return len;
	}    
    }
    
    return 0;
}


int demux_ts_fill_buffer(demuxer_t * demuxer)
{
    ES_info_t es;
    demux_packet_t *dp;
    int len;
    unsigned char packet[TS_FEC_PACKET_SIZE];
    int *apid, *vpid, *spid;
    
    apid = &(demuxer->audio->id);
    vpid = &(demuxer->video->id);
    spid = &(demuxer->sub->id);
    
    while(len = ts_parse(demuxer, &es, packet))
    {
	    mp_msg(MSGT_DEMUX, MSGL_V, "NEW_FILL_BUFFER, NEW_ADD_PACKET(%x, %d) type: %x, PTS: %f\n", es.start, es.size, es.type, es.pts);    
	
	    if(es.type == VIDEO_MPEG2)
	    {
		if(ts_fastparse)
		{
		    if(*vpid == -2)
			continue;
		    
		    if(*vpid == -1)
			*vpid = es.pid;
		}
		    
		if(*vpid != es.pid)
	    	    continue;
	
		dp = new_demux_packet(es.size);
		if(! dp || ! dp->buffer)
		{
	    	    fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d) FAILED\n", es.size);    
	    	    continue;
		}		
		memcpy(dp->buffer, es.start, es.size); 
		dp->pts = es.pts;
		dp->flags = 0;
		dp->pos = stream_tell(demuxer->stream);
		ds_add_packet(demuxer->video, dp);
		mp_msg(MSGT_DEMUX, MSGL_V, "VIDEO pts=%f\n", es.pts);
		return len;
	    }
	
	    if((es.type == AUDIO_MP2) || (es.type == AUDIO_A52))
	    {
		if(ts_fastparse)
		{
		    if(*apid == -2)
			continue;
		    
		    if(*apid == -1)
	    		*apid = es.pid;
		}
		        
		if(*apid != es.pid)
	    	    continue;
		    
		dp = new_demux_packet(es.size);
		if(! dp || ! dp->buffer)
		{
	    	    fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d) FAILED\n", es.size);    
	    	    continue;
		}
		memcpy(dp->buffer, es.start, es.size);    
		dp->flags = 0;
		dp->pts = es.pts;
		dp->pos = stream_tell(demuxer->stream);
		ds_add_packet(demuxer->audio, dp);    
		mp_msg(MSGT_DEMUX, MSGL_V, "AUDIO pts=%f\r\n", es.pts);
		return len;
	    }
	
	    mp_msg(MSGT_DEMUX, MSGL_V, "SKIP--------\n");    
    }
}




int stringent_ts_sync(demuxer_t *demuxer)
{
    ts_priv_t *priv = demuxer->priv;
    uint8_t c = 0, done = 0, i, buf[TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS];
    off_t pos;
    
    mp_msg(MSGT_DEMUX, MSGL_DBG2, "STRINGENT_TS_SYNC packet_size: %d\n", priv->packet_size);
    
    
    if(! demuxer->seekable)
	return 0;
    
	
    while(! done)
    {   
	while(((c=stream_read_char(demuxer->stream)) != 0x47) && !demuxer->stream->eof);
	
	if(c != 0x47)
	{
	    stream_reset(demuxer->stream);
	    return 0;
	}
	    
	pos = stream_tell(demuxer->stream);
	if(pos < 1)
	    pos = 1;
	mp_msg(MSGT_DEMUX, MSGL_DBG2, "dopo il while, pos=%u\n", pos);
	    
	done = 1;
	buf[0] = c;
	stream_read(demuxer->stream, &buf[1], (priv->packet_size * NUM_CONSECUTIVE_TS_PACKETS) - 1);	
	for(i = 0; i < 5; i++)
	{	
	    if (buf[i * priv->packet_size] != 0x47)
        	done = 0;
	    mp_msg(MSGT_DEMUX, MSGL_DBG2, "i: %d, char:  %x\n", i, buf[i * priv->packet_size]);	
	}
	
	if(done)
	    stream_seek(demuxer->stream, pos); 
	else
	    stream_seek(demuxer->stream, pos); 
    }
    //stream_seek(demuxer->stream, pos+1); 
    mp_msg(MSGT_DEMUX, MSGL_DBG2, "STRINGENT_TS_SYNC, STREAM_POS: %lu\n", stream_tell(demuxer->stream));	
    return 0x47;
}


extern void resync_audio_stream(sh_audio_t *);


int demux_seek_ts(demuxer_t * demuxer, float rel_seek_secs, int flags)
{
	int total_bitrate=0;
	off_t dest_offset;
	ts_priv_t * priv = demuxer->priv;
	int a_bps, v_bps;
	demux_stream_t *d_audio=demuxer->audio;
	demux_stream_t *d_video=demuxer->video;
	sh_audio_t *sh_audio=d_audio->sh;
	sh_video_t *sh_video=d_video->sh;


	/*
	 * Compute absolute offset inside the stream. Approximate total bitrate with sum of bitrates
	 * reported by the audio and video codecs. The seek is not accurate because, just like
	 * with MPEG streams, the bitrate is not constant. Moreover, we do not take into account
	 * the overhead caused by PVA and PES headers.
	 * If the calculated absolute offset is negative, seek to the beginning of the file.
	 */

	
	if(demuxer->audio->id != -2)
	{
	    a_bps = ((sh_audio_t *)demuxer->audio->sh)->i_bps;
	    total_bitrate += a_bps;
	}
	
	if(demuxer->video->id != -2)	
	{
	    v_bps = ((sh_video_t *)demuxer->video->sh)->i_bps;
	    total_bitrate += v_bps;
	}
	
	if(! total_bitrate)	
	{
	    mp_msg(MSGT_DEMUX, MSGL_V, "SEEK_TS, couldn't determine bitrate, no seek\n");
	    return 0;
	}
	
	dest_offset = stream_tell(demuxer->stream) + rel_seek_secs*total_bitrate;
	if(dest_offset < 0) dest_offset = 0;
	
	mp_msg(MSGT_DEMUX, MSGL_V, "SEEK TO: %f, BITRATE: %lu, FINAL_POS: %u \n", rel_seek_secs, total_bitrate, dest_offset);
	
	stream_seek(demuxer->stream, dest_offset);

	/*if(!ts_sync(demuxer))
	{
		mp_msg(MSGT_DEMUX, MSGL_V, "demux_ts: Couldn't seek!\n");
		return 0;
	}
	*/
	
	ds_fill_buffer(d_video);
	if(sh_audio)
	{
	  ds_fill_buffer(d_audio);
	  resync_audio_stream(sh_audio);
	}

	
	/*
	 * Reset the PTS info inside the ts_priv_t structure. This way we don't deliver
	 * data with the wrong PTSs (the ones we had before seeking).
	 *
	 */
	
	
	priv->last_video_pts=-1;
	priv->last_audio_pts=-1;
	
	return 1;
}





static int mpegts_read_close(MpegTSContext *ts)
{
    int i;
    for(i=0;i<NB_PID_MAX;i++)
        free(ts->pids[i]);
    return 0;
}