Commit bfa1de68 by Oliver Woodman

Move common MP4 parsing code to CommonMp4AtomParsers and Mp4Util.

Also add parseMp4vFromParent and return the track's duration in parseTrak.

This is in preparation for adding a non-fragmented MP4 extractor.
parent a968e553
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer.chunk.parser;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleHolder;
......@@ -79,6 +80,11 @@ public interface Extractor {
public MediaFormat getFormat();
/**
* Returns the duration of the stream in microseconds, or {@link C#UNKNOWN_TIME_US} if unknown.
*/
public long getDurationUs();
/**
* Returns the pssh information parsed from the stream.
*
* @return The pssh information. May be null if pssh data has yet to be parsed, or if the stream
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer.chunk.parser.webm;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleHolder;
......@@ -185,6 +186,11 @@ public final class WebmExtractor implements Extractor {
}
@Override
public long getDurationUs() {
return durationUs == UNKNOWN ? C.UNKNOWN_TIME_US : durationUs;
}
@Override
public Map<UUID, byte[]> getPsshInfo() {
// TODO: Parse pssh data from Webm streams.
return null;
......
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.google.android.exoplayer.mp4;
import com.google.android.exoplayer.util.CodecSpecificDataUtil;
import com.google.android.exoplayer.util.ParsableByteArray;
import java.nio.ByteBuffer;
/**
* Utility methods and constants for parsing fragmented and unfragmented MP4 files.
*/
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;
/** 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;
}
/**
* Replaces length prefixes of NAL units in {@code buffer} with start code prefixes, within the
* {@code size} bytes preceding the buffer's position.
*/
public static void replaceLengthPrefixesWithAvcStartCodes(ByteBuffer buffer, int size) {
int sampleOffset = buffer.position() - size;
int position = sampleOffset;
while (position < sampleOffset + size) {
buffer.position(position);
int length = readUnsignedIntToInt(buffer);
buffer.position(position);
buffer.put(NAL_START_CODE);
position += length + 4;
}
buffer.position(sampleOffset + size);
}
/** 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();
atom.skip(length);
return CodecSpecificDataUtil.buildNalUnit(atom.data, offset, length);
}
}
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer.mp4;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.chunk.parser.mp4.TrackEncryptionBox;
......@@ -43,6 +44,10 @@ public final class Track {
* Type of a meta track.
*/
public static final int TYPE_META = 0x6D657461;
/**
* Type of a time-code track.
*/
public static final int TYPE_TIME_CODE = 0x746D6364;
/**
* The track identifier.
......@@ -50,7 +55,8 @@ public final class Track {
public final int id;
/**
* One of {@link #TYPE_VIDEO}, {@link #TYPE_AUDIO}, {@link #TYPE_HINT} and {@link #TYPE_META}.
* One of {@link #TYPE_VIDEO}, {@link #TYPE_AUDIO}, {@link #TYPE_HINT}, {@link #TYPE_META} and
* {@link #TYPE_TIME_CODE}.
*/
public final int type;
......@@ -60,6 +66,11 @@ public final class Track {
public final long timescale;
/**
* The duration of the track in microseconds, or {@link C#UNKNOWN_TIME_US} if unknown.
*/
public final long durationUs;
/**
* The format if {@link #type} is {@link #TYPE_VIDEO} or {@link #TYPE_AUDIO}. Null otherwise.
*/
public final MediaFormat mediaFormat;
......@@ -69,11 +80,12 @@ public final class Track {
*/
public final TrackEncryptionBox[] sampleDescriptionEncryptionBoxes;
public Track(int id, int type, long timescale, MediaFormat mediaFormat,
public Track(int id, int type, long timescale, long durationUs, MediaFormat mediaFormat,
TrackEncryptionBox[] sampleDescriptionEncryptionBoxes) {
this.id = id;
this.type = type;
this.timescale = timescale;
this.durationUs = durationUs;
this.mediaFormat = mediaFormat;
this.sampleDescriptionEncryptionBoxes = sampleDescriptionEncryptionBoxes;
}
......
......@@ -167,8 +167,8 @@ public class SmoothStreamingChunkSource implements ChunkSource {
: Track.TYPE_AUDIO;
FragmentedMp4Extractor extractor = new FragmentedMp4Extractor(
FragmentedMp4Extractor.WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME);
extractor.setTrack(new Track(trackIndex, trackType, streamElement.timescale, mediaFormat,
trackEncryptionBoxes));
extractor.setTrack(new Track(trackIndex, trackType, streamElement.timescale,
initialManifest.durationUs, mediaFormat, trackEncryptionBoxes));
extractors.put(trackIndex, extractor);
}
this.maxHeight = maxHeight;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment