Как исправить exo player медленную загрузку видео - PullRequest
1 голос
/ 20 апреля 2019

Я пытаюсь написать приложение, в котором у меня будет пара URL-адресов видео, которые мне нужно воспроизвести. Я использую Exo Player для воспроизведения видео.
Exo Player воспроизводит видео, но проблема, с которой я сталкиваюсь, заключается в том, что exo player загружает некоторую часть видео (скажем, 5 секунд), а затем воспроизводит их, и как только exo Player завершает воспроизведение этой части, он пытается загрузить следующую часть видео, а затем воспроизводить эту часть видео. Эта проблема возникает, даже если скорость интернета хорошая. Я пытался читать документы exo player и другие сообщения от stackoverflow, но я не могу понять, что здесь не так.
Ниже приведен мой код для синглтон-класса экзо-игрока:

/**
 * Singleton class that manages all video playback in the app. Ensures that only a single stream can be heard at a time
 * and reports the current playback status to any interested listeners.
 */
public class VideoWrapper {
    private static String TAG = "VideoWrapper";

    private int VideoPlaybackState = VideoPlaybackListener.STATE_VIDEO_STOPPED;

    // Player that plays the videos.
    private SimpleExoPlayer exoPlayer;

    // Singleton instance of the class
    private static VideoWrapper videoWrapper;

    // URL of Current Video Item that is getting played.
    private String mCurrentStreamingUrl;

    // Handler to take request of video playback in-case there is a playlist is being sent for play.
    private Handler handler;

    // Add the listener and notify them if required. -- For demo i am not using it but for UI updates and all it will be useful.
    private List<VideoPlaybackListener> listeners = new LinkedList<>();

    // Tells to which screen we have to go back
    private String mPreviousScreenName;

    private Context context;

    public static VideoWrapper getInstance() {
        if (videoWrapper == null) {
            videoWrapper = new VideoWrapper();
        }

        return videoWrapper;
    }

    // Default constrructor!
    private VideoWrapper() {
        // Nothing to do.
    }

    public void setCurrentPreviousScreen(String screen) {
        mPreviousScreenName = screen;
    }

    public void init(Context context) {
        try {
            this.context = context;
            handler = new Handler(context.getMainLooper());
        } catch (Exception e) {
            // TODO
        }
    }

    public void stopAndReleasePlayer() {

        // Stop the player first.
        stopVideoStreaming();

        // Now release the player and make it null.
        if (exoPlayer != null) {
            exoPlayer.release();
            exoPlayer = null;
        }
    }

    public void addListener(VideoPlaybackListener listener) {
        listeners.add(listener);
    }

    public void removeListener(VideoPlaybackListener listener) {
        listeners.remove(listener);
    }

    public int getVideoPlaybackState() {
        return VideoPlaybackState;
    }

    private SimpleExoPlayer.VideoListener gVideoEventListener = new SimpleExoPlayer.VideoListener() {
        @Override
        public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
            // TODO: Do Something!
        }

