2016-03-16 30 views
6

Tôi đang quay video trong ứng dụng Android của mình bằng cách sử dụng MediaRecorder và tôi cũng muốn dữ liệu khung thông qua gọi lại onPreviewFrame.Không thể quay video và chụp khung hình từ trênPreviewFrame gọi lại cùng một lúc

Sự cố là: Nếu xem trước được khởi động lại trong surfaceChanged gọi lại thì quá trình quay video sẽ ngừng hoạt động. Nếu nó không được khởi động lại, bằng cách bình luận mọi thứ bên trong surfaceChanged, thì việc quay video vẫn hoạt động nhưng cuộc gọi lại onPreviewFrame ngừng hoạt động.

Tôi làm cách nào để cả hai hoạt động?

CameraActivity.java

import android.app.Activity; 
import android.hardware.Camera; 
import android.media.MediaRecorder; 
import android.os.Bundle; 
import android.os.Environment; 
import android.util.Log; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 
import android.view.View; 
import android.widget.Button; 
import android.widget.Toast; 

import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 

public class CameraActivity extends Activity implements SurfaceHolder.Callback, Camera.PreviewCallback { 
    private static final String TAG = "CameraActivity"; 

    public static final int MEDIA_TYPE_IMAGE = 1; 
    public static final int MEDIA_TYPE_VIDEO = 2; 

    private Camera mCamera; 
    private SurfaceView mPreview; 
    private SurfaceHolder mHolder; 
    private MediaRecorder mMediaRecorder; 
    private boolean isRecording = false; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_camera); 

     // Create an instance of Camera 
     mCamera = getCameraInstance(); 

     if (mCamera != null) { 
      // Create our Preview view and set it as the content of our activity. 
      mPreview = (SurfaceView) findViewById(R.id.camera_preview); 
      // Install a SurfaceHolder.Callback so we get notified when the 
      // underlying surface is created and destroyed. 
      mHolder = mPreview.getHolder(); 
      mHolder.addCallback(this); 
     } 

     startLockTask(); 
    } 

    public void surfaceCreated(SurfaceHolder holder) { 
     // The Surface has been created, now tell the camera where to draw the preview. 
     try { 
      mCamera.setPreviewCallback(this); 
      mCamera.setPreviewDisplay(holder); 
      mCamera.startPreview(); 

      prepareMediaRecorder(); 
      startVideoRecording(); 
     } catch (IOException e) { 
      Log.d(TAG, "Error setting camera preview: " + e.getMessage()); 
     } 
    } 

    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.setPreviewCallback(this); 
      mCamera.setPreviewDisplay(mHolder); 
      mCamera.startPreview(); 
     } catch (Exception e){ 
      Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 
     } 
    } 

    @Override 
    public void onPreviewFrame(byte[] bytes, Camera camera) { 

    } 

    private boolean prepareMediaRecorder() { 
     mMediaRecorder = new MediaRecorder(); 

     mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() { 
      @Override 
      public void onError(MediaRecorder mediaRecorder, int what, int extra) { 
       Log.e(TAG, "Media recorder error"); 
      } 
     }); 

     mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { 
      @Override 
      public void onInfo(MediaRecorder mr, int what, int extra) { 
       if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) { 
        stopVideoRecording(); 
        releaseMediaRecorder(); 
        prepareMediaRecorder(); 
        startVideoRecording(); 
       } 
      } 
     }); 

     // 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 3: Set a CamcorderProfile (requires API Level 8 or higher) 
//  mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW)); 

     mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 
     mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP); 
     mMediaRecorder.setVideoFrameRate(3); 
     mMediaRecorder.setVideoEncodingBitRate(6000000); 
     mMediaRecorder.setVideoSize(800, 480); 
     mMediaRecorder.setMaxDuration(60000); 

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

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

     // Step 6: Prepare configured MediaRecorder 
     try { 
      mMediaRecorder.prepare(); 
     } catch (IllegalStateException e) { 
      Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage()); 
      releaseMediaRecorder(); 
      return false; 
     } catch (IOException e) { 
      Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage()); 
      releaseMediaRecorder(); 
      return false; 
     } 
     return true; 
    } 

    private void startVideoRecording() { 
     mMediaRecorder.start(); 
     isRecording = true; 
    } 

    private void stopVideoRecording() { 
     // stop recording and release camera 
     mMediaRecorder.stop(); // stop the recording 
     isRecording = false; 
    } 

    /** A safe way to get an instance of the Camera object. */ 
    public static 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) 
     } 
     return c; // returns null if camera is unavailable 
    } 

    @Override 
    protected void onDestroy() { 
     super.onDestroy(); 
     releaseMediaRecorder();  // if you are using MediaRecorder, release it first 
     releaseCamera();    // release the camera immediately on pause event 
    } 

    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 
     } 
    } 

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

    /** Create a File for saving an image or video */ 
    private static 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_PICTURES), "MyCameraApp"); 
     // 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.d("MyCameraApp", "failed to create directory"); 
       return null; 
      } 
     } 

     // Create a media file name 
     String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
     File mediaFile; 
     if (type == MEDIA_TYPE_IMAGE){ 
      mediaFile = new File(mediaStorageDir.getPath() + File.separator + 
        "IMG_"+ timeStamp + ".jpg"); 
     } else if(type == MEDIA_TYPE_VIDEO) { 
      mediaFile = new File(mediaStorageDir.getPath() + File.separator + 
        "VID_"+ timeStamp + ".mp4"); 
     } else { 
      return null; 
     } 

     return mediaFile; 
    } 
} 

activity_camera.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="horizontal" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
    <SurfaceView 
     android:id="@+id/camera_preview" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:layout_weight="1" 
     /> 
</LinearLayout> 
+1

Đối với các API Máy ảnh cũ, bạn sẽ cần phải chỉ đạo việc xem trước để một SurfaceTexture, và sau đó việc này là hai lần, một lần cho màn hình và một lần để ghi (xem ví dụ https://github.com/google/grafika). Với Camera2 tôi tin rằng bạn có thể cấu hình nhiều bề mặt đầu ra. Yêu cầu API tối thiểu của bạn là gì? – fadden

+0

@fadden 21. Vì vậy, tôi có thể sử dụng Camera2. Nhưng tôi không thể hiểu tại sao 'SurfaceTexture' sẽ hoạt động và' SurfaceView' sẽ không? Làm thế nào điều này liên quan đến gọi lại 'onPreviewFrame'? –

+1

API camera cũ chỉ có thể chuyển tiếp khung đến một đích. Chụp ảnh đã dừng xem trước. Việc gửi khung đến SurfaceTexture không thay đổi điều đó, nhưng một khi bạn có khung trong kết cấu GLES, bạn có thể hiển thị khung đó bao nhiêu lần tùy thích. – fadden

Trả lời

0

Mã của bạn là gần như tương tự để liên kết được cung cấp dưới đây nhưng ở đây họ đã sử dụng TextureView thay vì Surface Xem và lớp tùy chỉnh CameraView.

này làm việc cho tôi, hy vọng sẽ giúp bạn quá

REF: https://github.com/googlesamples/android-MediaRecorder

Các vấn đề liên quan