Skip to content

Commit

Permalink
Merge branch 'main' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeMoolenaar committed Mar 10, 2024
2 parents b09a899 + 1549f44 commit bbba054
Show file tree
Hide file tree
Showing 19 changed files with 114 additions and 65 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:
build-and-test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: FedericoCarboni/setup-ffmpeg@v1
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Restore dependencies
Expand Down
38 changes: 19 additions & 19 deletions MatroskaLib/MatroskaLib.Test/ByteHelperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ namespace MatroskaLib.Test;
public class ByteHelperTest
{
public static TheoryData<ulong, List<byte>> TestData1 = new() {
{ 2UL, new () { 0x2 } },
{ 909UL, new () { 0x3, 0x8D } },
{ 1_800_70UL, new () { 0x2, 0xBF, 0x66 } },
{ 2UL, [0x2] },
{ 909UL, [0x3, 0x8D] },
{ 1_800_70UL, [0x2, 0xBF, 0x66] },
};
[Theory, MemberData(nameof(TestData1))]
public void ToBytesTest(ulong value, List<byte> lsBytesExpected)
Expand All @@ -19,10 +19,10 @@ public void ToBytesTest(ulong value, List<byte> lsBytesExpected)
}

public static TheoryData<List<byte>, List<byte>> TestData2 = new() {
{ new() {0x0, 0x0, 0x0, 0x96}, new () { 0x96 } },
{ new() {0x0, 0x0, 0x5, 0x0, 0x9}, new () { 0x5, 0x0, 0x9 } },
{ new() {0x9}, new () { 0x9 } },
{ new() {}, new () { } }
{ [0x0, 0x0, 0x0, 0x96], [0x96] },
{ [0x0, 0x0, 0x5, 0x0, 0x9], [0x5, 0x0, 0x9] },
{ [0x9], [0x9] },
{ [], [] }
};
[Theory, MemberData(nameof(TestData2))]
public void RemoveLeftZeroesTest(List<byte> lsBytes, List<byte> lsBytesExpected)
Expand All @@ -34,34 +34,34 @@ public void RemoveLeftZeroesTest(List<byte> lsBytes, List<byte> lsBytesExpected)

public static IEnumerable<object[]> Data()
{
yield return new object[]
{
yield return
[
new List<byte>{ 0x6B, 0x2D, 0xAE, 0xBB, 0xD7, 0x81, 0x02 },
new List<byte>{ 0x6B, 0x2D, 0xAE, 0xBE, 0xD7, 0x81, 0x02 },
4,
3
};
yield return new object[]
{
];
yield return
[
new List<byte>{ 0x81, 0x02, 0xAE, 0x42, 0x83, 0xD7, 0x81, 0x03 },
new List<byte>{ 0x81, 0x02, 0xAE, 0x42, 0x87, 0xD7, 0x81, 0x03 },
5,
4
};
yield return new object[]
{
];
yield return
[
new List<byte>{ 0x81, 0x02, 0xAE, 0x42, 0x83, 0xD7, 0x81, 0x03 },
new List<byte>{ 0x81, 0x02, 0xAE, 0x42, 0x87, 0xD7, 0x81, 0x03 },
5,
4
};
yield return new object[]
{
];
yield return
[
new List<byte>{ 0x00, 0x00, 0xAE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x3A, 0xD7, 81 },
new List<byte>{ 0x00, 0x00, 0xAE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x3D, 0xD7, 81 },
11,
3
};
];
}
[Theory, MemberData(nameof(Data))]

Expand Down
2 changes: 2 additions & 0 deletions MatroskaLib/MatroskaLib.Test/Helpers/MkvValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static class MkvValidator
private const string OutputRemoveRegex = @"(^At least one output file must be specified)|(^\[(.*)\] )";
public static void Validate(string filePath)
{
// Validate with ffmpeg
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardError = true;
Expand All @@ -26,6 +27,7 @@ public static void Validate(string filePath)
throw new Exception("ffmpeg's mkv validation produced errors:" + Environment.NewLine + output);
}

