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.BoxParser;
20import com.coremedia.iso.IsoTypeReader;
21import com.coremedia.iso.IsoTypeWriter;
22import com.coremedia.iso.boxes.Box;
23import com.coremedia.iso.boxes.ContainerBox;
24
25import 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 */
31public 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
69    public AudioSampleEntry(String type) {
70        super(type);
71    }
72
73    public int getChannelCount() {
74        return channelCount;
75    }
76
77    public int getSampleSize() {
78        return sampleSize;
79    }
80
81    public long getSampleRate() {
82        return sampleRate;
83    }
84
85    public int getSoundVersion() {
86        return soundVersion;
87    }
88
89    public int getCompressionId() {
90        return compressionId;
91    }
92
93    public int getPacketSize() {
94        return packetSize;
95    }
96
97    public long getSamplesPerPacket() {
98        return samplesPerPacket;
99    }
100
101    public long getBytesPerPacket() {
102        return bytesPerPacket;
103    }
104
105    public long getBytesPerFrame() {
106        return bytesPerFrame;
107    }
108
109    public long getBytesPerSample() {
110        return bytesPerSample;
111    }
112
113    public byte[] getSoundVersion2Data() {
114        return soundVersion2Data;
115    }
116
117    public int getReserved1() {
118        return reserved1;
119    }
120
121    public long getReserved2() {
122        return reserved2;
123    }
124
125    public void setChannelCount(int channelCount) {
126        this.channelCount = channelCount;
127    }
128
129    public void setSampleSize(int sampleSize) {
130        this.sampleSize = sampleSize;
131    }
132
133    public void setSampleRate(long sampleRate) {
134        this.sampleRate = sampleRate;
135    }
136
137    public void setSoundVersion(int soundVersion) {
138        this.soundVersion = soundVersion;
139    }
140
141    public void setCompressionId(int compressionId) {
142        this.compressionId = compressionId;
143    }
144
145    public void setPacketSize(int packetSize) {
146        this.packetSize = packetSize;
147    }
148
149    public void setSamplesPerPacket(long samplesPerPacket) {
150        this.samplesPerPacket = samplesPerPacket;
151    }
152
153    public void setBytesPerPacket(long bytesPerPacket) {
154        this.bytesPerPacket = bytesPerPacket;
155    }
156
157    public void setBytesPerFrame(long bytesPerFrame) {
158        this.bytesPerFrame = bytesPerFrame;
159    }
160
161    public void setBytesPerSample(long bytesPerSample) {
162        this.bytesPerSample = bytesPerSample;
163    }
164
165    public void setReserved1(int reserved1) {
166        this.reserved1 = reserved1;
167    }
168
169    public void setReserved2(long reserved2) {
170        this.reserved2 = reserved2;
171    }
172
173    public void setSoundVersion2Data(byte[] soundVersion2Data) {
174        this.soundVersion2Data = soundVersion2Data;
175    }
176
177    public void setBoxParser(BoxParser boxParser) {
178        this.boxParser = boxParser;
179    }
180
181    @Override
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
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
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
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