Mercurial > mplayer.hg
comparison libmpdemux/demux_mkv.cpp @ 11260:1c269ab5f3f6
Support for -chapter selection.
author | mosu |
---|---|
date | Sat, 25 Oct 2003 12:42:24 +0000 |
parents | b4040706e1d3 |
children | c367751bd7cb |
comparison
equal
deleted
inserted
replaced
11259:c0a674107197 | 11260:1c269ab5f3f6 |
---|---|
75 #endif | 75 #endif |
76 | 76 |
77 // for e.g. "-slang ger" | 77 // for e.g. "-slang ger" |
78 extern char *dvdsub_lang; | 78 extern char *dvdsub_lang; |
79 extern char *audio_lang; | 79 extern char *audio_lang; |
80 // for "-chapter x-y" | |
81 extern int dvd_chapter; | |
82 extern int dvd_last_chapter; | |
80 | 83 |
81 // default values for Matroska elements | 84 // default values for Matroska elements |
82 #define MKVD_TIMECODESCALE 1000000 // 1000000 = 1ms | 85 #define MKVD_TIMECODESCALE 1000000 // 1000000 = 1ms |
83 | 86 |
84 #define MKV_SUBTYPE_TEXT 1 | 87 #define MKV_SUBTYPE_TEXT 1 |
185 uint32_t enc_algo, sig_algo, sig_hash_algo; | 188 uint32_t enc_algo, sig_algo, sig_hash_algo; |
186 unsigned char *enc_keyid, *sig_keyid, *signature; | 189 unsigned char *enc_keyid, *sig_keyid, *signature; |
187 uint32_t enc_keyid_len, sig_keyid_len, signature_len; | 190 uint32_t enc_keyid_len, sig_keyid_len, signature_len; |
188 } mkv_content_encoding_t; | 191 } mkv_content_encoding_t; |
189 | 192 |
193 typedef struct { | |
194 int64_t start, end; | |
195 } mkv_chapter_t; | |
196 | |
190 typedef struct mkv_track { | 197 typedef struct mkv_track { |
191 uint32_t tnum, xid; | 198 uint32_t tnum, xid; |
192 | 199 |
193 char *codec_id; | 200 char *codec_id; |
194 int ms_compat; | 201 int ms_compat; |
266 vector<uint64_t> *parsed_seekheads; | 273 vector<uint64_t> *parsed_seekheads; |
267 vector<uint64_t> *parsed_cues; | 274 vector<uint64_t> *parsed_cues; |
268 | 275 |
269 int64_t skip_to_timecode; | 276 int64_t skip_to_timecode; |
270 bool v_skip_to_keyframe, a_skip_to_keyframe; | 277 bool v_skip_to_keyframe, a_skip_to_keyframe; |
278 | |
279 vector<mkv_chapter_t> *chapters; // No support for nested chapters atm. | |
280 uint64_t stop_timecode; | |
271 } mkv_demuxer_t; | 281 } mkv_demuxer_t; |
272 | 282 |
273 typedef struct { | 283 typedef struct { |
274 uint32_t chunks; // number of chunks | 284 uint32_t chunks; // number of chunks |
275 uint32_t timestamp; // timestamp from packet header | 285 uint32_t timestamp; // timestamp from packet header |
1114 delete d->saved_l1; | 1124 delete d->saved_l1; |
1115 if (d->in != NULL) | 1125 if (d->in != NULL) |
1116 delete d->in; | 1126 delete d->in; |
1117 if (d->segment != NULL) | 1127 if (d->segment != NULL) |
1118 delete d->segment; | 1128 delete d->segment; |
1129 if (d->chapters != NULL) | |
1130 delete d->chapters; | |
1119 | 1131 |
1120 free(d); | 1132 free(d); |
1121 } | 1133 } |
1122 | 1134 |
1123 static void add_index_entry(mkv_demuxer_t *d, uint32_t tnum, uint64_t filepos, | 1135 static void add_index_entry(mkv_demuxer_t *d, uint32_t tnum, uint64_t filepos, |
1293 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n"); | 1305 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n"); |
1294 | 1306 |
1295 mkv_d->cues_found = 1; | 1307 mkv_d->cues_found = 1; |
1296 } | 1308 } |
1297 | 1309 |
1310 static void parse_chapters(mkv_demuxer_t *mkv_d, uint64_t pos) { | |
1311 EbmlElement *l2 = NULL; | |
1312 EbmlStream *es; | |
1313 KaxChapters *kchapters; | |
1314 KaxEditionEntry *keentry; | |
1315 KaxChapterAtom *kcatom; | |
1316 KaxChapterTimeStart *kctstart; | |
1317 KaxChapterTimeEnd *kctend; | |
1318 int upper_lvl_el, i, k; | |
1319 mkv_chapter_t chapter; | |
1320 | |
1321 if (mkv_d->chapters != NULL) | |
1322 return; | |
1323 | |
1324 es = mkv_d->es; | |
1325 upper_lvl_el = 0; | |
1326 | |
1327 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing chapters ] ---------\n"); | |
1328 | |
1329 mkv_d->in->setFilePointer(pos); | |
1330 | |
1331 kchapters = | |
1332 (KaxChapters *)es->FindNextElement(mkv_d->segment->Generic().Context, | |
1333 upper_lvl_el, 0xFFFFFFFFL, true, 1); | |
1334 if (kchapters == NULL) | |
1335 return; | |
1336 | |
1337 if (!(EbmlId(*kchapters) == KaxChapters::ClassInfos.GlobalId)) { | |
1338 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxChapters element found but %s.\n" | |
1339 "[mkv] \\---- [ parsing chapters ] ---------\n", | |
1340 kchapters->Generic().DebugName); | |
1341 | |
1342 return; | |
1343 } | |
1344 | |
1345 mkv_d->chapters = new vector<mkv_chapter_t>; | |
1346 kchapters->Read(*es, KaxChapters::ClassInfos.Context, upper_lvl_el, l2, | |
1347 true); | |
1348 | |
1349 for (i = 0; i < (int)kchapters->ListSize(); i++) { | |
1350 keentry = (KaxEditionEntry *)(*kchapters)[i]; | |
1351 if (EbmlId(*keentry) == KaxEditionEntry::ClassInfos.GlobalId) { | |
1352 for (k = 0; k < (int)keentry->ListSize(); k++) { | |
1353 kcatom = (KaxChapterAtom *)(*keentry)[k]; | |
1354 if (EbmlId(*kcatom) == KaxChapterAtom::ClassInfos.GlobalId) { | |
1355 chapter.start = 0; | |
1356 chapter.end = 0; | |
1357 kctstart = FINDFIRST(kcatom, KaxChapterTimeStart); | |
1358 if (kctstart != NULL) | |
1359 chapter.start = uint64(*kctstart) / 1000000; | |
1360 kctend = FINDFIRST(kcatom, KaxChapterTimeEnd); | |
1361 if (kctend != NULL) | |
1362 chapter.end = uint64(*kctend) / 1000000; | |
1363 mkv_d->chapters->push_back(chapter); | |
1364 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter %u from %02d:%02d:%02d." | |
1365 "%03d to %02d:%02d:%02d.%03d\n", mkv_d->chapters->size(), | |
1366 (int)(chapter.start / 60 / 60 / 1000), | |
1367 (int)((chapter.start / 60 / 1000) % 60), | |
1368 (int)((chapter.start / 1000) % 60), | |
1369 (int)(chapter.start % 1000), | |
1370 (int)(chapter.end / 60 / 60 / 1000), | |
1371 (int)((chapter.end / 60 / 1000) % 60), | |
1372 (int)((chapter.end / 1000) % 60), | |
1373 (int)(chapter.end % 1000)); | |
1374 } | |
1375 } | |
1376 } | |
1377 } | |
1378 | |
1379 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing chapters ] ---------\n"); | |
1380 delete kchapters; | |
1381 } | |
1382 | |
1298 static void parse_seekhead(mkv_demuxer_t *mkv_d, uint64_t pos) { | 1383 static void parse_seekhead(mkv_demuxer_t *mkv_d, uint64_t pos) { |
1299 EbmlElement *l2 = NULL; | 1384 EbmlElement *l2 = NULL; |
1300 EbmlStream *es; | 1385 EbmlStream *es; |
1301 KaxSeekHead *kseekhead; | 1386 KaxSeekHead *kseekhead; |
1302 KaxSeek *kseek; | 1387 KaxSeek *kseek; |
1367 if ((seek_pos != 0) && (id != NULL)) { | 1452 if ((seek_pos != 0) && (id != NULL)) { |
1368 if (*id == KaxSeekHead::ClassInfos.GlobalId) | 1453 if (*id == KaxSeekHead::ClassInfos.GlobalId) |
1369 parse_seekhead(mkv_d, seek_pos); | 1454 parse_seekhead(mkv_d, seek_pos); |
1370 else if (*id == KaxCues::ClassInfos.GlobalId) | 1455 else if (*id == KaxCues::ClassInfos.GlobalId) |
1371 parse_cues(mkv_d, seek_pos); | 1456 parse_cues(mkv_d, seek_pos); |
1457 else if (*id == KaxChapters::ClassInfos.GlobalId) | |
1458 parse_chapters(mkv_d, seek_pos); | |
1372 } | 1459 } |
1373 | 1460 |
1374 if (id != NULL) | 1461 if (id != NULL) |
1375 delete id; | 1462 delete id; |
1376 } | 1463 } |
1378 delete kseekhead; | 1465 delete kseekhead; |
1379 | 1466 |
1380 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing seek head ] ---------\n"); | 1467 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing seek head ] ---------\n"); |
1381 } | 1468 } |
1382 | 1469 |
1383 extern "C" void print_wave_header(WAVEFORMATEX *h); | 1470 extern "C" void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, |
1471 int flags); | |
1384 | 1472 |
1385 extern "C" int demux_mkv_open(demuxer_t *demuxer) { | 1473 extern "C" int demux_mkv_open(demuxer_t *demuxer) { |
1386 unsigned char signature[4]; | 1474 unsigned char signature[4]; |
1387 stream_t *s; | 1475 stream_t *s; |
1388 demux_packet_t *dp; | 1476 demux_packet_t *dp; |
1822 | 1910 |
1823 } else if ((EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) && | 1911 } else if ((EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) && |
1824 !mkv_d->cues_found) { | 1912 !mkv_d->cues_found) { |
1825 if (!find_in_vector(cues_to_parse, l1->GetElementPosition())) | 1913 if (!find_in_vector(cues_to_parse, l1->GetElementPosition())) |
1826 cues_to_parse.push_back(l1->GetElementPosition()); | 1914 cues_to_parse.push_back(l1->GetElementPosition()); |
1915 l1->SkipData(*es, l1->Generic().Context); | |
1916 | |
1917 } else if (EbmlId(*l1) == KaxChapters::ClassInfos.GlobalId) { | |
1918 parse_chapters(mkv_d, l1->GetElementPosition()); | |
1827 l1->SkipData(*es, l1->Generic().Context); | 1919 l1->SkipData(*es, l1->Generic().Context); |
1828 | 1920 |
1829 } else if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) { | 1921 } else if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) { |
1830 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cluster, headers are " | 1922 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cluster, headers are " |
1831 "parsed completely :)\n"); | 1923 "parsed completely :)\n"); |
2292 "subtitle track with the id %u.\n", demuxer->sub->id); | 2384 "subtitle track with the id %u.\n", demuxer->sub->id); |
2293 demuxer->sub->sh = NULL; | 2385 demuxer->sub->sh = NULL; |
2294 } | 2386 } |
2295 } | 2387 } |
2296 | 2388 |
2389 demuxer->priv = mkv_d; | |
2390 | |
2391 if (mkv_d->chapters != NULL) { | |
2392 for (i = 0; i < (int)mkv_d->chapters->size(); i++) { | |
2393 (*mkv_d->chapters)[i].start -= mkv_d->first_tc; | |
2394 (*mkv_d->chapters)[i].end -= mkv_d->first_tc; | |
2395 } | |
2396 if ((dvd_last_chapter > 0) && | |
2397 (dvd_last_chapter <= (int)mkv_d->chapters->size())) { | |
2398 if ((*mkv_d->chapters)[dvd_last_chapter - 1].end != 0) | |
2399 mkv_d->stop_timecode = (*mkv_d->chapters)[dvd_last_chapter - 1].end; | |
2400 else if ((dvd_last_chapter + 1) <= (int)mkv_d->chapters->size()) | |
2401 mkv_d->stop_timecode = (*mkv_d->chapters)[dvd_last_chapter].start; | |
2402 } | |
2403 } | |
2404 | |
2297 if (s->end_pos == 0) | 2405 if (s->end_pos == 0) |
2298 demuxer->seekable = 0; | 2406 demuxer->seekable = 0; |
2299 else { | 2407 else { |
2300 demuxer->movi_start = s->start_pos; | 2408 demuxer->movi_start = s->start_pos; |
2301 demuxer->movi_end = s->end_pos; | 2409 demuxer->movi_end = s->end_pos; |
2302 demuxer->seekable = 1; | 2410 demuxer->seekable = 1; |
2411 if ((dvd_chapter != 1) && (mkv_d->chapters != NULL) && | |
2412 (dvd_chapter <= (int)mkv_d->chapters->size())) | |
2413 demux_mkv_seek(demuxer, (float)(*mkv_d->chapters)[dvd_chapter - 1].start | |
2414 / 1000.0, 1); | |
2303 } | 2415 } |
2304 | |
2305 demuxer->priv = mkv_d; | |
2306 | 2416 |
2307 return 1; | 2417 return 1; |
2308 } | 2418 } |
2309 | 2419 |
2310 // Taken from demux_real.c. Thanks to the original developpers :) | 2420 // Taken from demux_real.c. Thanks to the original developpers :) |
2716 kbdur = FINDFIRST(l2, KaxBlockDuration); | 2826 kbdur = FINDFIRST(l2, KaxBlockDuration); |
2717 if (kbdur != NULL) | 2827 if (kbdur != NULL) |
2718 block_duration = uint64(*kbdur); | 2828 block_duration = uint64(*kbdur); |
2719 | 2829 |
2720 kblock = FINDFIRST(l2, KaxBlock); | 2830 kblock = FINDFIRST(l2, KaxBlock); |
2721 if (kblock != NULL) | 2831 if (kblock != NULL) { |
2722 kblock->SetParent(*mkv_d->cluster); | 2832 kblock->SetParent(*mkv_d->cluster); |
2833 if ((mkv_d->stop_timecode > 0) && | |
2834 ((kblock->GlobalTimecode() / 1000000 - mkv_d->first_tc) >= | |
2835 mkv_d->stop_timecode)) { | |
2836 delete l2; | |
2837 return 0; | |
2838 } | |
2839 } | |
2723 | 2840 |
2724 krefblock = FINDFIRST(l2, KaxReferenceBlock); | 2841 krefblock = FINDFIRST(l2, KaxReferenceBlock); |
2725 while (krefblock != NULL) { | 2842 while (krefblock != NULL) { |
2726 if (int64(*krefblock) < 0) | 2843 if (int64(*krefblock) < 0) |
2727 block_bref = int64(*krefblock); | 2844 block_bref = int64(*krefblock); |
3024 index = &mkv_d->index[i]; | 3141 index = &mkv_d->index[i]; |
3025 for (k = 0; k < index->num_entries; k++) { | 3142 for (k = 0; k < index->num_entries; k++) { |
3026 if (!index->entries[k].is_key) | 3143 if (!index->entries[k].is_key) |
3027 continue; | 3144 continue; |
3028 diff = target_timecode - (int64_t)index->entries[k].timecode; | 3145 diff = target_timecode - (int64_t)index->entries[k].timecode; |
3029 if ((target_timecode <= (mkv_d->last_pts * 1000)) && | 3146 if (((flags & 1) || (target_timecode <= (mkv_d->last_pts * 1000))) && |
3030 (diff >= 0) && (diff < min_diff)) { | 3147 (diff >= 0) && (diff < min_diff)) { |
3031 min_diff = diff; | 3148 min_diff = diff; |
3032 entry = &index->entries[k]; | 3149 entry = &index->entries[k]; |
3033 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek BACK, solution: last_pts: " | 3150 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek BACK, solution: last_pts: " |
3034 "%d, target: %d, diff: %d, entry->timecode: %d, PREV diff: " | 3151 "%d, target: %d, diff: %d, entry->timecode: %d, PREV diff: " |