Skip to content

Commit 9e40123

Browse files
author
njovic
committed
Issue #582 | Support for WebM/MKV
1 parent 9f4ad4c commit 9e40123

14 files changed

+600
-0
lines changed

Source/com/drew/imaging/FileType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public enum FileType
5050
Avif("AVIF", "AV1 Image File Format", "image/avif", "avif"),
5151
Eps("EPS", "Encapsulated PostScript", "application/postscript", "eps", "epsf", "epsi"),
5252
Mp3("MP3", "MPEG Audio Layer III", "audio/mpeg", "mp3"),
53+
Mkv("MKV", "Matroska Video Container", "video/x-matroska", "mkv", "webm"),
5354

5455
/** Sony camera raw. */
5556
Arw("ARW", "Sony Camera Raw", null, "arw"),

Source/com/drew/imaging/FileTypeDetector.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public class FileTypeDetector
103103
_root.addPath(FileType.Swf, "ZWS".getBytes());
104104
_root.addPath(FileType.Vob, new byte[]{0x00, 0x00, 0x01, (byte)0xBA});
105105
_root.addPath(FileType.Zip, "PK".getBytes());
106+
_root.addPath(FileType.Mkv, new byte[]{0x1A, 0x45, (byte) 0xDF, (byte) 0xA3});
106107

