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
15 changes: 13 additions & 2 deletions MatroskaLib/MatroskaLib.Test/MkvFileTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void TestToString()
voidPosition = 40
};

string json = mkvFile.ToString();
string json = mkvFile.ToString().Replace("\r\n", "\n");
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes problems where the build environment serialization uses CR/LF instead of just LF


json.Should().Be("""
{
Expand All @@ -35,10 +35,21 @@ public void TestToString()
"flagDefaultByteNumber": 0,
"flagForced": true,
"flagForcedByteNumber": 0,
"flagHearingImpaired": false,
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to match new Track properties

"flagHearingImpairedByteNumber": 0,
"flagVisualImpaired": false,
"flagVisualImpairedByteNumber": 0,
"flagTextDescriptions": false,
"flagTextDescriptionsByteNumber": 0,
"flagOriginal": false,
"flagOriginalByteNumber": 0,
"flagCommentary": false,
"flagCommentaryByteNumber": 0,
"flagTypebytenumber": 0,
"type": "subtitle",
"name": "",
"language": "eng"
"language": "eng",
"codecId": null,
}
],
"seekList": [],
Expand Down
93 changes: 93 additions & 0 deletions MatroskaLib/MatroskaLib/Helpers/MediaInfoHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using MediaInfo;
using MediaInfo.Model;
using MatroskaLib.Types;
using Microsoft.Extensions.Logging.Abstractions;

namespace MatroskaLib.Helpers;

public static class MediaInfoHelper
{
public static void GetAllTrackFormats(Stream stream, IEnumerable<Track> tracks)
{

try
{
if (!stream.CanSeek)
{
Debug.WriteLine($"Stream is not seekable, cannot use MediaInfo");
return results;
}

long originalPosition = stream.Position;
stream.Position = 0;

var mediaInfo = new MediaInfoWrapper(stream, NullLogger.Instance);

stream.Position = originalPosition;

if (!mediaInfo.Success)
{
Debug.WriteLine($"MediaInfo failed to read from stream");
return results;
}

Debug.WriteLine($"MediaInfo found {mediaInfo.AudioStreams?.Count ?? 0} audio streams, {mediaInfo.Subtitles?.Count ?? 0} subtitle streams");

foreach (var track in tracks)
{
if (track.type == TrackTypeEnum.audio)
{
if (mediaInfo.AudioStreams != null && mediaInfo.AudioStreams.Any())
{
var audioStream = mediaInfo.AudioStreams.FirstOrDefault(a => a.Id == (int)track.number);

if (audioStream != null)
{
Debug.WriteLine($"Track #{track.number} (audio) - Format: '{audioStream.Format}', CodecDesc: '{audioStream.CodecDescription}', Bitrate: {audioStream.Bitrate}");
var format = string.Empty;

if (!string.IsNullOrEmpty(audioStream.CodecDescription))
format = audioStream.CodecDescription;
else if (!string.IsNullOrEmpty(audioStream.CodecFriendly))
format = audioStream.CodecFriendly;
else if (!string.IsNullOrEmpty(audioStream.Format))
format = audioStream.Format;

track.detectedFormat = format ?? string.Empty;
track.bitrate = audioStream.Bitrate;
}
else
{
Debug.WriteLine($"Track #{track.number} (audio) - No matching MediaInfo stream found");
}
}
}
else if (track.type == TrackTypeEnum.subtitle)
{
var subtitleStream = mediaInfo.Subtitles?.FirstOrDefault(s => s.Id == (int)track.number);

if (subtitleStream != null)
{
Debug.WriteLine($"Track #{track.number} (subtitle) - Format: '{subtitleStream.Format}'");
track.detectedFormat = subtitleStream.Format ?? string.Empty;
track.bitrate = 0; // Subtitles typically don't have a bitrate, so we set it to 0
}
else
{
Debug.WriteLine($"Track #{track.number} (subtitle) - No matching MediaInfo stream found");
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"MediaInfoHelper exception: {ex.Message}");
Debug.WriteLine($"Stack trace: {ex.StackTrace}");
}
}
}
3 changes: 2 additions & 1 deletion MatroskaLib/MatroskaLib/MatroskaLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NEbml" Version="1.1.0.5"/>
<PackageReference Include="MediaInfo.Wrapper.Core" Version="21.9.3" />
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MediaInfo.Wrapper.Core gets us a lot more decoding.

<PackageReference Include="NEbml" Version="1.1.0.5" />
</ItemGroup>

</Project>
21 changes: 20 additions & 1 deletion MatroskaLib/MatroskaLib/MatroskaReader.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MatroskaLib.Helpers;
using MatroskaLib.Types;
using NEbml.Core;
using NEbml.Matroska;
Expand All @@ -17,7 +19,7 @@ public static List<MkvFile> ReadMkvFiles(string[] filePaths)
var tracks = new List<Track>();
var seekList = new List<Seek>();

using var fileStream = File.Open(filePath, FileMode.Open);
using var fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allows FileShare.Read keeps us from breaking while we (or someone else) has the file open for read-only access.

var reader = new EbmlReader(fileStream);

int? seekHeadCheckSum = _ReadSeekHead(reader, fileStream, seekList);
Expand All @@ -44,6 +46,23 @@ public static List<MkvFile> ReadMkvFiles(string[] filePaths)

return mkvFiles;
}

public static void LoadMediaInfoForFile(MkvFile mkvFile)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lazy-load of the rest of the media information

{
if (mkvFile.mediaInfoLoaded)
return;

try
{
using var fileStream = File.Open(mkvFile.filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
MediaInfoHelper.GetAllTrackFormats(fileStream, mkvFile.tracks);
mkvFile.mediaInfoLoaded = true;
}
catch (System.Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Failed to load MediaInfo for {mkvFile.filePath}: {ex.Message}");
}
}

private static int? _ReadSeekHead(EbmlReader reader, FileStream fileStream, List<Seek> seekList)
{
Expand Down
57 changes: 0 additions & 57 deletions MatroskaLib/MatroskaLib/MkvFilesContainer.cs

This file was deleted.

26 changes: 3 additions & 23 deletions MatroskaLib/MatroskaLib/Types/MkvFile.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;

Expand All @@ -17,27 +15,9 @@ public record MkvFile
public required int endPosition { get; init; }
public required int tracksPosition { get; init; }
public required int beginHeaderPosition { get; init; }

public string? CompareToGetError(MkvFile? other)
{
if (other is null)
throw new ArgumentNullException(nameof(other));

for (int i = 0; i < tracks.Count; i++)
{
var track = tracks[i];
var trackOther = other.tracks.ElementAtOrDefault(i);

if (trackOther is null)
return $"Track at index {i} does not exist, expected {track.type} with language {track.language}.";
if (track.number != trackOther.number)
return $"Track number at index {i} does not match. Expected {track.number}, got {trackOther.number}.";
if (track.language != trackOther.language)
return $"Track language at index {i} does not match. Expected {track.language}, got {trackOther.language}.";
}

return null;
}

[JsonIgnore]
public bool mediaInfoLoaded { get; set; }

public override string ToString() =>
JsonSerializer.Serialize(this with { filePath = string.Empty }, SourceGeneratedMkvFile.Default.MkvFile);
Expand Down
Loading