parent
f7ffeb75cf
commit
8db1331021
@ -22,7 +22,6 @@ import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.audio.AudioTrack;
|
||||
import com.google.android.exoplayer.ext.opus.OpusDecoderWrapper.InputBuffer;
|
||||
@ -125,9 +124,10 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return MimeTypes.AUDIO_OPUS.equalsIgnoreCase(trackInfo.mimeType)
|
||||
|| MimeTypes.AUDIO_WEBM.equalsIgnoreCase(trackInfo.mimeType);
|
||||
protected boolean handlesTrack(MediaFormat mediaFormat) {
|
||||
// TODO: Stop claiming to handle the WebM mime type (b/22996976).
|
||||
return MimeTypes.AUDIO_OPUS.equalsIgnoreCase(mediaFormat.mimeType)
|
||||
|| MimeTypes.AUDIO_WEBM.equalsIgnoreCase(mediaFormat.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,7 +21,6 @@ import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.ext.vp9.VpxDecoderWrapper.InputBuffer;
|
||||
import com.google.android.exoplayer.ext.vp9.VpxDecoderWrapper.OutputBuffer;
|
||||
@ -149,9 +148,10 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return MimeTypes.VIDEO_VP9.equalsIgnoreCase(trackInfo.mimeType)
|
||||
|| MimeTypes.VIDEO_WEBM.equalsIgnoreCase(trackInfo.mimeType);
|
||||
protected boolean handlesTrack(MediaFormat mediaFormat) {
|
||||
// TODO: Stop claiming to handle the WebM mime type (b/22996976).
|
||||
return MimeTypes.VIDEO_VP9.equalsIgnoreCase(mediaFormat.mimeType)
|
||||
|| MimeTypes.VIDEO_WEBM.equalsIgnoreCase(mediaFormat.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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_CHANNEL_COUNT, in.channelCount);
|
||||
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_HEIGHT, in.getMaxVideoHeight());
|
||||
assertOptionalV16(out, android.media.MediaFormat.KEY_MAX_WIDTH, in.maxWidth);
|
||||
assertOptionalV16(out, android.media.MediaFormat.KEY_MAX_HEIGHT, in.maxHeight);
|
||||
for (int i = 0; i < in.initializationData.size(); i++) {
|
||||
byte[] originalData = in.initializationData.get(i);
|
||||
ByteBuffer frameworkBuffer = out.getByteBuffer("csd-" + i);
|
||||
|
@ -91,11 +91,11 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
|
||||
public void testMaxVideoDimensions() {
|
||||
DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO,
|
||||
null, null, null);
|
||||
MediaFormat out = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null);
|
||||
chunkSource.getMaxVideoDimensions(out);
|
||||
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null);
|
||||
format = chunkSource.getWithMaxVideoDimensions(format);
|
||||
|
||||
assertEquals(WIDE_WIDTH, out.getMaxVideoWidth());
|
||||
assertEquals(TALL_HEIGHT, out.getMaxVideoHeight());
|
||||
assertEquals(WIDE_WIDTH, format.maxWidth);
|
||||
assertEquals(TALL_HEIGHT, format.maxHeight);
|
||||
}
|
||||
|
||||
public void testGetSeekRangeOnVod() {
|
||||
@ -121,11 +121,11 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
|
||||
Representation.newInstance(0, 0, null, 0, WIDE_VIDEO, segmentBase2);
|
||||
|
||||
DashChunkSource chunkSource = new DashChunkSource(null, null, representation1, representation2);
|
||||
MediaFormat out = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null);
|
||||
chunkSource.getMaxVideoDimensions(out);
|
||||
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null);
|
||||
format = chunkSource.getWithMaxVideoDimensions(format);
|
||||
|
||||
assertEquals(WIDE_WIDTH, out.getMaxVideoWidth());
|
||||
assertEquals(TALL_HEIGHT, out.getMaxVideoHeight());
|
||||
assertEquals(WIDE_WIDTH, format.maxWidth);
|
||||
assertEquals(TALL_HEIGHT, format.maxHeight);
|
||||
}
|
||||
|
||||
public void testLiveEdgeNoLatency() {
|
||||
|
@ -35,7 +35,7 @@ public final class DummyTrackRenderer extends TrackRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TrackInfo getTrackInfo(int track) {
|
||||
protected MediaFormat getFormat(int track) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
private final Handler eventHandler;
|
||||
private final ExoPlayerImplInternal internalPlayer;
|
||||
private final CopyOnWriteArraySet<Listener> listeners;
|
||||
private final TrackInfo[][] trackInfos;
|
||||
private final MediaFormat[][] trackFormats;
|
||||
private final int[] selectedTrackIndices;
|
||||
|
||||
private boolean playWhenReady;
|
||||
@ -58,7 +58,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
this.playWhenReady = false;
|
||||
this.playbackState = STATE_IDLE;
|
||||
this.listeners = new CopyOnWriteArraySet<>();
|
||||
this.trackInfos = new TrackInfo[rendererCount][];
|
||||
this.trackFormats = new MediaFormat[rendererCount][];
|
||||
this.selectedTrackIndices = new int[rendererCount];
|
||||
eventHandler = new Handler() {
|
||||
@Override
|
||||
@ -92,7 +92,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
@Override
|
||||
public void prepare(TrackRenderer... renderers) {
|
||||
Arrays.fill(trackInfos, null);
|
||||
Arrays.fill(trackFormats, null);
|
||||
internalPlayer.prepare(renderers);
|
||||
}
|
||||
|
||||
@ -116,12 +116,12 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
// TODO: Expose in ExoPlayer.
|
||||
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.
|
||||
public TrackInfo getRendererTrackInfo(int rendererIndex, int trackIndex) {
|
||||
return trackInfos[rendererIndex][trackIndex];
|
||||
public MediaFormat getRendererTrackInfo(int rendererIndex, int trackIndex) {
|
||||
return trackFormats[rendererIndex][trackIndex];
|
||||
}
|
||||
|
||||
// TODO: Expose in ExoPlayer.
|
||||
@ -212,8 +212,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
/* package */ void handleEvent(Message msg) {
|
||||
switch (msg.what) {
|
||||
case ExoPlayerImplInternal.MSG_PREPARED: {
|
||||
TrackInfo[][] trackInfos = (TrackInfo[][]) msg.obj;
|
||||
System.arraycopy(trackInfos, 0, this.trackInfos, 0, trackInfos.length);
|
||||
System.arraycopy(msg.obj, 0, trackFormats, 0, trackFormats.length);
|
||||
playbackState = msg.arg1;
|
||||
for (Listener listener : listeners) {
|
||||
listener.onPlayerStateChanged(playWhenReady, playbackState);
|
||||
|
@ -67,7 +67,7 @@ import java.util.List;
|
||||
private final Handler eventHandler;
|
||||
private final StandaloneMediaClock standaloneMediaClock;
|
||||
private final List<TrackRenderer> enabledRenderers;
|
||||
private final TrackInfo[][] trackInfos;
|
||||
private final MediaFormat[][] trackFormats;
|
||||
private final int[] selectedTrackIndices;
|
||||
private final long minBufferUs;
|
||||
private final long minRebufferUs;
|
||||
@ -101,7 +101,7 @@ import java.util.List;
|
||||
|
||||
standaloneMediaClock = new StandaloneMediaClock();
|
||||
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
|
||||
// not normally change to this priority" is incorrect.
|
||||
internalPlaybackThread = new PriorityHandlerThread(getClass().getSimpleName() + ":Handler",
|
||||
@ -253,7 +253,7 @@ import java.util.List;
|
||||
private void prepareInternal(TrackRenderer[] renderers) throws ExoPlaybackException {
|
||||
resetInternal();
|
||||
this.renderers = renderers;
|
||||
Arrays.fill(trackInfos, null);
|
||||
Arrays.fill(trackFormats, null);
|
||||
for (int i = 0; i < renderers.length; i++) {
|
||||
MediaClock mediaClock = renderers[i].getMediaClock();
|
||||
if (mediaClock != null) {
|
||||
@ -292,11 +292,11 @@ import java.util.List;
|
||||
for (int rendererIndex = 0; rendererIndex < renderers.length; rendererIndex++) {
|
||||
TrackRenderer renderer = renderers[rendererIndex];
|
||||
int rendererTrackCount = renderer.getTrackCount();
|
||||
TrackInfo[] rendererTrackInfos = new TrackInfo[rendererTrackCount];
|
||||
MediaFormat[] rendererTrackFormats = new MediaFormat[rendererTrackCount];
|
||||
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 (durationUs == TrackRenderer.UNKNOWN_TIME_US) {
|
||||
// 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];
|
||||
if (0 <= trackIndex && trackIndex < rendererTrackInfos.length) {
|
||||
if (0 <= trackIndex && trackIndex < rendererTrackFormats.length) {
|
||||
renderer.enable(trackIndex, positionUs, false);
|
||||
enabledRenderers.add(renderer);
|
||||
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
|
||||
// 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.
|
||||
if (playWhenReady && state == ExoPlayer.STATE_READY) {
|
||||
@ -610,7 +610,7 @@ import java.util.List;
|
||||
|
||||
boolean isEnabled = rendererState == TrackRenderer.STATE_ENABLED
|
||||
|| rendererState == TrackRenderer.STATE_STARTED;
|
||||
boolean shouldEnable = 0 <= trackIndex && trackIndex < trackInfos[rendererIndex].length;
|
||||
boolean shouldEnable = 0 <= trackIndex && trackIndex < trackFormats[rendererIndex].length;
|
||||
|
||||
if (isEnabled) {
|
||||
// The renderer is currently enabled. We need to disable it, so that we can either re-enable
|
||||
|
@ -73,7 +73,7 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
||||
|
||||
private IOException preparationError;
|
||||
private MediaExtractor extractor;
|
||||
private TrackInfo[] trackInfos;
|
||||
private MediaFormat[] trackFormats;
|
||||
private boolean prepared;
|
||||
private int remainingReleaseCount;
|
||||
private int[] trackStates;
|
||||
@ -144,13 +144,9 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
||||
|
||||
trackStates = new int[extractor.getTrackCount()];
|
||||
pendingDiscontinuities = new boolean[trackStates.length];
|
||||
trackInfos = new TrackInfo[trackStates.length];
|
||||
trackFormats = new MediaFormat[trackStates.length];
|
||||
for (int i = 0; i < trackStates.length; i++) {
|
||||
android.media.MediaFormat format = 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);
|
||||
trackFormats[i] = createMediaFormat(extractor.getTrackFormat(i));
|
||||
}
|
||||
prepared = true;
|
||||
}
|
||||
@ -164,9 +160,9 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackInfo getTrackInfo(int track) {
|
||||
public MediaFormat getFormat(int track) {
|
||||
Assertions.checkState(prepared);
|
||||
return trackInfos[track];
|
||||
return trackFormats[track];
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -200,7 +196,7 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
||||
return NOTHING_READ;
|
||||
}
|
||||
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;
|
||||
trackStates[track] = TRACK_STATE_FORMAT_SENT;
|
||||
return FORMAT_READ;
|
||||
@ -319,7 +315,8 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
||||
long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION)
|
||||
? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US;
|
||||
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)
|
||||
|
@ -193,8 +193,9 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return MimeTypes.isAudio(trackInfo.mimeType);
|
||||
protected boolean handlesTrack(MediaFormat mediaFormat) {
|
||||
// TODO: Check the mime type against the available decoders (b/22996976).
|
||||
return MimeTypes.isAudio(mediaFormat.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -256,8 +256,9 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return MimeTypes.isVideo(trackInfo.mimeType);
|
||||
protected boolean handlesTrack(MediaFormat mediaFormat) {
|
||||
// TODO: Check the mime type against the available decoders (b/22996976).
|
||||
return MimeTypes.isVideo(mediaFormat.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,6 +35,11 @@ public final class MediaFormat {
|
||||
public final String mimeType;
|
||||
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 int width;
|
||||
@ -48,8 +53,8 @@ public final class MediaFormat {
|
||||
|
||||
public final List<byte[]> initializationData;
|
||||
|
||||
private int maxWidth;
|
||||
private int maxHeight;
|
||||
public final int maxWidth;
|
||||
public final int maxHeight;
|
||||
|
||||
// Lazy-initialized hashcode.
|
||||
private int hashCode;
|
||||
@ -71,7 +76,7 @@ public final class MediaFormat {
|
||||
public static MediaFormat createVideoFormat(String mimeType, int maxInputSize, long durationUs,
|
||||
int width, int height, float pixelWidthHeightRatio, List<byte[]> initializationData) {
|
||||
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,
|
||||
@ -83,7 +88,7 @@ public final class MediaFormat {
|
||||
public static MediaFormat createAudioFormat(String mimeType, int maxInputSize, long durationUs,
|
||||
int channelCount, int sampleRate, List<byte[]> initializationData) {
|
||||
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) {
|
||||
@ -92,7 +97,7 @@ public final class MediaFormat {
|
||||
|
||||
public static MediaFormat createTextFormat(String mimeType, String language, long durationUs) {
|
||||
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) {
|
||||
@ -101,12 +106,12 @@ public final class MediaFormat {
|
||||
|
||||
public static MediaFormat createFormatForMimeType(String mimeType, long durationUs) {
|
||||
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,
|
||||
int height, float pixelWidthHeightRatio, int channelCount, int sampleRate, String language,
|
||||
List<byte[]> initializationData) {
|
||||
List<byte[]> initializationData, int maxWidth, int maxHeight) {
|
||||
this.mimeType = mimeType;
|
||||
this.maxInputSize = maxInputSize;
|
||||
this.durationUs = durationUs;
|
||||
@ -118,26 +123,13 @@ public final class MediaFormat {
|
||||
this.language = language;
|
||||
this.initializationData = initializationData == null ? Collections.<byte[]>emptyList()
|
||||
: initializationData;
|
||||
maxWidth = NO_VALUE;
|
||||
maxHeight = NO_VALUE;
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
public void setMaxVideoDimensions(int maxWidth, int maxHeight) {
|
||||
this.maxWidth = maxWidth;
|
||||
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() {
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
public int getMaxVideoHeight() {
|
||||
return maxHeight;
|
||||
public MediaFormat copyWithMaxVideoDimension(int maxWidth, int maxHeight) {
|
||||
return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, pixelWidthHeightRatio,
|
||||
channelCount, sampleRate, language, initializationData, maxWidth, maxHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,9 +20,9 @@ import java.io.IOException;
|
||||
/**
|
||||
* A source of media samples.
|
||||
* <p>
|
||||
* A {@link SampleSource} may expose one or multiple tracks. The number of tracks and information
|
||||
* about each can be queried using {@link SampleSourceReader#getTrackCount()} and
|
||||
* {@link SampleSourceReader#getTrackInfo(int)} respectively.
|
||||
* A {@link SampleSource} may expose one or multiple tracks. The number of tracks and each track's
|
||||
* media format can be queried using {@link SampleSourceReader#getTrackCount()} and
|
||||
* {@link SampleSourceReader#getFormat(int)} respectively.
|
||||
*/
|
||||
public interface SampleSource {
|
||||
|
||||
@ -87,13 +87,14 @@ public interface SampleSource {
|
||||
public int getTrackCount();
|
||||
|
||||
/**
|
||||
* Returns information about the specified track.
|
||||
* Returns the format of the specified track.
|
||||
* <p>
|
||||
* 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
|
||||
|
@ -30,7 +30,6 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
||||
|
||||
private int enabledSourceTrackIndex;
|
||||
private int[] handledSourceTrackIndices;
|
||||
private TrackInfo[] trackInfos;
|
||||
|
||||
/**
|
||||
* @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 sourceTrackCount = source.getTrackCount();
|
||||
int[] trackIndices = new int[sourceTrackCount];
|
||||
TrackInfo[] trackInfos = new TrackInfo[sourceTrackCount];
|
||||
for (int trackIndex = 0; trackIndex < sourceTrackCount; trackIndex++) {
|
||||
TrackInfo trackInfo = source.getTrackInfo(trackIndex);
|
||||
if (handlesTrack(trackInfo)) {
|
||||
MediaFormat format = source.getFormat(trackIndex);
|
||||
if (handlesTrack(format)) {
|
||||
trackIndices[handledTrackCount] = trackIndex;
|
||||
trackInfos[handledTrackCount] = trackInfo;
|
||||
handledTrackCount++;
|
||||
}
|
||||
}
|
||||
this.handledSourceTrackIndices = Arrays.copyOf(trackIndices, handledTrackCount);
|
||||
this.trackInfos = Arrays.copyOf(trackInfos, handledTrackCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
protected abstract boolean handlesTrack(TrackInfo trackInfo);
|
||||
protected abstract boolean handlesTrack(MediaFormat mediaFormat);
|
||||
|
||||
@Override
|
||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
||||
@ -89,7 +85,7 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(enabledSourceTrackIndex).durationUs;
|
||||
return source.getFormat(enabledSourceTrackIndex).durationUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -123,12 +119,12 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
||||
|
||||
@Override
|
||||
protected final int getTrackCount() {
|
||||
return trackInfos.length;
|
||||
return handledSourceTrackIndices.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final TrackInfo getTrackInfo(int track) {
|
||||
return trackInfos[track];
|
||||
protected final MediaFormat getFormat(int track) {
|
||||
return source.getFormat(handledSourceTrackIndices[track]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DataSpec;
|
||||
import com.google.android.exoplayer.upstream.Loader;
|
||||
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import android.net.Uri;
|
||||
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 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 DataSource dataSource;
|
||||
private final MediaFormat format;
|
||||
private final TrackInfo trackInfo;
|
||||
private final int minLoadableRetryCount;
|
||||
|
||||
private int state;
|
||||
private byte[] sampleData;
|
||||
private int sampleSize;
|
||||
private boolean pendingSample;
|
||||
|
||||
private boolean loadingFinished;
|
||||
private Loader loader;
|
||||
@ -69,7 +73,6 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
|
||||
this.dataSource = dataSource;
|
||||
this.format = format;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
trackInfo = new TrackInfo(format.mimeType, format.durationUs);
|
||||
sampleData = new byte[INITIAL_SAMPLE_SIZE];
|
||||
}
|
||||
|
||||
@ -92,13 +95,13 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackInfo getTrackInfo(int track) {
|
||||
return trackInfo;
|
||||
public MediaFormat getFormat(int track) {
|
||||
return format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable(int track, long positionUs) {
|
||||
pendingSample = true;
|
||||
state = STATE_SEND_FORMAT;
|
||||
clearCurrentLoadableException();
|
||||
maybeStartLoading();
|
||||
}
|
||||
@ -121,9 +124,16 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
||||
if (onlyReadDiscontinuity) {
|
||||
return NOTHING_READ;
|
||||
} else if (!pendingSample) {
|
||||
} else if (state == STATE_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;
|
||||
} else {
|
||||
sampleHolder.timeUs = 0;
|
||||
@ -133,13 +143,16 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
|
||||
sampleHolder.replaceBuffer(sampleHolder.size);
|
||||
}
|
||||
sampleHolder.data.put(sampleData, 0, sampleSize);
|
||||
state = STATE_END_OF_STREAM;
|
||||
return SAMPLE_READ;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekToUs(long positionUs) {
|
||||
pendingSample = true;
|
||||
if (state == STATE_END_OF_STREAM) {
|
||||
state = STATE_SEND_SAMPLE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,7 +162,7 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
|
||||
|
||||
@Override
|
||||
public void disable(int track) {
|
||||
pendingSample = false;
|
||||
state = STATE_END_OF_STREAM;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -163,7 +176,7 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
|
||||
// Private methods.
|
||||
|
||||
private void maybeStartLoading() {
|
||||
if (loadingFinished || !pendingSample || loader.isLoading()) {
|
||||
if (loadingFinished || state != STATE_END_OF_STREAM || loader.isLoading()) {
|
||||
return;
|
||||
}
|
||||
if (currentLoadableException != null) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -138,17 +138,17 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about the specified track.
|
||||
* Returns the format of the specified track.
|
||||
* <p>
|
||||
* This method may be called when the renderer is in the following states:
|
||||
* {@link #STATE_PREPARED}, {@link #STATE_ENABLED}, {@link #STATE_STARTED}
|
||||
*
|
||||
* @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.
|
||||
protected TrackInfo getTrackInfo(int track) {
|
||||
return new TrackInfo("application/octet-stream", getDurationUs());
|
||||
protected MediaFormat getFormat(int track) {
|
||||
return MediaFormat.createFormatForMimeType("application/octet-stream", getDurationUs());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,6 @@ import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
||||
import com.google.android.exoplayer.upstream.Loader;
|
||||
@ -132,7 +131,7 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
||||
if (state == STATE_PREPARED) {
|
||||
return true;
|
||||
}
|
||||
loader = new Loader("Loader:" + chunkSource.getTrackInfo().mimeType);
|
||||
loader = new Loader("Loader:" + chunkSource.getFormat().mimeType);
|
||||
state = STATE_PREPARED;
|
||||
return true;
|
||||
}
|
||||
@ -144,10 +143,10 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackInfo getTrackInfo(int track) {
|
||||
public MediaFormat getFormat(int track) {
|
||||
Assertions.checkState(state == STATE_PREPARED || state == STATE_ENABLED);
|
||||
Assertions.checkState(track == 0);
|
||||
return chunkSource.getTrackInfo();
|
||||
return chunkSource.getFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -232,7 +231,7 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
||||
if (haveSamples || currentChunk.isMediaFormatFinal) {
|
||||
MediaFormat mediaFormat = currentChunk.getMediaFormat();
|
||||
if (!mediaFormat.equals(downstreamMediaFormat, true)) {
|
||||
chunkSource.getMaxVideoDimensions(mediaFormat);
|
||||
mediaFormat = chunkSource.getWithMaxVideoDimensions(mediaFormat);
|
||||
formatHolder.format = mediaFormat;
|
||||
formatHolder.drmInitData = currentChunk.getDrmInitData();
|
||||
downstreamMediaFormat = mediaFormat;
|
||||
|
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer.chunk;
|
||||
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
@ -32,23 +31,24 @@ import java.util.List;
|
||||
public interface ChunkSource {
|
||||
|
||||
/**
|
||||
* Gets information about the track for which this instance provides {@link Chunk}s.
|
||||
* Gets the format.
|
||||
* <p>
|
||||
* 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
|
||||
* the supplied {@link MediaFormat}. Other implementations do nothing.
|
||||
* <p>
|
||||
* Only called when the source is enabled.
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
|
@ -18,7 +18,6 @@ package com.google.android.exoplayer.chunk;
|
||||
import com.google.android.exoplayer.ExoPlaybackException;
|
||||
import com.google.android.exoplayer.ExoPlayer.ExoPlayerComponent;
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -61,8 +60,8 @@ public final class MultiTrackChunkSource implements ChunkSource, ExoPlayerCompon
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackInfo getTrackInfo() {
|
||||
return selectedSource.getTrackInfo();
|
||||
public MediaFormat getFormat() {
|
||||
return selectedSource.getFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -94,8 +93,8 @@ public final class MultiTrackChunkSource implements ChunkSource, ExoPlayerCompon
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getMaxVideoDimensions(MediaFormat out) {
|
||||
selectedSource.getMaxVideoDimensions(out);
|
||||
public MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
|
||||
return selectedSource.getWithMaxVideoDimensions(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,7 +17,6 @@ package com.google.android.exoplayer.chunk;
|
||||
|
||||
import com.google.android.exoplayer.C;
|
||||
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.DataSpec;
|
||||
|
||||
@ -36,7 +35,6 @@ public final class SingleSampleChunkSource implements ChunkSource {
|
||||
private final Format format;
|
||||
private final long durationUs;
|
||||
private final MediaFormat mediaFormat;
|
||||
private final TrackInfo trackInfo;
|
||||
|
||||
/**
|
||||
* @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.durationUs = durationUs;
|
||||
this.mediaFormat = mediaFormat;
|
||||
trackInfo = new TrackInfo(format.mimeType, durationUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackInfo getTrackInfo() {
|
||||
return trackInfo;
|
||||
public MediaFormat getFormat() {
|
||||
return mediaFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getMaxVideoDimensions(MediaFormat out) {
|
||||
// Do nothing.
|
||||
public MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
|
||||
return format;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,7 +18,6 @@ package com.google.android.exoplayer.dash;
|
||||
import com.google.android.exoplayer.BehindLiveWindowException;
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.TimeRange;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.chunk.Chunk;
|
||||
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper;
|
||||
@ -98,7 +97,7 @@ public class DashChunkSource implements ChunkSource {
|
||||
private final Handler eventHandler;
|
||||
private final EventListener eventListener;
|
||||
|
||||
private final TrackInfo trackInfo;
|
||||
private final MediaFormat mediaFormat;
|
||||
private final DataSource dataSource;
|
||||
private final FormatEvaluator formatEvaluator;
|
||||
private final Evaluation evaluation;
|
||||
@ -263,7 +262,9 @@ public class DashChunkSource implements ChunkSource {
|
||||
adaptationSetIndex, representationIndices);
|
||||
long periodDurationUs = (representations[0].periodDurationMs == TrackRenderer.UNKNOWN_TIME_US)
|
||||
? 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.representationHolders = new HashMap<>();
|
||||
@ -284,15 +285,14 @@ public class DashChunkSource implements ChunkSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void getMaxVideoDimensions(MediaFormat out) {
|
||||
if (trackInfo.mimeType.startsWith("video")) {
|
||||
out.setMaxVideoDimensions(maxWidth, maxHeight);
|
||||
}
|
||||
public final MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
|
||||
return MimeTypes.isVideo(mediaFormat.mimeType)
|
||||
? format.copyWithMaxVideoDimension(maxWidth, maxHeight) : format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final TrackInfo getTrackInfo() {
|
||||
return trackInfo;
|
||||
public final MediaFormat getFormat() {
|
||||
return mediaFormat;
|
||||
}
|
||||
|
||||
// VisibleForTesting
|
||||
|
@ -22,7 +22,6 @@ import com.google.android.exoplayer.ParserException;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
import com.google.android.exoplayer.upstream.Allocator;
|
||||
@ -163,7 +162,7 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
|
||||
|
||||
private boolean prepared;
|
||||
private int enabledTrackCount;
|
||||
private TrackInfo[] trackInfos;
|
||||
private MediaFormat[] mediaFormats;
|
||||
private long maxTrackDurationUs;
|
||||
private boolean[] pendingMediaFormat;
|
||||
private boolean[] pendingDiscontinuities;
|
||||
@ -292,11 +291,11 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
|
||||
trackEnabledStates = new boolean[trackCount];
|
||||
pendingDiscontinuities = new boolean[trackCount];
|
||||
pendingMediaFormat = new boolean[trackCount];
|
||||
trackInfos = new TrackInfo[trackCount];
|
||||
mediaFormats = new MediaFormat[trackCount];
|
||||
maxTrackDurationUs = C.UNKNOWN_TIME_US;
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
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) {
|
||||
maxTrackDurationUs = format.durationUs;
|
||||
}
|
||||
@ -314,9 +313,9 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackInfo getTrackInfo(int track) {
|
||||
public MediaFormat getFormat(int track) {
|
||||
Assertions.checkState(prepared);
|
||||
return trackInfos[track];
|
||||
return mediaFormats[track];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -224,19 +224,17 @@ public class HlsChunkSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adaptive implementations must set the maximum video dimensions on the supplied
|
||||
* {@link MediaFormat}. Other implementations do nothing.
|
||||
* <p>
|
||||
* Only called when the source is enabled.
|
||||
* 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 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) {
|
||||
if (maxWidth == -1 || maxHeight == -1) {
|
||||
// Not adaptive.
|
||||
return;
|
||||
}
|
||||
out.setMaxVideoDimensions(maxWidth, maxHeight);
|
||||
public MediaFormat getMaxVideoDimensions(MediaFormat format) {
|
||||
return (maxWidth == -1 || maxHeight == -1) ? format
|
||||
: format.copyWithMaxVideoDimension(maxWidth, maxHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,6 @@ import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener;
|
||||
import com.google.android.exoplayer.chunk.Chunk;
|
||||
@ -71,7 +70,7 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
|
||||
private int enabledTrackCount;
|
||||
private boolean[] trackEnabledStates;
|
||||
private boolean[] pendingDiscontinuities;
|
||||
private TrackInfo[] trackInfos;
|
||||
private MediaFormat[] mediaFormats;
|
||||
private MediaFormat[] downstreamMediaFormats;
|
||||
private Format downstreamFormat;
|
||||
|
||||
@ -135,10 +134,9 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
|
||||
trackEnabledStates = new boolean[trackCount];
|
||||
pendingDiscontinuities = new boolean[trackCount];
|
||||
downstreamMediaFormats = new MediaFormat[trackCount];
|
||||
trackInfos = new TrackInfo[trackCount];
|
||||
mediaFormats = new MediaFormat[trackCount];
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
MediaFormat format = extractor.getMediaFormat(i);
|
||||
trackInfos[i] = new TrackInfo(format.mimeType, chunkSource.getDurationUs());
|
||||
mediaFormats[i] = extractor.getMediaFormat(i);
|
||||
}
|
||||
prepared = true;
|
||||
return true;
|
||||
@ -170,9 +168,9 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackInfo getTrackInfo(int track) {
|
||||
public MediaFormat getFormat(int track) {
|
||||
Assertions.checkState(prepared);
|
||||
return trackInfos[track];
|
||||
return mediaFormats[track];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,11 +16,11 @@
|
||||
package com.google.android.exoplayer.metadata;
|
||||
|
||||
import com.google.android.exoplayer.ExoPlaybackException;
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
@ -88,8 +88,8 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return metadataParser.canParse(trackInfo.mimeType);
|
||||
protected boolean handlesTrack(MediaFormat mediaFormat) {
|
||||
return metadataParser.canParse(mediaFormat.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,7 +17,6 @@ package com.google.android.exoplayer.smoothstreaming;
|
||||
|
||||
import com.google.android.exoplayer.BehindLiveWindowException;
|
||||
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.ChunkExtractorWrapper;
|
||||
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 INITIALIZATION_VECTOR_SIZE = 8;
|
||||
|
||||
private final TrackInfo trackInfo;
|
||||
private final MediaFormat mediaFormat;
|
||||
private final DataSource dataSource;
|
||||
private final FormatEvaluator formatEvaluator;
|
||||
private final Evaluation evaluation;
|
||||
@ -135,7 +134,9 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
||||
this.liveEdgeLatencyUs = liveEdgeLatencyMs * 1000;
|
||||
|
||||
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();
|
||||
|
||||
TrackEncryptionBox[] trackEncryptionBoxes = null;
|
||||
@ -180,15 +181,14 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void getMaxVideoDimensions(MediaFormat out) {
|
||||
if (trackInfo.mimeType.startsWith("video")) {
|
||||
out.setMaxVideoDimensions(maxWidth, maxHeight);
|
||||
}
|
||||
public final MediaFormat getWithMaxVideoDimensions(MediaFormat format) {
|
||||
return MimeTypes.isVideo(mediaFormat.mimeType)
|
||||
? format.copyWithMaxVideoDimension(maxWidth, maxHeight) : format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final TrackInfo getTrackInfo() {
|
||||
return trackInfo;
|
||||
public final MediaFormat getFormat() {
|
||||
return mediaFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -384,7 +384,6 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
||||
if (streamElement.type == StreamElement.TYPE_VIDEO) {
|
||||
MediaFormat format = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE,
|
||||
trackFormat.width, trackFormat.height, Arrays.asList(trackElement.csd));
|
||||
format.setMaxVideoDimensions(streamElement.maxWidth, streamElement.maxHeight);
|
||||
return format;
|
||||
} else if (streamElement.type == StreamElement.TYPE_AUDIO) {
|
||||
List<byte[]> csd;
|
||||
|
@ -16,11 +16,11 @@
|
||||
package com.google.android.exoplayer.text;
|
||||
|
||||
import com.google.android.exoplayer.ExoPlaybackException;
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
@ -150,15 +150,15 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return getParserIndex(trackInfo) != -1;
|
||||
protected boolean handlesTrack(MediaFormat mediaFormat) {
|
||||
return getParserIndex(mediaFormat) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
||||
throws ExoPlaybackException {
|
||||
super.onEnabled(track, positionUs, joining);
|
||||
parserIndex = getParserIndex(getTrackInfo(track));
|
||||
parserIndex = getParserIndex(getFormat(track));
|
||||
parserThread = new HandlerThread("textParser");
|
||||
parserThread.start();
|
||||
parserHelper = new SubtitleParserHelper(parserThread.getLooper(), subtitleParsers[parserIndex]);
|
||||
@ -296,9 +296,9 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
|
||||
textRenderer.onCues(cues);
|
||||
}
|
||||
|
||||
private int getParserIndex(TrackInfo trackInfo) {
|
||||
private int getParserIndex(MediaFormat mediaFormat) {
|
||||
for (int i = 0; i < subtitleParsers.length; i++) {
|
||||
if (subtitleParsers[i].canParse(trackInfo.mimeType)) {
|
||||
if (subtitleParsers[i].canParse(mediaFormat.mimeType)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,11 @@ package com.google.android.exoplayer.text.eia608;
|
||||
|
||||
import com.google.android.exoplayer.C;
|
||||
import com.google.android.exoplayer.ExoPlaybackException;
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.text.Cue;
|
||||
import com.google.android.exoplayer.text.TextRenderer;
|
||||
@ -89,8 +89,8 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return eia608Parser.canParse(trackInfo.mimeType);
|
||||
protected boolean handlesTrack(MediaFormat mediaFormat) {
|
||||
return eia608Parser.canParse(mediaFormat.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user