【问题标题】:Android VideoView bufferingAndroid VideoView 缓冲
【发布时间】:2017-08-26 16:16:55
【问题描述】:

我正在开发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);
    }

【问题讨论】:

  • @pskink 不,我没有。如果我使用它,有很多代码需要更改,所以我想通过VideoView 来实现这一点。目前,这是唯一的问题,其他一切正常。
  • 如果无法使用VideoView 平滑流,那将是一个坏消息。
  • 请参阅“优缺点”部分:“支持基于 HTTP 的动态自适应流式传输 (DASH) 和 SmoothStreaming,MediaPlayer 都不支持这两种格式。还支持许多其他格式。请参阅支持的格式详情页。”,MediaPlayer 真的是穷人的播放器...只要看看一个示例应用程序,你就会发现它是多么容易完成
  • 在这里找到了一个不错的库,可以轻松迁移到ExoPlayergithub.com/brianwernick/ExoMedia

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


【解决方案1】:

不幸的是,我没有找到使用VideoView 实现此目的的方法,仅使用ExoPlayer,感谢@pskink 的正确方向。 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);
    }
}

【讨论】:

    猜你喜欢
    • 2011-06-29
    • 1970-01-01
    • 2017-10-23
    • 1970-01-01
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多