Android VideoView 缓冲
Posted
技术标签:
【中文标题】Android VideoView 缓冲【英文标题】:Android VideoView buffering 【发布时间】: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);
【问题讨论】:
试过ExoPlayer?更多信息:google.github.io/ExoPlayer/guide.html#pros-and-cons @pskink 不,我没有。如果我使用它,有很多代码需要更改,所以我想通过VideoView
来实现这一点。目前,这是唯一的问题,其他一切正常。
如果无法使用VideoView
平滑流,那将是一个坏消息。
请参阅“优缺点”部分:“支持基于 HTTP 的动态自适应流式传输 (DASH) 和 SmoothStreaming,MediaPlayer 都不支持这两种格式。还支持许多其他格式。请参阅支持的格式详情页。”,MediaPlayer
真的是穷人的播放器...只要看看一个示例应用程序,你就会发现它是多么容易完成
在这里找到了一个不错的库,可以轻松迁移到ExoPlayer
:github.com/brianwernick/ExoMedia。
【参考方案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);
【讨论】:
以上是关于Android VideoView 缓冲的主要内容,如果未能解决你的问题,请参考以下文章
Android videoview can't play this video on android 4.3 错误
如何在 Android Studio 中将一个 VideoView 放在另一个 VideoView 下方?
Android VideoView未解决,动态读取权限BottomNavigationView的用法