Skip to content

Commit

Permalink
MP4 : Support alternate way of storing multiple values [#290]
Browse files Browse the repository at this point in the history
  • Loading branch information
Zeugma440 committed Dec 1, 2024
1 parent eba0364 commit bb23499
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 7 deletions.
25 changes: 25 additions & 0 deletions ATL.unit-test/IO/MetaData/MP4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,7 @@ public void TagIO_RW_MP4_Multiple_Values()
{
new ConsoleLogger();

// == 1st variant : repetition of the same metadata structure
string testFileLocation = TestUtils.CopyAsTempTestFile("MP4/multiple_artists.m4a");
AudioDataManager theFile = new AudioDataManager(AudioDataIOFactory.GetInstance().GetFromPath(testFileLocation));

Expand All @@ -1210,6 +1211,30 @@ public void TagIO_RW_MP4_Multiple_Values()
// Check if separated values are still intact after rewriting
Assert.AreEqual("ArtistA" + ATL.Settings.InternalValueSeparator + "ArtistB" + ATL.Settings.InternalValueSeparator + "Demo", theFile.NativeTag.Artist);

if (Settings.DeleteAfterSuccess) File.Delete(testFileLocation);


// == 2nd variant : repetition of the 'data' atom inside one single field
testFileLocation = TestUtils.CopyAsTempTestFile("MP4/multiple_artists2.m4a");
theFile = new AudioDataManager(AudioDataIOFactory.GetInstance().GetFromPath(testFileLocation));

// Read
Assert.IsTrue(theFile.ReadFromFile(false, true));
Assert.IsNotNull(theFile.NativeTag);
Assert.IsTrue(theFile.NativeTag.Exists);

Assert.AreEqual("ArtistA" + ATL.Settings.InternalValueSeparator + "ArtistB" + ATL.Settings.InternalValueSeparator + "Demo2", theFile.NativeTag.Artist);

// Write
theTag = new TagHolder();
theTag.Title = "blah";

Assert.IsTrue(theFile.UpdateTagInFileAsync(theTag.tagData, MetaDataIOFactory.TagType.NATIVE).GetAwaiter().GetResult());
Assert.IsTrue(theFile.ReadFromFile(false, true));

// Check if separated values are still intact after rewriting
Assert.AreEqual("ArtistA" + ATL.Settings.InternalValueSeparator + "ArtistB" + ATL.Settings.InternalValueSeparator + "Demo2", theFile.NativeTag.Artist);

// Get rid of the working copy
if (Settings.DeleteAfterSuccess) File.Delete(testFileLocation);
}
Expand Down
Binary file not shown.
33 changes: 26 additions & 7 deletions ATL/AudioData/IO/MP4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,7 +1449,31 @@ private void readTag(BinaryReader source, ReadTagParams readTagParams)

if (1 == dataClass) // UTF-8 Text
{
values.Add(Encoding.UTF8.GetString(source.ReadBytes((int)metadataSize - 16)));
uint strSize = metadataSize;
long lastLocation;
var currentData = new List<string>();

do
{
int dataSize = Math.Max(0, (int)strSize - 16);
if (dataSize > 0)
{
strData = Encoding.UTF8.GetString(source.ReadBytes((int)strSize - 16));
currentData.Add(strData);
}

// Look for multiple values
lastLocation = source.BaseStream.Position;
strSize = navigateToAtom(source, "data");
if (strSize > 0)
{
source.BaseStream.Seek(8, SeekOrigin.Current);
metadataSize += strSize;
}
} while (strSize > 0);
source.BaseStream.Seek(lastLocation, SeekOrigin.Begin);
strData = string.Join(Settings.InternalValueSeparator, currentData);
values.Add(strData);
}
else if (21 == dataClass) // int8-16-24-32
{
Expand Down Expand Up @@ -2051,23 +2075,18 @@ private void writeTextFrame(BinaryWriter writer, string frameCode, string text)
{
string[] values = text.Split(Settings.InternalValueSeparator);
var first = true;
// Handle multiple values
// Handle multiple values = repeat the 'data' atom
foreach (string value in values)
{
if (0 == value.Length) continue;
if (first) first = false;
else
{
finalFramePos = writer.BaseStream.Position;
writer.BaseStream.Seek(frameSizePos1, SeekOrigin.Begin);
writer.Write(StreamUtils.EncodeBEUInt32(Convert.ToUInt32(finalFramePos - frameSizePos1)));
writer.BaseStream.Seek(frameSizePos2, SeekOrigin.Begin);
writer.Write(StreamUtils.EncodeBEUInt32(Convert.ToUInt32(finalFramePos - frameSizePos2)));
writer.BaseStream.Seek(finalFramePos, SeekOrigin.Begin);

frameSizePos1 = writer.BaseStream.Position;
writer.Write(0); // Frame size placeholder to be rewritten in a few lines
writer.Write(Utils.Latin1Encoding.GetBytes(frameCode));
frameSizePos2 = writer.BaseStream.Position;
writer.Write(0); // Frame size placeholder to be rewritten in a few lines
writer.Write(Utils.Latin1Encoding.GetBytes("data"));
Expand Down

0 comments on commit bb23499

Please sign in to comment.