【问题标题】:invalid preview surface android video recording无效的预览表面android视频录制
【发布时间】:2014-03-06 10:35:24
【问题描述】:

我有一个服务,我尝试将服务记录视频归档。

启动Service的Activity:

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();
}

服务:

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();
    }
}

当我在 Galaxy s 上调试代码时,我得到了 toast(在 StartRecord() 方法中)“无效的预览表面”

如何解决?

【问题讨论】:

    标签: android android-camera


    【解决方案1】:

    您看到的原因是您在创建表面之前执行了mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());。添加延迟碰巧有效,但不是处理此问题的正确方法。

    mSurfaceHolder = mSurfaceView.getHolder(); 行不会立即创建曲面。实际上 SurfaceHolder 提供了一个回调接口,让你知道 Surface 何时创建。

    mSurfaceHolder.addCallback(this); 行应位于您创建的类的构造函数中,该类扩展 SurfaceView 并实现 SurfaceHolder.Callback。然后,您可以覆盖 SurfaceHolder.Callback 接口的回调方法,以便您的代码在表面创建后执行。这是一个例子:

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

    【讨论】:

      【解决方案2】:

      我不得不延迟执行 MediaRecorder 启动。这意味着在onResume 中,我创建了一个处理程序并在其上调用了postDelayed。我知道,它仍然是同一个线程,但它对我有用。

      【讨论】:

      • 这行得通,但看起来相当老套。更好地使用回调。查看 Sani 的回答
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-27
      • 2017-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-19
      • 1970-01-01
      相关资源
      最近更新 更多