use of com.google.android.exoplayer2.util.NalUnitUtil.SpsData in project ExoPlayer by google.
the class AvcConfig method parse.
/**
* Parses AVC configuration data.
*
* @param data A {@link ParsableByteArray}, whose position is set to the start of the AVC
* configuration data to parse.
* @return A parsed representation of the AVC configuration data.
* @throws ParserException If an error occurred parsing the data.
*/
public static AvcConfig parse(ParsableByteArray data) throws ParserException {
try {
// Skip to the AVCDecoderConfigurationRecord (defined in 14496-15)
data.skipBytes(4);
int nalUnitLengthFieldLength = (data.readUnsignedByte() & 0x3) + 1;
if (nalUnitLengthFieldLength == 3) {
throw new IllegalStateException();
}
List<byte[]> initializationData = new ArrayList<>();
int numSequenceParameterSets = data.readUnsignedByte() & 0x1F;
for (int j = 0; j < numSequenceParameterSets; j++) {
initializationData.add(buildNalUnitForChild(data));
}
int numPictureParameterSets = data.readUnsignedByte();
for (int j = 0; j < numPictureParameterSets; j++) {
initializationData.add(buildNalUnitForChild(data));
}
int width = Format.NO_VALUE;
int height = Format.NO_VALUE;
float pixelWidthHeightRatio = 1;
@Nullable String codecs = null;
if (numSequenceParameterSets > 0) {
byte[] sps = initializationData.get(0);
SpsData spsData = NalUnitUtil.parseSpsNalUnit(initializationData.get(0), nalUnitLengthFieldLength, sps.length);
width = spsData.width;
height = spsData.height;
pixelWidthHeightRatio = spsData.pixelWidthHeightRatio;
codecs = CodecSpecificDataUtil.buildAvcCodecString(spsData.profileIdc, spsData.constraintsFlagsAndReservedZero2Bits, spsData.levelIdc);
}
return new AvcConfig(initializationData, nalUnitLengthFieldLength, width, height, pixelWidthHeightRatio, codecs);
} catch (ArrayIndexOutOfBoundsException e) {
throw ParserException.createForMalformedContainer("Error parsing AVC config", e);
}
}
use of com.google.android.exoplayer2.util.NalUnitUtil.SpsData in project ExoPlayer by google.
the class H264Reader method endNalUnit.
@RequiresNonNull({ "output", "sampleReader" })
private void endNalUnit(long position, int offset, int discardPadding, long pesTimeUs) {
if (!hasOutputFormat || sampleReader.needsSpsPps()) {
sps.endNalUnit(discardPadding);
pps.endNalUnit(discardPadding);
if (!hasOutputFormat) {
if (sps.isCompleted() && pps.isCompleted()) {
List<byte[]> initializationData = new ArrayList<>();
initializationData.add(Arrays.copyOf(sps.nalData, sps.nalLength));
initializationData.add(Arrays.copyOf(pps.nalData, pps.nalLength));
NalUnitUtil.SpsData spsData = NalUnitUtil.parseSpsNalUnit(sps.nalData, 3, sps.nalLength);
NalUnitUtil.PpsData ppsData = NalUnitUtil.parsePpsNalUnit(pps.nalData, 3, pps.nalLength);
String codecs = CodecSpecificDataUtil.buildAvcCodecString(spsData.profileIdc, spsData.constraintsFlagsAndReservedZero2Bits, spsData.levelIdc);
output.format(new Format.Builder().setId(formatId).setSampleMimeType(MimeTypes.VIDEO_H264).setCodecs(codecs).setWidth(spsData.width).setHeight(spsData.height).setPixelWidthHeightRatio(spsData.pixelWidthHeightRatio).setInitializationData(initializationData).build());
hasOutputFormat = true;
sampleReader.putSps(spsData);
sampleReader.putPps(ppsData);
sps.reset();
pps.reset();
}
} else if (sps.isCompleted()) {
NalUnitUtil.SpsData spsData = NalUnitUtil.parseSpsNalUnit(sps.nalData, 3, sps.nalLength);
sampleReader.putSps(spsData);
sps.reset();
} else if (pps.isCompleted()) {
NalUnitUtil.PpsData ppsData = NalUnitUtil.parsePpsNalUnit(pps.nalData, 3, pps.nalLength);
sampleReader.putPps(ppsData);
pps.reset();
}
}
if (sei.endNalUnit(discardPadding)) {
int unescapedLength = NalUnitUtil.unescapeStream(sei.nalData, sei.nalLength);
seiWrapper.reset(sei.nalData, unescapedLength);
// NAL prefix and nal_unit() header.
seiWrapper.setPosition(4);
seiReader.consume(pesTimeUs, seiWrapper);
}
boolean sampleIsKeyFrame = sampleReader.endNalUnit(position, offset, hasOutputFormat, randomAccessIndicator);
if (sampleIsKeyFrame) {
// This is either an IDR frame or the first I-frame since the random access indicator, so mark
// it as a keyframe. Clear the flag so that subsequent non-IDR I-frames are not marked as
// keyframes until we see another random access indicator.
randomAccessIndicator = false;
}
}
Aggregations