Bug 1628792 - p2: update GeckoHls* for API changes in exoplayer. r=agi,geckoview-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D78390
This commit is contained in:
John Lin 2020-06-05 02:06:14 +00:00
parent 68b7382249
commit b6a091d9dd
4 changed files with 77 additions and 115 deletions

View File

@ -23,6 +23,7 @@ import org.mozilla.thirdparty.com.google.android.exoplayer2.mediacodec.MediaCode
import org.mozilla.thirdparty.com.google.android.exoplayer2.util.MimeTypes;
import java.nio.ByteBuffer;
import java.util.List;
public class GeckoHlsAudioRenderer extends GeckoHlsRendererBase {
public GeckoHlsAudioRenderer(final GeckoHlsPlayer.ComponentEventDispatcher eventDispatcher) {
@ -55,18 +56,19 @@ public class GeckoHlsAudioRenderer extends GeckoHlsRendererBase {
*/
String mimeType = format.sampleMimeType;
if (!MimeTypes.isAudio(mimeType)) {
return RendererCapabilities.FORMAT_UNSUPPORTED_TYPE;
return RendererCapabilities.create(FORMAT_UNSUPPORTED_TYPE);
}
MediaCodecInfo decoderInfo = null;
List<MediaCodecInfo> decoderInfos = null;
try {
MediaCodecSelector mediaCodecSelector = MediaCodecSelector.DEFAULT;
decoderInfo = mediaCodecSelector.getDecoderInfo(mimeType, false);
decoderInfos = mediaCodecSelector.getDecoderInfos(mimeType, false, false);
} catch (MediaCodecUtil.DecoderQueryException e) {
Log.e(LOGTAG, e.getMessage());
}
if (decoderInfo == null) {
return RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE;
if (decoderInfos == null || decoderInfos.isEmpty()) {
return RendererCapabilities.create(FORMAT_UNSUPPORTED_SUBTYPE);
}
MediaCodecInfo info = decoderInfos.get(0);
/*
* Note : If the code can make it to this place, ExoPlayer assumes
* support for unknown sampleRate and channelCount when
@ -75,13 +77,13 @@ public class GeckoHlsAudioRenderer extends GeckoHlsRendererBase {
*/
boolean decoderCapable = (Build.VERSION.SDK_INT < 21) ||
((format.sampleRate == Format.NO_VALUE ||
decoderInfo.isAudioSampleRateSupportedV21(format.sampleRate)) &&
info.isAudioSampleRateSupportedV21(format.sampleRate)) &&
(format.channelCount == Format.NO_VALUE ||
decoderInfo.isAudioChannelCountSupportedV21(format.channelCount)));
int formatSupport = decoderCapable ?
RendererCapabilities.FORMAT_HANDLED :
RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES;
return RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | formatSupport;
info.isAudioChannelCountSupportedV21(format.channelCount)));
return RendererCapabilities.create(
decoderCapable ? FORMAT_HANDLED : FORMAT_EXCEEDS_CAPABILITIES,
ADAPTIVE_NOT_SEAMLESS,
TUNNELING_NOT_SUPPORTED);
}
@Override

View File

