Commit 32f0eb12 by Oliver Woodman

Enhance mp4 parsing.

parent 147bbe6d
...@@ -86,6 +86,7 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -86,6 +86,7 @@ public final class FragmentedMp4Extractor implements Extractor {
parsedAtoms.add(Atom.TYPE_moof); parsedAtoms.add(Atom.TYPE_moof);
parsedAtoms.add(Atom.TYPE_moov); parsedAtoms.add(Atom.TYPE_moov);
parsedAtoms.add(Atom.TYPE_mp4a); parsedAtoms.add(Atom.TYPE_mp4a);
parsedAtoms.add(Atom.TYPE_mvhd);
parsedAtoms.add(Atom.TYPE_sidx); parsedAtoms.add(Atom.TYPE_sidx);
parsedAtoms.add(Atom.TYPE_stsd); parsedAtoms.add(Atom.TYPE_stsd);
parsedAtoms.add(Atom.TYPE_tfdt); parsedAtoms.add(Atom.TYPE_tfdt);
...@@ -379,7 +380,8 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -379,7 +380,8 @@ public final class FragmentedMp4Extractor implements Extractor {
} }
ContainerAtom mvex = moov.getContainerAtomOfType(Atom.TYPE_mvex); ContainerAtom mvex = moov.getContainerAtomOfType(Atom.TYPE_mvex);
extendsDefaults = parseTrex(mvex.getLeafAtomOfType(Atom.TYPE_trex).data); extendsDefaults = parseTrex(mvex.getLeafAtomOfType(Atom.TYPE_trex).data);
track = CommonMp4AtomParsers.parseTrak(moov.getContainerAtomOfType(Atom.TYPE_trak)); track = CommonMp4AtomParsers.parseTrak(moov.getContainerAtomOfType(Atom.TYPE_trak),
moov.getLeafAtomOfType(Atom.TYPE_mvhd));
} }
private void onMoofContainerAtomRead(ContainerAtom moof) { private void onMoofContainerAtomRead(ContainerAtom moof) {
......
...@@ -39,6 +39,7 @@ public abstract class Atom { ...@@ -39,6 +39,7 @@ public abstract class Atom {
public static final int TYPE_trun = getAtomTypeInteger("trun"); public static final int TYPE_trun = getAtomTypeInteger("trun");
public static final int TYPE_sidx = getAtomTypeInteger("sidx"); public static final int TYPE_sidx = getAtomTypeInteger("sidx");
public static final int TYPE_moov = getAtomTypeInteger("moov"); public static final int TYPE_moov = getAtomTypeInteger("moov");
public static final int TYPE_mvhd = getAtomTypeInteger("mvhd");
public static final int TYPE_trak = getAtomTypeInteger("trak"); public static final int TYPE_trak = getAtomTypeInteger("trak");
public static final int TYPE_mdia = getAtomTypeInteger("mdia"); public static final int TYPE_mdia = getAtomTypeInteger("mdia");
public static final int TYPE_minf = getAtomTypeInteger("minf"); public static final int TYPE_minf = getAtomTypeInteger("minf");
...@@ -69,6 +70,7 @@ public abstract class Atom { ...@@ -69,6 +70,7 @@ public abstract class Atom {
public static final int TYPE_mp4v = getAtomTypeInteger("mp4v"); public static final int TYPE_mp4v = getAtomTypeInteger("mp4v");
public static final int TYPE_stts = getAtomTypeInteger("stts"); public static final int TYPE_stts = getAtomTypeInteger("stts");
public static final int TYPE_stss = getAtomTypeInteger("stss"); public static final int TYPE_stss = getAtomTypeInteger("stss");
public static final int TYPE_ctts = getAtomTypeInteger("ctts");
public static final int TYPE_stsc = getAtomTypeInteger("stsc"); public static final int TYPE_stsc = getAtomTypeInteger("stsc");
public static final int TYPE_stsz = getAtomTypeInteger("stsz"); public static final int TYPE_stsz = getAtomTypeInteger("stsz");
public static final int TYPE_stco = getAtomTypeInteger("stco"); public static final int TYPE_stco = getAtomTypeInteger("stco");
......
/*
* 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.Assertions;
import com.google.android.exoplayer.util.Util;
import android.media.MediaExtractor;
/** Sample table for a track in an MP4 file. */
public final class Mp4TrackSampleTable {
/** Sample offsets in bytes. */
public final long[] offsets;
/** Sample sizes in bytes. */
public final int[] sizes;
/** Sample timestamps in microseconds. */
public final long[] timestampsUs;
/** Sample flags. */
public final int[] flags;
Mp4TrackSampleTable(
long[] offsets, int[] sizes, long[] timestampsUs, int[] flags) {
Assertions.checkArgument(sizes.length == timestampsUs.length);
Assertions.checkArgument(offsets.length == timestampsUs.length);
Assertions.checkArgument(flags.length == timestampsUs.length);
this.offsets = offsets;
this.sizes = sizes;
this.timestampsUs = timestampsUs;
this.flags = flags;
}
/** Returns the number of samples in the table. */
public int getSampleCount() {
return sizes.length;
}
/**
* Returns the sample index of the closest synchronization sample at or before the given
* 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.
*/
public int getIndexOfEarlierOrEqualSynchronizationSample(long timeUs) {
int startIndex = Util.binarySearchFloor(timestampsUs, timeUs, true, false);
for (int i = startIndex; i >= 0; i--) {
if (timestampsUs[i] <= timeUs && (flags[i] & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
return i;
}
}
return Mp4Util.NO_SAMPLE;
}
/**
* Returns the sample index of the closest synchronization sample at or after the given timestamp,
* 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.
*/
public int getIndexOfLaterOrEqualSynchronizationSample(long timeUs) {
int startIndex = Util.binarySearchCeil(timestampsUs, timeUs, true, false);
for (int i = startIndex; i < timestampsUs.length; i++) {
if (timestampsUs[i] >= timeUs && (flags[i] & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
return i;
}
}
return Mp4Util.NO_SAMPLE;
}
}
...@@ -34,6 +34,15 @@ public final class Mp4Util { ...@@ -34,6 +34,15 @@ public final class Mp4Util {
/** Size of a full atom header, in bytes. */ /** Size of a full atom header, in bytes. */
public static final int FULL_ATOM_HEADER_SIZE = 12; 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;
/** Four initial bytes that must prefix H.264/AVC NAL units for decoding. */ /** 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}; private static final byte[] NAL_START_CODE = new byte[] {0, 0, 0, 1};
......
...@@ -91,8 +91,9 @@ public interface SampleExtractor { ...@@ -91,8 +91,9 @@ public interface SampleExtractor {
* {@link SampleSource#END_OF_STREAM} if the last samples in all tracks have been read, or * {@link SampleSource#END_OF_STREAM} if the last samples in all tracks have been read, or
* {@link SampleSource#NOTHING_READ} if the sample cannot be read immediately as it is not * {@link SampleSource#NOTHING_READ} if the sample cannot be read immediately as it is not
* loaded. * loaded.
* @throws IOException Thrown if the source can't be read.
*/ */
int readSample(int track, SampleHolder sampleHolder); int readSample(int track, SampleHolder sampleHolder) throws IOException;
/** Releases resources associated with this extractor. */ /** Releases resources associated with this extractor. */
void release(); void release();
......
...@@ -402,6 +402,32 @@ public final class Util { ...@@ -402,6 +402,32 @@ public final class Util {
} }
/** /**
* Applies {@link #scaleLargeTimestamp(long, long, long)} to an array of unscaled timestamps.
*
* @param timestamps The timestamps to scale.
* @param multiplier The multiplier.
* @param divisor The divisor.
*/
public static void scaleLargeTimestampsInPlace(long[] timestamps, long multiplier, long divisor) {
if (divisor >= multiplier && (divisor % multiplier) == 0) {
long divisionFactor = divisor / multiplier;
for (int i = 0; i < timestamps.length; i++) {
timestamps[i] /= divisionFactor;
}
} else if (divisor < multiplier && (multiplier % divisor) == 0) {
long multiplicationFactor = multiplier / divisor;
for (int i = 0; i < timestamps.length; i++) {
timestamps[i] *= multiplicationFactor;
}
} else {
double multiplicationFactor = (double) multiplier / divisor;
for (int i = 0; i < timestamps.length; i++) {
timestamps[i] = (long) (timestamps[i] * multiplicationFactor);
}
}
}
/**
* Converts a list of integers to a primitive array. * Converts a list of integers to a primitive array.
* *
* @param list A list of integers. * @param list A list of integers.
......
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