diff options
Diffstat (limited to 'demux/demux_mpg.c')
-rw-r--r-- | demux/demux_mpg.c | 1306 |
1 files changed, 0 insertions, 1306 deletions
diff --git a/demux/demux_mpg.c b/demux/demux_mpg.c deleted file mode 100644 index d47b3afd86..0000000000 --- a/demux/demux_mpg.c +++ /dev/null @@ -1,1306 +0,0 @@ -/* - * MPG/VOB file parser for DEMUXER v2.5 - * copyright (c) 2001 by A'rpi/ESP-team - * - * This file is part of MPlayer. - * - * MPlayer 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. - * - * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <math.h> - -#include "config.h" -#include "core/mp_msg.h" -#include "core/options.h" - -#include "libavutil/attributes.h" -#include "audio/decode/dec_audio.h" -#include "stream/stream.h" -#include "demux.h" -#include "parse_es.h" -#include "stheader.h" -#include "mp3_hdr.h" - -//#define MAX_PS_PACKETSIZE 2048 -#define MAX_PS_PACKETSIZE (224*1024) - -#define UNKNOWN 0 -#define VIDEO_MPEG1 0x10000001 -#define VIDEO_MPEG2 0x10000002 -#define VIDEO_MPEG4 0x10000004 -#define VIDEO_H264 0x10000005 -#define AUDIO_MP2 0x50 -#define AUDIO_A52 0x2000 -#define AUDIO_LPCM_BE 0x10001 -#define AUDIO_AAC mmioFOURCC('M', 'P', '4', 'A') - -typedef struct mpg_demuxer { - float last_pts; - float first_pts; // first pts found in stream - float first_to_final_pts_len; // difference between final pts and first pts - int has_valid_timestamps; // !=0 iff time stamps look linear - // (not necessarily starting with 0) - unsigned int es_map[0x40]; //es map of stream types (associated to the pes id) from 0xb0 to 0xef - int num_a_streams; - int a_stream_ids[MAX_A_STREAMS]; -} mpg_demuxer_t; - -static int mpeg_pts_error=0; -int64_t ps_probe = 0; - -static int parse_psm(demuxer_t *demux, int len) { - unsigned char c, id, type; - unsigned int plen, prog_len, es_map_len; - mpg_demuxer_t *priv = (mpg_demuxer_t *) demux->priv; - - mp_dbg(MSGT_DEMUX,MSGL_V, "PARSE_PSM, len=%d\n", len); - if(! len || len > 1018) - return 0; - - c = stream_read_char(demux->stream); - if(! (c & 0x80)) { - stream_skip(demux->stream, len - 1); //not yet valid, discard - return 0; - } - stream_skip(demux->stream, 1); - prog_len = stream_read_word(demux->stream); //length of program descriptors - stream_skip(demux->stream, prog_len); //.. that we ignore - es_map_len = stream_read_word(demux->stream); //length of elementary streams map - es_map_len = FFMIN(es_map_len, len - prog_len - 8); //sanity check - while(es_map_len > 0) { - type = stream_read_char(demux->stream); - id = stream_read_char(demux->stream); - if(id >= 0xB0 && id <= 0xEF && priv) { - int idoffset = id - 0xB0; - switch(type) { - case 0x1: - priv->es_map[idoffset] = VIDEO_MPEG1; - break; - case 0x2: - priv->es_map[idoffset] = VIDEO_MPEG2; - break; - case 0x3: - case 0x4: - priv->es_map[idoffset] = AUDIO_MP2; - break; - case 0x0f: - case 0x11: - priv->es_map[idoffset] = AUDIO_AAC; - break; - case 0x10: - priv->es_map[idoffset] = VIDEO_MPEG4; - break; - case 0x1b: - priv->es_map[idoffset] = VIDEO_H264; - break; - case 0x81: - priv->es_map[idoffset] = AUDIO_A52; - break; - } - mp_dbg(MSGT_DEMUX,MSGL_V, "PSM ES, id=0x%x, type=%x, stype: %x\n", id, type, priv->es_map[idoffset]); - } - plen = stream_read_word(demux->stream); //length of elementary stream descriptors - plen = FFMIN(plen, es_map_len); //sanity check - stream_skip(demux->stream, plen); //skip descriptors for now - es_map_len -= 4 + plen; - } - stream_skip(demux->stream, 4); //skip crc32 - return 1; -} - -// 500000 is a wild guess -#define TIMESTAMP_PROBE_LEN 500000 - -//MAX_PTS_DIFF_FOR_CONSECUTIVE denotes the maximum difference -//between two pts to consider them consecutive -//1.0 is a wild guess -#define MAX_PTS_DIFF_FOR_CONSECUTIVE 1.0 - -//returns the first pts found within TIME_STAMP_PROBE_LEN bytes after stream_pos in demuxer's stream. -//if no pts is found or an error occurs, -1.0 is returned. -//Packs are freed. -static float read_first_mpeg_pts_at_position(demuxer_t* demuxer, int64_t stream_pos) -{ - stream_t *s = demuxer->stream; - mpg_demuxer_t *mpg_d = demuxer->priv; - float pts = -1.0; //the pts to return; - float found_pts1; //the most recently found pts - float found_pts2; //the pts found before found_pts1 - float found_pts3; //the pts found before found_pts2 - int found = 0; - - if(!mpg_d || stream_pos < 0) - return pts; - - found_pts3 = found_pts2 = found_pts1 = mpg_d->last_pts; - stream_seek(s, stream_pos); - - //We look for pts. - //However, we do not stop at the first found one, as timestamps may reset - //Therefore, we seek until we found three consecutive - //pts within MAX_PTS_DIFF_FOR_CONSECUTIVE. - - while(found<3 && !s->eof - && (fabsf(found_pts2-found_pts1) < MAX_PTS_DIFF_FOR_CONSECUTIVE) - && (fabsf(found_pts3-found_pts2) < MAX_PTS_DIFF_FOR_CONSECUTIVE) - && (stream_tell(s) < stream_pos + TIMESTAMP_PROBE_LEN) - && ds_fill_buffer(demuxer->video)) - { - if(mpg_d->last_pts != found_pts1) - { - if(!found) - found_pts3 = found_pts2 = found_pts1 = mpg_d->last_pts; //the most recently found pts - else - { - found_pts3 = found_pts2; - found_pts2 = found_pts1; - found_pts1 = mpg_d->last_pts; - } - found++; - } - } - - if(found == 3) pts = found_pts3; - - //clean up from searching of first pts; - demux_flush(demuxer); - - return pts; -} - -/// Open an mpg physical stream -static demuxer_t* demux_mpg_open(demuxer_t* demuxer) { - stream_t *s = demuxer->stream; - mpg_demuxer_t* mpg_d; - - if (!ds_fill_buffer(demuxer->video)) return 0; - mpg_d = calloc(1,sizeof(mpg_demuxer_t)); - if(mpg_d) - { - demuxer->priv = mpg_d; - mpg_d->last_pts = -1.0; - mpg_d->first_pts = -1.0; - - //if seeking is allowed set has_valid_timestamps if appropriate - if(demuxer->seekable - && (demuxer->stream->type == STREAMTYPE_FILE - || demuxer->stream->type == STREAMTYPE_VCD) - && demuxer->movi_start != demuxer-> movi_end - ) - { - //We seek to the beginning of the stream, to somewhere in the - //middle, and to the end of the stream, while remembering the pts - //at each of the three positions. With these pts, we check whether - //or not the pts are "linear enough" to justify seeking by the pts - //of the stream - - //The position where the stream is now - int64_t pos = stream_tell(s); - float first_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_start); - if(first_pts != -1.0) - { - float middle_pts = read_first_mpeg_pts_at_position(demuxer, (demuxer->movi_end + demuxer->movi_start)/2); - if(middle_pts != -1.0) - { - float final_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_end - TIMESTAMP_PROBE_LEN); - if(final_pts != -1.0) - { - // found proper first, middle, and final pts. - float proportion = (middle_pts-first_pts==0) ? -1 : (final_pts-middle_pts)/(middle_pts-first_pts); - // if they are linear enough set has_valid_timestamps - if((0.5 < proportion) && (proportion < 2)) - { - mpg_d->first_pts = first_pts; - mpg_d->first_to_final_pts_len = final_pts - first_pts; - mpg_d->has_valid_timestamps = 1; - } - } - } - } - - //Cleaning up from seeking in stream - demuxer->stream->eof=0; - demuxer->video->eof=0; - demuxer->audio->eof=0; - - stream_seek(s,pos); - ds_fill_buffer(demuxer->video); - } // if ( demuxer->seekable ) - } // if ( mpg_d ) - return demuxer; -} - -static void demux_close_mpg(demuxer_t* demuxer) { - mpg_demuxer_t* mpg_d = demuxer->priv; - free(mpg_d); -} - - -static unsigned long long read_mpeg_timestamp(stream_t *s,int c){ - unsigned int d,e; - unsigned long long pts; - d=stream_read_word(s); - e=stream_read_word(s); - if( ((c&1)!=1) || ((d&1)!=1) || ((e&1)!=1) ){ - ++mpeg_pts_error; - return 0; // invalid pts - } - pts=(((uint64_t)((c>>1)&7))<<30)|((d>>1)<<15)|(e>>1); - mp_dbg(MSGT_DEMUX,MSGL_DBG3," pts {%llu}",pts); - return pts; -} - -static void new_audio_stream(demuxer_t *demux, int aid){ - if(!demux->a_streams[aid]){ - mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demux->priv; - sh_audio_t* sh_a; - new_sh_audio(demux,aid); - sh_a = (sh_audio_t*)demux->a_streams[aid]; - sh_a->needs_parsing = 1; - switch(aid & 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id) - case 0x00: sh_a->format=0x50;break; // mpeg - case 0xA0: sh_a->format=0x10001;break; // dvd pcm - case 0x80: if((aid & 0xF8) == 0x88) sh_a->format=0x2001;//dts - else sh_a->format=0x2000;break; // ac3 - } - //evo files - if((aid & 0xC0) == 0xC0) sh_a->format=0x2000; - else if(aid >= 0x98 && aid <= 0x9f) sh_a->format=0x2001; - if (mpg_d) mpg_d->a_stream_ids[mpg_d->num_a_streams++] = aid; - mp_set_audio_codec_from_tag(sh_a); - } - if(demux->audio->id==-1) demux->audio->id=aid; -} - -static void dvdpcm_header(sh_audio_t *sh) -{ - if (sh->format != 0x10001) - return; - - WAVEFORMATEX *wf = calloc(sizeof(*wf), 1); - - if(sh->codecdata_len==3){ - // we have LPCM header: - unsigned char h=sh->codecdata[1]; - wf->nChannels=1+(h&7); - switch((h>>4)&3){ - case 0: wf->nSamplesPerSec=48000;break; - case 1: wf->nSamplesPerSec=96000;break; - case 2: wf->nSamplesPerSec=44100;break; - case 3: wf->nSamplesPerSec=32000;break; - } - switch ((h >> 6) & 3) { - case 0: - wf->wBitsPerSample = 2 * 8; - break; - case 1: - mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Samples of this format are needed to improve support. Please contact the developers.\n"); - wf->nAvgBytesPerSec = wf->nChannels * wf->nSamplesPerSec * 5 / 2; - case 2: - wf->wBitsPerSample = 3 * 8; - break; - default: - wf->wBitsPerSample = 2 * 8; - } - } else { - // use defaults: - wf->nChannels=2; - wf->nSamplesPerSec=48000; - wf->wBitsPerSample = 2 * 8; - } - if (!wf->nAvgBytesPerSec) - wf->nAvgBytesPerSec = wf->wBitsPerSample / 8 * wf->nChannels * wf->nSamplesPerSec; - if (wf->wBitsPerSample == 16) - sh->format = 0x20776172; // 'raw ', pcm_s16be - sh->wf = wf; -} - -static int demux_mpg_read_packet(demuxer_t *demux,int id){ - int d av_unused; - int len; - int set_pts=0; // !=0 iff pts has been set to a proper value - unsigned char c=0; - unsigned long long pts=0; - unsigned long long dts av_unused = 0; - int l; - int pes_ext2_subid=-1; - double stream_pts = MP_NOPTS_VALUE; - demux_stream_t *ds=NULL; - demux_packet_t* dp; - mpg_demuxer_t *priv = (mpg_demuxer_t *) demux->priv; - - mp_dbg(MSGT_DEMUX,MSGL_DBG3,"demux_read_packet: %X\n",id); - -// if(id==0x1F0){ -// demux->synced=0; // force resync after 0x1F0 -// return -1; -//} - -// if(id==0x1BA) packet_start_pos=stream_tell(demux->stream); - if((id<0x1BC || id>=0x1F0) && id != 0x1FD) return -1; - if(id==0x1BE) return -1; // padding stream - if(id==0x1BF) return -1; // private2 - - len=stream_read_word(demux->stream); - mp_dbg(MSGT_DEMUX,MSGL_DBG3,"PACKET len=%d",len); -// if(len==62480){ demux->synced=0;return -1;} /* :) */ - if(len==0 || len>MAX_PS_PACKETSIZE){ - mp_dbg(MSGT_DEMUX,MSGL_DBG2,"Invalid PS packet len: %d\n",len); - return -2; // invalid packet !!!!!! - } - - mpeg_pts_error=0; - - if(id==0x1BC) { - parse_psm(demux, len); - return 0; - } - - while(len>0){ // Skip stuFFing bytes - c=stream_read_char(demux->stream); - --len; - if(c!=0xFF)break; - } - if((c>>6)==1){ // Read (skip) STD scale & size value -// printf(" STD_scale=%d",(c>>5)&1); - d=((c&0x1F)<<8)|stream_read_char(demux->stream); - len-=2; -// printf(" STD_size=%d",d); - c=stream_read_char(demux->stream); - } - // Read System-1 stream timestamps: - if((c>>4)==2){ - pts=read_mpeg_timestamp(demux->stream,c); - set_pts=1; - len-=4; - } else - if((c>>4)==3){ - pts=read_mpeg_timestamp(demux->stream,c); - c=stream_read_char(demux->stream); - if((c>>4)!=1) pts=0; //printf("{ERROR4}"); - else set_pts = 1; - dts=read_mpeg_timestamp(demux->stream,c); - len-=4+1+4; - } else - if((c>>6)==2){ - int pts_flags; - int hdrlen; - int parse_ext2; - // System-2 (.VOB) stream: - c=stream_read_char(demux->stream); - pts_flags=c>>6; - parse_ext2 = (id == 0x1FD) && ((c & 0x3F) == 1); - c=stream_read_char(demux->stream); - hdrlen=c; - len-=2; - mp_dbg(MSGT_DEMUX,MSGL_DBG3," hdrlen=%d (len=%d)",hdrlen,len); - if(hdrlen>len){ mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: invalid header length \n"); return -1;} - if(pts_flags==2 && hdrlen>=5){ - c=stream_read_char(demux->stream); - pts=read_mpeg_timestamp(demux->stream,c); - set_pts=1; - len-=5;hdrlen-=5; - } else - if(pts_flags==3 && hdrlen>=10){ - c=stream_read_char(demux->stream); - pts=read_mpeg_timestamp(demux->stream,c); - set_pts=1; - c=stream_read_char(demux->stream); - dts=read_mpeg_timestamp(demux->stream,c); - len-=10;hdrlen-=10; - } - len-=hdrlen; - if(parse_ext2 && hdrlen>=3) { - c=stream_read_char(demux->stream); - hdrlen--; - - if((c & 0x0F) != 0x0F) { - mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: pes_extension_flag2 not set, discarding pes packet\n"); - return -1; - } - if(c & 0x80) { //pes_private_data_flag - if(hdrlen<16) { - mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: not enough pes_private_data bytes: %d < 16, discarding pes packet\n", hdrlen); - return -1; - } - stream_skip(demux->stream, 16); - hdrlen-=16; - } - if(c & 0x40) { //pack_header_field_flag - int l = stream_read_char(demux->stream); - if(l < 0) //couldn't read from the stream? - return -1; - hdrlen--; - if(l < 0 || hdrlen < l) { - mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: not enough pack_header bytes: hdrlen: %d < skip: %d, discarding pes packet\n", - hdrlen, l); - return -1; - } - stream_skip(demux->stream, l); - hdrlen-=l; - } - if(c & 0x20) { //program_packet_sequence_counter_flag - if(hdrlen < 2) { - mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: not enough program_packet bytes: hdrlen: %d, discarding pes packet\n", hdrlen); - return -1; - } - stream_skip(demux->stream, 2); - hdrlen-=2; - } - if(c & 0x10) { - //STD - stream_skip(demux->stream, 2); - hdrlen-=2; - } - c=stream_read_char(demux->stream); //pes_extension2 flag - hdrlen--; - if(c!=0x81) { mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: unknown pes_extension2 format, len is > 1 \n"); return -1;} - c=stream_read_char(demux->stream); //pes_extension2 payload === substream id - hdrlen--; - if(c<0x55 || c>0x5F) { mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: unknown vc1 substream_id: 0x%x \n", c); return -1;} - pes_ext2_subid=c; - } - if(hdrlen>0) - stream_skip(demux->stream,hdrlen); // skip header and stuffing bytes - - if(id==0x1FD && pes_ext2_subid!=-1) { - //==== EVO VC1 STREAMS ===// - if(!demux->v_streams[pes_ext2_subid]) new_sh_video(demux,pes_ext2_subid); - if(demux->video->id==-1) demux->video->id=pes_ext2_subid; - if(demux->video->id==pes_ext2_subid){ - ds=demux->video; - if(!ds->sh) ds->sh=demux->v_streams[pes_ext2_subid]; - if(priv && ds->sh) { - sh_video_t *sh = (sh_video_t *)ds->sh; - sh->format = mmioFOURCC('W', 'V', 'C', '1'); - mp_set_video_codec_from_tag(sh); - } - } - } - //============== DVD Audio sub-stream ====================== - if(id==0x1BD){ - int aid, rawa52 = 0; - int64_t tmppos; - unsigned int tmp; - - tmppos = stream_tell(demux->stream); - tmp = stream_read_word(demux->stream); - stream_seek(demux->stream, tmppos); - /// vdr stores A52 without the 4 header bytes, so we have to check this condition first - if(tmp == 0x0B77) { - aid = 128; - rawa52 = 1; - } - else { - aid=stream_read_char(demux->stream);--len; - if(len<3) return -1; // invalid audio packet - } - - // AID: - // 0x20..0x3F subtitle - // 0x80..0x87 and 0xC0..0xCF AC3 audio - // 0x88..0x8F and 0x98..0x9F DTS audio - // 0xA0..0xBF PCM audio - - if((aid & 0xE0) == 0x20){ - // subtitle: - aid&=0x1F; - - if(!demux->s_streams[aid]){ - sh_sub_t *sh = new_sh_sub(demux, aid); - if (sh) sh->gsh->codec = "dvd_subtitle_mpg"; - mp_msg(MSGT_DEMUX,MSGL_V,"==> Found subtitle: %d\n",aid); - } - - if(demux->sub->id > -1) - demux->sub->id &= 0x1F; - if(!demux->opts->sub_lang && demux->sub->id == -1) - demux->sub->id = aid; - if(demux->sub->id==aid){ - ds=demux->sub; - } - } else if((aid >= 0x80 && aid <= 0x8F) || (aid >= 0x98 && aid <= 0xAF) || (aid >= 0xC0 && aid <= 0xCF)) { - -// aid=128+(aid&0x7F); - // aid=0x80..0xBF - new_audio_stream(demux, aid); - if(demux->audio->id==aid){ - int type; - ds=demux->audio; - if(!ds->sh) ds->sh=demux->a_streams[aid]; - // READ Packet: Skip additional audio header data: - if(!rawa52) { - c=stream_read_char(demux->stream);//num of frames - type=stream_read_char(demux->stream);//startpos hi - type=(type<<8)|stream_read_char(demux->stream);//startpos lo -// printf("\r[%02X][%04X]",c,type); - len-=3; - } - if((aid&0xE0)==0xA0 && len>=3){ - unsigned char* hdr; - // save audio header as codecdata! - if(!((sh_audio_t*)(ds->sh))->codecdata_len){ - ((sh_audio_t*)(ds->sh))->codecdata=malloc(3); - ((sh_audio_t*)(ds->sh))->codecdata_len=3; - } - hdr=((sh_audio_t*)(ds->sh))->codecdata; - // read LPCM header: - // emphasis[1], mute[1], rvd[1], frame number[5]: - hdr[0]=stream_read_char(demux->stream); -// printf(" [%01X:%02d]",c>>5,c&31); - // quantization[2],freq[2],rvd[1],channels[3] - hdr[1]=stream_read_char(demux->stream); -// printf("[%01X:%01X] ",c>>4,c&15); - // dynamic range control (0x80=off): - hdr[2]=stream_read_char(demux->stream); -// printf("[%02X] ",c); - len-=3; - if(len<=0) mp_msg(MSGT_DEMUX,MSGL_V,"End of packet while searching for PCM header\n"); - dvdpcm_header((sh_audio_t*)(ds->sh)); - mp_set_audio_codec_from_tag((sh_audio_t*)(ds->sh)); - } -// printf(" \n"); - } // if(demux->audio->id==aid) - - } else mp_msg(MSGT_DEMUX,MSGL_V,"Unknown 0x1BD substream: 0x%02X \n",aid); - } //if(id==0x1BD) - } else { - if(c!=0x0f){ - mp_msg(MSGT_DEMUX,MSGL_V," {ERROR5,c=%d} \n",c); - return -1; // invalid packet !!!!!! - } - } - if(mpeg_pts_error) mp_msg(MSGT_DEMUX,MSGL_V," {PTS_err:%d} \n",mpeg_pts_error); - mp_dbg(MSGT_DEMUX,MSGL_DBG3," => len=%d\n",len); - -// if(len<=0 || len>MAX_PS_PACKETSIZE) return -1; // Invalid packet size - if(len<=0 || len>MAX_PS_PACKETSIZE){ - mp_dbg(MSGT_DEMUX,MSGL_DBG2,"Invalid PS data len: %d\n",len); - return -1; // invalid packet !!!!!! - } - - if(id>=0x1C0 && id<=0x1DF){ - // mpeg audio - int aid=id-0x1C0; - new_audio_stream(demux, aid); - if(demux->audio->id==aid){ - ds=demux->audio; - if(!ds->sh) ds->sh=demux->a_streams[aid]; - if(priv && ds->sh) { - sh_audio_t *sh = (sh_audio_t *)ds->sh; - if(priv->es_map[id - 0x1B0]) - sh->format = priv->es_map[id - 0x1B0]; - mp_dbg(MSGT_DEMUX,MSGL_DBG2,"ASSIGNED TO STREAM %d CODEC %x\n", id, priv->es_map[id - 0x1B0]); - dvdpcm_header(sh); - mp_set_audio_codec_from_tag(sh); - } - } - } else - if(id>=0x1E0 && id<=0x1EF){ - // mpeg video - int aid=id-0x1E0; - if(!demux->v_streams[aid]) new_sh_video(demux,aid); - if(demux->video->id==-1) demux->video->id=aid; - if(demux->video->id==aid){ - ds=demux->video; - if(!ds->sh) ds->sh=demux->v_streams[aid]; - if(priv && ds->sh) { - sh_video_t *sh = (sh_video_t *)ds->sh; - if(priv->es_map[id - 0x1B0]) { - sh->format = priv->es_map[id - 0x1B0]; - mp_set_video_codec_from_tag(sh); - mp_dbg(MSGT_DEMUX,MSGL_DBG2,"ASSIGNED TO STREAM %d CODEC %x\n", id, priv->es_map[id - 0x1B0]); - } - } - } - } - - if(ds){ - mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_MPG: Read %d data bytes from packet %04X\n",len,id); -// printf("packet start = 0x%X \n",stream_tell(demux->stream)-packet_start_pos); - - dp=new_demux_packet(len); - if(!dp) { - mp_dbg(MSGT_DEMUX,MSGL_ERR,"DEMUX_MPG ERROR: couldn't create demux_packet(%d bytes)\n",len); - stream_skip(demux->stream,len); - return 0; - } - l = stream_read(demux->stream,dp->buffer,len); - if(l<len) - resize_demux_packet(dp, l); - len = l; - if(set_pts) - dp->pts=pts/90000.0f; - dp->pos=demux->filepos; - /* - workaround: - set dp->stream_pts only when feeding the video stream, or strangely interleaved files - (such as SWIII) will show strange alternations in the stream time, wildly going - back and forth - */ - if(ds == demux->video && stream_control(demux->stream, STREAM_CTRL_GET_CURRENT_TIME,(void *)&stream_pts)!=STREAM_UNSUPPORTED) - dp->stream_pts = stream_pts; - ds_add_packet(ds,dp); - if (demux->priv && set_pts) ((mpg_demuxer_t*)demux->priv)->last_pts = pts/90000.0f; -// if(ds==demux->sub) parse_dvdsub(ds->last->buffer,ds->last->len); - return 1; - } - mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_MPG: Skipping %d data bytes from packet %04X\n",len,id); - if(len<=2356) stream_skip(demux->stream,len); - return 0; -} - -static int num_elementary_packets100=0; -static int num_elementary_packets101=0; -static int num_elementary_packets12x=0; -static int num_elementary_packets1B6=0; -static int num_elementary_packetsPES=0; -static int num_mpeg12_startcode=0; -static int num_h264_slice=0; //combined slice -static int num_h264_dpa=0; //DPA Slice -static int num_h264_dpb=0; //DPB Slice -static int num_h264_dpc=0; //DPC Slice -static int num_h264_idr=0; //IDR Slice -static int num_h264_sps=0; -static int num_h264_pps=0; - -static int num_mp3audio_packets=0; - -static void clear_stats(void) -{ - num_elementary_packets100=0; - num_elementary_packets101=0; - num_elementary_packets1B6=0; - num_elementary_packets12x=0; - num_elementary_packetsPES=0; - num_mpeg12_startcode=0; - num_h264_slice=0; //combined slice - num_h264_dpa=0; //DPA Slice - num_h264_dpb=0; //DPB Slice - num_h264_dpc=0; //DPC Slice - num_h264_idr=0; //IDR Slice - num_h264_sps=0; - num_h264_pps=0; - num_mp3audio_packets=0; -} - -//assumes demuxer->synced < 2 -static inline void update_stats(int head) -{ - if(head==0x1B6) ++num_elementary_packets1B6; - else if(head==0x1B3 || head==0x1B8) ++num_mpeg12_startcode; - else if(head==0x100) ++num_elementary_packets100; - else if(head==0x101) ++num_elementary_packets101; - else if(head==0x1BD || (0x1C0<=head && head<=0x1EF)) - num_elementary_packetsPES++; - else if(head>=0x120 && head<=0x12F) ++num_elementary_packets12x; - if(head>=0x100 && head<0x1B0) - { - if((head&~0x60) == 0x101) ++num_h264_slice; - else if((head&~0x60) == 0x102) ++num_h264_dpa; - else if((head&~0x60) == 0x103) ++num_h264_dpb; - else if((head&~0x60) == 0x104) ++num_h264_dpc; - else if((head&~0x60) == 0x105 && head != 0x105) ++num_h264_idr; - else if((head&~0x60) == 0x107 && head != 0x107) ++num_h264_sps; - else if((head&~0x60) == 0x108 && head != 0x108) ++num_h264_pps; - } -} - -static int demux_mpg_probe(demuxer_t *demuxer) { - int pes av_unused = 1; - int tmp; - int64_t tmppos; - int file_format = DEMUXER_TYPE_UNKNOWN; - - tmppos=stream_tell(demuxer->stream); - tmp=stream_read_dword(demuxer->stream); - if(tmp==0x1E0 || tmp==0x1C0) { - tmp=stream_read_word(demuxer->stream); - if(tmp>1 && tmp<=2048) pes=0; // demuxer->synced=3; // PES... - } - stream_seek(demuxer->stream,tmppos); - - clear_stats(); - - if(demux_mpg_open(demuxer)) - file_format=DEMUXER_TYPE_MPEG_PS; - else { - mp_msg(MSGT_DEMUX,MSGL_V,"MPEG packet stats: p100: %d p101: %d p1B6: %d p12x: %d sli: %d a: %d b: %d c: %d idr: %d sps: %d pps: %d PES: %d MP3: %d, synced: %d\n", - num_elementary_packets100,num_elementary_packets101, - num_elementary_packets1B6,num_elementary_packets12x, - num_h264_slice, num_h264_dpa, - num_h264_dpb, num_h264_dpc=0, - num_h264_idr, num_h264_sps=0, - num_h264_pps, - num_elementary_packetsPES,num_mp3audio_packets, demuxer->synced); - - //MPEG packet stats: p100: 458 p101: 458 PES: 0 MP3: 1103 (.m2v) - if(num_mp3audio_packets>50 && num_mp3audio_packets>2*num_elementary_packets100 - && abs(num_elementary_packets100-num_elementary_packets101)>2) - return file_format; - - // some hack to get meaningfull error messages to our unhappy users: - if(num_mpeg12_startcode>=2 && num_elementary_packets100>=2 && num_elementary_packets101>=2 && - abs(num_elementary_packets101+8-num_elementary_packets100)<16) { - if(num_elementary_packetsPES>=4 && num_elementary_packetsPES>=num_elementary_packets100-4) { - return file_format; - } - file_format=DEMUXER_TYPE_MPEG_ES; // <-- hack is here :) - } else - // fuzzy mpeg4-es detection. do NOT enable without heavy testing of mpeg formats detection! - if(num_elementary_packets1B6>3 && num_elementary_packets12x>=1 && - num_elementary_packetsPES==0 && num_elementary_packets100<=num_elementary_packets12x && - demuxer->synced<2) { - file_format=DEMUXER_TYPE_MPEG4_ES; - } else - // fuzzy h264-es detection. do NOT enable without heavy testing of mpeg formats detection! - if((num_h264_slice>3 || (num_h264_dpa>3 && num_h264_dpb>3 && num_h264_dpc>3)) && - /* FIXME num_h264_sps>=1 && */ num_h264_pps>=1 && num_h264_idr>=1 && - num_elementary_packets1B6==0 && num_elementary_packetsPES==0 && - demuxer->synced<2) { - file_format=DEMUXER_TYPE_H264_ES; - } else - { - if(demuxer->synced==2) - mp_msg(MSGT_DEMUXER, MSGL_ERR, "MPEG: %s", - mp_gtext("Missing video stream!? Contact the author, it may be a bug :(\n")); - else - mp_tmsg(MSGT_DEMUXER,MSGL_V,"Not MPEG System Stream format... (maybe Transport Stream?)\n"); - } - } - //FIXME this shouldn't be necessary - stream_seek(demuxer->stream,tmppos); - return file_format; -} - -static int demux_mpg_es_fill_buffer(demuxer_t *demux, demux_stream_t *ds){ - // Elementary video stream - if(demux->stream->eof) return 0; - demux->filepos=stream_tell(demux->stream); - ds_read_packet(demux->video,demux->stream,STREAM_BUFFER_SIZE,0,demux->filepos,0); - return 1; -} - -/** - * \brief discard until 0x100 header and return a filled buffer - * \param b buffer-end pointer - * \param pos current pos in stream, negative since b points to end of buffer - * \param s stream to read from - * \return new position, differs from original pos when eof hit and thus - * b was modified to point to the new end of buffer - */ -static int find_end(unsigned char **b, int pos, stream_t *s) { - register int state = 0xffffffff; - unsigned char *buf = *b; - int start = pos; - int read, unused; - // search already read part - while (state != 0x100 && pos) { - state = state << 8 | buf[pos++]; - } - // continue search in stream - while (state != 0x100) { - register int c = stream_read_char(s); - if (c < 0) break; - state = state << 8 | c; - } - // modify previous header (from 0x1bc or 0x1bf to 0x100) - buf[start++] = 0; - // copy remaining buffer part to current pos - memmove(&buf[start], &buf[pos], -pos); - unused = start + -pos; // -unused bytes in buffer - read = stream_read(s, &buf[unused], -unused); - unused += read; - // fix buffer so it ends at pos == 0 (eof case) - *b = &buf[unused]; - start -= unused; - return start; -} - -/** - * This format usually uses an insane bitrate, which makes this function - * performance-critical! - * Be sure to benchmark any changes with different compiler versions. - */ -static int demux_mpg_gxf_fill_buffer(demuxer_t *demux, demux_stream_t *ds) { - demux_packet_t *pack; - int len; - demux->filepos = stream_tell(demux->stream); - pack = new_demux_packet(STREAM_BUFFER_SIZE); - len = stream_read(demux->stream, pack->buffer, STREAM_BUFFER_SIZE); - if (len <= 0) - { - free_demux_packet(pack); - return 0; - } - { - register uint32_t state = (uint32_t)(uintptr_t)demux->priv; - register int pos = -len; - unsigned char *buf = &pack->buffer[len]; - do { - state = state << 8 | buf[pos]; - if (unlikely((state | 3) == 0x1bf)) - pos = find_end(&buf, pos, demux->stream); - } while (++pos < 0); - demux->priv = (void *)(uintptr_t)state; - len = buf - pack->buffer; - } - if (len < STREAM_BUFFER_SIZE) - resize_demux_packet(pack, len); - ds_add_packet(ds, pack); - return 1; -} - -static int demux_mpg_fill_buffer(demuxer_t *demux, demux_stream_t *ds) -{ -unsigned int head=0; -int skipped=0; -int max_packs=256; // 512kbyte -int ret=0; - -// System stream -do{ - demux->filepos=stream_tell(demux->stream); - //lame workaround: this is needed to show the progress bar when playing dvdnav:// - //(ths poor guy doesn't know teh length of the stream at startup) - demux->movi_end = demux->stream->end_pos; - head=stream_read_dword(demux->stream); - if((head&0xFFFFFF00)!=0x100){ - // sync... - demux->filepos-=skipped; - while(1){ - int c=stream_read_char(demux->stream); - if(c<0) break; //EOF - head<<=8; - if(head!=0x100){ - head|=c; - if(mp_check_mp3_header(head)) ++num_mp3audio_packets; - ++skipped; //++demux->filepos; - continue; - } - head|=c; - break; - } - demux->filepos+=skipped; - } - if(stream_eof(demux->stream)) break; - // sure: head=0x000001XX - mp_dbg(MSGT_DEMUX,MSGL_DBG4,"*** head=0x%X\n",head); - if(demux->synced==0){ - if(head==0x1BA) demux->synced=1; //else -// if(head==0x1BD || (head>=0x1C0 && head<=0x1EF)) demux->synced=3; // PES? - } else - if(demux->synced==1){ - if(head==0x1BB || head==0x1BD || (head>=0x1C0 && head<=0x1EF)){ - demux->synced=2; - mp_msg(MSGT_DEMUX,MSGL_V,"system stream synced at 0x%"PRIX64" (%"PRId64")!\n",(int64_t)demux->filepos,(int64_t)demux->filepos); - num_elementary_packets100=0; // requires for re-sync! - num_elementary_packets101=0; // requires for re-sync! - } else demux->synced=0; - } // else - if(demux->synced>=2){ - ret=demux_mpg_read_packet(demux,head); - if(!ret) - if(--max_packs==0){ - demux->stream->eof=1; - mp_tmsg(MSGT_DEMUX,MSGL_ERR,"demux: File doesn't contain the selected audio or video stream.\n"); - return 0; - } - if(demux->synced==3) demux->synced=(ret==1)?2:0; // PES detect - } else { - update_stats(head); - if(head>=0x100 && head<0x1B0) - mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... elementary video packet found: %03X\n",head); - else if((head>=0x1C0 && head<0x1F0) || head==0x1BD) - mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... PES packet found: %03X\n",head); - - if(((num_elementary_packets100>50 && num_elementary_packets101>50) || - (num_elementary_packetsPES>50)) && skipped>4000000){ - mp_msg(MSGT_DEMUX,MSGL_V,"sync_mpeg_ps: seems to be ES/PES stream...\n"); - demux->stream->eof=1; - break; - } - if(num_mp3audio_packets>100 && num_elementary_packets100<10){ - mp_msg(MSGT_DEMUX,MSGL_V,"sync_mpeg_ps: seems to be MP3 stream...\n"); - demux->stream->eof=1; - break; - } - } -} while(ret!=1); - mp_dbg(MSGT_DEMUX,MSGL_DBG2,"demux: %d bad bytes skipped\n",skipped); - if(demux->stream->eof){ - mp_msg(MSGT_DEMUX,MSGL_V,"MPEG Stream reached EOF\n"); - return 0; - } - return 1; -} - -static void demux_seek_mpg(demuxer_t *demuxer, float rel_seek_secs, - float audio_delay, int flags) -{ - 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; - mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demuxer->priv; - int precision = 1; - float oldpts = 0; - int64_t oldpos = demuxer->filepos; - float newpts = 0; - int64_t newpos = (flags & SEEK_ABSOLUTE) ? demuxer->movi_start : oldpos; - - if(mpg_d) - oldpts = mpg_d->last_pts; - newpts = (flags & SEEK_ABSOLUTE) ? 0.0 : oldpts; - //================= seek in MPEG ========================== - //calculate the pts to seek to |