Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 64 additions & 24 deletions src/libse/ContainerFormats/Matroska/MatroskaFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ public sealed class MatroskaFile : IDisposable
private double _frameRate;
private string _videoCodecId;

private int _subtitleRipTrackNumber;
private readonly List<MatroskaSubtitle> _subtitleRip = new List<MatroskaSubtitle>();
private readonly Dictionary<int, List<MatroskaSubtitle>> _subtitleRipByTrackNumber = new Dictionary<int, List<MatroskaSubtitle>>();
private HashSet<int> _subtitleTrackNumbers;
private bool _subtitleRipLoaded;
private List<MatroskaTrackInfo> _tracks;
private List<MatroskaChapter> _chapters;

Expand Down Expand Up @@ -558,11 +559,7 @@ private void ReadCluster(Element clusterElement)
ReadBlockGroupElement(element, clusterTimeCode);
break;
case ElementId.SimpleBlock:
var subtitle = ReadSubtitleBlock(element, clusterTimeCode);
if (subtitle != null)
{
_subtitleRip.Add(subtitle);
}
AddSubtitleBlock(ReadSubtitleBlock(element, clusterTimeCode));
break;
default:
_stream.Seek(element.DataSize, SeekOrigin.Current);
Expand All @@ -581,12 +578,9 @@ private void ReadBlockGroupElement(Element clusterElement, long clusterTimeCode)
switch (element.Id)
{
case ElementId.Block:
subtitle = ReadSubtitleBlock(element, clusterTimeCode);
if (subtitle == null)
{
return;
}
_subtitleRip.Add(subtitle);
var subtitleBlock = ReadSubtitleBlock(element, clusterTimeCode);
subtitle = subtitleBlock?.Subtitle;
AddSubtitleBlock(subtitleBlock);
break;
case ElementId.BlockDuration:
var duration = ReadUIntAsLong(element.DataSize);
Expand All @@ -602,10 +596,10 @@ private void ReadBlockGroupElement(Element clusterElement, long clusterTimeCode)
}
}

