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);
}
}