【问题标题】:How to fix exo player slow loading of video如何修复exo播放器加载视频慢的问题
【发布时间】:2019-09-10 10:27:42
【问题描述】:

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

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

我尝试阅读 ExoPlayer 文档和其他 stackoverflow 帖子,但我无法弄清楚这里出了什么问题。

以下是我的 exo 播放器单例类代码:

/**
 * 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】:

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

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

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

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

    【讨论】:

    • 我已经尝试过这些设置。它不适合我。您还有其他选择吗?
    • 您面临的问题是什么? @VIVEKCHOUDHARY
    • 如上所述,我尝试了这些负载控制选项。我直接从网络播放视频。当我加载播放器时,它会缓冲至少 3-4 秒,然后开始播放视频。
    • 您可以进一步调整这些设置。试试这个bufferForPlaybackMs 2500; minBufferMs 15000; maxBufferMs 50000; bufferForPlaybackAfterRebufferMs 5000。还要检查您的网络速度和视频质量。如果是高清视频,则需要更多带宽。压缩视频并降低分辨率并尝试。 @VIVEKCHOUDHARY
    • 视频已被压缩。网络速度不错。加载仍然需要时间。
    猜你喜欢
    • 1970-01-01
    • 2021-12-24
    • 2015-09-15
    • 2016-08-27
    • 2014-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多