OLD | NEW |
1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved. | 1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved. |
2 // | 2 // |
3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
4 // that can be found in the LICENSE file in the root of the source | 4 // that can be found in the LICENSE file in the root of the source |
5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
8 | 8 |
9 #include "mkvparser.hpp" | 9 #include "mkvparser.hpp" |
10 #include <cassert> | 10 #include <cassert> |
11 #include <cstring> | 11 #include <cstring> |
12 #include <new> | 12 #include <new> |
13 #include <climits> | 13 #include <climits> |
14 | 14 |
15 #ifdef _MSC_VER | 15 #ifdef _MSC_VER |
16 // Disable MSVC warnings that suggest making code non-portable. | 16 // Disable MSVC warnings that suggest making code non-portable. |
17 #pragma warning(disable : 4996) | 17 #pragma warning(disable : 4996) |
18 #endif | 18 #endif |
19 | 19 |
20 mkvparser::IMkvReader::~IMkvReader() {} | 20 mkvparser::IMkvReader::~IMkvReader() {} |
21 | 21 |
22 void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision) { | 22 void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision) { |
23 major = 1; | 23 major = 1; |
24 minor = 0; | 24 minor = 0; |
25 build = 0; | 25 build = 0; |
26 revision = 28; | 26 revision = 30; |
27 } | 27 } |
28 | 28 |
29 long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) { | 29 long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) { |
30 assert(pReader); | 30 assert(pReader); |
31 assert(pos >= 0); | 31 assert(pos >= 0); |
32 | 32 |
33 int status; | 33 int status; |
34 | 34 |
35 //#ifdef _DEBUG | 35 //#ifdef _DEBUG |
36 // long long total, available; | 36 // long long total, available; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 unsigned char m = 0x80; | 123 unsigned char m = 0x80; |
124 | 124 |
125 while (!(b & m)) { | 125 while (!(b & m)) { |
126 m >>= 1; | 126 m >>= 1; |
127 ++len; | 127 ++len; |
128 } | 128 } |
129 | 129 |
130 return 0; // success | 130 return 0; // success |
131 } | 131 } |
132 | 132 |
| 133 // TODO(vigneshv): This function assumes that unsigned values never have their |
| 134 // high bit set. |
133 long long mkvparser::UnserializeUInt(IMkvReader* pReader, long long pos, | 135 long long mkvparser::UnserializeUInt(IMkvReader* pReader, long long pos, |
134 long long size) { | 136 long long size) { |
135 assert(pReader); | 137 assert(pReader); |
136 assert(pos >= 0); | 138 assert(pos >= 0); |
137 | 139 |
138 if ((size <= 0) || (size > 8)) | 140 if ((size <= 0) || (size > 8)) |
139 return E_FILE_FORMAT_INVALID; | 141 return E_FILE_FORMAT_INVALID; |
140 | 142 |
141 long long result = 0; | 143 long long result = 0; |
142 | 144 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 | 212 |
211 dd <<= 8; | 213 dd <<= 8; |
212 } | 214 } |
213 | 215 |
214 result = d; | 216 result = d; |
215 } | 217 } |
216 | 218 |
217 return 0; | 219 return 0; |
218 } | 220 } |
219 | 221 |
220 long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos, long size, | 222 long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos, |
221 long long& result) { | 223 long long size, long long& result) { |
222 assert(pReader); | 224 assert(pReader); |
223 assert(pos >= 0); | 225 assert(pos >= 0); |
224 assert(size > 0); | 226 assert(size > 0); |
225 assert(size <= 8); | 227 assert(size <= 8); |
226 | 228 |
227 { | 229 { |
228 signed char b; | 230 signed char b; |
229 | 231 |
230 const long status = pReader->Read(pos, 1, (unsigned char*)&b); | 232 const long status = pReader->Read(pos, 1, (unsigned char*)&b); |
231 | 233 |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 // m_element_size(elem_size), | 600 // m_element_size(elem_size), |
599 m_start(start), | 601 m_start(start), |
600 m_size(size), | 602 m_size(size), |
601 m_pos(start), | 603 m_pos(start), |
602 m_pUnknownSize(0), | 604 m_pUnknownSize(0), |
603 m_pSeekHead(NULL), | 605 m_pSeekHead(NULL), |
604 m_pInfo(NULL), | 606 m_pInfo(NULL), |
605 m_pTracks(NULL), | 607 m_pTracks(NULL), |
606 m_pCues(NULL), | 608 m_pCues(NULL), |
607 m_pChapters(NULL), | 609 m_pChapters(NULL), |
| 610 m_pTags(NULL), |
608 m_clusters(NULL), | 611 m_clusters(NULL), |
609 m_clusterCount(0), | 612 m_clusterCount(0), |
610 m_clusterPreloadCount(0), | 613 m_clusterPreloadCount(0), |
611 m_clusterSize(0) {} | 614 m_clusterSize(0) {} |
612 | 615 |
613 Segment::~Segment() { | 616 Segment::~Segment() { |
614 const long count = m_clusterCount + m_clusterPreloadCount; | 617 const long count = m_clusterCount + m_clusterPreloadCount; |
615 | 618 |
616 Cluster** i = m_clusters; | 619 Cluster** i = m_clusters; |
617 Cluster** j = m_clusters + count; | 620 Cluster** j = m_clusters + count; |
618 | 621 |
619 while (i != j) { | 622 while (i != j) { |
620 Cluster* const p = *i++; | 623 Cluster* const p = *i++; |
621 assert(p); | 624 assert(p); |
622 | 625 |
623 delete p; | 626 delete p; |
624 } | 627 } |
625 | 628 |
626 delete[] m_clusters; | 629 delete[] m_clusters; |
627 | 630 |
628 delete m_pTracks; | 631 delete m_pTracks; |
629 delete m_pInfo; | 632 delete m_pInfo; |
630 delete m_pCues; | 633 delete m_pCues; |
631 delete m_pChapters; | 634 delete m_pChapters; |
| 635 delete m_pTags; |
632 delete m_pSeekHead; | 636 delete m_pSeekHead; |
633 } | 637 } |
634 | 638 |
635 long long Segment::CreateInstance(IMkvReader* pReader, long long pos, | 639 long long Segment::CreateInstance(IMkvReader* pReader, long long pos, |
636 Segment*& pSegment) { | 640 Segment*& pSegment) { |
637 assert(pReader); | 641 assert(pReader); |
638 assert(pos >= 0); | 642 assert(pos >= 0); |
639 | 643 |
640 pSegment = NULL; | 644 pSegment = NULL; |
641 | 645 |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
900 Chapters(this, pos, size, element_start, element_size); | 904 Chapters(this, pos, size, element_start, element_size); |
901 | 905 |
902 if (m_pChapters == NULL) | 906 if (m_pChapters == NULL) |
903 return -1; | 907 return -1; |
904 | 908 |
905 const long status = m_pChapters->Parse(); | 909 const long status = m_pChapters->Parse(); |
906 | 910 |
907 if (status) | 911 if (status) |
908 return status; | 912 return status; |
909 } | 913 } |
| 914 } else if (id == 0x0254C367) { // Tags ID |
| 915 if (m_pTags == NULL) { |
| 916 m_pTags = new (std::nothrow) |
| 917 Tags(this, pos, size, element_start, element_size); |
| 918 |
| 919 if (m_pTags == NULL) |
| 920 return -1; |
| 921 |
| 922 const long status = m_pTags->Parse(); |
| 923 |
| 924 if (status) |
| 925 return status; |
| 926 } |
910 } | 927 } |
911 | 928 |
912 m_pos = pos + size; // consume payload | 929 m_pos = pos + size; // consume payload |
913 } | 930 } |
914 | 931 |
915 assert((segment_stop < 0) || (m_pos <= segment_stop)); | 932 assert((segment_stop < 0) || (m_pos <= segment_stop)); |
916 | 933 |
917 if (m_pInfo == NULL) // TODO: liberalize this behavior | 934 if (m_pInfo == NULL) // TODO: liberalize this behavior |
918 return E_FILE_FORMAT_INVALID; | 935 return E_FILE_FORMAT_INVALID; |
919 | 936 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1018 | 1035 |
1019 // pos now points to start of payload | 1036 // pos now points to start of payload |
1020 | 1037 |
1021 if (size == 0) { // weird | 1038 if (size == 0) { // weird |
1022 m_pos = pos; | 1039 m_pos = pos; |
1023 continue; | 1040 continue; |
1024 } | 1041 } |
1025 | 1042 |
1026 const long long unknown_size = (1LL << (7 * len)) - 1; | 1043 const long long unknown_size = (1LL << (7 * len)) - 1; |
1027 | 1044 |
1028 #if 0 // we must handle this to support live webm | |
1029 if (size == unknown_size) | |
1030 return E_FILE_FORMAT_INVALID; //TODO: allow this | |
1031 #endif | |
1032 | |
1033 if ((segment_stop >= 0) && (size != unknown_size) && | 1045 if ((segment_stop >= 0) && (size != unknown_size) && |
1034 ((pos + size) > segment_stop)) { | 1046 ((pos + size) > segment_stop)) { |
1035 return E_FILE_FORMAT_INVALID; | 1047 return E_FILE_FORMAT_INVALID; |
1036 } | 1048 } |
1037 | 1049 |
1038 #if 0 // commented-out, to support incremental cluster parsing | |
1039 len = static_cast<long>(size); | |
1040 | |
1041 if ((pos + size) > avail) | |
1042 return E_BUFFER_NOT_FULL; | |
1043 #endif | |
1044 | |
1045 if (id == 0x0C53BB6B) { // Cues ID | 1050 if (id == 0x0C53BB6B) { // Cues ID |
1046 if (size == unknown_size) | 1051 if (size == unknown_size) |
1047 return E_FILE_FORMAT_INVALID; // TODO: liberalize | 1052 return E_FILE_FORMAT_INVALID; // TODO: liberalize |
1048 | 1053 |
1049 if (m_pCues == NULL) { | 1054 if (m_pCues == NULL) { |
1050 const long long element_size = (pos - idpos) + size; | 1055 const long long element_size = (pos - idpos) + size; |
1051 | 1056 |
1052 m_pCues = new Cues(this, pos, size, idpos, element_size); | 1057 m_pCues = new Cues(this, pos, size, idpos, element_size); |
1053 assert(m_pCues); // TODO | 1058 assert(m_pCues); // TODO |
1054 } | 1059 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1150 --m_clusterPreloadCount; | 1155 --m_clusterPreloadCount; |
1151 | 1156 |
1152 m_pos = pos; // consume payload | 1157 m_pos = pos; // consume payload |
1153 assert((segment_stop < 0) || (m_pos <= segment_stop)); | 1158 assert((segment_stop < 0) || (m_pos <= segment_stop)); |
1154 | 1159 |
1155 return 0; // success | 1160 return 0; // success |
1156 } | 1161 } |
1157 } | 1162 } |
1158 | 1163 |
1159 if (status == 0) { // no entries found | 1164 if (status == 0) { // no entries found |
1160 if (cluster_size < 0) | 1165 if (cluster_size >= 0) |
1161 return E_FILE_FORMAT_INVALID; // TODO: handle this | 1166 pos += cluster_size; |
1162 | |
1163 pos += cluster_size; | |
1164 | 1167 |
1165 if ((total >= 0) && (pos >= total)) { | 1168 if ((total >= 0) && (pos >= total)) { |
1166 m_pos = total; | 1169 m_pos = total; |
1167 return 1; // no more clusters | 1170 return 1; // no more clusters |
1168 } | 1171 } |
1169 | 1172 |
1170 if ((segment_stop >= 0) && (pos >= segment_stop)) { | 1173 if ((segment_stop >= 0) && (pos >= segment_stop)) { |
1171 m_pos = segment_stop; | 1174 m_pos = segment_stop; |
1172 return 1; // no more clusters | 1175 return 1; // no more clusters |
1173 } | 1176 } |
(...skipping 20 matching lines...) Expand all Loading... |
1194 assert((segment_stop < 0) || (m_pos <= segment_stop)); | 1197 assert((segment_stop < 0) || (m_pos <= segment_stop)); |
1195 | 1198 |
1196 return 0; | 1199 return 0; |
1197 } | 1200 } |
1198 | 1201 |
1199 m_pUnknownSize = pCluster; | 1202 m_pUnknownSize = pCluster; |
1200 m_pos = -pos; | 1203 m_pos = -pos; |
1201 | 1204 |
1202 return 0; // partial success, since we have a new cluster | 1205 return 0; // partial success, since we have a new cluster |
1203 | 1206 |
1204 // status == 0 means "no block entries found" | 1207 // status == 0 means "no block entries found" |
1205 | 1208 // pos designates start of payload |
1206 // pos designates start of payload | 1209 // m_pos has NOT been adjusted yet (in case we need to come back here) |
1207 // m_pos has NOT been adjusted yet (in case we need to come back here) | |
1208 | |
1209 #if 0 | |
1210 | |
1211 if (cluster_size < 0) { //unknown size | |
1212 const long long payload_pos = pos; //absolute pos of cluster payload | |
1213 | |
1214 for (;;) { //determine cluster size | |
1215 if ((total >= 0) && (pos >= total)) | |
1216 break; | |
1217 | |
1218 if ((segment_stop >= 0) && (pos >= segment_stop)) | |
1219 break; //no more clusters | |
1220 | |
1221 //Read ID | |
1222 | |
1223 if ((pos + 1) > avail) | |
1224 { | |
1225 len = 1; | |
1226 return E_BUFFER_NOT_FULL; | |
1227 } | |
1228 | |
1229 long long result = GetUIntLength(m_pReader, pos, len); | |
1230 | |
1231 if (result < 0) //error | |
1232 return static_cast<long>(result); | |
1233 | |
1234 if (result > 0) //weird | |
1235 return E_BUFFER_NOT_FULL; | |
1236 | |
1237 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | |
1238 return E_FILE_FORMAT_INVALID; | |
1239 | |
1240 if ((pos + len) > avail) | |
1241 return E_BUFFER_NOT_FULL; | |
1242 | |
1243 const long long idpos = pos; | |
1244 const long long id = ReadUInt(m_pReader, idpos, len); | |
1245 | |
1246 if (id < 0) //error (or underflow) | |
1247 return static_cast<long>(id); | |
1248 | |
1249 //This is the distinguished set of ID's we use to determine | |
1250 //that we have exhausted the sub-element's inside the cluster | |
1251 //whose ID we parsed earlier. | |
1252 | |
1253 if (id == 0x0F43B675) //Cluster ID | |
1254 break; | |
1255 | |
1256 if (id == 0x0C53BB6B) //Cues ID | |
1257 break; | |
1258 | |
1259 switch (id) | |
1260 { | |
1261 case 0x20: //BlockGroup | |
1262 case 0x23: //Simple Block | |
1263 case 0x67: //TimeCode | |
1264 case 0x2B: //PrevSize | |
1265 break; | |
1266 | |
1267 default: | |
1268 assert(false); | |
1269 break; | |
1270 } | |
1271 | |
1272 pos += len; //consume ID (of sub-element) | |
1273 | |
1274 //Read Size | |
1275 | |
1276 if ((pos + 1) > avail) | |
1277 { | |
1278 len = 1; | |
1279 return E_BUFFER_NOT_FULL; | |
1280 } | |
1281 | |
1282 result = GetUIntLength(m_pReader, pos, len); | |
1283 | |
1284 if (result < 0) //error | |
1285 return static_cast<long>(result); | |
1286 | |
1287 if (result > 0) //weird | |
1288 return E_BUFFER_NOT_FULL; | |
1289 | |
1290 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | |
1291 return E_FILE_FORMAT_INVALID; | |
1292 | |
1293 if ((pos + len) > avail) | |
1294 return E_BUFFER_NOT_FULL; | |
1295 | |
1296 const long long size = ReadUInt(m_pReader, pos, len); | |
1297 | |
1298 if (size < 0) //error | |
1299 return static_cast<long>(size); | |
1300 | |
1301 pos += len; //consume size field of element | |
1302 | |
1303 //pos now points to start of sub-element's payload | |
1304 | |
1305 if (size == 0) //weird | |
1306 continue; | |
1307 | |
1308 const long long unknown_size = (1LL << (7 * len)) - 1; | |
1309 | |
1310 if (size == unknown_size) | |
1311 return E_FILE_FORMAT_INVALID; //not allowed for sub-elements | |
1312 | |
1313 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) //weird | |
1314 return E_FILE_FORMAT_INVALID; | |
1315 | |
1316 pos += size; //consume payload of sub-element | |
1317 assert((segment_stop < 0) || (pos <= segment_stop)); | |
1318 } //determine cluster size | |
1319 | |
1320 cluster_size = pos - payload_pos; | |
1321 assert(cluster_size >= 0); | |
1322 | |
1323 pos = payload_pos; //reset and re-parse original cluster | |
1324 } | |
1325 | |
1326 if (m_clusterPreloadCount > 0) | |
1327 { | |
1328 assert(idx < m_clusterSize); | |
1329 | |
1330 Cluster* const pCluster = m_clusters[idx]; | |
1331 assert(pCluster); | |
1332 assert(pCluster->m_index < 0); | |
1333 | |
1334 const long long off = pCluster->GetPosition(); | |
1335 assert(off >= 0); | |
1336 | |
1337 if (off == cluster_off) //preloaded already | |
1338 return E_FILE_FORMAT_INVALID; //subtle | |
1339 } | |
1340 | |
1341 m_pos = pos + cluster_size; //consume payload | |
1342 assert((segment_stop < 0) || (m_pos <= segment_stop)); | |
1343 | |
1344 return 2; //try to find another cluster | |
1345 | |
1346 #endif | |
1347 } | 1210 } |
1348 | 1211 |
1349 long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) { | 1212 long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) { |
1350 assert(m_pos < 0); | 1213 assert(m_pos < 0); |
1351 assert(m_pUnknownSize); | 1214 assert(m_pUnknownSize); |
1352 | 1215 |
1353 #if 0 | |
1354 assert(m_pUnknownSize->GetElementSize() < 0); //TODO: verify this | |
1355 | |
1356 const long long element_start = m_pUnknownSize->m_element_start; | |
1357 | |
1358 pos = -m_pos; | |
1359 assert(pos > element_start); | |
1360 | |
1361 //We have already consumed the (cluster) ID and size fields. | |
1362 //We just need to consume the blocks and other sub-elements | |
1363 //of this cluster, until we discover the boundary. | |
1364 | |
1365 long long total, avail; | |
1366 | |
1367 long status = m_pReader->Length(&total, &avail); | |
1368 | |
1369 if (status < 0) //error | |
1370 return status; | |
1371 | |
1372 assert((total < 0) || (avail <= total)); | |
1373 | |
1374 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; | |
1375 | |
1376 long long element_size = -1; | |
1377 | |
1378 for (;;) { //determine cluster size | |
1379 if ((total >= 0) && (pos >= total)) | |
1380 { | |
1381 element_size = total - element_start; | |
1382 assert(element_size > 0); | |
1383 | |
1384 break; | |
1385 } | |
1386 | |
1387 if ((segment_stop >= 0) && (pos >= segment_stop)) | |
1388 { | |
1389 element_size = segment_stop - element_start; | |
1390 assert(element_size > 0); | |
1391 | |
1392 break; | |
1393 } | |
1394 | |
1395 //Read ID | |
1396 | |
1397 if ((pos + 1) > avail) | |
1398 { | |
1399 len = 1; | |
1400 return E_BUFFER_NOT_FULL; | |
1401 } | |
1402 | |
1403 long long result = GetUIntLength(m_pReader, pos, len); | |
1404 | |
1405 if (result < 0) //error | |
1406 return static_cast<long>(result); | |
1407 | |
1408 if (result > 0) //weird | |
1409 return E_BUFFER_NOT_FULL; | |
1410 | |
1411 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | |
1412 return E_FILE_FORMAT_INVALID; | |
1413 | |
1414 if ((pos + len) > avail) | |
1415 return E_BUFFER_NOT_FULL; | |
1416 | |
1417 const long long idpos = pos; | |
1418 const long long id = ReadUInt(m_pReader, idpos, len); | |
1419 | |
1420 if (id < 0) //error (or underflow) | |
1421 return static_cast<long>(id); | |
1422 | |
1423 //This is the distinguished set of ID's we use to determine | |
1424 //that we have exhausted the sub-element's inside the cluster | |
1425 //whose ID we parsed earlier. | |
1426 | |
1427 if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { //Cluster ID or Cues ID | |
1428 element_size = pos - element_start; | |
1429 assert(element_size > 0); | |
1430 | |
1431 break; | |
1432 } | |
1433 | |
1434 #ifdef _DEBUG | |
1435 switch (id) | |
1436 { | |
1437 case 0x20: //BlockGroup | |
1438 case 0x23: //Simple Block | |
1439 case 0x67: //TimeCode | |
1440 case 0x2B: //PrevSize | |
1441 break; | |
1442 | |
1443 default: | |
1444 assert(false); | |
1445 break; | |
1446 } | |
1447 #endif | |
1448 | |
1449 pos += len; //consume ID (of sub-element) | |
1450 | |
1451 //Read Size | |
1452 | |
1453 if ((pos + 1) > avail) | |
1454 { | |
1455 len = 1; | |
1456 return E_BUFFER_NOT_FULL; | |
1457 } | |
1458 | |
1459 result = GetUIntLength(m_pReader, pos, len); | |
1460 | |
1461 if (result < 0) //error | |
1462 return static_cast<long>(result); | |
1463 | |
1464 if (result > 0) //weird | |
1465 return E_BUFFER_NOT_FULL; | |
1466 | |
1467 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | |
1468 return E_FILE_FORMAT_INVALID; | |
1469 | |
1470 if ((pos + len) > avail) | |
1471 return E_BUFFER_NOT_FULL; | |
1472 | |
1473 const long long size = ReadUInt(m_pReader, pos, len); | |
1474 | |
1475 if (size < 0) //error | |
1476 return static_cast<long>(size); | |
1477 | |
1478 pos += len; //consume size field of element | |
1479 | |
1480 //pos now points to start of sub-element's payload | |
1481 | |
1482 if (size == 0) //weird | |
1483 continue; | |
1484 | |
1485 const long long unknown_size = (1LL << (7 * len)) - 1; | |
1486 | |
1487 if (size == unknown_size) | |
1488 return E_FILE_FORMAT_INVALID; //not allowed for sub-elements | |
1489 | |
1490 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) //weird | |
1491 return E_FILE_FORMAT_INVALID; | |
1492 | |
1493 pos += size; //consume payload of sub-element | |
1494 assert((segment_stop < 0) || (pos <= segment_stop)); | |
1495 } //determine cluster size | |
1496 | |
1497 assert(element_size >= 0); | |
1498 | |
1499 m_pos = element_start + element_size; | |
1500 m_pUnknownSize = 0; | |
1501 | |
1502 return 2; //continue parsing | |
1503 #else | |
1504 const long status = m_pUnknownSize->Parse(pos, len); | 1216 const long status = m_pUnknownSize->Parse(pos, len); |
1505 | 1217 |
1506 if (status < 0) // error or underflow | 1218 if (status < 0) // error or underflow |
1507 return status; | 1219 return status; |
1508 | 1220 |
1509 if (status == 0) // parsed a block | 1221 if (status == 0) // parsed a block |
1510 return 2; // continue parsing | 1222 return 2; // continue parsing |
1511 | 1223 |
1512 assert(status > 0); // nothing left to parse of this cluster | 1224 assert(status > 0); // nothing left to parse of this cluster |
1513 | 1225 |
1514 const long long start = m_pUnknownSize->m_element_start; | 1226 const long long start = m_pUnknownSize->m_element_start; |
1515 | 1227 |
1516 const long long size = m_pUnknownSize->GetElementSize(); | 1228 const long long size = m_pUnknownSize->GetElementSize(); |
1517 assert(size >= 0); | 1229 assert(size >= 0); |
1518 | 1230 |
1519 pos = start + size; | 1231 pos = start + size; |
1520 m_pos = pos; | 1232 m_pos = pos; |
1521 | 1233 |
1522 m_pUnknownSize = 0; | 1234 m_pUnknownSize = 0; |
1523 | 1235 |
1524 return 2; // continue parsing | 1236 return 2; // continue parsing |
1525 #endif | |
1526 } | 1237 } |
1527 | 1238 |
1528 void Segment::AppendCluster(Cluster* pCluster) { | 1239 void Segment::AppendCluster(Cluster* pCluster) { |
1529 assert(pCluster); | 1240 assert(pCluster); |
1530 assert(pCluster->m_index >= 0); | 1241 assert(pCluster->m_index >= 0); |
1531 | 1242 |
1532 const long count = m_clusterCount + m_clusterPreloadCount; | 1243 const long count = m_clusterCount + m_clusterPreloadCount; |
1533 | 1244 |
1534 long& size = m_clusterSize; | 1245 long& size = m_clusterSize; |
1535 assert(size >= count); | 1246 assert(size >= count); |
1536 | 1247 |
1537 const long idx = pCluster->m_index; | 1248 const long idx = pCluster->m_index; |
1538 assert(idx == m_clusterCount); | 1249 assert(idx == m_clusterCount); |
1539 | 1250 |
1540 if (count >= size) { | 1251 if (count >= size) { |
1541 const long n = (size <= 0) ? 2048 : 2 * size; | 1252 const long n = (size <= 0) ? 2048 : 2 * size; |
1542 | 1253 |
1543 Cluster** const qq = new Cluster* [n]; | 1254 Cluster** const qq = new Cluster*[n]; |
1544 Cluster** q = qq; | 1255 Cluster** q = qq; |
1545 | 1256 |
1546 Cluster** p = m_clusters; | 1257 Cluster** p = m_clusters; |
1547 Cluster** const pp = p + count; | 1258 Cluster** const pp = p + count; |
1548 | 1259 |
1549 while (p != pp) | 1260 while (p != pp) |
1550 *q++ = *p++; | 1261 *q++ = *p++; |
1551 | 1262 |
1552 delete[] m_clusters; | 1263 delete[] m_clusters; |
1553 | 1264 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1587 assert(idx >= m_clusterCount); | 1298 assert(idx >= m_clusterCount); |
1588 | 1299 |
1589 const long count = m_clusterCount + m_clusterPreloadCount; | 1300 const long count = m_clusterCount + m_clusterPreloadCount; |
1590 | 1301 |
1591 long& size = m_clusterSize; | 1302 long& size = m_clusterSize; |
1592 assert(size >= count); | 1303 assert(size >= count); |
1593 | 1304 |
1594 if (count >= size) { | 1305 if (count >= size) { |
1595 const long n = (size <= 0) ? 2048 : 2 * size; | 1306 const long n = (size <= 0) ? 2048 : 2 * size; |
1596 | 1307 |
1597 Cluster** const qq = new Cluster* [n]; | 1308 Cluster** const qq = new Cluster*[n]; |
1598 Cluster** q = qq; | 1309 Cluster** q = qq; |
1599 | 1310 |
1600 Cluster** p = m_clusters; | 1311 Cluster** p = m_clusters; |
1601 Cluster** const pp = p + count; | 1312 Cluster** const pp = p + count; |
1602 | 1313 |
1603 while (p != pp) | 1314 while (p != pp) |
1604 *q++ = *p++; | 1315 *q++ = *p++; |
1605 | 1316 |
1606 delete[] m_clusters; | 1317 delete[] m_clusters; |
1607 | 1318 |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1787 const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const { | 1498 const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const { |
1788 if (idx < 0) | 1499 if (idx < 0) |
1789 return 0; | 1500 return 0; |
1790 | 1501 |
1791 if (idx >= m_void_element_count) | 1502 if (idx >= m_void_element_count) |
1792 return 0; | 1503 return 0; |
1793 | 1504 |
1794 return m_void_elements + idx; | 1505 return m_void_elements + idx; |
1795 } | 1506 } |
1796 | 1507 |
1797 #if 0 | |
1798 void Segment::ParseCues(long long off) | |
1799 { | |
1800 if (m_pCues) | |
1801 return; | |
1802 | |
1803 //odbgstream os; | |
1804 //os << "Segment::ParseCues (begin)" << endl; | |
1805 | |
1806 long long pos = m_start + off; | |
1807 const long long element_start = pos; | |
1808 const long long stop = m_start + m_size; | |
1809 | |
1810 long len; | |
1811 | |
1812 long long result = GetUIntLength(m_pReader, pos, len); | |
1813 assert(result == 0); | |
1814 assert((pos + len) <= stop); | |
1815 | |
1816 const long long idpos = pos; | |
1817 | |
1818 const long long id = ReadUInt(m_pReader, idpos, len); | |
1819 assert(id == 0x0C53BB6B); //Cues ID | |
1820 | |
1821 pos += len; //consume ID | |
1822 assert(pos < stop); | |
1823 | |
1824 //Read Size | |
1825 | |
1826 result = GetUIntLength(m_pReader, pos, len); | |
1827 assert(result == 0); | |
1828 assert((pos + len) <= stop); | |
1829 | |
1830 const long long size = ReadUInt(m_pReader, pos, len); | |
1831 assert(size >= 0); | |
1832 | |
1833 pos += len; //consume length of size of element | |
1834 assert((pos + size) <= stop); | |
1835 | |
1836 const long long element_size = size + pos - element_start; | |
1837 | |
1838 //Pos now points to start of payload | |
1839 | |
1840 m_pCues = new Cues(this, pos, size, element_start, element_size); | |
1841 assert(m_pCues); //TODO | |
1842 | |
1843 //os << "Segment::ParseCues (end)" << endl; | |
1844 } | |
1845 #else | |
1846 long Segment::ParseCues(long long off, long long& pos, long& len) { | 1508 long Segment::ParseCues(long long off, long long& pos, long& len) { |
1847 if (m_pCues) | 1509 if (m_pCues) |
1848 return 0; // success | 1510 return 0; // success |
1849 | 1511 |
1850 if (off < 0) | 1512 if (off < 0) |
1851 return -1; | 1513 return -1; |
1852 | 1514 |
1853 long long total, avail; | 1515 long long total, avail; |
1854 | 1516 |
1855 const int status = m_pReader->Length(&total, &avail); | 1517 const int status = m_pReader->Length(&total, &avail); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1950 return E_BUFFER_NOT_FULL; | 1612 return E_BUFFER_NOT_FULL; |
1951 | 1613 |
1952 const long long element_size = element_stop - element_start; | 1614 const long long element_size = element_stop - element_start; |
1953 | 1615 |
1954 m_pCues = | 1616 m_pCues = |
1955 new (std::nothrow) Cues(this, pos, size, element_start, element_size); | 1617 new (std::nothrow) Cues(this, pos, size, element_start, element_size); |
1956 assert(m_pCues); // TODO | 1618 assert(m_pCues); // TODO |
1957 | 1619 |
1958 return 0; // success | 1620 return 0; // success |
1959 } | 1621 } |
1960 #endif | |
1961 | 1622 |
1962 #if 0 | |
1963 void Segment::ParseSeekEntry( | |
1964 long long start, | |
1965 long long size_) | |
1966 { | |
1967 long long pos = start; | |
1968 | |
1969 const long long stop = start + size_; | |
1970 | |
1971 long len; | |
1972 | |
1973 const long long seekIdId = ReadUInt(m_pReader, pos, len); | |
1974 //seekIdId; | |
1975 assert(seekIdId == 0x13AB); //SeekID ID | |
1976 assert((pos + len) <= stop); | |
1977 | |
1978 pos += len; //consume id | |
1979 | |
1980 const long long seekIdSize = ReadUInt(m_pReader, pos, len); | |
1981 assert(seekIdSize >= 0); | |
1982 assert((pos + len) <= stop); | |
1983 | |
1984 pos += len; //consume size | |
1985 | |
1986 const long long seekId = ReadUInt(m_pReader, pos, len); //payload | |
1987 assert(seekId >= 0); | |
1988 assert(len == seekIdSize); | |
1989 assert((pos + len) <= stop); | |
1990 | |
1991 pos += seekIdSize; //consume payload | |
1992 | |
1993 const long long seekPosId = ReadUInt(m_pReader, pos, len); | |
1994 //seekPosId; | |
1995 assert(seekPosId == 0x13AC); //SeekPos ID | |
1996 assert((pos + len) <= stop); | |
1997 | |
1998 pos += len; //consume id | |
1999 | |
2000 const long long seekPosSize = ReadUInt(m_pReader, pos, len); | |
2001 assert(seekPosSize >= 0); | |
2002 assert((pos + len) <= stop); | |
2003 | |
2004 pos += len; //consume size | |
2005 assert((pos + seekPosSize) <= stop); | |
2006 | |
2007 const long long seekOff = UnserializeUInt(m_pReader, pos, seekPosSize); | |
2008 assert(seekOff >= 0); | |
2009 assert(seekOff < m_size); | |
2010 | |
2011 pos += seekPosSize; //consume payload | |
2012 assert(pos == stop); | |
2013 | |
2014 const long long seekPos = m_start + seekOff; | |
2015 assert(seekPos < (m_start + m_size)); | |
2016 | |
2017 if (seekId == 0x0C53BB6B) //Cues ID | |
2018 ParseCues(seekOff); | |
2019 } | |
2020 #else | |
2021 bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_, | 1623 bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_, |
2022 Entry* pEntry) { | 1624 Entry* pEntry) { |
2023 if (size_ <= 0) | 1625 if (size_ <= 0) |
2024 return false; | 1626 return false; |
2025 | 1627 |
2026 long long pos = start; | 1628 long long pos = start; |
2027 const long long stop = start + size_; | 1629 const long long stop = start + size_; |
2028 | 1630 |
2029 long len; | 1631 long len; |
2030 | 1632 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2103 if (pEntry->pos < 0) | 1705 if (pEntry->pos < 0) |
2104 return false; | 1706 return false; |
2105 | 1707 |
2106 pos += seekPosSize; // consume payload | 1708 pos += seekPosSize; // consume payload |
2107 | 1709 |
2108 if (pos != stop) | 1710 if (pos != stop) |
2109 return false; | 1711 return false; |
2110 | 1712 |
2111 return true; | 1713 return true; |
2112 } | 1714 } |
2113 #endif | |
2114 | 1715 |
2115 Cues::Cues(Segment* pSegment, long long start_, long long size_, | 1716 Cues::Cues(Segment* pSegment, long long start_, long long size_, |
2116 long long element_start, long long element_size) | 1717 long long element_start, long long element_size) |
2117 : m_pSegment(pSegment), | 1718 : m_pSegment(pSegment), |
2118 m_start(start_), | 1719 m_start(start_), |
2119 m_size(size_), | 1720 m_size(size_), |
2120 m_element_start(element_start), | 1721 m_element_start(element_start), |
2121 m_element_size(element_size), | 1722 m_element_size(element_size), |
2122 m_cue_points(NULL), | 1723 m_cue_points(NULL), |
2123 m_count(0), | 1724 m_count(0), |
(...skipping 21 matching lines...) Expand all Loading... |
2145 return -1; | 1746 return -1; |
2146 | 1747 |
2147 return m_count; // TODO: really ignore preload count? | 1748 return m_count; // TODO: really ignore preload count? |
2148 } | 1749 } |
2149 | 1750 |
2150 bool Cues::DoneParsing() const { | 1751 bool Cues::DoneParsing() const { |
2151 const long long stop = m_start + m_size; | 1752 const long long stop = m_start + m_size; |
2152 return (m_pos >= stop); | 1753 return (m_pos >= stop); |
2153 } | 1754 } |
2154 | 1755 |
2155 void Cues::Init() const { | 1756 bool Cues::Init() const { |
2156 if (m_cue_points) | 1757 if (m_cue_points) |
2157 return; | 1758 return true; |
2158 | 1759 |
2159 assert(m_count == 0); | 1760 assert(m_count == 0); |
2160 assert(m_preload_count == 0); | 1761 assert(m_preload_count == 0); |
2161 | 1762 |
2162 IMkvReader* const pReader = m_pSegment->m_pReader; | 1763 IMkvReader* const pReader = m_pSegment->m_pReader; |
2163 | 1764 |
2164 const long long stop = m_start + m_size; | 1765 const long long stop = m_start + m_size; |
2165 long long pos = m_start; | 1766 long long pos = m_start; |
2166 | 1767 |
2167 long cue_points_size = 0; | 1768 long cue_points_size = 0; |
2168 | 1769 |
2169 while (pos < stop) { | 1770 while (pos < stop) { |
2170 const long long idpos = pos; | 1771 const long long idpos = pos; |
2171 | 1772 |
2172 long len; | 1773 long len; |
2173 | 1774 |
2174 const long long id = ReadUInt(pReader, pos, len); | 1775 const long long id = ReadUInt(pReader, pos, len); |
2175 assert(id >= 0); // TODO | 1776 if (id < 0 || (pos + len) > stop) { |
2176 assert((pos + len) <= stop); | 1777 return false; |
| 1778 } |
2177 | 1779 |
2178 pos += len; // consume ID | 1780 pos += len; // consume ID |
2179 | 1781 |
2180 const long long size = ReadUInt(pReader, pos, len); | 1782 const long long size = ReadUInt(pReader, pos, len); |
2181 assert(size >= 0); | 1783 if (size < 0 || (pos + len > stop)) { |
2182 assert((pos + len) <= stop); | 1784 return false; |
| 1785 } |
2183 | 1786 |
2184 pos += len; // consume Size field | 1787 pos += len; // consume Size field |
2185 assert((pos + size) <= stop); | 1788 if (pos + size > stop) { |
| 1789 return false; |
| 1790 } |
2186 | 1791 |
2187 if (id == 0x3B) // CuePoint ID | 1792 if (id == 0x3B) // CuePoint ID |
2188 PreloadCuePoint(cue_points_size, idpos); | 1793 PreloadCuePoint(cue_points_size, idpos); |
2189 | 1794 |
2190 pos += size; // consume payload | 1795 pos += size; // skip payload |
2191 assert(pos <= stop); | |
2192 } | 1796 } |
| 1797 return true; |
2193 } | 1798 } |
2194 | 1799 |
2195 void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { | 1800 void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { |
2196 assert(m_count == 0); | 1801 assert(m_count == 0); |
2197 | 1802 |
2198 if (m_preload_count >= cue_points_size) { | 1803 if (m_preload_count >= cue_points_size) { |
2199 const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size; | 1804 const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size; |
2200 | 1805 |
2201 CuePoint** const qq = new CuePoint* [n]; | 1806 CuePoint** const qq = new CuePoint*[n]; |
2202 CuePoint** q = qq; // beginning of target | 1807 CuePoint** q = qq; // beginning of target |
2203 | 1808 |
2204 CuePoint** p = m_cue_points; // beginning of source | 1809 CuePoint** p = m_cue_points; // beginning of source |
2205 CuePoint** const pp = p + m_preload_count; // end of source | 1810 CuePoint** const pp = p + m_preload_count; // end of source |
2206 | 1811 |
2207 while (p != pp) | 1812 while (p != pp) |
2208 *q++ = *p++; | 1813 *q++ = *p++; |
2209 | 1814 |
2210 delete[] m_cue_points; | 1815 delete[] m_cue_points; |
2211 | 1816 |
2212 m_cue_points = qq; | 1817 m_cue_points = qq; |
2213 cue_points_size = n; | 1818 cue_points_size = n; |
2214 } | 1819 } |
2215 | 1820 |
2216 CuePoint* const pCP = new CuePoint(m_preload_count, pos); | 1821 CuePoint* const pCP = new CuePoint(m_preload_count, pos); |
2217 m_cue_points[m_preload_count++] = pCP; | 1822 m_cue_points[m_preload_count++] = pCP; |
2218 } | 1823 } |
2219 | 1824 |
2220 bool Cues::LoadCuePoint() const { | 1825 bool Cues::LoadCuePoint() const { |
2221 // odbgstream os; | 1826 // odbgstream os; |
2222 // os << "Cues::LoadCuePoint" << endl; | 1827 // os << "Cues::LoadCuePoint" << endl; |
2223 | 1828 |
2224 const long long stop = m_start + m_size; | 1829 const long long stop = m_start + m_size; |
2225 | 1830 |
2226 if (m_pos >= stop) | 1831 if (m_pos >= stop) |
2227 return false; // nothing else to do | 1832 return false; // nothing else to do |
2228 | 1833 |
2229 Init(); | 1834 if (!Init()) { |
| 1835 m_pos = stop; |
| 1836 return false; |
| 1837 } |
2230 | 1838 |
2231 IMkvReader* const pReader = m_pSegment->m_pReader; | 1839 IMkvReader* const pReader = m_pSegment->m_pReader; |
2232 | 1840 |
2233 while (m_pos < stop) { | 1841 while (m_pos < stop) { |
2234 const long long idpos = m_pos; | 1842 const long long idpos = m_pos; |
2235 | 1843 |
2236 long len; | 1844 long len; |
2237 | 1845 |
2238 const long long id = ReadUInt(pReader, m_pos, len); | 1846 const long long id = ReadUInt(pReader, m_pos, len); |
2239 assert(id >= 0); // TODO | 1847 assert(id >= 0); // TODO |
(...skipping 16 matching lines...) Expand all Loading... |
2256 } | 1864 } |
2257 | 1865 |
2258 assert(m_preload_count > 0); | 1866 assert(m_preload_count > 0); |
2259 | 1867 |
2260 CuePoint* const pCP = m_cue_points[m_count]; | 1868 CuePoint* const pCP = m_cue_points[m_count]; |
2261 assert(pCP); | 1869 assert(pCP); |
2262 assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos)); | 1870 assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos)); |
2263 if (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)) | 1871 if (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)) |
2264 return false; | 1872 return false; |
2265 | 1873 |
2266 pCP->Load(pReader); | 1874 if (!pCP->Load(pReader)) { |
| 1875 m_pos = stop; |
| 1876 return false; |
| 1877 } |
2267 ++m_count; | 1878 ++m_count; |
2268 --m_preload_count; | 1879 --m_preload_count; |
2269 | 1880 |
2270 m_pos += size; // consume payload | 1881 m_pos += size; // consume payload |
2271 assert(m_pos <= stop); | 1882 assert(m_pos <= stop); |
2272 | 1883 |
2273 return true; // yes, we loaded a cue point | 1884 return true; // yes, we loaded a cue point |
2274 } | 1885 } |
2275 | 1886 |
2276 // return (m_pos < stop); | 1887 // return (m_pos < stop); |
2277 return false; // no, we did not load a cue point | 1888 return false; // no, we did not load a cue point |
2278 } | 1889 } |
2279 | 1890 |
2280 bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP, | 1891 bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP, |
2281 const CuePoint::TrackPosition*& pTP) const { | 1892 const CuePoint::TrackPosition*& pTP) const { |
2282 assert(time_ns >= 0); | 1893 assert(time_ns >= 0); |
2283 assert(pTrack); | 1894 assert(pTrack); |
2284 | 1895 |
2285 #if 0 | |
2286 LoadCuePoint(); //establish invariant | |
2287 | |
2288 assert(m_cue_points); | |
2289 assert(m_count > 0); | |
2290 | |
2291 CuePoint** const ii = m_cue_points; | |
2292 CuePoint** i = ii; | |
2293 | |
2294 CuePoint** const jj = ii + m_count + m_preload_count; | |
2295 CuePoint** j = jj; | |
2296 | |
2297 pCP = *i; | |
2298 assert(pCP); | |
2299 | |
2300 if (time_ns <= pCP->GetTime(m_pSegment)) | |
2301 { | |
2302 pTP = pCP->Find(pTrack); | |
2303 return (pTP != NULL); | |
2304 } | |
2305 | |
2306 IMkvReader* const pReader = m_pSegment->m_pReader; | |
2307 | |
2308 while (i < j) | |
2309 { | |
2310 //INVARIANT: | |
2311 //[ii, i) <= time_ns | |
2312 //[i, j) ? | |
2313 //[j, jj) > time_ns | |
2314 | |
2315 CuePoint** const k = i + (j - i) / 2; | |
2316 assert(k < jj); | |
2317 | |
2318 CuePoint* const pCP = *k; | |
2319 assert(pCP); | |
2320 | |
2321 pCP->Load(pReader); | |
2322 | |
2323 const long long t = pCP->GetTime(m_pSegment); | |
2324 | |
2325 if (t <= time_ns) | |
2326 i = k + 1; | |
2327 else | |
2328 j = k; | |
2329 | |
2330 assert(i <= j); | |
2331 } | |
2332 | |
2333 assert(i == j); | |
2334 assert(i <= jj); | |
2335 assert(i > ii); | |
2336 | |
2337 pCP = *--i; | |
2338 assert(pCP); | |
2339 assert(pCP->GetTime(m_pSegment) <= time_ns); | |
2340 #else | |
2341 if (m_cue_points == NULL) | 1896 if (m_cue_points == NULL) |
2342 return false; | 1897 return false; |
2343 | 1898 |
2344 if (m_count == 0) | 1899 if (m_count == 0) |
2345 return false; | 1900 return false; |
2346 | 1901 |
2347 CuePoint** const ii = m_cue_points; | 1902 CuePoint** const ii = m_cue_points; |
2348 CuePoint** i = ii; | 1903 CuePoint** i = ii; |
2349 | 1904 |
2350 CuePoint** const jj = ii + m_count; | 1905 CuePoint** const jj = ii + m_count; |
(...skipping 29 matching lines...) Expand all Loading... |
2380 assert(i <= j); | 1935 assert(i <= j); |
2381 } | 1936 } |
2382 | 1937 |
2383 assert(i == j); | 1938 assert(i == j); |
2384 assert(i <= jj); | 1939 assert(i <= jj); |
2385 assert(i > ii); | 1940 assert(i > ii); |
2386 | 1941 |
2387 pCP = *--i; | 1942 pCP = *--i; |
2388 assert(pCP); | 1943 assert(pCP); |
2389 assert(pCP->GetTime(m_pSegment) <= time_ns); | 1944 assert(pCP->GetTime(m_pSegment) <= time_ns); |
2390 #endif | |
2391 | 1945 |
2392 // TODO: here and elsewhere, it's probably not correct to search | 1946 // TODO: here and elsewhere, it's probably not correct to search |
2393 // for the cue point with this time, and then search for a matching | 1947 // for the cue point with this time, and then search for a matching |
2394 // track. In principle, the matching track could be on some earlier | 1948 // track. In principle, the matching track could be on some earlier |
2395 // cue point, and with our current algorithm, we'd miss it. To make | 1949 // cue point, and with our current algorithm, we'd miss it. To make |
2396 // this bullet-proof, we'd need to create a secondary structure, | 1950 // this bullet-proof, we'd need to create a secondary structure, |
2397 // with a list of cue points that apply to a track, and then search | 1951 // with a list of cue points that apply to a track, and then search |
2398 // that track-based structure for a matching cue point. | 1952 // that track-based structure for a matching cue point. |
2399 | 1953 |
2400 pTP = pCP->Find(pTrack); | 1954 pTP = pCP->Find(pTrack); |
2401 return (pTP != NULL); | 1955 return (pTP != NULL); |
2402 } | 1956 } |
2403 | 1957 |
2404 #if 0 | |
2405 bool Cues::FindNext( | |
2406 long long time_ns, | |
2407 const Track* pTrack, | |
2408 const CuePoint*& pCP, | |
2409 const CuePoint::TrackPosition*& pTP) const | |
2410 { | |
2411 pCP = 0; | |
2412 pTP = 0; | |
2413 | |
2414 if (m_count == 0) | |
2415 return false; | |
2416 | |
2417 assert(m_cue_points); | |
2418 | |
2419 const CuePoint* const* const ii = m_cue_points; | |
2420 const CuePoint* const* i = ii; | |
2421 | |
2422 const CuePoint* const* const jj = ii + m_count; | |
2423 const CuePoint* const* j = jj; | |
2424 | |
2425 while (i < j) | |
2426 { | |
2427 //INVARIANT: | |
2428 //[ii, i) <= time_ns | |
2429 //[i, j) ? | |
2430 //[j, jj) > time_ns | |
2431 | |
2432 const CuePoint* const* const k = i + (j - i) / 2; | |
2433 assert(k < jj); | |
2434 | |
2435 pCP = *k; | |
2436 assert(pCP); | |
2437 | |
2438 const long long t = pCP->GetTime(m_pSegment); | |
2439 | |
2440 if (t <= time_ns) | |
2441 i = k + 1; | |
2442 else | |
2443 j = k; | |
2444 | |
2445 assert(i <= j); | |
2446 } | |
2447 | |
2448 assert(i == j); | |
2449 assert(i <= jj); | |
2450 | |
2451 if (i >= jj) //time_ns is greater than max cue point | |
2452 return false; | |
2453 | |
2454 pCP = *i; | |
2455 assert(pCP); | |
2456 assert(pCP->GetTime(m_pSegment) > time_ns); | |
2457 | |
2458 pTP = pCP->Find(pTrack); | |
2459 return (pTP != NULL); | |
2460 } | |
2461 #endif | |
2462 | |
2463 const CuePoint* Cues::GetFirst() const { | 1958 const CuePoint* Cues::GetFirst() const { |
2464 if (m_cue_points == NULL) | 1959 if (m_cue_points == NULL) |
2465 return NULL; | 1960 return NULL; |
2466 | 1961 |
2467 if (m_count == 0) | 1962 if (m_count == 0) |
2468 return NULL; | 1963 return NULL; |
2469 | 1964 |
2470 #if 0 | |
2471 LoadCuePoint(); //init cues | |
2472 | |
2473 const size_t count = m_count + m_preload_count; | |
2474 | |
2475 if (count == 0) //weird | |
2476 return NULL; | |
2477 #endif | |
2478 | |
2479 CuePoint* const* const pp = m_cue_points; | 1965 CuePoint* const* const pp = m_cue_points; |
2480 assert(pp); | 1966 assert(pp); |
2481 | 1967 |
2482 CuePoint* const pCP = pp[0]; | 1968 CuePoint* const pCP = pp[0]; |
2483 assert(pCP); | 1969 assert(pCP); |
2484 assert(pCP->GetTimeCode() >= 0); | 1970 assert(pCP->GetTimeCode() >= 0); |
2485 | 1971 |
2486 return pCP; | 1972 return pCP; |
2487 } | 1973 } |
2488 | 1974 |
2489 const CuePoint* Cues::GetLast() const { | 1975 const CuePoint* Cues::GetLast() const { |
2490 if (m_cue_points == NULL) | 1976 if (m_cue_points == NULL) |
2491 return NULL; | 1977 return NULL; |
2492 | 1978 |
2493 if (m_count <= 0) | 1979 if (m_count <= 0) |
2494 return NULL; | 1980 return NULL; |
2495 | 1981 |
2496 #if 0 | |
2497 LoadCuePoint(); //init cues | |
2498 | |
2499 const size_t count = m_count + m_preload_count; | |
2500 | |
2501 if (count == 0) //weird | |
2502 return NULL; | |
2503 | |
2504 const size_t index = count - 1; | |
2505 | |
2506 CuePoint* const* const pp = m_cue_points; | |
2507 assert(pp); | |
2508 | |
2509 CuePoint* const pCP = pp[index]; | |
2510 assert(pCP); | |
2511 | |
2512 pCP->Load(m_pSegment->m_pReader); | |
2513 assert(pCP->GetTimeCode() >= 0); | |
2514 #else | |
2515 const long index = m_count - 1; | 1982 const long index = m_count - 1; |
2516 | 1983 |
2517 CuePoint* const* const pp = m_cue_points; | 1984 CuePoint* const* const pp = m_cue_points; |
2518 assert(pp); | 1985 assert(pp); |
2519 | 1986 |
2520 CuePoint* const pCP = pp[index]; | 1987 CuePoint* const pCP = pp[index]; |
2521 assert(pCP); | 1988 assert(pCP); |
2522 assert(pCP->GetTimeCode() >= 0); | 1989 assert(pCP->GetTimeCode() >= 0); |
2523 #endif | |
2524 | 1990 |
2525 return pCP; | 1991 return pCP; |
2526 } | 1992 } |
2527 | 1993 |
2528 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const { | 1994 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const { |
2529 if (pCurr == NULL) | 1995 if (pCurr == NULL) |
2530 return NULL; | 1996 return NULL; |
2531 | 1997 |
2532 assert(pCurr->GetTimeCode() >= 0); | 1998 assert(pCurr->GetTimeCode() >= 0); |
2533 assert(m_cue_points); | 1999 assert(m_cue_points); |
2534 assert(m_count >= 1); | 2000 assert(m_count >= 1); |
2535 | 2001 |
2536 #if 0 | |
2537 const size_t count = m_count + m_preload_count; | |
2538 | |
2539 size_t index = pCurr->m_index; | |
2540 assert(index < count); | |
2541 | |
2542 CuePoint* const* const pp = m_cue_points; | |
2543 assert(pp); | |
2544 assert(pp[index] == pCurr); | |
2545 | |
2546 ++index; | |
2547 | |
2548 if (index >= count) | |
2549 return NULL; | |
2550 | |
2551 CuePoint* const pNext = pp[index]; | |
2552 assert(pNext); | |
2553 | |
2554 pNext->Load(m_pSegment->m_pReader); | |
2555 #else | |
2556 long index = pCurr->m_index; | 2002 long index = pCurr->m_index; |
2557 assert(index < m_count); | 2003 assert(index < m_count); |
2558 | 2004 |
2559 CuePoint* const* const pp = m_cue_points; | 2005 CuePoint* const* const pp = m_cue_points; |
2560 assert(pp); | 2006 assert(pp); |
2561 assert(pp[index] == pCurr); | 2007 assert(pp[index] == pCurr); |
2562 | 2008 |
2563 ++index; | 2009 ++index; |
2564 | 2010 |
2565 if (index >= m_count) | 2011 if (index >= m_count) |
2566 return NULL; | 2012 return NULL; |
2567 | 2013 |
2568 CuePoint* const pNext = pp[index]; | 2014 CuePoint* const pNext = pp[index]; |
2569 assert(pNext); | 2015 assert(pNext); |
2570 assert(pNext->GetTimeCode() >= 0); | 2016 assert(pNext->GetTimeCode() >= 0); |
2571 #endif | |
2572 | 2017 |
2573 return pNext; | 2018 return pNext; |
2574 } | 2019 } |
2575 | 2020 |
2576 const BlockEntry* Cues::GetBlock(const CuePoint* pCP, | 2021 const BlockEntry* Cues::GetBlock(const CuePoint* pCP, |
2577 const CuePoint::TrackPosition* pTP) const { | 2022 const CuePoint::TrackPosition* pTP) const { |
2578 if (pCP == NULL) | 2023 if (pCP == NULL) |
2579 return NULL; | 2024 return NULL; |
2580 | 2025 |
2581 if (pTP == NULL) | 2026 if (pTP == NULL) |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2698 m_element_size(0), | 2143 m_element_size(0), |
2699 m_index(idx), | 2144 m_index(idx), |
2700 m_timecode(-1 * pos), | 2145 m_timecode(-1 * pos), |
2701 m_track_positions(NULL), | 2146 m_track_positions(NULL), |
2702 m_track_positions_count(0) { | 2147 m_track_positions_count(0) { |
2703 assert(pos > 0); | 2148 assert(pos > 0); |
2704 } | 2149 } |
2705 | 2150 |
2706 CuePoint::~CuePoint() { delete[] m_track_positions; } | 2151 CuePoint::~CuePoint() { delete[] m_track_positions; } |
2707 | 2152 |
2708 void CuePoint::Load(IMkvReader* pReader) { | 2153 bool CuePoint::Load(IMkvReader* pReader) { |
2709 // odbgstream os; | 2154 // odbgstream os; |
2710 // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl; | 2155 // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl; |
2711 | 2156 |
2712 if (m_timecode >= 0) // already loaded | 2157 if (m_timecode >= 0) // already loaded |
2713 return; | 2158 return true; |
2714 | 2159 |
2715 assert(m_track_positions == NULL); | 2160 assert(m_track_positions == NULL); |
2716 assert(m_track_positions_count == 0); | 2161 assert(m_track_positions_count == 0); |
2717 | 2162 |
2718 long long pos_ = -m_timecode; | 2163 long long pos_ = -m_timecode; |
2719 const long long element_start = pos_; | 2164 const long long element_start = pos_; |
2720 | 2165 |
2721 long long stop; | 2166 long long stop; |
2722 | 2167 |
2723 { | 2168 { |
2724 long len; | 2169 long len; |
2725 | 2170 |
2726 const long long id = ReadUInt(pReader, pos_, len); | 2171 const long long id = ReadUInt(pReader, pos_, len); |
2727 assert(id == 0x3B); // CuePoint ID | 2172 assert(id == 0x3B); // CuePoint ID |
2728 if (id != 0x3B) | 2173 if (id != 0x3B) |
2729 return; | 2174 return false; |
2730 | 2175 |
2731 pos_ += len; // consume ID | 2176 pos_ += len; // consume ID |
2732 | 2177 |
2733 const long long size = ReadUInt(pReader, pos_, len); | 2178 const long long size = ReadUInt(pReader, pos_, len); |
2734 assert(size >= 0); | 2179 assert(size >= 0); |
2735 | 2180 |
2736 pos_ += len; // consume Size field | 2181 pos_ += len; // consume Size field |
2737 // pos_ now points to start of payload | 2182 // pos_ now points to start of payload |
2738 | 2183 |
2739 stop = pos_ + size; | 2184 stop = pos_ + size; |
2740 } | 2185 } |
2741 | 2186 |
2742 const long long element_size = stop - element_start; | 2187 const long long element_size = stop - element_start; |
2743 | 2188 |
2744 long long pos = pos_; | 2189 long long pos = pos_; |
2745 | 2190 |
2746 // First count number of track positions | 2191 // First count number of track positions |
2747 | 2192 |
2748 while (pos < stop) { | 2193 while (pos < stop) { |
2749 long len; | 2194 long len; |
2750 | 2195 |
2751 const long long id = ReadUInt(pReader, pos, len); | 2196 const long long id = ReadUInt(pReader, pos, len); |
2752 assert(id >= 0); // TODO | 2197 if ((id < 0) || (pos + len > stop)) { |
2753 assert((pos + len) <= stop); | 2198 return false; |
| 2199 } |
2754 | 2200 |
2755 pos += len; // consume ID | 2201 pos += len; // consume ID |
2756 | 2202 |
2757 const long long size = ReadUInt(pReader, pos, len); | 2203 const long long size = ReadUInt(pReader, pos, len); |
2758 assert(size >= 0); | 2204 if ((size < 0) || (pos + len > stop)) { |
2759 assert((pos + len) <= stop); | 2205 return false; |
| 2206 } |
2760 | 2207 |
2761 pos += len; // consume Size field | 2208 pos += len; // consume Size field |
2762 assert((pos + size) <= stop); | 2209 if ((pos + size) > stop) { |
| 2210 return false; |
| 2211 } |
2763 | 2212 |
2764 if (id == 0x33) // CueTime ID | 2213 if (id == 0x33) // CueTime ID |
2765 m_timecode = UnserializeUInt(pReader, pos, size); | 2214 m_timecode = UnserializeUInt(pReader, pos, size); |
2766 | 2215 |
2767 else if (id == 0x37) // CueTrackPosition(s) ID | 2216 else if (id == 0x37) // CueTrackPosition(s) ID |
2768 ++m_track_positions_count; | 2217 ++m_track_positions_count; |
2769 | 2218 |
2770 pos += size; // consume payload | 2219 pos += size; // consume payload |
2771 assert(pos <= stop); | |
2772 } | 2220 } |
2773 | 2221 |
2774 assert(m_timecode >= 0); | 2222 if (m_timecode < 0 || m_track_positions_count <= 0) { |
2775 assert(m_track_positions_count > 0); | 2223 return false; |
| 2224 } |
2776 | 2225 |
2777 // os << "CuePoint::Load(cont'd): idpos=" << idpos | 2226 // os << "CuePoint::Load(cont'd): idpos=" << idpos |
2778 // << " timecode=" << m_timecode | 2227 // << " timecode=" << m_timecode |
2779 // << endl; | 2228 // << endl; |
2780 | 2229 |
2781 m_track_positions = new TrackPosition[m_track_positions_count]; | 2230 m_track_positions = new TrackPosition[m_track_positions_count]; |
2782 | 2231 |
2783 // Now parse track positions | 2232 // Now parse track positions |
2784 | 2233 |
2785 TrackPosition* p = m_track_positions; | 2234 TrackPosition* p = m_track_positions; |
2786 pos = pos_; | 2235 pos = pos_; |
2787 | 2236 |
2788 while (pos < stop) { | 2237 while (pos < stop) { |
2789 long len; | 2238 long len; |
2790 | 2239 |
2791 const long long id = ReadUInt(pReader, pos, len); | 2240 const long long id = ReadUInt(pReader, pos, len); |
2792 assert(id >= 0); // TODO | 2241 assert(id >= 0); |
2793 assert((pos + len) <= stop); | 2242 assert((pos + len) <= stop); |
2794 | 2243 |
2795 pos += len; // consume ID | 2244 pos += len; // consume ID |
2796 | 2245 |
2797 const long long size = ReadUInt(pReader, pos, len); | 2246 const long long size = ReadUInt(pReader, pos, len); |
2798 assert(size >= 0); | 2247 assert(size >= 0); |
2799 assert((pos + len) <= stop); | 2248 assert((pos + len) <= stop); |
2800 | 2249 |
2801 pos += len; // consume Size field | 2250 pos += len; // consume Size field |
2802 assert((pos + size) <= stop); | 2251 assert((pos + size) <= stop); |
2803 | 2252 |
2804 if (id == 0x37) { // CueTrackPosition(s) ID | 2253 if (id == 0x37) { // CueTrackPosition(s) ID |
2805 TrackPosition& tp = *p++; | 2254 TrackPosition& tp = *p++; |
2806 tp.Parse(pReader, pos, size); | 2255 if (!tp.Parse(pReader, pos, size)) { |
| 2256 return false; |
| 2257 } |
2807 } | 2258 } |
2808 | 2259 |
2809 pos += size; // consume payload | 2260 pos += size; // consume payload |
2810 assert(pos <= stop); | 2261 assert(pos <= stop); |
2811 } | 2262 } |
2812 | 2263 |
2813 assert(size_t(p - m_track_positions) == m_track_positions_count); | 2264 assert(size_t(p - m_track_positions) == m_track_positions_count); |
2814 | 2265 |
2815 m_element_start = element_start; | 2266 m_element_start = element_start; |
2816 m_element_size = element_size; | 2267 m_element_size = element_size; |
| 2268 |
| 2269 return true; |
2817 } | 2270 } |
2818 | 2271 |
2819 void CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, | 2272 bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, |
2820 long long size_) { | 2273 long long size_) { |
2821 const long long stop = start_ + size_; | 2274 const long long stop = start_ + size_; |
2822 long long pos = start_; | 2275 long long pos = start_; |
2823 | 2276 |
2824 m_track = -1; | 2277 m_track = -1; |
2825 m_pos = -1; | 2278 m_pos = -1; |
2826 m_block = 1; // default | 2279 m_block = 1; // default |
2827 | 2280 |
2828 while (pos < stop) { | 2281 while (pos < stop) { |
2829 long len; | 2282 long len; |
2830 | 2283 |
2831 const long long id = ReadUInt(pReader, pos, len); | 2284 const long long id = ReadUInt(pReader, pos, len); |
2832 assert(id >= 0); // TODO | 2285 if ((id < 0) || ((pos + len) > stop)) { |
2833 assert((pos + len) <= stop); | 2286 return false; |
| 2287 } |
2834 | 2288 |
2835 pos += len; // consume ID | 2289 pos += len; // consume ID |
2836 | 2290 |
2837 const long long size = ReadUInt(pReader, pos, len); | 2291 const long long size = ReadUInt(pReader, pos, len); |
2838 assert(size >= 0); | 2292 if ((size < 0) || ((pos + len) > stop)) { |
2839 assert((pos + len) <= stop); | 2293 return false; |
| 2294 } |
2840 | 2295 |
2841 pos += len; // consume Size field | 2296 pos += len; // consume Size field |
2842 assert((pos + size) <= stop); | 2297 if ((pos + size) > stop) { |
| 2298 return false; |
| 2299 } |
2843 | 2300 |
2844 if (id == 0x77) // CueTrack ID | 2301 if (id == 0x77) // CueTrack ID |
2845 m_track = UnserializeUInt(pReader, pos, size); | 2302 m_track = UnserializeUInt(pReader, pos, size); |
2846 | 2303 |
2847 else if (id == 0x71) // CueClusterPos ID | 2304 else if (id == 0x71) // CueClusterPos ID |
2848 m_pos = UnserializeUInt(pReader, pos, size); | 2305 m_pos = UnserializeUInt(pReader, pos, size); |
2849 | 2306 |
2850 else if (id == 0x1378) // CueBlockNumber | 2307 else if (id == 0x1378) // CueBlockNumber |
2851 m_block = UnserializeUInt(pReader, pos, size); | 2308 m_block = UnserializeUInt(pReader, pos, size); |
2852 | 2309 |
2853 pos += size; // consume payload | 2310 pos += size; // consume payload |
2854 assert(pos <= stop); | |
2855 } | 2311 } |
2856 | 2312 |
2857 assert(m_pos >= 0); | 2313 if ((m_pos < 0) || (m_track <= 0)) { |
2858 assert(m_track > 0); | 2314 return false; |
2859 // assert(m_block > 0); | 2315 } |
| 2316 |
| 2317 return true; |
2860 } | 2318 } |
2861 | 2319 |
2862 const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const { | 2320 const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const { |
2863 assert(pTrack); | 2321 assert(pTrack); |
2864 | 2322 |
2865 const long long n = pTrack->GetNumber(); | 2323 const long long n = pTrack->GetNumber(); |
2866 | 2324 |
2867 const TrackPosition* i = m_track_positions; | 2325 const TrackPosition* i = m_track_positions; |
2868 const TrackPosition* const j = i + m_track_positions_count; | 2326 const TrackPosition* const j = i + m_track_positions_count; |
2869 | 2327 |
(...skipping 17 matching lines...) Expand all Loading... |
2887 assert(pInfo); | 2345 assert(pInfo); |
2888 | 2346 |
2889 const long long scale = pInfo->GetTimeCodeScale(); | 2347 const long long scale = pInfo->GetTimeCodeScale(); |
2890 assert(scale >= 1); | 2348 assert(scale >= 1); |
2891 | 2349 |
2892 const long long time = scale * m_timecode; | 2350 const long long time = scale * m_timecode; |
2893 | 2351 |
2894 return time; | 2352 return time; |
2895 } | 2353 } |
2896 | 2354 |
2897 #if 0 | |
2898 long long Segment::Unparsed() const | |
2899 { | |
2900 if (m_size < 0) | |
2901 return LLONG_MAX; | |
2902 | |
2903 const long long stop = m_start + m_size; | |
2904 | |
2905 const long long result = stop - m_pos; | |
2906 assert(result >= 0); | |
2907 | |
2908 return result; | |
2909 } | |
2910 #else | |
2911 bool Segment::DoneParsing() const { | 2355 bool Segment::DoneParsing() const { |
2912 if (m_size < 0) { | 2356 if (m_size < 0) { |
2913 long long total, avail; | 2357 long long total, avail; |
2914 | 2358 |
2915 const int status = m_pReader->Length(&total, &avail); | 2359 const int status = m_pReader->Length(&total, &avail); |
2916 | 2360 |
2917 if (status < 0) // error | 2361 if (status < 0) // error |
2918 return true; // must assume done | 2362 return true; // must assume done |
2919 | 2363 |
2920 if (total < 0) | 2364 if (total < 0) |
2921 return false; // assume live stream | 2365 return false; // assume live stream |
2922 | 2366 |
2923 return (m_pos >= total); | 2367 return (m_pos >= total); |
2924 } | 2368 } |
2925 | 2369 |
2926 const long long stop = m_start + m_size; | 2370 const long long stop = m_start + m_size; |
2927 | 2371 |
2928 return (m_pos >= stop); | 2372 return (m_pos >= stop); |
2929 } | 2373 } |
2930 #endif | |
2931 | 2374 |
2932 const Cluster* Segment::GetFirst() const { | 2375 const Cluster* Segment::GetFirst() const { |
2933 if ((m_clusters == NULL) || (m_clusterCount <= 0)) | 2376 if ((m_clusters == NULL) || (m_clusterCount <= 0)) |
2934 return &m_eos; | 2377 return &m_eos; |
2935 | 2378 |
2936 Cluster* const pCluster = m_clusters[0]; | 2379 Cluster* const pCluster = m_clusters[0]; |
2937 assert(pCluster); | 2380 assert(pCluster); |
2938 | 2381 |
2939 return pCluster; | 2382 return pCluster; |
2940 } | 2383 } |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3388 if (id != 0x0F43B675) { // not a Cluster ID | 2831 if (id != 0x0F43B675) { // not a Cluster ID |
3389 if (size == unknown_size) | 2832 if (size == unknown_size) |
3390 return E_FILE_FORMAT_INVALID; | 2833 return E_FILE_FORMAT_INVALID; |
3391 | 2834 |
3392 pos += size; // consume payload | 2835 pos += size; // consume payload |
3393 assert((segment_stop < 0) || (pos <= segment_stop)); | 2836 assert((segment_stop < 0) || (pos <= segment_stop)); |
3394 | 2837 |
3395 continue; | 2838 continue; |
3396 } | 2839 } |
3397 | 2840 |
3398 #if 0 // this is commented-out to support incremental cluster parsing | |
3399 len = static_cast<long>(size); | |
3400 | |
3401 if (element_stop > avail) | |
3402 return E_BUFFER_NOT_FULL; | |
3403 #endif | |
3404 | |
3405 // We have a cluster. | 2841 // We have a cluster. |
3406 | |
3407 off_next = idoff; | 2842 off_next = idoff; |
3408 | 2843 |
3409 if (size != unknown_size) | 2844 if (size != unknown_size) |
3410 cluster_size = size; | 2845 cluster_size = size; |
3411 | 2846 |
3412 break; | 2847 break; |
3413 } | 2848 } |
3414 | 2849 |
3415 assert(off_next > 0); // have cluster | 2850 assert(off_next > 0); // have cluster |
3416 | 2851 |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3640 const long k = i - 1; | 3075 const long k = i - 1; |
3641 | 3076 |
3642 Cluster* const pCluster = m_clusters[k]; | 3077 Cluster* const pCluster = m_clusters[k]; |
3643 assert(pCluster); | 3078 assert(pCluster); |
3644 assert(pCluster->m_index == k); | 3079 assert(pCluster->m_index == k); |
3645 assert(pCluster->GetTime() <= time_ns); | 3080 assert(pCluster->GetTime() <= time_ns); |
3646 | 3081 |
3647 return pCluster; | 3082 return pCluster; |
3648 } | 3083 } |
3649 | 3084 |
3650 #if 0 | |
3651 const BlockEntry* Segment::Seek( | |
3652 long long time_ns, | |
3653 const Track* pTrack) const | |
3654 { | |
3655 assert(pTrack); | |
3656 | |
3657 if ((m_clusters == NULL) || (m_clusterCount <= 0)) | |
3658 return pTrack->GetEOS(); | |
3659 | |
3660 Cluster** const i = m_clusters; | |
3661 assert(i); | |
3662 | |
3663 { | |
3664 Cluster* const pCluster = *i; | |
3665 assert(pCluster); | |
3666 assert(pCluster->m_index == 0); //m_clusterCount > 0 | |
3667 assert(pCluster->m_pSegment == this); | |
3668 | |
3669 if (time_ns <= pCluster->GetTime()) | |
3670 return pCluster->GetEntry(pTrack); | |
3671 } | |
3672 | |
3673 Cluster** const j = i + m_clusterCount; | |
3674 | |
3675 if (pTrack->GetType() == 2) { //audio | |
3676 //TODO: we could decide to use cues for this, as we do for video. | |
3677 //But we only use it for video because looking around for a keyframe | |
3678 //can get expensive. Audio doesn't require anything special so a | |
3679 //straight cluster search is good enough (we assume). | |
3680 | |
3681 Cluster** lo = i; | |
3682 Cluster** hi = j; | |
3683 | |
3684 while (lo < hi) | |
3685 { | |
3686 //INVARIANT: | |
3687 //[i, lo) <= time_ns | |
3688 //[lo, hi) ? | |
3689 //[hi, j) > time_ns | |
3690 | |
3691 Cluster** const mid = lo + (hi - lo) / 2; | |
3692 assert(mid < hi); | |
3693 | |
3694 Cluster* const pCluster = *mid; | |
3695 assert(pCluster); | |
3696 assert(pCluster->m_index == long(mid - m_clusters)); | |
3697 assert(pCluster->m_pSegment == this); | |
3698 | |
3699 const long long t = pCluster->GetTime(); | |
3700 | |
3701 if (t <= time_ns) | |
3702 lo = mid + 1; | |
3703 else | |
3704 hi = mid; | |
3705 | |
3706 assert(lo <= hi); | |
3707 } | |
3708 | |
3709 assert(lo == hi); | |
3710 assert(lo > i); | |
3711 assert(lo <= j); | |
3712 | |
3713 while (lo > i) | |
3714 { | |
3715 Cluster* const pCluster = *--lo; | |
3716 assert(pCluster); | |
3717 assert(pCluster->GetTime() <= time_ns); | |
3718 | |
3719 const BlockEntry* const pBE = pCluster->GetEntry(pTrack); | |
3720 | |
3721 if ((pBE != 0) && !pBE->EOS()) | |
3722 return pBE; | |
3723 | |
3724 //landed on empty cluster (no entries) | |
3725 } | |
3726 | |
3727 return pTrack->GetEOS(); //weird | |
3728 } | |
3729 | |
3730 assert(pTrack->GetType() == 1); //video | |
3731 | |
3732 Cluster** lo = i; | |
3733 Cluster** hi = j; | |
3734 | |
3735 while (lo < hi) | |
3736 { | |
3737 //INVARIANT: | |
3738 //[i, lo) <= time_ns | |
3739 //[lo, hi) ? | |
3740 //[hi, j) > time_ns | |
3741 | |
3742 Cluster** const mid = lo + (hi - lo) / 2; | |
3743 assert(mid < hi); | |
3744 | |
3745 Cluster* const pCluster = *mid; | |
3746 assert(pCluster); | |
3747 | |
3748 const long long t = pCluster->GetTime(); | |
3749 | |
3750 if (t <= time_ns) | |
3751 lo = mid + 1; | |
3752 else | |
3753 hi = mid; | |
3754 | |
3755 assert(lo <= hi); | |
3756 } | |
3757 | |
3758 assert(lo == hi); | |
3759 assert(lo > i); | |
3760 assert(lo <= j); | |
3761 | |
3762 Cluster* pCluster = *--lo; | |
3763 assert(pCluster); | |
3764 assert(pCluster->GetTime() <= time_ns); | |
3765 | |
3766 { | |
3767 const BlockEntry* const pBE = pCluster->GetEntry(pTrack, time_ns); | |
3768 | |
3769 if ((pBE != 0) && !pBE->EOS()) //found a keyframe | |
3770 return pBE; | |
3771 } | |
3772 | |
3773 const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack); | |
3774 | |
3775 while (lo != i) | |
3776 { | |
3777 pCluster = *--lo; | |
3778 assert(pCluster); | |
3779 assert(pCluster->GetTime() <= time_ns); | |
3780 | |
3781 const BlockEntry* const pBlockEntry = pCluster->GetMaxKey(pVideo); | |
3782 | |
3783 if ((pBlockEntry != 0) && !pBlockEntry->EOS()) | |
3784 return pBlockEntry; | |
3785 } | |
3786 | |
3787 //weird: we're on the first cluster, but no keyframe found | |
3788 //should never happen but we must return something anyway | |
3789 | |
3790 return pTrack->GetEOS(); | |
3791 } | |
3792 #endif | |
3793 | |
3794 #if 0 | |
3795 bool Segment::SearchCues( | |
3796 long long time_ns, | |
3797 Track* pTrack, | |
3798 Cluster*& pCluster, | |
3799 const BlockEntry*& pBlockEntry, | |
3800 const CuePoint*& pCP, | |
3801 const CuePoint::TrackPosition*& pTP) | |
3802 { | |
3803 if (pTrack->GetType() != 1) //not video | |
3804 return false; //TODO: for now, just handle video stream | |
3805 | |
3806 if (m_pCues == NULL) | |
3807 return false; | |
3808 | |
3809 if (!m_pCues->Find(time_ns, pTrack, pCP, pTP)) | |
3810 return false; //weird | |
3811 | |
3812 assert(pCP); | |
3813 assert(pTP); | |
3814 assert(pTP->m_track == pTrack->GetNumber()); | |
3815 | |
3816 //We have the cue point and track position we want, | |
3817 //so we now need to search for the cluster having | |
3818 //the indicated position. | |
3819 | |
3820 return GetCluster(pCP, pTP, pCluster, pBlockEntry); | |
3821 } | |
3822 #endif | |
3823 | |
3824 const Tracks* Segment::GetTracks() const { return m_pTracks; } | 3085 const Tracks* Segment::GetTracks() const { return m_pTracks; } |
3825 | |
3826 const SegmentInfo* Segment::GetInfo() const { return m_pInfo; } | 3086 const SegmentInfo* Segment::GetInfo() const { return m_pInfo; } |
3827 | |
3828 const Cues* Segment::GetCues() const { return m_pCues; } | 3087 const Cues* Segment::GetCues() const { return m_pCues; } |
3829 | |
3830 const Chapters* Segment::GetChapters() const { return m_pChapters; } | 3088 const Chapters* Segment::GetChapters() const { return m_pChapters; } |
3831 | 3089 const Tags* Segment::GetTags() const { return m_pTags; } |
3832 const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; } | 3090 const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; } |
3833 | 3091 |
3834 long long Segment::GetDuration() const { | 3092 long long Segment::GetDuration() const { |
3835 assert(m_pInfo); | 3093 assert(m_pInfo); |
3836 return m_pInfo->GetDuration(); | 3094 return m_pInfo->GetDuration(); |
3837 } | 3095 } |
3838 | 3096 |
3839 Chapters::Chapters(Segment* pSegment, long long payload_start, | 3097 Chapters::Chapters(Segment* pSegment, long long payload_start, |
3840 long long payload_size, long long element_start, | 3098 long long payload_size, long long element_start, |
3841 long long element_size) | 3099 long long element_size) |
3842 : m_pSegment(pSegment), | 3100 : m_pSegment(pSegment), |
3843 m_start(payload_start), | 3101 m_start(payload_start), |
3844 m_size(payload_size), | 3102 m_size(payload_size), |
3845 m_element_start(element_start), | 3103 m_element_start(element_start), |
3846 m_element_size(element_size), | 3104 m_element_size(element_size), |
3847 m_editions(NULL), | 3105 m_editions(NULL), |
3848 m_editions_size(0), | 3106 m_editions_size(0), |
3849 m_editions_count(0) {} | 3107 m_editions_count(0) {} |
3850 | 3108 |
3851 Chapters::~Chapters() { | 3109 Chapters::~Chapters() { |
3852 while (m_editions_count > 0) { | 3110 while (m_editions_count > 0) { |
3853 Edition& e = m_editions[--m_editions_count]; | 3111 Edition& e = m_editions[--m_editions_count]; |
3854 e.Clear(); | 3112 e.Clear(); |
3855 } | 3113 } |
| 3114 delete[] m_editions; |
3856 } | 3115 } |
3857 | 3116 |
3858 long Chapters::Parse() { | 3117 long Chapters::Parse() { |
3859 IMkvReader* const pReader = m_pSegment->m_pReader; | 3118 IMkvReader* const pReader = m_pSegment->m_pReader; |
3860 | 3119 |
3861 long long pos = m_start; // payload start | 3120 long long pos = m_start; // payload start |
3862 const long long stop = pos + m_size; // payload stop | 3121 const long long stop = pos + m_size; // payload stop |
3863 | 3122 |
3864 while (pos < stop) { | 3123 while (pos < stop) { |
3865 long long id, size; | 3124 long long id, size; |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4121 status = ParseDisplay(pReader, pos, size); | 3380 status = ParseDisplay(pReader, pos, size); |
4122 | 3381 |
4123 if (status < 0) // error | 3382 if (status < 0) // error |
4124 return status; | 3383 return status; |
4125 } else if (id == 0x1654) { // StringUID ID | 3384 } else if (id == 0x1654) { // StringUID ID |
4126 status = UnserializeString(pReader, pos, size, m_string_uid); | 3385 status = UnserializeString(pReader, pos, size, m_string_uid); |
4127 | 3386 |
4128 if (status < 0) // error | 3387 if (status < 0) // error |
4129 return status; | 3388 return status; |
4130 } else if (id == 0x33C4) { // UID ID | 3389 } else if (id == 0x33C4) { // UID ID |
4131 const long long val = UnserializeUInt(pReader, pos, size); | 3390 long long val; |
| 3391 status = UnserializeInt(pReader, pos, size, val); |
4132 | 3392 |
4133 if (val < 0) // error | 3393 if (status < 0) // error |
4134 return static_cast<long>(val); | 3394 return status; |
4135 | 3395 |
4136 m_uid = val; | 3396 m_uid = static_cast<unsigned long long>(val); |
4137 } else if (id == 0x11) { // TimeStart ID | 3397 } else if (id == 0x11) { // TimeStart ID |
4138 const long long val = UnserializeUInt(pReader, pos, size); | 3398 const long long val = UnserializeUInt(pReader, pos, size); |
4139 | 3399 |
4140 if (val < 0) // error | 3400 if (val < 0) // error |
4141 return static_cast<long>(val); | 3401 return static_cast<long>(val); |
4142 | 3402 |
4143 m_start_timecode = val; | 3403 m_start_timecode = val; |
4144 } else if (id == 0x12) { // TimeEnd ID | 3404 } else if (id == 0x12) { // TimeEnd ID |
4145 const long long val = UnserializeUInt(pReader, pos, size); | 3405 const long long val = UnserializeUInt(pReader, pos, size); |
4146 | 3406 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4250 | 3510 |
4251 delete[] m_country; | 3511 delete[] m_country; |
4252 m_country = NULL; | 3512 m_country = NULL; |
4253 } | 3513 } |
4254 | 3514 |
4255 long Chapters::Display::Parse(IMkvReader* pReader, long long pos, | 3515 long Chapters::Display::Parse(IMkvReader* pReader, long long pos, |
4256 long long size) { | 3516 long long size) { |
4257 const long long stop = pos + size; | 3517 const long long stop = pos + size; |
4258 | 3518 |
4259 while (pos < stop) { | 3519 while (pos < stop) { |
| 3520 long long id, size; |
| 3521 |
| 3522 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3523 |
| 3524 if (status < 0) // error |
| 3525 return status; |
| 3526 |
| 3527 if (size == 0) // weird |
| 3528 continue; |
| 3529 |
| 3530 if (id == 0x05) { // ChapterString ID |
| 3531 status = UnserializeString(pReader, pos, size, m_string); |
| 3532 |
| 3533 if (status) |
| 3534 return status; |
| 3535 } else if (id == 0x037C) { // ChapterLanguage ID |
| 3536 status = UnserializeString(pReader, pos, size, m_language); |
| 3537 |
| 3538 if (status) |
| 3539 return status; |
| 3540 } else if (id == 0x037E) { // ChapterCountry ID |
| 3541 status = UnserializeString(pReader, pos, size, m_country); |
| 3542 |
| 3543 if (status) |
| 3544 return status; |
| 3545 } |
| 3546 |
| 3547 pos += size; |
| 3548 assert(pos <= stop); |
| 3549 } |
| 3550 |
| 3551 assert(pos == stop); |
| 3552 return 0; |
| 3553 } |
| 3554 |
| 3555 Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size, |
| 3556 long long element_start, long long element_size) |
| 3557 : m_pSegment(pSegment), |
| 3558 m_start(payload_start), |
| 3559 m_size(payload_size), |
| 3560 m_element_start(element_start), |
| 3561 m_element_size(element_size), |
| 3562 m_tags(NULL), |
| 3563 m_tags_size(0), |
| 3564 m_tags_count(0) {} |
| 3565 |
| 3566 Tags::~Tags() { |
| 3567 while (m_tags_count > 0) { |
| 3568 Tag& t = m_tags[--m_tags_count]; |
| 3569 t.Clear(); |
| 3570 } |
| 3571 delete[] m_tags; |
| 3572 } |
| 3573 |
| 3574 long Tags::Parse() { |
| 3575 IMkvReader* const pReader = m_pSegment->m_pReader; |
| 3576 |
| 3577 long long pos = m_start; // payload start |
| 3578 const long long stop = pos + m_size; // payload stop |
| 3579 |
| 3580 while (pos < stop) { |
| 3581 long long id, size; |
| 3582 |
| 3583 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3584 |
| 3585 if (status < 0) |
| 3586 return status; |
| 3587 |
| 3588 if (size == 0) // 0 length tag, read another |
| 3589 continue; |
| 3590 |
| 3591 if (id == 0x3373) { // Tag ID |
| 3592 status = ParseTag(pos, size); |
| 3593 |
| 3594 if (status < 0) |
| 3595 return status; |
| 3596 } |
| 3597 |
| 3598 pos += size; |
| 3599 assert(pos <= stop); |
| 3600 if (pos > stop) |
| 3601 return -1; |
| 3602 } |
| 3603 |
| 3604 assert(pos == stop); |
| 3605 if (pos != stop) |
| 3606 return -1; |
| 3607 |
| 3608 return 0; |
| 3609 } |
| 3610 |
| 3611 int Tags::GetTagCount() const { return m_tags_count; } |
| 3612 |
| 3613 const Tags::Tag* Tags::GetTag(int idx) const { |
| 3614 if (idx < 0) |
| 3615 return NULL; |
| 3616 |
| 3617 if (idx >= m_tags_count) |
| 3618 return NULL; |
| 3619 |
| 3620 return m_tags + idx; |
| 3621 } |
| 3622 |
| 3623 bool Tags::ExpandTagsArray() { |
| 3624 if (m_tags_size > m_tags_count) |
| 3625 return true; // nothing else to do |
| 3626 |
| 3627 const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size; |
| 3628 |
| 3629 Tag* const tags = new (std::nothrow) Tag[size]; |
| 3630 |
| 3631 if (tags == NULL) |
| 3632 return false; |
| 3633 |
| 3634 for (int idx = 0; idx < m_tags_count; ++idx) { |
| 3635 m_tags[idx].ShallowCopy(tags[idx]); |
| 3636 } |
| 3637 |
| 3638 delete[] m_tags; |
| 3639 m_tags = tags; |
| 3640 |
| 3641 m_tags_size = size; |
| 3642 return true; |
| 3643 } |
| 3644 |
| 3645 long Tags::ParseTag(long long pos, long long size) { |
| 3646 if (!ExpandTagsArray()) |
| 3647 return -1; |
| 3648 |
| 3649 Tag& t = m_tags[m_tags_count++]; |
| 3650 t.Init(); |
| 3651 |
| 3652 return t.Parse(m_pSegment->m_pReader, pos, size); |
| 3653 } |
| 3654 |
| 3655 Tags::Tag::Tag() {} |
| 3656 |
| 3657 Tags::Tag::~Tag() {} |
| 3658 |
| 3659 int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; } |
| 3660 |
| 3661 const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const { |
| 3662 if (index < 0) |
| 3663 return NULL; |
| 3664 |
| 3665 if (index >= m_simple_tags_count) |
| 3666 return NULL; |
| 3667 |
| 3668 return m_simple_tags + index; |
| 3669 } |
| 3670 |
| 3671 void Tags::Tag::Init() { |
| 3672 m_simple_tags = NULL; |
| 3673 m_simple_tags_size = 0; |
| 3674 m_simple_tags_count = 0; |
| 3675 } |
| 3676 |
| 3677 void Tags::Tag::ShallowCopy(Tag& rhs) const { |
| 3678 rhs.m_simple_tags = m_simple_tags; |
| 3679 rhs.m_simple_tags_size = m_simple_tags_size; |
| 3680 rhs.m_simple_tags_count = m_simple_tags_count; |
| 3681 } |
| 3682 |
| 3683 void Tags::Tag::Clear() { |
| 3684 while (m_simple_tags_count > 0) { |
| 3685 SimpleTag& d = m_simple_tags[--m_simple_tags_count]; |
| 3686 d.Clear(); |
| 3687 } |
| 3688 |
| 3689 delete[] m_simple_tags; |
| 3690 m_simple_tags = NULL; |
| 3691 |
| 3692 m_simple_tags_size = 0; |
| 3693 } |
| 3694 |
| 3695 long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) { |
| 3696 const long long stop = pos + size; |
| 3697 |
| 3698 while (pos < stop) { |
| 3699 long long id, size; |
| 3700 |
| 3701 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3702 |
| 3703 if (status < 0) |
| 3704 return status; |
| 3705 |
| 3706 if (size == 0) // 0 length tag, read another |
| 3707 continue; |
| 3708 |
| 3709 if (id == 0x27C8) { // SimpleTag ID |
| 3710 status = ParseSimpleTag(pReader, pos, size); |
| 3711 |
| 3712 if (status < 0) |
| 3713 return status; |
| 3714 } |
| 3715 |
| 3716 pos += size; |
| 3717 assert(pos <= stop); |
| 3718 if (pos > stop) |
| 3719 return -1; |
| 3720 } |
| 3721 |
| 3722 assert(pos == stop); |
| 3723 if (pos != stop) |
| 3724 return -1; |
| 3725 return 0; |
| 3726 } |
| 3727 |
| 3728 long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos, |
| 3729 long long size) { |
| 3730 if (!ExpandSimpleTagsArray()) |
| 3731 return -1; |
| 3732 |
| 3733 SimpleTag& st = m_simple_tags[m_simple_tags_count++]; |
| 3734 st.Init(); |
| 3735 |
| 3736 return st.Parse(pReader, pos, size); |
| 3737 } |
| 3738 |
| 3739 bool Tags::Tag::ExpandSimpleTagsArray() { |
| 3740 if (m_simple_tags_size > m_simple_tags_count) |
| 3741 return true; // nothing else to do |
| 3742 |
| 3743 const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size; |
| 3744 |
| 3745 SimpleTag* const displays = new (std::nothrow) SimpleTag[size]; |
| 3746 |
| 3747 if (displays == NULL) |
| 3748 return false; |
| 3749 |
| 3750 for (int idx = 0; idx < m_simple_tags_count; ++idx) { |
| 3751 m_simple_tags[idx].ShallowCopy(displays[idx]); |
| 3752 } |
| 3753 |
| 3754 delete[] m_simple_tags; |
| 3755 m_simple_tags = displays; |
| 3756 |
| 3757 m_simple_tags_size = size; |
| 3758 return true; |
| 3759 } |
| 3760 |
| 3761 Tags::SimpleTag::SimpleTag() {} |
| 3762 |
| 3763 Tags::SimpleTag::~SimpleTag() {} |
| 3764 |
| 3765 const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; } |
| 3766 |
| 3767 const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; } |
| 3768 |
| 3769 void Tags::SimpleTag::Init() { |
| 3770 m_tag_name = NULL; |
| 3771 m_tag_string = NULL; |
| 3772 } |
| 3773 |
| 3774 void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const { |
| 3775 rhs.m_tag_name = m_tag_name; |
| 3776 rhs.m_tag_string = m_tag_string; |
| 3777 } |
| 3778 |
| 3779 void Tags::SimpleTag::Clear() { |
| 3780 delete[] m_tag_name; |
| 3781 m_tag_name = NULL; |
| 3782 |
| 3783 delete[] m_tag_string; |
| 3784 m_tag_string = NULL; |
| 3785 } |
| 3786 |
| 3787 long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos, |
| 3788 long long size) { |
| 3789 const long long stop = pos + size; |
| 3790 |
| 3791 while (pos < stop) { |
4260 long long id, size; | 3792 long long id, size; |
4261 | 3793 |
4262 long status = ParseElementHeader(pReader, pos, stop, id, size); | 3794 long status = ParseElementHeader(pReader, pos, stop, id, size); |
4263 | 3795 |
4264 if (status < 0) // error | 3796 if (status < 0) // error |
4265 return status; | 3797 return status; |
4266 | 3798 |
4267 if (size == 0) // weird | 3799 if (size == 0) // weird |
4268 continue; | 3800 continue; |
4269 | 3801 |
4270 if (id == 0x05) { // ChapterString ID | 3802 if (id == 0x5A3) { // TagName ID |
4271 status = UnserializeString(pReader, pos, size, m_string); | 3803 status = UnserializeString(pReader, pos, size, m_tag_name); |
4272 | 3804 |
4273 if (status) | 3805 if (status) |
4274 return status; | 3806 return status; |
4275 } else if (id == 0x037C) { // ChapterLanguage ID | 3807 } else if (id == 0x487) { // TagString ID |
4276 status = UnserializeString(pReader, pos, size, m_language); | 3808 status = UnserializeString(pReader, pos, size, m_tag_string); |
4277 | 3809 |
4278 if (status) | 3810 if (status) |
4279 return status; | 3811 return status; |
4280 } else if (id == 0x037E) { // ChapterCountry ID | |
4281 status = UnserializeString(pReader, pos, size, m_country); | |
4282 | |
4283 if (status) | |
4284 return status; | |
4285 } | 3812 } |
4286 | 3813 |
4287 pos += size; | 3814 pos += size; |
4288 assert(pos <= stop); | 3815 assert(pos <= stop); |
| 3816 if (pos > stop) |
| 3817 return -1; |
4289 } | 3818 } |
4290 | 3819 |
4291 assert(pos == stop); | 3820 assert(pos == stop); |
| 3821 if (pos != stop) |
| 3822 return -1; |
4292 return 0; | 3823 return 0; |
4293 } | 3824 } |
4294 | 3825 |
4295 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_, | 3826 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_, |
4296 long long element_start, long long element_size) | 3827 long long element_start, long long element_size) |
4297 : m_pSegment(pSegment), | 3828 : m_pSegment(pSegment), |
4298 m_start(start), | 3829 m_start(start), |
4299 m_size(size_), | 3830 m_size(size_), |
4300 m_element_start(element_start), | 3831 m_element_start(element_start), |
4301 m_element_size(element_size), | 3832 m_element_size(element_size), |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4451 | 3982 |
4452 while (enc_i != enc_j) { | 3983 while (enc_i != enc_j) { |
4453 ContentEncryption* const enc = *enc_i++; | 3984 ContentEncryption* const enc = *enc_i++; |
4454 delete enc; | 3985 delete enc; |
4455 } | 3986 } |
4456 | 3987 |
4457 delete[] encryption_entries_; | 3988 delete[] encryption_entries_; |
4458 } | 3989 } |
4459 | 3990 |
4460 const ContentEncoding::ContentCompression* | 3991 const ContentEncoding::ContentCompression* |
4461 ContentEncoding::GetCompressionByIndex(unsigned long idx) const { | 3992 ContentEncoding::GetCompressionByIndex(unsigned long idx) const { |
4462 const ptrdiff_t count = compression_entries_end_ - compression_entries_; | 3993 const ptrdiff_t count = compression_entries_end_ - compression_entries_; |
4463 assert(count >= 0); | 3994 assert(count >= 0); |
4464 | 3995 |
4465 if (idx >= static_cast<unsigned long>(count)) | 3996 if (idx >= static_cast<unsigned long>(count)) |
4466 return NULL; | 3997 return NULL; |
4467 | 3998 |
4468 return compression_entries_[idx]; | 3999 return compression_entries_[idx]; |
4469 } | 4000 } |
4470 | 4001 |
4471 unsigned long ContentEncoding::GetCompressionCount() const { | 4002 unsigned long ContentEncoding::GetCompressionCount() const { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4547 | 4078 |
4548 pos += size; // consume payload | 4079 pos += size; // consume payload |
4549 assert(pos <= stop); | 4080 assert(pos <= stop); |
4550 } | 4081 } |
4551 | 4082 |
4552 if (compression_count <= 0 && encryption_count <= 0) | 4083 if (compression_count <= 0 && encryption_count <= 0) |
4553 return -1; | 4084 return -1; |
4554 | 4085 |
4555 if (compression_count > 0) { | 4086 if (compression_count > 0) { |
4556 compression_entries_ = | 4087 compression_entries_ = |
4557 new (std::nothrow) ContentCompression* [compression_count]; | 4088 new (std::nothrow) ContentCompression*[compression_count]; |
4558 if (!compression_entries_) | 4089 if (!compression_entries_) |
4559 return -1; | 4090 return -1; |
4560 compression_entries_end_ = compression_entries_; | 4091 compression_entries_end_ = compression_entries_; |
4561 } | 4092 } |
4562 | 4093 |
4563 if (encryption_count > 0) { | 4094 if (encryption_count > 0) { |
4564 encryption_entries_ = | 4095 encryption_entries_ = |
4565 new (std::nothrow) ContentEncryption* [encryption_count]; | 4096 new (std::nothrow) ContentEncryption*[encryption_count]; |
4566 if (!encryption_entries_) { | 4097 if (!encryption_entries_) { |
4567 delete[] compression_entries_; | 4098 delete[] compression_entries_; |
4568 return -1; | 4099 return -1; |
4569 } | 4100 } |
4570 encryption_entries_end_ = encryption_entries_; | 4101 encryption_entries_end_ = encryption_entries_; |
4571 } | 4102 } |
4572 | 4103 |
4573 pos = start; | 4104 pos = start; |
4574 while (pos < stop) { | 4105 while (pos < stop) { |
4575 long long id, size; | 4106 long long id, size; |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4696 if (status < 0) // error | 4227 if (status < 0) // error |
4697 return status; | 4228 return status; |
4698 | 4229 |
4699 if (id == 0x7E1) { | 4230 if (id == 0x7E1) { |
4700 // ContentEncAlgo | 4231 // ContentEncAlgo |
4701 encryption->algo = UnserializeUInt(pReader, pos, size); | 4232 encryption->algo = UnserializeUInt(pReader, pos, size); |
4702 if (encryption->algo != 5) | 4233 if (encryption->algo != 5) |
4703 return E_FILE_FORMAT_INVALID; | 4234 return E_FILE_FORMAT_INVALID; |
4704 } else if (id == 0x7E2) { | 4235 } else if (id == 0x7E2) { |
4705 // ContentEncKeyID | 4236 // ContentEncKeyID |
4706 delete[] encryption -> key_id; | 4237 delete[] encryption->key_id; |
4707 encryption->key_id = NULL; | 4238 encryption->key_id = NULL; |
4708 encryption->key_id_len = 0; | 4239 encryption->key_id_len = 0; |
4709 | 4240 |
4710 if (size <= 0) | 4241 if (size <= 0) |
4711 return E_FILE_FORMAT_INVALID; | 4242 return E_FILE_FORMAT_INVALID; |
4712 | 4243 |
4713 const size_t buflen = static_cast<size_t>(size); | 4244 const size_t buflen = static_cast<size_t>(size); |
4714 typedef unsigned char* buf_t; | 4245 typedef unsigned char* buf_t; |
4715 const buf_t buf = new (std::nothrow) unsigned char[buflen]; | 4246 const buf_t buf = new (std::nothrow) unsigned char[buflen]; |
4716 if (buf == NULL) | 4247 if (buf == NULL) |
4717 return -1; | 4248 return -1; |
4718 | 4249 |
4719 const int read_status = | 4250 const int read_status = |
4720 pReader->Read(pos, static_cast<long>(buflen), buf); | 4251 pReader->Read(pos, static_cast<long>(buflen), buf); |
4721 if (read_status) { | 4252 if (read_status) { |
4722 delete[] buf; | 4253 delete[] buf; |
4723 return status; | 4254 return status; |
4724 } | 4255 } |
4725 | 4256 |
4726 encryption->key_id = buf; | 4257 encryption->key_id = buf; |
4727 encryption->key_id_len = buflen; | 4258 encryption->key_id_len = buflen; |
4728 } else if (id == 0x7E3) { | 4259 } else if (id == 0x7E3) { |
4729 // ContentSignature | 4260 // ContentSignature |
4730 delete[] encryption -> signature; | 4261 delete[] encryption->signature; |
4731 encryption->signature = NULL; | 4262 encryption->signature = NULL; |
4732 encryption->signature_len = 0; | 4263 encryption->signature_len = 0; |
4733 | 4264 |
4734 if (size <= 0) | 4265 if (size <= 0) |
4735 return E_FILE_FORMAT_INVALID; | 4266 return E_FILE_FORMAT_INVALID; |
4736 | 4267 |
4737 const size_t buflen = static_cast<size_t>(size); | 4268 const size_t buflen = static_cast<size_t>(size); |
4738 typedef unsigned char* buf_t; | 4269 typedef unsigned char* buf_t; |
4739 const buf_t buf = new (std::nothrow) unsigned char[buflen]; | 4270 const buf_t buf = new (std::nothrow) unsigned char[buflen]; |
4740 if (buf == NULL) | 4271 if (buf == NULL) |
4741 return -1; | 4272 return -1; |
4742 | 4273 |
4743 const int read_status = | 4274 const int read_status = |
4744 pReader->Read(pos, static_cast<long>(buflen), buf); | 4275 pReader->Read(pos, static_cast<long>(buflen), buf); |
4745 if (read_status) { | 4276 if (read_status) { |
4746 delete[] buf; | 4277 delete[] buf; |
4747 return status; | 4278 return status; |
4748 } | 4279 } |
4749 | 4280 |
4750 encryption->signature = buf; | 4281 encryption->signature = buf; |
4751 encryption->signature_len = buflen; | 4282 encryption->signature_len = buflen; |
4752 } else if (id == 0x7E4) { | 4283 } else if (id == 0x7E4) { |
4753 // ContentSigKeyID | 4284 // ContentSigKeyID |
4754 delete[] encryption -> sig_key_id; | 4285 delete[] encryption->sig_key_id; |
4755 encryption->sig_key_id = NULL; | 4286 encryption->sig_key_id = NULL; |
4756 encryption->sig_key_id_len = 0; | 4287 encryption->sig_key_id_len = 0; |
4757 | 4288 |
4758 if (size <= 0) | 4289 if (size <= 0) |
4759 return E_FILE_FORMAT_INVALID; | 4290 return E_FILE_FORMAT_INVALID; |
4760 | 4291 |
4761 const size_t buflen = static_cast<size_t>(size); | 4292 const size_t buflen = static_cast<size_t>(size); |
4762 typedef unsigned char* buf_t; | 4293 typedef unsigned char* buf_t; |
4763 const buf_t buf = new (std::nothrow) unsigned char[buflen]; | 4294 const buf_t buf = new (std::nothrow) unsigned char[buflen]; |
4764 if (buf == NULL) | 4295 if (buf == NULL) |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4984 long Track::GetFirst(const BlockEntry*& pBlockEntry) const { | 4515 long Track::GetFirst(const BlockEntry*& pBlockEntry) const { |
4985 const Cluster* pCluster = m_pSegment->GetFirst(); | 4516 const Cluster* pCluster = m_pSegment->GetFirst(); |
4986 | 4517 |
4987 for (int i = 0;;) { | 4518 for (int i = 0;;) { |
4988 if (pCluster == NULL) { | 4519 if (pCluster == NULL) { |
4989 pBlockEntry = GetEOS(); | 4520 pBlockEntry = GetEOS(); |
4990 return 1; | 4521 return 1; |
4991 } | 4522 } |
4992 | 4523 |
4993 if (pCluster->EOS()) { | 4524 if (pCluster->EOS()) { |
4994 #if 0 | |
4995 if (m_pSegment->Unparsed() <= 0) { //all clusters have been loaded | |
4996 pBlockEntry = GetEOS(); | |
4997 return 1; | |
4998 } | |
4999 #else | |
5000 if (m_pSegment->DoneParsing()) { | 4525 if (m_pSegment->DoneParsing()) { |
5001 pBlockEntry = GetEOS(); | 4526 pBlockEntry = GetEOS(); |
5002 return 1; | 4527 return 1; |
5003 } | 4528 } |
5004 #endif | |
5005 | 4529 |
5006 pBlockEntry = 0; | 4530 pBlockEntry = 0; |
5007 return E_BUFFER_NOT_FULL; | 4531 return E_BUFFER_NOT_FULL; |
5008 } | 4532 } |
5009 | 4533 |
5010 long status = pCluster->GetFirst(pBlockEntry); | 4534 long status = pCluster->GetFirst(pBlockEntry); |
5011 | 4535 |
5012 if (status < 0) // error | 4536 if (status < 0) // error |
5013 return status; | 4537 return status; |
5014 | 4538 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5091 } | 4615 } |
5092 | 4616 |
5093 pCluster = m_pSegment->GetNext(pCluster); | 4617 pCluster = m_pSegment->GetNext(pCluster); |
5094 | 4618 |
5095 if (pCluster == NULL) { | 4619 if (pCluster == NULL) { |
5096 pNextEntry = GetEOS(); | 4620 pNextEntry = GetEOS(); |
5097 return 1; | 4621 return 1; |
5098 } | 4622 } |
5099 | 4623 |
5100 if (pCluster->EOS()) { | 4624 if (pCluster->EOS()) { |
5101 #if 0 | |
5102 if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded | |
5103 { | |
5104 pNextEntry = GetEOS(); | |
5105 return 1; | |
5106 } | |
5107 #else | |
5108 if (m_pSegment->DoneParsing()) { | 4625 if (m_pSegment->DoneParsing()) { |
5109 pNextEntry = GetEOS(); | 4626 pNextEntry = GetEOS(); |
5110 return 1; | 4627 return 1; |
5111 } | 4628 } |
5112 #endif | |
5113 | 4629 |
5114 // TODO: there is a potential O(n^2) problem here: we tell the | 4630 // TODO: there is a potential O(n^2) problem here: we tell the |
5115 // caller to (pre)load another cluster, which he does, but then he | 4631 // caller to (pre)load another cluster, which he does, but then he |
5116 // calls GetNext again, which repeats the same search. This is | 4632 // calls GetNext again, which repeats the same search. This is |
5117 // a pathological case, since the only way it can happen is if | 4633 // a pathological case, since the only way it can happen is if |
5118 // there exists a long sequence of clusters none of which contain a | 4634 // there exists a long sequence of clusters none of which contain a |
5119 // block from this track. One way around this problem is for the | 4635 // block from this track. One way around this problem is for the |
5120 // caller to be smarter when he loads another cluster: don't call | 4636 // caller to be smarter when he loads another cluster: don't call |
5121 // us back until you have a cluster that contains a block from this | 4637 // us back until you have a cluster that contains a block from this |
5122 // track. (Of course, that's not cheap either, since our caller | 4638 // track. (Of course, that's not cheap either, since our caller |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5284 if (id == 0x2240) // ContentEncoding ID | 4800 if (id == 0x2240) // ContentEncoding ID |
5285 ++count; | 4801 ++count; |
5286 | 4802 |
5287 pos += size; // consume payload | 4803 pos += size; // consume payload |
5288 assert(pos <= stop); | 4804 assert(pos <= stop); |
5289 } | 4805 } |
5290 | 4806 |
5291 if (count <= 0) | 4807 if (count <= 0) |
5292 return -1; | 4808 return -1; |
5293 | 4809 |
5294 content_encoding_entries_ = new (std::nothrow) ContentEncoding* [count]; | 4810 content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count]; |
5295 if (!content_encoding_entries_) | 4811 if (!content_encoding_entries_) |
5296 return -1; | 4812 return -1; |
5297 | 4813 |
5298 content_encoding_entries_end_ = content_encoding_entries_; | 4814 content_encoding_entries_end_ = content_encoding_entries_; |
5299 | 4815 |
5300 pos = start; | 4816 pos = start; |
5301 while (pos < stop) { | 4817 while (pos < stop) { |
5302 long long id, size; | 4818 long long id, size; |
5303 long status = ParseElementHeader(pReader, pos, stop, id, size); | 4819 long status = ParseElementHeader(pReader, pos, stop, id, size); |
5304 if (status < 0) // error | 4820 if (status < 0) // error |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5343 long long element_start, long long element_size, | 4859 long long element_start, long long element_size, |
5344 VideoTrack*& pResult) { | 4860 VideoTrack*& pResult) { |
5345 if (pResult) | 4861 if (pResult) |
5346 return -1; | 4862 return -1; |
5347 | 4863 |
5348 if (info.type != Track::kVideo) | 4864 if (info.type != Track::kVideo) |
5349 return -1; | 4865 return -1; |
5350 | 4866 |
5351 long long width = 0; | 4867 long long width = 0; |
5352 long long height = 0; | 4868 long long height = 0; |
| 4869 long long display_width = 0; |
| 4870 long long display_height = 0; |
| 4871 long long display_unit = 0; |
| 4872 long long stereo_mode = 0; |
| 4873 |
5353 double rate = 0.0; | 4874 double rate = 0.0; |
5354 | 4875 |
5355 IMkvReader* const pReader = pSegment->m_pReader; | 4876 IMkvReader* const pReader = pSegment->m_pReader; |
5356 | 4877 |
5357 const Settings& s = info.settings; | 4878 const Settings& s = info.settings; |
5358 assert(s.start >= 0); | 4879 assert(s.start >= 0); |
5359 assert(s.size >= 0); | 4880 assert(s.size >= 0); |
5360 | 4881 |
5361 long long pos = s.start; | 4882 long long pos = s.start; |
5362 assert(pos >= 0); | 4883 assert(pos >= 0); |
(...skipping 11 matching lines...) Expand all Loading... |
5374 if (id == 0x30) { // pixel width | 4895 if (id == 0x30) { // pixel width |
5375 width = UnserializeUInt(pReader, pos, size); | 4896 width = UnserializeUInt(pReader, pos, size); |
5376 | 4897 |
5377 if (width <= 0) | 4898 if (width <= 0) |
5378 return E_FILE_FORMAT_INVALID; | 4899 return E_FILE_FORMAT_INVALID; |
5379 } else if (id == 0x3A) { // pixel height | 4900 } else if (id == 0x3A) { // pixel height |
5380 height = UnserializeUInt(pReader, pos, size); | 4901 height = UnserializeUInt(pReader, pos, size); |
5381 | 4902 |
5382 if (height <= 0) | 4903 if (height <= 0) |
5383 return E_FILE_FORMAT_INVALID; | 4904 return E_FILE_FORMAT_INVALID; |
| 4905 } else if (id == 0x14B0) { // display width |
| 4906 display_width = UnserializeUInt(pReader, pos, size); |
| 4907 |
| 4908 if (display_width <= 0) |
| 4909 return E_FILE_FORMAT_INVALID; |
| 4910 } else if (id == 0x14BA) { // display height |
| 4911 display_height = UnserializeUInt(pReader, pos, size); |
| 4912 |
| 4913 if (display_height <= 0) |
| 4914 return E_FILE_FORMAT_INVALID; |
| 4915 } else if (id == 0x14B2) { // display unit |
| 4916 display_unit = UnserializeUInt(pReader, pos, size); |
| 4917 |
| 4918 if (display_unit < 0) |
| 4919 return E_FILE_FORMAT_INVALID; |
| 4920 } else if (id == 0x13B8) { // stereo mode |
| 4921 stereo_mode = UnserializeUInt(pReader, pos, size); |
| 4922 |
| 4923 if (stereo_mode < 0) |
| 4924 return E_FILE_FORMAT_INVALID; |
5384 } else if (id == 0x0383E3) { // frame rate | 4925 } else if (id == 0x0383E3) { // frame rate |
5385 const long status = UnserializeFloat(pReader, pos, size, rate); | 4926 const long status = UnserializeFloat(pReader, pos, size, rate); |
5386 | 4927 |
5387 if (status < 0) | 4928 if (status < 0) |
5388 return status; | 4929 return status; |
5389 | 4930 |
5390 if (rate <= 0) | 4931 if (rate <= 0) |
5391 return E_FILE_FORMAT_INVALID; | 4932 return E_FILE_FORMAT_INVALID; |
5392 } | 4933 } |
5393 | 4934 |
(...skipping 11 matching lines...) Expand all Loading... |
5405 | 4946 |
5406 const int status = info.Copy(pTrack->m_info); | 4947 const int status = info.Copy(pTrack->m_info); |
5407 | 4948 |
5408 if (status) { // error | 4949 if (status) { // error |
5409 delete pTrack; | 4950 delete pTrack; |
5410 return status; | 4951 return status; |
5411 } | 4952 } |
5412 | 4953 |
5413 pTrack->m_width = width; | 4954 pTrack->m_width = width; |
5414 pTrack->m_height = height; | 4955 pTrack->m_height = height; |
| 4956 pTrack->m_display_width = display_width; |
| 4957 pTrack->m_display_height = display_height; |
| 4958 pTrack->m_display_unit = display_unit; |
| 4959 pTrack->m_stereo_mode = stereo_mode; |
5415 pTrack->m_rate = rate; | 4960 pTrack->m_rate = rate; |
5416 | 4961 |
5417 pResult = pTrack; | 4962 pResult = pTrack; |
5418 return 0; // success | 4963 return 0; // success |
5419 } | 4964 } |
5420 | 4965 |
5421 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const { | 4966 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const { |
5422 return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey(); | 4967 return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey(); |
5423 } | 4968 } |
5424 | 4969 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5491 pResult = pCluster->GetEntry(this, time_ns); | 5036 pResult = pCluster->GetEntry(this, time_ns); |
5492 | 5037 |
5493 if ((pResult != 0) && !pResult->EOS()) // found a keyframe | 5038 if ((pResult != 0) && !pResult->EOS()) // found a keyframe |
5494 return 0; | 5039 return 0; |
5495 | 5040 |
5496 while (lo != i) { | 5041 while (lo != i) { |
5497 pCluster = *--lo; | 5042 pCluster = *--lo; |
5498 assert(pCluster); | 5043 assert(pCluster); |
5499 assert(pCluster->GetTime() <= time_ns); | 5044 assert(pCluster->GetTime() <= time_ns); |
5500 | 5045 |
5501 #if 0 | |
5502 //TODO: | |
5503 //We need to handle the case when a cluster | |
5504 //contains multiple keyframes. Simply returning | |
5505 //the largest keyframe on the cluster isn't | |
5506 //good enough. | |
5507 pResult = pCluster->GetMaxKey(this); | |
5508 #else | |
5509 pResult = pCluster->GetEntry(this, time_ns); | 5046 pResult = pCluster->GetEntry(this, time_ns); |
5510 #endif | |
5511 | 5047 |
5512 if ((pResult != 0) && !pResult->EOS()) | 5048 if ((pResult != 0) && !pResult->EOS()) |
5513 return 0; | 5049 return 0; |
5514 } | 5050 } |
5515 | 5051 |
5516 // weird: we're on the first cluster, but no keyframe found | 5052 // weird: we're on the first cluster, but no keyframe found |
5517 // should never happen but we must return something anyway | 5053 // should never happen but we must return something anyway |
5518 | 5054 |
5519 pResult = GetEOS(); | 5055 pResult = GetEOS(); |
5520 return 0; | 5056 return 0; |
5521 } | 5057 } |
5522 | 5058 |
5523 long long VideoTrack::GetWidth() const { return m_width; } | 5059 long long VideoTrack::GetWidth() const { return m_width; } |
5524 | 5060 |
5525 long long VideoTrack::GetHeight() const { return m_height; } | 5061 long long VideoTrack::GetHeight() const { return m_height; } |
5526 | 5062 |
| 5063 long long VideoTrack::GetDisplayWidth() const { |
| 5064 return m_display_width > 0 ? m_display_width : GetWidth(); |
| 5065 } |
| 5066 |
| 5067 long long VideoTrack::GetDisplayHeight() const { |
| 5068 return m_display_height > 0 ? m_display_height : GetHeight(); |
| 5069 } |
| 5070 |
| 5071 long long VideoTrack::GetDisplayUnit() const { return m_display_unit; } |
| 5072 |
| 5073 long long VideoTrack::GetStereoMode() const { return m_stereo_mode; } |
| 5074 |
5527 double VideoTrack::GetFrameRate() const { return m_rate; } | 5075 double VideoTrack::GetFrameRate() const { return m_rate; } |
5528 | 5076 |
5529 AudioTrack::AudioTrack(Segment* pSegment, long long element_start, | 5077 AudioTrack::AudioTrack(Segment* pSegment, long long element_start, |
5530 long long element_size) | 5078 long long element_size) |
5531 : Track(pSegment, element_start, element_size) {} | 5079 : Track(pSegment, element_start, element_size) {} |
5532 | 5080 |
5533 long AudioTrack::Parse(Segment* pSegment, const Info& info, | 5081 long AudioTrack::Parse(Segment* pSegment, const Info& info, |
5534 long long element_start, long long element_size, | 5082 long long element_start, long long element_size, |
5535 AudioTrack*& pResult) { | 5083 AudioTrack*& pResult) { |
5536 if (pResult) | 5084 if (pResult) |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5651 | 5199 |
5652 pos += size; // consume payload | 5200 pos += size; // consume payload |
5653 assert(pos <= stop); | 5201 assert(pos <= stop); |
5654 } | 5202 } |
5655 | 5203 |
5656 assert(pos == stop); | 5204 assert(pos == stop); |
5657 | 5205 |
5658 if (count <= 0) | 5206 if (count <= 0) |
5659 return 0; // success | 5207 return 0; // success |
5660 | 5208 |
5661 m_trackEntries = new (std::nothrow) Track* [count]; | 5209 m_trackEntries = new (std::nothrow) Track*[count]; |
5662 | 5210 |
5663 if (m_trackEntries == NULL) | 5211 if (m_trackEntries == NULL) |
5664 return -1; | 5212 return -1; |
5665 | 5213 |
5666 m_trackEntriesEnd = m_trackEntries; | 5214 m_trackEntriesEnd = m_trackEntries; |
5667 | 5215 |
5668 pos = m_start; | 5216 pos = m_start; |
5669 | 5217 |
5670 while (pos < stop) { | 5218 while (pos < stop) { |
5671 const long long element_start = pos; | 5219 const long long element_start = pos; |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5934 pResult->ParseContentEncodingsEntry(e.start, e.size); | 5482 pResult->ParseContentEncodingsEntry(e.start, e.size); |
5935 } else { | 5483 } else { |
5936 // neither video nor audio - probably metadata or subtitles | 5484 // neither video nor audio - probably metadata or subtitles |
5937 | 5485 |
5938 if (a.start >= 0) | 5486 if (a.start >= 0) |
5939 return E_FILE_FORMAT_INVALID; | 5487 return E_FILE_FORMAT_INVALID; |
5940 | 5488 |
5941 if (v.start >= 0) | 5489 if (v.start >= 0) |
5942 return E_FILE_FORMAT_INVALID; | 5490 return E_FILE_FORMAT_INVALID; |
5943 | 5491 |
5944 if (e.start >= 0) | 5492 if (info.type == Track::kMetadata && e.start >= 0) |
5945 return E_FILE_FORMAT_INVALID; | 5493 return E_FILE_FORMAT_INVALID; |
5946 | 5494 |
5947 info.settings.start = -1; | 5495 info.settings.start = -1; |
5948 info.settings.size = 0; | 5496 info.settings.size = 0; |
5949 | 5497 |
5950 Track* pTrack = NULL; | 5498 Track* pTrack = NULL; |
5951 | 5499 |
5952 const long status = | 5500 const long status = |
5953 Track::Create(m_pSegment, info, element_start, element_size, pTrack); | 5501 Track::Create(m_pSegment, info, element_start, element_size, pTrack); |
5954 | 5502 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5996 | 5544 |
5997 const Track* Tracks::GetTrackByIndex(unsigned long idx) const { | 5545 const Track* Tracks::GetTrackByIndex(unsigned long idx) const { |
5998 const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries; | 5546 const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries; |
5999 | 5547 |
6000 if (idx >= static_cast<unsigned long>(count)) | 5548 if (idx >= static_cast<unsigned long>(count)) |
6001 return NULL; | 5549 return NULL; |
6002 | 5550 |
6003 return m_trackEntries[idx]; | 5551 return m_trackEntries[idx]; |
6004 } | 5552 } |
6005 | 5553 |
6006 #if 0 | |
6007 long long Cluster::Unparsed() const | |
6008 { | |
6009 if (m_timecode < 0) //not even partially loaded | |
6010 return LLONG_MAX; | |
6011 | |
6012 assert(m_pos >= m_element_start); | |
6013 //assert(m_element_size > m_size); | |
6014 | |
6015 const long long element_stop = m_element_start + m_element_size; | |
6016 assert(m_pos <= element_stop); | |
6017 | |
6018 const long long result = element_stop - m_pos; | |
6019 assert(result >= 0); | |
6020 | |
6021 return result; | |
6022 } | |
6023 #endif | |
6024 | |
6025 long Cluster::Load(long long& pos, long& len) const { | 5554 long Cluster::Load(long long& pos, long& len) const { |
6026 assert(m_pSegment); | 5555 assert(m_pSegment); |
6027 assert(m_pos >= m_element_start); | 5556 assert(m_pos >= m_element_start); |
6028 | 5557 |
6029 if (m_timecode >= 0) // at least partially loaded | 5558 if (m_timecode >= 0) // at least partially loaded |
6030 return 0; | 5559 return 0; |
6031 | 5560 |
6032 assert(m_pos == m_element_start); | 5561 assert(m_pos == m_element_start); |
6033 assert(m_element_size < 0); | 5562 assert(m_element_size < 0); |
6034 | 5563 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6108 return E_FILE_FORMAT_INVALID; // TODO: verify this | 5637 return E_FILE_FORMAT_INVALID; // TODO: verify this |
6109 | 5638 |
6110 pos += len; // consume length of size of element | 5639 pos += len; // consume length of size of element |
6111 | 5640 |
6112 const long long unknown_size = (1LL << (7 * len)) - 1; | 5641 const long long unknown_size = (1LL << (7 * len)) - 1; |
6113 | 5642 |
6114 if (size != unknown_size) | 5643 if (size != unknown_size) |
6115 cluster_size = size; | 5644 cluster_size = size; |
6116 } | 5645 } |
6117 | 5646 |
6118 // pos points to start of payload | 5647 // pos points to start of payload |
6119 | |
6120 #if 0 | |
6121 len = static_cast<long>(size_); | |
6122 | |
6123 if (cluster_stop > avail) | |
6124 return E_BUFFER_NOT_FULL; | |
6125 #endif | |
6126 | |
6127 long long timecode = -1; | 5648 long long timecode = -1; |
6128 long long new_pos = -1; | 5649 long long new_pos = -1; |
6129 bool bBlock = false; | 5650 bool bBlock = false; |
6130 | 5651 |
6131 long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size; | 5652 long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size; |
6132 | 5653 |
6133 for (;;) { | 5654 for (;;) { |
6134 if ((cluster_stop >= 0) && (pos >= cluster_stop)) | 5655 if ((cluster_stop >= 0) && (pos >= cluster_stop)) |
6135 break; | 5656 break; |
6136 | 5657 |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6488 return E_BUFFER_NOT_FULL; | 6009 return E_BUFFER_NOT_FULL; |
6489 | 6010 |
6490 const long long track = ReadUInt(pReader, pos, len); | 6011 const long long track = ReadUInt(pReader, pos, len); |
6491 | 6012 |
6492 if (track < 0) // error | 6013 if (track < 0) // error |
6493 return static_cast<long>(track); | 6014 return static_cast<long>(track); |
6494 | 6015 |
6495 if (track == 0) | 6016 if (track == 0) |
6496 return E_FILE_FORMAT_INVALID; | 6017 return E_FILE_FORMAT_INVALID; |
6497 | 6018 |
6498 #if 0 | |
6499 //TODO(matthewjheaney) | |
6500 //This turned out to be too conservative. The problem is that | |
6501 //if we see a track header in the tracks element with an unsupported | |
6502 //track type, we throw that track header away, so it is not present | |
6503 //in the track map. But even though we don't understand the track | |
6504 //header, there are still blocks in the cluster with that track | |
6505 //number. It was our decision to ignore that track header, so it's | |
6506 //up to us to deal with blocks associated with that track -- we | |
6507 //cannot simply report an error since technically there's nothing | |
6508 //wrong with the file. | |
6509 // | |
6510 //For now we go ahead and finish the parse, creating a block entry | |
6511 //for this block. This is somewhat wasteful, because without a | |
6512 //track header there's nothing you can do with the block. What | |
6513 //we really need here is a special return value that indicates to | |
6514 //the caller that he should ignore this particular block, and | |
6515 //continue parsing. | |
6516 | |
6517 const Tracks* const pTracks = m_pSegment->GetTracks(); | |
6518 assert(pTracks); | |
6519 | |
6520 const long tn = static_cast<long>(track); | |
6521 | |
6522 const Track* const pTrack = pTracks->GetTrackByNumber(tn); | |
6523 | |
6524 if (pTrack == NULL) | |
6525 return E_FILE_FORMAT_INVALID; | |
6526 #endif | |
6527 | |
6528 pos += len; // consume track number | 6019 pos += len; // consume track number |
6529 | 6020 |
6530 if ((pos + 2) > block_stop) | 6021 if ((pos + 2) > block_stop) |
6531 return E_FILE_FORMAT_INVALID; | 6022 return E_FILE_FORMAT_INVALID; |
6532 | 6023 |
6533 if ((pos + 2) > avail) { | 6024 if ((pos + 2) > avail) { |
6534 len = 2; | 6025 len = 2; |
6535 return E_BUFFER_NOT_FULL; | 6026 return E_BUFFER_NOT_FULL; |
6536 } | 6027 } |
6537 | 6028 |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6672 | 6163 |
6673 if (size == 0) // weird | 6164 if (size == 0) // weird |
6674 continue; | 6165 continue; |
6675 | 6166 |
6676 const long long unknown_size = (1LL << (7 * len)) - 1; | 6167 const long long unknown_size = (1LL << (7 * len)) - 1; |
6677 | 6168 |
6678 if (size == unknown_size) | 6169 if (size == unknown_size) |
6679 return E_FILE_FORMAT_INVALID; | 6170 return E_FILE_FORMAT_INVALID; |
6680 | 6171 |
6681 if (id == 0x35A2) { // DiscardPadding | 6172 if (id == 0x35A2) { // DiscardPadding |
6682 result = GetUIntLength(pReader, pos, len); | 6173 status = UnserializeInt(pReader, pos, size, discard_padding); |
6683 | |
6684 if (result < 0) // error | |
6685 return static_cast<long>(result); | |
6686 | |
6687 status = UnserializeInt(pReader, pos, len, discard_padding); | |
6688 | 6174 |
6689 if (status < 0) // error | 6175 if (status < 0) // error |
6690 return status; | 6176 return status; |
6691 } | 6177 } |
6692 | 6178 |
6693 if (id != 0x21) { // sub-part of BlockGroup is not a Block | 6179 if (id != 0x21) { // sub-part of BlockGroup is not a Block |
6694 pos += size; // consume sub-part of block group | 6180 pos += size; // consume sub-part of block group |
6695 | 6181 |
6696 if (pos > payload_stop) | 6182 if (pos > payload_stop) |
6697 return E_FILE_FORMAT_INVALID; | 6183 return E_FILE_FORMAT_INVALID; |
(...skipping 28 matching lines...) Expand all Loading... |
6726 return E_BUFFER_NOT_FULL; | 6212 return E_BUFFER_NOT_FULL; |
6727 | 6213 |
6728 const long long track = ReadUInt(pReader, pos, len); | 6214 const long long track = ReadUInt(pReader, pos, len); |
6729 | 6215 |
6730 if (track < 0) // error | 6216 if (track < 0) // error |
6731 return static_cast<long>(track); | 6217 return static_cast<long>(track); |
6732 | 6218 |
6733 if (track == 0) | 6219 if (track == 0) |
6734 return E_FILE_FORMAT_INVALID; | 6220 return E_FILE_FORMAT_INVALID; |
6735 | 6221 |
6736 #if 0 | |
6737 //TODO(matthewjheaney) | |
6738 //This turned out to be too conservative. The problem is that | |
6739 //if we see a track header in the tracks element with an unsupported | |
6740 //track type, we throw that track header away, so it is not present | |
6741 //in the track map. But even though we don't understand the track | |
6742 //header, there are still blocks in the cluster with that track | |
6743 //number. It was our decision to ignore that track header, so it's | |
6744 //up to us to deal with blocks associated with that track -- we | |
6745 //cannot simply report an error since technically there's nothing | |
6746 //wrong with the file. | |
6747 // | |
6748 //For now we go ahead and finish the parse, creating a block entry | |
6749 //for this block. This is somewhat wasteful, because without a | |
6750 //track header there's nothing you can do with the block. What | |
6751 //we really need here is a special return value that indicates to | |
6752 //the caller that he should ignore this particular block, and | |
6753 //continue parsing. | |
6754 | |
6755 const Tracks* const pTracks = m_pSegment->GetTracks(); | |
6756 assert(pTracks); | |
6757 | |
6758 const long tn = static_cast<long>(track); | |
6759 | |
6760 const Track* const pTrack = pTracks->GetTrackByNumber(tn); | |
6761 | |
6762 if (pTrack == NULL) | |
6763 return E_FILE_FORMAT_INVALID; | |
6764 #endif | |
6765 | |
6766 pos += len; // consume track number | 6222 pos += len; // consume track number |
6767 | 6223 |
6768 if ((pos + 2) > block_stop) | 6224 if ((pos + 2) > block_stop) |
6769 return E_FILE_FORMAT_INVALID; | 6225 return E_FILE_FORMAT_INVALID; |
6770 | 6226 |
6771 if ((pos + 2) > avail) { | 6227 if ((pos + 2) > avail) { |
6772 len = 2; | 6228 len = 2; |
6773 return E_BUFFER_NOT_FULL; | 6229 return E_BUFFER_NOT_FULL; |
6774 } | 6230 } |
6775 | 6231 |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6917 | 6373 |
6918 long long Cluster::GetPosition() const { | 6374 long long Cluster::GetPosition() const { |
6919 const long long pos = m_element_start - m_pSegment->m_start; | 6375 const long long pos = m_element_start - m_pSegment->m_start; |
6920 assert(pos >= 0); | 6376 assert(pos >= 0); |
6921 | 6377 |
6922 return pos; | 6378 return pos; |
6923 } | 6379 } |
6924 | 6380 |
6925 long long Cluster::GetElementSize() const { return m_element_size; } | 6381 long long Cluster::GetElementSize() const { return m_element_size; } |
6926 | 6382 |
6927 #if 0 | |
6928 bool Cluster::HasBlockEntries( | |
6929 const Segment* pSegment, | |
6930 long long off) { | |
6931 assert(pSegment); | |
6932 assert(off >= 0); //relative to start of segment payload | |
6933 | |
6934 IMkvReader* const pReader = pSegment->m_pReader; | |
6935 | |
6936 long long pos = pSegment->m_start + off; //absolute | |
6937 long long size; | |
6938 | |
6939 { | |
6940 long len; | |
6941 | |
6942 const long long id = ReadUInt(pReader, pos, len); | |
6943 (void)id; | |
6944 assert(id >= 0); | |
6945 assert(id == 0x0F43B675); //Cluster ID | |
6946 | |
6947 pos += len; //consume id | |
6948 | |
6949 size = ReadUInt(pReader, pos, len); | |
6950 assert(size > 0); | |
6951 | |
6952 pos += len; //consume size | |
6953 | |
6954 //pos now points to start of payload | |
6955 } | |
6956 | |
6957 const long long stop = pos + size; | |
6958 | |
6959 while (pos < stop) | |
6960 { | |
6961 long len; | |
6962 | |
6963 const long long id = ReadUInt(pReader, pos, len); | |
6964 assert(id >= 0); //TODO | |
6965 assert((pos + len) <= stop); | |
6966 | |
6967 pos += len; //consume id | |
6968 | |
6969 const long long size = ReadUInt(pReader, pos, len); | |
6970 assert(size >= 0); //TODO | |
6971 assert((pos + len) <= stop); | |
6972 | |
6973 pos += len; //consume size | |
6974 | |
6975 if (id == 0x20) //BlockGroup ID | |
6976 return true; | |
6977 | |
6978 if (id == 0x23) //SimpleBlock ID | |
6979 return true; | |
6980 | |
6981 pos += size; //consume payload | |
6982 assert(pos <= stop); | |
6983 } | |
6984 | |
6985 return false; | |
6986 } | |
6987 #endif | |
6988 | |
6989 long Cluster::HasBlockEntries( | 6383 long Cluster::HasBlockEntries( |
6990 const Segment* pSegment, | 6384 const Segment* pSegment, |
6991 long long off, // relative to start of segment payload | 6385 long long off, // relative to start of segment payload |
6992 long long& pos, long& len) { | 6386 long long& pos, long& len) { |
6993 assert(pSegment); | 6387 assert(pSegment); |
6994 assert(off >= 0); // relative to segment | 6388 assert(off >= 0); // relative to segment |
6995 | 6389 |
6996 IMkvReader* const pReader = pSegment->m_pReader; | 6390 IMkvReader* const pReader = pSegment->m_pReader; |
6997 | 6391 |
6998 long long total, avail; | 6392 long long total, avail; |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7262 long Cluster::CreateBlock(long long id, | 6656 long Cluster::CreateBlock(long long id, |
7263 long long pos, // absolute pos of payload | 6657 long long pos, // absolute pos of payload |
7264 long long size, long long discard_padding) { | 6658 long long size, long long discard_padding) { |
7265 assert((id == 0x20) || (id == 0x23)); // BlockGroup or SimpleBlock | 6659 assert((id == 0x20) || (id == 0x23)); // BlockGroup or SimpleBlock |
7266 | 6660 |
7267 if (m_entries_count < 0) { // haven't parsed anything yet | 6661 if (m_entries_count < 0) { // haven't parsed anything yet |
7268 assert(m_entries == NULL); | 6662 assert(m_entries == NULL); |
7269 assert(m_entries_size == 0); | 6663 assert(m_entries_size == 0); |
7270 | 6664 |
7271 m_entries_size = 1024; | 6665 m_entries_size = 1024; |
7272 m_entries = new BlockEntry* [m_entries_size]; | 6666 m_entries = new BlockEntry*[m_entries_size]; |
7273 | 6667 |
7274 m_entries_count = 0; | 6668 m_entries_count = 0; |
7275 } else { | 6669 } else { |
7276 assert(m_entries); | 6670 assert(m_entries); |
7277 assert(m_entries_size > 0); | 6671 assert(m_entries_size > 0); |
7278 assert(m_entries_count <= m_entries_size); | 6672 assert(m_entries_count <= m_entries_size); |
7279 | 6673 |
7280 if (m_entries_count >= m_entries_size) { | 6674 if (m_entries_count >= m_entries_size) { |
7281 const long entries_size = 2 * m_entries_size; | 6675 const long entries_size = 2 * m_entries_size; |
7282 | 6676 |
7283 BlockEntry** const entries = new BlockEntry* [entries_size]; | 6677 BlockEntry** const entries = new BlockEntry*[entries_size]; |
7284 assert(entries); | 6678 assert(entries); |
7285 | 6679 |
7286 BlockEntry** src = m_entries; | 6680 BlockEntry** src = m_entries; |
7287 BlockEntry** const src_end = src + m_entries_count; | 6681 BlockEntry** const src_end = src + m_entries_count; |
7288 | 6682 |
7289 BlockEntry** dst = entries; | 6683 BlockEntry** dst = entries; |
7290 | 6684 |
7291 while (src != src_end) | 6685 while (src != src_end) |
7292 *dst++ = *src++; | 6686 *dst++ = *src++; |
7293 | 6687 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7342 assert((pos + len) <= stop); | 6736 assert((pos + len) <= stop); |
7343 | 6737 |
7344 pos += len; // consume size | 6738 pos += len; // consume size |
7345 | 6739 |
7346 if (id == 0x21) { // Block ID | 6740 if (id == 0x21) { // Block ID |
7347 if (bpos < 0) { // Block ID | 6741 if (bpos < 0) { // Block ID |
7348 bpos = pos; | 6742 bpos = pos; |
7349 bsize = size; | 6743 bsize = size; |
7350 } | 6744 } |
7351 } else if (id == 0x1B) { // Duration ID | 6745 } else if (id == 0x1B) { // Duration ID |
7352 assert(size <= 8); | 6746 if (size > 8) |
| 6747 return E_FILE_FORMAT_INVALID; |
7353 | 6748 |
7354 duration = UnserializeUInt(pReader, pos, size); | 6749 duration = UnserializeUInt(pReader, pos, size); |
7355 assert(duration >= 0); // TODO | 6750 |
| 6751 if (duration < 0) |
| 6752 return E_FILE_FORMAT_INVALID; |
7356 } else if (id == 0x7B) { // ReferenceBlock | 6753 } else if (id == 0x7B) { // ReferenceBlock |
7357 assert(size <= 8); | 6754 if (size > 8 || size <= 0) |
| 6755 return E_FILE_FORMAT_INVALID; |
7358 const long size_ = static_cast<long>(size); | 6756 const long size_ = static_cast<long>(size); |
7359 | 6757 |
7360 long long time; | 6758 long long time; |
7361 | 6759 |
7362 long status = UnserializeInt(pReader, pos, size_, time); | 6760 long status = UnserializeInt(pReader, pos, size_, time); |
7363 assert(status == 0); | 6761 assert(status == 0); |
7364 if (status != 0) | 6762 if (status != 0) |
7365 return -1; | 6763 return -1; |
7366 | 6764 |
7367 if (time <= 0) // see note above | 6765 if (time <= 0) // see note above |
7368 prev = time; | 6766 prev = time; |
7369 else // weird | 6767 else // weird |
7370 next = time; | 6768 next = time; |
7371 } | 6769 } |
7372 | 6770 |
7373 pos += size; // consume payload | 6771 pos += size; // consume payload |
7374 assert(pos <= stop); | 6772 assert(pos <= stop); |
7375 } | 6773 } |
| 6774 if (bpos < 0) |
| 6775 return E_FILE_FORMAT_INVALID; |
7376 | 6776 |
7377 assert(pos == stop); | 6777 assert(pos == stop); |
7378 assert(bpos >= 0); | |
7379 assert(bsize >= 0); | 6778 assert(bsize >= 0); |
7380 | 6779 |
7381 const long idx = m_entries_count; | 6780 const long idx = m_entries_count; |
7382 | 6781 |
7383 BlockEntry** const ppEntry = m_entries + idx; | 6782 BlockEntry** const ppEntry = m_entries + idx; |
7384 BlockEntry*& pEntry = *ppEntry; | 6783 BlockEntry*& pEntry = *ppEntry; |
7385 | 6784 |
7386 pEntry = new (std::nothrow) | 6785 pEntry = new (std::nothrow) |
7387 BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding); | 6786 BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding); |
7388 | 6787 |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7532 | 6931 |
7533 long Cluster::GetEntryCount() const { return m_entries_count; } | 6932 long Cluster::GetEntryCount() const { return m_entries_count; } |
7534 | 6933 |
7535 const BlockEntry* Cluster::GetEntry(const Track* pTrack, | 6934 const BlockEntry* Cluster::GetEntry(const Track* pTrack, |
7536 long long time_ns) const { | 6935 long long time_ns) const { |
7537 assert(pTrack); | 6936 assert(pTrack); |
7538 | 6937 |
7539 if (m_pSegment == NULL) // this is the special EOS cluster | 6938 if (m_pSegment == NULL) // this is the special EOS cluster |
7540 return pTrack->GetEOS(); | 6939 return pTrack->GetEOS(); |
7541 | 6940 |
7542 #if 0 | |
7543 | |
7544 LoadBlockEntries(); | |
7545 | |
7546 if ((m_entries == NULL) || (m_entries_count <= 0)) | |
7547 return NULL; //return EOS here? | |
7548 | |
7549 const BlockEntry* pResult = pTrack->GetEOS(); | |
7550 | |
7551 BlockEntry** i = m_entries; | |
7552 assert(i); | |
7553 | |
7554 BlockEntry** const j = i + m_entries_count; | |
7555 | |
7556 while (i != j) | |
7557 { | |
7558 const BlockEntry* const pEntry = *i++; | |
7559 assert(pEntry); | |
7560 assert(!pEntry->EOS()); | |
7561 | |
7562 const Block* const pBlock = pEntry->GetBlock(); | |
7563 assert(pBlock); | |
7564 | |
7565 if (pBlock->GetTrackNumber() != pTrack->GetNumber()) | |
7566 continue; | |
7567 | |
7568 if (pTrack->VetEntry(pEntry)) | |
7569 { | |
7570 if (time_ns < 0) //just want first candidate block | |
7571 return pEntry; | |
7572 | |
7573 const long long ns = pBlock->GetTime(this); | |
7574 | |
7575 if (ns > time_ns) | |
7576 break; | |
7577 | |
7578 pResult = pEntry; | |
7579 } | |
7580 else if (time_ns >= 0) | |
7581 { | |
7582 const long long ns = pBlock->GetTime(this); | |
7583 | |
7584 if (ns > time_ns) | |
7585 break; | |
7586 } | |
7587 } | |
7588 | |
7589 return pResult; | |
7590 | |
7591 #else | |
7592 | |
7593 const BlockEntry* pResult = pTrack->GetEOS(); | 6941 const BlockEntry* pResult = pTrack->GetEOS(); |
7594 | 6942 |
7595 long index = 0; | 6943 long index = 0; |
7596 | 6944 |
7597 for (;;) { | 6945 for (;;) { |
7598 if (index >= m_entries_count) { | 6946 if (index >= m_entries_count) { |
7599 long long pos; | 6947 long long pos; |
7600 long len; | 6948 long len; |
7601 | 6949 |
7602 const long status = Parse(pos, len); | 6950 const long status = Parse(pos, len); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7636 pResult = pEntry; // have a candidate | 6984 pResult = pEntry; // have a candidate |
7637 } else if (time_ns >= 0) { | 6985 } else if (time_ns >= 0) { |
7638 const long long ns = pBlock->GetTime(this); | 6986 const long long ns = pBlock->GetTime(this); |
7639 | 6987 |
7640 if (ns > time_ns) | 6988 if (ns > time_ns) |
7641 return pResult; | 6989 return pResult; |
7642 } | 6990 } |
7643 | 6991 |
7644 ++index; | 6992 ++index; |
7645 } | 6993 } |
7646 | |
7647 #endif | |
7648 } | 6994 } |
7649 | 6995 |
7650 const BlockEntry* Cluster::GetEntry(const CuePoint& cp, | 6996 const BlockEntry* Cluster::GetEntry(const CuePoint& cp, |
7651 const CuePoint::TrackPosition& tp) const { | 6997 const CuePoint::TrackPosition& tp) const { |
7652 assert(m_pSegment); | 6998 assert(m_pSegment); |
7653 | |
7654 #if 0 | |
7655 | |
7656 LoadBlockEntries(); | |
7657 | |
7658 if (m_entries == NULL) | |
7659 return NULL; | |
7660 | |
7661 const long long count = m_entries_count; | |
7662 | |
7663 if (count <= 0) | |
7664 return NULL; | |
7665 | |
7666 const long long tc = cp.GetTimeCode(); | |
7667 | |
7668 if ((tp.m_block > 0) && (tp.m_block <= count)) | |
7669 { | |
7670 const size_t block = static_cast<size_t>(tp.m_block); | |
7671 const size_t index = block - 1; | |
7672 | |
7673 const BlockEntry* const pEntry = m_entries[index]; | |
7674 assert(pEntry); | |
7675 assert(!pEntry->EOS()); | |
7676 | |
7677 const Block* const pBlock = pEntry->GetBlock(); | |
7678 assert(pBlock); | |
7679 | |
7680 if ((pBlock->GetTrackNumber() == tp.m_track) && | |
7681 (pBlock->GetTimeCode(this) == tc)) | |
7682 { | |
7683 return pEntry; | |
7684 } | |
7685 } | |
7686 | |
7687 const BlockEntry* const* i = m_entries; | |
7688 const BlockEntry* const* const j = i + count; | |
7689 | |
7690 while (i != j) | |
7691 { | |
7692 #ifdef _DEBUG | |
7693 const ptrdiff_t idx = i - m_entries; | |
7694 idx; | |
7695 #endif | |
7696 | |
7697 const BlockEntry* const pEntry = *i++; | |
7698 assert(pEntry); | |
7699 assert(!pEntry->EOS()); | |
7700 | |
7701 const Block* const pBlock = pEntry->GetBlock(); | |
7702 assert(pBlock); | |
7703 | |
7704 if (pBlock->GetTrackNumber() != tp.m_track) | |
7705 continue; | |
7706 | |
7707 const long long tc_ = pBlock->GetTimeCode(this); | |
7708 assert(tc_ >= 0); | |
7709 | |
7710 if (tc_ < tc) | |
7711 continue; | |
7712 | |
7713 if (tc_ > tc) | |
7714 return NULL; | |
7715 | |
7716 const Tracks* const pTracks = m_pSegment->GetTracks(); | |
7717 assert(pTracks); | |
7718 | |
7719 const long tn = static_cast<long>(tp.m_track); | |
7720 const Track* const pTrack = pTracks->GetTrackByNumber(tn); | |
7721 | |
7722 if (pTrack == NULL) | |
7723 return NULL; | |
7724 | |
7725 const long long type = pTrack->GetType(); | |
7726 | |
7727 if (type == 2) //audio | |
7728 return pEntry; | |
7729 | |
7730 if (type != 1) //not video | |
7731 return NULL; | |
7732 | |
7733 if (!pBlock->IsKey()) | |
7734 return NULL; | |
7735 | |
7736 return pEntry; | |
7737 } | |
7738 | |
7739 return NULL; | |
7740 | |
7741 #else | |
7742 | |
7743 const long long tc = cp.GetTimeCode(); | 6999 const long long tc = cp.GetTimeCode(); |
7744 | 7000 |
7745 if (tp.m_block > 0) { | 7001 if (tp.m_block > 0) { |
7746 const long block = static_cast<long>(tp.m_block); | 7002 const long block = static_cast<long>(tp.m_block); |
7747 const long index = block - 1; | 7003 const long index = block - 1; |
7748 | 7004 |
7749 while (index >= m_entries_count) { | 7005 while (index >= m_entries_count) { |
7750 long long pos; | 7006 long long pos; |
7751 long len; | 7007 long len; |
7752 | 7008 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7828 return pEntry; | 7084 return pEntry; |
7829 | 7085 |
7830 if (type != 1) // not video | 7086 if (type != 1) // not video |
7831 return NULL; | 7087 return NULL; |
7832 | 7088 |
7833 if (!pBlock->IsKey()) | 7089 if (!pBlock->IsKey()) |
7834 return NULL; | 7090 return NULL; |
7835 | 7091 |
7836 return pEntry; | 7092 return pEntry; |
7837 } | 7093 } |
7838 | |
7839 #endif | |
7840 } | 7094 } |
7841 | 7095 |
7842 #if 0 | |
7843 const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack) const | |
7844 { | |
7845 assert(pTrack); | |
7846 | |
7847 if (m_pSegment == NULL) //EOS | |
7848 return pTrack->GetEOS(); | |
7849 | |
7850 LoadBlockEntries(); | |
7851 | |
7852 if ((m_entries == NULL) || (m_entries_count <= 0)) | |
7853 return pTrack->GetEOS(); | |
7854 | |
7855 BlockEntry** i = m_entries + m_entries_count; | |
7856 BlockEntry** const j = m_entries; | |
7857 | |
7858 while (i != j) | |
7859 { | |
7860 const BlockEntry* const pEntry = *--i; | |
7861 assert(pEntry); | |
7862 assert(!pEntry->EOS()); | |
7863 | |
7864 const Block* const pBlock = pEntry->GetBlock(); | |
7865 assert(pBlock); | |
7866 | |
7867 if (pBlock->GetTrackNumber() != pTrack->GetNumber()) | |
7868 continue; | |
7869 | |
7870 if (pBlock->IsKey()) | |
7871 return pEntry; | |
7872 } | |
7873 | |
7874 return pTrack->GetEOS(); //no satisfactory block found | |
7875 } | |
7876 #endif | |
7877 | |
7878 BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {} | 7096 BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {} |
7879 | |
7880 BlockEntry::~BlockEntry() {} | 7097 BlockEntry::~BlockEntry() {} |
7881 | |
7882 bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); } | 7098 bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); } |
7883 | |
7884 const Cluster* BlockEntry::GetCluster() const { return m_pCluster; } | 7099 const Cluster* BlockEntry::GetCluster() const { return m_pCluster; } |
7885 | |
7886 long BlockEntry::GetIndex() const { return m_index; } | 7100 long BlockEntry::GetIndex() const { return m_index; } |
7887 | 7101 |
7888 SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start, | 7102 SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start, |
7889 long long size) | 7103 long long size) |
7890 : BlockEntry(pCluster, idx), m_block(start, size, 0) {} | 7104 : BlockEntry(pCluster, idx), m_block(start, size, 0) {} |
7891 | 7105 |
7892 long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); } | 7106 long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); } |
7893 | |
7894 BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; } | 7107 BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; } |
7895 | |
7896 const Block* SimpleBlock::GetBlock() const { return &m_block; } | 7108 const Block* SimpleBlock::GetBlock() const { return &m_block; } |
7897 | 7109 |
7898 BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start, | 7110 BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start, |
7899 long long block_size, long long prev, long long next, | 7111 long long block_size, long long prev, long long next, |
7900 long long duration, long long discard_padding) | 7112 long long duration, long long discard_padding) |
7901 : BlockEntry(pCluster, idx), | 7113 : BlockEntry(pCluster, idx), |
7902 m_block(block_start, block_size, discard_padding), | 7114 m_block(block_start, block_size, discard_padding), |
7903 m_prev(prev), | 7115 m_prev(prev), |
7904 m_next(next), | 7116 m_next(next), |
7905 m_duration(duration) {} | 7117 m_duration(duration) {} |
7906 | 7118 |
7907 long BlockGroup::Parse() { | 7119 long BlockGroup::Parse() { |
7908 const long status = m_block.Parse(m_pCluster); | 7120 const long status = m_block.Parse(m_pCluster); |
7909 | 7121 |
7910 if (status) | 7122 if (status) |
7911 return status; | 7123 return status; |
7912 | 7124 |
7913 m_block.SetKey((m_prev > 0) && (m_next <= 0)); | 7125 m_block.SetKey((m_prev > 0) && (m_next <= 0)); |
7914 | 7126 |
7915 return 0; | 7127 return 0; |
7916 } | 7128 } |
7917 | 7129 |
7918 #if 0 | |
7919 void BlockGroup::ParseBlock(long long start, long long size) | |
7920 { | |
7921 IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader; | |
7922 | |
7923 Block* const pBlock = new Block(start, size, pReader); | |
7924 assert(pBlock); //TODO | |
7925 | |
7926 //TODO: the Matroska spec says you have multiple blocks within the | |
7927 //same block group, with blocks ranked by priority (the flag bits). | |
7928 | |
7929 assert(m_pBlock == NULL); | |
7930 m_pBlock = pBlock; | |
7931 } | |
7932 #endif | |
7933 | |
7934 BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; } | 7130 BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; } |
7935 | |
7936 const Block* BlockGroup::GetBlock() const { return &m_block; } | 7131 const Block* BlockGroup::GetBlock() const { return &m_block; } |
7937 | |
7938 long long BlockGroup::GetPrevTimeCode() const { return m_prev; } | 7132 long long BlockGroup::GetPrevTimeCode() const { return m_prev; } |
7939 | |
7940 long long BlockGroup::GetNextTimeCode() const { return m_next; } | 7133 long long BlockGroup::GetNextTimeCode() const { return m_next; } |
7941 | |
7942 long long BlockGroup::GetDurationTimeCode() const { return m_duration; } | 7134 long long BlockGroup::GetDurationTimeCode() const { return m_duration; } |
7943 | 7135 |
7944 Block::Block(long long start, long long size_, long long discard_padding) | 7136 Block::Block(long long start, long long size_, long long discard_padding) |
7945 : m_start(start), | 7137 : m_start(start), |
7946 m_size(size_), | 7138 m_size(size_), |
7947 m_track(0), | 7139 m_track(0), |
7948 m_timecode(-1), | 7140 m_timecode(-1), |
7949 m_flags(0), | 7141 m_flags(0), |
7950 m_frames(NULL), | 7142 m_frames(NULL), |
7951 m_frame_count(-1), | 7143 m_frame_count(-1), |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8021 return E_FILE_FORMAT_INVALID; | 7213 return E_FILE_FORMAT_INVALID; |
8022 | 7214 |
8023 m_frame_count = 1; | 7215 m_frame_count = 1; |
8024 m_frames = new Frame[m_frame_count]; | 7216 m_frames = new Frame[m_frame_count]; |
8025 | 7217 |
8026 Frame& f = m_frames[0]; | 7218 Frame& f = m_frames[0]; |
8027 f.pos = pos; | 7219 f.pos = pos; |
8028 | 7220 |
8029 const long long frame_size = stop - pos; | 7221 const long long frame_size = stop - pos; |
8030 | 7222 |
8031 if (frame_size > LONG_MAX) | 7223 if (frame_size > LONG_MAX || frame_size <= 0) |
8032 return E_FILE_FORMAT_INVALID; | 7224 return E_FILE_FORMAT_INVALID; |
8033 | 7225 |
8034 f.len = static_cast<long>(frame_size); | 7226 f.len = static_cast<long>(frame_size); |
8035 | 7227 |
8036 return 0; // success | 7228 return 0; // success |
8037 } | 7229 } |
8038 | 7230 |
8039 if (pos >= stop) | 7231 if (pos >= stop) |
8040 return E_FILE_FORMAT_INVALID; | 7232 return E_FILE_FORMAT_INVALID; |
8041 | 7233 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8081 | 7273 |
8082 if (val < 255) | 7274 if (val < 255) |
8083 break; | 7275 break; |
8084 } | 7276 } |
8085 | 7277 |
8086 Frame& f = *pf++; | 7278 Frame& f = *pf++; |
8087 assert(pf < pf_end); | 7279 assert(pf < pf_end); |
8088 | 7280 |
8089 f.pos = 0; // patch later | 7281 f.pos = 0; // patch later |
8090 | 7282 |
| 7283 if (frame_size <= 0) |
| 7284 return E_FILE_FORMAT_INVALID; |
| 7285 |
8091 f.len = frame_size; | 7286 f.len = frame_size; |
8092 size += frame_size; // contribution of this frame | 7287 size += frame_size; // contribution of this frame |
8093 | 7288 |
8094 --frame_count; | 7289 --frame_count; |
8095 } | 7290 } |
8096 | 7291 |
8097 assert(pf < pf_end); | 7292 assert(pf < pf_end); |
8098 assert(pos <= stop); | 7293 assert(pos <= stop); |
8099 | 7294 |
8100 { | 7295 { |
8101 Frame& f = *pf++; | 7296 Frame& f = *pf++; |
8102 | 7297 |
8103 if (pf != pf_end) | 7298 if (pf != pf_end) |
8104 return E_FILE_FORMAT_INVALID; | 7299 return E_FILE_FORMAT_INVALID; |
8105 | 7300 |
8106 f.pos = 0; // patch later | 7301 f.pos = 0; // patch later |
8107 | 7302 |
8108 const long long total_size = stop - pos; | 7303 const long long total_size = stop - pos; |
8109 | 7304 |
8110 if (total_size < size) | 7305 if (total_size < size) |
8111 return E_FILE_FORMAT_INVALID; | 7306 return E_FILE_FORMAT_INVALID; |
8112 | 7307 |
8113 const long long frame_size = total_size - size; | 7308 const long long frame_size = total_size - size; |
8114 | 7309 |
8115 if (frame_size > LONG_MAX) | 7310 if (frame_size > LONG_MAX || frame_size <= 0) |
8116 return E_FILE_FORMAT_INVALID; | 7311 return E_FILE_FORMAT_INVALID; |
8117 | 7312 |
8118 f.len = static_cast<long>(frame_size); | 7313 f.len = static_cast<long>(frame_size); |
8119 } | 7314 } |
8120 | 7315 |
8121 pf = m_frames; | 7316 pf = m_frames; |
8122 while (pf != pf_end) { | 7317 while (pf != pf_end) { |
8123 Frame& f = *pf++; | 7318 Frame& f = *pf++; |
8124 assert((pos + f.len) <= stop); | 7319 assert((pos + f.len) <= stop); |
8125 | 7320 |
8126 f.pos = pos; | 7321 f.pos = pos; |
8127 pos += f.len; | 7322 pos += f.len; |
8128 } | 7323 } |
8129 | 7324 |
8130 assert(pos == stop); | 7325 assert(pos == stop); |
8131 } else if (lacing == 2) { // fixed-size lacing | 7326 } else if (lacing == 2) { // fixed-size lacing |
| 7327 if (pos >= stop) |
| 7328 return E_FILE_FORMAT_INVALID; |
| 7329 |
8132 const long long total_size = stop - pos; | 7330 const long long total_size = stop - pos; |
8133 | 7331 |
8134 if ((total_size % m_frame_count) != 0) | 7332 if ((total_size % m_frame_count) != 0) |
8135 return E_FILE_FORMAT_INVALID; | 7333 return E_FILE_FORMAT_INVALID; |
8136 | 7334 |
8137 const long long frame_size = total_size / m_frame_count; | 7335 const long long frame_size = total_size / m_frame_count; |
8138 | 7336 |
8139 if (frame_size > LONG_MAX) | 7337 if (frame_size > LONG_MAX || frame_size <= 0) |
8140 return E_FILE_FORMAT_INVALID; | 7338 return E_FILE_FORMAT_INVALID; |
8141 | 7339 |
8142 Frame* pf = m_frames; | 7340 Frame* pf = m_frames; |
8143 Frame* const pf_end = pf + m_frame_count; | 7341 Frame* const pf_end = pf + m_frame_count; |
8144 | 7342 |
8145 while (pf != pf_end) { | 7343 while (pf != pf_end) { |
8146 assert((pos + frame_size) <= stop); | 7344 assert((pos + frame_size) <= stop); |
8147 | 7345 |
8148 Frame& f = *pf++; | 7346 Frame& f = *pf++; |
8149 | 7347 |
8150 f.pos = pos; | 7348 f.pos = pos; |
8151 f.len = static_cast<long>(frame_size); | 7349 f.len = static_cast<long>(frame_size); |
8152 | 7350 |
8153 pos += frame_size; | 7351 pos += frame_size; |
8154 } | 7352 } |
8155 | 7353 |
8156 assert(pos == stop); | 7354 assert(pos == stop); |
8157 } else { | 7355 } else { |
8158 assert(lacing == 3); // EBML lacing | 7356 assert(lacing == 3); // EBML lacing |
8159 | 7357 |
8160 if (pos >= stop) | 7358 if (pos >= stop) |
8161 return E_FILE_FORMAT_INVALID; | 7359 return E_FILE_FORMAT_INVALID; |
8162 | 7360 |
8163 long size = 0; | 7361 long size = 0; |
8164 int frame_count = m_frame_count; | 7362 int frame_count = m_frame_count; |
8165 | 7363 |
8166 long long frame_size = ReadUInt(pReader, pos, len); | 7364 long long frame_size = ReadUInt(pReader, pos, len); |
8167 | 7365 |
8168 if (frame_size < 0) | 7366 if (frame_size <= 0) |
8169 return E_FILE_FORMAT_INVALID; | 7367 return E_FILE_FORMAT_INVALID; |
8170 | 7368 |
8171 if (frame_size > LONG_MAX) | 7369 if (frame_size > LONG_MAX) |
8172 return E_FILE_FORMAT_INVALID; | 7370 return E_FILE_FORMAT_INVALID; |
8173 | 7371 |
8174 if ((pos + len) > stop) | 7372 if ((pos + len) > stop) |
8175 return E_FILE_FORMAT_INVALID; | 7373 return E_FILE_FORMAT_INVALID; |
8176 | 7374 |
8177 pos += len; // consume length of size of first frame | 7375 pos += len; // consume length of size of first frame |
8178 | 7376 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8220 | 7418 |
8221 pos += len; // consume length of (delta) size | 7419 pos += len; // consume length of (delta) size |
8222 assert(pos <= stop); | 7420 assert(pos <= stop); |
8223 | 7421 |
8224 const int exp = 7 * len - 1; | 7422 const int exp = 7 * len - 1; |
8225 const long long bias = (1LL << exp) - 1LL; | 7423 const long long bias = (1LL << exp) - 1LL; |
8226 const long long delta_size = delta_size_ - bias; | 7424 const long long delta_size = delta_size_ - bias; |
8227 | 7425 |
8228 frame_size += delta_size; | 7426 frame_size += delta_size; |
8229 | 7427 |
8230 if (frame_size < 0) | 7428 if (frame_size <= 0) |
8231 return E_FILE_FORMAT_INVALID; | 7429 return E_FILE_FORMAT_INVALID; |
8232 | 7430 |
8233 if (frame_size > LONG_MAX) | 7431 if (frame_size > LONG_MAX) |
8234 return E_FILE_FORMAT_INVALID; | 7432 return E_FILE_FORMAT_INVALID; |
8235 | 7433 |
8236 curr.len = static_cast<long>(frame_size); | 7434 curr.len = static_cast<long>(frame_size); |
8237 size += curr.len; // contribution of this frame | 7435 size += curr.len; // contribution of this frame |
8238 | 7436 |
8239 --frame_count; | 7437 --frame_count; |
8240 } | 7438 } |
8241 | 7439 |
8242 { | 7440 // parse last frame |
| 7441 if (frame_count > 0) { |
8243 assert(pos <= stop); | 7442 assert(pos <= stop); |
8244 assert(pf < pf_end); | 7443 assert(pf < pf_end); |
8245 | 7444 |
8246 const Frame& prev = *pf++; | 7445 const Frame& prev = *pf++; |
8247 assert(prev.len == frame_size); | 7446 assert(prev.len == frame_size); |
8248 if (prev.len != frame_size) | 7447 if (prev.len != frame_size) |
8249 return E_FILE_FORMAT_INVALID; | 7448 return E_FILE_FORMAT_INVALID; |
8250 | 7449 |
8251 assert(pf < pf_end); | 7450 assert(pf < pf_end); |
8252 | 7451 |
8253 Frame& curr = *pf++; | 7452 Frame& curr = *pf++; |
8254 assert(pf == pf_end); | 7453 assert(pf == pf_end); |
8255 | 7454 |
8256 curr.pos = 0; // patch later | 7455 curr.pos = 0; // patch later |
8257 | 7456 |
8258 const long long total_size = stop - pos; | 7457 const long long total_size = stop - pos; |
8259 | 7458 |
8260 if (total_size < size) | 7459 if (total_size < size) |
8261 return E_FILE_FORMAT_INVALID; | 7460 return E_FILE_FORMAT_INVALID; |
8262 | 7461 |
8263 frame_size = total_size - size; | 7462 frame_size = total_size - size; |
8264 | 7463 |
8265 if (frame_size > LONG_MAX) | 7464 if (frame_size > LONG_MAX || frame_size <= 0) |
8266 return E_FILE_FORMAT_INVALID; | 7465 return E_FILE_FORMAT_INVALID; |
8267 | 7466 |
8268 curr.len = static_cast<long>(frame_size); | 7467 curr.len = static_cast<long>(frame_size); |
8269 } | 7468 } |
8270 | 7469 |
8271 pf = m_frames; | 7470 pf = m_frames; |
8272 while (pf != pf_end) { | 7471 while (pf != pf_end) { |
8273 Frame& f = *pf++; | 7472 Frame& f = *pf++; |
8274 assert((pos + f.len) <= stop); | 7473 assert((pos + f.len) <= stop); |
8275 | 7474 |
8276 f.pos = pos; | 7475 f.pos = pos; |
8277 pos += f.len; | 7476 pos += f.len; |
8278 } | 7477 } |
8279 | 7478 |
8280 assert(pos == stop); | 7479 if (pos != stop) |
| 7480 return E_FILE_FORMAT_INVALID; |
8281 } | 7481 } |
8282 | 7482 |
8283 return 0; // success | 7483 return 0; // success |
8284 } | 7484 } |
8285 | 7485 |
8286 long long Block::GetTimeCode(const Cluster* pCluster) const { | 7486 long long Block::GetTimeCode(const Cluster* pCluster) const { |
8287 if (pCluster == 0) | 7487 if (pCluster == 0) |
8288 return m_timecode; | 7488 return m_timecode; |
8289 | 7489 |
8290 const long long tc0 = pCluster->GetTimeCode(); | 7490 const long long tc0 = pCluster->GetTimeCode(); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8349 assert(pReader); | 7549 assert(pReader); |
8350 assert(buf); | 7550 assert(buf); |
8351 | 7551 |
8352 const long status = pReader->Read(pos, len, buf); | 7552 const long status = pReader->Read(pos, len, buf); |
8353 return status; | 7553 return status; |
8354 } | 7554 } |
8355 | 7555 |
8356 long long Block::GetDiscardPadding() const { return m_discard_padding; } | 7556 long long Block::GetDiscardPadding() const { return m_discard_padding; } |
8357 | 7557 |
8358 } // end namespace mkvparser | 7558 } // end namespace mkvparser |
OLD | NEW |