@ -14,13 +14,12 @@ import org.mozilla.thirdparty.com.google.android.exoplayer2.C;
import org.mozilla.thirdparty.com.google.android.exoplayer2.DefaultLoadControl;
import org.mozilla.thirdparty.com.google.android.exoplayer2.ExoPlaybackException;
import org.mozilla.thirdparty.com.google.android.exoplayer2.ExoPlayer;
import org.mozilla.thirdparty.com.google.android.exoplayer2.ExoPlayerFactory;
import org.mozilla.thirdparty.com.google.android.exoplayer2.Format;
import org.mozilla.thirdparty.com.google.android.exoplayer2.PlaybackParameters;
import org.mozilla.thirdparty.com.google.android.exoplayer2.RendererCapabilities;
import org.mozilla.thirdparty.com.google.android.exoplayer2.Timeline;
import org.mozilla.thirdparty.com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
import org.mozilla.thirdparty.com.google.android.exoplayer2.source.MediaSource;
import org.mozilla.thirdparty.com.google.android.exoplayer2.source.MediaSourceEventListener;
import org.mozilla.thirdparty.com.google.android.exoplayer2.source.TrackGroup;
import org.mozilla.thirdparty.com.google.android.exoplayer2.source.TrackGroupArray;
import org.mozilla.thirdparty.com.google.android.exoplayer2.source.hls.HlsMediaSource;
@ -29,8 +28,6 @@ import org.mozilla.thirdparty.com.google.android.exoplayer2.trackselection.Defau
import org.mozilla.thirdparty.com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
import org.mozilla.thirdparty.com.google.android.exoplayer2.trackselection.TrackSelection;
import org.mozilla.thirdparty.com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import org.mozilla.thirdparty.com.google.android.exoplayer2.upstream.DataSource;
import org.mozilla.thirdparty.com.google.android.exoplayer2.upstream.DataSpec;
import org.mozilla.thirdparty.com.google.android.exoplayer2.upstream.DefaultAllocator;
import org.mozilla.thirdparty.com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import org.mozilla.thirdparty.com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
@ -44,14 +41,13 @@ import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.annotation.ReflectionTarget;
import org.mozilla.geckoview.BuildConfig;
import java.io.IOException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
@ReflectionTarget
public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
private static final String LOGTAG = "GeckoHlsPlayer";
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter.Builder(null).build();
private static final int MAX_TIMELINE_ITEM_LINES = 3;
private static final boolean DEBUG = !BuildConfig.MOZILLA_OFFICIAL;
@ -78,7 +74,6 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
// Default value is PLAY_STATE_PREPARING and it will be set to PLAY_STATE_PLAYING
// once HTMLMediaElement calls PlayInternal().
private MediaDecoderPlayState mMediaDecoderPlayState = MediaDecoderPlayState.PLAY_STATE_PREPARING;
private DataSource.Factory mMediaDataSourceFactory;
private Handler mMainHandler;
private HandlerThread mThread;
@ -202,77 +197,28 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
private final class SourceEventListener implements AdaptiveMediaSourceEventListener {
public void onLoadStarted(final DataSpec dataSpec,
final int dataType,
final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaStartTimeMs,
final long mediaEndTimeMs,
final long elapsedRealtimeMs) {
private final class SourceEventListener implements MediaSourceEventListener {
public void onLoadStarted(
final int windowIndex,
final MediaSource.MediaPeriodId mediaPeriodId,
final LoadEventInfo loadEventInfo,
final MediaLoadData mediaLoadData) {
if (mediaLoadData.dataType != C.DATA_TYPE_MEDIA) {
// Don't report non-media URLs.
return;
}
if (mMainHandler != null && mResourceCallbacks != null) {
mMainHandler.post(new Runnable() {
@Override
public void run() {
if (DEBUG) {
Log.d(LOGTAG, "[SourceEvent] load-started: url=" + dataSpec.uri + " track=" + trackType + " format=" + trackFormat);
Log.d(LOGTAG, "on-load: url=" + loadEventInfo.uri);
}
mResourceCallbacks.onLoad(dataSpec.uri.toString());
mResourceCallbacks.onLoad(loadEventInfo.uri.toString());
}
});
}
}
// Not interested in the following events.
public void onLoadCompleted(final DataSpec dataSpec,
final int dataType,
final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaStartTimeMs,
final long mediaEndTimeMs,
final long elapsedRealtimeMs,
final long loadDurationMs,
final long bytesLoaded) {
}
public void onLoadCanceled(final DataSpec dataSpec,
final int dataType,
final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaStartTimeMs,
final long mediaEndTimeMs,
final long elapsedRealtimeMs,
final long loadDurationMs,
final long bytesLoaded) {
}
public void onLoadError(final DataSpec dataSpec,
final int dataType,
final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaStartTimeMs,
final long mediaEndTimeMs,
final long elapsedRealtimeMs,
final long loadDurationMs,
final long bytesLoaded,
final IOException error,
final boolean wasCanceled) {
}
public void onUpstreamDiscarded(final int trackType,
final long mediaStartTimeMs,
final long mediaEndTimeMs) {
}
public void onDownstreamFormatChanged(final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaTimeMs) {
}
}
public final class ComponentEventDispatcher {
@ -372,10 +318,10 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
private DataSource.Factory buildDataSourceFactory(final Context ctx,
private HlsMediaSource.Factory buildDataSourceFactory(final Context ctx,
final DefaultBandwidthMeter bandwidthMeter) {
return new DefaultDataSourceFactory(ctx, bandwidthMeter,
buildHttpDataSourceFactory(bandwidthMeter));
return new HlsMediaSource.Factory(new DefaultDataSourceFactory(ctx, bandwidthMeter,
buildHttpDataSourceFactory(bandwidthMeter)));
}
private HttpDataSource.Factory buildHttpDataSourceFactory(
@ -459,9 +405,9 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
// Called on GeckoHlsPlayerThread from ExoPlayer
@Override
public void onPositionDiscontinuity() {
public void onPositionDiscontinuity(final int reason) {
if (DEBUG) {
Log.d(LOGTAG, "positionDiscontinuity");
Log.d(LOGTAG, "positionDiscontinuity: reason=" + reason);
}
}
@ -572,7 +518,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
// Called on GeckoHlsPlayerThread from ExoPlayer
@Override
public synchronized void onTimelineChanged(final Timeline timeline, final Object manifest) {
public synchronized void onTimelineChanged(final Timeline timeline, final int reason) {
// For now, we use the interface ExoPlayer.getDuration() for gecko,
// so here we create local variable 'window' & 'peroid' to obtain
// the dynamic duration.
@ -685,21 +631,24 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
mRenderers[0] = mVRenderer;
mRenderers[1] = mARenderer;
DefaultLoadControl dlc =
new DefaultLoadControl(
new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
DEFAULT_MIN_BUFFER_MS,
DEFAULT_MAX_BUFFER_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
DefaultLoadControl dlc = new DefaultLoadControl.Builder()
.setAllocator(new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE))
.setBufferDurationsMs(DEFAULT_MIN_BUFFER_MS,
DEFAULT_MAX_BUFFER_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS)
.createDefaultLoadControl();
// Create ExoPlayer instance with specific components.
mPlayer = ExoPlayerFactory.newInstance(mRenderers, mTrackSelector, dlc);
mPlayer = new ExoPlayer.Builder(ctx, mRenderers)
.setTrackSelector(mTrackSelector)
.setLoadControl(dlc)
.build();
mPlayer.addListener(this);
Uri uri = Uri.parse(url);
mMediaDataSourceFactory = buildDataSourceFactory(ctx, BANDWIDTH_METER);
mMediaSource = buildDataSourceFactory(ctx, BANDWIDTH_METER).createMediaSource(uri);
mSourceEventListener = new SourceEventListener();
mMediaSource = new HlsMediaSource(uri, mMediaDataSourceFactory, mMainHandler, mSourceEventListener);
mMediaSource.addEventListener(mMainHandler, mSourceEventListener);
if (DEBUG) {
Log.d(LOGTAG, "Uri is " + uri +
", ContentType is " + Util.inferContentType(uri.getLastPathSegment()));

View File

@ -14,6 +14,7 @@ import org.mozilla.thirdparty.com.google.android.exoplayer2.decoder.DecoderInput
import org.mozilla.thirdparty.com.google.android.exoplayer2.ExoPlaybackException;
import org.mozilla.thirdparty.com.google.android.exoplayer2.Format;
import org.mozilla.thirdparty.com.google.android.exoplayer2.FormatHolder;
import org.mozilla.thirdparty.com.google.android.exoplayer2.RendererCapabilities;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@ -191,7 +192,10 @@ public abstract class GeckoHlsRendererBase extends BaseRenderer {
createInputBuffer();
mInitialized = true;
} catch (OutOfMemoryError e) {
throw ExoPlaybackException.createForRenderer(new RuntimeException(e), getIndex());
throw ExoPlaybackException.createForRenderer(new RuntimeException(e),
getIndex(),
mFormats.isEmpty() ? null : getFormat(mFormats.size() - 1),
RendererCapabilities.FORMAT_HANDLED);
}
}

View File

@ -23,6 +23,7 @@ import org.mozilla.thirdparty.com.google.android.exoplayer2.RendererCapabilities
import org.mozilla.thirdparty.com.google.android.exoplayer2.util.MimeTypes;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
public class GeckoHlsVideoRenderer extends GeckoHlsRendererBase {
@ -89,21 +90,28 @@ public class GeckoHlsVideoRenderer extends GeckoHlsRendererBase {
*/
final String mimeType = format.sampleMimeType;
if (!MimeTypes.isVideo(mimeType)) {
return RendererCapabilities.FORMAT_UNSUPPORTED_TYPE;
return RendererCapabilities.create(FORMAT_UNSUPPORTED_TYPE);
}
MediaCodecInfo decoderInfo = null;
List<MediaCodecInfo> decoderInfos = null;
try {
MediaCodecSelector mediaCodecSelector = MediaCodecSelector.DEFAULT;
decoderInfo = mediaCodecSelector.getDecoderInfo(mimeType, false);
decoderInfos = mediaCodecSelector.getDecoderInfos(mimeType, false, false);
} catch (MediaCodecUtil.DecoderQueryException e) {
Log.e(LOGTAG, e.getMessage());
}
if (decoderInfo == null) {
return RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE;
if (decoderInfos == null || decoderInfos.isEmpty()) {
return RendererCapabilities.create(FORMAT_UNSUPPORTED_SUBTYPE);
}
boolean decoderCapable = decoderInfo.isCodecSupported(format.codecs);
boolean decoderCapable = false;
MediaCodecInfo info = null;
for (MediaCodecInfo i : decoderInfos) {
if (i.isCodecSupported(format)) {
decoderCapable = true;
info = i;
}
}
if (decoderCapable && format.width > 0 && format.height > 0) {
if (Build.VERSION.SDK_INT < 21) {
try {
@ -118,20 +126,16 @@ public class GeckoHlsVideoRenderer extends GeckoHlsRendererBase {
}
}
} else {
decoderCapable =
decoderInfo.isVideoSizeAndRateSupportedV21(format.width,
format.height,
format.frameRate);
decoderCapable = info.isVideoSizeAndRateSupportedV21(format.width,
format.height,
format.frameRate);
}
}
int adaptiveSupport = decoderInfo.adaptive ?
RendererCapabilities.ADAPTIVE_SEAMLESS :
RendererCapabilities.ADAPTIVE_NOT_SEAMLESS;
int formatSupport = decoderCapable ?
RendererCapabilities.FORMAT_HANDLED :
RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES;
return adaptiveSupport | formatSupport;
return RendererCapabilities.create(
decoderCapable ? FORMAT_HANDLED : FORMAT_EXCEEDS_CAPABILITIES,
info != null && info.adaptive ? ADAPTIVE_SEAMLESS : ADAPTIVE_NOT_SEAMLESS,
TUNNELING_NOT_SUPPORTED);
}
@Override
@ -149,7 +153,10 @@ public class GeckoHlsVideoRenderer extends GeckoHlsRendererBase {
mInputBuffer = ByteBuffer.wrap(new byte[mCodecMaxValues.inputSize]);
} catch (OutOfMemoryError e) {
Log.e(LOGTAG, "cannot allocate input buffer of size " + mCodecMaxValues.inputSize, e);
throw ExoPlaybackException.createForRenderer(new Exception(e), getIndex());
throw ExoPlaybackException.createForRenderer(new Exception(e),
getIndex(),
mFormats.isEmpty() ? null : getFormat(mFormats.size() - 1),
RendererCapabilities.FORMAT_HANDLED);
}
}
@ -429,7 +436,7 @@ public class GeckoHlsVideoRenderer extends GeckoHlsRendererBase {
}
@Override
protected void onStreamChanged(final Format[] formats) {
protected void onStreamChanged(final Format[] formats, final long offsetUs) {
mStreamFormats = formats;
}