Propagate MediaFormat instead of TrackInfo.

Issue #514.
This commit is contained in:
Oliver Woodman 2015-08-11 18:23:22 +01:00
parent f7ffeb75cf
commit 8db1331021
28 changed files with 178 additions and 235 deletions

View File

@ -22,7 +22,6 @@ import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder; import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceTrackRenderer; import com.google.android.exoplayer.SampleSourceTrackRenderer;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioTrack; import com.google.android.exoplayer.audio.AudioTrack;
import com.google.android.exoplayer.ext.opus.OpusDecoderWrapper.InputBuffer; import com.google.android.exoplayer.ext.opus.OpusDecoderWrapper.InputBuffer;
@ -125,9 +124,10 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
} }
@Override @Override
protected boolean handlesTrack(TrackInfo trackInfo) { protected boolean handlesTrack(MediaFormat mediaFormat) {
return MimeTypes.AUDIO_OPUS.equalsIgnoreCase(trackInfo.mimeType) // TODO: Stop claiming to handle the WebM mime type (b/22996976).
|| MimeTypes.AUDIO_WEBM.equalsIgnoreCase(trackInfo.mimeType); return MimeTypes.AUDIO_OPUS.equalsIgnoreCase(mediaFormat.mimeType)
|| MimeTypes.AUDIO_WEBM.equalsIgnoreCase(mediaFormat.mimeType);
} }
@Override @Override

View File

@ -21,7 +21,6 @@ import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder; import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceTrackRenderer; import com.google.android.exoplayer.SampleSourceTrackRenderer;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.ext.vp9.VpxDecoderWrapper.InputBuffer; import com.google.android.exoplayer.ext.vp9.VpxDecoderWrapper.InputBuffer;
import com.google.android.exoplayer.ext.vp9.VpxDecoderWrapper.OutputBuffer; import com.google.android.exoplayer.ext.vp9.VpxDecoderWrapper.OutputBuffer;
@ -149,9 +148,10 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
} }
@Override @Override
protected boolean handlesTrack(TrackInfo trackInfo) { protected boolean handlesTrack(MediaFormat mediaFormat) {
return MimeTypes.VIDEO_VP9.equalsIgnoreCase(trackInfo.mimeType) // TODO: Stop claiming to handle the WebM mime type (b/22996976).
|| MimeTypes.VIDEO_WEBM.equalsIgnoreCase(trackInfo.mimeType); return MimeTypes.VIDEO_VP9.equalsIgnoreCase(mediaFormat.mimeType)
|| MimeTypes.VIDEO_WEBM.equalsIgnoreCase(mediaFormat.mimeType);
} }
@Override @Override

View File

