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