// Validate with mkvalidator
p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardError = true;
Expand Down
4 changes: 4 additions & 0 deletions MatroskaLib/MatroskaLib.Test/MatroskaLib.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
<Link>mkv files\TestFile5_MkvProEdit.mkv</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\TestMkvFiles\mkv files\TestFile6_SmallSeekHead.mkv">
<Link>mkv files\TestFile6_SmallSeekHead.mkv</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="mkvalidator.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Expand Down
37 changes: 25 additions & 12 deletions MatroskaLib/MatroskaLib.Test/MatroskaLibTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ namespace MatroskaLib.Test;
* Only first void with checksum elements
* MkvProEdit
* Only second void and may need to change length of that void
* TestFile6_SmallSeekHead.mkv
* SeekHead size of 2, which caused an exception (see github issue #10).
* Do that this is not a valid mkv file accordant to MkValidator.
*/
public class MatroskaLibTest
{
Expand All @@ -22,7 +25,7 @@ public class MatroskaLibTest
[InlineData("mkv files/TestFile1_MkvToolNix.mkv")]
public void ReadTestFile1(string file)
{
string[] filePaths = { file };
string[] filePaths = [file];

List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles(filePaths);
List<Track> lsTracks = lsMkvFiles[0].tracks;
Expand All @@ -40,12 +43,12 @@ public void ReadTestFile1(string file)
public void WriteTestFile1(string file)
{
File.Copy(file, TestFilePath, true);
List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles(new[] { TestFilePath });
List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles([TestFilePath]);
lsMkvFiles[0].tracks[0].flagDefault = false;
lsMkvFiles[0].tracks[2].flagDefault = false;

MatroskaWriter.WriteMkvFile(lsMkvFiles[0]);
lsMkvFiles = MatroskaReader.ReadMkvFiles(new[] { TestFilePath });
lsMkvFiles = MatroskaReader.ReadMkvFiles([TestFilePath]);
List<Track> lsTracks = lsMkvFiles[0].tracks;

lsTracks.Should().HaveCount(3);
Expand All @@ -59,7 +62,7 @@ public void WriteTestFile1(string file)
[InlineData("mkv files/TestFile2_MkvToolNix.mkv")]
public void ReadTestFile2(string file)
{
string[] filePaths = { file };
string[] filePaths = [file];

List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles(filePaths);
List<Track> lsTracks = lsMkvFiles[0].tracks;
Expand All @@ -79,12 +82,12 @@ public void ReadTestFile2(string file)
public void WriteTestFile2(string file)
{
File.Copy(file, TestFilePath, true);
List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles(new[] { TestFilePath });
List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles([TestFilePath]);
lsMkvFiles[0].tracks[1].flagDefault = true;
lsMkvFiles[0].tracks[3].flagDefault = true;

MatroskaWriter.WriteMkvFile(lsMkvFiles[0]);
lsMkvFiles = MatroskaReader.ReadMkvFiles(new[] { TestFilePath });
lsMkvFiles = MatroskaReader.ReadMkvFiles([TestFilePath]);
List<Track> lsTracks = lsMkvFiles[0].tracks;

lsTracks.Should().HaveCount(5);
Expand All @@ -100,7 +103,7 @@ public void WriteTestFile2(string file)
[InlineData("mkv files/TestFile3_HandBrake.mkv")]
public void ReadTestFile3(string file)
{
string[] filePaths = { file };
string[] filePaths = [file];

List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles(filePaths);
List<Track> lsTracks = lsMkvFiles[0].tracks;
Expand All @@ -119,12 +122,12 @@ public void ReadTestFile3(string file)
public void WriteTestFile3(string file)
{
File.Copy(file, TestFilePath, true);
List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles(new[] { TestFilePath });
List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles([TestFilePath]);
lsMkvFiles[0].tracks[1].flagDefault = true;
lsMkvFiles[0].tracks[3].flagDefault = true;

MatroskaWriter.WriteMkvFile(lsMkvFiles[0]);
lsMkvFiles = MatroskaReader.ReadMkvFiles(new[] { TestFilePath });
lsMkvFiles = MatroskaReader.ReadMkvFiles([TestFilePath]);
List<Track> lsTracks = lsMkvFiles[0].tracks;

lsTracks.Should().HaveCount(4);
Expand All @@ -140,7 +143,7 @@ public void WriteTestFile3(string file)
[InlineData("mkv files/TestFile5_MkvProEdit.mkv")]
public void ReadTestFile4(string file)
{
string[] filePaths = { file };
string[] filePaths = [file];

List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles(filePaths);
List<Track> lsTracks = lsMkvFiles[0].tracks;
Expand All @@ -158,12 +161,12 @@ public void ReadTestFile4(string file)
public void WriteTestFile4(string file)
{
File.Copy(file, TestFilePath, true);
List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles(new[] { TestFilePath });
List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles([TestFilePath]);
lsMkvFiles[0].tracks[0].flagDefault = false;
lsMkvFiles[0].tracks[2].flagDefault = false;

MatroskaWriter.WriteMkvFile(lsMkvFiles[0]);
lsMkvFiles = MatroskaReader.ReadMkvFiles(new[] { TestFilePath });
lsMkvFiles = MatroskaReader.ReadMkvFiles([TestFilePath]);
List<Track> lsTracks = lsMkvFiles[0].tracks;

lsTracks.Should().HaveCount(3);
Expand All @@ -172,4 +175,14 @@ public void WriteTestFile4(string file)
lsTracks[2].Should().BeEquivalentTo(new { flagDefault = false, flagForced = false, language = "jpn", type = TrackTypeEnum.audio });
MkvValidator.Validate(TestFilePath);
}

[Fact]
public void FileWithSeekHeadSizeOf2ShouldNotThrow()
{
File.Copy("mkv files/TestFile6_SmallSeekHead.mkv", TestFilePath, true);
List<MkvFile> lsMkvFiles = MatroskaReader.ReadMkvFiles([TestFilePath]);
lsMkvFiles[0].tracks[0].flagDefault = false;

MatroskaWriter.WriteMkvFile(lsMkvFiles[0]);
}
}
2 changes: 1 addition & 1 deletion MatroskaLib/MatroskaLib.Test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The unit tests depend on ffmpeg and mkvalidator to make sure the program outputs
If you are on a Ubuntu based distro: [use this PPA](https://launchpad.net/~hizo/+archive/ubuntu/mkv-extractor-gui) to install mkvalidator
Otherwise: [Download the source code](https://sourceforge.net/projects/matroska/files/mkvalidator/) and compile using make.

**MacOS**
**MacOS**
Use homebrew:
```
brew install mkvalidator ffmpeg
Expand Down
3 changes: 2 additions & 1 deletion MatroskaLib/MatroskaLib/Helpers/ByteHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public static void ChangeLength(List<byte> lsBytes, int position, List<byte> lsL

// Convert new length to bytes and strip bytes
List<byte> lsNewBytes = ToBytes(ret);
if (lsNewBytes.Count != lsLengthBytes.Count) throw new Exception("New length doesn't fit into existing length element");
if (lsNewBytes.Count != lsLengthBytes.Count)
throw new InvalidOperationException($"New length bytes are not the same length as the old ones. Old length: {lsLengthBytes.Count}, new length: {lsNewBytes.Count}");

// Replace old length with new length bytes
lsBytes.RemoveRange(position, lsNewBytes.Count);
Expand Down
2 changes: 1 addition & 1 deletion MatroskaLib/MatroskaLib/Helpers/CustomExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static void LocateElement(this EbmlReader reader, ulong descriptor)
}
}

throw new Exception($"Cannot find descriptor 0x{descriptor:X}");
throw new InvalidOperationException($"Cannot find descriptor 0x{descriptor:X}");
}
}
}
13 changes: 9 additions & 4 deletions MatroskaLib/MatroskaLib/MatroskaWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace MatroskaLib;

public static class MatroskaWriter
{
public static void WriteMkvFile(MkvFile mkfFile)
public static void WriteMkvFile(MkvFile mkfFile, bool dryRun = false)
{
using var dataStream = File.Open(mkfFile.filePath, FileMode.Open);
dataStream.Seek(0, SeekOrigin.Begin);
Expand All @@ -25,6 +25,7 @@ public static void WriteMkvFile(MkvFile mkfFile)
offset, lsBytes);

// Write modified changes to file
if (dryRun) return;
dataStream.Seek(0, SeekOrigin.Begin);
dataStream.Write(lsBytes.ToArray(), 0, lsBytes.Count);
}
Expand Down Expand Up @@ -71,10 +72,14 @@ private static void _ChangeVoidLengthAndHeaders(List<Seek> seekList, int? seekHe
foreach (var s in seekList.Where(s =>
s.seekId is MatroskaElements.Tracks or MatroskaElements.SegmentInfo))
{
int desiredLength = Convert.ToInt32(lsBytes[s.seekPositionByteNumber - 1] - 0x80);
List<byte> lsNewBytes = ByteHelper.ToBytes(s.seekPosition - (ulong)offset);
if (desiredLength != lsNewBytes.Count)
throw new Exception("New seekposition doesn't fit into existing element");
if (lsNewBytes.Count > s.elementLength)
throw new InvalidOperationException($"New seekPosition bytes are bigger than the old one. Trying to fit {lsNewBytes.Count} bytes into {s.elementLength} bytes");
if (lsNewBytes.Count < s.elementLength)
{
// The new seekPosition is smaller than the old one, add padding
lsNewBytes.AddRange(new byte[s.elementLength - lsNewBytes.Count]);
}

lsBytes.RemoveRange(s.seekPositionByteNumber, lsNewBytes.Count);
lsBytes.InsertRange(s.seekPositionByteNumber, lsNewBytes);
Expand Down
7 changes: 4 additions & 3 deletions MatroskaLib/MatroskaLib/MkvFilesContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,19 @@ namespace MatroskaLib;
public class MkvFilesContainer
{
public readonly List<MkvFile> MkvFiles = new();
public readonly List<MkvFile> MkFilesRejected = new();
public readonly List<(MkvFile file, string error)> MkFilesRejected = new();

public MkvFilesContainer(string[] filePaths)
{
var files = MatroskaReader.ReadMkvFiles(filePaths);
MkvFiles.Add(files[0]);
for (int i = 1; i < files.Count; i++)
{
if (files[0].CompareTo(files[i]) == 0)
string? error = files[0].CompareToGetError(files[i]);
if (error is null)
MkvFiles.Add(files[i]);
else
MkFilesRejected.Add(files[i]);
MkFilesRejected.Add((files[i], error));
}
}

Expand Down
15 changes: 10 additions & 5 deletions MatroskaLib/MatroskaLib/Types/MkvFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace MatroskaLib.Types;

public record MkvFile : IComparable<MkvFile>
public record MkvFile
{
public required string filePath { get; init; }
public required List<Track> tracks { get; init; }
Expand All @@ -18,7 +18,7 @@ public record MkvFile : IComparable<MkvFile>
public required int tracksPosition { get; init; }
public required int beginHeaderPosition { get; init; }

public int CompareTo(MkvFile? other)
public string? CompareToGetError(MkvFile? other)
{
if (other is null)
throw new ArgumentNullException(nameof(other));
Expand All @@ -27,11 +27,16 @@ public int CompareTo(MkvFile? other)
{
var track = tracks[i];
var trackOther = other.tracks.ElementAtOrDefault(i);
if (trackOther is null || track.number != trackOther.number || track.language != trackOther.language)
return -1;

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 0;
return null;
}

public override string ToString() =>
Expand Down
2 changes: 2 additions & 0 deletions MatroskaLib/MatroskaLib/Types/Seek.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class Seek
public ulong seekId { get; private set; }
public ulong seekPosition { get; private set; }
public int seekPositionByteNumber { get; private set; }
public int elementLength { get; private set; }

public Seek(EbmlReader reader) =>
_reader = reader;
Expand All @@ -23,6 +24,7 @@ public void ApplyElement(FileStream fileStream)
{
seekPositionByteNumber = (int)fileStream.Position;
seekPosition = _reader.ReadUInt();
elementLength = (int)_reader.ElementSize;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<key>CFBundleIdentifier</key>
<string>com.mikemoolenaar.MkvDefaultTrackChanger</string>
<key>CFBundleShortVersionString</key>
<string>1.1.0</string>
<string>1.2.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.12</string>
<key>CFBundleDevelopmentRegion</key>
Expand Down
Loading

0 comments on commit bbba054

Please sign in to comment.