如何解决exo播放器加载视频慢的问题

Ali*_*phy 6 java performance video-streaming exoplayer exoplayer2.x

我正在尝试编写一个应用程序,其中有几个我需要播放的视频 URL。我正在使用 ExoPlayer 播放视频。

ExoPlayer is playing the videos but the problem i am facing is, ExoPlayer is loading some part of video (let's say 5 seconds) and then playing them and once exo player is done playing that part, it is trying to load next part of video and then playing that part of video. This problem is occurring even when the internet speed is good.

I tried reading ExoPlayer docs and other stackoverflow posts but i am not able to figure out what's wrong here.

Below is my code for exo player's singleton class:

/**
 * 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;
    }
}  
Run Code Online (Sandbox Code Playgroud)

Can someone help me with this?

Sp4*_*4Rx 9

为您的负载控制尝试此设置:

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();
Run Code Online (Sandbox Code Playgroud)

这个想法是将最小缓冲区保持在较低的水平,以便视频加载速度更快。

题外话:我不知道你为什么使用单例模式,可能是为了在应用程序的任何地方获得控制权。当您使用单例模式时,您可以使用应用程序上下文的弱引用。

  • 我尝试了如上所述的负载控制的这些选项。我直接播放网络视频。当我加载播放器时,它会缓冲至少 3-4 秒,然后开始播放视频。 (3认同)