mirror of
https://github.com/androidx/media.git
synced 2025-05-05 06:30:24 +08:00
Common base class for SampleSource based TrackRenderers.
This will allow multi-track support when consuming from a SampleSource to be added in a single class, rather than in 6. Prep for Issue #514.
This commit is contained in:
parent
150b3cdb19
commit
13f4a3e3bd
@ -21,7 +21,8 @@ import com.google.android.exoplayer.MediaClock;
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
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;
|
||||
@ -30,7 +31,6 @@ import com.google.android.exoplayer.util.MimeTypes;
|
||||
|
||||
import android.os.Handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
@ -39,7 +39,8 @@ import java.util.List;
|
||||
*
|
||||
* @author vigneshv@google.com (Vignesh Venkatasubramanian)
|
||||
*/
|
||||
public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClock {
|
||||
public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
|
||||
implements MediaClock {
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be notified of {@link LibopusAudioTrackRenderer} events.
|
||||
@ -76,7 +77,6 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
*/
|
||||
public static final int MSG_SET_VOLUME = 1;
|
||||
|
||||
private final SampleSourceReader source;
|
||||
private final Handler eventHandler;
|
||||
private final EventListener eventListener;
|
||||
private final MediaFormatHolder formatHolder;
|
||||
@ -86,7 +86,6 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
private InputBuffer inputBuffer;
|
||||
private OutputBuffer outputBuffer;
|
||||
|
||||
private int trackIndex;
|
||||
private long currentPositionUs;
|
||||
private boolean allowPositionDiscontinuity;
|
||||
private boolean inputStreamEnded;
|
||||
@ -112,7 +111,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
*/
|
||||
public LibopusAudioTrackRenderer(SampleSource source, Handler eventHandler,
|
||||
EventListener eventListener) {
|
||||
this.source = source.register();
|
||||
super(source);
|
||||
this.eventHandler = eventHandler;
|
||||
this.eventListener = eventListener;
|
||||
this.audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
||||
@ -126,20 +125,15 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
if (source.getTrackInfo(i).mimeType.equalsIgnoreCase(MimeTypes.AUDIO_OPUS)
|
||||
|| source.getTrackInfo(i).mimeType.equalsIgnoreCase(MimeTypes.AUDIO_WEBM)) {
|
||||
trackIndex = i;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
}
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return MimeTypes.AUDIO_OPUS.equalsIgnoreCase(trackInfo.mimeType)
|
||||
|| MimeTypes.AUDIO_WEBM.equalsIgnoreCase(trackInfo.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
super.onEnabled(positionUs, joining);
|
||||
seekToInternal(positionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -147,8 +141,8 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
if (outputStreamEnded) {
|
||||
return;
|
||||
}
|
||||
sourceIsReady = source.continueBuffering(trackIndex, positionUs);
|
||||
checkForDiscontinuity();
|
||||
sourceIsReady = continueBufferingSource(positionUs);
|
||||
checkForDiscontinuity(positionUs);
|
||||
|
||||
// Try and read a format if we don't have one already.
|
||||
if (format == null && !readFormat(positionUs)) {
|
||||
@ -189,7 +183,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
// Rendering loop.
|
||||
try {
|
||||
renderBuffer();
|
||||
while (feedInputBuffer()) {}
|
||||
while (feedInputBuffer(positionUs)) {}
|
||||
} catch (AudioTrack.InitializationException e) {
|
||||
notifyAudioTrackInitializationError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
@ -249,7 +243,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
}
|
||||
}
|
||||
|
||||
private boolean feedInputBuffer() throws OpusDecoderException {
|
||||
private boolean feedInputBuffer(long positionUs) throws OpusDecoderException {
|
||||
if (inputStreamEnded) {
|
||||
return false;
|
||||
}
|
||||
@ -261,8 +255,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
}
|
||||
}
|
||||
|
||||
int result = source.readData(trackIndex, currentPositionUs, formatHolder,
|
||||
inputBuffer.sampleHolder, false);
|
||||
int result = readSource(positionUs, formatHolder, inputBuffer.sampleHolder, false);
|
||||
if (result == SampleSource.NOTHING_READ) {
|
||||
return false;
|
||||
}
|
||||
@ -291,11 +284,11 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkForDiscontinuity() {
|
||||
private void checkForDiscontinuity(long positionUs) {
|
||||
if (decoder == null) {
|
||||
return;
|
||||
}
|
||||
int result = source.readData(trackIndex, currentPositionUs, formatHolder, null, true);
|
||||
int result = readSource(positionUs, formatHolder, null, true);
|
||||
if (result == SampleSource.DISCONTINUITY_READ) {
|
||||
flushDecoder();
|
||||
}
|
||||
@ -319,11 +312,6 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
return audioTrack.hasPendingData() || (format != null && sourceIsReady);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(trackIndex).durationUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPositionUs() {
|
||||
long newCurrentPositionUs = audioTrack.getCurrentPositionUs(isEnded());
|
||||
@ -335,14 +323,9 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
return currentPositionUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getBufferedPositionUs() {
|
||||
return source.getBufferedPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
||||
source.seekToUs(positionUs);
|
||||
super.seekTo(positionUs);
|
||||
seekToInternal(positionUs);
|
||||
}
|
||||
|
||||
@ -350,18 +333,11 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
audioTrack.reset();
|
||||
currentPositionUs = positionUs;
|
||||
allowPositionDiscontinuity = true;
|
||||
source.seekToUs(positionUs);
|
||||
inputStreamEnded = false;
|
||||
outputStreamEnded = false;
|
||||
sourceIsReady = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) {
|
||||
source.enable(trackIndex, positionUs);
|
||||
seekToInternal(positionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStarted() {
|
||||
audioTrack.play();
|
||||
@ -373,38 +349,24 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReleased() {
|
||||
source.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisabled() {
|
||||
if (decoder != null) {
|
||||
decoder.release();
|
||||
decoder = null;
|
||||
}
|
||||
protected void onDisabled() throws ExoPlaybackException {
|
||||
inputBuffer = null;
|
||||
outputBuffer = null;
|
||||
format = null;
|
||||
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
||||
try {
|
||||
if (decoder != null) {
|
||||
decoder.release();
|
||||
decoder = null;
|
||||
}
|
||||
audioTrack.release();
|
||||
} finally {
|
||||
inputBuffer = null;
|
||||
outputBuffer = null;
|
||||
format = null;
|
||||
source.disable(trackIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
super.onDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readFormat(long positionUs) {
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, null, false);
|
||||
int result = readSource(positionUs, formatHolder, null, false);
|
||||
if (result == SampleSource.FORMAT_READ) {
|
||||
format = formatHolder.format;
|
||||
audioTrack.reconfigure(format.getFrameworkMediaFormatV16());
|
||||
|
@ -20,7 +20,8 @@ import com.google.android.exoplayer.ExoPlayer;
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
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;
|
||||
@ -32,12 +33,10 @@ import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Decodes and renders video using the native VP9 decoder.
|
||||
*/
|
||||
public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be notified of {@link LibvpxVideoTrackRenderer} events.
|
||||
@ -91,7 +90,6 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
public static final int MSG_SET_SURFACE = 1;
|
||||
public static final int MSG_SET_VPX_SURFACE_VIEW = 2;
|
||||
|
||||
private final SampleSourceReader source;
|
||||
private final boolean scaleToFit;
|
||||
private final Handler eventHandler;
|
||||
private final EventListener eventListener;
|
||||
@ -110,7 +108,6 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
private VpxVideoSurfaceView vpxVideoSurfaceView;
|
||||
private boolean outputRgb;
|
||||
|
||||
private int trackIndex;
|
||||
private boolean inputStreamEnded;
|
||||
private boolean outputStreamEnded;
|
||||
private boolean sourceIsReady;
|
||||
@ -141,7 +138,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
*/
|
||||
public LibvpxVideoTrackRenderer(SampleSource source, boolean scaleToFit,
|
||||
Handler eventHandler, EventListener eventListener, int maxDroppedFrameCountToNotify) {
|
||||
this.source = source.register();
|
||||
super(source);
|
||||
this.scaleToFit = scaleToFit;
|
||||
this.eventHandler = eventHandler;
|
||||
this.eventListener = eventListener;
|
||||
@ -152,20 +149,9 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
if (source.getTrackInfo(i).mimeType.equalsIgnoreCase(MimeTypes.VIDEO_VP9)
|
||||
|| source.getTrackInfo(i).mimeType.equalsIgnoreCase(MimeTypes.VIDEO_WEBM)) {
|
||||
trackIndex = i;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
}
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return MimeTypes.VIDEO_VP9.equalsIgnoreCase(trackInfo.mimeType)
|
||||
|| MimeTypes.VIDEO_WEBM.equalsIgnoreCase(trackInfo.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -173,7 +159,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
if (outputStreamEnded) {
|
||||
return;
|
||||
}
|
||||
sourceIsReady = source.continueBuffering(trackIndex, positionUs);
|
||||
sourceIsReady = continueBufferingSource(positionUs);
|
||||
checkForDiscontinuity(positionUs);
|
||||
|
||||
// Try and read a format if we don't have one already.
|
||||
@ -302,7 +288,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, inputBuffer.sampleHolder,
|
||||
int result = readSource(positionUs, formatHolder, inputBuffer.sampleHolder,
|
||||
false);
|
||||
if (result == SampleSource.NOTHING_READ) {
|
||||
return false;
|
||||
@ -334,7 +320,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
if (decoder == null) {
|
||||
return;
|
||||
}
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, null, true);
|
||||
int result = readSource(positionUs, formatHolder, null, true);
|
||||
if (result == SampleSource.DISCONTINUITY_READ) {
|
||||
flushDecoder();
|
||||
}
|
||||
@ -356,25 +342,15 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
return format != null && sourceIsReady;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(trackIndex).durationUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getBufferedPositionUs() {
|
||||
return source.getBufferedPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
||||
source.seekToUs(positionUs);
|
||||
super.seekTo(positionUs);
|
||||
seekToInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) {
|
||||
source.enable(trackIndex, positionUs);
|
||||
protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
super.onEnabled(positionUs, joining);
|
||||
seekToInternal();
|
||||
}
|
||||
|
||||
@ -397,33 +373,22 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReleased() {
|
||||
source.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisabled() {
|
||||
if (decoder != null) {
|
||||
decoder.release();
|
||||
decoder = null;
|
||||
}
|
||||
protected void onDisabled() throws ExoPlaybackException {
|
||||
inputBuffer = null;
|
||||
outputBuffer = null;
|
||||
format = null;
|
||||
source.disable(trackIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
if (decoder != null) {
|
||||
decoder.release();
|
||||
decoder = null;
|
||||
}
|
||||
} finally {
|
||||
super.onDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readFormat(long positionUs) {
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, null, false);
|
||||
int result = readSource(positionUs, formatHolder, null, false);
|
||||
if (result == SampleSource.FORMAT_READ) {
|
||||
format = formatHolder.format;
|
||||
return true;
|
||||
|
@ -157,12 +157,12 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesMimeType(String mimeType) {
|
||||
return MimeTypes.isAudio(mimeType) && super.handlesMimeType(mimeType);
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return MimeTypes.isAudio(trackInfo.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) {
|
||||
protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
super.onEnabled(positionUs, joining);
|
||||
seekToInternal(positionUs);
|
||||
}
|
||||
@ -231,7 +231,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisabled() {
|
||||
protected void onDisabled() throws ExoPlaybackException {
|
||||
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
||||
try {
|
||||
audioTrack.release();
|
||||
|
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
import com.google.android.exoplayer.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
@ -31,7 +30,6 @@ import android.media.MediaCrypto;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -40,7 +38,7 @@ import java.util.List;
|
||||
* An abstract {@link TrackRenderer} that uses {@link MediaCodec} to decode samples for rendering.
|
||||
*/
|
||||
@TargetApi(16)
|
||||
public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer {
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be notified of {@link MediaCodecTrackRenderer} events.
|
||||
@ -183,7 +181,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final boolean playClearSamplesWithoutKeys;
|
||||
private final SampleSourceReader source;
|
||||
private final SampleHolder sampleHolder;
|
||||
private final MediaFormatHolder formatHolder;
|
||||
private final List<Long> decodeOnlyPresentationTimestamps;
|
||||
@ -207,7 +204,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
private int codecReinitializationState;
|
||||
private boolean codecHasQueuedBuffers;
|
||||
|
||||
private int trackIndex;
|
||||
private int sourceState;
|
||||
private boolean inputStreamEnded;
|
||||
private boolean outputStreamEnded;
|
||||
@ -229,8 +225,8 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
*/
|
||||
public MediaCodecTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
|
||||
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener) {
|
||||
super(source);
|
||||
Assertions.checkState(Util.SDK_INT >= 16);
|
||||
this.source = source.register();
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
|
||||
this.eventHandler = eventHandler;
|
||||
@ -245,39 +241,8 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
// TODO: Right now this is getting the mime types of the container format
|
||||
// (e.g. audio/mp4 and video/mp4 for fragmented mp4). It needs to be getting the mime types
|
||||
// of the actual samples (e.g. audio/mp4a-latm and video/avc).
|
||||
if (handlesMimeType(source.getTrackInfo(i).mimeType)) {
|
||||
trackIndex = i;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
}
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a mime type is handled by the renderer.
|
||||
*
|
||||
* @param mimeType The mime type to test.
|
||||
* @return True if the renderer can handle the mime type. False otherwise.
|
||||
*/
|
||||
protected boolean handlesMimeType(String mimeType) {
|
||||
return true;
|
||||
// TODO: Uncomment once the TODO above is fixed.
|
||||
// DecoderInfoUtil.getDecoder(mimeType) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) {
|
||||
source.enable(trackIndex, positionUs);
|
||||
protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
super.onEnabled(positionUs, joining);
|
||||
seekToInternal();
|
||||
}
|
||||
|
||||
@ -400,7 +365,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisabled() {
|
||||
protected void onDisabled() throws ExoPlaybackException {
|
||||
format = null;
|
||||
drmInitData = null;
|
||||
try {
|
||||
@ -412,7 +377,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
openedDrmSession = false;
|
||||
}
|
||||
} finally {
|
||||
source.disable(trackIndex);
|
||||
super.onDisabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -445,24 +410,9 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReleased() {
|
||||
source.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(trackIndex).durationUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getBufferedPositionUs() {
|
||||
return source.getBufferedPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
||||
source.seekToUs(positionUs);
|
||||
super.seekTo(positionUs);
|
||||
seekToInternal();
|
||||
}
|
||||
|
||||
@ -484,7 +434,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
|
||||
@Override
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||
sourceState = source.continueBuffering(trackIndex, positionUs)
|
||||
sourceState = continueBufferingSource(positionUs)
|
||||
? (sourceState == SOURCE_STATE_NOT_READY ? SOURCE_STATE_READY : sourceState)
|
||||
: SOURCE_STATE_NOT_READY;
|
||||
checkForDiscontinuity(positionUs);
|
||||
@ -506,7 +456,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
}
|
||||
|
||||
private void readFormat(long positionUs) throws ExoPlaybackException {
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
int result = readSource(positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.FORMAT_READ) {
|
||||
onInputFormatChanged(formatHolder);
|
||||
}
|
||||
@ -516,7 +466,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
if (codec == null) {
|
||||
return;
|
||||
}
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, true);
|
||||
int result = readSource(positionUs, formatHolder, sampleHolder, true);
|
||||
if (result == SampleSource.DISCONTINUITY_READ) {
|
||||
flushCodec();
|
||||
}
|
||||
@ -597,7 +547,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
}
|
||||
codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING;
|
||||
}
|
||||
result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
result = readSource(positionUs, formatHolder, sampleHolder, false);
|
||||
if (firstFeed && sourceState == SOURCE_STATE_READY && result == SampleSource.NOTHING_READ) {
|
||||
sourceState = SOURCE_STATE_READY_READ_MAY_FAIL;
|
||||
}
|
||||
@ -774,15 +724,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnded() {
|
||||
return outputStreamEnded;
|
||||
@ -950,11 +891,8 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||
* incorrectly on the host device. False otherwise.
|
||||
*/
|
||||
private static boolean codecNeedsEndOfStreamWorkaround(String name) {
|
||||
return Util.SDK_INT <= 17
|
||||
&& "OMX.rk.video_decoder.avc".equals(name)
|
||||
&& ("ht7s3".equals(Util.DEVICE) // Tesco HUDL
|
||||
|| "rk30sdk".equals(Util.DEVICE) // Rockchip rk30
|
||||
|| "rk31sdk".equals(Util.DEVICE)); // Rockchip rk31
|
||||
return Util.SDK_INT <= 17 && "ht7s3".equals(Util.DEVICE) // Tesco HUDL
|
||||
&& "OMX.rk.video_decoder.avc".equals(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -256,12 +256,12 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesMimeType(String mimeType) {
|
||||
return MimeTypes.isVideo(mimeType) && super.handlesMimeType(mimeType);
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return MimeTypes.isVideo(trackInfo.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) {
|
||||
protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
super.onEnabled(positionUs, joining);
|
||||
renderedFirstFrame = false;
|
||||
if (joining && allowedJoiningTimeUs > 0) {
|
||||
@ -314,7 +314,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisabled() {
|
||||
protected void onDisabled() throws ExoPlaybackException {
|
||||
currentWidth = -1;
|
||||
currentHeight = -1;
|
||||
currentPixelWidthHeightRatio = -1;
|
||||
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Base class for {@link TrackRenderer} implementations that render samples obtained from a
|
||||
* {@link SampleSource}.
|
||||
*/
|
||||
public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
||||
|
||||
private final SampleSourceReader source;
|
||||
|
||||
private int trackIndex;
|
||||
|
||||
/**
|
||||
* @param source The upstream source from which the renderer obtains samples.
|
||||
*/
|
||||
public SampleSourceTrackRenderer(SampleSource source) {
|
||||
this.source = source.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
TrackInfo trackInfo = source.getTrackInfo(i);
|
||||
if (handlesTrack(trackInfo)) {
|
||||
trackIndex = i;
|
||||
onTrackSelected(trackInfo);
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
}
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this renderer is capable of handling the provided track.
|
||||
*
|
||||
* @param trackInfo The track.
|
||||
* @return True if the renderer can handle the track, false otherwise.
|
||||
*/
|
||||
protected abstract boolean handlesTrack(TrackInfo trackInfo);
|
||||
|
||||
/**
|
||||
* Invoked when a track is selected.
|
||||
*
|
||||
* @param trackInfo The selected track.
|
||||
*/
|
||||
protected void onTrackSelected(TrackInfo trackInfo) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
source.enable(trackIndex, positionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
||||
source.seekToUs(positionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getBufferedPositionUs() {
|
||||
return source.getBufferedPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(trackIndex).durationUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisabled() throws ExoPlaybackException {
|
||||
source.disable(trackIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReleased() throws ExoPlaybackException {
|
||||
source.release();
|
||||
}
|
||||
|
||||
protected final boolean continueBufferingSource(long positionUs) {
|
||||
return source.continueBuffering(trackIndex, positionUs);
|
||||
}
|
||||
|
||||
protected final int readSource(long positionUs, MediaFormatHolder formatHolder,
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
||||
return source.readData(trackIndex, positionUs, formatHolder, sampleHolder,
|
||||
onlyReadDiscontinuity);
|
||||
}
|
||||
|
||||
}
|
@ -110,11 +110,11 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final int prepare(long positionUs) throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_UNPREPARED);
|
||||
Assertions.checkState(state == STATE_UNPREPARED);
|
||||
state = doPrepare(positionUs);
|
||||
Assertions.checkState(state == TrackRenderer.STATE_UNPREPARED ||
|
||||
state == TrackRenderer.STATE_PREPARED ||
|
||||
state == TrackRenderer.STATE_IGNORE);
|
||||
Assertions.checkState(state == STATE_UNPREPARED ||
|
||||
state == STATE_PREPARED ||
|
||||
state == STATE_IGNORE);
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -143,8 +143,8 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void enable(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_PREPARED);
|
||||
state = TrackRenderer.STATE_ENABLED;
|
||||
Assertions.checkState(state == STATE_PREPARED);
|
||||
state = STATE_ENABLED;
|
||||
onEnabled(positionUs, joining);
|
||||
}
|
||||
|
||||
@ -170,8 +170,8 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void start() throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_ENABLED);
|
||||
state = TrackRenderer.STATE_STARTED;
|
||||
Assertions.checkState(state == STATE_ENABLED);
|
||||
state = STATE_STARTED;
|
||||
onStarted();
|
||||
}
|
||||
|
||||
@ -192,8 +192,8 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void stop() throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_STARTED);
|
||||
state = TrackRenderer.STATE_ENABLED;
|
||||
Assertions.checkState(state == STATE_STARTED);
|
||||
state = STATE_ENABLED;
|
||||
onStopped();
|
||||
}
|
||||
|
||||
@ -214,8 +214,8 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void disable() throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_ENABLED);
|
||||
state = TrackRenderer.STATE_PREPARED;
|
||||
Assertions.checkState(state == STATE_ENABLED);
|
||||
state = STATE_PREPARED;
|
||||
onDisabled();
|
||||
}
|
||||
|
||||
@ -236,10 +236,10 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void release() throws ExoPlaybackException {
|
||||
Assertions.checkState(state != TrackRenderer.STATE_ENABLED
|
||||
&& state != TrackRenderer.STATE_STARTED
|
||||
&& state != TrackRenderer.STATE_RELEASED);
|
||||
state = TrackRenderer.STATE_RELEASED;
|
||||
Assertions.checkState(state != STATE_ENABLED
|
||||
&& state != STATE_STARTED
|
||||
&& state != STATE_RELEASED);
|
||||
state = STATE_RELEASED;
|
||||
onReleased();
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
||||
private static final int STATE_PREPARED = 2;
|
||||
private static final int STATE_ENABLED = 3;
|
||||
|
||||
private static final int NO_RESET_PENDING = -1;
|
||||
private static final long NO_RESET_PENDING = Long.MIN_VALUE;
|
||||
|
||||
private final int eventSourceId;
|
||||
private final LoadControl loadControl;
|
||||
|
@ -93,7 +93,7 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
|
||||
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT_LIVE = 6;
|
||||
|
||||
private static final int MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA = -1;
|
||||
private static final int NO_RESET_PENDING = -1;
|
||||
private static final long NO_RESET_PENDING = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* Default extractor classes in priority order. They are referred to indirectly so that it is
|
||||
@ -326,10 +326,14 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
|
||||
enabledTrackCount++;
|
||||
trackEnabledStates[track] = true;
|
||||
pendingMediaFormat[track] = true;
|
||||
if (enabledTrackCount == 1) {
|
||||
seekToUs(positionUs);
|
||||
}
|
||||
pendingDiscontinuities[track] = false;
|
||||
if (enabledTrackCount == 1) {
|
||||
// Treat all enables in non-seekable media as being from t=0.
|
||||
positionUs = !seekMap.isSeekable() ? 0 : positionUs;
|
||||
downstreamPositionUs = positionUs;
|
||||
lastSeekPositionUs = positionUs;
|
||||
restartFrom(positionUs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -431,10 +435,8 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
|
||||
public void seekToUs(long positionUs) {
|
||||
Assertions.checkState(prepared);
|
||||
Assertions.checkState(enabledTrackCount > 0);
|
||||
if (!seekMap.isSeekable()) {
|
||||
// Treat all seeks into non-seekable media as seeks to the start.
|
||||
positionUs = 0;
|
||||
}
|
||||
// Treat all seeks into non-seekable media as being to t=0.
|
||||
positionUs = !seekMap.isSeekable() ? 0 : positionUs;
|
||||
|
||||
long currentPositionUs = isPendingReset() ? pendingResetPositionUs : downstreamPositionUs;
|
||||
downstreamPositionUs = positionUs;
|
||||
|
@ -52,7 +52,7 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
|
||||
*/
|
||||
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
|
||||
|
||||
private static final int NO_RESET_PENDING = -1;
|
||||
private static final long NO_RESET_PENDING = Long.MIN_VALUE;
|
||||
|
||||
private final HlsChunkSource chunkSource;
|
||||
private final LinkedList<HlsExtractorWrapper> extractors;
|
||||
@ -182,15 +182,17 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
|
||||
enabledTrackCount++;
|
||||
trackEnabledStates[track] = true;
|
||||
downstreamMediaFormats[track] = null;
|
||||
pendingDiscontinuities[track] = false;
|
||||
downstreamFormat = null;
|
||||
if (!loadControlRegistered) {
|
||||
loadControl.register(this, bufferSizeContribution);
|
||||
loadControlRegistered = true;
|
||||
}
|
||||
if (enabledTrackCount == 1) {
|
||||
seekToUs(positionUs);
|
||||
downstreamPositionUs = positionUs;
|
||||
lastSeekPositionUs = positionUs;
|
||||
restartFrom(positionUs);
|
||||
}
|
||||
pendingDiscontinuities[track] = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,7 +19,8 @@ import com.google.android.exoplayer.ExoPlaybackException;
|
||||
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.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
@ -35,7 +36,7 @@ import java.io.IOException;
|
||||
*
|
||||
* @param <T> The type of the metadata.
|
||||
*/
|
||||
public final class MetadataTrackRenderer<T> extends TrackRenderer implements Callback {
|
||||
public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer implements Callback {
|
||||
|
||||
/**
|
||||
* An interface for components that process metadata.
|
||||
@ -55,16 +56,13 @@ public final class MetadataTrackRenderer<T> extends TrackRenderer implements Cal
|
||||
|
||||
private static final int MSG_INVOKE_RENDERER = 0;
|
||||
|
||||
private final SampleSourceReader source;
|
||||
private final MetadataParser<T> metadataParser;
|
||||
private final MetadataRenderer<T> metadataRenderer;
|
||||
private final Handler metadataHandler;
|
||||
private final MediaFormatHolder formatHolder;
|
||||
private final SampleHolder sampleHolder;
|
||||
|
||||
private int trackIndex;
|
||||
private boolean inputStreamEnded;
|
||||
|
||||
private long pendingMetadataTimestamp;
|
||||
private T pendingMetadata;
|
||||
|
||||
@ -80,7 +78,7 @@ public final class MetadataTrackRenderer<T> extends TrackRenderer implements Cal
|
||||
*/
|
||||
public MetadataTrackRenderer(SampleSource source, MetadataParser<T> metadataParser,
|
||||
MetadataRenderer<T> metadataRenderer, Looper metadataRendererLooper) {
|
||||
this.source = source.register();
|
||||
super(source);
|
||||
this.metadataParser = Assertions.checkNotNull(metadataParser);
|
||||
this.metadataRenderer = Assertions.checkNotNull(metadataRenderer);
|
||||
this.metadataHandler = metadataRendererLooper == null ? null
|
||||
@ -90,30 +88,19 @@ public final class MetadataTrackRenderer<T> extends TrackRenderer implements Cal
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
if (metadataParser.canParse(source.getTrackInfo(i).mimeType)) {
|
||||
trackIndex = i;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
}
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return metadataParser.canParse(trackInfo.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) {
|
||||
source.enable(trackIndex, positionUs);
|
||||
protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
super.onEnabled(positionUs, joining);
|
||||
seekToInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
||||
source.seekToUs(positionUs);
|
||||
super.seekTo(positionUs);
|
||||
seekToInternal();
|
||||
}
|
||||
|
||||
@ -123,23 +110,21 @@ public final class MetadataTrackRenderer<T> extends TrackRenderer implements Cal
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs)
|
||||
throws ExoPlaybackException {
|
||||
source.continueBuffering(trackIndex, positionUs);
|
||||
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||
continueBufferingSource(positionUs);
|
||||
if (!inputStreamEnded && pendingMetadata == null) {
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.SAMPLE_READ) {
|
||||
pendingMetadataTimestamp = sampleHolder.timeUs;
|
||||
try {
|
||||
pendingMetadata = metadataParser.parse(sampleHolder.data.array(), sampleHolder.size);
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
sampleHolder.data.clear();
|
||||
} else if (result == SampleSource.END_OF_STREAM) {
|
||||
inputStreamEnded = true;
|
||||
int result = readSource(positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.SAMPLE_READ) {
|
||||
pendingMetadataTimestamp = sampleHolder.timeUs;
|
||||
try {
|
||||
pendingMetadata = metadataParser.parse(sampleHolder.data.array(), sampleHolder.size);
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
sampleHolder.data.clear();
|
||||
} else if (result == SampleSource.END_OF_STREAM) {
|
||||
inputStreamEnded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingMetadata != null && pendingMetadataTimestamp <= positionUs) {
|
||||
@ -149,23 +134,9 @@ public final class MetadataTrackRenderer<T> extends TrackRenderer implements Cal
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisabled() {
|
||||
protected void onDisabled() throws ExoPlaybackException {
|
||||
pendingMetadata = null;
|
||||
source.disable(trackIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(trackIndex).durationUs;
|
||||
super.onDisabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,7 +19,8 @@ import com.google.android.exoplayer.ExoPlaybackException;
|
||||
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.SampleSourceTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
@ -58,7 +59,7 @@ import java.util.List;
|
||||
* {@link SubtitleParser#canParse(String)} will be used.
|
||||
*/
|
||||
@TargetApi(16)
|
||||
public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||
public final class TextTrackRenderer extends SampleSourceTrackRenderer implements Callback {
|
||||
|
||||
private static final int MSG_UPDATE_OVERLAY = 0;
|
||||
|
||||
@ -104,15 +105,11 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||
|
||||
private final Handler textRendererHandler;
|
||||
private final TextRenderer textRenderer;
|
||||
private final SampleSourceReader source;
|
||||
private final MediaFormatHolder formatHolder;
|
||||
private final SubtitleParser[] subtitleParsers;
|
||||
|
||||
private int parserIndex;
|
||||
private int trackIndex;
|
||||
|
||||
private boolean inputStreamEnded;
|
||||
|
||||
private Subtitle subtitle;
|
||||
private Subtitle nextSubtitle;
|
||||
private SubtitleParserHelper parserHelper;
|
||||
@ -132,7 +129,7 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||
*/
|
||||
public TextTrackRenderer(SampleSource source, TextRenderer textRenderer,
|
||||
Looper textRendererLooper, SubtitleParser... subtitleParsers) {
|
||||
this.source = source.register();
|
||||
super(source);
|
||||
this.textRenderer = Assertions.checkNotNull(textRenderer);
|
||||
this.textRendererHandler = textRendererLooper == null ? null
|
||||
: new Handler(textRendererLooper, this);
|
||||
@ -153,27 +150,29 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
int trackCount = source.getTrackCount();
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
for (int i = 0; i < subtitleParsers.length; i++) {
|
||||
for (int j = 0; j < trackCount; j++) {
|
||||
if (subtitleParsers[i].canParse(source.getTrackInfo(j).mimeType)) {
|
||||
parserIndex = i;
|
||||
trackIndex = j;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
if (subtitleParsers[i].canParse(trackInfo.mimeType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) {
|
||||
source.enable(trackIndex, positionUs);
|
||||
protected void onTrackSelected(TrackInfo trackInfo) {
|
||||
for (int i = 0; i < subtitleParsers.length; i++) {
|
||||
if (subtitleParsers[i].canParse(trackInfo.mimeType)) {
|
||||
parserIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Invalid track selected");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
super.onEnabled(positionUs, joining);
|
||||
parserThread = new HandlerThread("textParser");
|
||||
parserThread.start();
|
||||
parserHelper = new SubtitleParserHelper(parserThread.getLooper(), subtitleParsers[parserIndex]);
|
||||
@ -181,8 +180,8 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seekTo(long positionUs) {
|
||||
source.seekToUs(positionUs);
|
||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
||||
super.seekTo(positionUs);
|
||||
seekToInternal();
|
||||
}
|
||||
|
||||
@ -196,8 +195,7 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||
|
||||
@Override
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||
source.continueBuffering(trackIndex, positionUs);
|
||||
|
||||
continueBufferingSource(positionUs);
|
||||
if (nextSubtitle == null) {
|
||||
try {
|
||||
nextSubtitle = parserHelper.getAndClearResult();
|
||||
@ -241,7 +239,7 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||
// Try and read the next subtitle from the source.
|
||||
SampleHolder sampleHolder = parserHelper.getSampleHolder();
|
||||
sampleHolder.clearData();
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
int result = readSource(positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.SAMPLE_READ) {
|
||||
parserHelper.startParseOperation();
|
||||
} else if (result == SampleSource.END_OF_STREAM) {
|
||||
@ -251,33 +249,14 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisabled() {
|
||||
protected void onDisabled() throws ExoPlaybackException {
|
||||
subtitle = null;
|
||||
nextSubtitle = null;
|
||||
parserThread.quit();
|
||||
parserThread = null;
|
||||
parserHelper = null;
|
||||
clearTextRenderer();
|
||||
source.disable(trackIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReleased() {
|
||||
source.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(trackIndex).durationUs;
|
||||
super.onDisabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,7 +20,8 @@ import com.google.android.exoplayer.ExoPlaybackException;
|
||||
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.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;
|
||||
@ -32,14 +33,13 @@ import android.os.Handler.Callback;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* A {@link TrackRenderer} for EIA-608 closed captions in a media stream.
|
||||
*/
|
||||
public final class Eia608TrackRenderer extends TrackRenderer implements Callback {
|
||||
public final class Eia608TrackRenderer extends SampleSourceTrackRenderer implements Callback {
|
||||
|
||||
private static final int MSG_INVOKE_RENDERER = 0;
|
||||
|
||||
@ -53,7 +53,6 @@ public final class Eia608TrackRenderer extends TrackRenderer implements Callback
|
||||
// The maximum duration that captions are parsed ahead of the current position.
|
||||
private static final int MAX_SAMPLE_READAHEAD_US = 5000000;
|
||||
|
||||
private final SampleSourceReader source;
|
||||
private final Eia608Parser eia608Parser;
|
||||
private final TextRenderer textRenderer;
|
||||
private final Handler textRendererHandler;
|
||||
@ -62,9 +61,7 @@ public final class Eia608TrackRenderer extends TrackRenderer implements Callback
|
||||
private final StringBuilder captionStringBuilder;
|
||||
private final TreeSet<ClosedCaptionList> pendingCaptionLists;
|
||||
|
||||
private int trackIndex;
|
||||
private boolean inputStreamEnded;
|
||||
|
||||
private int captionMode;
|
||||
private int captionRowCount;
|
||||
private String caption;
|
||||
@ -81,7 +78,7 @@ public final class Eia608TrackRenderer extends TrackRenderer implements Callback
|
||||
*/
|
||||
public Eia608TrackRenderer(SampleSource source, TextRenderer textRenderer,
|
||||
Looper textRendererLooper) {
|
||||
this.source = source.register();
|
||||
super(source);
|
||||
this.textRenderer = Assertions.checkNotNull(textRenderer);
|
||||
textRendererHandler = textRendererLooper == null ? null : new Handler(textRendererLooper, this);
|
||||
eia608Parser = new Eia608Parser();
|
||||
@ -92,30 +89,19 @@ public final class Eia608TrackRenderer extends TrackRenderer implements Callback
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
if (eia608Parser.canParse(source.getTrackInfo(i).mimeType)) {
|
||||
trackIndex = i;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
}
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
protected boolean handlesTrack(TrackInfo trackInfo) {
|
||||
return eia608Parser.canParse(trackInfo.mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(long positionUs, boolean joining) {
|
||||
source.enable(trackIndex, positionUs);
|
||||
protected void onEnabled(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
super.onEnabled(positionUs, joining);
|
||||
seekToInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
||||
source.seekToUs(positionUs);
|
||||
super.seekTo(positionUs);
|
||||
seekToInternal();
|
||||
}
|
||||
|
||||
@ -130,15 +116,14 @@ public final class Eia608TrackRenderer extends TrackRenderer implements Callback
|
||||
|
||||
@Override
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||
source.continueBuffering(trackIndex, positionUs);
|
||||
|
||||
continueBufferingSource(positionUs);
|
||||
if (isSamplePending()) {
|
||||
maybeParsePendingSample(positionUs);
|
||||
}
|
||||
|
||||
int result = inputStreamEnded ? SampleSource.END_OF_STREAM : SampleSource.SAMPLE_READ;
|
||||
while (!isSamplePending() && result == SampleSource.SAMPLE_READ) {
|
||||
result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
result = readSource(positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.SAMPLE_READ) {
|
||||
maybeParsePendingSample(positionUs);
|
||||
} else if (result == SampleSource.END_OF_STREAM) {
|
||||
@ -161,25 +146,6 @@ public final class Eia608TrackRenderer extends TrackRenderer implements Callback
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisabled() {
|
||||
source.disable(trackIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(trackIndex).durationUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getBufferedPositionUs() {
|
||||
return TrackRenderer.END_OF_TRACK_US;
|
||||
|
Loading…
x
Reference in New Issue
Block a user