使用surface view android录制视频

使用surface view android录制视频,android,android-mediarecorder,video-recording,Android,Android Mediarecorder,Video Recording,我必须创建一个android应用程序,在其中我尝试使用surface view录制视频和捕获图像。 到目前为止,我能够捕获视频,但在录制视频时遇到了问题。 我的录像代码是- onCreate(){ .. surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH

我必须创建一个android应用程序,在其中我尝试使用surface view录制视频和捕获图像。 到目前为止,我能够捕获视频,但在录制视频时遇到了问题。 我的录像代码是-

onCreate(){
      ..
     surfaceHolder = surfaceView.getHolder();
     surfaceHolder.addCallback(this);
     surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
     startRecording();
     .
     .
}


protected void startRecording() throws IOException
    {
        if(mCamera==null)
            mCamera = Camera.open();

         String filename;
         String path;

         path= Environment.getExternalStorageDirectory().getAbsolutePath().toString();

         Date date=new Date();
         filename="/rec"+date.toString().replace(" ", "_").replace(":", "_")+".mp4";

         File file=new File(path,filename);

        mrec = new MediaRecorder(); 

        mCamera.lock();
        mCamera.unlock();


        mrec.setCamera(mCamera);    
        mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mrec.setAudioSource(MediaRecorder.AudioSource.MIC);     
        mrec.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mrec.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
        mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        mrec.setPreviewDisplay(surfaceHolder.getSurface());
        mrec.setOutputFile(path+filename);
        mrec.setMaxDuration(10000); 
  }
       @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,int                height) {      

        Camera.Parameters parameters = mCamera.getParameters();      
        parameters.setPreviewSize(width, height);     
        try {
            mCamera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        mCamera.setParameters(parameters);       
        mCamera.startPreview(); 

    }
但当在第行调用onSurfaceChange方法代码时,应用程序强制关闭- mCamera.setPreviewDisplay(surfaceHolder);异常为java.lang.RuntimeException:setParameters失败

那么我如何管理它,以便开始录像呢。
提前感谢。

通过调用Camera.getParameters返回的Camera.Parameters对象中的getSupportedPreviewSizes,可以获得可用预览大小的列表

surfaceChanged
方法中添加以下代码

Camera.Parameters parameters = camera.getParameters();  
   List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();  
   Camera.Size cs = sizes.get(0);  // You need to choose the most appropriate previewSize for your app. So select one from the list
   parameters.setPreviewSize(cs.width, cs.height);  
   camera.setParameters(parameters);
   camera.startPreview();

检查这段代码,希望它能工作

import java.io.IOException;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ToggleButton;

public class MediaRecorderRecipe extends Activity implements SurfaceHolder.Callback {
private final String VIDEO_PATH_NAME = "/mnt/sdcard/VGA_30fps_512vbrate.mp4";

private MediaRecorder mMediaRecorder;
private Camera mCamera;
private SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private View mToggleButton;
private boolean mInitSuccesful;

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

    // we shall take the video in landscape orientation
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
    mHolder = mSurfaceView.getHolder();
    mHolder.addCallback(this);
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    mToggleButton = (ToggleButton) findViewById(R.id.toggleRecordingButton);
    mToggleButton.setOnClickListener(new OnClickListener() {
        @Override
        // toggle video recording
        public void onClick(View v) {
            if (((ToggleButton)v).isChecked()) {
                mMediaRecorder.start();
                try {
                    Thread.sleep(10 * 1000); // This will recode for 10 seconds, if you don't want then just remove it.
                } catch (Exception e) {
                    e.printStackTrace();
                }
                finish();
            }
            else {
                mMediaRecorder.stop();
                mMediaRecorder.reset();
                try {
                    initRecorder(mHolder.getSurface());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    });     
}

/* Init the MediaRecorder, the order the methods are called is vital to
 * its correct functioning */
private void initRecorder(Surface surface) throws IOException {
    // It is very important to unlock the camera before doing setCamera
    // or it will results in a black preview
    if(mCamera == null) {
        mCamera = Camera.open();
        mCamera.unlock();
    }

    if(mMediaRecorder == null)  mMediaRecorder = new MediaRecorder();
    mMediaRecorder.setPreviewDisplay(surface);
    mMediaRecorder.setCamera(mCamera);

    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
   //       mMediaRecorder.setOutputFormat(8);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
    mMediaRecorder.setVideoFrameRate(30);
    mMediaRecorder.setVideoSize(640, 480);
    mMediaRecorder.setOutputFile(VIDEO_PATH_NAME);

    try {
        mMediaRecorder.prepare();
    } catch (IllegalStateException e) {
        // This is thrown if the previous calls are not called with the 
        // proper order
        e.printStackTrace();
    }

    mInitSuccesful = true;
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    try {
        if(!mInitSuccesful)
            initRecorder(mHolder.getSurface());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    shutdown();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}

private void shutdown() {
    // Release MediaRecorder and especially the Camera as it's a shared
    // object that can be used by other applications
    mMediaRecorder.reset();
    mMediaRecorder.release();
    mCamera.release();

    // once the objects have been released they can't be reused
    mMediaRecorder = null;
    mCamera = null;
}
权限

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.camera.autofocus" />

它失败是因为并非所有设备都支持任意预览大小。显然有些人会,但你不能依赖它。那么我如何处理这个问题。检查我下面的答案,它必须在
surfaceChanged
方法中完成。检查此链接我发布的完整示例对你没有帮助?参数。getSupportedPreviewSizes();在我的三星S7562上返回null使用
getPreviewSize
替换
getPreviewSize
并选中。列表大小=(列表)参数。getPreviewSize();还返回空。你能用不同的手机检查一下吗?医生说
这种方法总是会返回一个至少包含一个元素的列表。
请更换你的手机并检查一次。如果我想增加录制时间,我可以用你的代码录制视频。现在可以在录制时同时捕获图像了吗怎么了?嗨@Aniruddha我可以录制视频,但我的应用程序会在10秒后录制完成后自动销毁。。你能告诉我这背后的原因吗?谢谢你的光临advance@RuchaBhatt:在mToggleButton.setOnClickListener方法中,catch块后有finish(),请注释finish(),然后您的应用程序将不会关闭。我将复制并通过您的代码,但尝试调用虚拟方法“android.view.SurfaceHolder android.view.SurfaceView.getHolder()时出现错误
)'在空对象引用上
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ToggleButton
 android:id="@+id/toggleRecordingButton"
 android:layout_width="fill_parent"
 android:textOff="Start Recording" 
 android:textOn="Stop Recording"
 android:layout_height="wrap_content"
/>
<FrameLayout
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <SurfaceView android:id="@+id/surfaceView" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"></SurfaceView>

</FrameLayout>
</LinearLayout>
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;
}