如何解决 ExoPlayer 缓慢加载视频的问题?

问题描述 投票:0回答:1

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

ExoPlayer 正在播放视频,但我面临的问题是,ExoPlayer 正在加载视频的某些部分(比如说 5 秒)然后播放它们,一旦 exo 播放器播放完该部分,它就会尝试加载视频的下一部分然后播放那部分视频。即使互联网速度很好,也会出现此问题。

下面是我的 ExoPlayer 单例类的代码:

/**
 * 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;
    }
}
java performance video-streaming exoplayer exoplayer2.x
1个回答
11
投票

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

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();

想法是保持最小缓冲区较低,以便视频加载速度更快。

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

© www.soinside.com 2019 - 2024. All rights reserved.