1/*
2 * Copyright 2008 CoreMedia AG, Hamburg
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.coremedia.iso.boxes;
18
19
20import com.coremedia.iso.IsoTypeReader;
21import com.coremedia.iso.IsoTypeWriter;
22import com.googlecode.mp4parser.AbstractFullBox;
23
24import java.nio.ByteBuffer;
25
26/**
27 * This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track.<br>
28 * In the absence of an edit list, the presentation of a track starts at the beginning of the overall presentation. An
29 * empty edit is used to offset the start time of a track. <br>
30 * The default value of the track header flags for media tracks is 7 (track_enabled, track_in_movie,
31 * track_in_preview). If in a presentation all tracks have neither track_in_movie nor track_in_preview set, then all
32 * tracks shall be treated as if both flags were set on all tracks. Hint tracks should have the track header flags set
33 * to 0, so that they are ignored for local playback and preview.
34 */
35public class TrackHeaderBox extends AbstractFullBox {
36
37    public static final String TYPE = "tkhd";
38
39    private long creationTime;
40    private long modificationTime;
41    private long trackId;
42    private long duration;
43    private int layer;
44    private int alternateGroup;
45    private float volume;
46    private long[] matrix = new long[]{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000};
47    private double width;
48    private double height;
49
50
51    public TrackHeaderBox() {
52        super(TYPE);
53
54    }
55
56    public long getCreationTime() {
57        return creationTime;
58    }
59
60    public long getModificationTime() {
61        return modificationTime;
62    }
63
64    public long getTrackId() {
65        return trackId;
66    }
67
68    public long getDuration() {
69        return duration;
70    }
71
72    public int getLayer() {
73        return layer;
74    }
75
76    public int getAlternateGroup() {
77        return alternateGroup;
78    }
79
80    public float getVolume() {
81        return volume;
82    }
83
84    public long[] getMatrix() {
85        return matrix;
86    }
87
88    public double getWidth() {
89        return width;
90    }
91
92    public double getHeight() {
93        return height;
94    }
95
96    protected long getContentSize() {
97        long contentSize = 4;
98        if (getVersion() == 1) {
99            contentSize += 32;
100        } else {
101            contentSize += 20;
102        }
103        contentSize += 60;
104        return contentSize;
105    }
106
107    @Override
108    public void _parseDetails(ByteBuffer content) {
109        parseVersionAndFlags(content);
110        if (getVersion() == 1) {
111            creationTime = IsoTypeReader.readUInt64(content);
112            modificationTime = IsoTypeReader.readUInt64(content);
113            trackId = IsoTypeReader.readUInt32(content);
114            IsoTypeReader.readUInt32(content);
115            duration = IsoTypeReader.readUInt64(content);
116        } else {
117            creationTime = IsoTypeReader.readUInt32(content);
118            modificationTime = IsoTypeReader.readUInt32(content);
119            trackId = IsoTypeReader.readUInt32(content);
120            IsoTypeReader.readUInt32(content);
121            duration = IsoTypeReader.readUInt32(content);
122        } // 196
123        IsoTypeReader.readUInt32(content);
124        IsoTypeReader.readUInt32(content);
125        layer = IsoTypeReader.readUInt16(content);    // 204
126        alternateGroup = IsoTypeReader.readUInt16(content);
127        volume = IsoTypeReader.readFixedPoint88(content);
128        IsoTypeReader.readUInt16(content);     // 212
129        matrix = new long[9];
130        for (int i = 0; i < 9; i++) {
131            matrix[i] = IsoTypeReader.readUInt32(content);
132        }
133        width = IsoTypeReader.readFixedPoint1616(content);    // 248
134        height = IsoTypeReader.readFixedPoint1616(content);
135    }
136
137    public void getContent(ByteBuffer byteBuffer) {
138        writeVersionAndFlags(byteBuffer);
139        if (getVersion() == 1) {
140            IsoTypeWriter.writeUInt64(byteBuffer, creationTime);
141            IsoTypeWriter.writeUInt64(byteBuffer, modificationTime);
142            IsoTypeWriter.writeUInt32(byteBuffer, trackId);
143            IsoTypeWriter.writeUInt32(byteBuffer, 0);
144            IsoTypeWriter.writeUInt64(byteBuffer, duration);
145        } else {
146            IsoTypeWriter.writeUInt32(byteBuffer, creationTime);
147            IsoTypeWriter.writeUInt32(byteBuffer, modificationTime);
148            IsoTypeWriter.writeUInt32(byteBuffer, trackId);
149            IsoTypeWriter.writeUInt32(byteBuffer, 0);
150            IsoTypeWriter.writeUInt32(byteBuffer, duration);
151        } // 196
152        IsoTypeWriter.writeUInt32(byteBuffer, 0);
153        IsoTypeWriter.writeUInt32(byteBuffer, 0);
154        IsoTypeWriter.writeUInt16(byteBuffer, layer);
155        IsoTypeWriter.writeUInt16(byteBuffer, alternateGroup);
156        IsoTypeWriter.writeFixedPont88(byteBuffer, volume);
157        IsoTypeWriter.writeUInt16(byteBuffer, 0);
158        for (int i = 0; i < 9; i++) {
159            IsoTypeWriter.writeUInt32(byteBuffer, matrix[i]);
160        }
161        IsoTypeWriter.writeFixedPont1616(byteBuffer, width);
162        IsoTypeWriter.writeFixedPont1616(byteBuffer, height);
163    }
164
165    public String toString() {
166        StringBuilder result = new StringBuilder();
167        result.append("TrackHeaderBox[");
168        result.append("creationTime=").append(getCreationTime());
169        result.append(";");
170        result.append("modificationTime=").append(getModificationTime());
171        result.append(";");
172        result.append("trackId=").append(getTrackId());
173        result.append(";");
174        result.append("duration=").append(getDuration());
175        result.append(";");
176        result.append("layer=").append(getLayer());
177        result.append(";");
178        result.append("alternateGroup=").append(getAlternateGroup());
179        result.append(";");
180        result.append("volume=").append(getVolume());
181        for (int i = 0; i < matrix.length; i++) {
182            result.append(";");
183            result.append("matrix").append(i).append("=").append(matrix[i]);
184        }
185        result.append(";");
186        result.append("width=").append(getWidth());
187        result.append(";");
188        result.append("height=").append(getHeight());
189        result.append("]");
190        return result.toString();
191    }
192
193    public void setCreationTime(long creationTime) {
194        this.creationTime = creationTime;
195    }
196
197    public void setModificationTime(long modificationTime) {
198        this.modificationTime = modificationTime;
199    }
200
201    public void setTrackId(long trackId) {
202        this.trackId = trackId;
203    }
204
205    public void setDuration(long duration) {
206        this.duration = duration;
207    }
208
209    public void setLayer(int layer) {
210        this.layer = layer;
211    }
212
213    public void setAlternateGroup(int alternateGroup) {
214        this.alternateGroup = alternateGroup;
215    }
216
217    public void setVolume(float volume) {
218        this.volume = volume;
219    }
220
221    public void setMatrix(long[] matrix) {
222        this.matrix = matrix;
223    }
224
225    public void setWidth(double width) {
226        this.width = width;
227    }
228
229    public void setHeight(double height) {
230        this.height = height;
231    }
232
233
234    public boolean isEnabled() {
235        return (getFlags() & 1) > 0;
236    }
237
238    public boolean isInMovie() {
239        return (getFlags() & 2) > 0;
240    }
241
242    public boolean isInPreview() {
243        return (getFlags() & 4) > 0;
244    }
245
246    public boolean isInPoster() {
247        return (getFlags() & 8) > 0;
248    }
249}
250