我希望以 YouTube 支持使用 Exoplayer 2 的方式实现质量再现选项,如(320p、480p、720p 和 1080p)。真的很努力地寻找答案,但找不到任何东西。由于我是 Exoplayer 的新手,从今以后,如果我能得到一些帮助,那就太好了。

这是我的 MainActivity.java 代码

package com.geoffledak.exoplayerfullscreen;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private final String STATE_RESUME_WINDOW = "resumeWindow";
private final String STATE_RESUME_POSITION = "resumePosition";
private final String STATE_PLAYER_FULLSCREEN = "playerFullscreen";

private SimpleExoPlayerView mExoPlayerView;
private MediaSource mVideoSource;
private boolean mExoPlayerFullscreen = false;
private FrameLayout mFullScreenButton;
private ImageView mFullScreenIcon;
private ImageButton btn_settings;
private ExoPlayer player;

private Dialog mFullScreenDialog;

private int mResumeWindow;
private long mResumePosition;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    btn_settings = (ImageButton) findViewById(R.id.btn_settings);

    btn_settings.setOnClickListener(this);


    if (savedInstanceState != null) {
        mResumeWindow = savedInstanceState.getInt(STATE_RESUME_WINDOW);
        mResumePosition = savedInstanceState.getLong(STATE_RESUME_POSITION);
        mExoPlayerFullscreen = savedInstanceState.getBoolean(STATE_PLAYER_FULLSCREEN);
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {

    outState.putInt(STATE_RESUME_WINDOW, mResumeWindow);
    outState.putLong(STATE_RESUME_POSITION, mResumePosition);
    outState.putBoolean(STATE_PLAYER_FULLSCREEN, mExoPlayerFullscreen);

    super.onSaveInstanceState(outState);
}

private void initFullscreenDialog() {

    mFullScreenDialog = new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen) {
        public void onBackPressed() {
            if (mExoPlayerFullscreen)
                closeFullscreenDialog();
            super.onBackPressed();
        }
    };
}

 private void openFullscreenDialog() {

    ((ViewGroup) mExoPlayerView.getParent()).removeView(mExoPlayerView);
    mFullScreenDialog.addContentView(mExoPlayerView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    mFullScreenIcon.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fullscreen_shrink));
    mExoPlayerFullscreen = true;
    mFullScreenDialog.show();
   setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}


private void closeFullscreenDialog() {

    ((ViewGroup) mExoPlayerView.getParent()).removeView(mExoPlayerView);
    ((FrameLayout) findViewById(R.id.main_media_frame)).addView(mExoPlayerView);
    mExoPlayerFullscreen = false;
    mFullScreenDialog.dismiss();
    mFullScreenIcon.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fullscreen_expand));
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

private void initFullscreenButton() {
    PlaybackControlView controlView = mExoPlayerView.findViewById(R.id.exo_controller);
    mFullScreenIcon = controlView.findViewById(R.id.exo_fullscreen_icon);
    mFullScreenButton = controlView.findViewById(R.id.exo_fullscreen_button);
    mFullScreenButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (!mExoPlayerFullscreen)
                openFullscreenDialog();
            else
                closeFullscreenDialog();
        }
    });
}

private void initExoPlayer() {

    BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
    TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
    TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
    LoadControl loadControl = new DefaultLoadControl();
    SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(this), trackSelector, loadControl);
    mExoPlayerView.setPlayer(player);

    boolean haveResumePosition = mResumeWindow != C.INDEX_UNSET;

    if (haveResumePosition) {
        mExoPlayerView.getPlayer().seekTo(mResumeWindow, mResumePosition);
    }
    mExoPlayerView.getPlayer().prepare(mVideoSource);
    mExoPlayerView.getPlayer().setPlayWhenReady(true);
}


@Override
protected void onResume() {
    super.onResume();
    if (mExoPlayerView == null) {
        mExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.exoplayer);
        initFullscreenDialog();
        initFullscreenButton();
        String streamUrl = "http://playertest.longtailvideo.com/adaptive/bbbfull/bbbfull.m3u8";
        String userAgent = Util.getUserAgent(MainActivity.this, getApplicationContext().getApplicationInfo().packageName);
        DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory(userAgent, null, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, true);
        DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(MainActivity.this, null, httpDataSourceFactory);
        Uri daUri = Uri.parse(streamUrl);

        mVideoSource = new HlsMediaSource(daUri, dataSourceFactory, 1, null, null);
    }

    initExoPlayer();

    if (mExoPlayerFullscreen) {
        ((ViewGroup) mExoPlayerView.getParent()).removeView(mExoPlayerView);
        mFullScreenDialog.addContentView(mExoPlayerView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        mFullScreenIcon.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fullscreen_shrink));
        mFullScreenDialog.show();
    }
}


@Override
protected void onPause() {

    super.onPause();

    if (mExoPlayerView != null && mExoPlayerView.getPlayer() != null) {
        mResumeWindow = mExoPlayerView.getPlayer().getCurrentWindowIndex();
        mResumePosition = Math.max(0, mExoPlayerView.getPlayer().getContentPosition());

        mExoPlayerView.getPlayer().release();
    }

    if (mFullScreenDialog != null)
        mFullScreenDialog.dismiss();
}

@Override
public void onClick(View view) {
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "Landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "Portrait", Toast.LENGTH_SHORT).show();
    }
}

}

最佳答案

您需要研究的核心点是轨道选择(通过 TrackSelector)以及 TrackSelectionHelper。我将在下面包含重要的代码示例,希望这些示例足以让您继续前进。但最终只要按照演示应用程序中的类似内容进行操作,您就可以到达需要的位置。

您将保留用于初始化播放器的轨道选择器,并将其用于几乎所有内容。

下面只是一段代码,可以理想地涵盖您尝试做的事情的要点,因为该演示似乎确实使事情变得过于复杂。另外我还没有运行代码,但它已经足够接近了。

这里有更多的描述。

我检查了解决方案 here ,我相信它会帮助你。

    // 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 来使其工作。

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

谢谢,我希望它有帮助。

关于android - Exoplayer 2 质量再现,如 320p、480p、720p 和 1080p,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48859968/

10-12 05:46