@@ -854,42 +854,134 @@ static int CheckLacingKeyframe(void)
854854 return Result ;
855855}
856856
857- static int CheckCueEntries (ebml_master * Cues )
857+ static int CheckCueEntries (ebml_master * Cues , filepos_t SegmentDataOffset )
858858{
859859 int Result = 0 ;
860- timecode_t TimecodeEntry , PrevTimecode = INVALID_TIMECODE_T ;
861- int16_t TrackNumEntry ;
862- matroska_cluster * * Cluster ;
863- matroska_block * Block ;
864- int ClustNum = 0 ;
865860
866861 if (!RSegmentInfo )
867862 Result |= OutputError (0x310 ,T ("A Cues (index) is defined but no SegmentInfo was found" ));
868863 else if (ARRAYCOUNT (RClusters ,matroska_cluster * ))
869864 {
870- matroska_cuepoint * CuePoint = (matroska_cuepoint * )EBML_MasterFindChild (Cues , & MATROSKA_ContextCuePoint );
865+ matroska_cluster * * Cluster = ARRAYBEGIN (RClusters ,matroska_cluster * );
866+ matroska_cuepoint * CuePoint = (matroska_cuepoint * )EBML_MasterFindChild (Cues , & MATROSKA_ContextCuePoint );
867+ timecode_t TimecodeEntry , PrevTimecode = INVALID_TIMECODE_T ;
868+ int CueNum = 0 ;
869+
871870 while (CuePoint )
872871 {
873- if (!Quiet && ClustNum ++ % 24 == 0 )
872+ if (!Quiet && CueNum ++ % 24 == 0 )
874873 TextWrite (StdErr ,T ("." ));
875874 MATROSKA_LinkCueSegmentInfo (CuePoint ,RSegmentInfo );
876875 TimecodeEntry = MATROSKA_CueTimecode (CuePoint );
877- TrackNumEntry = MATROSKA_CueTrackNum (CuePoint );
876+
877+ if (TimecodeEntry == INVALID_TIMECODE_T )
878+ goto NextCuePoint ;
878879
879880 if (TimecodeEntry < PrevTimecode && PrevTimecode != INVALID_TIMECODE_T )
880881 OutputWarning (0x311 ,T ("The Cues entry for timecode %" ) TPRId64 T (" ms is listed after entry %" ) TPRId64 T (" ms" ),Scale64 (TimecodeEntry ,1 ,1000000 ),Scale64 (PrevTimecode ,1 ,1000000 ));
881882
882- // find a matching Block
883- for (Cluster = ARRAYBEGIN (RClusters ,matroska_cluster * );Cluster != ARRAYEND (RClusters ,matroska_cluster * ); ++ Cluster )
884- {
885- Block = MATROSKA_GetBlockForTimecode (* Cluster , TimecodeEntry , TrackNumEntry );
886- if (Block )
887- break ;
888- }
889- if (Cluster == ARRAYEND (RClusters ,matroska_cluster * ))
890- Result |= OutputError (0x312 ,T ("CueEntry Track #%d and timecode %" ) TPRId64 T (" ms not found" ),(int )TrackNumEntry ,Scale64 (TimecodeEntry ,1 ,1000000 ));
891- PrevTimecode = TimecodeEntry ;
892- CuePoint = (matroska_cuepoint * )EBML_MasterFindNextElt (Cues , (ebml_element * )CuePoint , 0 , 0 );
883+ for (ebml_element * CueTrackPositions = EBML_MasterFindChild (CuePoint , & MATROSKA_ContextCueTrackPositions );
884+ CueTrackPositions ; CueTrackPositions = EBML_MasterNextChild (CuePoint , CueTrackPositions ))
885+ {
886+ ebml_element * Block = NULL , * Element = EBML_MasterFindChild (CueTrackPositions ,& MATROSKA_ContextCueTrack );
887+ filepos_t ClusterOffset , CueRelativePosition ;
888+ int Direction ;
889+ int16_t TrackNumEntry ;
890+ bool_t ClusterExists ;
891+ tchar_t Error [384 ];
892+
893+ if (!Element )
894+ continue ;
895+
896+ TrackNumEntry = EL_Int (Element );
897+
898+ Element = EBML_MasterFindChild (CueTrackPositions , & MATROSKA_ContextCueClusterPosition );
899+ if (!Element )
900+ continue ;
901+
902+ ClusterOffset = EL_Int (Element ) + SegmentDataOffset ;
903+
904+ Element = EBML_MasterFindChild (CueTrackPositions , & MATROSKA_ContextCueRelativePosition );
905+ CueRelativePosition = Element ? EL_Int (Element ) : INVALID_FILEPOS_T ;
906+
907+ Direction = EL_Pos (* Cluster ) <= ClusterOffset ? 1 : -1 ;
908+
909+ do
910+ {
911+ if (EL_Pos (* Cluster ) == ClusterOffset )
912+ {
913+ Block = MATROSKA_GetNextBlockForTimecode (* Cluster , NULL , TimecodeEntry , TrackNumEntry , 1 );
914+ break ;
915+ }
916+
917+ if ((Direction == 1 && (EL_Pos (* Cluster ) > ClusterOffset || Cluster == ARRAYEND (RClusters , matroska_cluster * ) - 1 )) ||
918+ (Direction == -1 && (EL_Pos (* Cluster ) < ClusterOffset || Cluster == ARRAYBEGIN (RClusters , matroska_cluster * ))))
919+ break ;
920+
921+ Cluster += Direction ;
922+ }
923+ while (1 );
924+
925+ if (Block )
926+ {
927+ ebml_element * PreviousBlock ;
928+
929+ if (CueRelativePosition == INVALID_FILEPOS_T || EL_Pos (Block ) - EBML_ElementPositionData ((ebml_element * )* Cluster ) == CueRelativePosition )
930+ continue ;
931+
932+ while (Block && EL_Pos (Block ) - EBML_ElementPositionData ((ebml_element * )* Cluster ) < CueRelativePosition )
933+ {
934+ PreviousBlock = Block ;
935+ Block = MATROSKA_GetNextBlockForTimecode (* Cluster , PreviousBlock , TimecodeEntry , TrackNumEntry , 1 );
936+ }
937+
938+ Block = Block ? Block : PreviousBlock ;
939+
940+ if (EL_Pos (Block ) - EBML_ElementPositionData ((ebml_element * )* Cluster ) == CueRelativePosition )
941+ continue ;
942+ }
943+
944+ stprintf_s (Error , TSIZEOF (Error ), T ("An invalid Cues entry points to a (Simple)Block in track #%d with timecode %" )
945+ TPRId64 T (" ms supposedly in the cluster with offset %" ) TPRId64 , TrackNumEntry , Scale64 (TimecodeEntry ,1 ,1000000 ), ClusterOffset );
946+
947+ if (CueRelativePosition != INVALID_FILEPOS_T )
948+ stcatprintf_s (Error , TSIZEOF (Error ), T (" (relative offset %" ) TPRId64 T (")" ), CueRelativePosition );
949+
950+ if (Block )
951+ {
952+ stcatprintf_s (Error , TSIZEOF (Error ), T (". The actual relative offset is %" ) TPRId64 T ("." ),
953+ EL_Pos (Block ) - EBML_ElementPositionData ((ebml_element * )* Cluster ));
954+ Result |= OutputError (0x314 , Error );
955+ continue ;
956+ }
957+
958+ if (EL_Pos (* Cluster ) != ClusterOffset )
959+ tcscat_s (Error , TSIZEOF (Error ), T (". No cluster with this offset exists" ));
960+
961+ for (Cluster = ARRAYBEGIN (RClusters , matroska_cluster * ); Cluster != ARRAYEND (RClusters , matroska_cluster * ); ++ Cluster )
962+ {
963+ Block = MATROSKA_GetNextBlockForTimecode (* Cluster , NULL , TimecodeEntry , TrackNumEntry , 1 );
964+ if (Block )
965+ break ;
966+ }
967+
968+ if (!Block )
969+ {
970+ tcscat_s (Error , TSIZEOF (Error ), T (". No (Simple)Block with this timecode exists in this track at all." ));
971+ Result |= OutputError (0x312 , Error );
972+ }
973+ else
974+ {
975+ stcatprintf_s (Error , TSIZEOF (Error ), T (". A (Simple)Block with this timecode is in the cluster with offset %" ) TPRId64
976+ T (" (relative offset %" ) TPRId64 T (")." ), EL_Pos (* Cluster ), EL_Pos (Block ) - EBML_ElementPositionData ((ebml_element * )* Cluster ));
977+ Result |= OutputError (0x313 , Error );
978+ }
979+ }
980+
981+ PrevTimecode = TimecodeEntry ;
982+
983+ NextCuePoint :
984+ CuePoint = (matroska_cuepoint * )EBML_MasterFindNextElt (Cues , (ebml_element * )CuePoint , 0 , 0 );
893985 }
894986 }
895987 return Result ;
@@ -1384,7 +1476,7 @@ int main(int argc, const char *argv[])
13841476 OutputWarning (0x800 ,T ("The segment has Clusters but no Cues section (bad for seeking)" ));
13851477 }
13861478 else
1387- Result |= CheckCueEntries (RCues );
1479+ Result |= CheckCueEntries (RCues , EBML_ElementPositionData (( ebml_element * ) RSegment ) );
13881480 if (!RTrackInfo )
13891481 {
13901482 Result = OutputError (0x41 ,T ("The segment has Clusters but no TrackInfo section" ));
0 commit comments