Android VideoView缓冲

时间:2017-04-01 12:21:56

标签: android android-mediaplayer android-videoview android-tv

我正在使用Android TV应用,该应用使用VideoView来播放网址中的视频。每次视频暂停然后恢复 - 首先预先下载(进度条出现的几秒钟)需要一些时间。目标是在播放期间缓冲视频,以便在我暂停然后恢复时 - 它立即从预缓冲状态恢复。我也尝试了videoView.resume()方法,但它也没有帮助。有没有办法做到这一点,还是我做错了什么?

以下是播放/恢复视频的代码:

public void onFragmentPlayPause(final Video video,
                                    final VideoQuality quality,
                                    final int position,
                                    final Boolean play) {
        stopSeeking();

        videoView.setVideoPath(video.videoUrl(quality));

        if (position == 0 || playbackState == LeanbackPlaybackState.IDLE) {
            setupCallbacks();
            playbackState = LeanbackPlaybackState.IDLE;
        }

        if (play && playbackState != LeanbackPlaybackState.PLAYING) {
            progressBar.setVisibility(View.VISIBLE);
            playbackState = LeanbackPlaybackState.PLAYING;
            if (position > 0) {
                videoView.seekTo(position);
                videoView.start();
            }
            playbackFragment.startProgressObservation(progressFlowable());
        } else {
            playbackState = LeanbackPlaybackState.PAUSED;
            videoView.pause();
            playbackFragment.stopProgressObservation();
        }

        updatePlaybackState(position);
        updateMetadata(video);
    }

1 个答案:

答案 0 :(得分:1)

不幸的是,由于@pskink指向了正确的方向,我还没有找到使用VideoView实现此目的的方法,仅使用ExoPlayer。该API返回了mp4视频,因此我使用了ExtractorMediaSource。可以在ExoPlayer GitHub page上找到支持多种格式的完整演示示例。

以下是我最终使用ExoPlayer

的最终代码
private void playPause(final Video video, final int position, final Boolean play) {
        if (position == 0 || playbackState == LeanbackPlaybackState.IDLE) {
            setupCallbacks();
            playbackState = LeanbackPlaybackState.IDLE;
        }

        if (play && playbackState != LeanbackPlaybackState.PLAYING) {
            progressBar.setVisibility(View.VISIBLE);
            playbackState = LeanbackPlaybackState.PLAYING;
            player.start();
            playbackFragment.startProgressObservation(progressFlowable());
        } else {
            playbackState = LeanbackPlaybackState.PAUSED;
            player.pause();
            playbackFragment.stopProgressObservation();
        }

        updatePlaybackState(position);
        updateMetadata(video);
    }

Player实施:

public class Player implements MediaController.MediaPlayerControl, ExoPlayer.EventListener {

    private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();

    private final SimpleExoPlayer exoPlayer;
    private final Context context;

    private OnErrorListener onErrorListener;
    private OnPreparedListener onPreparedListener;
    private OnCompletionListener onCompletionListener;

    private String url;

    public interface OnErrorListener {
        void onError(final Exception e);
    }

    public interface OnPreparedListener {
        void onPrepared();
    }

    public interface OnCompletionListener {
        void onComplete();
    }

    public Player(final Context context) {
        this.context = context;

        final @SimpleExoPlayer.ExtensionRendererMode int extensionRendererMode =
                SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF;
        final TrackSelection.Factory videoTrackSelectionFactory =
                new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
        this.exoPlayer = ExoPlayerFactory.newSimpleInstance(
                context,
                new DefaultTrackSelector(videoTrackSelectionFactory),
                new DefaultLoadControl(),
                null,
                extensionRendererMode
        );
        this.exoPlayer.addListener(this);
    }

    @Override
    public boolean canPause() {
        return true;
    }

    @Override
    public boolean canSeekBackward() {
        return true;
    }

    @Override
    public boolean canSeekForward() {
        return true;
    }

    @Override
    public int getAudioSessionId() {
        throw new UnsupportedOperationException();
    }

    @Override
    public int getBufferPercentage() {
        return exoPlayer.getBufferedPercentage();
    }

    @Override
    public int getCurrentPosition() {
        return exoPlayer.getDuration() == com.google.android.exoplayer2.C.TIME_UNSET ? 0
                : (int) exoPlayer.getCurrentPosition();
    }

    @Override
    public int getDuration() {
        return exoPlayer.getDuration() == com.google.android.exoplayer2.C.TIME_UNSET ? 0
                : (int) exoPlayer.getDuration();
    }

    @Override
    public boolean isPlaying() {
        return exoPlayer.getPlayWhenReady();
    }

    @Override
    public void start() {
        exoPlayer.setPlayWhenReady(true);
    }

    @Override
    public void pause() {
        exoPlayer.setPlayWhenReady(false);
    }

    public void stop() {
        exoPlayer.seekTo(0);
        pause();
    }

    public void setOnErrorListener(final OnErrorListener onErrorListener) {
        this.onErrorListener = onErrorListener;
    }

    public void setOnPreparedListener(final OnPreparedListener onPreparedListener) {
        this.onPreparedListener = onPreparedListener;
    }

    public void setOnCompletionListener(final OnCompletionListener onCompletionListener) {
        this.onCompletionListener = onCompletionListener;
    }

    public void setVolume(final float volume) {
        exoPlayer.setVolume(volume);
    }

    public void release() {
        exoPlayer.release();
    }

    public void updateUrl(final String url) {
        this.url = url;
        exoPlayer.prepare(buildMediaSource(Uri.parse(url)));
    }

    public SimpleExoPlayer exoPlayer() {
        return exoPlayer;
    }

    @Override
    public void seekTo(final int timeMillis) {
        exoPlayer.seekTo(timeMillis);
    }

    @Override
    public void onTimelineChanged(final Timeline timeline, final Object manifest) {
    }

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

    @Override
    public void onLoadingChanged(final boolean isLoading) {
    }

    @Override
    public void onPlayerStateChanged(final boolean playWhenReady, final int playbackState) {
        if (playbackState == ExoPlayer.STATE_READY) {
            onPreparedListener.onPrepared();
        }
        if (playbackState == ExoPlayer.STATE_ENDED) {
            onCompletionListener.onComplete();
        }
    }

    @Override
    public void onPlayerError(final ExoPlaybackException error) {
        onErrorListener.onError(error);
    }

    @Override
    public void onPositionDiscontinuity() {
    }

    public String url() {
        return url;
    }

    private MediaSource buildMediaSource(final Uri uri) {
        return new ExtractorMediaSource(uri, buildDataSourceFactory(true), new DefaultExtractorsFactory(),
                null, null);
    }

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

    private HttpDataSource.Factory buildHttpDataSourceFactory(final DefaultBandwidthMeter bandwidthMeter) {
        return new DefaultHttpDataSourceFactory(Util.getUserAgent(context, Application.TAG), bandwidthMeter);
    }

    private DataSource.Factory buildDataSourceFactory(final boolean useBandwidthMeter) {
        return buildDataSourceFactory(useBandwidthMeter ? BANDWIDTH_METER : null);
    }
}