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: "