Youtube like video track selection
1. Loaded event will give the information about available video tracks 2. selectedVideoTrack prop will give the interface to select the video track. This prop will take the height of the video (Similar to youtube like 144p, 350p etc) and set the video track. If height is 0 then all video tracks will be added to list so that it will work like 'Auto' in youtube
This commit is contained in:
parent
7dc9e85793
commit
16688cef0f
7
Video.js
7
Video.js
@ -323,6 +323,13 @@ Video.propTypes = {
|
||||
PropTypes.number
|
||||
])
|
||||
}),
|
||||
selectedVideoTrack: PropTypes.shape({
|
||||
type: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number
|
||||
])
|
||||
}),
|
||||
selectedTextTrack: PropTypes.shape({
|
||||
type: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([
|
||||
|
@ -46,6 +46,7 @@ import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
|
||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
||||
@ -121,6 +122,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private boolean repeat;
|
||||
private String audioTrackType;
|
||||
private Dynamic audioTrackValue;
|
||||
private String videoTrackType;
|
||||
private Dynamic videoTrackValue;
|
||||
private ReadableArray audioTracks;
|
||||
private String textTrackType;
|
||||
private Dynamic textTrackValue;
|
||||
@ -512,12 +515,13 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
if (loadVideoStarted) {
|
||||
loadVideoStarted = false;
|
||||
setSelectedAudioTrack(audioTrackType, audioTrackValue);
|
||||
setSelectedVideoTrack(videoTrackType, videoTrackValue);
|
||||
setSelectedTextTrack(textTrackType, textTrackValue);
|
||||
Format videoFormat = player.getVideoFormat();
|
||||
int width = videoFormat != null ? videoFormat.width : 0;
|
||||
int height = videoFormat != null ? videoFormat.height : 0;
|
||||
eventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height,
|
||||
getAudioTrackInfo(), getTextTrackInfo());
|
||||
getAudioTrackInfo(), getTextTrackInfo(), getVideoTrackInfo());
|
||||
}
|
||||
}
|
||||
|
||||
@ -543,6 +547,40 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
return audioTracks;
|
||||
}
|
||||
|
||||
private WritableArray getVideoTrackInfo() {
|
||||
WritableArray videoTracks = Arguments.createArray();
|
||||
|
||||
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
|
||||
int index = getTrackRendererIndex(C.TRACK_TYPE_VIDEO);
|
||||
if (info == null || index == C.INDEX_UNSET) {
|
||||
return videoTracks;
|
||||
}
|
||||
|
||||
TrackGroupArray groups = info.getTrackGroups(index);
|
||||
for (int i = 0; i < groups.length; ++i) {
|
||||
TrackGroup group = groups.get(i);
|
||||
|
||||
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
|
||||
Format format = group.getFormat(trackIndex);
|
||||
|
||||
WritableMap videoTrack = Arguments.createMap();
|
||||
|
||||
videoTrack.putString("width",
|
||||
format.width == Format.NO_VALUE ? "" : format.width + "");
|
||||
videoTrack.putString("height",
|
||||
format.height == Format.NO_VALUE ? "" : format.height + "");
|
||||
videoTrack.putString("bitrate",
|
||||
format.bitrate == Format.NO_VALUE ? ""
|
||||
: String.format(Locale.US, "%.2fMbps", format.bitrate / 1000000f));
|
||||
videoTrack.putString("trackid", format.id == null ? "" : "" + format.id + "");
|
||||
|
||||
videoTracks.pushMap(videoTrack);
|
||||
}
|
||||
|
||||
}
|
||||
return videoTracks;
|
||||
}
|
||||
|
||||
private WritableArray getTextTrackInfo() {
|
||||
WritableArray textTracks = Arguments.createArray();
|
||||
|
||||
@ -758,6 +796,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
public void setSelectedTrack(int trackType, String type, Dynamic value) {
|
||||
|
||||
int rendererIndex = getTrackRendererIndex(trackType);
|
||||
if (rendererIndex == C.INDEX_UNSET) {
|
||||
return;
|
||||
@ -768,7 +807,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
TrackGroupArray groups = info.getTrackGroups(rendererIndex);
|
||||
int trackIndex = C.INDEX_UNSET;
|
||||
int groupIndex = C.INDEX_UNSET;
|
||||
int[] tracks = {0} ;
|
||||
|
||||
if (TextUtils.isEmpty(type)) {
|
||||
type = "default";
|
||||
@ -786,7 +826,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
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;
|
||||
groupIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -794,13 +834,56 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
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;
|
||||
groupIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (type.equals("index")) {
|
||||
if (value.asInt() < groups.length) {
|
||||
trackIndex = value.asInt();
|
||||
groupIndex = value.asInt();
|
||||
}
|
||||
} else if (type.equals("videoHeight")) {
|
||||
groupIndex = C.INDEX_UNSET;
|
||||
|
||||
/*0 is auto mode. Add all tracks of group 0*/
|
||||
if (0 == value.asInt()) {
|
||||
TrackGroup group = groups.get(0);
|
||||
|
||||
tracks = new int[group.length];
|
||||
|
||||
groupIndex = 0;
|
||||
|
||||
for (int j = 0; j < group.length; j++) {
|
||||
tracks[j] = j;
|
||||
}
|
||||
} else {
|
||||
/*Search for the exact video Height*/
|
||||
for (int i = 0; i < groups.length; ++i) {
|
||||
TrackGroup group = groups.get(i);
|
||||
|
||||
for (int j = 0; j < group.length; j++) {
|
||||
Format format = group.getFormat(j);
|
||||
|
||||
if (format.height == value.asInt()) {
|
||||
groupIndex = i;
|
||||
tracks[0] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*If exact height not found then make it auto. Add all tracks of group 0*/
|
||||
if (groupIndex == C.INDEX_UNSET) {
|
||||
TrackGroup group = groups.get(0);
|
||||
|
||||
tracks = new int[group.length];
|
||||
|
||||
groupIndex = 0;
|
||||
|
||||
for (int j = 0; j < group.length; j++) {
|
||||
tracks[j] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // default
|
||||
if (rendererIndex == C.TRACK_TYPE_TEXT && Util.SDK_INT > 18 && groups.length > 0) {
|
||||
@ -808,14 +891,14 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
CaptioningManager captioningManager
|
||||
= (CaptioningManager)themedReactContext.getSystemService(Context.CAPTIONING_SERVICE);
|
||||
if (captioningManager != null && captioningManager.isEnabled()) {
|
||||
trackIndex = getTrackIndexForDefaultLocale(groups);
|
||||
groupIndex = getGroupIndexForDefaultLocale(groups);
|
||||
}
|
||||
} else if (rendererIndex == C.TRACK_TYPE_AUDIO) {
|
||||
trackIndex = getTrackIndexForDefaultLocale(groups);
|
||||
groupIndex = getGroupIndexForDefaultLocale(groups);
|
||||
}
|
||||
}
|
||||
|
||||
if (trackIndex == C.INDEX_UNSET) {
|
||||
if (groupIndex == C.INDEX_UNSET) {
|
||||
trackSelector.setParameters(disableParameters);
|
||||
return;
|
||||
}
|
||||
@ -824,24 +907,30 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
.buildUpon()
|
||||
.setRendererDisabled(rendererIndex, false)
|
||||
.setSelectionOverride(rendererIndex, groups,
|
||||
new DefaultTrackSelector.SelectionOverride(trackIndex, 0))
|
||||
new DefaultTrackSelector.SelectionOverride(groupIndex, tracks))
|
||||
.build();
|
||||
trackSelector.setParameters(selectionParameters);
|
||||
}
|
||||
|
||||
private int getTrackIndexForDefaultLocale(TrackGroupArray groups) {
|
||||
int trackIndex = 0; // default if no match
|
||||
private int getGroupIndexForDefaultLocale(TrackGroupArray groups) {
|
||||
int groupIndex = 0; // default if no match
|
||||
String locale2 = Locale.getDefault().getLanguage(); // 2 letter code
|
||||
String locale3 = Locale.getDefault().getISO3Language(); // 3 letter code
|
||||
for (int i = 0; i < groups.length; ++i) {
|
||||
Format format = groups.get(i).getFormat(0);
|
||||
String language = format.language;
|
||||
if (language != null && (language.equals(locale2) || language.equals(locale3))) {
|
||||
trackIndex = i;
|
||||
groupIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return trackIndex;
|
||||
return groupIndex;
|
||||
}
|
||||
|
||||
public void setSelectedVideoTrack(String type, Dynamic value) {
|
||||
videoTrackType = type;
|
||||
videoTrackValue = value;
|
||||
setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue);
|
||||
}
|
||||
|
||||
public void setSelectedAudioTrack(String type, Dynamic value) {
|
||||
|
@ -51,6 +51,9 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
private static final String PROP_DISABLE_FOCUS = "disableFocus";
|
||||
private static final String PROP_FULLSCREEN = "fullscreen";
|
||||
private static final String PROP_USE_TEXTURE_VIEW = "useTextureView";
|
||||
private static final String PROP_SELECTED_VIDEO_TRACK = "selectedVideoTrack";
|
||||
private static final String PROP_SELECTED_VIDEO_TRACK_TYPE = "type";
|
||||
private static final String PROP_SELECTED_VIDEO_TRACK_VALUE = "value";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@ -136,6 +139,20 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
videoView.setRepeatModifier(repeat);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_SELECTED_VIDEO_TRACK)
|
||||
public void setSelectedVideoTrack(final ReactExoplayerView videoView,
|
||||
@Nullable ReadableMap selectedVideoTrack) {
|
||||
String typeString = null;
|
||||
Dynamic value = null;
|
||||
if (selectedVideoTrack != null) {
|
||||
typeString = selectedVideoTrack.hasKey(PROP_SELECTED_VIDEO_TRACK_TYPE)
|
||||
? selectedVideoTrack.getString(PROP_SELECTED_VIDEO_TRACK_TYPE) : null;
|
||||
value = selectedVideoTrack.hasKey(PROP_SELECTED_VIDEO_TRACK_VALUE)
|
||||
? selectedVideoTrack.getDynamic(PROP_SELECTED_VIDEO_TRACK_VALUE) : null;
|
||||
}
|
||||
videoView.setSelectedVideoTrack(typeString, value);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_SELECTED_AUDIO_TRACK)
|
||||
public void setSelectedAudioTrack(final ReactExoplayerView videoView,
|
||||
@Nullable ReadableMap selectedAudioTrack) {
|
||||
|
@ -109,6 +109,7 @@ class VideoEventEmitter {
|
||||
private static final String EVENT_PROP_WIDTH = "width";
|
||||
private static final String EVENT_PROP_HEIGHT = "height";
|
||||
private static final String EVENT_PROP_ORIENTATION = "orientation";
|
||||
private static final String EVENT_PROP_VIDEO_TRACKS = "videoTracks";
|
||||
private static final String EVENT_PROP_AUDIO_TRACKS = "audioTracks";
|
||||
private static final String EVENT_PROP_TEXT_TRACKS = "textTracks";
|
||||
private static final String EVENT_PROP_HAS_AUDIO_FOCUS = "hasAudioFocus";
|
||||
@ -131,7 +132,7 @@ class VideoEventEmitter {
|
||||
}
|
||||
|
||||
void load(double duration, double currentPosition, int videoWidth, int videoHeight,
|
||||
WritableArray audioTracks, WritableArray textTracks) {
|
||||
WritableArray audioTracks, WritableArray textTracks, WritableArray videoTracks) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
event.putDouble(EVENT_PROP_DURATION, duration / 1000D);
|
||||
event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D);
|
||||
@ -146,6 +147,7 @@ class VideoEventEmitter {
|
||||
}
|
||||
event.putMap(EVENT_PROP_NATURAL_SIZE, naturalSize);
|
||||
|
||||
event.putArray(EVENT_PROP_VIDEO_TRACKS, videoTracks);
|
||||
event.putArray(EVENT_PROP_AUDIO_TRACKS, audioTracks);
|
||||
event.putArray(EVENT_PROP_TEXT_TRACKS, textTracks);
|
||||
|
||||
|
@ -17,11 +17,6 @@ public class ReactVideoPackage implements ReactPackage {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// Deprecated RN 0.47
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Collections.<ViewManager>singletonList(new ReactExoplayerViewManager());
|
||||
|
Loading…
Reference in New Issue
Block a user