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.BoxParser;
20 import com.coremedia.iso.IsoTypeReader;
21 import com.coremedia.iso.IsoTypeWriter;
22 import com.coremedia.iso.boxes.Box;
23 import com.coremedia.iso.boxes.ContainerBox;
24 
25 import java.nio.ByteBuffer;
26 
27 /**
28  * Contains basic information about the audio samples in this track. Format-specific information
29  * is appened as boxes after the data described in ISO/IEC 14496-12 chapter 8.16.2.
30  */
31 public class AudioSampleEntry extends SampleEntry implements ContainerBox {
32 
33     public static final String TYPE1 = "samr";
34     public static final String TYPE2 = "sawb";
35     public static final String TYPE3 = "mp4a";
36     public static final String TYPE4 = "drms";
37     public static final String TYPE5 = "alac";
38     public static final String TYPE7 = "owma";
39     public static final String TYPE8 = "ac-3"; /* ETSI TS 102 366 1.2.1 Annex F */
40     public static final String TYPE9 = "ec-3"; /* ETSI TS 102 366 1.2.1 Annex F */
41     public static final String TYPE10 = "mlpa";
42     public static final String TYPE11 = "dtsl";
43     public static final String TYPE12 = "dtsh";
44     public static final String TYPE13 = "dtse";
45 
46     /**
47      * Identifier for an encrypted audio track.
48      *
49      * @see com.coremedia.iso.boxes.ProtectionSchemeInformationBox
50      */
51     public static final String TYPE_ENCRYPTED = "enca";
52 
53     private int channelCount;
54     private int sampleSize;
55     private long sampleRate;
56     private int soundVersion;
57     private int compressionId;
58     private int packetSize;
59     private long samplesPerPacket;
60     private long bytesPerPacket;
61     private long bytesPerFrame;
62     private long bytesPerSample;
63 
64     private int reserved1;
65     private long reserved2;
66     private byte[] soundVersion2Data;
67     private BoxParser boxParser;
68 
AudioSampleEntry(String type)69     public AudioSampleEntry(String type) {
70         super(type);
71     }
72 
getChannelCount()73     public int getChannelCount() {
74         return channelCount;
75     }
76 
getSampleSize()77     public int getSampleSize() {
78         return sampleSize;
79     }
80 
getSampleRate()81     public long getSampleRate() {
82         return sampleRate;
83     }
84 
getSoundVersion()85     public int getSoundVersion() {
86         return soundVersion;
87     }
88 
getCompressionId()89     public int getCompressionId() {
90         return compressionId;
91     }
92 
getPacketSize()93     public int getPacketSize() {
94         return packetSize;
95     }
96 
getSamplesPerPacket()97     public long getSamplesPerPacket() {
98         return samplesPerPacket;
99     }
100 
getBytesPerPacket()101     public long getBytesPerPacket() {
102         return bytesPerPacket;
103     }
104 
getBytesPerFrame()105     public long getBytesPerFrame() {
106         return bytesPerFrame;
107     }
108 
getBytesPerSample()109     public long getBytesPerSample() {
110         return bytesPerSample;
111     }
112 
getSoundVersion2Data()113     public byte[] getSoundVersion2Data() {
114         return soundVersion2Data;
115     }
116 
getReserved1()117     public int getReserved1() {
118         return reserved1;
119     }
120 
getReserved2()121     public long getReserved2() {
122         return reserved2;
123     }
124 
setChannelCount(int channelCount)125     public void setChannelCount(int channelCount) {
126         this.channelCount = channelCount;
127     }
128 
setSampleSize(int sampleSize)129     public void setSampleSize(int sampleSize) {
130         this.sampleSize = sampleSize;
131     }
132 
setSampleRate(long sampleRate)133     public void setSampleRate(long sampleRate) {
134         this.sampleRate = sampleRate;
135     }
136 
setSoundVersion(int soundVersion)137     public void setSoundVersion(int soundVersion) {
138         this.soundVersion = soundVersion;
139     }
140 
setCompressionId(int compressionId)141     public void setCompressionId(int compressionId) {
142         this.compressionId = compressionId;
143     }
144 
setPacketSize(int packetSize)145     public void setPacketSize(int packetSize) {
146         this.packetSize = packetSize;
147     }
148 
setSamplesPerPacket(long samplesPerPacket)149     public void setSamplesPerPacket(long samplesPerPacket) {
150         this.samplesPerPacket = samplesPerPacket;
151     }
152 
setBytesPerPacket(long bytesPerPacket)153     public void setBytesPerPacket(long bytesPerPacket) {
154         this.bytesPerPacket = bytesPerPacket;
155     }
156 
setBytesPerFrame(long bytesPerFrame)157     public void setBytesPerFrame(long bytesPerFrame) {
158         this.bytesPerFrame = bytesPerFrame;
159     }
160 
setBytesPerSample(long bytesPerSample)161     public void setBytesPerSample(long bytesPerSample) {
162         this.bytesPerSample = bytesPerSample;
163     }
164 
setReserved1(int reserved1)165     public void setReserved1(int reserved1) {
166         this.reserved1 = reserved1;
167     }
168 
setReserved2(long reserved2)169     public void setReserved2(long reserved2) {
170         this.reserved2 = reserved2;
171     }
172 
setSoundVersion2Data(byte[] soundVersion2Data)173     public void setSoundVersion2Data(byte[] soundVersion2Data) {
174         this.soundVersion2Data = soundVersion2Data;
175     }
176 
setBoxParser(BoxParser boxParser)177     public void setBoxParser(BoxParser boxParser) {
178         this.boxParser = boxParser;
179     }
180 
181     @Override
_parseDetails(ByteBuffer content)182     public void _parseDetails(ByteBuffer content) {
183         _parseReservedAndDataReferenceIndex(content);    //parses the six reserved bytes and dataReferenceIndex
184         // 8 bytes already parsed
185         //reserved bits - used by qt
186         soundVersion = IsoTypeReader.readUInt16(content);
187 
188         //reserved
189         reserved1 = IsoTypeReader.readUInt16(content);
190         reserved2 = IsoTypeReader.readUInt32(content);
191 
192         channelCount = IsoTypeReader.readUInt16(content);
193         sampleSize = IsoTypeReader.readUInt16(content);
194         //reserved bits - used by qt
195         compressionId = IsoTypeReader.readUInt16(content);
196         //reserved bits - used by qt
197         packetSize = IsoTypeReader.readUInt16(content);
198         //sampleRate = in.readFixedPoint1616();
199         sampleRate = IsoTypeReader.readUInt32(content);
200         if (!type.equals("mlpa")) {
201             sampleRate = sampleRate >>> 16;
202         }
203 
204         //more qt stuff - see http://mp4v2.googlecode.com/svn-history/r388/trunk/src/atom_sound.cpp
205         if (soundVersion > 0) {
206             samplesPerPacket = IsoTypeReader.readUInt32(content);
207             bytesPerPacket = IsoTypeReader.readUInt32(content);
208             bytesPerFrame = IsoTypeReader.readUInt32(content);
209             bytesPerSample = IsoTypeReader.readUInt32(content);
210         }
211         if (soundVersion == 2) {
212 
213             soundVersion2Data = new byte[20];
214             content.get(20);
215         }
216         _parseChildBoxes(content);
217 
218     }
219 
220 
221     @Override
getContentSize()222     protected long getContentSize() {
223         long contentSize = 28;
224         contentSize += soundVersion > 0 ? 16 : 0;
225         contentSize += soundVersion == 2 ? 20 : 0;
226         for (Box boxe : boxes) {
227             contentSize += boxe.getSize();
228         }
229         return contentSize;
230     }
231 
232     @Override
toString()233     public String toString() {
234         return "AudioSampleEntry{" +
235                 "bytesPerSample=" + bytesPerSample +
236                 ", bytesPerFrame=" + bytesPerFrame +
237                 ", bytesPerPacket=" + bytesPerPacket +
238                 ", samplesPerPacket=" + samplesPerPacket +
239                 ", packetSize=" + packetSize +
240                 ", compressionId=" + compressionId +
241                 ", soundVersion=" + soundVersion +
242                 ", sampleRate=" + sampleRate +
243                 ", sampleSize=" + sampleSize +
244                 ", channelCount=" + channelCount +
245                 ", boxes=" + getBoxes() +
246                 '}';
247     }
248 
249     @Override
getContent(ByteBuffer byteBuffer)250     protected void getContent(ByteBuffer byteBuffer) {
251         _writeReservedAndDataReferenceIndex(byteBuffer);
252         IsoTypeWriter.writeUInt16(byteBuffer, soundVersion);
253         IsoTypeWriter.writeUInt16(byteBuffer, reserved1);
254         IsoTypeWriter.writeUInt32(byteBuffer, reserved2);
255         IsoTypeWriter.writeUInt16(byteBuffer, channelCount);
256         IsoTypeWriter.writeUInt16(byteBuffer, sampleSize);
257         IsoTypeWriter.writeUInt16(byteBuffer, compressionId);
258         IsoTypeWriter.writeUInt16(byteBuffer, packetSize);
259         //isos.writeFixedPont1616(getSampleRate());
260         if (type.equals("mlpa")) {
261             IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate());
262         } else {
263             IsoTypeWriter.writeUInt32(byteBuffer, getSampleRate() << 16);
264         }
265 
266         if (soundVersion > 0) {
267             IsoTypeWriter.writeUInt32(byteBuffer, samplesPerPacket);
268             IsoTypeWriter.writeUInt32(byteBuffer, bytesPerPacket);
269             IsoTypeWriter.writeUInt32(byteBuffer, bytesPerFrame);
270             IsoTypeWriter.writeUInt32(byteBuffer, bytesPerSample);
271         }
272 
273         if (soundVersion == 2) {
274             byteBuffer.put(soundVersion2Data);
275         }
276         _writeChildBoxes(byteBuffer);
277     }
278 }
279