Code · 78 lines · 3954 bytes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace MediaContainers.Matroska;

public class MatroskaCuePoint : List<MatroskaCueTrackPosition>
{
	public ulong SegmentOffset { get; set; }
	public ulong Timestamp { get; set; }

	public void ReadFrom(EBMLMasterElement element)
	{
		if (element == null) { return; }
		if (element.Definition != MatroskaSpecification.CuePoint) { return; }
		foreach (var child in element.Children)
		{
			if (child.Definition == MatroskaSpecification.CueTime) { Timestamp = child.UIntValue; }
			else if (child.Definition == MatroskaSpecification.CueTrackPositions)
			{
				var track = new MatroskaCueTrackPosition();
				foreach (var sub in ((EBMLMasterElement)child).Children)
				{
					if (sub.Definition == MatroskaSpecification.CueTrack) { track.CueTrack = (int)sub.IntValue; }
					else if (sub.Definition == MatroskaSpecification.CueClusterPosition) { track.CueClusterPosition = sub.UIntValue + SegmentOffset; }
					else if (sub.Definition == MatroskaSpecification.CueRelativePosition) { track.CueRelativePosition = sub.UIntValue; }
					else if (sub.Definition == MatroskaSpecification.CueDuration) { track.CueDuration = (int)sub.IntValue; }
					else if (sub.Definition == MatroskaSpecification.CueBlockNumber) { track.CueBlockNumber = (int)sub.IntValue; }
				}
				Add(track);
			}
		}
	}

	public async ValueTask Write(EBMLWriter writer, CancellationToken cancellationToken = default)
	{
		await writer.BeginMasterElement(MatroskaSpecification.CuePoint, cancellationToken);
		await writer.WriteUnsignedInteger(MatroskaSpecification.CueTime, Timestamp, cancellationToken);
		for (int i = 0; i < Count; i++)
		{
			var track = this[i];
			await writer.BeginMasterElement(MatroskaSpecification.CueTrackPositions, cancellationToken);
			await writer.WriteUnsignedInteger(MatroskaSpecification.CueTrack, (ulong)track.CueTrack, cancellationToken);
			await writer.WriteUnsignedInteger(MatroskaSpecification.CueClusterPosition, track.CueClusterPosition - SegmentOffset, cancellationToken);
			if (track.CueRelativePosition > 0) { await writer.WriteUnsignedInteger(MatroskaSpecification.CueRelativePosition, track.CueRelativePosition, cancellationToken); }
			if (track.CueDuration > 0) { await writer.WriteUnsignedInteger(MatroskaSpecification.CueDuration, (ulong)track.CueDuration, cancellationToken); }
			if (track.CueBlockNumber > 0) { await writer.WriteUnsignedInteger(MatroskaSpecification.CueBlockNumber, (ulong)track.CueBlockNumber, cancellationToken); }
			await writer.EndMasterElement(cancellationToken);
		}
		await writer.EndMasterElement(cancellationToken);
	}

	public EBMLMasterElement ToElement()
	{
		var cue = new EBMLMasterElement(MatroskaSpecification.CuePoint);
		cue.AddChild(new EBMLUnsignedIntegerElement(MatroskaSpecification.CueTime, Timestamp));
		foreach (var track in this)
		{
			var pos = new EBMLMasterElement(MatroskaSpecification.CueTrackPositions);
			pos.AddChild(new EBMLUnsignedIntegerElement(MatroskaSpecification.CueTrack, (ulong)track.CueTrack));
			pos.AddChild(new EBMLUnsignedIntegerElement(MatroskaSpecification.CueClusterPosition, track.CueClusterPosition - SegmentOffset));
			if (track.CueRelativePosition > 0) { pos.AddChild(new EBMLUnsignedIntegerElement(MatroskaSpecification.CueRelativePosition, track.CueRelativePosition)); }
			if (track.CueDuration > 0) { pos.AddChild(new EBMLUnsignedIntegerElement(MatroskaSpecification.CueDuration, (ulong)track.CueDuration)); }
			if (track.CueBlockNumber > 0) { pos.AddChild(new EBMLUnsignedIntegerElement(MatroskaSpecification.CueBlockNumber, (ulong)track.CueBlockNumber)); }
			cue.AddChild(pos);
		}
		return cue;
	}
}

public class MatroskaCueTrackPosition
{
	public int CueTrack { get; set; }
	public ulong CueClusterPosition { get; set; }
	public ulong CueRelativePosition { get; set; }
	public int CueDuration { get; set; }
	public int CueBlockNumber { get; set; }
}