From 5bed2bf5032a4e5bea36a30a667a795ed172798a Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 29 Aug 2017 13:55:19 -0700 Subject: [PATCH] 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 --- .../source/chunk/ChunkExtractorWrapper.java | 35 +++++++++------- .../exoplayer2/source/dash/DashUtil.java | 41 +++++++++++-------- .../source/dash/DefaultDashChunkSource.java | 10 ++--- .../smoothstreaming/DefaultSsChunkSource.java | 2 +- 4 files changed, 51 insertions(+), 37 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java index 07d1cce8cb..17eb30dee9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java @@ -29,9 +29,10 @@ import com.google.android.exoplayer2.util.ParsableByteArray; 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. *

- * 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 { @@ -56,7 +57,8 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { public final Extractor extractor; - private final Format manifestFormat; + private final int primaryTrackType; + private final Format primaryTrackManifestFormat; private final SparseArray bindingTrackOutputs; private boolean extractorInitialized; @@ -66,12 +68,16 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { /** * @param extractor The extractor to wrap. - * @param manifestFormat A manifest defined {@link Format} whose data should be merged into any - * sample {@link Format} output from the {@link Extractor}. + * @param primaryTrackType The type of the primary track. Typically one of the + * {@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.manifestFormat = manifestFormat; + this.primaryTrackType = primaryTrackType; + this.primaryTrackManifestFormat = primaryTrackManifestFormat; 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 - * receive data from a new chunk. + * Initializes the wrapper to output to {@link TrackOutput}s provided by the specified + * {@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. */ @@ -116,7 +122,9 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { if (bindingTrackOutput == null) { // Assert that if we're seeing a new track we have not seen endTracks. 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); bindingTrackOutputs.put(id, bindingTrackOutput); } @@ -160,16 +168,15 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { return; } trackOutput = trackOutputProvider.track(id, type); - if (trackOutput != null) { + if (sampleFormat != null) { trackOutput.format(sampleFormat); } } @Override public void format(Format format) { - // TODO: This should only happen for the primary track. Additional metadata/text tracks need - // to be copied with different manifest derived formats. - sampleFormat = format.copyWithManifestFormatInfo(manifestFormat); + sampleFormat = manifestFormat != null ? format.copyWithManifestFormatInfo(manifestFormat) + : format; trackOutput.format(sampleFormat); } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java index 59fbfb18fe..ed2f916b87 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java @@ -72,9 +72,11 @@ public final class DashUtil { */ public static DrmInitData loadDrmInitData(DataSource dataSource, Period period) 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) { - representation = getFirstRepresentation(period, C.TRACK_TYPE_AUDIO); + primaryTrackType = C.TRACK_TYPE_AUDIO; + representation = getFirstRepresentation(period, primaryTrackType); if (representation == null) { return null; } @@ -85,7 +87,7 @@ public final class DashUtil { // as per DASH IF Interoperability Recommendations V3.0, 7.5.3. return drmInitData; } - Format sampleFormat = DashUtil.loadSampleFormat(dataSource, representation); + Format sampleFormat = DashUtil.loadSampleFormat(dataSource, primaryTrackType, representation); 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}. * * @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. * @return the sample {@link Format} of the given representation. * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ - public static Format loadSampleFormat(DataSource dataSource, Representation representation) - throws IOException, InterruptedException { - ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, representation, - false); + public static Format loadSampleFormat(DataSource dataSource, int trackType, + Representation representation) throws IOException, InterruptedException { + ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, + representation, false); return extractorWrapper == null ? null : extractorWrapper.getSampleFormats()[0]; } @@ -110,16 +114,18 @@ public final class DashUtil { * ChunkIndex}. * * @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. * @return The {@link ChunkIndex} of the given representation, or null if no initialization or * index data exists. * @throws IOException Thrown when there is an error while loading. * @throws InterruptedException Thrown if the thread was interrupted. */ - public static ChunkIndex loadChunkIndex(DataSource dataSource, Representation representation) - throws IOException, InterruptedException { - ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, representation, - true); + public static ChunkIndex loadChunkIndex(DataSource dataSource, int trackType, + Representation representation) throws IOException, InterruptedException { + ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, + representation, true); return extractorWrapper == null ? null : (ChunkIndex) extractorWrapper.getSeekMap(); } @@ -128,6 +134,8 @@ public final class DashUtil { * returns a {@link ChunkExtractorWrapper} which contains the output. * * @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 loadIndex Whether to load index data too. * @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 InterruptedException Thrown if the thread was interrupted. */ - private static ChunkExtractorWrapper loadInitializationData(DataSource dataSource, - Representation representation, boolean loadIndex) - throws IOException, InterruptedException { + private static ChunkExtractorWrapper loadInitializationData(DataSource dataSource, int trackType, + Representation representation, boolean loadIndex) throws IOException, InterruptedException { RangedUri initializationUri = representation.getInitializationUri(); if (initializationUri == null) { return null; } - ChunkExtractorWrapper extractorWrapper = newWrappedExtractor(representation.format); + ChunkExtractorWrapper extractorWrapper = newWrappedExtractor(trackType, representation.format); RangedUri requestUri; if (loadIndex) { RangedUri indexUri = representation.getIndexUri(); @@ -174,12 +181,12 @@ public final class DashUtil { initializationChunk.load(); } - private static ChunkExtractorWrapper newWrappedExtractor(Format format) { + private static ChunkExtractorWrapper newWrappedExtractor(int trackType, Format format) { String mimeType = format.containerMimeType; boolean isWebm = mimeType.startsWith(MimeTypes.VIDEO_WEBM) || mimeType.startsWith(MimeTypes.AUDIO_WEBM); 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) { diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index dd62d47621..c6c1461001 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -134,8 +134,8 @@ public class DefaultDashChunkSource implements DashChunkSource { representationHolders = new RepresentationHolder[trackSelection.length()]; for (int i = 0; i < representationHolders.length; i++) { Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); - representationHolders[i] = new RepresentationHolder(periodDurationUs, representation, - enableEventMessageTrack, enableCea608Track); + representationHolders[i] = new RepresentationHolder(periodDurationUs, trackType, + representation, enableEventMessageTrack, enableCea608Track); } } @@ -390,8 +390,8 @@ public class DefaultDashChunkSource implements DashChunkSource { private long periodDurationUs; private int segmentNumShift; - /* package */ RepresentationHolder(long periodDurationUs, Representation representation, - boolean enableEventMessageTrack, boolean enableCea608Track) { + /* package */ RepresentationHolder(long periodDurationUs, int trackType, + Representation representation, boolean enableEventMessageTrack, boolean enableCea608Track) { this.periodDurationUs = periodDurationUs; this.representation = representation; 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, // 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(); } diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java index f2e4c57298..1069527989 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java @@ -102,7 +102,7 @@ public class DefaultSsChunkSource implements SsChunkSource { FragmentedMp4Extractor extractor = new FragmentedMp4Extractor( FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME | FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, null, track); - extractorWrappers[i] = new ChunkExtractorWrapper(extractor, format); + extractorWrappers[i] = new ChunkExtractorWrapper(extractor, streamElement.type, format); } }