Mercurial > mplayer.hg
comparison libmpdemux/demux_real.c @ 11596:6d377637ea60
Proper runtime index generation with support for growing files. Patch by rgselk <rgselknospam@yahoo.com>
author | alex |
---|---|
date | Mon, 08 Dec 2003 22:03:49 +0000 |
parents | fef5c880a61c |
children | a7c9ad2e4c45 |
comparison
equal
deleted
inserted
replaced
11595:95413c6d76a0 | 11596:6d377637ea60 |
---|---|
39 #define MAX_STREAMS 32 | 39 #define MAX_STREAMS 32 |
40 | 40 |
41 typedef struct { | 41 typedef struct { |
42 int timestamp; | 42 int timestamp; |
43 int offset; | 43 int offset; |
44 int packetno; | 44 // int packetno; |
45 int len; /* only filled by our index generator */ | 45 // int len; /* only filled by our index generator */ |
46 int flags; /* only filled by our index generator */ | 46 // int flags; /* only filled by our index generator */ |
47 } real_index_table_t; | 47 } real_index_table_t; |
48 | 48 |
49 typedef struct { | 49 typedef struct { |
50 /* for seeking */ | 50 /* for seeking */ |
51 int index_chunk_offset; | 51 int index_chunk_offset; |
52 real_index_table_t *index_table[MAX_STREAMS]; | 52 real_index_table_t *index_table[MAX_STREAMS]; |
53 | 53 |
54 // int *index_table[MAX_STREAMS]; | 54 // int *index_table[MAX_STREAMS]; |
55 int index_table_size[MAX_STREAMS]; | 55 int index_table_size[MAX_STREAMS]; |
56 int index_malloc_size[MAX_STREAMS]; | |
56 int data_chunk_offset; | 57 int data_chunk_offset; |
57 int num_of_packets; | 58 int num_of_packets; |
58 int current_packet; | 59 int current_packet; |
59 | 60 |
60 // need for seek | 61 // need for seek |
125 entries = priv->index_table_size[stream_id]; | 126 entries = priv->index_table_size[stream_id]; |
126 | 127 |
127 printf("Index table for stream %d\n", stream_id); | 128 printf("Index table for stream %d\n", stream_id); |
128 for (i = 0; i < entries; i++) | 129 for (i = 0; i < entries; i++) |
129 { | 130 { |
131 #if 1 | |
132 printf("i: %d, pos: %d, timestamp: %d\n", i, index[i].offset, index[i].timestamp); | |
133 #else | |
130 printf("packetno: %x pos: %x len: %x timestamp: %x flags: %x\n", | 134 printf("packetno: %x pos: %x len: %x timestamp: %x flags: %x\n", |
131 index[i].packetno, index[i].offset, index[i].len, index[i].timestamp, | 135 index[i].packetno, index[i].offset, index[i].len, index[i].timestamp, |
132 index[i].flags); | 136 index[i].flags); |
137 #endif | |
133 } | 138 } |
134 } | 139 } |
135 | 140 |
136 static int parse_index_chunk(demuxer_t *demuxer) | 141 static int parse_index_chunk(demuxer_t *demuxer) |
137 { | 142 { |
188 for (i = 0; i < entries; i++) | 193 for (i = 0; i < entries; i++) |
189 { | 194 { |
190 stream_skip(demuxer->stream, 2); /* version */ | 195 stream_skip(demuxer->stream, 2); /* version */ |
191 priv->index_table[stream_id][i].timestamp = stream_read_dword(demuxer->stream); | 196 priv->index_table[stream_id][i].timestamp = stream_read_dword(demuxer->stream); |
192 priv->index_table[stream_id][i].offset = stream_read_dword(demuxer->stream); | 197 priv->index_table[stream_id][i].offset = stream_read_dword(demuxer->stream); |
193 priv->index_table[stream_id][i].packetno = stream_read_dword(demuxer->stream); | 198 stream_skip(demuxer->stream, 4); /* packetno */ |
199 // priv->index_table[stream_id][i].packetno = stream_read_dword(demuxer->stream); | |
194 // printf("Index table: Stream#%d: entry: %d: pos: %d\n", | 200 // printf("Index table: Stream#%d: entry: %d: pos: %d\n", |
195 // stream_id, i, priv->index_table[stream_id][i].offset); | 201 // stream_id, i, priv->index_table[stream_id][i].offset); |
196 } | 202 } |
197 | 203 |
198 dump_index(demuxer, stream_id); | 204 dump_index(demuxer, stream_id); |
209 return 0; | 215 return 0; |
210 else | 216 else |
211 return 1; | 217 return 1; |
212 } | 218 } |
213 | 219 |
220 #if 1 | |
221 | |
222 static void add_index_item(demuxer_t *demuxer, int stream_id, int timestamp, int offset) | |
223 { | |
224 if (index_mode > 0 && (unsigned)stream_id < MAX_STREAMS) | |
225 { | |
226 real_priv_t *priv = demuxer->priv; | |
227 real_index_table_t *index; | |
228 if (priv->index_table_size[stream_id] >= priv->index_malloc_size[stream_id]) | |
229 { | |
230 if (priv->index_malloc_size[stream_id] == 0) | |
231 priv->index_malloc_size[stream_id] = 2048; | |
232 else | |
233 priv->index_malloc_size[stream_id] += priv->index_malloc_size[stream_id] / 2; | |
234 priv->index_table[stream_id] = realloc(priv->index_table[stream_id], priv->index_malloc_size[stream_id]*sizeof(priv->index_table[0][0])); | |
235 } | |
236 if (priv->index_table_size[stream_id] > 0) | |
237 { | |
238 index = &priv->index_table[stream_id][priv->index_table_size[stream_id] - 1]; | |
239 if (index->timestamp >= timestamp || index->offset >= offset) | |
240 return; | |
241 } | |
242 index = &priv->index_table[stream_id][priv->index_table_size[stream_id]++]; | |
243 index->timestamp = timestamp; | |
244 index->offset = offset; | |
245 demuxer->seekable = 1; | |
246 } | |
247 } | |
248 | |
249 static void add_index_segment(demuxer_t *demuxer, int seek_stream_id, int seek_timestamp) | |
250 { | |
251 int tag, len, stream_id, timestamp, flags; | |
252 if (seek_timestamp != -1 && (unsigned)seek_stream_id >= MAX_STREAMS) | |
253 return; | |
254 while (1) | |
255 { | |
256 demuxer->filepos = stream_tell(demuxer->stream); | |
257 | |
258 tag = stream_read_dword(demuxer->stream); | |
259 if (tag == MKTAG('A', 'T', 'A', 'D')) | |
260 { | |
261 stream_skip(demuxer->stream, 14); | |
262 continue; /* skip to next loop */ | |
263 } | |
264 len = tag & 0xffff; | |
265 if (tag == -256 || len < 12) | |
266 break; | |
267 | |
268 stream_id = stream_read_word(demuxer->stream); | |
269 timestamp = stream_read_dword(demuxer->stream); | |
270 | |
271 stream_skip(demuxer->stream, 1); /* reserved */ | |
272 flags = stream_read_char(demuxer->stream); | |
273 | |
274 if (flags == -256) | |
275 break; | |
276 | |
277 if (flags & 2) | |
278 { | |
279 add_index_item(demuxer, stream_id, timestamp, demuxer->filepos); | |
280 if (stream_id == seek_stream_id && timestamp >= seek_timestamp) | |
281 { | |
282 stream_seek(demuxer->stream, demuxer->filepos); | |
283 return; | |
284 } | |
285 } | |
286 // printf("Index: stream=%d packet=%d timestamp=%d len=%d flags=0x%x datapos=0x%x\n", stream_id, entries, timestamp, len, flags, index->offset); | |
287 /* skip data */ | |
288 stream_skip(demuxer->stream, len-12); | |
289 } | |
290 } | |
291 | |
292 static int generate_index(demuxer_t *demuxer) | |
293 { | |
294 real_priv_t *priv = demuxer->priv; | |
295 int origpos = stream_tell(demuxer->stream); | |
296 int data_pos = priv->data_chunk_offset-10; | |
297 int i; | |
298 int tag; | |
299 | |
300 stream_seek(demuxer->stream, data_pos); | |
301 tag = stream_read_dword(demuxer->stream); | |
302 if (tag != MKTAG('A', 'T', 'A', 'D')) | |
303 { | |
304 printf("Something went wrong, no data chunk found on given address (%d)\n", data_pos); | |
305 } | |
306 else | |
307 { | |
308 stream_skip(demuxer->stream, 14); | |
309 add_index_segment(demuxer, -1, -1); | |
310 } | |
311 demuxer->seekable = 0; | |
312 for (i = 0; i < MAX_STREAMS; i++) | |
313 { | |
314 if (priv->index_table_size[i] > 0) | |
315 { | |
316 dump_index(demuxer, i); | |
317 demuxer->seekable = 1; /* got index, we're able to seek */ | |
318 } | |
319 } | |
320 stream_reset(demuxer->stream); | |
321 stream_seek(demuxer->stream, origpos); | |
322 return 0; | |
323 } | |
324 | |
325 #else | |
326 | |
214 static int generate_index(demuxer_t *demuxer) | 327 static int generate_index(demuxer_t *demuxer) |
215 { | 328 { |
216 real_priv_t *priv = demuxer->priv; | 329 real_priv_t *priv = demuxer->priv; |
217 int origpos = stream_tell(demuxer->stream); | 330 int origpos = stream_tell(demuxer->stream); |
218 int data_pos = priv->data_chunk_offset-10; | 331 int data_pos = priv->data_chunk_offset-10; |
300 if (i == -256) | 413 if (i == -256) |
301 return 0; | 414 return 0; |
302 else | 415 else |
303 return 1; | 416 return 1; |
304 } | 417 } |
418 #endif | |
419 | |
305 | 420 |
306 int real_check_file(demuxer_t* demuxer) | 421 int real_check_file(demuxer_t* demuxer) |
307 { | 422 { |
308 real_priv_t *priv; | 423 real_priv_t *priv; |
309 int c; | 424 int c; |
431 reserved = stream_read_char(demuxer->stream); | 546 reserved = stream_read_char(demuxer->stream); |
432 flags = stream_read_char(demuxer->stream); | 547 flags = stream_read_char(demuxer->stream); |
433 /* flags: */ | 548 /* flags: */ |
434 /* 0x1 - reliable */ | 549 /* 0x1 - reliable */ |
435 /* 0x2 - keyframe */ | 550 /* 0x2 - keyframe */ |
551 | |
552 if (flags & 2) | |
553 add_index_item(demuxer, stream_id, timestamp, demuxer->filepos); | |
436 | 554 |
437 // printf("%08X: packet v%d len=%4d id=%d pts=%6d rvd=%d flags=%d \n", | 555 // printf("%08X: packet v%d len=%4d id=%d pts=%6d rvd=%d flags=%d \n", |
438 // (int)demuxer->filepos,(int)version,(int)len, stream_id, | 556 // (int)demuxer->filepos,(int)version,(int)len, stream_id, |
439 // (int) timestamp, reserved, flags); | 557 // (int) timestamp, reserved, flags); |
440 | 558 |
505 dp->pos = demuxer->filepos; | 623 dp->pos = demuxer->filepos; |
506 dp->flags = (flags & 0x2) ? 0x10 : 0; | 624 dp->flags = (flags & 0x2) ? 0x10 : 0; |
507 ds_add_packet(ds, dp); | 625 ds_add_packet(ds, dp); |
508 } | 626 } |
509 // we will not use audio index if we use -idx and have a video | 627 // we will not use audio index if we use -idx and have a video |
510 if(!demuxer->video->sh && index_mode == 2) | 628 if(!demuxer->video->sh && index_mode == 2 && (unsigned)demuxer->audio->id < MAX_STREAMS) |
511 while (timestamp > priv->index_table[demuxer->audio->id][priv->current_apacket].timestamp) | 629 while (priv->current_apacket + 1 < priv->index_table_size[demuxer->audio->id] && |
630 timestamp > priv->index_table[demuxer->audio->id][priv->current_apacket].timestamp) | |
512 priv->current_apacket += 1; | 631 priv->current_apacket += 1; |
513 | 632 |
514 return 1; | 633 return 1; |
515 } | 634 } |
516 | 635 |
704 if(len){ | 823 if(len){ |
705 printf("\n******** !!!!!!!! BUG!! len=%d !!!!!!!!!!! ********\n",len); | 824 printf("\n******** !!!!!!!! BUG!! len=%d !!!!!!!!!!! ********\n",len); |
706 if(len>0) stream_skip(demuxer->stream, len); | 825 if(len>0) stream_skip(demuxer->stream, len); |
707 } | 826 } |
708 } | 827 } |
709 if (index_mode == 1 || index_mode == 2) | 828 if ((unsigned)demuxer->video->id < MAX_STREAMS) |
710 while (timestamp > priv->index_table[demuxer->video->id][priv->current_vpacket + 1].timestamp) | 829 while (priv->current_vpacket + 1 < priv->index_table_size[demuxer->video->id] && |
830 timestamp > priv->index_table[demuxer->video->id][priv->current_vpacket + 1].timestamp) | |
711 priv->current_vpacket += 1; | 831 priv->current_vpacket += 1; |
712 | 832 |
713 return 1; | 833 return 1; |
714 } | 834 } |
715 | 835 |
1242 } | 1362 } |
1243 | 1363 |
1244 if(demuxer->video->sh){ | 1364 if(demuxer->video->sh){ |
1245 sh_video_t *sh=demuxer->video->sh; | 1365 sh_video_t *sh=demuxer->video->sh; |
1246 mp_msg(MSGT_DEMUX,MSGL_INFO,"VIDEO: %.4s [%08X,%08X] %dx%d (aspect %4.2f) %4.2f fps\n", | 1366 mp_msg(MSGT_DEMUX,MSGL_INFO,"VIDEO: %.4s [%08X,%08X] %dx%d (aspect %4.2f) %4.2f fps\n", |
1247 &sh->format,((unsigned int*)(sh->bih+1))[1],((unsigned int*)(sh->bih+1))[0], | 1367 (char *)&(le2me_32(sh->format)),((unsigned int*)(sh->bih+1))[1],((unsigned int*)(sh->bih+1))[0], |
1248 sh->disp_w,sh->disp_h,sh->aspect,sh->fps); | 1368 sh->disp_w,sh->disp_h,sh->aspect,sh->fps); |
1249 } | 1369 } |
1250 | 1370 |
1251 } | 1371 } |
1252 | 1372 |
1270 demux_stream_t *d_video = demuxer->video; | 1390 demux_stream_t *d_video = demuxer->video; |
1271 sh_audio_t *sh_audio = d_audio->sh; | 1391 sh_audio_t *sh_audio = d_audio->sh; |
1272 sh_video_t *sh_video = d_video->sh; | 1392 sh_video_t *sh_video = d_video->sh; |
1273 int vid = d_video->id, aid = d_audio->id; | 1393 int vid = d_video->id, aid = d_audio->id; |
1274 int next_offset = 0; | 1394 int next_offset = 0; |
1275 int rel_seek_frames = 0; | |
1276 int cur_timestamp = 0; | 1395 int cur_timestamp = 0; |
1277 int streams = 0; | 1396 int streams = 0; |
1397 int retried = 0; | |
1278 | 1398 |
1279 if ((index_mode != 1) && (index_mode != 2)) | 1399 if ((index_mode != 1) && (index_mode != 2)) |
1280 return 0; | 1400 return 0; |
1281 | 1401 |
1282 if (sh_video) | 1402 if (sh_video && (unsigned)vid < MAX_STREAMS && priv->index_table_size[vid]) |
1283 streams |= 1; | 1403 streams |= 1; |
1284 if (sh_audio) | 1404 if (sh_audio && (unsigned)aid < MAX_STREAMS && priv->index_table_size[aid]) |
1285 streams |= 2; | 1405 streams |= 2; |
1286 | 1406 |
1287 // printf("streams: %d\n", streams); | 1407 // printf("streams: %d\n", streams); |
1288 | 1408 |
1289 if (!streams) | 1409 if (!streams) |
1291 | 1411 |
1292 if (flags & 1) | 1412 if (flags & 1) |
1293 /* seek absolute */ | 1413 /* seek absolute */ |
1294 priv->current_apacket = priv->current_vpacket = 0; | 1414 priv->current_apacket = priv->current_vpacket = 0; |
1295 | 1415 |
1296 if (index_mode == 1) { | 1416 if ((streams & 1) && priv->current_vpacket >= priv->index_table_size[vid]) |
1417 priv->current_vpacket = priv->index_table_size[vid] - 1; | |
1418 if ((streams & 2) && priv->current_apacket >= priv->index_table_size[aid]) | |
1419 priv->current_apacket = priv->index_table_size[aid] - 1; | |
1420 | |
1421 // if (index_mode == 1 || index_mode == 2) { | |
1297 if (streams & 1) {// use the video index if we have one | 1422 if (streams & 1) {// use the video index if we have one |
1298 cur_timestamp = priv->index_table[vid][priv->current_vpacket].timestamp; | 1423 cur_timestamp = priv->index_table[vid][priv->current_vpacket].timestamp; |
1299 if (rel_seek_secs > 0) | 1424 if (rel_seek_secs > 0) |
1300 while ((priv->index_table[vid][priv->current_vpacket].timestamp - cur_timestamp) < rel_seek_secs * 1000){ | 1425 while ((priv->index_table[vid][priv->current_vpacket].timestamp - cur_timestamp) < rel_seek_secs * 1000){ |
1301 priv->current_vpacket += 1; | 1426 priv->current_vpacket += 1; |
1302 if (priv->current_vpacket >= priv->index_table_size[vid]) { | 1427 if (priv->current_vpacket >= priv->index_table_size[vid]) { |
1303 priv->current_vpacket = priv->index_table_size[vid] - 1; | 1428 priv->current_vpacket = priv->index_table_size[vid] - 1; |
1304 break; | 1429 if (!retried) { |
1430 stream_seek(demuxer->stream, priv->index_table[vid][priv->current_vpacket].offset); | |
1431 add_index_segment(demuxer, vid, cur_timestamp + rel_seek_secs * 1000); | |
1432 retried = 1; | |
1433 } | |
1434 else | |
1435 break; | |
1305 } | 1436 } |
1306 } | 1437 } |
1307 else if (rel_seek_secs < 0) | 1438 else if (rel_seek_secs < 0) |
1308 while ((cur_timestamp - priv->index_table[vid][priv->current_vpacket].timestamp) < - rel_seek_secs * 1000){ | 1439 while ((cur_timestamp - priv->index_table[vid][priv->current_vpacket].timestamp) < - rel_seek_secs * 1000){ |
1309 priv->current_vpacket -= 1; | 1440 priv->current_vpacket -= 1; |
1334 break; | 1465 break; |
1335 } | 1466 } |
1336 } | 1467 } |
1337 next_offset = priv->index_table[aid][priv->current_apacket].offset; | 1468 next_offset = priv->index_table[aid][priv->current_apacket].offset; |
1338 } | 1469 } |
1339 } | 1470 // } |
1340 else if (index_mode == 2) { | |
1341 /* flags & 2 ? */ | |
1342 if (streams & 1) | |
1343 rel_seek_frames = (int)(sh_video->fps*rel_seek_secs); | |
1344 else if (streams & 2) | |
1345 rel_seek_frames = (int)(rel_seek_secs); | |
1346 | |
1347 // printf("rel_seek_frames: %d\n", rel_seek_frames); | |
1348 | |
1349 if (streams & 2) | |
1350 priv->current_apacket += rel_seek_frames; | |
1351 if (streams & 1) | |
1352 priv->current_vpacket += rel_seek_frames; | |
1353 | |
1354 if ( | |
1355 ((streams & 2) && (priv->current_apacket > priv->index_table_size[aid])) || | |
1356 ((streams & 1) && (priv->current_vpacket > priv->index_table_size[vid])) ) | |
1357 return 0; | |
1358 | |
1359 /* both video and audio stream */ | |
1360 if (streams == 3) | |
1361 { | |
1362 // if (priv->current_apacket > priv->current_vpacket) | |
1363 // { | |
1364 /* search keyframe */ | |
1365 while (!(priv->index_table[vid][priv->current_vpacket].flags & 0x2)) | |
1366 priv->current_vpacket++; | |
1367 next_offset = priv->index_table[vid][priv->current_vpacket].offset; | |
1368 priv->audio_need_keyframe = 1; | |
1369 priv->video_after_seek = 1; | |
1370 // } | |
1371 // else | |
1372 // { | |
1373 // next_offset = priv->index_table[aid][priv->current_apacket].offset; | |
1374 // } | |
1375 } | |
1376 else | |
1377 { | |
1378 if (streams & 1) | |
1379 { | |
1380 /* search keyframe */ | |
1381 while (!(priv->index_table[vid][priv->current_vpacket].flags & 0x2)) | |
1382 priv->current_vpacket++; | |
1383 next_offset = priv->index_table[vid][priv->current_vpacket].offset; | |
1384 } | |
1385 else if (streams & 2) | |
1386 { | |
1387 next_offset = priv->index_table[aid][priv->current_apacket].offset; | |
1388 } | |
1389 } | |
1390 } | |
1391 // printf("seek: pos: %d, current packets: a: %d, v: %d\n", | 1471 // printf("seek: pos: %d, current packets: a: %d, v: %d\n", |
1392 // next_offset, priv->current_apacket, priv->current_vpacket); | 1472 // next_offset, priv->current_apacket, priv->current_vpacket); |
1393 stream_seek(demuxer->stream, next_offset); | 1473 if (next_offset) |
1474 stream_seek(demuxer->stream, next_offset); | |
1394 | 1475 |
1395 demux_real_fill_buffer(demuxer); | 1476 demux_real_fill_buffer(demuxer); |
1396 if (sh_audio) | 1477 if (sh_audio) |
1397 resync_audio_stream(sh_audio); | 1478 resync_audio_stream(sh_audio); |
1398 return 1; | 1479 return 1; |