HLS не работает в exoplayer в следующем коде - PullRequest
0 голосов
/ 25 января 2020

Какие изменения необходимо внести в следующий код, чтобы получить ссылку m3u8 для воспроизведения?

Я могу заставить работать обычные видео MP4, но не HLS. Что мне нужно сделать, чтобы ссылки HLS работали?

Я хотел бы реализовать нечто подобное, что позволяет воспроизводить различные медиаисточники. https://gist.github.com/navi25/7ab41931eb52bbcb693b5599e6955245#file -mediasourcebuilder-kt

public class VideoPlayerRecyclerView extends RecyclerView {

private static final String TAG = "VideoPlayerRecyclerView";

private enum VolumeState {ON, OFF};

// ui
private ImageView thumbnail, volumeControl;
private ProgressBar progressBar;
private View viewHolderParent;
private FrameLayout frameLayout;
private PlayerView videoSurfaceView;
private SimpleExoPlayer videoPlayer;

// vars
private ArrayList<MediaObject> mediaObjects = new ArrayList<>();
private int videoSurfaceDefaultHeight = 0;
private int screenDefaultHeight = 0;
private Context context;
private int playPosition = -1;
private boolean isVideoViewAdded;
private RequestManager requestManager;

// controlling playback state
private VolumeState volumeState;

public VideoPlayerRecyclerView(@NonNull Context context) {
    super(context);
    init(context);
}

public VideoPlayerRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(context);
}


private void init(Context context){
    this.context = context.getApplicationContext();
    Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    Point point = new Point();
    display.getSize(point);
    videoSurfaceDefaultHeight = point.x;
    screenDefaultHeight = point.y;

    videoSurfaceView = new PlayerView(this.context);
    videoSurfaceView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_ZOOM);

    BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
    TrackSelection.Factory videoTrackSelectionFactory =
            new AdaptiveTrackSelection.Factory(bandwidthMeter);
    TrackSelector trackSelector =
            new DefaultTrackSelector(videoTrackSelectionFactory);

    // 2. Create the player
    videoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
    // Bind the player to the view.
    videoSurfaceView.setUseController(false);
    videoSurfaceView.setPlayer(videoPlayer);
    setVolumeControl(VolumeState.ON);

    addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                Log.d(TAG, "onScrollStateChanged: called.");
                if(thumbnail != null){ // show the old thumbnail
                    thumbnail.setVisibility(VISIBLE);
                }

                // There's a special case when the end of the list has been reached.
                // Need to handle that with this bit of logic
                if(!recyclerView.canScrollVertically(1)){
                    playVideo(true);
                }
                else{
                    playVideo(false);
                }
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
        }
    });

    addOnChildAttachStateChangeListener(new OnChildAttachStateChangeListener() {
        @Override
        public void onChildViewAttachedToWindow(View view) {

        }

        @Override
        public void onChildViewDetachedFromWindow(View view) {
            if (viewHolderParent != null && viewHolderParent.equals(view)) {
                resetVideoView();
            }

        }
    });

    videoPlayer.addListener(new Player.EventListener() {
        @Override
        public void onTimelineChanged(Timeline timeline, @Nullable Object manifest, int reason) {

        }

        @Override
        public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {

        }

        @Override
        public void onLoadingChanged(boolean isLoading) {

        }

        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            switch (playbackState) {

                case Player.STATE_BUFFERING:
                    Log.e(TAG, "onPlayerStateChanged: Buffering video.");
                    if (progressBar != null) {
                        progressBar.setVisibility(VISIBLE);
                    }

                    break;
                case Player.STATE_ENDED:
                    Log.d(TAG, "onPlayerStateChanged: Video ended.");
                    videoPlayer.seekTo(0);
                    break;
                case Player.STATE_IDLE:

                    break;
                case Player.STATE_READY:
                    Log.e(TAG, "onPlayerStateChanged: Ready to play.");
                    if (progressBar != null) {
                        progressBar.setVisibility(GONE);
                    }
                    if(!isVideoViewAdded){
                        addVideoView();
                    }
                    break;
                default:
                    break;
            }
        }

        @Override
        public void onRepeatModeChanged(int repeatMode) {

        }

        @Override
        public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {

        }

        @Override
        public void onPlayerError(ExoPlaybackException error) {

        }

        @Override
        public void onPositionDiscontinuity(int reason) {

        }

        @Override
        public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {

        }

        @Override
        public void onSeekProcessed() {

        }
    });
}

