Skip to content

Commit b8ecff9

Browse files
committed
Improve AVI handling
- Fix end of stream exception - Add "Date/Time Original" tag - Use "AVI" for directory name, matching Java - Return all tags on a single AviDirectory rather than multiple
1 parent 9d5c41d commit b8ecff9

File tree

11 files changed

+74
-71
lines changed

11 files changed

+74
-71
lines changed

MetadataExtractor/Formats/Avi/AviDirectory.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class AviDirectory : Directory
1717
public const int TagWidth = 6;
1818
public const int TagHeight = 7;
1919
public const int TagStreams = 8;
20+
public const int TagDateTimeOriginal = 320;
2021

2122
private static readonly Dictionary<int, string> _tagNameMap = new Dictionary<int, string>
2223
{
@@ -27,15 +28,16 @@ public class AviDirectory : Directory
2728
{TagAudioCodec, "Audio Codec"},
2829
{TagWidth, "Width"},
2930
{TagHeight, "Height"},
30-
{TagStreams, "Stream Count"}
31+
{TagStreams, "Stream Count"},
32+
{TagDateTimeOriginal, "Date/Time Original"}
3133
};
3234

3335
public AviDirectory()
3436
{
3537
SetDescriptor(new AviDescriptor(this));
3638
}
3739

38-
public override string Name => "Avi";
40+
public override string Name => "AVI";
3941

