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.sampleentry;
18
19import com.coremedia.iso.IsoTypeReader;
20import com.coremedia.iso.IsoTypeWriter;
21import com.coremedia.iso.Utf8;
22import com.coremedia.iso.boxes.Box;
23import com.coremedia.iso.boxes.ContainerBox;
24
25import java.nio.ByteBuffer;
26
27/**
28 * Contains information common to all visual tracks.
29 * <code>
30 * <pre>
31 * class VisualSampleEntry(codingname) extends SampleEntry (codingname){
32 * unsigned int(16) pre_defined = 0;
33 * const unsigned int(16) reserved = 0;
34 * unsigned int(32)[3] pre_defined = 0;
35 * unsigned int(16) width;
36 * unsigned int(16) height;
37 * template unsigned int(32) horizresolution = 0x00480000; // 72 dpi
38 * template unsigned int(32) vertresolution = 0x00480000; // 72 dpi
39 * const unsigned int(32) reserved = 0;
40 * template unsigned int(16) frame_count = 1;
41 * string[32] compressorname;
42 * template unsigned int(16) depth = 0x0018;
43 * int(16) pre_defined = -1;
44 * }<br>
45 * </pre>
46 * </code>
47 * <p/>
48 * Format-specific informationis appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2.
49 */
50public class VisualSampleEntry extends SampleEntry implements ContainerBox {
51    public static final String TYPE1 = "mp4v";
52    public static final String TYPE2 = "s263";
53    public static final String TYPE3 = "avc1";
54
55
56    /**
57     * Identifier for an encrypted video track.
58     *
59     * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox
60     */
61    public static final String TYPE_ENCRYPTED = "encv";
62
63
64    private int width;
65    private int height;
66    private double horizresolution = 72;
67    private double vertresolution = 72;
68    private int frameCount = 1;
69    private String compressorname;
70    private int depth = 24;
71
72    private long[] predefined = new long[3];
73
74    public VisualSampleEntry(String type) {
75        super(type);
76    }
77
78    public int getWidth() {
79        return width;
80    }
81
82    public int getHeight() {
83        return height;
84    }
85
86    public double getHorizresolution() {
87        return horizresolution;
88    }
89
90    public double getVertresolution() {
91        return vertresolution;
92    }
93
94    public int getFrameCount() {
95        return frameCount;
96    }
97
98    public String getCompressorname() {
99        return compressorname;
100    }
101
102    public int getDepth() {
103        return depth;
104    }
105
106    public void setCompressorname(String compressorname) {
107        this.compressorname = compressorname;
108    }
109
110    public void setWidth(int width) {
111        this.width = width;
112    }
113
114    public void setHeight(int height) {
115        this.height = height;
116    }
117
118    public void setHorizresolution(double horizresolution) {
119        this.horizresolution = horizresolution;
120    }
121
122    public void setVertresolution(double vertresolution) {
123        this.vertresolution = vertresolution;
124    }
125
126    public void setFrameCount(int frameCount) {
127        this.frameCount = frameCount;
128    }
129
130    public void setDepth(int depth) {
131        this.depth = depth;
132    }
133
134    @Override
135    public void _parseDetails(ByteBuffer content) {
136        _parseReservedAndDataReferenceIndex(content);
137        long tmp = IsoTypeReader.readUInt16(content);
138        assert 0 == tmp : "reserved byte not 0";
139        tmp = IsoTypeReader.readUInt16(content);
140        assert 0 == tmp : "reserved byte not 0";
141        predefined[0] = IsoTypeReader.readUInt32(content);     // should be zero
142        predefined[1] = IsoTypeReader.readUInt32(content);     // should be zero
143        predefined[2] = IsoTypeReader.readUInt32(content);     // should be zero
144        width = IsoTypeReader.readUInt16(content);
145        height = IsoTypeReader.readUInt16(content);
146        horizresolution = IsoTypeReader.readFixedPoint1616(content);
147        vertresolution = IsoTypeReader.readFixedPoint1616(content);
148        tmp = IsoTypeReader.readUInt32(content);
149        assert 0 == tmp : "reserved byte not 0";
150        frameCount = IsoTypeReader.readUInt16(content);
151        int compressornameDisplayAbleData = IsoTypeReader.readUInt8(content);
152        if (compressornameDisplayAbleData > 31) {
153            System.out.println("invalid compressor name displayable data: " + compressornameDisplayAbleData);
154            compressornameDisplayAbleData = 31;
155        }
156        byte[] bytes = new byte[compressornameDisplayAbleData];
157        content.get(bytes);
158        compressorname = Utf8.convert(bytes);
159        if (compressornameDisplayAbleData < 31) {
160            byte[] zeros = new byte[31 - compressornameDisplayAbleData];
161            content.get(zeros);
162            //assert Arrays.equals(zeros, new byte[zeros.length]) : "The compressor name length was not filled up with zeros";
163        }
164        depth = IsoTypeReader.readUInt16(content);
165        tmp = IsoTypeReader.readUInt16(content);
166        assert 0xFFFF == tmp;
167
168        _parseChildBoxes(content);
169
170    }
171
172
173    protected long getContentSize() {
174        long contentSize = 78;
175        for (Box boxe : boxes) {
176            contentSize += boxe.getSize();
177        }
178        return contentSize;
179    }
180
181    @Override
182    protected void getContent(ByteBuffer byteBuffer) {
183        _writeReservedAndDataReferenceIndex(byteBuffer);
184        IsoTypeWriter.writeUInt16(byteBuffer, 0);
185        IsoTypeWriter.writeUInt16(byteBuffer, 0);
186        IsoTypeWriter.writeUInt32(byteBuffer, predefined[0]);
187        IsoTypeWriter.writeUInt32(byteBuffer, predefined[1]);
188        IsoTypeWriter.writeUInt32(byteBuffer, predefined[2]);
189
190        IsoTypeWriter.writeUInt16(byteBuffer, getWidth());
191        IsoTypeWriter.writeUInt16(byteBuffer, getHeight());
192
193        IsoTypeWriter.writeFixedPont1616(byteBuffer, getHorizresolution());
194        IsoTypeWriter.writeFixedPont1616(byteBuffer, getVertresolution());
195
196
197        IsoTypeWriter.writeUInt32(byteBuffer, 0);
198        IsoTypeWriter.writeUInt16(byteBuffer, getFrameCount());
199        IsoTypeWriter.writeUInt8(byteBuffer, Utf8.utf8StringLengthInBytes(getCompressorname()));
200        byteBuffer.put(Utf8.convert(getCompressorname()));
201        int a = Utf8.utf8StringLengthInBytes(getCompressorname());
202        while (a < 31) {
203            a++;
204            byteBuffer.put((byte) 0);
205        }
206        IsoTypeWriter.writeUInt16(byteBuffer, getDepth());
207        IsoTypeWriter.writeUInt16(byteBuffer, 0xFFFF);
208
209        _writeChildBoxes(byteBuffer);
210
211    }
212
213}
214