我为从 URL 播放视频的 Android 服务编写了以下代码。我使用服务的原因是因为我希望媒体播放器在从具有表面视图的活动切换到没有(例如)的活动时保持音频播放。
虽然代码适用于 Android 4.0+ 设备,但我无法解决:
- 错误(100, 0)
- 错误(-38, 0)
在 Android 2.3 上运行时(目前在三星 Galaxy S1 上测试)。
下面是我的服务的代码:
/**
* The MediaPlayer instance
*/
private MediaPlayer mediaPlayer;
/**
* Boolean value indicating if the service is running or not.
*/
private static boolean videoServiceRunning = false;
/**
* Boolean value indicating if the video is playing or not.
*/
private static boolean videoPlaying = false;
/**
* Boolean value indicating if the video has not been started yet or if it has ended playing.
*/
private static boolean videoPrepared = false;
@Override
public void onCreate() {
super.onCreate();
Log.i(LOGTAG, "Service Started.");
mediaPlayer = new MediaPlayer();
videoServiceRunning = true;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("MyService", "Service Stopped.");
videoServiceRunning = false;
try {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
setVideoPlaying(false);
}
mediaPlayer.release();
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(LOGTAG, "Received start id " + startId + ": " + intent);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnErrorListener(this);
return START_STICKY; // Run until explicitly stopped.
}
@Override
public IBinder onBind(Intent intent) {
Log.i(LOGTAG, "onBind");
return inMessenger.getBinder();
}
public static boolean isVideoServiceRunning()
{
return videoServiceRunning;
}
private void prepareVideo() {
try {
mediaPlayer.setDataSource(getApplicationContext(), Uri.parse(videoURL));
mediaPlayer.setScreenOnWhilePlaying(true);
mediaPlayer.prepare();
setVideoPrepared(true);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
String message = isNetworkAvailable() ?
getApplicationContext().getString(R.string.movie_unavailable) :
getApplicationContext().getString(R.string.network_error);
sendErrorMessageToActivity(message);
}
}
private void play() {
try {
mediaPlayer.start();
setVideoPlaying(true);
sendMessageToActivity(MEDIAPLAYER_PLAYING);
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
private void pause() {
try {
mediaPlayer.pause();
setVideoPlaying(false);
sendMessageToActivity(MEDIAPLAYER_PAUSED);
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
private void coupleSurface() {
try {
SurfaceHolder surfaceHolder = SurfaceViewHolder.getInstance().getSurfaceHolder();
mediaPlayer.setDisplay(surfaceHolder);
sendMessageToActivity(MEDIAPLAYER_SURFACE_COUPLED);
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
private void uncoupleSurface() {
try {
mediaPlayer.setDisplay(null);
sendMessageToActivity(MEDIAPLAYER_SURFACE_UNCOUPLED);
}
catch (IllegalStateException e) {
e.printStackTrace();
sendMessageToActivity(MEDIAPLAYER_ERROR);
}
}
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
setVideoPlaying(false);
sendMessageToActivity(MEDIAPLAYER_ENDED);
}
@Override
public void onPrepared(MediaPlayer mp) {
sendMessageToActivity(ACTIVITY_VIDEO_PREPARED);
VideoService.videoDuration = mediaPlayer.getDuration();
VideoService.videoWidth = mediaPlayer.getVideoWidth();
VideoService.videoHeight = mediaPlayer.getVideoHeight();
Runnable updateProgressRunnable = new Runnable() {
@Override
public void run() {
if (videoServiceRunning) {
currentPosition = -1;
try {
currentPosition = mediaPlayer.getCurrentPosition();
}
catch (IllegalStateException e) {
Log.e(LOGTAG, "An exception has occurred while trying to retrieve the current position: "+ e);
}
if (currentPosition != -1) {
SurfaceViewHolder.getInstance().updateSeekBarProgress(currentPosition);
}
//TODO should the handler continue scheduling the runnable for execution in case of an exception?
handler.postDelayed(this, 1000);
}
}
};
handler.postDelayed(updateProgressRunnable, 1000);
SurfaceHolder surfaceHolder = SurfaceViewHolder.getInstance().getSurfaceHolder();
mediaPlayer.setDisplay(surfaceHolder);
if (playVideo) {
play();
}
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(LOGTAG, "What: "+what+", Extra: "+extra);
return false;
}
public static synchronized boolean isVideoPlaying() {
return VideoService.videoPlaying;
}
public static synchronized void setVideoPlaying(boolean videoPlaying) {
VideoService.videoPlaying = videoPlaying;
}
public static synchronized boolean isVideoPrepared() {
return videoPrepared;
}
public static synchronized void setVideoPrepared(boolean videoPrepared) {
VideoService.videoPrepared = videoPrepared;
}
此外,logcat 输出:
09-24 15:10:57.671: D/VideoService(5561): handleMessage: 4
09-24 15:10:57.765: D/VideoService(5561): handleMessage: 0
09-24 15:10:57.765: I/MediaPlayer(5561): uri is:http://techslides.com/demos/sample-videos/small.mp4
09-24 15:10:57.765: I/MediaPlayer(5561): path is null
09-24 15:10:57.769: D/MediaPlayer(5561): Couldn't open file on client side, trying server side
09-24 15:11:00.679: D/VideoService(5561): handleMessage: 1
09-24 15:11:08.718: I/dalvikvm(5561): threadid=4: reacting to signal 3
09-24 15:11:08.730: I/dalvikvm(5561): Wrote stack traces to '/data/anr/traces.txt'
09-24 15:11:12.214: D/VideoService(5561): handleMessage: 7
09-24 15:11:15.722: W/IMediaDeathNotifier(5561): media server died
09-24 15:11:15.726: E/MediaPlayer(5561): error (100, 0)
09-24 15:11:15.726: W/AudioSystem(5561): AudioFlinger server died!
09-24 15:11:15.753: E/MediaPlayer(5561): Error (100,0)
09-24 15:11:15.753: E/VideoService(5561): What: 100, Extra: 0
09-24 15:11:15.812: D/VideoService(5561): handleMessage: 1
09-24 15:11:15.812: E/MediaPlayer(5561): start called in state 0
09-24 15:11:15.812: E/MediaPlayer(5561): error (-38, 0)
09-24 15:11:15.921: E/MediaPlayer(5561): Error (-38,0)
09-24 15:11:15.921: E/VideoService(5561): What: -38, Extra: 0
09-24 15:11:16.996: D/VideoService(5561): handleMessage: 1
09-24 15:11:16.996: E/MediaPlayer(5561): start called in state 0
09-24 15:11:17.000: E/MediaPlayer(5561): error (-38, 0)
09-24 15:11:17.003: E/MediaPlayer(5561): Error (-38,0)
09-24 15:11:17.007: E/VideoService(5561): What: -38, Extra: 0
请记住,
- 这只是一个测试项目,因此我可以在将其实施到我正在开发的应用程序之前了解这些步骤
- 我省略了 VideoService 类中有关与 Activity 进行通信的部分内容(因为崩溃与媒体播放器相关)。
- SurfaceViewHolder 是一个单例,用于保留各种 UI 元素(例如对进度条的引用或当前可用的 SurfaceView,如果有),对于在活动之间切换(具有不同的 UI)和保持视频播放(或将音频保持在后台)很有用)
乐:
在 onErrorListener 中为错误 100 和 -38 返回 true 后,每当我尝试播放视频时,我都会得到以下 logcat 输出。媒体服务器死亡错误仍然存在。
09-25 11:07:12.226: E/AndroidRuntime(7921): Set to default setting_6 : region=-Duser.region=US propRegn=US
09-25 11:07:15.378: E/AndroidRuntime(7930): Set to default setting_6 : region=-Duser.region=US propRegn=US
09-25 11:07:19.097: E/AndroidRuntime(7946): Set to default setting_6 : region=-Duser.region=US propRegn=US
09-25 11:07:30.027: E/MediaPlayerService(7886): MediaPlayerService::mIsAnyDrmVideoPlaying : 0
09-25 11:07:30.449: E/SecHardwareRenderer(7886): Unable to create the overlay!
09-25 11:07:30.449: A/SoftwareRenderer(7886): frameworks/base/media/libstagefright/colorconversion/SoftwareRenderer.cpp:59 mConverter.isValid()
09-25 11:07:35.167: E/dalvikvm(1566): Failed to write stack traces to /data/anr/traces.txt (1627 of 2166): No such file or directory
09-25 11:07:35.941: E/dalvikvm(1642): Failed to write stack traces to /data/anr/traces.txt (816 of 2839): No such file or directory
09-25 11:07:37.449: E/dalvikvm(7751): Failed to write stack traces to /data/anr/traces.txt (1162 of 2250): No such file or directory
09-25 11:07:37.449: E/dalvikvm(7787): Failed to write stack traces to /data/anr/traces.txt (-1 of 2249): Math result not representable
09-25 11:07:37.468: E/dalvikvm(7763): Failed to write stack traces to /data/anr/traces.txt (-1 of 2250): Math result not representable
09-25 11:07:37.476: E/dalvikvm(7803): Failed to write stack traces to /data/anr/traces.txt (-1 of 3216): Math result not representable
09-25 11:07:37.796: E/dalvikvm(7954): Failed to write stack traces to /data/anr/traces.txt (-1 of 2376): Math result not representable
09-25 11:07:37.800: E/dalvikvm(7744): Failed to write stack traces to /data/anr/traces.txt (-1 of 2241): Math result not representable
09-25 11:07:37.804: E/dalvikvm(7907): Failed to write stack traces to /data/anr/traces.txt (-1 of 2230): Math result not representable
09-25 11:07:37.929: E/dalvikvm(7829): Failed to write stack traces to /data/anr/traces.txt (10370 of 13387): No such file or directory
09-25 11:07:44.617: E/MediaPlayer(7954): error (100, 0)
09-25 11:07:44.625: E/MediaPlayer(7954): Error (100,0)
09-25 11:07:44.632: E/VideoService(7954): What: 100, Extra: 0
09-25 11:07:45.074: E/SoundBooster(7989): readSBTable: file open error!
09-25 11:07:45.074: E/AcousticEQ(7989): [AEQ] aeqcoe.txt: file open error!
09-25 11:07:46.117: E/AudioService(1462): Media server died.
09-25 11:07:46.125: E/AudioService(1462): Media server started.
希望比我有更多经验的人可以帮助我。
提前致谢!