使用表面视图android录制视频

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23948573/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:39:44  来源:igfitidea点击:

Record Video using surface view android

androidandroid-mediarecordervideo-recording

提问by Ravi Bhandari

I have to create an android app in which i am trying to record video and capture image using surface view. Up to now i am able to capture video but facing problem in record video. My code for video recording is -

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

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

    }

but app force close when onSurfaceChange method code is called at line - mCamera.setPreviewDisplay(surfaceHolder); with exception java.lang.RuntimeException: setParameters failed

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

so how can i manage it so i can start video recording. Thanks in advance.

那么我该如何管理它以便我可以开始视频录制。提前致谢。

回答by Aniruddha

Check this code, hopefully it works..

检查此代码,希望它有效..

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

Permissions

权限

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

XML文件

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

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

回答by Aniruddha

You can get a list of available preview sizes by calling getSupportedPreviewSizes in the Camera.Parameters object returned by Camera.getParameters. Check here

您可以通过在 Camera.getParameters 返回的 Camera.Parameters 对象中调用 getSupportedPreviewSizes 来获取可用预览尺寸的列表。在这里查看

Add these below code inside surfaceChangedmethod

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

EDITChange your surfaceChangedmethod like below and check

编辑更改您的surfaceChanged方法如下所示并检查

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.
        Log.d("Function", "surfaceChanged");
        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.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }