使用表面视图android录制视频
Posted
技术标签:
【中文标题】使用表面视图android录制视频【英文标题】:Record Video using surface view android 【发布时间】:2014-07-19 20:35:30 【问题描述】:我必须创建一个 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();
但是当在线调用 onSurfaceChange 方法代码时应用程序强制关闭 - mCamera.setPreviewDisplay(surfaceHolder);异常 java.lang.RuntimeException: setParameters failed
那么我该如何管理它,以便我可以开始视频录制。 提前致谢。
【问题讨论】:
它失败了,因为并非所有设备都支持任意预览尺寸。显然有些可以,但你不能依赖它。 那么我该如何处理这个问题。 在下面检查我的答案,它必须在surfaceChanged
方法中完成。
查看此链接github.com/krazykira/CuXtomCam/blob/master/…
我发布的完整示例对您没有帮助?
【参考方案1】:
检查此代码,希望它有效..
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" />
XML 文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_
android:layout_>
<ToggleButton
android:id="@+id/toggleRecordingButton"
android:layout_
android:textOff="Start Recording"
android:textOn="Stop Recording"
android:layout_
/>
<FrameLayout
android:layout_
android:layout_>
<SurfaceView android:id="@+id/surfaceView"
android:layout_
android:layout_></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;
【讨论】:
如果我想增加录制时间? 我可以使用您的代码录制视频..现在可以在录制过程中同时捕获图像吗? hii .. @Aniruddha 我可以录制视频,但我的应用会在 10 秒后录制完成后自动销毁。你能告诉我这背后的原因吗?提前谢谢你 @RuchaBhatt:在mToggleButton.setOnClickListener方法里面,catch块后面有finish(),请注释finish(),然后你的应用程序不会关闭。 我只是复制并粘贴您的代码,但它给了我一个错误Attempt to invoke virtual method 'android.view.SurfaceHolder android.view.SurfaceView.getHolder()' on a null object reference
【参考方案2】:
您可以通过在 Camera.getParameters 返回的 Camera.Parameters 对象中调用 getSupportedPreviewSizes 来获取可用预览尺寸的列表。 Check here
在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();
编辑如下更改您的 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());
【讨论】:
parameters.getSupportedPreviewSizes();在我的三星 s7562 上返回 null 用getPreviewSize
替换getSupportedPreviewSizes
并检查。
ListThis method will always return a list with at least one element.
请换手机检查一次。以上是关于使用表面视图android录制视频的主要内容,如果未能解决你的问题,请参考以下文章