diff --git a/Video.js b/Video.js index 5c6cd1d3..a10c7dd4 100644 --- a/Video.js +++ b/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([ diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index e098c72a..bcac252f 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -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) { diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index 9ead70ce..f7510335 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -51,6 +51,9 @@ public class ReactExoplayerViewManager extends ViewGroupManager> createJSModules() { - return Collections.emptyList(); - } - @Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.singletonList(new ReactExoplayerViewManager());