我正在使用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);
}
答案 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);
}
}