Don't copy primary-track format to non-primary tracks

This time plumbing the track type in from the other side.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=166898172
This commit is contained in:
olly 2017-08-29 13:55:19 -07:00 committed by Oliver Woodman
parent d9cd13ce74
commit 5bed2bf503
4 changed files with 51 additions and 37 deletions

View File

@ -29,9 +29,10 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.IOException; import java.io.IOException;
/** /**
* An {@link Extractor} wrapper for loading chunks containing a single track. * An {@link Extractor} wrapper for loading chunks that contain a single primary track, and possibly
* additional embedded tracks.
* <p> * <p>
* The wrapper allows switching of the {@link TrackOutput} that receives parsed data. * The wrapper allows switching of the {@link TrackOutput}s that receive parsed data.
*/ */
public final class ChunkExtractorWrapper implements ExtractorOutput { public final class ChunkExtractorWrapper implements ExtractorOutput {
@ -56,7 +57,8 @@ public final class ChunkExtractorWrapper implements ExtractorOutput {
public final Extractor extractor; public final Extractor extractor;
private final Format manifestFormat; private final int primaryTrackType;
private final Format primaryTrackManifestFormat;
private final SparseArray<BindingTrackOutput> bindingTrackOutputs; private final SparseArray<BindingTrackOutput> bindingTrackOutputs;
private boolean extractorInitialized; private boolean extractorInitialized;
@ -66,12 +68,16 @@ public final class ChunkExtractorWrapper implements ExtractorOutput {
/** /**
* @param extractor The extractor to wrap. * @param extractor The extractor to wrap.
* @param manifestFormat A manifest defined {@link Format} whose data should be merged into any * @param primaryTrackType The type of the primary track. Typically one of the
* sample {@link Format} output from the {@link Extractor}. * {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param primaryTrackManifestFormat A manifest defined {@link Format} whose data should be merged
* into any sample {@link Format} output from the {@link Extractor} for the primary track.
*/ */
public ChunkExtractorWrapper(Extractor extractor, Format manifestFormat) { public ChunkExtractorWrapper(Extractor extractor, int primaryTrackType,
Format primaryTrackManifestFormat) {
this.extractor = extractor; this.extractor = extractor;
this.manifestFormat = manifestFormat; this.primaryTrackType = primaryTrackType;
this.primaryTrackManifestFormat = primaryTrackManifestFormat;
bindingTrackOutputs = new SparseArray<>(); bindingTrackOutputs = new SparseArray<>();
} }
@ -90,8 +96,8 @@ public final class ChunkExtractorWrapper implements ExtractorOutput {
} }
/** /**
* Initializes the extractor to output to the provided {@link TrackOutput}, and configures it to * Initializes the wrapper to output to {@link TrackOutput}s provided by the specified
* receive data from a new chunk. * {@link TrackOutputProvider}, and configures the extractor to receive data from a new chunk.
* *
* @param trackOutputProvider The provider of {@link TrackOutput}s that will receive sample data. * @param trackOutputProvider The provider of {@link TrackOutput}s that will receive sample data.
*/ */
@ -116,7 +122,9 @@ public final class ChunkExtractorWrapper implements ExtractorOutput {
if (bindingTrackOutput == null) { if (bindingTrackOutput == null) {
// Assert that if we're seeing a new track we have not seen endTracks. // Assert that if we're seeing a new track we have not seen endTracks.
Assertions.checkState(sampleFormats == null); Assertions.checkState(sampleFormats == null);
bindingTrackOutput = new BindingTrackOutput(id, type, manifestFormat); // TODO: Manifest formats for embedded tracks should also be passed here.
bindingTrackOutput = new BindingTrackOutput(id, type,
type == primaryTrackType ? primaryTrackManifestFormat : null);
bindingTrackOutput.bind(trackOutputProvider); bindingTrackOutput.bind(trackOutputProvider);
bindingTrackOutputs.put(id, bindingTrackOutput); bindingTrackOutputs.put(id, bindingTrackOutput);
} }
@ -160,16 +168,15 @@ public final class ChunkExtractorWrapper implements ExtractorOutput {
return; return;
} }
trackOutput = trackOutputProvider.track(id, type); trackOutput = trackOutputProvider.track(id, type);
if (trackOutput != null) { if (sampleFormat != null) {
trackOutput.format(sampleFormat); trackOutput.format(sampleFormat);
} }
} }
@Override @Override
public void format(Format format) { public void format(Format format) {
// TODO: This should only happen for the primary track. Additional metadata/text tracks need sampleFormat = manifestFormat != null ? format.copyWithManifestFormatInfo(manifestFormat)
// to be copied with different manifest derived formats. : format;
sampleFormat = format.copyWithManifestFormatInfo(manifestFormat);
trackOutput.format(sampleFormat); trackOutput.format(sampleFormat);
} }

View File

@ -72,9 +72,11 @@ public final class DashUtil {
*/ */
public static DrmInitData loadDrmInitData(DataSource dataSource, Period period) public static DrmInitData loadDrmInitData(DataSource dataSource, Period period)
throws IOException, InterruptedException { throws IOException, InterruptedException {
Representation representation = getFirstRepresentation(period, C.TRACK_TYPE_VIDEO); int primaryTrackType = C.TRACK_TYPE_VIDEO;
Representation representation = getFirstRepresentation(period, primaryTrackType);
if (representation == null) { if (representation == null) {
representation = getFirstRepresentation(period, C.TRACK_TYPE_AUDIO); primaryTrackType = C.TRACK_TYPE_AUDIO;
representation = getFirstRepresentation(period, primaryTrackType);
if (representation == null) { if (representation == null) {
return null; return null;
} }
@ -85,7 +87,7 @@ public final class DashUtil {
// as per DASH IF Interoperability Recommendations V3.0, 7.5.3. // as per DASH IF Interoperability Recommendations V3.0, 7.5.3.
return drmInitData; return drmInitData;
} }
Format sampleFormat = DashUtil.loadSampleFormat(dataSource, representation); Format sampleFormat = DashUtil.loadSampleFormat(dataSource, primaryTrackType, representation);
return sampleFormat == null ? null : sampleFormat.drmInitData; return sampleFormat == null ? null : sampleFormat.drmInitData;
} }
@ -93,15 +95,17 @@ public final class DashUtil {
* Loads initialization data for the {@code representation} and returns the sample {@link Format}. * Loads initialization data for the {@code representation} and returns the sample {@link Format}.
* *
* @param dataSource The source from which the data should be loaded. * @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the
* {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to. * @param representation The representation which initialization chunk belongs to.
* @return the sample {@link Format} of the given representation. * @return the sample {@link Format} of the given representation.
* @throws IOException Thrown when there is an error while loading. * @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted. * @throws InterruptedException Thrown if the thread was interrupted.
*/ */
public static Format loadSampleFormat(DataSource dataSource, Representation representation) public static Format loadSampleFormat(DataSource dataSource, int trackType,
throws IOException, InterruptedException { Representation representation) throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, representation, ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
false); representation, false);
return extractorWrapper == null ? null : extractorWrapper.getSampleFormats()[0]; return extractorWrapper == null ? null : extractorWrapper.getSampleFormats()[0];
} }
@ -110,16 +114,18 @@ public final class DashUtil {
* ChunkIndex}. * ChunkIndex}.
* *
* @param dataSource The source from which the data should be loaded. * @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the
* {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to. * @param representation The representation which initialization chunk belongs to.
* @return The {@link ChunkIndex} of the given representation, or null if no initialization or * @return The {@link ChunkIndex} of the given representation, or null if no initialization or
* index data exists. * index data exists.
* @throws IOException Thrown when there is an error while loading. * @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted. * @throws InterruptedException Thrown if the thread was interrupted.
*/ */
public static ChunkIndex loadChunkIndex(DataSource dataSource, Representation representation) public static ChunkIndex loadChunkIndex(DataSource dataSource, int trackType,
throws IOException, InterruptedException { Representation representation) throws IOException, InterruptedException {
ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, representation, ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType,
true); representation, true);
return extractorWrapper == null ? null : (ChunkIndex) extractorWrapper.getSeekMap(); return extractorWrapper == null ? null : (ChunkIndex) extractorWrapper.getSeekMap();
} }
@ -128,6 +134,8 @@ public final class DashUtil {
* returns a {@link ChunkExtractorWrapper} which contains the output. * returns a {@link ChunkExtractorWrapper} which contains the output.
* *
* @param dataSource The source from which the data should be loaded. * @param dataSource The source from which the data should be loaded.
* @param trackType The type of the representation. Typically one of the
* {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants.
* @param representation The representation which initialization chunk belongs to. * @param representation The representation which initialization chunk belongs to.
* @param loadIndex Whether to load index data too. * @param loadIndex Whether to load index data too.
* @return A {@link ChunkExtractorWrapper} for the {@code representation}, or null if no * @return A {@link ChunkExtractorWrapper} for the {@code representation}, or null if no
@ -135,14 +143,13 @@ public final class DashUtil {
* @throws IOException Thrown when there is an error while loading. * @throws IOException Thrown when there is an error while loading.
* @throws InterruptedException Thrown if the thread was interrupted. * @throws InterruptedException Thrown if the thread was interrupted.
*/ */
private static ChunkExtractorWrapper loadInitializationData(DataSource dataSource, private static ChunkExtractorWrapper loadInitializationData(DataSource dataSource, int trackType,
Representation representation, boolean loadIndex) Representation representation, boolean loadIndex) throws IOException, InterruptedException {
throws IOException, InterruptedException {
RangedUri initializationUri = representation.getInitializationUri(); RangedUri initializationUri = representation.getInitializationUri();
if (initializationUri == null) { if (initializationUri == null) {
return null; return null;
} }
ChunkExtractorWrapper extractorWrapper = newWrappedExtractor(representation.format); ChunkExtractorWrapper extractorWrapper = newWrappedExtractor(trackType, representation.format);
RangedUri requestUri; RangedUri requestUri;
if (loadIndex) { if (loadIndex) {
RangedUri indexUri = representation.getIndexUri(); RangedUri indexUri = representation.getIndexUri();
@ -174,12 +181,12 @@ public final class DashUtil {
initializationChunk.load(); initializationChunk.load();
} }
private static ChunkExtractorWrapper newWrappedExtractor(Format format) { private static ChunkExtractorWrapper newWrappedExtractor(int trackType, Format format) {
String mimeType = format.containerMimeType; String mimeType = format.containerMimeType;
boolean isWebm = mimeType.startsWith(MimeTypes.VIDEO_WEBM) boolean isWebm = mimeType.startsWith(MimeTypes.VIDEO_WEBM)
|| mimeType.startsWith(MimeTypes.AUDIO_WEBM); || mimeType.startsWith(MimeTypes.AUDIO_WEBM);
Extractor extractor = isWebm ? new MatroskaExtractor() : new FragmentedMp4Extractor(); Extractor extractor = isWebm ? new MatroskaExtractor() : new FragmentedMp4Extractor();
return new ChunkExtractorWrapper(extractor, format); return new ChunkExtractorWrapper(extractor, trackType, format);
} }
private static Representation getFirstRepresentation(Period period, int type) { private static Representation getFirstRepresentation(Period period, int type) {

View File

@ -134,8 +134,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
representationHolders = new RepresentationHolder[trackSelection.length()]; representationHolders = new RepresentationHolder[trackSelection.length()];
for (int i = 0; i < representationHolders.length; i++) { for (int i = 0; i < representationHolders.length; i++) {
Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i));
representationHolders[i] = new RepresentationHolder(periodDurationUs, representation, representationHolders[i] = new RepresentationHolder(periodDurationUs, trackType,
enableEventMessageTrack, enableCea608Track); representation, enableEventMessageTrack, enableCea608Track);
} }
} }
@ -390,8 +390,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
private long periodDurationUs; private long periodDurationUs;
private int segmentNumShift; private int segmentNumShift;
/* package */ RepresentationHolder(long periodDurationUs, Representation representation, /* package */ RepresentationHolder(long periodDurationUs, int trackType,
boolean enableEventMessageTrack, boolean enableCea608Track) { Representation representation, boolean enableEventMessageTrack, boolean enableCea608Track) {
this.periodDurationUs = periodDurationUs; this.periodDurationUs = periodDurationUs;
this.representation = representation; this.representation = representation;
String containerMimeType = representation.format.containerMimeType; String containerMimeType = representation.format.containerMimeType;
@ -415,7 +415,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
} }
// Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream, // Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream,
// as per DASH IF Interoperability Recommendations V3.0, 7.5.3. // as per DASH IF Interoperability Recommendations V3.0, 7.5.3.
extractorWrapper = new ChunkExtractorWrapper(extractor, representation.format); extractorWrapper = new ChunkExtractorWrapper(extractor, trackType, representation.format);
} }
segmentIndex = representation.getIndex(); segmentIndex = representation.getIndex();
} }

View File

@ -102,7 +102,7 @@ public class DefaultSsChunkSource implements SsChunkSource {
FragmentedMp4Extractor extractor = new FragmentedMp4Extractor( FragmentedMp4Extractor extractor = new FragmentedMp4Extractor(
FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
| FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, null, track); | FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, null, track);
extractorWrappers[i] = new ChunkExtractorWrapper(extractor, format); extractorWrappers[i] = new ChunkExtractorWrapper(extractor, streamElement.type, format);
} }
} }