Home | History | Annotate | Download | only in h264
      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 
     44     public AvcConfigurationBox() {
     45         super(TYPE);
     46     }
     47 
     48     public int getConfigurationVersion() {
     49         return avcDecoderConfigurationRecord.configurationVersion;
     50     }
     51 
     52     public int getAvcProfileIndication() {
     53         return avcDecoderConfigurationRecord.avcProfileIndication;
     54     }
     55 
     56     public int getProfileCompatibility() {
     57         return avcDecoderConfigurationRecord.profileCompatibility;
     58     }
     59 
     60     public int getAvcLevelIndication() {
     61         return avcDecoderConfigurationRecord.avcLevelIndication;
     62     }
     63 
     64     public int getLengthSizeMinusOne() {
     65         return avcDecoderConfigurationRecord.lengthSizeMinusOne;
     66     }
     67 
     68     public List<byte[]> getSequenceParameterSets() {
     69         return Collections.unmodifiableList(avcDecoderConfigurationRecord.sequenceParameterSets);
     70     }
     71 
     72     public List<byte[]> getPictureParameterSets() {
     73         return Collections.unmodifiableList(avcDecoderConfigurationRecord.pictureParameterSets);
     74     }
     75 
     76     public void setConfigurationVersion(int configurationVersion) {
     77         this.avcDecoderConfigurationRecord.configurationVersion = configurationVersion;
     78     }
     79 
     80     public void setAvcProfileIndication(int avcProfileIndication) {
     81         this.avcDecoderConfigurationRecord.avcProfileIndication = avcProfileIndication;
     82     }
     83 
     84     public void setProfileCompatibility(int profileCompatibility) {
     85         this.avcDecoderConfigurationRecord.profileCompatibility = profileCompatibility;
     86     }
     87 
     88     public void setAvcLevelIndication(int avcLevelIndication) {
     89         this.avcDecoderConfigurationRecord.avcLevelIndication = avcLevelIndication;
     90     }
     91 
     92     public void setLengthSizeMinusOne(int lengthSizeMinusOne) {
     93         this.avcDecoderConfigurationRecord.lengthSizeMinusOne = lengthSizeMinusOne;
     94     }
     95 
     96     public void setSequenceParameterSets(List<byte[]> sequenceParameterSets) {
     97         this.avcDecoderConfigurationRecord.sequenceParameterSets = sequenceParameterSets;
     98     }
     99 
    100     public void setPictureParameterSets(List<byte[]> pictureParameterSets) {
    101         this.avcDecoderConfigurationRecord.pictureParameterSets = pictureParameterSets;
    102     }
    103 
    104     public int getChromaFormat() {
    105         return avcDecoderConfigurationRecord.chromaFormat;
    106     }
    107 
    108     public void setChromaFormat(int chromaFormat) {
    109         this.avcDecoderConfigurationRecord.chromaFormat = chromaFormat;
    110     }
    111 
    112     public int getBitDepthLumaMinus8() {
    113         return avcDecoderConfigurationRecord.bitDepthLumaMinus8;
    114     }
    115 
    116     public void setBitDepthLumaMinus8(int bitDepthLumaMinus8) {
    117         this.avcDecoderConfigurationRecord.bitDepthLumaMinus8 = bitDepthLumaMinus8;
    118     }
    119 
    120     public int getBitDepthChromaMinus8() {
    121         return avcDecoderConfigurationRecord.bitDepthChromaMinus8;
    122     }
    123 
    124     public void setBitDepthChromaMinus8(int bitDepthChromaMinus8) {
    125         this.avcDecoderConfigurationRecord.bitDepthChromaMinus8 = bitDepthChromaMinus8;
    126     }
    127 
    128     public List<byte[]> getSequenceParameterSetExts() {
    129         return avcDecoderConfigurationRecord.sequenceParameterSetExts;
    130     }
    131 
    132     public void setSequenceParameterSetExts(List<byte[]> sequenceParameterSetExts) {
    133         this.avcDecoderConfigurationRecord.sequenceParameterSetExts = sequenceParameterSetExts;
    134     }
    135 
    136     public boolean hasExts() {
    137         return avcDecoderConfigurationRecord.hasExts;
    138     }
    139 
    140     public void setHasExts(boolean hasExts) {
    141         this.avcDecoderConfigurationRecord.hasExts = hasExts;
    142     }
    143 
    144     @Override
    145     public void _parseDetails(ByteBuffer content) {
    146         avcDecoderConfigurationRecord = new AVCDecoderConfigurationRecord(content);
    147     }
    148 
    149 
    150     @Override
    151     public long getContentSize() {
    152         return avcDecoderConfigurationRecord.getContentSize();
    153     }
    154 
    155 
    156     @Override
    157     public void getContent(ByteBuffer byteBuffer) {
    158         avcDecoderConfigurationRecord.getContent(byteBuffer);
    159     }
    160 
    161     // just to display sps in isoviewer no practical use
    162     public String[] getSPS() {
    163         return avcDecoderConfigurationRecord.getSPS();
    164     }
    165 
    166     public String[] getPPS() {
    167         return avcDecoderConfigurationRecord.getPPS();
    168     }
    169 
    170     public List<String> getSequenceParameterSetsAsStrings() {
    171         return avcDecoderConfigurationRecord.getSequenceParameterSetsAsStrings();
    172     }
    173 
    174     public List<String> getSequenceParameterSetExtsAsStrings() {
    175         return avcDecoderConfigurationRecord.getSequenceParameterSetExtsAsStrings();
    176     }
    177 
    178     public List<String> getPictureParameterSetsAsStrings() {
    179         return avcDecoderConfigurationRecord.getPictureParameterSetsAsStrings();
    180     }
    181 
    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 
    211         public AVCDecoderConfigurationRecord() {
    212         }
    213 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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