Clean up max dimension handling.

This commit is contained in:
Oliver Woodman 2015-09-01 14:17:21 +01:00
parent 4a9ff7b094
commit cb85dc25aa
12 changed files with 83 additions and 144 deletions

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer.dash;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.TimeRange; import com.google.android.exoplayer.TimeRange;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.chunk.ChunkOperationHolder; import com.google.android.exoplayer.chunk.ChunkOperationHolder;
@ -85,23 +84,14 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
private static final Format WIDE_VIDEO = private static final Format WIDE_VIDEO =
new Format("3", "video/mp4", WIDE_WIDTH, 50, -1, -1, -1, 1000); new Format("3", "video/mp4", WIDE_WIDTH, 50, -1, -1, -1, 1000);
@Mock private DataSource mockDataSource; @Mock
private DataSource mockDataSource;
@Override @Override
public void setUp() throws Exception { public void setUp() throws Exception {
TestUtil.setUpMockito(this); TestUtil.setUpMockito(this);
} }
public void testMaxVideoDimensions() {
DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO,
null, null, null);
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 5000, 1, 1, 1, 1, 1, null);
format = chunkSource.getWithMaxVideoDimensions(format);
assertEquals(WIDE_WIDTH, format.maxWidth);
assertEquals(TALL_HEIGHT, format.maxHeight);
}
public void testGetAvailableRangeOnVod() { public void testGetAvailableRangeOnVod() {
DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO, DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO,
null, null, mock(FormatEvaluator.class)); null, null, mock(FormatEvaluator.class));
@ -192,22 +182,6 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
checkSegmentRequestSequenceOnMultiPeriodLive(chunkSource); checkSegmentRequestSequenceOnMultiPeriodLive(chunkSource);
} }
public void testMaxVideoDimensionsLegacy() {
SingleSegmentBase segmentBase1 = new SingleSegmentBase("https://example.com/1.mp4");
Representation representation1 =
Representation.newInstance(0, 0, null, 0, TALL_VIDEO, segmentBase1);
SingleSegmentBase segmentBase2 = new SingleSegmentBase("https://example.com/2.mp4");
Representation representation2 =
Representation.newInstance(0, 0, null, 0, WIDE_VIDEO, segmentBase2);
DashChunkSource chunkSource = new DashChunkSource(null, null, representation1, representation2);
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 5000, 1, 1, 1, 1, 1, null);
format = chunkSource.getWithMaxVideoDimensions(format);
assertEquals(WIDE_WIDTH, format.maxWidth);
assertEquals(TALL_HEIGHT, format.maxHeight);
}
public void testLiveEdgeNoLatency() { public void testLiveEdgeNoLatency() {
long startTimeMs = 0; long startTimeMs = 0;

View File

@ -323,25 +323,12 @@ public final class MediaFormat {
if (obj == null || getClass() != obj.getClass()) { if (obj == null || getClass() != obj.getClass()) {
return false; return false;
} }
return equalsInternal((MediaFormat) obj, false); MediaFormat other = (MediaFormat) obj;
}
public boolean equals(MediaFormat other, boolean ignoreMaxDimensions) {
if (this == other) {
return true;
}
if (other == null) {
return false;
}
return equalsInternal(other, ignoreMaxDimensions);
}
private boolean equalsInternal(MediaFormat other, boolean ignoreMaxDimensions) {
if (adaptive != other.adaptive || bitrate != other.bitrate || maxInputSize != other.maxInputSize if (adaptive != other.adaptive || bitrate != other.bitrate || maxInputSize != other.maxInputSize
|| width != other.width || height != other.height || width != other.width || height != other.height
|| rotationDegrees != other.rotationDegrees || rotationDegrees != other.rotationDegrees
|| pixelWidthHeightRatio != other.pixelWidthHeightRatio || pixelWidthHeightRatio != other.pixelWidthHeightRatio
|| (!ignoreMaxDimensions && (maxWidth != other.maxWidth || maxHeight != other.maxHeight)) || maxWidth != other.maxWidth || maxHeight != other.maxHeight
|| channelCount != other.channelCount || sampleRate != other.sampleRate || channelCount != other.channelCount || sampleRate != other.sampleRate
|| !Util.areEqual(language, other.language) || !Util.areEqual(mimeType, other.mimeType) || !Util.areEqual(language, other.language) || !Util.areEqual(mimeType, other.mimeType)
|| initializationData.size() != other.initializationData.size()) { || initializationData.size() != other.initializationData.size()) {

View File

@ -232,8 +232,7 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
if (haveSamples || currentChunk.isMediaFormatFinal) { if (haveSamples || currentChunk.isMediaFormatFinal) {
MediaFormat mediaFormat = currentChunk.getMediaFormat(); MediaFormat mediaFormat = currentChunk.getMediaFormat();
if (!mediaFormat.equals(downstreamMediaFormat, true)) { if (!mediaFormat.equals(downstreamMediaFormat)) {
mediaFormat = chunkSource.getWithMaxVideoDimensions(mediaFormat);
formatHolder.format = mediaFormat; formatHolder.format = mediaFormat;
formatHolder.drmInitData = currentChunk.getDrmInitData(); formatHolder.drmInitData = currentChunk.getDrmInitData();
downstreamMediaFormat = mediaFormat; downstreamMediaFormat = mediaFormat;

View File

@ -76,19 +76,6 @@ public interface ChunkSource {
*/ */
void enable(int track); void enable(int track);
/**
* Adaptive video {@link ChunkSource} implementations must return a copy of the provided
* {@link MediaFormat} with the maximum video dimensions set. Other implementations can return
* the provided {@link MediaFormat} directly.
* <p>
* This method should only be called when the source is enabled.
*
* @param format The format to be copied or returned.
* @return A copy of the provided {@link MediaFormat} with the maximum video dimensions set, or
* the provided format.
*/
MediaFormat getWithMaxVideoDimensions(MediaFormat format);
/** /**
* Indicates to the source that it should still be checking for updates to the stream. * Indicates to the source that it should still be checking for updates to the stream.
* <p> * <p>

View File

@ -36,6 +36,8 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOu
private final ChunkExtractorWrapper extractorWrapper; private final ChunkExtractorWrapper extractorWrapper;
private final long sampleOffsetUs; private final long sampleOffsetUs;
private final int adaptiveMaxWidth;
private final int adaptiveMaxHeight;
private MediaFormat mediaFormat; private MediaFormat mediaFormat;
private DrmInitData drmInitData; private DrmInitData drmInitData;
@ -56,6 +58,12 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOu
* @param extractorWrapper A wrapped extractor to use for parsing the data. * @param extractorWrapper A wrapped extractor to use for parsing the data.
* @param mediaFormat The {@link MediaFormat} of the chunk, if known. May be null if the data is * @param mediaFormat The {@link MediaFormat} of the chunk, if known. May be null if the data is
* known to define its own format. * known to define its own format.
* @param adaptiveMaxWidth If this chunk contains video and is part of an adaptive playback, this
* is the maximum width of the video in pixels that will be encountered during the playback.
* {@link MediaFormat#NO_VALUE} otherwise.
* @param adaptiveMaxHeight If this chunk contains video and is part of an adaptive playback, this
* is the maximum height of the video in pixels that will be encountered during the playback.
* {@link MediaFormat#NO_VALUE} otherwise.
* @param drmInitData The {@link DrmInitData} for the chunk. Null if the media is not drm * @param drmInitData The {@link DrmInitData} for the chunk. Null if the media is not drm
* protected. May also be null if the data is known to define its own initialization data. * protected. May also be null if the data is known to define its own initialization data.
* @param isMediaFormatFinal True if {@code mediaFormat} and {@code drmInitData} are known to be * @param isMediaFormatFinal True if {@code mediaFormat} and {@code drmInitData} are known to be
@ -64,13 +72,16 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOu
*/ */
public ContainerMediaChunk(DataSource dataSource, DataSpec dataSpec, int trigger, Format format, public ContainerMediaChunk(DataSource dataSource, DataSpec dataSpec, int trigger, Format format,
long startTimeUs, long endTimeUs, int chunkIndex, boolean isLastChunk, long sampleOffsetUs, long startTimeUs, long endTimeUs, int chunkIndex, boolean isLastChunk, long sampleOffsetUs,
ChunkExtractorWrapper extractorWrapper, MediaFormat mediaFormat, DrmInitData drmInitData, ChunkExtractorWrapper extractorWrapper, MediaFormat mediaFormat, int adaptiveMaxWidth,
boolean isMediaFormatFinal, int parentId) { int adaptiveMaxHeight, DrmInitData drmInitData, boolean isMediaFormatFinal, int parentId) {
super(dataSource, dataSpec, trigger, format, startTimeUs, endTimeUs, chunkIndex, isLastChunk, super(dataSource, dataSpec, trigger, format, startTimeUs, endTimeUs, chunkIndex, isLastChunk,
isMediaFormatFinal, parentId); isMediaFormatFinal, parentId);
this.extractorWrapper = extractorWrapper; this.extractorWrapper = extractorWrapper;
this.sampleOffsetUs = sampleOffsetUs; this.sampleOffsetUs = sampleOffsetUs;
this.mediaFormat = getAdjustedMediaFormat(mediaFormat, sampleOffsetUs); this.adaptiveMaxWidth = adaptiveMaxWidth;
this.adaptiveMaxHeight = adaptiveMaxHeight;
this.mediaFormat = getAdjustedMediaFormat(mediaFormat, sampleOffsetUs, adaptiveMaxWidth,
adaptiveMaxHeight);
this.drmInitData = drmInitData; this.drmInitData = drmInitData;
} }
@ -103,7 +114,8 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOu
@Override @Override
public final void format(MediaFormat mediaFormat) { public final void format(MediaFormat mediaFormat) {
this.mediaFormat = getAdjustedMediaFormat(mediaFormat, sampleOffsetUs); this.mediaFormat = getAdjustedMediaFormat(mediaFormat, sampleOffsetUs, adaptiveMaxWidth,
adaptiveMaxHeight);
} }
@Override @Override
@ -163,10 +175,16 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackOu
// Private methods. // Private methods.
private static MediaFormat getAdjustedMediaFormat(MediaFormat format, long sampleOffsetUs) { private static MediaFormat getAdjustedMediaFormat(MediaFormat format, long sampleOffsetUs,
if (sampleOffsetUs != 0 && format != null int adaptiveMaxWidth, int adaptiveMaxHeight) {
&& format.subsampleOffsetUs != MediaFormat.OFFSET_SAMPLE_RELATIVE) { if (format == null) {
return format.copyWithSubsampleOffsetUs(format.subsampleOffsetUs + sampleOffsetUs); return null;
}
if (sampleOffsetUs != 0 && format.subsampleOffsetUs != MediaFormat.OFFSET_SAMPLE_RELATIVE) {
format = format.copyWithSubsampleOffsetUs(format.subsampleOffsetUs + sampleOffsetUs);
}
if (adaptiveMaxWidth != MediaFormat.NO_VALUE || adaptiveMaxHeight != MediaFormat.NO_VALUE) {
format = format.copyWithMaxVideoDimensions(adaptiveMaxWidth, adaptiveMaxHeight);
} }
return format; return format;
} }

View File

@ -108,11 +108,6 @@ public final class MultiTrackChunkSource implements ChunkSource, ExoPlayerCompon
selectedSource.maybeThrowError(); selectedSource.maybeThrowError();
} }
@Override
public MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
return selectedSource.getWithMaxVideoDimensions(format);
}
@Override @Override
public void handleMessage(int what, Object msg) throws ExoPlaybackException { public void handleMessage(int what, Object msg) throws ExoPlaybackException {
Assertions.checkState(!enabled); Assertions.checkState(!enabled);

View File

@ -69,11 +69,6 @@ public final class SingleSampleChunkSource implements ChunkSource {
return mediaFormat; return mediaFormat;
} }
@Override
public MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
return format;
}
@Override @Override
public void enable(int track) { public void enable(int track) {
// Do nothing. // Do nothing.

View File

@ -271,11 +271,10 @@ public class DashChunkSource implements ChunkSource {
processManifest(currentManifest); processManifest(currentManifest);
String mimeType = "";
long totalDurationUs = 0; long totalDurationUs = 0;
int maxHeight = 0;
int maxWidth = 0; int maxWidth = 0;
int maxHeight = 0;
String mimeType = "";
for (int i = 0; i < periodHolders.size(); i++) { for (int i = 0; i < periodHolders.size(); i++) {
PeriodHolder periodHolder = periodHolders.valueAt(i); PeriodHolder periodHolder = periodHolders.valueAt(i);
if (totalDurationUs != TrackRenderer.UNKNOWN_TIME_US) { if (totalDurationUs != TrackRenderer.UNKNOWN_TIME_US) {
@ -285,21 +284,15 @@ public class DashChunkSource implements ChunkSource {
totalDurationUs += periodHolder.durationUs; totalDurationUs += periodHolder.durationUs;
} }
} }
mimeType = periodHolder.mimeType;
maxHeight = Math.max(maxHeight, periodHolder.maxHeight);
maxWidth = Math.max(maxWidth, periodHolder.maxWidth); maxWidth = Math.max(maxWidth, periodHolder.maxWidth);
maxHeight = Math.max(maxHeight, periodHolder.maxHeight);
mimeType = periodHolder.mimeType;
} }
this.maxWidth = maxWidth == 0 ? MediaFormat.NO_VALUE : maxWidth;
this.maxHeight = maxHeight == 0 ? MediaFormat.NO_VALUE : maxHeight;
// TODO: Remove this and pass proper formats instead (b/22996976). // TODO: Remove this and pass proper formats instead (b/22996976).
this.mediaFormat = MediaFormat.createFormatForMimeType(mimeType, MediaFormat.NO_VALUE, this.mediaFormat = MediaFormat.createFormatForMimeType(mimeType, MediaFormat.NO_VALUE,
totalDurationUs); totalDurationUs);
this.maxHeight = maxHeight;
this.maxWidth = maxWidth;
}
@Override
public final MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
return MimeTypes.isVideo(mediaFormat.mimeType)
? format.copyWithMaxVideoDimensions(maxWidth, maxHeight) : format;
} }
@Override @Override
@ -606,8 +599,8 @@ public class DashChunkSource implements ChunkSource {
boolean isMediaFormatFinal = (mediaFormat != null); boolean isMediaFormatFinal = (mediaFormat != null);
return new ContainerMediaChunk(dataSource, dataSpec, trigger, representation.format, return new ContainerMediaChunk(dataSource, dataSpec, trigger, representation.format,
startTimeUs, endTimeUs, segmentNum, isLastSegment, sampleOffsetUs, startTimeUs, endTimeUs, segmentNum, isLastSegment, sampleOffsetUs,
representationHolder.extractorWrapper, mediaFormat, drmInitData, isMediaFormatFinal, representationHolder.extractorWrapper, mediaFormat, maxWidth, maxHeight, drmInitData,
periodHolder.manifestIndex); isMediaFormatFinal, periodHolder.manifestIndex);
} }
} }
@ -854,8 +847,8 @@ public class DashChunkSource implements ChunkSource {
formats = new Format[representationCount]; formats = new Format[representationCount];
representationHolders = new HashMap<>(representationCount); representationHolders = new HashMap<>(representationCount);
int maxWidth = -1; int maxWidth = 0;
int maxHeight = -1; int maxHeight = 0;
String mimeType = ""; String mimeType = "";
for (int i = 0; i < representationCount; i++) { for (int i = 0; i < representationCount; i++) {
int representationIndex = representationIndices != null ? representationIndices[i] : i; int representationIndex = representationIndices != null ? representationIndices[i] : i;

View File

@ -119,8 +119,8 @@ public class HlsChunkSource {
private final BandwidthMeter bandwidthMeter; private final BandwidthMeter bandwidthMeter;
private final int adaptiveMode; private final int adaptiveMode;
private final String baseUri; private final String baseUri;
private final int maxWidth; private final int adaptiveMaxWidth;
private final int maxHeight; private final int adaptiveMaxHeight;
private final long minBufferDurationToSwitchUpUs; private final long minBufferDurationToSwitchUpUs;
private final long maxBufferDurationToSwitchDownUs; private final long maxBufferDurationToSwitchDownUs;
@ -184,8 +184,8 @@ public class HlsChunkSource {
variantBlacklistTimes = new long[1]; variantBlacklistTimes = new long[1];
setMediaPlaylist(0, (HlsMediaPlaylist) playlist); setMediaPlaylist(0, (HlsMediaPlaylist) playlist);
// We won't be adapting between different variants. // We won't be adapting between different variants.
maxWidth = -1; adaptiveMaxWidth = MediaFormat.NO_VALUE;
maxHeight = -1; adaptiveMaxHeight = MediaFormat.NO_VALUE;
} else { } else {
List<Variant> masterPlaylistVariants = ((HlsMasterPlaylist) playlist).variants; List<Variant> masterPlaylistVariants = ((HlsMasterPlaylist) playlist).variants;
variants = buildOrderedVariants(masterPlaylistVariants, variantIndices); variants = buildOrderedVariants(masterPlaylistVariants, variantIndices);
@ -208,13 +208,13 @@ public class HlsChunkSource {
} }
if (variants.length <= 1 || adaptiveMode == ADAPTIVE_MODE_NONE) { if (variants.length <= 1 || adaptiveMode == ADAPTIVE_MODE_NONE) {
// We won't be adapting between different variants. // We won't be adapting between different variants.
this.maxWidth = -1; this.adaptiveMaxWidth = MediaFormat.NO_VALUE;
this.maxHeight = -1; this.adaptiveMaxHeight = MediaFormat.NO_VALUE;
} else { } else {
// We will be adapting between different variants. // We will be adapting between different variants.
// TODO: We should allow the default values to be passed through the constructor. // TODO: We should allow the default values to be passed through the constructor.
this.maxWidth = maxWidth > 0 ? maxWidth : 1920; this.adaptiveMaxWidth = maxWidth > 0 ? maxWidth : 1920;
this.maxHeight = maxHeight > 0 ? maxHeight : 1080; this.adaptiveMaxHeight = maxHeight > 0 ? maxHeight : 1080;
} }
} }
} }
@ -223,20 +223,6 @@ public class HlsChunkSource {
return live ? C.UNKNOWN_TIME_US : durationUs; return live ? C.UNKNOWN_TIME_US : durationUs;
} }
/**
* Adaptive implementations must return a copy of the provided {@link MediaFormat} with the
* maximum video dimensions set. Other implementations can return the provided {@link MediaFormat}
* directly.
*
* @param format The format to be copied or returned.
* @return A copy of the provided {@link MediaFormat} with the maximum video dimensions set, or
* the provided format.
*/
public MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
return (maxWidth == -1 || maxHeight == -1) ? format
: format.copyWithMaxVideoDimensions(maxWidth, maxHeight);
}
/** /**
* Returns the next {@link Chunk} that should be loaded. * Returns the next {@link Chunk} that should be loaded.
* *
@ -348,7 +334,7 @@ public class HlsChunkSource {
Extractor extractor = chunkUri.getLastPathSegment().endsWith(AAC_FILE_EXTENSION) Extractor extractor = chunkUri.getLastPathSegment().endsWith(AAC_FILE_EXTENSION)
? new AdtsExtractor(startTimeUs) : new TsExtractor(startTimeUs); ? new AdtsExtractor(startTimeUs) : new TsExtractor(startTimeUs);
extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor, extractorWrapper = new HlsExtractorWrapper(trigger, format, startTimeUs, extractor,
switchingVariantSpliced); switchingVariantSpliced, adaptiveMaxWidth, adaptiveMaxHeight);
} else { } else {
extractorWrapper = previousTsChunk.extractorWrapper; extractorWrapper = previousTsChunk.extractorWrapper;
} }

View File

@ -27,6 +27,7 @@ import com.google.android.exoplayer.extractor.SeekMap;
import com.google.android.exoplayer.extractor.TrackOutput; import com.google.android.exoplayer.extractor.TrackOutput;
import com.google.android.exoplayer.upstream.Allocator; import com.google.android.exoplayer.upstream.Allocator;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.MimeTypes;
import android.util.SparseArray; import android.util.SparseArray;
@ -44,7 +45,10 @@ public final class HlsExtractorWrapper implements ExtractorOutput {
private final Extractor extractor; private final Extractor extractor;
private final SparseArray<DefaultTrackOutput> sampleQueues; private final SparseArray<DefaultTrackOutput> sampleQueues;
private final boolean shouldSpliceIn; private final boolean shouldSpliceIn;
private final int adaptiveMaxWidth;
private final int adaptiveMaxHeight;
private MediaFormat[] sampleQueueFormats;
private Allocator allocator; private Allocator allocator;
private volatile boolean tracksBuilt; private volatile boolean tracksBuilt;
@ -54,12 +58,14 @@ public final class HlsExtractorWrapper implements ExtractorOutput {
private boolean spliceConfigured; private boolean spliceConfigured;
public HlsExtractorWrapper(int trigger, Format format, long startTimeUs, Extractor extractor, public HlsExtractorWrapper(int trigger, Format format, long startTimeUs, Extractor extractor,
boolean shouldSpliceIn) { boolean shouldSpliceIn, int adaptiveMaxWidth, int adaptiveMaxHeight) {
this.trigger = trigger; this.trigger = trigger;
this.format = format; this.format = format;
this.startTimeUs = startTimeUs; this.startTimeUs = startTimeUs;
this.extractor = extractor; this.extractor = extractor;
this.shouldSpliceIn = shouldSpliceIn; this.shouldSpliceIn = shouldSpliceIn;
this.adaptiveMaxWidth = adaptiveMaxWidth;
this.adaptiveMaxHeight = adaptiveMaxHeight;
sampleQueues = new SparseArray<>(); sampleQueues = new SparseArray<>();
} }
@ -86,6 +92,15 @@ public final class HlsExtractorWrapper implements ExtractorOutput {
} }
} }
prepared = true; prepared = true;
sampleQueueFormats = new MediaFormat[sampleQueues.size()];
for (int i = 0; i < sampleQueueFormats.length; i++) {
MediaFormat format = sampleQueues.valueAt(i).getFormat();
if (MimeTypes.isVideo(format.mimeType) && (adaptiveMaxWidth != MediaFormat.NO_VALUE
|| adaptiveMaxHeight != MediaFormat.NO_VALUE)) {
format = format.copyWithMaxVideoDimensions(adaptiveMaxWidth, adaptiveMaxHeight);
}
sampleQueueFormats[i] = format;
}
} }
return prepared; return prepared;
} }
@ -169,7 +184,7 @@ public final class HlsExtractorWrapper implements ExtractorOutput {
*/ */
public MediaFormat getMediaFormat(int track) { public MediaFormat getMediaFormat(int track) {
Assertions.checkState(isPrepared()); Assertions.checkState(isPrepared());
return sampleQueues.valueAt(track).getFormat(); return sampleQueueFormats[track];
} }
/** /**

View File

@ -138,11 +138,11 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
mediaFormats = new MediaFormat[trackCount]; mediaFormats = new MediaFormat[trackCount];
long durationUs = chunkSource.getDurationUs(); long durationUs = chunkSource.getDurationUs();
for (int i = 0; i < trackCount; i++) { for (int i = 0; i < trackCount; i++) {
mediaFormats[i] = extractor.getMediaFormat(i).copyWithDurationUs(durationUs); MediaFormat format = extractor.getMediaFormat(i).copyWithDurationUs(durationUs);
if (MimeTypes.isVideo(mediaFormats[i].mimeType)) { if (MimeTypes.isVideo(format.mimeType)) {
mediaFormats[i] = chunkSource.getWithMaxVideoDimensions(mediaFormats[i]) format = format.copyAsAdaptive();
.copyAsAdaptive();
} }
mediaFormats[i] = format;
} }
prepared = true; prepared = true;
return true; return true;
@ -294,8 +294,7 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
} }
MediaFormat mediaFormat = extractor.getMediaFormat(track); MediaFormat mediaFormat = extractor.getMediaFormat(track);
if (mediaFormat != null && !mediaFormat.equals(downstreamMediaFormats[track], true)) { if (mediaFormat != null && !mediaFormat.equals(downstreamMediaFormats[track])) {
mediaFormat = chunkSource.getWithMaxVideoDimensions(mediaFormat);
formatHolder.format = mediaFormat; formatHolder.format = mediaFormat;
downstreamMediaFormats[track] = mediaFormat; downstreamMediaFormats[track] = mediaFormat;
return FORMAT_READ; return FORMAT_READ;

View File

@ -196,15 +196,6 @@ public class SmoothStreamingChunkSource implements ChunkSource,
} }
} }
@Override
public final MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
if (enabledTrack.isAdaptive() && MimeTypes.isVideo(format.mimeType)) {
return format.copyWithMaxVideoDimensions(
enabledTrack.adaptiveMaxWidth, enabledTrack.adaptiveMaxHeight);
}
return format;
}
@Override @Override
public void continueBuffering(long playbackPositionUs) { public void continueBuffering(long playbackPositionUs) {
if (manifestFetcher == null || !currentManifest.isLive || fatalError != null) { if (manifestFetcher == null || !currentManifest.isLive || fatalError != null) {
@ -323,10 +314,10 @@ public class SmoothStreamingChunkSource implements ChunkSource,
int manifestTrackKey = getManifestTrackKey(enabledTrack.elementIndex, manifestTrackIndex); int manifestTrackKey = getManifestTrackKey(enabledTrack.elementIndex, manifestTrackIndex);
Uri uri = streamElement.buildRequestUri(manifestTrackIndex, chunkIndex); Uri uri = streamElement.buildRequestUri(manifestTrackIndex, chunkIndex);
Chunk mediaChunk = newMediaChunk(selectedFormat, uri, null, Chunk mediaChunk = newMediaChunk(selectedFormat, uri, null,
extractorWrappers.get(manifestTrackKey), extractorWrappers.get(manifestTrackKey), drmInitData, dataSource, currentAbsoluteChunkIndex,
drmInitData, dataSource, currentAbsoluteChunkIndex, isLastChunk, chunkStartTimeUs, isLastChunk, chunkStartTimeUs, chunkEndTimeUs, evaluation.trigger,
chunkEndTimeUs, evaluation.trigger, mediaFormats.get(manifestTrackKey), enabledTrack.adaptiveMaxWidth,
mediaFormats.get(manifestTrackKey)); enabledTrack.adaptiveMaxHeight);
out.chunk = mediaChunk; out.chunk = mediaChunk;
} }
@ -480,14 +471,14 @@ public class SmoothStreamingChunkSource implements ChunkSource,
private static MediaChunk newMediaChunk(Format formatInfo, Uri uri, String cacheKey, private static MediaChunk newMediaChunk(Format formatInfo, Uri uri, String cacheKey,
ChunkExtractorWrapper extractorWrapper, DrmInitData drmInitData, DataSource dataSource, ChunkExtractorWrapper extractorWrapper, DrmInitData drmInitData, DataSource dataSource,
int chunkIndex, boolean isLast, long chunkStartTimeUs, long chunkEndTimeUs, int chunkIndex, boolean isLast, long chunkStartTimeUs, long chunkEndTimeUs,
int trigger, MediaFormat mediaFormat) { int trigger, MediaFormat mediaFormat, int adaptiveMaxWidth, int adaptiveMaxHeight) {
long offset = 0; long offset = 0;
DataSpec dataSpec = new DataSpec(uri, offset, -1, cacheKey); DataSpec dataSpec = new DataSpec(uri, offset, -1, cacheKey);
// In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk. // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk.
// To convert them the absolute timestamps, we need to set sampleOffsetUs to -chunkStartTimeUs. // To convert them the absolute timestamps, we need to set sampleOffsetUs to -chunkStartTimeUs.
return new ContainerMediaChunk(dataSource, dataSpec, trigger, formatInfo, chunkStartTimeUs, return new ContainerMediaChunk(dataSource, dataSpec, trigger, formatInfo, chunkStartTimeUs,
chunkEndTimeUs, chunkIndex, isLast, chunkStartTimeUs, extractorWrapper, mediaFormat, chunkEndTimeUs, chunkIndex, isLast, chunkStartTimeUs, extractorWrapper, mediaFormat,
drmInitData, true, Chunk.NO_PARENT_ID); adaptiveMaxWidth, adaptiveMaxHeight, drmInitData, true, Chunk.NO_PARENT_ID);
} }
private static int getManifestTrackKey(int elementIndex, int trackIndex) { private static int getManifestTrackKey(int elementIndex, int trackIndex) {
@ -538,17 +529,17 @@ public class SmoothStreamingChunkSource implements ChunkSource,
this.elementIndex = elementIndex; this.elementIndex = elementIndex;
this.fixedFormat = fixedFormat; this.fixedFormat = fixedFormat;
this.adaptiveFormats = null; this.adaptiveFormats = null;
this.adaptiveMaxWidth = -1; this.adaptiveMaxWidth = MediaFormat.NO_VALUE;
this.adaptiveMaxHeight = -1; this.adaptiveMaxHeight = MediaFormat.NO_VALUE;
} }
public ExposedTrack(MediaFormat format, int elementIndex, Format[] adaptiveFormats, public ExposedTrack(MediaFormat format, int elementIndex, Format[] adaptiveFormats,
int maxWidth, int maxHeight) { int adaptiveMaxWidth, int adaptiveMaxHeight) {
this.format = format; this.format = format;
this.elementIndex = elementIndex; this.elementIndex = elementIndex;
this.adaptiveFormats = adaptiveFormats; this.adaptiveFormats = adaptiveFormats;
this.adaptiveMaxWidth = maxWidth; this.adaptiveMaxWidth = adaptiveMaxWidth;
this.adaptiveMaxHeight = maxHeight; this.adaptiveMaxHeight = adaptiveMaxHeight;
this.fixedFormat = null; this.fixedFormat = null;
} }