Commit 16688cef authored by sridhar's avatar sridhar
Browse files

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
parent 7dc9e857
Loading
Loading
Loading
Loading
+7 −0
Changes for Video.js: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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([
+102 −13
Changes for android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java: 102 added lines, 13 removed lines.
Original line number Diff line number Diff line
@@ -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) {
+17 −0
Changes for android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java: 17 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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) {
+3 −1
Changes for android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java: 3 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -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);

+0 −5
Changes for android-exoplayer/src/main/java/com/brentvatne/react/ReactVideoPackage.java: 0 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -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());