        @Override
        public void onRenderedFirstFrame() {
            // TODO: Do Something!
        }
    };

    private ExoPlayer.EventListener eventListener = new ExoPlayer.EventListener() {
        @Override
        public void onTimelineChanged(Timeline timeline, Object manifest) {
            // TODO: Do Something!
        }

        @Override
        public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
            // TODO: Do Something!
        }

        @Override
        public void onLoadingChanged(boolean isLoading) {
            // TODO: Do Something!
        }

        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            switch (playbackState) {
                // playback state handling serially
                case ExoPlayer.STATE_IDLE:
                    // TODO: Do something!
                    break;

                case ExoPlayer.STATE_BUFFERING:
                    // TODO: Do something!
                    break;

                case ExoPlayer.STATE_READY:
                    // TODO: Do something!
                    break;

                case ExoPlayer.STATE_ENDED:
                    // TODO: Do something!
                    break;
            }
        }

        @Override
        public void onPlayerError(ExoPlaybackException error) {
            int errorType = error.type;
            switch (errorType) {
                case ExoPlaybackException.TYPE_RENDERER:
                    // TODO: Do something!
                    break;
                case ExoPlaybackException.TYPE_SOURCE:
                    // TODO: Do something!
                    break;
                case ExoPlaybackException.TYPE_UNEXPECTED:
                    // TODO: Do something!
                    break;
                default:
                    // TODO: Do something!
                    break;
            }
        }

        @Override
        public void onPositionDiscontinuity() {
            // TODO: Do something!
        }
    };

    private boolean canPlayCurrentItem() {
        return mCurrentStreamingUrl != null && !TextUtils.isEmpty(mCurrentStreamingUrl);
    }

    public void stopVideoStreaming() {
        if (exoPlayer != null) {
            exoPlayer.setPlayWhenReady(false);
        }
    }

    private void restartVideoStreaming() {
        if (canPlayCurrentItem()) {
            streamCurrentTrack();
        }
    }

    public void startVideoStreaming(String streamUrl) {
        // Stop any video if it is playing.
        stopVideoStreaming();
        VideoPlaybackState = VideoPlaybackListener.STATE_VIDEO_STOPPED;
        mCurrentStreamingUrl = streamUrl;

        openStreamUrl();
    }

    private void openStreamUrl() {
        Uri uri = Uri.parse(mCurrentStreamingUrl);

        TrackSelector trackSelector = new DefaultTrackSelector();

        LoadControl loadControl = new DefaultLoadControl();

        DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        DataSource.Factory dataSourceFactory = buildDataSourceFactory(bandwidthMeter);

        // This is the MediaSource representing the media to be played.
        HlsMediaSource mediaSource = new HlsMediaSource(uri, dataSourceFactory, handler, new AdaptiveMediaSourceEventListener() {
            @Override
            public void onLoadStarted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs) {
                // TODO: Do something!
            }

            @Override
            public void onLoadCompleted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) {
                // TODO: Do something!
            }

            @Override
            public void onLoadCanceled(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) {
                // TODO: Do something!
            }

            @Override
            public void onLoadError(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded, IOException error, boolean wasCanceled) {
                // TODO: Do something!
            }

            @Override
            public void onUpstreamDiscarded(int trackType, long mediaStartTimeMs, long mediaEndTimeMs) {
                // TODO: Do something!
            }

            @Override
            public void onDownstreamFormatChanged(int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaTimeMs) {
                // TODO: Do something!
            }
        });

        exoPlayer.prepare(mediaSource);

        streamCurrentTrack();
    }

    private DataSource.Factory buildDataSourceFactory(DefaultBandwidthMeter bandwidthMeter){
        return new DefaultDataSourceFactory(context, bandwidthMeter, buildHttpDataSourceFactory(bandwidthMeter));
    }

    private HttpDataSource.Factory buildHttpDataSourceFactory(DefaultBandwidthMeter bandwidthMeter){
        return new DefaultHttpDataSourceFactory("TiVoPhoenix", bandwidthMeter);
    }

    public void togglePlayPause() {
        if (canPlayCurrentItem()) {
            if (VideoPlaybackState == PlaybackListener.STATE_PLAYING) {
                stopVideoStreaming();
                VideoPlaybackState = PlaybackListener.STATE_PAUSED;
            } else {
                restartVideoStreaming();
            }
        }
    }

    private void streamCurrentTrack() {
        VideoPlaybackState = VideoPlaybackListener.STATE_VIDEO_PLAYING;
        exoPlayer.setPlayWhenReady(true);
    }

    public SimpleExoPlayer getPlayer() {
        TrackSelector trackSelector = new DefaultTrackSelector();
        LoadControl loadControl = new DefaultLoadControl();

        // Stop and release the video player before re-creating it.
        stopAndReleasePlayer();

        exoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector, loadControl);
        exoPlayer.addListener(eventListener);
        exoPlayer.setVideoListener(gVideoEventListener);

        return exoPlayer;
    }
}  

Не могли бы вы, ребята, помочь мне с этим?

1 Ответ

0 голосов
/ 23 апреля 2019

Попробуйте следующие настройки для управления загрузкой:

public class VideoPlayerConfig {
    //Minimum Video you want to buffer while Playing
    public static final int MIN_BUFFER_DURATION = 2000;
    //Max Video you want to buffer during PlayBack
    public static final int MAX_BUFFER_DURATION = 5000;
   //Min Video you want to buffer before start Playing it
    public static final int MIN_PLAYBACK_START_BUFFER = 1500;
    //Min video You want to buffer when user resumes video
    public static final int MIN_PLAYBACK_RESUME_BUFFER = 2000;
}

LoadControl loadControl = new DefaultLoadControl.Builder()
            .setAllocator(new DefaultAllocator(true, 16))
            .setBufferDurationsMs(VideoPlayerConfig.MIN_BUFFER_DURATION,
                    VideoPlayerConfig.MAX_BUFFER_DURATION,
                    VideoPlayerConfig.MIN_PLAYBACK_START_BUFFER,
                    VideoPlayerConfig.MIN_PLAYBACK_RESUME_BUFFER)
            .setTargetBufferBytes(-1)
            .setPrioritizeTimeOverSizeThresholds(true).createDefaultLoadControl();

Идея состоит в том, чтобы поддерживать минимальный буфер на низком уровне, чтобы видео загружалось быстрее.

Не по теме: а я нетзнать, почему вы используете шаблон синглтона, возможно, чтобы получить контроль над всем приложением.Поскольку вы используете шаблон синглтона, вы можете использовать слабую ссылку на контекст приложения.

...