Merge branch 'master' into master
This commit is contained in:
@@ -19,6 +19,7 @@ import okhttp3.JavaNetCookieJar;
|
||||
import okhttp3.OkHttpClient;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class DataSourceUtil {
|
||||
|
||||
private DataSourceUtil() {
|
||||
@@ -32,14 +33,14 @@ public class DataSourceUtil {
|
||||
DataSourceUtil.userAgent = userAgent;
|
||||
}
|
||||
|
||||
public static String getUserAgent(Context context) {
|
||||
public static String getUserAgent(ReactContext context) {
|
||||
if (userAgent == null) {
|
||||
userAgent = Util.getUserAgent(context.getApplicationContext(), "ReactNativeVideo");
|
||||
userAgent = Util.getUserAgent(context, "ReactNativeVideo");
|
||||
}
|
||||
return userAgent;
|
||||
}
|
||||
|
||||
public static DataSource.Factory getRawDataSourceFactory(Context context) {
|
||||
public static DataSource.Factory getRawDataSourceFactory(ReactContext context) {
|
||||
if (rawDataSourceFactory == null) {
|
||||
rawDataSourceFactory = buildRawDataSourceFactory(context);
|
||||
}
|
||||
@@ -50,6 +51,7 @@ public class DataSourceUtil {
|
||||
DataSourceUtil.rawDataSourceFactory = factory;
|
||||
}
|
||||
|
||||
|
||||
public static DataSource.Factory getDefaultDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map<String, String> requestHeaders) {
|
||||
if (defaultDataSourceFactory == null || (requestHeaders != null && !requestHeaders.isEmpty())) {
|
||||
defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders);
|
||||
@@ -61,7 +63,7 @@ public class DataSourceUtil {
|
||||
DataSourceUtil.defaultDataSourceFactory = factory;
|
||||
}
|
||||
|
||||
private static DataSource.Factory buildRawDataSourceFactory(Context context) {
|
||||
private static DataSource.Factory buildRawDataSourceFactory(ReactContext context) {
|
||||
return new RawResourceDataSourceFactory(context.getApplicationContext());
|
||||
}
|
||||
|
||||
@@ -75,7 +77,6 @@ public class DataSourceUtil {
|
||||
CookieJarContainer container = (CookieJarContainer) client.cookieJar();
|
||||
ForwardingCookieHandler handler = new ForwardingCookieHandler(context);
|
||||
container.setCookieJar(new JavaNetCookieJar(handler));
|
||||
|
||||
OkHttpDataSourceFactory okHttpDataSourceFactory = new OkHttpDataSourceFactory(client, getUserAgent(context), bandwidthMeter);
|
||||
|
||||
if (requestHeaders != null)
|
||||
|
@@ -18,8 +18,6 @@ import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.MetadataRenderer;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.text.TextRenderer;
|
||||
@@ -27,17 +25,20 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||
|
||||
import java.util.List;
|
||||
import java.lang.Object;
|
||||
|
||||
@TargetApi(16)
|
||||
public final class ExoPlayerView extends FrameLayout {
|
||||
|
||||
private final View surfaceView;
|
||||
private View surfaceView;
|
||||
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 = false;
|
||||
|
||||
public ExoPlayerView(Context context) {
|
||||
this(context, null);
|
||||
@@ -50,9 +51,9 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
public ExoPlayerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
boolean useTextureView = false;
|
||||
this.context = context;
|
||||
|
||||
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
|
||||
layoutParams = new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
|
||||
@@ -66,25 +67,45 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
layout.setLayoutParams(aspectRatioParams);
|
||||
|
||||
shutterView = new View(getContext());
|
||||
shutterView.setLayoutParams(params);
|
||||
shutterView.setLayoutParams(layoutParams);
|
||||
shutterView.setBackgroundColor(ContextCompat.getColor(context, android.R.color.black));
|
||||
|
||||
subtitleLayout = new SubtitleView(context);
|
||||
subtitleLayout.setLayoutParams(params);
|
||||
subtitleLayout.setLayoutParams(layoutParams);
|
||||
subtitleLayout.setUserDefaultStyle();
|
||||
subtitleLayout.setUserDefaultTextSize();
|
||||
|
||||
View view = useTextureView ? new TextureView(context) : new SurfaceView(context);
|
||||
view.setLayoutParams(params);
|
||||
surfaceView = view;
|
||||
updateSurfaceView();
|
||||
|
||||
layout.addView(surfaceView, 0, params);
|
||||
layout.addView(shutterView, 1, params);
|
||||
layout.addView(subtitleLayout, 2, params);
|
||||
layout.addView(shutterView, 1, layoutParams);
|
||||
layout.addView(subtitleLayout, 2, layoutParams);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#setTextOutput} and
|
||||
* {@link SimpleExoPlayer#setVideoListener} method of the player will be called and previous
|
||||
@@ -101,20 +122,14 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
this.player.setVideoListener(null);
|
||||
this.player.removeListener(componentListener);
|
||||
this.player.setVideoSurface(null);
|
||||
this.player.setMetadataOutput(componentListener);
|
||||
}
|
||||
this.player = player;
|
||||
shutterView.setVisibility(VISIBLE);
|
||||
if (player != null) {
|
||||
if (surfaceView instanceof TextureView) {
|
||||
player.setVideoTextureView((TextureView) surfaceView);
|
||||
} else if (surfaceView instanceof SurfaceView) {
|
||||
player.setVideoSurfaceView((SurfaceView) surfaceView);
|
||||
}
|
||||
setVideoView();
|
||||
player.setVideoListener(componentListener);
|
||||
player.addListener(componentListener);
|
||||
player.setTextOutput(componentListener);
|
||||
player.setMetadataOutput(componentListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,6 +156,11 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
return surfaceView;
|
||||
}
|
||||
|
||||
public void setUseTextureView(boolean useTextureView) {
|
||||
this.useTextureView = useTextureView;
|
||||
updateSurfaceView();
|
||||
}
|
||||
|
||||
private final Runnable measureAndLayout = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -168,7 +188,7 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
}
|
||||
|
||||
private final class ComponentListener implements SimpleExoPlayer.VideoListener,
|
||||
TextRenderer.Output, ExoPlayer.EventListener, MetadataRenderer.Output {
|
||||
TextRenderer.Output, ExoPlayer.EventListener {
|
||||
|
||||
// TextRenderer.Output implementation
|
||||
|
||||
@@ -232,11 +252,6 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMetadata(Metadata metadata) {
|
||||
Log.d("onMetadata", "onMetadata");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeekProcessed() {
|
||||
// Do nothing.
|
||||
|
@@ -16,6 +16,7 @@ import android.widget.FrameLayout;
|
||||
import com.brentvatne.react.R;
|
||||
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
|
||||
import com.brentvatne.receiver.BecomingNoisyListener;
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
@@ -46,6 +47,7 @@ import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
@@ -101,6 +103,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private Uri srcUri;
|
||||
private String extension;
|
||||
private boolean repeat;
|
||||
private String textTrackType;
|
||||
private Dynamic textTrackValue;
|
||||
private boolean disableFocus;
|
||||
private float mProgressUpdateInterval = 250.0f;
|
||||
private boolean playInBackground = false;
|
||||
@@ -135,9 +139,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
|
||||
public ReactExoplayerView(ThemedReactContext context) {
|
||||
super(context);
|
||||
this.themedReactContext = context;
|
||||
createViews();
|
||||
this.eventEmitter = new VideoEventEmitter(context);
|
||||
this.themedReactContext = context;
|
||||
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
themedReactContext.addLifecycleEventListener(this);
|
||||
audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext);
|
||||
@@ -448,6 +452,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private void videoLoaded() {
|
||||
if (loadVideoStarted) {
|
||||
loadVideoStarted = false;
|
||||
setSelectedTextTrack(textTrackType, textTrackValue);
|
||||
Format videoFormat = player.getVideoFormat();
|
||||
int width = videoFormat != null ? videoFormat.width : 0;
|
||||
int height = videoFormat != null ? videoFormat.height : 0;
|
||||
@@ -570,6 +575,16 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getTextTrackRendererIndex() {
|
||||
int rendererCount = player.getRendererCount();
|
||||
for (int rendererIndex = 0; rendererIndex < rendererCount; rendererIndex++) {
|
||||
if (player.getRendererType(rendererIndex) == C.TRACK_TYPE_TEXT) {
|
||||
return rendererIndex;
|
||||
}
|
||||
}
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMetadata(Metadata metadata) {
|
||||
eventEmitter.timedMetadata(metadata);
|
||||
@@ -585,7 +600,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
this.srcUri = uri;
|
||||
this.extension = extension;
|
||||
this.requestHeaders = headers;
|
||||
this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, BANDWIDTH_METER, requestHeaders);
|
||||
this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, BANDWIDTH_METER, this.requestHeaders);
|
||||
|
||||
if (!isOriginalSourceNull && !isSourceEqual) {
|
||||
reloadSource();
|
||||
@@ -604,7 +619,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
|
||||
this.srcUri = uri;
|
||||
this.extension = extension;
|
||||
this.mediaDataSourceFactory = DataSourceUtil.getRawDataSourceFactory(getContext());
|
||||
this.mediaDataSourceFactory = DataSourceUtil.getRawDataSourceFactory(this.themedReactContext);
|
||||
|
||||
if (!isOriginalSourceNull && !isSourceEqual) {
|
||||
reloadSource();
|
||||
@@ -632,6 +647,60 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
this.repeat = repeat;
|
||||
}
|
||||
|
||||
public void setSelectedTextTrack(String type, Dynamic value) {
|
||||
textTrackType = type;
|
||||
textTrackValue = value;
|
||||
|
||||
int index = getTextTrackRendererIndex();
|
||||
if (index == C.INDEX_UNSET) {
|
||||
return;
|
||||
}
|
||||
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
|
||||
if (info == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TrackGroupArray groups = info.getTrackGroups(index);
|
||||
int trackIndex = C.INDEX_UNSET;
|
||||
if (TextUtils.isEmpty(type)) {
|
||||
// Do nothing
|
||||
} else if (type.equals("disabled")) {
|
||||
trackSelector.setSelectionOverride(index, groups, null);
|
||||
return;
|
||||
} else if (type.equals("language")) {
|
||||
for (int i = 0; i < groups.length; ++i) {
|
||||
Format format = groups.get(i).getFormat(0);
|
||||
if (format.language != null && format.language.equals(value.asString())) {
|
||||
trackIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (type.equals("title")) {
|
||||
for (int i = 0; i < groups.length; ++i) {
|
||||
Format format = groups.get(i).getFormat(0);
|
||||
if (format.id != null && format.id.equals(value.asString())) {
|
||||
trackIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (type.equals("index")) {
|
||||
trackIndex = value.asInt();
|
||||
} else { // default. invalid type or "system"
|
||||
trackSelector.clearSelectionOverrides(index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (trackIndex == C.INDEX_UNSET) {
|
||||
trackSelector.clearSelectionOverrides(trackIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
MappingTrackSelector.SelectionOverride override
|
||||
= new MappingTrackSelector.SelectionOverride(
|
||||
new FixedTrackSelection.Factory(), trackIndex, 0);
|
||||
trackSelector.setSelectionOverride(index, groups, override);
|
||||
}
|
||||
|
||||
public void setPausedModifier(boolean paused) {
|
||||
isPaused = paused;
|
||||
if (player != null) {
|
||||
@@ -713,4 +782,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
eventEmitter.fullscreenDidDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public void setUseTextureView(boolean useTextureView) {
|
||||
exoPlayerView.setUseTextureView(useTextureView);
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
@@ -26,6 +27,9 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
private static final String PROP_SRC_HEADERS = "requestHeaders";
|
||||
private static final String PROP_RESIZE_MODE = "resizeMode";
|
||||
private static final String PROP_REPEAT = "repeat";
|
||||
private static final String PROP_SELECTED_TEXT_TRACK = "selectedTextTrack";
|
||||
private static final String PROP_SELECTED_TEXT_TRACK_TYPE = "type";
|
||||
private static final String PROP_SELECTED_TEXT_TRACK_VALUE = "value";
|
||||
private static final String PROP_PAUSED = "paused";
|
||||
private static final String PROP_MUTED = "muted";
|
||||
private static final String PROP_VOLUME = "volume";
|
||||
@@ -35,6 +39,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
|
||||
private static final String PROP_DISABLE_FOCUS = "disableFocus";
|
||||
private static final String PROP_FULLSCREEN = "fullscreen";
|
||||
private static final String PROP_USE_TEXTURE_VIEW = "useTextureView";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -120,6 +125,16 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
videoView.setRepeatModifier(repeat);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_SELECTED_TEXT_TRACK)
|
||||
public void setSelectedTextTrack(final ReactExoplayerView videoView,
|
||||
@Nullable ReadableMap selectedTextTrack) {
|
||||
String typeString = selectedTextTrack.hasKey(PROP_SELECTED_TEXT_TRACK_TYPE)
|
||||
? selectedTextTrack.getString(PROP_SELECTED_TEXT_TRACK_TYPE) : null;
|
||||
Dynamic value = selectedTextTrack.hasKey(PROP_SELECTED_TEXT_TRACK_VALUE)
|
||||
? selectedTextTrack.getDynamic(PROP_SELECTED_TEXT_TRACK_VALUE) : null;
|
||||
videoView.setSelectedTextTrack(typeString, value);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_PAUSED, defaultBoolean = false)
|
||||
public void setPaused(final ReactExoplayerView videoView, final boolean paused) {
|
||||
videoView.setPausedModifier(paused);
|
||||
@@ -165,6 +180,11 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
videoView.setFullscreen(fullscreen);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_USE_TEXTURE_VIEW, defaultBoolean = false)
|
||||
public void setUseTextureView(final ReactExoplayerView videoView, final boolean useTextureView) {
|
||||
videoView.setUseTextureView(useTextureView);
|
||||
}
|
||||
|
||||
private boolean startsWithValidScheme(String uriString) {
|
||||
return uriString.startsWith("http://")
|
||||
|| uriString.startsWith("https://")
|
||||
|
Reference in New Issue
Block a user