0

我为从 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.

希望比我有更多经验的人可以帮助我。

提前致谢!

4

1 回答 1

0

在状态 0(-38)中调用 Start 意味着您在正确设置媒体和准备之前调用 start。100 错误是媒体服务器死亡消息。您提供了无效的媒体并调用了 start 。您应该在准备和启动之前添加一些 if 语句作为保障,并在 MediaPlayer 的 onInfo 和 onError 回调中处理错误输出。

编辑:在 onError 处理程序中,区分致命错误和非致命错误。对非致命错误返回 true 以指示错误已得到处理。返回 false 告诉MediaPlayer调用 onCompletion 处理程序并停止。我经常看到“媒体服务器死机”错误,这并不一定意味着媒体无效(如您所述)。抱歉,我之前没有注意到这一点。

于 2013-09-25T00:49:41.530 回答