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:
sridhar 2018-08-24 15:33:46 +05:30
parent 7dc9e85793
commit 16688cef0f
5 changed files with 129 additions and 19 deletions

View File

@ -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([

View File

@ -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) {

View File

@ -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) {

View File

@ -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);

View File

@ -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());