Add ability to sideload text tracks and report them in onLoad
This commit is contained in:
parent
a1a4e0c44b
commit
e2ea849d9e
@ -16,8 +16,13 @@ import android.widget.FrameLayout;
|
|||||||
import com.brentvatne.react.R;
|
import com.brentvatne.react.R;
|
||||||
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
|
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
|
||||||
import com.brentvatne.receiver.BecomingNoisyListener;
|
import com.brentvatne.receiver.BecomingNoisyListener;
|
||||||
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.LifecycleEventListener;
|
import com.facebook.react.bridge.LifecycleEventListener;
|
||||||
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
|
import com.facebook.react.bridge.WritableArray;
|
||||||
|
import com.facebook.react.bridge.WritableMap;
|
||||||
import com.facebook.react.uimanager.ThemedReactContext;
|
import com.facebook.react.uimanager.ThemedReactContext;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||||
@ -62,7 +67,6 @@ import java.net.CookiePolicy;
|
|||||||
import java.lang.Math;
|
import java.lang.Math;
|
||||||
import java.lang.Object;
|
import java.lang.Object;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class ReactExoplayerView extends FrameLayout implements
|
class ReactExoplayerView extends FrameLayout implements
|
||||||
@ -108,6 +112,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
private boolean repeat;
|
private boolean repeat;
|
||||||
private String textTrackType;
|
private String textTrackType;
|
||||||
private Dynamic textTrackValue;
|
private Dynamic textTrackValue;
|
||||||
|
private ReadableArray textTracks;
|
||||||
private boolean disableFocus;
|
private boolean disableFocus;
|
||||||
private float mProgressUpdateInterval = 250.0f;
|
private float mProgressUpdateInterval = 250.0f;
|
||||||
private boolean playInBackground = false;
|
private boolean playInBackground = false;
|
||||||
@ -234,25 +239,17 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
player.setPlaybackParameters(params);
|
player.setPlaybackParameters(params);
|
||||||
}
|
}
|
||||||
if (playerNeedsSource && srcUri != null) {
|
if (playerNeedsSource && srcUri != null) {
|
||||||
ArrayList<MediaSource> mediaSources = new ArrayList<>();
|
ArrayList<MediaSource> mediaSourceList = buildTextSources();
|
||||||
mediaSources.add(buildMediaSource(srcUri, extension)); // video source
|
MediaSource videoSource = buildMediaSource(srcUri, extension);
|
||||||
MediaSource text0 = buildTextSource(
|
|
||||||
"ES VTT",
|
|
||||||
Uri.parse("https://bitdash-a.akamaihd.net/content/sintel/subtitles/subtitles_es.vtt"),
|
|
||||||
"vtt",
|
|
||||||
"es"
|
|
||||||
);
|
|
||||||
if (text0 != null) {
|
|
||||||
mediaSources.add(text0);
|
|
||||||
}
|
|
||||||
MediaSource mediaSource;
|
MediaSource mediaSource;
|
||||||
if (mediaSources.size() > 1) {
|
if (mediaSourceList.size() == 0) {
|
||||||
MediaSource[] textSourceArray = mediaSources.toArray(
|
mediaSource = videoSource;
|
||||||
new MediaSource[mediaSources.size()]
|
} else {
|
||||||
|
mediaSourceList.add(0, videoSource);
|
||||||
|
MediaSource[] textSourceArray = mediaSourceList.toArray(
|
||||||
|
new MediaSource[mediaSourceList.size()]
|
||||||
);
|
);
|
||||||
mediaSource = new MergingMediaSource(textSourceArray);
|
mediaSource = new MergingMediaSource(textSourceArray);
|
||||||
} else {
|
|
||||||
mediaSource = mediaSources.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean haveResumePosition = resumeWindow != C.INDEX_UNSET;
|
boolean haveResumePosition = resumeWindow != C.INDEX_UNSET;
|
||||||
@ -288,6 +285,27 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ArrayList<MediaSource> buildTextSources() {
|
||||||
|
ArrayList<MediaSource> textSources = new ArrayList<>();
|
||||||
|
if (textTracks == null) {
|
||||||
|
return textSources;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < textTracks.size(); ++i) {
|
||||||
|
ReadableMap textTrack = textTracks.getMap(i);
|
||||||
|
String language = textTrack.getString("language");
|
||||||
|
String title = textTrack.hasKey("title")
|
||||||
|
? textTrack.getString("title") : language + " " + i;
|
||||||
|
Uri uri = Uri.parse(textTrack.getString("uri"));
|
||||||
|
MediaSource textSource = buildTextSource(title, uri, textTrack.getString("type"),
|
||||||
|
language);
|
||||||
|
if (textSource != null) {
|
||||||
|
textSources.add(textSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return textSources;
|
||||||
|
}
|
||||||
|
|
||||||
private MediaSource buildTextSource(String title, Uri uri, String mimeType, String language) {
|
private MediaSource buildTextSource(String title, Uri uri, String mimeType, String language) {
|
||||||
String sampleType;
|
String sampleType;
|
||||||
switch (mimeType) {
|
switch (mimeType) {
|
||||||
@ -494,10 +512,33 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
Format videoFormat = player.getVideoFormat();
|
Format videoFormat = player.getVideoFormat();
|
||||||
int width = videoFormat != null ? videoFormat.width : 0;
|
int width = videoFormat != null ? videoFormat.width : 0;
|
||||||
int height = videoFormat != null ? videoFormat.height : 0;
|
int height = videoFormat != null ? videoFormat.height : 0;
|
||||||
eventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height);
|
eventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height,
|
||||||
|
getTextTrackInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WritableArray getTextTrackInfo() {
|
||||||
|
WritableArray textTracks = Arguments.createArray();
|
||||||
|
|
||||||
|
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
|
||||||
|
int index = getTextTrackRendererIndex();
|
||||||
|
if (info == null || index == C.INDEX_UNSET) {
|
||||||
|
return textTracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackGroupArray groups = info.getTrackGroups(index);
|
||||||
|
for (int i = 0; i < groups.length; ++i) {
|
||||||
|
Format format = groups.get(i).getFormat(0);
|
||||||
|
WritableMap textTrack = Arguments.createMap();
|
||||||
|
textTrack.putInt("index", i);
|
||||||
|
textTrack.putString("title", format.id);
|
||||||
|
textTrack.putString("type", format.sampleMimeType);
|
||||||
|
textTrack.putString("language", format.language);
|
||||||
|
textTracks.pushMap(textTrack);
|
||||||
|
}
|
||||||
|
return textTracks;
|
||||||
|
}
|
||||||
|
|
||||||
private void onBuffering(boolean buffering) {
|
private void onBuffering(boolean buffering) {
|
||||||
if (isBuffering == buffering) {
|
if (isBuffering == buffering) {
|
||||||
return;
|
return;
|
||||||
@ -664,6 +705,11 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTextTracks(ReadableArray textTracks) {
|
||||||
|
this.textTracks = textTracks;
|
||||||
|
reloadSource();
|
||||||
|
}
|
||||||
|
|
||||||
private void reloadSource() {
|
private void reloadSource() {
|
||||||
playerNeedsSource = true;
|
playerNeedsSource = true;
|
||||||
initializePlayer();
|
initializePlayer();
|
||||||
|
@ -5,6 +5,7 @@ import android.net.Uri;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.common.MapBuilder;
|
import com.facebook.react.common.MapBuilder;
|
||||||
import com.facebook.react.uimanager.ThemedReactContext;
|
import com.facebook.react.uimanager.ThemedReactContext;
|
||||||
@ -28,6 +29,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
|||||||
private static final String PROP_SELECTED_TEXT_TRACK = "selectedTextTrack";
|
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_TYPE = "type";
|
||||||
private static final String PROP_SELECTED_TEXT_TRACK_VALUE = "value";
|
private static final String PROP_SELECTED_TEXT_TRACK_VALUE = "value";
|
||||||
|
private static final String PROP_TEXT_TRACKS = "textTracks";
|
||||||
private static final String PROP_PAUSED = "paused";
|
private static final String PROP_PAUSED = "paused";
|
||||||
private static final String PROP_MUTED = "muted";
|
private static final String PROP_MUTED = "muted";
|
||||||
private static final String PROP_VOLUME = "volume";
|
private static final String PROP_VOLUME = "volume";
|
||||||
@ -131,6 +133,12 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
|||||||
videoView.setSelectedTextTrack(typeString, value);
|
videoView.setSelectedTextTrack(typeString, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = PROP_TEXT_TRACKS)
|
||||||
|
public void setPropTextTracks(final ReactExoplayerView videoView,
|
||||||
|
@Nullable ReadableArray textTracks) {
|
||||||
|
videoView.setTextTracks(textTracks);
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = PROP_PAUSED, defaultBoolean = false)
|
@ReactProp(name = PROP_PAUSED, defaultBoolean = false)
|
||||||
public void setPaused(final ReactExoplayerView videoView, final boolean paused) {
|
public void setPaused(final ReactExoplayerView videoView, final boolean paused) {
|
||||||
videoView.setPausedModifier(paused);
|
videoView.setPausedModifier(paused);
|
||||||
|
@ -109,6 +109,7 @@ class VideoEventEmitter {
|
|||||||
private static final String EVENT_PROP_WIDTH = "width";
|
private static final String EVENT_PROP_WIDTH = "width";
|
||||||
private static final String EVENT_PROP_HEIGHT = "height";
|
private static final String EVENT_PROP_HEIGHT = "height";
|
||||||
private static final String EVENT_PROP_ORIENTATION = "orientation";
|
private static final String EVENT_PROP_ORIENTATION = "orientation";
|
||||||
|
private static final String EVENT_PROP_TEXT_TRACKS = "textTracks";
|
||||||
private static final String EVENT_PROP_HAS_AUDIO_FOCUS = "hasAudioFocus";
|
private static final String EVENT_PROP_HAS_AUDIO_FOCUS = "hasAudioFocus";
|
||||||
private static final String EVENT_PROP_IS_BUFFERING = "isBuffering";
|
private static final String EVENT_PROP_IS_BUFFERING = "isBuffering";
|
||||||
private static final String EVENT_PROP_PLAYBACK_RATE = "playbackRate";
|
private static final String EVENT_PROP_PLAYBACK_RATE = "playbackRate";
|
||||||
@ -128,7 +129,8 @@ class VideoEventEmitter {
|
|||||||
receiveEvent(EVENT_LOAD_START, null);
|
receiveEvent(EVENT_LOAD_START, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void load(double duration, double currentPosition, int videoWidth, int videoHeight) {
|
void load(double duration, double currentPosition, int videoWidth, int videoHeight,
|
||||||
|
WritableArray textTracks) {
|
||||||
WritableMap event = Arguments.createMap();
|
WritableMap event = Arguments.createMap();
|
||||||
event.putDouble(EVENT_PROP_DURATION, duration / 1000D);
|
event.putDouble(EVENT_PROP_DURATION, duration / 1000D);
|
||||||
event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D);
|
event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D);
|
||||||
@ -143,6 +145,8 @@ class VideoEventEmitter {
|
|||||||
}
|
}
|
||||||
event.putMap(EVENT_PROP_NATURAL_SIZE, naturalSize);
|
event.putMap(EVENT_PROP_NATURAL_SIZE, naturalSize);
|
||||||
|
|
||||||
|
event.putArray(EVENT_PROP_TEXT_TRACKS, textTracks);
|
||||||
|
|
||||||
// TODO: Actually check if you can.
|
// TODO: Actually check if you can.
|
||||||
event.putBoolean(EVENT_PROP_FAST_FORWARD, true);
|
event.putBoolean(EVENT_PROP_FAST_FORWARD, true);
|
||||||
event.putBoolean(EVENT_PROP_SLOW_FORWARD, true);
|
event.putBoolean(EVENT_PROP_SLOW_FORWARD, true);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user