Some Matroska files have their tracks stored non-interleaved, e.g.
with all audio data appended after all video data. ffmpeg reads such
files incorrectly when demuxing multiple streams interleaved: the
output audio can end up with wrong timestamps or be scrambled, while
reading each stream type individually works fine. This caused exported
segments of such files to play back starting from the wrong position.
To fix the problem without relying on ffmpeg behavior:
- Add checkMatroskaTrackInterleaving() in main/ffmpeg.ts: scans only
EBML cluster headers (no media data is read, so it stays fast even
for large files) and flags the file when cluster timestamps jump
backwards by more than 2 seconds.
- Run the check when opening a Matroska file (in loadMedia; skipped
for files that get html5ified or are not Matroska) and inform the
user with a toast explaining that the workaround will be applied
automatically on export.
- Add losslessCutSingleAudioSafe() in useFfmpegOperations: cuts the
segment in two passes (all streams except audio, then audio only)
and losslessly merges them, cutting each pass in a way ffmpeg
handles correctly for such files. Temp files are deleted afterwards;
stream order, metadata and chapters are preserved. The safe path is
only used for files flagged at load time; all other files go through
the existing losslessCutSingle path unchanged.
- Add translations for the new notice (en, zh_Hans).
"This experimental feature will re-encode the part of the video from the cutpoint until the next keyframe in order to attempt to make a 100% accurate cut. Only works on some files. I've had success with some h264 files, and only a few h265 files. See more here: {{url}}":"This experimental feature will re-encode the part of the video from the cutpoint until the next keyframe in order to attempt to make a 100% accurate cut. Only works on some files. I've had success with some h264 files, and only a few h265 files. See more here: {{url}}",
"This file contains an audio track that FFmpeg is unable to mux into the MP4 format, so MOV has been auto-selected as the default output format.":"This file contains an audio track that FFmpeg is unable to mux into the MP4 format, so MOV has been auto-selected as the default output format.",
"This file does not have a valid duration. This may cause issues. You can try to fix the file's duration from the File menu":"This file does not have a valid duration. This may cause issues. You can try to fix the file's duration from the File menu",
"This file has broken track interleaving":"This file has broken track interleaving (some tracks are not interleaved properly). LosslessCut will automatically work around this when exporting, so that exported segments get correct timestamps.",
"This file has embedded chapters. Do you want to import the chapters as cut-segments?":"This file has embedded chapters. Do you want to import the chapters as cut-segments?",
"This gives you an overview of the export and allows you to customise more parameters before exporting, like changing the output file name.":"This gives you an overview of the export and allows you to customise more parameters before exporting, like changing the output file name.",
"This is hardcoded by FFmpeg and cannot be changed.":"This is hardcoded by FFmpeg and cannot be changed.",
"This file does not have a valid duration. This may cause issues. You can try to fix the file's duration from the File menu":"此文件的时长无效。这可能有问题。你可以尝试使用文件菜单中的修复错误时长",
"This file has broken track interleaving":"此文件的轨道交织损坏(部分轨道未正确交织存储)。导出时 LosslessCut 会自动采用安全切割方式规避该问题,以保证导出片段的时间戳正确。",
// Detection of Matroska files with broken track interleaving, e.g. where all audio data is stored at the very end of the file instead of being interleaved with the video data.
// ffmpeg's multi-stream interleaved reading of such files produces outputs with wrong timestamps (e.g. audio starting at 17s instead of 0s), while reading each track type individually works fine.
// Only EBML cluster headers are scanned (no media data is read), so this is fast even for large files.
// Iterate over the Segment's top-level elements, only parsing cluster headers (no media data is read).
// Cluster timestamps increase monotonically in a properly interleaved file; a large jump backwards indicates that clusters of some track(s) were written after clusters of other tracks.
while(offset<segmentLimit){
constelement=awaitreadEbmlElementHeader(offset);
if(element.unknownSize)break;// e.g. live stream, cannot reliably scan
constdataStart=offset+element.headerLength;
if(element.id===ID_CLUSTER){
// Look for the Timestamp child element (only scan a bounded part of the cluster's children)
// Detect Matroska files with broken track interleaving: exporting them needs a special workaround, so detect it now (when the file is opened) instead of having to deal with it after exporting.
showNotification({icon:'info',text: i18n.t('The audio track is not supported while previewing. You can convert to a supported format from the menu')});
}elseif(!validDuration){
getSwal().toast.fire({icon:'warning',timer: 10000,text: i18n.t('This file does not have a valid duration. This may cause issues. You can try to fix the file\'s duration from the File menu')});
}elseif(trackInterleavingProblemDetected){
getSwal().toast.fire({icon:'info',timer: 15000,showConfirmButton: true,text: i18n.t('This file has broken track interleaving')});
}
// This needs to be last, because it triggers <video> to load the video
// Same as losslessCutSingle, but safe for Matroska files with broken track interleaving (e.g. audio data stored after all video data instead of being interleaved).
// ffmpeg reads such files incorrectly when reading multiple streams interleaved, and some streams end up with wrong timestamps.
// Workaround: cut the file twice - once with all streams except audio, once with audio only (both are read correctly because ffmpeg doesn't need interleaved reading in those cases), then losslessly merge them.