public void playVideo(boolean isEndOfList) {

    int targetPosition;

    if(!isEndOfList){
        int startPosition = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();
        int endPosition = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition();

        // if there is more than 2 list-items on the screen, set the difference to be 1
        if (endPosition - startPosition > 1) {
            endPosition = startPosition + 1;
        }

        // something is wrong. return.
        if (startPosition < 0 || endPosition < 0) {
            return;
        }

        // if there is more than 1 list-item on the screen
        if (startPosition != endPosition) {
            int startPositionVideoHeight = getVisibleVideoSurfaceHeight(startPosition);
            int endPositionVideoHeight = getVisibleVideoSurfaceHeight(endPosition);

            targetPosition = startPositionVideoHeight > endPositionVideoHeight ? startPosition : endPosition;
        }
        else {
            targetPosition = startPosition;
        }
    }
    else{
        targetPosition = mediaObjects.size() - 1;
    }

    Log.d(TAG, "playVideo: target position: " + targetPosition);

    // video is already playing so return
    if (targetPosition == playPosition) {
        return;
    }

    // set the position of the list-item that is to be played
    playPosition = targetPosition;
    if (videoSurfaceView == null) {
        return;
    }

    // remove any old surface views from previously playing videos
    videoSurfaceView.setVisibility(INVISIBLE);
    removeVideoView(videoSurfaceView);

    int currentPosition = targetPosition - ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();

    View child = getChildAt(currentPosition);
    if (child == null) {
        return;
    }

    VideoPlayerViewHolder holder = (VideoPlayerViewHolder) child.getTag();
    if (holder == null) {
        playPosition = -1;
        return;
    }
    thumbnail = holder.thumbnail;
    progressBar = holder.progressBar;
    volumeControl = holder.volumeControl;
    viewHolderParent = holder.itemView;
    requestManager = holder.requestManager;
    frameLayout = holder.itemView.findViewById(R.id.media_container);

    videoSurfaceView.setPlayer(videoPlayer);

    viewHolderParent.setOnClickListener(videoViewClickListener);

    DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(
            context, Util.getUserAgent(context, "RecyclerView VideoPlayer"));
    String mediaUrl = mediaObjects.get(targetPosition).getMedia_url();
    if (mediaUrl != null) {
        MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory)
                .createMediaSource(Uri.parse(mediaUrl));
        videoPlayer.prepare(videoSource);
        videoPlayer.setPlayWhenReady(true);
    }
}

private OnClickListener videoViewClickListener = new OnClickListener() {
    @Override
    public void onClick(View v) {
        toggleVolume();
    }
};

/**
 * Returns the visible region of the video surface on the screen.
 * if some is cut off, it will return less than the @videoSurfaceDefaultHeight
 * @param playPosition
 * @return
 */
private int getVisibleVideoSurfaceHeight(int playPosition) {
    int at = playPosition - ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();
    Log.d(TAG, "getVisibleVideoSurfaceHeight: at: " + at);

    View child = getChildAt(at);
    if (child == null) {
        return 0;
    }

    int[] location = new int[2];
    child.getLocationInWindow(location);

    if (location[1] < 0) {
        return location[1] + videoSurfaceDefaultHeight;
    } else {
        return screenDefaultHeight - location[1];
    }
}


// Remove the old player
private void removeVideoView(PlayerView videoView) {
    ViewGroup parent = (ViewGroup) videoView.getParent();
    if (parent == null) {
        return;
    }

    int index = parent.indexOfChild(videoView);
    if (index >= 0) {
        parent.removeViewAt(index);
        isVideoViewAdded = false;
        viewHolderParent.setOnClickListener(null);
    }

}

private void addVideoView(){
    frameLayout.addView(videoSurfaceView);
    isVideoViewAdded = true;
    videoSurfaceView.requestFocus();
    videoSurfaceView.setVisibility(VISIBLE);
    videoSurfaceView.setAlpha(1);
    thumbnail.setVisibility(GONE);
}

private void resetVideoView(){
    if(isVideoViewAdded){
        removeVideoView(videoSurfaceView);
        playPosition = -1;
        videoSurfaceView.setVisibility(INVISIBLE);
        thumbnail.setVisibility(VISIBLE);
    }
}

public void releasePlayer() {

    if (videoPlayer != null) {
        videoPlayer.release();
        videoPlayer = null;
    }

    viewHolderParent = null;
}

private void toggleVolume() {
    if (videoPlayer != null) {
        if (volumeState == VolumeState.OFF) {
            Log.d(TAG, "togglePlaybackState: enabling volume.");
            setVolumeControl(VolumeState.ON);

        } else if(volumeState == VolumeState.ON) {
            Log.d(TAG, "togglePlaybackState: disabling volume.");
            setVolumeControl(VolumeState.OFF);

        }
    }
}

private void setVolumeControl(VolumeState state){
    volumeState = state;
    if(state == VolumeState.OFF){
        videoPlayer.setVolume(0f);
        animateVolumeControl();
    }
    else if(state == VolumeState.ON){
        videoPlayer.setVolume(1f);
        animateVolumeControl();
    }
}

private void animateVolumeControl(){
    if(volumeControl != null){
        volumeControl.bringToFront();
        if(volumeState == VolumeState.OFF){
            requestManager.load(R.drawable.ic_volume_off_grey_24dp)
                    .into(volumeControl);
        }
        else if(volumeState == VolumeState.ON){
            requestManager.load(R.drawable.ic_volume_up_grey_24dp)
                    .into(volumeControl);
        }
        volumeControl.animate().cancel();

        volumeControl.setAlpha(1f);

        volumeControl.animate()
                .alpha(0f)
                .setDuration(600).setStartDelay(1000);
    }
}

public void setMediaObjects(ArrayList<MediaObject> mediaObjects){
    this.mediaObjects = mediaObjects;
}

}

1 Ответ

1 голос
/ 26 января 2020

Вам необходимо использовать HlsMediaSource вместо значения по умолчанию MediaSource для HLS.

Источники информации

...