react-native-video/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java

290 lines
9.3 KiB
Java
Raw Normal View History

2017-01-11 05:51:45 -07:00
package com.brentvatne.exoplayer;
import android.annotation.TargetApi;
import android.content.Context;
2019-07-28 07:42:32 -06:00
import androidx.core.content.ContextCompat;
2017-01-11 05:51:45 -07:00
import android.util.AttributeSet;
import android.util.Log;
2017-01-11 05:51:45 -07:00
import android.view.Gravity;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.PlaybackParameters;
2017-01-11 05:51:45 -07:00
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.text.TextRenderer;
2020-06-11 07:17:33 -06:00
import com.google.android.exoplayer2.text.TextOutput;
2017-01-11 05:51:45 -07:00
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.ui.SubtitleView;
import java.util.List;
@TargetApi(16)
public final class ExoPlayerView extends FrameLayout {
private View surfaceView;
2017-01-11 05:51:45 -07:00
private final View shutterView;
private final SubtitleView subtitleLayout;
private final AspectRatioFrameLayout layout;
private final ComponentListener componentListener;
private SimpleExoPlayer player;
private Context context;
private ViewGroup.LayoutParams layoutParams;
private boolean useTextureView = true;
private boolean hideShutterView = false;
2017-01-11 05:51:45 -07:00
public ExoPlayerView(Context context) {
this(context, null);
}
public ExoPlayerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ExoPlayerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
2017-01-11 05:51:45 -07:00
layoutParams = new ViewGroup.LayoutParams(
2017-01-11 05:51:45 -07:00
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
componentListener = new ComponentListener();
FrameLayout.LayoutParams aspectRatioParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
aspectRatioParams.gravity = Gravity.CENTER;
layout = new AspectRatioFrameLayout(context);
layout.setLayoutParams(aspectRatioParams);
shutterView = new View(getContext());
shutterView.setLayoutParams(layoutParams);
2017-01-11 05:51:45 -07:00
shutterView.setBackgroundColor(ContextCompat.getColor(context, android.R.color.black));
subtitleLayout = new SubtitleView(context);
subtitleLayout.setLayoutParams(layoutParams);
2017-01-11 05:51:45 -07:00
subtitleLayout.setUserDefaultStyle();
subtitleLayout.setUserDefaultTextSize();
updateSurfaceView();
2017-01-11 05:51:45 -07:00
layout.addView(shutterView, 1, layoutParams);
layout.addView(subtitleLayout, 2, layoutParams);
2017-01-11 05:51:45 -07:00
addViewInLayout(layout, 0, aspectRatioParams);
}
private void setVideoView() {
if (surfaceView instanceof TextureView) {
player.setVideoTextureView((TextureView) surfaceView);
} else if (surfaceView instanceof SurfaceView) {
player.setVideoSurfaceView((SurfaceView) surfaceView);
}
}
private void updateSurfaceView() {
View view = useTextureView ? new TextureView(context) : new SurfaceView(context);
view.setLayoutParams(layoutParams);
surfaceView = view;
if (layout.getChildAt(0) != null) {
layout.removeViewAt(0);
}
layout.addView(surfaceView, 0, layoutParams);
if (this.player != null) {
setVideoView();
}
}
private void updateShutterViewVisibility() {
shutterView.setVisibility(this.hideShutterView ? View.INVISIBLE : View.VISIBLE);
}
2017-01-11 05:51:45 -07:00
/**
* Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#setTextOutput} and
* {@link SimpleExoPlayer#setVideoListener} method of the player will be called and previous
* assignments are overridden.
*
* @param player The {@link SimpleExoPlayer} to use.
*/
public void setPlayer(SimpleExoPlayer player) {
if (this.player == player) {
return;
}
if (this.player != null) {
this.player.setTextOutput(null);
this.player.setVideoListener(null);
this.player.removeListener(componentListener);
this.player.setVideoSurface(null);
}
this.player = player;
shutterView.setVisibility(VISIBLE);
if (player != null) {
setVideoView();
2017-01-11 05:51:45 -07:00
player.setVideoListener(componentListener);
player.addListener(componentListener);
player.setTextOutput(componentListener);
}
}
/**
* Sets the resize mode which can be of value {@link ResizeMode.Mode}
*
* @param resizeMode The resize mode.
*/
public void setResizeMode(@ResizeMode.Mode int resizeMode) {
if (layout.getResizeMode() != resizeMode) {
layout.setResizeMode(resizeMode);
post(measureAndLayout);
}
}
/**
* Get the view onto which video is rendered. This is either a {@link SurfaceView} (default)
* or a {@link TextureView} if the {@code use_texture_view} view attribute has been set to true.
*
* @return either a {@link SurfaceView} or a {@link TextureView}.
*/
public View getVideoSurfaceView() {
return surfaceView;
}
public void setUseTextureView(boolean useTextureView) {
if (useTextureView != this.useTextureView) {
this.useTextureView = useTextureView;
updateSurfaceView();
}
}
public void setHideShutterView(boolean hideShutterView) {
this.hideShutterView = hideShutterView;
updateShutterViewVisibility();
}
2017-01-11 05:51:45 -07:00
private final Runnable measureAndLayout = new Runnable() {
@Override
public void run() {
measure(
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
layout(getLeft(), getTop(), getRight(), getBottom());
}
};
private void updateForCurrentTrackSelections() {
if (player == null) {
return;
}
TrackSelectionArray selections = player.getCurrentTrackSelections();
for (int i = 0; i < selections.length; i++) {
if (player.getRendererType(i) == C.TRACK_TYPE_VIDEO && selections.get(i) != null) {
// Video enabled so artwork must be hidden. If the shutter is closed, it will be opened in
// onRenderedFirstFrame().
return;
}
}
// Video disabled so the shutter must be closed.
shutterView.setVisibility(VISIBLE);
}
public void invalidateAspectRatio() {
// Resetting aspect ratio will force layout refresh on next video size changed
layout.invalidateAspectRatio();
}
2017-01-11 05:51:45 -07:00
private final class ComponentListener implements SimpleExoPlayer.VideoListener,
2020-06-11 07:17:33 -06:00
TextOutput, ExoPlayer.EventListener {
2017-01-11 05:51:45 -07:00
// TextRenderer.Output implementation
@Override
public void onCues(List<Cue> cues) {
subtitleLayout.onCues(cues);
}
// SimpleExoPlayer.VideoListener implementation
@Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
boolean isInitialRatio = layout.getAspectRatio() == 0;
layout.setAspectRatio(height == 0 ? 1 : (width * pixelWidthHeightRatio) / height);
// React native workaround for measuring and layout on initial load.
if (isInitialRatio) {
post(measureAndLayout);
}
}
@Override
public void onRenderedFirstFrame() {
shutterView.setVisibility(INVISIBLE);
}
// ExoPlayer.EventListener implementation
@Override
public void onLoadingChanged(boolean isLoading) {
// Do nothing.
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
// Do nothing.
}
@Override
public void onPlayerError(ExoPlaybackException e) {
// Do nothing.
}
@Override
2018-04-03 11:19:04 -06:00
public void onPositionDiscontinuity(int reason) {
2017-01-11 05:51:45 -07:00
// Do nothing.
}
@Override
2018-04-03 11:19:04 -06:00
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
2017-01-11 05:51:45 -07:00
// Do nothing.
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
updateForCurrentTrackSelections();
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters params) {
// Do nothing
}
2018-04-03 11:19:04 -06:00
@Override
public void onSeekProcessed() {
// Do nothing.
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
// Do nothing.
}
@Override
public void onRepeatModeChanged(int repeatMode) {
// Do nothing.
}
2017-01-11 05:51:45 -07:00
}
}