comparison libmpdemux/demux_mkv.cpp @ 10685:f54ffeb29447

Support for linked seek heads, multiple seek heads, multiple cues.
author mosu
date Sun, 24 Aug 2003 12:34:42 +0000
parents 99eb26749a14
children 4079bc9b15f9
comparison
equal deleted inserted replaced
10684:99eb26749a14 10685:f54ffeb29447
17 17
18 #include "../subreader.h" 18 #include "../subreader.h"
19 #include "../libvo/sub.h" 19 #include "../libvo/sub.h"
20 } 20 }
21 21
22 #include <iostream>
23 #include <cassert>
24 #include <typeinfo>
25 #include <vector> 22 #include <vector>
26 23
27 #include <ebml/EbmlHead.h> 24 #include <ebml/EbmlHead.h>
28 #include <ebml/EbmlSubHead.h> 25 #include <ebml/EbmlSubHead.h>
29 #include <ebml/EbmlStream.h> 26 #include <ebml/EbmlStream.h>
196 193
197 mkv_track_index_t *index; 194 mkv_track_index_t *index;
198 int num_indexes, cues_found, cues_searched; 195 int num_indexes, cues_found, cues_searched;
199 int64_t *cluster_positions; 196 int64_t *cluster_positions;
200 int num_cluster_pos; 197 int num_cluster_pos;
198 vector<uint64_t> *parsed_seekheads;
199 vector<uint64_t> *parsed_cues;
201 200
202 int64_t skip_to_timecode; 201 int64_t skip_to_timecode;
203 bool v_skip_to_keyframe, a_skip_to_keyframe; 202 bool v_skip_to_keyframe, a_skip_to_keyframe;
204 } mkv_demuxer_t; 203 } mkv_demuxer_t;
205 204
796 mkv_d->num_cluster_pos++; 795 mkv_d->num_cluster_pos++;
797 } else 796 } else
798 mkv_d->num_cluster_pos = 0; 797 mkv_d->num_cluster_pos = 0;
799 } 798 }
800 799
800 static int find_in_vector(vector<uint64_t> &vec, uint64_t value) {
801 unsigned int i;
802
803 for (i = 0; i < vec.size(); i++)
804 if (vec[i] == value)
805 return 1;
806
807 return 0;
808 }
809
801 #define in_parent(p) (mkv_d->in->getFilePointer() < \ 810 #define in_parent(p) (mkv_d->in->getFilePointer() < \
802 (p->GetElementPosition() + p->ElementSize())) 811 (p->GetElementPosition() + p->ElementSize()))
803 #define FINDFIRST(p, c) (static_cast<c *> \ 812 #define FINDFIRST(p, c) (static_cast<c *> \
804 (((EbmlMaster *)p)->FindFirstElt(c::ClassInfos, false))) 813 (((EbmlMaster *)p)->FindFirstElt(c::ClassInfos, false)))
805 #define FINDNEXT(p, c, e) (static_cast<c *> \ 814 #define FINDNEXT(p, c, e) (static_cast<c *> \
806 (((EbmlMaster *)p)->FindNextElt(*e, false))) 815 (((EbmlMaster *)p)->FindNextElt(*e, false)))
807 816
808 static int parse_cues(mkv_demuxer_t *mkv_d) { 817 static void parse_cues(mkv_demuxer_t *mkv_d, uint64_t pos) {
809 EbmlElement *l2 = NULL; 818 EbmlElement *l2 = NULL;
810 EbmlStream *es; 819 EbmlStream *es;
811 KaxCues *cues; 820 KaxCues *cues;
812 KaxCuePoint *cpoint; 821 KaxCuePoint *cpoint;
813 KaxCueTime *ctime; 822 KaxCueTime *ctime;
818 int upper_lvl_el, i, k; 827 int upper_lvl_el, i, k;
819 uint64_t tc_scale, filepos = 0, timecode = 0; 828 uint64_t tc_scale, filepos = 0, timecode = 0;
820 uint32_t tnum = 0; 829 uint32_t tnum = 0;
821 mkv_index_entry_t *entry; 830 mkv_index_entry_t *entry;
822 831
832 if (find_in_vector(*mkv_d->parsed_cues, pos))
833 return;
834
835 mkv_d->parsed_cues->push_back(pos);
836
837 mkv_d->in->setFilePointer(pos);
838
823 es = mkv_d->es; 839 es = mkv_d->es;
824 tc_scale = mkv_d->tc_scale; 840 tc_scale = mkv_d->tc_scale;
825 upper_lvl_el = 0; 841 upper_lvl_el = 0;
826 842
827 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing cues ] -----------\n"); 843 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing cues ] -----------\n");
828 844
829 cues = (KaxCues *)es->FindNextElement(mkv_d->segment->Generic().Context, 845 cues = (KaxCues *)es->FindNextElement(mkv_d->segment->Generic().Context,
830 upper_lvl_el, 0xFFFFFFFFL, true, 1); 846 upper_lvl_el, 0xFFFFFFFFL, true, 1);
831 if (cues == NULL) 847 if (cues == NULL)
832 return 0; 848 return;
833 849
834 if (!(EbmlId(*cues) == KaxCues::ClassInfos.GlobalId)) { 850 if (!(EbmlId(*cues) == KaxCues::ClassInfos.GlobalId)) {
835 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxCues element found but but %s.\n" 851 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxCues element found but %s.\n"
836 "[mkv] \\---- [ parsing cues ] -----------\n", 852 "[mkv] \\---- [ parsing cues ] -----------\n",
837 cues->Generic().DebugName); 853 cues->Generic().DebugName);
838 854
839 return 0; 855 return;
840 } 856 }
841 857
842 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cues\n"); 858 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cues\n");
843 859
844 cues->Read(*es, KaxCues::ClassInfos.Context, upper_lvl_el, l2, true); 860 cues->Read(*es, KaxCues::ClassInfos.Context, upper_lvl_el, l2, true);
905 } 921 }
906 } 922 }
907 923
908 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n"); 924 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n");
909 925
910 return 1; 926 mkv_d->cues_found = 1;
927 }
928
929 static void parse_seekhead(mkv_demuxer_t *mkv_d, uint64_t pos) {
930 EbmlElement *l2 = NULL;
931 EbmlStream *es;
932 KaxSeekHead *kseekhead;
933 KaxSeek *kseek;
934 KaxSeekID *ksid;
935 KaxSeekPosition *kspos;
936 int upper_lvl_el, i, k, s, id_found;
937 uint64_t seek_pos;
938 EbmlId *id;
939 EbmlElement *e;
940 binary *b;
941
942 if (find_in_vector(*mkv_d->parsed_seekheads, pos))
943 return;
944
945 mkv_d->parsed_seekheads->push_back(pos);
946
947 es = mkv_d->es;
948 upper_lvl_el = 0;
949
950 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing seek head ] ---------\n");
951
952 mkv_d->in->setFilePointer(pos);
953
954 kseekhead =
955 (KaxSeekHead *)es->FindNextElement(mkv_d->segment->Generic().Context,
956 upper_lvl_el, 0xFFFFFFFFL, true, 1);
957 if (kseekhead == NULL)
958 return;
959
960 if (!(EbmlId(*kseekhead) == KaxSeekHead::ClassInfos.GlobalId)) {
961 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] No KaxSeekead element found but %s.\n"
962 "[mkv] \\---- [ parsing seek head ] ---------\n",
963 kseekhead->Generic().DebugName);
964
965 return;
966 }
967
968 kseekhead->Read(*es, KaxSeekHead::ClassInfos.Context, upper_lvl_el, l2,
969 true);
970
971 for (i = 0; i < (int)kseekhead->ListSize(); i++) {
972 kseek = (KaxSeek *)(*kseekhead)[i];
973 if (!(EbmlId(*kseek) == KaxSeek::ClassInfos.GlobalId))
974 continue;
975
976 seek_pos = 0;
977 id = NULL;
978
979 for (k = 0; k < (int)kseek->ListSize(); k++) {
980 e = (*kseek)[k];
981
982 if (EbmlId(*e) == KaxSeekID::ClassInfos.GlobalId) {
983 ksid = (KaxSeekID *)e;
984
985 b = ksid->GetBuffer();
986 s = ksid->GetSize();
987 if (id != NULL)
988 delete id;
989 id = new EbmlId(b, s);
990
991 } else if (EbmlId(*e) == KaxSeekPosition::ClassInfos.GlobalId) {
992 kspos = (KaxSeekPosition *)e;
993 seek_pos = mkv_d->segment->GetGlobalPosition(uint64(*kspos));
994
995 }
996 }
997
998 if ((seek_pos != 0) && (id != NULL)) {
999 if (*id == KaxSeekHead::ClassInfos.GlobalId)
1000 parse_seekhead(mkv_d, seek_pos);
1001 else if (*id == KaxCues::ClassInfos.GlobalId)
1002 parse_cues(mkv_d, seek_pos);
1003 }
1004
1005 if (id != NULL)
1006 delete id;
1007 }
1008
1009 delete kseekhead;
1010
1011 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing seek head ] ---------\n");
911 } 1012 }
912 1013
913 extern "C" void print_wave_header(WAVEFORMATEX *h); 1014 extern "C" void print_wave_header(WAVEFORMATEX *h);
914 1015
915 extern "C" int demux_mkv_open(demuxer_t *demuxer) { 1016 extern "C" int demux_mkv_open(demuxer_t *demuxer) {
922 EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL; 1023 EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL;
923 EbmlStream *es; 1024 EbmlStream *es;
924 mkv_track_t *track; 1025 mkv_track_t *track;
925 sh_audio_t *sh_a; 1026 sh_audio_t *sh_a;
926 sh_video_t *sh_v; 1027 sh_video_t *sh_v;
927 uint64_t seek_pos, current_pos, cues_pos; 1028 vector<uint64_t> seekheads_to_parse;
928 int seek_element_is_cue; 1029 vector<uint64_t> cues_to_parse;
1030 int64_t current_pos;
929 1031
930 #ifdef USE_ICONV 1032 #ifdef USE_ICONV
931 subcp_open(); 1033 subcp_open();
932 #endif 1034 #endif
933 1035
989 } 1091 }
990 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n"); 1092 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n");
991 1093
992 mkv_d->segment = (KaxSegment *)l0; 1094 mkv_d->segment = (KaxSegment *)l0;
993 mkv_d->tc_scale = MKVD_TIMECODESCALE; 1095 mkv_d->tc_scale = MKVD_TIMECODESCALE;
994 cues_pos = 0; 1096 mkv_d->parsed_seekheads = new vector<uint64_t>;
1097 mkv_d->parsed_cues = new vector<uint64_t>;
995 1098
996 upper_lvl_el = 0; 1099 upper_lvl_el = 0;
997 exit_loop = 0; 1100 exit_loop = 0;
998 // We've got our segment, so let's find the tracks 1101 // We've got our segment, so let's find the tracks
999 l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, 1102 l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL,
1223 } // while (ktentry != NULL) 1326 } // while (ktentry != NULL)
1224 1327
1225 l1->SkipData(*es, l1->Generic().Context); 1328 l1->SkipData(*es, l1->Generic().Context);
1226 1329
1227 } else if (EbmlId(*l1) == KaxSeekHead::ClassInfos.GlobalId) { 1330 } else if (EbmlId(*l1) == KaxSeekHead::ClassInfos.GlobalId) {
1228 1331 if (!find_in_vector(seekheads_to_parse, l1->GetElementPosition()))
1229 KaxSeek *kseek; 1332 seekheads_to_parse.push_back(l1->GetElementPosition());
1230 KaxSeekID *ksid; 1333 l1->SkipData(*es, l1->Generic().Context);
1231 KaxSeekPosition *kspos;
1232
1233 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found seek head\n");
1234
1235 l1->Read(*es, KaxSeekHead::ClassInfos.Context, upper_lvl_el, l2, true);
1236
1237 kseek = FINDFIRST(l1, KaxSeek);
1238
1239 while (kseek != NULL) {
1240 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + seek entry\n");
1241
1242 seek_element_is_cue = 0;
1243 seek_pos = 0;
1244
1245 ksid = FINDFIRST(kseek, KaxSeekID);
1246 if (ksid != NULL) {
1247 binary *b;
1248 int s;
1249
1250 b = ksid->GetBuffer();
1251 s = ksid->GetSize();
1252 EbmlId id(b, s);
1253
1254 if (id == KaxCues::ClassInfos.GlobalId)
1255 seek_element_is_cue = 1;
1256
1257 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + seek ID: ");
1258 for (i = 0; i < s; i++)
1259 mp_msg(MSGT_DEMUX, MSGL_V, "0x%02x ",
1260 ((unsigned char *)b)[i]);
1261 mp_msg(MSGT_DEMUX, MSGL_V, "(%s)\n",
1262 (id == KaxInfo::ClassInfos.GlobalId) ?
1263 "KaxInfo" :
1264 (id == KaxCluster::ClassInfos.GlobalId) ?
1265 "KaxCluster" :
1266 (id == KaxTracks::ClassInfos.GlobalId) ?
1267 "KaxTracks" :
1268 (id == KaxCues::ClassInfos.GlobalId) ?
1269 "KaxCues" :
1270 (id == KaxAttachments::ClassInfos.GlobalId) ?
1271 "KaxAttachments" :
1272 (id == KaxChapters::ClassInfos.GlobalId) ?
1273 "KaxChapters" :
1274 "unknown");
1275 }
1276
1277 kspos = FINDFIRST(kseek, KaxSeekPosition);
1278 if (kspos != NULL) {
1279 seek_pos = uint64(*kspos);
1280 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + seek position: %llu\n",
1281 seek_pos);
1282 }
1283
1284 if (!mkv_d->cues_found && (kspos != NULL) &&
1285 seek_element_is_cue && (s->end_pos != 0))
1286 cues_pos = mkv_d->segment->GetGlobalPosition(seek_pos);
1287
1288 kseek = FINDNEXT(l1, KaxSeek, kseek);
1289
1290 } // while (kseek != NULL)
1291 1334
1292 } else if ((EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) && 1335 } else if ((EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) &&
1293 !mkv_d->cues_found) { 1336 !mkv_d->cues_found) {
1294 // If the cues are up front then by all means read them now! 1337 if (!find_in_vector(cues_to_parse, l1->GetElementPosition()))
1295 current_pos = io.getFilePointer(); 1338 cues_to_parse.push_back(l1->GetElementPosition());
1296 io.setFilePointer(l1->GetElementPosition());
1297 mkv_d->cues_found = parse_cues(mkv_d);
1298 stream_reset(s);
1299 l1->SkipData(*es, l1->Generic().Context); 1339 l1->SkipData(*es, l1->Generic().Context);
1300 1340
1301 } else if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) { 1341 } else if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) {
1302 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cluster, headers are " 1342 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cluster, headers are "
1303 "parsed completely :)\n"); 1343 "parsed completely :)\n");
1342 free_mkv_demuxer(mkv_d); 1382 free_mkv_demuxer(mkv_d);
1343 return 0; 1383 return 0;
1344 } 1384 }
1345 1385
1346 current_pos = io.getFilePointer(); 1386 current_pos = io.getFilePointer();
1387
1347 // Try to find the very first timecode (cluster timecode). 1388 // Try to find the very first timecode (cluster timecode).
1348 l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el, 1389 l2 = es->FindNextElement(l1->Generic().Context, upper_lvl_el,
1349 0xFFFFFFFFL, true, 1); 1390 0xFFFFFFFFL, true, 1);
1350 if ((l2 != NULL) && !upper_lvl_el && 1391 if ((l2 != NULL) && !upper_lvl_el &&
1351 (EbmlId(*l2) == KaxClusterTimecode::ClassInfos.GlobalId)) { 1392 (EbmlId(*l2) == KaxClusterTimecode::ClassInfos.GlobalId)) {
1353 ctc.ReadData(es->I_O()); 1394 ctc.ReadData(es->I_O());
1354 mkv_d->first_tc = uint64(ctc) * mkv_d->tc_scale / 1000000; 1395 mkv_d->first_tc = uint64(ctc) * mkv_d->tc_scale / 1000000;
1355 delete l2; 1396 delete l2;
1356 } else 1397 } else
1357 mkv_d->first_tc = 0; 1398 mkv_d->first_tc = 0;
1399
1400 // Parse all cues and seek heads
1401 for (i = 0; i < (int)cues_to_parse.size(); i++)
1402 parse_cues(mkv_d, cues_to_parse[i]);
1403 for (i = 0; i < (int)seekheads_to_parse.size(); i++)
1404 parse_seekhead(mkv_d, seekheads_to_parse[i]);
1405
1358 io.setFilePointer(current_pos); 1406 io.setFilePointer(current_pos);
1359
1360 // If we have found an entry for the cues in the meta seek data but no
1361 // cues at the front of the file then read them now. This way the
1362 // timecode scale will have been initialized correctly.
1363 if (cues_pos && !mkv_d->cues_found) {
1364 current_pos = io.getFilePointer();
1365 io.setFilePointer(cues_pos);
1366 mkv_d->cues_found = parse_cues(mkv_d);
1367 if (s->eof)
1368 stream_reset(s);
1369 io.setFilePointer(current_pos);
1370 }
1371 1407
1372 } catch (exception &ex) { 1408 } catch (exception &ex) {
1373 mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] caught exception\n"); 1409 mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] caught exception\n");
1374 return 0; 1410 return 0;
1375 } 1411 }
2132 while (l1 != NULL) { 2168 while (l1 != NULL) {
2133 if (upper_lvl_el) 2169 if (upper_lvl_el)
2134 break; 2170 break;
2135 2171
2136 if (EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) { 2172 if (EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) {
2137 mkv_d->in->setFilePointer(l1->GetElementPosition()); 2173 parse_cues(mkv_d, l1->GetElementPosition());
2138 delete l1; 2174 delete l1;
2139 mkv_d->cues_found = parse_cues(mkv_d);
2140 break; 2175 break;
2141 } else { 2176 } else {
2142 if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) 2177 if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId)
2143 add_cluster_position(mkv_d, l1->GetElementPosition()); 2178 add_cluster_position(mkv_d, l1->GetElementPosition());
2144 l1->SkipData(static_cast<EbmlStream &>(*mkv_d->es), 2179 l1->SkipData(static_cast<EbmlStream &>(*mkv_d->es),
2238 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek result: target_timecode %lld, " 2273 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek result: target_timecode %lld, "
2239 "did not find an entry. Calculated target_filspos: %lld\n", 2274 "did not find an entry. Calculated target_filspos: %lld\n",
2240 target_timecode, target_filepos); 2275 target_timecode, target_filepos);
2241 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek found %p (%s).\n", 2276 mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek found %p (%s).\n",
2242 mkv_d->saved_l1, mkv_d->saved_l1 == NULL ? "null" : 2277 mkv_d->saved_l1, mkv_d->saved_l1 == NULL ? "null" :
2243 typeid(*mkv_d->saved_l1).name()); 2278 mkv_d->saved_l1->Generic().DebugName);
2244 } 2279 }
2245 2280
2246 if (mkv_d->video != NULL) 2281 if (mkv_d->video != NULL)
2247 mkv_d->v_skip_to_keyframe = true; 2282 mkv_d->v_skip_to_keyframe = true;
2248 if (rel_seek_secs > 0.0) 2283 if (rel_seek_secs > 0.0)