Mercurial > mplayer.hg
annotate seek.c @ 1444:67af15b5f1a2
more paranoia -> check for DEC_OPT_FRAME_311
author | arpi |
---|---|
date | Mon, 06 Aug 2001 00:10:19 +0000 |
parents | 1728d249c783 |
children | fbcadb06e44f |
rev | line source |
---|---|
1405 | 1 #include <stdio.h> |
2 #include <stdlib.h> | |
1430 | 3 #include <unistd.h> |
1403 | 4 |
1405 | 5 extern int verbose; // defined in mplayer.c |
6 | |
7 #include "config.h" | |
8 | |
9 #include "stream.h" | |
10 #include "demuxer.h" | |
11 #include "parse_es.h" | |
12 | |
13 #include "wine/mmreg.h" | |
14 #include "wine/avifmt.h" | |
15 #include "wine/vfw.h" | |
16 | |
17 #include "codec-cfg.h" | |
18 #include "stheader.h" | |
19 | |
20 extern void resync_audio_stream(sh_audio_t *sh_audio); | |
21 extern void skip_audio_frame(sh_audio_t *sh_audio); | |
22 | |
23 extern int asf_packetsize; // for seeking | |
24 | |
25 extern float avi_audio_pts; | |
26 extern float avi_video_pts; | |
1408 | 27 //extern float avi_video_ftime; |
1405 | 28 extern int skip_video_frames; |
29 extern float initial_pts_delay; | |
30 extern int seek_to_byte; | |
31 extern char* current_module; // for debugging | |
32 | |
33 // flags: | |
34 // 0x1 - absolute/relative | |
35 // 0x2 - keyframe/hard | |
36 | |
37 int demux_seek(demuxer_t *demuxer,float rel_seek_secs,int flags){ | |
38 demux_stream_t *d_audio=demuxer->audio; | |
39 demux_stream_t *d_video=demuxer->video; | |
40 sh_audio_t *sh_audio=d_audio->sh; | |
41 sh_video_t *sh_video=d_video->sh; | |
1403 | 42 float skip_audio_secs=0; |
43 | |
1405 | 44 if(demuxer->file_format==DEMUXER_TYPE_AVI && demuxer->idx_size<=0){ |
45 printf("Can't seek in raw .AVI streams! (index required, try with the -idx switch!) \n"); | |
46 return 0; | |
47 } | |
48 | |
49 current_module="seek"; | |
50 | |
1403 | 51 // clear demux buffers: |
52 if(sh_audio){ ds_free_packs(d_audio);sh_audio->a_buffer_len=0;} | |
53 ds_free_packs(d_video); | |
54 | |
1421 | 55 demuxer->stream->eof=0; // clear eof flag |
56 | |
1403 | 57 // printf("sh_audio->a_buffer_len=%d \n",sh_audio->a_buffer_len); |
58 | |
59 | |
1405 | 60 switch(demuxer->file_format){ |
1403 | 61 |
1428
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
62 //FIXME: OFF_T - Didn't check AVI case yet (avi files can't be >2G anyway?) |
1403 | 63 case DEMUXER_TYPE_AVI: { |
64 //================= seek in AVI ========================== | |
65 int rel_seek_frames=rel_seek_secs*sh_video->fps; | |
66 int curr_audio_pos=0; | |
67 int audio_chunk_pos=-1; | |
68 int video_chunk_pos=d_video->pos; | |
1405 | 69 int i; |
1403 | 70 |
71 skip_video_frames=0; | |
72 avi_audio_pts=0; | |
73 | |
74 // find nearest video keyframe chunk pos: | |
75 if(rel_seek_frames>0){ | |
76 // seek forward | |
77 while(video_chunk_pos<demuxer->idx_size){ | |
78 int id=((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].ckid; | |
79 if(avi_stream_id(id)==d_video->id){ // video frame | |
80 if((--rel_seek_frames)<0 && ((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break; | |
1408 | 81 // ++skip_audio_bytes; |
1403 | 82 } |
83 ++video_chunk_pos; | |
84 } | |
85 } else { | |
86 // seek backward | |
87 while(video_chunk_pos>=0){ | |
88 int id=((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].ckid; | |
89 if(avi_stream_id(id)==d_video->id){ // video frame | |
90 if((++rel_seek_frames)>0 && ((AVIINDEXENTRY *)demuxer->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break; | |
1408 | 91 // --skip_audio_bytes; |
1403 | 92 } |
93 --video_chunk_pos; | |
94 } | |
95 } | |
96 demuxer->idx_pos_a=demuxer->idx_pos_v=demuxer->idx_pos=video_chunk_pos; | |
97 // printf("%d frames skipped\n",skip_audio_bytes); | |
98 | |
99 // re-calc video pts: | |
100 d_video->pack_no=0; | |
101 for(i=0;i<video_chunk_pos;i++){ | |
102 int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid; | |
103 if(avi_stream_id(id)==d_video->id) ++d_video->pack_no; | |
104 } | |
105 sh_video->num_frames=d_video->pack_no; | |
106 avi_video_pts=d_video->pack_no*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; | |
107 | |
108 if(sh_audio){ | |
109 int i; | |
110 int apos=0; | |
111 int last=0; | |
112 int len=0; | |
1408 | 113 int skip_audio_bytes=0; |
1403 | 114 |
115 // calc new audio position in audio stream: (using avg.bps value) | |
116 curr_audio_pos=(avi_video_pts) * sh_audio->wf->nAvgBytesPerSec; | |
117 if(curr_audio_pos<0)curr_audio_pos=0; | |
118 #if 1 | |
119 curr_audio_pos&=~15; // requires for PCM formats!!! | |
120 #else | |
121 curr_audio_pos/=sh_audio->wf->nBlockAlign; | |
122 curr_audio_pos*=sh_audio->wf->nBlockAlign; | |
123 demuxer->audio_seekable=1; | |
124 #endif | |
125 | |
126 // find audio chunk pos: | |
127 for(i=0;i<video_chunk_pos;i++){ | |
128 int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid; | |
129 if(avi_stream_id(id)==d_audio->id){ | |
130 len=((AVIINDEXENTRY *)demuxer->idx)[i].dwChunkLength; | |
131 last=i; | |
132 if(apos<=curr_audio_pos && curr_audio_pos<(apos+len)){ | |
133 if(verbose)printf("break;\n"); | |
134 break; | |
135 } | |
136 apos+=len; | |
137 } | |
138 } | |
139 if(verbose)printf("XXX i=%d last=%d apos=%d curr_audio_pos=%d \n", | |
140 i,last,apos,curr_audio_pos); | |
141 // audio_chunk_pos=last; // maybe wrong (if not break; ) | |
142 audio_chunk_pos=i; // maybe wrong (if not break; ) | |
143 skip_audio_bytes=curr_audio_pos-apos; | |
144 | |
145 // update stream position: | |
146 d_audio->pos=audio_chunk_pos; | |
147 d_audio->dpos=apos; | |
148 d_audio->pts=initial_pts_delay+(float)apos/(float)sh_audio->wf->nAvgBytesPerSec; | |
149 demuxer->idx_pos_a=demuxer->idx_pos_v=demuxer->idx_pos=audio_chunk_pos; | |
150 | |
151 if(!(sh_audio->codec->flags&CODECS_FLAG_SEEKABLE)){ | |
152 #if 0 | |
153 // curr_audio_pos=apos; // selected audio codec can't seek in chunk | |
154 skip_audio_secs=(float)skip_audio_bytes/(float)sh_audio->wf->nAvgBytesPerSec; | |
155 //printf("Seek_AUDIO: %d bytes --> %5.3f secs\n",skip_audio_bytes,skip_audio_secs); | |
156 skip_audio_bytes=0; | |
157 #else | |
158 int d=skip_audio_bytes % sh_audio->wf->nBlockAlign; | |
159 skip_audio_bytes-=d; | |
160 // curr_audio_pos-=d; | |
161 skip_audio_secs=(float)d/(float)sh_audio->wf->nAvgBytesPerSec; | |
162 //printf("Seek_AUDIO: %d bytes --> %5.3f secs\n",d,skip_audio_secs); | |
163 #endif | |
164 } | |
165 // now: audio_chunk_pos=pos in index | |
166 // skip_audio_bytes=bytes to skip from that chunk | |
167 // skip_audio_secs=time to play audio before video (if can't skip) | |
168 | |
169 // calc skip_video_frames & adjust video pts counter: | |
170 // i=last; | |
171 for(i=demuxer->idx_pos;i<video_chunk_pos;i++){ | |
172 int id=((AVIINDEXENTRY *)demuxer->idx)[i].ckid; | |
173 if(avi_stream_id(id)==d_video->id) ++skip_video_frames; | |
174 } | |
175 // requires for correct audio pts calculation (demuxer): | |
176 avi_video_pts-=skip_video_frames*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; | |
1408 | 177 |
178 if(verbose) printf("SEEK: idx=%d (a:%d v:%d) v.skip=%d a.skip=%d/%4.3f \n", | |
179 demuxer->idx_pos,audio_chunk_pos,video_chunk_pos, | |
180 skip_video_frames,skip_audio_bytes,skip_audio_secs); | |
1403 | 181 |
1408 | 182 if(skip_audio_bytes){ |
183 demux_read_data(d_audio,NULL,skip_audio_bytes); | |
184 //d_audio->pts=0; // PTS is outdated because of the raw data skipping | |
185 } | |
186 resync_audio_stream(sh_audio); | |
187 } | |
1403 | 188 |
189 } | |
190 break; | |
191 | |
1428
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
192 //FIXME: OFF_T - didn't test ASF case yet (don't have a large asf...) |
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
193 //FIXME: reports good or bad to steve@daviesfam.org please |
1403 | 194 case DEMUXER_TYPE_ASF: { |
195 //================= seek in ASF ========================== | |
196 float p_rate=10; // packets / sec | |
1428
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
197 off_t rel_seek_packs=rel_seek_secs*p_rate; // FIXME: int may be enough? |
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
198 off_t rel_seek_bytes=rel_seek_packs*asf_packetsize; |
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
199 off_t newpos; |
1403 | 200 //printf("ASF: packs: %d duration: %d \n",(int)fileh.packets,*((int*)&fileh.duration)); |
201 // printf("ASF_seek: %d secs -> %d packs -> %d bytes \n", | |
202 // rel_seek_secs,rel_seek_packs,rel_seek_bytes); | |
203 newpos=demuxer->filepos+rel_seek_bytes; | |
204 if(newpos<0 || newpos<demuxer->movi_start) newpos=demuxer->movi_start; | |
205 // printf("\r -- asf: newpos=%d -- \n",newpos); | |
206 stream_seek(demuxer->stream,newpos); | |
207 | |
208 ds_fill_buffer(d_video); | |
1408 | 209 if(sh_audio){ |
210 ds_fill_buffer(d_audio); | |
211 resync_audio_stream(sh_audio); | |
212 } | |
1403 | 213 |
214 while(1){ | |
1408 | 215 if(sh_audio && !d_audio->eof){ |
216 float a_pts=d_audio->pts; | |
217 a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps; | |
1403 | 218 // sync audio: |
1408 | 219 if (d_video->pts > a_pts){ |
220 skip_audio_frame(sh_audio); | |
221 // if(!ds_fill_buffer(d_audio)) sh_audio=NULL; // skip audio. EOF? | |
1403 | 222 continue; |
223 } | |
224 } | |
225 if(d_video->flags&1) break; // found a keyframe! | |
226 if(!ds_fill_buffer(d_video)) break; // skip frame. EOF? | |
227 } | |
228 | |
229 } | |
230 break; | |
231 | |
232 case DEMUXER_TYPE_MPEG_ES: | |
233 case DEMUXER_TYPE_MPEG_PS: { | |
234 //================= seek in MPEG ========================== | |
1428
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
235 off_t newpos; |
1403 | 236 if(!sh_video->i_bps) // unspecified? |
237 newpos=demuxer->filepos+2324*75*rel_seek_secs; // 174.3 kbyte/sec | |
238 else | |
239 newpos=demuxer->filepos+(sh_video->i_bps)*rel_seek_secs; | |
240 | |
241 if(newpos<seek_to_byte) newpos=seek_to_byte; | |
1428
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
242 #ifdef _LARGEFILE_SOURCE |
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
243 newpos&=~((long long)STREAM_BUFFER_SIZE-1); /* sector boundary */ |
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
244 #else |
1403 | 245 newpos&=~(STREAM_BUFFER_SIZE-1); /* sector boundary */ |
1428
a90d889eb649
largefile patch by Stephen Davies <steve@daviesfam.org>
arpi
parents:
1421
diff
changeset
|
246 #endif |
1403 | 247 stream_seek(demuxer->stream,newpos); |
1408 | 248 |
1403 | 249 // re-sync video: |
250 videobuf_code_len=0; // reset ES stream buffer | |
1408 | 251 |
252 ds_fill_buffer(d_video); | |
253 if(sh_audio){ | |
254 ds_fill_buffer(d_audio); | |
255 resync_audio_stream(sh_audio); | |
256 } | |
257 | |
258 while(1){ | |
259 int i; | |
260 if(sh_audio && !d_audio->eof && d_video->pts && d_audio->pts){ | |
261 float a_pts=d_audio->pts; | |
262 a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps; | |
263 if(d_video->pts>a_pts){ | |
264 skip_audio_frame(sh_audio); // sync audio | |
265 continue; | |
266 } | |
267 } | |
268 i=sync_video_packet(d_video); | |
1403 | 269 if(i==0x1B3 || i==0x1B8) break; // found it! |
1405 | 270 if(!i || !skip_video_packet(d_video)) break; // EOF? |
1403 | 271 } |
1408 | 272 |
1403 | 273 } |
274 break; | |
275 | |
1405 | 276 } // switch(demuxer->file_format) |
1403 | 277 |
278 //====================== re-sync audio: ===================== | |
279 if(sh_audio){ | |
1408 | 280 if(verbose){ |
281 float a_pts=d_audio->pts; | |
282 a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps; | |
283 printf("SEEK: A: %5.3f V: %5.3f A-V: %5.3f \n",a_pts,d_video->pts,a_pts-d_video->pts); | |
284 } | |
1405 | 285 printf("A:%6.1f V:%6.1f A-V:%7.3f ct: ? \r",d_audio->pts,d_video->pts,0.0f); |
1403 | 286 } else { |
1405 | 287 printf("A: --- V:%6.1f \r",d_video->pts); |
1403 | 288 } |
1405 | 289 fflush(stdout); |
1403 | 290 |
291 if(sh_audio) sh_audio->timer=-skip_audio_secs; | |
292 sh_video->timer=0; // !!!!!! | |
293 | |
1405 | 294 return 1; |
295 } |