Mercurial > mplayer.hg
annotate libmpdemux/demux_mpg.c @ 13738:39004f891def
seeking based on the largest timestamp in an mpeg stream
It is often more accurate than the current seeking and it has the
additional benefit of giving the (almost) precise total time of the movie.
patch by Michael Behrisch < behrisch at informatik.hu-berlin.de >
author | aurel |
---|---|
date | Sat, 23 Oct 2004 00:05:38 +0000 |
parents | 6a2bc6c93b7b |
children | 3faa873334d7 |
rev | line source |
---|---|
1 | 1 // MPG/VOB file parser for DEMUXER v2.5 by A'rpi/ESP-team |
2 | |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
3 #include <stdio.h> |
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
4 #include <stdlib.h> |
1430 | 5 #include <unistd.h> |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
6 |
1567 | 7 #include "config.h" |
8 #include "mp_msg.h" | |
1973
5216f108cb4f
all error/warn/info messages moved to help_mp-en.h for translation
arpi
parents:
1735
diff
changeset
|
9 #include "help_mp.h" |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
10 |
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
11 #include "stream.h" |
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
12 #include "demuxer.h" |
1466 | 13 #include "parse_es.h" |
2338 | 14 #include "stheader.h" |
4711 | 15 #include "mp3_hdr.h" |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
16 |
524
9105fc95636c
A fast'n'ugly hack to correct DVD VOB playback problems
lgb
parents:
501
diff
changeset
|
17 //#define MAX_PS_PACKETSIZE 2048 |
501 | 18 #define MAX_PS_PACKETSIZE (224*1024) |
19 | |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
20 typedef struct mpg_demuxer { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
21 float last_pts; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
22 float final_pts; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
23 int has_valid_timestamps; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
24 } mpg_demuxer_t; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
25 |
547 | 26 static int mpeg_pts_error=0; |
27 | |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
28 /// Open an mpg physical stream |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
29 int demux_mpg_open(demuxer_t* demuxer) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
30 stream_t *s = demuxer->stream; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
31 off_t pos = stream_tell(s); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
32 off_t end_seq_start = demuxer->movi_end-500000; // 500000 is a wild guess |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
33 float half_pts = 0.0; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
34 mpg_demuxer_t* mpg_d; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
35 |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
36 if (!ds_fill_buffer(demuxer->video)) return 0; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
37 mpg_d = (mpg_demuxer_t*)calloc(1,sizeof(mpg_demuxer_t)); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
38 demuxer->priv = mpg_d; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
39 mpg_d->final_pts = 0.0; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
40 mpg_d->has_valid_timestamps = 1; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
41 if (demuxer->seekable && stream_tell(demuxer->stream) < end_seq_start) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
42 stream_seek(s,(pos + end_seq_start / 2)); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
43 while ((!s->eof) && ds_fill_buffer(demuxer->video) && half_pts == 0.0) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
44 half_pts = mpg_d->last_pts; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
45 } |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
46 stream_seek(s,end_seq_start); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
47 while ((!s->eof) && ds_fill_buffer(demuxer->video)) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
48 if (mpg_d->final_pts < mpg_d->last_pts) mpg_d->final_pts = mpg_d->last_pts; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
49 } |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
50 // educated guess about validity of timestamps |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
51 if (mpg_d->final_pts > 3 * half_pts || mpg_d->final_pts < 1.5 * half_pts) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
52 mpg_d->has_valid_timestamps = 0; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
53 } |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
54 ds_free_packs(demuxer->audio); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
55 ds_free_packs(demuxer->video); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
56 demuxer->stream->eof=0; // clear eof flag |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
57 demuxer->video->eof=0; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
58 demuxer->audio->eof=0; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
59 |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
60 stream_seek(s,pos); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
61 ds_fill_buffer(demuxer->video); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
62 } |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
63 return 1; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
64 } |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
65 |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
66 void demux_close_mpg(demuxer_t* demuxer) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
67 mpg_demuxer_t* mpg_d = demuxer->priv; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
68 if (mpg_d) free(mpg_d); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
69 } |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
70 |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
71 |
1 | 72 static unsigned int read_mpeg_timestamp(stream_t *s,int c){ |
73 int d,e; | |
74 unsigned int pts; | |
75 d=stream_read_word(s); | |
76 e=stream_read_word(s); | |
547 | 77 if( ((c&1)!=1) || ((d&1)!=1) || ((e&1)!=1) ){ |
78 ++mpeg_pts_error; | |
79 return 0; // invalid pts | |
80 } | |
1 | 81 pts=(((c>>1)&7)<<30)|((d>>1)<<15)|(e>>1); |
1567 | 82 mp_dbg(MSGT_DEMUX,MSGL_DBG3,"{%d}",pts); |
1 | 83 return pts; |
84 } | |
85 | |
86 static int demux_mpg_read_packet(demuxer_t *demux,int id){ | |
87 int d; | |
88 int len; | |
89 unsigned char c=0; | |
90 unsigned int pts=0; | |
91 unsigned int dts=0; | |
92 demux_stream_t *ds=NULL; | |
93 | |
1567 | 94 mp_dbg(MSGT_DEMUX,MSGL_DBG3,"demux_read_packet: %X\n",id); |
1 | 95 |
536 | 96 // if(id==0x1F0){ |
97 // demux->synced=0; // force resync after 0x1F0 | |
98 // return -1; | |
99 //} | |
501 | 100 |
1 | 101 // if(id==0x1BA) packet_start_pos=stream_tell(demux->stream); |
501 | 102 if(id<0x1BC || id>=0x1F0) return -1; |
1 | 103 if(id==0x1BE) return -1; // padding stream |
104 if(id==0x1BF) return -1; // private2 | |
105 | |
106 len=stream_read_word(demux->stream); | |
1567 | 107 mp_dbg(MSGT_DEMUX,MSGL_DBG3,"PACKET len=%d",len); |
536 | 108 // if(len==62480){ demux->synced=0;return -1;} /* :) */ |
501 | 109 if(len==0 || len>MAX_PS_PACKETSIZE){ |
1567 | 110 mp_dbg(MSGT_DEMUX,MSGL_DBG2,"Invalid PS packet len: %d\n",len); |
501 | 111 return -2; // invalid packet !!!!!! |
112 } | |
1 | 113 |
547 | 114 mpeg_pts_error=0; |
115 | |
1 | 116 while(len>0){ // Skip stuFFing bytes |
117 c=stream_read_char(demux->stream);--len; | |
118 if(c!=0xFF)break; | |
119 } | |
120 if((c>>6)==1){ // Read (skip) STD scale & size value | |
121 // printf(" STD_scale=%d",(c>>5)&1); | |
122 d=((c&0x1F)<<8)|stream_read_char(demux->stream); | |
123 len-=2; | |
124 // printf(" STD_size=%d",d); | |
125 c=stream_read_char(demux->stream); | |
126 } | |
127 // Read System-1 stream timestamps: | |
128 if((c>>4)==2){ | |
129 pts=read_mpeg_timestamp(demux->stream,c); | |
130 len-=4; | |
131 } else | |
132 if((c>>4)==3){ | |
133 pts=read_mpeg_timestamp(demux->stream,c); | |
134 c=stream_read_char(demux->stream); | |
135 if((c>>4)!=1) pts=0; //printf("{ERROR4}"); | |
136 dts=read_mpeg_timestamp(demux->stream,c); | |
137 len-=4+1+4; | |
138 } else | |
139 if((c>>6)==2){ | |
140 int pts_flags; | |
141 int hdrlen; | |
142 // System-2 (.VOB) stream: | |
492 | 143 if((c>>4)&3) { |
1973
5216f108cb4f
all error/warn/info messages moved to help_mp-en.h for translation
arpi
parents:
1735
diff
changeset
|
144 mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_EncryptedVOB); |
492 | 145 } |
1 | 146 c=stream_read_char(demux->stream); pts_flags=c>>6; |
147 c=stream_read_char(demux->stream); hdrlen=c; | |
148 len-=2; | |
1567 | 149 mp_dbg(MSGT_DEMUX,MSGL_DBG3," hdrlen=%d (len=%d)",hdrlen,len); |
150 if(hdrlen>len){ mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: invalid header length \n"); return -1;} | |
7671 | 151 if(pts_flags==2 && hdrlen>=5){ |
1 | 152 c=stream_read_char(demux->stream); |
153 pts=read_mpeg_timestamp(demux->stream,c); | |
154 len-=5;hdrlen-=5; | |
155 } else | |
7671 | 156 if(pts_flags==3 && hdrlen>=10){ |
1 | 157 c=stream_read_char(demux->stream); |
158 pts=read_mpeg_timestamp(demux->stream,c); | |
159 c=stream_read_char(demux->stream); | |
160 dts=read_mpeg_timestamp(demux->stream,c); | |
161 len-=10;hdrlen-=10; | |
162 } | |
163 len-=hdrlen; | |
164 if(hdrlen>0) stream_skip(demux->stream,hdrlen); // skip header bytes | |
165 | |
166 //============== DVD Audio sub-stream ====================== | |
167 if(id==0x1BD){ | |
552 | 168 int aid=stream_read_char(demux->stream);--len; |
1 | 169 if(len<3) return -1; // invalid audio packet |
552 | 170 |
171 // AID: | |
172 // 0x20..0x3F subtitle | |
173 // 0x80..0x9F AC3 audio | |
174 // 0xA0..0xBF PCM audio | |
175 | |
176 if((aid & 0xE0) == 0x20){ | |
177 // subtitle: | |
178 aid&=0x1F; | |
426 | 179 |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
180 if(!demux->s_streams[aid]){ |
1567 | 181 mp_msg(MSGT_DEMUX,MSGL_V,"==> Found subtitle: %d\n",aid); |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
182 demux->s_streams[aid]=1; |
552 | 183 } |
184 | |
185 if(demux->sub->id==aid){ | |
186 ds=demux->sub; | |
187 } | |
188 | |
3955 | 189 } else if((aid & 0xC0) == 0x80 || (aid & 0xE0) == 0x00) { |
552 | 190 |
191 // aid=128+(aid&0x7F); | |
192 // aid=0x80..0xBF | |
193 | |
1289 | 194 if(!demux->a_streams[aid]) new_sh_audio(demux,aid); |
552 | 195 if(demux->audio->id==-1) demux->audio->id=aid; |
426 | 196 |
197 if(demux->audio->id==aid){ | |
7671 | 198 int type; |
426 | 199 ds=demux->audio; |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
200 if(!ds->sh) ds->sh=demux->a_streams[aid]; |
1 | 201 // READ Packet: Skip additional audio header data: |
7671 | 202 c=stream_read_char(demux->stream);//num of frames |
203 type=stream_read_char(demux->stream);//startpos hi | |
204 type=(type<<8)|stream_read_char(demux->stream);//startpos lo | |
205 // printf("\r[%02X][%04X]",c,type); | |
1 | 206 len-=3; |
7671 | 207 if((aid&0xE0)==0xA0 && len>=3){ |
208 unsigned char* hdr; | |
209 // save audio header as codecdata! | |
210 if(!((sh_audio_t*)(ds->sh))->codecdata_len){ | |
211 ((sh_audio_t*)(ds->sh))->codecdata=malloc(3); | |
212 ((sh_audio_t*)(ds->sh))->codecdata_len=3; | |
213 } | |
214 hdr=((sh_audio_t*)(ds->sh))->codecdata; | |
215 // read LPCM header: | |
216 // emphasis[1], mute[1], rvd[1], frame number[5]: | |
217 hdr[0]=stream_read_char(demux->stream); | |
218 // printf(" [%01X:%02d]",c>>5,c&31); | |
219 // quantization[2],freq[2],rvd[1],channels[3] | |
220 hdr[1]=stream_read_char(demux->stream); | |
221 // printf("[%01X:%01X] ",c>>4,c&15); | |
222 // dynamic range control (0x80=off): | |
223 hdr[2]=stream_read_char(demux->stream); | |
224 // printf("[%02X] ",c); | |
225 len-=3; | |
226 if(len<=0) mp_msg(MSGT_DEMUX,MSGL_V,"End of packet while searching for PCM header\n"); | |
1 | 227 } |
7671 | 228 // printf(" \n"); |
552 | 229 } // if(demux->audio->id==aid) |
230 | |
1567 | 231 } else mp_msg(MSGT_DEMUX,MSGL_V,"Unknown 0x1BD substream: 0x%02X \n",aid); |
552 | 232 |
233 } //if(id==0x1BD) | |
1 | 234 |
235 } else { | |
539 | 236 if(c!=0x0f){ |
1567 | 237 mp_msg(MSGT_DEMUX,MSGL_V," {ERROR5,c=%d} \n",c); |
539 | 238 return -1; // invalid packet !!!!!! |
239 } | |
1 | 240 } |
1567 | 241 if(mpeg_pts_error) mp_msg(MSGT_DEMUX,MSGL_V," {PTS_err:%d} \n",mpeg_pts_error); |
242 mp_dbg(MSGT_DEMUX,MSGL_DBG3," => len=%d\n",len); | |
1 | 243 |
501 | 244 // if(len<=0 || len>MAX_PS_PACKETSIZE) return -1; // Invalid packet size |
245 if(len<=0 || len>MAX_PS_PACKETSIZE){ | |
1567 | 246 mp_dbg(MSGT_DEMUX,MSGL_DBG2,"Invalid PS data len: %d\n",len); |
501 | 247 return -1; // invalid packet !!!!!! |
248 } | |
1 | 249 |
250 if(id>=0x1C0 && id<=0x1DF){ | |
251 // mpeg audio | |
252 int aid=id-0x1C0; | |
1289 | 253 if(!demux->a_streams[aid]) new_sh_audio(demux,aid); |
1 | 254 if(demux->audio->id==-1) demux->audio->id=aid; |
255 if(demux->audio->id==aid){ | |
256 ds=demux->audio; | |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
257 if(!ds->sh) ds->sh=demux->a_streams[aid]; |
1 | 258 } |
259 } else | |
260 if(id>=0x1E0 && id<=0x1EF){ | |
261 // mpeg video | |
262 int aid=id-0x1E0; | |
1289 | 263 if(!demux->v_streams[aid]) new_sh_video(demux,aid); |
1 | 264 if(demux->video->id==-1) demux->video->id=aid; |
426 | 265 if(demux->video->id==aid){ |
266 ds=demux->video; | |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
267 if(!ds->sh) ds->sh=demux->v_streams[aid]; |
426 | 268 } |
1 | 269 } |
270 | |
271 if(ds){ | |
1567 | 272 mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_MPG: Read %d data bytes from packet %04X\n",len,id); |
1 | 273 // printf("packet start = 0x%X \n",stream_tell(demux->stream)-packet_start_pos); |
1735 | 274 ds_read_packet(ds,demux->stream,len,pts/90000.0f,demux->filepos,0); |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
275 if (demux->priv) ((mpg_demuxer_t*)demux->priv)->last_pts = pts/90000.0f; |
554 | 276 // if(ds==demux->sub) parse_dvdsub(ds->last->buffer,ds->last->len); |
1 | 277 return 1; |
278 } | |
1567 | 279 mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_MPG: Skipping %d data bytes from packet %04X\n",len,id); |
536 | 280 if(len<=2356) stream_skip(demux->stream,len); |
1 | 281 return 0; |
282 } | |
283 | |
587
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
284 int num_elementary_packets100=0; |
8511095c5283
stage#1 completed: c files no more included from mplayer.c
arpi_esp
parents:
554
diff
changeset
|
285 int num_elementary_packets101=0; |
9069
0d2b25a821c9
raw mpeg4-es support (you need to set -fps manually!)
arpi
parents:
8254
diff
changeset
|
286 int num_elementary_packets12x=0; |
1162 | 287 int num_elementary_packets1B6=0; |
1338
345585097137
mpeg PES steram support (only 1E0 & 1C0 packets, no 1BA/1BB headers)
arpi
parents:
1331
diff
changeset
|
288 int num_elementary_packetsPES=0; |
9824 | 289 int num_h264_slice=0; //combined slice |
290 int num_h264_dpa=0; //DPA Slice | |
291 int num_h264_dpb=0; //DPB Slice | |
292 int num_h264_dpc=0; //DPC Slice | |
293 int num_h264_idr=0; //IDR Slice | |
294 int num_h264_sps=0; | |
295 int num_h264_pps=0; | |
296 | |
4711 | 297 int num_mp3audio_packets=0; |
1 | 298 |
299 int demux_mpg_es_fill_buffer(demuxer_t *demux){ | |
300 // Elementary video stream | |
301 if(demux->stream->eof) return 0; | |
302 demux->filepos=stream_tell(demux->stream); | |
1735 | 303 ds_read_packet(demux->video,demux->stream,STREAM_BUFFER_SIZE,0,demux->filepos,0); |
1 | 304 return 1; |
305 } | |
306 | |
307 int demux_mpg_fill_buffer(demuxer_t *demux){ | |
308 unsigned int head=0; | |
309 int skipped=0; | |
5570
3a8d8c51355a
max_packs increased for some dvd with too many audio/sub
arpi
parents:
4711
diff
changeset
|
310 int max_packs=256; // 512kbyte |
1 | 311 int ret=0; |
312 | |
313 // System stream | |
314 do{ | |
315 demux->filepos=stream_tell(demux->stream); | |
316 head=stream_read_dword(demux->stream); | |
547 | 317 if((head&0xFFFFFF00)!=0x100){ |
318 // sync... | |
319 demux->filepos-=skipped; | |
320 while(1){ | |
536 | 321 int c=stream_read_char(demux->stream); |
322 if(c<0) break; //EOF | |
323 head<<=8; | |
324 if(head!=0x100){ | |
325 head|=c; | |
4711 | 326 if(mp_check_mp3_header(head)) ++num_mp3audio_packets; |
536 | 327 ++skipped; //++demux->filepos; |
328 continue; | |
329 } | |
330 head|=c; | |
331 break; | |
547 | 332 } |
333 demux->filepos+=skipped; | |
1 | 334 } |
335 if(stream_eof(demux->stream)) break; | |
336 // sure: head=0x000001XX | |
1567 | 337 mp_dbg(MSGT_DEMUX,MSGL_DBG4,"*** head=0x%X\n",head); |
1 | 338 if(demux->synced==0){ |
3770 | 339 if(head==0x1BA) demux->synced=1; //else |
340 // if(head==0x1BD || (head>=0x1C0 && head<=0x1EF)) demux->synced=3; // PES? | |
1 | 341 } else |
342 if(demux->synced==1){ | |
929 | 343 if(head==0x1BB || head==0x1BD || (head>=0x1C0 && head<=0x1EF)){ |
1 | 344 demux->synced=2; |
1567 | 345 mp_msg(MSGT_DEMUX,MSGL_V,"system stream synced at 0x%X (%d)!\n",demux->filepos,demux->filepos); |
536 | 346 num_elementary_packets100=0; // requires for re-sync! |
347 num_elementary_packets101=0; // requires for re-sync! | |
1 | 348 } else demux->synced=0; |
349 } // else | |
3255
ee28577dad02
combined PS/PES sync to allow .VDR playback from stdin
arpi
parents:
2555
diff
changeset
|
350 if(demux->synced>=2){ |
1 | 351 ret=demux_mpg_read_packet(demux,head); |
352 if(!ret) | |
353 if(--max_packs==0){ | |
354 demux->stream->eof=1; | |
1973
5216f108cb4f
all error/warn/info messages moved to help_mp-en.h for translation
arpi
parents:
1735
diff
changeset
|
355 mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_DoesntContainSelectedStream); |
1 | 356 return 0; |
357 } | |
3255
ee28577dad02
combined PS/PES sync to allow .VDR playback from stdin
arpi
parents:
2555
diff
changeset
|
358 if(demux->synced==3) demux->synced=(ret==1)?2:0; // PES detect |
1 | 359 } else { |
360 if(head>=0x100 && head<0x1B0){ | |
1162 | 361 if(head==0x100) ++num_elementary_packets100; else |
9069
0d2b25a821c9
raw mpeg4-es support (you need to set -fps manually!)
arpi
parents:
8254
diff
changeset
|
362 if(head==0x101) ++num_elementary_packets101; else |
0d2b25a821c9
raw mpeg4-es support (you need to set -fps manually!)
arpi
parents:
8254
diff
changeset
|
363 if(head>=0x120 && head<=0x12F) ++num_elementary_packets12x; |
9824 | 364 |
365 if((head&~0x60) == 0x101) ++num_h264_slice; else | |
366 if((head&~0x60) == 0x102) ++num_h264_dpa; else | |
367 if((head&~0x60) == 0x103) ++num_h264_dpb; else | |
368 if((head&~0x60) == 0x104) ++num_h264_dpc; else | |
369 if((head&~0x60) == 0x105 && head != 0x105) ++num_h264_idr; else | |
370 if((head&~0x60) == 0x107 && head != 0x107) ++num_h264_sps; else | |
371 if((head&~0x60) == 0x108 && head != 0x108) ++num_h264_pps; | |
372 | |
1567 | 373 mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... elementary video packet found: %03X\n",head); |
1162 | 374 } else |
4711 | 375 if((head>=0x1C0 && head<0x1F0) || head==0x1BD){ |
1338
345585097137
mpeg PES steram support (only 1E0 & 1C0 packets, no 1BA/1BB headers)
arpi
parents:
1331
diff
changeset
|
376 ++num_elementary_packetsPES; |
1567 | 377 mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... PES packet found: %03X\n",head); |
1338
345585097137
mpeg PES steram support (only 1E0 & 1C0 packets, no 1BA/1BB headers)
arpi
parents:
1331
diff
changeset
|
378 } else |
1162 | 379 if(head==0x1B6) ++num_elementary_packets1B6; |
1 | 380 #if 1 |
1338
345585097137
mpeg PES steram support (only 1E0 & 1C0 packets, no 1BA/1BB headers)
arpi
parents:
1331
diff
changeset
|
381 if( ( (num_elementary_packets100>50 && num_elementary_packets101>50) || |
345585097137
mpeg PES steram support (only 1E0 & 1C0 packets, no 1BA/1BB headers)
arpi
parents:
1331
diff
changeset
|
382 (num_elementary_packetsPES>50) ) && skipped>4000000){ |
1567 | 383 mp_msg(MSGT_DEMUX,MSGL_V,"sync_mpeg_ps: seems to be ES/PES stream...\n"); |
1 | 384 demux->stream->eof=1; |
385 break; | |
386 } | |
4711 | 387 if(num_mp3audio_packets>100 && num_elementary_packets100<10){ |
388 mp_msg(MSGT_DEMUX,MSGL_V,"sync_mpeg_ps: seems to be MP3 stream...\n"); | |
389 demux->stream->eof=1; | |
390 break; | |
391 } | |
1 | 392 #endif |
393 } | |
394 } while(ret!=1); | |
1567 | 395 mp_dbg(MSGT_DEMUX,MSGL_DBG2,"demux: %d bad bytes skipped\n",skipped); |
1 | 396 if(demux->stream->eof){ |
1567 | 397 mp_msg(MSGT_DEMUX,MSGL_V,"MPEG Stream reached EOF\n"); |
1 | 398 return 0; |
399 } | |
400 return 1; | |
401 } | |
402 | |
8123
9fc45fe0d444
*HUGE* set of compiler warning fixes, unused variables removal
arpi
parents:
7671
diff
changeset
|
403 extern void resync_audio_stream(sh_audio_t *sh_audio); |
9fc45fe0d444
*HUGE* set of compiler warning fixes, unused variables removal
arpi
parents:
7671
diff
changeset
|
404 extern void skip_audio_frame(sh_audio_t *sh_audio); |
9fc45fe0d444
*HUGE* set of compiler warning fixes, unused variables removal
arpi
parents:
7671
diff
changeset
|
405 |
1466 | 406 void demux_seek_mpg(demuxer_t *demuxer,float rel_seek_secs,int flags){ |
407 demux_stream_t *d_audio=demuxer->audio; | |
408 demux_stream_t *d_video=demuxer->video; | |
409 sh_audio_t *sh_audio=d_audio->sh; | |
410 sh_video_t *sh_video=d_video->sh; | |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
411 mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demuxer->priv; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
412 int precision = 1; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
413 float oldpts = mpg_d->last_pts; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
414 off_t oldpos = demuxer->filepos; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
415 float newpts = (flags & 1) ? 0.0 : oldpts; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
416 off_t newpos = (flags & 1) ? demuxer->movi_start : oldpos; |
1466 | 417 |
418 //================= seek in MPEG ========================== | |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
419 //calculate the pts to seek to |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
420 if(flags & 2) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
421 if (mpg_d->final_pts > 0.0) |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
422 newpts += mpg_d->final_pts * rel_seek_secs; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
423 else |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
424 newpts += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) * oldpts / oldpos; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
425 } else |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
426 newpts += rel_seek_secs; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
427 if (newpts < 0) newpts = 0; |
1628
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
428 |
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
429 if(flags&2){ |
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
430 // float seek 0..1 |
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
431 newpos+=(demuxer->movi_end-demuxer->movi_start)*rel_seek_secs; |
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
432 } else { |
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
433 // time seek (secs) |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
434 if (mpg_d && mpg_d->has_valid_timestamps) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
435 if (mpg_d->final_pts > 0.0) |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
436 newpos += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) / mpg_d->final_pts; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
437 else if (oldpts > 0.0) |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
438 newpos += rel_seek_secs * (oldpos - demuxer->movi_start) / oldpts; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
439 } else if(!sh_video || !sh_video->i_bps) // unspecified or VBR |
1628
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
440 newpos+=2324*75*rel_seek_secs; // 174.3 kbyte/sec |
1466 | 441 else |
1628
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
442 newpos+=sh_video->i_bps*rel_seek_secs; |
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
443 } |
1466 | 444 |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
445 while (1) { |
4391
6394c1e9e770
DVD start position handling changed (progbar/eta fix)
arpi
parents:
3975
diff
changeset
|
446 if(newpos<demuxer->movi_start){ |
6394c1e9e770
DVD start position handling changed (progbar/eta fix)
arpi
parents:
3975
diff
changeset
|
447 if(demuxer->stream->type!=STREAMTYPE_VCD) demuxer->movi_start=0; // for VCD |
6394c1e9e770
DVD start position handling changed (progbar/eta fix)
arpi
parents:
3975
diff
changeset
|
448 if(newpos<demuxer->movi_start) newpos=demuxer->movi_start; |
6394c1e9e770
DVD start position handling changed (progbar/eta fix)
arpi
parents:
3975
diff
changeset
|
449 } |
1628
bd1ef18cdf33
seeking flags implemented: 0x1=rel/abs and 0x2=time/percent
arpi
parents:
1597
diff
changeset
|
450 |
1466 | 451 #ifdef _LARGEFILE_SOURCE |
452 newpos&=~((long long)STREAM_BUFFER_SIZE-1); /* sector boundary */ | |
453 #else | |
454 newpos&=~(STREAM_BUFFER_SIZE-1); /* sector boundary */ | |
455 #endif | |
456 stream_seek(demuxer->stream,newpos); | |
457 | |
458 // re-sync video: | |
459 videobuf_code_len=0; // reset ES stream buffer | |
460 | |
461 ds_fill_buffer(d_video); | |
462 if(sh_audio){ | |
463 ds_fill_buffer(d_audio); | |
464 resync_audio_stream(sh_audio); | |
465 } | |
466 | |
467 while(1){ | |
468 int i; | |
469 if(sh_audio && !d_audio->eof && d_video->pts && d_audio->pts){ | |
470 float a_pts=d_audio->pts; | |
471 a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps; | |
472 if(d_video->pts>a_pts){ | |
473 skip_audio_frame(sh_audio); // sync audio | |
474 continue; | |
475 } | |
476 } | |
477 i=sync_video_packet(d_video); | |
478 if(i==0x1B3 || i==0x1B8) break; // found it! | |
479 if(!i || !skip_video_packet(d_video)) break; // EOF? | |
480 } | |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
481 if (!precision || abs(newpts - mpg_d->last_pts) < 0.5 || (mpg_d->last_pts == oldpts)) break; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
482 if ((newpos - oldpos) * (mpg_d->last_pts - oldpts) < 0) { // invalid timestamps |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
483 mpg_d->has_valid_timestamps = 0; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
484 break; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
485 } |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
486 precision--; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
487 //prepare another seek because we are off by more than 0.5s |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
488 newpos += (newpts - mpg_d->last_pts) * (newpos - oldpos) / (mpg_d->last_pts - oldpts); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
489 ds_free_packs(d_audio); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
490 ds_free_packs(d_video); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
491 demuxer->stream->eof=0; // clear eof flag |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
492 d_video->eof=0; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
493 d_audio->eof=0; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
494 } |
1466 | 495 } |
496 | |
8208
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
497 int demux_mpg_control(demuxer_t *demuxer,int cmd, void *arg){ |
8254
772d6d27fd66
warning patch by (Dominik Mierzejewski <dominik at rangers dot eu dot org>)
michael
parents:
8208
diff
changeset
|
498 /* demux_stream_t *d_audio=demuxer->audio;*/ |
8208
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
499 demux_stream_t *d_video=demuxer->video; |
8254
772d6d27fd66
warning patch by (Dominik Mierzejewski <dominik at rangers dot eu dot org>)
michael
parents:
8208
diff
changeset
|
500 /* sh_audio_t *sh_audio=d_audio->sh;*/ |
8208
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
501 sh_video_t *sh_video=d_video->sh; |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
502 mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demuxer->priv; |
8208
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
503 |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
504 switch(cmd) { |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
505 case DEMUXER_CTRL_GET_TIME_LENGTH: |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
506 if (mpg_d && mpg_d->has_valid_timestamps) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
507 *((unsigned long *)arg)=(long)mpg_d->final_pts; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
508 return DEMUXER_CTRL_GUESS; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
509 } |
13649 | 510 if(!sh_video || !sh_video->i_bps) // unspecified or VBR |
8208
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
511 return DEMUXER_CTRL_DONTKNOW; |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
512 *((unsigned long *)arg)=(demuxer->movi_end-demuxer->movi_start)/sh_video->i_bps; |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
513 return DEMUXER_CTRL_GUESS; |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
514 |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
515 case DEMUXER_CTRL_GET_PERCENT_POS: |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
516 if (demuxer->movi_end==demuxer->movi_start) |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
517 return DEMUXER_CTRL_DONTKNOW; |
13738
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
518 if (mpg_d && mpg_d->has_valid_timestamps && mpg_d->final_pts > 0.0) { |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
519 *((int *)arg)=(int)(100 * mpg_d->last_pts / mpg_d->final_pts); |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
520 return DEMUXER_CTRL_OK; |
39004f891def
seeking based on the largest timestamp in an mpeg stream
aurel
parents:
13649
diff
changeset
|
521 } |
8208
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
522 *((int *)arg)=(int)((demuxer->filepos-demuxer->movi_start)/((demuxer->movi_end-demuxer->movi_start)/100)); |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
523 return DEMUXER_CTRL_OK; |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
524 |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
525 default: |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
526 return DEMUXER_CTRL_NOTIMPL; |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
527 } |
ae5a2ae1c349
demuxer_control(), percent position and time length query implemented in
arpi
parents:
8123
diff
changeset
|
528 } |