@ -69,8 +69,8 @@ public final class MediaFormatTest extends TestCase {
assertOptionalV16(out, android.media.MediaFormat.KEY_HEIGHT, in.height); assertOptionalV16(out, android.media.MediaFormat.KEY_HEIGHT, in.height);
assertOptionalV16(out, android.media.MediaFormat.KEY_CHANNEL_COUNT, in.channelCount); assertOptionalV16(out, android.media.MediaFormat.KEY_CHANNEL_COUNT, in.channelCount);
assertOptionalV16(out, android.media.MediaFormat.KEY_SAMPLE_RATE, in.sampleRate); assertOptionalV16(out, android.media.MediaFormat.KEY_SAMPLE_RATE, in.sampleRate);
assertOptionalV16(out, android.media.MediaFormat.KEY_MAX_WIDTH, in.getMaxVideoWidth()); assertOptionalV16(out, android.media.MediaFormat.KEY_MAX_WIDTH, in.maxWidth);
assertOptionalV16(out, android.media.MediaFormat.KEY_MAX_HEIGHT, in.getMaxVideoHeight()); assertOptionalV16(out, android.media.MediaFormat.KEY_MAX_HEIGHT, in.maxHeight);
for (int i = 0; i < in.initializationData.size(); i++) { for (int i = 0; i < in.initializationData.size(); i++) {
byte[] originalData = in.initializationData.get(i); byte[] originalData = in.initializationData.get(i);
ByteBuffer frameworkBuffer = out.getByteBuffer("csd-" + i); ByteBuffer frameworkBuffer = out.getByteBuffer("csd-" + i);

View File

@ -91,11 +91,11 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
public void testMaxVideoDimensions() { public void testMaxVideoDimensions() {
DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO, DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO,
null, null, null); null, null, null);
MediaFormat out = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null); MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null);
chunkSource.getMaxVideoDimensions(out); format = chunkSource.getWithMaxVideoDimensions(format);
assertEquals(WIDE_WIDTH, out.getMaxVideoWidth()); assertEquals(WIDE_WIDTH, format.maxWidth);
assertEquals(TALL_HEIGHT, out.getMaxVideoHeight()); assertEquals(TALL_HEIGHT, format.maxHeight);
} }
public void testGetSeekRangeOnVod() { public void testGetSeekRangeOnVod() {
@ -121,11 +121,11 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
Representation.newInstance(0, 0, null, 0, WIDE_VIDEO, segmentBase2); Representation.newInstance(0, 0, null, 0, WIDE_VIDEO, segmentBase2);
DashChunkSource chunkSource = new DashChunkSource(null, null, representation1, representation2); DashChunkSource chunkSource = new DashChunkSource(null, null, representation1, representation2);
MediaFormat out = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null); MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null);
chunkSource.getMaxVideoDimensions(out); format = chunkSource.getWithMaxVideoDimensions(format);
assertEquals(WIDE_WIDTH, out.getMaxVideoWidth()); assertEquals(WIDE_WIDTH, format.maxWidth);
assertEquals(TALL_HEIGHT, out.getMaxVideoHeight()); assertEquals(TALL_HEIGHT, format.maxHeight);
} }
public void testLiveEdgeNoLatency() { public void testLiveEdgeNoLatency() {

View File

@ -35,7 +35,7 @@ public final class DummyTrackRenderer extends TrackRenderer {
} }
@Override @Override
protected TrackInfo getTrackInfo(int track) { protected MediaFormat getFormat(int track) {
throw new IllegalStateException(); throw new IllegalStateException();
} }

View File

@ -34,7 +34,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private final Handler eventHandler; private final Handler eventHandler;
private final ExoPlayerImplInternal internalPlayer; private final ExoPlayerImplInternal internalPlayer;
private final CopyOnWriteArraySet<Listener> listeners; private final CopyOnWriteArraySet<Listener> listeners;
private final TrackInfo[][] trackInfos; private final MediaFormat[][] trackFormats;
private final int[] selectedTrackIndices; private final int[] selectedTrackIndices;
private boolean playWhenReady; private boolean playWhenReady;
@ -58,7 +58,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
this.playWhenReady = false; this.playWhenReady = false;
this.playbackState = STATE_IDLE; this.playbackState = STATE_IDLE;
this.listeners = new CopyOnWriteArraySet<>(); this.listeners = new CopyOnWriteArraySet<>();
this.trackInfos = new TrackInfo[rendererCount][]; this.trackFormats = new MediaFormat[rendererCount][];
this.selectedTrackIndices = new int[rendererCount]; this.selectedTrackIndices = new int[rendererCount];
eventHandler = new Handler() { eventHandler = new Handler() {
@Override @Override
@ -92,7 +92,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public void prepare(TrackRenderer... renderers) { public void prepare(TrackRenderer... renderers) {
Arrays.fill(trackInfos, null); Arrays.fill(trackFormats, null);
internalPlayer.prepare(renderers); internalPlayer.prepare(renderers);
} }
@ -116,12 +116,12 @@ import java.util.concurrent.CopyOnWriteArraySet;
// TODO: Expose in ExoPlayer. // TODO: Expose in ExoPlayer.
public int getRendererTrackCount(int rendererIndex) { public int getRendererTrackCount(int rendererIndex) {
return trackInfos[rendererIndex] != null ? trackInfos[rendererIndex].length : 0; return trackFormats[rendererIndex] != null ? trackFormats[rendererIndex].length : 0;
} }
// TODO: Expose in ExoPlayer. // TODO: Expose in ExoPlayer.
public TrackInfo getRendererTrackInfo(int rendererIndex, int trackIndex) { public MediaFormat getRendererTrackInfo(int rendererIndex, int trackIndex) {
return trackInfos[rendererIndex][trackIndex]; return trackFormats[rendererIndex][trackIndex];
} }
// TODO: Expose in ExoPlayer. // TODO: Expose in ExoPlayer.
@ -212,8 +212,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
/* package */ void handleEvent(Message msg) { /* package */ void handleEvent(Message msg) {
switch (msg.what) { switch (msg.what) {
case ExoPlayerImplInternal.MSG_PREPARED: { case ExoPlayerImplInternal.MSG_PREPARED: {
TrackInfo[][] trackInfos = (TrackInfo[][]) msg.obj; System.arraycopy(msg.obj, 0, trackFormats, 0, trackFormats.length);
System.arraycopy(trackInfos, 0, this.trackInfos, 0, trackInfos.length);
playbackState = msg.arg1; playbackState = msg.arg1;
for (Listener listener : listeners) { for (Listener listener : listeners) {
listener.onPlayerStateChanged(playWhenReady, playbackState); listener.onPlayerStateChanged(playWhenReady, playbackState);

View File

@ -67,7 +67,7 @@ import java.util.List;
private final Handler eventHandler; private final Handler eventHandler;
private final StandaloneMediaClock standaloneMediaClock; private final StandaloneMediaClock standaloneMediaClock;
private final List<TrackRenderer> enabledRenderers; private final List<TrackRenderer> enabledRenderers;
private final TrackInfo[][] trackInfos; private final MediaFormat[][] trackFormats;
private final int[] selectedTrackIndices; private final int[] selectedTrackIndices;
private final long minBufferUs; private final long minBufferUs;
private final long minRebufferUs; private final long minRebufferUs;
@ -101,7 +101,7 @@ import java.util.List;
standaloneMediaClock = new StandaloneMediaClock(); standaloneMediaClock = new StandaloneMediaClock();
enabledRenderers = new ArrayList<>(selectedTrackIndices.length); enabledRenderers = new ArrayList<>(selectedTrackIndices.length);
trackInfos = new TrackInfo[selectedTrackIndices.length][]; trackFormats = new MediaFormat[selectedTrackIndices.length][];
// Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can // Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
// not normally change to this priority" is incorrect. // not normally change to this priority" is incorrect.
internalPlaybackThread = new PriorityHandlerThread(getClass().getSimpleName() + ":Handler", internalPlaybackThread = new PriorityHandlerThread(getClass().getSimpleName() + ":Handler",
@ -253,7 +253,7 @@ import java.util.List;
private void prepareInternal(TrackRenderer[] renderers) throws ExoPlaybackException { private void prepareInternal(TrackRenderer[] renderers) throws ExoPlaybackException {
resetInternal(); resetInternal();
this.renderers = renderers; this.renderers = renderers;
Arrays.fill(trackInfos, null); Arrays.fill(trackFormats, null);
for (int i = 0; i < renderers.length; i++) { for (int i = 0; i < renderers.length; i++) {
MediaClock mediaClock = renderers[i].getMediaClock(); MediaClock mediaClock = renderers[i].getMediaClock();
if (mediaClock != null) { if (mediaClock != null) {
@ -292,11 +292,11 @@ import java.util.List;
for (int rendererIndex = 0; rendererIndex < renderers.length; rendererIndex++) { for (int rendererIndex = 0; rendererIndex < renderers.length; rendererIndex++) {
TrackRenderer renderer = renderers[rendererIndex]; TrackRenderer renderer = renderers[rendererIndex];
int rendererTrackCount = renderer.getTrackCount(); int rendererTrackCount = renderer.getTrackCount();
TrackInfo[] rendererTrackInfos = new TrackInfo[rendererTrackCount]; MediaFormat[] rendererTrackFormats = new MediaFormat[rendererTrackCount];
for (int trackIndex = 0; trackIndex < rendererTrackCount; trackIndex++) { for (int trackIndex = 0; trackIndex < rendererTrackCount; trackIndex++) {
rendererTrackInfos[trackIndex] = renderer.getTrackInfo(trackIndex); rendererTrackFormats[trackIndex] = renderer.getFormat(trackIndex);
} }
trackInfos[rendererIndex] = rendererTrackInfos; trackFormats[rendererIndex] = rendererTrackFormats;
if (rendererTrackCount > 0) { if (rendererTrackCount > 0) {
if (durationUs == TrackRenderer.UNKNOWN_TIME_US) { if (durationUs == TrackRenderer.UNKNOWN_TIME_US) {
// We've already encountered a track for which the duration is unknown, so the media // We've already encountered a track for which the duration is unknown, so the media
@ -312,7 +312,7 @@ import java.util.List;
} }
} }
int trackIndex = selectedTrackIndices[rendererIndex]; int trackIndex = selectedTrackIndices[rendererIndex];
if (0 <= trackIndex && trackIndex < rendererTrackInfos.length) { if (0 <= trackIndex && trackIndex < rendererTrackFormats.length) {
renderer.enable(trackIndex, positionUs, false); renderer.enable(trackIndex, positionUs, false);
enabledRenderers.add(renderer); enabledRenderers.add(renderer);
allRenderersEnded = allRenderersEnded && renderer.isEnded(); allRenderersEnded = allRenderersEnded && renderer.isEnded();
@ -332,7 +332,7 @@ import java.util.List;
// Fire an event indicating that the player has been prepared, passing the initial state and // Fire an event indicating that the player has been prepared, passing the initial state and
// renderer track information. // renderer track information.
eventHandler.obtainMessage(MSG_PREPARED, state, 0, trackInfos).sendToTarget(); eventHandler.obtainMessage(MSG_PREPARED, state, 0, trackFormats).sendToTarget();
// Start the renderers if required, and schedule the first piece of work. // Start the renderers if required, and schedule the first piece of work.
if (playWhenReady && state == ExoPlayer.STATE_READY) { if (playWhenReady && state == ExoPlayer.STATE_READY) {
@ -610,7 +610,7 @@ import java.util.List;
boolean isEnabled = rendererState == TrackRenderer.STATE_ENABLED boolean isEnabled = rendererState == TrackRenderer.STATE_ENABLED
|| rendererState == TrackRenderer.STATE_STARTED; || rendererState == TrackRenderer.STATE_STARTED;
boolean shouldEnable = 0 <= trackIndex && trackIndex < trackInfos[rendererIndex].length; boolean shouldEnable = 0 <= trackIndex && trackIndex < trackFormats[rendererIndex].length;
if (isEnabled) { if (isEnabled) {
// The renderer is currently enabled. We need to disable it, so that we can either re-enable // The renderer is currently enabled. We need to disable it, so that we can either re-enable

View File

@ -73,7 +73,7 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
private IOException preparationError; private IOException preparationError;
private MediaExtractor extractor; private MediaExtractor extractor;
private TrackInfo[] trackInfos; private MediaFormat[] trackFormats;
private boolean prepared; private boolean prepared;
private int remainingReleaseCount; private int remainingReleaseCount;
private int[] trackStates; private int[] trackStates;
@ -144,13 +144,9 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
trackStates = new int[extractor.getTrackCount()]; trackStates = new int[extractor.getTrackCount()];
pendingDiscontinuities = new boolean[trackStates.length]; pendingDiscontinuities = new boolean[trackStates.length];
trackInfos = new TrackInfo[trackStates.length]; trackFormats = new MediaFormat[trackStates.length];
for (int i = 0; i < trackStates.length; i++) { for (int i = 0; i < trackStates.length; i++) {
android.media.MediaFormat format = extractor.getTrackFormat(i); trackFormats[i] = createMediaFormat(extractor.getTrackFormat(i));
long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION)
? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US;
String mime = format.getString(android.media.MediaFormat.KEY_MIME);
trackInfos[i] = new TrackInfo(mime, durationUs);
} }
prepared = true; prepared = true;
} }
@ -164,9 +160,9 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
} }
@Override @Override
public TrackInfo getTrackInfo(int track) { public MediaFormat getFormat(int track) {
Assertions.checkState(prepared); Assertions.checkState(prepared);
return trackInfos[track]; return trackFormats[track];
} }
@Override @Override
@ -200,7 +196,7 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
return NOTHING_READ; return NOTHING_READ;
} }
if (trackStates[track] != TRACK_STATE_FORMAT_SENT) { if (trackStates[track] != TRACK_STATE_FORMAT_SENT) {
formatHolder.format = createMediaFormat(extractor.getTrackFormat(track)); formatHolder.format = trackFormats[track];
formatHolder.drmInitData = Util.SDK_INT >= 18 ? getDrmInitDataV18() : null; formatHolder.drmInitData = Util.SDK_INT >= 18 ? getDrmInitDataV18() : null;
trackStates[track] = TRACK_STATE_FORMAT_SENT; trackStates[track] = TRACK_STATE_FORMAT_SENT;
return FORMAT_READ; return FORMAT_READ;
@ -319,7 +315,8 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION) long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION)
? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US; ? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US;
return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, MediaFormat.NO_VALUE, return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, MediaFormat.NO_VALUE,
channelCount, sampleRate, language, initializationData); channelCount, sampleRate, language, initializationData, MediaFormat.NO_VALUE,
MediaFormat.NO_VALUE);
} }
@TargetApi(16) @TargetApi(16)

View File

@ -193,8 +193,9 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
} }
@Override @Override
protected boolean handlesTrack(TrackInfo trackInfo) { protected boolean handlesTrack(MediaFormat mediaFormat) {
return MimeTypes.isAudio(trackInfo.mimeType); // TODO: Check the mime type against the available decoders (b/22996976).
return MimeTypes.isAudio(mediaFormat.mimeType);
} }
@Override @Override

View File

@ -256,8 +256,9 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
} }
@Override @Override
protected boolean handlesTrack(TrackInfo trackInfo) { protected boolean handlesTrack(MediaFormat mediaFormat) {
return MimeTypes.isVideo(trackInfo.mimeType); // TODO: Check the mime type against the available decoders (b/22996976).
return MimeTypes.isVideo(mediaFormat.mimeType);
} }
@Override @Override

View File

@ -35,6 +35,11 @@ public final class MediaFormat {
public final String mimeType; public final String mimeType;
public final int maxInputSize; public final int maxInputSize;
/**
* The duration in microseconds, or {@link C#UNKNOWN_TIME_US} if the duration is unknown, or
* {@link C#MATCH_LONGEST_US} if the duration should match the duration of the longest track whose
* duration is known.
*/
public final long durationUs; public final long durationUs;
public final int width; public final int width;
@ -48,8 +53,8 @@ public final class MediaFormat {
public final List<byte[]> initializationData; public final List<byte[]> initializationData;
private int maxWidth; public final int maxWidth;
private int maxHeight; public final int maxHeight;
// Lazy-initialized hashcode. // Lazy-initialized hashcode.
private int hashCode; private int hashCode;
@ -71,7 +76,7 @@ public final class MediaFormat {
public static MediaFormat createVideoFormat(String mimeType, int maxInputSize, long durationUs, public static MediaFormat createVideoFormat(String mimeType, int maxInputSize, long durationUs,
int width, int height, float pixelWidthHeightRatio, List<byte[]> initializationData) { int width, int height, float pixelWidthHeightRatio, List<byte[]> initializationData) {
return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, pixelWidthHeightRatio, return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, pixelWidthHeightRatio,
NO_VALUE, NO_VALUE, null, initializationData); NO_VALUE, NO_VALUE, null, initializationData, NO_VALUE, NO_VALUE);
} }
public static MediaFormat createAudioFormat(String mimeType, int maxInputSize, int channelCount, public static MediaFormat createAudioFormat(String mimeType, int maxInputSize, int channelCount,
@ -83,7 +88,7 @@ public final class MediaFormat {
public static MediaFormat createAudioFormat(String mimeType, int maxInputSize, long durationUs, public static MediaFormat createAudioFormat(String mimeType, int maxInputSize, long durationUs,
int channelCount, int sampleRate, List<byte[]> initializationData) { int channelCount, int sampleRate, List<byte[]> initializationData) {
return new MediaFormat(mimeType, maxInputSize, durationUs, NO_VALUE, NO_VALUE, NO_VALUE, return new MediaFormat(mimeType, maxInputSize, durationUs, NO_VALUE, NO_VALUE, NO_VALUE,
channelCount, sampleRate, null, initializationData); channelCount, sampleRate, null, initializationData, NO_VALUE, NO_VALUE);
} }
public static MediaFormat createTextFormat(String mimeType, String language) { public static MediaFormat createTextFormat(String mimeType, String language) {
@ -92,7 +97,7 @@ public final class MediaFormat {
public static MediaFormat createTextFormat(String mimeType, String language, long durationUs) { public static MediaFormat createTextFormat(String mimeType, String language, long durationUs) {
return new MediaFormat(mimeType, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE, return new MediaFormat(mimeType, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, language, null); NO_VALUE, NO_VALUE, language, null, NO_VALUE, NO_VALUE);
} }
public static MediaFormat createFormatForMimeType(String mimeType) { public static MediaFormat createFormatForMimeType(String mimeType) {
@ -101,12 +106,12 @@ public final class MediaFormat {
public static MediaFormat createFormatForMimeType(String mimeType, long durationUs) { public static MediaFormat createFormatForMimeType(String mimeType, long durationUs) {
return new MediaFormat(mimeType, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE, return new MediaFormat(mimeType, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, null, null); NO_VALUE, NO_VALUE, null, null, NO_VALUE, NO_VALUE);
} }
/* package */ MediaFormat(String mimeType, int maxInputSize, long durationUs, int width, /* package */ MediaFormat(String mimeType, int maxInputSize, long durationUs, int width,
int height, float pixelWidthHeightRatio, int channelCount, int sampleRate, String language, int height, float pixelWidthHeightRatio, int channelCount, int sampleRate, String language,
List<byte[]> initializationData) { List<byte[]> initializationData, int maxWidth, int maxHeight) {
this.mimeType = mimeType; this.mimeType = mimeType;
this.maxInputSize = maxInputSize; this.maxInputSize = maxInputSize;
this.durationUs = durationUs; this.durationUs = durationUs;
@ -118,26 +123,13 @@ public final class MediaFormat {
this.language = language; this.language = language;
this.initializationData = initializationData == null ? Collections.<byte[]>emptyList() this.initializationData = initializationData == null ? Collections.<byte[]>emptyList()
: initializationData; : initializationData;
maxWidth = NO_VALUE;
maxHeight = NO_VALUE;
}
@SuppressLint("InlinedApi")
public void setMaxVideoDimensions(int maxWidth, int maxHeight) {
this.maxWidth = maxWidth; this.maxWidth = maxWidth;
this.maxHeight = maxHeight; this.maxHeight = maxHeight;
if (frameworkMediaFormat != null) {
maybeSetIntegerV16(frameworkMediaFormat, android.media.MediaFormat.KEY_MAX_WIDTH, maxWidth);
maybeSetIntegerV16(frameworkMediaFormat, android.media.MediaFormat.KEY_MAX_HEIGHT, maxHeight);
}
} }
public int getMaxVideoWidth() { public MediaFormat copyWithMaxVideoDimension(int maxWidth, int maxHeight) {
return maxWidth; return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, pixelWidthHeightRatio,
} channelCount, sampleRate, language, initializationData, maxWidth, maxHeight);
public int getMaxVideoHeight() {
return maxHeight;
} }
/** /**

View File

@ -20,9 +20,9 @@ import java.io.IOException;
/** /**
* A source of media samples. * A source of media samples.
* <p> * <p>
* A {@link SampleSource} may expose one or multiple tracks. The number of tracks and information * A {@link SampleSource} may expose one or multiple tracks. The number of tracks and each track's
* about each can be queried using {@link SampleSourceReader#getTrackCount()} and * media format can be queried using {@link SampleSourceReader#getTrackCount()} and
* {@link SampleSourceReader#getTrackInfo(int)} respectively. * {@link SampleSourceReader#getFormat(int)} respectively.
*/ */
public interface SampleSource { public interface SampleSource {
@ -87,13 +87,14 @@ public interface SampleSource {
public int getTrackCount(); public int getTrackCount();
/** /**
* Returns information about the specified track. * Returns the format of the specified track.
* <p> * <p>
* This method should not be called until after the source has been successfully prepared. * This method should not be called until after the source has been successfully prepared.
* *
* @return Information about the specified track. * @param track The track index.
* @return The format of the specified track.
*/ */
public TrackInfo getTrackInfo(int track); public MediaFormat getFormat(int track);
/** /**
* Enable the specified track. This allows the track's format and samples to be read from * Enable the specified track. This allows the track's format and samples to be read from

View File

@ -30,7 +30,6 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
private int enabledSourceTrackIndex; private int enabledSourceTrackIndex;
private int[] handledSourceTrackIndices; private int[] handledSourceTrackIndices;
private TrackInfo[] trackInfos;
/** /**
* @param source The upstream source from which the renderer obtains samples. * @param source The upstream source from which the renderer obtains samples.
@ -48,27 +47,24 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
int handledTrackCount = 0; int handledTrackCount = 0;
int sourceTrackCount = source.getTrackCount(); int sourceTrackCount = source.getTrackCount();
int[] trackIndices = new int[sourceTrackCount]; int[] trackIndices = new int[sourceTrackCount];
TrackInfo[] trackInfos = new TrackInfo[sourceTrackCount];
for (int trackIndex = 0; trackIndex < sourceTrackCount; trackIndex++) { for (int trackIndex = 0; trackIndex < sourceTrackCount; trackIndex++) {
TrackInfo trackInfo = source.getTrackInfo(trackIndex); MediaFormat format = source.getFormat(trackIndex);
if (handlesTrack(trackInfo)) { if (handlesTrack(format)) {
trackIndices[handledTrackCount] = trackIndex; trackIndices[handledTrackCount] = trackIndex;
trackInfos[handledTrackCount] = trackInfo;
handledTrackCount++; handledTrackCount++;
} }
} }
this.handledSourceTrackIndices = Arrays.copyOf(trackIndices, handledTrackCount); this.handledSourceTrackIndices = Arrays.copyOf(trackIndices, handledTrackCount);
this.trackInfos = Arrays.copyOf(trackInfos, handledTrackCount);
return true; return true;
} }
/** /**
* Returns whether this renderer is capable of handling the provided track. * Returns whether this renderer is capable of handling the provided track.
* *
* @param trackInfo The track. * @param mediaFormat The track.
* @return True if the renderer can handle the track, false otherwise. * @return True if the renderer can handle the track, false otherwise.
*/ */
protected abstract boolean handlesTrack(TrackInfo trackInfo); protected abstract boolean handlesTrack(MediaFormat mediaFormat);
@Override @Override
protected void onEnabled(int track, long positionUs, boolean joining) protected void onEnabled(int track, long positionUs, boolean joining)
@ -89,7 +85,7 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
@Override @Override
protected long getDurationUs() { protected long getDurationUs() {
return source.getTrackInfo(enabledSourceTrackIndex).durationUs; return source.getFormat(enabledSourceTrackIndex).durationUs;
} }
@Override @Override
@ -123,12 +119,12 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
@Override @Override
protected final int getTrackCount() { protected final int getTrackCount() {
return trackInfos.length; return handledSourceTrackIndices.length;
} }
@Override @Override
protected final TrackInfo getTrackInfo(int track) { protected final MediaFormat getFormat(int track) {
return trackInfos[track]; return source.getFormat(handledSourceTrackIndices[track]);
} }
} }

View File

@ -20,6 +20,7 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec; import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.upstream.Loader;
import com.google.android.exoplayer.upstream.Loader.Loadable; import com.google.android.exoplayer.upstream.Loader.Loadable;
import com.google.android.exoplayer.util.Assertions;
import android.net.Uri; import android.net.Uri;
import android.os.SystemClock; import android.os.SystemClock;
@ -43,15 +44,18 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
*/ */
private static final int INITIAL_SAMPLE_SIZE = 1; private static final int INITIAL_SAMPLE_SIZE = 1;
private static final int STATE_SEND_FORMAT = 0;
private static final int STATE_SEND_SAMPLE = 1;
private static final int STATE_END_OF_STREAM = 2;
private final Uri uri; private final Uri uri;
private final DataSource dataSource; private final DataSource dataSource;
private final MediaFormat format; private final MediaFormat format;
private final TrackInfo trackInfo;
private final int minLoadableRetryCount; private final int minLoadableRetryCount;
private int state;
private byte[] sampleData; private byte[] sampleData;
private int sampleSize; private int sampleSize;
private boolean pendingSample;
private boolean loadingFinished; private boolean loadingFinished;
private Loader loader; private Loader loader;
@ -69,7 +73,6 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
this.dataSource = dataSource; this.dataSource = dataSource;
this.format = format; this.format = format;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
trackInfo = new TrackInfo(format.mimeType, format.durationUs);
sampleData = new byte[INITIAL_SAMPLE_SIZE]; sampleData = new byte[INITIAL_SAMPLE_SIZE];
} }
@ -92,13 +95,13 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
} }
@Override @Override
public TrackInfo getTrackInfo(int track) { public MediaFormat getFormat(int track) {
return trackInfo; return format;
} }
@Override @Override
public void enable(int track, long positionUs) { public void enable(int track, long positionUs) {
pendingSample = true; state = STATE_SEND_FORMAT;
clearCurrentLoadableException(); clearCurrentLoadableException();
maybeStartLoading(); maybeStartLoading();
} }
@ -121,9 +124,16 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) { SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
if (onlyReadDiscontinuity) { if (onlyReadDiscontinuity) {
return NOTHING_READ; return NOTHING_READ;
} else if (!pendingSample) { } else if (state == STATE_END_OF_STREAM) {
return END_OF_STREAM; return END_OF_STREAM;
} else if (!loadingFinished) { } else if (state == STATE_SEND_FORMAT) {
formatHolder.format = format;
state = STATE_SEND_SAMPLE;
return FORMAT_READ;
}
Assertions.checkState(state == STATE_SEND_SAMPLE);
if (!loadingFinished) {
return NOTHING_READ; return NOTHING_READ;
} else { } else {
sampleHolder.timeUs = 0; sampleHolder.timeUs = 0;
@ -133,13 +143,16 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
sampleHolder.replaceBuffer(sampleHolder.size); sampleHolder.replaceBuffer(sampleHolder.size);
} }
sampleHolder.data.put(sampleData, 0, sampleSize); sampleHolder.data.put(sampleData, 0, sampleSize);
state = STATE_END_OF_STREAM;
return SAMPLE_READ; return SAMPLE_READ;
} }
} }
@Override @Override
public void seekToUs(long positionUs) { public void seekToUs(long positionUs) {
pendingSample = true; if (state == STATE_END_OF_STREAM) {
state = STATE_SEND_SAMPLE;
}
} }
@Override @Override
@ -149,7 +162,7 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
@Override @Override
public void disable(int track) { public void disable(int track) {
pendingSample = false; state = STATE_END_OF_STREAM;
} }
@Override @Override
@ -163,7 +176,7 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
// Private methods. // Private methods.
private void maybeStartLoading() { private void maybeStartLoading() {
if (loadingFinished || !pendingSample || loader.isLoading()) { if (loadingFinished || state != STATE_END_OF_STREAM || loader.isLoading()) {
return; return;
} }
if (currentLoadableException != null) { if (currentLoadableException != null) {

View File

@ -1,46 +0,0 @@
/*
* 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;
/**
* Holds high level information about a media track.
*/
public final class TrackInfo {
/**
* The mime type.
*/
public final String mimeType;
/**
* The duration in microseconds, or {@link C#UNKNOWN_TIME_US} if the duration is unknown, or
* {@link C#MATCH_LONGEST_US} if the duration should match the duration of the longest track whose
* duration is known.
*/
public final long durationUs;
/**
* @param mimeType The mime type.
* @param durationUs The duration in microseconds, or {@link C#UNKNOWN_TIME_US} if the duration
* is unknown, or {@link C#MATCH_LONGEST_US} if the duration should match the duration of the
* longest track whose duration is known.
*/
public TrackInfo(String mimeType, long durationUs) {
this.mimeType = mimeType;
this.durationUs = durationUs;
}
}

View File

@ -138,17 +138,17 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
} }
/** /**
* Returns information about the specified track. * Returns the format of the specified track.
* <p> * <p>
* This method may be called when the renderer is in the following states: * This method may be called when the renderer is in the following states:
* {@link #STATE_PREPARED}, {@link #STATE_ENABLED}, {@link #STATE_STARTED} * {@link #STATE_PREPARED}, {@link #STATE_ENABLED}, {@link #STATE_STARTED}
* *
* @param track The track index. * @param track The track index.
* @return Information about the specified track. * @return The format of the specified track.
*/ */
// TODO: This method should be abstract. This implementation is provided as an interim step only. // TODO: This method should be abstract. This implementation is provided as an interim step only.
protected TrackInfo getTrackInfo(int track) { protected MediaFormat getFormat(int track) {
return new TrackInfo("application/octet-stream", getDurationUs()); return MediaFormat.createFormatForMimeType("application/octet-stream", getDurationUs());
} }
/** /**

View File

@ -22,7 +22,6 @@ import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleHolder; import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSource.SampleSourceReader; import com.google.android.exoplayer.SampleSource.SampleSourceReader;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.extractor.DefaultTrackOutput; import com.google.android.exoplayer.extractor.DefaultTrackOutput;
import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.upstream.Loader;
@ -132,7 +131,7 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
if (state == STATE_PREPARED) { if (state == STATE_PREPARED) {
return true; return true;
} }
loader = new Loader("Loader:" + chunkSource.getTrackInfo().mimeType); loader = new Loader("Loader:" + chunkSource.getFormat().mimeType);
state = STATE_PREPARED; state = STATE_PREPARED;
return true; return true;
} }
@ -144,10 +143,10 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
} }
@Override @Override
public TrackInfo getTrackInfo(int track) { public MediaFormat getFormat(int track) {
Assertions.checkState(state == STATE_PREPARED || state == STATE_ENABLED); Assertions.checkState(state == STATE_PREPARED || state == STATE_ENABLED);
Assertions.checkState(track == 0); Assertions.checkState(track == 0);
return chunkSource.getTrackInfo(); return chunkSource.getFormat();
} }
@Override @Override
@ -232,7 +231,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, true)) {
chunkSource.getMaxVideoDimensions(mediaFormat); mediaFormat = chunkSource.getWithMaxVideoDimensions(mediaFormat);
formatHolder.format = mediaFormat; formatHolder.format = mediaFormat;
formatHolder.drmInitData = currentChunk.getDrmInitData(); formatHolder.drmInitData = currentChunk.getDrmInitData();
downstreamMediaFormat = mediaFormat; downstreamMediaFormat = mediaFormat;

View File

@ -16,7 +16,6 @@
package com.google.android.exoplayer.chunk; package com.google.android.exoplayer.chunk;
import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.TrackInfo;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -32,23 +31,24 @@ import java.util.List;
public interface ChunkSource { public interface ChunkSource {
/** /**
* Gets information about the track for which this instance provides {@link Chunk}s. * Gets the format.
* <p> * <p>
* May be called when the source is disabled or enabled. * May be called when the source is disabled or enabled.
* *
* @return Information about the track. * @return The format.
*/ */
TrackInfo getTrackInfo(); MediaFormat getFormat();
/** /**
* Adaptive video {@link ChunkSource} implementations must set the maximum video dimensions on * Adaptive video {@link ChunkSource} implementations must return a copy of the provided
* the supplied {@link MediaFormat}. Other implementations do nothing. * {@link MediaFormat} with the maximum video dimensions set. Other implementations can return
* <p> * the provided {@link MediaFormat} directly.
* Only called when the source is enabled.
* *
* @param out The {@link MediaFormat} on which the maximum video dimensions should be set. * @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.
*/ */
void getMaxVideoDimensions(MediaFormat out); MediaFormat getWithMaxVideoDimensions(MediaFormat format);
/** /**
* Called when the source is enabled. * Called when the source is enabled.

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer.chunk;
import com.google.android.exoplayer.ExoPlaybackException; import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.ExoPlayer.ExoPlayerComponent; import com.google.android.exoplayer.ExoPlayer.ExoPlayerComponent;
import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import java.io.IOException; import java.io.IOException;
@ -61,8 +60,8 @@ public final class MultiTrackChunkSource implements ChunkSource, ExoPlayerCompon
} }
@Override @Override
public TrackInfo getTrackInfo() { public MediaFormat getFormat() {
return selectedSource.getTrackInfo(); return selectedSource.getFormat();
} }
@Override @Override
@ -94,8 +93,8 @@ public final class MultiTrackChunkSource implements ChunkSource, ExoPlayerCompon
} }
@Override @Override
public void getMaxVideoDimensions(MediaFormat out) { public MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
selectedSource.getMaxVideoDimensions(out); return selectedSource.getWithMaxVideoDimensions(format);
} }
@Override @Override

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer.chunk;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec; import com.google.android.exoplayer.upstream.DataSpec;
@ -36,7 +35,6 @@ public final class SingleSampleChunkSource implements ChunkSource {
private final Format format; private final Format format;
private final long durationUs; private final long durationUs;
private final MediaFormat mediaFormat; private final MediaFormat mediaFormat;
private final TrackInfo trackInfo;
/** /**
* @param dataSource A {@link DataSource} suitable for loading the sample data. * @param dataSource A {@link DataSource} suitable for loading the sample data.
@ -54,17 +52,16 @@ public final class SingleSampleChunkSource implements ChunkSource {
this.format = format; this.format = format;
this.durationUs = durationUs; this.durationUs = durationUs;
this.mediaFormat = mediaFormat; this.mediaFormat = mediaFormat;
trackInfo = new TrackInfo(format.mimeType, durationUs);
} }
@Override @Override
public TrackInfo getTrackInfo() { public MediaFormat getFormat() {
return trackInfo; return mediaFormat;
} }
@Override @Override
public void getMaxVideoDimensions(MediaFormat out) { public MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
// Do nothing. return format;
} }
@Override @Override

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer.dash;
import com.google.android.exoplayer.BehindLiveWindowException; import com.google.android.exoplayer.BehindLiveWindowException;
import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.TimeRange; import com.google.android.exoplayer.TimeRange;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.chunk.Chunk; import com.google.android.exoplayer.chunk.Chunk;
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper; import com.google.android.exoplayer.chunk.ChunkExtractorWrapper;
@ -98,7 +97,7 @@ public class DashChunkSource implements ChunkSource {
private final Handler eventHandler; private final Handler eventHandler;
private final EventListener eventListener; private final EventListener eventListener;
private final TrackInfo trackInfo; private final MediaFormat mediaFormat;
private final DataSource dataSource; private final DataSource dataSource;
private final FormatEvaluator formatEvaluator; private final FormatEvaluator formatEvaluator;
private final Evaluation evaluation; private final Evaluation evaluation;
@ -263,7 +262,9 @@ public class DashChunkSource implements ChunkSource {
adaptationSetIndex, representationIndices); adaptationSetIndex, representationIndices);
long periodDurationUs = (representations[0].periodDurationMs == TrackRenderer.UNKNOWN_TIME_US) long periodDurationUs = (representations[0].periodDurationMs == TrackRenderer.UNKNOWN_TIME_US)
? TrackRenderer.UNKNOWN_TIME_US : representations[0].periodDurationMs * 1000; ? TrackRenderer.UNKNOWN_TIME_US : representations[0].periodDurationMs * 1000;
this.trackInfo = new TrackInfo(representations[0].format.mimeType, periodDurationUs); // TODO: Remove this and pass proper formats instead (b/22996976).
this.mediaFormat = MediaFormat.createFormatForMimeType(representations[0].format.mimeType,
periodDurationUs);
this.formats = new Format[representations.length]; this.formats = new Format[representations.length];
this.representationHolders = new HashMap<>(); this.representationHolders = new HashMap<>();
@ -284,15 +285,14 @@ public class DashChunkSource implements ChunkSource {
} }
@Override @Override
public final void getMaxVideoDimensions(MediaFormat out) { public final MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
if (trackInfo.mimeType.startsWith("video")) { return MimeTypes.isVideo(mediaFormat.mimeType)
out.setMaxVideoDimensions(maxWidth, maxHeight); ? format.copyWithMaxVideoDimension(maxWidth, maxHeight) : format;
}
} }
@Override @Override
public final TrackInfo getTrackInfo() { public final MediaFormat getFormat() {
return trackInfo; return mediaFormat;
} }
// VisibleForTesting // VisibleForTesting

View File

@ -22,7 +22,6 @@ import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleHolder; import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSource.SampleSourceReader; import com.google.android.exoplayer.SampleSource.SampleSourceReader;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.drm.DrmInitData; import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.upstream.Allocator; import com.google.android.exoplayer.upstream.Allocator;
@ -163,7 +162,7 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
private boolean prepared; private boolean prepared;
private int enabledTrackCount; private int enabledTrackCount;
private TrackInfo[] trackInfos; private MediaFormat[] mediaFormats;
private long maxTrackDurationUs; private long maxTrackDurationUs;
private boolean[] pendingMediaFormat; private boolean[] pendingMediaFormat;
private boolean[] pendingDiscontinuities; private boolean[] pendingDiscontinuities;
@ -292,11 +291,11 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
trackEnabledStates = new boolean[trackCount]; trackEnabledStates = new boolean[trackCount];
pendingDiscontinuities = new boolean[trackCount]; pendingDiscontinuities = new boolean[trackCount];
pendingMediaFormat = new boolean[trackCount]; pendingMediaFormat = new boolean[trackCount];
trackInfos = new TrackInfo[trackCount]; mediaFormats = new MediaFormat[trackCount];
maxTrackDurationUs = C.UNKNOWN_TIME_US; maxTrackDurationUs = C.UNKNOWN_TIME_US;
for (int i = 0; i < trackCount; i++) { for (int i = 0; i < trackCount; i++) {
MediaFormat format = sampleQueues.valueAt(i).getFormat(); MediaFormat format = sampleQueues.valueAt(i).getFormat();
trackInfos[i] = new TrackInfo(format.mimeType, format.durationUs); mediaFormats[i] = format;
if (format.durationUs != C.UNKNOWN_TIME_US && format.durationUs > maxTrackDurationUs) { if (format.durationUs != C.UNKNOWN_TIME_US && format.durationUs > maxTrackDurationUs) {
maxTrackDurationUs = format.durationUs; maxTrackDurationUs = format.durationUs;
} }
@ -314,9 +313,9 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
} }
@Override @Override
public TrackInfo getTrackInfo(int track) { public MediaFormat getFormat(int track) {
Assertions.checkState(prepared); Assertions.checkState(prepared);
return trackInfos[track]; return mediaFormats[track];
} }
@Override @Override

View File

@ -224,19 +224,17 @@ public class HlsChunkSource {
} }
/** /**
* Adaptive implementations must set the maximum video dimensions on the supplied * Adaptive implementations must return a copy of the provided {@link MediaFormat} with the
* {@link MediaFormat}. Other implementations do nothing. * maximum video dimensions set. Other implementations can return the provided {@link MediaFormat}
* <p> * directly.
* Only called when the source is enabled.
* *
* @param out The {@link MediaFormat} on which the maximum video dimensions should be set. * @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 void getMaxVideoDimensions(MediaFormat out) { public MediaFormat getMaxVideoDimensions(MediaFormat format) {
if (maxWidth == -1 || maxHeight == -1) { return (maxWidth == -1 || maxHeight == -1) ? format
// Not adaptive. : format.copyWithMaxVideoDimension(maxWidth, maxHeight);
return;
}
out.setMaxVideoDimensions(maxWidth, maxHeight);
} }
/** /**

View File

@ -22,7 +22,6 @@ import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleHolder; import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSource.SampleSourceReader; import com.google.android.exoplayer.SampleSource.SampleSourceReader;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener; import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener;
import com.google.android.exoplayer.chunk.Chunk; import com.google.android.exoplayer.chunk.Chunk;
@ -71,7 +70,7 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
private int enabledTrackCount; private int enabledTrackCount;
private boolean[] trackEnabledStates; private boolean[] trackEnabledStates;
private boolean[] pendingDiscontinuities; private boolean[] pendingDiscontinuities;
private TrackInfo[] trackInfos; private MediaFormat[] mediaFormats;
private MediaFormat[] downstreamMediaFormats; private MediaFormat[] downstreamMediaFormats;
private Format downstreamFormat; private Format downstreamFormat;
@ -135,10 +134,9 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
trackEnabledStates = new boolean[trackCount]; trackEnabledStates = new boolean[trackCount];
pendingDiscontinuities = new boolean[trackCount]; pendingDiscontinuities = new boolean[trackCount];
downstreamMediaFormats = new MediaFormat[trackCount]; downstreamMediaFormats = new MediaFormat[trackCount];
trackInfos = new TrackInfo[trackCount]; mediaFormats = new MediaFormat[trackCount];
for (int i = 0; i < trackCount; i++) { for (int i = 0; i < trackCount; i++) {
MediaFormat format = extractor.getMediaFormat(i); mediaFormats[i] = extractor.getMediaFormat(i);
trackInfos[i] = new TrackInfo(format.mimeType, chunkSource.getDurationUs());
} }
prepared = true; prepared = true;
return true; return true;
@ -170,9 +168,9 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
} }
@Override @Override
public TrackInfo getTrackInfo(int track) { public MediaFormat getFormat(int track) {
Assertions.checkState(prepared); Assertions.checkState(prepared);
return trackInfos[track]; return mediaFormats[track];
} }
@Override @Override

View File

@ -16,11 +16,11 @@
package com.google.android.exoplayer.metadata; package com.google.android.exoplayer.metadata;
import com.google.android.exoplayer.ExoPlaybackException; import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder; import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleHolder; import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceTrackRenderer; import com.google.android.exoplayer.SampleSourceTrackRenderer;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
@ -88,8 +88,8 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
} }
@Override @Override
protected boolean handlesTrack(TrackInfo trackInfo) { protected boolean handlesTrack(MediaFormat mediaFormat) {
return metadataParser.canParse(trackInfo.mimeType); return metadataParser.canParse(mediaFormat.mimeType);
} }
@Override @Override

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer.smoothstreaming;
import com.google.android.exoplayer.BehindLiveWindowException; import com.google.android.exoplayer.BehindLiveWindowException;
import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.chunk.Chunk; import com.google.android.exoplayer.chunk.Chunk;
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper; import com.google.android.exoplayer.chunk.ChunkExtractorWrapper;
import com.google.android.exoplayer.chunk.ChunkOperationHolder; import com.google.android.exoplayer.chunk.ChunkOperationHolder;
@ -59,7 +58,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
private static final int MINIMUM_MANIFEST_REFRESH_PERIOD_MS = 5000; private static final int MINIMUM_MANIFEST_REFRESH_PERIOD_MS = 5000;
private static final int INITIALIZATION_VECTOR_SIZE = 8; private static final int INITIALIZATION_VECTOR_SIZE = 8;
private final TrackInfo trackInfo; private final MediaFormat mediaFormat;
private final DataSource dataSource; private final DataSource dataSource;
private final FormatEvaluator formatEvaluator; private final FormatEvaluator formatEvaluator;
private final Evaluation evaluation; private final Evaluation evaluation;
@ -135,7 +134,9 @@ public class SmoothStreamingChunkSource implements ChunkSource {
this.liveEdgeLatencyUs = liveEdgeLatencyMs * 1000; this.liveEdgeLatencyUs = liveEdgeLatencyMs * 1000;
StreamElement streamElement = getElement(initialManifest); StreamElement streamElement = getElement(initialManifest);
trackInfo = new TrackInfo(streamElement.tracks[0].format.mimeType, initialManifest.durationUs); // TODO: Remove this and pass proper formats instead (b/22996976).
mediaFormat = MediaFormat.createFormatForMimeType(streamElement.tracks[0].format.mimeType,
initialManifest.durationUs);
evaluation = new Evaluation(); evaluation = new Evaluation();
TrackEncryptionBox[] trackEncryptionBoxes = null; TrackEncryptionBox[] trackEncryptionBoxes = null;
@ -180,15 +181,14 @@ public class SmoothStreamingChunkSource implements ChunkSource {
} }
@Override @Override
public final void getMaxVideoDimensions(MediaFormat out) { public final MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
if (trackInfo.mimeType.startsWith("video")) { return MimeTypes.isVideo(mediaFormat.mimeType)
out.setMaxVideoDimensions(maxWidth, maxHeight); ? format.copyWithMaxVideoDimension(maxWidth, maxHeight) : format;
}
} }
@Override @Override
public final TrackInfo getTrackInfo() { public final MediaFormat getFormat() {
return trackInfo; return mediaFormat;
} }
@Override @Override
@ -384,7 +384,6 @@ public class SmoothStreamingChunkSource implements ChunkSource {
if (streamElement.type == StreamElement.TYPE_VIDEO) { if (streamElement.type == StreamElement.TYPE_VIDEO) {
MediaFormat format = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, MediaFormat format = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE,
trackFormat.width, trackFormat.height, Arrays.asList(trackElement.csd)); trackFormat.width, trackFormat.height, Arrays.asList(trackElement.csd));
format.setMaxVideoDimensions(streamElement.maxWidth, streamElement.maxHeight);
return format; return format;
} else if (streamElement.type == StreamElement.TYPE_AUDIO) { } else if (streamElement.type == StreamElement.TYPE_AUDIO) {
List<byte[]> csd; List<byte[]> csd;

View File

@ -16,11 +16,11 @@
package com.google.android.exoplayer.text; package com.google.android.exoplayer.text;
import com.google.android.exoplayer.ExoPlaybackException; import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder; import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleHolder; import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceTrackRenderer; import com.google.android.exoplayer.SampleSourceTrackRenderer;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
@ -150,15 +150,15 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
} }
@Override @Override
protected boolean handlesTrack(TrackInfo trackInfo) { protected boolean handlesTrack(MediaFormat mediaFormat) {
return getParserIndex(trackInfo) != -1; return getParserIndex(mediaFormat) != -1;
} }
@Override @Override
protected void onEnabled(int track, long positionUs, boolean joining) protected void onEnabled(int track, long positionUs, boolean joining)
throws ExoPlaybackException { throws ExoPlaybackException {
super.onEnabled(track, positionUs, joining); super.onEnabled(track, positionUs, joining);
parserIndex = getParserIndex(getTrackInfo(track)); parserIndex = getParserIndex(getFormat(track));
parserThread = new HandlerThread("textParser"); parserThread = new HandlerThread("textParser");
parserThread.start(); parserThread.start();
parserHelper = new SubtitleParserHelper(parserThread.getLooper(), subtitleParsers[parserIndex]); parserHelper = new SubtitleParserHelper(parserThread.getLooper(), subtitleParsers[parserIndex]);
@ -296,9 +296,9 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
textRenderer.onCues(cues); textRenderer.onCues(cues);
} }
private int getParserIndex(TrackInfo trackInfo) { private int getParserIndex(MediaFormat mediaFormat) {
for (int i = 0; i < subtitleParsers.length; i++) { for (int i = 0; i < subtitleParsers.length; i++) {
if (subtitleParsers[i].canParse(trackInfo.mimeType)) { if (subtitleParsers[i].canParse(mediaFormat.mimeType)) {
return i; return i;
} }
} }

View File

@ -17,11 +17,11 @@ package com.google.android.exoplayer.text.eia608;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.ExoPlaybackException; import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder; import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleHolder; import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SampleSourceTrackRenderer; import com.google.android.exoplayer.SampleSourceTrackRenderer;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.text.Cue; import com.google.android.exoplayer.text.Cue;
import com.google.android.exoplayer.text.TextRenderer; import com.google.android.exoplayer.text.TextRenderer;
@ -89,8 +89,8 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
} }
@Override @Override
protected boolean handlesTrack(TrackInfo trackInfo) { protected boolean handlesTrack(MediaFormat mediaFormat) {
return eia608Parser.canParse(trackInfo.mimeType); return eia608Parser.canParse(mediaFormat.mimeType);
} }
@Override @Override