From 09b424fbbb44ecfe2fc7c9a86d7a1c72adcc852e Mon Sep 17 00:00:00 2001 From: odrling Date: Tue, 17 Nov 2020 17:15:46 +0100 Subject: [PATCH] fix sub timing in mkv files with video delay Some matroska files have audio start at timestamp 0 and video later. In this case mkvtoolnix seems to use the first block of the first cluster to the audio track (I would assume this is only an implementation detail and not really from the matroska specs. And also could happen in other cases without the video being delayed, but that's not the point). Aegisub used to read this first block and use its timestamp as the starting point of the video track. With this commit, Aegisub tries to read all the blocks until it can read the first timestamp of the video track and use it for the subtitles' timestamps. Audio tracks don't seem to be impacted by these changes. --- src/MatroskaParser.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/MatroskaParser.c b/src/MatroskaParser.c index c50f494f6..5cc42bdbb 100644 --- a/src/MatroskaParser.c +++ b/src/MatroskaParser.c @@ -1088,8 +1088,9 @@ static void parseSegmentInfo(MatroskaFile *mf,uint64_t toplen) { static void parseFirstCluster(MatroskaFile *mf,uint64_t toplen) { uint64_t end = filepos(mf) + toplen; + int tracknum = -1; + int i = 0; - mf->seen.Cluster = 1; mf->firstTimecode = 0; FOREACH(mf,toplen) @@ -1097,22 +1098,40 @@ static void parseFirstCluster(MatroskaFile *mf,uint64_t toplen) { mf->firstTimecode += readUInt(mf,(unsigned)len); break; case 0xa3: // BlockEx - readVLUInt(mf); // track number - mf->firstTimecode += readSInt(mf, 2); + start = filepos(mf); + tracknum = readVLUInt(mf); // track number - skipbytes(mf,end - filepos(mf)); - return; + for (i = 0; i < mf->nTracks; ++i) { + if (mf->Tracks[i]->Number == tracknum && mf->Tracks[i]->Type == TT_VIDEO) { + mf->firstTimecode += readSInt(mf, 2); + mf->seen.Cluster = 1; + skipbytes(mf,end - filepos(mf)); + return; + } + } + + skipbytes(mf, len - (filepos(mf) - start)); + break; case 0xa0: // BlockGroup FOREACH(mf,len) - case 0xa1: // Block - readVLUInt(mf); // track number - mf->firstTimecode += readSInt(mf,2); + case 0xa1: // Block + start = filepos(mf); + tracknum = readVLUInt(mf); // track number - skipbytes(mf,end - filepos(mf)); - return; + for (i = 0; i < mf->nTracks; ++i) { + if (mf->Tracks[i]->Number == tracknum && mf->Tracks[i]->Type == TT_VIDEO) { + mf->firstTimecode += readSInt(mf, 2); + mf->seen.Cluster = 1; + skipbytes(mf,end - filepos(mf)); + return; + } + } + + skipbytes(mf, len - (filepos(mf) - start)); + break; ENDFOR(mf); - break; ENDFOR(mf); + } static void parseVideoInfo(MatroskaFile *mf,uint64_t toplen,struct TrackInfo *ti) {