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 
17 package com.coremedia.iso.boxes.sampleentry;
18 
19 import com.coremedia.iso.IsoTypeReader;
20 import com.coremedia.iso.IsoTypeWriter;
21 import com.coremedia.iso.Utf8;
22 import com.coremedia.iso.boxes.Box;
23 import com.coremedia.iso.boxes.ContainerBox;
24 
25 import 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  */
50 public 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 
VisualSampleEntry(String type)74     public VisualSampleEntry(String type) {
75         super(type);
76     }
77 
getWidth()78     public int getWidth() {
79         return width;
80     }
81 
getHeight()82     public int getHeight() {
83         return height;
84     }
85 
getHorizresolution()86     public double getHorizresolution() {
87         return horizresolution;
88     }
89 
getVertresolution()90     public double getVertresolution() {
91         return vertresolution;
92     }
93 
getFrameCount()94     public int getFrameCount() {
95         return frameCount;
96     }
97 
getCompressorname()98     public String getCompressorname() {
99         return compressorname;
100     }
101 
getDepth()102     public int getDepth() {
103         return depth;
104     }
105 
setCompressorname(String compressorname)106     public void setCompressorname(String compressorname) {
107         this.compressorname = compressorname;
108     }
109 
setWidth(int width)110     public void setWidth(int width) {
111         this.width = width;
112     }
113 
setHeight(int height)114     public void setHeight(int height) {
115         this.height = height;
116     }
117 
setHorizresolution(double horizresolution)118     public void setHorizresolution(double horizresolution) {
119         this.horizresolution = horizresolution;
120     }
121 
setVertresolution(double vertresolution)122     public void setVertresolution(double vertresolution) {
123         this.vertresolution = vertresolution;
124     }
125 
setFrameCount(int frameCount)126     public void setFrameCount(int frameCount) {
127         this.frameCount = frameCount;
128     }
129 
setDepth(int depth)130     public void setDepth(int depth) {
131         this.depth = depth;
132     }
133 
134     @Override
_parseDetails(ByteBuffer content)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 
getContentSize()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
getContent(ByteBuffer byteBuffer)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