diff --git a/library/src/main/java/com/google/android/exoplayer/chunk/parser/mp4/FragmentedMp4Extractor.java b/library/src/main/java/com/google/android/exoplayer/chunk/parser/mp4/FragmentedMp4Extractor.java index 23fffe997a..42de648051 100644 --- a/library/src/main/java/com/google/android/exoplayer/chunk/parser/mp4/FragmentedMp4Extractor.java +++ b/library/src/main/java/com/google/android/exoplayer/chunk/parser/mp4/FragmentedMp4Extractor.java @@ -26,9 +26,9 @@ import com.google.android.exoplayer.mp4.Atom; import com.google.android.exoplayer.mp4.Atom.ContainerAtom; import com.google.android.exoplayer.mp4.Atom.LeafAtom; import com.google.android.exoplayer.mp4.CommonMp4AtomParsers; -import com.google.android.exoplayer.mp4.Mp4Util; import com.google.android.exoplayer.mp4.Track; import com.google.android.exoplayer.upstream.NonBlockingInputStream; +import com.google.android.exoplayer.util.H264Util; import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.ParsableByteArray; import com.google.android.exoplayer.util.Util; @@ -157,7 +157,7 @@ public final class FragmentedMp4Extractor implements Extractor { public FragmentedMp4Extractor(int workaroundFlags) { this.workaroundFlags = workaroundFlags; parserState = STATE_READING_ATOM_HEADER; - atomHeader = new ParsableByteArray(Mp4Util.ATOM_HEADER_SIZE); + atomHeader = new ParsableByteArray(Atom.ATOM_HEADER_SIZE); extendedTypeScratch = new byte[16]; containerAtoms = new Stack(); fragmentRun = new TrackFragment(); @@ -259,14 +259,14 @@ public final class FragmentedMp4Extractor implements Extractor { } private int readAtomHeader(NonBlockingInputStream inputStream) { - int remainingBytes = Mp4Util.ATOM_HEADER_SIZE - atomBytesRead; + int remainingBytes = Atom.ATOM_HEADER_SIZE - atomBytesRead; int bytesRead = inputStream.read(atomHeader.data, atomBytesRead, remainingBytes); if (bytesRead == -1) { return RESULT_END_OF_STREAM; } rootAtomBytesRead += bytesRead; atomBytesRead += bytesRead; - if (atomBytesRead != Mp4Util.ATOM_HEADER_SIZE) { + if (atomBytesRead != Atom.ATOM_HEADER_SIZE) { return RESULT_NEED_MORE_DATA; } @@ -288,10 +288,10 @@ public final class FragmentedMp4Extractor implements Extractor { if (CONTAINER_TYPES.contains(atomTypeInteger)) { enterState(STATE_READING_ATOM_HEADER); containerAtoms.add(new ContainerAtom(atomType, - rootAtomBytesRead + atomSize - Mp4Util.ATOM_HEADER_SIZE)); + rootAtomBytesRead + atomSize - Atom.ATOM_HEADER_SIZE)); } else { atomData = new ParsableByteArray(atomSize); - System.arraycopy(atomHeader.data, 0, atomData.data, 0, Mp4Util.ATOM_HEADER_SIZE); + System.arraycopy(atomHeader.data, 0, atomData.data, 0, Atom.ATOM_HEADER_SIZE); enterState(STATE_READING_ATOM_PAYLOAD); } } else { @@ -360,7 +360,7 @@ public final class FragmentedMp4Extractor implements Extractor { LeafAtom child = moovChildren.get(i); if (child.type == Atom.TYPE_pssh) { ParsableByteArray psshAtom = child.data; - psshAtom.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE); + psshAtom.setPosition(Atom.FULL_ATOM_HEADER_SIZE); UUID uuid = new UUID(psshAtom.readLong(), psshAtom.readLong()); int dataSize = psshAtom.readInt(); byte[] data = new byte[dataSize]; @@ -399,7 +399,7 @@ public final class FragmentedMp4Extractor implements Extractor { * Parses a trex atom (defined in 14496-12). */ private static DefaultSampleValues parseTrex(ParsableByteArray trex) { - trex.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE + 4); + trex.setPosition(Atom.FULL_ATOM_HEADER_SIZE + 4); int defaultSampleDescriptionIndex = trex.readUnsignedIntToInt() - 1; int defaultSampleDuration = trex.readUnsignedIntToInt(); int defaultSampleSize = trex.readUnsignedIntToInt(); @@ -453,9 +453,9 @@ public final class FragmentedMp4Extractor implements Extractor { private static void parseSaiz(TrackEncryptionBox encryptionBox, ParsableByteArray saiz, TrackFragment out) { int vectorSize = encryptionBox.initializationVectorSize; - saiz.setPosition(Mp4Util.ATOM_HEADER_SIZE); + saiz.setPosition(Atom.ATOM_HEADER_SIZE); int fullAtom = saiz.readInt(); - int flags = Mp4Util.parseFullAtomFlags(fullAtom); + int flags = Atom.parseFullAtomFlags(fullAtom); if ((flags & 0x01) == 1) { saiz.skip(8); } @@ -490,9 +490,9 @@ public final class FragmentedMp4Extractor implements Extractor { */ private static DefaultSampleValues parseTfhd(DefaultSampleValues extendsDefaults, ParsableByteArray tfhd) { - tfhd.setPosition(Mp4Util.ATOM_HEADER_SIZE); + tfhd.setPosition(Atom.ATOM_HEADER_SIZE); int fullAtom = tfhd.readInt(); - int flags = Mp4Util.parseFullAtomFlags(fullAtom); + int flags = Atom.parseFullAtomFlags(fullAtom); tfhd.skip(4); // trackId if ((flags & 0x01 /* base_data_offset_present */) != 0) { @@ -519,9 +519,9 @@ public final class FragmentedMp4Extractor implements Extractor { * media, expressed in the media's timescale. */ private static long parseTfdt(ParsableByteArray tfdt) { - tfdt.setPosition(Mp4Util.ATOM_HEADER_SIZE); + tfdt.setPosition(Atom.ATOM_HEADER_SIZE); int fullAtom = tfdt.readInt(); - int version = Mp4Util.parseFullAtomVersion(fullAtom); + int version = Atom.parseFullAtomVersion(fullAtom); return version == 1 ? tfdt.readUnsignedLongToLong() : tfdt.readUnsignedInt(); } @@ -536,9 +536,9 @@ public final class FragmentedMp4Extractor implements Extractor { */ private static void parseTrun(Track track, DefaultSampleValues defaultSampleValues, long decodeTime, int workaroundFlags, ParsableByteArray trun, TrackFragment out) { - trun.setPosition(Mp4Util.ATOM_HEADER_SIZE); + trun.setPosition(Atom.ATOM_HEADER_SIZE); int fullAtom = trun.readInt(); - int flags = Mp4Util.parseFullAtomFlags(fullAtom); + int flags = Atom.parseFullAtomFlags(fullAtom); int sampleCount = trun.readUnsignedIntToInt(); if ((flags & 0x01 /* data_offset_present */) != 0) { @@ -596,7 +596,7 @@ public final class FragmentedMp4Extractor implements Extractor { private static void parseUuid(ParsableByteArray uuid, TrackFragment out, byte[] extendedTypeScratch) { - uuid.setPosition(Mp4Util.ATOM_HEADER_SIZE); + uuid.setPosition(Atom.ATOM_HEADER_SIZE); uuid.readBytes(extendedTypeScratch, 0, 16); // Currently this parser only supports Microsoft's PIFF SampleEncryptionBox. @@ -615,9 +615,9 @@ public final class FragmentedMp4Extractor implements Extractor { } private static void parseSenc(ParsableByteArray senc, int offset, TrackFragment out) { - senc.setPosition(Mp4Util.ATOM_HEADER_SIZE + offset); + senc.setPosition(Atom.ATOM_HEADER_SIZE + offset); int fullAtom = senc.readInt(); - int flags = Mp4Util.parseFullAtomFlags(fullAtom); + int flags = Atom.parseFullAtomFlags(fullAtom); if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) { // TODO: Implement this. @@ -639,9 +639,9 @@ public final class FragmentedMp4Extractor implements Extractor { * Parses a sidx atom (defined in 14496-12). */ private static SegmentIndex parseSidx(ParsableByteArray atom) { - atom.setPosition(Mp4Util.ATOM_HEADER_SIZE); + atom.setPosition(Atom.ATOM_HEADER_SIZE); int fullAtom = atom.readInt(); - int version = Mp4Util.parseFullAtomVersion(fullAtom); + int version = Atom.parseFullAtomVersion(fullAtom); atom.skip(4); long timescale = atom.readUnsignedInt(); @@ -781,7 +781,7 @@ public final class FragmentedMp4Extractor implements Extractor { if (track.type == Track.TYPE_VIDEO) { // The mp4 file contains length-prefixed NAL units, but the decoder wants start code // delimited content. - Mp4Util.replaceLengthPrefixesWithAvcStartCodes(outputData, sampleSize); + H264Util.replaceLengthPrefixesWithAvcStartCodes(outputData, sampleSize); } out.size = sampleSize; } diff --git a/library/src/main/java/com/google/android/exoplayer/hls/parser/H264Reader.java b/library/src/main/java/com/google/android/exoplayer/hls/parser/H264Reader.java index 40b3b1ca32..68582dc20b 100644 --- a/library/src/main/java/com/google/android/exoplayer/hls/parser/H264Reader.java +++ b/library/src/main/java/com/google/android/exoplayer/hls/parser/H264Reader.java @@ -18,8 +18,8 @@ package com.google.android.exoplayer.hls.parser; import com.google.android.exoplayer.C; import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.hls.parser.HlsExtractor.TrackOutput; -import com.google.android.exoplayer.mp4.Mp4Util; import com.google.android.exoplayer.util.Assertions; +import com.google.android.exoplayer.util.H264Util; import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.ParsableBitArray; import com.google.android.exoplayer.util.ParsableByteArray; @@ -73,7 +73,7 @@ import java.util.List; // Scan the appended data, processing NAL units as they are encountered while (offset < limit) { - int nextNalUnitOffset = Mp4Util.findNalUnit(dataArray, offset, limit, prefixFlags); + int nextNalUnitOffset = H264Util.findNalUnit(dataArray, offset, limit, prefixFlags); if (nextNalUnitOffset < limit) { // We've seen the start of a NAL unit. @@ -84,7 +84,7 @@ import java.util.List; feedNalUnitTargetBuffersData(dataArray, offset, nextNalUnitOffset); } - int nalUnitType = Mp4Util.getNalUnitType(dataArray, nextNalUnitOffset); + int nalUnitType = H264Util.getNalUnitType(dataArray, nextNalUnitOffset); int nalUnitOffsetInData = nextNalUnitOffset - limit; if (nalUnitType == NAL_UNIT_TYPE_AUD) { if (output.isWritingSample()) { diff --git a/library/src/main/java/com/google/android/exoplayer/mp4/Atom.java b/library/src/main/java/com/google/android/exoplayer/mp4/Atom.java index b3b96dce94..ffe0f9cc77 100644 --- a/library/src/main/java/com/google/android/exoplayer/mp4/Atom.java +++ b/library/src/main/java/com/google/android/exoplayer/mp4/Atom.java @@ -24,6 +24,18 @@ import java.util.List; public abstract class Atom { + /** Size of an atom header, in bytes. */ + public static final int ATOM_HEADER_SIZE = 8; + + /** Size of a long atom header, in bytes. */ + public static final int LONG_ATOM_HEADER_SIZE = 16; + + /** Size of a full atom header, in bytes. */ + public static final int FULL_ATOM_HEADER_SIZE = 12; + + /** Value for the first 32 bits of atomSize when the atom size is actually a long value. */ + public static final int LONG_SIZE_PREFIX = 1; + public static final int TYPE_ftyp = getAtomTypeInteger("ftyp"); public static final int TYPE_avc1 = getAtomTypeInteger("avc1"); public static final int TYPE_avc3 = getAtomTypeInteger("avc3"); @@ -154,6 +166,20 @@ public abstract class Atom { } + /** + * Parses the version number out of the additional integer component of a full atom. + */ + public static int parseFullAtomVersion(int fullAtomInt) { + return 0x000000FF & (fullAtomInt >> 24); + } + + /** + * Parses the atom flags out of the additional integer component of a full atom. + */ + public static int parseFullAtomFlags(int fullAtomInt) { + return 0x00FFFFFF & fullAtomInt; + } + private static String getAtomTypeString(int type) { return "" + (char) (type >> 24) + (char) ((type >> 16) & 0xFF) diff --git a/library/src/main/java/com/google/android/exoplayer/mp4/CommonMp4AtomParsers.java b/library/src/main/java/com/google/android/exoplayer/mp4/CommonMp4AtomParsers.java index 0f9e754204..2170425058 100644 --- a/library/src/main/java/com/google/android/exoplayer/mp4/CommonMp4AtomParsers.java +++ b/library/src/main/java/com/google/android/exoplayer/mp4/CommonMp4AtomParsers.java @@ -20,6 +20,7 @@ import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.chunk.parser.mp4.TrackEncryptionBox; import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.CodecSpecificDataUtil; +import com.google.android.exoplayer.util.H264Util; import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.ParsableByteArray; import com.google.android.exoplayer.util.Util; @@ -102,7 +103,7 @@ public final class CommonMp4AtomParsers { ParsableByteArray ctts = cttsAtom != null ? cttsAtom.data : null; // Skip full atom. - stsz.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE); + stsz.setPosition(Atom.FULL_ATOM_HEADER_SIZE); int fixedSampleSize = stsz.readUnsignedIntToInt(); int sampleCount = stsz.readUnsignedIntToInt(); @@ -112,10 +113,10 @@ public final class CommonMp4AtomParsers { int[] flags = new int[sampleCount]; // Prepare to read chunk offsets. - chunkOffsets.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE); + chunkOffsets.setPosition(Atom.FULL_ATOM_HEADER_SIZE); int chunkCount = chunkOffsets.readUnsignedIntToInt(); - stsc.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE); + stsc.setPosition(Atom.FULL_ATOM_HEADER_SIZE); int remainingSamplesPerChunkChanges = stsc.readUnsignedIntToInt() - 1; Assertions.checkState(stsc.readInt() == 1, "stsc first chunk must be 1"); int samplesPerChunk = stsc.readUnsignedIntToInt(); @@ -130,7 +131,7 @@ public final class CommonMp4AtomParsers { int remainingSamplesInChunk = samplesPerChunk; // Prepare to read sample timestamps. - stts.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE); + stts.setPosition(Atom.FULL_ATOM_HEADER_SIZE); int remainingTimestampDeltaChanges = stts.readUnsignedIntToInt() - 1; int remainingSamplesAtTimestampDelta = stts.readUnsignedIntToInt(); int timestampDeltaInTimeUnits = stts.readUnsignedIntToInt(); @@ -141,8 +142,8 @@ public final class CommonMp4AtomParsers { int remainingTimestampOffsetChanges = 0; int timestampOffset = 0; if (ctts != null) { - ctts.setPosition(Mp4Util.ATOM_HEADER_SIZE); - cttsHasSignedOffsets = Mp4Util.parseFullAtomVersion(ctts.readInt()) == 1; + ctts.setPosition(Atom.ATOM_HEADER_SIZE); + cttsHasSignedOffsets = Atom.parseFullAtomVersion(ctts.readInt()) == 1; remainingTimestampOffsetChanges = ctts.readUnsignedIntToInt() - 1; remainingSamplesAtTimestampOffset = ctts.readUnsignedIntToInt(); timestampOffset = cttsHasSignedOffsets ? ctts.readInt() : ctts.readUnsignedIntToInt(); @@ -151,7 +152,7 @@ public final class CommonMp4AtomParsers { int nextSynchronizationSampleIndex = -1; int remainingSynchronizationSamples = 0; if (stss != null) { - stss.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE); + stss.setPosition(Atom.FULL_ATOM_HEADER_SIZE); remainingSynchronizationSamples = stss.readUnsignedIntToInt(); nextSynchronizationSampleIndex = stss.readUnsignedIntToInt() - 1; } @@ -249,10 +250,10 @@ public final class CommonMp4AtomParsers { * @return Timescale for the movie. */ private static long parseMvhd(ParsableByteArray mvhd) { - mvhd.setPosition(Mp4Util.ATOM_HEADER_SIZE); + mvhd.setPosition(Atom.ATOM_HEADER_SIZE); int fullAtom = mvhd.readInt(); - int version = Mp4Util.parseFullAtomVersion(fullAtom); + int version = Atom.parseFullAtomVersion(fullAtom); mvhd.skip(version == 0 ? 8 : 16); @@ -266,9 +267,9 @@ public final class CommonMp4AtomParsers { * the movie header box). The duration is set to -1 if the duration is unspecified. */ private static Pair parseTkhd(ParsableByteArray tkhd) { - tkhd.setPosition(Mp4Util.ATOM_HEADER_SIZE); + tkhd.setPosition(Atom.ATOM_HEADER_SIZE); int fullAtom = tkhd.readInt(); - int version = Mp4Util.parseFullAtomVersion(fullAtom); + int version = Atom.parseFullAtomVersion(fullAtom); tkhd.skip(version == 0 ? 8 : 16); @@ -302,7 +303,7 @@ public final class CommonMp4AtomParsers { * @return The track type. */ private static int parseHdlr(ParsableByteArray hdlr) { - hdlr.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE + 4); + hdlr.setPosition(Atom.FULL_ATOM_HEADER_SIZE + 4); return hdlr.readInt(); } @@ -313,9 +314,9 @@ public final class CommonMp4AtomParsers { * @return The media timescale, defined as the number of time units that pass in one second. */ private static long parseMdhd(ParsableByteArray mdhd) { - mdhd.setPosition(Mp4Util.ATOM_HEADER_SIZE); + mdhd.setPosition(Atom.ATOM_HEADER_SIZE); int fullAtom = mdhd.readInt(); - int version = Mp4Util.parseFullAtomVersion(fullAtom); + int version = Atom.parseFullAtomVersion(fullAtom); mdhd.skip(version == 0 ? 8 : 16); return mdhd.readUnsignedInt(); @@ -323,7 +324,7 @@ public final class CommonMp4AtomParsers { private static Pair parseStsd( ParsableByteArray stsd, long durationUs) { - stsd.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE); + stsd.setPosition(Atom.FULL_ATOM_HEADER_SIZE); int numberOfEntries = stsd.readInt(); MediaFormat mediaFormat = null; TrackEncryptionBox[] trackEncryptionBoxes = new TrackEncryptionBox[numberOfEntries]; @@ -357,7 +358,7 @@ public final class CommonMp4AtomParsers { /** Returns the media format for an avc1 box. */ private static Pair parseAvcFromParent(ParsableByteArray parent, int position, int size, long durationUs) { - parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE); + parent.setPosition(position + Atom.ATOM_HEADER_SIZE); parent.skip(24); int width = parent.readUnsignedShort(); @@ -394,7 +395,7 @@ public final class CommonMp4AtomParsers { } private static List parseAvcCFromParent(ParsableByteArray parent, int position) { - parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE + 4); + parent.setPosition(position + Atom.ATOM_HEADER_SIZE + 4); // Start of the AVCDecoderConfigurationRecord (defined in 14496-15) int nalUnitLength = (parent.readUnsignedByte() & 0x3) + 1; if (nalUnitLength != 4) { @@ -407,18 +408,18 @@ public final class CommonMp4AtomParsers { // expose the AVC profile and level somewhere useful; Most likely in MediaFormat. int numSequenceParameterSets = parent.readUnsignedByte() & 0x1F; for (int j = 0; j < numSequenceParameterSets; j++) { - initializationData.add(Mp4Util.parseChildNalUnit(parent)); + initializationData.add(H264Util.parseChildNalUnit(parent)); } int numPictureParameterSets = parent.readUnsignedByte(); for (int j = 0; j < numPictureParameterSets; j++) { - initializationData.add(Mp4Util.parseChildNalUnit(parent)); + initializationData.add(H264Util.parseChildNalUnit(parent)); } return initializationData; } private static TrackEncryptionBox parseSinfFromParent(ParsableByteArray parent, int position, int size) { - int childPosition = position + Mp4Util.ATOM_HEADER_SIZE; + int childPosition = position + Atom.ATOM_HEADER_SIZE; TrackEncryptionBox trackEncryptionBox = null; while (childPosition - position < size) { @@ -441,7 +442,7 @@ public final class CommonMp4AtomParsers { } private static float parsePaspFromParent(ParsableByteArray parent, int position) { - parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE); + parent.setPosition(position + Atom.ATOM_HEADER_SIZE); int hSpacing = parent.readUnsignedIntToInt(); int vSpacing = parent.readUnsignedIntToInt(); return (float) hSpacing / vSpacing; @@ -449,7 +450,7 @@ public final class CommonMp4AtomParsers { private static TrackEncryptionBox parseSchiFromParent(ParsableByteArray parent, int position, int size) { - int childPosition = position + Mp4Util.ATOM_HEADER_SIZE; + int childPosition = position + Atom.ATOM_HEADER_SIZE; while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); @@ -471,7 +472,7 @@ public final class CommonMp4AtomParsers { /** Returns the media format for an mp4v box. */ private static MediaFormat parseMp4vFromParent(ParsableByteArray parent, int position, int size, long durationUs) { - parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE); + parent.setPosition(position + Atom.ATOM_HEADER_SIZE); parent.skip(24); int width = parent.readUnsignedShort(); @@ -498,7 +499,7 @@ public final class CommonMp4AtomParsers { private static Pair parseAudioSampleEntry( ParsableByteArray parent, int atomType, int position, int size, long durationUs) { - parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE); + parent.setPosition(position + Atom.ATOM_HEADER_SIZE); parent.skip(16); int channelCount = parent.readUnsignedShort(); int sampleSize = parent.readUnsignedShort(); @@ -563,7 +564,7 @@ public final class CommonMp4AtomParsers { /** Returns codec-specific initialization data contained in an esds box. */ private static byte[] parseEsdsFromParent(ParsableByteArray parent, int position) { - parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE + 4); + parent.setPosition(position + Atom.ATOM_HEADER_SIZE + 4); // Start of the ES_Descriptor (defined in 14496-1) parent.skip(1); // ES_Descriptor tag int varIntByte = parent.readUnsignedByte(); @@ -607,7 +608,7 @@ public final class CommonMp4AtomParsers { private static Ac3Format parseAc3SpecificBoxFromParent(ParsableByteArray parent, int position) { // Start of the dac3 atom (defined in ETSI TS 102 366) - parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE); + parent.setPosition(position + Atom.ATOM_HEADER_SIZE); // fscod (sample rate code) int fscod = (parent.readUnsignedByte() & 0xC0) >> 6; @@ -645,7 +646,7 @@ public final class CommonMp4AtomParsers { private static int parseEc3SpecificBoxFromParent(ParsableByteArray parent, int position) { // Start of the dec3 atom (defined in ETSI TS 102 366) - parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE); + parent.setPosition(position + Atom.ATOM_HEADER_SIZE); // TODO: Implement parsing for enhanced AC-3 with multiple sub-streams. return 0; } diff --git a/library/src/main/java/com/google/android/exoplayer/mp4/Mp4TrackSampleTable.java b/library/src/main/java/com/google/android/exoplayer/mp4/Mp4TrackSampleTable.java index 9e60146140..d3ce98225f 100644 --- a/library/src/main/java/com/google/android/exoplayer/mp4/Mp4TrackSampleTable.java +++ b/library/src/main/java/com/google/android/exoplayer/mp4/Mp4TrackSampleTable.java @@ -22,6 +22,9 @@ import com.google.android.exoplayer.util.Util; /** Sample table for a track in an MP4 file. */ public final class Mp4TrackSampleTable { + /** Sample index when no sample is available. */ + public static final int NO_SAMPLE = -1; + /** Sample offsets in bytes. */ public final long[] offsets; /** Sample sizes in bytes. */ @@ -53,7 +56,7 @@ public final class Mp4TrackSampleTable { * timestamp, if one is available. * * @param timeUs Timestamp adjacent to which to find a synchronization sample. - * @return Index of the synchronization sample, or {@link Mp4Util#NO_SAMPLE} if none. + * @return Index of the synchronization sample, or {@link #NO_SAMPLE} if none. */ public int getIndexOfEarlierOrEqualSynchronizationSample(long timeUs) { int startIndex = Util.binarySearchFloor(timestampsUs, timeUs, true, false); @@ -63,7 +66,7 @@ public final class Mp4TrackSampleTable { } } - return Mp4Util.NO_SAMPLE; + return NO_SAMPLE; } /** @@ -71,7 +74,7 @@ public final class Mp4TrackSampleTable { * if one is available. * * @param timeUs Timestamp adjacent to which to find a synchronization sample. - * @return index Index of the synchronization sample, or {@link Mp4Util#NO_SAMPLE} if none. + * @return index Index of the synchronization sample, or {@link #NO_SAMPLE} if none. */ public int getIndexOfLaterOrEqualSynchronizationSample(long timeUs) { int startIndex = Util.binarySearchCeil(timestampsUs, timeUs, true, false); @@ -81,7 +84,7 @@ public final class Mp4TrackSampleTable { } } - return Mp4Util.NO_SAMPLE; + return NO_SAMPLE; } } diff --git a/library/src/main/java/com/google/android/exoplayer/source/Mp4SampleExtractor.java b/library/src/main/java/com/google/android/exoplayer/source/Mp4SampleExtractor.java index 4a51492951..f7154c2acf 100644 --- a/library/src/main/java/com/google/android/exoplayer/source/Mp4SampleExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer/source/Mp4SampleExtractor.java @@ -25,7 +25,6 @@ import com.google.android.exoplayer.mp4.Atom; import com.google.android.exoplayer.mp4.Atom.ContainerAtom; import com.google.android.exoplayer.mp4.CommonMp4AtomParsers; import com.google.android.exoplayer.mp4.Mp4TrackSampleTable; -import com.google.android.exoplayer.mp4.Mp4Util; import com.google.android.exoplayer.mp4.Track; import com.google.android.exoplayer.upstream.BufferPool; import com.google.android.exoplayer.upstream.BufferedNonBlockingInputStream; @@ -35,6 +34,7 @@ import com.google.android.exoplayer.upstream.DataSpec; import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.upstream.Loader.Loadable; import com.google.android.exoplayer.util.Assertions; +import com.google.android.exoplayer.util.H264Util; import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.ParsableByteArray; import com.google.android.exoplayer.util.Util; @@ -58,6 +58,8 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac private static final String TAG = "Mp4SampleExtractor"; private static final String LOADER_THREAD_NAME = "Mp4SampleExtractor"; + private static final int NO_TRACK = -1; + // Reading results private static final int RESULT_NEED_MORE_DATA = 1; private static final int RESULT_END_OF_STREAM = 2; @@ -167,7 +169,7 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac // TODO: Implement Allocator here so it is possible to check there is only one buffer at a time. bufferPool = new BufferPool(readAheadAllocationSize); loader = new Loader(LOADER_THREAD_NAME); - atomHeader = new ParsableByteArray(Mp4Util.LONG_ATOM_HEADER_SIZE); + atomHeader = new ParsableByteArray(Atom.LONG_ATOM_HEADER_SIZE); containerAtoms = new Stack(); parserState = STATE_READING_ATOM_HEADER; @@ -206,12 +208,12 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac // Get the timestamp of the earliest currently-selected sample. int earliestSampleTrackIndex = getTrackIndexOfEarliestCurrentSample(); - if (earliestSampleTrackIndex == Mp4Util.NO_TRACK) { + if (earliestSampleTrackIndex == NO_TRACK) { tracks[trackIndex].sampleIndex = 0; return; } - if (earliestSampleTrackIndex == Mp4Util.NO_SAMPLE) { - tracks[trackIndex].sampleIndex = Mp4Util.NO_SAMPLE; + if (earliestSampleTrackIndex == Mp4TrackSampleTable.NO_SAMPLE) { + tracks[trackIndex].sampleIndex = Mp4TrackSampleTable.NO_SAMPLE; return; } long timestampUs = @@ -281,7 +283,7 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac Mp4TrackSampleTable sampleTable = tracks[trackIndex].sampleTable; int sampleIndex = sampleTable.getIndexOfEarlierOrEqualSynchronizationSample(positionUs); - if (sampleIndex == Mp4Util.NO_SAMPLE) { + if (sampleIndex == Mp4TrackSampleTable.NO_SAMPLE) { sampleIndex = sampleTable.getIndexOfLaterOrEqualSynchronizationSample(positionUs); } tracks[trackIndex].sampleIndex = sampleIndex; @@ -333,7 +335,7 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac int sampleIndex = track.sampleIndex; // Check for the end of the stream. - if (sampleIndex == Mp4Util.NO_SAMPLE) { + if (sampleIndex == Mp4TrackSampleTable.NO_SAMPLE) { // TODO: Should END_OF_STREAM be returned as soon as this track has no more samples, or as // soon as no tracks have a sample (as implemented here)? return hasSampleInAnySelectedTrack() ? SampleSource.NOTHING_READ : SampleSource.END_OF_STREAM; @@ -395,7 +397,7 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac if (MimeTypes.VIDEO_H264.equals(tracks[trackIndex].track.mediaFormat.mimeType)) { // The mp4 file contains length-prefixed access units, but the decoder wants start code // delimited content. - Mp4Util.replaceLengthPrefixesWithAvcStartCodes(sampleHolder.data, sampleSize); + H264Util.replaceLengthPrefixesWithAvcStartCodes(sampleHolder.data, sampleSize); } sampleHolder.size = sampleSize; } @@ -411,7 +413,7 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac // Advance to the next sample, checking if this was the last sample. track.sampleIndex = - sampleIndex + 1 == track.sampleTable.getSampleCount() ? Mp4Util.NO_SAMPLE : sampleIndex + 1; + sampleIndex + 1 == track.sampleTable.getSampleCount() ? Mp4TrackSampleTable.NO_SAMPLE : sampleIndex + 1; // Reset the loading error counter if we read past the offset at which the error was thrown. if (dataSourceStream.getReadPosition() > loadErrorPosition) { @@ -489,12 +491,12 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac } /** - * Returns the index of the track that contains the earliest current sample, or - * {@link Mp4Util#NO_TRACK} if no track is selected, or {@link Mp4Util#NO_SAMPLE} if no samples - * remain in selected tracks. + * Returns the index of the track that contains the earliest current sample, or {@link #NO_TRACK} + * if no track is selected, or {@link Mp4TrackSampleTable#NO_SAMPLE} if no samples remain in + * selected tracks. */ private int getTrackIndexOfEarliestCurrentSample() { - int earliestSampleTrackIndex = Mp4Util.NO_TRACK; + int earliestSampleTrackIndex = NO_TRACK; long earliestSampleOffset = Long.MAX_VALUE; for (int trackIndex = 0; trackIndex < tracks.length; trackIndex++) { Mp4Track track = tracks[trackIndex]; @@ -503,10 +505,10 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac } int sampleIndex = track.sampleIndex; - if (sampleIndex == Mp4Util.NO_SAMPLE) { - if (earliestSampleTrackIndex == Mp4Util.NO_TRACK) { + if (sampleIndex == Mp4TrackSampleTable.NO_SAMPLE) { + if (earliestSampleTrackIndex == NO_TRACK) { // A track is selected, but it has no more samples. - earliestSampleTrackIndex = Mp4Util.NO_SAMPLE; + earliestSampleTrackIndex = Mp4TrackSampleTable.NO_SAMPLE; } continue; } @@ -524,7 +526,8 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac private boolean hasSampleInAnySelectedTrack() { boolean hasSample = false; for (int trackIndex = 0; trackIndex < tracks.length; trackIndex++) { - if (tracks[trackIndex].selected && tracks[trackIndex].sampleIndex != Mp4Util.NO_SAMPLE) { + if (tracks[trackIndex].selected && tracks[trackIndex].sampleIndex + != Mp4TrackSampleTable.NO_SAMPLE) { hasSample = true; break; } @@ -556,10 +559,10 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac // The size value is either 4 or 8 bytes long (in which case atomSize = Mp4Util.LONG_ATOM_SIZE). int remainingBytes; - if (atomSize != Mp4Util.LONG_ATOM_SIZE) { - remainingBytes = Mp4Util.ATOM_HEADER_SIZE - atomBytesRead; + if (atomSize != Atom.LONG_SIZE_PREFIX) { + remainingBytes = Atom.ATOM_HEADER_SIZE - atomBytesRead; } else { - remainingBytes = Mp4Util.LONG_ATOM_HEADER_SIZE - atomBytesRead; + remainingBytes = Atom.LONG_ATOM_HEADER_SIZE - atomBytesRead; } int bytesRead = inputStream.read(atomHeader.data, atomBytesRead, remainingBytes); @@ -568,17 +571,17 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac } rootAtomBytesRead += bytesRead; atomBytesRead += bytesRead; - if (atomBytesRead < Mp4Util.ATOM_HEADER_SIZE - || (atomSize == Mp4Util.LONG_ATOM_SIZE && atomBytesRead < Mp4Util.LONG_ATOM_HEADER_SIZE)) { + if (atomBytesRead < Atom.ATOM_HEADER_SIZE + || (atomSize == Atom.LONG_SIZE_PREFIX && atomBytesRead < Atom.LONG_ATOM_HEADER_SIZE)) { return RESULT_NEED_MORE_DATA; } atomHeader.setPosition(0); atomSize = atomHeader.readUnsignedInt(); atomType = atomHeader.readInt(); - if (atomSize == Mp4Util.LONG_ATOM_SIZE) { + if (atomSize == Atom.LONG_SIZE_PREFIX) { // The extended atom size is contained in the next 8 bytes, so try to read it now. - if (atomBytesRead < Mp4Util.LONG_ATOM_HEADER_SIZE) { + if (atomBytesRead < Atom.LONG_ATOM_HEADER_SIZE) { return readAtomHeader(); } @@ -587,18 +590,18 @@ public final class Mp4SampleExtractor implements SampleExtractor, Loader.Callbac Integer atomTypeInteger = atomType; // Avoids boxing atomType twice. if (CONTAINER_TYPES.contains(atomTypeInteger)) { - if (atomSize == Mp4Util.LONG_ATOM_SIZE) { + if (atomSize == Atom.LONG_SIZE_PREFIX) { containerAtoms.add(new ContainerAtom( - atomType, rootAtomBytesRead + atomSize - Mp4Util.LONG_ATOM_HEADER_SIZE)); + atomType, rootAtomBytesRead + atomSize - Atom.LONG_ATOM_HEADER_SIZE)); } else { containerAtoms.add(new ContainerAtom( - atomType, rootAtomBytesRead + atomSize - Mp4Util.ATOM_HEADER_SIZE)); + atomType, rootAtomBytesRead + atomSize - Atom.ATOM_HEADER_SIZE)); } enterState(STATE_READING_ATOM_HEADER); } else if (LEAF_ATOM_TYPES.contains(atomTypeInteger)) { Assertions.checkState(atomSize <= Integer.MAX_VALUE); atomData = new ParsableByteArray((int) atomSize); - System.arraycopy(atomHeader.data, 0, atomData.data, 0, Mp4Util.ATOM_HEADER_SIZE); + System.arraycopy(atomHeader.data, 0, atomData.data, 0, Atom.ATOM_HEADER_SIZE); enterState(STATE_READING_ATOM_PAYLOAD); } else { atomData = null; diff --git a/library/src/main/java/com/google/android/exoplayer/mp4/Mp4Util.java b/library/src/main/java/com/google/android/exoplayer/util/H264Util.java similarity index 55% rename from library/src/main/java/com/google/android/exoplayer/mp4/Mp4Util.java rename to library/src/main/java/com/google/android/exoplayer/util/H264Util.java index ea41e3a2cf..e9feaaefd6 100644 --- a/library/src/main/java/com/google/android/exoplayer/mp4/Mp4Util.java +++ b/library/src/main/java/com/google/android/exoplayer/util/H264Util.java @@ -13,67 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer.mp4; - -import com.google.android.exoplayer.util.Assertions; -import com.google.android.exoplayer.util.CodecSpecificDataUtil; -import com.google.android.exoplayer.util.ParsableByteArray; +package com.google.android.exoplayer.util; import java.nio.ByteBuffer; /** - * Utility methods and constants for parsing fragmented and unfragmented MP4 files. + * Utility methods for handling H264 data. */ -public final class Mp4Util { - - /** Size of an atom header, in bytes. */ - public static final int ATOM_HEADER_SIZE = 8; - - /** Size of a long atom header, in bytes. */ - public static final int LONG_ATOM_HEADER_SIZE = 16; - - /** Size of a full atom header, in bytes. */ - public static final int FULL_ATOM_HEADER_SIZE = 12; - - /** Value for the first 32 bits of atomSize when the atom size is actually a long value. */ - public static final int LONG_ATOM_SIZE = 1; - - /** Sample index when no sample is available. */ - public static final int NO_SAMPLE = -1; - - /** Track index when no track is selected. */ - public static final int NO_TRACK = -1; +public final class H264Util { /** Four initial bytes that must prefix H.264/AVC NAL units for decoding. */ - private static final byte[] NAL_START_CODE = new byte[] {0, 0, 0, 1}; - - /** Parses the version number out of the additional integer component of a full atom. */ - public static int parseFullAtomVersion(int fullAtomInt) { - return 0x000000FF & (fullAtomInt >> 24); - } - - /** Parses the atom flags out of the additional integer component of a full atom. */ - public static int parseFullAtomFlags(int fullAtomInt) { - return 0x00FFFFFF & fullAtomInt; - } - - /** - * Reads an unsigned integer into an integer. This method is suitable for use when it can be - * assumed that the top bit will always be set to zero. - * - * @throws IllegalArgumentException If the top bit of the input data is set. - */ - public static int readUnsignedIntToInt(ByteBuffer data) { - int result = 0xFF & data.get(); - for (int i = 1; i < 4; i++) { - result <<= 8; - result |= 0xFF & data.get(); - } - if (result < 0) { - throw new IllegalArgumentException("Top bit not zero: " + result); - } - return result; - } + public static final byte[] NAL_START_CODE = new byte[] {0, 0, 0, 1}; /** * Replaces length prefixes of NAL units in {@code buffer} with start code prefixes, within the @@ -92,7 +42,9 @@ public final class Mp4Util { buffer.position(sampleOffset + size); } - /** Constructs and returns a NAL unit with a start code followed by the data in {@code atom}. */ + /** + * Constructs and returns a NAL unit with a start code followed by the data in {@code atom}. + */ public static byte[] parseChildNalUnit(ParsableByteArray atom) { int length = atom.readUnsignedShort(); int offset = atom.getPosition(); @@ -101,43 +53,39 @@ public final class Mp4Util { } /** - * Finds the first NAL unit in {@code data}. - *

- * For a NAL unit to be found, its first four bytes must be contained within the part of the - * array being searched. + * Gets the type of the NAL unit in {@code data} that starts at {@code offset}. * * @param data The data to search. - * @param startOffset The offset (inclusive) in the data to start the search. - * @param endOffset The offset (exclusive) in the data to end the search. - * @param type The type of the NAL unit to search for, or -1 for any NAL unit. - * @return The offset of the NAL unit, or {@code endOffset} if a NAL unit was not found. + * @param offset The start offset of a NAL unit. Must lie between {@code -3} (inclusive) and + * {@code data.length - 3} (exclusive). + * @return The type of the unit. */ - public static int findNalUnit(byte[] data, int startOffset, int endOffset, int type) { - return findNalUnit(data, startOffset, endOffset, type, null); + public static int getNalUnitType(byte[] data, int offset) { + return data[offset + 3] & 0x1F; } /** - * Like {@link #findNalUnit(byte[], int, int, int)}, but supports finding of NAL units across - * array boundaries. + * Finds the first NAL unit in {@code data}. *

- * To use this method, pass the same {@code prefixFlags} parameter to successive calls where the - * data passed represents a contiguous stream. The state maintained in this parameter allows the - * detection of NAL units where the NAL unit prefix spans array boundaries. + * If {@code prefixFlags} is null then the first four bytes of a NAL unit must be entirely + * contained within the part of the array being searched in order for it to be found. *

- * Note that when using {@code prefixFlags} the return value may be 3, 2 or 1 less than - * {@code startOffset}, to indicate a NAL unit starting 3, 2 or 1 bytes before the first byte in - * the current array. + * When {@code prefixFlags} is non-null, this method supports finding NAL units whose first four + * bytes span {@code data} arrays passed to successive calls. To use this feature, pass the same + * {@code prefixFlags} parameter to successive calls. State maintained in this parameter enables + * the detection of such NAL units. Note that when using this feature, the return value may be 3, + * 2 or 1 less than {@code startOffset}, to indicate a NAL unit starting 3, 2 or 1 bytes before + * the first byte in the current array. * * @param data The data to search. * @param startOffset The offset (inclusive) in the data to start the search. * @param endOffset The offset (exclusive) in the data to end the search. - * @param type The type of the NAL unit to search for, or -1 for any NAL unit. * @param prefixFlags A boolean array whose first three elements are used to store the state * required to detect NAL units where the NAL unit prefix spans array boundaries. The array * must be at least 3 elements long. * @return The offset of the NAL unit, or {@code endOffset} if a NAL unit was not found. */ - public static int findNalUnit(byte[] data, int startOffset, int endOffset, int type, + public static int findNalUnit(byte[] data, int startOffset, int endOffset, boolean[] prefixFlags) { int length = endOffset - startOffset; @@ -147,15 +95,14 @@ public final class Mp4Util { } if (prefixFlags != null) { - if (prefixFlags[0] && matchesType(data, startOffset, type)) { + if (prefixFlags[0]) { clearPrefixFlags(prefixFlags); return startOffset - 3; - } else if (length > 1 && prefixFlags[1] && data[startOffset] == 1 - && matchesType(data, startOffset + 1, type)) { + } else if (length > 1 && prefixFlags[1] && data[startOffset] == 1) { clearPrefixFlags(prefixFlags); return startOffset - 2; } else if (length > 2 && prefixFlags[2] && data[startOffset] == 0 - && data[startOffset + 1] == 1 && matchesType(data, startOffset + 2, type)) { + && data[startOffset + 1] == 1) { clearPrefixFlags(prefixFlags); return startOffset - 1; } @@ -169,8 +116,7 @@ public final class Mp4Util { if ((data[i] & 0xFE) != 0) { // There isn't a NAL prefix here, or at the next two positions. Do nothing and let the // loop advance the index by three. - } else if (data[i - 2] == 0 && data[i - 1] == 0 && data[i] == 1 - && matchesType(data, i + 1, type)) { + } else if (data[i - 2] == 0 && data[i - 1] == 0 && data[i] == 1) { if (prefixFlags != null) { clearPrefixFlags(prefixFlags); } @@ -199,45 +145,25 @@ public final class Mp4Util { } /** - * Like {@link #findNalUnit(byte[], int, int, int)} with {@code type == -1}. + * Reads an unsigned integer into an integer. This method is suitable for use when it can be + * assumed that the top bit will always be set to zero. * - * @param data The data to search. - * @param startOffset The offset (inclusive) in the data to start the search. - * @param endOffset The offset (exclusive) in the data to end the search. - * @return The offset of the NAL unit, or {@code endOffset} if a NAL unit was not found. + * @throws IllegalArgumentException If the top bit of the input data is set. */ - public static int findNalUnit(byte[] data, int startOffset, int endOffset) { - return findNalUnit(data, startOffset, endOffset, null); + private static int readUnsignedIntToInt(ByteBuffer data) { + int result = 0xFF & data.get(); + for (int i = 1; i < 4; i++) { + result <<= 8; + result |= 0xFF & data.get(); + } + if (result < 0) { + throw new IllegalArgumentException("Top bit not zero: " + result); + } + return result; } /** - * Like {@link #findNalUnit(byte[], int, int, int, boolean[])} with {@code type == -1}. - * - * @param data The data to search. - * @param startOffset The offset (inclusive) in the data to start the search. - * @param endOffset The offset (exclusive) in the data to end the search. - * @param prefixFlags A boolean array of length at least 3. - * @return The offset of the NAL unit, or {@code endOffset} if a NAL unit was not found. - */ - public static int findNalUnit(byte[] data, int startOffset, int endOffset, - boolean[] prefixFlags) { - return findNalUnit(data, startOffset, endOffset, -1, prefixFlags); - } - - /** - * Gets the type of the NAL unit in {@code data} that starts at {@code offset}. - * - * @param data The data to search. - * @param offset The start offset of a NAL unit. Must lie between {@code -3} (inclusive) and - * {@code data.length - 3} (exclusive). - * @return The type of the unit. - */ - public static int getNalUnitType(byte[] data, int offset) { - return data[offset + 3] & 0x1F; - } - - /** - * Clears prefix flags, as used by {@link #findNalUnit(byte[], int, int, int, boolean[])}. + * Clears prefix flags, as used by {@link #findNalUnit(byte[], int, int, boolean[])}. * * @param prefixFlags The flags to clear. */ @@ -247,11 +173,4 @@ public final class Mp4Util { prefixFlags[2] = false; } - /** - * Returns true if the type at {@code offset} is equal to {@code type}, or if {@code type == -1}. - */ - private static boolean matchesType(byte[] data, int offset, int type) { - return type == -1 || (data[offset] & 0x1F) == type; - } - } diff --git a/library/src/test/java/com/google/android/exoplayer/mp4/Mp4UtilTest.java b/library/src/test/java/com/google/android/exoplayer/util/H264UtilTest.java similarity index 75% rename from library/src/test/java/com/google/android/exoplayer/mp4/Mp4UtilTest.java rename to library/src/test/java/com/google/android/exoplayer/util/H264UtilTest.java index fe304b14b6..78bfa0c3fb 100644 --- a/library/src/test/java/com/google/android/exoplayer/mp4/Mp4UtilTest.java +++ b/library/src/test/java/com/google/android/exoplayer/util/H264UtilTest.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer.mp4; +package com.google.android.exoplayer.util; import junit.framework.TestCase; import java.util.Arrays; /** - * Tests for {@link Mp4Util}. + * Tests for {@link H264Util}. */ -public class Mp4UtilTest extends TestCase { +public class H264UtilTest extends TestCase { private static final int TEST_PARTIAL_NAL_POSITION = 4; private static final int TEST_NAL_POSITION = 10; @@ -31,19 +31,19 @@ public class Mp4UtilTest extends TestCase { byte[] data = buildTestData(); // Should find NAL unit. - int result = Mp4Util.findNalUnit(data, 0, data.length); + int result = H264Util.findNalUnit(data, 0, data.length, null); assertEquals(TEST_NAL_POSITION, result); // Should find NAL unit whose prefix ends one byte before the limit. - result = Mp4Util.findNalUnit(data, 0, TEST_NAL_POSITION + 4); + result = H264Util.findNalUnit(data, 0, TEST_NAL_POSITION + 4, null); assertEquals(TEST_NAL_POSITION, result); // Shouldn't find NAL unit whose prefix ends at the limit (since the limit is exclusive). - result = Mp4Util.findNalUnit(data, 0, TEST_NAL_POSITION + 3); + result = H264Util.findNalUnit(data, 0, TEST_NAL_POSITION + 3, null); assertEquals(TEST_NAL_POSITION + 3, result); // Should find NAL unit whose prefix starts at the offset. - result = Mp4Util.findNalUnit(data, TEST_NAL_POSITION, data.length); + result = H264Util.findNalUnit(data, TEST_NAL_POSITION, data.length, null); assertEquals(TEST_NAL_POSITION, result); // Shouldn't find NAL unit whose prefix starts one byte past the offset. - result = Mp4Util.findNalUnit(data, TEST_NAL_POSITION + 1, data.length); + result = H264Util.findNalUnit(data, TEST_NAL_POSITION + 1, data.length, null); assertEquals(data.length, result); } @@ -54,9 +54,9 @@ public class Mp4UtilTest extends TestCase { boolean[] prefixFlags = new boolean[3]; byte[] data1 = Arrays.copyOfRange(data, 0, TEST_NAL_POSITION + 1); byte[] data2 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 1, data.length); - int result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags); + int result = H264Util.findNalUnit(data1, 0, data1.length, prefixFlags); assertEquals(data1.length, result); - result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags); + result = H264Util.findNalUnit(data2, 0, data2.length, prefixFlags); assertEquals(-1, result); assertPrefixFlagsCleared(prefixFlags); @@ -64,9 +64,9 @@ public class Mp4UtilTest extends TestCase { prefixFlags = new boolean[3]; data1 = Arrays.copyOfRange(data, 0, TEST_NAL_POSITION + 3); data2 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 3, data.length); - result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags); + result = H264Util.findNalUnit(data1, 0, data1.length, prefixFlags); assertEquals(data1.length, result); - result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags); + result = H264Util.findNalUnit(data2, 0, data2.length, prefixFlags); assertEquals(-3, result); assertPrefixFlagsCleared(prefixFlags); @@ -75,11 +75,11 @@ public class Mp4UtilTest extends TestCase { data1 = Arrays.copyOfRange(data, 0, TEST_NAL_POSITION + 1); data2 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 1, TEST_NAL_POSITION + 2); byte[] data3 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 2, data.length); - result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags); + result = H264Util.findNalUnit(data1, 0, data1.length, prefixFlags); assertEquals(data1.length, result); - result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags); + result = H264Util.findNalUnit(data2, 0, data2.length, prefixFlags); assertEquals(data2.length, result); - result = Mp4Util.findNalUnit(data3, 0, data3.length, prefixFlags); + result = H264Util.findNalUnit(data3, 0, data3.length, prefixFlags); assertEquals(-2, result); assertPrefixFlagsCleared(prefixFlags); @@ -89,13 +89,13 @@ public class Mp4UtilTest extends TestCase { data2 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 1, TEST_NAL_POSITION + 2); data3 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 2, TEST_NAL_POSITION + 3); byte[] data4 = Arrays.copyOfRange(data, TEST_NAL_POSITION + 2, data.length); - result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags); + result = H264Util.findNalUnit(data1, 0, data1.length, prefixFlags); assertEquals(data1.length, result); - result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags); + result = H264Util.findNalUnit(data2, 0, data2.length, prefixFlags); assertEquals(data2.length, result); - result = Mp4Util.findNalUnit(data3, 0, data3.length, prefixFlags); + result = H264Util.findNalUnit(data3, 0, data3.length, prefixFlags); assertEquals(data3.length, result); - result = Mp4Util.findNalUnit(data4, 0, data4.length, prefixFlags); + result = H264Util.findNalUnit(data4, 0, data4.length, prefixFlags); assertEquals(-3, result); assertPrefixFlagsCleared(prefixFlags); @@ -103,9 +103,9 @@ public class Mp4UtilTest extends TestCase { prefixFlags = new boolean[3]; data1 = Arrays.copyOfRange(data, 0, TEST_PARTIAL_NAL_POSITION + 2); data2 = Arrays.copyOfRange(data, TEST_PARTIAL_NAL_POSITION + 2, data.length); - result = Mp4Util.findNalUnit(data1, 0, data1.length, prefixFlags); + result = H264Util.findNalUnit(data1, 0, data1.length, prefixFlags); assertEquals(data1.length, result); - result = Mp4Util.findNalUnit(data2, 0, data2.length, prefixFlags); + result = H264Util.findNalUnit(data2, 0, data2.length, prefixFlags); assertEquals(4, result); assertPrefixFlagsCleared(prefixFlags); }