4042
protected override bool TryGetTagName(int tagType, out string tagName)
4143
{

MetadataExtractor/Formats/Avi/AviRiffHandler.cs

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ namespace MetadataExtractor.Formats.Avi
2727
public sealed class AviRiffHandler : IRiffHandler
2828
{
2929
private readonly List<Directory> _directories;
30+
private AviDirectory? _directory;
3031

3132
public AviRiffHandler(List<Directory> directories)
3233
{
@@ -35,51 +36,48 @@ public AviRiffHandler(List<Directory> directories)
3536

3637
public bool ShouldAcceptRiffIdentifier(string identifier) => identifier == "AVI ";
3738

38-
public bool ShouldAcceptChunk(string fourCc) => fourCc == "strh" ||
39-
fourCc == "avih";
39+
public bool ShouldAcceptChunk(string fourCc) => fourCc switch
40+
{
41+
"strh" => true,
42+
"avih" => true,
43+
"IDIT" => true,
44+
_ => false
45+
};
4046

41-
public bool ShouldAcceptList(string fourCc) => fourCc == "hdrl" ||
42-
fourCc == "strl" ||
43-
fourCc == "AVI ";
47+
public bool ShouldAcceptList(string fourCc) => fourCc switch
48+
{
49+
"hdrl" => true,
50+
"strl" => true,
51+
"AVI " => true,
52+
_ => false
53+
};
4454

4555
public void ProcessChunk(string fourCc, byte[] payload)
4656
{
4757
switch (fourCc)
4858
{
4959
case "strh":
5060
{
51-
string? error = null;
5261
var reader = new ByteArrayReader(payload, isMotorolaByteOrder: false);
53-
string? fccType = null;
54-
string? fccHandler = null;
55-
float dwScale = 0;
56-
float dwRate = 0;
57-
int dwLength = 0;
62+
63+
var directory = GetOrCreateAviDirectory();
5864
try
5965
{
60-
fccType = reader.GetString(0, 4, Encoding.ASCII);
61-
fccHandler = reader.GetString(4, 4, Encoding.ASCII);
66+
var fccType = reader.GetString(0, 4, Encoding.ASCII);
67+
var fccHandler = reader.GetString(4, 4, Encoding.ASCII);
6268
//int dwFlags = reader.GetInt32(8);
6369
//int wPriority = reader.GetInt16(12);
6470
//int wLanguage = reader.GetInt16(14);
6571
//int dwInitialFrames = reader.GetInt32(16);
66-
dwScale = reader.GetFloat32(20);
67-
dwRate = reader.GetFloat32(24);
72+
var dwScale = reader.GetFloat32(20);
73+
var dwRate = reader.GetFloat32(24);
6874
//int dwStart = reader.GetInt32(28);
69-
dwLength = reader.GetInt32(32);
75+
var dwLength = reader.GetInt32(32);
7076
//int dwSuggestedBufferSize = reader.GetInt32(36);
7177
//int dwQuality = reader.GetInt32(40);
7278
//int dwSampleSize = reader.GetInt32(44);
7379
//byte[] rcFrame = reader.GetBytes(48, 2);
74-
}
75-
catch (IOException e)
76-
{
77-
error = "Exception reading AviRiff chunk 'strh' : " + e.Message;
78-
}
7980

80-
var directory = new AviDirectory();
81-
if (error == null)
82-
{
8381
if (fccType == "vids")
8482
{
8583
directory.Set(AviDirectory.TagFramesPerSecond, (dwRate / dwScale));
@@ -93,24 +91,23 @@ public void ProcessChunk(string fourCc, byte[] payload)
9391
directory.Set(AviDirectory.TagDuration, time);
9492
directory.Set(AviDirectory.TagVideoCodec, fccHandler!);
9593
}
96-
else
97-
if (fccType == "auds")
94+
else if (fccType == "auds")
9895
{
9996
directory.Set(AviDirectory.TagSamplesPerSecond, (dwRate / dwScale));
10097
}
10198
}
102-
else
103-
directory.AddError(error);
104-
_directories.Add(directory);
99+
catch (IOException e)
100+
{
101+
directory.AddError("Exception reading AviRiff chunk 'strh' : " + e.Message);
102+
}
103+
105104
break;
106105
}
107106
case "avih":
108107
{
109-
string? error = null;
108+
var directory = GetOrCreateAviDirectory();
109+
110110
var reader = new ByteArrayReader(payload, isMotorolaByteOrder: false);
111-
int dwStreams = 0;
112-
int dwWidth = 0;
113-
int dwHeight = 0;
114111
try
115112
{
116113
//int dwMicroSecPerFrame = reader.GetInt32(0);
@@ -119,30 +116,47 @@ public void ProcessChunk(string fourCc, byte[] payload)
119116
//int dwFlags = reader.GetInt32(12);
120117
//int dwTotalFrames = reader.GetInt32(16);
121118
//int dwInitialFrames = reader.GetInt32(20);
122-
dwStreams = reader.GetInt32(24);
119+
var dwStreams = reader.GetInt32(24);
123120
//int dwSuggestedBufferSize = reader.GetInt32(28);
124-
dwWidth = reader.GetInt32(32);
125-
dwHeight = reader.GetInt32(36);
121+
var dwWidth = reader.GetInt32(32);
122+
var dwHeight = reader.GetInt32(36);
126123
//byte[] dwReserved = reader.GetBytes(40, 4);
124+
125+
directory.Set(AviDirectory.TagWidth, dwWidth);
126+
directory.Set(AviDirectory.TagHeight, dwHeight);
127+
directory.Set(AviDirectory.TagStreams, dwStreams);
127128
}
128129
catch (IOException e)
129130
{
130-
error = "Exception reading AviRiff chunk 'avih' : " + e.Message;
131+
directory.AddError("Exception reading AviRiff chunk 'avih' : " + e.Message);
131132
}
132133

133-
var directory = new AviDirectory();
134-
if (error == null)
134+
break;
135+
}
136+
case "IDIT":
137+
{
138+
var reader = new ByteArrayReader(payload);
139+
var str = reader.GetString(0, payload.Length, Encoding.ASCII);
140+
if (str.Length == 26 && str.EndsWith("\n\0"))
135141
{
136-
directory.Set(AviDirectory.TagWidth, dwWidth);
137-
directory.Set(AviDirectory.TagHeight, dwHeight);
138-
directory.Set(AviDirectory.TagStreams, dwStreams);
142+
// ?0A 00? "New Line" + padded to nearest WORD boundary
143+
str = str.Substring(0, 24);
139144
}
140-
else
141-
directory.AddError(error);
142-
_directories.Add(directory);
145+
GetOrCreateAviDirectory().Set(AviDirectory.TagDateTimeOriginal, str);
143146
break;
144147
}
145148
}
146149
}
150+
151+
private AviDirectory GetOrCreateAviDirectory()
152+
{
153+
if (_directory == null)
154+
{
155+
_directory = new AviDirectory();
156+
_directories.Add(_directory);
157+
}
158+
159+
return _directory;
160+
}
147161
}
148162
}

MetadataExtractor/Formats/Riff/RiffReader.cs

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,41 +44,31 @@ public void ProcessRiff(SequentialReader reader, IRiffHandler handler)
4444
if (!handler.ShouldAcceptRiffIdentifier(identifier))
4545
return;
4646

47-
ProcessChunks(reader, sizeLeft, handler);
47+
var maxPosition = reader.Position + sizeLeft;
48+
ProcessChunks(reader, maxPosition, handler);
4849
}
4950

