-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathMp4.java
134 lines (125 loc) · 4.12 KB
/
Mp4.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import java.util.*;
import java.io.*;
public class Mp4 {
private AtomRandomAccessFile r; // underlying file (not owned)
private Atom root; // cached atom structure
Mp4(AtomRandomAccessFile r) throws IOException {
this.r = r;
root = parse();
}
public class Atom {
String type; // 4-character code
long offset; // position in file
long size; // length of atom
public final List<Atom> children = new ArrayList<Atom>();
public Atom(String type, long offset, long size) {
this.type = type;
this.offset = offset;
this.size = size;
}
String readType(long atom_offset) throws IOException {
return r.readType(offset + atom_offset);
}
int readInt(long atom_offset) throws IOException {
return r.readInt(offset + atom_offset);
}
long readLong(long atom_offset) throws IOException {
return r.readLong(offset + atom_offset);
}
byte[] readFully(long atom_offset, long len) throws IOException {
return r.readFully(offset + atom_offset, len);
}
byte[] readFully(long atom_offset) throws IOException {
return readFully(atom_offset, size - atom_offset);
}
int[] readIntArray(long atom_offset, int count) throws IOException {
return r.readIntArray(offset + atom_offset, count);
}
long[] readLongArray(long atom_offset, int count) throws IOException {
return r.readLongArray(offset + atom_offset, count);
}
public void print() {
print("");
}
private void print(String indent) {
System.out.println(indent + type + " " + offset + " " + size);
for (Atom child : children) {
child.print(indent + " ");
}
}
public Atom find(String types) {
if (types.equals("")) return this;
String first = types.substring(0, 4);
String rest;
if (types.length() == 4) {
rest = "";
} else {
assert types.charAt(4) == '.';
rest = types.substring(5);
}
for (Atom child : children) {
if (child.type.equals(first)) {
Atom a = child.find(rest);
if (a != null) return a;
}
}
return null;
}
}
public Atom find(String types) {
return root.find(types);
}
// Information about what offset the children of an atom start.
// Any atom not in this map is assumed to have no children.
// TODO: needs to be adjusted for 64-bit atoms?
private static HashMap<String,Integer> children_offset = new HashMap<String,Integer>();
static {
children_offset.put("moov", 8);
children_offset.put("trak", 8);
children_offset.put("mdia", 8);
children_offset.put("minf", 8);
children_offset.put("stbl", 8);
children_offset.put("stsd", 16);
children_offset.put("drms", 36);
children_offset.put("drmi", 86);
children_offset.put("p608", 16);
children_offset.put("drmt", 46);
children_offset.put("sinf", 8);
children_offset.put("schi", 8);
}
private Atom parse() throws IOException {
long length = r.length();
Atom atom = new Atom("file", 0, length); // fake wrapper atom
r.seek(0);
atom.children.addAll(parse(length));
return atom;
}
private List<Atom> parse(long stop_offset) throws IOException {
List<Atom> atoms = new ArrayList<Atom>();
while (r.getFilePointer() < stop_offset) {
long offset = r.getFilePointer();
long size = r.readInt() & 0xffffffffL;
String type = r.readType();
int hdr_size = 8;
if (size == 1) { size = r.readLong(); hdr_size = 16; }
Atom atom = new Atom(type, offset, size);
if (children_offset.containsKey(type)) {
r.skipBytes(children_offset.get(type) - hdr_size); // TODO: fix for 64-bit atoms?
atom.children.addAll(parse(offset + size));
} else {
r.seek(offset + size);
}
atoms.add(atom);
assert r.getFilePointer() == offset + size;
}
return atoms;
}
public static void main(String[] args) throws IOException {
for (String arg : args) {
AtomRandomAccessFile r = new AtomRandomAccessFile(arg, "r");
Mp4 mp4 = new Mp4(r);
mp4.root.print();
r.close();
}
}
}