如何在Android上捕捉video录制?
如何在Android上捕捉video录制?
以下是使用MediaRecorder的一个简单的录像例子:
public class VideoCapture extends Activity implements OnClickListener, SurfaceHolder.Callback { MediaRecorder recorder; SurfaceHolder holder; boolean recording = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); recorder = new MediaRecorder(); initRecorder(); setContentView(R.layout.main); SurfaceView cameraView = (SurfaceView) findViewById(R.id.CameraView); holder = cameraView.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); cameraView.setClickable(true); cameraView.setOnClickListener(this); } private void initRecorder() { recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); CamcorderProfile cpHigh = CamcorderProfile .get(CamcorderProfile.QUALITY_HIGH); recorder.setProfile(cpHigh); recorder.setOutputFile("/sdcard/videocapture_example.mp4"); recorder.setMaxDuration(50000); // 50 seconds recorder.setMaxFileSize(5000000); // Approximately 5 megabytes } private void prepareRecorder() { recorder.setPreviewDisplay(holder.getSurface()); try { recorder.prepare(); } catch (IllegalStateException e) { e.printStackTrace(); finish(); } catch (IOException e) { e.printStackTrace(); finish(); } } public void onClick(View v) { if (recording) { recorder.stop(); recording = false; // Let's initRecorder so we can record again initRecorder(); prepareRecorder(); } else { recording = true; recorder.start(); } } public void surfaceCreated(SurfaceHolder holder) { prepareRecorder(); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } public void surfaceDestroyed(SurfaceHolder holder) { if (recording) { recorder.stop(); recording = false; } recorder.release(); finish(); } }
这是从我的书: 专业Android媒体:为智能手机和平板电脑开发graphics,音乐,video和富媒体应用程序
另外,不要忘记在清单中包含这些权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
这是另一个正在工作的例子
public class EnregistrementVideoStackActivity extends Activity implements SurfaceHolder.Callback { private SurfaceHolder surfaceHolder; private SurfaceView surfaceView; public MediaRecorder mrec = new MediaRecorder(); private Button startRecording = null; File video; private Camera mCamera; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.camera_surface); Log.i(null , "Video starting"); startRecording = (Button)findViewById(R.id.buttonstart); mCamera = Camera.open(); surfaceView = (SurfaceView) findViewById(R.id.surface_camera); surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, 0, 0, "StartRecording"); menu.add(0, 1, 0, "StopRecording"); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case 0: try { startRecording(); } catch (Exception e) { String message = e.getMessage(); Log.i(null, "Problem Start"+message); mrec.release(); } break; case 1: //GoToAllNotes mrec.stop(); mrec.release(); mrec = null; break; default: break; } return super.onOptionsItemSelected(item); } protected void startRecording() throws IOException { mrec = new MediaRecorder(); // Works well mCamera.unlock(); mrec.setCamera(mCamera); mrec.setPreviewDisplay(surfaceHolder.getSurface()); mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA); mrec.setAudioSource(MediaRecorder.AudioSource.MIC); mrec.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); mrec.setPreviewDisplay(surfaceHolder.getSurface()); mrec.setOutputFile("/sdcard/zzzz.3gp"); mrec.prepare(); mrec.start(); } protected void stopRecording() { mrec.stop(); mrec.release(); mCamera.release(); } private void releaseMediaRecorder(){ if (mrec != null) { mrec.reset(); // clear recorder configuration mrec.release(); // release the recorder object mrec = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { if (mCamera != null){ Parameters params = mCamera.getParameters(); mCamera.setParameters(params); } else { Toast.makeText(getApplicationContext(), "Camera not available!", Toast.LENGTH_LONG).show(); finish(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { mCamera.stopPreview(); mCamera.release(); } }
camera_surface.xml
<?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <SurfaceView android:id="@+id/surface_camera" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:id="@+id/buttonstart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/record_start" /> </RelativeLayout>
当然也包括这些许可:
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
您使用相同的MediaRecorder类录制audio和video。 这很简单。 这是一个例子 。
这个演示将有助于你….
video.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ToggleButton android:id="@+id/toggleRecordingButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" /> <SurfaceView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/surface_camera" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerInParent="true" android:layout_weight="1" > </SurfaceView>
您的主要活动:Video.java
public class Video extends Activity implements OnClickListener, SurfaceHolder.Callback { private static final String TAG = "CAMERA_TUTORIAL"; private SurfaceView mSurfaceView; private SurfaceHolder mHolder; private Camera mCamera; private boolean previewRunning; private MediaRecorder mMediaRecorder; private final int maxDurationInMs = 20000; private final long maxFileSizeInBytes = 500000; private final int videoFramesPerSecond = 20; Button btn_record; boolean mInitSuccesful = false; File file; ToggleButton mToggleButton; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.video); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera); 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(); else { mMediaRecorder.stop(); mMediaRecorder.reset(); try { initRecorder(mHolder.getSurface()); } catch (IOException e) { e.printStackTrace(); } } } }); } 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.CAMERA); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); mMediaRecorder.setOutputFile(this.initFile().getAbsolutePath()); // No limit. Don't forget to check the space on disk. mMediaRecorder.setMaxDuration(50000); mMediaRecorder.setVideoFrameRate(24); mMediaRecorder.setVideoSize(1280, 720); mMediaRecorder.setVideoEncodingBitRate(3000000); mMediaRecorder.setAudioEncodingBitRate(8000); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT); mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); try { mMediaRecorder.prepare(); } catch (IllegalStateException e) { // This is thrown if the previous calls are not called with the // proper order e.printStackTrace(); } mInitSuccesful = true; } private File initFile() { // File dir = new // File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), // this File dir = new File(Environment.getExternalStorageDirectory(), this .getClass().getPackage().getName()); if (!dir.exists() && !dir.mkdirs()) { Log.wtf(TAG, "Failed to create storage directory: " + dir.getAbsolutePath()); Toast.makeText(Video.this, "not record", Toast.LENGTH_SHORT); file = null; } else { file = new File(dir.getAbsolutePath(), new SimpleDateFormat( "'IMG_'yyyyMMddHHmmss'.mp4'").format(new Date())); } return file; } @Override public void surfaceCreated(SurfaceHolder holder) { try { if (!mInitSuccesful) initRecorder(mHolder.getSurface()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 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; } @Override public void surfaceDestroyed(SurfaceHolder holder) { shutdown(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void onClick(View v) { // TODO Auto-generated method stub } }
MediaMetadataRetriever类
public class MediaMetadataRetriever { static { System.loadLibrary("media_jni"); native_init(); } // The field below is accessed by native methods @SuppressWarnings("unused") private int mNativeContext; public MediaMetadataRetriever() { native_setup(); } /** * Call this method before setDataSource() so that the mode becomes * effective for subsequent operations. This method can be called only once * at the beginning if the intended mode of operation for a * MediaMetadataRetriever object remains the same for its whole lifetime, * and thus it is unnecessary to call this method each time setDataSource() * is called. If this is not never called (which is allowed), by default the * intended mode of operation is to both capture frame and retrieve meta * data (ie, MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY). * Often, this may not be what one wants, since doing this has negative * performance impact on execution time of a call to setDataSource(), since * both types of operations may be time consuming. * * @param mode The intended mode of operation. Can be any combination of * MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY: * 1. MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY: * For neither frame capture nor meta data retrieval * 2. MODE_GET_METADATA_ONLY: For meta data retrieval only * 3. MODE_CAPTURE_FRAME_ONLY: For frame capture only * 4. MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY: * For both frame capture and meta data retrieval */ public native void setMode(int mode); /** * @return the current mode of operation. A negative return value indicates * some runtime error has occurred. */ public native int getMode(); /** * Sets the data source (file pathname) to use. Call this * method before the rest of the methods in this class. This method may be * time-consuming. * * @param path The path of the input media file. * @throws IllegalArgumentException If the path is invalid. */ public native void setDataSource(String path) throws IllegalArgumentException; /** * Sets the data source (FileDescriptor) to use. It is the caller's * responsibility to close the file descriptor. It is safe to do so as soon * as this call returns. Call this method before the rest of the methods in * this class. This method may be time-consuming. * * @param fd the FileDescriptor for the file you want to play * @param offset the offset into the file where the data to be played starts, * in bytes. It must be non-negative * @param length the length in bytes of the data to be played. It must be * non-negative. * @throws IllegalArgumentException if the arguments are invalid */ public native void setDataSource(FileDescriptor fd, long offset, long length) throws IllegalArgumentException; /** * Sets the data source (FileDescriptor) to use. It is the caller's * responsibility to close the file descriptor. It is safe to do so as soon * as this call returns. Call this method before the rest of the methods in * this class. This method may be time-consuming. * * @param fd the FileDescriptor for the file you want to play * @throws IllegalArgumentException if the FileDescriptor is invalid */ public void setDataSource(FileDescriptor fd) throws IllegalArgumentException { // intentionally less than LONG_MAX setDataSource(fd, 0, 0x7ffffffffffffffL); } /** * Sets the data source as a content Uri. Call this method before * the rest of the methods in this class. This method may be time-consuming. * * @param context the Context to use when resolving the Uri * @param uri the Content URI of the data you want to play * @throws IllegalArgumentException if the Uri is invalid * @throws SecurityException if the Uri cannot be used due to lack of * permission. */ public void setDataSource(Context context, Uri uri) throws IllegalArgumentException, SecurityException { if (uri == null) { throw new IllegalArgumentException(); } String scheme = uri.getScheme(); if(scheme == null || scheme.equals("file")) { setDataSource(uri.getPath()); return; } AssetFileDescriptor fd = null; try { ContentResolver resolver = context.getContentResolver(); try { fd = resolver.openAssetFileDescriptor(uri, "r"); } catch(FileNotFoundException e) { throw new IllegalArgumentException(); } if (fd == null) { throw new IllegalArgumentException(); } FileDescriptor descriptor = fd.getFileDescriptor(); if (!descriptor.valid()) { throw new IllegalArgumentException(); } // Note: using getDeclaredLength so that our behavior is the same // as previous versions when the content provider is returning // a full file. if (fd.getDeclaredLength() < 0) { setDataSource(descriptor); } else { setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength()); } return; } catch (SecurityException ex) { } finally { try { if (fd != null) { fd.close(); } } catch(IOException ioEx) { } } setDataSource(uri.toString()); } /** * Call this method after setDataSource(). This method retrieves the * meta data value associated with the keyCode. * * The keyCode currently supported is listed below as METADATA_XXX * constants. With any other value, it returns a null pointer. * * @param keyCode One of the constants listed below at the end of the class. * @return The meta data value associate with the given keyCode on success; * null on failure. */ public native String extractMetadata(int keyCode); /** * Call this method after setDataSource(). This method finds a * representative frame if successful and returns it as a bitmap. This is * useful for generating a thumbnail for an input media source. * * @return A Bitmap containing a representative video frame, which * can be null, if such a frame cannot be retrieved. */ public native Bitmap captureFrame(); /** * Call this method after setDataSource(). This method finds the optional * graphic or album art associated (embedded or external url linked) the * related data source. * * @return null if no such graphic is found. */ public native byte[] extractAlbumArt(); /** * Call it when one is done with the object. This method releases the memory * allocated internally. */ public native void release(); private native void native_setup(); private static native void native_init(); private native final void native_finalize(); @Override protected void finalize() throws Throwable { try { native_finalize(); } finally { super.finalize(); } } public static final int MODE_GET_METADATA_ONLY = 0x01; public static final int MODE_CAPTURE_FRAME_ONLY = 0x02; /* * Do not change these values without updating their counterparts * in include/media/mediametadataretriever.h! */ public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; public static final int METADATA_KEY_ALBUM = 1; public static final int METADATA_KEY_ARTIST = 2; public static final int METADATA_KEY_AUTHOR = 3; public static final int METADATA_KEY_COMPOSER = 4; public static final int METADATA_KEY_DATE = 5; public static final int METADATA_KEY_GENRE = 6; public static final int METADATA_KEY_TITLE = 7; public static final int METADATA_KEY_YEAR = 8; public static final int METADATA_KEY_DURATION = 9; public static final int METADATA_KEY_NUM_TRACKS = 10; public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11; public static final int METADATA_KEY_CODEC = 12; public static final int METADATA_KEY_RATING = 13; public static final int METADATA_KEY_COMMENT = 14; public static final int METADATA_KEY_COPYRIGHT = 15; public static final int METADATA_KEY_BIT_RATE = 16; public static final int METADATA_KEY_FRAME_RATE = 17; public static final int METADATA_KEY_VIDEO_FORMAT = 18; public static final int METADATA_KEY_VIDEO_HEIGHT = 19; public static final int METADATA_KEY_VIDEO_WIDTH = 20; public static final int METADATA_KEY_WRITER = 21; // Add more here... }
查看这个示例相机预览代码CameraPreview
。 这可以帮助您在video预览中设置video录制代码,创buildMediaRecorder
对象并设置video录制参数。
为了search者的利益,这个例子将给你一个积极的预览,与开始/停止button进行logging。 它从这个安卓博客修改,似乎相当可靠。
java类(VideoWithSurfaceVw)
package <<your packagename here>>; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Activity; import android.content.Context; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; import android.widget.Toast; public class VideoWithSurfaceVw extends Activity{ // Adapted from http://sandyandroidtutorials.blogspot.co.uk/2013/05/android-video-capture-tutorial.html private Camera myCamera; private MyCameraSurfaceView myCameraSurfaceView; private MediaRecorder mediaRecorder; Button myButton; SurfaceHolder surfaceHolder; boolean recording; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); recording = false; setContentView(R.layout.activity_video_with_surface_vw); //Get Camera for preview myCamera = getCameraInstance(); if(myCamera == null){ Toast.makeText(VideoWithSurfaceVw.this, "Fail to get Camera", Toast.LENGTH_LONG).show(); } myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera); FrameLayout myCameraPreview = (FrameLayout)findViewById(R.id.videoview); myCameraPreview.addView(myCameraSurfaceView); myButton = (Button)findViewById(R.id.mybutton); myButton.setOnClickListener(myButtonOnClickListener); } Button.OnClickListener myButtonOnClickListener = new Button.OnClickListener(){ @Override public void onClick(View v) { // TODO Auto-generated method stub try{ if(recording){ // stop recording and release camera mediaRecorder.stop(); // stop the recording releaseMediaRecorder(); // release the MediaRecorder object //Exit after saved //finish(); myButton.setText("REC"); recording = false; }else{ //Release Camera before MediaRecorder start releaseCamera(); if(!prepareMediaRecorder()){ Toast.makeText(VideoWithSurfaceVw.this, "Fail in prepareMediaRecorder()!\n - Ended -", Toast.LENGTH_LONG).show(); finish(); } mediaRecorder.start(); recording = true; myButton.setText("STOP"); } }catch (Exception ex){ ex.printStackTrace(); } }}; private Camera getCameraInstance(){ // TODO Auto-generated method stub Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e){ // Camera is not available (in use or does not exist) } return c; // returns null if camera is unavailable } private String getFileName_CustomFormat() { SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH_mm_ss"); Date now = new Date(); String strDate = sdfDate.format(now); return strDate; } private boolean prepareMediaRecorder(){ myCamera = getCameraInstance(); mediaRecorder = new MediaRecorder(); myCamera.unlock(); mediaRecorder.setCamera(myCamera); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); mediaRecorder.setOutputFile("/sdcard/" + getFileName_CustomFormat() + ".mp4"); //mediaRecorder.setOutputFile("/sdcard/myvideo1.mp4"); mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec. mediaRecorder.setMaxFileSize(50000000); // Set max file size 50M mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface()); try { mediaRecorder.prepare(); } catch (IllegalStateException e) { releaseMediaRecorder(); return false; } catch (IOException e) { releaseMediaRecorder(); return false; } return true; } @Override protected void onPause() { super.onPause(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private void releaseMediaRecorder(){ if (mediaRecorder != null) { mediaRecorder.reset(); // clear recorder configuration mediaRecorder.release(); // release the recorder object mediaRecorder = new MediaRecorder(); myCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (myCamera != null){ myCamera.release(); // release the camera for other applications myCamera = null; } } public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{ private SurfaceHolder mHolder; private Camera mCamera; public MyCameraSurfaceView(Context context, Camera camera) { super(context); mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int weight, int height) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. 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 } // make any resize, rotate or reformatting changes here // start preview with new settings try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e){ } } @Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub // The Surface has been created, now tell the camera where to draw the preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { } } @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub } } }
活动(activity_video_with_surface_vw)
<RelativeLayout android:id="@+id/surface_camera" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerInParent="true" android:layout_weight="1" > <RelativeLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/videoview" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <Button android:id="@+id/mybutton" android:layout_width="100dp" android:layout_height="50dp" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" android:text="REC" android:textSize="12dp"/> </RelativeLayout> </RelativeLayout>
只要按照这个url你可以find所有可用的设置在Android中,一切都是定制的
如果您正在使用后置摄像头,上面的例子将工作。 如果你使用前置摄像头,你将不得不调整一些东西:
首先,您需要在清单中添加新的权限。
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
在你的initRecorder
方法中,而不是
CamcorderProfile cpHigh = CamcorderProfile .get(CamcorderProfile.QUALITY_HIGH); recorder.setProfile(cpHigh);
你需要使用:
CamcorderProfile profile = CamcorderProfile.get(Camera.CameraInfo.CAMERA_FACING_FRONT, CamcorderProfile.QUALITY_LOW); recorder.setProfile(profile);
因为CamcorderProfile.QUALITY_HIGH
是为后置摄像头保留的。
您还将必须设置录像机的video大小,因为它是在您的表面视图。
以下是从前置摄像头录制video的完整示例,带有小型预览显示:
Android.manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera.front" android:required="false" />
activity_camera.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="CameraActivity"> <SurfaceView android:layout_width="200dp" android:layout_height="wrap_content" android:id="@+id/surfaceView"/> <Button android:layout_width="100dp" android:layout_height="100dp" android:text="REC" android:id="@+id/btnRecord" android:layout_alignParentBottom="true" android:layout_marginBottom="25dp" /> </RelativeLayout>
CameraActivity.java
public class SongVideoActivity extends BaseActivity implements SurfaceHolder.Callback { private int mCameraContainerWidth = 0; private SurfaceView mSurfaceView = null; private SurfaceHolder mSurfaceHolder = null; private Camera mCamera = null; private boolean mIsRecording = false; private int mPreviewHeight; private int mPreviewWidth; MediaRecorder mRecorder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_song_video); Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread thread, Throwable ex) { releaseMediaRecorder(); releaseCamera(); } }); mCamera = getCamera(); //camera preview mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mCameraContainerWidth = mSurfaceView.getLayoutParams().width; findViewById(R.id.btnRecord).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mIsRecording) { stopRecording(); } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mRecorder.start(); // inform the user that recording has started Toast.makeText(getApplicationContext(), "Started recording", Toast.LENGTH_SHORT).show(); mIsRecording = true; } else { // prepare didn't work, release the camera releaseMediaRecorder(); // inform user } } } }); } private void stopRecording() { mRecorder.stop(); // stop the recording releaseMediaRecorder(); // release the MediaRecorder object mCamera.lock(); // take camera access back from MediaRecorder // inform the user that recording has stopped Toast.makeText(this, "Recording complete", Toast.LENGTH_SHORT).show(); mIsRecording = false; } @Override protected void onDestroy() { super.onDestroy(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private Camera getCamera() { Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); camIdx++) { Camera.getCameraInfo(camIdx, cameraInfo); if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { try { return mCamera = Camera.open(camIdx); } catch (RuntimeException e) { Log.e("cameras", "Camera failed to open: " + e.getLocalizedMessage()); } } } return null; } @Override protected void onPause() { super.onPause(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private Camera.Size getBestPreviewSize(Camera.Parameters parameters) { Camera.Size result=null; for (Camera.Size size : parameters.getSupportedPreviewSizes()) { if(size.width < size.height) continue; //we are only interested in landscape variants if (result == null) { result = size; } else { int resultArea = result.width*result.height; int newArea = size.width*size.height; if (newArea > resultArea) { result = size; } } } return(result); } private boolean prepareVideoRecorder(){ mRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mRecorder.setCamera(mCamera); // Step 2: Set sources mRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); mRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); //recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) // Customise your profile based on a pre-existing profile CamcorderProfile profile = CamcorderProfile.get(Camera.CameraInfo.CAMERA_FACING_FRONT, CamcorderProfile.QUALITY_LOW); mRecorder.setProfile(profile); // Step 4: Set output file mRecorder.setOutputFile(new File(getFilesDir(), "movie-" + UUID.randomUUID().toString()).getAbsolutePath()); //recorder.setMaxDuration(50000); // 50 seconds //recorder.setMaxFileSize(500000000); // Approximately 500 megabytes mRecorder.setVideoSize(mPreviewWidth, mPreviewHeight); // Step 5: Set the preview output mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); // Step 6: Prepare configured MediaRecorder try { mRecorder.prepare(); } catch (IllegalStateException e) { Toast.makeText(getApplicationContext(), "exception: " + e.getMessage(), Toast.LENGTH_LONG).show(); releaseMediaRecorder(); return false; } catch (IOException e) { Toast.makeText(getApplicationContext(), "exception: " + e.getMessage(), Toast.LENGTH_LONG).show(); releaseMediaRecorder(); return false; } return true; } private void releaseMediaRecorder(){ if (mRecorder != null) { mRecorder.reset(); // clear recorder configuration mRecorder.release(); // release the recorder object mRecorder = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } @Override public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. Camera.Parameters parameters = mCamera.getParameters(); parameters.setRecordingHint(true); Camera.Size size = getBestPreviewSize(parameters); mCamera.setParameters(parameters); //resize the view to the specified surface view width in layout int newHeight = size.height / (size.width / mCameraContainerWidth); mSurfaceView.getLayoutParams().height = newHeight; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mPreviewHeight = mCamera.getParameters().getPreviewSize().height; mPreviewWidth = mCamera.getParameters().getPreviewSize().width; mCamera.stopPreview(); try { mCamera.setPreviewDisplay(mSurfaceHolder); } catch (IOException e) { e.printStackTrace(); } mCamera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (mIsRecording) { stopRecording(); } releaseMediaRecorder(); releaseCamera(); } }
作为一个方面的说明 – 似乎有一个在Android API或错误的文档中的错误,或者我只是简单的愚蠢。 谷歌文档明确指出以下内容:
注意:从Android 4.0(API级别14)开始,Camera.lock()和Camera.unlock()调用会自动为您pipe理。
请参阅: http : //developer.android.com/guide/topics/media/camera.html
这似乎并不是这样!
在没有任何成功和许多小问题如“未能开始”有点错误后,我决定手动实施locking和BAM! 一切正常。
我使用genymotion模拟器4.1.1设备与最小sdk 14。