Skip to content

Commit 99e61f5

Browse files
authored
Merge branch 'master' into feature/dng
2 parents 4b12960 + 0cef5a2 commit 99e61f5

16 files changed

+698
-57
lines changed

MetadataExtractor.sln

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio 15
4-
VisualStudioVersion = 15.0.27130.0
4+
VisualStudioVersion = 15.0.27130.2010
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8CF154EA-6A2C-4BF4-B263-78758F834192}"
77
ProjectSection(SolutionItems) = preProject
@@ -157,6 +157,6 @@ Global
157157
HideSolutionNode = FALSE
158158
EndGlobalSection
159159
GlobalSection(ExtensibilityGlobals) = postSolution
160-
SolutionGuid = {B3C98CDA-0400-456E-887B-70F751903DC3}
160+
SolutionGuid = {15F8CDD5-5EFF-4277-8559-5AA83D1353C8}
161161
EndGlobalSection
162162
EndGlobal
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#region License
2+
//
3+
// Copyright 2002-2017 Drew Noakes
4+
// Ported from Java to C# by Yakov Danilov for Imazen LLC in 2014
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// More information about this project is available at:
19+
//
20+
// https://github.com/drewnoakes/metadata-extractor-dotnet
21+
// https://drewnoakes.com/code/exif/
22+
//
23+
#endregion
24+
25+
using System.Diagnostics.CodeAnalysis;
26+
using JetBrains.Annotations;
27+
28+
namespace MetadataExtractor.Formats.Avi
29+
{
30+
/// <author>Payton Garland</author>
31+
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
32+
public class AviDescriptor : TagDescriptor<AviDirectory>
33+
{
34+
public AviDescriptor([NotNull] AviDirectory directory)
35+
: base(directory)
36+
{
37+
}
38+
39+
public override string GetDescription(int tagType)
40+
{
41+
switch (tagType)
42+
{
43+
case AviDirectory.TAG_WIDTH:
44+
case AviDirectory.TAG_HEIGHT:
45+
return Directory.GetString(tagType) + " pixels";
46+
}
47+
return base.GetDescription(tagType);
48+
}
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#region License
2+
//
3+
// Copyright 2002-2017 Drew Noakes
4+
// Ported from Java to C# by Yakov Danilov for Imazen LLC in 2014
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// More information about this project is available at:
19+
//
20+
// https://github.com/drewnoakes/metadata-extractor-dotnet
21+
// https://drewnoakes.com/code/exif/
22+
//
23+
#endregion
24+
25+
using System.Collections.Generic;
26+
using System.Diagnostics.CodeAnalysis;
27+
28+
namespace MetadataExtractor.Formats.Avi
29+
{
30+
/// <author>Payton Garland</author>
31+
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
32+
public class AviDirectory : Directory
33+
{
34+
public const int TAG_FRAMES_PER_SECOND = 1;
35+
public const int TAG_SAMPLES_PER_SECOND = 2;
36+
public const int TAG_DURATION = 3;
37+
public const int TAG_VIDEO_CODEC = 4;
38+
public const int TAG_AUDIO_CODEC = 5;
39+
public const int TAG_WIDTH = 6;
40+
public const int TAG_HEIGHT = 7;
41+
public const int TAG_STREAMS = 8;
42+
43+
private static readonly Dictionary<int, string> _tagNameMap = new Dictionary<int, string>
44+
{
45+
{TAG_FRAMES_PER_SECOND, "Frames Per Second"},
46+
{TAG_SAMPLES_PER_SECOND, "Samples Per Second"},
47+
{TAG_DURATION, "Duration"},
48+
{TAG_VIDEO_CODEC, "Video Codec"},
49+
{TAG_AUDIO_CODEC, "Audio Codec"},
50+
{TAG_WIDTH, "Width"},
51+
{TAG_HEIGHT, "Height"},
52+
{TAG_STREAMS, "Stream Count"}
53+
};
54+
55+
public AviDirectory()
56+
{
57+
SetDescriptor(new AviDescriptor(this));
58+
}
59+
60+
public override string Name => "Avi";
61+
62+
protected override bool TryGetTagName(int tagType, out string tagName)
63+
{
64+
return _tagNameMap.TryGetValue(tagType, out tagName);
65+
}
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#region License
2+
//
3+
// Copyright 2002-2017 Drew Noakes
4+
// Ported from Java to C# by Yakov Danilov for Imazen LLC in 2014
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// More information about this project is available at:
19+
//
20+
// https://github.com/drewnoakes/metadata-extractor-dotnet
21+
// https://drewnoakes.com/code/exif/
22+
//
23+
#endregion
24+
25+
using System.Collections.Generic;
26+
using System.IO;
27+
using JetBrains.Annotations;
28+
using MetadataExtractor.Formats.FileSystem;
29+
using MetadataExtractor.Formats.Riff;
30+
using MetadataExtractor.IO;
31+
32+
#if NET35
33+
using DirectoryList = System.Collections.Generic.IList<MetadataExtractor.Directory>;
34+
#else
35+
using DirectoryList = System.Collections.Generic.IReadOnlyList<MetadataExtractor.Directory>;
36+
#endif
37+
38+
namespace MetadataExtractor.Formats.Avi
39+
{
40+
/// <summary>Obtains metadata from Avi files.</summary>
41+
/// <author>Drew Noakes https://drewnoakes.com</author>
42+
public static class AviMetadataReader
43+
{
44+
/// <exception cref="System.IO.IOException"/>
45+
/// <exception cref="RiffProcessingException"/>
46+
[NotNull]
47+
public static DirectoryList ReadMetadata([NotNull] string filePath)
48+
{
49+
var directories = new List<Directory>();
50+
51+
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
52+
directories.AddRange(ReadMetadata(stream));
53+
54+
directories.Add(new FileMetadataReader().Read(filePath));
55+
56+
return directories;
57+
}
58+
59+
/// <exception cref="System.IO.IOException"/>
60+
/// <exception cref="RiffProcessingException"/>
61+
[NotNull]
62+
public static DirectoryList ReadMetadata([NotNull] Stream stream)
63+
{
64+
var directories = new List<Directory>();
65+
new RiffReader().ProcessRiff(new SequentialStreamReader(stream), new AviRiffHandler(directories));
66+
return directories;
67+
}
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#region License
2+
//
3+
// Copyright 2002-2017 Drew Noakes
4+
// Ported from Java to C# by Yakov Danilov for Imazen LLC in 2014
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// More information about this project is available at:
19+
//
20+
// https://github.com/drewnoakes/metadata-extractor-dotnet
21+
// https://drewnoakes.com/code/exif/
22+
//
23+
#endregion
24+
25+
using System;
26+
using System.Collections.Generic;
27+
using System.IO;
28+
using System.Text;
29+
using JetBrains.Annotations;
30+
using MetadataExtractor.Formats.Riff;
31+
using MetadataExtractor.IO;
32+
33+
namespace MetadataExtractor.Formats.Avi
34+
{
35+
/// <summary>
36+
/// Implementation of <see cref="IRiffHandler"/> specialising in AVI support.
37+
/// </summary>
38+
/// <remarks>
39+
/// Extracts data from chunk/list types:
40+
/// <list type="bullet">
41+
/// <item><c>"avih"</c>: width, height, streams</item>
42+
/// <item><c>"strh"</c>: frames/second, samples/second, duration, video codec</item>
43+
/// </list>
44+
/// Sources:
45+
/// http://www.alexander-noe.com/video/documentation/avi.pdf
46+
/// https://msdn.microsoft.com/en-us/library/ms899422.aspx
47+
/// https://www.loc.gov/preservation/digital/formats/fdd/fdd000025.shtml
48+
/// </remarks>
49+
/// <author>Payton Garland</author>
50+
public sealed class AviRiffHandler : IRiffHandler
51+
{
52+
[NotNull]
53+
private readonly List<Directory> _directories;
54+
55+
public AviRiffHandler([NotNull] List<Directory> directories)
56+
{
57+
_directories = directories;
58+
}
59+
60+
public bool ShouldAcceptRiffIdentifier(string identifier) => identifier == "AVI ";
61+
62+
public bool ShouldAcceptChunk(string fourCc) => fourCc == "strh" ||
63+
fourCc == "avih";
64+
65+
public bool ShouldAcceptList(string fourCc) => fourCc == "hdrl" ||
66+
fourCc == "strl" ||
67+
fourCc == "AVI ";
68+
69+
public void ProcessChunk(string fourCc, byte[] payload)
70+
{
71+
switch (fourCc)
72+
{
73+
case "strh":
74+
{
75+
string error = null;
76+
var reader = new ByteArrayReader(payload, isMotorolaByteOrder: false);
77+
string fccType = null;
78+
string fccHandler = null;
79+
float dwScale = 0;
80+
float dwRate = 0;
81+
int dwLength = 0;
82+
try
83+
{
84+
fccType = reader.GetString(0, 4, Encoding.ASCII);
85+
fccHandler = reader.GetString(4, 4, Encoding.ASCII);
86+
//int dwFlags = reader.GetInt32(8);
87+
//int wPriority = reader.GetInt16(12);
88+
//int wLanguage = reader.GetInt16(14);
89+
//int dwInitialFrames = reader.GetInt32(16);
90+
dwScale = reader.GetFloat32(20);
91+
dwRate = reader.GetFloat32(24);
92+
//int dwStart = reader.GetInt32(28);
93+
dwLength = reader.GetInt32(32);
94+
//int dwSuggestedBufferSize = reader.GetInt32(36);
95+
//int dwQuality = reader.GetInt32(40);
96+
//int dwSampleSize = reader.GetInt32(44);
97+
//byte[] rcFrame = reader.GetBytes(48, 2);
98+
}
99+
catch (IOException e)
100+
{
101+
error = "Exception reading AviRiff chunk 'strh' : " + e.Message;
102+
}
103+
104+
var directory = new AviDirectory();
105+
if (error == null)
106+
{
107+
if (fccType == "vids")
108+
{
109+
directory.Set(AviDirectory.TAG_FRAMES_PER_SECOND, (dwRate / dwScale));
110+
111+
double duration = dwLength / (dwRate / dwScale);
112+
int hours = (int)duration / (int)(Math.Pow(60, 2));
113+
int minutes = ((int)duration / (int)(Math.Pow(60, 1))) - (hours * 60);
114+
int seconds = (int)Math.Round((duration / (Math.Pow(60, 0))) - (minutes * 60));
115+
string time = new DateTime(2000, 1, 1, hours, minutes, seconds).ToString("hh:mm:ss");
116+
117+
directory.Set(AviDirectory.TAG_DURATION, time);
118+
directory.Set(AviDirectory.TAG_VIDEO_CODEC, fccHandler);
119+
}
120+
else
121+
if (fccType == "auds")
122+
{
123+
directory.Set(AviDirectory.TAG_SAMPLES_PER_SECOND, (dwRate / dwScale));
124+
}
125+
}
126+
else
127+
directory.AddError(error);
128+
_directories.Add(directory);
129+
break;
130+
}
131+
case "avih":
132+
{
133+
string error = null;
134+
var reader = new ByteArrayReader(payload, isMotorolaByteOrder: false);
135+
int dwStreams = 0;
136+
int dwWidth = 0;
137+
int dwHeight = 0;
138+
try
139+
{
140+
//int dwMicroSecPerFrame = reader.GetInt32(0);
141+
//int dwMaxBytesPerSec = reader.GetInt32(4);
142+
//int dwPaddingGranularity = reader.GetInt32(8);
143+
//int dwFlags = reader.GetInt32(12);
144+
//int dwTotalFrames = reader.GetInt32(16);
145+
//int dwInitialFrames = reader.GetInt32(20);
146+
dwStreams = reader.GetInt32(24);
147+
//int dwSuggestedBufferSize = reader.GetInt32(28);
148+
dwWidth = reader.GetInt32(32);
149+
dwHeight = reader.GetInt32(36);
150+
//byte[] dwReserved = reader.GetBytes(40, 4);
151+
}
152+
catch (IOException e)
153+
{
154+
error = "Exception reading AviRiff chunk 'avih' : " + e.Message;
155+
}
156+
157+
var directory = new AviDirectory();
158+
if (error == null)
159+
{
160+
directory.Set(AviDirectory.TAG_WIDTH, dwWidth);
161+
directory.Set(AviDirectory.TAG_HEIGHT, dwHeight);
162+
directory.Set(AviDirectory.TAG_STREAMS, dwStreams);
163+
}
164+
else
165+
directory.AddError(error);
166+
_directories.Add(directory);
167+
break;
168+
}
169+
}
170+
}
171+
}
172+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using JetBrains.Annotations;
3+
4+
namespace MetadataExtractor.Formats.Exif.Makernotes
5+
{
6+
/// <summary>
7+
/// Provides human-readable string representations of tag values stored in a <see cref="DJIMakernoteDirectory"/>.
8+
/// </summary>
9+
/// <remarks>Using information from https://metacpan.org/pod/distribution/Image-ExifTool/lib/Image/ExifTool/TagNames.pod#DJI-Tags</remarks>
10+
/// <author>Charlie Matherne, adapted from Drew Noakes https://drewnoakes.com</author>
11+
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
12+
public class DJIMakernoteDescriptor : TagDescriptor<DJIMakernoteDirectory>
13+
{
14+
public DJIMakernoteDescriptor([NotNull] DJIMakernoteDirectory directory)
15+
: base(directory)
16+
{
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)