• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.h264;
18 
19 import com.coremedia.iso.Hex;
20 import com.coremedia.iso.IsoTypeReader;
21 import com.coremedia.iso.IsoTypeWriter;
22 import com.googlecode.mp4parser.AbstractBox;
23 import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitReaderBuffer;
24 import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.BitWriterBuffer;
25 import com.googlecode.mp4parser.h264.model.PictureParameterSet;
26 import com.googlecode.mp4parser.h264.model.SeqParameterSet;
27 
28 import java.io.ByteArrayInputStream;
29 import java.io.IOException;
30 import java.nio.ByteBuffer;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.List;
34 
35 /**
36  * Defined in ISO/IEC 14496-15:2004.
37  */
38 public final class AvcConfigurationBox extends AbstractBox {
39     public static final String TYPE = "avcC";
40 
41     public AVCDecoderConfigurationRecord avcDecoderConfigurationRecord = new AVCDecoderConfigurationRecord();
42 
43 
AvcConfigurationBox()44     public AvcConfigurationBox() {
45         super(TYPE);
46     }
47 
getConfigurationVersion()48     public int getConfigurationVersion() {
49         return avcDecoderConfigurationRecord.configurationVersion;
50     }
51 
getAvcProfileIndication()52     public int getAvcProfileIndication() {
53         return avcDecoderConfigurationRecord.avcProfileIndication;
54     }
55 
getProfileCompatibility()56     public int getProfileCompatibility() {
57         return avcDecoderConfigurationRecord.profileCompatibility;
58     }
59 
getAvcLevelIndication()60     public int getAvcLevelIndication() {
61         return avcDecoderConfigurationRecord.avcLevelIndication;
62     }
63 
getLengthSizeMinusOne()64     public int getLengthSizeMinusOne() {
65         return avcDecoderConfigurationRecord.lengthSizeMinusOne;
66     }
67 
getSequenceParameterSets()68     public List<byte[]> getSequenceParameterSets() {
69         return Collections.unmodifiableList(avcDecoderConfigurationRecord.sequenceParameterSets);
70     }
71 
getPictureParameterSets()72     public List<byte[]> getPictureParameterSets() {
73         return Collections.unmodifiableList(avcDecoderConfigurationRecord.pictureParameterSets);
74     }
75 
setConfigurationVersion(int configurationVersion)76     public void setConfigurationVersion(int configurationVersion) {
77         this.avcDecoderConfigurationRecord.configurationVersion = configurationVersion;
78     }
79 
setAvcProfileIndication(int avcProfileIndication)80     public void setAvcProfileIndication(int avcProfileIndication) {
81         this.avcDecoderConfigurationRecord.avcProfileIndication = avcProfileIndication;
82     }
83 
setProfileCompatibility(int profileCompatibility)84     public void setProfileCompatibility(int profileCompatibility) {
85         this.avcDecoderConfigurationRecord.profileCompatibility = profileCompatibility;
86     }
87 
setAvcLevelIndication(int avcLevelIndication)88     public void setAvcLevelIndication(int avcLevelIndication) {
89         this.avcDecoderConfigurationRecord.avcLevelIndication = avcLevelIndication;
90     }
91 
setLengthSizeMinusOne(int lengthSizeMinusOne)92     public void setLengthSizeMinusOne(int lengthSizeMinusOne) {
93         this.avcDecoderConfigurationRecord.lengthSizeMinusOne = lengthSizeMinusOne;
94     }
95 
setSequenceParameterSets(List<byte[]> sequenceParameterSets)96     public void setSequenceParameterSets(List<byte[]> sequenceParameterSets) {
97         this.avcDecoderConfigurationRecord.sequenceParameterSets = sequenceParameterSets;
98     }
99 
setPictureParameterSets(List<byte[]> pictureParameterSets)100     public void setPictureParameterSets(List<byte[]> pictureParameterSets) {
101         this.avcDecoderConfigurationRecord.pictureParameterSets = pictureParameterSets;
102     }
103 
getChromaFormat()104     public int getChromaFormat() {
105         return avcDecoderConfigurationRecord.chromaFormat;
106     }
107 
setChromaFormat(int chromaFormat)108     public void setChromaFormat(int chromaFormat) {
109         this.avcDecoderConfigurationRecord.chromaFormat = chromaFormat;
110     }
111 
getBitDepthLumaMinus8()112     public int getBitDepthLumaMinus8() {
113         return avcDecoderConfigurationRecord.bitDepthLumaMinus8;
114     }
115 
setBitDepthLumaMinus8(int bitDepthLumaMinus8)116     public void setBitDepthLumaMinus8(int bitDepthLumaMinus8) {
117         this.avcDecoderConfigurationRecord.bitDepthLumaMinus8 = bitDepthLumaMinus8;
118     }
119 
getBitDepthChromaMinus8()120     public int getBitDepthChromaMinus8() {
121         return avcDecoderConfigurationRecord.bitDepthChromaMinus8;
122     }
123 
setBitDepthChromaMinus8(int bitDepthChromaMinus8)124     public void setBitDepthChromaMinus8(int bitDepthChromaMinus8) {
125         this.avcDecoderConfigurationRecord.bitDepthChromaMinus8 = bitDepthChromaMinus8;
126     }
127 
getSequenceParameterSetExts()128     public List<byte[]> getSequenceParameterSetExts() {
129         return avcDecoderConfigurationRecord.sequenceParameterSetExts;
130     }
131 
setSequenceParameterSetExts(List<byte[]> sequenceParameterSetExts)132     public void setSequenceParameterSetExts(List<byte[]> sequenceParameterSetExts) {
133         this.avcDecoderConfigurationRecord.sequenceParameterSetExts = sequenceParameterSetExts;
134     }
135 
hasExts()136     public boolean hasExts() {
137         return avcDecoderConfigurationRecord.hasExts;
138     }
139 
setHasExts(boolean hasExts)140     public void setHasExts(boolean hasExts) {
141         this.avcDecoderConfigurationRecord.hasExts = hasExts;
142     }
143 
144     @Override
_parseDetails(ByteBuffer content)145     public void _parseDetails(ByteBuffer content) {
146         avcDecoderConfigurationRecord = new AVCDecoderConfigurationRecord(content);
147     }
148 
149 
150     @Override
getContentSize()151     public long getContentSize() {
152         return avcDecoderConfigurationRecord.getContentSize();
153     }
154 
155 
156     @Override
getContent(ByteBuffer byteBuffer)157     public void getContent(ByteBuffer byteBuffer) {
158         avcDecoderConfigurationRecord.getContent(byteBuffer);
159     }
160 
161     // just to display sps in isoviewer no practical use
getSPS()162     public String[] getSPS() {
163         return avcDecoderConfigurationRecord.getSPS();
164     }
165 
getPPS()166     public String[] getPPS() {
167         return avcDecoderConfigurationRecord.getPPS();
168     }
169 
getSequenceParameterSetsAsStrings()170     public List<String> getSequenceParameterSetsAsStrings() {
171         return avcDecoderConfigurationRecord.getSequenceParameterSetsAsStrings();
172     }
173 
getSequenceParameterSetExtsAsStrings()174     public List<String> getSequenceParameterSetExtsAsStrings() {
175         return avcDecoderConfigurationRecord.getSequenceParameterSetExtsAsStrings();
176     }
177 
getPictureParameterSetsAsStrings()178     public List<String> getPictureParameterSetsAsStrings() {
179         return avcDecoderConfigurationRecord.getPictureParameterSetsAsStrings();
180     }
181 
getavcDecoderConfigurationRecord()182     public AVCDecoderConfigurationRecord getavcDecoderConfigurationRecord() {
183         return avcDecoderConfigurationRecord;
184     }
185 
186 
187     public static class AVCDecoderConfigurationRecord {
188         public int configurationVersion;
189         public int avcProfileIndication;
190         public int profileCompatibility;
191         public int avcLevelIndication;
192         public int lengthSizeMinusOne;
193         public List<byte[]> sequenceParameterSets = new ArrayList<byte[]>();
194         public List<byte[]> pictureParameterSets = new ArrayList<byte[]>();
195 
196         public boolean hasExts = true;
197         public int chromaFormat = 1;
198         public int bitDepthLumaMinus8 = 0;
199         public int bitDepthChromaMinus8 = 0;
200         public List<byte[]> sequenceParameterSetExts = new ArrayList<byte[]>();
201 
202         /**
203          * Just for non-spec-conform encoders
204          */
205         public int lengthSizeMinusOnePaddingBits = 60;
206         public int numberOfSequenceParameterSetsPaddingBits = 7;
207         public int chromaFormatPaddingBits = 31;
208         public int bitDepthLumaMinus8PaddingBits = 31;
209         public int bitDepthChromaMinus8PaddingBits = 31;
210 
AVCDecoderConfigurationRecord()211         public AVCDecoderConfigurationRecord() {
212         }
213 
AVCDecoderConfigurationRecord(ByteBuffer content)214         public AVCDecoderConfigurationRecord(ByteBuffer content) {
215             configurationVersion = IsoTypeReader.readUInt8(content);
216             avcProfileIndication = IsoTypeReader.readUInt8(content);
217             profileCompatibility = IsoTypeReader.readUInt8(content);
218             avcLevelIndication = IsoTypeReader.readUInt8(content);
219             BitReaderBuffer brb = new BitReaderBuffer(content);
220             lengthSizeMinusOnePaddingBits = brb.readBits(6);
221             lengthSizeMinusOne = brb.readBits(2);
222             numberOfSequenceParameterSetsPaddingBits = brb.readBits(3);
223             int numberOfSeuqenceParameterSets = brb.readBits(5);
224             for (int i = 0; i < numberOfSeuqenceParameterSets; i++) {
225                 int sequenceParameterSetLength = IsoTypeReader.readUInt16(content);
226 
227                 byte[] sequenceParameterSetNALUnit = new byte[sequenceParameterSetLength];
228                 content.get(sequenceParameterSetNALUnit);
229                 sequenceParameterSets.add(sequenceParameterSetNALUnit);
230             }
231             long numberOfPictureParameterSets = IsoTypeReader.readUInt8(content);
232             for (int i = 0; i < numberOfPictureParameterSets; i++) {
233                 int pictureParameterSetLength = IsoTypeReader.readUInt16(content);
234                 byte[] pictureParameterSetNALUnit = new byte[pictureParameterSetLength];
235                 content.get(pictureParameterSetNALUnit);
236                 pictureParameterSets.add(pictureParameterSetNALUnit);
237             }
238             if (content.remaining() < 4) {
239                 hasExts = false;
240             }
241             if (hasExts && (avcProfileIndication == 100 || avcProfileIndication == 110 || avcProfileIndication == 122 || avcProfileIndication == 144)) {
242                 // actually only some bits are interesting so masking with & x would be good but not all Mp4 creating tools set the reserved bits to 1.
243                 // So we need to store all bits
244                 brb = new BitReaderBuffer(content);
245                 chromaFormatPaddingBits = brb.readBits(6);
246                 chromaFormat = brb.readBits(2);
247                 bitDepthLumaMinus8PaddingBits = brb.readBits(5);
248                 bitDepthLumaMinus8 = brb.readBits(3);
249                 bitDepthChromaMinus8PaddingBits = brb.readBits(5);
250                 bitDepthChromaMinus8 = brb.readBits(3);
251                 long numOfSequenceParameterSetExt = IsoTypeReader.readUInt8(content);
252                 for (int i = 0; i < numOfSequenceParameterSetExt; i++) {
253                     int sequenceParameterSetExtLength = IsoTypeReader.readUInt16(content);
254                     byte[] sequenceParameterSetExtNALUnit = new byte[sequenceParameterSetExtLength];
255                     content.get(sequenceParameterSetExtNALUnit);
256                     sequenceParameterSetExts.add(sequenceParameterSetExtNALUnit);
257                 }
258             } else {
259                 chromaFormat = -1;
260                 bitDepthLumaMinus8 = -1;
261                 bitDepthChromaMinus8 = -1;
262             }
263         }
264 
getContent(ByteBuffer byteBuffer)265         public void getContent(ByteBuffer byteBuffer) {
266             IsoTypeWriter.writeUInt8(byteBuffer, configurationVersion);
267             IsoTypeWriter.writeUInt8(byteBuffer, avcProfileIndication);
268             IsoTypeWriter.writeUInt8(byteBuffer, profileCompatibility);
269             IsoTypeWriter.writeUInt8(byteBuffer, avcLevelIndication);
270             BitWriterBuffer bwb = new BitWriterBuffer(byteBuffer);
271             bwb.writeBits(lengthSizeMinusOnePaddingBits, 6);
272             bwb.writeBits(lengthSizeMinusOne, 2);
273             bwb.writeBits(numberOfSequenceParameterSetsPaddingBits, 3);
274             bwb.writeBits(pictureParameterSets.size(), 5);
275             for (byte[] sequenceParameterSetNALUnit : sequenceParameterSets) {
276                 IsoTypeWriter.writeUInt16(byteBuffer, sequenceParameterSetNALUnit.length);
277                 byteBuffer.put(sequenceParameterSetNALUnit);
278             }
279             IsoTypeWriter.writeUInt8(byteBuffer, pictureParameterSets.size());
280             for (byte[] pictureParameterSetNALUnit : pictureParameterSets) {
281                 IsoTypeWriter.writeUInt16(byteBuffer, pictureParameterSetNALUnit.length);
282                 byteBuffer.put(pictureParameterSetNALUnit);
283             }
284             if (hasExts && (avcProfileIndication == 100 || avcProfileIndication == 110 || avcProfileIndication == 122 || avcProfileIndication == 144)) {
285 
286                 bwb = new BitWriterBuffer(byteBuffer);
287                 bwb.writeBits(chromaFormatPaddingBits, 6);
288                 bwb.writeBits(chromaFormat, 2);
289                 bwb.writeBits(bitDepthLumaMinus8PaddingBits, 5);
290                 bwb.writeBits(bitDepthLumaMinus8, 3);
291                 bwb.writeBits(bitDepthChromaMinus8PaddingBits, 5);
292                 bwb.writeBits(bitDepthChromaMinus8, 3);
293                 for (byte[] sequenceParameterSetExtNALUnit : sequenceParameterSetExts) {
294                     IsoTypeWriter.writeUInt16(byteBuffer, sequenceParameterSetExtNALUnit.length);
295                     byteBuffer.put(sequenceParameterSetExtNALUnit);
296                 }
297             }
298         }
299 
getContentSize()300         public long getContentSize() {
301             long size = 5;
302             size += 1; // sequenceParamsetLength
303             for (byte[] sequenceParameterSetNALUnit : sequenceParameterSets) {
304                 size += 2; //lengthSizeMinusOne field
305                 size += sequenceParameterSetNALUnit.length;
306             }
307             size += 1; // pictureParamsetLength
308             for (byte[] pictureParameterSetNALUnit : pictureParameterSets) {
309                 size += 2; //lengthSizeMinusOne field
310                 size += pictureParameterSetNALUnit.length;
311             }
312             if (hasExts && (avcProfileIndication == 100 || avcProfileIndication == 110 || avcProfileIndication == 122 || avcProfileIndication == 144)) {
313                 size += 4;
314                 for (byte[] sequenceParameterSetExtNALUnit : sequenceParameterSetExts) {
315                     size += 2;
316                     size += sequenceParameterSetExtNALUnit.length;
317                 }
318             }
319 
320             return size;
321         }
322 
getPPS()323         public String[] getPPS() {
324             ArrayList<String> l = new ArrayList<String>();
325             for (byte[] pictureParameterSet : pictureParameterSets) {
326                 String details = "not parsable";
327                 try {
328                     details = PictureParameterSet.read(pictureParameterSet).toString();
329                 } catch (IOException e) {
330                     throw new RuntimeException(e);
331                 }
332 
333                 l.add(details);
334             }
335             return l.toArray(new String[l.size()]);
336         }
337 
getSPS()338         public String[] getSPS() {
339             ArrayList<String> l = new ArrayList<String>();
340             for (byte[] sequenceParameterSet : sequenceParameterSets) {
341                 String detail = "not parsable";
342                 try {
343                     detail = SeqParameterSet.read(new ByteArrayInputStream(sequenceParameterSet)).toString();
344                 } catch (IOException e) {
345 
346                 }
347                 l.add(detail);
348             }
349             return l.toArray(new String[l.size()]);
350         }
351 
getSequenceParameterSetsAsStrings()352         public List<String> getSequenceParameterSetsAsStrings() {
353             List <String> result = new ArrayList<String>(sequenceParameterSets.size());
354             for (byte[] parameterSet : sequenceParameterSets) {
355                 result.add(Hex.encodeHex(parameterSet));
356             }
357             return result;
358         }
359 
getSequenceParameterSetExtsAsStrings()360         public List<String> getSequenceParameterSetExtsAsStrings() {
361             List <String> result = new ArrayList<String>(sequenceParameterSetExts.size());
362             for (byte[] parameterSet : sequenceParameterSetExts) {
363                 result.add(Hex.encodeHex(parameterSet));
364             }
365             return result;
366         }
367 
getPictureParameterSetsAsStrings()368         public List<String> getPictureParameterSetsAsStrings() {
369             List <String> result = new ArrayList<String>(pictureParameterSets.size());
370             for (byte[] parameterSet : pictureParameterSets) {
371                 result.add(Hex.encodeHex(parameterSet));
372             }
373             return result;
374         }
375 
376     }
377 }
378 
379