Exoplayer 2质量演绎,如320p,480p,720p和1080p

时间:2018-02-19 05:25:38

标签: android android-studio playback exoplayer2.x

我希望像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();
    }
}

}

1 个答案:

答案 0 :(得分:1)

您想要查看的核心点是轨道选择(通过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以使其发挥作用。

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

谢谢,我希望它有所帮助。