2

私のアプリケーションでは、ライブ ストリーミング (音楽) を行い、それをバッファリングし、終了したら再生し、ビデオ (再生中の音楽と一緒にビデオ、カラオケのようなもの) をキャプチャする必要があります。問題は、アプリケーションを実行すると、Log cat に次のメッセージが表示されることです。アプリケーションが表面を失った理由は何ですか?

    05-05 15:43:48.929: D/MediaRecorder(4745): doCleanUp
05-05 15:43:49.519: E/MediaRecorderJNI(4745): Application lost the surface
05-05 15:43:49.542: D/***VideoRecording***(4745): IOException preparing MediaRecorder: invalid preview surface
05-05 15:43:49.542: D/***VideoRecording***(4745): java.io.IOException: invalid preview surface
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.media.MediaRecorder._prepare(Native Method)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.media.MediaRecorder.prepare(MediaRecorder.java:591)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at com.astro.mania.activities.VideoRecording.prepareVideoRecorder(VideoRecording.java:340)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at com.astro.mania.activities.VideoRecording.onCreate(VideoRecording.java:161)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1615)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1667)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.app.ActivityThread.access$1500(ActivityThread.java:117)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.os.Handler.dispatchMessage(Handler.java:99)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.os.Looper.loop(Looper.java:123)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at android.app.ActivityThread.main(ActivityThread.java:3687)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at java.lang.reflect.Method.invokeNative(Native Method)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at java.lang.reflect.Method.invoke(Method.java:507)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
05-05 15:43:49.542: D/***VideoRecording***(4745):   at dalvik.system.NativeStart.main(Native Method)
05-05 15:43:49.562: D/MediaRecorder(4745): reset:E
05-05 15:43:49.562: D/MediaRecorder(4745): doCleanUp
05-05 15:43:49.562: D/MediaRecorder(4745): doReset:E
05-05 15:43:49.578: D/MediaRecorder(4745): doReset:X
05-05 15:43:49.578: D/MediaRecorder(4745): close
05-05 15:43:49.582: D/MediaRecorder(4745): reset:X
05-05 15:43:49.582: D/MediaRecorder(4745): release:E

私の CamcorderView カルスは次のとおりです。

public class CamcorderView extends SurfaceView implements SurfaceHolder.Callback{

    private SurfaceHolder mHolder;
    private Camera mCamera;

    //Create constructor of Preview Class. In this, get an object of
    //surfaceHolder class by calling getHolder() method. After that add
    //callback to the surfaceHolder. The callback will inform when surface is
    //created/changed/destroyed. Also set surface not to have its own buffers.

    public CamcorderView(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
     }

    // Implement the methods of SurfaceHolder.Callback interface
    // SurfaceCreated : This method gets called when surface is created.
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.e("Error in CamcorderView", "Error setting camera preview: " + e.getMessage(), e);
        }
    }


    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or reformatting changes here
        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
        } catch (Exception e){
            Log.e("Error>>>>>", "Error starting camera preview: " + e.getMessage(), e);
        }
    }
}

およびビデオ録画クラス:

public class VideoRecording extends Activity implements OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener {

    private static final String TAG           = "***VideoRecording***";
    private static final int MEDIA_TYPE_VIDEO = 1;
    private static final String MEDIA_NAME    = "Mania-Karaoke";
    private static final String VIDEO_FORMAT  = ".mp4";
    private static final String AUDIO_SOURCE  = "http://www.hrupin.com/wp-content/uploads/mp3/testsong_20_sec.mp3";
//  private static String AUDIO_SOURCE;

    private boolean mIsMusicReadyToBePlayed = false;
    private boolean mIsMusicPrepared = false;

    private String fileUri; //Holds the address of current video which is capturing
    private Camera mCamera;
    private CamcorderView preview;

    private MediaRecorder mMediaRecorder = null;
    private boolean isRecording = false;
    private boolean isAudioPlayerReady = false;
    private boolean isVideoRecorderReady = false;

    private MediaPlayer mediaPlayer = null;

    private ImageView stopButton;
    private ImageView captureButton;
    private ImageView imHide;
    private RelativeLayout rlMenu;
    private TextView tvInfo;

    private Handler mHandler;
    private Runnable mUpdateUITimerTask;

    private int elapsedTime = 0;
    private DecimalFormat df;

    private Animation animation;


    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camcorder_preview);


        Log.i(TAG, "VideoRecording activity started...");


        Bundle extras = getIntent().getExtras();
        if (extras == null) {
            return;
        }
//      AUDIO_SOURCE = extras.getString("SONG_URL");
        Log.i(TAG, "Music comes from: " + AUDIO_SOURCE);


        // Close activity if there is no camera
        if(!checkCameraHardware(VideoRecording.this)){
            Toast.makeText(VideoRecording.this, "Sorry! Your device doesn't have camera.", Toast.LENGTH_LONG).show();
            VideoRecording.this.finish();
        }

        // Create an instance of Camera
        mCamera = getCameraInstance();
        if(mCamera == null){
            Toast.makeText(VideoRecording.this, "Oops! Your device doesn't have camera or it's in use.", Toast.LENGTH_LONG).show();
            releaseCamera();
            VideoRecording.this.finish();
        }



        // Initialize Animation, setting alpha of button view 0 and 1 in order to blink the button
        recordAnimation();

        // Set volume button of mobile device to increase/decrease sound instead of ringtone 
        setVolumeControlStream(AudioManager.STREAM_MUSIC);


        tvInfo = (TextView) findViewById(R.id.tv_info);
        df = new DecimalFormat("#.##");

        mHandler = new Handler();
        mUpdateUITimerTask = new Runnable() {
            public void run() {
                elapsedTime++;

                int hours = elapsedTime / 3600;
                int remainder = elapsedTime - hours * 3600;
                int mins = remainder / 60;
                remainder = remainder - mins * 60;
                int secs = remainder;


                File file = new File(getOutputMediaFileUri());
                float fileSize = file.length();

                if(fileSize <= 1024)
                    tvInfo.setText("E.T: " + hours + ":" + mins + ":" + secs + " / " + df.format(fileSize));
                else if((fileSize > 1024) && (fileSize <= 1024*1024)){
                    fileSize /= 1024;
                    tvInfo.setText("E.T: " + hours + ":" + mins + ":" + secs + " / " + df.format(fileSize) + " K");
                } else if((fileSize > 1024*1024) && (fileSize <= 1024*1024*1024)){
                    fileSize /= 1024*1024;
                    tvInfo.setText("E.T: " + hours + ":" + mins + ":" + secs + " / " + df.format(fileSize) + " M");
                } else{
                    fileSize /= 1024*1024*1024;
                    tvInfo.setText("E.T: " + hours + ":" + mins + ":" + secs + " / " + df.format(fileSize) + " G");
                }

//              Log.i(TAG, " " + elapsedTime + " / " + fileSize + " : " + fileUri.toString());

                mHandler.postDelayed(mUpdateUITimerTask, 1000);
            }
        };


        // Create our Preview view and set it as the content of our activity.
        preview = new CamcorderView(this, mCamera);
        FrameLayout flPreview = (FrameLayout) findViewById(R.id.camera_preview);
        flPreview.addView(preview);


        // initialize media player
        isAudioPlayerReady   = prepareAudioPlayer();
        isVideoRecorderReady = prepareVideoRecorder();

        // Add a listener to the Capture button
        captureButton = (ImageView) findViewById(R.id.btn_record);
        captureButton.setVisibility(View.INVISIBLE);
        captureButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {   
                    captureButton.setEnabled(false);
                    stopButton.setEnabled(true);

                    if (!isRecording) {

                        // initialize video camera
                        if (isAudioPlayerReady && isVideoRecorderReady) {
                            // Play background music
                            startMusicPlayback();

                            // Camera is available and unlocked, MediaRecorder is prepared,
                            // now you can start recording
                            mMediaRecorder.start();

                            // inform the user that recording has started
                            Toast.makeText(VideoRecording.this, "Video recording started", Toast.LENGTH_LONG).show();
                            isRecording = true;


                            captureButton.startAnimation(animation);

                            // Try to call handller each one second to update elapse time on screen
                            mHandler.postDelayed(mUpdateUITimerTask, 1000);
                        } 
                    }
                }
        });

        stopButton = (ImageView) findViewById(R.id.btn_stop);
        stopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                captureButton.setEnabled(true);
                stopButton.setEnabled(false);

                if (isRecording) {
                    // stop recording and release camera
                    pauseMusicPlayback();

//                    mCamera.lock();         // take camera access back from MediaRecorder

                    // inform the user that recording has stopped
                    Toast.makeText(VideoRecording.this, "Video recording stopped", Toast.LENGTH_LONG).show();
                    isRecording = false;

                    captureButton.clearAnimation();

                    // Try to stop handller
                    elapsedTime = 0;
                    mHandler.removeCallbacks(mUpdateUITimerTask);
                }
            }
        });

        Button btnDone = (Button) findViewById(R.id.btn_done);
        btnDone.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                VideoRecording.this.finish();
            }
        });

        rlMenu = (RelativeLayout) findViewById(R.id.rlMenu);
        imHide  = (ImageView) findViewById(R.id.btn_hide);
        imHide.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                rlMenu.setVisibility(View.INVISIBLE);
            }
        });
    }


    @Override
    protected void onPause() {
        super.onPause();

        Log.i(TAG, "onPause called");

        // Reset Audio manager to stream ring when user pushes volume button
        setVolumeControlStream(AudioManager.STREAM_RING);

        releaseMediaRecorder();       // if you are using MediaRecorder, release it first
        releaseCamera();              // release the camera immediately on pause event

        releaseMediaPlayer();

        elapsedTime = 0;
        mHandler.removeCallbacks(mUpdateUITimerTask);

        captureButton.clearAnimation();

        // Closing the activity
        VideoRecording.this.finish();

        Log.i(TAG, "All resources are released from memory in onPause() method.");
    }   


    public void onBufferingUpdate(MediaPlayer arg0, int percent) {
        if(percent <= 99)
            Log.i(TAG, "onBufferingUpdate percent:" + percent);
        else {
            captureButton.setVisibility(View.VISIBLE);
            mIsMusicReadyToBePlayed = true;
        }
    }

    public void onCompletion(MediaPlayer arg0) {
        Log.i(TAG, "onCompletion called");
    }

    public void onPrepared(MediaPlayer mediaplayer) {
        Log.i(TAG, "onPrepared called");

        mIsMusicPrepared = true;
    }

    private void startMusicPlayback() {
        Log.i(TAG, "startMusicPlayback called");

        if(mIsMusicReadyToBePlayed && mIsMusicPrepared) {
            if(!mediaPlayer.isPlaying()) {
                mediaPlayer.seekTo(0);
                mediaPlayer.start();
            }
        }
    }

    private void pauseMusicPlayback() {
        Log.i(TAG, "pauseMusicPlayback called");

        if(mediaPlayer.isPlaying())
            mediaPlayer.pause();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        rlMenu.setVisibility(View.VISIBLE);

        return super.onTouchEvent(event);
    }


    private boolean prepareVideoRecorder(){

        mMediaRecorder = new MediaRecorder();

        // Step 1: Unlock and set camera to MediaRecorder
        mCamera.unlock();
        mMediaRecorder.setCamera(mCamera);

        // Step 2: Set sources
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

//      // Step *: Optional settings
//      mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

        // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
        mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

        // Step 4: Set output file
        mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

        // Step 5: Set the preview output
        mMediaRecorder.setPreviewDisplay(preview.getHolder().getSurface());     

        // Step 7: Prepare configured MediaRecorder
        try {
            mMediaRecorder.prepare();
            Log.i(TAG, "Media Recorder prepared successfully.");
        } catch (IllegalStateException e) {
            Log.e(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage(), e);
            releaseMediaRecorder();
            return false;
        } catch (IOException e) {
            Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage(), e);
            releaseMediaRecorder();
            return false;
        }

        // Optional settings
//      mMediaRecorder.setVideoEncodingBitRate();
//      mMediaRecorder.setVideoSize();
//      mMediaRecorder.setVideoFrameRate();
//      mMediaRecorder.setAudioEncodingBitRate();
//      mMediaRecorder.setAudioChannels();
//      mMediaRecorder.setAudioSamplingRate();


        return true;
    }


    private boolean prepareAudioPlayer() {
        boolean flag = false;

        // Create a new media player and set the listeners       
        mediaPlayer = new MediaPlayer();

        try {
            mediaPlayer.setDataSource(AUDIO_SOURCE);
            mediaPlayer.prepare();
            mediaPlayer.setOnBufferingUpdateListener(this);
            mediaPlayer.setOnCompletionListener(this);
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

            flag = true;    
            Log.i(TAG, "Media Player prepared successfully.");
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Media Player did not prepare successfully.");
            Log.e(TAG, "IllegalArgumentException > " + e.getMessage(), e);
        } catch (IllegalStateException e) {
            Log.e(TAG, "Media Player did not prepare successfully.");
            Log.e(TAG, "IllegalStateException > " + e.getMessage(), e);
        } catch (IOException e) {
            Log.e(TAG, "Media Player did not prepare successfully.");
            Log.e(TAG, "IOException > " + e.getMessage(), e);
        }

        return flag;
    }


    /** Create a file Uri for saving an image or video */
    private String getOutputMediaFileUri(){
          return fileUri;
    }

    /** Create a File for saving an image or video */
    private File getOutputMediaFile(int type) {
        // To be safe, you should check that the SDCard is mounted
        // using Environment.getExternalStorageState() before doing this.
        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), MEDIA_NAME);
        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.

        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                Log.e(MEDIA_NAME, "failed to create directory");
                Toast.makeText(VideoRecording.this, "SD Card not found!", Toast.LENGTH_LONG).show();
                return null;
            }
        }

        // Create a media file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File mediaFile;
        if (type == MEDIA_TYPE_VIDEO){
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + MEDIA_NAME + "_"+ timeStamp + VIDEO_FORMAT); // or .mp4
            fileUri = mediaFile.toString();
        } else {
            return null;
        }

        return mediaFile;
    }

    private void releaseMediaRecorder() {
        if (mMediaRecorder != null) {
            mMediaRecorder.reset();   // clear recorder configuration
            mMediaRecorder.release(); // release the recorder object
            mMediaRecorder = null;
            mCamera.lock();           // lock camera for later use

            Log.i(TAG, "Media Recorder released successfully.");
        }
    }

    private void releaseCamera() {
        if (mCamera != null){
            mCamera.release();        // release the camera for other applications
            mCamera = null;

            Log.i(TAG, "Camera released successfully.");
        }
    }

    /** A safe way to get an instance of the Camera object. */
    public Camera getCameraInstance() {
        Camera c = null;
        try {
            c = Camera.open(); // attempt to get a Camera instance
        } catch (Exception e){
            // Camera is not available (in use or does not exist)
            Toast.makeText(VideoRecording.this, "Sorry! Your device doesn't have camera or it's in use.", Toast.LENGTH_LONG).show();
        }
        return c; // returns null if camera is unavailable
    }

    /** Check if this device has a camera */
    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            // this device has a camera
            return true;
        } else {
            // no camera on this device
            return false;
        }
    }

    private void releaseMediaPlayer() {
        if(mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;

            Log.i(TAG, "Media Player released successfully.");
        }
    }

    private void recordAnimation(){
        animation = new AlphaAnimation(1, 0); // Change alpha from fully visible to invisible
        animation.setDuration(500); // duration - half a second
        animation.setInterpolator(new LinearInterpolator()); // do not alter animation rate
        animation.setRepeatCount(Animation.INFINITE); // Repeat animation infinitely
        animation.setRepeatMode(Animation.REVERSE); // Reverse animation at the end so the button will fade back in
    }

}

4

0 に答える 0