invalid preview surface android video recording

笑着哭i 提交于 2019-12-23 10:52:16

问题


I have a service, and I try to make the service record video to file.

The Activity that starts the Service:

public static SurfaceView mSurfaceView;
public static SurfaceHolder mSurfaceHolder;
public static Camera mCamera;
@Override
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView1);
    mSurfaceHolder = mSurfaceView.getHolder();
    mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mSurfaceHolder.addCallback(this);
    Intent intent = new Intent(MainActivity.this, RecordService.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startService(intent);
    finish();
}

the service:

private MediaRecorder mMediaRecorder;
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private boolean mRecordingStatus;
private Camera mServiceCamera;
private Size  mPreviewSize;

@Override
public void onCreate() 
{
    mRecordingStatus = false;
    mSurfaceView = MainActivity.mSurfaceView;
    mSurfaceHolder = MainActivity.mSurfaceHolder;
    mServiceCamera=MainActivity.mCamera;
    InitCamera();
    super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) 
{
    super.onStartCommand(intent, flags, startId);
    if (!mRecordingStatus)
        StartRecord();
    else
        StopRecord();

    return START_STICKY;
}
private void InitCamera()
{
    mServiceCamera = Camera.open();
    Camera.Parameters p = mServiceCamera.getParameters();

    final List<Size> listSize = p.getSupportedPreviewSizes();
    mPreviewSize = listSize.get(2);
    p.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
    p.setPreviewFormat(PixelFormat.YCbCr_420_SP);
    mServiceCamera.setParameters(p);
    try 
    {
        mServiceCamera.setPreviewDisplay(mSurfaceHolder);
        mServiceCamera.startPreview();
    }
    catch (IOException e) 
    {

        e.printStackTrace();
    }

    mServiceCamera.unlock();
}
private void StartRecord()
{
    try
    {
        mMediaRecorder = new MediaRecorder();
        mMediaRecorder.setCamera(mServiceCamera);
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
        mMediaRecorder.setOutputFile(Environment.getExternalStorageDirectory().getPath()+File.separator+ "video.mp4");
        mMediaRecorder.setVideoFrameRate(30);
        mMediaRecorder.setVideoSize(mPreviewSize.width, mPreviewSize.height);
        mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

        mMediaRecorder.prepare();
        mMediaRecorder.start(); 

        mRecordingStatus = true;

        Toast toast = Toast.makeText(getBaseContext(), "Recording",1000);
        toast.show();
    }
    catch (IOException e) 
    {
        Toast toast = Toast.makeText(getBaseContext(), e.getMessage(),2000);
        toast.show();
    }
}

when I debug the code on my Galaxy s I get the toast(in the StartRecord() method) "invalid preview surface"

How it can be fixed?


回答1:


I had to make the MediaRecorder startup be executed with some delay. That means in onResume, I created a Handler and invoked postDelayed on that. It's still the same Thread, I know, but it worked with me.




回答2:


The reason you were seeing is because you executed mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); before the surface was created. Adding a delay happens to work but is not the correct way to handle this.

The line mSurfaceHolder = mSurfaceView.getHolder(); does not create the surface immediately. In fact SurfaceHolder provides a callback interface to let you know when the surface has been created.

The line mSurfaceHolder.addCallback(this); should be in the constructor of a class you create which extends SurfaceView and implements SurfaceHolder.Callback. You can then override the callback methods of the SurfaceHolder.Callback interface so your code executes after the surface has been created. Here is an example:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

private SurfaceHolder surfaceHolder;


public CameraPreview(Context context, VideoHandler vh) {
    super(context);
    videoHandler = vh;

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

@Override
public void surfaceCreated(SurfaceHolder holder) {
    // Perform actions that require Surface to have been created here e.g.
    // mMediaRecorder.setPreviewDisplay(holder.getSurface()); etc.

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    // Take care of releasing camera preview etc.
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // Handle changes
}

}


来源:https://stackoverflow.com/questions/12131508/invalid-preview-surface-android-video-recording

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!