【问题标题】:Quality selector for ExoPlayer 2ExoPlayer 2 的质量选择器
【发布时间】:2018-01-31 19:09:34
【问题描述】:

我目前正在开发一个直播和电影播放器​​应用程序。我选择了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() {

}

请帮助解决这个问题。 非常感谢。

【问题讨论】:

    标签: android exoplayer exoplayer2.x


    【解决方案1】:

    您想要实现的一切都可以在 ExoPlayer2 demo app 中查看。更具体地说是PlayerActivity 类。

    您也可以查看此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);
    

    正如我上面提到的,这有点过于简单化了这个过程,但核心部分是你在搞乱TrackSelectorSelectionOverrideTrack/TrackGroups来得到这个工作。

    您可以想象逐字复制演示代码,它应该可以工作,但我强烈建议您花时间了解每个部分在做什么,并根据您的用例定制您的解决方案。

    如果我有更多时间,我会编译并运行它。但是,如果您可以获取我的示例,请随时编辑我的帖子。

    希望有帮助:)

    【讨论】:

    • @KyleVenn 你能告诉我更多关于这一点,比如如果轨道包含 240p 质量,它将通过添加上述代码自动显示?
    • @WaleedAsim 有一个 for 循环遍历轨道索引。 240p 将是可用的质量之一。所以在group.getFormat(trackIndex) 行中,240p 将由组中的一种格式表示。上面的代码只是关于如何遍历格式,然后通过“覆盖”强制格式。
    • @KyleVenn 你能告诉我如何在安卓存储中下载 hls 格式的视频
    • @WaleedAsim 这篇文章介绍了如何通过CacheDataSourcemedium.com/google-exoplayer/downloading-streams-6d259eec7f95实现这一目标
    • @Kyle Venn 如果可能,请您提供完整代码
    【解决方案2】:

    我避免使用上面发布的方式。我的方式是使用 DefaultTrackSelector 如下:

    trackSelector.setParameters(trackSelector.getParameters()
                              .withMaxVideoBitrate(bitrate)
                              .withMaxVideoSize(width, height));
    

    我已经使用 HLS 视频进行了测试,它似乎以正确的方式执行。我从 HlsManifest 中读取比特率、宽度和高度。

    【讨论】:

      【解决方案3】:

      您可以从此链接复制示例代码。 ExoPlayer Video Quality Control.

      注意:不要忘记在 build.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'
      

      【讨论】:

        猜你喜欢
        • 2018-07-22
        • 1970-01-01
        • 1970-01-01
        • 2021-11-14
        • 1970-01-01
        • 2020-05-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多