ExoPlayer 在某些设备上不工作

ExoPlayer doesn work on some devices

我想在我的 android 应用中实现视频播放器 (ExoPlayer)。播放器必须播放一些 url 的视频(不大,大约 2-3 分钟)。在 nexus 5 上它运行良好,但不幸的是在 phone "Samsung GT-I8552 Galaxy Win" 上它不起作用。编译启动app后有异常日志:

内部运行时错误。
java.lang.IllegalStateException

在 android.media.MediaCodec.dequeueOutputBuffer(本机方法)

这是我的代码:

      private SurfaceView surfaceView;
      private ExoPlayer player;
      private MediaCodecVideoTrackRenderer videoRenderer;
      private MediaCodecAudioTrackRenderer audioRenderer;
      private CustomMediaController mediaController;
      private String userAgent;
      private final int RENDERER_COUNT = 8;
      private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
      private static final int BUFFER_SEGMENT_COUNT =  256;  
      private static final int minBufferMs = 10000;
      private static final int minRebufferMs = 5000;
      private final String videoUrl_2 = "someurl...";

...

    surfaceView = (SurfaceView) findViewById(R.id.surface_view);
    player = ExoPlayer.Factory.newInstance(RENDERER_COUNT, minBufferMs, minRebufferMs);
    userAgent = Util.getUserAgent(this, "MyPlayer");
    Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
    DataSource dataSource = new DefaultUriDataSource(context, null, userAgent);

    ExtractorSampleSource sampleSource = new ExtractorSampleSource(Uri.parse(videoUrl_2), dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE);
    videoRenderer = new MediaCodecVideoTrackRenderer(context,
            sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
    audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource, MediaCodecSelector.DEFAULT);
    player.prepare(videoRenderer, audioRenderer);
    player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surfaceView.getHolder().getSurface());

    player.setPlayWhenReady(true);

    CustomMediaPlayerControl customMediaPlayerControl = new CustomMediaPlayerControl(player);
    mediaController = new CustomMediaController(context);
    mediaController.setMediaPlayer(customMediaPlayerControl);
    mediaController.setAnchorView(surfaceView);
    mediaController.setEnabled(true);

我的 class CustomMediaPlayerControl:

public class CustomMediaPlayerControl implements MediaController.MediaPlayerControl {
private ExoPlayer player;

public CustomMediaPlayerControl(ExoPlayer player) {
    this.player = player;
}

@Override
public void start() {
    player.setPlayWhenReady(true);
}

@Override
public void pause() {
    player.setPlayWhenReady(false);
}

@Override
public int getDuration() {
    return (int) player.getDuration();
}

@Override
public int getCurrentPosition() {
    return (int) player.getCurrentPosition();
}

@Override
public void seekTo(int pos) {
    player.seekTo(pos);
}

@Override
public boolean isPlaying() {
    return player.getPlayWhenReady();
}

@Override
public int getBufferPercentage() {
    return (int) player.getBufferedPercentage();
}

@Override
public boolean canPause() {
    return true;
}

@Override
public boolean canSeekBackward() {
    return true;
}

@Override
public boolean canSeekForward() {
    return true;
}

@Override
public int getAudioSessionId() {
    return 0;
}
}

还有我的 class CustomMediaController:

public class CustomMediaController extends MediaController {

private MediaController.MediaPlayerControl playerControl;

public CustomMediaController(Context context) {
    super(context);
}

@Override
public void setMediaPlayer(MediaController.MediaPlayerControl playerControl) {
    super.setMediaPlayer(playerControl);
    this.playerControl = playerControl;
}

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    int keyCode = event.getKeyCode();
    if (playerControl.canSeekForward() && keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            playerControl.seekTo(playerControl.getCurrentPosition() + 15000); // milliseconds
            show();
        }
        return true;
    } else if (playerControl.canSeekBackward() && keyCode == KeyEvent.KEYCODE_MEDIA_REWIND) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            playerControl.seekTo(playerControl.getCurrentPosition() - 5000); // milliseconds
            show();
        }
        return true;
    }
    return super.dispatchKeyEvent(event);
}
}

ExoPlayer 的最低 SDK 级别 16 要求。

ExoPlayer’s standard audio and video components rely on Android’s MediaCodec API, which was released in Android 4.1 (API level 16). Hence they do not work on earlier versions of Android.
From: https://google.github.io/ExoPlayer/guide.html