ExoPlayer 2 的质量选择器
Quality selector for ExoPlayer 2
我目前正在开发一个直播和电影播放器应用程序。我选择了 ExoPlayer version 2 播放电影,我对它了解不多。我想让用户在播放器屏幕上选择电影的质量,例如,720p 或 1080p 等。
但我不知道如何获得现有品质的列表并将它们展示给用户。
下面的代码是我对 SimpleExoPlayer 的实现:
private void initPlayer(String path){
Handler handler = new Handler();
// 1. Create a default TrackSelector
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
new DefaultTrackSelector(videoTrackSelectionFactory);
// 2. Create a default LoadControl
LoadControl loadControl = new DefaultLoadControl();
// 3. Create the player
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
SimpleExoPlayerView playerView = (SimpleExoPlayerView) findViewById(R.id.player_view);
playerView.setPlayer(player);
playerView.setKeepScreenOn(true);
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "ExoPlayer"));
// This is the MediaSource representing the media to be played.
MediaSource videoSource = new HlsMediaSource(Uri.parse(path),
dataSourceFactory,handler, null);
// Prepare the player with the source.
player.addListener(this);
player.prepare(videoSource);
playerView.requestFocus();
player.setPlayWhenReady(true); // to play video when ready. Use false to pause a video
}
// ExoPlayer Listener Methods :
@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
@Override
public void onLoadingChanged(boolean isLoading) {
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) {
case ExoPlayer.STATE_BUFFERING:
//You can use progress dialog to show user that video is preparing or buffering so please wait
progressBar.setVisibility(View.VISIBLE);
break;
case ExoPlayer.STATE_IDLE:
//idle state
break;
case ExoPlayer.STATE_READY:
// dismiss your dialog here because our video is ready to play now
progressBar.setVisibility(GONE);
//Toast.makeText(getApplicationContext(),String.valueOf(player.getCurrentTrackSelections().get(0).getSelectedFormat().bitrate),Toast.LENGTH_SHORT).show();
break;
case ExoPlayer.STATE_ENDED:
// do your processing after ending of video
break;
}
}
@Override
public void onPlayerError(ExoPlaybackException error) {
// show user that something went wrong. it can be a dialog
}
@Override
public void onPositionDiscontinuity() {
}
请帮忙解决这个问题。
非常感谢。
您想要实现的一切都可以在 ExoPlayer2 中查看 demo app. More specifically the PlayerActivity
class.
您还可以查看有关该主题的 good article。
您要研究的核心点是曲目选择(通过 TrackSelector
)和 TrackSelectionHelper
。我将在下面包含重要的代码示例,希望它们足以让您继续学习。但最终只要按照演示应用程序中的类似内容进行操作,您就可以到达目的地。
您将保留用于初始化播放器的曲目选择器并将其用于几乎所有事情。
下面只是一段代码,可以理想地涵盖您要执行的操作的要点,因为该演示确实使事情过于复杂了。我也没有 运行 代码,但它已经足够接近了。
// These two could be fields OR passed around
int videoRendererIndex;
TrackGroupArray trackGroups;
// This is the body of the logic for see if there are even video tracks
// It also does some field setting
MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
for (int i = 0; i < mappedTrackInfo.length; i++) {
TrackGroupArray trackGroups = mappedTrackInfo.getTrackGroups(i);
if (trackGroups.length != 0) {
switch (player.getRendererType(i)) {
case C.TRACK_TYPE_VIDEO:
videoRendererIndex = i;
return true;
}
}
}
// This next part is actually about getting the list. It doesn't include
// some additional logic they put in for adaptive tracks (DASH/HLS/SS),
// but you can look at the sample for that (TrackSelectionHelper#buildView())
// Below you'd be building up items in a list. This just does
// views directly, but you could just have a list of track names (with indexes)
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
TrackGroup group = trackGroups.get(groupIndex);
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
if (trackIndex == 0) {
// Beginning of a new set, the demo app adds a divider
}
CheckedTextView trackView = ...; // The TextView to show in the list
// The below points to a util which extracts the quality from the TrackGroup
trackView.setText(DemoUtil.buildTrackName(group.getFormat(trackIndex)));
}
// Assuming you tagged the view with the groupIndex and trackIndex, you
// can build your override with that info.
Pair<Integer, Integer> tag = (Pair<Integer, Integer>) view.getTag();
int groupIndex = tag.first;
int trackIndex = tag.second;
// This is the override you'd use for something that isn't adaptive.
override = new SelectionOverride(FIXED_FACTORY, groupIndex, trackIndex);
// Otherwise they call their helper for adaptives, which roughly does:
int[] tracks = getTracksAdding(override, trackIndex);
TrackSelection.Factory factory = tracks.length == 1 ? FIXED_FACTORY : adaptiveTrackSelectionFactory;
override = new SelectionOverride(factory, groupIndex, tracks);
// Then we actually set our override on the selector to switch the quality/track
selector.setSelectionOverride(rendererIndex, trackGroups, override);
正如我上面提到的,这是对过程的稍微过度简化,但核心部分是你在搞乱 TrackSelector
、SelectionOverride
和 Track
/TrackGroups
让它工作。
可以想象,您可以逐字复制演示代码,它应该可以工作,但我强烈建议您花时间了解每一部分的作用,并根据您的用例定制解决方案。
如果我有更多时间,我会编译它并运行。但是,如果你能让我的样本继续运行,那么请随意编辑我的 post.
希望对您有所帮助:)
我避免了上面贴的方式。我的方法是按如下方式使用 DefaultTrackSelector:
trackSelector.setParameters(trackSelector.getParameters()
.withMaxVideoBitrate(bitrate)
.withMaxVideoSize(width, height));
我已经用 HLS 视频进行了测试,它似乎以正确的方式执行。我从 HlsManifest 中读取比特率、宽度和高度。
您可以从这个 link 复制示例代码。
ExoPlayer Video Quality Control.
注意:不要忘记在 built.gradle 文件中添加 exoplayer 依赖项
implementation 'com.google.android.exoplayer:exoplayer-core:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer:2.16.1'
我目前正在开发一个直播和电影播放器应用程序。我选择了 ExoPlayer version 2 播放电影,我对它了解不多。我想让用户在播放器屏幕上选择电影的质量,例如,720p 或 1080p 等。 但我不知道如何获得现有品质的列表并将它们展示给用户。 下面的代码是我对 SimpleExoPlayer 的实现:
private void initPlayer(String path){
Handler handler = new Handler();
// 1. Create a default TrackSelector
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
new DefaultTrackSelector(videoTrackSelectionFactory);
// 2. Create a default LoadControl
LoadControl loadControl = new DefaultLoadControl();
// 3. Create the player
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
SimpleExoPlayerView playerView = (SimpleExoPlayerView) findViewById(R.id.player_view);
playerView.setPlayer(player);
playerView.setKeepScreenOn(true);
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "ExoPlayer"));
// This is the MediaSource representing the media to be played.
MediaSource videoSource = new HlsMediaSource(Uri.parse(path),
dataSourceFactory,handler, null);
// Prepare the player with the source.
player.addListener(this);
player.prepare(videoSource);
playerView.requestFocus();
player.setPlayWhenReady(true); // to play video when ready. Use false to pause a video
}
// ExoPlayer Listener Methods :
@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
@Override
public void onLoadingChanged(boolean isLoading) {
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) {
case ExoPlayer.STATE_BUFFERING:
//You can use progress dialog to show user that video is preparing or buffering so please wait
progressBar.setVisibility(View.VISIBLE);
break;
case ExoPlayer.STATE_IDLE:
//idle state
break;
case ExoPlayer.STATE_READY:
// dismiss your dialog here because our video is ready to play now
progressBar.setVisibility(GONE);
//Toast.makeText(getApplicationContext(),String.valueOf(player.getCurrentTrackSelections().get(0).getSelectedFormat().bitrate),Toast.LENGTH_SHORT).show();
break;
case ExoPlayer.STATE_ENDED:
// do your processing after ending of video
break;
}
}
@Override
public void onPlayerError(ExoPlaybackException error) {
// show user that something went wrong. it can be a dialog
}
@Override
public void onPositionDiscontinuity() {
}
请帮忙解决这个问题。 非常感谢。
您想要实现的一切都可以在 ExoPlayer2 中查看 demo app. More specifically the PlayerActivity
class.
您还可以查看有关该主题的 good article。
您要研究的核心点是曲目选择(通过 TrackSelector
)和 TrackSelectionHelper
。我将在下面包含重要的代码示例,希望它们足以让您继续学习。但最终只要按照演示应用程序中的类似内容进行操作,您就可以到达目的地。
您将保留用于初始化播放器的曲目选择器并将其用于几乎所有事情。
下面只是一段代码,可以理想地涵盖您要执行的操作的要点,因为该演示确实使事情过于复杂了。我也没有 运行 代码,但它已经足够接近了。
// These two could be fields OR passed around
int videoRendererIndex;
TrackGroupArray trackGroups;
// This is the body of the logic for see if there are even video tracks
// It also does some field setting
MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
for (int i = 0; i < mappedTrackInfo.length; i++) {
TrackGroupArray trackGroups = mappedTrackInfo.getTrackGroups(i);
if (trackGroups.length != 0) {
switch (player.getRendererType(i)) {
case C.TRACK_TYPE_VIDEO:
videoRendererIndex = i;
return true;
}
}
}
// This next part is actually about getting the list. It doesn't include
// some additional logic they put in for adaptive tracks (DASH/HLS/SS),
// but you can look at the sample for that (TrackSelectionHelper#buildView())
// Below you'd be building up items in a list. This just does
// views directly, but you could just have a list of track names (with indexes)
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
TrackGroup group = trackGroups.get(groupIndex);
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
if (trackIndex == 0) {
// Beginning of a new set, the demo app adds a divider
}
CheckedTextView trackView = ...; // The TextView to show in the list
// The below points to a util which extracts the quality from the TrackGroup
trackView.setText(DemoUtil.buildTrackName(group.getFormat(trackIndex)));
}
// Assuming you tagged the view with the groupIndex and trackIndex, you
// can build your override with that info.
Pair<Integer, Integer> tag = (Pair<Integer, Integer>) view.getTag();
int groupIndex = tag.first;
int trackIndex = tag.second;
// This is the override you'd use for something that isn't adaptive.
override = new SelectionOverride(FIXED_FACTORY, groupIndex, trackIndex);
// Otherwise they call their helper for adaptives, which roughly does:
int[] tracks = getTracksAdding(override, trackIndex);
TrackSelection.Factory factory = tracks.length == 1 ? FIXED_FACTORY : adaptiveTrackSelectionFactory;
override = new SelectionOverride(factory, groupIndex, tracks);
// Then we actually set our override on the selector to switch the quality/track
selector.setSelectionOverride(rendererIndex, trackGroups, override);
正如我上面提到的,这是对过程的稍微过度简化,但核心部分是你在搞乱 TrackSelector
、SelectionOverride
和 Track
/TrackGroups
让它工作。
可以想象,您可以逐字复制演示代码,它应该可以工作,但我强烈建议您花时间了解每一部分的作用,并根据您的用例定制解决方案。
如果我有更多时间,我会编译它并运行。但是,如果你能让我的样本继续运行,那么请随意编辑我的 post.
希望对您有所帮助:)
我避免了上面贴的方式。我的方法是按如下方式使用 DefaultTrackSelector:
trackSelector.setParameters(trackSelector.getParameters()
.withMaxVideoBitrate(bitrate)
.withMaxVideoSize(width, height));
我已经用 HLS 视频进行了测试,它似乎以正确的方式执行。我从 HlsManifest 中读取比特率、宽度和高度。
您可以从这个 link 复制示例代码。 ExoPlayer Video Quality Control.
注意:不要忘记在 built.gradle 文件中添加 exoplayer 依赖项
implementation 'com.google.android.exoplayer:exoplayer-core:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer:2.16.1'