/*
* Copyright 2008 CoreMedia AG, Hamburg
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.coremedia.iso.boxes.h264;
import com.coremedia.iso.BoxParser;
import com.coremedia.iso.IsoBufferWrapper;
import com.coremedia.iso.IsoBufferWrapperImpl;
import com.coremedia.iso.IsoFile;
import com.coremedia.iso.IsoOutputStream;
import com.coremedia.iso.boxes.AbstractBox;
import com.coremedia.iso.boxes.Box;
import com.googlecode.mp4parser.h264.model.PictureParameterSet;
import com.googlecode.mp4parser.h264.model.SeqParameterSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Defined in ISO/IEC 14496-15:2004.
*/
public final class AvcConfigurationBox extends AbstractBox {
public static final String TYPE = "avcC";
private int configurationVersion;
private int avcProfileIndicaation;
private int profileCompatibility;
private int avcLevelIndication;
private int lengthSizeMinusOne;
List<byte[]> sequenceParameterSets = new ArrayList<byte[]>();
List<byte[]> pictureParameterSets = new ArrayList<byte[]>();
public AvcConfigurationBox() {
super(IsoFile.fourCCtoBytes(TYPE));
}
public int getConfigurationVersion() {
return configurationVersion;
}
public int getAvcProfileIndicaation() {
return avcProfileIndicaation;
}
public int getProfileCompatibility() {
return profileCompatibility;
}
public int getAvcLevelIndication() {
return avcLevelIndication;
}
public int getLengthSizeMinusOne() {
return lengthSizeMinusOne;
}
public List<byte[]> getSequenceParameterSets() {
return Collections.unmodifiableList(sequenceParameterSets);
}
public List<byte[]> getPictureParameterSets() {
return Collections.unmodifiableList(pictureParameterSets);
}
public void setConfigurationVersion(int configurationVersion) {
this.configurationVersion = configurationVersion;
}
public void setAvcProfileIndicaation(int avcProfileIndicaation) {
this.avcProfileIndicaation = avcProfileIndicaation;
}
public void setProfileCompatibility(int profileCompatibility) {
this.profileCompatibility = profileCompatibility;
}
public void setAvcLevelIndication(int avcLevelIndication) {
this.avcLevelIndication = avcLevelIndication;
}
public void setLengthSizeMinusOne(int lengthSizeMinusOne) {
this.lengthSizeMinusOne = lengthSizeMinusOne;
}
public void setSequenceParameterSets(List<byte[]> sequenceParameterSets) {
this.sequenceParameterSets = sequenceParameterSets;
}
public void setPictureParameterSets(List<byte[]> pictureParameterSets) {
this.pictureParameterSets = pictureParameterSets;
}
public void parse(IsoBufferWrapper in, long size, BoxParser boxParser, Box lastMovieFragmentBox) throws IOException {
/*
unsigned int(8) configurationVersion = 1;
unsigned int(8) AVCProfileIndication;
unsigned int(8) profile_compatibility;
unsigned int(8) AVCLevelIndication;
bit(6) reserved = '111111'b;
unsigned int(2) lengthSizeMinusOne;
bit(3) reserved = '111'b;
*/
configurationVersion = in.readUInt8();
avcProfileIndicaation = in.readUInt8();
profileCompatibility = in.readUInt8();
avcLevelIndication = in.readUInt8();
int temp = in.readUInt8();
lengthSizeMinusOne = temp & 3;
long numberOfSeuqenceParameterSets = in.readUInt8() & 31;
for (int i = 0; i < numberOfSeuqenceParameterSets; i++) {
int sequenceParameterSetLength = in.readUInt16();
byte[] sequenceParameterSetNALUnit = in.read(sequenceParameterSetLength);
sequenceParameterSets.add(sequenceParameterSetNALUnit);
}
long numberOfPictureParameterSets = in.readUInt8();
for (int i = 0; i < numberOfPictureParameterSets; i++) {
int pictureParameterSetLength = in.readUInt16();
byte[] pictureParameterSetNALUnit = in.read(pictureParameterSetLength);
pictureParameterSets.add(pictureParameterSetNALUnit);
}
}
protected long getContentSize() {
long size = 5;
size += 1; // sequenceParamsetLength
for (byte[] sequenceParameterSetNALUnit : sequenceParameterSets) {
size += 2; //lengthSizeMinusOne field
size += sequenceParameterSetNALUnit.length;
}
size += 1; // pictureParamsetLength
for (byte[] pictureParameterSetNALUnit : pictureParameterSets) {
size += 2; //lengthSizeMinusOne field
size += pictureParameterSetNALUnit.length;
}
return size;
}
protected void getContent(IsoOutputStream os) throws IOException {
os.writeUInt8(configurationVersion);
os.writeUInt8(avcProfileIndicaation);
os.writeUInt8(profileCompatibility);
os.writeUInt8(avcLevelIndication);
os.writeUInt8(lengthSizeMinusOne | (63 << 2));
os.writeUInt8((pictureParameterSets.size() & 31) | (7 << 5));
for (byte[] sequenceParameterSetNALUnit : sequenceParameterSets) {
os.writeUInt16(sequenceParameterSetNALUnit.length);
os.write(sequenceParameterSetNALUnit);
}
os.writeUInt8(pictureParameterSets.size());
for (byte[] pictureParameterSetNALUnit : pictureParameterSets) {
os.writeUInt16(pictureParameterSetNALUnit.length);
os.write(pictureParameterSetNALUnit);
}
}
// just to display sps in isoviewer no practical use
public String[] getPPS() {
ArrayList<String> l = new ArrayList<String>();
for (byte[] pictureParameterSet : pictureParameterSets) {
String details = "not parsable";
try {
details = PictureParameterSet.read(new IsoBufferWrapperImpl(pictureParameterSet)).toString();
} catch (IOException e) {
}
l.add(details);
}
return l.toArray(new String[l.size()]);
}
// just to display sps in isoviewer no practical use
public String[] getSPS() {
ArrayList<String> l = new ArrayList<String>();
for (byte[] sequenceParameterSet : sequenceParameterSets) {
String detail = "not parsable";
try {
detail = SeqParameterSet.read(new IsoBufferWrapperImpl(sequenceParameterSet)).toString();
} catch (IOException e) {
}
l.add(detail);
}
return l.toArray(new String[l.size()]);
}
}