5051
// PROCESS CHUNKS
51-
public void ProcessChunks(SequentialReader reader, int sizeLeft, IRiffHandler handler)
52+
private static void ProcessChunks(SequentialReader reader, long maxPosition, IRiffHandler handler)
5253
{
5354
// Processing chunks. Each chunk is 8 bytes header (4 bytes CC code + 4 bytes length of chunk) + data of the chunk
5455

55-
while (sizeLeft > 0)
56+
while (reader.Position < maxPosition - 8)
5657
{
57-
// Check if end of the file is closer then 8 bytes
58-
if (sizeLeft < 8)
59-
break;
60-
6158
string chunkFourCc = reader.GetString(4, Encoding.ASCII);
6259
int chunkSize = reader.GetInt32();
6360

64-
sizeLeft -= 8;
65-
6661
// NOTE we fail a negative chunk size here (greater than 0x7FFFFFFF) as we cannot allocate arrays larger than this
67-
if (chunkSize < 0 || sizeLeft < chunkSize)
62+
if (chunkSize < 0 || chunkSize + reader.Position > maxPosition)
6863
throw new RiffProcessingException("Invalid RIFF chunk size");
6964

70-
// Check if end of the file is closer then chunkSize bytes
71-
if (sizeLeft < chunkSize)
72-
break;
73-
7465
if (chunkFourCc == "LIST" || chunkFourCc == "RIFF")
7566
{
7667
string listName = reader.GetString(4, Encoding.ASCII);
7768
if (handler.ShouldAcceptList(listName))
78-
ProcessChunks(reader, sizeLeft - 4, handler);
69+
ProcessChunks(reader, reader.Position + chunkSize - 4, handler);
7970
else
80-
reader.Skip(sizeLeft - 4);
81-
sizeLeft -= chunkSize;
71+
reader.Skip(chunkSize - 4);
8272
}
8373
else
8474
{
@@ -92,13 +82,10 @@ public void ProcessChunks(SequentialReader reader, int sizeLeft, IRiffHandler ha
9282
reader.Skip(chunkSize);
9383
}
9484

95-
sizeLeft -= chunkSize;
96-
9785
// Skip any padding byte added to keep chunks aligned to even numbers of bytes
9886
if (chunkSize % 2 == 1)
9987
{
10088
reader.Skip(1);
101-
sizeLeft--;
10289
}
10390
}
10491
}

MetadataExtractor/PublicAPI/net35/PublicAPI.Shipped.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,6 @@ MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(S
12791279
MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(string? message) -> void
12801280
MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(string? message, System.Exception? innerException) -> void
12811281
MetadataExtractor.Formats.Riff.RiffReader
1282-
MetadataExtractor.Formats.Riff.RiffReader.ProcessChunks(MetadataExtractor.IO.SequentialReader! reader, int sizeLeft, MetadataExtractor.Formats.Riff.IRiffHandler! handler) -> void
12831282
MetadataExtractor.Formats.Riff.RiffReader.ProcessRiff(MetadataExtractor.IO.SequentialReader! reader, MetadataExtractor.Formats.Riff.IRiffHandler! handler) -> void
12841283
MetadataExtractor.Formats.Riff.RiffReader.RiffReader() -> void
12851284
MetadataExtractor.Formats.Tga.TgaDeveloperDirectory

MetadataExtractor/PublicAPI/net35/PublicAPI.Unshipped.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDescriptor.GetAccelerati
33
MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDescriptor.GetHdrImageTypeDescription() -> string?
44
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
55
MetadataExtractor.Rational.IsPositive.get -> bool
6+
const MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal = 320 -> int
67
const MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDirectory.TagAccelerationVector = 8 -> int
78
const MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDirectory.TagContentIdentifier = 17 -> int
89
const MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDirectory.TagImageUniqueId = 21 -> int

MetadataExtractor/PublicAPI/net45/PublicAPI.Shipped.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,6 @@ MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(S
12791279
MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(string? message) -> void
12801280
MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(string? message, System.Exception? innerException) -> void
12811281
MetadataExtractor.Formats.Riff.RiffReader
1282-
MetadataExtractor.Formats.Riff.RiffReader.ProcessChunks(MetadataExtractor.IO.SequentialReader! reader, int sizeLeft, MetadataExtractor.Formats.Riff.IRiffHandler! handler) -> void
12831282
MetadataExtractor.Formats.Riff.RiffReader.ProcessRiff(MetadataExtractor.IO.SequentialReader! reader, MetadataExtractor.Formats.Riff.IRiffHandler! handler) -> void
12841283
MetadataExtractor.Formats.Riff.RiffReader.RiffReader() -> void
12851284
MetadataExtractor.Formats.Tga.TgaDeveloperDirectory

MetadataExtractor/PublicAPI/net45/PublicAPI.Unshipped.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDescriptor.GetAccelerati
33
MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDescriptor.GetHdrImageTypeDescription() -> string?
44
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
55
MetadataExtractor.Rational.IsPositive.get -> bool
6+
const MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal = 320 -> int
67
const MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDirectory.TagAccelerationVector = 8 -> int
78
const MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDirectory.TagContentIdentifier = 17 -> int
89
const MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDirectory.TagImageUniqueId = 21 -> int

MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,6 @@ MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(S
12761276
MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(string? message) -> void
12771277
MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(string? message, System.Exception? innerException) -> void
12781278
MetadataExtractor.Formats.Riff.RiffReader
1279-
MetadataExtractor.Formats.Riff.RiffReader.ProcessChunks(MetadataExtractor.IO.SequentialReader! reader, int sizeLeft, MetadataExtractor.Formats.Riff.IRiffHandler! handler) -> void
12801279
MetadataExtractor.Formats.Riff.RiffReader.ProcessRiff(MetadataExtractor.IO.SequentialReader! reader, MetadataExtractor.Formats.Riff.IRiffHandler! handler) -> void
12811280
MetadataExtractor.Formats.Riff.RiffReader.RiffReader() -> void
12821281
MetadataExtractor.Formats.Tga.TgaDeveloperDirectory

MetadataExtractor/PublicAPI/netstandard1.3/PublicAPI.Unshipped.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDescriptor.GetAccelerati
33
MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDescriptor.GetHdrImageTypeDescription() -> string?
44
MetadataExtractor.Rational.Absolute.get -> MetadataExtractor.Rational
55
MetadataExtractor.Rational.IsPositive.get -> bool
6+
const MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal = 320 -> int
67
const MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDirectory.TagAccelerationVector = 8 -> int
78
const MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDirectory.TagContentIdentifier = 17 -> int
89
const MetadataExtractor.Formats.Exif.Makernotes.AppleMakernoteDirectory.TagImageUniqueId = 21 -> int

MetadataExtractor/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,6 @@ MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(S
12791279
MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(string? message) -> void
12801280
MetadataExtractor.Formats.Riff.RiffProcessingException.RiffProcessingException(string? message, System.Exception? innerException) -> void
12811281
MetadataExtractor.Formats.Riff.RiffReader
1282-
MetadataExtractor.Formats.Riff.RiffReader.ProcessChunks(MetadataExtractor.IO.SequentialReader! reader, int sizeLeft, MetadataExtractor.Formats.Riff.IRiffHandler! handler) -> void
12831282
MetadataExtractor.Formats.Riff.RiffReader.ProcessRiff(MetadataExtractor.IO.SequentialReader! reader, MetadataExtractor.Formats.Riff.IRiffHandler! handler) -> void
12841283
MetadataExtractor.Formats.Riff.RiffReader.RiffReader() -> void
12851284
MetadataExtractor.Formats.Tga.TgaDeveloperDirectory

0 commit comments

Comments
 (0)