Mercurial > mplayer.hg
comparison libmpdemux/demux_avi.c @ 2310:9e059416eea6
libdemuxer...
author | arpi |
---|---|
date | Sat, 20 Oct 2001 18:49:08 +0000 |
parents | demux_avi.c@18f4dd5d568f |
children | d0e1c32ad432 |
comparison
equal
deleted
inserted
replaced
2309:3128b9d8b4ea | 2310:9e059416eea6 |
---|---|
1 // AVI file parser for DEMUXER v2.9 by A'rpi/ESP-team | |
2 | |
3 #include <stdio.h> | |
4 #include <stdlib.h> | |
5 #include <unistd.h> | |
6 | |
7 #include "config.h" | |
8 #include "mp_msg.h" | |
9 #include "help_mp.h" | |
10 | |
11 #include "stream.h" | |
12 #include "demuxer.h" | |
13 | |
14 #include "wine/mmreg.h" | |
15 #include "wine/avifmt.h" | |
16 #include "wine/vfw.h" | |
17 | |
18 #include "codec-cfg.h" | |
19 #include "stheader.h" | |
20 | |
21 #include "aviheader.h" | |
22 | |
23 // Select ds from ID | |
24 demux_stream_t* demux_avi_select_stream(demuxer_t *demux,unsigned int id){ | |
25 int stream_id=avi_stream_id(id); | |
26 | |
27 // printf("demux_avi_select_stream(%d) {a:%d/v:%d}\n",stream_id, | |
28 // demux->audio->id,demux->video->id); | |
29 | |
30 if(demux->video->id==-1) | |
31 if(demux->v_streams[stream_id]) | |
32 demux->video->id=stream_id; | |
33 | |
34 if(demux->audio->id==-1) | |
35 if(demux->a_streams[stream_id]) | |
36 demux->audio->id=stream_id; | |
37 | |
38 if(stream_id==demux->audio->id){ | |
39 if(!demux->audio->sh){ | |
40 demux->audio->sh=demux->a_streams[stream_id]; | |
41 mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected AVI audio ID = %d\n",demux->audio->id); | |
42 } | |
43 return demux->audio; | |
44 } | |
45 if(stream_id==demux->video->id){ | |
46 if(!demux->video->sh){ | |
47 demux->video->sh=demux->v_streams[stream_id]; | |
48 mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected AVI video ID = %d\n",demux->video->id); | |
49 } | |
50 return demux->video; | |
51 } | |
52 if(id!=mmioFOURCC('J','U','N','K')){ | |
53 // unknown | |
54 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Unknown chunk: %.4s (%X)\n",(char *) &id,id); | |
55 } | |
56 return NULL; | |
57 } | |
58 | |
59 static int demux_avi_read_packet(demuxer_t *demux,unsigned int id,unsigned int len,int idxpos,int flags){ | |
60 avi_priv_t *priv=demux->priv; | |
61 int skip; | |
62 float pts=0; | |
63 demux_stream_t *ds=demux_avi_select_stream(demux,id); | |
64 | |
65 mp_dbg(MSGT_DEMUX,MSGL_DBG3,"demux_avi.read_packet: %X\n",id); | |
66 | |
67 if(ds==demux->audio){ | |
68 | |
69 if(priv->pts_corrected==0){ | |
70 // printf("\rYYY-A A: %5.3f V: %5.3f \n",priv->avi_audio_pts,priv->avi_video_pts); | |
71 if(priv->pts_has_video){ | |
72 // we have video pts now | |
73 float delay=(float)priv->pts_corr_bytes/((sh_audio_t*)(ds->sh))->wf->nAvgBytesPerSec; | |
74 mp_msg(MSGT_DEMUX,MSGL_V,"XXX initial v_pts=%5.3f a_pos=%d (%5.3f) \n",priv->avi_audio_pts,priv->pts_corr_bytes,delay); | |
75 //priv->pts_correction=-priv->avi_audio_pts+delay; | |
76 priv->pts_correction=delay-priv->avi_audio_pts; | |
77 priv->avi_audio_pts+=priv->pts_correction; | |
78 priv->pts_corrected=1; | |
79 } else | |
80 priv->pts_corr_bytes+=len; | |
81 } | |
82 pts=priv->avi_audio_pts; //+priv->pts_correction; | |
83 priv->avi_audio_pts=0; | |
84 } else | |
85 if(ds==demux->video){ | |
86 // video | |
87 if(priv->skip_video_frames>0){ | |
88 // drop frame (seeking) | |
89 --priv->skip_video_frames; | |
90 ds=NULL; | |
91 // } else { | |
92 // pts=priv->avi_video_pts; | |
93 } | |
94 // ezt a 2 sort lehet hogy fell kell majd cserelni: | |
95 //priv->avi_video_pts+=avi_pts_frametime; | |
96 //priv->avi_video_pts+=(float)avi_header.video.dwScale/(float)avi_header.video.dwRate; | |
97 //priv->avi_video_pts+=((sh_video_t*)ds->sh)->frametime; | |
98 // FIXME!!! | |
99 #if 1 | |
100 // printf("ds=0x%X\n",ds); | |
101 // printf("packno=%d\n",ds->pack_no); | |
102 // printf("### pack_no=%d\n",demux->video->pack_no+demux->video->packs); | |
103 priv->avi_video_pts = (demux->video->pack_no+demux->video->packs) * | |
104 (float)((sh_video_t*)demux->video->sh)->video.dwScale / | |
105 (float)((sh_video_t*)demux->video->sh)->video.dwRate; | |
106 #else | |
107 priv->avi_video_pts+=(float)((sh_video_t*)(demux->video->sh))->video.dwScale/(float)((sh_video_t*)(demux->video->sh))->video.dwRate; | |
108 // priv->avi_video_pts+=avi_video_ftime; | |
109 #endif | |
110 // printf("\rYYY-V A: %5.3f V: %5.3f \n",priv->avi_audio_pts,priv->avi_video_pts); | |
111 priv->avi_audio_pts=priv->avi_video_pts+priv->pts_correction; | |
112 priv->pts_has_video=1; | |
113 | |
114 pts=priv->avi_video_pts; | |
115 | |
116 //printf("read pack_no: %d pts %5.3f \n",demux->video->pack_no+demux->video->packs,pts); | |
117 | |
118 } | |
119 | |
120 // len=stream_read_dword_le(demux->stream); | |
121 skip=(len+1)&(~1); // total bytes in this chunk | |
122 | |
123 if(ds){ | |
124 mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_AVI: Read %d data bytes from packet %04X\n",len,id); | |
125 ds_read_packet(ds,demux->stream,len,pts,idxpos,flags); | |
126 skip-=len; | |
127 } | |
128 if(skip){ | |
129 mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_AVI: Skipping %d bytes from packet %04X\n",skip,id); | |
130 stream_skip(demux->stream,skip); | |
131 } | |
132 return ds?1:0; | |
133 } | |
134 | |
135 // return value: | |
136 // 0 = EOF or no stream found | |
137 // 1 = successfully read a packet | |
138 int demux_avi_fill_buffer(demuxer_t *demux){ | |
139 avi_priv_t *priv=demux->priv; | |
140 unsigned int id=0; | |
141 unsigned int len; | |
142 int max_packs=128; | |
143 int ret=0; | |
144 | |
145 do{ | |
146 int flags=0; | |
147 AVIINDEXENTRY *idx=NULL; | |
148 #if 0 | |
149 demux->filepos=stream_tell(demux->stream); | |
150 if(demux->filepos>=demux->movi_end){ | |
151 demux->stream->eof=1; | |
152 return 0; | |
153 } | |
154 if(stream_eof(demux->stream)) return 0; | |
155 #endif | |
156 if(priv->idx_size>0 && priv->idx_pos<priv->idx_size){ | |
157 unsigned int pos; | |
158 | |
159 //if(priv->idx_pos<0) printf("Fatal! idx_pos=%d\n",priv->idx_pos); | |
160 | |
161 idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++]; | |
162 | |
163 //printf("[%d]",priv->idx_pos);fflush(stdout); | |
164 | |
165 //stream_seek(demux->stream,idx.dwChunkOffset); | |
166 //printf("IDX pos=%X idx.pos=%X idx.size=%X idx.flags=%X\n",demux->filepos, | |
167 // pos-4,idx->dwChunkLength,idx->dwFlags); | |
168 if(idx->dwFlags&AVIIF_LIST){ | |
169 // LIST | |
170 continue; | |
171 } | |
172 if(!demux_avi_select_stream(demux,idx->ckid)){ | |
173 mp_dbg(MSGT_DEMUX,MSGL_DBG3,"Skip chunk %.4s (0x%X) \n",(char *)&idx->ckid,(unsigned int)idx->ckid); | |
174 continue; // skip this chunk | |
175 } | |
176 | |
177 pos=idx->dwChunkOffset+priv->idx_offset; | |
178 if(pos<demux->movi_start || pos>=demux->movi_end){ | |
179 mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! idx=0x%X \n",pos); | |
180 continue; | |
181 } | |
182 #if 0 | |
183 if(pos!=demux->filepos){ | |
184 mp_msg(MSGT_DEMUX,MSGL_V,"Warning! pos=0x%X idx.pos=0x%X diff=%d \n",demux->filepos,pos,pos-demux->filepos); | |
185 } | |
186 #endif | |
187 stream_seek(demux->stream,pos); | |
188 demux->filepos=stream_tell(demux->stream); | |
189 id=stream_read_dword_le(demux->stream); | |
190 if(stream_eof(demux->stream)) return 0; // EOF! | |
191 | |
192 if(id!=idx->ckid){ | |
193 mp_msg(MSGT_DEMUX,MSGL_V,"ChunkID mismatch! raw=%.4s idx=%.4s \n",(char *)&id,(char *)&idx->ckid); | |
194 id=idx->ckid; | |
195 // continue; | |
196 } | |
197 len=stream_read_dword_le(demux->stream); | |
198 // if((len&(~1))!=(idx->dwChunkLength&(~1))){ | |
199 // if((len)!=(idx->dwChunkLength)){ | |
200 if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){ | |
201 mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%ld \n",len,idx->dwChunkLength); | |
202 len=idx->dwChunkLength; | |
203 // continue; | |
204 } | |
205 if(idx->dwFlags&AVIIF_KEYFRAME) flags=1; | |
206 } else { | |
207 demux->filepos=stream_tell(demux->stream); | |
208 if(demux->filepos>=demux->movi_end){ | |
209 demux->stream->eof=1; | |
210 return 0; | |
211 } | |
212 id=stream_read_dword_le(demux->stream); | |
213 len=stream_read_dword_le(demux->stream); | |
214 if(stream_eof(demux->stream)) return 0; // EOF! | |
215 | |
216 if(id==mmioFOURCC('L','I','S','T')){ | |
217 id=stream_read_dword_le(demux->stream); // list type | |
218 continue; | |
219 } | |
220 } | |
221 ret=demux_avi_read_packet(demux,id,len,priv->idx_pos-1,flags); | |
222 // if(!ret && priv->skip_video_frames<=0) | |
223 // if(--max_packs==0){ | |
224 // demux->stream->eof=1; | |
225 // mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_DoesntContainSelectedStream); | |
226 // return 0; | |
227 // } | |
228 } while(ret!=1); | |
229 return 1; | |
230 } | |
231 | |
232 | |
233 // return value: | |
234 // 0 = EOF or no stream found | |
235 // 1 = successfully read a packet | |
236 int demux_avi_fill_buffer_ni(demuxer_t *demux,demux_stream_t* ds){ | |
237 avi_priv_t *priv=demux->priv; | |
238 unsigned int id=0; | |
239 unsigned int len; | |
240 int max_packs=128; | |
241 int ret=0; | |
242 | |
243 do{ | |
244 int flags=0; | |
245 AVIINDEXENTRY *idx=NULL; | |
246 int idx_pos=0; | |
247 demux->filepos=stream_tell(demux->stream); | |
248 | |
249 if(ds==demux->video) idx_pos=priv->idx_pos_v++; else | |
250 if(ds==demux->audio) idx_pos=priv->idx_pos_a++; else | |
251 idx_pos=priv->idx_pos++; | |
252 | |
253 if(priv->idx_size>0 && idx_pos<priv->idx_size){ | |
254 unsigned int pos; | |
255 idx=&((AVIINDEXENTRY *)priv->idx)[idx_pos]; | |
256 // idx=&priv->idx[idx_pos]; | |
257 | |
258 if(idx->dwFlags&AVIIF_LIST){ | |
259 // LIST | |
260 continue; | |
261 } | |
262 if(ds && demux_avi_select_stream(demux,idx->ckid)!=ds){ | |
263 mp_dbg(MSGT_DEMUX,MSGL_DBG3,"Skip chunk %.4s (0x%X) \n",(char *)&idx->ckid,(unsigned int)idx->ckid); | |
264 continue; // skip this chunk | |
265 } | |
266 | |
267 pos=idx->dwChunkOffset+priv->idx_offset; | |
268 if(pos<demux->movi_start || pos>=demux->movi_end){ | |
269 mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! current=0x%X idx=0x%X \n",demux->filepos,pos); | |
270 continue; | |
271 } | |
272 #if 0 | |
273 if(pos!=demux->filepos){ | |
274 mp_msg(MSGT_DEMUX,MSGL_V,"Warning! pos=0x%X idx.pos=0x%X diff=%d \n",demux->filepos,pos,pos-demux->filepos); | |
275 } | |
276 #endif | |
277 stream_seek(demux->stream,pos); | |
278 | |
279 id=stream_read_dword_le(demux->stream); | |
280 | |
281 if(stream_eof(demux->stream)) return 0; | |
282 | |
283 if(id!=idx->ckid){ | |
284 mp_msg(MSGT_DEMUX,MSGL_V,"ChunkID mismatch! raw=%.4s idx=%.4s \n",(char *)&id,(char *)&idx->ckid); | |
285 id=idx->ckid; | |
286 // continue; | |
287 } | |
288 len=stream_read_dword_le(demux->stream); | |
289 // if((len&(~1))!=(idx->dwChunkLength&(~1))){ | |
290 // if((len)!=(idx->dwChunkLength)){ | |
291 if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){ | |
292 mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%ld \n",len,idx->dwChunkLength); | |
293 len=idx->dwChunkLength; | |
294 // continue; | |
295 } | |
296 if(idx->dwFlags&AVIIF_KEYFRAME) flags=1; | |
297 } else return 0; | |
298 ret=demux_avi_read_packet(demux,id,len,idx_pos,flags); | |
299 // if(!ret && priv->skip_video_frames<=0) | |
300 // if(--max_packs==0){ | |
301 // demux->stream->eof=1; | |
302 // mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_DoesntContainSelectedStream); | |
303 // return 0; | |
304 // } | |
305 } while(ret!=1); | |
306 return 1; | |
307 } | |
308 | |
309 | |
310 // return value: | |
311 // 0 = EOF or no stream found | |
312 // 1 = successfully read a packet | |
313 int demux_avi_fill_buffer_nini(demuxer_t *demux,demux_stream_t* ds){ | |
314 avi_priv_t *priv=demux->priv; | |
315 unsigned int id=0; | |
316 unsigned int len; | |
317 int ret=0; | |
318 int *fpos=NULL; | |
319 | |
320 if(ds==demux->video) fpos=&priv->idx_pos_v; else | |
321 if(ds==demux->audio) fpos=&priv->idx_pos_a; else | |
322 return 0; | |
323 | |
324 stream_seek(demux->stream,fpos[0]); | |
325 | |
326 do{ | |
327 | |
328 demux->filepos=stream_tell(demux->stream); | |
329 if(demux->filepos>=demux->movi_end){ | |
330 demux->stream->eof=1; | |
331 return 0; | |
332 } | |
333 if(stream_eof(demux->stream)) return 0; | |
334 | |
335 id=stream_read_dword_le(demux->stream); | |
336 len=stream_read_dword_le(demux->stream); | |
337 if(id==mmioFOURCC('L','I','S','T')){ | |
338 id=stream_read_dword_le(demux->stream); // list type | |
339 continue; | |
340 } | |
341 | |
342 if(ds==demux_avi_select_stream(demux,id)){ | |
343 // read it! | |
344 ret=demux_avi_read_packet(demux,id,len,priv->idx_pos-1,0); | |
345 } else { | |
346 // skip it! | |
347 int skip=(len+1)&(~1); // total bytes in this chunk | |
348 stream_skip(demux->stream,skip); | |
349 } | |
350 | |
351 } while(ret!=1); | |
352 fpos[0]=stream_tell(demux->stream); | |
353 return 1; | |
354 } | |
355 | |
356 //extern int audio_id; | |
357 //extern int video_id; | |
358 extern int index_mode; // -1=untouched 0=don't use index 1=use (geneate) index | |
359 extern int force_ni; | |
360 extern int pts_from_bps; | |
361 | |
362 void read_avi_header(demuxer_t *demuxer,int index_mode); | |
363 | |
364 demuxer_t* demux_open_avi(demuxer_t* demuxer){ | |
365 demux_stream_t *d_audio=demuxer->audio; | |
366 demux_stream_t *d_video=demuxer->video; | |
367 sh_audio_t *sh_audio=NULL; | |
368 sh_video_t *sh_video=NULL; | |
369 avi_priv_t* priv=malloc(sizeof(avi_priv_t)); | |
370 | |
371 // priv struct: | |
372 priv->avi_audio_pts=priv->avi_video_pts=0.0f; | |
373 priv->pts_correction=0.0f; | |
374 priv->skip_video_frames=0; | |
375 priv->pts_corr_bytes=0; | |
376 priv->pts_has_video=priv->pts_corrected=0; | |
377 demuxer->priv=(void*)priv; | |
378 | |
379 //---- AVI header: | |
380 read_avi_header(demuxer,(demuxer->stream->type!=STREAMTYPE_STREAM)?index_mode:-2); | |
381 stream_reset(demuxer->stream); | |
382 stream_seek(demuxer->stream,demuxer->movi_start); | |
383 priv->idx_pos=0; | |
384 priv->idx_pos_a=0; | |
385 priv->idx_pos_v=0; | |
386 if(priv->idx_size>0){ | |
387 // decide index format: | |
388 if(((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start) | |
389 priv->idx_offset=demuxer->movi_start-4; | |
390 else | |
391 priv->idx_offset=0; | |
392 mp_msg(MSGT_DEMUX,MSGL_V,"AVI index offset: %d\n",priv->idx_offset); | |
393 } | |
394 // demuxer->endpos=avi_header.movi_end; | |
395 | |
396 if(priv->idx_size>0){ | |
397 // check that file is non-interleaved: | |
398 int i; | |
399 int a_pos=-1; | |
400 int v_pos=-1; | |
401 for(i=0;i<priv->idx_size;i++){ | |
402 AVIINDEXENTRY* idx=&((AVIINDEXENTRY *)priv->idx)[i]; | |
403 demux_stream_t* ds=demux_avi_select_stream(demuxer,idx->ckid); | |
404 int pos=idx->dwChunkOffset+priv->idx_offset; | |
405 if(a_pos==-1 && ds==demuxer->audio){ | |
406 a_pos=pos; | |
407 if(v_pos!=-1) break; | |
408 } | |
409 if(v_pos==-1 && ds==demuxer->video){ | |
410 v_pos=pos; | |
411 if(a_pos!=-1) break; | |
412 } | |
413 } | |
414 if(v_pos==-1){ | |
415 mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI_NI: " MSGTR_MissingVideoStream); | |
416 return NULL; | |
417 // GUI_MSG( mplErrorAVINI ) | |
418 } | |
419 if(a_pos==-1){ | |
420 mp_msg(MSGT_DEMUX,MSGL_INFO,"AVI_NI: " MSGTR_MissingAudioStream); | |
421 sh_audio=NULL; | |
422 } else { | |
423 if(force_ni || abs(a_pos-v_pos)>0x100000){ // distance > 1MB | |
424 mp_msg(MSGT_DEMUX,MSGL_INFO,MSGTR_NI_Message,force_ni?MSGTR_NI_Forced:MSGTR_NI_Detected); | |
425 demuxer->type=DEMUXER_TYPE_AVI_NI; // HACK!!!! | |
426 pts_from_bps=1; // force BPS sync! | |
427 } | |
428 } | |
429 } else { | |
430 // no index | |
431 if(force_ni){ | |
432 mp_msg(MSGT_DEMUX,MSGL_INFO,MSGTR_UsingNINI); | |
433 demuxer->type=DEMUXER_TYPE_AVI_NINI; // HACK!!!! | |
434 priv->idx_pos_a= | |
435 priv->idx_pos_v=demuxer->movi_start; | |
436 pts_from_bps=1; // force BPS sync! | |
437 } | |
438 demuxer->seekable=0; | |
439 } | |
440 if(!ds_fill_buffer(d_video)){ | |
441 mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI: " MSGTR_MissingVideoStreamBug); | |
442 return NULL; | |
443 // GUI_MSG( mplAVIErrorMissingVideoStream ) | |
444 } | |
445 sh_video=d_video->sh;sh_video->ds=d_video; | |
446 if(d_audio->id!=-2){ | |
447 mp_msg(MSGT_DEMUX,MSGL_V,"AVI: Searching for audio stream (id:%d)\n",d_audio->id); | |
448 if(!ds_fill_buffer(d_audio)){ | |
449 mp_msg(MSGT_DEMUX,MSGL_INFO,"AVI: " MSGTR_MissingAudioStream); | |
450 sh_audio=NULL; | |
451 } else { | |
452 sh_audio=d_audio->sh;sh_audio->ds=d_audio; | |
453 sh_audio->format=sh_audio->wf->wFormatTag; | |
454 } | |
455 } | |
456 // calc. FPS: | |
457 sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale; | |
458 sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; | |
459 // calculating video bitrate: | |
460 sh_video->i_bps=demuxer->movi_end-demuxer->movi_start-priv->idx_size*8; | |
461 if(sh_audio) sh_video->i_bps-=sh_audio->audio.dwLength; | |
462 mp_msg(MSGT_DEMUX,MSGL_V,"AVI video length=%d\n",sh_video->i_bps); | |
463 sh_video->i_bps=((float)sh_video->i_bps/(float)sh_video->video.dwLength)*sh_video->fps; | |
464 mp_msg(MSGT_DEMUX,MSGL_INFO,"VIDEO: [%.4s] %ldx%ld %dbpp %4.2f fps %5.1f kbps (%4.1f kbyte/s)\n", | |
465 (char *)&sh_video->bih->biCompression, | |
466 sh_video->bih->biWidth, | |
467 sh_video->bih->biHeight, | |
468 sh_video->bih->biBitCount, | |
469 sh_video->fps, | |
470 sh_video->i_bps*0.008f, | |
471 sh_video->i_bps/1024.0f ); | |
472 | |
473 return demuxer; | |
474 | |
475 } | |
476 | |
477 //extern float initial_pts_delay; | |
478 | |
479 void demux_seek_avi(demuxer_t *demuxer,float rel_seek_secs,int flags){ | |
480 avi_priv_t *priv=demuxer->priv; | |
481 demux_stream_t *d_audio=demuxer->audio; | |
482 demux_stream_t *d_video=demuxer->video; | |
483 sh_audio_t *sh_audio=d_audio->sh; | |
484 sh_video_t *sh_video=d_video->sh; | |
485 float skip_audio_secs=0; | |
486 | |
487 //FIXME: OFF_T - Didn't check AVI case yet (avi files can't be >2G anyway?) | |
488 //================= seek in AVI ========================== | |
489 int rel_seek_frames=rel_seek_secs*sh_video->fps; | |
490 int video_chunk_pos=d_video->pos; | |
491 int i; | |
492 | |
493 if(flags&1){ | |
494 // seek absolute | |
495 video_chunk_pos=0; | |
496 } | |
497 | |
498 if(flags&2){ | |
499 // float 0..1 | |
500 int total=sh_video->video.dwLength; | |
501 if(total<=1){ | |
502 // bad video header, try to get it from audio | |
503 if(sh_audio) total=sh_video->fps*sh_audio->audio.dwLength/sh_audio->wf->nAvgBytesPerSec; | |
504 if(total<=1){ | |
505 mp_msg(MSGT_SEEK,MSGL_WARN,MSGTR_CouldntDetFNo); | |
506 total=0; | |
507 } | |
508 } | |
509 rel_seek_frames=rel_seek_secs*total; | |
510 } | |
511 | |
512 priv->skip_video_frames=0; | |
513 priv->avi_audio_pts=0; | |
514 | |
515 // ------------ STEP 1: find nearest video keyframe chunk ------------ | |
516 // find nearest video keyframe chunk pos: | |
517 if(rel_seek_frames>0){ | |
518 // seek forward | |
519 while(video_chunk_pos<priv->idx_size){ | |
520 int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid; | |
521 if(avi_stream_id(id)==d_video->id){ // video frame | |
522 if((--rel_seek_frames)<0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break; | |
523 } | |
524 ++video_chunk_pos; | |
525 } | |
526 } else { | |
527 // seek backward | |
528 while(video_chunk_pos>0){ | |
529 int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid; | |
530 if(avi_stream_id(id)==d_video->id){ // video frame | |
531 if((++rel_seek_frames)>0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break; | |
532 } | |
533 --video_chunk_pos; | |
534 } | |
535 } | |
536 priv->idx_pos_a=priv->idx_pos_v=priv->idx_pos=video_chunk_pos; | |
537 | |
538 // re-calc video pts: | |
539 d_video->pack_no=0; | |
540 for(i=0;i<video_chunk_pos;i++){ | |
541 int id=((AVIINDEXENTRY *)priv->idx)[i].ckid; | |
542 if(avi_stream_id(id)==d_video->id) ++d_video->pack_no; | |
543 } | |
544 sh_video->num_frames=sh_video->num_frames_decoded=d_video->pack_no; | |
545 priv->avi_video_pts=d_video->pack_no*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; | |
546 d_video->pos=video_chunk_pos; | |
547 | |
548 mp_msg(MSGT_SEEK,MSGL_DBG2,"V_SEEK: pack=%d pts=%5.3f chunk=%d \n",d_video->pack_no,priv->avi_video_pts,video_chunk_pos); | |
549 | |
550 // ------------ STEP 2: seek audio, find the right chunk & pos ------------ | |
551 | |
552 d_audio->pack_no=0; | |
553 d_audio->dpos=0; | |
554 | |
555 if(sh_audio){ | |
556 int i; | |
557 // int apos=0; | |
558 int last=0; | |
559 int len=0; | |
560 int skip_audio_bytes=0; | |
561 int curr_audio_pos=-1; | |
562 int audio_chunk_pos=-1; | |
563 int chunk_max=(demuxer->type==DEMUXER_TYPE_AVI)?video_chunk_pos:priv->idx_size; | |
564 | |
565 if(sh_audio->audio.dwSampleSize){ | |
566 // constant rate audio stream | |
567 #if 0 | |
568 int align; | |
569 curr_audio_pos=(priv->avi_video_pts) * sh_audio->wf->nAvgBytesPerSec; | |
570 if(curr_audio_pos<0)curr_audio_pos=0; | |
571 align=sh_audio->audio.dwSampleSize; | |
572 if(sh_audio->wf->nBlockAlign>align) align=sh_audio->wf->nBlockAlign; | |
573 curr_audio_pos/=align; | |
574 curr_audio_pos*=align; | |
575 #else | |
576 curr_audio_pos=(priv->avi_video_pts)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale; | |
577 curr_audio_pos*=sh_audio->audio.dwSampleSize; | |
578 #endif | |
579 | |
580 // find audio chunk pos: | |
581 for(i=0;i<chunk_max;i++){ | |
582 int id=((AVIINDEXENTRY *)priv->idx)[i].ckid; | |
583 if(avi_stream_id(id)==d_audio->id){ | |
584 len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength; | |
585 audio_chunk_pos=i; ++d_audio->pack_no; | |
586 if(d_audio->dpos<=curr_audio_pos && curr_audio_pos<(d_audio->dpos+len)){ | |
587 //if(verbose)printf("break;\n"); | |
588 break; | |
589 } | |
590 d_audio->dpos+=len; | |
591 } | |
592 } | |
593 skip_audio_bytes=curr_audio_pos-d_audio->dpos; | |
594 | |
595 } else { | |
596 // VBR audio | |
597 int chunks=(priv->avi_video_pts)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale; | |
598 audio_chunk_pos=0; | |
599 | |
600 // find audio chunk pos: | |
601 for(i=0;i<priv->idx_size && chunks>0;i++){ | |
602 int id=((AVIINDEXENTRY *)priv->idx)[i].ckid; | |
603 if(avi_stream_id(id)==d_audio->id){ | |
604 len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength; | |
605 if(i>chunk_max){ | |
606 skip_audio_bytes+=len; | |
607 } else { | |
608 ++d_audio->pack_no; | |
609 d_audio->dpos+=len; | |
610 audio_chunk_pos=i; | |
611 } | |
612 --chunks; | |
613 } | |
614 } | |
615 //if(audio_chunk_pos>chunk_max) audio_chunk_pos=chunk_max; | |
616 | |
617 // printf("VBR seek: %5.3f -> chunk_no %d -> chunk_idx %d + skip %d \n", | |
618 // priv->avi_video_pts, audio_chunk_pos, ); | |
619 | |
620 } | |
621 | |
622 // Now we have: | |
623 // audio_chunk_pos = chunk no in index table (it's <=chunk_max) | |
624 // skip_audio_bytes = bytes to be skipped after chunk seek | |
625 // d-audio->pack_no = chunk_no in stream at audio_chunk_pos | |
626 // d_audio->dpos = bytepos in stream at audio_chunk_pos | |
627 // let's seek! | |
628 | |
629 // update stream position: | |
630 d_audio->pos=audio_chunk_pos; | |
631 // d_audio->dpos=apos; | |
632 // d_audio->pts=initial_pts_delay+(float)apos/(float)sh_audio->wf->nAvgBytesPerSec; | |
633 | |
634 if(demuxer->type==DEMUXER_TYPE_AVI){ | |
635 // interleaved stream: | |
636 if(audio_chunk_pos<video_chunk_pos){ | |
637 // calc priv->skip_video_frames & adjust video pts counter: | |
638 for(i=audio_chunk_pos;i<video_chunk_pos;i++){ | |
639 int id=((AVIINDEXENTRY *)priv->idx)[i].ckid; | |
640 if(avi_stream_id(id)==d_video->id) ++priv->skip_video_frames; | |
641 } | |
642 // requires for correct audio pts calculation (demuxer): | |
643 priv->avi_video_pts-=priv->skip_video_frames*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; | |
644 priv->idx_pos_a=priv->idx_pos_v=priv->idx_pos=audio_chunk_pos; | |
645 } | |
646 } else { | |
647 // non-interleaved stream: | |
648 priv->idx_pos_a=audio_chunk_pos; | |
649 priv->idx_pos_v=video_chunk_pos; | |
650 priv->idx_pos=(audio_chunk_pos<video_chunk_pos)?audio_chunk_pos:video_chunk_pos; | |
651 } | |
652 | |
653 | |
654 | |
655 mp_msg(MSGT_SEEK,MSGL_V,"SEEK: idx=%d (a:%d v:%d) v.skip=%d a.skip=%d/%4.3f \n", | |
656 priv->idx_pos,audio_chunk_pos,video_chunk_pos, | |
657 priv->skip_video_frames,skip_audio_bytes,skip_audio_secs); | |
658 | |
659 if(skip_audio_bytes){ | |
660 demux_read_data(d_audio,NULL,skip_audio_bytes); | |
661 //d_audio->pts=0; // PTS is outdated because of the raw data skipping | |
662 } | |
663 resync_audio_stream(sh_audio); | |
664 | |
665 // sh_audio->timer=-skip_audio_secs; | |
666 | |
667 } | |
668 d_video->pts=priv->avi_video_pts; // OSD | |
669 | |
670 } | |
671 | |
672 | |
673 |