private MatroskaSubtitle ReadSubtitleBlock(Element blockElement, long clusterTimeCode)
private MatroskaSubtitleBlock ReadSubtitleBlock(Element blockElement, long clusterTimeCode)
{
var trackNumber = (int)ReadVariableLengthUInt();
if (trackNumber != _subtitleRipTrackNumber)
if (!IsSubtitleTrackNumber(trackNumber))
{
_stream.Seek(blockElement.EndPosition, SeekOrigin.Begin);
return null;
Expand Down Expand Up @@ -644,22 +638,68 @@ private MatroskaSubtitle ReadSubtitleBlock(Element blockElement, long clusterTim
var data = new byte[dataLength];
_stream.Read(data, 0, dataLength);

return new MatroskaSubtitle(data, (long)Math.Round(GetTimeScaledToMilliseconds(clusterTimeCode + timeCode)));
var subtitle = new MatroskaSubtitle(data, (long)Math.Round(GetTimeScaledToMilliseconds(clusterTimeCode + timeCode)));
return new MatroskaSubtitleBlock(trackNumber, subtitle);
}

public List<MatroskaSubtitle> GetSubtitle(int trackNumber, LoadMatroskaCallback progressCallback)
{
// Cache: GetSubtitle is called multiple times per UI flow (preview, OCR).
// Reuse the previously parsed list when the track matches.
if (_subtitleRipTrackNumber == trackNumber && _subtitleRip.Count > 0)
if (!_subtitleRipLoaded)
{
return _subtitleRip;
EnsureSubtitleTrackNumbers();
_subtitleRipByTrackNumber.Clear();
ReadSegmentCluster(progressCallback);
_subtitleRipLoaded = true;
}

_subtitleRip.Clear();
_subtitleRipTrackNumber = trackNumber;
ReadSegmentCluster(progressCallback);
return _subtitleRip;
return _subtitleRipByTrackNumber.TryGetValue(trackNumber, out var subtitles)
? subtitles
: new List<MatroskaSubtitle>();
}

private bool IsSubtitleTrackNumber(int trackNumber)
{
EnsureSubtitleTrackNumbers();
return _subtitleTrackNumbers.Contains(trackNumber);
}

private void EnsureSubtitleTrackNumbers()
{
if (_subtitleTrackNumbers == null)
{
ReadSegmentInfoAndTracks();
_subtitleTrackNumbers = new HashSet<int>(
_tracks?.Where(p => p.IsSubtitle).Select(p => p.TrackNumber) ?? Enumerable.Empty<int>());
}
}

private void AddSubtitleBlock(MatroskaSubtitleBlock subtitleBlock)
{
if (subtitleBlock == null)
{
return;
}

if (!_subtitleRipByTrackNumber.TryGetValue(subtitleBlock.TrackNumber, out var subtitles))
{
subtitles = new List<MatroskaSubtitle>();
_subtitleRipByTrackNumber.Add(subtitleBlock.TrackNumber, subtitles);
}

subtitles.Add(subtitleBlock.Subtitle);
}

private sealed class MatroskaSubtitleBlock
{
public MatroskaSubtitleBlock(int trackNumber, MatroskaSubtitle subtitle)
{
TrackNumber = trackNumber;
Subtitle = subtitle;
}

public int TrackNumber { get; }

public MatroskaSubtitle Subtitle { get; }
}

public void Dispose() => Dispose(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,8 @@ private async Task Export()
else if (trackInfo.CodecId == MatroskaTrackType.TextSt && subtitles != null && _matroskaFile != null)
{
var subtitle = new Subtitle();
var sub = _matroskaFile.GetSubtitle(trackInfo.TrackNumber, null);
Utilities.LoadMatroskaTextSubtitle(trackInfo, _matroskaFile, sub, subtitle);
Utilities.ParseMatroskaTextSt(trackInfo, sub, subtitle);
Utilities.LoadMatroskaTextSubtitle(trackInfo, _matroskaFile, subtitles, subtitle);
Utilities.ParseMatroskaTextSt(trackInfo, subtitles, subtitle);
await WriteTextSubtitleFile(Window, trackInfo, subtitles, new SubRip());
}
else
Expand Down Expand Up @@ -261,9 +260,8 @@ private bool TrackChanged()
else if (trackInfo.CodecId == MatroskaTrackType.TextSt && subtitles != null && _matroskaFile != null)
{
var subtitle = new Subtitle();
var sub = _matroskaFile.GetSubtitle(trackInfo.TrackNumber, null);
Utilities.LoadMatroskaTextSubtitle(trackInfo, _matroskaFile, sub, subtitle);
Utilities.ParseMatroskaTextSt(trackInfo, sub, subtitle);
Utilities.LoadMatroskaTextSubtitle(trackInfo, _matroskaFile, subtitles, subtitle);
Utilities.ParseMatroskaTextSt(trackInfo, subtitles, subtitle);

for (var i = 0; i < 20 && i < subtitle.Paragraphs.Count; i++)
{
Expand Down Expand Up @@ -315,4 +313,4 @@ internal void SelectAndScrollToRow(int index)
TrackChanged();
}, DispatcherPriority.Background);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,8 @@ private bool InitTrack()
else if (trackInfo.CodecId == MatroskaTrackType.TextSt && subtitles != null && _matroskaFile != null)
{
var subtitle = new Subtitle();
var sub = _matroskaFile.GetSubtitle(trackInfo.TrackNumber, null);
Utilities.LoadMatroskaTextSubtitle(trackInfo, _matroskaFile, sub, subtitle);
Utilities.ParseMatroskaTextSt(trackInfo, sub, subtitle);
Utilities.LoadMatroskaTextSubtitle(trackInfo, _matroskaFile, subtitles, subtitle);
Utilities.ParseMatroskaTextSt(trackInfo, subtitles, subtitle);

for (var i = 0; i < 20 && i < subtitle.Paragraphs.Count; i++)
{
Expand Down Expand Up @@ -211,4 +210,4 @@ internal void Loaded()
{
InitTrack();
}
}
}