mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Yet more simplifications.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=118775612
This commit is contained in:
parent
9c2a971109
commit
b041b72bae
5 changed files with 150 additions and 219 deletions
|
|
@ -31,11 +31,10 @@ import com.google.android.exoplayer.TimeRange;
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
import com.google.android.exoplayer.TrackRenderer;
|
||||||
import com.google.android.exoplayer.audio.AudioCapabilities;
|
import com.google.android.exoplayer.audio.AudioCapabilities;
|
||||||
import com.google.android.exoplayer.audio.AudioTrack;
|
import com.google.android.exoplayer.audio.AudioTrack;
|
||||||
import com.google.android.exoplayer.chunk.ChunkSampleSource;
|
import com.google.android.exoplayer.chunk.ChunkSampleSourceEventListener;
|
||||||
import com.google.android.exoplayer.dash.DashChunkSource;
|
import com.google.android.exoplayer.dash.DashChunkSource;
|
||||||
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
||||||
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
||||||
import com.google.android.exoplayer.hls.HlsSampleSource;
|
|
||||||
import com.google.android.exoplayer.metadata.MetadataTrackRenderer;
|
import com.google.android.exoplayer.metadata.MetadataTrackRenderer;
|
||||||
import com.google.android.exoplayer.metadata.MetadataTrackRenderer.MetadataRenderer;
|
import com.google.android.exoplayer.metadata.MetadataTrackRenderer.MetadataRenderer;
|
||||||
import com.google.android.exoplayer.metadata.id3.Id3Frame;
|
import com.google.android.exoplayer.metadata.id3.Id3Frame;
|
||||||
|
|
@ -65,12 +64,11 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
* SmoothStreaming and so on).
|
* SmoothStreaming and so on).
|
||||||
*/
|
*/
|
||||||
public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.EventListener,
|
public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.EventListener,
|
||||||
ChunkSampleSource.EventListener, HlsSampleSource.EventListener,
|
ChunkSampleSourceEventListener, ExtractorSampleSource.EventListener,
|
||||||
ExtractorSampleSource.EventListener, SingleSampleSource.EventListener,
|
SingleSampleSource.EventListener, DefaultBandwidthMeter.EventListener,
|
||||||
DefaultBandwidthMeter.EventListener, MediaCodecVideoTrackRenderer.EventListener,
|
MediaCodecVideoTrackRenderer.EventListener, MediaCodecAudioTrackRenderer.EventListener,
|
||||||
MediaCodecAudioTrackRenderer.EventListener, StreamingDrmSessionManager.EventListener,
|
StreamingDrmSessionManager.EventListener, DashChunkSource.EventListener, TextRenderer,
|
||||||
DashChunkSource.EventListener, TextRenderer, MetadataRenderer<List<Id3Frame>>,
|
MetadataRenderer<List<Id3Frame>>, DebugTextViewHelper.Provider {
|
||||||
DebugTextViewHelper.Provider {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a source to play.
|
* Builds a source to play.
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,11 @@ import com.google.android.exoplayer.TrackGroup;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
import com.google.android.exoplayer.TrackSelection;
|
import com.google.android.exoplayer.TrackSelection;
|
||||||
import com.google.android.exoplayer.TrackStream;
|
import com.google.android.exoplayer.TrackStream;
|
||||||
|
import com.google.android.exoplayer.chunk.ChunkSampleSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
||||||
import com.google.android.exoplayer.upstream.Loader;
|
import com.google.android.exoplayer.upstream.Loader;
|
||||||
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer.util.Assertions;
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
import com.google.android.exoplayer.util.Util;
|
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
|
@ -45,11 +45,6 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Callback {
|
public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Callback {
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface definition for a callback to be notified of {@link ChunkSampleSource} events.
|
|
||||||
*/
|
|
||||||
public interface EventListener extends BaseChunkSampleSourceEventListener {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default minimum number of times to retry loading data prior to failing.
|
* The default minimum number of times to retry loading data prior to failing.
|
||||||
*/
|
*/
|
||||||
|
|
@ -58,7 +53,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
private static final long NO_RESET_PENDING = Long.MIN_VALUE;
|
private static final long NO_RESET_PENDING = Long.MIN_VALUE;
|
||||||
|
|
||||||
private final Loader loader;
|
private final Loader loader;
|
||||||
private final int eventSourceId;
|
|
||||||
private final LoadControl loadControl;
|
private final LoadControl loadControl;
|
||||||
private final ChunkSource chunkSource;
|
private final ChunkSource chunkSource;
|
||||||
private final ChunkOperationHolder currentLoadableHolder;
|
private final ChunkOperationHolder currentLoadableHolder;
|
||||||
|
|
@ -66,8 +60,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
private final List<BaseMediaChunk> readOnlyMediaChunks;
|
private final List<BaseMediaChunk> readOnlyMediaChunks;
|
||||||
private final DefaultTrackOutput sampleQueue;
|
private final DefaultTrackOutput sampleQueue;
|
||||||
private final int bufferSizeContribution;
|
private final int bufferSizeContribution;
|
||||||
private final Handler eventHandler;
|
private final EventDispatcher eventDispatcher;
|
||||||
private final EventListener eventListener;
|
|
||||||
|
|
||||||
private boolean prepared;
|
private boolean prepared;
|
||||||
private long downstreamPositionUs;
|
private long downstreamPositionUs;
|
||||||
|
|
@ -106,8 +99,8 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
* @param eventSourceId An identifier that gets passed to {@code eventListener} methods.
|
* @param eventSourceId An identifier that gets passed to {@code eventListener} methods.
|
||||||
*/
|
*/
|
||||||
public ChunkSampleSource(ChunkSource chunkSource, LoadControl loadControl,
|
public ChunkSampleSource(ChunkSource chunkSource, LoadControl loadControl,
|
||||||
int bufferSizeContribution, Handler eventHandler, EventListener eventListener,
|
int bufferSizeContribution, Handler eventHandler,
|
||||||
int eventSourceId) {
|
ChunkSampleSourceEventListener eventListener, int eventSourceId) {
|
||||||
this(chunkSource, loadControl, bufferSizeContribution, eventHandler, eventListener,
|
this(chunkSource, loadControl, bufferSizeContribution, eventHandler, eventListener,
|
||||||
eventSourceId, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
eventSourceId, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
||||||
}
|
}
|
||||||
|
|
@ -124,15 +117,13 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
* before propagating an error.
|
* before propagating an error.
|
||||||
*/
|
*/
|
||||||
public ChunkSampleSource(ChunkSource chunkSource, LoadControl loadControl,
|
public ChunkSampleSource(ChunkSource chunkSource, LoadControl loadControl,
|
||||||
int bufferSizeContribution, Handler eventHandler, EventListener eventListener,
|
int bufferSizeContribution, Handler eventHandler,
|
||||||
int eventSourceId, int minLoadableRetryCount) {
|
ChunkSampleSourceEventListener eventListener, int eventSourceId, int minLoadableRetryCount) {
|
||||||
this.chunkSource = chunkSource;
|
this.chunkSource = chunkSource;
|
||||||
this.loadControl = loadControl;
|
this.loadControl = loadControl;
|
||||||
this.bufferSizeContribution = bufferSizeContribution;
|
this.bufferSizeContribution = bufferSizeContribution;
|
||||||
this.eventHandler = eventHandler;
|
|
||||||
this.eventListener = eventListener;
|
|
||||||
this.eventSourceId = eventSourceId;
|
|
||||||
loader = new Loader("Loader:ChunkSampleSource", minLoadableRetryCount);
|
loader = new Loader("Loader:ChunkSampleSource", minLoadableRetryCount);
|
||||||
|
eventDispatcher = new EventDispatcher(eventHandler, eventListener, eventSourceId);
|
||||||
currentLoadableHolder = new ChunkOperationHolder();
|
currentLoadableHolder = new ChunkOperationHolder();
|
||||||
mediaChunks = new LinkedList<>();
|
mediaChunks = new LinkedList<>();
|
||||||
readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks);
|
readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks);
|
||||||
|
|
@ -200,9 +191,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
if (loader.isLoading()) {
|
if (loader.isLoading()) {
|
||||||
loader.cancelLoading();
|
loader.cancelLoading();
|
||||||
} else {
|
} else {
|
||||||
sampleQueue.clear();
|
clearState();
|
||||||
mediaChunks.clear();
|
|
||||||
clearCurrentLoadable();
|
|
||||||
loadControl.trimAllocator();
|
loadControl.trimAllocator();
|
||||||
}
|
}
|
||||||
} else if (trackEnabled) {
|
} else if (trackEnabled) {
|
||||||
|
|
@ -307,7 +296,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downstreamFormat == null || !downstreamFormat.equals(currentChunk.format)) {
|
if (downstreamFormat == null || !downstreamFormat.equals(currentChunk.format)) {
|
||||||
notifyDownstreamFormatChanged(currentChunk.format, currentChunk.trigger,
|
eventDispatcher.downstreamFormatChanged(currentChunk.format, currentChunk.trigger,
|
||||||
currentChunk.startTimeUs);
|
currentChunk.startTimeUs);
|
||||||
downstreamFormat = currentChunk.format;
|
downstreamFormat = currentChunk.format;
|
||||||
}
|
}
|
||||||
|
|
@ -351,10 +340,11 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
chunkSource.onChunkLoadCompleted(currentLoadable);
|
chunkSource.onChunkLoadCompleted(currentLoadable);
|
||||||
if (isMediaChunk(currentLoadable)) {
|
if (isMediaChunk(currentLoadable)) {
|
||||||
BaseMediaChunk mediaChunk = (BaseMediaChunk) currentLoadable;
|
BaseMediaChunk mediaChunk = (BaseMediaChunk) currentLoadable;
|
||||||
notifyLoadCompleted(currentLoadable.bytesLoaded(), mediaChunk.type, mediaChunk.trigger,
|
eventDispatcher.loadCompleted(currentLoadable.bytesLoaded(), mediaChunk.type,
|
||||||
mediaChunk.format, mediaChunk.startTimeUs, mediaChunk.endTimeUs, now, loadDurationMs);
|
mediaChunk.trigger, mediaChunk.format, mediaChunk.startTimeUs, mediaChunk.endTimeUs, now,
|
||||||
|
loadDurationMs);
|
||||||
} else {
|
} else {
|
||||||
notifyLoadCompleted(currentLoadable.bytesLoaded(), currentLoadable.type,
|
eventDispatcher.loadCompleted(currentLoadable.bytesLoaded(), currentLoadable.type,
|
||||||
currentLoadable.trigger, currentLoadable.format, -1, -1, now, loadDurationMs);
|
currentLoadable.trigger, currentLoadable.format, -1, -1, now, loadDurationMs);
|
||||||
}
|
}
|
||||||
clearCurrentLoadable();
|
clearCurrentLoadable();
|
||||||
|
|
@ -364,13 +354,11 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
@Override
|
@Override
|
||||||
public void onLoadCanceled(Loadable loadable) {
|
public void onLoadCanceled(Loadable loadable) {
|
||||||
Chunk currentLoadable = currentLoadableHolder.chunk;
|
Chunk currentLoadable = currentLoadableHolder.chunk;
|
||||||
notifyLoadCanceled(currentLoadable.bytesLoaded());
|
eventDispatcher.loadCanceled(currentLoadable.bytesLoaded());
|
||||||
clearCurrentLoadable();
|
|
||||||
if (trackEnabled) {
|
if (trackEnabled) {
|
||||||
restartFrom(pendingResetPositionUs);
|
restartFrom(pendingResetPositionUs);
|
||||||
} else {
|
} else {
|
||||||
sampleQueue.clear();
|
clearState();
|
||||||
mediaChunks.clear();
|
|
||||||
loadControl.trimAllocator();
|
loadControl.trimAllocator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -391,12 +379,12 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clearCurrentLoadable();
|
clearCurrentLoadable();
|
||||||
notifyLoadError(e);
|
eventDispatcher.loadError(e);
|
||||||
notifyLoadCanceled(bytesLoaded);
|
eventDispatcher.loadCanceled(bytesLoaded);
|
||||||
maybeStartLoading();
|
maybeStartLoading();
|
||||||
return Loader.DONT_RETRY;
|
return Loader.DONT_RETRY;
|
||||||
} else {
|
} else {
|
||||||
notifyLoadError(e);
|
eventDispatcher.loadError(e);
|
||||||
return Loader.RETRY;
|
return Loader.RETRY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -420,13 +408,17 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
if (loader.isLoading()) {
|
if (loader.isLoading()) {
|
||||||
loader.cancelLoading();
|
loader.cancelLoading();
|
||||||
} else {
|
} else {
|
||||||
sampleQueue.clear();
|
clearState();
|
||||||
mediaChunks.clear();
|
|
||||||
clearCurrentLoadable();
|
|
||||||
maybeStartLoading();
|
maybeStartLoading();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearState() {
|
||||||
|
sampleQueue.clear();
|
||||||
|
mediaChunks.clear();
|
||||||
|
clearCurrentLoadable();
|
||||||
|
}
|
||||||
|
|
||||||
private void clearCurrentLoadable() {
|
private void clearCurrentLoadable() {
|
||||||
currentLoadableHolder.chunk = null;
|
currentLoadableHolder.chunk = null;
|
||||||
}
|
}
|
||||||
|
|
@ -482,10 +474,10 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
if (isPendingReset()) {
|
if (isPendingReset()) {
|
||||||
pendingResetPositionUs = NO_RESET_PENDING;
|
pendingResetPositionUs = NO_RESET_PENDING;
|
||||||
}
|
}
|
||||||
notifyLoadStarted(mediaChunk.dataSpec.length, mediaChunk.type, mediaChunk.trigger,
|
eventDispatcher.loadStarted(mediaChunk.dataSpec.length, mediaChunk.type, mediaChunk.trigger,
|
||||||
mediaChunk.format, mediaChunk.startTimeUs, mediaChunk.endTimeUs);
|
mediaChunk.format, mediaChunk.startTimeUs, mediaChunk.endTimeUs);
|
||||||
} else {
|
} else {
|
||||||
notifyLoadStarted(currentLoadable.dataSpec.length, currentLoadable.type,
|
eventDispatcher.loadStarted(currentLoadable.dataSpec.length, currentLoadable.type,
|
||||||
currentLoadable.trigger, currentLoadable.format, -1, -1);
|
currentLoadable.trigger, currentLoadable.format, -1, -1);
|
||||||
}
|
}
|
||||||
loader.startLoading(currentLoadable, this);
|
loader.startLoading(currentLoadable, this);
|
||||||
|
|
@ -524,8 +516,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
startTimeUs = removed.startTimeUs;
|
startTimeUs = removed.startTimeUs;
|
||||||
}
|
}
|
||||||
sampleQueue.discardUpstreamSamples(removed.getFirstSampleIndex());
|
sampleQueue.discardUpstreamSamples(removed.getFirstSampleIndex());
|
||||||
|
eventDispatcher.upstreamDiscarded(startTimeUs, endTimeUs);
|
||||||
notifyUpstreamDiscarded(startTimeUs, endTimeUs);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -537,79 +528,4 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
||||||
return pendingResetPositionUs != NO_RESET_PENDING;
|
return pendingResetPositionUs != NO_RESET_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyLoadStarted(final long length, final int type, final int trigger,
|
|
||||||
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onLoadStarted(eventSourceId, length, type, trigger, format,
|
|
||||||
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyLoadCompleted(final long bytesLoaded, final int type, final int trigger,
|
|
||||||
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs,
|
|
||||||
final long elapsedRealtimeMs, final long loadDurationMs) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onLoadCompleted(eventSourceId, bytesLoaded, type, trigger, format,
|
|
||||||
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs), elapsedRealtimeMs,
|
|
||||||
loadDurationMs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyLoadCanceled(final long bytesLoaded) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onLoadCanceled(eventSourceId, bytesLoaded);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyLoadError(final IOException e) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onLoadError(eventSourceId, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyUpstreamDiscarded(final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onUpstreamDiscarded(eventSourceId, Util.usToMs(mediaStartTimeUs),
|
|
||||||
Util.usToMs(mediaEndTimeUs));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyDownstreamFormatChanged(final Format format, final int trigger,
|
|
||||||
final long positionUs) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onDownstreamFormatChanged(eventSourceId, format, trigger,
|
|
||||||
Util.usToMs(positionUs));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,16 @@ import com.google.android.exoplayer.C;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.SampleSource;
|
import com.google.android.exoplayer.SampleSource;
|
||||||
import com.google.android.exoplayer.TrackStream;
|
import com.google.android.exoplayer.TrackStream;
|
||||||
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for callbacks to be notified of chunk based {@link SampleSource} events.
|
* Interface for callbacks to be notified of chunk based {@link SampleSource} events.
|
||||||
*/
|
*/
|
||||||
public interface BaseChunkSampleSourceEventListener {
|
public interface ChunkSampleSourceEventListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when an upstream load is started.
|
* Invoked when an upstream load is started.
|
||||||
|
|
@ -102,4 +105,96 @@ public interface BaseChunkSampleSourceEventListener {
|
||||||
*/
|
*/
|
||||||
void onDownstreamFormatChanged(int sourceId, Format format, int trigger, long mediaTimeMs);
|
void onDownstreamFormatChanged(int sourceId, Format format, int trigger, long mediaTimeMs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches events to a {@link ChunkSampleSourceEventListener}.
|
||||||
|
*/
|
||||||
|
final class EventDispatcher {
|
||||||
|
|
||||||
|
private final Handler handler;
|
||||||
|
private final ChunkSampleSourceEventListener listener;
|
||||||
|
private final int sourceId;
|
||||||
|
|
||||||
|
public EventDispatcher(Handler handler, ChunkSampleSourceEventListener listener, int sourceId) {
|
||||||
|
this.handler = listener != null ? handler : null;
|
||||||
|
this.listener = listener;
|
||||||
|
this.sourceId = sourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadStarted(final long length, final int type, final int trigger,
|
||||||
|
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
||||||
|
if (listener != null) {
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.onLoadStarted(sourceId, length, type, trigger, format,
|
||||||
|
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadCompleted(final long bytesLoaded, final int type, final int trigger,
|
||||||
|
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs,
|
||||||
|
final long elapsedRealtimeMs, final long loadDurationMs) {
|
||||||
|
if (listener != null) {
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.onLoadCompleted(sourceId, bytesLoaded, type, trigger, format,
|
||||||
|
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs), elapsedRealtimeMs,
|
||||||
|
loadDurationMs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadCanceled(final long bytesLoaded) {
|
||||||
|
if (listener != null) {
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.onLoadCanceled(sourceId, bytesLoaded);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadError(final IOException e) {
|
||||||
|
if (listener != null) {
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.onLoadError(sourceId, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void upstreamDiscarded(final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
||||||
|
if (listener != null) {
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.onUpstreamDiscarded(sourceId, Util.usToMs(mediaStartTimeUs),
|
||||||
|
Util.usToMs(mediaEndTimeUs));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void downstreamFormatChanged(final Format format, final int trigger,
|
||||||
|
final long positionUs) {
|
||||||
|
if (listener != null) {
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.onDownstreamFormatChanged(sourceId, format, trigger,
|
||||||
|
Util.usToMs(positionUs));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -18,7 +18,6 @@ package com.google.android.exoplayer.hls;
|
||||||
import com.google.android.exoplayer.BehindLiveWindowException;
|
import com.google.android.exoplayer.BehindLiveWindowException;
|
||||||
import com.google.android.exoplayer.C;
|
import com.google.android.exoplayer.C;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener;
|
|
||||||
import com.google.android.exoplayer.chunk.Chunk;
|
import com.google.android.exoplayer.chunk.Chunk;
|
||||||
import com.google.android.exoplayer.chunk.ChunkOperationHolder;
|
import com.google.android.exoplayer.chunk.ChunkOperationHolder;
|
||||||
import com.google.android.exoplayer.chunk.DataChunk;
|
import com.google.android.exoplayer.chunk.DataChunk;
|
||||||
|
|
@ -57,11 +56,6 @@ import java.util.Locale;
|
||||||
*/
|
*/
|
||||||
public class HlsChunkSource {
|
public class HlsChunkSource {
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface definition for a callback to be notified of {@link HlsChunkSource} events.
|
|
||||||
*/
|
|
||||||
public interface EventListener extends BaseChunkSampleSourceEventListener {}
|
|
||||||
|
|
||||||
public static final int TYPE_DEFAULT = 0;
|
public static final int TYPE_DEFAULT = 0;
|
||||||
public static final int TYPE_AUDIO = 1;
|
public static final int TYPE_AUDIO = 1;
|
||||||
public static final int TYPE_SUBTITLE = 2;
|
public static final int TYPE_SUBTITLE = 2;
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,14 @@ import com.google.android.exoplayer.TrackGroup;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
import com.google.android.exoplayer.TrackSelection;
|
import com.google.android.exoplayer.TrackSelection;
|
||||||
import com.google.android.exoplayer.TrackStream;
|
import com.google.android.exoplayer.TrackStream;
|
||||||
import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener;
|
|
||||||
import com.google.android.exoplayer.chunk.Chunk;
|
import com.google.android.exoplayer.chunk.Chunk;
|
||||||
import com.google.android.exoplayer.chunk.ChunkOperationHolder;
|
import com.google.android.exoplayer.chunk.ChunkOperationHolder;
|
||||||
|
import com.google.android.exoplayer.chunk.ChunkSampleSourceEventListener;
|
||||||
|
import com.google.android.exoplayer.chunk.ChunkSampleSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer.upstream.Loader;
|
import com.google.android.exoplayer.upstream.Loader;
|
||||||
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer.util.Assertions;
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
import com.google.android.exoplayer.util.MimeTypes;
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
import com.google.android.exoplayer.util.Util;
|
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
|
@ -47,11 +47,6 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface definition for a callback to be notified of {@link HlsSampleSource} events.
|
|
||||||
*/
|
|
||||||
public interface EventListener extends BaseChunkSampleSourceEventListener {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default minimum number of times to retry loading data prior to failing.
|
* The default minimum number of times to retry loading data prior to failing.
|
||||||
*/
|
*/
|
||||||
|
|
@ -69,11 +64,8 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
private final LinkedList<HlsExtractorWrapper> extractors;
|
private final LinkedList<HlsExtractorWrapper> extractors;
|
||||||
private final int bufferSizeContribution;
|
private final int bufferSizeContribution;
|
||||||
private final ChunkOperationHolder chunkOperationHolder;
|
private final ChunkOperationHolder chunkOperationHolder;
|
||||||
|
private final EventDispatcher eventDispatcher;
|
||||||
private final int eventSourceId;
|
|
||||||
private final LoadControl loadControl;
|
private final LoadControl loadControl;
|
||||||
private final Handler eventHandler;
|
|
||||||
private final EventListener eventListener;
|
|
||||||
|
|
||||||
private boolean prepared;
|
private boolean prepared;
|
||||||
private boolean seenFirstTrackSelection;
|
private boolean seenFirstTrackSelection;
|
||||||
|
|
@ -108,23 +100,21 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
||||||
int bufferSizeContribution, Handler eventHandler, EventListener eventListener,
|
int bufferSizeContribution, Handler eventHandler,
|
||||||
int eventSourceId) {
|
ChunkSampleSourceEventListener eventListener, int eventSourceId) {
|
||||||
this(chunkSource, loadControl, bufferSizeContribution, eventHandler, eventListener,
|
this(chunkSource, loadControl, bufferSizeContribution, eventHandler, eventListener,
|
||||||
eventSourceId, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
eventSourceId, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
||||||
int bufferSizeContribution, Handler eventHandler, EventListener eventListener,
|
int bufferSizeContribution, Handler eventHandler,
|
||||||
int eventSourceId, int minLoadableRetryCount) {
|
ChunkSampleSourceEventListener eventListener, int eventSourceId, int minLoadableRetryCount) {
|
||||||
this.chunkSource = chunkSource;
|
this.chunkSource = chunkSource;
|
||||||
this.loadControl = loadControl;
|
this.loadControl = loadControl;
|
||||||
this.bufferSizeContribution = bufferSizeContribution;
|
this.bufferSizeContribution = bufferSizeContribution;
|
||||||
this.eventHandler = eventHandler;
|
|
||||||
this.eventListener = eventListener;
|
|
||||||
this.eventSourceId = eventSourceId;
|
|
||||||
this.pendingResetPositionUs = NO_RESET_PENDING;
|
this.pendingResetPositionUs = NO_RESET_PENDING;
|
||||||
loader = new Loader("Loader:HLS", minLoadableRetryCount);
|
loader = new Loader("Loader:HLS", minLoadableRetryCount);
|
||||||
|
eventDispatcher = new EventDispatcher(eventHandler, eventListener, eventSourceId);
|
||||||
extractors = new LinkedList<>();
|
extractors = new LinkedList<>();
|
||||||
chunkOperationHolder = new ChunkOperationHolder();
|
chunkOperationHolder = new ChunkOperationHolder();
|
||||||
}
|
}
|
||||||
|
|
@ -336,7 +326,8 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
|
|
||||||
if (downstreamFormat == null || !downstreamFormat.equals(extractor.format)) {
|
if (downstreamFormat == null || !downstreamFormat.equals(extractor.format)) {
|
||||||
// Notify a change in the downstream format.
|
// Notify a change in the downstream format.
|
||||||
notifyDownstreamFormatChanged(extractor.format, extractor.trigger, extractor.startTimeUs);
|
eventDispatcher.downstreamFormatChanged(extractor.format, extractor.trigger,
|
||||||
|
extractor.startTimeUs);
|
||||||
downstreamFormat = extractor.format;
|
downstreamFormat = extractor.format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,11 +380,11 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
if (isTsChunk(currentLoadable)) {
|
if (isTsChunk(currentLoadable)) {
|
||||||
Assertions.checkState(currentLoadable == currentTsLoadable);
|
Assertions.checkState(currentLoadable == currentTsLoadable);
|
||||||
previousTsLoadable = currentTsLoadable;
|
previousTsLoadable = currentTsLoadable;
|
||||||
notifyLoadCompleted(currentLoadable.bytesLoaded(), currentTsLoadable.type,
|
eventDispatcher.loadCompleted(currentLoadable.bytesLoaded(), currentTsLoadable.type,
|
||||||
currentTsLoadable.trigger, currentTsLoadable.format, currentTsLoadable.startTimeUs,
|
currentTsLoadable.trigger, currentTsLoadable.format, currentTsLoadable.startTimeUs,
|
||||||
currentTsLoadable.endTimeUs, now, loadDurationMs);
|
currentTsLoadable.endTimeUs, now, loadDurationMs);
|
||||||
} else {
|
} else {
|
||||||
notifyLoadCompleted(currentLoadable.bytesLoaded(), currentLoadable.type,
|
eventDispatcher.loadCompleted(currentLoadable.bytesLoaded(), currentLoadable.type,
|
||||||
currentLoadable.trigger, currentLoadable.format, -1, -1, now, loadDurationMs);
|
currentLoadable.trigger, currentLoadable.format, -1, -1, now, loadDurationMs);
|
||||||
}
|
}
|
||||||
clearCurrentLoadable();
|
clearCurrentLoadable();
|
||||||
|
|
@ -402,7 +393,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadCanceled(Loadable loadable) {
|
public void onLoadCanceled(Loadable loadable) {
|
||||||
notifyLoadCanceled(currentLoadable.bytesLoaded());
|
eventDispatcher.loadCanceled(currentLoadable.bytesLoaded());
|
||||||
if (enabledTrackCount > 0) {
|
if (enabledTrackCount > 0) {
|
||||||
restartFrom(pendingResetPositionUs);
|
restartFrom(pendingResetPositionUs);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -416,16 +407,16 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
long bytesLoaded = currentLoadable.bytesLoaded();
|
long bytesLoaded = currentLoadable.bytesLoaded();
|
||||||
boolean cancelable = !isTsChunk(currentLoadable) || bytesLoaded == 0;
|
boolean cancelable = !isTsChunk(currentLoadable) || bytesLoaded == 0;
|
||||||
if (chunkSource.onChunkLoadError(currentLoadable, cancelable, e)) {
|
if (chunkSource.onChunkLoadError(currentLoadable, cancelable, e)) {
|
||||||
|
eventDispatcher.loadError(e);
|
||||||
|
eventDispatcher.loadCanceled(bytesLoaded);
|
||||||
|
clearCurrentLoadable();
|
||||||
if (previousTsLoadable == null && !isPendingReset()) {
|
if (previousTsLoadable == null && !isPendingReset()) {
|
||||||
pendingResetPositionUs = lastSeekPositionUs;
|
pendingResetPositionUs = lastSeekPositionUs;
|
||||||
}
|
}
|
||||||
clearCurrentLoadable();
|
|
||||||
notifyLoadError(e);
|
|
||||||
notifyLoadCanceled(bytesLoaded);
|
|
||||||
maybeStartLoading();
|
maybeStartLoading();
|
||||||
return Loader.DONT_RETRY;
|
return Loader.DONT_RETRY;
|
||||||
} else {
|
} else {
|
||||||
notifyLoadError(e);
|
eventDispatcher.loadError(e);
|
||||||
return Loader.RETRY;
|
return Loader.RETRY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -679,11 +670,11 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
extractorWrapper.init(loadControl.getAllocator());
|
extractorWrapper.init(loadControl.getAllocator());
|
||||||
extractors.addLast(extractorWrapper);
|
extractors.addLast(extractorWrapper);
|
||||||
}
|
}
|
||||||
notifyLoadStarted(tsChunk.dataSpec.length, tsChunk.type, tsChunk.trigger, tsChunk.format,
|
eventDispatcher.loadStarted(tsChunk.dataSpec.length, tsChunk.type, tsChunk.trigger,
|
||||||
tsChunk.startTimeUs, tsChunk.endTimeUs);
|
tsChunk.format, tsChunk.startTimeUs, tsChunk.endTimeUs);
|
||||||
currentTsLoadable = tsChunk;
|
currentTsLoadable = tsChunk;
|
||||||
} else {
|
} else {
|
||||||
notifyLoadStarted(currentLoadable.dataSpec.length, currentLoadable.type,
|
eventDispatcher.loadStarted(currentLoadable.dataSpec.length, currentLoadable.type,
|
||||||
currentLoadable.trigger, currentLoadable.format, -1, -1);
|
currentLoadable.trigger, currentLoadable.format, -1, -1);
|
||||||
}
|
}
|
||||||
loader.startLoading(currentLoadable, this);
|
loader.startLoading(currentLoadable, this);
|
||||||
|
|
@ -712,69 +703,6 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||||
return pendingResetPositionUs != NO_RESET_PENDING;
|
return pendingResetPositionUs != NO_RESET_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyLoadStarted(final long length, final int type, final int trigger,
|
|
||||||
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onLoadStarted(eventSourceId, length, type, trigger, format,
|
|
||||||
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyLoadCompleted(final long bytesLoaded, final int type, final int trigger,
|
|
||||||
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs,
|
|
||||||
final long elapsedRealtimeMs, final long loadDurationMs) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onLoadCompleted(eventSourceId, bytesLoaded, type, trigger, format,
|
|
||||||
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs), elapsedRealtimeMs,
|
|
||||||
loadDurationMs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyLoadCanceled(final long bytesLoaded) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onLoadCanceled(eventSourceId, bytesLoaded);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyLoadError(final IOException e) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onLoadError(eventSourceId, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyDownstreamFormatChanged(final Format format, final int trigger,
|
|
||||||
final long positionUs) {
|
|
||||||
if (eventHandler != null && eventListener != null) {
|
|
||||||
eventHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
eventListener.onDownstreamFormatChanged(eventSourceId, format, trigger,
|
|
||||||
Util.usToMs(positionUs));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class TrackStreamImpl implements TrackStream {
|
private final class TrackStreamImpl implements TrackStream {
|
||||||
|
|
||||||
private final int group;
|
private final int group;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue