Mercurial > mplayer.hg
comparison demux_avi.c @ 1485:b895f95e7657
AVI demuxer cleanups, fileformat-dependent stuff moved to priv_t
author | arpi |
---|---|
date | Sat, 11 Aug 2001 20:37:33 +0000 |
parents | db2a6ae7e296 |
children | 8c3e93ef116d |
comparison
equal
deleted
inserted
replaced
1484:14af3106c359 | 1485:b895f95e7657 |
---|---|
1 // AVI file parser for DEMUXER v2.6 by A'rpi/ESP-team | 1 // AVI file parser for DEMUXER v2.9 by A'rpi/ESP-team |
2 | 2 |
3 #include <stdio.h> | 3 #include <stdio.h> |
4 #include <stdlib.h> | 4 #include <stdlib.h> |
5 #include <unistd.h> | 5 #include <unistd.h> |
6 | 6 |
14 #include "wine/vfw.h" | 14 #include "wine/vfw.h" |
15 | 15 |
16 #include "codec-cfg.h" | 16 #include "codec-cfg.h" |
17 #include "stheader.h" | 17 #include "stheader.h" |
18 | 18 |
19 //static float avi_pts_frametime=1.0f/25.0f; | 19 #include "aviheader.h" |
20 float avi_audio_pts=0; | |
21 float avi_video_pts=0; | |
22 //float avi_video_ftime=0.04; | |
23 int skip_video_frames=0; | |
24 | 20 |
25 // Select ds from ID | 21 // Select ds from ID |
26 demux_stream_t* demux_avi_select_stream(demuxer_t *demux,unsigned int id){ | 22 demux_stream_t* demux_avi_select_stream(demuxer_t *demux,unsigned int id){ |
27 int stream_id=avi_stream_id(id); | 23 int stream_id=avi_stream_id(id); |
28 | 24 |
56 if(verbose>=2) printf("Unknown chunk: %.4s (%X)\n",(char *) &id,id); | 52 if(verbose>=2) printf("Unknown chunk: %.4s (%X)\n",(char *) &id,id); |
57 } | 53 } |
58 return NULL; | 54 return NULL; |
59 } | 55 } |
60 | 56 |
61 static float pts_correction=0.0; | |
62 static int pts_corrected=0; | |
63 static int pts_has_video=0; | |
64 static unsigned int pts_corr_bytes=0; | |
65 | 57 |
66 static int demux_avi_read_packet(demuxer_t *demux,unsigned int id,unsigned int len,int idxpos,int flags){ | 58 static int demux_avi_read_packet(demuxer_t *demux,unsigned int id,unsigned int len,int idxpos,int flags){ |
59 avi_priv_t *priv=demux->priv; | |
67 int skip; | 60 int skip; |
68 float pts=0; | 61 float pts=0; |
69 demux_stream_t *ds=demux_avi_select_stream(demux,id); | 62 demux_stream_t *ds=demux_avi_select_stream(demux,id); |
70 | 63 |
71 if(verbose>=3) printf("demux_avi.read_packet: %X\n",id); | 64 if(verbose>=3) printf("demux_avi.read_packet: %X\n",id); |
72 | 65 |
73 if(ds==demux->audio){ | 66 if(ds==demux->audio){ |
74 | 67 |
75 if(pts_corrected==0){ | 68 if(priv->pts_corrected==0){ |
76 // printf("\rYYY-A A: %5.3f V: %5.3f \n",avi_audio_pts,avi_video_pts); | 69 // printf("\rYYY-A A: %5.3f V: %5.3f \n",priv->avi_audio_pts,priv->avi_video_pts); |
77 if(pts_has_video){ | 70 if(priv->pts_has_video){ |
78 // we have video pts now | 71 // we have video pts now |
79 float delay=(float)pts_corr_bytes/((sh_audio_t*)(ds->sh))->wf->nAvgBytesPerSec; | 72 float delay=(float)priv->pts_corr_bytes/((sh_audio_t*)(ds->sh))->wf->nAvgBytesPerSec; |
80 printf("XXX initial v_pts=%5.3f a_pos=%d (%5.3f) \n",avi_audio_pts,pts_corr_bytes,delay); | 73 printf("XXX initial v_pts=%5.3f a_pos=%d (%5.3f) \n",priv->avi_audio_pts,priv->pts_corr_bytes,delay); |
81 //pts_correction=-avi_audio_pts+delay; | 74 //priv->pts_correction=-priv->avi_audio_pts+delay; |
82 pts_correction=delay-avi_audio_pts; | 75 priv->pts_correction=delay-priv->avi_audio_pts; |
83 avi_audio_pts+=pts_correction; | 76 priv->avi_audio_pts+=priv->pts_correction; |
84 pts_corrected=1; | 77 priv->pts_corrected=1; |
85 } else | 78 } else |
86 pts_corr_bytes+=len; | 79 priv->pts_corr_bytes+=len; |
87 } | 80 } |
88 pts=avi_audio_pts; //+pts_correction; | 81 pts=priv->avi_audio_pts; //+priv->pts_correction; |
89 avi_audio_pts=0; | 82 priv->avi_audio_pts=0; |
90 } else | 83 } else |
91 if(ds==demux->video){ | 84 if(ds==demux->video){ |
92 // video | 85 // video |
93 if(skip_video_frames>0){ | 86 if(priv->skip_video_frames>0){ |
94 // drop frame (seeking) | 87 // drop frame (seeking) |
95 --skip_video_frames; | 88 --priv->skip_video_frames; |
96 ds=NULL; | 89 ds=NULL; |
97 } else { | 90 } else { |
98 pts=avi_video_pts; | 91 pts=priv->avi_video_pts; |
99 } | 92 } |
100 // ezt a 2 sort lehet hogy fell kell majd cserelni: | 93 // ezt a 2 sort lehet hogy fell kell majd cserelni: |
101 //avi_video_pts+=avi_pts_frametime; | 94 //priv->avi_video_pts+=avi_pts_frametime; |
102 //avi_video_pts+=(float)avi_header.video.dwScale/(float)avi_header.video.dwRate; | 95 //priv->avi_video_pts+=(float)avi_header.video.dwScale/(float)avi_header.video.dwRate; |
103 //avi_video_pts+=((sh_video_t*)ds->sh)->frametime; | 96 //priv->avi_video_pts+=((sh_video_t*)ds->sh)->frametime; |
104 // FIXME!!! | 97 // FIXME!!! |
105 #if 1 | 98 #if 1 |
106 // printf("ds=0x%X\n",ds); | 99 // printf("ds=0x%X\n",ds); |
107 // printf("packno=%d\n",ds->pack_no); | 100 // printf("packno=%d\n",ds->pack_no); |
108 // printf("### pack_no=%d\n",demux->video->pack_no+demux->video->packs); | 101 // printf("### pack_no=%d\n",demux->video->pack_no+demux->video->packs); |
109 avi_video_pts = (demux->video->pack_no+demux->video->packs) * | 102 priv->avi_video_pts = (demux->video->pack_no+demux->video->packs) * |
110 (float)((sh_video_t*)demux->video->sh)->video.dwScale / | 103 (float)((sh_video_t*)demux->video->sh)->video.dwScale / |
111 (float)((sh_video_t*)demux->video->sh)->video.dwRate; | 104 (float)((sh_video_t*)demux->video->sh)->video.dwRate; |
112 #else | 105 #else |
113 avi_video_pts+=(float)((sh_video_t*)(demux->video->sh))->video.dwScale/(float)((sh_video_t*)(demux->video->sh))->video.dwRate; | 106 priv->avi_video_pts+=(float)((sh_video_t*)(demux->video->sh))->video.dwScale/(float)((sh_video_t*)(demux->video->sh))->video.dwRate; |
114 // avi_video_pts+=avi_video_ftime; | 107 // priv->avi_video_pts+=avi_video_ftime; |
115 #endif | 108 #endif |
116 // printf("\rYYY-V A: %5.3f V: %5.3f \n",avi_audio_pts,avi_video_pts); | 109 // printf("\rYYY-V A: %5.3f V: %5.3f \n",priv->avi_audio_pts,priv->avi_video_pts); |
117 avi_audio_pts=avi_video_pts+pts_correction; | 110 priv->avi_audio_pts=priv->avi_video_pts+priv->pts_correction; |
118 pts_has_video=1; | 111 priv->pts_has_video=1; |
119 | 112 |
120 } | 113 } |
121 | 114 |
122 // len=stream_read_dword_le(demux->stream); | 115 // len=stream_read_dword_le(demux->stream); |
123 skip=(len+1)&(~1); // total bytes in this chunk | 116 skip=(len+1)&(~1); // total bytes in this chunk |
132 stream_skip(demux->stream,skip); | 125 stream_skip(demux->stream,skip); |
133 } | 126 } |
134 return ds?1:0; | 127 return ds?1:0; |
135 } | 128 } |
136 | 129 |
137 //static int num_elementary_packets100=0; | |
138 //static int num_elementary_packets101=0; | |
139 | |
140 // return value: | 130 // return value: |
141 // 0 = EOF or no stream found | 131 // 0 = EOF or no stream found |
142 // 1 = successfully read a packet | 132 // 1 = successfully read a packet |
143 int demux_avi_fill_buffer(demuxer_t *demux){ | 133 int demux_avi_fill_buffer(demuxer_t *demux){ |
134 avi_priv_t *priv=demux->priv; | |
144 unsigned int id=0; | 135 unsigned int id=0; |
145 unsigned int len; | 136 unsigned int len; |
146 int max_packs=128; | 137 int max_packs=128; |
147 int ret=0; | 138 int ret=0; |
148 | 139 |
155 demux->stream->eof=1; | 146 demux->stream->eof=1; |
156 return 0; | 147 return 0; |
157 } | 148 } |
158 if(stream_eof(demux->stream)) return 0; | 149 if(stream_eof(demux->stream)) return 0; |
159 #endif | 150 #endif |
160 if(demux->idx_size>0 && demux->idx_pos<demux->idx_size){ | 151 if(priv->idx_size>0 && priv->idx_pos<priv->idx_size){ |
161 unsigned int pos; | 152 unsigned int pos; |
162 | 153 |
163 //if(demux->idx_pos<0) printf("Fatal! idx_pos=%d\n",demux->idx_pos); | 154 //if(priv->idx_pos<0) printf("Fatal! idx_pos=%d\n",priv->idx_pos); |
164 | 155 |
165 idx=&((AVIINDEXENTRY *)demux->idx)[demux->idx_pos++]; | 156 idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++]; |
166 | 157 |
167 //printf("[%d]",demux->idx_pos);fflush(stdout); | 158 //printf("[%d]",priv->idx_pos);fflush(stdout); |
168 | 159 |
169 //stream_seek(demux->stream,idx.dwChunkOffset); | 160 //stream_seek(demux->stream,idx.dwChunkOffset); |
170 //printf("IDX pos=%X idx.pos=%X idx.size=%X idx.flags=%X\n",demux->filepos, | 161 //printf("IDX pos=%X idx.pos=%X idx.size=%X idx.flags=%X\n",demux->filepos, |
171 // pos-4,idx->dwChunkLength,idx->dwFlags); | 162 // pos-4,idx->dwChunkLength,idx->dwFlags); |
172 if(idx->dwFlags&AVIIF_LIST){ | 163 if(idx->dwFlags&AVIIF_LIST){ |
176 if(!demux_avi_select_stream(demux,idx->ckid)){ | 167 if(!demux_avi_select_stream(demux,idx->ckid)){ |
177 if(verbose>2) printf("Skip chunk %.4s (0x%X) \n",(char *)&idx->ckid,(unsigned int)idx->ckid); | 168 if(verbose>2) printf("Skip chunk %.4s (0x%X) \n",(char *)&idx->ckid,(unsigned int)idx->ckid); |
178 continue; // skip this chunk | 169 continue; // skip this chunk |
179 } | 170 } |
180 | 171 |
181 pos=idx->dwChunkOffset+demux->idx_offset; | 172 pos=idx->dwChunkOffset+priv->idx_offset; |
182 if(pos<demux->movi_start || pos>=demux->movi_end){ | 173 if(pos<demux->movi_start || pos>=demux->movi_end){ |
183 printf("ChunkOffset out of range! idx=0x%X \n",pos); | 174 printf("ChunkOffset out of range! idx=0x%X \n",pos); |
184 continue; | 175 continue; |
185 } | 176 } |
186 #if 0 | 177 #if 0 |
220 if(id==mmioFOURCC('L','I','S','T')){ | 211 if(id==mmioFOURCC('L','I','S','T')){ |
221 id=stream_read_dword_le(demux->stream); // list type | 212 id=stream_read_dword_le(demux->stream); // list type |
222 continue; | 213 continue; |
223 } | 214 } |
224 } | 215 } |
225 ret=demux_avi_read_packet(demux,id,len,demux->idx_pos-1,flags); | 216 ret=demux_avi_read_packet(demux,id,len,priv->idx_pos-1,flags); |
226 if(!ret && skip_video_frames<=0) | 217 if(!ret && priv->skip_video_frames<=0) |
227 if(--max_packs==0){ | 218 if(--max_packs==0){ |
228 demux->stream->eof=1; | 219 demux->stream->eof=1; |
229 printf("demux: file doesn't contain the selected audio or video stream\n"); | 220 printf("demux: file doesn't contain the selected audio or video stream\n"); |
230 return 0; | 221 return 0; |
231 } | 222 } |
236 | 227 |
237 // return value: | 228 // return value: |
238 // 0 = EOF or no stream found | 229 // 0 = EOF or no stream found |
239 // 1 = successfully read a packet | 230 // 1 = successfully read a packet |
240 int demux_avi_fill_buffer_ni(demuxer_t *demux,demux_stream_t* ds){ | 231 int demux_avi_fill_buffer_ni(demuxer_t *demux,demux_stream_t* ds){ |
232 avi_priv_t *priv=demux->priv; | |
241 unsigned int id=0; | 233 unsigned int id=0; |
242 unsigned int len; | 234 unsigned int len; |
243 int max_packs=128; | 235 int max_packs=128; |
244 int ret=0; | 236 int ret=0; |
245 | 237 |
247 int flags=0; | 239 int flags=0; |
248 AVIINDEXENTRY *idx=NULL; | 240 AVIINDEXENTRY *idx=NULL; |
249 int idx_pos=0; | 241 int idx_pos=0; |
250 demux->filepos=stream_tell(demux->stream); | 242 demux->filepos=stream_tell(demux->stream); |
251 | 243 |
252 if(ds==demux->video) idx_pos=demux->idx_pos_v++; else | 244 if(ds==demux->video) idx_pos=priv->idx_pos_v++; else |
253 if(ds==demux->audio) idx_pos=demux->idx_pos_a++; else | 245 if(ds==demux->audio) idx_pos=priv->idx_pos_a++; else |
254 idx_pos=demux->idx_pos++; | 246 idx_pos=priv->idx_pos++; |
255 | 247 |
256 if(demux->idx_size>0 && idx_pos<demux->idx_size){ | 248 if(priv->idx_size>0 && idx_pos<priv->idx_size){ |
257 unsigned int pos; | 249 unsigned int pos; |
258 idx=&((AVIINDEXENTRY *)demux->idx)[idx_pos]; | 250 idx=&((AVIINDEXENTRY *)priv->idx)[idx_pos]; |
259 // idx=&demux->idx[idx_pos]; | 251 // idx=&priv->idx[idx_pos]; |
260 | 252 |
261 if(idx->dwFlags&AVIIF_LIST){ | 253 if(idx->dwFlags&AVIIF_LIST){ |
262 // LIST | 254 // LIST |
263 continue; | 255 continue; |
264 } | 256 } |
265 if(ds && demux_avi_select_stream(demux,idx->ckid)!=ds){ | 257 if(ds && demux_avi_select_stream(demux,idx->ckid)!=ds){ |
266 if(verbose>2) printf("Skip chunk %.4s (0x%X) \n",(char *)&idx->ckid,(unsigned int)idx->ckid); | 258 if(verbose>2) printf("Skip chunk %.4s (0x%X) \n",(char *)&idx->ckid,(unsigned int)idx->ckid); |
267 continue; // skip this chunk | 259 continue; // skip this chunk |
268 } | 260 } |
269 | 261 |
270 pos=idx->dwChunkOffset+demux->idx_offset; | 262 pos=idx->dwChunkOffset+priv->idx_offset; |
271 if(pos<demux->movi_start || pos>=demux->movi_end){ | 263 if(pos<demux->movi_start || pos>=demux->movi_end){ |
272 printf("ChunkOffset out of range! current=0x%X idx=0x%X \n",demux->filepos,pos); | 264 printf("ChunkOffset out of range! current=0x%X idx=0x%X \n",demux->filepos,pos); |
273 continue; | 265 continue; |
274 } | 266 } |
275 #if 0 | 267 #if 0 |
297 // continue; | 289 // continue; |
298 } | 290 } |
299 if(idx->dwFlags&AVIIF_KEYFRAME) flags=1; | 291 if(idx->dwFlags&AVIIF_KEYFRAME) flags=1; |
300 } else return 0; | 292 } else return 0; |
301 ret=demux_avi_read_packet(demux,id,len,idx_pos,flags); | 293 ret=demux_avi_read_packet(demux,id,len,idx_pos,flags); |
302 if(!ret && skip_video_frames<=0) | 294 if(!ret && priv->skip_video_frames<=0) |
303 if(--max_packs==0){ | 295 if(--max_packs==0){ |
304 demux->stream->eof=1; | 296 demux->stream->eof=1; |
305 printf("demux: file doesn't contain the selected audio or video stream\n"); | 297 printf("demux: file doesn't contain the selected audio or video stream\n"); |
306 return 0; | 298 return 0; |
307 } | 299 } |
312 | 304 |
313 // return value: | 305 // return value: |
314 // 0 = EOF or no stream found | 306 // 0 = EOF or no stream found |
315 // 1 = successfully read a packet | 307 // 1 = successfully read a packet |
316 int demux_avi_fill_buffer_nini(demuxer_t *demux,demux_stream_t* ds){ | 308 int demux_avi_fill_buffer_nini(demuxer_t *demux,demux_stream_t* ds){ |
309 avi_priv_t *priv=demux->priv; | |
317 unsigned int id=0; | 310 unsigned int id=0; |
318 unsigned int len; | 311 unsigned int len; |
319 int ret=0; | 312 int ret=0; |
320 int *fpos=NULL; | 313 int *fpos=NULL; |
321 | 314 |
322 if(ds==demux->video) fpos=&demux->idx_pos_v; else | 315 if(ds==demux->video) fpos=&priv->idx_pos_v; else |
323 if(ds==demux->audio) fpos=&demux->idx_pos_a; else | 316 if(ds==demux->audio) fpos=&priv->idx_pos_a; else |
324 return 0; | 317 return 0; |
325 | 318 |
326 stream_seek(demux->stream,fpos[0]); | 319 stream_seek(demux->stream,fpos[0]); |
327 | 320 |
328 do{ | 321 do{ |
341 continue; | 334 continue; |
342 } | 335 } |
343 | 336 |
344 if(ds==demux_avi_select_stream(demux,id)){ | 337 if(ds==demux_avi_select_stream(demux,id)){ |
345 // read it! | 338 // read it! |
346 ret=demux_avi_read_packet(demux,id,len,demux->idx_pos-1,0); | 339 ret=demux_avi_read_packet(demux,id,len,priv->idx_pos-1,0); |
347 } else { | 340 } else { |
348 // skip it! | 341 // skip it! |
349 int skip=(len+1)&(~1); // total bytes in this chunk | 342 int skip=(len+1)&(~1); // total bytes in this chunk |
350 stream_skip(demux->stream,skip); | 343 stream_skip(demux->stream,skip); |
351 } | 344 } |
353 } while(ret!=1); | 346 } while(ret!=1); |
354 fpos[0]=stream_tell(demux->stream); | 347 fpos[0]=stream_tell(demux->stream); |
355 return 1; | 348 return 1; |
356 } | 349 } |
357 | 350 |
358 extern float initial_pts_delay; | 351 extern int audio_id; |
352 extern int video_id; | |
353 extern int index_mode; // -1=untouched 0=don't use index 1=use (geneate) index | |
354 extern int force_ni; | |
355 extern int pts_from_bps; | |
356 | |
357 demuxer_t* demux_open_avi(demuxer_t* demuxer){ | |
358 demux_stream_t *d_audio=demuxer->audio; | |
359 demux_stream_t *d_video=demuxer->video; | |
360 sh_audio_t *sh_audio=NULL; | |
361 sh_video_t *sh_video=NULL; | |
362 avi_priv_t* priv=malloc(sizeof(avi_priv_t)); | |
363 | |
364 // priv struct: | |
365 priv->avi_audio_pts=priv->avi_video_pts=0.0f; | |
366 priv->pts_correction=0.0f; | |
367 priv->skip_video_frames=0; | |
368 priv->pts_corr_bytes=0; | |
369 priv->pts_has_video=priv->pts_corrected=0; | |
370 demuxer->priv=(void*)priv; | |
371 | |
372 //---- AVI header: | |
373 read_avi_header(demuxer,(demuxer->stream->type!=STREAMTYPE_STREAM)?index_mode:-2); | |
374 stream_reset(demuxer->stream); | |
375 stream_seek(demuxer->stream,demuxer->movi_start); | |
376 priv->idx_pos=0; | |
377 priv->idx_pos_a=0; | |
378 priv->idx_pos_v=0; | |
379 if(priv->idx_size>0){ | |
380 // decide index format: | |
381 if(((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start) | |
382 priv->idx_offset=demuxer->movi_start-4; | |
383 else | |
384 priv->idx_offset=0; | |
385 if(verbose) printf("AVI index offset: %d\n",priv->idx_offset); | |
386 } | |
387 // demuxer->endpos=avi_header.movi_end; | |
388 | |
389 if(priv->idx_size>0){ | |
390 // check that file is non-interleaved: | |
391 int i; | |
392 int a_pos=-1; | |
393 int v_pos=-1; | |
394 for(i=0;i<priv->idx_size;i++){ | |
395 AVIINDEXENTRY* idx=&((AVIINDEXENTRY *)priv->idx)[i]; | |
396 demux_stream_t* ds=demux_avi_select_stream(demuxer,idx->ckid); | |
397 int pos=idx->dwChunkOffset+priv->idx_offset; | |
398 if(a_pos==-1 && ds==demuxer->audio){ | |
399 a_pos=pos; | |
400 if(v_pos!=-1) break; | |
401 } | |
402 if(v_pos==-1 && ds==demuxer->video){ | |
403 v_pos=pos; | |
404 if(a_pos!=-1) break; | |
405 } | |
406 } | |
407 if(v_pos==-1){ | |
408 fprintf(stderr,"AVI_NI: missing video stream!? contact the author, it may be a bug :(\n"); | |
409 return NULL; | |
410 // GUI_MSG( mplErrorAVINI ) | |
411 // exit(1); | |
412 } | |
413 if(a_pos==-1){ | |
414 printf("AVI_NI: No audio stream found -> nosound\n"); | |
415 sh_audio=NULL; | |
416 } else { | |
417 if(force_ni || abs(a_pos-v_pos)>0x100000){ // distance > 1MB | |
418 printf("%s NON-INTERLEAVED AVI file-format!\n",force_ni?"Forced":"Detected"); | |
419 demuxer->type=DEMUXER_TYPE_AVI_NI; // HACK!!!! | |
420 pts_from_bps=1; // force BPS sync! | |
421 } | |
422 } | |
423 } else { | |
424 // no index | |
425 if(force_ni){ | |
426 printf("Using NON-INTERLEAVED Broken AVI file-format!\n"); | |
427 demuxer->type=DEMUXER_TYPE_AVI_NINI; // HACK!!!! | |
428 priv->idx_pos_a= | |
429 priv->idx_pos_v=demuxer->movi_start; | |
430 pts_from_bps=1; // force BPS sync! | |
431 } | |
432 } | |
433 if(!ds_fill_buffer(d_video)){ | |
434 fprintf(stderr,"AVI: missing video stream!? contact the author, it may be a bug :(\n"); | |
435 return NULL; | |
436 // GUI_MSG( mplAVIErrorMissingVideoStream ) | |
437 // exit(1); | |
438 } | |
439 sh_video=d_video->sh;sh_video->ds=d_video; | |
440 if(audio_id!=-2){ | |
441 if(verbose) printf("AVI: Searching for audio stream (id:%d)\n",d_audio->id); | |
442 if(!ds_fill_buffer(d_audio)){ | |
443 printf("AVI: No Audio stream found... ->nosound\n"); | |
444 sh_audio=NULL; | |
445 } else { | |
446 sh_audio=d_audio->sh;sh_audio->ds=d_audio; | |
447 sh_audio->format=sh_audio->wf->wFormatTag; | |
448 } | |
449 } | |
450 // calc. FPS: | |
451 sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale; | |
452 sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; | |
453 // calculating video bitrate: | |
454 sh_video->i_bps=demuxer->movi_end-demuxer->movi_start-priv->idx_size*8; | |
455 if(sh_audio) sh_video->i_bps-=sh_audio->audio.dwLength; | |
456 if(verbose) printf("AVI video length=%d\n",sh_video->i_bps); | |
457 sh_video->i_bps=((float)sh_video->i_bps/(float)sh_video->video.dwLength)*sh_video->fps; | |
458 printf("VIDEO: [%.4s] %ldx%ld %dbpp %4.2f fps %5.1f kbps (%4.1f kbyte/s)\n", | |
459 (char *)&sh_video->bih->biCompression, | |
460 sh_video->bih->biWidth, | |
461 sh_video->bih->biHeight, | |
462 sh_video->bih->biBitCount, | |
463 sh_video->fps, | |
464 sh_video->i_bps*0.008f, | |
465 sh_video->i_bps/1024.0f ); | |
466 | |
467 return demuxer; | |
468 | |
469 } | |
470 | |
471 //extern float initial_pts_delay; | |
359 | 472 |
360 void demux_seek_avi(demuxer_t *demuxer,float rel_seek_secs,int flags){ | 473 void demux_seek_avi(demuxer_t *demuxer,float rel_seek_secs,int flags){ |
474 avi_priv_t *priv=demuxer->priv; | |
361 demux_stream_t *d_audio=demuxer->audio; | 475 demux_stream_t *d_audio=demuxer->audio; |
362 demux_stream_t *d_video=demuxer->video; | 476 demux_stream_t *d_video=demuxer->video; |
363 sh_audio_t *sh_audio=d_audio->sh; | 477 sh_audio_t *sh_audio=d_audio->sh; |
364 sh_video_t *sh_video=d_video->sh; | 478 sh_video_t *sh_video=d_video->sh; |
365 float skip_audio_secs=0; | 479 float skip_audio_secs=0; |
368 //================= seek in AVI ========================== | 482 //================= seek in AVI ========================== |
369 int rel_seek_frames=rel_seek_secs*sh_video->fps; | 483 int rel_seek_frames=rel_seek_secs*sh_video->fps; |
370 int video_chunk_pos=d_video->pos; | 484 int video_chunk_pos=d_video->pos; |
371 int i; | 485 int i; |
372 | 486 |
373 skip_video_frames=0; | 487 priv->skip_video_frames=0; |
374 avi_audio_pts=0; | 488 priv->avi_audio_pts=0; |
375 | 489 |
376 // ------------ STEP 1: find nearest video keyframe chunk ------------ | 490 // ------------ STEP 1: find nearest video keyframe chunk ------------ |
377 // find nearest video keyframe chunk pos: | 491 // find nearest video keyframe chunk pos: |
378 if(rel_seek_frames>0){ | 492 if(rel_seek_frames>0){ |
379 // seek forward | 493 // seek forward |
380 while(video_chunk_pos<demuxer->idx_size){ | 494 while(video_chunk_pos<priv->idx_size){ |
381 int id=((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].ckid; | 495 int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid; |
382 if(avi_stream_id(id)==d_video->id){ // video frame | 496 if(avi_stream_id(id)==d_video->id){ // video frame |
383 if((--rel_seek_frames)<0 && ((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break; | 497 if((--rel_seek_frames)<0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break; |
384 } | 498 } |
385 ++video_chunk_pos; | 499 ++video_chunk_pos; |
386 } | 500 } |
387 } else { | 501 } else { |
388 // seek backward | 502 // seek backward |
389 while(video_chunk_pos>=0){ | 503 while(video_chunk_pos>=0){ |
390 int id=((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].ckid; | 504 int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid; |
391 if(avi_stream_id(id)==d_video->id){ // video frame | 505 if(avi_stream_id(id)==d_video->id){ // video frame |
392 if((++rel_seek_frames)>0 && ((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break; | 506 if((++rel_seek_frames)>0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break; |
393 } | 507 } |
394 --video_chunk_pos; | 508 --video_chunk_pos; |
395 } | 509 } |
396 } | 510 } |
397 demuxer->idx_pos_a=demuxer->idx_pos_v=demuxer->idx_pos=video_chunk_pos; | 511 priv->idx_pos_a=priv->idx_pos_v=priv->idx_pos=video_chunk_pos; |
398 | 512 |
399 // re-calc video pts: | 513 // re-calc video pts: |
400 d_video->pack_no=0; | 514 d_video->pack_no=0; |
401 for(i=0;i<video_chunk_pos;i++){ | 515 for(i=0;i<video_chunk_pos;i++){ |
402 int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid; | 516 int id=((AVIINDEXENTRY *)priv->idx)[i].ckid; |
403 if(avi_stream_id(id)==d_video->id) ++d_video->pack_no; | 517 if(avi_stream_id(id)==d_video->id) ++d_video->pack_no; |
404 } | 518 } |
405 sh_video->num_frames=d_video->pack_no; | 519 sh_video->num_frames=d_video->pack_no; |
406 avi_video_pts=d_video->pack_no*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; | 520 priv->avi_video_pts=d_video->pack_no*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; |
407 d_video->pos=video_chunk_pos; | 521 d_video->pos=video_chunk_pos; |
408 | 522 |
409 // ------------ STEP 2: seek audio, find the right chunk & pos ------------ | 523 // ------------ STEP 2: seek audio, find the right chunk & pos ------------ |
410 | 524 |
411 d_audio->pack_no=0; | 525 d_audio->pack_no=0; |
417 int last=0; | 531 int last=0; |
418 int len=0; | 532 int len=0; |
419 int skip_audio_bytes=0; | 533 int skip_audio_bytes=0; |
420 int curr_audio_pos=-1; | 534 int curr_audio_pos=-1; |
421 int audio_chunk_pos=-1; | 535 int audio_chunk_pos=-1; |
422 int chunk_max=(demuxer->type==DEMUXER_TYPE_AVI)?video_chunk_pos:demuxer->idx_size; | 536 int chunk_max=(demuxer->type==DEMUXER_TYPE_AVI)?video_chunk_pos:priv->idx_size; |
423 | 537 |
424 if(sh_audio->audio.dwSampleSize){ | 538 if(sh_audio->audio.dwSampleSize){ |
425 // constant rate audio stream | 539 // constant rate audio stream |
426 #if 0 | 540 #if 0 |
427 int align; | 541 int align; |
428 curr_audio_pos=(avi_video_pts) * sh_audio->wf->nAvgBytesPerSec; | 542 curr_audio_pos=(priv->avi_video_pts) * sh_audio->wf->nAvgBytesPerSec; |
429 if(curr_audio_pos<0)curr_audio_pos=0; | 543 if(curr_audio_pos<0)curr_audio_pos=0; |
430 align=sh_audio->audio.dwSampleSize; | 544 align=sh_audio->audio.dwSampleSize; |
431 if(sh_audio->wf->nBlockAlign>align) align=sh_audio->wf->nBlockAlign; | 545 if(sh_audio->wf->nBlockAlign>align) align=sh_audio->wf->nBlockAlign; |
432 curr_audio_pos/=align; | 546 curr_audio_pos/=align; |
433 curr_audio_pos*=align; | 547 curr_audio_pos*=align; |
434 #else | 548 #else |
435 curr_audio_pos=(avi_video_pts)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale; | 549 curr_audio_pos=(priv->avi_video_pts)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale; |
436 curr_audio_pos*=sh_audio->audio.dwSampleSize; | 550 curr_audio_pos*=sh_audio->audio.dwSampleSize; |
437 #endif | 551 #endif |
438 | 552 |
439 // find audio chunk pos: | 553 // find audio chunk pos: |
440 for(i=0;i<chunk_max;i++){ | 554 for(i=0;i<chunk_max;i++){ |
441 int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid; | 555 int id=((AVIINDEXENTRY *)priv->idx)[i].ckid; |
442 if(avi_stream_id(id)==d_audio->id){ | 556 if(avi_stream_id(id)==d_audio->id){ |
443 len=((AVIINDEXENTRY *)demuxer->idx)[i].dwChunkLength; | 557 len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength; |
444 audio_chunk_pos=i; ++d_audio->pack_no; | 558 audio_chunk_pos=i; ++d_audio->pack_no; |
445 if(d_audio->dpos<=curr_audio_pos && curr_audio_pos<(d_audio->dpos+len)){ | 559 if(d_audio->dpos<=curr_audio_pos && curr_audio_pos<(d_audio->dpos+len)){ |
446 //if(verbose)printf("break;\n"); | 560 //if(verbose)printf("break;\n"); |
447 break; | 561 break; |
448 } | 562 } |
451 } | 565 } |
452 skip_audio_bytes=curr_audio_pos-d_audio->dpos; | 566 skip_audio_bytes=curr_audio_pos-d_audio->dpos; |
453 | 567 |
454 } else { | 568 } else { |
455 // VBR audio | 569 // VBR audio |
456 int chunks=(avi_video_pts)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale; | 570 int chunks=(priv->avi_video_pts)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale; |
457 audio_chunk_pos=0; | 571 audio_chunk_pos=0; |
458 | 572 |
459 // find audio chunk pos: | 573 // find audio chunk pos: |
460 for(i=0;i<demuxer->idx_size && chunks>0;i++){ | 574 for(i=0;i<priv->idx_size && chunks>0;i++){ |
461 int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid; | 575 int id=((AVIINDEXENTRY *)priv->idx)[i].ckid; |
462 if(avi_stream_id(id)==d_audio->id){ | 576 if(avi_stream_id(id)==d_audio->id){ |
463 len=((AVIINDEXENTRY *)demuxer->idx)[i].dwChunkLength; | 577 len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength; |
464 if(i>chunk_max){ | 578 if(i>chunk_max){ |
465 skip_audio_bytes+=len; | 579 skip_audio_bytes+=len; |
466 } else { | 580 } else { |
467 ++d_audio->pack_no; | 581 ++d_audio->pack_no; |
468 d_audio->dpos+=len; | 582 d_audio->dpos+=len; |
472 } | 586 } |
473 } | 587 } |
474 //if(audio_chunk_pos>chunk_max) audio_chunk_pos=chunk_max; | 588 //if(audio_chunk_pos>chunk_max) audio_chunk_pos=chunk_max; |
475 | 589 |
476 // printf("VBR seek: %5.3f -> chunk_no %d -> chunk_idx %d + skip %d \n", | 590 // printf("VBR seek: %5.3f -> chunk_no %d -> chunk_idx %d + skip %d \n", |
477 // avi_video_pts, audio_chunk_pos, ); | 591 // priv->avi_video_pts, audio_chunk_pos, ); |
478 | 592 |
479 } | 593 } |
480 | 594 |
481 // Now we have: | 595 // Now we have: |
482 // audio_chunk_pos = chunk no in index table (it's <=chunk_max) | 596 // audio_chunk_pos = chunk no in index table (it's <=chunk_max) |
491 // d_audio->pts=initial_pts_delay+(float)apos/(float)sh_audio->wf->nAvgBytesPerSec; | 605 // d_audio->pts=initial_pts_delay+(float)apos/(float)sh_audio->wf->nAvgBytesPerSec; |
492 | 606 |
493 if(demuxer->type==DEMUXER_TYPE_AVI){ | 607 if(demuxer->type==DEMUXER_TYPE_AVI){ |
494 // interleaved stream: | 608 // interleaved stream: |
495 if(audio_chunk_pos<video_chunk_pos){ | 609 if(audio_chunk_pos<video_chunk_pos){ |
496 // calc skip_video_frames & adjust video pts counter: | 610 // calc priv->skip_video_frames & adjust video pts counter: |
497 for(i=audio_chunk_pos;i<video_chunk_pos;i++){ | 611 for(i=audio_chunk_pos;i<video_chunk_pos;i++){ |
498 int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid; | 612 int id=((AVIINDEXENTRY *)priv->idx)[i].ckid; |
499 if(avi_stream_id(id)==d_video->id) ++skip_video_frames; | 613 if(avi_stream_id(id)==d_video->id) ++priv->skip_video_frames; |
500 } | 614 } |
501 // requires for correct audio pts calculation (demuxer): | 615 // requires for correct audio pts calculation (demuxer): |
502 avi_video_pts-=skip_video_frames*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; | 616 priv->avi_video_pts-=priv->skip_video_frames*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; |
503 demuxer->idx_pos_a=demuxer->idx_pos_v=demuxer->idx_pos=audio_chunk_pos; | 617 priv->idx_pos_a=priv->idx_pos_v=priv->idx_pos=audio_chunk_pos; |
504 } | 618 } |
505 } else { | 619 } else { |
506 // non-interleaved stream: | 620 // non-interleaved stream: |
507 demuxer->idx_pos_a=audio_chunk_pos; | 621 priv->idx_pos_a=audio_chunk_pos; |
508 demuxer->idx_pos_v=video_chunk_pos; | 622 priv->idx_pos_v=video_chunk_pos; |
509 demuxer->idx_pos=(audio_chunk_pos<video_chunk_pos)?audio_chunk_pos:video_chunk_pos; | 623 priv->idx_pos=(audio_chunk_pos<video_chunk_pos)?audio_chunk_pos:video_chunk_pos; |
510 } | 624 } |
511 | 625 |
512 if(verbose) printf("SEEK: idx=%d (a:%d v:%d) v.skip=%d a.skip=%d/%4.3f \n", | 626 if(verbose) printf("SEEK: idx=%d (a:%d v:%d) v.skip=%d a.skip=%d/%4.3f \n", |
513 demuxer->idx_pos,audio_chunk_pos,video_chunk_pos, | 627 priv->idx_pos,audio_chunk_pos,video_chunk_pos, |
514 skip_video_frames,skip_audio_bytes,skip_audio_secs); | 628 priv->skip_video_frames,skip_audio_bytes,skip_audio_secs); |
515 | 629 |
516 if(skip_audio_bytes){ | 630 if(skip_audio_bytes){ |
517 demux_read_data(d_audio,NULL,skip_audio_bytes); | 631 demux_read_data(d_audio,NULL,skip_audio_bytes); |
518 //d_audio->pts=0; // PTS is outdated because of the raw data skipping | 632 //d_audio->pts=0; // PTS is outdated because of the raw data skipping |
519 } | 633 } |