Update MkvInfoReader, Add MkvNode extensions

This commit is contained in:
2022-03-17 13:32:20 +01:00
parent 09d1a52aed
commit df86aee35f
9 changed files with 142 additions and 28 deletions

View File

@@ -1,21 +0,0 @@
namespace MkvPropEditWrapper.MkvInfo;
public static class NodeUtils
{
public static IEnumerable<MkvNode> Descendants(this MkvNode root)
{
var nodes = new Stack<MkvNode>(new[] {root});
while (nodes.Any())
{
var node = nodes.Pop();
yield return node;
foreach (var newNode in node.Children)
{
nodes.Push(newNode);
}
}
}
}

View File

@@ -1,4 +1,6 @@
namespace MkvPropEditWrapper.MkvInfo;
using System.Runtime.CompilerServices;
namespace MkvPropEditWrapper.MkvInfo.Reader;
public class MkvInfoReader
{
@@ -46,6 +48,7 @@ public class MkvInfoReader
return _root;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessLine(ReadOnlyMemory<char> line)
{
var lineSpan = line.Span;
@@ -71,7 +74,7 @@ public class MkvInfoReader
if (propertyIndex != -1)
{
var name = content[..propertyIndex];
var value = content[(propertyIndex + 1)..];
var value = content[(propertyIndex + 2)..];
node = new MkvProperty(_currentNode, name, value);
}
@@ -90,6 +93,7 @@ public class MkvInfoReader
/// Read in the span till next \n or EOF while incrementing _currentPosition
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ReadOnlyMemory<char> ReadLine()
{
var remainingSpan = _remainingMemory.Span;

View File

@@ -1,7 +1,7 @@
using System.Collections;
using System.Text;
namespace MkvPropEditWrapper.MkvInfo;
namespace MkvPropEditWrapper.MkvInfo.Reader;
public class MkvNode : IEnumerable<MkvNode>
{

View File

@@ -1,6 +1,6 @@
using System.Text;
namespace MkvPropEditWrapper.MkvInfo;
namespace MkvPropEditWrapper.MkvInfo.Reader;
public class MkvNodeRoot : MkvNode
{

View File

@@ -1,11 +1,13 @@
using System.Text;
namespace MkvPropEditWrapper.MkvInfo;
namespace MkvPropEditWrapper.MkvInfo.Reader;
public class MkvProperty : MkvNode
{
private static class KnownProperties
{
public const string TrackType = "Track type";
public const string TrackNumber = "Track number";
public const string FlagDefault = "\"Default track\" flag";
public const string FlagForced = "\"Forced display\" flag";
public const string Language = "Language";
@@ -26,6 +28,16 @@ public class MkvProperty : MkvNode
private static PropertyType FindPropertyType(ReadOnlyMemory<char> name)
{
var span = name.Span;
if (span.SequenceEqual(KnownProperties.TrackType))
{
return PropertyType.TrackType;
}
if (span.SequenceEqual(KnownProperties.TrackNumber))
{
return PropertyType.TrackNumber;
}
if (span.SequenceEqual(KnownProperties.FlagDefault))
{

View File

@@ -1,4 +1,4 @@
namespace MkvPropEditWrapper.MkvInfo;
namespace MkvPropEditWrapper.MkvInfo.Reader;
public enum NodeType
{

View File

@@ -0,0 +1,107 @@
using MkvPropEditWrapper.Shared;
namespace MkvPropEditWrapper.MkvInfo.Reader;
public static class NodeUtils
{
public static IEnumerable<MkvNode> Descendants(this MkvNode root)
{
var nodes = new Stack<MkvNode>(new[] {root});
while (nodes.Any())
{
var node = nodes.Pop();
yield return node;
foreach (var newNode in node.Children)
{
nodes.Push(newNode);
}
}
}
/// <summary>
/// Generate track info from parsed output, only works on the first root node as it uses absolute depth
/// </summary>
/// <param name="root">Node root</param>
/// <returns>All parseable <see cref="TrackInfo"/></returns>
public static IEnumerable<TrackInfo> GetTrackInfos(this MkvNodeRoot root)
{
TrackInfo? ParseTrackInfo(MkvNode track)
{
ReadOnlySpan<char> audioType = "audio";
ReadOnlySpan<char> subtitleType = "subtitles";
int number = -1;
var trackType = TrackType.Unknown;
string language = "Unknown";
bool defaultFlag = default;
bool forcedFlag = default;
foreach (var child in track.Children)
{
if (child is MkvProperty property)
{
ReadOnlySpan<char> span;
switch (property.PropertyType)
{
case PropertyType.TrackType:
span = property.Value.Span;
if (span.SequenceEqual(audioType))
{
trackType = TrackType.Audio;
}
else if (span.SequenceEqual(subtitleType))
{
trackType = TrackType.Subtitles;
}
else
{
return null;
}
break;
case PropertyType.TrackNumber:
span = property.Value.Span;
number = int.Parse(span[..span.IndexOf(' ')]);
break;
case PropertyType.Language:
language = property.Value.ToString();
break;
case PropertyType.FlagDefault:
defaultFlag = property.Value.Span[0] == '1';
break;
case PropertyType.FlagForced:
forcedFlag = property.Value.Span[0] == '1';
break;
}
}
}
return number == -1 ? null : new TrackInfo(number, trackType, language, defaultFlag, forcedFlag);
}
var tracks = root.Descendants().Where(n => n is { Depth: 2, NodeType: NodeType.Track });
foreach (var track in tracks)
{
var trackInfo = ParseTrackInfo(track);
if (trackInfo is not null)
{
yield return trackInfo;
}
}
}
public static (IEnumerable<TrackInfo> audio, IEnumerable<TrackInfo> subtitles) SplitByType(this IEnumerable<TrackInfo> trackInfos)
{
var lookup = trackInfos.OrderBy(t => t.Number).ToLookup(t => t.TrackType);
return (lookup[TrackType.Audio], lookup[TrackType.Subtitles]);
}
}

View File

@@ -1,7 +1,9 @@
namespace MkvPropEditWrapper.MkvInfo;
namespace MkvPropEditWrapper.MkvInfo.Reader;
public enum PropertyType
{
TrackType,
TrackNumber,
Unknown,
FlagDefault,
FlagForced,

View File

@@ -0,0 +1,10 @@
namespace MkvPropEditWrapper.Shared;
public record TrackInfo(int Number, TrackType TrackType, string Language, bool IsDefault, bool IsForced);
public enum TrackType
{
Unknown,
Audio,
Subtitles
}