diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/full/FullPlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer/demo/full/FullPlayerActivity.java index 0a4f2b626f..668b02cbf2 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/full/FullPlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/full/FullPlayerActivity.java @@ -25,7 +25,6 @@ import com.google.android.exoplayer.demo.full.player.DemoPlayer; import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder; import com.google.android.exoplayer.demo.full.player.HlsRendererBuilder; import com.google.android.exoplayer.demo.full.player.SmoothStreamingRendererBuilder; -import com.google.android.exoplayer.metadata.ClosedCaption; import com.google.android.exoplayer.metadata.TxxxMetadata; import com.google.android.exoplayer.text.CaptionStyleCompat; import com.google.android.exoplayer.text.SubtitleView; @@ -57,15 +56,13 @@ import android.widget.PopupMenu; import android.widget.PopupMenu.OnMenuItemClickListener; import android.widget.TextView; -import java.util.List; import java.util.Map; /** * An activity that plays media using {@link DemoPlayer}. */ public class FullPlayerActivity extends Activity implements SurfaceHolder.Callback, OnClickListener, - DemoPlayer.Listener, DemoPlayer.TextListener, DemoPlayer.Id3MetadataListener, - DemoPlayer.ClosedCaptionListener { + DemoPlayer.Listener, DemoPlayer.TextListener, DemoPlayer.Id3MetadataListener { private static final String TAG = "FullPlayerActivity"; @@ -198,7 +195,6 @@ public class FullPlayerActivity extends Activity implements SurfaceHolder.Callba player.addListener(this); player.setTextListener(this); player.setMetadataListener(this); - player.setClosedCaptionListener(this); player.seekTo(playerPosition); playerNeedsPrepare = true; mediaController.setMediaPlayer(player.getPlayerControl()); @@ -428,31 +424,6 @@ public class FullPlayerActivity extends Activity implements SurfaceHolder.Callba } } - // DemoPlayer.ClosedCaptioListener implementation - - @Override - public void onClosedCaption(List closedCaptions) { - StringBuilder stringBuilder = new StringBuilder(); - for (ClosedCaption caption : closedCaptions) { - // Ignore control characters and just insert a new line in between words. - if (caption.type == ClosedCaption.TYPE_CTRL) { - if (stringBuilder.length() > 0 - && stringBuilder.charAt(stringBuilder.length() - 1) != '\n') { - stringBuilder.append('\n'); - } - } else if (caption.type == ClosedCaption.TYPE_TEXT) { - stringBuilder.append(caption.text); - } - } - if (stringBuilder.length() > 0 && stringBuilder.charAt(stringBuilder.length() - 1) == '\n') { - stringBuilder.deleteCharAt(stringBuilder.length() - 1); - } - if (stringBuilder.length() > 0) { - subtitleView.setVisibility(View.VISIBLE); - subtitleView.setText(stringBuilder.toString()); - } - } - // SurfaceHolder.Callback implementation @Override diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/full/player/DemoPlayer.java b/demo/src/main/java/com/google/android/exoplayer/demo/full/player/DemoPlayer.java index cdd1445a34..816312cee8 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/full/player/DemoPlayer.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/full/player/DemoPlayer.java @@ -145,13 +145,6 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi void onId3Metadata(Map metadata); } - /** - * A listener for receiving closed captions parsed from the media stream. - */ - public interface ClosedCaptionListener { - void onClosedCaption(List closedCaptions); - } - // Constants pulled into this class for convenience. public static final int STATE_IDLE = ExoPlayer.STATE_IDLE; public static final int STATE_PREPARING = ExoPlayer.STATE_PREPARING; @@ -162,13 +155,12 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi public static final int DISABLED_TRACK = -1; public static final int PRIMARY_TRACK = 0; - public static final int RENDERER_COUNT = 6; + public static final int RENDERER_COUNT = 5; public static final int TYPE_VIDEO = 0; public static final int TYPE_AUDIO = 1; public static final int TYPE_TEXT = 2; public static final int TYPE_TIMED_METADATA = 3; - public static final int TYPE_CLOSED_CAPTIONS = 4; - public static final int TYPE_DEBUG = 5; + public static final int TYPE_DEBUG = 4; private static final int RENDERER_BUILDING_STATE_IDLE = 1; private static final int RENDERER_BUILDING_STATE_BUILDING = 2; @@ -179,6 +171,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi private final PlayerControl playerControl; private final Handler mainHandler; private final CopyOnWriteArrayList listeners; + private final StringBuilder closedCaptionStringBuilder; private int rendererBuildingState; private int lastReportedPlaybackState; @@ -194,7 +187,6 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi private TextListener textListener; private Id3MetadataListener id3MetadataListener; - private ClosedCaptionListener closedCaptionListener; private InternalErrorListener internalErrorListener; private InfoListener infoListener; @@ -210,6 +202,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi selectedTracks = new int[RENDERER_COUNT]; // Disable text initially. selectedTracks[TYPE_TEXT] = DISABLED_TRACK; + closedCaptionStringBuilder = new StringBuilder(); } public PlayerControl getPlayerControl() { @@ -240,10 +233,6 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi id3MetadataListener = listener; } - public void setClosedCaptionListener(ClosedCaptionListener listener) { - closedCaptionListener = listener; - } - public void setSurface(Surface surface) { this.surface = surface; pushSurfaceAndVideoTrack(false); @@ -275,6 +264,9 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi pushSurfaceAndVideoTrack(false); } else { pushTrackSelection(type, true); + if (type == TYPE_TEXT && index == DISABLED_TRACK && textListener != null) { + textListener.onText(null); + } } } @@ -483,36 +475,28 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi @Override public void onText(String text) { - if (textListener != null) { - textListener.onText(text); - } + processText(text); } /* package */ MetadataTrackRenderer.MetadataRenderer> getId3MetadataRenderer() { return new MetadataTrackRenderer.MetadataRenderer>() { - @Override public void onMetadata(Map metadata) { if (id3MetadataListener != null) { id3MetadataListener.onId3Metadata(metadata); } } - }; } /* package */ MetadataTrackRenderer.MetadataRenderer> getClosedCaptionMetadataRenderer() { return new MetadataTrackRenderer.MetadataRenderer>() { - @Override public void onMetadata(List metadata) { - if (closedCaptionListener != null) { - closedCaptionListener.onClosedCaption(metadata); - } + processClosedCaption(metadata); } - }; } @@ -607,6 +591,36 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi } } + /* package */ void processText(String text) { + if (textListener == null || selectedTracks[TYPE_TEXT] == DISABLED_TRACK) { + return; + } + textListener.onText(text); + } + + /* package */ void processClosedCaption(List metadata) { + if (textListener == null || selectedTracks[TYPE_TEXT] == DISABLED_TRACK) { + return; + } + closedCaptionStringBuilder.setLength(0); + for (ClosedCaption caption : metadata) { + // Ignore control characters and just insert a new line in between words. + if (caption.type == ClosedCaption.TYPE_CTRL) { + if (closedCaptionStringBuilder.length() > 0 + && closedCaptionStringBuilder.charAt(closedCaptionStringBuilder.length() - 1) != '\n') { + closedCaptionStringBuilder.append('\n'); + } + } else if (caption.type == ClosedCaption.TYPE_TEXT) { + closedCaptionStringBuilder.append(caption.text); + } + } + if (closedCaptionStringBuilder.length() > 0 + && closedCaptionStringBuilder.charAt(closedCaptionStringBuilder.length() - 1) == '\n') { + closedCaptionStringBuilder.deleteCharAt(closedCaptionStringBuilder.length() - 1); + } + textListener.onText(closedCaptionStringBuilder.toString()); + } + private class InternalRendererBuilderCallback implements RendererBuilderCallback { private boolean canceled; diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/full/player/HlsRendererBuilder.java b/demo/src/main/java/com/google/android/exoplayer/demo/full/player/HlsRendererBuilder.java index 5a3a3535e9..9d7a06a554 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/full/player/HlsRendererBuilder.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/full/player/HlsRendererBuilder.java @@ -100,7 +100,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback= targetBufferDurationUs)) { + // We're either finished, or we have the target amount of data buffered. return null; } @@ -303,8 +341,8 @@ public class HlsChunkSource { : adaptiveMode == ADAPTIVE_MODE_SPLICE ? previousTsChunk.startTimeUs : previousTsChunk.endTimeUs; long bufferedUs = bufferedPositionUs - playbackPositionUs; - if ((idealVariantIndex > variantIndex && bufferedUs < MAX_BUFFER_TO_SWITCH_DOWN_US) - || (idealVariantIndex < variantIndex && bufferedUs > MIN_BUFFER_TO_SWITCH_UP_US)) { + if ((idealVariantIndex > variantIndex && bufferedUs < maxBufferDurationToSwitchDownUs) + || (idealVariantIndex < variantIndex && bufferedUs > minBufferDurationToSwitchUpUs)) { // Switch variant. return idealVariantIndex; } diff --git a/library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java b/library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java index e2ef450970..00e4e4f513 100644 --- a/library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java @@ -40,7 +40,6 @@ public class HlsSampleSource implements SampleSource, Loader.Callback { */ public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 1; - private static final long BUFFER_DURATION_US = 20000000; private static final int NO_RESET_PENDING = -1; private final HlsChunkSource chunkSource; @@ -350,7 +349,7 @@ public class HlsSampleSource implements SampleSource, Loader.Callback { } private void maybeStartLoading() { - if (currentLoadableExceptionFatal || loadingFinished) { + if (currentLoadableExceptionFatal || loadingFinished || loader.isLoading()) { return; } @@ -364,17 +363,6 @@ public class HlsSampleSource implements SampleSource, Loader.Callback { return; } - boolean bufferFull = false; - if (!extractors.isEmpty()) { - long largestSampleTimestamp = extractors.getLast().getLargestSampleTimestamp(); - bufferFull = largestSampleTimestamp != Long.MIN_VALUE - && (largestSampleTimestamp - downstreamPositionUs) >= BUFFER_DURATION_US; - } - - if (loader.isLoading() || bufferFull) { - return; - } - HlsChunk nextLoadable = chunkSource.getChunkOperation(previousTsLoadable, pendingResetPositionUs, downstreamPositionUs); if (nextLoadable == null) {