107108
int bytesNeeded = _root.getMaxDepth();
108109
for (TypeChecker fixedChecker : _fixedCheckers) {

Source/com/drew/imaging/ImageMetadataReader.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.drew.imaging.heif.HeifMetadataReader;
2828
import com.drew.imaging.ico.IcoMetadataReader;
2929
import com.drew.imaging.jpeg.JpegMetadataReader;
30+
import com.drew.imaging.mkv.MkvMetadataReader;
3031
import com.drew.imaging.mp3.Mp3MetadataReader;
3132
import com.drew.imaging.mp4.Mp4MetadataReader;
3233
import com.drew.imaging.quicktime.QuickTimeMetadataReader;
@@ -182,6 +183,8 @@ public static Metadata readMetadata(@NotNull final InputStream inputStream, fina
182183
case Heif:
183184
case Avif:
184185
return HeifMetadataReader.readMetadata(inputStream);
186+
case Mkv:
187+
return MkvMetadataReader.readMetadata(inputStream);
185188
case Unknown:
186189
throw new ImageProcessingException("File format could not be determined");
187190
default:
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.drew.imaging.mkv;
2+
3+
import com.drew.imaging.heif.HeifReader;
4+
import com.drew.lang.StreamReader;
5+
import com.drew.lang.annotations.NotNull;
6+
import com.drew.metadata.Metadata;
7+
import com.drew.metadata.heif.HeifBoxHandler;
8+
import com.drew.metadata.mkv.MkvReader;
9+
10+
import java.io.IOException;
11+
import java.io.InputStream;
12+
13+
public class MkvMetadataReader {
14+
@NotNull
15+
public static Metadata readMetadata(@NotNull InputStream inputStream) throws IOException {
16+
Metadata metadata = new Metadata();
17+
new MkvReader().extract(new StreamReader(inputStream), metadata);
18+
return metadata;
19+
}
20+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package com.drew.imaging.mkv;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.drew.metadata.mkv;
2+
3+
import com.drew.metadata.Directory;
4+
import com.drew.metadata.TagDescriptor;
5+
6+
import java.util.HashMap;
7+
8+
import static com.drew.metadata.mkv.ElementIDs.*;
9+
10+
public class AudioDirectory extends Directory {
11+
private static final HashMap<Integer, String> _tagNameMap = new HashMap<>();
12+
13+
public AudioDirectory(){
14+
this.setDescriptor(new TagDescriptor<Directory>(this));
15+
}
16+
static {
17+
18+
_tagNameMap.put(TRACK_NUMBER, "Track number");
19+
_tagNameMap.put(TRACK_UID, "Track UID");
20+
_tagNameMap.put(TRACK_TYPE, "Track type");
21+
_tagNameMap.put(TAG_LACING, "Tag lacing");
22+
_tagNameMap.put(CODEC_ID, "Codec ID");
23+
_tagNameMap.put(LANGUAGE, "Language");
24+
_tagNameMap.put(LANGUAGE_BCP47, "Language BCP47");
25+
_tagNameMap.put(DEFAULT_DURATION, "Default duration");
26+
_tagNameMap.put(CHANNELS, "Channels");
27+
_tagNameMap.put(SAMPLING_FREQUENCY, "Sampling frequency");
28+
_tagNameMap.put(BIT_DEPTH, "Bit depth");
29+
30+
}
31+
32+
@Override
33+
public String getName() {
34+
return "Audio";
35+
}
36+
37+
@Override
38+
protected HashMap<Integer, String> getTagNameMap() {
39+
return _tagNameMap;
40+
}
41+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.drew.metadata.mkv;
2+
3+
import com.drew.lang.SequentialReader;
4+
5+
import java.io.IOException;
6+
7+
public class DataParser {
8+
private static final long[] VSINT_SUBTR = { 0x3F, 0x1FFF, 0x0FFFFF, 0x07FFFFFF,
9+
0x03FFFFFFFFL, 0x01FFFFFFFFFFL,
10+
0x00FFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL };
11+
12+
static long doDecodeInteger(final SequentialReader reader, boolean signed) throws IOException {
13+
byte firstByte = reader.getBytes(1)[0];
14+
int position = 7;
15+
for (; position >= 0; position--) {
16+
if ((firstByte & (1 << position)) != 0) {
17+
break;
18+
}
19+
}
20+
int length = 7 - position;
21+
byte[] values = reader.getBytes(length);
22+
long result = (firstByte & ((1L << position) - 1)) << (length * 8);
23+
for (int i = 1; i <= length; i++) {
24+
result |= ((long) (values[i - 1] & 0xFF) << ((length - i) * 8));
25+
}
26+
return signed ? result - VSINT_SUBTR[length] : result;
27+
}
28+
29+
static long decodeInteger(final SequentialReader reader) throws IOException {
30+
return doDecodeInteger(reader, false);
31+
}
32+
33+
static long decodeSignedInteger(final SequentialReader reader) throws IOException {
34+
return doDecodeInteger(reader, true);
35+
}
36+
37+
static int getElementId(final SequentialReader reader) throws IOException {
38+
byte firstByte = reader.getBytes(1)[0];
39+
int position = 7;
40+
for (; position >= 0; position--) {
41+
if ((firstByte & (1 << position)) != 0) {
42+
break;
43+
}
44+
}
45+
int length = 7 - position;
46+
byte[] values = reader.getBytes(length);
47+
int result = ((int) (firstByte & 0xFF)) << (length * 8);
48+
for (int i = 1; i <= length; i++) {
49+
result |= (((int) values[i - 1] & 0xFF) << ((length - i) * 8));
50+
}
51+
return result;
52+
}
53+
54+
static long getLong(final SequentialReader reader, long size) throws IOException {
55+
long result = 0L;
56+
for (long i = size - 1; i >= 0; i--){
57+
result |= (long) (reader.getByte() & 0xFF) << (i * 8);
58+
}
59+
return result;
60+
}
61+
62+
static byte[] getByteArray(final SequentialReader reader, long size) throws IOException {
63+
return reader.getBytes((int) size);
64+
}
65+
static String getString(final SequentialReader reader, long size) throws IOException{
66+
return reader.getString((int) size);
67+
}
68+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.drew.metadata.mkv;
2+
3+
import com.drew.metadata.Directory;
4+
import com.drew.metadata.TagDescriptor;
5+
6+
import java.util.HashMap;
7+
import static com.drew.metadata.mkv.ElementIDs.*;
8+
9+
public class EbmlDirectory extends Directory {
10+
11+
private static final HashMap<Integer, String> _tagNameMap = new HashMap<>();
12+
static {
13+
_tagNameMap.put(EBML_VERSION, "Version");
14+
_tagNameMap.put(EBML_READ_VERSION, "Read version");
15+
_tagNameMap.put(EBML_MAX_ID_LENGTH, "Maximum ID length");
16+
_tagNameMap.put(EBML_MAX_SIZE_LENGTH, "Maximum size length");
17+
_tagNameMap.put(DOCTYPE, "Doctype");
18+
_tagNameMap.put(DOCTYPE_VERSION, "Doctype version");
19+
_tagNameMap.put(DOCTYPE_READ_VERSION, "Doctype read version");
20+
}
21+
22+
public EbmlDirectory() {
23+
this.setDescriptor(new TagDescriptor<Directory>(this));
24+
}
25+
26+
@Override
27+
public String getName() {
28+
return "EBML";
29+
}
30+
31+
@Override
32+
protected HashMap<Integer, String> getTagNameMap() {
33+
return _tagNameMap;
34+
}
35+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.drew.metadata.mkv;
2+
3+
public class EbmlElement {
4+
private final String name;
5+
private final Type type;
6+
private final DirectoryType directory;
7+
8+
public String toString(){
9+
return name;
10+
}
11+
public String getName() {
12+
return name;
13+
}
14+
15+
public Type getType() {
16+
return type;
17+
}
18+
19+
public EbmlElement(String name, Type type) {
20+
this(name, type, DirectoryType.UNKNOWN);
21+
}
22+
public EbmlElement(String name, Type type, DirectoryType directory) {
23+
this.name = name;
24+
this.type = type;
25+
this.directory = directory;
26+
}
27+
28+
public DirectoryType getDirectory() {
29+
return directory;
30+
}
31+
32+
public enum Type{
33+
MASTER, STRING, INTEGER, SIGNED_INTEGER, UTF8, BINARY, VOID, UNKNOWN, FLOAT
34+
}
35+
36+
public enum DirectoryType{
37+
EBML, SEGMENT, VIDEO, AUDIO, UNKNOWN
38+
}
39+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.drew.metadata.mkv;
2+
3+
public class ElementIDs {
4+
5+
static final int EBML_HEADER_ELEMENT = 0x1A45DFA3;
6+
static final int EBML_VERSION = 0x4286;
7+
static final int EBML_READ_VERSION = 0x42F7;
8+
static final int EBML_MAX_ID_LENGTH = 0x42F2;
9+
static final int EBML_MAX_SIZE_LENGTH = 0x42F3;
10+
static final int DOCTYPE = 0x4282;
11+
static final int DOCTYPE_VERSION = 0x4287;
12+
static final int DOCTYPE_READ_VERSION = 0x4285;
13+
static final int SEGMENT = 0x18538067;
14+
static final int SEGMENT_INFO = 0x1549A966;
15+
static final int SEEK_HEAD = 0x114D9B74;
16+
static final int SEEK = 0x4DBB;
17+
static final int SEEK_ID = 0x53AB;
18+
static final int SEEK_POSITION = 0x53AC;
19+
static final int MUXING_APP = 0x4D80;
20+
static final int WRITING_APP = 0x5741;
21+
static final int CODEC_ID = 0x86;
22+
static final int VOID_ELEMENT = 0xEC;
23+
static final int TIMESTAMP_SCALE = 0x2AD7B1;
24+
static final int DURATION = 0x4489;
25+
static final int CLUSTER = 0x1F43B675;
26+
static final int SEGMENT_UUID = 0x73A4;
27+
static final int TRACKS = 0x1654AE6B;
28+
static final int TRACK_ENTRY = 0xAE;
29+
static final int TRACK_NUMBER = 0xD7;
30+
static final int TRACK_UID = 0x73C5;
31+
static final int TRACK_TYPE = 0x83;
32+
static final int TAG_LACING = 0x9C;
33+
static final int AUDIO = 0xE1;
34+
static final int CHANNELS = 0x9F;
35+
static final int SAMPLING_FREQUENCY = 0xB5;
36+
static final int BIT_DEPTH = 0x6264;
37+
static final int CODEC_PRIVATE = 0x63A2;
38+
static final int CUES = 0x1C53BB6B;
39+
static final int LANGUAGE = 0x22B59C;
40+
static final int LANGUAGE_BCP47 = 0x22B59D;
41+
static final int DEFAULT_DURATION = 0x23E383;
42+
static final int VIDEO = 0xE0;
43+
static final int DISPLAY_WIDTH = 0x54B0;
44+
static final int DISPLAY_HEIGHT = 0x54BA;
45+
static final int DISPLAY_UNIT = 0x54B2;
46+
static final int PIXEL_WIDTH = 0xB0;
47+
static final int PIXEL_HEIGHT = 0xBA;
48+
static final int FLAG_INTERLACED = 0x9A;
49+
static final int COLOR = 0x55B0;
50+
static final int TRANSFER_CHARACTERISTICS = 0x55BA;
51+
static final int MATRIX_COEFFICIENTS = 0x55B1;
52+
static final int PRIMARIES = 0x55BB;
53+
static final int RANGE = 0x55B9;
54+
static final int CHROMA_SITING_HORZ = 0x55B7;
55+
static final int CHROMA_SITING_VERT = 0x55B8;
56+
static final int CODEC_DELAY = 0x56AA;
57+
static final int SEEK_PRE_ROLL = 0x56BB;
58+
static final int TAGS = 0x1254C367;
59+
static final int TAG = 0x7373;
60+
static final int TARGETS = 0x63C0;
61+
static final int SIMPLE_TAG = 0x67C8;
62+
static final int TAG_NAME = 0x45A3;
63+
static final int TAG_LANGUAGE = 0x447A;
64+
static final int TAG_STRING = 0x4487;
65+
static final int TAG_LANGUAGE_BCP47 = 0x447B;
66+
static final int TAG_TRACK_UID = 0x63C5;
67+
}

0 commit comments

Comments
 (0)