【发布时间】:2016-04-19 08:32:08
【问题描述】:
我想在我的 Android 应用中实现视频播放器 (ExoPlayer)。播放器必须从某个网址播放视频(不大,约 2-3 分钟)。在 nexus 5 上它运行良好,但在手机“Samsung GT-I8552 Galaxy Win”上很遗憾它不起作用。编译启动app后有异常日志:
内部运行时错误。
java.lang.IllegalStateException
在 android.media.MediaCodec.dequeueOutputBuffer(Native Method)
这是我的代码:
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);
我的班级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;
}
}
还有我的班级 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);
}
}
【问题讨论】: