diff -Naur MPlayer-0.90rc4/libmpdemux/demuxer.c MPlayer-0.90rc4-ts/libmpdemux/demuxer.c --- MPlayer-0.90rc4/libmpdemux/demuxer.c 2003-01-28 01:12:23.000000000 +0100 +++ MPlayer-0.90rc4-ts/libmpdemux/demuxer.c 2003-02-17 21:19:28.000000000 +0100 @@ -134,6 +134,7 @@ extern void demux_close_smjpeg(demuxer_t* demuxer); extern void demux_close_xmms(demuxer_t* demuxer); extern void demux_close_gif(demuxer_t* demuxer); +extern void demux_close_ts(demuxer_t* demuxer); #ifdef USE_TV #include "tv.h" @@ -204,6 +205,8 @@ case DEMUXER_TYPE_GIF: demux_close_gif(demuxer); break; #endif + case DEMUXER_TYPE_MPEG_TS: + demux_close_ts(demuxer); break; } // free streams: @@ -282,6 +285,7 @@ int demux_pva_fill_buffer(demuxer_t *demux); int demux_xmms_fill_buffer(demuxer_t *demux,demux_stream_t *ds); int demux_gif_fill_buffer(demuxer_t *demux); +int demux_ts_fill_buffer(demuxer_t *demux); extern int demux_demuxers_fill_buffer(demuxer_t *demux,demux_stream_t *ds); extern int demux_ogg_fill_buffer(demuxer_t *d); @@ -334,6 +338,7 @@ #ifdef HAVE_GIF case DEMUXER_TYPE_GIF: return demux_gif_fill_buffer(demux); #endif + case DEMUXER_TYPE_MPEG_TS: return demux_ts_fill_buffer(demux); } return 0; } @@ -560,6 +565,7 @@ extern int demux_xmms_open(demuxer_t* demuxer); extern int gif_check_file(demuxer_t *demuxer); extern int demux_open_gif(demuxer_t* demuxer); +extern int ts_check_file(demuxer_t * demuxer); extern demuxer_t* init_avi_with_ogg(demuxer_t* demuxer); @@ -817,6 +823,17 @@ demuxer=NULL; } } +//=============== Try to open as MPEG-TS file: ================= +if(file_format == DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_TS){ + demuxer=new_demuxer(stream,DEMUXER_TYPE_MPEG_TS,audio_id,video_id,dvdsub_id); + if(ts_check_file(demuxer)) { + mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_Detected_XXX_FileFormat,"TS"); + file_format=DEMUXER_TYPE_MPEG_TS; + } else { + free_demuxer(demuxer); + demuxer=NULL; + } +} //=============== Try to open as MPEG-PS file: ================= if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_PS){ int pes=1; @@ -1127,6 +1144,10 @@ break; } #endif + case DEMUXER_TYPE_MPEG_TS: { + demux_open_ts(demuxer); + break; + } } // switch(file_format) pts_from_bps=0; // !!! return demuxer; @@ -1195,6 +1216,7 @@ void demux_seek_mov(demuxer_t *demuxer,float pts,int flags); int demux_seek_real(demuxer_t *demuxer,float rel_seek_secs,int flags); int demux_seek_pva(demuxer_t *demuxer,float rel_seek_secs,int flags); +int demux_seek_ts(demuxer_t *demuxer,float rel_seek_secs,int flags); #ifdef HAVE_LIBDV095 int demux_seek_rawdv(demuxer_t *demuxer, float pts, int flags); @@ -1294,7 +1316,8 @@ case DEMUXER_TYPE_XMMS: demux_xmms_seek(demuxer,rel_seek_secs,flags); break; #endif - + case DEMUXER_TYPE_MPEG_TS: + demux_seek_ts(demuxer,rel_seek_secs,flags); break; } // switch(demuxer->file_format) diff -Naur MPlayer-0.90rc4/libmpdemux/demuxer.h MPlayer-0.90rc4-ts/libmpdemux/demuxer.h --- MPlayer-0.90rc4/libmpdemux/demuxer.h 2003-01-28 01:12:23.000000000 +0100 +++ MPlayer-0.90rc4-ts/libmpdemux/demuxer.h 2003-02-17 21:14:14.000000000 +0100 @@ -37,11 +37,12 @@ #define DEMUXER_TYPE_RAWVIDEO 26 #define DEMUXER_TYPE_MPEG4_ES 27 #define DEMUXER_TYPE_GIF 28 +#define DEMUXER_TYPE_MPEG_TS 29 // This should always match the higest demuxer type number. // Unless you want to disallow users to force the demuxer to some types #define DEMUXER_TYPE_MIN 0 -#define DEMUXER_TYPE_MAX 28 +#define DEMUXER_TYPE_MAX 29 #define DEMUXER_TYPE_DEMUXERS (1<<16) // A virtual demuxer type for the network code diff -Naur MPlayer-0.90rc4/libmpdemux/demux_ts.c MPlayer-0.90rc4-ts/libmpdemux/demux_ts.c --- MPlayer-0.90rc4/libmpdemux/demux_ts.c 1970-01-01 01:00:00.000000000 +0100 +++ MPlayer-0.90rc4-ts/libmpdemux/demux_ts.c 2003-02-17 22:22:51.000000000 +0100 @@ -0,0 +1,517 @@ + + /* + * 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 +#include +#include + +#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 + +enum MpegTSState { + MPEGTS_HEADER = 0, + MPEGTS_PESHEADER_FILL, + MPEGTS_PESHEADER_FLAGS, + MPEGTS_PESHEADER_SIZE, + MPEGTS_PESHEADER_READ, + MPEGTS_PAYLOAD, + MPEGTS_SKIP, +}; + +/* enough for PES header + length */ +#define MAX_HEADER_SIZE 6 + +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; + enum { + VIDEO = 0, + AUDIO + } type; + unsigned char header[MAX_HEADER_SIZE]; + char *pes_buffer; + int offset; + float 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; + + + + +static int get_packet_size(const unsigned char *buf, int size) +{ + int i; + + if (size < (TS_FEC_PACKET_SIZE * 5 + 1)) + return -1; + + for(i=0; i<5; i++) + { + if (buf[i * TS_PACKET_SIZE] != 0x47) + goto try_fec; + } + return TS_PACKET_SIZE; + + try_fec: + for(i=0;i<5;i++) + { + if (buf[i * TS_FEC_PACKET_SIZE] != 0x47) + return -1; + } + return TS_FEC_PACKET_SIZE; +} + + + +int ts_check_file(demuxer_t * demuxer) +{ + int buf_size = TS_FEC_PACKET_SIZE * 5 + 1; + char buf[buf_size]; + int _read, size; + char *buf2 = ((ts_priv_t*)demuxer->priv)->buffer; //da usare al posto di buf perche' senno' ci perdiamo i byte + + mp_msg(MSGT_DEMUX, MSGL_V, "*************Checking for TS************\n"); + + _read = stream_read(demuxer->stream, buf, buf_size); + stream_seek(demuxer->stream, 0); + if(_read < buf_size) + { + mp_msg(MSGT_DEMUX, MSGL_V, "NOT A TS FILE\n"); + return 0; + } + + size = get_packet_size(buf, buf_size); + if (size < 0) + return 0; + else + return size; +} + + +demuxer_t * demux_open_ts(demuxer_t * demuxer) +{ + int packet_size; + demuxer_t *vd, *ad; + stream_t *s; + sh_video_t *sh_video; + sh_audio_t *sh_audio; + ts_priv_t * priv; + + + demuxer->type= DEMUXER_TYPE_MPEG_TS; + demuxer->seekable = 0; + + + stream_reset(demuxer->stream); + stream_seek(demuxer->stream, 0); + + if(! (packet_size = ts_check_file(demuxer))) + 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...\n"); + + + sh_video->format = 0x10000002; //MPEG2 video + sh_audio->format = 0x50; //MPEG1L2 audio + /* + demuxer->movi_start = 0; + demuxer->movi_end = demuxer->stream->end_pos; + */ + return demuxer; +} + + + + + +void demux_close_ts(demuxer_t * demuxer) +{ + if(demuxer->priv) + { + free(demuxer->priv); + demuxer->priv=NULL; + } +} + + + + +static int mpegts_push_data(MpegTSStream *tss, + const unsigned char *buf, int buf_size, int is_start, char *dest) +{ + const unsigned char *p; + int len, code, codec_type, codec_id; + + + if (is_start) + { + tss->state = MPEGTS_HEADER; + tss->header_size = 0; + } + p = buf; + while (buf_size > 0) + { + len = buf_size; + switch(tss->state) + { + case MPEGTS_HEADER: + if (len > MAX_HEADER_SIZE - tss->header_size) + len = MAX_HEADER_SIZE - tss->header_size; + + mp_msg(MSGT_DEMUX, MSGL_V, "LEN: %d\n", len); + memcpy(tss->header, p, len); + tss->header_size += len; + p += len; + buf_size -= len; + if (tss->header_size == MAX_HEADER_SIZE) //abbiamo letto tutto l'header + { + /* we got all the PES or section header. We can now + decide */ + if (tss->header[0] == 0x00 && tss->header[1] == 0x00 && + tss->header[2] == 0x01) + { + /* it must be an mpeg2 PES stream */ + /* XXX: add AC3 support */ + code = tss->header[3] | 0x100; + if (!((code >= 0x1c0 && code <= 0x1df) || + (code >= 0x1e0 && code <= 0x1ef))) + goto skip; + + /* allocate stream */ + if (code >= 0x1c0 && code <= 0x1df) + { + tss->type = AUDIO; + } + else + { + tss->type = VIDEO; + } + tss->state = MPEGTS_PESHEADER_FILL; + tss->payload_size = (tss->header[4] << 8) | tss->header[5]; + if (tss->payload_size == 0) + tss->payload_size = 65536; + + //fprintf(stderr, "PID: %u, PAYLOADSIZE: %u\n", code, tss->payload_size); + } + else + { + /* otherwise, it should be a table */ + /* skip packet */ + skip: + tss->state = MPEGTS_SKIP; + continue; + } + + + + } + break; + + /**********************************************/ + /* PES packing parsing */ + case MPEGTS_PESHEADER_FILL: + mp_msg(MSGT_DEMUX, MSGL_DBG2, "PES_HEADER_FILL\n"); + /* skip filling */ + code = *p++; + buf_size--; + tss->payload_size--; + if (code != 0xff) + { + if ((code & 0xc0) != 0x80) + goto skip; + tss->state = MPEGTS_PESHEADER_FLAGS; + } + break; + case MPEGTS_PESHEADER_FLAGS: + mp_msg(MSGT_DEMUX, MSGL_DBG2, "PES_HEADER_FLAGS\n"); + code = *p++; + buf_size--; + tss->payload_size--; + tss->state = MPEGTS_PESHEADER_SIZE; + break; + case MPEGTS_PESHEADER_SIZE: + mp_msg(MSGT_DEMUX, MSGL_DBG2, "PES_HEADER_SIZE\n"); + tss->pes_header_size = *p++; + buf_size--; + tss->payload_size--; + tss->state = MPEGTS_PESHEADER_READ; + break; + case MPEGTS_PESHEADER_READ: + mp_msg(MSGT_DEMUX, MSGL_DBG2, "PES_HEADER_READ\n"); + /* currently we do nothing except skipping */ + if (len > tss->pes_header_size) + len = tss->pes_header_size; + p += len; + buf_size -= len; + tss->pes_header_size -= len; + tss->payload_size -= len; + if (tss->pes_header_size == 0) + tss->state = MPEGTS_PAYLOAD; + break; + case MPEGTS_PAYLOAD: + if(((tss->type == VIDEO ) || (tss->type == AUDIO)) && is_start) + mp_msg(MSGT_DEMUX, MSGL_DBG2, "BUF: %x, %02X %02X %02X %02X, P: %x, DIFF: %d, IS_START: %d, TYPE: %d, STRING: %02X %02X %02X %02X\n", + buf, buf[0], buf[1], buf[2], buf[3], p, p-buf, is_start, tss->type, p[0], p[1], p[2], p[3]); + if (len > tss->payload_size) + len = tss->payload_size; + if (len > 0) + { + if(is_start) + { + if((buf[7] & 0x80)) + { + uint64_t pts; + pts = (int64_t)(buf[9] & 0x0E) << 29 ; + pts |= buf[10] << 22 ; + pts |= (buf[11] & 0xFE) << 14 ; + pts |= buf[12] << 7 ; + pts |= (buf[13] & 0xFE) >> 1 ; + + tss->pts = pts/90000.0f; + mp_msg(MSGT_DEMUX, MSGL_V, "PTS: %lf\n", pts/90000.0f); + } + else + mp_msg(MSGT_DEMUX, MSGL_DBG2, "NO PTS FLAG PRESENT: %d, IS_START: %d\n", buf[7] & 0x80, is_start); + } + + if(dest) + { + memcpy(dest, p, buf_size); + return buf_size; + } + else + { + mp_msg(MSGT_DEMUX, MSGL_INFO, "PASSED A NULL POINTER, DISCARD\n", is_start, tss->pid, tss->payload_size, buf_size); + } + tss->payload_size -= len; + } + buf_size = 0; + break; + case MPEGTS_SKIP: + mp_msg(MSGT_DEMUX, MSGL_DBG2, "TS_SKIP\n"); + buf_size = 0; + break; + } + } + return 0; +} + + + +// 0 = EOF or no stream found +// 1 = successfully read a packet +int demux_ts_fill_buffer (demuxer_t * demuxer) +{ + MpegTSContext ts; + MpegTSStream *tss; + uint8_t done = 0, filled = 0; + demux_packet_t *dp; + ts_priv_t *priv = demuxer->priv; + uint16_t buf_size; + char tmp[TS_FEC_PACKET_SIZE]; + + + unsigned char packet[TS_FEC_PACKET_SIZE]; + int len, pid, cc, cc_ok, afc; + const unsigned char *p; + + while(!done) + { + //len = get_buffer(pb, packet, ts->raw_packet_size); + len = stream_read(demuxer->stream, packet, priv->packet_size); + if (len != priv->packet_size) + return 0; + + /* check paquet sync byte */ + /* XXX: accept to resync ? */ + if (packet[0] != 0x47) + { + mp_msg(MSGT_DEMUX, MSGL_V, "DOESN'T BEGIN WITH A TS-SIGNATURE\n"); + return 0; + } + + pid = ((packet[1] & 0x1f) << 8) | packet[2]; + tss = ts.pids[pid]; //un 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; + mp_msg(MSGT_DEMUX, MSGL_V, "new pid=%u\n", pid); + } + + cc = (packet[3] & 0xf); + cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == 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; + + // da qui c' il contenuto di un pes, la funzione che segue ci dara' il tipo del payload + + buf_size = TS_PACKET_SIZE - (p - packet); + + + if(len = mpegts_push_data(tss, p, buf_size, packet[1] & 0x40, tmp)) + { + dp = new_demux_packet(len); + memcpy(dp->buffer, tmp, len); + tss->offset += len; + filled=1; + if((tss->type == VIDEO)) + { + dp->pts = 0; + dp->flags = 0; + dp->pos = stream_tell(demuxer->stream); + dp->pts = tss->pts; + ds_add_packet(demuxer->video, dp); + return len; + } + if((tss->type == AUDIO)) + { + dp->pts = 0; + dp->flags = 0; + dp->pts = tss->pts; + dp->pos = stream_tell(demuxer->stream); + ds_add_packet(demuxer->audio, dp); + return len; + } + } + } + +} + + +int demux_seek_ts(demuxer_t * demuxer, float rel_seek_secs, int flags) +{ + return 0; +} + + + + +static int mpegts_read_close(MpegTSContext *ts) +{ + int i; + for(i=0;ipids[i]); + return 0; +} + + + diff -Naur MPlayer-0.90rc4/libmpdemux/Makefile MPlayer-0.90rc4-ts/libmpdemux/Makefile --- MPlayer-0.90rc4/libmpdemux/Makefile 2003-02-03 11:27:50.000000000 +0100 +++ MPlayer-0.90rc4-ts/libmpdemux/Makefile 2003-02-17 21:19:57.000000000 +0100 @@ -3,7 +3,7 @@ include ../config.mak -SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c +SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c demux_ts.c ifeq ($(XMMS_PLUGINS),yes) SRCS += demux_xmms.c endif