Mercurial > mplayer.hg
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) |