Skip to content

Commit

Permalink
add support for apple live-photo mov file refer drewnoakes#344 drewno…
Browse files Browse the repository at this point in the history
  • Loading branch information
naughtyGitCat committed Sep 9, 2024
1 parent ed79cc0 commit fa422ef
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 2 deletions.
Binary file not shown.
42 changes: 42 additions & 0 deletions MetadataExtractor.Tests/Formats/Apple/LivePhotoMovTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Drew Noakes and contributors. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace MetadataExtractor.Tests.Formats.Apple;

public sealed class LivePhotoMovTest
{
private const string TestFile = "Data/apple-livephoto-quicktime.mov";

[Fact]
public void GetLivePhotoQuickTimeInfo()
{
var exception = Record.Exception(() => ImageMetadataReader.ReadMetadata(TestFile));
Assert.Null(exception);
}

[Fact]
public void GetDirectoryNames()
{
var directories =ImageMetadataReader.ReadMetadata(TestFile);
Assert.NotNull(directories);
Assert.NotEmpty(directories);
var names = directories.Select(d => d.Name).ToArray();
Assert.Contains("QuickTime Movie Header", names);
Assert.Contains("QuickTime Track Header", names);
Assert.Contains("QuickTime Metadata Header", names);
Assert.Contains("File Type", names);
Assert.Contains("File", names);
}

/// <summary>
/// Live Photos is actually two files. Original JPEG/HEIF Image and Full HD Video(QuickTime).
/// in the ios ecology, live photo connect image with mov with same name, and meta key `Content Identifier`
/// </summary>
[Fact]
public void GetLivePhotoContentIdentifier()
{
var directories =ImageMetadataReader.ReadMetadata(TestFile);
var quickTimeMetadataHeaderDirectory = directories.Where(d => d.Name == "QuickTime Metadata Header")!.First();
var contentIdentifierTag = quickTimeMetadataHeaderDirectory.Tags.Where(t => t.Name == "Content Identifier")!.First();
Assert.Equal("EE6D649E-788F-4E3A-BCD2-483651BF7B34", contentIdentifierTag.Description);
}

}
31 changes: 29 additions & 2 deletions MetadataExtractor/Formats/QuickTime/QuickTimeTypeChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,40 @@ internal sealed class QuickTimeTypeChecker : ITypeChecker

private static ReadOnlySpan<byte> FtypBytes => "ftyp"u8;

public int ByteCount => 12;
public int ByteCount => 16;

public Util.FileType CheckType(byte[] bytes)
public Util.FileType CheckTypeOld(byte[] bytes)
{
return bytes.AsSpan(4, 4).SequenceEqual(FtypBytes)
? _ftypTrie.Find(bytes.AsSpan(8, 4))
: Util.FileType.Unknown;
}

public Util.FileType CheckType(byte[] bytes)
{
// for standard apple quicktime format
// 00000000: 0000 0014 6674 7970 7174 2020 0000 0000 ....ftypqt ....
// 00000010: 7174 2020 0000 0008 7769 6465 003e f32a qt ....wide.>.*
// 00000020: 6d64 6174 cefe f2fe 09ff 09ff 0dff 31ff mdat..........1.
if (bytes.AsSpan(4, 4).SequenceEqual(FtypBytes))
{
return _ftypTrie.Find(bytes.AsSpan(8, 4));
}

// for live photo which is export from native protocols with afcclient/afcservice
// example 1
// 00000000: 0000 0008 7769 6465 0033 a50e 6d64 6174 ....wide.3..mdat
// 00000010: 0000 001f 4e01 051a 4756 4adc 5c4c 433f ....N...GVJ.\LC?
// 00000020: 94ef c511 3cd1 43a8 03ee 1111 ee02 00c3 ....<.C.........
// example 2
// 00000000: 0000 0008 7769 6465 004f 854d 6d64 6174 ....wide.O.Mmdat
// 00000010: 0000 002a 4e01 0523 4756 4adc 5c4c 433f ...*N..#GVJ.\LC?
// 00000020: 94ef c511 3cd1 43a8 0000 0300 0003 0000 ....<.C.........
if (bytes.AsSpan(4, 4).SequenceEqual("wide"u8) && bytes.AsSpan(12, 4).SequenceEqual("mdat"u8))
{
return Util.FileType.QuickTime;
}
return Util.FileType.Unknown;
}
}
}

0 comments on commit fa422ef

Please sign in to comment.